From 762bf140c0e2bfad9d04173c7ac9f202d1cabc36 Mon Sep 17 00:00:00 2001 From: icex2 Date: Sat, 3 Oct 2020 20:56:55 +0200 Subject: [PATCH] Version 1.08 with public source code release. --- .clang-format | 45 + .dockerignore | 10 + .gitignore | 5 + CHANGELOG.md | 56 + CMakeLists.txt | 3 + CONTRIBUTING.md | 31 + Dockerfile | 42 + LICENSE | 24 + Makefile | 67 + Package.mk | 269 ++ README.md | 119 +- cmake/CMakeLists.txt | 66 + cmake/modules/AddResources.cmake | 12 + cmake/src/CMakeLists.txt | 3 + cmake/src/imports/CMakeLists.txt | 1 + cmake/src/imports/cmocka/CMakeLists.txt | 13 + cmake/src/main/CMakeLists.txt | 13 + cmake/src/main/asset/CMakeLists.txt | 7 + cmake/src/main/asset/f2/CMakeLists.txt | 2 + cmake/src/main/asset/f2/lib/CMakeLists.txt | 11 + cmake/src/main/asset/fex/CMakeLists.txt | 2 + cmake/src/main/asset/fex/lib/CMakeLists.txt | 11 + cmake/src/main/asset/fex/tool/CMakeLists.txt | 1 + .../asset/fex/tool/usb-profile/CMakeLists.txt | 11 + cmake/src/main/asset/nx/CMakeLists.txt | 2 + cmake/src/main/asset/nx/lib/CMakeLists.txt | 10 + cmake/src/main/asset/nx/tool/CMakeLists.txt | 1 + .../asset/nx/tool/settings/CMakeLists.txt | 11 + cmake/src/main/asset/nx2/CMakeLists.txt | 2 + cmake/src/main/asset/nx2/lib/CMakeLists.txt | 13 + cmake/src/main/asset/nx2/tool/CMakeLists.txt | 1 + .../asset/nx2/tool/usb-profile/CMakeLists.txt | 11 + cmake/src/main/asset/nxa/CMakeLists.txt | 2 + cmake/src/main/asset/nxa/lib/CMakeLists.txt | 13 + cmake/src/main/asset/nxa/tool/CMakeLists.txt | 1 + .../asset/nxa/tool/usb-profile/CMakeLists.txt | 11 + cmake/src/main/asset/x2/CMakeLists.txt | 1 + cmake/src/main/asset/x2/lib/CMakeLists.txt | 9 + cmake/src/main/asset/zero/CMakeLists.txt | 1 + cmake/src/main/asset/zero/lib/CMakeLists.txt | 9 + cmake/src/main/capnhook/CMakeLists.txt | 2 + cmake/src/main/capnhook/hook/CMakeLists.txt | 20 + .../src/main/capnhook/hooklib/CMakeLists.txt | 20 + cmake/src/main/crypt/CMakeLists.txt | 12 + cmake/src/main/hook/CMakeLists.txt | 16 + cmake/src/main/hook/core/CMakeLists.txt | 14 + cmake/src/main/hook/exc/CMakeLists.txt | 19 + cmake/src/main/hook/f2/CMakeLists.txt | 19 + cmake/src/main/hook/fex/CMakeLists.txt | 18 + cmake/src/main/hook/fst/CMakeLists.txt | 18 + cmake/src/main/hook/mk3/CMakeLists.txt | 19 + cmake/src/main/hook/nx/CMakeLists.txt | 19 + cmake/src/main/hook/nx2/CMakeLists.txt | 19 + cmake/src/main/hook/nxa/CMakeLists.txt | 19 + cmake/src/main/hook/patch/CMakeLists.txt | 39 + cmake/src/main/hook/pri/CMakeLists.txt | 19 + cmake/src/main/hook/pro/CMakeLists.txt | 15 + cmake/src/main/hook/pro2/CMakeLists.txt | 15 + cmake/src/main/hook/propatch/CMakeLists.txt | 13 + cmake/src/main/hook/x2/CMakeLists.txt | 19 + cmake/src/main/hook/zero/CMakeLists.txt | 19 + cmake/src/main/io/CMakeLists.txt | 3 + cmake/src/main/io/piubtn/CMakeLists.txt | 14 + cmake/src/main/io/piuio/CMakeLists.txt | 14 + cmake/src/main/io/util/CMakeLists.txt | 11 + cmake/src/main/ptapi/CMakeLists.txt | 2 + cmake/src/main/ptapi/piubtn/CMakeLists.txt | 10 + .../ptapi/piubtn/joystick-conf/CMakeLists.txt | 11 + .../ptapi/piubtn/joystick-util/CMakeLists.txt | 13 + .../main/ptapi/piubtn/joystick/CMakeLists.txt | 15 + .../ptapi/piubtn/keyboard-conf/CMakeLists.txt | 11 + .../ptapi/piubtn/keyboard-util/CMakeLists.txt | 13 + .../main/ptapi/piubtn/keyboard/CMakeLists.txt | 15 + .../src/main/ptapi/piubtn/null/CMakeLists.txt | 15 + .../src/main/ptapi/piubtn/real/CMakeLists.txt | 15 + .../src/main/ptapi/piubtn/test/CMakeLists.txt | 11 + .../src/main/ptapi/piubtn/util/CMakeLists.txt | 13 + cmake/src/main/ptapi/piuio/CMakeLists.txt | 10 + .../ptapi/piuio/joystick-conf/CMakeLists.txt | 11 + .../ptapi/piuio/joystick-util/CMakeLists.txt | 13 + .../main/ptapi/piuio/joystick/CMakeLists.txt | 15 + .../ptapi/piuio/keyboard-conf/CMakeLists.txt | 11 + .../ptapi/piuio/keyboard-util/CMakeLists.txt | 13 + .../main/ptapi/piuio/keyboard/CMakeLists.txt | 15 + .../src/main/ptapi/piuio/null/CMakeLists.txt | 15 + .../src/main/ptapi/piuio/real/CMakeLists.txt | 15 + .../src/main/ptapi/piuio/test/CMakeLists.txt | 11 + .../src/main/ptapi/piuio/util/CMakeLists.txt | 13 + cmake/src/main/pumpnet/CMakeLists.txt | 2 + cmake/src/main/pumpnet/client/CMakeLists.txt | 11 + cmake/src/main/pumpnet/lib/CMakeLists.txt | 15 + cmake/src/main/sec/CMakeLists.txt | 4 + cmake/src/main/sec/hasp/CMakeLists.txt | 3 + cmake/src/main/sec/hasp/lib/CMakeLists.txt | 17 + cmake/src/main/sec/hasp/old/CMakeLists.txt | 13 + cmake/src/main/sec/hasp/server/CMakeLists.txt | 11 + cmake/src/main/sec/lockchip/CMakeLists.txt | 13 + cmake/src/main/sec/microdog34/CMakeLists.txt | 13 + cmake/src/main/sec/microdog40/CMakeLists.txt | 14 + cmake/src/main/util/CMakeLists.txt | 28 + cmake/src/test/CMakeLists.txt | 9 + cmake/src/test/capnhook/CMakeLists.txt | 1 + cmake/src/test/capnhook/hook/CMakeLists.txt | 1 + .../src/test/capnhook/hook/lib/CMakeLists.txt | 11 + cmake/src/test/hook/CMakeLists.txt | 1 + cmake/src/test/hook/propatch/CMakeLists.txt | 1 + .../test/hook/propatch/usb-fix/CMakeLists.txt | 11 + cmake/src/test/test-util/CMakeLists.txt | 13 + cmake/src/test/util/CMakeLists.txt | 2 + cmake/src/test/util/mem/CMakeLists.txt | 11 + cmake/src/test/util/str/CMakeLists.txt | 11 + dist/api/ptapi-io-piubtn-stub.c | 62 + dist/api/ptapi-io-piuio-stub.c | 79 + dist/conf/exchook.conf | 47 + dist/conf/f2hook.conf | 50 + dist/conf/fexhook.conf | 50 + dist/conf/fsthook.conf | 50 + dist/conf/mk3hook.conf | 62 + dist/conf/nx2hook.conf | 56 + dist/conf/nxahook.conf | 50 + dist/conf/nxhook.conf | 47 + dist/conf/prihook.conf | 47 + dist/conf/pro2hook.conf | 38 + dist/conf/prohook.conf | 50 + dist/conf/x2hook.conf | 47 + dist/conf/zerohook.conf | 47 + dist/piueb | 407 ++ doc/README.md | 10 + doc/api/api.md | 8 + doc/api/io/piubtn.md | 58 + doc/api/io/piuio.md | 57 + doc/api/io/x11-input-hook.md | 9 + doc/development/architecture.md | 43 + doc/development/development.md | 163 + doc/development/images/architecture.dia | Bin 0 -> 2836 bytes doc/development/images/architecture.png | Bin 0 -> 32305 bytes .../notes/exc-sound-manager-notes.md | 55 + doc/development/notes/exc2-unlock-songs.md | 217 + doc/development/notes/extract-song-list.md | 141 + ...f2-crashing-on-modern-linux-post-mortem.md | 255 ++ doc/development/notes/hardware.md | 107 + .../notes/nx2-usb-profile-loading-saving.md | 141 + .../notes/pad-command-codes-notes.md | 448 +++ doc/development/notes/pro-notes.md | 9 + doc/game/01-1st.md | 134 + doc/game/02-2nd.md | 188 + doc/game/03-3rd.md | 182 + doc/game/04-3se.md | 211 + doc/game/05-tc.md | 211 + doc/game/06-pc.md | 199 + doc/game/07-extra.md | 183 + doc/game/08-prem1.md | 113 + doc/game/09-prex1.md | 112 + doc/game/10-reb.md | 92 + doc/game/11-prem2.md | 92 + doc/game/12-prex2.md | 98 + doc/game/13-prem3.md | 99 + doc/game/14-prex3.md | 100 + doc/game/15-exc.md | 145 + doc/game/16-exc2.md | 295 ++ doc/game/17-zero.md | 312 ++ doc/game/18-nx.md | 281 ++ doc/game/20-nx2.md | 295 ++ doc/game/game.md | 23 + doc/game/guide/nx2.pdf | Bin 0 -> 3900989 bytes doc/game/image/arrow/c.png | Bin 0 -> 7111 bytes doc/game/image/arrow/dl.png | Bin 0 -> 6896 bytes doc/game/image/arrow/dr.png | Bin 0 -> 6856 bytes doc/game/image/arrow/qm.png | Bin 0 -> 24497 bytes doc/game/image/arrow/ul.png | Bin 0 -> 6343 bytes doc/game/image/arrow/ur.png | Bin 0 -> 6313 bytes doc/game_old/(NXA)World_Max_Guide.pdf | Bin 0 -> 1230952 bytes doc/game_old/NX Absolute Guide v1.0.xls | Bin 0 -> 301056 bytes doc/game_old/piu new codes.pdf | Bin 0 -> 737680 bytes doc/game_old/piu old coes.pdf | Bin 0 -> 682352 bytes doc/hook/exchook.md | 54 + doc/hook/f2hook.md | 96 + doc/hook/fexhook.md | 88 + doc/hook/fsthook.md | 89 + doc/hook/hook.md | 201 + doc/hook/mk3hook.md | 283 ++ doc/hook/nx2hook.md | 154 + doc/hook/nxahook.md | 55 + doc/hook/nxhook.md | 52 + doc/hook/os.md | 59 + doc/hook/prihook.md | 108 + doc/hook/pro2hook.md | 91 + doc/hook/prohook.md | 107 + doc/hook/x2hook.md | 60 + doc/hook/zerohook.md | 50 + scripts/run-tests.sh | 13 + src/api/ptapi/io/piubtn.h | 105 + src/api/ptapi/io/piuio.h | 163 + src/api/ptapi/io/x11-input-hook.h | 39 + src/imports/cmocka/cmocka.c | 3522 +++++++++++++++++ src/imports/cmocka/cmocka.h | 2389 +++++++++++ src/imports/cmocka/cmocka_private.h | 163 + src/imports/cmocka/config.h | 6 + src/imports/fmodex/fmod.h | 2499 ++++++++++++ src/imports/fmodex/fmod.hpp | 609 +++ src/imports/fmodex/fmod_codec.h | 159 + src/imports/fmodex/fmod_dsp.h | 746 ++++ src/imports/fmodex/fmod_errors.h | 127 + src/imports/fmodex/fmod_memoryinfo.h | 201 + src/imports/fmodex/fmod_output.h | 93 + src/imports/fmodex/fmodlinux.h | 36 + src/main/asset/f2/lib/usb-rank.c | 49 + src/main/asset/f2/lib/usb-rank.h | 21 + src/main/asset/f2/lib/usb-save.c | 47 + src/main/asset/f2/lib/usb-save.h | 105 + src/main/asset/f2/lib/util.c | 96 + src/main/asset/f2/lib/util.h | 21 + src/main/asset/fex/lib/usb-rank.c | 32 + src/main/asset/fex/lib/usb-rank.h | 28 + src/main/asset/fex/lib/usb-save.c | 339 ++ src/main/asset/fex/lib/usb-save.h | 191 + src/main/asset/fex/lib/util.c | 100 + src/main/asset/fex/lib/util.h | 21 + src/main/asset/fex/tool/usb-profile.c | 154 + src/main/asset/game-version.h | 38 + src/main/asset/nx/lib/settings.c | 68 + src/main/asset/nx/lib/settings.h | 101 + src/main/asset/nx/lib/util.c | 35 + src/main/asset/nx/lib/util.h | 12 + src/main/asset/nx/tool/settings.c | 88 + src/main/asset/nx2/lib/usb-rank.c | 93 + src/main/asset/nx2/lib/usb-rank.h | 42 + src/main/asset/nx2/lib/usb-save.c | 370 ++ src/main/asset/nx2/lib/usb-save.h | 122 + src/main/asset/nx2/lib/util.c | 100 + src/main/asset/nx2/lib/util.h | 21 + src/main/asset/nx2/tool/usb-profile.c | 154 + src/main/asset/nxa/lib/usb-rank.c | 103 + src/main/asset/nxa/lib/usb-rank.h | 43 + src/main/asset/nxa/lib/usb-save.c | 457 +++ src/main/asset/nxa/lib/usb-save.h | 275 ++ src/main/asset/nxa/lib/util.c | 100 + src/main/asset/nxa/lib/util.h | 21 + src/main/asset/nxa/tool/usb-profile.c | 154 + src/main/asset/x2/lib/settings.c | 87 + src/main/asset/x2/lib/settings.h | 82 + src/main/asset/zero/lib/settings.c | 62 + src/main/asset/zero/lib/settings.h | 95 + src/main/capnhook/hook/common.h | 12 + src/main/capnhook/hook/filehook.c | 662 ++++ src/main/capnhook/hook/filehook.h | 90 + src/main/capnhook/hook/fshook.c | 447 +++ src/main/capnhook/hook/fshook.h | 72 + src/main/capnhook/hook/iobuf.c | 253 ++ src/main/capnhook/hook/iobuf.h | 162 + src/main/capnhook/hook/iohook.c | 552 +++ src/main/capnhook/hook/iohook.h | 90 + src/main/capnhook/hook/lib-main.h | 57 + src/main/capnhook/hook/lib.c | 179 + src/main/capnhook/hook/lib.h | 84 + src/main/capnhook/hook/result.c | 99 + src/main/capnhook/hook/result.h | 52 + src/main/capnhook/hook/sig.c | 58 + src/main/capnhook/hook/sig.h | 26 + src/main/capnhook/hook/usbhook.c | 624 +++ src/main/capnhook/hook/usbhook.h | 75 + src/main/capnhook/hooklib/filehook-mon.c | 57 + src/main/capnhook/hooklib/filehook-mon.h | 17 + src/main/capnhook/hooklib/fileopen-mon.c | 96 + src/main/capnhook/hooklib/fileopen-mon.h | 35 + src/main/capnhook/hooklib/fshook-mon.c | 43 + src/main/capnhook/hooklib/fshook-mon.h | 17 + src/main/capnhook/hooklib/iohook-mon.c | 54 + src/main/capnhook/hooklib/iohook-mon.h | 17 + src/main/capnhook/hooklib/redir.c | 371 ++ src/main/capnhook/hooklib/redir.h | 44 + src/main/capnhook/hooklib/usb-emu.c | 494 +++ src/main/capnhook/hooklib/usb-emu.h | 42 + src/main/capnhook/hooklib/usb-init-fix.c | 80 + src/main/capnhook/hooklib/usb-init-fix.h | 17 + src/main/capnhook/hooklib/usbhook-mon.c | 55 + src/main/capnhook/hooklib/usbhook-mon.h | 17 + src/main/crypt/aes.c | 29 + src/main/crypt/aes.h | 43 + src/main/crypt/lib/md5.c | 333 ++ src/main/crypt/lib/md5.h | 35 + src/main/crypt/lib/rijndael.c | 1208 ++++++ src/main/crypt/lib/rijndael.h | 17 + src/main/crypt/md5.c | 14 + src/main/crypt/md5.h | 16 + src/main/hook/core/options.c | 50 + src/main/hook/core/options.h | 15 + src/main/hook/core/piu-utils.c | 133 + src/main/hook/core/piu-utils.h | 53 + src/main/hook/exc/eeprom.c | 98 + src/main/hook/exc/eeprom.h | 19 + src/main/hook/exc/io.c | 505 +++ src/main/hook/exc/io.h | 26 + src/main/hook/exc/lockchip.c | 43 + src/main/hook/exc/lockchip.h | 19 + src/main/hook/exc/main.c | 256 ++ src/main/hook/exc/mempatch.c | 62 + src/main/hook/exc/mempatch.h | 29 + src/main/hook/exc/options.c | 184 + src/main/hook/exc/options.h | 55 + src/main/hook/f2/f2hook.hasp.key | 1 + src/main/hook/f2/f2hook.hdd.raw | 1 + src/main/hook/f2/main.c | 244 ++ src/main/hook/f2/options.c | 195 + src/main/hook/f2/options.h | 59 + src/main/hook/fex/fexhook.dog.key | 1 + src/main/hook/fex/fexhook.hdd.raw | 1 + src/main/hook/fex/main.c | 242 ++ src/main/hook/fex/options.c | 195 + src/main/hook/fex/options.h | 59 + src/main/hook/fst/fsthook.dog.key | 1 + src/main/hook/fst/fsthook.hdd.raw | 1 + src/main/hook/fst/main.c | 242 ++ src/main/hook/fst/options.c | 195 + src/main/hook/fst/options.h | 59 + src/main/hook/mk3/1st-2nd-fs-fix.c | 41 + src/main/hook/mk3/1st-2nd-fs-fix.h | 14 + src/main/hook/mk3/config.c | 136 + src/main/hook/mk3/config.h | 17 + src/main/hook/mk3/fmodex.c | 126 + src/main/hook/mk3/fmodex.h | 19 + src/main/hook/mk3/main.c | 251 ++ src/main/hook/mk3/ogl-fix.c | 37 + src/main/hook/mk3/options.c | 230 ++ src/main/hook/mk3/options.h | 60 + src/main/hook/nx/main.c | 272 ++ src/main/hook/nx/nxhook.dog.key | Bin 0 -> 66876 bytes src/main/hook/nx/nxhook.hdd.raw | Bin 0 -> 5120 bytes src/main/hook/nx/options.c | 183 + src/main/hook/nx/options.h | 55 + src/main/hook/nx/unlock.c | 81 + src/main/hook/nx/unlock.h | 12 + src/main/hook/nx2/main.c | 320 ++ src/main/hook/nx2/nx2hook.dog.key | Bin 0 -> 91424 bytes src/main/hook/nx2/nx2hook.hdd.raw | Bin 0 -> 5120 bytes src/main/hook/nx2/options.c | 215 + src/main/hook/nx2/options.h | 61 + src/main/hook/nx2/profile-gen.c | 70 + src/main/hook/nx2/profile-gen.h | 14 + src/main/hook/nxa/main.c | 310 ++ src/main/hook/nxa/nxahook.dog.key | 1 + src/main/hook/nxa/nxahook.hdd.raw | 1 + src/main/hook/nxa/options.c | 195 + src/main/hook/nxa/options.h | 59 + src/main/hook/nxa/profile-gen.c | 108 + src/main/hook/nxa/profile-gen.h | 14 + src/main/hook/patch/amixer-block.c | 53 + src/main/hook/patch/amixer-block.h | 13 + src/main/hook/patch/asound-fix.c | 147 + src/main/hook/patch/asound-fix.h | 25 + src/main/hook/patch/blacklist-url.c | 66 + src/main/hook/patch/blacklist-url.h | 19 + src/main/hook/patch/block-keyboard-grab.c | 36 + src/main/hook/patch/block-keyboard-grab.h | 10 + src/main/hook/patch/gfx.c | 125 + src/main/hook/patch/gfx.h | 17 + src/main/hook/patch/hasp.c | 63 + src/main/hook/patch/hasp.h | 15 + src/main/hook/patch/hasp2.c | 40 + src/main/hook/patch/hasp2.h | 22 + src/main/hook/patch/hdd-check.c | 257 ++ src/main/hook/patch/hdd-check.h | 16 + src/main/hook/patch/hook-mon.c | 36 + src/main/hook/patch/hook-mon.h | 20 + src/main/hook/patch/main-loop.c | 235 ++ src/main/hook/patch/main-loop.h | 59 + src/main/hook/patch/microdog34.c | 72 + src/main/hook/patch/microdog34.h | 15 + src/main/hook/patch/microdog40.c | 40 + src/main/hook/patch/microdog40.h | 20 + src/main/hook/patch/mounts.c | 105 + src/main/hook/patch/mounts.h | 13 + src/main/hook/patch/net-profile.c | 594 +++ src/main/hook/patch/net-profile.h | 31 + src/main/hook/patch/network.c | 96 + src/main/hook/patch/network.h | 23 + src/main/hook/patch/piubtn.c | 292 ++ src/main/hook/patch/piubtn.h | 32 + src/main/hook/patch/piuio-exit.c | 87 + src/main/hook/patch/piuio-exit.h | 12 + src/main/hook/patch/piuio.c | 572 +++ src/main/hook/patch/piuio.h | 22 + src/main/hook/patch/ram-wipe.c | 25 + src/main/hook/patch/ram-wipe.h | 13 + src/main/hook/patch/redir.c | 14 + src/main/hook/patch/redir.h | 12 + src/main/hook/patch/sigsegv.c | 53 + src/main/hook/patch/sigsegv.h | 16 + src/main/hook/patch/sound.c | 66 + src/main/hook/patch/sound.h | 15 + src/main/hook/patch/usb-emu.c | 12 + src/main/hook/patch/usb-emu.h | 12 + src/main/hook/patch/usb-init-fix.c | 12 + src/main/hook/patch/usb-init-fix.h | 12 + src/main/hook/patch/usb-mnt.c | 29 + src/main/hook/patch/usb-mnt.h | 13 + src/main/hook/patch/usb-unlock.c | 73 + src/main/hook/patch/usb-unlock.h | 13 + src/main/hook/patch/usbfs.c | 130 + src/main/hook/patch/usbfs.h | 14 + src/main/hook/patch/x11-event-loop.c | 269 ++ src/main/hook/patch/x11-event-loop.h | 18 + src/main/hook/pri/main.c | 294 ++ src/main/hook/pri/options.c | 183 + src/main/hook/pri/options.h | 58 + src/main/hook/pri/prihook.hasp.key | 1 + src/main/hook/pri/prihook.hdd.raw | 1 + src/main/hook/pri/usb-updates.c | 27 + src/main/hook/pri/usb-updates.h | 12 + src/main/hook/pro/main.c | 218 + src/main/hook/pro/options.c | 197 + src/main/hook/pro/options.h | 53 + src/main/hook/pro2/main.c | 230 ++ src/main/hook/pro2/options.c | 155 + src/main/hook/pro2/options.h | 46 + src/main/hook/propatch/usb-fix.c | 177 + src/main/hook/propatch/usb-fix.h | 5 + src/main/hook/x2/main.c | 250 ++ src/main/hook/x2/ogl-fix.c | 38 + src/main/hook/x2/options.c | 183 + src/main/hook/x2/options.h | 55 + src/main/hook/x2/unlock.c | 81 + src/main/hook/x2/unlock.h | 12 + src/main/hook/x2/x2hook.dog.key | Bin 0 -> 64444 bytes src/main/hook/zero/main.c | 255 ++ src/main/hook/zero/options.c | 183 + src/main/hook/zero/options.h | 55 + src/main/hook/zero/unlock.c | 81 + src/main/hook/zero/unlock.h | 12 + src/main/hook/zero/zerohook.dog.key | Bin 0 -> 92792 bytes src/main/hook/zero/zerohook.hdd.raw | Bin 0 -> 5120 bytes src/main/io/piubtn/defs.h | 17 + src/main/io/piubtn/device.c | 84 + src/main/io/piubtn/device.h | 41 + src/main/io/piuio/defs.h | 17 + src/main/io/piuio/device.c | 84 + src/main/io/piuio/device.h | 41 + src/main/io/util/joystick-util.c | 51 + src/main/io/util/joystick-util.h | 20 + src/main/io/util/joystick.c | 121 + src/main/io/util/joystick.h | 27 + src/main/io/util/usb.c | 171 + src/main/io/util/usb_.h | 46 + src/main/ptapi/io/piubtn/joystick-conf/main.c | 255 ++ .../io/piubtn/joystick-util/joystick-conf.c | 99 + .../io/piubtn/joystick-util/joystick-conf.h | 50 + src/main/ptapi/io/piubtn/joystick/joystick.c | 174 + src/main/ptapi/io/piubtn/keyboard-conf/main.c | 142 + .../io/piubtn/keyboard-util/keyboard-conf.c | 50 + .../io/piubtn/keyboard-util/keyboard-conf.h | 33 + src/main/ptapi/io/piubtn/keyboard/keyboard.c | 126 + src/main/ptapi/io/piubtn/null/null.c | 42 + src/main/ptapi/io/piubtn/real/piubtn.c | 135 + src/main/ptapi/io/piubtn/test/main.c | 103 + src/main/ptapi/io/piubtn/util/lib.c | 34 + src/main/ptapi/io/piubtn/util/lib.h | 8 + src/main/ptapi/io/piuio/joystick-conf/main.c | 254 ++ .../io/piuio/joystick-util/joystick-conf.c | 106 + .../io/piuio/joystick-util/joystick-conf.h | 57 + src/main/ptapi/io/piuio/joystick/joystick.c | 195 + src/main/ptapi/io/piuio/keyboard-conf/main.c | 147 + .../io/piuio/keyboard-util/keyboard-conf.c | 57 + .../io/piuio/keyboard-util/keyboard-conf.h | 40 + src/main/ptapi/io/piuio/keyboard/keyboard.c | 151 + src/main/ptapi/io/piuio/null/null.c | 55 + src/main/ptapi/io/piuio/real/piuio.c | 187 + src/main/ptapi/io/piuio/test/main.c | 181 + src/main/ptapi/io/piuio/util/lib.c | 38 + src/main/ptapi/io/piuio/util/lib.h | 8 + src/main/pumpnet/client/main.c | 115 + src/main/pumpnet/lib/http.c | 297 ++ src/main/pumpnet/lib/http.h | 22 + src/main/pumpnet/lib/profile-token.c | 44 + src/main/pumpnet/lib/profile-token.h | 15 + src/main/pumpnet/lib/protocol.h | 53 + src/main/pumpnet/lib/pumpnet.c | 343 ++ src/main/pumpnet/lib/pumpnet.h | 33 + src/main/sec/hasp/lib/asn1.c | 518 +++ src/main/sec/hasp/lib/asn1.h | 71 + src/main/sec/hasp/lib/const.h | 80 + src/main/sec/hasp/lib/handler.c | 118 + src/main/sec/hasp/lib/handler.h | 41 + src/main/sec/hasp/lib/object.c | 4 + src/main/sec/hasp/lib/object.h | 6 + src/main/sec/hasp/lib/object/client-id-req.c | 61 + src/main/sec/hasp/lib/object/client-id-req.h | 24 + src/main/sec/hasp/lib/object/client-id-resp.c | 48 + src/main/sec/hasp/lib/object/client-id-resp.h | 22 + src/main/sec/hasp/lib/object/login-req.c | 139 + src/main/sec/hasp/lib/object/login-req.h | 38 + src/main/sec/hasp/lib/server.c | 162 + src/main/sec/hasp/lib/server.h | 33 + src/main/sec/hasp/lib/util.c | 15 + src/main/sec/hasp/lib/util.h | 10 + src/main/sec/hasp/old/hasp.c | 87 + src/main/sec/hasp/old/hasp.h | 35 + src/main/sec/hasp/server/main.c | 7 + src/main/sec/lockchip/lockchip-defs.h | 64 + src/main/sec/lockchip/lockchip.c | 87 + src/main/sec/lockchip/lockchip.h | 31 + src/main/sec/microdog34/microdog34.c | 399 ++ src/main/sec/microdog34/microdog34.h | 51 + src/main/sec/microdog40/microdog40.c | 427 ++ src/main/sec/microdog40/microdog40.h | 111 + src/main/sec/microdog40/microdog40d.c | 109 + src/main/sec/microdog40/microdog40d.h | 35 + src/main/util/adler32.c | 17 + src/main/util/adler32.h | 17 + src/main/util/array.c | 55 + src/main/util/array.h | 60 + src/main/util/base64.c | 170 + src/main/util/base64.h | 8 + src/main/util/defs.h | 18 + src/main/util/fs.c | 222 ++ src/main/util/fs.h | 81 + src/main/util/glibc.c | 10 + src/main/util/glibc.h | 6 + src/main/util/hex.c | 73 + src/main/util/hex.h | 14 + src/main/util/iobuf.c | 22 + src/main/util/iobuf.h | 35 + src/main/util/list.c | 91 + src/main/util/list.h | 79 + src/main/util/log.c | 149 + src/main/util/log.h | 97 + src/main/util/mem.c | 108 + src/main/util/mem.h | 57 + src/main/util/net.c | 41 + src/main/util/net.h | 17 + src/main/util/options.c | 758 ++++ src/main/util/options.h | 170 + src/main/util/patch.c | 59 + src/main/util/patch.h | 52 + src/main/util/proc.c | 218 + src/main/util/proc.h | 47 + src/main/util/rand.c | 34 + src/main/util/rand.h | 10 + src/main/util/sock-tcp.c | 185 + src/main/util/sock-tcp.h | 30 + src/main/util/str.c | 212 + src/main/util/str.h | 107 + src/main/util/sys-info.c | 22 + src/main/util/sys-info.h | 9 + src/main/util/test.c | 159 + src/main/util/test.h | 81 + src/main/util/time.c | 69 + src/main/util/time.h | 26 + src/test/capnhook/hook/lib/main.c | 73 + src/test/hook/propatch/usb-fix/main.c | 145 + src/test/test-util/mem.c | 52 + src/test/test-util/mem.h | 6 + src/test/util/mem/main.c | 50 + src/test/util/str/main.c | 101 + utils/files-lowercase.sh | 15 + utils/grab_deps.sh | 35 + 555 files changed, 55502 insertions(+), 3 deletions(-) create mode 100644 .clang-format create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CMakeLists.txt create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Package.mk create mode 100644 cmake/CMakeLists.txt create mode 100644 cmake/modules/AddResources.cmake create mode 100644 cmake/src/CMakeLists.txt create mode 100644 cmake/src/imports/CMakeLists.txt create mode 100644 cmake/src/imports/cmocka/CMakeLists.txt create mode 100644 cmake/src/main/CMakeLists.txt create mode 100644 cmake/src/main/asset/CMakeLists.txt create mode 100644 cmake/src/main/asset/f2/CMakeLists.txt create mode 100644 cmake/src/main/asset/f2/lib/CMakeLists.txt create mode 100644 cmake/src/main/asset/fex/CMakeLists.txt create mode 100644 cmake/src/main/asset/fex/lib/CMakeLists.txt create mode 100644 cmake/src/main/asset/fex/tool/CMakeLists.txt create mode 100644 cmake/src/main/asset/fex/tool/usb-profile/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx/lib/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx/tool/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx/tool/settings/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx2/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx2/lib/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx2/tool/CMakeLists.txt create mode 100644 cmake/src/main/asset/nx2/tool/usb-profile/CMakeLists.txt create mode 100644 cmake/src/main/asset/nxa/CMakeLists.txt create mode 100644 cmake/src/main/asset/nxa/lib/CMakeLists.txt create mode 100644 cmake/src/main/asset/nxa/tool/CMakeLists.txt create mode 100644 cmake/src/main/asset/nxa/tool/usb-profile/CMakeLists.txt create mode 100644 cmake/src/main/asset/x2/CMakeLists.txt create mode 100644 cmake/src/main/asset/x2/lib/CMakeLists.txt create mode 100644 cmake/src/main/asset/zero/CMakeLists.txt create mode 100644 cmake/src/main/asset/zero/lib/CMakeLists.txt create mode 100644 cmake/src/main/capnhook/CMakeLists.txt create mode 100644 cmake/src/main/capnhook/hook/CMakeLists.txt create mode 100644 cmake/src/main/capnhook/hooklib/CMakeLists.txt create mode 100644 cmake/src/main/crypt/CMakeLists.txt create mode 100644 cmake/src/main/hook/CMakeLists.txt create mode 100644 cmake/src/main/hook/core/CMakeLists.txt create mode 100644 cmake/src/main/hook/exc/CMakeLists.txt create mode 100644 cmake/src/main/hook/f2/CMakeLists.txt create mode 100644 cmake/src/main/hook/fex/CMakeLists.txt create mode 100644 cmake/src/main/hook/fst/CMakeLists.txt create mode 100644 cmake/src/main/hook/mk3/CMakeLists.txt create mode 100644 cmake/src/main/hook/nx/CMakeLists.txt create mode 100644 cmake/src/main/hook/nx2/CMakeLists.txt create mode 100644 cmake/src/main/hook/nxa/CMakeLists.txt create mode 100644 cmake/src/main/hook/patch/CMakeLists.txt create mode 100644 cmake/src/main/hook/pri/CMakeLists.txt create mode 100644 cmake/src/main/hook/pro/CMakeLists.txt create mode 100644 cmake/src/main/hook/pro2/CMakeLists.txt create mode 100644 cmake/src/main/hook/propatch/CMakeLists.txt create mode 100644 cmake/src/main/hook/x2/CMakeLists.txt create mode 100644 cmake/src/main/hook/zero/CMakeLists.txt create mode 100644 cmake/src/main/io/CMakeLists.txt create mode 100644 cmake/src/main/io/piubtn/CMakeLists.txt create mode 100644 cmake/src/main/io/piuio/CMakeLists.txt create mode 100644 cmake/src/main/io/util/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/joystick-conf/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/joystick-util/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/joystick/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/keyboard-conf/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/keyboard-util/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/keyboard/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/null/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/real/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/test/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piubtn/util/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/joystick-conf/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/joystick-util/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/joystick/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/keyboard-conf/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/keyboard-util/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/keyboard/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/null/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/real/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/test/CMakeLists.txt create mode 100644 cmake/src/main/ptapi/piuio/util/CMakeLists.txt create mode 100644 cmake/src/main/pumpnet/CMakeLists.txt create mode 100644 cmake/src/main/pumpnet/client/CMakeLists.txt create mode 100644 cmake/src/main/pumpnet/lib/CMakeLists.txt create mode 100644 cmake/src/main/sec/CMakeLists.txt create mode 100644 cmake/src/main/sec/hasp/CMakeLists.txt create mode 100644 cmake/src/main/sec/hasp/lib/CMakeLists.txt create mode 100644 cmake/src/main/sec/hasp/old/CMakeLists.txt create mode 100644 cmake/src/main/sec/hasp/server/CMakeLists.txt create mode 100644 cmake/src/main/sec/lockchip/CMakeLists.txt create mode 100644 cmake/src/main/sec/microdog34/CMakeLists.txt create mode 100644 cmake/src/main/sec/microdog40/CMakeLists.txt create mode 100644 cmake/src/main/util/CMakeLists.txt create mode 100644 cmake/src/test/CMakeLists.txt create mode 100644 cmake/src/test/capnhook/CMakeLists.txt create mode 100644 cmake/src/test/capnhook/hook/CMakeLists.txt create mode 100644 cmake/src/test/capnhook/hook/lib/CMakeLists.txt create mode 100644 cmake/src/test/hook/CMakeLists.txt create mode 100644 cmake/src/test/hook/propatch/CMakeLists.txt create mode 100644 cmake/src/test/hook/propatch/usb-fix/CMakeLists.txt create mode 100644 cmake/src/test/test-util/CMakeLists.txt create mode 100644 cmake/src/test/util/CMakeLists.txt create mode 100644 cmake/src/test/util/mem/CMakeLists.txt create mode 100644 cmake/src/test/util/str/CMakeLists.txt create mode 100644 dist/api/ptapi-io-piubtn-stub.c create mode 100644 dist/api/ptapi-io-piuio-stub.c create mode 100644 dist/conf/exchook.conf create mode 100644 dist/conf/f2hook.conf create mode 100644 dist/conf/fexhook.conf create mode 100644 dist/conf/fsthook.conf create mode 100644 dist/conf/mk3hook.conf create mode 100644 dist/conf/nx2hook.conf create mode 100644 dist/conf/nxahook.conf create mode 100644 dist/conf/nxhook.conf create mode 100644 dist/conf/prihook.conf create mode 100644 dist/conf/pro2hook.conf create mode 100644 dist/conf/prohook.conf create mode 100644 dist/conf/x2hook.conf create mode 100644 dist/conf/zerohook.conf create mode 100755 dist/piueb create mode 100644 doc/README.md create mode 100644 doc/api/api.md create mode 100644 doc/api/io/piubtn.md create mode 100644 doc/api/io/piuio.md create mode 100644 doc/api/io/x11-input-hook.md create mode 100644 doc/development/architecture.md create mode 100644 doc/development/development.md create mode 100644 doc/development/images/architecture.dia create mode 100644 doc/development/images/architecture.png create mode 100644 doc/development/notes/exc-sound-manager-notes.md create mode 100644 doc/development/notes/exc2-unlock-songs.md create mode 100644 doc/development/notes/extract-song-list.md create mode 100644 doc/development/notes/f2-crashing-on-modern-linux-post-mortem.md create mode 100644 doc/development/notes/hardware.md create mode 100644 doc/development/notes/nx2-usb-profile-loading-saving.md create mode 100644 doc/development/notes/pad-command-codes-notes.md create mode 100644 doc/development/notes/pro-notes.md create mode 100644 doc/game/01-1st.md create mode 100644 doc/game/02-2nd.md create mode 100644 doc/game/03-3rd.md create mode 100644 doc/game/04-3se.md create mode 100644 doc/game/05-tc.md create mode 100644 doc/game/06-pc.md create mode 100644 doc/game/07-extra.md create mode 100644 doc/game/08-prem1.md create mode 100644 doc/game/09-prex1.md create mode 100644 doc/game/10-reb.md create mode 100644 doc/game/11-prem2.md create mode 100644 doc/game/12-prex2.md create mode 100644 doc/game/13-prem3.md create mode 100644 doc/game/14-prex3.md create mode 100644 doc/game/15-exc.md create mode 100644 doc/game/16-exc2.md create mode 100644 doc/game/17-zero.md create mode 100644 doc/game/18-nx.md create mode 100644 doc/game/20-nx2.md create mode 100644 doc/game/game.md create mode 100644 doc/game/guide/nx2.pdf create mode 100644 doc/game/image/arrow/c.png create mode 100644 doc/game/image/arrow/dl.png create mode 100644 doc/game/image/arrow/dr.png create mode 100644 doc/game/image/arrow/qm.png create mode 100644 doc/game/image/arrow/ul.png create mode 100644 doc/game/image/arrow/ur.png create mode 100644 doc/game_old/(NXA)World_Max_Guide.pdf create mode 100644 doc/game_old/NX Absolute Guide v1.0.xls create mode 100644 doc/game_old/piu new codes.pdf create mode 100644 doc/game_old/piu old coes.pdf create mode 100644 doc/hook/exchook.md create mode 100644 doc/hook/f2hook.md create mode 100644 doc/hook/fexhook.md create mode 100644 doc/hook/fsthook.md create mode 100644 doc/hook/hook.md create mode 100644 doc/hook/mk3hook.md create mode 100644 doc/hook/nx2hook.md create mode 100644 doc/hook/nxahook.md create mode 100644 doc/hook/nxhook.md create mode 100644 doc/hook/os.md create mode 100644 doc/hook/prihook.md create mode 100644 doc/hook/pro2hook.md create mode 100644 doc/hook/prohook.md create mode 100644 doc/hook/x2hook.md create mode 100644 doc/hook/zerohook.md create mode 100755 scripts/run-tests.sh create mode 100644 src/api/ptapi/io/piubtn.h create mode 100644 src/api/ptapi/io/piuio.h create mode 100644 src/api/ptapi/io/x11-input-hook.h create mode 100644 src/imports/cmocka/cmocka.c create mode 100644 src/imports/cmocka/cmocka.h create mode 100644 src/imports/cmocka/cmocka_private.h create mode 100644 src/imports/cmocka/config.h create mode 100644 src/imports/fmodex/fmod.h create mode 100644 src/imports/fmodex/fmod.hpp create mode 100644 src/imports/fmodex/fmod_codec.h create mode 100644 src/imports/fmodex/fmod_dsp.h create mode 100644 src/imports/fmodex/fmod_errors.h create mode 100644 src/imports/fmodex/fmod_memoryinfo.h create mode 100644 src/imports/fmodex/fmod_output.h create mode 100644 src/imports/fmodex/fmodlinux.h create mode 100644 src/main/asset/f2/lib/usb-rank.c create mode 100644 src/main/asset/f2/lib/usb-rank.h create mode 100644 src/main/asset/f2/lib/usb-save.c create mode 100644 src/main/asset/f2/lib/usb-save.h create mode 100644 src/main/asset/f2/lib/util.c create mode 100644 src/main/asset/f2/lib/util.h create mode 100644 src/main/asset/fex/lib/usb-rank.c create mode 100644 src/main/asset/fex/lib/usb-rank.h create mode 100644 src/main/asset/fex/lib/usb-save.c create mode 100644 src/main/asset/fex/lib/usb-save.h create mode 100644 src/main/asset/fex/lib/util.c create mode 100644 src/main/asset/fex/lib/util.h create mode 100644 src/main/asset/fex/tool/usb-profile.c create mode 100644 src/main/asset/game-version.h create mode 100644 src/main/asset/nx/lib/settings.c create mode 100644 src/main/asset/nx/lib/settings.h create mode 100644 src/main/asset/nx/lib/util.c create mode 100644 src/main/asset/nx/lib/util.h create mode 100644 src/main/asset/nx/tool/settings.c create mode 100644 src/main/asset/nx2/lib/usb-rank.c create mode 100644 src/main/asset/nx2/lib/usb-rank.h create mode 100644 src/main/asset/nx2/lib/usb-save.c create mode 100644 src/main/asset/nx2/lib/usb-save.h create mode 100644 src/main/asset/nx2/lib/util.c create mode 100644 src/main/asset/nx2/lib/util.h create mode 100644 src/main/asset/nx2/tool/usb-profile.c create mode 100644 src/main/asset/nxa/lib/usb-rank.c create mode 100644 src/main/asset/nxa/lib/usb-rank.h create mode 100644 src/main/asset/nxa/lib/usb-save.c create mode 100644 src/main/asset/nxa/lib/usb-save.h create mode 100644 src/main/asset/nxa/lib/util.c create mode 100644 src/main/asset/nxa/lib/util.h create mode 100644 src/main/asset/nxa/tool/usb-profile.c create mode 100644 src/main/asset/x2/lib/settings.c create mode 100644 src/main/asset/x2/lib/settings.h create mode 100644 src/main/asset/zero/lib/settings.c create mode 100644 src/main/asset/zero/lib/settings.h create mode 100644 src/main/capnhook/hook/common.h create mode 100644 src/main/capnhook/hook/filehook.c create mode 100644 src/main/capnhook/hook/filehook.h create mode 100644 src/main/capnhook/hook/fshook.c create mode 100644 src/main/capnhook/hook/fshook.h create mode 100644 src/main/capnhook/hook/iobuf.c create mode 100644 src/main/capnhook/hook/iobuf.h create mode 100644 src/main/capnhook/hook/iohook.c create mode 100644 src/main/capnhook/hook/iohook.h create mode 100644 src/main/capnhook/hook/lib-main.h create mode 100644 src/main/capnhook/hook/lib.c create mode 100644 src/main/capnhook/hook/lib.h create mode 100644 src/main/capnhook/hook/result.c create mode 100644 src/main/capnhook/hook/result.h create mode 100644 src/main/capnhook/hook/sig.c create mode 100644 src/main/capnhook/hook/sig.h create mode 100644 src/main/capnhook/hook/usbhook.c create mode 100644 src/main/capnhook/hook/usbhook.h create mode 100644 src/main/capnhook/hooklib/filehook-mon.c create mode 100644 src/main/capnhook/hooklib/filehook-mon.h create mode 100644 src/main/capnhook/hooklib/fileopen-mon.c create mode 100644 src/main/capnhook/hooklib/fileopen-mon.h create mode 100644 src/main/capnhook/hooklib/fshook-mon.c create mode 100644 src/main/capnhook/hooklib/fshook-mon.h create mode 100644 src/main/capnhook/hooklib/iohook-mon.c create mode 100644 src/main/capnhook/hooklib/iohook-mon.h create mode 100644 src/main/capnhook/hooklib/redir.c create mode 100644 src/main/capnhook/hooklib/redir.h create mode 100644 src/main/capnhook/hooklib/usb-emu.c create mode 100644 src/main/capnhook/hooklib/usb-emu.h create mode 100644 src/main/capnhook/hooklib/usb-init-fix.c create mode 100644 src/main/capnhook/hooklib/usb-init-fix.h create mode 100644 src/main/capnhook/hooklib/usbhook-mon.c create mode 100644 src/main/capnhook/hooklib/usbhook-mon.h create mode 100644 src/main/crypt/aes.c create mode 100644 src/main/crypt/aes.h create mode 100644 src/main/crypt/lib/md5.c create mode 100644 src/main/crypt/lib/md5.h create mode 100644 src/main/crypt/lib/rijndael.c create mode 100644 src/main/crypt/lib/rijndael.h create mode 100644 src/main/crypt/md5.c create mode 100644 src/main/crypt/md5.h create mode 100644 src/main/hook/core/options.c create mode 100644 src/main/hook/core/options.h create mode 100644 src/main/hook/core/piu-utils.c create mode 100644 src/main/hook/core/piu-utils.h create mode 100644 src/main/hook/exc/eeprom.c create mode 100644 src/main/hook/exc/eeprom.h create mode 100644 src/main/hook/exc/io.c create mode 100644 src/main/hook/exc/io.h create mode 100644 src/main/hook/exc/lockchip.c create mode 100644 src/main/hook/exc/lockchip.h create mode 100644 src/main/hook/exc/main.c create mode 100644 src/main/hook/exc/mempatch.c create mode 100644 src/main/hook/exc/mempatch.h create mode 100644 src/main/hook/exc/options.c create mode 100644 src/main/hook/exc/options.h create mode 100644 src/main/hook/f2/f2hook.hasp.key create mode 100644 src/main/hook/f2/f2hook.hdd.raw create mode 100644 src/main/hook/f2/main.c create mode 100644 src/main/hook/f2/options.c create mode 100644 src/main/hook/f2/options.h create mode 100644 src/main/hook/fex/fexhook.dog.key create mode 100644 src/main/hook/fex/fexhook.hdd.raw create mode 100644 src/main/hook/fex/main.c create mode 100644 src/main/hook/fex/options.c create mode 100644 src/main/hook/fex/options.h create mode 100644 src/main/hook/fst/fsthook.dog.key create mode 100644 src/main/hook/fst/fsthook.hdd.raw create mode 100644 src/main/hook/fst/main.c create mode 100644 src/main/hook/fst/options.c create mode 100644 src/main/hook/fst/options.h create mode 100644 src/main/hook/mk3/1st-2nd-fs-fix.c create mode 100644 src/main/hook/mk3/1st-2nd-fs-fix.h create mode 100644 src/main/hook/mk3/config.c create mode 100644 src/main/hook/mk3/config.h create mode 100644 src/main/hook/mk3/fmodex.c create mode 100644 src/main/hook/mk3/fmodex.h create mode 100644 src/main/hook/mk3/main.c create mode 100644 src/main/hook/mk3/ogl-fix.c create mode 100644 src/main/hook/mk3/options.c create mode 100644 src/main/hook/mk3/options.h create mode 100644 src/main/hook/nx/main.c create mode 100644 src/main/hook/nx/nxhook.dog.key create mode 100755 src/main/hook/nx/nxhook.hdd.raw create mode 100644 src/main/hook/nx/options.c create mode 100644 src/main/hook/nx/options.h create mode 100644 src/main/hook/nx/unlock.c create mode 100644 src/main/hook/nx/unlock.h create mode 100644 src/main/hook/nx2/main.c create mode 100755 src/main/hook/nx2/nx2hook.dog.key create mode 100755 src/main/hook/nx2/nx2hook.hdd.raw create mode 100644 src/main/hook/nx2/options.c create mode 100644 src/main/hook/nx2/options.h create mode 100644 src/main/hook/nx2/profile-gen.c create mode 100644 src/main/hook/nx2/profile-gen.h create mode 100644 src/main/hook/nxa/main.c create mode 100644 src/main/hook/nxa/nxahook.dog.key create mode 100644 src/main/hook/nxa/nxahook.hdd.raw create mode 100644 src/main/hook/nxa/options.c create mode 100644 src/main/hook/nxa/options.h create mode 100644 src/main/hook/nxa/profile-gen.c create mode 100644 src/main/hook/nxa/profile-gen.h create mode 100644 src/main/hook/patch/amixer-block.c create mode 100644 src/main/hook/patch/amixer-block.h create mode 100644 src/main/hook/patch/asound-fix.c create mode 100644 src/main/hook/patch/asound-fix.h create mode 100644 src/main/hook/patch/blacklist-url.c create mode 100644 src/main/hook/patch/blacklist-url.h create mode 100644 src/main/hook/patch/block-keyboard-grab.c create mode 100644 src/main/hook/patch/block-keyboard-grab.h create mode 100644 src/main/hook/patch/gfx.c create mode 100644 src/main/hook/patch/gfx.h create mode 100644 src/main/hook/patch/hasp.c create mode 100644 src/main/hook/patch/hasp.h create mode 100644 src/main/hook/patch/hasp2.c create mode 100644 src/main/hook/patch/hasp2.h create mode 100644 src/main/hook/patch/hdd-check.c create mode 100644 src/main/hook/patch/hdd-check.h create mode 100644 src/main/hook/patch/hook-mon.c create mode 100644 src/main/hook/patch/hook-mon.h create mode 100644 src/main/hook/patch/main-loop.c create mode 100644 src/main/hook/patch/main-loop.h create mode 100644 src/main/hook/patch/microdog34.c create mode 100644 src/main/hook/patch/microdog34.h create mode 100644 src/main/hook/patch/microdog40.c create mode 100644 src/main/hook/patch/microdog40.h create mode 100644 src/main/hook/patch/mounts.c create mode 100644 src/main/hook/patch/mounts.h create mode 100644 src/main/hook/patch/net-profile.c create mode 100644 src/main/hook/patch/net-profile.h create mode 100644 src/main/hook/patch/network.c create mode 100644 src/main/hook/patch/network.h create mode 100644 src/main/hook/patch/piubtn.c create mode 100644 src/main/hook/patch/piubtn.h create mode 100644 src/main/hook/patch/piuio-exit.c create mode 100644 src/main/hook/patch/piuio-exit.h create mode 100644 src/main/hook/patch/piuio.c create mode 100644 src/main/hook/patch/piuio.h create mode 100644 src/main/hook/patch/ram-wipe.c create mode 100644 src/main/hook/patch/ram-wipe.h create mode 100644 src/main/hook/patch/redir.c create mode 100644 src/main/hook/patch/redir.h create mode 100644 src/main/hook/patch/sigsegv.c create mode 100644 src/main/hook/patch/sigsegv.h create mode 100644 src/main/hook/patch/sound.c create mode 100644 src/main/hook/patch/sound.h create mode 100644 src/main/hook/patch/usb-emu.c create mode 100644 src/main/hook/patch/usb-emu.h create mode 100644 src/main/hook/patch/usb-init-fix.c create mode 100644 src/main/hook/patch/usb-init-fix.h create mode 100644 src/main/hook/patch/usb-mnt.c create mode 100644 src/main/hook/patch/usb-mnt.h create mode 100644 src/main/hook/patch/usb-unlock.c create mode 100644 src/main/hook/patch/usb-unlock.h create mode 100644 src/main/hook/patch/usbfs.c create mode 100644 src/main/hook/patch/usbfs.h create mode 100644 src/main/hook/patch/x11-event-loop.c create mode 100644 src/main/hook/patch/x11-event-loop.h create mode 100644 src/main/hook/pri/main.c create mode 100644 src/main/hook/pri/options.c create mode 100644 src/main/hook/pri/options.h create mode 100644 src/main/hook/pri/prihook.hasp.key create mode 100644 src/main/hook/pri/prihook.hdd.raw create mode 100644 src/main/hook/pri/usb-updates.c create mode 100644 src/main/hook/pri/usb-updates.h create mode 100644 src/main/hook/pro/main.c create mode 100644 src/main/hook/pro/options.c create mode 100644 src/main/hook/pro/options.h create mode 100644 src/main/hook/pro2/main.c create mode 100644 src/main/hook/pro2/options.c create mode 100644 src/main/hook/pro2/options.h create mode 100644 src/main/hook/propatch/usb-fix.c create mode 100644 src/main/hook/propatch/usb-fix.h create mode 100644 src/main/hook/x2/main.c create mode 100644 src/main/hook/x2/ogl-fix.c create mode 100644 src/main/hook/x2/options.c create mode 100644 src/main/hook/x2/options.h create mode 100644 src/main/hook/x2/unlock.c create mode 100644 src/main/hook/x2/unlock.h create mode 100755 src/main/hook/x2/x2hook.dog.key create mode 100644 src/main/hook/zero/main.c create mode 100644 src/main/hook/zero/options.c create mode 100644 src/main/hook/zero/options.h create mode 100644 src/main/hook/zero/unlock.c create mode 100644 src/main/hook/zero/unlock.h create mode 100755 src/main/hook/zero/zerohook.dog.key create mode 100755 src/main/hook/zero/zerohook.hdd.raw create mode 100644 src/main/io/piubtn/defs.h create mode 100644 src/main/io/piubtn/device.c create mode 100644 src/main/io/piubtn/device.h create mode 100644 src/main/io/piuio/defs.h create mode 100644 src/main/io/piuio/device.c create mode 100644 src/main/io/piuio/device.h create mode 100644 src/main/io/util/joystick-util.c create mode 100644 src/main/io/util/joystick-util.h create mode 100644 src/main/io/util/joystick.c create mode 100644 src/main/io/util/joystick.h create mode 100644 src/main/io/util/usb.c create mode 100644 src/main/io/util/usb_.h create mode 100644 src/main/ptapi/io/piubtn/joystick-conf/main.c create mode 100644 src/main/ptapi/io/piubtn/joystick-util/joystick-conf.c create mode 100644 src/main/ptapi/io/piubtn/joystick-util/joystick-conf.h create mode 100644 src/main/ptapi/io/piubtn/joystick/joystick.c create mode 100644 src/main/ptapi/io/piubtn/keyboard-conf/main.c create mode 100644 src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.c create mode 100644 src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.h create mode 100644 src/main/ptapi/io/piubtn/keyboard/keyboard.c create mode 100644 src/main/ptapi/io/piubtn/null/null.c create mode 100644 src/main/ptapi/io/piubtn/real/piubtn.c create mode 100644 src/main/ptapi/io/piubtn/test/main.c create mode 100644 src/main/ptapi/io/piubtn/util/lib.c create mode 100644 src/main/ptapi/io/piubtn/util/lib.h create mode 100644 src/main/ptapi/io/piuio/joystick-conf/main.c create mode 100644 src/main/ptapi/io/piuio/joystick-util/joystick-conf.c create mode 100644 src/main/ptapi/io/piuio/joystick-util/joystick-conf.h create mode 100644 src/main/ptapi/io/piuio/joystick/joystick.c create mode 100644 src/main/ptapi/io/piuio/keyboard-conf/main.c create mode 100644 src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.c create mode 100644 src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.h create mode 100644 src/main/ptapi/io/piuio/keyboard/keyboard.c create mode 100644 src/main/ptapi/io/piuio/null/null.c create mode 100644 src/main/ptapi/io/piuio/real/piuio.c create mode 100644 src/main/ptapi/io/piuio/test/main.c create mode 100644 src/main/ptapi/io/piuio/util/lib.c create mode 100644 src/main/ptapi/io/piuio/util/lib.h create mode 100644 src/main/pumpnet/client/main.c create mode 100644 src/main/pumpnet/lib/http.c create mode 100644 src/main/pumpnet/lib/http.h create mode 100644 src/main/pumpnet/lib/profile-token.c create mode 100644 src/main/pumpnet/lib/profile-token.h create mode 100644 src/main/pumpnet/lib/protocol.h create mode 100644 src/main/pumpnet/lib/pumpnet.c create mode 100644 src/main/pumpnet/lib/pumpnet.h create mode 100644 src/main/sec/hasp/lib/asn1.c create mode 100644 src/main/sec/hasp/lib/asn1.h create mode 100644 src/main/sec/hasp/lib/const.h create mode 100644 src/main/sec/hasp/lib/handler.c create mode 100644 src/main/sec/hasp/lib/handler.h create mode 100644 src/main/sec/hasp/lib/object.c create mode 100644 src/main/sec/hasp/lib/object.h create mode 100644 src/main/sec/hasp/lib/object/client-id-req.c create mode 100644 src/main/sec/hasp/lib/object/client-id-req.h create mode 100644 src/main/sec/hasp/lib/object/client-id-resp.c create mode 100644 src/main/sec/hasp/lib/object/client-id-resp.h create mode 100644 src/main/sec/hasp/lib/object/login-req.c create mode 100644 src/main/sec/hasp/lib/object/login-req.h create mode 100644 src/main/sec/hasp/lib/server.c create mode 100644 src/main/sec/hasp/lib/server.h create mode 100644 src/main/sec/hasp/lib/util.c create mode 100644 src/main/sec/hasp/lib/util.h create mode 100644 src/main/sec/hasp/old/hasp.c create mode 100644 src/main/sec/hasp/old/hasp.h create mode 100644 src/main/sec/hasp/server/main.c create mode 100644 src/main/sec/lockchip/lockchip-defs.h create mode 100644 src/main/sec/lockchip/lockchip.c create mode 100644 src/main/sec/lockchip/lockchip.h create mode 100644 src/main/sec/microdog34/microdog34.c create mode 100644 src/main/sec/microdog34/microdog34.h create mode 100644 src/main/sec/microdog40/microdog40.c create mode 100644 src/main/sec/microdog40/microdog40.h create mode 100644 src/main/sec/microdog40/microdog40d.c create mode 100644 src/main/sec/microdog40/microdog40d.h create mode 100644 src/main/util/adler32.c create mode 100644 src/main/util/adler32.h create mode 100644 src/main/util/array.c create mode 100644 src/main/util/array.h create mode 100644 src/main/util/base64.c create mode 100644 src/main/util/base64.h create mode 100644 src/main/util/defs.h create mode 100644 src/main/util/fs.c create mode 100644 src/main/util/fs.h create mode 100644 src/main/util/glibc.c create mode 100644 src/main/util/glibc.h create mode 100644 src/main/util/hex.c create mode 100644 src/main/util/hex.h create mode 100644 src/main/util/iobuf.c create mode 100644 src/main/util/iobuf.h create mode 100644 src/main/util/list.c create mode 100644 src/main/util/list.h create mode 100644 src/main/util/log.c create mode 100644 src/main/util/log.h create mode 100644 src/main/util/mem.c create mode 100644 src/main/util/mem.h create mode 100644 src/main/util/net.c create mode 100644 src/main/util/net.h create mode 100644 src/main/util/options.c create mode 100644 src/main/util/options.h create mode 100644 src/main/util/patch.c create mode 100644 src/main/util/patch.h create mode 100644 src/main/util/proc.c create mode 100644 src/main/util/proc.h create mode 100644 src/main/util/rand.c create mode 100644 src/main/util/rand.h create mode 100644 src/main/util/sock-tcp.c create mode 100644 src/main/util/sock-tcp.h create mode 100644 src/main/util/str.c create mode 100644 src/main/util/str.h create mode 100644 src/main/util/sys-info.c create mode 100644 src/main/util/sys-info.h create mode 100644 src/main/util/test.c create mode 100644 src/main/util/test.h create mode 100644 src/main/util/time.c create mode 100644 src/main/util/time.h create mode 100644 src/test/capnhook/hook/lib/main.c create mode 100644 src/test/hook/propatch/usb-fix/main.c create mode 100644 src/test/test-util/mem.c create mode 100644 src/test/test-util/mem.h create mode 100644 src/test/util/mem/main.c create mode 100644 src/test/util/str/main.c create mode 100755 utils/files-lowercase.sh create mode 100755 utils/grab_deps.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..094640d --- /dev/null +++ b/.clang-format @@ -0,0 +1,45 @@ +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: 'false' +AlignConsecutiveDeclarations: 'false' +AlignEscapedNewlines: Left +AlignOperands: 'false' +AlignTrailingComments: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'true' +BinPackArguments: 'false' +BinPackParameters: 'false' +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Linux +BreakBeforeTernaryOperators: 'false' +BreakStringLiterals: 'true' +ColumnLimit: '80' +ContinuationIndentWidth: '4' +IncludeBlocks: Preserve +IndentCaseLabels: 'true' +IndentPPDirectives: None +IndentWidth: '2' +IndentWrappedFunctionNames: 'false' +KeepEmptyLinesAtTheStartOfBlocks: 'true' +Language: Cpp +MaxEmptyLinesToKeep: '1' +PointerAlignment: Right +ReflowComments: 'true' +SortIncludes: 'true' +SpaceAfterCStyleCast: 'true' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +TabWidth: '2' +UseTab: Never diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ca3661d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.idea +build +.vscode +*.iml +*.ipr +*.iws +.DS_Store +tmp +utils +cmake-build-debug \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..649adff --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode +build/ +cmake-build-debug/ +.idea/ +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..56634c9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,56 @@ +# Release history +## 1.08 +* Documentation updates +* Public release, working hooks: mk3, exc, x2, zero, nx, nx2, pro, pro2 + +## 1.07 +* Bugfix nx2hook usb thumb drives not being detected on all kernel versions correctly +* Include piubtn library and api (piu pro button board) in distribution for SGL +* Various documentation improvements +* Various minor bugfixes and improvements + +## 1.06 +* nx2hook: Add hook library for NX2 +* pumpnet: Support usbprofiles over network for NX2 +* Various bugfixes + +## 1.05 +* Minor improvements +* Improve log/debug output +* piueb: Add `valgrind` run mode for debugging +* Improve documentation +* ptapi/piuio: Bugfix resolving path to configuration file. Config file local to piuio library. +* usbhooking: Bugfix to make PIUIO work without using ptapi-io-piuio-real.so on newer games, Exceed 2, Zero, NX + +## 1.04 +* nxhook: Add hook library for NX +* Minor bugfixes + +## 1.03 +* zerohook: Add hook library for Zero +* Bugfix linking error ptapi piuio real impl +* Bugfix piueb environment variable order with LD_LOAD_LIBRARY +* Readme/documentation cleanup, merged duplicate documentation for hooks +* Various other bugfixes + +## 1.02 +* x2hook: Add hook library for Exceed 2 +* Various bugfixes +* Documentation and code cleanup + +## 1.01 +* exchook: Add hook library for Exceed +* mk3hook: Add support for piuio emulation -> configurable keyboard and joystick supported +* Add game documentation: Trivia, unlocks and pad codes about all games released so far (check game-doc.zip) +* Update API documentation +* Add stub example for implementing your own piuio module +* Add configurable joystick/gamepad support for piuio emulation (see readme files for instructions) +* Add configurable keyboard support for piuio emulation (see readme files for instructions) +* Refactor pumptools API (ptapi) piuio and piubtn modules +* Build releases using docker container with ubuntu 16.04 to enhance compatibility with older libc versions +* piueb: Add commands "debug" and "strace" to start game with a gdb server or strace attached for quick debugging +* Various bugfixes + +## 1.00 +* Release of mk3hook for Linux ports +* Initial public release of binary distribution of pumptools \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cca0961 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8) + +add_subdirectory(cmake) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dd306c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing +Please have a look at the issue board about what's currently going on. If you see an issue that is not assigned yet and +that you can and want to work on, please leave a comment to reach out to one of our developers. You can also ask +questions and discuss the issue. + +# Bug reports +Please check if the bug was already reported by searching the existing issues. If it does, feel free to leave a comment +that you also have this issue. Add additional information, screenshots, log files etc. The more information and details +we have, the easier it might get to solve the issue. + +When creating new issues, use our template for reporting bugs. It tells you what kind of information we need. + +# Pull requests: bugfixes, new features or other code contributions +Pull requests are welcome! May it be a PR to an already known issue or a new feature that you consider as a valuable +contribution, please open a PR. If you want to start working on a new feature that was proposed in an issue, yet, it +is recommended to reach out to the developers about this, first, to discuss if this contribution is valuable to the +project. Otherwise, you might waste your time on implementing something that won't make it into master. + +Please read our [development guidelines](doc/development/development.md) as they contain valuable information that your +contribution meets our standards. + +Fork the upstream repository and start developing on your personal fork. Make sure to test your changes with games that +are affected by them. Pay attention to the target platform/hardware you are testing on! This is valuable information +that should be included in the PR. + +Once you completed your implementation, open a pull request on the upstream repository to propose your changes. We will +review your contribution and get back to you about any changes or when we merge them to our upstream repository. Your +changes, once approved, will be included in the next release. + +# Roadmap +No concrete roadmap or timeline exists. When the time is right, we continue adding support for newer games as well. \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0b80944 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +# Use a rather old version of ubuntu to ensure compatibility regarding libc +FROM ubuntu:16.04 + +LABEL description="Build environment for pumptools" + +# Install build dependencies, multilib to get 32-bit versions +RUN dpkg --add-architecture i386 +RUN apt-get update && apt-get install -y \ + g++-multilib \ + gcc-multilib \ + zip \ + cmake \ + make \ + git \ + libc6-dev-i386 \ + libusb-1.0-0-dev:i386 \ + libusb-dev:i386 \ + libasound2-dev:i386 \ + libconfig++-dev:i386 \ + libx11-dev:i386 \ + libcurl4-gnutls-dev:i386 + +# Copy files for building to container +RUN mkdir /pumptools +WORKDIR /pumptools + +COPY CHANGELOG.md CHANGELOG.md +COPY CMakeLists.txt CMakeLists.txt +COPY CONTRIBUTING.md CONTRIBUTING.md +COPY LICENSE LICENSE +COPY Makefile Makefile +COPY Package.mk Package.mk +COPY README.md README.md +COPY dist dist +COPY doc doc +COPY cmake cmake +COPY src src +# .git folder required or building fails when version is generated +COPY .git .git + +# Building +RUN make build package \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..623df41 --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +V ?= @ +BUILDDIR ?= build + +gitrev := $(shell git rev-parse HEAD) +libcver := $(shell ldd --version | head -n 1) + +all: \ +usage + +.PHONY: \ +build \ +clean \ +test \ +build-docker \ +git-version \ +libc-version \ +clang-format \ +package + +usage: + $(V)echo "Pumptools project build makefile" + $(V)echo " build: Build the pumptools project" + $(V)echo " clean: Clean up all build output" + $(V)echo " test: Run pumptools's unit tests" + $(V)echo " build-docker: Build the pumptools project in a docker container" + $(V)echo " git-version: Generate a text file with the current git revision" + $(V)echo " libc-version: Generate a text file with the libc version available" + $(V)echo " clang-format: Apply code style defined in .clang-format style to all code in src/" + $(V)echo " package: Package the build output into distribution zip files" + +# Standard build target to build pumptools +build: git-version libc-version + $(V)mkdir -p $(BUILDDIR) + $(V)cd $(BUILDDIR) && cmake .. && make -j $(grep -c ^processor /proc/cpuinfo) + +clean: + $(V)rm -rf $(BUILDDIR) + +test: build + $(V)scripts/run-tests.sh $(BUILDDIR) + +# Build pumptools in a docker image and extract the build output +build-docker: + $(V)rm -rf $(BUILDDIR)/docker + $(V)mkdir -p $(BUILDDIR)/docker + $(V)docker build -t pumptools:build . + $(V)docker create --name pumptools-build pumptools:build + $(V)docker cp pumptools-build:/pumptools/build $(BUILDDIR)/docker + $(V)mv $(BUILDDIR)/docker/build/* $(BUILDDIR)/docker + $(V)rm -r $(BUILDDIR)/docker/build + $(V)docker rm -f pumptools-build + $(V)echo "Build output of docker build can be found in build/docker subfolder." + +# Generate a version file to identify the build +git-version: + $(V)mkdir -p $(BUILDDIR) + $(V)echo "$(gitrev)" > $(BUILDDIR)/git-version + +# Generate a version file to identify the libc runtime used to build +libc-version: + $(V)mkdir -p $(BUILDDIR) + $(V)echo "$(libcver)" > $(BUILDDIR)/libc-version + +clang-format: + $(V)find src/ -iname *.h -o -iname *.c | xargs clang-format -i -style=file + +include Package.mk \ No newline at end of file diff --git a/Package.mk b/Package.mk new file mode 100644 index 0000000..9ac4cfe --- /dev/null +++ b/Package.mk @@ -0,0 +1,269 @@ +# +# Distribution build rules +# + +builddir := $(BUILDDIR) +zipdir := $(BUILDDIR)/zip + +$(zipdir)/: + $(V)mkdir -p $@ + +################################################ +# Hooks: Lexical sorting + +$(zipdir)/exchook.zip: \ + $(builddir)/bin/exchook.so \ + dist/conf/exchook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/f2hook.zip: \ + $(builddir)/bin/f2hook.so \ + dist/conf/f2hook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/fexhook.zip: \ + $(builddir)/bin/fexhook.so \ + dist/conf/fexhook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/fsthook.zip: \ + $(builddir)/bin/fsthook.so \ + dist/conf/fsthook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/mk3hook.zip: \ + $(builddir)/bin/mk3hook.so \ + dist/piueb \ + dist/conf/mk3hook.conf \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/nx2hook.zip: \ + $(builddir)/bin/nx2hook.so \ + dist/conf/nx2hook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/nxahook.zip: \ + $(builddir)/bin/nxahook.so \ + dist/conf/nxahook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/nxhook.zip: \ + $(builddir)/bin/nxhook.so \ + dist/conf/nxhook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/prihook.zip: \ + $(builddir)/bin/prihook.so \ + dist/conf/prihook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/prohook.zip: \ + $(builddir)/bin/prohook.so \ + dist/conf/prohook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/pro2hook.zip: \ + $(builddir)/bin/pro2hook.so \ + dist/conf/pro2hook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/x2hook.zip: \ + $(builddir)/bin/x2hook.so \ + dist/conf/x2hook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/zerohook.zip: \ + $(builddir)/bin/zerohook.so \ + dist/conf/zerohook.conf \ + dist/piueb \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +################################################ +# API: Lexical sorting + +# Very messed up and hacky way to preserve the sub-directories as zip does not support this. +# Feel free to improve if you got a more sophisticated solution. +$(zipdir)/api.zip: \ + src/api/ptapi \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)cp -r src/api/ptapi $(builddir) + $(V)cd $(builddir) && pwd && zip -r api.zip ptapi && cp api.zip zip/api.zip + +$(zipdir)/piubtn.zip: \ + $(builddir)/bin/ptapi-io-piubtn-joystick.so \ + $(builddir)/bin/ptapi-io-piubtn-joystick-conf \ + $(builddir)/bin/ptapi-io-piubtn-keyboard.so \ + $(builddir)/bin/ptapi-io-piubtn-keyboard-conf \ + $(builddir)/bin/ptapi-io-piubtn-null.so \ + $(builddir)/bin/ptapi-io-piubtn-real.so \ + $(builddir)/bin/ptapi-io-piubtn-test \ + dist/api/ptapi-io-piubtn-stub.c \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/piuio.zip: \ + $(builddir)/bin/ptapi-io-piuio-joystick.so \ + $(builddir)/bin/ptapi-io-piuio-joystick-conf \ + $(builddir)/bin/ptapi-io-piuio-keyboard.so \ + $(builddir)/bin/ptapi-io-piuio-keyboard-conf \ + $(builddir)/bin/ptapi-io-piuio-null.so \ + $(builddir)/bin/ptapi-io-piuio-real.so \ + $(builddir)/bin/ptapi-io-piuio-test \ + dist/api/ptapi-io-piuio-stub.c \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +################################################ +# (USB) profile: Lexical sorting + +# $(builddir)/bin/fex-profile-tool \ + +$(zipdir)/profile-tools.zip: \ + $(builddir)/bin/nx2-profile-tool \ + $(builddir)/bin/nxa-profile-tool \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +################################################ +# pumpnet: Lexical sorting + +$(zipdir)/pumpnet.zip: \ + $(builddir)/bin/pumpnet-client \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +################################################ +# Documentation + +$(zipdir)/doc.zip: \ + doc/api/io/piuio.md \ + doc/api/io/x11-input-hook.md \ + doc/game/image \ + doc/game/01-1st.md \ + doc/game/02-2nd.md \ + doc/game/03-3rd.md \ + doc/game/04-3se.md \ + doc/game/05-tc.md \ + doc/game/06-pc.md \ + doc/game/07-extra.md \ + doc/game/08-prem1.md \ + doc/game/09-prex1.md \ + doc/game/10-reb.md \ + doc/game/11-prem2.md \ + doc/game/12-prex2.md \ + doc/game/13-prem3.md \ + doc/game/14-prex3.md \ + doc/game/15-exc.md \ + doc/game/16-exc2.md \ + doc/game/17-zero.md \ + doc/game/18-nx.md \ + doc/game/20-nx2.md \ + doc/game/game.md \ + doc/hook/exchook.md \ + doc/hook/hook.md \ + doc/hook/mk3hook.md \ + doc/hook/nxhook.md \ + doc/hook/nx2hook.md \ + doc/hook/os.md \ + doc/hook/x2hook.md \ + doc/hook/zerohook.md \ + doc/README.md \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip $@ $^ + +################################################ + +$(builddir)/pumptools.zip: \ + $(zipdir)/api.zip \ + $(zipdir)/doc.zip \ + $(zipdir)/exchook.zip \ + $(zipdir)/f2hook.zip \ + $(zipdir)/fexhook.zip \ + $(zipdir)/fsthook.zip \ + $(zipdir)/mk3hook.zip \ + $(zipdir)/nx2hook.zip \ + $(zipdir)/nxahook.zip \ + $(zipdir)/nxhook.zip \ + $(zipdir)/piubtn.zip \ + $(zipdir)/piuio.zip \ + $(zipdir)/profile-tools.zip \ + $(zipdir)/prihook.zip \ + $(zipdir)/pro2hook.zip \ + $(zipdir)/prohook.zip \ + $(zipdir)/pumpnet.zip \ + $(zipdir)/x2hook.zip \ + $(zipdir)/zerohook.zip \ + CHANGELOG.md \ + CONTRIBUTING.md \ + LICENSE \ + README.md \ + $(builddir)/git-version \ + $(builddir)/libc-version + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(builddir)/pumptools-public.zip: \ + $(zipdir)/api.zip \ + $(zipdir)/doc.zip \ + $(zipdir)/exchook.zip \ + $(zipdir)/mk3hook.zip \ + $(zipdir)/nxhook.zip \ + $(zipdir)/nx2hook.zip \ + $(zipdir)/piubtn.zip \ + $(zipdir)/piuio.zip \ + $(zipdir)/x2hook.zip \ + $(zipdir)/zerohook.zip \ + CHANGELOG.md \ + LICENSE \ + README.md \ + $(builddir)/git-version \ + $(builddir)/libc-version + $(V)echo ... $@ + $(V)zip -j $@ $^ + +################################################ + +package: $(builddir)/pumptools.zip $(builddir)/pumptools-public.zip \ No newline at end of file diff --git a/README.md b/README.md index 31bda43..4fc5be6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,117 @@ -This is currently a placeholder repository for the source release of pumptools. +# Pumptools: The ultimate toolset to run all Linux based PIU games on any* kernel and distribution +Version: 1.08
+[Release history](CHANGELOG.md) -In the meantime, use the issue tracker to report any bugs you encounter with -the binary releases. \ No newline at end of file +This tool-set provides hook libraries that can be pre-loaded to run vanilla dumps of all Pump It Up games running on +Linux. This also includes the only exclusive MK5 hardware based game Exceed and the MK3 Linux ports. + +## Public release note +Currently, the public release contains all source code required to run all games listed +[here](#games-and-latest-versions-supported). The following games however are currently not working due to missing +dongle key tables and raw hdd areas (dummy files exist to allow full compilation of the project): +* NXA +* Fiesta +* FiestaEX +* Fiesta 2 +* Prime + +The required assets to run these games will follow with future releases. + +## Documentation +Additional documentation on different topics related to pumptools are located in the `doc` subfolder +[here](doc/README.md). + +For release distribution packages, you can find a `doc.zip` file inside the `pumptools.zip` package that contains all +documentation also referenced from here: +* [pumptools api](doc/api/api.md) +* [pumptools development](doc/development/development.md) +* [pumptools's architecture](doc/development/architecture.md) +* [general game related stuff like pad codes, unlocks etc](doc/game/game.md) +* [game hook libraries](doc/hook/hook.md) + +## Hook libraries +### Features +* Run all supported games on recent hardware, Linux distributions and kernel versions +* Environment sandboxing to increase compatibility and portability +* API for hardware abstraction: Write your own drivers for IO devices +* Full dongle emulation in software +* Works with **vanilla** data, no hex edits +* Various (bug)fixes and quality of live improvements for many games + +### Games and latest versions supported +All hooks share a major set of features provided by pumptools. Therefore, common topics are covered in the +[main hook readme](doc/hook/hook.md). Start there when you are setting up a game with pumptools. Additionally, refer to +each dedicated hook readme for further important and required information to successfully setup and run the games. + +The following games are supported and tested with the latest versions available. Earlier version might also be support +and work because of the nature the hooks are implemented. + +* [MK3 Linux Ports: 1st to Prem 3/Prex 3](doc/hook/mk3hook.md): MK3 Linux ports (there is only one version officially +available per game version) +* [Exceed](doc/hook/exchook.md): 20040408 +* [Exceed 2](doc/hook/x2hook.md): 102 +* [Zero](doc/hook/zerohook.md): 103 +* [NX](doc/hook/nxhook.md): 108 +* [NX2](doc/hook/nx2hook.md): 154 + +Not available, yet: +* [Pro](doc/hook/prohook.md): R5 nodongle +* [NXA](doc/hook/nxahook.md): 110 +* [Pro2](doc/hook/pro2hook.md): R5 nodongle +* [Fiesta](doc/hook/fsthook.md): 120 +* [FiestaEX](doc/hook/fexhook.md): 151 +* [Fiesta 2](doc/hook/f2hook.md): 161 +* [Prime](doc/hook/prihook.md): 122 + +### Prepare your operating system +Before you start installing and configuring anything of pumptools, read [this readme](doc/hook/os.md) on how to prepare +your operating system and environment. + +### Get and prepare game data +You need **vanilla**, i.e. non-tempered and non-decrypted, game assets as well as non-tempered executable binaries +which can be pulled from legit and clean physical disks or images of them. + +For setting up the games, have a look at the dedicated readme files for +[each hook and game](#games-and-latest-versions-supported). + +### Setup hook libraries +**READ THE WHOLE README OF THE HOOK BUILD YOU WANT TO USE FIRST BEFORE DOING ANYTHING!!!** + +The readme files go into great detail how to setup things with various potential relevant aspects spread across the +document. Being aware of them will save you a lot of puzzling and time. Furthermore, read the FAQ/troubleshooting +section before as well to be aware of any known issues when you encounter them. + +## Building +Make sure you have the [required tools](doc/development.md) installed. Once that's done, simply run +```shell script +make build +``` + +to build it on your current host from the root directory of this project. + +The build output is located in the `build` subdirectory. The built binaries can be found in `build/bin` and a +distribution package called `pumptools.zip` can be found in the `build` subfolder. + +You can also build in a docker container. The container provides the necessary build environment and also ensures +[compatibility regarding glibc versions](doc/development/development.md#compatibility-issues-with-newer-glibc-versions). +```shell script +make build-docker +``` + +The build output from the docker image is located in `build/docker`. + +## Development +## API +Please refer to the [API documentation](doc/api/api.md). + +## Architecture +A dedicate [architecture document](doc/architecture.md) outlines the architecture of pumptools and points out the most +important aspects you should know before you get started with development. + +## Pumptools development +Please refer to the [development readme](doc/development.md) regarding what you have to know when you want to develop +something for pumptools. + +## License +Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the +[LICENSE file](LICENSE) included with the source code. \ No newline at end of file diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000..b47daf9 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 2.8) + +option(PT_PUBLIC_RELEASE "PT_PUBLIC_RELEASE" "0") + +if (PT_PUBLIC_RELEASE STREQUAL "1") + message(WARNING "!!! Compiling public release !!!\n!!! Compiling public release !!!\n!!! Compiling public release !!!") +endif () + +# set git revision +execute_process(COMMAND git log -1 --format=%h --date=short HEAD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE GITREV ERROR_QUIET) +string(STRIP "${GITREV}" GITREV) +if (GITREV STREQUAL "") + set(GITREV "not available") +endif () + +include(modules/AddResources.cmake) + +set(PT_ROOT_SRC "${CMAKE_CURRENT_LIST_DIR}/../src") + +set(PT_ROOT_IMPORTS "${PT_ROOT_SRC}/imports") +set(PT_ROOT_PTAPI "${PT_ROOT_SRC}/api") +set(PT_ROOT_MAIN "${PT_ROOT_SRC}/main") +set(PT_ROOT_TEST "${PT_ROOT_SRC}/test") + +# force out of source build +message(STATUS "Force out of source build check...") +string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" insource) + +if (insource) + message(FATAL_ERROR "Do not build in your source dir. Use a dedicated build folder. Now go cleanup the cache in the CMakeCache.txt and CMakeFiles folder which don't belong there!") +endif () + +# binary output dir +set(PT_BIN_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin" CACHE STRING "Output path for compiled binaries") + +# For generic no-config case +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PT_BIN_OUTPUT_PATH}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PT_BIN_OUTPUT_PATH}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PT_BIN_OUTPUT_PATH}) + +# Common C/C++ save +set(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 14) + +# TODO cleanup flags and add them to each module separately +# Important note: Don't use -O3 because that will break the dongle emulation code for microdog40 (wtf) +# Also, -O3 seems to optimize too much stuff and kills the amixer-block module entirely (the system() preload +# can't be called anymore) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGITREV=${GITREV} -pipe -Wall -Werror -std=gnu99 -D_GNU_SOURCE -Wno-attributes -m32") +set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined -m32") + +# Enable debug flags on non public builds +if (PT_PUBLIC_RELEASE STREQUAL "0") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -g -rdynamic") +endif () + +# Disable asserts and strip binary +if (PT_PUBLIC_RELEASE STREQUAL "1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNDEBUG -DPT_PUBLIC_RELEASE") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -s") +endif () + +add_subdirectory(src) + +# Add a text file containing the git commit rev +file(WRITE ${CMAKE_BINARY_DIR}/version ${GITREV}) \ No newline at end of file diff --git a/cmake/modules/AddResources.cmake b/cmake/modules/AddResources.cmake new file mode 100644 index 0000000..57d546a --- /dev/null +++ b/cmake/modules/AddResources.cmake @@ -0,0 +1,12 @@ +# Compilation step for static resources +FUNCTION(ADD_RESOURCES out_var path file) + SET(result) + SET(result "${PROJECT_BINARY_DIR}/${file}.o") + ADD_CUSTOM_COMMAND(OUTPUT ${result} + COMMAND ld -m elf_i386 -L"${path}" -r -b binary -o ${result} ${file} + DEPENDS ${path}/${file} + WORKING_DIRECTORY ${path} + COMMENT "Building binary data object ${result}" + VERBATIM) + SET(${out_var} "${result}" PARENT_SCOPE) +ENDFUNCTION() diff --git a/cmake/src/CMakeLists.txt b/cmake/src/CMakeLists.txt new file mode 100644 index 0000000..5995d66 --- /dev/null +++ b/cmake/src/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(imports) +add_subdirectory(main) +add_subdirectory(test) \ No newline at end of file diff --git a/cmake/src/imports/CMakeLists.txt b/cmake/src/imports/CMakeLists.txt new file mode 100644 index 0000000..0838b25 --- /dev/null +++ b/cmake/src/imports/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(cmocka) \ No newline at end of file diff --git a/cmake/src/imports/cmocka/CMakeLists.txt b/cmake/src/imports/cmocka/CMakeLists.txt new file mode 100644 index 0000000..847a4cf --- /dev/null +++ b/cmake/src/imports/cmocka/CMakeLists.txt @@ -0,0 +1,13 @@ +project(cmocka) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_SRC}/imports/cmocka) + +include_directories(${SRC}) + +MESSAGE(STATUS, "${PT_IMPORTS_SRC}") + +set(SOURCE_FILES + ${SRC}/cmocka.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/CMakeLists.txt b/cmake/src/main/CMakeLists.txt new file mode 100644 index 0000000..ce40bd0 --- /dev/null +++ b/cmake/src/main/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories(${PT_ROOT_IMPORTS}) +include_directories(${PT_ROOT_PTAPI}) +include_directories(${PT_ROOT_MAIN}) + +add_subdirectory(asset) +add_subdirectory(capnhook) +add_subdirectory(crypt) +add_subdirectory(hook) +add_subdirectory(io) +add_subdirectory(ptapi) +add_subdirectory(pumpnet) +add_subdirectory(sec) +add_subdirectory(util) \ No newline at end of file diff --git a/cmake/src/main/asset/CMakeLists.txt b/cmake/src/main/asset/CMakeLists.txt new file mode 100644 index 0000000..71c5dad --- /dev/null +++ b/cmake/src/main/asset/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(f2) +add_subdirectory(fex) +add_subdirectory(nx) +add_subdirectory(nx2) +add_subdirectory(nxa) +add_subdirectory(x2) +add_subdirectory(zero) \ No newline at end of file diff --git a/cmake/src/main/asset/f2/CMakeLists.txt b/cmake/src/main/asset/f2/CMakeLists.txt new file mode 100644 index 0000000..10b87d1 --- /dev/null +++ b/cmake/src/main/asset/f2/CMakeLists.txt @@ -0,0 +1,2 @@ +#add_subdirectory(lib) +#add_subdirectory(tool) \ No newline at end of file diff --git a/cmake/src/main/asset/f2/lib/CMakeLists.txt b/cmake/src/main/asset/f2/lib/CMakeLists.txt new file mode 100644 index 0000000..988c3af --- /dev/null +++ b/cmake/src/main/asset/f2/lib/CMakeLists.txt @@ -0,0 +1,11 @@ +project(asset-f2) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/f2/lib) + +set(SOURCE_FILES + ${SRC}/usb-rank.c + ${SRC}/usb-save.c + ${SRC}/util.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/asset/fex/CMakeLists.txt b/cmake/src/main/asset/fex/CMakeLists.txt new file mode 100644 index 0000000..83ad3ac --- /dev/null +++ b/cmake/src/main/asset/fex/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(lib) +add_subdirectory(tool) \ No newline at end of file diff --git a/cmake/src/main/asset/fex/lib/CMakeLists.txt b/cmake/src/main/asset/fex/lib/CMakeLists.txt new file mode 100644 index 0000000..09a18d7 --- /dev/null +++ b/cmake/src/main/asset/fex/lib/CMakeLists.txt @@ -0,0 +1,11 @@ +project(asset-fex) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/fex/lib) + +set(SOURCE_FILES + ${SRC}/usb-rank.c + ${SRC}/usb-save.c + ${SRC}/util.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/asset/fex/tool/CMakeLists.txt b/cmake/src/main/asset/fex/tool/CMakeLists.txt new file mode 100644 index 0000000..69a87ae --- /dev/null +++ b/cmake/src/main/asset/fex/tool/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(usb-profile) \ No newline at end of file diff --git a/cmake/src/main/asset/fex/tool/usb-profile/CMakeLists.txt b/cmake/src/main/asset/fex/tool/usb-profile/CMakeLists.txt new file mode 100644 index 0000000..d859695 --- /dev/null +++ b/cmake/src/main/asset/fex/tool/usb-profile/CMakeLists.txt @@ -0,0 +1,11 @@ +project(fex-usb-profile-tool) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/fex/tool) + +set(SOURCE_FILES + ${SRC}/usb-profile.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} asset-fex util) diff --git a/cmake/src/main/asset/nx/CMakeLists.txt b/cmake/src/main/asset/nx/CMakeLists.txt new file mode 100644 index 0000000..83ad3ac --- /dev/null +++ b/cmake/src/main/asset/nx/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(lib) +add_subdirectory(tool) \ No newline at end of file diff --git a/cmake/src/main/asset/nx/lib/CMakeLists.txt b/cmake/src/main/asset/nx/lib/CMakeLists.txt new file mode 100644 index 0000000..f8611d9 --- /dev/null +++ b/cmake/src/main/asset/nx/lib/CMakeLists.txt @@ -0,0 +1,10 @@ +project(asset-nx) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/nx/lib) + +set(SOURCE_FILES + ${SRC}/settings.c + ${SRC}/util.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/asset/nx/tool/CMakeLists.txt b/cmake/src/main/asset/nx/tool/CMakeLists.txt new file mode 100644 index 0000000..2508341 --- /dev/null +++ b/cmake/src/main/asset/nx/tool/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(settings) \ No newline at end of file diff --git a/cmake/src/main/asset/nx/tool/settings/CMakeLists.txt b/cmake/src/main/asset/nx/tool/settings/CMakeLists.txt new file mode 100644 index 0000000..ce7a039 --- /dev/null +++ b/cmake/src/main/asset/nx/tool/settings/CMakeLists.txt @@ -0,0 +1,11 @@ +project(nx-settings-tool) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/nx/tool) + +set(SOURCE_FILES + ${SRC}/settings.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} asset-nx util) diff --git a/cmake/src/main/asset/nx2/CMakeLists.txt b/cmake/src/main/asset/nx2/CMakeLists.txt new file mode 100644 index 0000000..83ad3ac --- /dev/null +++ b/cmake/src/main/asset/nx2/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(lib) +add_subdirectory(tool) \ No newline at end of file diff --git a/cmake/src/main/asset/nx2/lib/CMakeLists.txt b/cmake/src/main/asset/nx2/lib/CMakeLists.txt new file mode 100644 index 0000000..b565742 --- /dev/null +++ b/cmake/src/main/asset/nx2/lib/CMakeLists.txt @@ -0,0 +1,13 @@ +project(asset-nx2) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/nx2/lib) + +set(SOURCE_FILES + ${SRC}/usb-rank.c + ${SRC}/usb-save.c + ${SRC}/util.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} util) diff --git a/cmake/src/main/asset/nx2/tool/CMakeLists.txt b/cmake/src/main/asset/nx2/tool/CMakeLists.txt new file mode 100644 index 0000000..69a87ae --- /dev/null +++ b/cmake/src/main/asset/nx2/tool/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(usb-profile) \ No newline at end of file diff --git a/cmake/src/main/asset/nx2/tool/usb-profile/CMakeLists.txt b/cmake/src/main/asset/nx2/tool/usb-profile/CMakeLists.txt new file mode 100644 index 0000000..887c6fd --- /dev/null +++ b/cmake/src/main/asset/nx2/tool/usb-profile/CMakeLists.txt @@ -0,0 +1,11 @@ +project(nx2-profile-tool) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/nx2/tool) + +set(SOURCE_FILES + ${SRC}/usb-profile.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} asset-nx2 util) diff --git a/cmake/src/main/asset/nxa/CMakeLists.txt b/cmake/src/main/asset/nxa/CMakeLists.txt new file mode 100644 index 0000000..83ad3ac --- /dev/null +++ b/cmake/src/main/asset/nxa/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(lib) +add_subdirectory(tool) \ No newline at end of file diff --git a/cmake/src/main/asset/nxa/lib/CMakeLists.txt b/cmake/src/main/asset/nxa/lib/CMakeLists.txt new file mode 100644 index 0000000..02efdf0 --- /dev/null +++ b/cmake/src/main/asset/nxa/lib/CMakeLists.txt @@ -0,0 +1,13 @@ +project(asset-nxa) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/nxa/lib) + +set(SOURCE_FILES + ${SRC}/usb-rank.c + ${SRC}/usb-save.c + ${SRC}/util.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} util) diff --git a/cmake/src/main/asset/nxa/tool/CMakeLists.txt b/cmake/src/main/asset/nxa/tool/CMakeLists.txt new file mode 100644 index 0000000..69a87ae --- /dev/null +++ b/cmake/src/main/asset/nxa/tool/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(usb-profile) \ No newline at end of file diff --git a/cmake/src/main/asset/nxa/tool/usb-profile/CMakeLists.txt b/cmake/src/main/asset/nxa/tool/usb-profile/CMakeLists.txt new file mode 100644 index 0000000..6069fa0 --- /dev/null +++ b/cmake/src/main/asset/nxa/tool/usb-profile/CMakeLists.txt @@ -0,0 +1,11 @@ +project(nxa-profile-tool) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/nxa/tool) + +set(SOURCE_FILES + ${SRC}/usb-profile.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} asset-nxa util) diff --git a/cmake/src/main/asset/x2/CMakeLists.txt b/cmake/src/main/asset/x2/CMakeLists.txt new file mode 100644 index 0000000..8570eeb --- /dev/null +++ b/cmake/src/main/asset/x2/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(lib) \ No newline at end of file diff --git a/cmake/src/main/asset/x2/lib/CMakeLists.txt b/cmake/src/main/asset/x2/lib/CMakeLists.txt new file mode 100644 index 0000000..a173f0e --- /dev/null +++ b/cmake/src/main/asset/x2/lib/CMakeLists.txt @@ -0,0 +1,9 @@ +project(asset-x2) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/x2/lib) + +set(SOURCE_FILES + ${SRC}/settings.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/asset/zero/CMakeLists.txt b/cmake/src/main/asset/zero/CMakeLists.txt new file mode 100644 index 0000000..8570eeb --- /dev/null +++ b/cmake/src/main/asset/zero/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(lib) \ No newline at end of file diff --git a/cmake/src/main/asset/zero/lib/CMakeLists.txt b/cmake/src/main/asset/zero/lib/CMakeLists.txt new file mode 100644 index 0000000..c9cf062 --- /dev/null +++ b/cmake/src/main/asset/zero/lib/CMakeLists.txt @@ -0,0 +1,9 @@ +project(asset-zero) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/asset/zero/lib) + +set(SOURCE_FILES + ${SRC}/settings.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/capnhook/CMakeLists.txt b/cmake/src/main/capnhook/CMakeLists.txt new file mode 100644 index 0000000..bd338bc --- /dev/null +++ b/cmake/src/main/capnhook/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(hook) +add_subdirectory(hooklib) \ No newline at end of file diff --git a/cmake/src/main/capnhook/hook/CMakeLists.txt b/cmake/src/main/capnhook/hook/CMakeLists.txt new file mode 100644 index 0000000..2395d71 --- /dev/null +++ b/cmake/src/main/capnhook/hook/CMakeLists.txt @@ -0,0 +1,20 @@ +project(capnhook-hook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/capnhook/hook) + +set(SOURCE_FILES + ${PT_ROOT_MAIN}/capnhook/hook/fshook.c + ${PT_ROOT_MAIN}/capnhook/hook/filehook.c + ${PT_ROOT_MAIN}/capnhook/hook/iobuf.c + ${PT_ROOT_MAIN}/capnhook/hook/iohook.c + ${PT_ROOT_MAIN}/capnhook/hook/lib.c + ${PT_ROOT_MAIN}/capnhook/hook/result.c + ${PT_ROOT_MAIN}/capnhook/hook/sig.c + ${PT_ROOT_MAIN}/capnhook/hook/usbhook.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} dl util) \ No newline at end of file diff --git a/cmake/src/main/capnhook/hooklib/CMakeLists.txt b/cmake/src/main/capnhook/hooklib/CMakeLists.txt new file mode 100644 index 0000000..4c7cd29 --- /dev/null +++ b/cmake/src/main/capnhook/hooklib/CMakeLists.txt @@ -0,0 +1,20 @@ +project(capnhook-hooklib) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/capnhook/hooklib) + +set(SOURCE_FILES + ${PT_ROOT_MAIN}/capnhook/hooklib/filehook-mon.c + ${PT_ROOT_MAIN}/capnhook/hooklib/fileopen-mon.c + ${PT_ROOT_MAIN}/capnhook/hooklib/fshook-mon.c + ${PT_ROOT_MAIN}/capnhook/hooklib/iohook-mon.c + ${PT_ROOT_MAIN}/capnhook/hooklib/redir.c + ${PT_ROOT_MAIN}/capnhook/hooklib/usb-emu.c + ${PT_ROOT_MAIN}/capnhook/hooklib/usb-init-fix.c + ${PT_ROOT_MAIN}/capnhook/hooklib/usbhook-mon.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} capnhook-hook util) \ No newline at end of file diff --git a/cmake/src/main/crypt/CMakeLists.txt b/cmake/src/main/crypt/CMakeLists.txt new file mode 100644 index 0000000..99e0f15 --- /dev/null +++ b/cmake/src/main/crypt/CMakeLists.txt @@ -0,0 +1,12 @@ +project(crypt) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/crypt) + +set(SOURCE_FILES + ${SRC}/lib/md5.c + ${SRC}/lib/rijndael.c + ${SRC}/aes.c + ${SRC}/md5.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/main/hook/CMakeLists.txt b/cmake/src/main/hook/CMakeLists.txt new file mode 100644 index 0000000..e86398f --- /dev/null +++ b/cmake/src/main/hook/CMakeLists.txt @@ -0,0 +1,16 @@ +add_subdirectory(core) +add_subdirectory(exc) +add_subdirectory(f2) +add_subdirectory(fex) +add_subdirectory(fst) +add_subdirectory(mk3) +add_subdirectory(nx2) +add_subdirectory(nxa) +add_subdirectory(nx) +add_subdirectory(patch) +add_subdirectory(pri) +add_subdirectory(pro2) +add_subdirectory(propatch) +add_subdirectory(pro) +add_subdirectory(x2) +add_subdirectory(zero) \ No newline at end of file diff --git a/cmake/src/main/hook/core/CMakeLists.txt b/cmake/src/main/hook/core/CMakeLists.txt new file mode 100644 index 0000000..626ef81 --- /dev/null +++ b/cmake/src/main/hook/core/CMakeLists.txt @@ -0,0 +1,14 @@ +project(hook-core) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/core) + +set(SOURCE_FILES + ${SRC}/options.c + ${SRC}/piu-utils.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} util) \ No newline at end of file diff --git a/cmake/src/main/hook/exc/CMakeLists.txt b/cmake/src/main/hook/exc/CMakeLists.txt new file mode 100644 index 0000000..076bf52 --- /dev/null +++ b/cmake/src/main/hook/exc/CMakeLists.txt @@ -0,0 +1,19 @@ +project(exchook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/exc) + +set(SOURCE_FILES + ${SRC}/eeprom.c + ${SRC}/io.c + ${SRC}/lockchip.c + ${SRC}/main.c + ${SRC}/mempatch.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} hook-core lockchip ptapi-io-piuio-util patch util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/f2/CMakeLists.txt b/cmake/src/main/hook/f2/CMakeLists.txt new file mode 100644 index 0000000..a0d14d7 --- /dev/null +++ b/cmake/src/main/hook/f2/CMakeLists.txt @@ -0,0 +1,19 @@ +project(f2hook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/f2) + +add_resources(HDD_RAW ${SRC} f2hook.hdd.raw) +add_resources(DOG_KEY ${SRC} f2hook.hasp.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-shared") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} crypt hook-core microdog34 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/fex/CMakeLists.txt b/cmake/src/main/hook/fex/CMakeLists.txt new file mode 100644 index 0000000..b06027c --- /dev/null +++ b/cmake/src/main/hook/fex/CMakeLists.txt @@ -0,0 +1,18 @@ +project(fexhook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/fex) + +add_resources(HDD_RAW ${SRC} fexhook.hdd.raw) +add_resources(DOG_KEY ${SRC} fexhook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} crypt hook-core microdog40 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/fst/CMakeLists.txt b/cmake/src/main/hook/fst/CMakeLists.txt new file mode 100644 index 0000000..9cb5a70 --- /dev/null +++ b/cmake/src/main/hook/fst/CMakeLists.txt @@ -0,0 +1,18 @@ +project(fsthook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/fst) + +add_resources(HDD_RAW ${SRC} fsthook.hdd.raw) +add_resources(DOG_KEY ${SRC} fsthook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} crypt hook-core microdog40 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/mk3/CMakeLists.txt b/cmake/src/main/hook/mk3/CMakeLists.txt new file mode 100644 index 0000000..a451a44 --- /dev/null +++ b/cmake/src/main/hook/mk3/CMakeLists.txt @@ -0,0 +1,19 @@ +project(mk3hook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/mk3) + +set(SOURCE_FILES + ${SRC}/1st-2nd-fs-fix.c + ${SRC}/config.c + ${SRC}/fmodex.c + ${SRC}/main.c + ${SRC}/ogl-fix.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} hook-core patch util dl ptapi-io-piuio-util) \ No newline at end of file diff --git a/cmake/src/main/hook/nx/CMakeLists.txt b/cmake/src/main/hook/nx/CMakeLists.txt new file mode 100644 index 0000000..4ea5cd7 --- /dev/null +++ b/cmake/src/main/hook/nx/CMakeLists.txt @@ -0,0 +1,19 @@ +project(nxhook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/nx) + +add_resources(HDD_RAW ${SRC} nxhook.hdd.raw) +add_resources(DOG_KEY ${SRC} nxhook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c + ${SRC}/unlock.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} asset-nx hook-core microdog34 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/nx2/CMakeLists.txt b/cmake/src/main/hook/nx2/CMakeLists.txt new file mode 100644 index 0000000..6cab2ae --- /dev/null +++ b/cmake/src/main/hook/nx2/CMakeLists.txt @@ -0,0 +1,19 @@ +project(nx2hook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/nx2) + +add_resources(HDD_RAW ${SRC} nx2hook.hdd.raw) +add_resources(DOG_KEY ${SRC} nx2hook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c + ${SRC}/profile-gen.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} capnhook-hook capnhook-hooklib crypt hook-core microdog40 asset-nx2 patch ptapi-io-piuio-util pumpnet-lib util dl pthread curl) \ No newline at end of file diff --git a/cmake/src/main/hook/nxa/CMakeLists.txt b/cmake/src/main/hook/nxa/CMakeLists.txt new file mode 100644 index 0000000..8f57a75 --- /dev/null +++ b/cmake/src/main/hook/nxa/CMakeLists.txt @@ -0,0 +1,19 @@ +project(nxahook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/nxa) + +add_resources(HDD_RAW ${SRC} nxahook.hdd.raw) +add_resources(DOG_KEY ${SRC} nxahook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c + ${SRC}/profile-gen.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} asset-nxa crypt hook-core microdog40 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/patch/CMakeLists.txt b/cmake/src/main/hook/patch/CMakeLists.txt new file mode 100644 index 0000000..17c2234 --- /dev/null +++ b/cmake/src/main/hook/patch/CMakeLists.txt @@ -0,0 +1,39 @@ +project(patch) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/patch) + +set(SOURCE_FILES + ${SRC}/asound-fix.c + ${SRC}/amixer-block.c + ${SRC}/blacklist-url.c + ${SRC}/block-keyboard-grab.c + ${SRC}/gfx.c + ${SRC}/hasp.c + ${SRC}/hdd-check.c + ${SRC}/hook-mon.c + ${SRC}/main-loop.c + ${SRC}/microdog34.c + ${SRC}/microdog40.c + ${SRC}/mounts.c + ${SRC}/net-profile.c + ${SRC}/network.c + ${SRC}/piubtn.c + ${SRC}/piuio.c + ${SRC}/piuio-exit.c + ${SRC}/ram-wipe.c + ${SRC}/redir.c + ${SRC}/sigsegv.c + ${SRC}/sound.c + ${SRC}/usb-emu.c + ${SRC}/usb-init-fix.c + ${SRC}/usb-mnt.c + ${SRC}/usb-unlock.c + ${SRC}/usbfs.c + ${SRC}/x11-event-loop.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} capnhook-hook capnhook-hooklib hasp-old microdog34 microdog40) diff --git a/cmake/src/main/hook/pri/CMakeLists.txt b/cmake/src/main/hook/pri/CMakeLists.txt new file mode 100644 index 0000000..8502c22 --- /dev/null +++ b/cmake/src/main/hook/pri/CMakeLists.txt @@ -0,0 +1,19 @@ +project(prihook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/pri) + +add_resources(HDD_RAW ${SRC} prihook.hdd.raw) +add_resources(DOG_KEY ${SRC} prihook.hasp.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c + ${SRC}/usb-updates.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${HDD_RAW} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} crypt hasp-old hook-core patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/pro/CMakeLists.txt b/cmake/src/main/hook/pro/CMakeLists.txt new file mode 100644 index 0000000..b519ced --- /dev/null +++ b/cmake/src/main/hook/pro/CMakeLists.txt @@ -0,0 +1,15 @@ +project(prohook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/pro) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} hook-core patch propatch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/pro2/CMakeLists.txt b/cmake/src/main/hook/pro2/CMakeLists.txt new file mode 100644 index 0000000..45a1c31 --- /dev/null +++ b/cmake/src/main/hook/pro2/CMakeLists.txt @@ -0,0 +1,15 @@ +project(pro2hook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/pro2) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} hook-core patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/propatch/CMakeLists.txt b/cmake/src/main/hook/propatch/CMakeLists.txt new file mode 100644 index 0000000..6197c19 --- /dev/null +++ b/cmake/src/main/hook/propatch/CMakeLists.txt @@ -0,0 +1,13 @@ +project(propatch) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/propatch) + +set(SOURCE_FILES + ${SRC}/usb-fix.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} capnhook-hook capnhook-hooklib) diff --git a/cmake/src/main/hook/x2/CMakeLists.txt b/cmake/src/main/hook/x2/CMakeLists.txt new file mode 100644 index 0000000..4987bd7 --- /dev/null +++ b/cmake/src/main/hook/x2/CMakeLists.txt @@ -0,0 +1,19 @@ +project(x2hook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/x2) + +add_resources(DOG_KEY ${SRC} x2hook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/ogl-fix.c + ${SRC}/options.c + ${SRC}/unlock.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${DOG_KEY}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} asset-x2 hook-core microdog34 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/hook/zero/CMakeLists.txt b/cmake/src/main/hook/zero/CMakeLists.txt new file mode 100644 index 0000000..eba0b2a --- /dev/null +++ b/cmake/src/main/hook/zero/CMakeLists.txt @@ -0,0 +1,19 @@ +project(zerohook) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/hook/zero) + +add_resources(HDD_RAW ${SRC} zerohook.hdd.raw) +add_resources(DOG_KEY ${SRC} zerohook.dog.key) + +set(SOURCE_FILES + ${SRC}/main.c + ${SRC}/options.c + ${SRC}/unlock.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${DOG_KEY} ${HDD_RAW}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} asset-zero hook-core microdog34 patch ptapi-io-piuio-util util dl pthread) \ No newline at end of file diff --git a/cmake/src/main/io/CMakeLists.txt b/cmake/src/main/io/CMakeLists.txt new file mode 100644 index 0000000..ee6ad67 --- /dev/null +++ b/cmake/src/main/io/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(piubtn) +add_subdirectory(piuio) +add_subdirectory(util) \ No newline at end of file diff --git a/cmake/src/main/io/piubtn/CMakeLists.txt b/cmake/src/main/io/piubtn/CMakeLists.txt new file mode 100644 index 0000000..433ce8d --- /dev/null +++ b/cmake/src/main/io/piubtn/CMakeLists.txt @@ -0,0 +1,14 @@ +project(io-piubtn) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/io/piubtn) + +set(SOURCE_FILES + ${SRC}/device.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) +add_library(piubtn SHARED ${SOURCE_FILES}) + +set_target_properties(piubtn PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} io-util util usb-1.0) \ No newline at end of file diff --git a/cmake/src/main/io/piuio/CMakeLists.txt b/cmake/src/main/io/piuio/CMakeLists.txt new file mode 100644 index 0000000..32b348b --- /dev/null +++ b/cmake/src/main/io/piuio/CMakeLists.txt @@ -0,0 +1,14 @@ +project(io-piuio) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/io/piuio) + +set(SOURCE_FILES + ${SRC}/device.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) +add_library(piuio SHARED ${SOURCE_FILES}) + +set_target_properties(piuio PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} io-util util usb-1.0) \ No newline at end of file diff --git a/cmake/src/main/io/util/CMakeLists.txt b/cmake/src/main/io/util/CMakeLists.txt new file mode 100644 index 0000000..786b24a --- /dev/null +++ b/cmake/src/main/io/util/CMakeLists.txt @@ -0,0 +1,11 @@ +project(io-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/io/util) + +set(SOURCE_FILES + ${SRC}/joystick.c + ${SRC}/joystick-util.c + ${SRC}/usb.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) \ No newline at end of file diff --git a/cmake/src/main/ptapi/CMakeLists.txt b/cmake/src/main/ptapi/CMakeLists.txt new file mode 100644 index 0000000..39c7fda --- /dev/null +++ b/cmake/src/main/ptapi/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(piubtn) +add_subdirectory(piuio) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/CMakeLists.txt new file mode 100644 index 0000000..f4ea518 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(joystick-conf) +add_subdirectory(joystick) +add_subdirectory(joystick-util) +add_subdirectory(keyboard) +add_subdirectory(keyboard-conf) +add_subdirectory(keyboard-util) +add_subdirectory(null) +add_subdirectory(real) +add_subdirectory(test) +add_subdirectory(util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/joystick-conf/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/joystick-conf/CMakeLists.txt new file mode 100644 index 0000000..34861f7 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/joystick-conf/CMakeLists.txt @@ -0,0 +1,11 @@ +project(ptapi-io-piubtn-joystick-conf) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/joystick-conf) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} ptapi-io-piubtn-joystick-util io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/joystick-util/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/joystick-util/CMakeLists.txt new file mode 100644 index 0000000..e5be6aa --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/joystick-util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(ptapi-io-piubtn-joystick-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/joystick-util) + +set(SOURCE_FILES + ${SRC}/joystick-conf.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/joystick/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/joystick/CMakeLists.txt new file mode 100644 index 0000000..1ed0445 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/joystick/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piubtn-joystick) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/joystick) + +set(SOURCE_FILES + ${SRC}/joystick.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} ptapi-io-piubtn-joystick-util io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/keyboard-conf/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/keyboard-conf/CMakeLists.txt new file mode 100644 index 0000000..c2a5bc7 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/keyboard-conf/CMakeLists.txt @@ -0,0 +1,11 @@ +project(ptapi-io-piubtn-keyboard-conf) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/keyboard-conf) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} ptapi-io-piubtn-keyboard-util io-util util X11) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/keyboard-util/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/keyboard-util/CMakeLists.txt new file mode 100644 index 0000000..7fac733 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/keyboard-util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(ptapi-io-piubtn-keyboard-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/keyboard-util) + +set(SOURCE_FILES + ${SRC}/keyboard-conf.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/keyboard/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/keyboard/CMakeLists.txt new file mode 100644 index 0000000..33e50de --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/keyboard/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piubtn-keyboard) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/keyboard) + +set(SOURCE_FILES + ${SRC}/keyboard.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} ptapi-io-piubtn-keyboard-util io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/null/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/null/CMakeLists.txt new file mode 100644 index 0000000..e10bd5f --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/null/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piubtn-null) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/null) + +set(SOURCE_FILES + ${SRC}/null.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/real/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/real/CMakeLists.txt new file mode 100644 index 0000000..b5eea68 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/real/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piubtn-real) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/real) + +set(SOURCE_FILES + ${SRC}/piubtn.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} io-util util usb-1.0) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/test/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/test/CMakeLists.txt new file mode 100644 index 0000000..ec9eb63 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/test/CMakeLists.txt @@ -0,0 +1,11 @@ +project(ptapi-io-piubtn-test) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/test) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} capnhook-hook ptapi-io-piubtn-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piubtn/util/CMakeLists.txt b/cmake/src/main/ptapi/piubtn/util/CMakeLists.txt new file mode 100644 index 0000000..b600a98 --- /dev/null +++ b/cmake/src/main/ptapi/piubtn/util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(ptapi-io-piubtn-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piubtn/util) + +set(SOURCE_FILES + ${SRC}/lib.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} capnhook-hook dl util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/CMakeLists.txt b/cmake/src/main/ptapi/piuio/CMakeLists.txt new file mode 100644 index 0000000..b62b082 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(joystick-conf) +add_subdirectory(joystick) +add_subdirectory(joystick-util) +add_subdirectory(keyboard-conf) +add_subdirectory(keyboard) +add_subdirectory(keyboard-util) +add_subdirectory(null) +add_subdirectory(real) +add_subdirectory(test) +add_subdirectory(util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/joystick-conf/CMakeLists.txt b/cmake/src/main/ptapi/piuio/joystick-conf/CMakeLists.txt new file mode 100644 index 0000000..e78cf18 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/joystick-conf/CMakeLists.txt @@ -0,0 +1,11 @@ +project(ptapi-io-piuio-joystick-conf) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/joystick-conf) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} ptapi-io-piuio-joystick-util io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/joystick-util/CMakeLists.txt b/cmake/src/main/ptapi/piuio/joystick-util/CMakeLists.txt new file mode 100644 index 0000000..093cb52 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/joystick-util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(ptapi-io-piuio-joystick-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/joystick-util) + +set(SOURCE_FILES + ${SRC}/joystick-conf.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/joystick/CMakeLists.txt b/cmake/src/main/ptapi/piuio/joystick/CMakeLists.txt new file mode 100644 index 0000000..9dc3c1b --- /dev/null +++ b/cmake/src/main/ptapi/piuio/joystick/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piuio-joystick) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/joystick) + +set(SOURCE_FILES + ${SRC}/joystick.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} ptapi-io-piuio-joystick-util io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/keyboard-conf/CMakeLists.txt b/cmake/src/main/ptapi/piuio/keyboard-conf/CMakeLists.txt new file mode 100644 index 0000000..18e541f --- /dev/null +++ b/cmake/src/main/ptapi/piuio/keyboard-conf/CMakeLists.txt @@ -0,0 +1,11 @@ +project(ptapi-io-piuio-keyboard-conf) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/keyboard-conf) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} ptapi-io-piuio-keyboard-util io-util util X11) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/keyboard-util/CMakeLists.txt b/cmake/src/main/ptapi/piuio/keyboard-util/CMakeLists.txt new file mode 100644 index 0000000..5cb797d --- /dev/null +++ b/cmake/src/main/ptapi/piuio/keyboard-util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(ptapi-io-piuio-keyboard-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/keyboard-util) + +set(SOURCE_FILES + ${SRC}/keyboard-conf.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/keyboard/CMakeLists.txt b/cmake/src/main/ptapi/piuio/keyboard/CMakeLists.txt new file mode 100644 index 0000000..b8a40c3 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/keyboard/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piuio-keyboard) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/keyboard) + +set(SOURCE_FILES + ${SRC}/keyboard.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} ptapi-io-piuio-keyboard-util io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/null/CMakeLists.txt b/cmake/src/main/ptapi/piuio/null/CMakeLists.txt new file mode 100644 index 0000000..3d5fe29 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/null/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piuio-null) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/null) + +set(SOURCE_FILES + ${SRC}/null.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} io-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/real/CMakeLists.txt b/cmake/src/main/ptapi/piuio/real/CMakeLists.txt new file mode 100644 index 0000000..4edee67 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/real/CMakeLists.txt @@ -0,0 +1,15 @@ +project(ptapi-io-piuio-real) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/real) + +set(SOURCE_FILES + ${SRC}/piuio.c) + +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") +# Remove library name "lib" prefix +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${PROJECT_NAME} io-piuio io-util util usb-1.0) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/test/CMakeLists.txt b/cmake/src/main/ptapi/piuio/test/CMakeLists.txt new file mode 100644 index 0000000..7baf69c --- /dev/null +++ b/cmake/src/main/ptapi/piuio/test/CMakeLists.txt @@ -0,0 +1,11 @@ +project(ptapi-io-piuio-test) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/test) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} capnhook-hook ptapi-io-piuio-util util) \ No newline at end of file diff --git a/cmake/src/main/ptapi/piuio/util/CMakeLists.txt b/cmake/src/main/ptapi/piuio/util/CMakeLists.txt new file mode 100644 index 0000000..e7cb6a4 --- /dev/null +++ b/cmake/src/main/ptapi/piuio/util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(ptapi-io-piuio-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/ptapi/io/piuio/util) + +set(SOURCE_FILES + ${SRC}/lib.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} capnhook-hook dl util) \ No newline at end of file diff --git a/cmake/src/main/pumpnet/CMakeLists.txt b/cmake/src/main/pumpnet/CMakeLists.txt new file mode 100644 index 0000000..54a82bc --- /dev/null +++ b/cmake/src/main/pumpnet/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(client) +add_subdirectory(lib) \ No newline at end of file diff --git a/cmake/src/main/pumpnet/client/CMakeLists.txt b/cmake/src/main/pumpnet/client/CMakeLists.txt new file mode 100644 index 0000000..0c0f36a --- /dev/null +++ b/cmake/src/main/pumpnet/client/CMakeLists.txt @@ -0,0 +1,11 @@ +project(pumpnet-client) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/pumpnet/client) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} pumpnet-lib -lcurl) \ No newline at end of file diff --git a/cmake/src/main/pumpnet/lib/CMakeLists.txt b/cmake/src/main/pumpnet/lib/CMakeLists.txt new file mode 100644 index 0000000..d376102 --- /dev/null +++ b/cmake/src/main/pumpnet/lib/CMakeLists.txt @@ -0,0 +1,15 @@ +project(pumpnet-lib) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/pumpnet/lib) + +set(SOURCE_FILES + ${SRC}/http.c + ${SRC}/profile-token.c + ${SRC}/pumpnet.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} asset-nx2 util) diff --git a/cmake/src/main/sec/CMakeLists.txt b/cmake/src/main/sec/CMakeLists.txt new file mode 100644 index 0000000..d487339 --- /dev/null +++ b/cmake/src/main/sec/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(hasp) +add_subdirectory(lockchip) +add_subdirectory(microdog34) +add_subdirectory(microdog40) \ No newline at end of file diff --git a/cmake/src/main/sec/hasp/CMakeLists.txt b/cmake/src/main/sec/hasp/CMakeLists.txt new file mode 100644 index 0000000..0bd40f8 --- /dev/null +++ b/cmake/src/main/sec/hasp/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(lib) +add_subdirectory(old) +add_subdirectory(server) \ No newline at end of file diff --git a/cmake/src/main/sec/hasp/lib/CMakeLists.txt b/cmake/src/main/sec/hasp/lib/CMakeLists.txt new file mode 100644 index 0000000..72a299a --- /dev/null +++ b/cmake/src/main/sec/hasp/lib/CMakeLists.txt @@ -0,0 +1,17 @@ +project(hasp) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/hasp/lib) + +set(SOURCE_FILES + ${SRC}/object/client-id-req.c + ${SRC}/object/client-id-resp.c + ${SRC}/asn1.c + ${SRC}/handler.c + ${SRC}/server.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} crypt) diff --git a/cmake/src/main/sec/hasp/old/CMakeLists.txt b/cmake/src/main/sec/hasp/old/CMakeLists.txt new file mode 100644 index 0000000..ef17dcc --- /dev/null +++ b/cmake/src/main/sec/hasp/old/CMakeLists.txt @@ -0,0 +1,13 @@ +project(hasp-old) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/hasp/old) + +set(SOURCE_FILES + ${SRC}/hasp.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} crypt) diff --git a/cmake/src/main/sec/hasp/server/CMakeLists.txt b/cmake/src/main/sec/hasp/server/CMakeLists.txt new file mode 100644 index 0000000..b4367e2 --- /dev/null +++ b/cmake/src/main/sec/hasp/server/CMakeLists.txt @@ -0,0 +1,11 @@ +project(hasp-server) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/hasp/server) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} hasp util) \ No newline at end of file diff --git a/cmake/src/main/sec/lockchip/CMakeLists.txt b/cmake/src/main/sec/lockchip/CMakeLists.txt new file mode 100644 index 0000000..9376e41 --- /dev/null +++ b/cmake/src/main/sec/lockchip/CMakeLists.txt @@ -0,0 +1,13 @@ +project(lockchip) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/lockchip) + +set(SOURCE_FILES + ${SRC}/lockchip.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} crypt) diff --git a/cmake/src/main/sec/microdog34/CMakeLists.txt b/cmake/src/main/sec/microdog34/CMakeLists.txt new file mode 100644 index 0000000..6355141 --- /dev/null +++ b/cmake/src/main/sec/microdog34/CMakeLists.txt @@ -0,0 +1,13 @@ +project(microdog34) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/microdog34) + +set(SOURCE_FILES + ${SRC}/microdog34.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} crypt) diff --git a/cmake/src/main/sec/microdog40/CMakeLists.txt b/cmake/src/main/sec/microdog40/CMakeLists.txt new file mode 100644 index 0000000..6813f2a --- /dev/null +++ b/cmake/src/main/sec/microdog40/CMakeLists.txt @@ -0,0 +1,14 @@ +project(microdog40) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/microdog40) + +set(SOURCE_FILES + ${SRC}/microdog40.c + ${SRC}/microdog40d.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} crypt) diff --git a/cmake/src/main/util/CMakeLists.txt b/cmake/src/main/util/CMakeLists.txt new file mode 100644 index 0000000..2219ccc --- /dev/null +++ b/cmake/src/main/util/CMakeLists.txt @@ -0,0 +1,28 @@ +project(util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/util) + +set(SOURCE_FILES + ${SRC}/adler32.c + ${SRC}/array.c + ${SRC}/base64.c + ${SRC}/fs.c + ${SRC}/glibc.c + ${SRC}/hex.c + ${SRC}/iobuf.c + ${SRC}/list.c + ${SRC}/log.c + ${SRC}/mem.c + ${SRC}/net.c + ${SRC}/options.c + ${SRC}/patch.c + ${SRC}/proc.c + ${SRC}/rand.c + ${SRC}/sock-tcp.c + ${SRC}/str.c + ${SRC}/sys-info.c + ${SRC}/test.c + ${SRC}/time.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) diff --git a/cmake/src/test/CMakeLists.txt b/cmake/src/test/CMakeLists.txt new file mode 100644 index 0000000..a462985 --- /dev/null +++ b/cmake/src/test/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(${PT_ROOT_IMPORTS}) +include_directories(${PT_ROOT_PTAPI}) +include_directories(${PT_ROOT_MAIN}) +include_directories(${PT_ROOT_TEST}) + +add_subdirectory(capnhook) +add_subdirectory(hook) +add_subdirectory(test-util) +add_subdirectory(util) \ No newline at end of file diff --git a/cmake/src/test/capnhook/CMakeLists.txt b/cmake/src/test/capnhook/CMakeLists.txt new file mode 100644 index 0000000..30d014b --- /dev/null +++ b/cmake/src/test/capnhook/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(hook) \ No newline at end of file diff --git a/cmake/src/test/capnhook/hook/CMakeLists.txt b/cmake/src/test/capnhook/hook/CMakeLists.txt new file mode 100644 index 0000000..8570eeb --- /dev/null +++ b/cmake/src/test/capnhook/hook/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(lib) \ No newline at end of file diff --git a/cmake/src/test/capnhook/hook/lib/CMakeLists.txt b/cmake/src/test/capnhook/hook/lib/CMakeLists.txt new file mode 100644 index 0000000..f9aa7fb --- /dev/null +++ b/cmake/src/test/capnhook/hook/lib/CMakeLists.txt @@ -0,0 +1,11 @@ +project(test-capnhook-hook-lib) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_TEST}/capnhook/hook/lib) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} capnhook-hooklib cmocka util dl) diff --git a/cmake/src/test/hook/CMakeLists.txt b/cmake/src/test/hook/CMakeLists.txt new file mode 100644 index 0000000..694f307 --- /dev/null +++ b/cmake/src/test/hook/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(propatch) \ No newline at end of file diff --git a/cmake/src/test/hook/propatch/CMakeLists.txt b/cmake/src/test/hook/propatch/CMakeLists.txt new file mode 100644 index 0000000..90b3f52 --- /dev/null +++ b/cmake/src/test/hook/propatch/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(usb-fix) \ No newline at end of file diff --git a/cmake/src/test/hook/propatch/usb-fix/CMakeLists.txt b/cmake/src/test/hook/propatch/usb-fix/CMakeLists.txt new file mode 100644 index 0000000..1ecf120 --- /dev/null +++ b/cmake/src/test/hook/propatch/usb-fix/CMakeLists.txt @@ -0,0 +1,11 @@ +project(test-hook-propatch-usb-fix) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_TEST}/hook/propatch/usb-fix) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} cmocka propatch test-util util) diff --git a/cmake/src/test/test-util/CMakeLists.txt b/cmake/src/test/test-util/CMakeLists.txt new file mode 100644 index 0000000..99a2bc5 --- /dev/null +++ b/cmake/src/test/test-util/CMakeLists.txt @@ -0,0 +1,13 @@ +project(test-util) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_TEST}/test-util) + +set(SOURCE_FILES + ${SRC}/mem.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} cmocka util) diff --git a/cmake/src/test/util/CMakeLists.txt b/cmake/src/test/util/CMakeLists.txt new file mode 100644 index 0000000..2466eca --- /dev/null +++ b/cmake/src/test/util/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(mem) +add_subdirectory(str) \ No newline at end of file diff --git a/cmake/src/test/util/mem/CMakeLists.txt b/cmake/src/test/util/mem/CMakeLists.txt new file mode 100644 index 0000000..44cc750 --- /dev/null +++ b/cmake/src/test/util/mem/CMakeLists.txt @@ -0,0 +1,11 @@ +project(test-util-mem) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_TEST}/util/mem) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} cmocka test-util util) diff --git a/cmake/src/test/util/str/CMakeLists.txt b/cmake/src/test/util/str/CMakeLists.txt new file mode 100644 index 0000000..74ca99d --- /dev/null +++ b/cmake/src/test/util/str/CMakeLists.txt @@ -0,0 +1,11 @@ +project(test-util-str) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_TEST}/util/str) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +target_link_libraries(${PROJECT_NAME} cmocka test-util util) diff --git a/dist/api/ptapi-io-piubtn-stub.c b/dist/api/ptapi-io-piubtn-stub.c new file mode 100644 index 0000000..fc05de7 --- /dev/null +++ b/dist/api/ptapi-io-piubtn-stub.c @@ -0,0 +1,62 @@ +/** + * Example implementation of the piubtn API. This doesn't really implement anything but rather provides a stub file that + * helps anyone to get started with API development/prototyping. + * + * A simple setup for a quick start: + * 1. Ensure that the API folders with the headers are located next to this file, specifically ptapi/io/piubtn.h. + * 2. Compile using: gcc -I. -m32 -shared -fPIC -o ptapi-io-piubtn-stub.so ptapi-io-piubtn-stub.c + * 3. Follow the steps in the readme to configure it for the game of your choice. + */ +#include +#include + +#include "ptapi/io/piubtn.h" + +const char* ptapi_io_piubtn_ident(void) +{ + return "stub"; +} + +bool ptapi_io_piubtn_open(void) +{ + printf("piubtn-stub: ptapi_io_piubtn_open\n"); + + return true; +} + + +void ptapi_io_piubtn_close(void) +{ + printf("piubtn-stub: ptapi_io_piubtn_close\n"); +} + +bool ptapi_io_piubtn_recv(void) +{ + return true; +} + +bool ptapi_io_piubtn_send(void) +{ + return true; +} + +void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* inputs) +{ + // Set all inputs to off + if (player == 0) { + inputs->left = false; + inputs->right = false; + inputs->start = false; + inputs->back = false; + } else { + inputs->left = false; + inputs->right = false; + inputs->start = false; + inputs->back = false; + } +} + +void ptapi_io_piubtn_set_output(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs) +{ + +} \ No newline at end of file diff --git a/dist/api/ptapi-io-piuio-stub.c b/dist/api/ptapi-io-piuio-stub.c new file mode 100644 index 0000000..b25e381 --- /dev/null +++ b/dist/api/ptapi-io-piuio-stub.c @@ -0,0 +1,79 @@ +/** + * Example implementation of the piuio API. This doesn't really implement anything but rather provides a stub file that + * helps anyone to get started with API development/prototyping. + * + * A simple setup for a quick start: + * 1. Ensure that the API folders with the headers are located next to this file, specifically ptapi/io/piuio.h. + * 2. Compile using: gcc -I. -m32 -shared -fPIC -o ptapi-io-piuio-stub.so ptapi-io-piuio-stub.c + * 3. Follow the steps in the readme to configure it for the game of your choice. + */ +#include +#include + +#include "ptapi/io/piuio.h" + +const char* ptapi_io_piuio_ident(void) +{ + return "stub"; +} + +bool ptapi_io_piuio_open(void) +{ + printf("piuio-stub: ptapi_io_piuio_open\n"); + + return true; +} + +void ptapi_io_piuio_close(void) +{ + printf("piuio-stub: ptapi_io_piuio_close\n"); +} + +bool ptapi_io_piuio_recv(void) +{ + return true; +} + +bool ptapi_io_piuio_send(void) +{ + return true; +} + +void ptapi_io_piuio_get_input_pad(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs) +{ + // Set all inputs to off + if (player == 0) { + inputs->lu = false; + inputs->ru = false; + inputs->cn = false; + inputs->ld = false; + inputs->rd = false; + } else { + inputs->lu = false; + inputs->ru = false; + inputs->cn = false; + inputs->ld = false; + inputs->rd = false; + } +} + +void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs) +{ + // Set all inputs to off + inputs->test = false; + inputs->service = false; + inputs->clear = false; + inputs->coin = false; + inputs->coin2 = false; +} + +void ptapi_io_piuio_set_output_pad(uint8_t player, const struct ptapi_io_piuio_pad_outputs* outputs) +{ + +} + +void ptapi_io_piuio_set_output_cab(const struct ptapi_io_piuio_cab_outputs* outputs) +{ + +} \ No newline at end of file diff --git a/dist/conf/exchook.conf b/dist/conf/exchook.conf new file mode 100644 index 0000000..f1b55b9 --- /dev/null +++ b/dist/conf/exchook.conf @@ -0,0 +1,47 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [str]: Version of the game (format YYYYMMDD). Make sure this matches exactly the version you are running because the hook lib has to apply memory patches. +game.version=20040408 + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/f2hook.conf b/dist/conf/f2hook.conf new file mode 100644 index 0000000..1007f99 --- /dev/null +++ b/dist/conf/f2hook.conf @@ -0,0 +1,50 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Address and port of pumpnet server (e.g. 127.0.0.1:1234) +patch.net_profile.server= + +# [int]: Machine id for pumpnet +patch.net_profile.machine_id=0 + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/fexhook.conf b/dist/conf/fexhook.conf new file mode 100644 index 0000000..1007f99 --- /dev/null +++ b/dist/conf/fexhook.conf @@ -0,0 +1,50 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Address and port of pumpnet server (e.g. 127.0.0.1:1234) +patch.net_profile.server= + +# [int]: Machine id for pumpnet +patch.net_profile.machine_id=0 + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/fsthook.conf b/dist/conf/fsthook.conf new file mode 100644 index 0000000..1007f99 --- /dev/null +++ b/dist/conf/fsthook.conf @@ -0,0 +1,50 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Address and port of pumpnet server (e.g. 127.0.0.1:1234) +patch.net_profile.server= + +# [int]: Machine id for pumpnet +patch.net_profile.machine_id=0 + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/mk3hook.conf b/dist/conf/mk3hook.conf new file mode 100644 index 0000000..c65ec22 --- /dev/null +++ b/dist/conf/mk3hook.conf @@ -0,0 +1,62 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [int]: Sync offset in ms +game.sync_offset=115 + +# [double]: Sync multiplier +game.sync_multiplier=4.166667 + +# [double]: Volume of music playback +game.music_vol=1.000000 + +# [double]: Volume of sound effects playback +game.sfx_vol=1.000000 + +# [bool (0/1)]: Enable this option when running 1st or 2nd. This uses different file system redirects for the game directory as well as enables a fix. Without this, the game throws errors about not finding files +game.1st_2nd_fs=0 + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device= + +# [bool (0/1)]: Enable debug output for the fmod library. This requires you to use the fmodexL.so instead of the standard fmodex.so +patch.sound.debug_output=0 + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/nx2hook.conf b/dist/conf/nx2hook.conf new file mode 100644 index 0000000..2c23960 --- /dev/null +++ b/dist/conf/nx2hook.conf @@ -0,0 +1,56 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Address and port of pumpnet server (e.g. 127.0.0.1:1234) +patch.net_profile.server= + +# [int]: Machine id for pumpnet +patch.net_profile.machine_id=0 + +# [bool (0/1/)]: Enable verbose log output for pumpnet related things, e.g. logging network traffic +patch.net_profile.verbose_log_output=0 + +# [str]: Path to a folder containing the client key, certificate and CA bundle to enable https communication +patch.net_profile.cert_dir_path= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/nxahook.conf b/dist/conf/nxahook.conf new file mode 100644 index 0000000..1007f99 --- /dev/null +++ b/dist/conf/nxahook.conf @@ -0,0 +1,50 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Address and port of pumpnet server (e.g. 127.0.0.1:1234) +patch.net_profile.server= + +# [int]: Machine id for pumpnet +patch.net_profile.machine_id=0 + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/nxhook.conf b/dist/conf/nxhook.conf new file mode 100644 index 0000000..2bf1dc3 --- /dev/null +++ b/dist/conf/nxhook.conf @@ -0,0 +1,47 @@ +# [bool (0/1)]: Force unlock the game. Modifies the current and any new PIUNX.INI settings file permanently +game.force_unlock=0 + +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/prihook.conf b/dist/conf/prihook.conf new file mode 100644 index 0000000..dcb224d --- /dev/null +++ b/dist/conf/prihook.conf @@ -0,0 +1,47 @@ +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (PRI) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Address and port of pumpnet server (e.g. 127.0.0.1:1234) +patch.net.server= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=hw:0 + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/pro2hook.conf b/dist/conf/pro2hook.conf new file mode 100644 index 0000000..7242f84 --- /dev/null +++ b/dist/conf/pro2hook.conf @@ -0,0 +1,38 @@ +# [str]: Path to game data (game) folder +game.data=./game + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [str]: Path to library implementing the piubtn api for piubtn emulation +patch.piubtn.emu_lib= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_x11_event_loop.input_handler_lib= + +# [str]: Path to a second library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_x11_event_loop.input_handler_lib2= + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/prohook.conf b/dist/conf/prohook.conf new file mode 100644 index 0000000..17b3602 --- /dev/null +++ b/dist/conf/prohook.conf @@ -0,0 +1,50 @@ +# [str]: Path to game data (game) folder +game.data=./game + +# [str]: Path to game settings (data) folder +game.settings=./save + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [str]: Path to library implementing the piubtn api for piubtn emulation +patch.piubtn.emu_lib= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Bus and port (format: X-X, e.g. 1-2) of the USB slot to assign to Player 1 when a USB thumb drive is plugged in +patch.usb_profile.p1.bus_port= + +# [str]: Bus and port (format: X-X, e.g. 1-2) of the USB slot to assign to Player 2 when a USB thumb drive is plugged in +patch.usb_profile.p2.bus_port= + +# [str]: Device nodes of plugged in USB thumb drives to consider for mounting for usb profiles, format: sdX,sdY e.g. sde,sdf +patch.usb_profile.dev_nodes= + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_x11_event_loop.input_handler_lib= + +# [str]: Path to a second library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_x11_event_loop.input_handler_lib2= + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/x2hook.conf b/dist/conf/x2hook.conf new file mode 100644 index 0000000..65e6777 --- /dev/null +++ b/dist/conf/x2hook.conf @@ -0,0 +1,47 @@ +# [bool (0/1)]: Force unlock the game. Modifies the current and any new PIUEXCEED.INI settings file permanently +game.force_unlock=0 + +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/conf/zerohook.conf b/dist/conf/zerohook.conf new file mode 100644 index 0000000..8bd93de --- /dev/null +++ b/dist/conf/zerohook.conf @@ -0,0 +1,47 @@ +# [bool (0/1)]: Force unlock the game. Modifies the current and any new PIUZERO.INI settings file permanently +game.force_unlock=0 + +# [str]: Path to game settings (SETTINGS) folder +game.settings=./save + +# [bool (0/1)]: Force game into window mode +patch.gfx.windowed=0 + +# [bool (0/1)]: Enable file call monitoring +patch.hook_mon.file=0 + +# [bool (0/1)]: Enable file system related call monitoring +patch.hook_mon.fs=0 + +# [bool (0/1)]: Enable IO syscall monitoring +patch.hook_mon.io=0 + +# [bool (0/1)]: Enable any file/IO open call monitoring +patch.hook_mon.open=0 + +# [bool (0/1)]: Enable libusb call monitoring +patch.hook_mon.usb=0 + +# [bool (0/1)]: Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) +patch.hook_main_loop.disable_built_in_inputs=0 + +# [str]: Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs +patch_hook_main_loop.x11_input_handler= + +# [str]: Path to library implementing the piuio api for piuio emulation +patch.piuio.emu_lib= + +# [bool (0/1)]: Enable game exit on Test + Service +patch.piuio_exit.test_serv=0 + +# [str]: Select the sound device to open on snd_pcm_open +patch.sound.device=dmix + +# [bool (0/1)]: Halt on sigsegv to attach a debugger to the process +patch.sigsegv.halt_on_segv=0 + +# [str]: Print the log output to the specified file +util.log.file=pumptools.log + +# [int]: Set the log level (0-4) +util.log.level=4 diff --git a/dist/piueb b/dist/piueb new file mode 100755 index 0000000..1b1bde1 --- /dev/null +++ b/dist/piueb @@ -0,0 +1,407 @@ +#!/usr/bin/env bash + +### +# Pump It Up Environment Bootstrap (piueb) +# +# This script sets up an environment to run all (MK5/6) Linux based PIU games as well as the MK3 linux ports. +# It takes care of the following tasks: +# - Check if all necessary files and directories are available +# - Verify that local dependencies for the game are used +# - Force the game into VSYNC +# - Bootstrap the application executable with: +# - A a subset of local libs or even a private ld-linux to ensure highest compatibility accross distros +# - A pumptools hook.so +# +# Therefore, this script expects the following folder structure and naming (!) to run the game: +# - game: The game folder with vanilla assets +# - lib: All (additional) dependencies the game needs to run +# - (save): Depending on your hook configuration, this can be located somewhere else, too +# - hook.conf: Configuration file with hook specific settings +# - hook.so: The game specific hook library compiled from pumptools +# - piu: The game's executable +# - piueb: This script +# +# To get usage/help output from piueb: +# ./piueb help +# +# To run the game, simply run this script with the "run" command: +# ./piueb run +# +# Additional arguments to hook.so are also supported: +# ./piueb run arg1 arg2 +# +# For example, to get help/usage output from the hook library: +# ./piueb run -h +# +# For debugging purpose, a log file (piueb.log) is written to the folder this script is in. +### + +readonly VERSION="1.0" + +readonly LOG_LEVEL_ERROR="E" +readonly LOG_LEVEL_WARN="W" +readonly LOG_LEVEL_INFO="I" +readonly LOG_LEVEL_DEBUG="M" + +################################################################################## + +SELF_DIR="$(dirname "$(readlink -f "$0")")" + +LOG_FILE="$SELF_DIR/piueb.log" + +GAME_EXEC="$SELF_DIR/piu" + +GAME_DIR="$SELF_DIR/game" +LIBS_DIR="$SELF_DIR/lib" + +HOOK_FILE="$SELF_DIR/hook.so" +HOOK_CONFIG_FILE="$SELF_DIR/hook.conf" + +LIBS_LINKER="$SELF_DIR/lib/ld-linux.so.2" + +################################################################################## + +log_init() +{ + rm -f "$LOG_FILE" +} + +log() +{ + local level="$1" + local msg="$2" + + local timestamp="$(date "+%Y/%m/%d-%H:%M:%S:%3N")" + + local color="" + + case $level in + $LOG_LEVEL_ERROR) + color="\e[1m\e[31m" + ;; + $LOG_LEVEL_WARN) + color="\e[33m" + ;; + $LOG_LEVEL_INFO) + color="\e[34m" + ;; + $LOG_LEVEL_DEBUG) + color="\e[37m" + ;; + esac + + echo -e "${color}[$level]\e[0m[$timestamp] ${msg}" + echo "[$level][$timestamp] ${msg}" >> "$LOG_FILE" +} + +log_error() +{ + log "$LOG_LEVEL_ERROR" "$@" +} + +log_warn() +{ + log "$LOG_LEVEL_WARN" "$@" +} + +log_info() +{ + log "$LOG_LEVEL_INFO" "$@" +} + +log_debug() +{ + log "$LOG_LEVEL_DEBUG" "$@" +} + +verify_running_as_root() +{ + log_debug "Verify running as root user/with sudo..." + + if [ "$EUID" -ne 0 ]; then + log_error "Running as non-root user, game likely to crash!" + fi +} + +verify_file_exists() +{ + local file_path="$1" + local warn_only="$2" + + log_debug "Verify file/dir exists $file_path..." + + if [ ! -e "$file_path" ]; then + if [ "$warn_only" ]; then + log_warn "Missing file \"$file_path\"" + else + log_error "Missing required file \"$file_path\"" + exit 1 + fi + fi +} + +verify_dir_not_empty() +{ + local dir_path="$1" + + if [ -z "$(ls -A $dir_path)" ]; then + log_error "Directory empty: $dir_path" + exit 1 + fi +} + +verify_deps_all_local() +{ + local exec_path="$1" + local lib_path="$2" + + local ldd_output="$(ldd $exec_path >&1)" + + log_debug "Verify dependencies all local..." + + log_debug "ldd output for $exec_path:\\n$ldd_output" + + while read -r line; do + # Skip any additional output/error messages that are not part of the library listing + if [[ "$line:0:1" != "\t" ]]; then + continue + fi + + local libname="$(echo "$line" | cut -d '.' -f 1)" + local libpath="$(echo "$line" | cut -d ' ' -f 3)" + + # Skip a bunch of libs that are kernel specific like bound to GPU drivers + case $libname in + "linux-gate") ;& # fallthrough + "libGL") ;& # fallthrough + "libGLX") ;& # fallthrough + "libGLdispatch") ;& # fallthrough + # That will still point to the current machine's linker + # but we will use our own further down to bootstrap the elf + "ld-linux") ;& # fallthrough + "/lib/ld-linux") + log_debug "Skipping $libname" + continue + ;; + *) + ;; + esac + + log_debug "Checking $libname: $libpath..." + + if [[ $libpath != $LIBS_DIR* ]]; then + log_warn "$libname is not local to the game, path $libpath" + fi + done <<< "$ldd_output" +} + +verify_game_executable() +{ + local exec_path="$1" + + log_debug "Verifying that game is executable: $exec_path..." + + if [ ! -x "$exec_path" ]; then + log_warn "Game exec $exec_path not executable, fixing..." + chmod +x "$exec_path" + fi +} + +print_usage() +{ + echo "Pump It Up Environment Bootstrap (piueb), version $VERSION" + echo "Easily bootstrap linux based Pump games using pumptools." + echo "Usage: piueb ..." + echo "Commands:" + echo " run - Run the game located next to this script" + echo " strace - Run the game with local libraries and strace attached for debugging" + echo " debug - Run the game with local libraries and a GDB debugger server attached for debugging" + echo " help - Print this usage message" +} + +# Supports native mk6 linux games as well as the mk3 linux ports using mk3hook +cmd_run() +{ + local mode="$1" + + log_init + + log_info "Pump It Up Environment Bootstrap (piueb), version $VERSION" + + verify_running_as_root + + log_info "Current path: $SELF_DIR" + + log_debug "File and path verification..." + + # Some file and folder verfication + + verify_file_exists "$GAME_EXEC" + + verify_file_exists "$GAME_DIR" + verify_dir_not_empty "$GAME_DIR" + verify_file_exists "$LIBS_DIR" + verify_dir_not_empty "$LIBS_DIR" + + verify_file_exists "$HOOK_FILE" + # Only warn to allow creating of default hook.conf if no file exists + verify_file_exists "$HOOK_CONFIG_FILE" 1 + + # Support two modes of setting up the runtime environment with the game's + # dependencies: + # 1. Using a separate linker application which might be necessary when having + # to run the application with different libc (and/or other library) versions. + # This avoids incompatibilities with newer libc runtime and ld-linux versions + # (see f2-crashing-on-modern-linux-post-mortem.md). + # + # 2. Use only a subset of local libraries and take everything else from the + # current system. Your typical LD_LIBRARY_PATH method. + local lib_mode="" + + if [ -e "$LIBS_LINKER" ]; then + lib_mode="ld" + else + lib_mode="local" + fi + + log_info "Resolving dependencies mode: $lib_mode" + + # LD_LIBRARY_PATH setup to use local libraries instead of system ones + + if [ -z "$LD_LIBRARY_PATH" ]; then + LD_LIBRARY_PATH="$LIBS_DIR" + else + LD_LIBRARY_PATH="$LIBS_DIR:$LD_LIBRARY_PATH" + fi + + log_debug "LD_LIBRARY_PATH: $LD_LIBRARY_PATH" + + # Required that ldd shows us the correct paths + export LD_LIBRARY_PATH + + # Check if all dependencies used are actually bundled with the game + verify_deps_all_local "$GAME_EXEC" "$LIBS_DIR" + + local LD_PRELOAD="$HOOK_FILE" + + local ldd_output_hook="$(ldd $HOOK_FILE >&1)" + + log_debug "ldd output for $HOOK_FILE:\\n$ldd_output_hook" + + if [ "${*:1}" ]; then + log_info "Additional cmd arguments provided: ${*:1}" + fi + + log_info "Executing game $GAME_EXEC, mode $mode, lib_mode $lib_mode...\n==============================================================================================================================" + + # Because people forget this when setting up the data manually + chmod +x "$GAME_EXEC" + + # Force the game to run to vsync blank interval for nvidia cards: __GL_SYNC_TO_VBLANK=1 + + if [ "$mode" = "normal" ] && [ "$lib_mode" = "ld" ]; then + # / after GAME_DIR required + # Use private linker to avoid platform incompatibility issues (see above) + exec \ + env __GL_SYNC_TO_VBLANK=1 \ + env LD_PRELOAD="$LD_PRELOAD" \ + "$LIBS_LINKER" \ + --library-path "$LD_LIBRARY_PATH" \ + "$GAME_EXEC" \ + "${GAME_DIR}/" \ + "--options" "$HOOK_CONFIG_FILE" \ + "${@:2}" + elif [ "$mode" = "normal" ] && [ "$lib_mode" = "local" ]; then + # / after GAME_DIR required + exec \ + env __GL_SYNC_TO_VBLANK=1 \ + env LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ + env LD_PRELOAD="$LD_PRELOAD" \ + "$GAME_EXEC" \ + "${GAME_DIR}/" \ + "--options" "$HOOK_CONFIG_FILE" \ + "${@:2}" + elif [ "$mode" = "debug" ] && [ "$lib_mode" = "ld" ]; then + log_error "debug mode with lib type ld not supported" + elif [ "$mode" = "debug" ] && [ "$lib_mode" = "local" ]; then + gdbserver \ + --wrapper \ + env \ + __GL_SYNC_TO_VBLANK=1 \ + LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ + LD_PRELOAD="$LD_PRELOAD" \ + -- 0.0.0.0:1234 \ + "$GAME_EXEC" \ + "${GAME_DIR}/" \ + "--options" "$HOOK_CONFIG_FILE" \ + "${@:2}" + elif [ "$mode" = "strace" ] && [ "$lib_mode" = "ld" ]; then + log_error "strace mode with lib type ld not supported" + elif [ "$mode" = "strace" ] && [ "$lib_mode" = "local" ]; then + strace \ + -E __GL_SYNC_TO_VBLANK=1 \ + -E LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ + -E LD_PRELOAD="$LD_PRELOAD" \ + "$GAME_EXEC" \ + "${GAME_DIR}/" \ + "--options" "$HOOK_CONFIG_FILE" \ + "${@:2}" + elif [ "$mode" = "valgrind" ] && [ "$lib_mode" = "ld" ]; then + log_error "valgrind mode with lib type ld not supported" + elif [ "$mode" = "valgrind" ] && [ "$lib_mode" = "local" ]; then + valgrind \ + --trace-children=yes \ + env \ + __GL_SYNC_TO_VBLANK=1 \ + LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ + LD_PRELOAD="$LD_PRELOAD" \ + "$GAME_EXEC" \ + "${GAME_DIR}/" \ + "--options" "$HOOK_CONFIG_FILE" \ + "${@:2}" + else + log_error "Unsupported mode ($mode) or lib_mode (($lib_mode)" + fi +} + +cmd_help() +{ + print_usage +} + +################################################################################## + +CMD="$1" + +case $CMD in + "") + echo "Insufficient arguments." + print_usage + exit 1 + ;; + "help") + cmd_help + exit 0 + ;; + "run") + cmd_run "normal" "${@:2}" + exit 0 + ;; + "debug") + cmd_run "debug" "${@:2}" + exit 0 + ;; + "strace") + cmd_run "strace" "${@:2}" + exit 0 + ;; + "valgrind") + cmd_run "valgrind" "${@:2}" + exit 0 + ;; + *) + echo "Invalid command." + print_usage + exit 1 + ;; +esac \ No newline at end of file diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..a52e1ac --- /dev/null +++ b/doc/README.md @@ -0,0 +1,10 @@ +# Pumptools documentation +This folder contains all documentation for pumptools in markdown format. + +Index: +* [api](api/api.md): Various documentation about the API, using and configuring the provided API implementations, e.g. +PIUIO, PIUBTN +* [development](development/development.md): Get started with developing for pumptools, development setup, architecture +and notes about various efforts for future reference. +* [game](game/game.md): Information about the games including trivia, pad codes, unlocks etc. +* [hook](hook/hook.md): How to setup and configure pumptools with the games supported. \ No newline at end of file diff --git a/doc/api/api.md b/doc/api/api.md new file mode 100644 index 0000000..ba798dd --- /dev/null +++ b/doc/api/api.md @@ -0,0 +1,8 @@ +# Pumptools API +The *api* sub-folder contains various headers that allow you to develop your own libraries to hook into various places +inside pumptools. + +## IO +* [PIUBTN](io/piubtn.md): The button board introduced with Pump It Up Pro +* [PIUIO](io/piuio.md): Also known as the MK6 IO, the main IO board for pads and lights +* [X11 input hook](io/x11-input-hook.md): Hook input processing to X11 to receive keyboard events \ No newline at end of file diff --git a/doc/api/io/piubtn.md b/doc/api/io/piubtn.md new file mode 100644 index 0000000..b88e24c --- /dev/null +++ b/doc/api/io/piubtn.md @@ -0,0 +1,58 @@ +# PIUBTN API +This contains various PIUBTN related tools and libraries. PIUBTN is the button board that was first introduced with +Pump PRO and officially works as an optional peripheral on all classic pump games starting Fiesta. + +## Pumptools PIUBTN API implementations +The following libraries implement pumptool's PIUBTN API interface. Set the configuration value `patch.piubtn.emu_lib` +in your hook configuration to point to the library you want to use, e.g. +`patch.piubtn.emu_lib=./ptapi-io-piubtn-null.so`. + +### Null: ptapi-io-piubtn-null.so +A null implementation for API dummy testing against libraries/applications calling API implementations. + +### Real PIUIO: ptapi-io-piubtn-real.so +Support for a real USB PIUBTN. This library is not useful for games that already support the hardware natively. +However, games that require an emulation layer need this. + +### Joystick/Gamepad: ptapi-io-piubtn-joystick.so +Support all (USB) Joysticks and Gamepads that are detected by the Linux kernel. This uses the Kernel's joystick API. + +Button mappings are configured by using the `ptapi-io-piubtn-joystick-conf` (this is an executable!) tool. You might +have to `chmod +x ptapi-io-piubtn-joystick-conf` it prior being able to run it: `./ptapi-io-piubtn-joystick-conf`. Run +the tool and follow the instructions. Once successfully completed, a `piubtn-joystick-conf.bin` configuration file is +located in the same folder. This must be located next to the `ptapi-io-piubtn-joystick.so` file which should be located +next to your `piu` executable. + +Configure your `hook.conf` file accordingly: +``` +patch.piubtn.emu_lib=./ptapi-io-piubtn-joystick.so +``` + +### Keyboard: ptapi-io-piubtn-keyboard.so +Support for inputs via your standard keyboard using the X11 API. + +Button mappings are configured by using the `ptapi-io-piubtn-keyboard-conf` (this is an executable!) tool. You might +have to `chmod +x ptapi-io-piubtn-keyboard-conf` it prior being able to run it: `./ptapi-io-piubtn-keyboard-conf`. Run +the tool and follow the instructions. Once successfully completed, a `piubtn-keyboard-conf.bin` configuration file is +located in the same folder. This must be located next to the `ptapi-io-piubtn-keyboard.so` file which should be located +next to your `piu` executable. + +Configure your `hook.conf` file accordingly: +``` +patch.piubtn.emu_lib=./ptapi-io-piubtn-keyboard.so +patch_hook_main_loop.x11_input_handler=./ptapi-io-piubtn-keyboard.so +``` + +Setting the key `patch_hook_main_loop.x11_input_handler` is important. Otherwise, the library does not receive any +input events from X11 and your configured keyboard input does not work in the game. + +## Pumptools PIUBTN API tester: ptapi-io-piubtn-test +The tool *ptapi-io-piubtn-test* lets you easily test and debug your library implementing pumptool's piubtn API without +having to setup and/or run any games. + +## Development +The [piubtn header](../../src/api/ptapi/io/piubtn.h) contains all the prototypes to be implemented by your library to +provide your own implementation for a PIUBTN. Checkout the header file for documentation. + +Checkout the [stub implementation](../../dist/api/ptapi-io-piubtn-stub.c) to get started with a simple example. +Instructions are located in the header comment of the file. \ No newline at end of file diff --git a/doc/api/io/piuio.md b/doc/api/io/piuio.md new file mode 100644 index 0000000..d74bd7b --- /dev/null +++ b/doc/api/io/piuio.md @@ -0,0 +1,57 @@ +# PIUIO API +This contains various MK6 USB PIUIO related tools and libraries. The hardware was first introduced with Exceed 2 and +is supported by all games up to this day. + +## Pumptools PIUIO API implementations +The following libraries implement pumptool's PIUIO API interface. Set the configuration value `patch.piuio.emu_lib` +in your hook configuration to point to the library you want to use, e.g. `patch.piuio.emu_lib=./ptapi-io-piuio-null.so`. + +### Null: ptapi-io-piuio-null.so +A null implementation for API dummy testing against libraries/applications calling API implementations. + +### Real PIUIO: ptapi-io-piuio-real.so +Support for a real USB PIUIO. This library is not useful for games that already support the hardware natively. +However, games that require an emulation layer need this to run on real PIUIO hardware, e.g. Exceed (1). + +### Joystick/Gamepad: ptapi-io-piuio-joystick.so +Support all (USB) Joysticks and Gamepads that are detected by the Linux kernel. This uses the Kernel's joystick API. + +Button mappings are configured by using the `ptapi-io-piuio-joystick-conf` (this is an executable!) tool. You might have +to `chmod +x ptapi-io-piuio-joystick-conf` it prior being able to run it: `./ptapi-io-piuio-joystick-conf`. Run the tool +and follow the instructions. Once successfully completed, a `piuio-joystick-conf.bin` configuration file is located in +the same folder. This must be located next to the `ptapi-io-piuio-joystick.so` file which should be located next to your +`piu` executable. + +Configure your `hook.conf` file accordingly: +``` +patch.piuio.emu_lib=./ptapi-io-piuio-joystick.so +``` + +### Keyboard: ptapi-io-piuio-keyboard.so +Support for inputs via your standard keyboard using the X11 API. + +Button mappings are configured by using the `ptapi-io-piuio-keyboard-conf` (this is an executable!) tool. You might have +to `chmod +x ptapi-io-piuio-keyboard-conf` it prior being able to run it: `./ptapi-io-piuio-keyboard-conf`. Run the tool +and follow the instructions. Once successfully completed, a `piuio-keyboard-conf.bin` configuration file is located in +the same folder. This must be located next to the `ptapi-io-piuio-keyboard.so` file which should be located next to your +`piu` executable. + +Configure your `hook.conf` file accordingly: +``` +patch.piuio.emu_lib=./ptapi-io-piuio-keyboard.so +patch_hook_main_loop.x11_input_handler=./ptapi-io-piuio-keyboard.so +``` + +Setting the key `patch_hook_main_loop.x11_input_handler` is important. Otherwise, the library does not receive any +input events from X11 and your configured keyboard input does not work in the game. + +## Pumptools PIUIO API tester: ptapi-io-piuio-test +The tool *ptapi-io-piuio-test* lets you easily test and debug your library implementing pumptool's piuio API without +having to setup and/or run any games. + +## Development +The [piuio header](../../src/api/ptapi/io/piuio.h) contains all the prototypes to be implemented by your library to +provide your own implementation for a PIUIO. Checkout the header file for documentation. + +Checkout the [stub implementation](../../dist/api/ptapi-io-piuio-stub.c) to get started with a simple example. +Instructions are located in the header comment of the file. \ No newline at end of file diff --git a/doc/api/io/x11-input-hook.md b/doc/api/io/x11-input-hook.md new file mode 100644 index 0000000..20f6a63 --- /dev/null +++ b/doc/api/io/x11-input-hook.md @@ -0,0 +1,9 @@ +# X11 input hook API +The [x11-input-hook header](../../src/api/ptapi/io/x11-input-hook.h) allows you to hook into the main loop of the game +to receive X11 keyboard inputs. This might be useful for implementations of other APIs, e.g. PIUIO, to trigger PIUIO +inputs when pressing keys on the keyboard. + +You have to configure your `hook.conf` accordingly that your implementation gets loaded by the hook library: +``` +patch_hook_main_loop.x11_input_handler=./ptapi-io-my-x11-input-hook.so +``` \ No newline at end of file diff --git a/doc/development/architecture.md b/doc/development/architecture.md new file mode 100644 index 0000000..46c9ba6 --- /dev/null +++ b/doc/development/architecture.md @@ -0,0 +1,43 @@ +# Architecture +The follow image shows a rough outline of pumptools's architecture based on the project's namespacing. Arrows indicate +architectural dependencies. Modules in red colored boxes expose APIs and blue colored boxes expose application/library +binaries. + +![](images/architecture.png) + +## util +The kitchen sink, basically used by everything. Not going to elaborate the details here as it is quite self-explanatory +when taking a look at its modules. + +## crypt +Kitchen sink for everything crypto related. Could be with `util` but I somewhat felt the need to have this separated. + +## asset +Modules for handling various types of asserts from pump games, e.g. usb profiles. + +## pumpnet +Modules to talk to pumpnet for usb profiles over sockets. Used by NX2 to Fiesta 2. + +## sec +Contains several sub-modules for security/dongle related topics such as full software emulation. + +## capnhook +This is the heart of pumptools to enable hooking of system and library calls. `capnhook` has two sub-modules, `hook` +and `hooklib`. `hook` provides the foundation for hooking various things, typically IO related, such as files, +filesystem, hardware IO (e.g. USB), signal handlers. `hooklib` provides helper modules based on `hook` that take care +of common tasks such as path based redirects, USB device emulation and IO call monitoring. + +## ptapi +Pumptools's API package exposing APIs to the end-user. Also contains any libraries and tools used by the APIs. + +## io +Contains modules to talk to real IO hardware, e.g. `piuio`, `piubtn`. + +## patch +`patch` is a common package for various modules that are shared with multiple pump versions. A patch module takes care +of patching, i.e. hooking and detouring usually, a single aspect like fixing a API quirk, enabling window mode etc. + +# game hooks +`game hooks` are composed of multiple `patch` modules making up the final hook library that you preload to the target +application. The structure of each `game hook` is identical and only the patches and hooks applied differ per game +version. diff --git a/doc/development/development.md b/doc/development/development.md new file mode 100644 index 0000000..7a31fbd --- /dev/null +++ b/doc/development/development.md @@ -0,0 +1,163 @@ +# Development +This document covers various aspects of developing for pumptools. For developing using the API, see +[the dedicated readme](../api/api.md). + +## Architecture +[This document](architecture.md) gives an introduction to the architecture of pumptools. This helps you to get familiar +with the codebase and its features, definitely recommended to read this first. + +## Development environment setup +Pumptools is written entirely in C and built using cmake. Various helper scripts are written as bash/shell scripts. +Therefore, you need the following tools on your development setup: +* gcc +* cmake +* make +* bash or compatible shell + +Pumptools requires the following dependencies to be installed on your development OS: +* libcurl4 i386 +* libusb 1.0 i386 + +Furthermore, header files, which come with the development packages of the libs, of the following libraries are +required: +* fmodex +* libconfig +* X11 +* libalsa +* libusb-0.1 (**not** 1.0) + +The project does not depend on any specific IDE. However, if you use CLion, the project can be imported easily. + +## Code style +The main style guidelines are defined by the `.clang-format` file and the code style can be easily applied to the +whole `src` directory using the following command from the root folder: +```shell script +make clang-format +``` + +Make sure that your contributions follow the style and apply it before submitting your changes. + +For other source files like shell scripts, cmake, makefile or markdown documents, please follow the already established +style in the existing documents. + +## Building +See the [main readme](../../README.md#building). + +## Compatibility issues with newer glibc versions +We have experienced various issues with different glibc versions which had a major impact on the builds. The following +table gives you a list of tested glibc versions and issues that are either present or not with each version listed. +"ok" indicates that the specified glibc version is compatible and the specific issue does not occur, "bad" indicates +incompatibility and that the specific issue does occur when using a binary compiled with that glibc version. + +| Issue/glibc version | 2.23 | 2.30 | +|---------------------|------|------| +| Issue 1 | ok | bad | +| Issue 2 | ok | bad | + +The issues are further described in the following sub-sections + +### Issue 1: Crash during static initialization +For a detailed report on this issue, see the [dedicated notes](notes/f2-crashing-on-modern-linux-post-mortem.md). + +Summarized: Fiesta 2 and newer will segfault before even running the application's main method. The application fails +on runtime initialization when initializing the static context. This is caused by ABI incompatibility of inlined code +of C++'s STL, first occurring with string allocations during static initialization. + +### Issue 2: sscanf not being detoured +With NX2, Andamiro locked the USB drives to be used to a specific brand which they sold back then. That lock is patched +out by detouring `sscanf` and manipulating the VID/PID and serial number parsing logic in the game to always return +the values, the game wants to see to accept the connected USB drive. + +However, some incompatibility on newer glibc versions does not setup the `sscanf` detour properly. The detour function +is there and gets called by various parts of the game code in the beginning, but later calls to `sscanf` always go +to the real function instead. Thus, the usb unlock feature does not work. + +## Unit tests +Unfortunately, this was started very late in the development of pumptools, but it's not too late to keep extending this +with every change to ensure existing features don't break and future ones work. + +When you have a change to commit, check if there is an existing unit-test which needs to be aligned with your change(s). +If not, create one. + +For testing code that gets hooked, there is a specific pattern that needs to be applied in order to allow testing +hooks without having to actually hook them. As an example, you can take a look at the +[usb-fix module](../../src/main/hook/propatch/usb-fix.h) for piu pro and the +[corresponding test](../../src/test/hook/propatch/usb-fix/main.c). It shows you how to setup the hooks and create +mocks for the functions that you can trap the calls to the real detoured functions to check if they are getting called +or return fixed values for testing. + +## Debugging +### Pumptool's built-in tooling +Pumptools has a few basic debugging features built in which helps analyzing common issues very quickly without the +need of external tools. + +#### Help and usage message of hook library +When running a game with any of pumptools's `hook.so` libs attached, you can always add the parameter `-h` to display a +help/usage message with all available command line and configuration parameters. + +For example, when using `piueb` for bootstrapping: +``` +./piueb run -h +``` + +The `-h` is passed on as a parameter and appended to the execution command. You can make use of that with other +available cmd parameters as well (see usage information). + +#### Logging +Logging to console and file as well as the level of verbosity can be controlled using the `hook.conf` configuration file +or via command line arguments provided on execution. + +All hooks implement various sanity checks for parameters provided, file checks etc. so there is a good coverage of +common mistakes and misconfiguration that can be easily detected by watching out for any ERROR or WARNING level messages +showing up in the log. + +Example in configuration file: +``` +util.log.file=pumptools.log +util.log.level=4 +``` + +Furthermore, `piueb` outputs a separate log file `piueb.log` which contains logging data of the environment setup +process of `piueb`. + +#### File and IO hook monitoring +In the configuration file or via cmd args, you can enable monitoring of file, filesystem, usb and/or open system calls +for tracing and debugging. This can be useful, to check if the game cannot find certain files like game assets. + +Example in configuration file: +``` +patch.hook_mon.file=0 +patch.hook_mon.fs=0 +patch.hook_mon.io=0 +patch.hook_mon.open=1 +patch.hook_mon.usb=0 +``` + +#### Halt on SIGSEGV and attach debugger +Also enabled via configuration or cmd args, the application is halted on SIGSEGV to allow attaching a debugger. + +Example in configuration file: +``` +patch.sigsegv.halt_on_segv=1 +``` + +### External tooling +#### Remote debugging +You can run the application with `gdbserver` using `piueb`: +```shell script +./piueb debug +``` + +And connect with your favorite debugger (e.g. IDA). + +#### strace +You can run the application with `strace` using `piueb`: +```shell script +./piueb strace +``` + +#### valgrind +You can run the application with `valgrind` using `piueb`: +```shell script +./piueb valgrind +``` \ No newline at end of file diff --git a/doc/development/images/architecture.dia b/doc/development/images/architecture.dia new file mode 100644 index 0000000000000000000000000000000000000000..f0256816df4531bee549b6bd9b2c23004feda815 GIT binary patch literal 2836 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%0DGuP)~N#U{I{_->3w6#%bI@k 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 m<|OwXILE~~tCHa)-}O_qA8)?AJv>YN)Cpr(int a1@, _DWORD *arg_0, _DWORD *songid) +{ + int v3; // eax@1 + int v4; // ecx@1 + signed int v5; // edi@3 + int v6; // eax@6 + signed int v7; // eax@16 + signed int v8; // eax@23 + signed int v9; // eax@30 + signed int v10; // eax@37 + signed int v11; // eax@42 + int v13; // [sp+0h] [bp-18h]@3 + char result_unlocked_song; // [sp+7h] [bp-11h]@1 + + result_unlocked_song = 0; + v3 = sub_8061C62(dword_80BED54, "PLAY"); + v4 = v3 - 200696; + if ( !v3 ) + v4 = 0; + v5 = 0; + v13 = v4; + do + { + if ( v5 ) + { + if ( v5 != 1 ) + goto LABEL_11; + if ( !(dword_80BECD4 & 2) ) + goto LABEL_43; + v6 = sub_8056E76(v13, 1); + } + else + { + if ( !(dword_80BECD4 & 1) ) + goto LABEL_43; + v6 = sub_8056E76(v13, 0); + } + a1 = v6; +LABEL_11: + if ( currentStateCount > 2 + && !stationCurrentlySelected // 0 = arcade station + && *(&songList.trackNum + 18 * sub_8062DC6(dword_80BECE4)) == 0xB13// ill give you all my love + && byte_80BECF5 & 2 + && *(_DWORD *)(a1 + 456) <= 10 ) + { + v7 = GetSongRealIndex(0xB19); // canon-d + *arg_0 = 0; + result_unlocked_song = 1; + *songid = 0xB19; // canon-d + songList.enableMode[72 * v7 + 4] = 0; // +4 mode offset = nightmare + } + if ( currentStateCount == 1 ) + { + if ( stationCurrentlySelected == 1 // 1 = remix station + && *(&songList.trackNum + 18 * sub_8062DC6(dword_80BECDC)) == 0xB31// diva's remix + && *(_DWORD *)(a1 + 400) <= 20 + && !*(_DWORD *)(a1 + 448) + && *(float *)(a1 + 368) >= 1.0 ) + { + v8 = GetSongRealIndex(0xB54); // 2nd hidden remix + *arg_0 = 3; + result_unlocked_song = 1; + *songid = 0xB54; // 2nd hidden remix + songList.enableMode[72 * v8 + 4] = 0; // +4 mode offset = nightmare + } + if ( currentStateCount == 1 ) + { + if ( stationCurrentlySelected == 1 + && *(&songList.trackNum + 18 * sub_8062DC6(dword_80BECDC)) == 0xB30// deux remix + && *(_DWORD *)(a1 + 400) <= 20 + && !*(_DWORD *)(a1 + 448) + && *(float *)(a1 + 368) >= 1.0 ) + { + v9 = GetSongRealIndex(0xB29); // banya classic remix + *arg_0 = 3; + result_unlocked_song = 1; + *songid = 0xB29; // banya classic remix + songList.enableMode[72 * v9 + 4] = 0; // +4 mode offset = nightmare + } + if ( currentStateCount == 1 ) + { + if ( stationCurrentlySelected == 1 + && *(&songList.trackNum + 18 * sub_8062DC6(dword_80BECDC)) == 0xB29// banya classic remix + && *(_DWORD *)(a1 + 400) <= 20 + && !*(_DWORD *)(a1 + 448) + && *(float *)(a1 + 368) >= 1.0 ) + { + v10 = GetSongRealIndex(0xB51); // dignity full remix + *arg_0 = 3; + result_unlocked_song = 1; + *songid = 0xB51; // dignity full remix + songList.enableMode[72 * v10 + 2] = 0;// +2 mode offset = crazy + } + if ( currentStateCount == 1 + && stationCurrentlySelected == 1 + && *(&songList.trackNum + 18 * sub_8062DC6(dword_80BECDC)) == 0xB28// treme vook of the war + && byte_80BECED & 2 ) + { + *(&songList.hiddenSong + 72 * GetSongRealIndex(0xB58)) = 0;// disable this song as a hidden song + v11 = GetSongRealIndex(0xB58); // treme of the vook war another + *arg_0 = 3; + result_unlocked_song = 1; + *(&songList.enableSong + 72 * v11) = 1; + *songid = 0xB58; + } + } + } + } +LABEL_43: + ++v5; + } + while ( v5 <= 1 ); + if ( result_unlocked_song ) + sub_8074CA8(9, 0); + if ( settings->unlocks_maybe[10] == 1 && stationCurrentlySelected == 1 ) + { + *(&songList.hiddenSong + 0x48 * GetSongRealIndex(0xB57)) = 0;// disable this song as a hidden song + *(&songList.enableSong + 0x48 * GetSongRealIndex(0xB57)) = 1; + if ( !result_unlocked_song ) + { + *arg_0 = 3; + *songid = 0xB57; // canon-d full mix + } + result_unlocked_song = 1; + } + return (unsigned __int8)result_unlocked_song; +} +``` \ No newline at end of file diff --git a/doc/development/notes/extract-song-list.md b/doc/development/notes/extract-song-list.md new file mode 100644 index 0000000..d2af521 --- /dev/null +++ b/doc/development/notes/extract-song-list.md @@ -0,0 +1,141 @@ +# Extracting song list from game +## NX2 and NXA +The song list is compiled into the game's executable as a big table with the following structure: +```c +struct SongList_t +{ + int IndexNum; // Index in the song list array + int TrackNum; // Song ID + int szArtistName_kr; // const char* to the null terminated string + int szArtistName_en; // const char* to the null terminated string + int szSongName_kr; // const char* to the null terminated string + int szSongName_en; // const char* to the null terminated string + int BPM; + int ChannelInfo; + int Level[6]; // Array indices correspond to the following and the content is the difficulty level for that mode + // See GetRandomTrack() + // 0 - eStepNormal + // 1 - eStepHard + // 2 - eStepCrazy + // 3 - eStepHalfDouble + // 4 - eStepFreestyle + // 5 - eStepNightmare + bool bEnable_m; + bool bHidden_m; + bool bEnableDemoPlay; // Allow playing in attract mode + bool bCensor; // Don't show song in game (configurable) + bool bPad; + bool bCensorLock; // Permanently censored (not configurable) + bool bEnable_play; + bool bHidden_play; + int TexID; + bool bEnableMode_m[6]; // Modes where this song is allowed + bool bEnableMode_play[6]; + short unknown1; + short time; // Time value used to calculate kcal and VO2 + short SongMileage; // Cost to unlock this song + short ModeMileage[3]; // Mileage required to play this song on the different modes +} __attribute__((packed)); +``` + +Probably the easiest method to locate that table is to find a string that any of the entries points to using your +favorite decompiler. Song names are good candidates as most of them should be unique and easy to locate when your tool +can expose all strings of the binary. Follow any references to the string and you should easily find a chunk of that +that looks like this: +```text +.data:08130FDF db 0 +.data:08130FE0 ; int g_songListWithouBlazeEmotion[] +.data:08130FE0 g_songListWithouBlazeEmotion dd 0F02h ; DATA XREF: HandleSongUnlocksMaybe:loc_806A5B5r +.data:08130FE0 ; HandleSongUnlocksMaybe+26Br ... +.data:08130FE4 dd offset aACn ; "8¥¦ 8ûì " +.data:08130FE8 dd offset aYahpp ; "YAHPP " +.data:08130FEC dd offset aRieX_1 ; "8¦Édà+ X.1 " +.data:08130FF0 dd offset aCannonX_1 ; "Cannon X.1 " +.data:08130FF4 dd offset a185 ; "185 " +.data:08130FF8 dd 0 +.data:08130FFC dd 3 +.data:08131000 dd 0Ah +.data:08131004 dd 14h +.data:08131008 dd 0Dh +.data:0813100C dd 16h +.data:08131010 db 1 +.data:08131011 db 1 +.data:08131012 db 0 +.data:08131013 db 1 +.data:08131014 db 0 +.data:08131015 db 1 +.data:08131016 db 0 +.data:08131017 db 0 +.data:08131018 dd 0FFFFFFFFh +.data:0813101C db 1 +.data:0813101D db 1 +.data:0813101E db 1 +.data:0813101F db 1 +.data:08131020 db 1 +.data:08131021 db 0 +.data:08131022 db 0 +.data:08131023 db 0 +.data:08131024 db 0 +.data:08131025 db 0 +.data:08131026 db 0 +.data:08131027 db 0 +.data:08131028 dw 79h +.data:0813102A dw 0 +.data:0813102C dw 0 +.data:0813102E dw 0 +.data:08131030 dw 0 +.data:08131032 dw 0 +.data:08131034 dw 0 +.data:08131036 dw 0 +.data:08131038 dw 2 +.data:0813103A dw 0 +.data:0813103C dd 0F03h +``` + +Find the beginning by going backwards and checking where the first valid entry with pointers to artist, title etc +start. Usually, the first entry is also the primary reference for the game to address the song list. + +This should allow you to find the function `GetSongRealIndex`. From there, you can easily find out the total length +of the song list. +```c +int __cdecl GetSongRealIndex(int songNo) +{ + signed int v1; // ebx@1 + int v2; // ecx@2 + int v3; // edx@3 + int v4; // eax@4 + + v1 = GetTotalTrackNum(); // 324 + if ( v1 <= 0 ) + return -1; + v2 = 0; + if ( g_songIdBlazingEmotion[0] != songNo ) + { + v2 = 0; + v3 = 0; + while ( 1 ) + { + ++v2; + if ( v2 == v1 ) + break; + v4 = g_songListWithouBlazeEmotion[v3]; + v3 += 23; + if ( v4 == songNo ) + return *(&g_songList[0].TrackNum + 23 * v2); + } + return -1; + } + return *(&g_songList[0].TrackNum + 23 * v2); +} +``` + +With that info, you can dump the list straight from the binary, e.g. using `dd`: +```shell script +dd if=./piu bs=1 skip=954240 count=31200 of=songlist.bin +``` + +Requires you to manually calculate the size by using the above struct as reference. + +Note: This part does not cover the dumping of the referenced strings to build a full song list. This process was mainly +used to get a song index mapping table for mapping absolute indices of the song table array to the song IDs and vice +versa (for pumpnet). \ No newline at end of file diff --git a/doc/development/notes/f2-crashing-on-modern-linux-post-mortem.md b/doc/development/notes/f2-crashing-on-modern-linux-post-mortem.md new file mode 100644 index 0000000..1562f4f --- /dev/null +++ b/doc/development/notes/f2-crashing-on-modern-linux-post-mortem.md @@ -0,0 +1,255 @@ +# Post mortem: Fiesta 2 crashing on modern linux +Date of writing: 17th November 2019 + +This is a port mortem about an issue that was puzzling me for months. In the following sections, I am documenting the +whole story as detailed as possible hoping this is going to be useful for anyone else (or even myself) in the future. + +## What happened? +I have been running a multidisk setup with all pump games on it for a few years now and have been maintaining and +improving pumptools in the process. I always kept things quite up to date because once you need some more tooling +even on something like a dedicated machine, updating the system after it has not been updated for months or years +becomes very difficult. Furthermore, things might stop working that have worked before because of one or even multiple +issues that got introduced with the update. + +Anyway, my cabinet with the multidisk setup yields the following on `uname -a`: +`Linux piumd 4.15.11-1-ARCH #1 SMP PREEMPT Mon Mar 19 18:21:03 UTC 2018 x86_64 GNU/Linux` + +My workstation is a bit more up-to-date with (though, I am behind a few months...): +`Linux ambient 5.2.3-arch1-1-ARCH #1 SMP PREEMPT Fri Jul 26 08:13:47 UTC 2019 x86_64 GNU/Linux` + +In the past, like more than a year ago, my workstation was also running a newer kernel, version of runtime libraries +etc. but running Fiesta 2 and newer with pumptools wasn't an issue. However, Fiesta 2 and newer stopped working when +I was continuing with my development efforts and just crashed with a segmentation fault. All old versions prior +Fiesta 2 were still working perfectly fine. + +## Error analysis: first information and debugging steps +First, I enabled f2hooks built in logging to yield more output `util.log.level=4` and enabled halting on crashes to +be able to attach a debugger `patch.sigsegv.halt_on_segv=1`. This is the output I got: +``` +[I][f2hook][main.c:155]: Hooking finished +[M][f2hook][main.c:168]: Calling orig_init +[E][patch-sigsegv][sigsegv.c:18]: =================== +[E][patch-sigsegv][sigsegv.c:19]: !!!!! SIGSEGV !!!!! +[E][patch-sigsegv][sigsegv.c:28]: Backtrace (3 frames): +[E][patch-sigsegv][sigsegv.c:31]: ./f2hook.so(+0x6a02) [0xf7e20a02] +[E][patch-sigsegv][sigsegv.c:31]: ./f2hook.so(+0xf827) [0xf7e29827] +[E][patch-sigsegv][sigsegv.c:31]: linux-gate.so.1(__kernel_sigreturn+0) [0xf7f07940] +[E][patch-sigsegv][sigsegv.c:37]: Halting for debugger... +``` + +Ok, so it seems like something crashed in f2hook.so. However, hooking up the debugger did not yield anything useful +and this was just pointing to the sigsegv handler (thought it worked with debugging other issues and actually pointed +to the location where it crashed...strange). + +Next, I started removing stuff from f2hook to get a minimal version which still boots up to that point, no changes. + +Then, I hooked up gdb, set a breakpoint before the crash happened and stepped my way through the whole libc +runtime setup. I figured out, that the crash happens when the libc runtime is calling handler functions of the +target application which setup various parts of the runtime environment, like static initialization. + +And this is the place where the crash happened. There is one function in the piu executable which setups up all static +variables, for example constructing static strings or other objects. Once it tried to construct the first static string +of that static setup function, it crashed. To be more precise, it crashed in the string constructor when allocating +memory for the string. + +Great, we found the root cause for that. Let's figure out why that happens and what's different now that it crashes +there. + +## Tracing the bug down to libstdc++ and being totally mislead by various things +Because there have been issues with incompatible libc/libcstd++ versions previously, I quickly came to the idea of +comparing the version that worked on my cabinet and the version that did not work on my workstation. Indeed, these +were different versions (considering the age gap of the two OSes, that wasn't very surprising). + +I started digging into the libstdc++ source code, especially looking at what is going on when strings are allocated. +Navigating the libstdc++ source is not a nice task. The naming is very confusing and, imo, non intuitive. With +templating all over the place, this makes it even worse. + +Finally, I found something that sounded very related to what I have discovered so far: +In the file include/bits/basic_string.h, search for +``` +_GLIBCXX_RESOLVE_LIB_DEFECTS +3076. basic_string CTAD ambiguity +``` + +and you will end up at a string constructor call. From that, I concluded that something was fixed related to +constructor calls. I compared the string allocation call of both versions, the non working and working ones. The +allocation for strings has changed. + +Going back to the location of the crash in the piu executable, I saw that the string allocation was even inlined and +not going to a library call of...boost filesystem. The first static object created is the path "../" which is used by +a path object by boost filesystem. Because boost filesystem is a header only library, I assume that's why this got +inlined. + +However, I was using the libstdc++ version of my local machine where the string allocation scheme was different. This +still did not truly explain why it crashed there with a jump to address 0, but things aligned pretty well so far. + +So, the first idea for a solution was to use the old libstdc++ version from the machine where everything was fine +and working. However, using it did not change anything. I went on and grabbed more libraries from the machine until +I had all of them on my workstation and hooked them up with a `LD_LIBRARY_PATH`. But now, the application did crash +very early and did not even get to setting up the runtime at all. I did some poking but could not figure out what +was happening there. It just crashed with another jump to 0 very early in launching the elf. + +Debugging continued for a bunch of weeks, on and off. I got more focused on digging deeper into the string allocation +thing as this was giving me a direction and was aligning with my findings so far. I came up with a "solution" to hook +and overwrite the string constructor calls of the newer libstdc++ version. + +I started replacing them one by one to re-implement the old allocation scheme. However, this was not enough as many +function calls that are working with string objects rely on the used allocation scheme, too. Therefore, I also started +patching these until I realized that I have to re-implement, at least, everything basic_string related. + +At that point, I was quite sure that this is the wrong way to go and stopped with this approach. + +A few more months passed, I got back at this multiple times but couldn't come up with another solution or even +direction. + +## AppImage +In a talk with a buddy, I had the idea of using some sort of sandboxing or environment boxing to pack things up nicely +into a single blob to make it easier to handle, even distributable and maybe even more platform independent. + +After some internet research, I found a solution that looked like it fits the pump game use-case very well which was +AppImage. AppImage packs all your stuff into a single binary blob which is basically just a sqash fs image with a +special runtime bootstrapping the whole image and running a bash script once the image is mounted. The provided features +are very minimalistic but solve all our needs for packing pump games nicely. + +The reference documentation also pointed out a few things about packing runtime libraries and how to set them up using +`LD_LIBRARY_PATH` which I was already doing but just using a naked bash script. However, this reading was starting to +point me into the right direction. + +## Providing a platform/distro independent environment for your application down to the linker +I started playing around with the libraries I used for Fiesta 2. First, I grabbed _all_ libraries from my cabinet which +are required to run the game (using `ldd`). Then I started trying different combinations of including them using +`LD_LIBRARY_PATH` and some used by my native system. Nope, either I was running into the static init crashing issue +or things crashed even earlier on. + +Wait, have I ever looked into why the application crashed so early, even before spinning up the runtime environment? +After working on this on and off for months and totally losing track by getting to deep into this libstdc++ thing, I +realized I didn't. + +I set up the application to use all libraries from my cabinet and started debugging. First, I tried my luck with `gdb` +but didn't get very far as it just showed me a jump to 0, again. Next, I got pointed out to using `valgrind`. This was +a great hint as valgrind hooks into the bootstrapping process of the application and even displays a lot of information +about library loading and setting up the environment even way before the runtime is set up. Recommendation: Use +`valgrind -v -v -v` to get a lot of output. + +However, in the end, valgrind also just pointed out the jump to 0 being the reason for the crash but not why this +happened. The additional information was good to figure out the steps happening in the application setup process but +did not yield any additional insights. + +After giving this some more thought and making sure I used all runtime libraries from the cabinet, I did some +internet research again and tried go get more information on how ELFs are bootstrapped and what happens. It turned out +that information on that topic very sparse and difficult to find. However, this brought me to the following thread +from the gnu mailing list: +``` +Hi all; + +I have a need to use a different runtime linker (ld-linux.so) for some +of my applications. I _don't_ want to change the executables themselves +(changing the path to the runtime linker in the ELF image for example). + +I know that I can just run my application as an argument to ld-linux.so, +and that actually does work very well. But, I am left with two +problems: + + * Some of my applications fork/exec other programs, and those other + programs also need to use the other runtime linker. Just as I don't + want to change the ELF image, I certainly don't want to have to + recompile the programs to exec the runtime linker! + + * Debugging: I can't debug because I can't find a way to convince GDB + to invoke the program-to-be-debugged using an alternative runtime + linker. + +I was wondering if anyone has any ideas about how to do this? I checked +the man pages and didn't see anything (I was looking for something like +an environment variable that ld-linux.so might obey to re-exec a +different version, or some such thing--not likely, I know). + +If there's nothing like that available another idea is to use LD_PRELOAD +to install a private version of the execve() system call, which would +set the alternative ld-linux.so as the first argument. Any thoughts on +this approach? Do you think it would solve the GDB problem as well? +I'm going to proceed to work on this idea but I wanted to see if anyone +had other thoughts about it. + + + +PS. In case anyone's curious, I'm trying to run some programs natively + on my desktop system which were actually compiled for a different + system, and the native and target systems have different versions of + glibc installed. I can't change either of the versions of glibc, + but I do have the complete root filesystem of the target box in a + subdirectory of my native box and I can use LD_LIBRARY_PATH, etc. to + use them... I just need a way to get the runtime environment to + initialize properly. + +-- +------------------------------------------------------------------------------- + Paul D. Smith HASMAT--HA Software Mthds & Tools + "Please remain calm...I may be mad, but I am a professional." --Mad Scientist +------------------------------------------------------------------------------- + These are my opinions---Nortel Networks takes no responsibility for them. +``` + +Source: https://lists.gnu.org/archive/html/help-gnu-utils/2004-06/msg00020.html + +Oh, wow. I was amazed that someone else was having a very similar use-case of running applications from legacy systems +on a newer machine with different library versions and conflicts. + +Reading on, this answer was finally revealing the last piece of the puzzle to understand the issue I was facing with +Fiesta 2: +``` +If you have an old a.elf main executable program that was linked +to run with libc.so.6, and you want to run that a.elf on a machine +whose libc.so.6 differs from the one which a.elf was linked against, +and you want a reasonable guarantee that it will work, then it may +be necessary to use something like rtldi to choose the matching +ld-linux.so.2 and libc.so.6 and other libraries as of the time of +static binding of a.elf. In theory, libc.so.6 is backwards compatibile +(a given a.elf should run the same under any subsequent libc.so.6), +but in practice there have been too many bugs in {ld-linux.so.2, +libc.so.6, ...}. For example, many programs linked for libc.so.6 +under RedHat Linux 7.2 and earlier won't run under glibc-2.3.2. +The most effective way to run such a program may be to install the +old glibc-x.y.z[.rpm] in a different location, binary edit the PT_INTERP +string of the a.elf, and use rtldi. This makes the old [edited] a.elf +simultaneously interoperable with other programs from different +libc.so.6 generations, and only the "oddball" program has to know. + +... + +ld-linux.so.2, libc.so.6, libdl.so, libnss*.so, and _many_ other shared +libraries of a given released version, are a matched set. They must be +used together, all from the same release, or not at all. Mixing and +matching pieces from different glibc-x.y.z need not work. In order to +use a consistent set that differs from the default set, you must invoke +the ld-linux.so.2 using "--library-path PATH" to specify the location +of the rest of the set. Using --library-path supersedes LD_LIBRARY_PATH +for one execve() only, and does not interfere with chilren, execve() +with no fork(), or other processes. +``` + +Oh, I was not aware about ld-linux.so being THAT important to this set of libc.sp, libdl.so etc. Therefore, I grabbed +the ld-linux.so file from my cabinet and ran the application with all libraries (except the GPU driver specific ones) +on my workstation like this: +``` +LD_PRELOAD="./f2hook.so" ./ld-linux.so.2 --library-path ./lib ./piu ./game/ --options ./hook.conf +``` + +And the application starts up, passes runtime initializing, hits main and the game works. + +I don't think there is anything else to add to the copy-pasted explanations above. Make sure to read them carefully to +understand the whole issue. Once you know what is going on, the whole thing is not even super complex. + +## Conclusions +I would consider this being one of the major issues I have resolved so far for pumptools as this was so misleading, +difficult to debug and find any general information on. The reason behind that and the solution are super simple, once +you know them. + +As we have already discussed various times in the past, this issue further points out how important proper solutions +for sandboxing, containerizing or how you want to call it for legacy applications like pump games are. The naked +bash script setting up everything is already quite good and doing the job. AppImage further enhances this by making +the whole application more portable. + +However, understanding the whole process behind ELF loading, library linking, setting up the process environment and +setting up the runtime environment is very important. Otherwise, rather simple incompatibilities are the result which +have a major impact on running the application. \ No newline at end of file diff --git a/doc/development/notes/hardware.md b/doc/development/notes/hardware.md new file mode 100644 index 0000000..6e453eb --- /dev/null +++ b/doc/development/notes/hardware.md @@ -0,0 +1,107 @@ +# Hardware used by Pump It Up Games +## Main PC/CPU hardware +### MK 1 +We have not seen this piece of hardware and the chances these boards still exist and are sold somewhere is rather low. +However, there are pointers in the code of the game and the evolution of the hardware that it existed for the first +few versions of PIU: +* Songs were played back entirely from CD requiring to store them as 16-bit PCM audio. Therefore, the hardware did not +have a chip for decoding MP3. +* Absence of hardware security/lockchip. + +We assume that this hardware was shipped and used with 1st, 2nd and 3rd. Starting 3rd SE, song files were stored as +encoded MP3 files on the CD requiring a MP3 decoder available with [MK3 hardware](###MK 3). + +### MK 3 +All games from 1st to Prex3/Premiere 3 are running on this revision of hardware. 1st to 3rd are compatible with this +hardware. + +System configuration dump using PC-DOCTOR DOS 3.0 +``` +SYSTEM CONFIGURATION===================================================== + + Operating System - DOS 7.10 in HMA + CPU Type - 333 MHz Intel Celeron 333 + CPUID - "GenuineIntel", Family 6, Model 6, Step 5 + - MMX available + Coprocessor Type - 686 + Expansion Bus Type - ISA, PCI + ROM BIOS Date - 04/20/99 + ROM BIOS Copyright - COPYRIGHT Award Software Inc. + Additional ROM - C800[8kB] + Base Memory - 640 kB + Expanded Memory - N/A + Extended Memory - 64512 kB (CMOS Configuration) + XMS Memory - 62400 kB (XMS 3.00, Driver 3.95) A20=ON + Serial Ports - None Installed + Parallel Ports - None Installed + Video Adapter - VGA: 3Dfx Interactive, Inc. + - Total Memory : 8192 kB + Fixed Disk Drives - 42 MB + Floppy Disk Drives - 1 - 1=3.5"/1.44M + Mouse - No Mouse + Joysticks - None + Sound Card - N/A + CAS Fax/Modem Card - N/A + Disk Compression - N/A +CD-ROM Driver Version - MSCDEX V2.25, Drive: D: + Disk Cache - Smartdrive 5.02, Hits 76%, Size 2048 kB + Primary IDE Master - ATAPI: HL-DT-STDVD-ROM GDR8164B + Primary IDE Slave - IDE: QUANTUM FIREBALL_TM1280A, S/N:692708422782 + Secondary IDE Master - No Drive + Secondary IDE Slave - No Drive + SCSI - N/A + Network - N/A + Power Management - APM V1.2, Power On + USB Port - Installed on IRQ 10 + Chipset Type - Intel 440BX + L2 Cache Type - 128 kB + DRAM Row 0 - 64 MB + DRAM Row 1 - Empty + DRAM Row 2 - Empty + DRAM Row 3 - Empty + DRAM Row 4 - Empty + DRAM Row 5 - Empty + DRAM Row 6 - Empty + DRAM Row 7 - Empty + + +PC-DOCTOR DOS 3.0 Copyr 2004 PC-Doctor, Inc. 16:15 9/25/2000 +``` + +A bunch of custom chips for handling the following: +* Sound + * YAMAHA YMZ280B-F (8-Channel PCM/ADPCM Decoder) + * 16-bit PCM sound effects are played from external memory + * YAMAHA YAC516 (Delta Sigma Modulation D/A Converter with 8 times Over-sampling Filter) + * MICRONAS DAC3550A C2 (Stereo Audio DAC) + * MICRONAS MAS3507D F10 (MPEG 1/2 Layer 2/3 Audio Decoder) + * Songs are stored MP3 encoded + +### MK 5 + +### MK 6 + +### MK 7 + +### MK 9 + +### MK X + +## IO hardware +### ISA PIUIO + +### USB PIUIO + +### USB PIUIO 2 + +### PIUBTN + +### XX Card reader + +## Security +### Lockchip + +### USB dongles + +### ds1963s +Used for Pro 1/2 (and ITG 1/2). \ No newline at end of file diff --git a/doc/development/notes/nx2-usb-profile-loading-saving.md b/doc/development/notes/nx2-usb-profile-loading-saving.md new file mode 100644 index 0000000..4a57100 --- /dev/null +++ b/doc/development/notes/nx2-usb-profile-loading-saving.md @@ -0,0 +1,141 @@ +# Notes about how NX2 handles saving and loading usb profile data +Executable of v1.54. + +This document outlines the relevant parts regarding how NX2 loads and stores profiles and how this had an impact on the +design of the patch module `net-profile`, that hooks up usb profile loading over socket to a remote server. + +## Syscall flow +The game calls the following system calls in order per player, here player 1 (id 0), when loading usb profile data +(assume all calls are successful here): +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +fread(fd_save) // stats area +fread(fd_save) // encrypted area +fclose(fd_save) + +fopen("/mnt/0/nx2rank.bin") +fread(fd_rank) // encrypted area +fclose(fd_rank) +``` + +For saving the profile, this is the call flow: +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +fseek(fd_save) // beginning +fwrite(fd_save) // stats area +fwrite(fd_save) // encrypted area +fclose(fd_save) + +fopen("/mnt/0/nx2rank.bin") +fseek(fd_rank) // beginning +fwrite(fd_rank) // encrypted area +fclose(fd_rank) +``` + +We can see that in both scenarios, for loading and saving, the game first takes care of a single file before moving on +to the next one. + +There is another flow that is slightly different when playing World Max. After playing a song in World Max, the game +writes the changes of the `nx2save.bin` file back: +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +fseek(fd_save) // beginning +fwrite(fd_save) // stats area +fwrite(fd_save) // encrypted area +fclose(fd_save) +``` + +## Pumpnet RPCs +The above set the requirements for how pumpnet needs to handle file loading and storing. + +### First solution +The initial solution was combining the loading and storing process of both files, `nx2save.bin` and `nx2rank.bin` +into a single download/upload call. + +Load phase: +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +pumpnet_download_profiles() +fread(fd_save) // read from buffered data +fread(fd_save) // read from buffered data +fclose(fd_save) + +fopen("/mnt/0/nx2rank.bin") // skip, data already buffered +fread(fd_rank) // read from buffered data +fclose(fd_rank) // clear all buffers and reset internal state +``` + +Save phase: +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +pumpnet_download_profiles() +fseek(fd_save) // seek for buffers +fwrite(fd_save) // write to buffers +fwrite(fd_save) // write to buffers +fclose(fd_save) // skip, do nothing + +fopen("/mnt/0/nx2rank.bin") // skip, data already buffered +fseek(fd_rank) // seek for buffers +fwrite(fd_rank) // write to buffers +pumpnet_upload_profiles() +fclose(fd_rank) // clear all buffers and reset internal state +``` + +However, with the additional flow during World Max, this solution didn't work and broke internal state handling. +Modifying this solution to incorporate saving just the `nx2save.bin` file wasn't feasible with the above architecture. + +### Second solution +Therefore, the pumpnet backend was re-designed to operate on on a single file level and separate for saving and +loading. + +Load phase: +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +pumpnet_download_save() +fread(fd_save) // read from buffered data +fread(fd_save) // read from buffered data +fclose(fd_save) +pumpnet_clear_save_cache() + +fopen("/mnt/0/nx2rank.bin") +pumpnet_download_rank() +fread(fd_rank) // read from buffered data +fclose(fd_rank) +pumpnet_clear_rank_cache() +``` + +Save phase: +```c +// Simplified pseudo-like C code omitting non relevant parameters +fopen("/mnt/0/nx2save.bin") +pumpnet_download_save() +fseek(fd_save) // seek for buffers +fwrite(fd_save) // write to buffers +fwrite(fd_save) // write to buffers +fclose(fd_save) +pumpnet_upload_save() +pumpnet_clear_save_cache() + +fopen("/mnt/0/nx2rank.bin") +fseek(fd_rank) // seek for buffers +fwrite(fd_rank) // write to buffers +fclose(fd_rank) +pumpnet_upload_rank() +pumpnet_clear_rank_cache() +``` + +Buffer modifications are detected when `fwrite` is called and flagged accordingly that the module is aware of having +to write back dirty data on the call to `fclose`. + +State handling is also simplified as it only needs to be taken care of on a file level between `fopen` and `fclose` +calls and not on a multi-file level. + +This solution is definitely more robust and flexible than the previous one that operated on a full profile level. +However, the call overhead to the remote server is four times higher compared to the previous solution. Considering +that these calls are not being issued on a high frequency, server load is unlikely to be an issue. \ No newline at end of file diff --git a/doc/development/notes/pad-command-codes-notes.md b/doc/development/notes/pad-command-codes-notes.md new file mode 100644 index 0000000..60694b0 --- /dev/null +++ b/doc/development/notes/pad-command-codes-notes.md @@ -0,0 +1,448 @@ +# Pad command codes notes +Raw data and notes about pad command codes which were extracted directly from the games because I could not find a +complete and 100% accurate list per game. + +All codes extracted from the MK3 games are based on the Linux port executables. + +How did I find these? I used the `ac_sound_play_effect` with the second parameter set to the value `3` as my entry +point. This plays the sound effect that you can hear when you entered the modifier code correctly. After I have found +the right call, it's next to some code like this (taken from 03_3rd): +``` +... + if ( modFlags & 1 ) + { + if ( modFlagsSpeed1P & 1 ) + result = func_2a2dc(0, 1); + if ( modFlagsSpeed1P & 2 ) + result = func_2a2dc(0, 2); + if ( modFlagsSpeed1P & 4 ) + result = func_2a2dc(0, 4); + if ( modFlagsSpeed1P & 8 ) + result = func_2a2dc(0, 8); + if ( modFlagsSpeed1P & 0x10 ) + result = func_2a2dc(0, 16); + } + if ( modFlags & 2 ) + { + if ( modFlagsSpeed2P & 1 ) + result = func_2a2dc(1, 1); + if ( modFlagsSpeed2P & 2 ) + result = func_2a2dc(1, 2); + if ( modFlagsSpeed2P & 4 ) + result = func_2a2dc(1, 4); + if ( modFlagsSpeed2P & 8 ) + result = func_2a2dc(1, 8); + if ( modFlagsSpeed2P & 0x10 ) + result = func_2a2dc(1, 16); + } + if ( modFlagsSpeed1P & 0x1F ) + { + checkIfModifierSet2(); + result = ac_sound_play_effect(0, 3u, 2u); + } + if ( modFlagsSpeed2P & 0x1F ) + { + checkIfModifierSet(); + result = ac_sound_play_effect(0, 3u, 2u); + } + return result; +} +``` + +I already renamed the function that is called prior the `ac_sound_play_effect` to `checkIfModifierSet` here. That +function checks the last eight pad inputs from a list against a list of command codes. Once a code matches, flags are +set accordingly. + +Excerpt, again from 03_3rd: +``` +signed int checkIfModifierSet() +{ + const char *v0; // edx@1 + int v1; // ebp@1 + signed int v2; // ebx@1 + const char *v3; // edx@19 + unsigned int v4; // ebx@19 + signed int result; // eax@41 + signed int v6; // [sp+0h] [bp-1Ch]@1 + + v0 = (const char *)&codeList; // THIS is the code list + v1 = *(_DWORD *)&modFlags; + v2 = 0; + v6 = *(_DWORD *)&data_3299a4; + while ( memcmp((const char *)&data_44e9e8, v0, 8) )// iterate command list and currently post 8 inputs + { + ++v2; + v0 += 8; // each modifier code is 8 commands + if ( v2 >= 13 ) // beyond command list size + goto jump_2a17f; + } + switch ( v2 ) // found command id + { + case 0: + *(_DWORD *)&data_3299a4 = 0; + *(_DWORD *)&modFlags = *(_WORD *)&modFlags & 0xFFF; + break; +``` + +## 03_3rd +``` +1 = DL +2 = DR +4 = C +8 = UL +16 = UR + +-- cancel +.data:0810833A db 4 +.data:0810833B db 4 +.data:0810833C db 4 +.data:0810833D db 4 + +.data:0810833E db 4 +.data:0810833F db 4 +.data:08108340 db 4 +.data:08108341 db 4 +--------------------------- vanish +.data:08108342 db 4 center +.data:08108343 db 4 center +.data:08108344 db 10h up right +.data:08108345 db 8 up left +.data:08108346 db 4 center +.data:08108347 db 2 down right +.data:08108348 db 1 down left +.data:08108349 db 4 center +----------------- mirror +.data:0810834A db 4 +.data:0810834B db 4 +.data:0810834C db 1 +.data:0810834D db 4 +.data:0810834E db 10h +.data:0810834F db 2 +.data:08108350 db 4 +.data:08108351 db 8 +---- 8X +.data:08108352 db 4 +.data:08108353 db 4 +.data:08108354 db 1 +.data:08108355 db 4 +.data:08108356 db 2 +.data:08108357 db 4 +.data:08108358 db 4 +.data:08108359 db 4 +- 4 X +.data:0810835A db 4 +.data:0810835B db 4 +.data:0810835C db 2 +.data:0810835D db 4 +.data:0810835E db 4 +.data:0810835F db 8 +.data:08108360 db 4 +.data:08108361 db 4 +2X +.data:08108362 db 4 +.data:08108363 db 4 +.data:08108364 db 8 +.data:08108365 db 4 +.data:08108366 db 4 +.data:08108367 db 4 +.data:08108368 db 10h +.data:08108369 db 4 +random step +.data:0810836A db 4 +.data:0810836B db 1 +.data:0810836C db 4 +.data:0810836D db 2 +.data:0810836E db 4 +.data:0810836F db 10h +.data:08108370 db 4 +.data:08108371 db 8 +nonstep +.data:08108372 db 8 +.data:08108373 db 10h +.data:08108374 db 4 +.data:08108375 db 8 +.data:08108376 db 10h +.data:08108377 db 4 +.data:08108378 db 8 +.data:08108379 db 10h +synchro +.data:0810837A db 4 +.data:0810837B db 4 +.data:0810837C db 8 +.data:0810837D db 10h +.data:0810837E db 8 +.data:0810837F db 10h +.data:08108380 db 4 +.data:08108381 db 4 +couple +.data:08108382 db 4 +.data:08108383 db 4 +.data:08108384 db 10h +.data:08108385 db 8 +.data:08108386 db 10h +.data:08108387 db 8 +.data:08108388 db 4 +.data:08108389 db 4 +union +.data:0810838A db 1 +.data:0810838B db 2 +.data:0810838C db 4 +.data:0810838D db 8 +.data:0810838E db 2 +.data:0810838F db 1 +.data:08108390 db 4 +.data:08108391 db 10h +random vanish +.data:08108392 db 8 +.data:08108393 db 10h +.data:08108394 db 4 +.data:08108395 db 1 +.data:08108396 db 2 +.data:08108397 db 4 +.data:08108398 db 8 +.data:08108399 db 10h +random speed +.data:0810839A db 8 +.data:0810839B db 10h +.data:0810839C db 2 +.data:0810839D db 4 +.data:0810839E db 1 +.data:0810839F db 4 +.data:081083A0 db 2 +.data:081083A1 db 1 + +``` + +Looking further into the code, there seems to be another command list with three entries right after that and it's +checked in the same function. This time, the number of inputs are 10 instead of 8: +``` + v3 = (const char *)&data_108d84; // THIS is the code list + v4 = 0; + while ( memcmp(data_44e9f8, v3, 10) ) + { + ++v4; + v3 += 10; + if ( (signed int)v4 >= 3 ) + goto jump_2a289; + } + if ( v4 < 1 ) + { + if ( !v4 && data_44ea30 == 2 ) + data_108bad |= 0x80u; + } + else if ( v4 <= 1 ) + { + if ( data_108bad & 4 ) + { + *(_WORD *)&modFlags |= 0x820u; + qmemcpy(data_44e488, &data_388e00[20 * (4 * data_108ba8 + 52)], 0x50u); + } + } + else if ( v4 == 2 + && (data_108bad & 2 && data_108ba8 >= 2 || data_108bad & 4 && !(modFlags & 0x20) && data_108ba8 == 1) ) + { + data_108bae |= 1u; + } +``` + +Code list: +``` +1 = DL +2 = DR +4 = C +8 = UL +16 = UR + +.data:081083A2 data_108d84 db 2 ; DATA XREF: func_29ce8:jump_29e70o +.data:081083A2 ; checkIfModifierSet:jump_2a17fo +.data:081083A3 db 1 +.data:081083A4 db 8 +.data:081083A5 db 10h +.data:081083A6 db 18h +.data:081083A7 db 20h +.data:081083A8 db 12h +.data:081083A9 db 11h +.data:081083AA db 10h +.data:081083AB db 18h + +.data:081083AC db 12h +.data:081083AD db 18h +.data:081083AE db 10h +.data:081083AF db 1 +.data:081083B0 db 8 +.data:081083B1 db 2 +.data:081083B2 db 11h +.data:081083B3 db 20h +.data:081083B4 db 11h +.data:081083B5 db 10h + +.data:081083B6 db 8 +.data:081083B7 db 2 +.data:081083B8 db 18h +.data:081083B9 db 12h +.data:081083BA db 1 +.data:081083BB db 10h +.data:081083BC db 11h +.data:081083BD db 20h +.data:081083BE db 2 +.data:081083BF db 18h +``` + +However, the code list seems to have inputs with multiple bit fields set, e.g. 0x12, 0x11. Untested. + +## 04_3se +List of previous version extended by 3 more codes (last ones in the list). + +``` +1 = DL +2 = DR +4 = C +8 = UL +16 = UR + +data_12ae8c db 4 ; DATA XREF: func_2a8c0+23o +.data:08123643 ; func_2ab98+23o +.data:08123644 db 4 +.data:08123645 db 4 +.data:08123646 db 4 +.data:08123647 db 4 +.data:08123648 db 4 +.data:08123649 db 4 +.data:0812364A db 4 + +.data:0812364B db 4 +.data:0812364C db 4 +.data:0812364D db 10h +.data:0812364E db 8 +.data:0812364F db 4 +.data:08123650 db 2 +.data:08123651 db 1 +.data:08123652 db 4 + +.data:08123653 db 4 +.data:08123654 db 4 +.data:08123655 db 1 +.data:08123656 db 4 +.data:08123657 db 10h +.data:08123658 db 2 +.data:08123659 db 4 +.data:0812365A db 8 + +.data:0812365B db 4 +.data:0812365C db 4 +.data:0812365D db 1 +.data:0812365E db 4 +.data:0812365F db 2 +.data:08123660 db 4 +.data:08123661 db 4 +.data:08123662 db 4 + +.data:08123663 db 4 +.data:08123664 db 4 +.data:08123665 db 2 +.data:08123666 db 4 +.data:08123667 db 4 +.data:08123668 db 8 +.data:08123669 db 4 +.data:0812366A db 4 + +.data:0812366B db 4 +.data:0812366C db 4 +.data:0812366D db 8 +.data:0812366E db 4 +.data:0812366F db 4 +.data:08123670 db 4 +.data:08123671 db 10h +.data:08123672 db 4 + +.data:08123673 db 4 +.data:08123674 db 1 +.data:08123675 db 4 +.data:08123676 db 2 +.data:08123677 db 4 +.data:08123678 db 10h +.data:08123679 db 4 +.data:0812367A db 8 + +.data:0812367B db 8 +.data:0812367C db 10h +.data:0812367D db 4 +.data:0812367E db 8 +.data:0812367F db 10h +.data:08123680 db 4 +.data:08123681 db 8 +.data:08123682 db 10h + +.data:08123683 db 4 +.data:08123684 db 4 +.data:08123685 db 8 +.data:08123686 db 10h +.data:08123687 db 8 +.data:08123688 db 10h +.data:08123689 db 4 +.data:0812368A db 4 + +.data:0812368B db 4 +.data:0812368C db 4 +.data:0812368D db 10h +.data:0812368E db 8 +.data:0812368F db 10h +.data:08123690 db 8 +.data:08123691 db 4 +.data:08123692 db 4 + +.data:08123693 db 1 +.data:08123694 db 2 +.data:08123695 db 4 +.data:08123696 db 8 +.data:08123697 db 2 +.data:08123698 db 1 +.data:08123699 db 4 +.data:0812369A db 10h + +.data:0812369B db 8 +.data:0812369C db 10h +.data:0812369D db 4 +.data:0812369E db 1 +.data:0812369F db 2 +.data:081236A0 db 4 +.data:081236A1 db 8 +.data:081236A2 db 10h + +.data:081236A3 db 8 +.data:081236A4 db 10h +.data:081236A5 db 2 +.data:081236A6 db 4 +.data:081236A7 db 1 +.data:081236A8 db 4 +.data:081236A9 db 2 +.data:081236AA db 1 +--- remix double +.data:081236AB db 1 +.data:081236AC db 8 +.data:081236AD db 1 +.data:081236AE db 4 +.data:081236AF db 10h +.data:081236B0 db 2 +.data:081236B1 db 10h +.data:081236B2 db 4 +---- crazy mode +.data:081236B3 db 4 +.data:081236B4 db 1 +.data:081236B5 db 4 +.data:081236B6 db 2 +.data:081236B7 db 4 +.data:081236B8 db 1 +.data:081236B9 db 4 +.data:081236BA db 2 +--- all select code? doesn't make sense and doesn't seem to work, probably unused +.data:081236BB db 10h +.data:081236BC db 4 +.data:081236BD db 1 +.data:081236BE db 10h +.data:081236BF db 8 +.data:081236C0 db 4 +.data:081236C1 data_12af0a db 2 ; DATA XREF: func_2c380+139r +.data:081236C1 ; func_2c51c+559r +.data:081236C2 db 8 +``` \ No newline at end of file diff --git a/doc/development/notes/pro-notes.md b/doc/development/notes/pro-notes.md new file mode 100644 index 0000000..d326fad --- /dev/null +++ b/doc/development/notes/pro-notes.md @@ -0,0 +1,9 @@ +# Notes about working with Pump It Up Pro +## Enable game's log output in arcade mode +Go to `data0.zip/Data/Static/ini` and change the following lines under the category `[Options-arcade]`: +```text +LogToDisk=1 +ShowLogOutput=1 +``` + +The game logs all log levels including trace level. \ No newline at end of file diff --git a/doc/game/01-1st.md b/doc/game/01-1st.md new file mode 100644 index 0000000..dc4d4f5 --- /dev/null +++ b/doc/game/01-1st.md @@ -0,0 +1,134 @@ +# Pump it Up: The 1st Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: September 1999 +* Korea exclusive +* First game in the series +* 15 songs +* 4 non-stop remixes +* 4 battle songs + +## Game modes +* Easy +* Hard +* Double +* Non-stop remix +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +## Unlock and modifier codes +All codes must be entered in the song select menu (after selecting easy, hard, double, non-stop remix or battle). When +a code was entered successfully, a sound effect is played. For some modifiers, an icon is also displayed on left side +of the screen for player 1 and on the right side of the screen for player 2. + +### Velocity 2x +Arrow scroll speed 2x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Velocity 4x +Arrow scroll speed 4x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Velocity 8x +Arrow scroll speed 8x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Synchro +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Couple +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/02-2nd.md b/doc/game/02-2nd.md new file mode 100644 index 0000000..33dcd8a --- /dev/null +++ b/doc/game/02-2nd.md @@ -0,0 +1,188 @@ +# Pump it Up: The 2nd Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: December 1999 +* Korea exclusive +* Only 4 songs and one remix taken over from previous version +* 17 new songs +* 6 new non-stop remixes + +# Game modes +* Easy +* Hard +* Double +* Non-stop remix +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. +* Non-stop remix double: Needs to be unlocked [using a code](###Non-stop remix double) which needs to be entered on the +non-stop remix screen. + +When the second player joined by also pressing the center panel, battle modes is available on the mode select screen +instead of double. + +## Unlock and modifier codes +All codes must be entered in the song select menu (after selecting easy, hard, double, non-stop remix or battle) except +the [non-stop remix double code](###Non-stop remix double). When a code was entered successfully, a sound effect is +played. For some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of +the screen for player 2. + +### Velocity 2x +Arrow scroll speed 2x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Velocity 4x +Arrow scroll speed 4x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Velocity 8x +Arrow scroll speed 8x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Synchro +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Couple +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Non-stop remix double +Must be entered on the non-step remix select screen. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Union +??? + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) + +### All Select +Enter this code on the select mode screen (easy, hard, double, non-stop). When entered correctly, the game transitions +automatically to a selection screen with all available songs. + +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) \ No newline at end of file diff --git a/doc/game/03-3rd.md b/doc/game/03-3rd.md new file mode 100644 index 0000000..3ac509b --- /dev/null +++ b/doc/game/03-3rd.md @@ -0,0 +1,182 @@ +# Pump it Up The O.B.G: The 3rd Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: May 2000 +* Korea exclusive +* 23 new songs but only 2 old songs taken over + +# Game modes +* Easy +* Hard +* Double +* Non-stop remix +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +When the second player joined by also pressing the center panel, battle modes is available on the mode select screen +instead of double. + +## Unlock and modifier codes +All codes must be entered in the song select menu (after selecting easy, hard, double, non-stop remix or battle). When a +code was entered successfully, a sound effect is played. For some modifiers, an icon is also displayed on left side of +the screen for player 1 and on the right side of the screen for player 2. + +### Velocity 2x +Arrow scroll speed 2x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Velocity 4x +Arrow scroll speed 4x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Velocity 8x +Arrow scroll speed 8x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Synchro +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Couple +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Union +??? + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) + +### Random Vanish +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Random Speed +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) \ No newline at end of file diff --git a/doc/game/04-3se.md b/doc/game/04-3se.md new file mode 100644 index 0000000..ac5d0e5 --- /dev/null +++ b/doc/game/04-3se.md @@ -0,0 +1,211 @@ +# Pump it Up The O.B.G: The Season Evolution Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: September 2000 +* Korea exclusive +* First version to feature the `Crazy` game mode +* 14 new songs, 1 new remix +* First game to introduce a non-unlockable songwheel + +# Game modes +* Easy +* Hard +* Crazy: Must be unlocked [using a code](#crazy-mode) +* Double +* Non-stop remix double: Needs to be unlocked [using a code](#non-stop-remix-double) which needs to be entered on the +non-stop remix screen. +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +When the second player joined by also pressing the center panel, battle modes is available on the mode select screen +instead of double. + +## Unlock and modifier codes +All codes must be entered in the song select menu (after selecting easy, hard, double, non-stop remix or battle) except +the [non-stop remix double code](#non-stop-remix-double). When a code was entered successfully, a sound effect is +played. For some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of +the screen for player 2. + +### Velocity 2x +Arrow scroll speed 2x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Velocity 4x +Arrow scroll speed 4x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Velocity 8x +Arrow scroll speed 8x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Synchro +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Couple +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Union +??? + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) + +### Random Vanish +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Random Speed +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Non-stop remix double +Must be entered on the non-step remix select screen. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Crazy mode +Must be entered on the mode select screen. When entered successful, the "Non-stop remix" panel is replaced with "Crazy". + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) \ No newline at end of file diff --git a/doc/game/05-tc.md b/doc/game/05-tc.md new file mode 100644 index 0000000..724ee79 --- /dev/null +++ b/doc/game/05-tc.md @@ -0,0 +1,211 @@ +# Pump it Up: The Collection +This document collects various information about the game itself. + +## Trivia +* Release: November 2000 +* Korea exclusive +* As the name implies, this game is a collection of all the songs of the past versions except for the song "Kiss" +* Same interface as O.B.G SE +* A total of 66 songs and 18 non-stop remixes + +# Game modes +* Easy +* Hard +* Crazy: Must be unlocked [using a code](#crazy-mode) +* Double +* Non-stop remix double: Needs to be unlocked [using a code](#non-stop-remix-double) which needs to be entered on the +non-stop remix screen. +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +When the second player joined by also pressing the center panel, battle modes is available on the mode select screen +instead of double. + +## Unlock and modifier codes +All codes must be entered in the song select menu (after selecting easy, hard, double, non-stop remix or battle) except +the [non-stop remix double code](#non-stop-remix-double). When a code was entered successfully, a sound effect is +played. For some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of +the screen for player 2. + +### Velocity 2x +Arrow scroll speed 2x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Velocity 4x +Arrow scroll speed 4x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Velocity 8x +Arrow scroll speed 8x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Synchro +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Couple +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Union +??? + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) + +### Random Vanish +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Random Speed +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Non-stop remix double +Must be entered on the non-step remix select screen. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Crazy mode +Must be entered on the mode select screen. When entered successful, the "Non-stop remix" panel is replaced with "Crazy". + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) \ No newline at end of file diff --git a/doc/game/06-pc.md b/doc/game/06-pc.md new file mode 100644 index 0000000..80e23cb --- /dev/null +++ b/doc/game/06-pc.md @@ -0,0 +1,199 @@ +# Pump it Up: The Perfect Collection +This document collects various information about the game itself. + +## Trivia +* Release: December 2000 +* Korea exclusive +* As the name implies, this game extends the previous version "The Collection" by adding 17 new songs +* Game mode select re-designed to allow selecting `Crazy` mode without a code. +* A total of 83 songs and 18 non-stop remixes + +# Game modes +* Easy +* Hard +* Crazy +* Double +* Non-stop remix double: Needs to be unlocked [using a code](#non-stop-remix-double) which needs to be entered on the +non-stop remix screen. +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +When the second player joined by also pressing the center panel, battle modes is available on the mode select screen +instead of double. + +## Unlock and modifier codes +All codes must be entered in the song select menu (after selecting easy, hard, double, non-stop remix or battle) except +the [non-stop remix double code](#non-stop-remix-double). When a code was entered successfully, a sound effect is +played. For some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of +the screen for player 2. + +### Velocity 2x +Arrow scroll speed 2x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Velocity 4x +Arrow scroll speed 4x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Velocity 8x +Arrow scroll speed 8x the BPM. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Synchro +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Couple +??? + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Union +??? + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) + +### Random Vanish +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Random Speed +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Non-stop remix double +Must be entered on the non-step remix select screen. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/07-extra.md b/doc/game/07-extra.md new file mode 100644 index 0000000..8a421a3 --- /dev/null +++ b/doc/game/07-extra.md @@ -0,0 +1,183 @@ +# Pump it Up Extra +This document collects various information about the game itself. + +## Trivia +* Release: February 2001 +* Korea exclusive +* Crazy-mode was renamed to "Extra Expert" (XX) +* Introduction of hold/long arrows +* Double charts for Extra Expert and Non-stop Remix are available in the songwheel (no unlock code needed) +* New interface and pad navigation +* A game mode does not have to be selected prior selecting a song but can be switched on a per song basis +* This version of the game was produced by F2System, a partner of Andamiro. F2System also produced Techno Motion +* 58 songs and 9 non-stop remixes + +# Game modes +* Normal +* Hard +* Extra Expert +* Double +* Non-stop remix + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. When +a modifier was activated, an icon is displayed either on the left side of the screen for player 1 and on the right side +of the screen for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 4x, 8x +Arrow scroll speed 2x, 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 4x, +three times for 8x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Synchro +??? + +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + + +### Random step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Speed +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Random Vanish +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Rush +??? + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Noteskin select +Select a different noteskin. For the blank (second to last arrow), fill in one of the four directions to get a different +noteskin. There are two noteskin select codes. + +#### Code 1 +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/qm.png) +![](image/arrow/c.png) + +For blank:
+![](image/arrow/dl.png): Star and moon
+![](image/arrow/dr.png): UFO
+![](image/arrow/ul.png): Snowman
+![](image/arrow/ur.png): Restroom sign and poop (yep, poop)
+ +#### Code 2: +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/qm.png) +![](image/arrow/c.png) + +For blank:
+![](image/arrow/dl.png): Octopus and fish
+![](image/arrow/dr.png): Card
+![](image/arrow/ul.png): Pineapple
+![](image/arrow/ur.png): Disk jockey
\ No newline at end of file diff --git a/doc/game/08-prem1.md b/doc/game/08-prem1.md new file mode 100644 index 0000000..2116438 --- /dev/null +++ b/doc/game/08-prem1.md @@ -0,0 +1,113 @@ +# Pump it Up The Premiere: The International Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: June 2001 +* First official international release +* New interface +* 87 songs + +# Game modes +* Normal +* Hard +* Crazy +* Double +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. When +a modifier was activated, an icon is displayed either on the left side of the screen for player 1 and on the right side +of the screen for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Change arrow scroll speed +Using the two codes below, you cycle through the following scroll speeds: off (1x), 2x, 4x, 8x, random +Random changes the scroll speed during the song to any of the four speeds above. + +#### Next/increase scroll speed +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) + +#### Previous/decrease scroll speed +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Vanish +The steps fade out about halfway to the target. + +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Synchro +When choosing a single player game mode and a second player joins, this plays the same step chart on the other players +side. If this is not activated, no step chart is played for the second player. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Couple +When choosing a single player game mode and a second player joins, this plays the same step chart on the other players +side by mirrored along the "y axis". If this or [synchro](#synchro) is not activated, no step chart is played for the +second player. + +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Random Vanish +Steps are visible at the bottom of the screen, disappear midfield and re-appear before hitting the targets. + +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) \ No newline at end of file diff --git a/doc/game/09-prex1.md b/doc/game/09-prex1.md new file mode 100644 index 0000000..d3ece5f --- /dev/null +++ b/doc/game/09-prex1.md @@ -0,0 +1,112 @@ +# Pump it Up The PREX: The International Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: November 2001 +* PREX = The **PR**emiere and **EX**tra +* 87 songs + +# Game modes +* Normal +* Hard +* Crazy +* Double +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. When +a modifier was activated, an icon is displayed either on the left side of the screen for player 1 and on the right side +of the screen for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Change arrow scroll speed +Using the two codes below, you cycle through the following scroll speeds: off (1x), 2x, 4x, 8x, random +Random changes the scroll speed during the song to any of the four speeds above. + +#### Next/increase scroll speed +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) + +#### Previous/decrease scroll speed +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Vanish +The steps fade out about halfway to the target. + +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Synchro +When choosing a single player game mode and a second player joins, this plays the same step chart on the other players +side. If this is not activated, no step chart is played for the second player. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Couple +When choosing a single player game mode and a second player joins, this plays the same step chart on the other players +side by mirrored along the "y axis". If this or [synchro](#synchro) is not activated, no step chart is played for the +second player. + +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Random Vanish +Steps are visible at the bottom of the screen, disappear midfield and re-appear before hitting the targets. + +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) \ No newline at end of file diff --git a/doc/game/10-reb.md b/doc/game/10-reb.md new file mode 100644 index 0000000..b2901fd --- /dev/null +++ b/doc/game/10-reb.md @@ -0,0 +1,92 @@ +# Pump it Up The Rebirth: The 8th Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: January 2002 +* Korea exclusive version +* 87 songs + +# Game modes +* Normal +* Hard +* Crazy +* Double +* Half-Double +* Division +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. When +a modifier was activated, an icon is displayed either on the left side of the screen for player 1 and on the right side +of the screen for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +#### Change arrow scroll speed: Next/increase scroll speed +Using this code to cycle through the following scroll speeds: off (1x), 2x, 3x, 4x. + +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) + +#### Random arrow scroll speed +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) + +#### Change difficulty +Allows you to change the difficulty on the song select screen. + +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Vanish +The steps fade out about halfway to the target. + +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) \ No newline at end of file diff --git a/doc/game/11-prem2.md b/doc/game/11-prem2.md new file mode 100644 index 0000000..251cae7 --- /dev/null +++ b/doc/game/11-prem2.md @@ -0,0 +1,92 @@ +# Pump it Up The Premiere 2: The International 2nd Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: March 2002 +* International version of Rebirth +* 102 songs + +# Game modes +* Normal +* Hard +* Crazy +* Double +* Half-Double +* Division +* Battle: When player 2 joins in the mode select screen, battle mode becomes visible by replacing double mode. + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. When +a modifier was activated, an icon is displayed either on the left side of the screen for player 1 and on the right side +of the screen for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +#### Change arrow scroll speed: Next/increase scroll speed +Using this code to cycle through the following scroll speeds: off (1x), 2x, 3x, 4x. + +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) + +#### Random arrow scroll speed +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) + +#### Change difficulty +Allows you to change the difficulty on the song select screen. + +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Vanish +The steps fade out about halfway to the target. + +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) + +### Mirror +All steps are mirrored along the "x axis", i.e. arrows
+![](image/arrow/ul.png) <-> ![](image/arrow/ur.png) +
and
+![](image/arrow/dl.png) <-> ![](image/arrow/dr.png) +
are switched. + +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) + +### Random step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) \ No newline at end of file diff --git a/doc/game/12-prex2.md b/doc/game/12-prex2.md new file mode 100644 index 0000000..ca92ffb --- /dev/null +++ b/doc/game/12-prex2.md @@ -0,0 +1,98 @@ +# Pump it Up The PREX 2 +This document collects various information about the game itself. + +## Trivia +* Release: November 2002 +* 93 songs + +# Game modes/difficulties +* Normal +* Hard +* Crazy +* Double +* Battle: Can be selected once player 2 joined the game + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. For +some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of the screen +for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x +Arrow scroll speed 2x, 3x or 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x and +three times for 4x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/13-prem3.md b/doc/game/13-prem3.md new file mode 100644 index 0000000..0ea0278 --- /dev/null +++ b/doc/game/13-prem3.md @@ -0,0 +1,99 @@ +# Pump it Up The Premiere 3: The International 3rd Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: May 2003 +* 56 songs + +# Game modes/difficulties +* Normal +* Hard +* Crazy +* Double +* Half-Double +* Battle: Can be selected once player 2 joined the game + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. For +some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of the screen +for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x +Arrow scroll speed 2x, 3x or 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x and +three times for 4x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/14-prex3.md b/doc/game/14-prex3.md new file mode 100644 index 0000000..27235a9 --- /dev/null +++ b/doc/game/14-prex3.md @@ -0,0 +1,100 @@ +# Pump it Up The PREX 3: The International 4th Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: October 2003 +* 77 songs + +# Game modes/difficulties +* Normal +* Hard +* Crazy +* Freestyle +* Nightmare +* Half-Double +* Battle: Can be selected once player 2 joined the game + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. For +some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of the screen +for player 2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x +Arrow scroll speed 2x, 3x or 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x and +three times for 4x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/15-exc.md b/doc/game/15-exc.md new file mode 100644 index 0000000..0231388 --- /dev/null +++ b/doc/game/15-exc.md @@ -0,0 +1,145 @@ +# Pump it Up Exceed: The International 5th Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: April 2004 +* First game to run on Linux and MK5 hardware +* 24 new songs +* 102 songs total +* Songs are separated into channels: Banya, Pop and K-Pop +* Three hidden songs that have to be [unlocked using a code](#hidden-songs-unlock) + +# Game modes/difficulties +* Normal +* Hard +* Crazy +* Freestyle +* Nightmare +* Battle: Can be selected once player 2 joined the game + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. For +some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of the screen +for player 2. + +### Hidden songs unlock +This code unlocks the following songs: +* Monkey Fingers +* Oh Rosa (same song/steps on the select screen but music switchd to spanish version) +* First Love (same song/steps on the select screen but music switchd to spanish version) + +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x +Arrow scroll speed 2x, 3x, 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x, +three times for 4x and four times for 8x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Earthworm +Makes the arrows wave back and fourth as they scroll to the top. + +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Exceed Mode +Arrows travel diagonally towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/16-exc2.md b/doc/game/16-exc2.md new file mode 100644 index 0000000..3c62372 --- /dev/null +++ b/doc/game/16-exc2.md @@ -0,0 +1,295 @@ +# Pump it Up Exceed 2: The International 6th Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: November 2004 +* First game to run on Linux, MK6 hardware and the USB PIUIO +* 18 new songs +* 136 songs total +* Based on Exceed's interface + +# Game modes/difficulties +* Normal +* Hard +* Crazy +* Freestyle +* Nightmare +* Battle: Can be selected once player 2 joined the game +* Remix Station + +## Game play unlocks +The following songs are unlockable by fulfilling the described conditions. + +### Arcade station: Canon-D, nightmare +Naturally, this only works as a single player. This unlock is not permanent. + +1. Select arcade station +1. Play any two songs and get an A ranking on both +1. Play "I'll Give You All My Love" on crazy difficulty as your 3rd song and get an A ranking with less than 10 misses +1. You will receive a bonus stage and the nightmare difficulty on Canon-D is unlocked + +### Remix station: 2nd Hidden Remix, nightmare +Naturally, this only works as a single player. This unlock is only temporary. + +1. Select remix station +1. Play "Diva Remix" on freestyle difficult and get an S ranking +1. The nightmare difficulty on "2nd Hidden Remix" is unlocked + +### Remix station: Raw, nightmare +Raw (as it's known) is the same song (and background movie) as the opening movie of Exceed 2. Auto-fail (Stage Break) +is not on during this song, and the game will not stop if you get a 50+ miss combo. This song is not a selectable song +(ever), and you cannot choose your modifiers or difficulties before this song, as the game will bleed into it after your +last remix song and will start automatically after giving you a greeting screen for the song. It is set on double mode. + +This unlock is not permanent. + +1. Select remix station +1. Play any remix songs and get an S ranking on all of them +1. The game automatically starts the song "Raw" as your last song + +### Remix station: Banya Classic Remix, nightmare +Naturally, this only works as a single player. This unlock is only temporary. + +1. Select remix station +1. Play "Deux Remix" on fresstyle and get an S ranking +1. The nightmare difficulty on "Banya Classic Remix" is unlocked + +### Remix station: Dignity Remix, crazy +Naturally, this only works as a single player. This unlock is only temporary. + +1. Select remix station +1. Play "Banya Classic Remix" on hard and get an S ranking with a full combo +1. The crazy difficulty on "Dignity Remix" is unlocked + +### Remix station: Treme Vook of the War Another +Naturally, this only works as a single player. This unlock is only temporary. + +1. Select remix station +1. Play "Treme Vook of the War" on crazy and get an A ranking +1. The songs "Treme Vook of the War Another" is unlocked + +### Remix station: Turbo Remix, nightmare +Naturally, this only works as a single player. This unlock is only temporary. + +1. Select remix station +1. Play "Diva Remix" on crazy and get an S ranking, without any goods or bads +1. The nightmare difficulty on "Turbo Remix" is unlocked + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. For +some modifiers, an icon is also displayed on left side of the screen for player 1 and on the right side of the screen +for player 2. + +### Unlock: Solitary 2 +This code unlocks the song "Solitary 2" and must be entered in the song select menu. When entered correctly, the song +appears immediately. This unlock is only temporary. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Unlock: Canon-D Full Mix +This code unlocks the song "Canon-D Full Mix" and must be entered on the select screen of the **Remix Station**. When +entered correctly. This unlock is permanent. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x, 8x +Arrow scroll speed 2x, 3x, 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x, +three times for 4x and four times for 8x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Earthworm +Makes the arrows wave back and fourth as they scroll to the top. + +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Exceed Mode +Arrows travel diagonally towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Freedom +Stationary arrows at the top are invisible. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Acceleration +Arrows start scrolling slowly at the bottom of the screen and accelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Deceleration +Arrows start scrolling fast at the bottom of the screen and decelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Extra mix noteskin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Flower card noteskin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) \ No newline at end of file diff --git a/doc/game/17-zero.md b/doc/game/17-zero.md new file mode 100644 index 0000000..c4b2f05 --- /dev/null +++ b/doc/game/17-zero.md @@ -0,0 +1,312 @@ +# Pump it Up Zero: International 7th Dance Floor +This document collects various information about the game itself. + +## Trivia +* Release: February 2006 +* Entirely new interface. First mix to feature BG video preview playback on the song select screen. Furthermore, when +playing with a second player, each player can select a different difficulty level. +* 130 songs total + +# Game modes +* Arcade Station: Separated into 4 channels. Each channel contains songs with chart difficulties Normal, Hard, Crazy, Freestyle, +Nightmare + * Banya + * K-Pop + * Pop + * Another: Many songs/charts of this channel must be unlocked, first. +* Easy Station +* Remix Station +* Mission Station: Clear missions to unlock content + +## Game play unlocks +The game has an internal point system. Points are earned by simply playing the game, passing songs etc. A lot of +content can be unlocked using this point system. However, certain content is bound to specific missions and cannot be +unlocked by earning points. + +### Point unlocks +These are either unlocked by just playing the game or once a certain mission becomes available. + +* Eres Para Mi - Another Freestyle - unlocked upon unlock of Another station +* Final Audition 2 - Another Crazy - unlocked upon unlock of Another station +* Final Audition 3 U.F - Another Nightmare - unlocked upon unlock of Another station +* Mexi Mexi - Another Nightmare - unlocked upon unlock of Another station +* My Friend - Another Freestyle - unlocked upon unlock of Another station +* Solitary 2 - Another Crazy - unlocked upon unlock of Another station +* Extravaganza - Another Crazy - time/point-release unlock - after opening of mission 7 +* Final Audition 2 - Another Nightmare - time/point-release unlock - after opening of mission 11 +* Love is a Danger Zone 2 - Another Hard - time/point-release unlock - after opening of mission 13 +* Love is a Danger Zone 2 - Another Crazy - time/point-release unlock - after opening of mission 13 +* Love is a Danger Zone 2 - Another Nightmare - time/point-release unlock - after opening of mission 13 +* Naissance 2 - Another Nightmare - time/point-release unlock - after opening of mission 15 +* Final Audition - Another Nightmare - time/point-release unlock - after opening of mission 17 +* Do it Yourself - Another Nightmare - time/point-release unlock - after opening of mission 19 +* Solitary 2 - Another Nightmare - time/point-release unlock - after opening of mission 21 +* Mr. Larpus - Another Nightmare - time/point-release unlock - after opening of mission 23 +* Extravaganza - Another Nightmare - time/point-release unlock - after opening of mission 25 +* Another Truth - Another Nightmare - time/point-release unlock - after opening of mission 27 +* Witch Doctor - Another Nightmare - time/point-release unlock - after opening of mission 29 + +### Mission station unlocks +The following songs/step charts can only be unlocked by unlocking specific missions. + +* [New arrow skin](#new-arrow-skin) - clear mission 9 +* [Music note skin](#musical-note-skin) - clear mission 10 +* [Extra mix skin](#extra-mix-skin) - clear mission 11 +* [Grade reverse modifier](#grade-reverse) - clear mission 12 +* Love is a Danger Zone - Another Freestyle - mission unlock (mission 16) +* Love is a Danger Zone - Another Nightmare - mission unlock (mission 16) +* Witch Doctor - Another Crazy - mission unlock (mission 17) +* [Canon-D eye skin](#canon-d-eye-skin) - clear mission 18 +* Final Audition - Another Crazy - mission unlock (mission 19) +* Join The Party - Another Nightmare - mission unlock (mission 20) +* [Flower card skin](#flower-card-skin) - clear mission 24 +* Circus Magic - Another Nightmare - mission unlock (mission 26), note: only mode playable for this song in the entire +game +* Vook - Another Freestyle - mission unlock (mission 27) +* Vook - Another Nightmare - mission unlock (mission 27) +* I'll Give You All My Love - Another Nightmare - mission unlock (mission 28) + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. An +icon on the left/right side of the screen indicates if the modifier is active for player 1/2. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x, 8x +Arrow scroll speed 2x, 3x, 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x, +three times for 4x and four times for 8x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Earthworm +Makes the arrows wave back and fourth as they scroll to the top. + +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Exceed Mode +Arrows travel diagonally towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Freedom +Stationary arrows at the top are invisible. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Acceleration +Arrows start scrolling slowly at the bottom of the screen and accelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Deceleration +Arrows start scrolling fast at the bottom of the screen and decelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Battle mode +In arcade station, player 2 must have joined that the game shows "1P + 2P mode" at the top left. Entering the code +below actives battle mode and shows "1P VS. 2P mode" at the top left. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Grade reverse +Shows inverse judgements during game play, i.e. perfect = miss, great = bad + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### New arrow skin +Requirement: Clear mission 9 + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) + +### Musical note skin +Requirement: Clear mission 10 + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) + +### Extra mix skin +Requirement: Clear mission 11 + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Canon-D eye skin +Requirement: Clear mission 18 + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Flower card skin +Requirement: Clear mission 24 + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) \ No newline at end of file diff --git a/doc/game/18-nx.md b/doc/game/18-nx.md new file mode 100644 index 0000000..7452e33 --- /dev/null +++ b/doc/game/18-nx.md @@ -0,0 +1,281 @@ +# Pump it Up NX: New Xenesis +This document collects various information about the game itself. + +## Trivia +* Release: December 2006 + +# Game modes +* Arcade Station: Separated into 3 channels. Each channel contains songs with chart difficulties Normal, Hard, Crazy, +Freestyle, Nightmare + * New Tunes + * Banya + * K-Pop + * Pop +* Training Station +* Special Station: Full versions, remixes and another step (charts) +* World Tour: Clear missions to unlock further locked missions and content in Special Station + +## Game play unlocks +The song *Final Audition Episode 2-2* is the only locked song in the whole game. This song can be unlocked by playing +the song *Final Audition Episode 2-1* 100 times. You do not have to pass the song, failing the song also counts +towards this play count. + +Clearing missions in World Tour unlocks further missions and content in Special Zone. However, all locked content of +World Tour and Special Station is also unlocked when the total play count on the machine reaches about 20000 plays. + +## Unlock and modifier codes +All codes must be entered in the song select menu. When a code was entered successfully, a sound effect is played. An +icon on the left/right side of the screen indicates if the modifier is active for player 1/2. These codes do not work +on World Tour (Station). + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Velocity 2x, 3x, 4x, 8x +Arrow scroll speed 2x, 3x, 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x, +three times for 4x and four times for 8x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Earthworm +Makes the arrows wave back and fourth as they scroll to the top. + +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Exceed Mode +Arrows travel diagonally towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Freedom +Stationary arrows at the top are invisible. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Acceleration +Arrows start scrolling slowly at the bottom of the screen and accelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Deceleration +Arrows start scrolling fast at the bottom of the screen and decelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Battle mode +In arcade station, player 2 must have joined that the game shows "1P + 2P mode" at the top left. Entering the code +below actives battle mode and shows "1P VS. 2P mode" at the top left. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Under attack +Point mirror the target (grey) area with the center of the screen as the origin. This results in the P1 target area +positioned upside down in bottom right corner and the P2 target area positioned upside down in the bottom left corner. + +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Flash +Arrows are disappearing and appearing in short intervals ("flashing") when moving towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### NX mode +Tilts the perspective of the arrows scrolling towards the targets from an "overhead" perspective to a "distant" +perspective. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) + +### Grade reverse +Shows inverse judgements during game play, i.e. perfect = miss, great = bad + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + + +### Extra mix skin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Canon-D eye skin +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Flower card skin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) \ No newline at end of file diff --git a/doc/game/20-nx2.md b/doc/game/20-nx2.md new file mode 100644 index 0000000..a6fcf7a --- /dev/null +++ b/doc/game/20-nx2.md @@ -0,0 +1,295 @@ +# Pump it Up NX2: Next Xenesis +This document collects various information about the game itself. + +## Trivia +* Release: October 2007 +* First version to allow storing player scores and unlock state on a usb thumb drive. The original game only allows +special brand of usb thumb drives. Other drives are not accepted by the game. Profiles were managed and uploaded by +the player using a proprietary software called "PUMBI" which is no longer supported. + +# Game modes +* Arcade Station: Separated into 3 channels. Each channel contains songs with chart difficulties Normal, Hard, Crazy, +Freestyle, Nightmare + * New Tunes + * Banya + * K-Pop + * Pop +* Training Station +* Special Station: Full versions, remixes and another step (charts) +* World Max: Clear missions to unlock further locked missions and content in Special Station + +## World max guide and unlocks +Either take a look at the `missions.txt` file in the `game` data folder or use [Turkeyslam's guide](guide/nx2.pdf) which +was published on ph-online back in the days. + +### Cancel +Clear all modifiers previously enabled. + +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) + +### Increase arrow scroll speed +Arrow scroll speed 2x, 3x, 4x or 8x the BPM. The following code must be entered one time for 2x, two times for 3x, +three times for 4x and four times for 8x. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Decrease arrow scroll speed + +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Vanish +The arrows vanish before reaching the target at the top. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Nonstep +Hide all steps. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Mirror +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Random Step +Randomizes the step chart. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) + +### Random Velocity +The arrow scroll speed changes randomly during the song. + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Earthworm +Makes the arrows wave back and fourth as they scroll to the top. + +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Exceed Mode +Arrows travel diagonally towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Freedom +Stationary arrows at the top are invisible. + +![](image/arrow/ul.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Acceleration +Arrows start scrolling slowly at the bottom of the screen and accelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Deceleration +Arrows start scrolling fast at the bottom of the screen and decelerate when scrolling towards the top stationary +arrows. + +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + +### Under attack +Point mirror the target (grey) area with the center of the screen as the origin. This results in the P1 target area +positioned upside down in bottom right corner and the P2 target area positioned upside down in the bottom left corner. + +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### Flash +Arrows are disappearing and appearing in short intervals ("flashing") when moving towards the top. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) + +### NX mode +Tilts the perspective of the arrows scrolling towards the targets from an "overhead" perspective to a "distant" +perspective. + +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) + +### Grade reverse +Shows inverse judgements during game play, i.e. perfect = miss, great = bad + +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/ur.png) +![](image/arrow/ul.png) +![](image/arrow/c.png) + + +### Extra mix skin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) + +### Canon-D eye skin +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/c.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) + +### Flower card skin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) + +### Playing card skin +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/ur.png) + +### Random skin +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ul.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/ur.png) +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/dl.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/dr.png) +![](image/arrow/c.png) \ No newline at end of file diff --git a/doc/game/game.md b/doc/game/game.md new file mode 100644 index 0000000..e5f0055 --- /dev/null +++ b/doc/game/game.md @@ -0,0 +1,23 @@ +# Game Documentations +This kind of documentation provides various information about the game itself like some trivia, available features like +game modes, unlock and modifier codes etc. + +* [The 1st Dance Floor](01-1st.md) +* [The 2nd Dance Floor](02-2nd.md) +* [The O.B.G: The 3rd Dance Floor](03-3rd.md) +* [The O.B.G: The Season Evolution Dance Floor](04-3se.md) +* [The Collection](05-tc.md) +* [The Perfect Collection](06-pc.md) +* [Extra](07-extra.md) +* [The Premiere: The International Dance Floor](08-prem1.md) +* [The PREX: The International Dance Floor](09-prex1.md) +* [The Rebirth: The 8th Dance Floor](10-reb.md) +* [The Premiere 2: The International 2nd Dance Floor](11-prem2.md) +* [The PREX 2](12-prex2.md) +* [The Premiere 3: The International 3rd Dance Floor](13-prem3.md) +* [The PREX 3: The International 4th Dance Floor](14-prex3.md) +* [Exceed: The International 5th Dance Floor](15-exc.md) +* [Exceed 2: The International 6th Dance Floor](16-exc2.md) +* [Pump it Up Zero: International 7th Dance Floor](17-zero.md) +* [Pump it Up NX: New Xenesis](18-nx.md) +* [Pump it Up NX2: Next Xenesis](20-nx2.md) \ No newline at end of file diff --git a/doc/game/guide/nx2.pdf b/doc/game/guide/nx2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9e7a28d7b5781f2cd35e95e92eaca4df93857046 GIT binary patch literal 3900989 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�G6k$zmf}jtCjUk98ubkqVGzmzNQjj6wTke|DLq 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 z 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%0D)><+5tYyi-JhG!zcGRSZMJo1c={ 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 z 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

-D%K~0jQ*F#zZ1wJo ztGl+izD03uYKKZ~5+5HypC6}^WXQ?ji&E}68HDuLENZYIOD?1b$~#FA737>%QPurI1yN5N59Op6H@K0nPe_7P9{#WKZnT{ruRA zpLE1JjDsy;JISoyjrf&_0!cgDarFxC?Mt7U>&hSq!z0wO^ahKeYE@G^)NA@sUvP@_ zC(C??Y4#vJRxadA*>2PMg%MhJ>ry=s;1dRe}WzQ+1eK1KWqUO4KAdQ`#NgJZ;#{K zVtddqquc!`Ou1d|?C;$sX+{Nbx7hIS2LA2~6&~*Ou8m5QODxo*RjJI3Y7Z%DdMR~* zw7@4E#XY$Np+`auHm8cQw%er%Efa@@6M*2{L)og~hUdbxX>%jyot(AmXfh-p>c7x&=pP68@z_E_S zW(=9ld3muxVYP}l(h{K*lVm?dxR4)U2)ifQ^qbTM(>z7&{z^3joWhrj_}Y5;Y2 zv~eMa*zm@97PPLuoIlk&2^9a}Lq$_xx>TB+@V(~vySZvy;=pUA*j0;;Wv;yo^_RhJ z#jy9*RIizo_%2=pjhQBS6kB$VZMd1 zD>2h~5YkHq#G7$S@u?nt$y(L#y;d95^zVIpxBzuFAehO`;M9@;G1muXVl7UN_~7_L ze|O_I>9wF|pA!>p&o4-Qb^;DZS+n1KsuY}RQJc({sLFk6%_kZT&fQ&Qy{LDK6t|Ir zu8@`o$(~mqCzx*dVuM@sdtwvx0!3f1bDZ=61km{;#C3YAgF>F4?caVtDMHmF8L1rP zrXAlk9HDIkQ7|&|&I<}2W?KMnY4#eraAerZjd!X1=lE~mO;RNJU_0xRlmb#ca*?&l ze!V||%h^t=VZMci=}p?_nL(X>MJ_rly7SQF#3$D>zFMghnQwlXss!vWks*vc?HOqM z(-no6RJxSQSBg!w=t$;TDf6$A|2KF_X5!|;KdK~|^qn?{5K{uegk({xuWTQ-2_|^OUip{#Z12tl$5LA=mqiS}Jwq?}xmXY7s ziJrx%2q;KST_G!bgB1TPY!R~FUsLEL5c;wcBo*h{Jz>n;ADd z(8KwmnTW4f2efD?TEi_%UnzA8S*b^nhet+Dwa4AQ_CU0%$R-)$;;e=9# zn?O=WfKTnc+Q+zk$#5$g>_E1n-<-&pSE^_lZ{KdSQd%3;Bh$b)pqed1TN^bIod2$k zX4JRPe0jhX6(Pk2-Srj{1_F;}4q=bi?cJ@Aw4EglUP`g37FEV#p*Be2ufpRjW66-F zUK|7Wx8Dn-m`Cru*-uzi6ZjUFaeI9R14~5LoQ1&_K0q&&!si0RTUYb%&+xlfr7#5j zu(9V$r9f4aIHPjW)b37dxFN`eC5BcuePDRsluhwTY`0@+!o-{Uk@=r1gu;7;^-85| zXuws&aATqR@!&rJ7RPIKnYYko3Ua8kvLJ9fo*hxi1=lI(mvTcnxtR6dz^~a9h@PPnyFQBfHS?UCe_y zb;$-Ea+tNMdyd*kH(AjK?)0 zCcHh?FDa`%T{j_wo!G!68l*3n$|IhoIDhZMLnoFr_o4;REWBh!k8JZ87Q~X{u_Cie zraW0!7FCu6HOmW4yask~n@Ar7CM!F(CzZM zkdwTS>Zz2GJ{Jjw<$^P|%eEJ#?2jaGQZh^qJ7SMRGdW71gIZK2%SEbE`r7B9iPPC1 zse@Q^0E@dgsjiS<4<47IVG*)#&m?}d(O1MD)&)9KkUe1Q-EANc7Wm|E*c~dQ)&S%Tzkey98~49*lHZ_K01>M+6)~2DIss29 zIx$M-<6znL-OT_t!vXx1VizPt!wOqtz$n2ydc2~3<8^AxK+b~4C;ZdX(?O4SC5T-` zv7TOfbop5yE$Cy4zOXf~cfM@rafQb5#o3wFN*{xIv^JG*P0-(c!o&e>-}DxJ6G=*% zSpM#5g=1Y6$R!!nIDT1Jqx8-nj2=Gf-C^(bxdL$4JxY&Trnxu<>Vxh;1*c+;;se{=gl_q0pft4uSz2fm1R zdp!Hb?zT^(H)~=?@NY4Ld$zu) zQvZm<89sxEyc`5j%n#32gp5&1Pib&o8tMav*NpxZ@+kVaF-f{&$Zk^k@h4 zZxbnI?g0>E<b16B`aIMWb5uCUYnwsWw1s z?}Tak2Revidw?z^V`m0qkyO})ESP5TV=m>Q*E|2!ARJ$c>zimw!KfB}NA=hxZE4hW zF!K38N8T@dj=2nlY&JLvZ+lL>I1nf|^QulqgI~K*dH;-EN-J(ztrV2%(OE3DXA}M^ zM0d~wz!}9^5824r`OM^%{DjmWilNx|Go=y#s!4rO^%|0P z|5($%*Pcg!{p1#s#e~y!UViUr6wui@z2fZeL-og!dOM{^RF42-t*Q>Fy~wHQNOY0N zXh=KGp}7Rt&L2UFN4PHIib>k(gY?ZZ_Dj}~kCeS*^YjI7h6=t%_q(JJH(}=|M1?;1%F#JkWVEYmU5>`^$c7Mn_X>xx~zy!D)QyHDaE6jBpFrl zsQqYbIv)9ry=avlkHrVC8}E3cBHGrNi6d~J`G>4lsbgY^dPEuR2m3FhRJ){0qW)Wd-6~bft3u4So^Yh2LN6>U=m#peT^jy4(Muv_Pswps`R{FNEUu zJHOo)q@A_jV%Bc5lN-qhya{!644sKH2xr31F?vdZ%P@M+nquyfu@BwIS$>DG7m2yw z9k}jU^08DHhg0+y54j@yr>Vx&`9~S>c!8Lamv2d6USr%S^tkPlz5PNPlIZ!BhrPt- zmRde=shq63x4gurmSDQ~fiJ-Ew*ja0%x{%OP1B}yT$CKX6kO;XzvXnIeu ze-tq*fG(l-R+v0{Xt9{viN?m`_ZSPNUfZN_vH2fptW=6dwa7pg3sp^TqAz^+1$c?J z0KY{6E(joO3c8Tuq}nl(dD)sgL~<}5Xxwl6WaKj1> zw+DQNvr+R6Fz;mZ$O2JVTfR7oJp_(F0NY{$99F~(J?v4$McK>7vz1_bFL^2r-mkkiDy|_cH~b`hwB$L@6NEB05>X7F4xj ztL+XnzSu&QDGD^05j_ujsGB6(D85WFe=&fw(^m^$W*a{)@?ntsI%;X%Ha;z2&fy9) z?ECBMGe9@cSt*iC^Iwr+KzU3xQFOI89u1W%#jRQ-D$9kc;@0v{aDLlS+tt2JR|~@& z6rqqLv)82AY$q6N9m1_7_W8ZeL@%-`>+o5!?A9aQF7)aVKyOY56@D$5quem(Gq&>Q zjmV2&J+Xa9JAP3v%y{p)O=vC{Kqs1>>B^5XZ@s2x;{n#*mU2I#n2wC#9MFlwfQPU_ zG-mak zC}S3MRar2t{Z!NO81!>Xltrc#^w&W@3kKHjt1+vEZG4FqF-o9BXl z(C`#Ac~Pvjd#l}I3EfCWzvF`l1IvPkqtXt%;S7hOFR#u4#T52<^PGiMemziKtCUEm zC`Gbb)HMs0uia^bax@*u1sQN3zCmFZOt0rUf?J)3$r<}a=!(tL`3HGO@`Y~*X0Lv0 zXv4r`H0&JE*`6Z?%-%q-7jc~PFb~dmJ6ecSX0!&${gw>IY>)xmJJSS#fNnmF`0J-% z2LDJUZ?ccq$@Grp02{zQbRy?Sod`*v+k+OSf`t5JzC2tONGqy;F$8i)9ja^{tEa3L zDX0tCl^M#mp%*Vyi;$xvBHt0%Rzu%jA2lMmE2XdMu>3_`&hRYV4vQ6TdGcDyiGGvXJofyxy~jXm3x@cF z3%+-(?r1ZlJOTaMu{@%w-A;maQoVtV$4zb=4@h!8`oo9kKP}F*;x@3n#yY;OMt9XU z>htDpo;Sm>@%V=y#iP9Wvi)|i+LIT~sPHm#WapOkFT^;jw+)Y(NyZpH86V_dqS+Vu z-;FPCrCz`$=gT+Ci6u!PHAVd2~ zsC!a+q3-t~g_gb{HR-(_&E7sXlNTf}x4$45yB9hn+fr#uJGUqMtdJbu5pDYoIV#Qm zYWF$&pSDK`oIyk9VC+>6f59D7T4w(7gZuNI+r@IbmfEZ@OkI6WzuV%18SjOZUTN&tTbNu{E_OY)!u*SLtdG>(^O#6?`nAc~Kw4wWbZf2Zt*}WQ@ zDxchfV(L<72U>8=)s}1Xt^1XD%1-(snloK4LYkIF!cSAxZ;EyLgl{a?D|Ya65MY9*0avoiEX93@hG(R39g$_tNA{CLh`b3o{lW1Hs%VWYa^N?ZB~r-L8l73qZ%17Ad8zeX&>0UN{fkO$s`I?4J2F zLEO;o`F{r|V_2NZpk!)4Z_}9`=n%=3!eoyM{{hjDv(WocKR#tZ) z#e9+*rQ$ryW6K8W=FH8h6oC;)~7PeB*&m0JxZALigTsUFtT zLaizGF&W9iq#%1|;n-e)SP98g9^+6!MA3&Ndy}gbIBgf=@;JCiW>oG%(QBkYzoK<8 zld!Ld5#g=PVD6FX?A`|A>#A_i3y#J-*%9wyIJo40^p#Sb0bV>)gQdp8TIG+#JMXg& zX#1?U`bZS8lae&Lm@qA*pvo8Q@}h*h>_wrG&0|u1zu+d>d1`z zykE<^bo+a@w+gvn4mc^}%7Bi~ipA3eO)tR8vlc}i3t~zW(o4k(X12v!U)c`Y;zepv zel3=$dM8-BVxj3D1ebKGKsFv8ePM$nM>Js_;IQL>q3L@5tD?h)K_R~fNxVYsbsPPf zKu$K7%J|pBj4e|@19Sr~OrrP&Bz|kWYwGHLY|ebP3)Qyy)r z0c4iW^NDyONSc(9Ks)dhX{8Y!H;I)-JwRs|gQr`f(2Ln#B0Nq$4d@)H`~*BkNp^W6 z`gaE9SI8c*rT8TzIJA@;3DbNXm@uH*~2hvdBYt8}HWK~1`~%CAAYdZ*#9;opv+kY=tQ=;$F( zl#QN!U$g4&5 zG2ksXI{)bMEFtc=4r%6^EI0AtclFBj3L*jhz1p|{ebQ+**MS4dy&v?37duJ?$WRwJ zPB;d2pXHV@3L=6D!JbVa?fzA0n9(o~2lVB?X8xb^z_Q9QVc}rb6WQLr1>;<8S#y6+ z@R7t${Y@$C|BL!KG~E45AO8=A;y=OC-wdtz@D}2OONI=N1U*PPQ=U15oZQoah8^{l zGsZ>c7X|Y`(WuYbtG1xn9a!`2cN$adzZq={=*AcqH2cKyVtX|+QIC%qJ`uvw(t}$ z3eUg?+@TR~XQfP-p8tS06cu$X?;#kfAOk6r#^EyfI37aKUhcp)jO&<70=GLZWUY7I zFn5i|v6*-dBUUnZVFs_Xg4f`?1(%=&xghd-5C>NO-5d#SBN{_auDVnzn`K1NoAZh& zTks-FENM5eM4o{Zu^l0dml?39`MY!bmbsOYs|I`UQTPz{rhUaw`YHG?>d=3D2r5qj z+E0OocR;bHNWHDU%LO6#gwbH^A}I-!XBkEYpi4nW2?lgLQmS=d=_A)bk7W?aVoT9u z*=C$8B-8q_M8^FDj>nOX#*NF22nj>Znc*U!dD|Q%I1#df1T*nu$RX`201`-rPGP#I zHTjK&Uwss3M$8(bF;aoaFsR6}f$D_OCFm^q?pL#);N;B-zA^^A7|R1@HY$4qi`60| zTd16mq?ODxogod%7(rq$C^Ujtw@j3n2RM=Pp8WgvSSmg;>XQ<*V-&ZKa}lFnAV|ut z5Qj!3~<7lW7-@dH{cJoa*w4Ma`^gZ0C%gCztum2Xs)>2v4UW-!)6 zark%!W1o=|`uAQLJ}U{DZN>VN%@z<6(`>SA-ZBy%oPY2XU9kx~;W*48I-7qFTo8Ne zkxHSj7IoMXE=Q;aeeD>a>6KrOv)GapxFw7e*zE0Hj4d(ZeNxm%K(ZcMZ!=4Jo=UK7 zC~lRMeZMuZ38~fxE?)vW>zCQLpHgRespMm`cuGD`cxe;DI#V%hA=|0E6HHEA0)z(=}N}q&!3IU_BRiJx`D*_^a89Fh?^o&1h3JMS3 zA)R*AjvyhNPP_>IZj`s+j7aa`6@_{3(*5Z{O2Mxdh1g<=s;!WA643PTL6AsJ!;H|e znEO44-=JYsEHHF4qu9F=Gu@ha$SPk_^xJUK2-mM!c9*a}L$Hh_=;X8oso?lnVrp*^ zjpU}c3(SJqW9+*<&)NAU{gQT0W0&x5)6~x$w;b@wK1zyV)3Zg41NKYjT}(N)yS;6^ z9H*G@9~^u)a~SSoR49$3&3I0WEgHVK_PXckTLiSsZR;_NRr(0jBMe)rN(pI0)HVGP zxTHy!Nrlib*h*g>8YXHX(Ixb0g6tiHWPeE7K5RJ3eCQGxg;LC;Ew12+yO2By z3~k)Y>KKTW{n}yFwvluQn=*gZ0Qylq*qBP$dF!J&q+T}xFXX;JHrPHXd4k% zl=*;)!bMzxu2;4%nRAoMZ-dI!mg)S07!c%60}bA-!%@1>`qOcT!3Tx4_~3Avt!vb! z(E5izHbkb<;<+UIZaRsay!k^356#Hy0%Bvhy1(*{oqR(yB^i^N$$GA(}Zofgqk13Rs*QzYzp zHhf@kM=A8xqz9`U7^gJ?X}Am)BqnLtH@`Rj!HUK|2Evh*k@L!l_=Ap(sJq1 z=O<~=j#SEpizIXG=@PjR4b$ZdY>L2ZqcRz`n?%F#1;=ckFt*jBtmJbsf-&Yj4svL7 zjQA%##j?QTTmKg+Og(b2h03v9*6*JE8Lwr3-h%ycNf&b;0UZlq_*utMBn<3Di7mh)vyd^xky!R zQ%m=2dV?cpF^55as}RS4@!smr*urBW;v2y5o3uQzk}|W)W%AI86Z$9y3(#lg^*Za7 z0!hR02t&|41+*nM2#t?WnBOi^v)!5ea&FXN^d-MjDlX7Ig7GLQJQJQiF6xXPp9_kgG!DK^_4J?O~+YhAt_co@9|oZo+&v^qfn z9q)VxS%^Oyct?VYL)F;_Tx4r{rU<8bKgf9Hbie12Viow8{>g?)A+8p&S4-~ybr_$Z zQ8bK3`<>mt8N?lx>B?BHwoz4ST>tjk6F}$iod-O03ZQ>RFc<33R{;MZ?n$&N;%6E{ zN&15wNufzwOn+-UzKNE754t3XTT7*SCo;-qTslR68oz29l z$b8If?CTM1_mkQV)H8w47%O#UKvrk57*jl$8~(%Lo$C$J69OZ9fodY-Y~gA zX|-32Zfmhb)j?Hj(b057D^_;@Y1Vh>0{epI0#Pq@Ix_$46e^mSt3PI6W^WPHQA^r) zifGgl$jKkgR;X%>#OE_gY$Q%$Z1?TC27ZY%y`fUI<3i@Zq*K*9c18EG0TO% zhLmguoEd`K6!SL@;emP-!+VH2&jn{hkQE}B&kn;a;63x;CV&(nhf87KbFeVqyl&0% zy9&KFeBLa&(x;#vy;kL3UaQw?`csHyiT;`F<3~A3p;71g|7z4ZVwrk9G9&x+q0 z9XX~T2!y}Ee|vNk?vjM@W>9qVB}uSsb8P^>i;=ZX$j#9uvi4MeC0~U|u()CD#>ja; ziYjvi^g%>7Le4(4$Eynsvj%WK@s@cVlTSHq`E9gvgE#ahC%T^p^v(frE;rduzMVT% zvH>{pcuWdvRzH=}>Xg0+^(eCDsw%SDBCqj99#-|qYdX1==(&(~tQ8IGfPZjPtXykE z1NX^7xT5>w+Es99B&A%KyUzBB&x-}d0psU$^GTmPz{m)Bjobq6M+<;A$%v24(2thr zj;1dPsw*Hk?I;7b^6Aez6=IX`&2jO{Fm0|T9adEmQrp98I;MltBuJS(=w$yKYYNzR z4+vR62j-Xu@O0N3pcjtiz}SU^ZfcSkx2}ut2J>VCFv1q@h?o?jvf8y{12m*#F7u{8vX`{(tZ2KY+Jp2A5JkITW*+B?}jV&t${c?s9?=wqTkd zQ%c-?!$&7})HWAXZfN~ika_fXoU7p+o}%WT_8D)Y6x!-hUtuX%an)8EH>lwbOP34@ zQc!`i@#pbFd)r}yZ6szepqrq6YVRhGy#d55@B~e4;zN^gbD9g0Ww*D`RlZVw#p)(a zf?3}eAgjP>l4U?FD0D`TbGX0S@QNtZ>arVf z6}(%~6Kw?ypG&33kMU9CY?1d|UCEV;Q^=69{m>Wu+Al^?zCF6$Kc^JaY7tp2th71$ ze-%u_6TCExj{~Ol{Uqrxgi-7a*pDBD{D^;b_EmSMZo!31=)-wUAZa@}ggNAu zgMR!45XpR;V#IOdMQMlkHzJKyuqA&mLqWgv&NA>&ihDH)s492l+BgJFZ(GudVPvMl zEt4i}0BeI`cDFxQ@Ow7SRd*nN#YSzyCm_%E@0bA7a!i6-H`j_*6uF}}NWSL~nh1{p zE%B2JTN-qMA!COaI%sA|Sxk6EC@=q|!>FG8CmD1E5X(WeQb4OmKc%b8y=VjfG#t>e zIYboDX`z8U!OIva`w#)+D*4eO`ZWLaqe{0@kudfon=Pq62LU(P4C&hg&us>jY^`5=)t&NF$1`d~*iF>*;2=?9Wlq>La ztQI2$uf(YAoTY>thVS-dlpE9tGqL$orxQ^-YCv_n0hvCG-4{atIVD4ir&J~P4bjj> zU{XHG!?>aBoHus~fNourp~*@wNt>%j&xFQDEzbWMlpzs%lMr*PNC?UJ2URMYfE;Z z;wd1{tK6yPQDSED%KHOltSJ&CG*_6I`46VSrbmi(h^yJHN)01$b5adU&K7i)@BL{T z2@P)~6qfIh-xJ*{&%)as^Ffe+amLo=Qs~a!xEIcnUDCs5XZ)k|d4aVX(gViWFHr(1 z&L72Gr!UwZx^QRE*iphLTMo&+CUCJ{Ml`~u2Pv3VhWP8R_{~9~h@Wkh4=OFO>X8i> zYun<#3h(SPf=;wOO$Gw`53|V6zlZ~?sEULPePK<6Ke^vxTKc_#{_-Yg0Ssxup+@)^ zow&*|+FiG3M@2sHYlKTU`D9u4bUDiy6ein6Rw%0RvDCpXrTA5k7O47inzkBics0Hl zx1EeA2LZW&>GZimyq(UzF6?3zYT*t9ofg=fyEi2 znRNuVw}D_y65t=^M|kg3XxQE9{gFy>s}{Y_TxGikTtax~M*&Qv=-T>Uq=I?wy2DChPCW8TuN$J;CJ4LoK=W;CA)%XtFs+l=j}So7oqF(PEgSA3Qq z!5sUlcYc1$X$93aZ)E5nN^7WEq&9PFReM)$rjDj76fR;ZD;%`)TJI)Dt{nf%s!*KD zKi)(}VFS3F{c`@)M^mTvKHsF6sXX=Dl={=4Ql$olz}!+*hCqu;O~<9D*C0|bsE}|! z-dR&}{r!^H`R3CG6(9G6o_cGg^-(R7m$`+imS8OoH64c)`y8X+`~KSlx)VNC1R!X{@bPg?hB21uXYh*{#_BaABz<@4C|}gqYQ_ZYSEA^ z%vCLd+JqKO$6?Sj7&ko+f6^QPn7?7ufanQ2@wKh%0*~bfic&rkK0vpGBvRf0oybXa z7=ah}mKWs%5e(d2=i2Cawl=HWA6@KBRp-8-m;y|eZQCYCCJzwoO*???k@MVm- z^^)ID%m;bCKTRpD)uTc!QFZpwhH_~-tYiIw{poBu!yaaG`T1XUb%~is=b~Zg#+7IT za{53J$^0-G_d&mUdGW@hF?c#`jo9Zi9)4?kD8B4HNN|05}!$9Y3WPW^HmaxJLwD}zN1$vchhVdmeU_-zW z{mGa~6F&SBooFe727#{|r~RPx6{tnM(niz$b>b{yMertS-oIXf13VH?M&q&Mc!2(u z!0SyOGK?p}Y2X4+mtZe^+!Oi+yZP0Ps;HSoJ34d9(Zyq#fLl}n46h{#8pwLe9<3S0 z=L&$~&bo-78SCr8oXwzEwv{&@7&eOQuw%m|RMNI8G^{|1?r_BWi@?^xH%Rfv*E=Im z{eSGeX;f3^`Zj)ATY9LpoNAHc6t!AfQBcF+$gZW-sft4d6d|HwL{wA+6oh@O7AvUK z5i7!098eh|BA`rB5l}%QW0)heB!nlo(?cE=bJ;HCQtgdwCeh!_JO%yqvk}b7?60^>11B*DWSY<^%jEDiwT1V zq)5q%Wf^^tJ?q!MrTKK8`}QO4ZOx5Yl_ffhB1O!VzCkJUQo_(N7`tNtOMIvj$vAg+ z0!NU2GwP7rp0EG2nsn>Nn!n4+;c2-Cq%>L*xQ-Q%a+iE(Od{cC}hcE55sJzRto) z4W%_(-|Jesa2h&3MJze@Luj#7c)}^!CVSR4YhlHf{i+;TBJ>@^@_!e=1FPJ=)5cq_ zaS`m%2}^3oE(d+frY#-oXW%N-&1g#NwEvlKNj4X>r7KxBRaQBX zGv)^RPJ5*l;0yj)dsQbKDWQ(+n0gy-(SC^rUMA-u$J(!RZdtNWMpp&tpQYrEI^i6) zAa{I_X^kV~y(EAr!Ea$}<}vfOWgE_LZPe9p?gT%W)P@)(lYK8T@d;nU3tTnPb_1HI z;jtTWxFvVvDt-nS7H5Tx)=oz4Ucg5uo++Vw>}KjMI;B7R299Tseb6QTFme(?d5G>A zIVeH#u^gI+4#H&js{67_?jV|w9>tB=)9SZ0-RnfQ{Lu`pO!^20fkK z#;bN|<rp4z4>#PN0w|)SGb9}=7GNKLguaM*j_EqRN@W^ov@~aXR_1#I)ygjH}rmYUNGSE zF~HmwmMs_um#7K`xps+=Ic;CC*@7l@^mWc6xOsKZ4`gw1tGOIsbuwcCOcFjzJhxxI)pL-Ol-4W}n%=|LR|Wc!lDGgd&JSGt^8xJTF28z^@xS!2Eoh6^Y&^FgmZDYpj#6Bhbmi`_Yw9mewW8Y&)Nz6a_ z?`A~WLu@CFZ>gaS_0_v4CNJ|4VFfKig=+w_Cr2Z-!T6#6Zsm)L&v32Xvo!xCE$fs} zRt9*lKEIyk+TYe1ei)iuA2bi|H#0t-qde1(DtS+r`d6K3ri2u;o2~b#X#egT6id26 zd5Z=mC$%4IsKYVnn{pq20uqN}01H}tg@QZRm>IjJgNa+#uEdiERV50y78_w#XK^({ zK)QepF|t9^en~S+v3?s~x(-F;R*TKQ3nT^AjBW7VO;H69%yX6nn+ZlD=jJ^%9XLw= z9ChJ583IMAQb94aut%1+Cre>oRkN}u4Vr}Ja;_nlW@`rxs^^|g7Dsfx07_^#yE*g= z_^Y_Ys0RflL0bvfAD|NW!=>+Uo(h=r?+_q)a$0_3aLND{TgYuEe1bdR+5H|cq!VMg zl_x%f78m0A_ugkaspu1!X_Lp_9!v_mdv07|0oVI*MIsN>?9M4>jYFyF5pW#=9udTNtKd z==8-!7Wx$IvF-FWSfuyZ2H)FANn(E4|MWIbS3CfUvno!Pkk~e@{vL>4ckUXLWXbx? z9j!rglGTXjsT%1d|3K9hKupVm%ndR3;AyK7<1ICtmCEl11us}|Y5wQN`%*%{G!k_- z_X|`y0Ph&n6xhX9KBpz`A@FpGl>=6oW z9>dqLxBV34xSB;uwnElP(P>7V0Pe=u!kxDlD|*i}N?0&}7)`92f)nNEFTC4>d-mRsK5maTzP|0E(4g8 zn3o-Yl!xL}e0CWhAFesKuZ?s}Q;iIdhT%Du1 z{W4i5xCKkHm@GvS$xoNE&U!lAsA1R~X8X~NqN81~@vZ=>DoNte98opV4oxCCe9mqB zQPuS@Z<5O)0P|~)syjT+M$lEW6NaJK#Ha^pqC=4k$nN`FeYT8u-CA7t6=r?#K5x&m z&E@fh%K$R?uli_=PJ@562&dv5(EIkOf0-GzjC9K!6;p_7Jk`X+n(&T<)Bus`lltJX z@F^|;qzZrGJ!Js1=&fS$@U$s2ygY%L$10MG1j{wTxec(m%L-a}@ibjy0&ajdf2lyt z$c|h;l$xyMZ5%ZfrVmsS$N0T9#GOc1zm0D(c~Zs4t6*4amV4SZ!S-I$y~)yXB2VYX z<1Do)T33&oKhgOOpol`%S6fBvPYu19=^&m!liNkj=qn(C=_fsNU|C0Y8FzG)>&IbP z?UH)f{|Incov^|)Y(6T_m-?cC+tf%neodYg$vfai3NE&x-Q!*|G6-EtFARo^UTCu7 zt3&0+9V3a)Ydn>_JH1LI7%XM{?Hiq-ri4JXpP{!mC9MlE^u}f@dFI+q1nKM0Hf0A^ z1KZRxXyVMng^@=R3xWDM47svxoJY&S@#>&E>k!DwXN%x^y-ady7@JwGtzDO zaEv5Hq!25}u--WyntoH)i_ML{4cWgw5CC7#bTuAf>?r4Y!RuBd!Y6y{!s2u08*bx|cfqV7tl;X7&P76e`_!Ld zxZ3TD*Xv`=HIj_J!4uHpWa6(MWV@zWX}gS!f?H}6*%vJYPSmj9z<(Td8l+~zNp#6n-u5T-$;Jl(M)xC~CN2LApt zeoahUk*Im8yly(kl@R;;RGCPdYw^|nUg$Afi5+fm=Kp+D)H)mOlajPu^P3~~&uGI$G>fyW>AI4OJR&$4FmGB5 zL&7eH^IBLo6$OlIE-5cTmqv*dNKsL?{;?rPod$@qbz(fK0W$B4B9BPKByVNTkd#w6 zcmvl1FeB%&deQ-J#>5V+fS)d7C1+aS!X^eO z1kJ_YI-yZEx_5!(8?7L?d)NdooiBkJhIO{yFM-}@8hGQcE`ug+nXbJJ3PdaIC8d4% zltVL5m*6&a++Br9!=Q!izO9;MzxG%2R%(*`g8PF(3D-KirhNdb)vOj_hcDmUMcVN= z3CTQI)q^Y8g$bVwVn;Y|j;Jp>K4yvtkL;@EHUnbe>`rh>!N44+!7v%`s}sgk_*ngM4y6r@%7qMjtl-{@^s;U4n?f2z8ig7J!$Cuj%pFa)`V3d2!k0!Qz8oFZ5_Id?m=97;ij=Z#R?Ra9s^BSf<`!HUwOuE@+#KlmP+z24}suk zHg&iF?LLqACk@`xYKMnXzIdt={nQY%daEsI3lc*|f2RSMS(UT9sqyFF?Iqos{m_wG{@80KDA`G^`~X zH>~UBcF8zy>&86gnpfTW6?Xmf6F%w`v>zUDwQHI!ixA6t2GRK6L3fbl{hrBVFvb^gvZRxRorz=0fJzm(D|} zJ7iU!fA~}ckL>j6gro!1Bn~yFL;DRJct=GHW|AyUAvAmDelM{IY<^{v(~6rOwgCYo z?1|WbQ?4Qp+^J!*_*0AQHimQ;_2zJ(C(|W-NFrn2IsG zF(=M|mh5^x+CeAusbO#(X6qTmM)&-N4te10H2+I zSo<-MFol~Bc#$p2$yOR(uZ$ZvNcakpydiG_o(8fJq=%1=lI1@D6Fg(&mz4cVV%n}6 z!R|*urqd9q4WxURpVCcg*nXocd7@cYfH_?FyGWQ6H9 zafHtJVWcXfM6^S%dj2w^oh8~Ql~*dfV!KfD(ivjAEoozN zmZ^|?Gj+}w4G;9=5rI-SwC$Nzhc8lA<3?TPkuYDB11^rvs}6!@q@QPfS3?Rp4sei4|JA&ifCQE@lP-P4Sd!4 zJRX{y39?4nn_)rZ@T;OL(ImI|jFPt!O{*#Ait3MJ7F{(Ag*nDt(1R5`xm*HKjE%xw z)#nC?^G9)^rL|C{=m)Fh<})K;d;_=nfEjbDeBtp3hW!vWjhBSYXPCk1$qm{4kCeovk01$neLtrxQ@;>~ zILeiGyR7TrS?h8rGLFN0)i(ouv8El|e*at2$kj<}P>Zx<1wb3k zku85O(g|{km|cDK3-mt6&_S*)QzhN_rB%)1ApZjnSXYz~H%87?ZwY^m9X@*zsTMNS zxCH;gPNd}cXuWMyY-{AxH1c|dPYrG~C*yuMlxf(t>9DaKtusfimu2B2jE^6Ha@in` zTyIJCeid(LLnAc#7%AUu&_poyGn+o5MP&-PJYZ&&T_aP%(CM07cMuwTHEFTp?$1hX zp&xsFv_R(@poG)4pQZ0=hkgTw{svxPVrXL79uFJ#AeC8bGCl~IHybnXFYmyZ^)arh zqc7}K3`YK5{4#7?Bj?7+VEtzCJalE=GF>wQ#(eqG&J%bq=jOb|jePoXm7C*k4*cc{ z8>%{hP0^l2Mi2Z3WTrx_;PJZAqJ8brajb!-AoTlc)tSMMvAZyx0R9pwG$~uh>dfNf zn}jec_z@bK^Cx+GAj6z9^Xuh=cS35I#?tSb6V5qm%QxQUO>ve9I-Up<36ZIog>7jO z|6gSm_RzN%S|DSImo5k|ZeF&TtZ_S6(#$~p&>B?lR;!(3QQmx^d!m(z?*m)JP(6*W6AC$y1E^=#F?)Uq!g8uX_ zq-GAVC#Aq;#2}oB1P?E-r@0RZHUkB3zKqN1$-vU=$)zbU(MiSY7)WdMCEhFTucHLRkb_^>o@O zdAs9Ctl-0Q)$+m~21|~#nm@rUOE-SMI;=#w?-$hIdx*QRIh-6Z=JXN(o+u2T93Bik zHbagF+K&FHD*ir46a+0I+07!@&mQ1|+&U_F4OqO0b5*z^$4^Bd#m=3*IMk;}px z0OyHo{|{=*0TmvVjW6|0{vGZi)Jq|rx)54CK?K{miyvfnt{tn@`LLgjS)=nkP($`2 zUj>^rft&Un*zGgHX30)(Hu~|?n_t{rHf{IWyl;Yyo9~u=+a}PAm!VGtvBA*AxQXPj zktX?pYDZi+*`KGz{j;#&)3)(HQp$~B&=N0lqH^12a{DRPXi=6cujEHLQY(8S`pXC4 z4`j>1Mv&+&202pvfOWR(PhN0$|K5hUF=9zO9~q^^o_nTU=)3;<{#>1?riRC*`<=he zoz@%eGNu^}si;AVpTyh5r zRseQgee@Ga_%<%;qEgNmsX|^rlgchkWu=&`6!dpsiOBz3ijHQGx6~xx2@`a_1d6C# zeS=@=jgO(%cafI}UtzvoiTxgejewO;VAe)}8!bBZ@ZqbY-QkTm7l(+6KMpS2c(5io_VAhf6qb9j zoM?F>L@qotOVC;SeALwsY#^JuMXXDrnV9R85Dov44Vq#J)dKAlD>?Z7QJt`+hOpIJ zr$$$GLx**PNX5WfqoD~QE0!Wfg7he49wY~emY5%xYC8VtcIia=?)+`;&O3o+Q4bd#k6%mKsca&BR+)>=eSO0D#Guv#;gP(K zsSArUDWX92Ewl6ih{2axM1fXmjX44^rxNP!3ng7nSql&9x}kd+PHj1!!v;yTq5biBkp$(a4%SA-}XPB zZROv#pDfsZtGf((X{?NoD+h=x9X%D8^~BhJ-j;FsFt;WYews7=(5m;~wQ3ndo*NH{I#hXhnDfsuU}nEm5~tmCychRTtxk+nLTuWhzCb@B$9C4c zH?EmZHxO^pK&T%{Qf|p1b1a+({kyr&o}){d;iZ6g`5&vG>N;tjS-lt8GO4Q3DrBCT z@Lm{GG`a)xslG0A`MIM2f96^}9^CCo@bhw3qpQ1(+xoZagf1l$;5p!$qvYRvhqEB+dDp_f{at5KrH1&^yC0y3I71)eVly-@ zC$F-4TsH7M(PH=rzYRxXCL7`U@;L$U)U>W;p6e@zofu+}&%9*bDndo#!w2Es53)nj zd={bn-tb#xpz6F?)cI*zcH_5(fde|BO9^Rbiz3AIYh`EIzWaW_nC=JOq8|ud)O6IY zPKiC(EadQE+@A8a-Thme+>qK1rq#Ka8Sh)IK$yJwUgKJwn52YpvvttBNBt9wSL10+ z{+F0Mw8`{~1EoKk$V_6wH^40PL6=VH=l+=5zZ_Y#txSQUP^gtse9Hi+TQ%L>V6795 z)G%Q)^cD2eUw1?Qx<8JVLW|G+tGJGSaEfwnvF7yp6V6c^%%Wcen)!@UOdTD=wb@)g zEwe&-5L(2)?nGPJwMg@vHk7esW7QEA!fVWi*PrUdD>d}iY<cop46GR%-x z0rHDIaYt%qyz%3GX5O{1yN7$rSB2F@hi6~`<>%f65QzbH-QTTgN#GpmZ6pCSc~Rlov@^Yv9d+( z^7@THbKd;~w1Vz7|I2Q3X5S3v`(H+{`|VMDi-!V_0MntxbGXIXciJoMSCZ#3d!v zj;({fM=dkyU8Dh0mH*jACSm7cK(p3bDp_S-%zqJ#!a~y;yRd?gXp;4Xr}L*;@pAi& zMqO6<%vsbBHhSyp{sdoYdRqDRE$XBwT2)N+n1g_ZgtVKFwDQgut@x>U^CDq=b&KpP}y;nZCy}^l@3; z3plx$FeTm^@?K&j=JWzLvN{nss~CUEviat~Ho@8v=Ro3tazgdHNKpm@Do;Xdvht_N z2W6#=GEV<+iG5Q;zJep4kIeC|D4`c*_tmRk0XO6#Ff$7>XWIxvG8Ne2yUIjtq+Eq} z5ir2(wvzZJGy{s`$V#RPJNy#(VWrSf&D(7?c}B0-5Tm8C7%=~y9B5{2Gk>jCj~tXe z;k3>tK@H<$udlHTU6c*5NB!dlQ+!cXd~_FVxCNI?erd?^FwG({e!+PpB>77Z=DTr@FN*He6;J=aBh5 zU_YG$I8$;47a=+5fjI!0m_dtauG8vs7WEFI#liDLzJHpJu);m~g4X+`_U94KI?+!N ziKK5=LYH7eFTt_UB-*73W(AOmC|P4lMyBkNB*2gRVF7%PAm}6SU6@Ujx%hc6J)yGXAhu@nftgv>~3Yx{HW4m=e0g9+Bx)3jM zUVdrArq&UsSKr<)9DQ;9S2wnHjymsJW}UjLcYM6pqls6%TRuCr%Fthc_WDAY8wR!A@TJd{I*Twh ztQkVJetiht4gV#(VM?enI}~269}4LrZ16=``u`Q-u8@~V<#z_91*K+Hxcl$uC$8*Q z@ssY(E5V7=ELUzBh|@4rgi2NurnRMTlY&R#6WfWcRUPtXRtG2LB+1*Y*&V03WxW&G z-6pSv7F&0vNoHp?N{}Pm?JgKZvK8AxvWv!T1L4RiOWjLUR=9IT`$*41b34&-=(w~7 znbOwW)!wGMEwTvJS&Atl?C4TV_rw1`iwR0dJGh1jQ$*3xWtc9*y34RFMI4>J*Zy=FHuy3u z1#il5k7|cDSzL*d#YHgJ{T};;h}+f5IeHe0gYj)OM^%_q_Qs>)NP{_K|HcP$Q0&aV zn5PtE2<^!Zn^>T}%@uKuH4Gy~-0e8Za=0umP4czz3OfMT%;x~93Yt8gSsC396@%WY zf3GEMCJ*8^X&uD=eN+Tr((UkHCNn2gMly&uJl)mMCYh2k#L9^rAJ29n@V<%a;#1-U=Ngs)ZIX zDn-ScQQpumm#SXk9*L>Q^<~m+@Db#Gb;5bD6vkiV0=9#M%aZ}(tUYkl+z#Kah(`P4 zfgofLyB#pykzb+w$3a0X_n$w^U!H@{-vyYSrykyq;&p0s{Ic(k_t9CBY0i!=$?v`- zQ^eWPD&oINBz$PYe^)r)1G`!+<5bM894Nj3Cx>oVV>xPEg1cAwBn#~D zg^x3TU&gN@{$2s4LmdC5CrTvvL2f7X6i!uvTY*n;qkePp`9SCnG4EcWZ?fruZQ7HL zz|1idbyj1FXghu10j;1gbOpu#;-mvPw^6aCaL^Zo^t#y4*ToGx0Yfmrg>3gbUfr7& zL_Vt@_t*;AyDQC%vnrwYmJoC(ce&>lH1QMX$v7(B?pz;S%|7*Te*icNVz{+IHN)$s zzc7R5Yw^qBJ2kxmb*S@qj2Z#SyVJX*7TcWS@$Dyx!XB5DlFaE3pi(mZgtRUMen4O< z_Wda@GY*ywAfj%9+H{}J!b=fRr>|&;F1!X_c>n7IXB3I}|E%gFdiY15UF?0^CfMrj z-}&w%I_!<;h>o{ej(NzUeVb2@IAdu)o;xB{{ZPGCWj7{x*YuhjN3V?UnR;MkByN;F zt4g~exV52SP*-V0#&G}7fXVz1Fzxj|C3xk`LstY#D5n(b8W>=vOl*q(I1a+yy2 zQA1woePv1e7#kw~{^+;h5eQsX@NHz4snt6*yvrA+Ly;$GUhV9erD`rcYab02?f@Ob z7pG409v!8XxOjWF>I|&6qlDG^FXD}9%Q^!bVg6GdIeuHvZEtTGbcER9!`)I8o7Mh{ zP+rY5GoIat)|iWbtkwOgri4_oo1w3<>@0_OZ|mtx`-Q!QUsz5mz#8gs4EmXjy1nyl=A{Y3BPC}ij8FrKq zPqy~@N@MBa#?U|N4I9MJ#8;M>*b1t%4W$>9G72=)ll;9?5cvfgVZaF`OM)}*I z{5sjjk_kl7JMS99)Iko!3T{NDPV9Jm-ls%;F1m*h_m_YIT7VRWS;B2U|qM>!)Z% zhYs(&s!pe?>RVLR28omv%ZkW%uX=br?dHO*C074V^C&!9qcc?)^_CRC&<^QS^n~H; zcMrp1Gz{MYhB+CUld4czVo<6S#HvZTl4}u_IgR}Ki@tBt!4l~?72gw?d~Pd>!|wyj zHYGGk>%yFUljZh`E1CqhPjlT<(&d^~jQu@48**VYoa_s@anNFed0<$niucf*Ke)BK zSo%nNx8k{ESfkGRN(uF3KU3e?%;8T^UrlLXzXh;kQ)Hn)LJ~Dwd9dGC#*J&hrVBUC zeo3D6iw7N*xQ(;aez)g(%tpI35yLZtax!hj&jY5yWf@JSct6MwdTd$GN=Zp$p z86M9=nIu~}<55~p9Ar*gX=Z%fL9E;p)*||Tp3F_EeHUvO6Cdb&7nD$9_K0cKui(?~ z!qA)ISX=m};MXjw;>1FEi{QBPnd_62pty+#ZSQ)$!U{(6t<-`QkT1HPCMzH}i<7{m z3;65fm>+p8#Y)8C-Nqk{DOTTyiI;9^PODhiqoZUQB9eV`y>fua*>&*h?hgks`GXp` zOZynY!kUUzSd+JuMIhs)!hPi#eM-31IL_AYV4zc&=_c9elqe1c?ULQaBYafX#$Z2`o;f*Ce8yc z`DF+9fy5)t`RAa;sNJY#N*0L1lrB7tsX57rguX9GUS9|gu+}%g48{dE&`-qCc$`jbvX z?tRFpYSoEAO2|E1y-#Xr?V=&}1OE}{_-|i|#5v#&9+nQG>a$D6BjLmAOqk*b2=9e4 zMehTI$BMZP13K|Y2@R+J!kEURVdIe{{|W|t4tTpSgQ!hMTJVVK{^6qnXKGVTCr+xd z)(JyuNHzV-qTRb+7}GZ|Z_^uQ#MR>w$jd%6M#H{eo0;%f!4dTf#z5xH>B6NqwXx45 zUe%ZB!lMHhb6-IN&>;dfTE%=g@q6DKf>k}XT_-*MKn*pNb zNpA&wI8?m5rT(P3)U6TbDa=Q_o}l$lalO!aNGD7wA*5^_^cBJ&QSUn!!Yrc;=6_i* z{|M80!C-t&irth+hdxbSIV~VJ6t?*RK_SX_PB|m2*r?5=Q`Xll*9k~Uh#=e9=#Y9% z;HG^CcKb}QS+dicjeh*}<`;LDP1}7o@0(!b=DP*m|D!9hcMeD<4am0uWZ(%gZlrt+ zO+tHN>-1-2GoG^S@T$$L%nx_AT%Yvbjs^WwaOOXA(E_MEtI0_xE~z19^p~^Jh0?%x z;=}z_SgL;A;{MWPHOlX z2Ys7O`Y6lLo6Xi@4OS@_B-!`9vvFbh_RrKVxi4VQ5Ef|WeH;;q54DYD-mHdGIw46B zfuk>l`0m|#w$koAZ)IKm7;%U}u2rxh2~9hj_9$*BRF$$~{KM>lKJ5|JjhA(2b%K#1 z_D0|ONXz{Vy*`SB2gEi`cBAZezn4}o6QJxXSC;X<-?aO3BX9m@oj|09zoDpHPX4U40{ z7?{3!Ht<=yVLiYz%VE$nto&0^#YXoJ9+g_cbsF~Uw7W9Q>Bm+)BI;;RS9%q(Eqp(4 z5Q$ah%gq0!#^{ZFJys`9so{8L>+AbW?}jW5L;qaI?IO=iv1#Lu z*YNtBSBEy_Lz8|bbOg(U6_KIIBVY!3J!$dHm0GvQ&+1-H(FsgySRAzcp=;yvOB*(| zjyS#g_IBaui|fC-v9)v5dDk-Q)Lp&f7ZbSWRZn-q4r|V)KV5fIt1tKNu`}Ye-hOwabcMY+y ztdAgnx0-n9J;52Vc94#UZ+WB>os`fvc6R!HtZ7Qo(9s!N1T4=h;dn53;sRSeYY=nV zMP_|{!Y;{gfBqLKFu#q58)f`lun*?b!fqj(cDuCt4K8kQ?27WNmawy1OvJvy0uJ1@m)vjhjv|Q$r8U z(YI35#HFEE>ITmi+PvZ%JL&_$_FHza<`MyTkk=b*a*W*dy&YFJ0+|!I7e<{y( z^2@g8Xz%3rZTlxW0ZI{3q_1F;<}VE%pcT+$r0gj-7EW%E3rdi+y-AD2)A>7}@kVo4 z@XpOBPuVrDTk7JcJxVRP{$jO2rW2gh5Jq$KC5-58y`h6MheKiw4Y+{&GXCHJcxEUJ zkw*la*OlOx8hqo9SLo~K$l%_AWY@B>J*#5uJ=#(E#J*|I)QM1P_$1`Epx@e*-c%VP zLjSX=ve_ww%%^O~{`E7+d$nWkn5U<$ZgO|2Y$m@vsW5F={wTXCu)X{%&2fTjipopP39Fs=?`J~f)K8whF=a%Vr{bP?cM~(D^E90)Covx z2qyi#5B>!5xXm=%`8I4PM};-K<`VE;5lTz=%y^&AKR)?X!+Xh65m!LW*`oI!{ea}f zZHRWN|9gX#4qV#KpoVsGu+_Jn{1dS7wCmv8xDFN)jnL$FuNRtgO1L%C&Cfu^S?Iq< zv&QYz7*acbf3>#GSSK8*;hARYd%DK_6PyRlq08i3l*xtxv>eLsg&sTby@6fPDbPMg zGgnP`mqa<|*w-?mv#>dXLeu=Zk6N)?f}3lVyxnOIJ4#4~U=Wqo$s@iPR1(jdpZ1(p zp+ag_E7cV_Z##n;63JFyIUT*$H1v)$_6Kt0W|^P_Um8{;IS&Q+>0086~mNrFbGvE(`JQMNUak zxDxw4HOMT?3UkuB9RBD5B6XHxN{A#oTYXodG?8TJfc8jMxvp)WI+p`5Qv zBfiLS0;h77tCYb~nK>KtnmXc(;Jz+xuK3-JDxpqHQ^Gyj&C;8Dq8;cA{2=5_uK2PZ zZLWAqSS}dZg-7gsEVVhCeeWLV%XM7I?Rr>j#f|OEj&$^B;AUkn5c!VSY_iFqa=PQlV(hSbxjg6%QrqyEIx;>Px6U3BoRCdVdOFssH?lcU(Fv~~=PI4O< z9zoT>IGq&SCgDX-=gx6?nzq)FZHS<@E+yoZ-7I~t>X9VtojZV<(c|4)jCad+YX0T4D8?Jk zH%7vY^i(C^+09N?hOIz3FyW>u-ks?n=7wzNNXQ_Bc-~Fo&P|b@H<@D8Ym>SB&k#y>Ed@bg|ql? zYDE8kb)a&XPW(|qY}p~cO23akT|o^Ie}AN0MK7R9G*KfUc@qM!sEM{P!m~i{=5Ay4J8Ui=AE$95dwX);+{Vr*R$tVKW{QY1 zeOCfBQD*39j(v?s7>B+g6~a^m3h`_U?%{gf#xtkP=qy$pEplMw!*BK|yD);6WIIai z+obUG&a+xc)=TjcwKk23b;pNvndzwxRpN8prq!1e1a}@KK=g+e4nntfbc?WYRg5g2 z5u;@qs$xGHsT0}M&}I5-8fej?fzxHN$Rh|{!(h-ir8fKswB!M<9e@_2_WCAAErBn& zuf0hZ<1jfc6M@E2qmbM|0>gLx~-3aOPKhq|Vt6n1AO> z?nHBE`==%?R-Dg1qSczkjFFk?tjpBUXiR;lIU2?W-*Kb>Ea#P*bd6Oi;}(3DL;Al^ zLX+VSY-{S;@z*TX45%i%ZOSYHeUoDpNms%ID{{dT%@f>T24{JuZ3{l6Ih8GAGTQK9 zlKl@Ab8yAwq}OAVbpzV9aQ{eUflee-LZ{iG0Z+ezOq;+NI+B;=?I8Qlt698yJgq)Q zgB2V**NR)!K)-!v<#`jj)U(5pM5nPET8v%ZVVV#7#aMytoQ#!Von0e@b9T2rlMDs^ zK8OJ|uTQ$2EX}AB;hJPj!+e?1`3&pu8Mvf{^xvZ2)5*{w-3$dihOPcg$Lx2%Wu8cH zncrf|oZ|r9ZPDdv`9vZgd@$0Dxp|942xoMJASuSGk_o*rVr{EJ?wE&=d$<$@e zkL5!6ISeR+?6v1aGAsjHd^#591`T9bi=CHWAQ9|6=>TOj_XP_E7 zoYg0@k8-UEZ9NStUwfn<=@z&3RO&oSLv$4d-*o$#`ks@c5WsiN9J|rq^tbq?ht}c| z0EPSY0`_kq8kY{NAaXghcs@YvFh2fZ4>(jD){K3&20VrAmG0hn7O>%ETovF8G;)x% zWMgiM+*Brggne3tu9rj>@!vWZ&U_9m9s3r5zk!X^NUqcxB=_faP+&DB+VuB4@;g3`j5F z7qrdBoPe*->8#GwuzARAM86r1ejJ8gojvwJmt$FKmWzhBJ0P$JST*4OD1p^B8EY|v zP2gp#3}3+z23Nams4DDx@|6lZeAf%&5sGHCvWRg7?Ai5Dx`vc~Ddq07&USUXfp5?Z z@Gq^*84fMhw_?ZqA@5FaB_3g(6rNVaV0m%}IYkL4x_Tsa51MZJD=%3=UP*o;5O+fp z>vY7g44Q+Ht_!Y$mR7WvvnU+5U*}7ph6!ZqdrWWpCm8*P(VvO8_)KVBa#cOt7hycg{(a!c%@kqGFT4(@Y)*bH!{OS&n!7=i$wpjRzOqgLKtA-eBaQD+6NX>H10TPnhIVwob=Pu~WG#M zs4;zxyAn6o+{Rka(ML!-9$^uc9X~#)>ykV!D;$QvsDRJCLUSS==frC|0{U7ME=4GT z475Z34f1XSD0YKwm`%3px~ExXUGr5$%hLgKsTRnUUCJh%K&FQK(_fDNCpZSRq`T#} z=$4mp6qtiZQ7E<9_hrYF9^%(@IK5Fxw0!3tBimksnT9B7%IRl zO%4VA<}f|wSsAo=Ty0asF*EjrFZ(2|H?2?DdC9cUfAq+-Unle_;Rx;Y&OWoJp>NeKG=Cd6I{15%q|-3|E{&3lk&NEx3D5y zxehLTQFs`1*xXim2#Li)IK2nC0B^h4kD@1Hm4GoSkgU3Bvy&V!EzYfkW24X!iX7gl zDFDw01W~wAwlL%453?huHfYbLn~jFM>jXR{grxmUeKpebj?mCsa5b01c7g2QxEj>2 z^bzTkystou`V}_h{aS$pbNZh2R0qrx{{oqpo}Px%hv7k&{R&HgV9oYnEXP{hCEUA7 zf`94*E%Nhk!AW0yV<{!PA74_kqBZOpo>kI~B$sG*!JnV+;i^l?s~Rjv#;q=a89o=w z;H|A*@Wjpm+$d(wO@_C=~<~a{Hur=+1wMG}c%tAVy^WdxxHJM#GnBPqU71-@t9)dZHfx zXaAn-(8T4M6rR`k2`hfxHQ(KvP-DOEERE2xp{ye3h=n7?C@tdAqc;l z>gj{4*~7i0+6}yE51cfX(RURPB_~P$_6`_mBb=45{&v!?2kiwa;;ubgIC4dSyjlVC+x?wG@jDq`1S!Xk0Q>Tru3uJ1# z&)kI`0_e6$R1sYc$2!)qxNG62hJ;j(5ww^EH0(RzRDTI5jWvtP_Nx6_i}ej9pPtf* zb!x~{g^*+YY`0{;Tb1{xKT%KH?Bapj$86H&!IGj z3{~^KI)rvEDIa$-0wkI}3ZkJ$jnzWC9pZgvVeN1>8Tbn+zn$IdQX^_;$BwN4S?X7K z#4k6h+0Kt+?8%WDC9x1ih~{IJ#E`aXf7=f3>%=rg?5N&V`%mDSPiNP^jca~Xn3{Ca zNV(zd(5G~(<9gU1+JQ&7XW&x~&BQt#4l?h;e8rHOjK-A=@GPTw?a-13VJ`4^D5(N z1`BCb$fatVRpy?49Ro1W>Y#$RzoZ%ssrzF1EDoH<%o)H6szJu27E2EJdv4Z(roO8( z%zPch9Ym}R>!$G1;jwENB0-sCk}l>P!T&n7lJ!!pmEf&J+~jYnimbQ5#@xvM$X)52Sygf39V zNeNpCUor~v#{^29NTT<)ihJ%OYjD@xm7|7N7EQL)ljh?Tq<-p|8}v6M+Icfs-?HF0ii_)iXS z$?po%CAX4Q$8+xr-vTU8^r$$dVi?HwO=e|kT(+LOR0=Zlykxo1BEB?y4{RWzNpI$) zLo-K-7-BrH&$$(x2WWu3+&Ee1wLQ9WqhdFY+zItt(a_wLp??)(gQ3fkCKZ1qWHxTt zIc|Ws0vC~@bMSPwt@#CR8h)@0D0u5cZZ!;I7MDz4e3{65lG~P!&wv4H-UJ2FqT)ak zn-$x6aL*7r^5~XwnGGXh~*(2J*HgvKrtE)yM16!81e+V`dD#Q%8!#U{!Ll^W7k(fIzJYaP`Y*w z`req*wpRxKEc6t+&tuit+-uSBF85UcX#vUl-aK%@eD^cqDKj+k8+cCPj=SjNvIl)} z)~R^Dl`$mtOJEPnCKYdyOjUgc%MUuMiA^G`hBseYEW`?)WEVr(3&4Bz>U!F?*ca{S zYjE`RKcaNO9+_29@HMcr*Z0PQCZ`M@_9;@duwS5;Fuo-{OpKwx?yuc@adICtFL(BI z`Lt$uS@44Oa95k#9_;ROxbU9Le#Ax9T}l&cfo6cMj8X?QRBYbb7t zP^Q?fY0=q0!6Izm+8RjTnGOj`sk#(#*XY1L#; z*u!)lJRvTWiXLT-zSyRX?hUp!jQl_ zUS%LVy*hmBGI(C)@|~2MUj@(AhO`y8agjnkHA%z1-?ypUD@84-{2nmxO$KRd-aj;p zVJK4BC*PST{qRugdUdvCumca6THu_e>LpglnQ7 zny2{s1LPU=`k1-1&iYObMLS2|GbwtPZ|HBJ0Z~z;M|ib-RNZjE-v4+z%$j=x{IWVm zwzmwk_}6U-3Og5J1v#pk`u6KmE3trwC!}rj=ZPFpPVa19SN_0(AmE}Lf+k}+Va|5d zRFa%_LRxg1(PYzjF}O1w=K~i_Iuy?ag!dj_aCj|6I2D0SK<-b3X^n z9|=zG?o}~C1?SMPI)O2Iy3R*H3A1aD(k1lk;px?-p+5qx>|TZMEkXr7UelGl_~pHV za^~%PcuT60ccYH{%z*@Gq4Gz6Ou(3wW$H9C{aT*%kxc<|+aHMGd%$9jpG+?1rN#$d z2gedX0ov$KjFvk*KMETack(?1(!{;_mMcS%>G?%y5_u)`eKhR8XaK~-vM;s`WjcFu z54ytLl3tkjTC*GJ?K3Liu3?3Qjj$rq7=D4WQ;=`Y)Hg(LVj>UwjxZ=Sh1>~rPkwgtsQ>#Lb-{ve*!-HT7?xz6V))IcpiBH@T9>c zCs=l7nCF?Us*+nqtRGxQi=@ujRCO(5 zuH@d$WucGbP`~usvoR{24}lV@*KW4H{SwV-8G64I>r9Sxk_k%irC}=GOXT2W`G0qC zDhZLPM(*k7j<3R3d2(0caO9prD``Y(LRW0~;(X<6puSCtPMBT=OpWh19Z>2D)4NNc z$$T~Ofxm{g@^k1WTzc6-PTc7^04-MRIO9QnBh3PCQZ5G>n3;t?(Mo^rt{ibtC-Ny` zbM@7L(zKSLBi|!c_CHZC?&040vjs?Vq0j zO3>58`pz=8yfdt?sh9VJsO>}#7xK5>chECqaUE%y_p@&7Y+&Ir)xFF&j&PI2A+yIK zSIAcX8X)yiqS-fxHLXE`K(jxU480fERukJN8w%oiyV^nb?-4r)VS54iY#-EGj&TUk zicg8IOL>a&Y4+G|b#Nc3m0ZSP*>_ex<$|~t%se#HVP_YbTo2kig27Qkb2I4bxRsRX zr-kpeoo+PxnTQ4xU+L?`3vX%>vIwL-CHt<6njWGPV+Me4)^B`r5d)tG}bh}e^NJ+SmVy!s+>X;0!TG9XEtOQ4gaOF$MOY{=_#biW*? zf(d(WQr&LU3Ba>n&d6{4DgOvs$X|}}3J9hNGVwoxC(=QZs})HQ=o5R8BO9C0;|KQW z`2#{Ta}KqGoPO`cmmNW_Czu6Y*JkmdNOSouGVe?Z8Q6ym$p^YJLik`OOgLSl7oOD> zjRO{L4r`@AlhJ@I*h!pJHbkh9hAmhoFuWW&{m7)-ho06UKZr#b3}c9RpwtBG(U4uQ zfbuqh967S+$NRml6vY1&OEv{-6?$R8Jk$-WCR}t1uG0Fnb$jMc6}L@}4%!swCd+;Z)@LYy4tjH* zN!8@4(P|j4Ciq!8XiUee$+}nDqt;f%unrrnXH#pw98dW}(8To`d$z@l#-{#57)x;- z3G7u`wzs2!h2ZJ!z{k*r?dVEE9NP>0NBPe4&?vHdoi^!(GrvXT)pIJq?Ixh?^;V7S zL8A+9LYTJ_lDp4Kos&yIQ$sYtZB!jc?9=qWlxqo z7)j0Gs&--rygo7_34Pya4;Y2PCxeT7H?` z43AiZWoY&quyj-L@?0XgBeSMM0lTDG;+vE4hk-e;n)|_%Evy5{{otBa=i`$sJ1n^p zS8ptzTUtOOF-w&w5e5H>sx{e<$rBk`S$ii~m-_w>6~Z8-FNWYk#HU5@=jOOfoZi*K zeG1p4L*M(yDJsOnhJy|kjM4bKGh(;uV+3~;77zTPJ(c(iCYZ8%L zXlKT2?6r%sU*NY`Bp7!DhEQ0OlDj|d47%!7SdA~t*T**-=mBTe@RO9- zr-ui?+}JZ^bakY}g*=5K{-FT;PQD4oo!Q1;a* zetti{wjcZhyLVlUUq|OEEmO@&!OsW~ZYYk)-tS&53Dshfb5W}bRvF6vDberr8_L(CvQ{VXL#S-t>mMBnHdSj-90MO6d*RY-8|-kskkRb_aKqBAe(GP1VsZsB3|mh0)8ZVJg+a)W>hFS1n@TQO^;q}xN*7f zG5!+eUqA~#%&{}p+ml)LnEGE3`Ja<7AJPpv>L)6p&wdw)U9kvNRZk`L_Z(dAakUGp z@gq3$m9m4+>IG9c$|cKsVOnS*Ay&Ks=l74y9!p4;=@;L@j~tw;l(wM!Km|*J9&ehb z;>+Yf4wHyf9c0$Lu_SwuRWe{JZhP8il?=XTA^)zw7%(nlX zx$J`3pnsfp9RzLYaTdQCbl&e1ehX`Q+(2NV8b>N0a&q=Wcjjt@wF1C?)Qz6jeMPou zgs1OlF*_XQW9?fhRd3WPvKm$5d(SkI-&%t%1QwF@C4tZ2`LJ+cVKZF!?@m~xX%wMz z=Y_DEE6{Uf>ozN(yh89FZ~I1t)FqVwmkd(i_FGJ1&JF+isRnu6^)X}nDSri;m|$Zc z0EP)R`3K;S+b)0E7SLm-mz~uj(vYJyo}gQsdP66Se2nQH&*s=dOwUtc(QqN^_^Ox{ z3hbA~V^*40mx!&;(c_J;p7PJRLxbDfkI7=$KYI;2D{vQn33#@Ge!5tE)7Unk(iv_cxM5v2^t$ci* zFZ@R)txp8Ht-!irzH2Km%S&C^D;&^K_Y=|&Jo#QgcM0chZ{>;)0q zij%B%-qt@%ou>!&XT7j}+%_cl=r06c@!m4&>73!C{R)=p)Wy5Syz;NIP2Nkd?lAmK;6)L6S{HQaS4ck6ibNEGmVfiF4wP$M9Axc}Ev|d{*Gq z`@8a-&pd~oh_iK#P)u>IJONzEX%2&H*&#F47_?CDc5>C1ggOT7>_FDz-F<`tBOe&_ zaf<`TB2;exJl3V-FJO)&-39Eu%)WcP-35vsh^ za6A}3Cun#1iEP;P`{in8=*U_BHp4~Sco9;pcn-Trh~lyD{3=aZmH3G4tC75$(l ztslvCjIru;6)LfXPkyenn1)n<@F~#fLCTXr3$25J(Vu~)g``@yz|35=+CI<;6hrH4#G;uz*EQv{v%tXpa%l6|Q&_ke`O^?^a(=1PY$71-6N` zT{@W`K64aUDd9XN<5owgw9RwGHL9ZjvSM2hTi}y04WtR82y=r0qK^)E#OtIzK1I!# zHM*D-ydWgqoA>7v-fBoa*Mz*E=?UC`+;M9S@`YjI%|j;Mr2Hl5;f8IEegkH_efj4m zM*jH*^3O=I@?S=XKDZk}$%<`1ltox3z5=QucnmyF=?<-b!mrMQ@4+-OW6i|5R(;&I zxM*`udm&UspA&<5B|z*K=t6LdQ&eJC@~Q90^R?(NJq_x8T-P(*r&nnq%pbZ8K1d03 zddOd+)jv$DWAd$zS|=Qyq33gP$!;HI2I{XYh^<8DsWq{pMF&RfWrAL5R5ICp=w7Qv zvU|ceKzc-HeMjzkJ_kJB7fa43%wZy_tE4k51mlFE4Fu=Am zjkPpn)IX*U{jqR2GbG@ptPnjLSbr0)avFJhRKE%?BrjIPOj8OE_mqbd3d^9|pn2!h zz+2>qrc}NPRNosL^o&eXA-VDkI{qMYcSp4y-t3S97N_C`nK7-rP9#T6s=p^+ZYP`c z$R(M08C>PhsB!MUMX1ZL=KbMXsDc((1E>ueq0nFP6&g06Y!Ih=y4ObpT6jc|y-fiZs88yFh3#gjGjLjav-=D5=( zkYw*BGPICBP;Fp^IVcqj4D;Og^NkKN9)D8f0E+OE3_m|Hix50FT9d^cZ;$ zY>Y{C>5D6VGE|LNfl>_|0CX-_f4UWTxK5E_Q(-;VQ+5aVw`z-6Bh0Nt$ez81$Wv}3 zx;UP{a}yM1e>)olYp@F^9U~=yUMGL%8F;bX!`^>E1?*XWH3pbDi8t{g?{p}ZuuP4D z>&=lcIBd`KvVA1iH%aGxMTM;y;GPtP?pU)fsBOLKFd;kurPQ@RJWrRif(TECmt!Fv zV9BkEryDJaW(YA8N4maAv2f_ib5PI5*Gum1T9ti1Kl7qa#v`i- zOK+j;&qZ5+9w~ZUEFjsVkAor58TuAvhkXms<3p1&lUY+hzz&wqD<_RqkHjXnEYoW0 zoF`s!Rkt+1c-fe%Y6iP50k4weAutps*&Fss>ASW3XNN^8@>-Bx$y2QIvF?+_Vsq6s zB>PY=aTd%0NN(dn_c5W4&_HxraVv4-^|j>tuf|tV{u8v2#2k*X+aRW`G4-|vMuW*< zknc!fk?io&uME1|*0;7}SSYB1n^JFR6(miW z&|n^}mSrET)hE7+&i48t18e?I z4udKw@l6lo%h;d1Gx|2(e!xAE@?R<}P^Tsk1fzDO%Ho7s#7l>@1*FQyfK9M_9+T7;Iqo-F%b;Re@k ztj^~n@*7@NQibrBCqVfnu=dKoF5(I#hERY+yW#UFkxvT=Y&*l)%FZxhre4`2e;`I| zdL8c7c?-qiHj~6GLMM4GmQ*T9?kPf13a#JPYdHkh?*I`%pwoB*vfDG34J&u5N+5UK z<#r*tJzjc1+(|2Q5X7!R8;KBXF{BCnvqBuu&8S+Z6ZWxValx#f9Yk1n?020zp>niJ z+yy3#Q@i6_*A;}4L?g_7J2xP^mvaHKz){~T?DL)M0eqySq82$T@QM?Uk)+K2lw+jpu6xZ@!~tC+ zMi$io_R$UnxbFc9s^j#0**!4jOyaiEVqkXPXHz^Nws@!-^uot7z~1rm9W-&)@`HiI ziR%U6B4AH#D{&Ky01Yb><^c3~U;`i0!~Dc>t>kVylAEfY?oUfR`q-Kz6txazfCuKr8P%%oZLki*9R7`AU;AZN)424U?Ug)ahJwMd6K!@d8gwveO8NWnIHg&3Ns1Zi6lw(#iVdwh-LN99*J zJAvi37Bp))yn657SRBo6DL5uG7lQE|F$h-{>I$$%H2aoN&V#zUBDf_b(MgB*@Sb!Q zR**9mgFU#=OGU6cKy~UpyE4Q(W7|yWTo~&uUgY_-1Rb zutD0|0?a<1aQGUDI6Phpe6*{0Xrm*XHl+J!7#hdc9d zyurhv3u}Y7#N$=sv}YhDP42DLr&pgtc>`{Y0PKDHmd^?|&@2pu&I z>5hma7V#_5JImsVnyQKB^%NFiU$k73dk`8Wyb_OAQDtn0rltFFuQfLsjVI^1q zbiyFtK6Kq>^cf5sc;dbu%_7CmBIZla{z|w*N;+k3t*pf0A=)u<(lyHef)=KjV`Hp` zs14K2n0U8uEGuUBbh~Glo_y}yFAtH}DWt!{9PDnmYL!Yd;JAF*r62*4!EG7fFkyY# z(H+?o4Fbu2VL%i<&~W=$Zuee2C8lX&dW}^%GjZ6a&IjcHVOBGPJ#ld z3X5$;s)mmq`vnO6A#iFz`>_0A5m4$PI}f#ymOU-5YIKHGyRMTXjFCO_?>YzBFZeJJ zwjg4SCbL7w%}kSvrJ%IEBxq}gEZ^fvfX_9Upm+4X4uX5x%=g_W!A%d%YtP)ezblPQ zWH2#e!E3V1y-q2-Ci4OED&@K{Lk|`0&}3^IiS@T}{z9}6ZJ+$G?`}WNy`82Mqg`O* z=uI*pY*?IM56qlZXkP03`S=y`3$1rX9X?90U+b(KA+Fd41Rp|q+cO}(sB&IS3ZJRl z#R^DaeV5?GPRvP=aC?vib&tZ-VP)W)bqa{mK^OF2txoxd534bB^gEOmddeSx9@dx9 zxV~SP_Hry!#dEt zn-##nJV=!?MUO02Xe29Eh+)L49?ri%!3-HKcNaXZpGEqwh}R*JTCo2yQmi_QCf}0x zKN+fjG}qm6z+A&t)6H`%rPvc9ln%2u=0|vE9tYnOI9EGOjn30cxY++`fcu&5SIfZ3jxN7yEvWxi zElBWz{{MI7QdO=VnXywZdF}=tCOGMTJD5}?PY|~o>blQUJ!R~LJx$~*v#xwsrr#&S zx`5e|)nc%7F=VS|bcaMi7alUD2t`T3#f)2W;*~C^ziqH>cssh+A3cM7G7c za}riK#UH_$P76iLu`!mSDCO*9KMA|u81tF|R0tU;%J@9^9Sx2Du>`|R5YjO3K z!1&F=-mrbPasNE&sJESaceZR7SiGE+3smT|D(jYYASseiT-lkB6OyU2h_=l&XZ^vFF)UT^oQR0yv5|mM`yff>)nszl3 zq({?`)E;g-Iw(e_luA25-rZYXTTc}Q7NIQdkzsA+@Dt%-a6%Otq|%M>@4@QpK%Q@L z%IDXXuXfP3kw=^muq6Nn#yus}HHg?M4rsOqfmTO%K3>ylXn(!!2L4EiX3Sj zm>O&9%|eZb5<3Gdwv+5_v>eL6g;mF~nt+bsIjPwwR&@S6Z4=_d+ zXyUV2WJ0g(=)cV}FePa1muqCbuYkpsdo~r5(e9kPlgaGg`Dmz@ifh&h?!sO2r-2}> z3CVpwO3z1XU)R}H-(eDB`87fjqZ8ZRHy0xh`h^X$`ebOiamXwB0x9@K3Ra3^66<{& zxBx`HH@|k^K1zhs!w_<&GYDVoxa`XMjg7<4uDY|meaz)`lWuNp8Fj&>$V#-UYkaiF zgDeYlyqm-bIS$Nbw1TKpGb4b;h49l$=DTKpAls45IsrW01;BqXVI8%b zh*4Tz=???vO57~J0zpcpc)v^qE*&Dn2*oos)&cenhAxo~apbXW+3*B9=maq9mCPK~ zc^+@-J96WPCg=q7^VI?0Q$m{-&d&x0su@?jnNGswp$)Yg>x02OuxFqZRElrWH z48tUsy_cJe52FI}44POu8zY+u2F#`o=BEKYy7Njbx)Xf0ZnFSdzis>!h`He~5c22u z^OtB4hnaoDB*9Qd-K*n6!}6Vv-I5gz=8;D_Fpmz*Qny8ajX*v~s|C@}BfW8*YjJ_3 zbJ(L!{*IvZN%LgR6Y>7qCc}E;NEX>e32Iu1Iop}WR%pgC&eTDzZ$RhBZ;lVz2^QZW zWDc)@+42d8&n#B$G(_KJYnmR`;OJ>{m;o~kFZBvK01Cvtm;~DW>@H5(dK;)&Pzd@` zwoGU56i+r4I0Fk+x#Z(C{#q0-!hb`ijN0koA=#Wp`fR@*DCPH9W+xVdaYy9C%FvZ& zoKEn~wmTrQ5cWdwexN(5lw>c;E97hY69a2J#Qvnt(uWT-=J&%ani`KYzdaYB)nNbP zue!Wno5!81m~w^kH=%|06QgyBaD=IWaiC z3;1L@16b^>7iygCFTenqQy+sYXV6%AT{KLnM&=$OBpLQwy^E&7L&_pQgGcV^HWH@< zG)=srv2~x37@0btdHbM8ZY?3UBn9aix>|>9U6W4-79BvYcAYr)B%xqy<;&Nh2ORK9 zG$qbuBA(iL@Q9X#^XD^n0PTJ*sY2CLm6n=aAe)4VFEGff2%4K5*fOnmPL~9gVQZit z%C9>}IB-@i1x1vwrinTav^_P(|F=$Y#$uYdCR1^C;b zZ$BQibx;r^&v*lQMm0R@4c}^&faPR*u=R}>?mt!zZkL9M?cuUBfl^xb7-S5ylK!cs%3x$n3v> zcegK7O5dcEih4u-t-;8Fch}vEYe{*w4jXq^bSz9>vt5}1*d1|I3YU!%chpxaYd1I@ zB)RnDfYp0?7iM3JYqQm|4%_-g10wAZ5%;C}ovt$0E&i0@qo+k^pk&jkN;ieFtkS~- zPB*r!GGI3K(Mx|m;!J5HLdL^vOfPKjO7q-S$MHP<|hmbbL#RSXyX28(U*LS!Sv-b;L&Q>_)PlqQgjg z`Cd@o93h%;(!f-_Dy*Qg`{K-`hki4fOSYN$_Q$DdOb_q|JwQ#Dj)f6Wd{*tD@m`7h z0d8pK#?NGH&ao1~<5xiVg{=lTA}{xk24S5FyLRfyXH*y%Q;Buu6u@x8tko`L{(8|(n7o0*cp4h&j`~@y`u8^31Mv! zGz}uz<7#wm$b#p%pZl1hmDZUd(@D6g^7N>Tr$i$??3U5iC=3~3>S(Na0-eq~`T+aU z72szJhyF(N^aeFH-k%gcn6YG2-6aAQKIZ$C=yLn|&f~6%tMjGRb+%H!Wb1@RBpFzW z)iC*#gf7t1kfTr6f`61;4vI%F!B`4bVZ`hEA&sy8C?%Zf;kMYuk^l^xO&!j>7-EET z50pa|l(C{f_+#kRS?jCiuQzvh8jlOw%uDVRYY$3-_;qWX&ve)99g;1J;ph7X{Y~EpOF)d^k$KF^R+x`Uz1SXhk z{u^|>Jg8pBi-Cm*ZUHLC6@f%jnDCh7OFEH*o>R3KYSoRu1uM}^aVPi@M6~+*cS1v} zOZriuqr^?}EUO%Ck#`5Eo+R1gf{W9KZu<_3D~HC}aY?}(tr7{J@2%wd4i(%tcR_Gr zL-=leoF1Dc4a6n89SJq*e&`L4wgGhZ2|zBz*}{zmx^&_kjz zRw(bxeKRk<_g~(&0wPh39BB;ENyDPykzGiM8!Mg^UYlG`zC5{b|Fc$)sqH$Y_R2*v zj9-W%r2V=nU;~K+d&4#+6in%ytZO?+JV+-bOGc=_QCtE!=Z1C@?J6} zqG@5(I8Y&G9IM83C#K$=M5>{KgqIqNhQ?Ga?LNN#%7Tdhw{+@re^TC@Bg9)l_BeIV zf^KARl9oTL8JvgmVu6If(u829$1|`}Woo)Pi^RU#Z` zCM`Uj4TP+5*!~O9bjz6)-5WG40eP4@j4=0|fx{KXuCV7+A-0^Ew2*4XYZc&v@2!h% zRx;3g1L#GTLsp2MjoM=O)$_wm$bvja*H7}{`(D1Hg7QpgCQW3Su~ug=cloU& zaXf>>{~;0&ZyYxI;Ip61RAx}x4NAXE1xHB!1^E`|B%4vThJ9{RTzNlLi^-;iDzh=# z^BqbQ-#P?`FcAD7LU2a+boPKR!`A-tAi5zkL50j|a8<4jO_icE=itIGU`B`HpYx?< zFOFHSMuQI}R(wPX*jfd8+}t8GQ*_9s-XMdyWYh8`B}i$az>Ia$V?b)^bCA9an60eN z2WK0xI?}iJeAO#oJgy028Qeu|7I(vo7@H?GHz@H)3khapXYB04yxXRT$3NcfG;}?Y z1{K(HFC7|lFV-U!op6N|e(?j;6x>*Jb(q1GX~?$fWt4EFhs2t0?12^>?ce$v?#aC2 zZ}5iK;KJ;|U>@E&wl7;op3waS?LbPwNRNHXhN0Ws`$_#t1Xz?UN$3DJ)9}}E6g!Kr zixS3i2O}aL319QgkzKPW;YtfvWn(+b$juK^Jx#lMDwZly{3IwMtM;KS=%9>$>f|@U zcLP3qX)q5hs*}D)2}F7bBcrdbpt0jyubWOx-F$<(sb8|Q=}VQ+%@3Ls@I8U!l1&+h zER#;X&Nk0W=@5Q@(D9-8Gjz1nK`}?#Ijj#PTftw7sc-!CI+u;(}1p%v=-e( zp}*4a5i;O^t$xQ!b0>p^UELUc3MG_jA(o7%>usmMeJGD*p!^0=%BojD!&e{Xm%Q|ugPr22Dn>@`+Ys9zA#*P?O0z$c~b)w zrF5VXYO;+R|6TS`~L9hqrw`x^42qKDd`%!Yi9YSrqAEwPqPR zi7~n;Q-`5EDCaCNtMLcysp9^#)^Az+)%ZGw-S3W(wP1^eH9m=;5hm8LQ4?R41lh5A`r~ ziEs)kSI>qP0l(O#q0l&>()p;*ogkvgn+!(xdQRPb1;A(elbG6ON?6juTG`kd3rj{g zZ{mY^Sula>ZahJ`chCo{v?}MLJ#ZH^a8H>FB?4)ooowulb);Z;Q&TUDPrKAe^AeJc z>vo~N$~!7Y@cn?#9#v=CjGDG#-CX@=VBMMbE?k8XHFluz@|59E41&?6yv7(xgwjJQ z%`nzCjX|iXBUFD@7HnJfJ}Fo+%M)Y@$lF#4=h2yXI5!_m`}pts5}f_I_K;nur>g^x z=#jv)=_Eps{(SQAU9li{kvDmU{G3-f?eLx}uCJ|B2gG!hQeu}D7Rkn**|g`sD;bMQ z?SK7#c&%FRC}P!_A1(8m4~xd_kVU8!C2nQ2I67e;>`oOgh3nlrCzpI}=t9riHnmZr zlpa24hOx^chU+x-3j0*9=bM9UP;Ezg1;#B}F|!Zjq^!MW?d~}88GdC>uRdR0 z4}=Xvd|qLeO3dsb!Kw$}Y@G?Dttw#l@r1)0o*1r*EHss-aR@Y%;55l?La_@XW%GnwCQubZ>5>I5mc z*!>d8l@0_JOU-=?FH4?f_H8NCBd6pYtV%H4&D);v?m>^wvj|mfxu0TSk3x46-%(X! zxVEGL(l&O+9!D{btELWVdDTmFe<|qfKraM}et^a&Gf@E{R|AU@OJC3FhAa!~r`0k_ zJkmoW*&5rwGI%s~Jn}?Z*&U1&R@5etJZG#G$-Ok+^|%hM@4ve*B`I-84{K!nnF$j~ zVd9I@#$X)j^is>>z|-A8Jd&NU1(D&^O}!vK?IaLR zd@peE1~#73$3&PI2B~dA?>HS-dMKn>%zE@)Suu4L;K*un zJE$oIiuTM)O4s!uTVp=F?YGIp+a8p4On&ILUnj+58>WmZ{KYWPbf-4{N{LRI=q00F z?-;4Ei9g&<@mi$S6Ij&38>Q}P*(>y#xJ6glrS4~b`+fYhPE!0>?CxmwAa zGq^vP<1YqK;*%C~$;Qsu`(>NIKx667=#kz)k2FP%yZf#_l4&z~6dbTWb4O(k(<{;l zZj3$*nC1UF@I?HgY9%EkY2u8G-NrMApr+np{#MY3R*#2g%t9TE*o}{hvvHZ^<2m*6 z?rjz4=MT<^Wo3elbz-0tlh)zq^RIKl4I<9H2b(cUh|)wD8T+a;n|D)(s28@4=&6H} z;tufDy7l`p{K%rK0`YFyg;S`4B`>kvZijg(%6rsT<9@#WYZ-wogIT9zNcR2R)rr~w zkYd&OIe;sqlk++#S4a>ebgb5mUu81>j3(HL{^9e)Zy72TR`PVLi@%Sy8kewxl-!+! zHea_o4srOrOqxVhJ8kKqcp%)3V=WoUrwPLF&o&P)aI~uq$Htd&bGqb{_r8D=&#LpK z0hIWohtjb#_U&dU9aDe1D+)T%oADenEjFmIVvcnOl5-cG7w6%$>2C(JyXKJUJW4Fm zL+i{kcAL&fJ53#ny9jQEHLwVpmu}D=-=B8)<13;G-Y^!`qT#}L=*mYGCB<+ zQ*G5=@(&zt()R^cPo%^nJv@({(TC;C{9=NQ;~(?OSVRO`Tik(s6F>*q)s&$3fW@Rq z0dPy?y%HQN{@3MDTupTkB_RJ7sU1i*F5R+Auy5Pvwl>D@Dc}AQX!#(S{bY zqvR7;9r^0KK7!Bl?(5Nvk{{Ks6B$}Id+$&BCW z4zty3$4er8rhzt{a02vO@{pVWTP|z4Iwbee0l3_kbK0@#$45#GoTxb8n$oZau83&Z zL~(44t>jGCYwBGuFP@Yg1!g0GMY4m^uN)m-s}gRggW~0z2FI|t)+>qwl_XIh1cw|z z2~7Lyi}(n9iiyIA2H?GbP)_SZE#A*;NhM3~C9c*bmCPGuM z+mRe_S{I;-Rc%IAfzoO+?GT9$vOM$K#j$$U80_vMvUQRsCg@(?G=XceWq{sVKh2>V zM(l1@V}T*S!YV%JhFaLrvskYO7Qfn5=-FT;SsP0Tui5S*!>_=g-LV`?!#W+TT+Gf_)ZU(7kDDSez2vrs#%XtaR%u6$qt*7SnZYt`G&s1$OcX#x2 zxL}weKmG1QF(txjVevRd`&ls}F;hqQ|D)ON5pD=*g|5>fqU(YzFr8Xv9Ehbe`%jl+t-H+UCJ%fjY6ZComva3~GoP2bq6D`3w9na+7eq z@}Jea(KkPDKWD>s5R9SN|f#BCDE7y?M140oU=WSMetOg}$NVivX$2LkFb{ z4q$-*aI25uXX+RCpG+~I_?`S|gz`P&fix@uOsHPs%KObad_Rxz*c>W^1(HfyLtQ`G>I<^XzB^@ zlWZBwy028XSNq8$ZhiVp#PO-Cn7u$%c*m{arTxQ%dr${ZFTQM3(-iAcUoge6&|E)e z5v4gJbV;CLPjAaM)?dW#FTl7CV@BgQ7>)nC@40eXFPXkarbPALK(M>1#O(&LFp&5a znCEJWZ=Sf$t9p6*-M}EVD4^LGkW|3-jwEmcHw3P{2f++ zpK6@@50;?Ew`!$xFy|-W)nm~e@T-4x3i*9;CnkZ6z>9?CJiYMSZ&akL1+G@t3q0fH zpMc#S*>V`z)7>mCN(x*7*uKz5B}Bh>+nE%A&{}ZuJB`ZLW=LCVKzJ7F08oI75Z|~&E;NK^Qf3xmHax{|eAacYh$7Q7+ zb1T8r<|TwYO^=N(xU23!&t|KU+*BQZskwV-bf=(!uY7^4MS*?7HF+$Zq&s{kkge0B zAMw1wHnR2dSl}(W2e(!S93S4SOjCOCfZ$e?_Mmpd)!9)B6`x-R@;+^w?4R5!EHS^a zfP=e|aGpQ3VA9W&e*`VO@&6!z{V%{ke8IF?Z_;LoGy$Z75V~Bh2AVW2lAEa#x{n!} zj=i5bv+Ol@U|IbYB^>Etc_AfW9CyGFVkTdp_2}^-Ts7DQv(fhPUm&?nUn-@X!{3Ew zW~x}rxuJx*6g(+7NrWMA2c#DsmPhCt2%%;YsNsMU`PV=DpkzFz+XvW7!_u(b{&p)| zpWtDc=JthM;U=}-Gw1;}U#=WP2}4>)Q5%l2K1P3mYPy_(;TynktN_MX zsbuo7X}q$$Zs`~~RZ@yr|iKYWA#IM9{FNP)%!)wHJQrk?r$H>ed(k136ygdZ)$(*IzM&cM$E zAK^dX$3s-05Qm}zDBq8G#_=u(_Un^?&V%HK=U=zzHNbJ^&DzP7aHNUVF;;@lR6|pI zlmCEYYtR*3a&>AJ@XqT+=Q;EH56Zdm9=Nc>)nm$AA|j*;KS2T12tsqBbEf1^+0>nEB^_2Qhrn&ObJL@Xc!yg z-2j=c(WJXZzV4Wu+c6akTe{iIT-51#2lQ;}l}S*KsoU=wcGx~kYbmcb?P;P?j5Uy8 z);K2qKyLuS1)w&Wz!0ru_l%v2^>J&*4AmI!%g)THKq*TiJyeRFv3()~LlcK#gRY<- zDczR`IvarB&cGMVx`Nn#bY2b2c>401fnN?5)ihC}ksfMgma#esW@<5YG{)`fN9B#X`x{_(@n<}bt~hF zTJR>P*^z2Oc<3~+*hsQ*H{Tn2?=rs2nfF@ELo-L){8RI2p&F?xl_TAtxiIL$SVB^T zlhUwuux{okPNhMFJ7i4z4a$;96G>z2g)@_8YwFK<04doHni0`@5r2kO(Tq$P#o3ll z@J4BqE$A{?l>d^YgFw;z3014oXnc z!_v$$mZf1fkfshw=U0SqT~aM@DMIh?iU{xXq@OFCvt@@x6U;upkBfbFUO1OOfQ0@o z55A~PrNkvoe2uZaBZEs*$E6Bp7>tnV34vRzUbx{w{oX3`&@qoPZAMLBCNKH%$!XB@ z6lf%OZ%_DJhoOs1a+NKi1Sd_jjj@L^Hh%&6nLD#0e}fgd{E03usUkCE`qHZ5ZJ+Pc z1mI73xV$e%Xf(v1(s($)MsL8`Nn>30qn? z9vfSuHZGRmlU--P4w+6TBp>Iks_Isj#4w)Mj_x%Fe7o_=js^^v-giu1OeP7i@I z%UH=IwC8;5oVO?QpufR`&Qt4HNFyd?@eY+w?n83>WV`{n1na~O_DY@Pxwyw$D_Og8 z%oGm`1GhMAenSprk)(&t;TSuhGY4R%__qIX04Cetf#TEUqDAi+a@rQ?o@=R)H-jen z#@McM=3gL)a0pWr-=rwEpvNtBIM#}MJQVQOUgVI(_wogUQpM-cMsR#WmXO=%B9FUiQo|5=|OD5zUW z2}*i69b03SKMbE};(Vgkg%IwwSBVw4;6R^mR^0E0;i6pstlXRufiw{~#vV2>ue7O` zMc)2D4bgWVlDaBXhFyN&|JQR;DeeoBZ#gCT7-B4ZGh}xuQArPd!_>uhWg%G>OrW|O zPf+e1^Z_fa%K50lMrz=mG8ak&(!um$A~lD{t|o>v+sF> zeNR9N;i|;Mwvg9;f50BMsumc`76mVGs*p?X&;D@zzL6Vn=w&g-t%~ZH!4_&1X)yZX zaEw)2*iL`@m>kPs@(nN&wk{XnJ~S)j#_c?Z>jQoKKc z#6~5I*M=$bP&;6@FJUWMO~N){+w%{7DQhl0><(j+@y>LqTlx{}ENENRSWgPvcF$DF zUZRoF*ggJ~;a64|1R1_ts|%^nIFlB}hXdJm;}q)bzd*IMXR7TRRNJimxI-3lw2+sWYS zBI3vaC1B~{gpBqoV90S(Tz>vRj+-OTKS?B55kZzdG0~ zs_iXTTE=&v+4$43Nw?%1WQiODg}(7gYZWC>>EVj(8LsG^SvtA*pfDk<^DKHjaJdr6 zeZ*H`8SSzkJmcqliONHJo($zD=&?x{#BHmsuc45x9os~?6ouR&4b#32$5_P?^PHPv zA^qby=i7IR#hA@O@uGkBK*I9F?&oJIOCv3G5ofy5rIAqpo4AsrCI#M`6&ak^&d%#= z>O&F&Isp4oJt=unCXI35M6Sef%arX^$+v;Ur_0NbpAnzDiPIlq+ZrKKou{^qrbH@D z%#pE3Wqeglu}J>8+l#d07^wC7w@X{>P3b90EYd<5ao|8> z+~mVt>6$tgc{??F-M}uPYl{>)5k-27`_Vzcj_%}QYp|KGb(7Q%x94v0yR%US$h1W$6>6m^OS{wkvwnZ2(Q7HPj_0UY4lKSh6g z!iLp=ZIj{;-2D9kw<3w(EIBHI?g|-NS&>pW%C{~Oz18}v2+Eo@13vtU3f_?VpI!-0LBIukv zynaR6vi?(Z)#&kpf|uw#7a)Z@*79rqXNJwm1kt!s+#0AsVjt?9;(df9T}r1FvXhuhn_&@S2hp#^{l@zf3Ozrugvp{dnutu6EntC z(sxB_RVdX6d-?T1w-tRN4-^qiH{cPA#(a3&vqR5s;>eL+teLL^>~yPy`U;)!+tUD9 zFcnyy`7PbI1@&IWC$BH;2dQvZJI98#ZeCh+-AXuI9dnu)0l}!)HW%Q1U!-*0x$IEv-~7YNgsLRg|bqjvQ@^6IE0cP=u(6 z5m8VPQ4r48s#rm#j;M%HETS?*lo{cu2nZ;VF#tPPXZ zJ4{v{4S0l+UpK#$IC%^k1#Q(g(2Nxc);FyLv#sPM$=ec@VvdwEvhn*M-(;3N_FBI9 zs2CsYgH{EWBFI=~bo|^CJYD`YM>%I5(cYXJd02cqFiEYJNi&ws(1>H5uvm7}v}Li7 zx$|G{lw|vun|i3HBoXgK6pXtY#Ob* z+<8nDx2I^PbeSsYH7_-uJ+(bgP={xDn&K`(SE~1V2@b66-HN8v*=HWSmY7Tsg^qRj za9hJBNG-@JQ(%S1PPF2dV13_LP*t#VH+beL9nTj_`D7w7yMH!VR6kQT(s)j;jq8|{ zkrelf^1K#$oD5BRYae~9QK^9PiFKk>(00;8+lasXMHnjkySSKp45-+{a{gse5L6wV z1FogG^N_pNBX+EVMJbc3Xc?32VHaC?O%W)+-m3~K<0!GIenMuzZTsWFsXcU8$ei$A zJYuA;X9IaLxY1YkVo5ENfv}w$VqpccCy-sK~Tdl9f45eNl zr@#LcnvX7_EpBuZjYzPNi3gDhNuPN8_2Pr~gSli~V+@ZyEfOSs?8R3DyxL;RFbVtV zeRMIwhaEZ1-6h3fT!sQE!trE0ZO=*`V^mi~zq4x1!V`m6oKx{faltt1WZjHd z@LjCn-f@s)g}+9n9^rOG$C}gE!w(enAO%p=T`4{XG0SV#{4ce9s&?cz8sC6!SiPCr zMpPKyfWE&0k5pA3HU`Ynt-49>^MD+Xbcakm@$vdCQnow~qn$kV<BJ)f_2nBH8V4sRWv{(P_hdSxv~bY=!e=qQQtyS}52pAGy&Sz5+MP zD37LC@;{X8=+XR>U_7!qH{Il$q?p}|jDT}7`zAmyM_Guaj6XPiN4Yw+a{l6B$2GnH z-B5z|+U@}D-UCX|!qD))L&Gm@5D-RS_Nm~6Cm-I}(cGP3d#RzP=3~N-?YbAWV{|Qq zDN*V6t2QYDc|8QM%kYS(<(>^3uUhfkFh$f6dD`v%sZ!@XygDX>;_lqoY*mYA;q6+hPzHELtC`i)NbW% zka6gH!7mR-D@IEJKCcm+Y>MeKo#@A1QeutcuVl2%fq|Ht^I(o2Fe);XQ%UR%8@ONa zfxWRZ!AcafRx;;A9>2na$PV8@$=(pDQx)8v5b05T+`-JX6V8rl&9%oC2IqgAX|m$RPs^YOtnFKWlck2vn> z7Ol&gZd`~W+3pPB?xcR97zZUzSx;bdF2!znKr_lx<7K18Ip$N7^N=v9sUPk8`nf7c zjab$VCy59n?XYa%B=x;R@Q^Cmms8;iWLqg#%GqtDh-)mTX9f9sG+~#$Mk>WwAYr^| z;>TDCly~H1{K)5g4w1@SVIg6+JnrrQv%NwPKC5yMUZlF-o`{`-E9H0%HY>~R`)U3y z+$c54et!1{Cp7`uRwvY?oz@4?h8>5#1DfQpn8+s|WI4@Cy*-zyhMapT#b-CK5h(Zy zjAQ9A3YOfZ_@C1(w?S<+Pa!8U(B3a06NyW1ohI4i7KpGy$5RjXbrqX) znQK%R_}}wx^Cv=S;$sMQSkZLf>ZMR*sioA7;hvbdEdM=!MjN#nFGR^ip>*2Ao|(YPJ!=hb94f*G=Kvekpb42gtU-1 z=F!Z!fQpOQWje876HRyu*omSyI0|rv6a~RRyS(W>h~^pH%g5k5L#-qZLJ zbV703Y3=%EcnSLc5@M4T{3l>M91%RJ{*Zsm6>Ud4)&age)~_BrcF8;qCT+b9bC6YL z>s2e!*Zt8ZOp*OkxU&{nV_Tdf!OY*i4nOue#!Qs5H@4moGdf`tx`MGBK__mbCGATZ zO(awCujxdV2gP&h#U1YksBQuGs!a#YE0IF3&Y+PYHsML0$VZ zF(JnHcKA#4z<9_>d|i#iyCZM%!O@m(6l-SM-9A1Cj2ZVov^);QUc_byc8!tFAcMsm zc#|A+e|P1Yfz=DutI8?n-y~{$1iIlnXKE|dH9P`+e*{hpz`6otO|FmrC=^QxHgVj8+}MxtUP}nN6MSmi(*x2f@rb@Xu1)>Z%{xQI z@Q@a7U!lSyOcyAIsux6<*P1pjKmLq)uaNa}ZWqoTw2YnkHi0TBQQ=W4c5Y-H9s*Cp zonFRU?MR@}Vl(vfuQV>{Z4J~X=kTfc1!QsH6(&r zT|RK{yxv;Mk%oriBFMezS9hQy>KP<&e;Hkj&xk}6{sVfb@RHRD$${QS(zK(r^|aC; z{BAgZHk|4C{A%Y=$rhp0$e=LA7xgN9GBT92SqZ8`WR_o&-1C_7u zl{_juPi4_`0gQP8JmS^y{mn+3n-H{ls(VW|JdKuo# zwcZx1GT;@NZwZ|=OYSO>oGn&vev3^GI<}}4GpoR;Qnj~8OTB8o#-2ns^yw@+E!U8S zF;(A@Om>JDMR@^h#rn0NL{jl|M^9_`q3_DPCa_fmJ-w_j2kR%$3@_FUv{(zjV-CGN zFY^Vn3HJ@GLcFVslt9|W$-^py{0UieA8%JavaBaDhc$#dI0{S6OVFmrcQjakuX+g+ zW{7>}^X92=OIofHBe%(s+`P!cNxt9?LdW_-YAU6ss)oX7jaPKG zy5U|Cz76~MzsWxS|GKp(N4FN|(X9n^i6+m^ps)2NoB^}9gen8t=XSYE(S@D!sw`Cl za9WmbxSSHsR$4~M`1d*`_}yH_0K4U9s)b?_H0wq3x;`#y$$!3A4blw!c9pw%P5636 z|HUqxlfj0|tB`xi41TJbeflN%3ytg(x{KGrWs%)9!#?Kk;vo^ckTUiD(=l>hgDJ^g zP}znR3a9qtMpFd2&%okw7rUp-L>>4e3#o2IRQt6@>8??XXSvJA`ONr|yFc+yfa$?f_6fRdP3j`o%th8vNm;Dt}8 zc^umj%;@?gRT}$F_{KQog37LRhz`qp%r|k zX`JNOHM>uwj&HeasXkN+IWk_T@jd8-%e9@Q?H#t^J?Q&;cy?Zb*={Lfq(kUY4-~`Ur8J>k95g&kmHm=( zJke*KqENbJGE%XXZ_#NJbsUVDU$y01cVlV(zjR66Qz(#>0O7aYA_FWTFMw3^oIpImC*2J&;1tP#w{j0~a%EJMOoZocX0>ChX;l50 z|MR^@QyM$nkh)r@=os9V^!;IYAj$EumlVeWg_h*xb|B?UxtvJ+u-+`nE(NZ;4)+C; z6DD_VGgW!<2RwvW0ZNbJs4uivp6Yos70z~t2dh}wXI9xcqhpoBXBEuoBJgRMM zp&5t1*ndswht$d9+xV%vgs={*@M%TA)MTU#&!!Wpa*|0jfc4B{;q@wXllZ6xnW|Fk zB%AXU&qf-{zkG85Sut6h$W{tV!1|No?je&8Y|8%p2^rjp%sRq)t`DrB&LeS}>+&%g zmHMaw(Fqr(wFJWO2K0QS^+=Usjg4v_gOr_E6}a@Fp;lrc!>4=JNPMbQ;(iObSnt8_ zc^i$gTNCp8p$BP_E0l6O2ta@NYlyd7Wo$KAchAEqze}&NV>zOu1NiRd6yk~}!~{xe z=b`n_SN`aZC0~dY4)t`a+_&=y;1gdQOZ<;;}$TCR>Pr_DvrSi1D{@P+igWn{kt282CCrq&IOs!Y_hL3@se+(MeL2w_x3FFu+(t5E& zkG9iH6A{=VlkBFoKrW_oGf_WOM9z|8m9F670~`y1Q^6j}r~oN?Q1`!c_4oIelj4#~ zSI$YsScI9wDvIy8>#oF-LV2QDpX4M_@y!)Wn3bDf+$&I+)?M+xIwtmE)xd487^<8hhW zoey}{B!rcFHL3NW&ew;fY6QMcXkEMM+Nz%oq=3FxeUf9bAI!$$p;SPOf_3J>lO*i> z55s?%8|MS43!;%nuo)H!^&dl+l-=@UaeUY&5y57|wk&^2EJ-9@FXEXKS#ovISXc6O zxBrQ_uga3MuKMkjVK+FEdnZhIQFIk?r@tk?lVBtHTlQ{e^sFAgLKif`31EF-qeqRz z=>~{JUGUPPLdpF$@a-ZRAAFAV2eV9MVC71sgEPvq zFQNl=)X1x1(gXTFCQF7O4jAqDZ#m_~_LgyGH<=$}Lto>8bOKND@5duTJ5ZMP~-s)l2iq026m;&2uC{tO21 zA~IokC{yx3??QfTZc`fOSg24?32(HA$lTvypNbc$%!_A8jVRWI4S66_g7Hw6Z*pUx z{OF|zaSYWrz2?j$nA!*BSq?}=WN{wtndTp7{F)kX&O2~Xj^4oBy<-|Qz5(6v!rBKl z7~X)MzX6X_C9_KzCNZt!@)JGrcojeYzLF7{8qZnvmXM*&{`fW3MoV%c=^TFsL~Hxl zEv;q0<2NK0pWlU)nKXN2+WHu25sl63AGsIW=B`)?+!JmjzX0i{t;VFddME-mQeg_y zk)DNjW%9YIJ8$Tf!0s+UL0G2`7XOkj{Z7G7N*N&L8O`@v6(h9{k3nPcoK&+&jW0kq zEU~?|u5PyWe?1-GWS|4yfetA4AuWb7D z1x%r>2R{7Rn}f))X`b?HDt6;G1(Wj(f-ZejJY)#W8_t8$8H%>?fVBPWpWBJ%P!zti zWT3t!*mIOH23uP{sM)*zZFbYrVU^}mF&0hQ|D|8O}=Q?h%|L>^OZuAf9OYcM038R^DGGAx)EJ;0AVGXtoY9V8hN2E zxE?clp+ZV#)kvoKGgBpZ+ODQIcsH1hxDa`m`3pLIdE3v$%a>7edv6krV=9oJql4u?fGCQHFw%`&vk;!erBg&3tHJN9td4L-0 zuWL1-AMGf0LIG>d0~l()o_9TOhm#h5UjIVBAIg=r{^4aNNZi5YY;j};UUU2VCLGWW zd;9&TC|GKxtPx8=hhopcxv`Pr@VX&kS7k=)LfX57F^`Lko#|CrnyOO93`l{3x450; zP1Eow*C;Rw3{-Ki4kR_x-3R!Q?fA(v0uGW}WKQ+2Y(6>a1eRC?o6FSTfBC_f0~*1v z8y47JTS<_i;nDYXPtldlF27!*4DVDd1Bd%f(|EbJh7g|n-Xk!>`AJW!Hjt#DWJ{v&Z0!_(2O z%sh#Bd*2JWe?DGCD!3J#10J{!EnBm8l+Yzm@JKYLOAUJSuwk1tf?hYwufe-{^54Z1 zg5+?;AA|K69HpV;CQ|E9?VQ(7WCZTgW5q>mNP!+zqhkY;sS16;) z&P$`2;0>{9AnSLNx;Q?P<8o$>`sL~76m$$aa?vB29oVVcAK zRy-n3*v2UH;NIrnoP?)rsqp`JbiTA1pJ;QNM&EpNyTS@g?Yl z2DY1~ZTUBJ{`y}2Jv#qm+dqx@2YtJZut$-z!pOr%Xx7$Q;uI7>5w1u=>(6uLjWTTI zYVg>MPgFf}NI~}JLN7oPhdXziyyH%)j!wvs{wN^_70}CW=McB)pKD}zo(%j-3kDWR zu|rjLZ*V!%OQZeg%oW6<%!yz8kdDg|2T&r>fH%6v304K}SR_@M6E}cTbrr?upA!or zeMt2Q{A1g3r!+nZoe;$Tg)GQ04(RzfFuDXqCKq=TF>qG-6+a)^7D@Sh5f{y{`EOLR z;W%x5GhrdN*j{yqVmEe62!{^ns4d8MeuHvb;yU0;4b1ptPfBDrP{mf^8#$`NXWT!y z(0&|Qe$Epy8=6HX=lK$l1S#>sSym^4a4X2)eVcM$TicI?@!E+3^mhXS%M%jQ?HASH zKc7A-R3rFx#Qti#2{McW`u;tL<@7O;m!U1v@wd5S5fHc>vKSmXDn99T(pfMT=i~V^ zy??-8L=tKAneJ{pbTum7>&*rdU!y~?sS>7nIS5m#+)ZlmR@E7F5)-2OG{7fGWW1L8*Y+abP~P<&>PJYnZ^lcIz69>8 znSM=dIcnm!kuX9e?|L&i@9!(H!d#)0IQ)pkPi6Xv6Vfj9^8FM%OINB?@k}gZUn9D)pFUfGXCo2a z7RjT`_|fWqCY8$MV2G!_H1rRUB3Ho!POh{1gvhpO_cJ=+fiQ*Gkq$e%w$ zec+Yp!+ygb)^^VPKAXNgJcD-TWhj_pV7>O@-bLrWhp+7G!t%$rn36E5o?>lHA!6yQ zmm&EpC?j8#{w0h$SUh!VHqCBXnt#6dQuqCBr2{5BH^@;`U1`IfS1~aQ#1M;=%B9{- z<`NTAtSp-*xmQ(4*5i{g>aNB|pc{JE@Cg1k>(1s{Wa2#8Ud3`}BL+8VucQ);&CRWn ziBuJ9RZQJ?2l2@n2aj61Lf}7cXM4$6brJLW!0hZ#iO_<+6Tc^w7UhBH`3O> zBuiw;feiWy#Z9}d3V1jG#wS;@_xdK!UB_5a3ZZped=|es>nZ$!)7Vc30FQ8tkuF7c z5c5>*gKk%Ly~QIaw}J-srZYcdWT~b{FiR&auOX$*x{dM&n%Ghk(u4Ae_937y5kQoq@yg2)!oF5w0KQjE-OGso~ zFSuvb*1rv9X=Hxz%#-TcD!EIeXp97k;G^Tot(L=1&xV@{Z&IAf!OfNhG{MiVRKP`w zaWY79vtvdfjiM_^=$#$68Ta?~683 zZTFBtJ44k~laS`saYSvFwd|vjw>3gvC$zAw_NpKQ^z|M3DH104&q&{|+FoEG5O@-# zX+6lR2j$g06oA?7R!-i8VAYwI%5gON9tvy}x^%*fnu38u8auQ~D07nH6EZ(qh@}!( zSS{Ps32xTTL<5H1lr84HFR_Nu&sejIwv~7IjLNO*Y9&l%zt2obPt(!M@n4 zKMkJ?zA`zg5%jtte(ki@flmMHRnXoB?f*My|NXYhu`XozR&a&pKF?^TOB(PblwfhT z1LA5D@;$`tb1kPvUGX;01Ya*X``R8D+3|u}#DmQ_F1Y6=h*^KC=g32xUn;^+m%($n zqBNHwJJi-3{t0ybuor}(6do3p+ssZO=HMNx=_{OjXpHEWKT>;MJ^Sr5jfB@M-H^O? zT9dqn>aOqAozsiWX>pUdSZ0|g!DKsViUZ@xYHVf_F{-S`TSY_K3cFzSRD!l3I}RYx zv&9xyVEqFQcRy`P^z|b5L=kd|t8*r~J2y&#Mwg<=HXw$n;`S81Sd;E7-=%!?U7vX3ffMZQ z{fbi%MskLTh_6fhvAJMzM#9Si>unB4c`{U5ZT_YP4r+EN7+qE0DG9 z+cJ%BLpNNo_IaoV|2IAV3e;5~@)x;YvD{1O>de*4-(Ww<;|Uck&y9SMk+%d(6~fuE zxmW4KW5A>rpIX1D`zzY|@+Z|GnMyOnk&bhsIy}1Ob=~BzTnsHtw>%G@OW};)rWG|ZaTQUqA6W-E>N35awo{o>gpJ10!xHWsD zxEE_+SF1VVe)8*XjSoR59I@Rrtv?cmNIX4%2q-3iE51dsUK1+zIM)s)Iz8Wv-2D^! zV~DZB@^0v*0Wz}>V&5L@PiT@~7w@p32eYZg4i_i&SY&Xqd4f?lX2mUi3K&ir> zRXzKsJ5`G1uq~Bnw(TpWWK0^l`H!H!lVFD~BX?-wX(@A6RO`nAbK)jZfvh1Otvxkg zOk}m1(;cxHaApTY3*p8`VP8OXCdvs`eoivhF~t*MSt{QfTl4+;W%N-}ik!Kmc}%)G z@xWF3O#KOB65`4_BSh7MZWr8#W)<7X@lgz4UfKrJ`w$&qvim!hhDTvPO(z7ht*y3? z!VsCH@3VwDK;WN2!eLcnbi37SNs7f%mh}h`y@w_vF)*uHb=~|A=LYZ-aL^j*5_$=D zLDGs9GF(sf`0-$g#}9AspF+3sJ~t@)gNPRM&t0Po3*v%*6qN6*%-G_gT+}sGJiQw>%lU@Rs#YPLJ%*O>%YNJM@PAz_Q5{h63KyHUKA?QRprUB`GOfp@>GPK$gOKXnhRcBRIm@4ZGDhpHMNb}QFgSy zLalN;74z}W8nLY#;ughbYlm$^lcMj~uB`)OEF*|V{45t*9}!`h^hYDh&gM| ztJs%TwctaAFk^qM`8=rog>H&d+Pe(;?zF(8qQsJ7-Biz~PfJ4Gn6!nGy|D;KV zYzO1zE8k2d&6$xPSx=u?vf(gwy~qvupsY}?pyBPKMa?`PIKh^jYbVBC- z7a^y1f4yqK!k}7s2i1bI6LmAPI65nkByMo(qibOG7F5_ntmxA74=$Js%}4RWW9d&>WF?M2nD(}-Q{4(J3;m%$zCXWVDuCf_X|tt zkN4YFf}P5L83oy25ft}ZxOJW?Z@58eM3g=7p==Qx4gcVipMC;E~ z6E1O{JUI)WJAsSF-_q{mB>yeC17g5UgX>`$#Zk30m{C*}|A#tM5G^xy6oR4Ifl;Oj6&?JQwe%vfbqVP+HK;#a- zD|tbkSTSpC925+6aGtHFv7Ai@>l*M=Xh#(2t*RV2CW6D=e{#d;t%EgwM0COp+uCTo zE3*CTyDLvacl8e4m9|U&wc(3aOSAi996brgV279tY&*CJp5YNZ6o1Xy>BS7*0j8cL zhWv8JI1Xz2tczm(o_sq06u%G2egu8gGL4AV3Abx&tL=u!u>I8gZ@|AZfWN?Q!x=X4 zINu^%3RT#O-+o*^`*Zzv{Lm+LpaA8FFG*-zIEM{6k8f1ABf zCt7XZXcs`^{ywZQ-a>eC5t1!i(K4T<8}_`yCY;*w=Ck2lkRvL9Ij92})YKl8n&H=B zp36MzRG;V?&Mu^n?e9gL*F6+?bhwbA#KpsnuvjbbqC@)j(k6ZCO=qbO*{rEtPuC44 zt39G;{`C#WhlU2^9U2fX+WDC$jVC<=+obc{+u&jkyrE>y_z$)nA&X>~gF7hWC}vuc z2?~$f7eud%kqYA#{HR8$c{$ZWaYd<8f*OiE+O{`j?M2e(@DpI%$DJ`kr0AztcFlg1 zu1+3xDF5JzMnvm|e%1Q6(4fiJ_XecVpXMYH4eWKEX*9cVFUb*0z&0;(N>lb~`V_fl zf4N&fX2hj?xW2I`I*8%OYG*u<=U zIeTqmor<+jRStR7H7k*aA7s}S<-wDlS~^z3-snu#yqwQVpK@xxTZ9_)xyOh7s1fwK z;bmuOJ4YHoukWCb!dxf;7&lg+LzD-Sm&@D4(Ya__uJ#yQd^=!{IY-65mPrYV_8;68 zW&Q-dS`SD+Tu%aKgpEKd%2Ld5ZY2i|E1U2IGWVX;=<<3l} zUnr_AkzYb&KrNK+Nwib3c*QU7{vn}qM8L`q@?bC75G8EG)m z{_sYef)xrRDXw=K|Bc2Mp&RZNt^KuA>lpU&`uQ`AZrHBwuzoA{%25XLHqeU6VN%RN|O$;gX` zJx+Q#6HNw7M2HR;iC*99x`edi=k(SPZxWlN=BPv#V`pl76FQ-7ZEdu5rZTuO>-(FC zEyE*>7Pa%A;itn|+0A%F8~TBN%igm_@;05yM@hU-FJFS4{kKZR*-ITC1w6H!viHNu z{9Gy^2big0)z}~4yDty?Ddv@^)ZwROCIczcL+kQXyjGlvR_`fg?drAUuIq!YXvDNm zcvoAkc~=_)i=^jL1P^U@?moVCjNwMajh8(>;ejfPhZMRt_eAupRFV=5W@8Bz_W{(b z8F1<7<;Q?%RWlbB(5P#9x|tfP5zRW`L~XRz&%XzE<68_H$#>XDl2cDOe)i{4s(5aN z#{0YJx*;yDwT)>o5SRMi7H$bhq#+=!&q6sNY~ zcwcYWZAnS=QwXW1owkQK(wGIZ)CheGt?O$fn_Gy0E}nS`R=L?8Z}C7zlb=>9h=Oux zb-#zQ5_;pznTa)O!T6>V?Sr7$a9P2Zz8tyL~q9`0Uetmr1-0J{5%G!S|IQ&r+BA(mwW7BOOca51u%UT;0Q z4_s@-c@X9H{Q-JFnV-QG<7c5dhfAIjh04%fkh_2=xCBwQ+YrHWm8!tKrZo5|O1ik# z`>l$~Ne+kTV=oXE$EPkinrkznM_qFN@!Mx_G(uiCl;8|)#i#}XMBgD#5}Xn)a*Vr- ztmDG^@rWY_Q*ZTRyZ073`Km7DBg5(3x5zUwwdNSgWP&s#!((QmkVt1V)cL8_;hiIq z_e5MX_ijAO^&m2pd@i0dovZ`a@5E{$z2y7njjyqv_LBn4-rnv8{RXy?4zwEen%vr~%=aP#O z)Z4Z(*^^o|J`tU8gf{lty3?U%|1a-KRvNmJcj!tQmy#AnYKqVad@t=vq~+%+aXULV za+=*5&yP;41*xAFG~CjNN8RvqTH9b5xD0(S*|9!<+F*%@)K~`xXcHGHc~M|}VTvHP z4xch_Zo+QdnaU91POUIQR2Fao3BWZ$l-w$9gD3BgAz>*BL12zs(gv>|^?W z1K|J6eR2DL=f0%32Uo9ms|;{JG4OcP3p{`tHs>1hO7FBn5+@g62AnSr*)PPWWJvrc zn8+@k8%l-AeOAUus{{YEiP+Zh!D)?{)(L5+Jq2wr2GaYo{U3=gGqKqa=%or^UZF-h zx>dR%m(Au-2-$UG1%0Pz@(D+>Ztk>OY3S(psl5zkIBuY#{s`-5)MFc;QkVXjizlfg zY775xn;qnv%-ZLpUX^r@k{!{AW*u>XT8o6Y~fc4>~;FF<>adP(cdOSjXav+&1 zP_7>X^Qbii{oalDQLvF|3Rk@WSxCsXX+kn0HKu(VunGNs?p(%?zIy^!`0V~EV8_k? ze;@xn-y$#Ap8~cA>~`6?(c9-+^?rKQw~U3p+xPhF{?>!BaQntRK0o_-2W;^WWSv-Ml;>#~8>*7v$hkxC0Q)550vzY{a^>O zm)+vDVLkIT!613_hEgR5TzQdr3sHq^czDji4(uT3*I40Wkr&bj5qIG9op8w|Dw2mn_8^UlVLd zA917#LiFG!ldtzb{nc1%9I(9=te>#ZRk#s~Hs3s(O*uJGYb)OXb`Zee8!$-XC!P zzax#D%6hRzMCyh*)81X~J(#WxQs8%5%qr1h)~%gi3UL|L1?99Upx8&@uV8)CN-*0> zUXpyfN+n~G3g-%8m^&nP7_C@NVTW957#-&K$8Q|gXJXIXkJ6M*qEr4k9gyxtXXOEd zciI!ol)-QD{OsnX-f06zi;kMmy$ZD5I)C)zJdNPi5r?LA0+{_@FU4^(l-qYGx3Nbk zQx_?}9A6sNzz?-Ap+zX>XcEds`dS19tz3L?MvZ*Po2GK{Z}*W6bZO_ffLiKMKfb#j zQsyey8`Iol_TH<+Bl^-O?JdsYiEvdN{T3g53+2Xp?>1GRZB!R22Qzc#lGIc8OIM8|LUL;6J( zOD-t{#v=K-(Cx^5qBst}MRP2iyyxYKq8}3-uI5tZLffwgcfVrfSQb#Z)Gx#DAoyuW^1i= zlkpxFwY__vYYQD;+Nj!uL1OCyVM5aHC?<`LQ&3Z$~R2^RQuHGo-s3_^J1GCgho$?p- z?;7E(8@g?#wu@qed|lt0jJ!Q`G)KahnXhx8*w0R*VXz7xoLhD`TzIjU-Leg(W(`(* zOr0-j-l7qdI^o@H?6j4Sy$8ua%MB&=9ZGCRuJS)z*Xovfe*j2^@U*OEu0{yzhCrLC z?do>Md$3FJHDK@^Fql_D3;oXA1M36B@-{GhPdjjy91Og4&jat!azMUk>g`6yHH zw^(=h^_J5iwNL8Fu?-a(0jU$7%hpa?Ss{`o{N*>0qYcIK9g1aaFy;LA5IX-2Y_ulP z29?PWh(##F%-Xy1ZpfCY`zOWvbn&p8Y+*qwR;ZMVyV=VIeJ8~(WY8L-4^6GcxOa;5M_b(xOz5Ml zon60SX4iK(#>!~++#z877_p#ff(IpHqD}z$zVOV+`hINop<#B?d(a-GOvC;ZtvowPbHA7j zp(5r9N00O2>tDw`T_@Y1*v&W*6g^xJT)Qk~ublfFS0UG>0k-ETOV{ve>qF)HR2CT| zic)EWb1#&t20EIdfDt8F(C~S`uTj%UC!5J0jU`wobds&L)*SzPur@VFu->UdO_B4T z{7bX)6?Ps1N92LT8y&?Q$sONfnOGxU3n6I_PmPi)MtV9Dxq<176tD0e+S#rI9f;pX z&NBW+$IHtpnH5iwHr0i4Zay@>r5`FH2={buS3ZSkfR8^RcWcD6PM9cLbeF4LOJPVm z(f8_1cH*JJ8x90x6a2glc;3vY> z685+ibbzE3jHA{%K4Ni|+&g)lSm8wvQOWJ)R)VVV&S3S1_K?4l(1>H5&{?+D+A^vJ z9P2xd8!MC+(wu*u<0uE%*PQ7#;bYvHgZEXr%eIhww?3%_%ZnPPc(sX|e9CQZH*WaM3N@uTx7R!s3}QTJ#L zaT>mFpaYQJ%InmF|9OClrl*Pc4~?MJ5v65lFaI`2DiX>ZR}qcojjLdwhlrJUjT-81 zhwSZ56fT(C_s{>#a}@bCX;ed_53CLt0voMwwhiBLJ^zlARXjQ>_iGy6pO(3CHCnjX z>4cg3FVrUQfr+aj+2CEi-?1_U`{mI;>C~B-5+v)pqd1v5{+DhdI>>j*Vs$@h?q6S^ z>C7@TsLWALDr44Qv|c` zJ#;O<`}QFxD)r@&h^$AD?jZM}Ig`k@F%oR;cp)bc=>o>To}AlsOl<`;slWGsG=f(* zMACF^CDMjrNZ-L5n@W?km}0y7pYu?(VTWRh1s!v?`bXcu$9_H%Sg2zC zpx|yuNZUk@J9#vyK~lo&hL9&TXY=KRq^;gc#DDIbC(_(|>V!A4nW=54vw=6#ci0NU zX+nlCrUM)H;^i#fxum^2A-Rjle!_@le?c@39mpDH7) zGVdqsO`dI2hDiG3Q=Y*BirE~a{WZ5erk zc3R)zn-W)yN0{za5M#?hxV9^7LwLP7rVlD|BUPK!!2rI48(cLOQ{8YyT02!5Sap3z zQR`i}BZ!AN^oC?De;5y+^!v)8`tY zsUwa^TamND)>q$)r3Z&3l^?!k^OEq*P|dU;*&7Rwqrh)Bl=@omrP060_7le%cWJ_; zy>3V%tv}!fOzJ%*rS!j-^|T5foTK1Zs94Xd+#k3kq-}kqzLkHeYSbt>MhQE*7;upI zPP=uz!M;@A5m~<3?bJUO{;Hm#>U!|Jo6RUyq_?0nabV%_Wm%iR*uxd%6m zBx<;JzIdZCmk(`ebWtm{b{jLS+4a0uZj>G*&51IYngZqNpe7n;B~_O*w|`2gBwI~dJf8Rk&?Z>LY;3m zXY#NIG+F^2G_AU+5q>&iZ)~+3ZVc>=o`0}gj>PSydMA*?*t=k9mK!ZB&j8~9F|eL| zx+lZ$&s&S}gBw57h)3Pm&aD z(~Zs}nZ!a{h%Tm&Ie!$Kk)2cVxB^%=V}$Js_0$}f->_8^7*XJbE;c%L+WN;Ew%_^= zMxju~WI`y^+T3V}2Ux-m3t7WEy6jVE%=Epg@^ zpD&CKZ!k%k@AhReVgju#t2J&Ak#U7CYT+zxrH%%ruD)ZiZ&5$y650WxUI^aNRIE%Y zA$~*qZ6av6(dkcS$Ph(MS%R~umm^Kg^qX?2QmyD&KBnDVW0lkm|DyHiV%R3?`8Lrn zRf<_WoK2eYn$Qfbo}2?5o@?}VpQ#&)MQivOCTD#tkpD3`r*z>R)XIPie|$;Gzb5C2 z_p1+TEPuKoQ_#tSmQtPfz`)9oY56W%+q{KMWXXbqsm9~KMc0V`W4-Uz;;V;Lh|_DI zUDd4-hVL7xGUKl|3>s^Q5&AD4s0y`m1c{3iZ1y(6J{ zCF(mGtMG`6V0Hi*@3&FhJFhlx4}24EHJEY2@w4@gBR$Ppt;D#hoR&M^%9~$_7Ts%) zze>{xPMwe~w$rqg${HN1^c|dyZzWjHdYA{hb}XfmgbbSzwoh^+KbkgZx<^w57=L;W z%*MWeVeX7QMf9<4Z}5m03XJ7D<&~NiT>4pOxkjYwhLX|RvfRe@uODqZ4WrFFj5fl? zK3sYRMBVuLsoCN-WSM4sd;G!A*N5KgUk>-y&@Ncu%8`X=1GIa7v&Lj|MB(XzDYQ38 zc>XT#yH!V&7DDDzPGECO?v+`TL%4!%&SiQa7xO))F4W{H>2) z^M9`+`MV1thrR+~N_=qQ&7Yd^d_l19lx-W;-)iHHJdL`>S-N3okYY_scE)gkrRVIl z(5nq!Zc5j)v)`@?syw#L`Xc60$^ zFzV=Ias1D%kViXh@y3I;P7Va$OQTm=#dltzp?i{LlZ!@J>WJXc`j*uoyU@cr`R_T$K0KXft&n;`)>2@W^J4Pk zut&TUJUW!@jUU7m52Dc)y(RkPTn%`fIZZbdkJd{dgBPjZx0Z>Nsf&~^0<)^RiQ&OS zO~Tr;7m$y}o))zxZPU~jcQt}hCzOuOECb*8ciBjKWI!}Z_hbkxQctd<6Ssl58M7Q= zn>w!xyo=&fJ7-7}%q~hfB%TG`Rqn6G3MLPm{gb-2H2eAW&l+K>6F$e*#xRcmZD2Z} zVh_t9na(Qi&cND%w_qIYTnZtn^pfwVO_MJO8AI|HNqKQxCLUb+(#bpSb#cHFiI2xG z?fC9cVEy(6#w4U|&+~YVN4SP{McKXuv#f>*$c52Fv>O=<*tevP zd5&p0EVYdM-u}R~*Gi^^P>M;DA?uHDG1KeR9g6LhPVaiT7uxQDu~_IK>4Zk9TwF+) zMRf}7@2Xsq)Js!)0kudYpmoD2X>Id2<2~5q`x*fKE`ZL2v3VU>VF!<5&D<5%i$@6g z5Enb_YpRF6N>JPwEO0AdwBI+`QlQ3W^|sc3XvC&&SSEX|w*c>fA|%{^&3C|N)ctlm zqAd@s*V|Lvoh`M}LIvr@n@F*;6`NKbQpY=)KWl8#h)3NJOj>UN46z)`|~a z)l@_T~8K+TkLENE7CPOh+|42*X-b`t$yo#NzCOcg$jah4L$#|gi? zY+X!oNCaWlFjBUJXO1b@8^aWM#Lz{KkHXurRSsdPbj6w5iCn13gHXC{cX51vG&VtP z2e+kW&}L0ldAd$GEnBTEkkHZRU%tw+FicnPFkLkoktNVQk`8PPq$=?UEXD3Tm~Dzd z)771QD|!9b!R*CL{~B!e-LQu!6>?!;l#rP%8UftrOsO#5@7X=MNi)&B#;IF8eBXZJ zt-_MbsIc_o!WZ(9!@jm0U|&1%JFx>D8-r*I*`BSFl zDx3j|;w$qYaU;5bl9Ynki1jEk?e}_^^rQxOGC8r`m2ZM_|EzEGN$2mU`LFFeTFz{> z_&@BuX;@Qd+ckVwEmozaRgvOEor(j47zU}zu2r;(8WjN*L#hZ75m1>_hW%I-D~MDP zQ4yk8M46&8$(Sl4B0>~}2oWM>M{vY!;cPAeY37(5OS#fxhJk%i;@Z1a0y3 z0Q6vYzDXo7{;U$MkCQI|^!rVnS2N$ zoV=3QPtfbOiI{dc?a%?gO>E9cU_6S)H%SH-1IV#w^h^iIMia4+Kt@uZRuj8ne90UeE}2-cgq zPg+aCU=_|N;Zqj}`>>#|q5XUrvBn1%T($wmPsjFO0x)B(XMnk^3L!VAS&liMQuYfG z)rUq|ZaSLNu%yP|3i|?aGrSi%eM2u0%CYb4m030_--TwxJh(ioUbWY~3vGWFbR6E?LcsIzrKC_Ki8e`WK`0h2qy4~!sw>`%qHeoV6 zFgv+dnSQ=Idem!`AlHc4XRY?0u5RB)+d=N0j>kXr1ICSMz`AybC>%yADDmHpKIN28 zr#Oyyr39p+vw4~-KrZ?V#X7hwzRt^^7PRLp8+&!T5$nYtn&Gh38>wSB-h<(&?Va@k zL$-(cFI*~pxrFz0@M+1(4K7QWUxWm_`_Ub_v23e+_uZs}#=y_hy`Mp`k$*WKcmcK~bv>USzW27((^)p&=O_lYK@w`(*p(c4a1N5X<*m#u{?}gz zPTs1Eo0yYO*KaY_aPzKi_km1XUk`R_KxiV_-+;YKe(*G2<;cD~C$sdzw&_D*#=;1z zsssJGsr>C^(@4H_{y_SgzfH{2{f!kx zB!lgx`>Bz)oUnKN)0T~E9I=nrq70W}-k|t^uV=bK5_PyW&hE+jvU4*^MMp}i`$P1S z{3c{?qi)zMeLMfivhPU;?zD=TQwa&l!lI|X|K0#3J_RWYPjnh{fN)pl#^^eHXZ zr`jQP6YpxFJaZ#Kql~^|H%giiE6Tq*r{|z;@8)kGBG387EaHHp2s!Bkj2+&Bu6wPn zgL1m_R~suWuIf?Uo*#=qq=`rtD8K6Fmv*sn&g1MB3~f!#uIzLWw(#Umed)A za=3>TWKsGcyrt9Z)|>qs(Gxe#z)2<8H6zBVA7uGA$iLE^8GE0O%3T>!Q2g(Zf?#1> z6Sz=~k^%4k9x2i@2GYC}= z`LtpB&eVo?XbBG_v(qAMi0|dXY;ovBDo$HCPJR`nZ|Z|bRN(WmI3Dbi)yI~?QKG|b zqN)S9ix+7|v{ieU{_x$Aw{DcEdLQ6p>#@w->1CNrVl7dI)8c>q=@-2A$)=&zuRrZW zBQQ_IMo_7UV-ckAvH|+?=Ptw7j}sCxE2QQG_$hKTM}fIw2|zy}r+^J@vAo|R3`=-qS^701@Y>kfsVijZqCB*`&q)$tCcsz@QoubAVO1l_|BRUjLhD_I9eWg# z*G!MuRmk`5=xvbM1~U=d#bD8xCK^WHx$BiAaR?kqwQlqS5`KU*HxD;|Zqg0jm2X8O z)+j6+^)YHT)1r716~8m=vhGsJo0DAdT5=hbi0EyVL!vn`#YfJ7i_)%u-QRDM!yR_> zlg297*x-_+2F@ASsJ+9kTVvDqski}&-Hb5=-C)r@Tak=j-5_Fa>*0e4q`U{cK!L$R$k^Jc6CkWaedqFlqzZNOW1p0du zGB9)+aX0e$bOK&RI*U<}*T6Ao6Z_amG&~Z2A*U@`=tX#a+O-GaoFICN`$s@gEFS2A5Vn`tqSF^g}1Q zCd$3q=-0LR+FtIlYI$a^1G^jKqGI~a7CB-$sc&Hc=$FxF*beONK%=5Jl)r-@4F<~; ziFsmz8wWfT3&xyI6cJ&e2j~Q;^jU}@?(YM_#)8u%k!17y^5{{If~Vh7w)n|qM(HZi{}(F8 zkoN!It_ijEvcJJz$P}Go{2q$2JPjxBwG^PsWJtw0{OvdSKz~A=h@kyM1FSclX?Mhq z>$kskXpOth#U4a5o0OP55ts4VD%nJkJ8zE9rCo}>@ z3@N1h`FjDCo<7p+y2BBlESoH3mvDm|S>e+nXT9V2Zuzfnb_0+*1GjxWF$<0!5O$)w z6*mt933n(#X<5$SYs69c0{%iJ_)jlD{iF-s3()cx@SltTH5@=%x@ik=-;I8)*xVpT zYJJdNnpw}0@HcTkQ$pE9m@!I_79;MKThaD6(Q>|<7@XT7z^=nBtRI632CoMkSvO*q zNi#R56rD}PdxLl6cjI_KdVy){2XICH%r@V0j(dr6@34_KS!L1%Ni(|cVs$N~x=}#u zM}b^!jrjE$oVD;8%zI_~5-f@%9f5+?5R($aCIM`2Cre0gJDvy_t3@PN{0K<*f^o3H zb?_c=7JZ1m)4Rc~q){FruCt}C6oGv|!Kh=0q=3UuE#6TT=w$jwhSR~VByk6htUe~^ zUlCDP8U^DHBp{e4cJ>hqj_qqMwr(t0TA&;QTo)KdtE~T;5qZ_VnyKSFwH^5`v3;ms zR{-4RdiWYP{u_h4tGWdC*bNSFh0BFYvm;r9RLjjBCclI}L4zZwg$j=iB2^+_+-}#v z+**8-Z^RNY*{{81VP4H~jo|z}B7nODv%JBtHvly0Y+HMesk@sTXr}-+et`S|=79PY=b3IF^YH4||Q<>5Z^q<_tfU6L6g_m{qK$d=a zqL}GG&}Rf@e}6M@j6{CI-Q)_GSL_WqU7$I~;bJ;L-}#*r&YmTDl#{xe){rgBKZ8}h zFv5eFR6{QH^{w1_Pvf2Yj+}pM$IN)JBFBIR@?2aqn0s;x-WO zaFUM0UuT510ORw+-H=vFfM1s#X?KS5BB=dV82JbSL_3P5^tMx=6)w|YV4h!IJS2r? zVvli#i5QH(H2%xbyz)@u$~a_{a;Gfi)r=gKuR}vpu)0Q1-9Vu2Z4oxe^$VL`rJ!AW zb`bCzfPSFkgQmNnEDtSvviF!GYI{{@!RcTwSeo~ zolfs!vd#x86CXFvRq~;C{l{CWguP}2VR)HGy$(qiSEB8(=M0N_kk1JBJ_-F=FC1{s zJ5s2p>rnb2eZ~cv$Rvf#>_fwa2qA=hk^}@r0ooy^g33An>%HJxCYC5Zo}Q!k_P(|xLN z4sS?lK>D>^q_+6=H%K3E@_ zNA#e+P~}V+H&a%wI9PROJ)Vh(2tqc5a~V znwz$N3f#Nlbi9T`{B92V-14sAo!Ci)rU&~t!AbXgdH6w`aH8@}r-1l*r+^6RWR|Cb zWmO%>7zyBn;m9%P3y*dYC_~hOJ|XS_=T;e6jOtl-OvZtJG((2sdq-z{j?Wwq25%{# zTN+N+=}D0*%jfHZiyObH!r_*E@eAPJzc_fBtw3yNl&*)|`}2eY|09qcY0P z>Z55al@CHQTCu&_1GDa%q2=rmCgS=nv6oQ8TtF+q-RAb(q03}Bb=@RzVBQfxU+w{F zP`#YQ8)BrXj<{(TWQZ@W06XVyd@Ai)6}AauPg#avL-5{!771cwSpbf_NaUbn$e7H)s2+>@L?0)y0D4&+K&k#$k`MznkfdpjkQ@@0c$;- zLCA5G=jHgI{FSk93om@r094D8@h7McHq${4e4G`m+h=4v*Runncw!>pEF)DvHD5`@ zzwy30@D5q+TZSlTQr>1?T+j&jDyxiwTM7wNXeqr>rFdMljWU@}+lDD+;iA^DCMtpc z7s|qaT9a2hLjJ?EK)Otc8Se%3%w;sk*2CO>p)kNul2bnUN@E)c3Um6#H}nZ zUrntDTZEn&C|YoL8Wl!<62rSwGKR3|B8;1r7h3M>>7H|B-ztyOtE>`f$11C@KF!@B z*;TM^eEWIDHb&YV2Y=ZeAlM>z`S<{qY(ITf2F2=6rO{w|qKwlk$~xP4?FU+T3fk{y^r9Wg0* z+1C65e2Ab6UnH5b78K`-!lce^O(uWC#wK-MQ%$Rz5(#9sQI1WQJ5_y-K{%AdN3R@*k#kI3qb>D29tJC1z%a8$h5gpTJkC#2me z_bAEqN=Ql|;yRtHmXW{lci0xXg}@Z7nMZS6s*IKIW$fem<5j+wzfc_ikD{`*Cw3KEjG@mt{XDt4t{K?il{)%r| ze9u*F7Bh;@xX(`s#Rqf3C*q4D$VOEyC0|UN5j!EIWVFl4HQ$@{$jx1zUC-MZ)Rya4 z80s!k=Kt=VL_u*rf%Xj^jiVkF*2}LcPk8_O-8hxOz7S*@5JhZA>WY8X zi#~Lx=B;P0>(t((Q{%YvL*XTuVRZW~Hy~~1GpmTAV4n+jUG7Qx&{RKw!JO)kcO*Kj z11|#oh|w7H^nyu!W*0&0Kquz5aq zS!Mawh>ZOooZtH3iNM}^GjvFP40JRQqt z!gC!$6F&!3ii~6^V3%RZH94TFHbb&r6J5q)b;W}ZKZ@$Ywcd|YO{#*r@}pj6A~-J( zFQ*Yzf^h_CheW|zm_B>qLg{h}zstnP)G`NY9WM~m+rA5k48g0aepexMr~bL7#$2;Uh7T4M;dh ze{(^?gbO=nXW)f`gZ;>g%y0!Q^GED~>$b@;Vz1JCWtY?7IZ~xr$VMZIu(jIWh(&fE zesuKFHQevfaC7<;CQL;f(6_9W}Zdt#|q_Epl399tV&q^g+k#Uu(VP8Focc+)_Pb*;S*Mfxi#q8Wv|mW zj|WQt<56m@FWB=$Bm)@h4N#;HZi^QoFzcHr6e25rC|wO}YKOUy3ut=`$GCY${#-73 zOL*2$6}0`{M{rg-2)Kn8dBqercAE6i0|(+*@Uwq#EI6nV(|@6u_a{tSsatB{`A!Fi zz@UR(JN-T#d*}*=c7Tz3A6eRw?etcy($ib@)ov-8bpO)PW3jQxu?feLlau4)kHxG$ zo_I1TY4zssFH%>!uJzd9x^~s7<&I>^@-?fsty)#F!@26$XAd8)^k}JXeDHV`>(#?g zc7HO<)YR0#E^d@148ahN6#O_{8k;yqs!svJp(57d%*18T$3n9GerC z-AW6fK_MnkiDeDRaq41u(cj>Z$QT_v@E+_ySck-wMBrjJ*lo5quk5XI>pz1KR3b&z zlk&e*;&I;PW~wSY!VjoMuW5G7K(M-oiGGldVw+V-1N>>cUtzI%)gplq6BmU!R15hH&4uV7)Y8BW@Av zNV5B|J5vLfMeijh52EQ`_N*jm0vB z>_&xRF`zrYQZNcrz>fLj%Y)Y9tsN|Ma?L&Tp6oQXBs1rG>8C}}v7#!*W2OMTfwxCw zDohLfV8dVx71aYyo@IF=B!>ZvPbUf^&+|i}dEC520hhs-e~&e>LZ(EVYOGzrjh| zO}eJxJ(`9XYd|hK2lSaKuR&$RGA0bud7UPoCLss=EHtMO>3d}z@UTj-l>(0W;&0mK zs6?hlv@B~|b$Nd%5PWdnf4UBt{~P9GVkbT zLrOXI(e)Q9?}fwIYfUgsYESt(=2P3h^+}b)zrC)P2}=U0;E1S3!Ll7mA!`I1BF;Zb zy);4Df4=f)5vnYU8c~+4;hw#EQ@&2(*LF-U;0OvFq36l^zYevE(2%vjcyCX3|3`y1GJLtNy{c! zUrEH=jw9x=T|>!F?NY?>`ckv6*$*{I@n3*u;vc|=%jOU3=CMzN|4Mq9K+k8 z+$?mQ@m8gm#7;BPk=iGMbrw=>FP_a+a-{4*X2rm8F}{?w~zi>8=QAI}*DtDCp;W z`{3zxFG^W19?;IPh&>VONSW-r;egFDBKUbi$Y7Py1mvIRANR*FBi?*a(2Z0(xOFJ#%dNr)hNK5j*5}6tja@6fEbsuhRMCKnKZmQ%42%Jc;_FpApb{%g+qZ){D|JD;{ zjBT8$5{4QPb8OVs6RmANyq-wW(UtE(S8_hXsz9$15y-h@DW|usEW^+!Q4I_)x%e`z z&&$%@j@k7BjXEPIdk>1jxzEry7r4i#)hNszSL?5zUsBX3W z@PW;`#H#lU=n*OC{9(e$x{GH*U>-L@Sxce~Op#~Xx^kj55dhQiL zza~a1jJgjAI^casZv}0uB?v9b+~Y2zKVx>uOHI086)I?l6pEh|cGslLjP>vWKv*L< zkV$Oj!qYEb|7*gES<_TjevJrK|G}-)zrn_cF2wD#lD#y9JKu+h?7BX!6MeBZ}nvE#HYMg@Q`?pQJD&G&@tkIpa@idy@24) zkukq>AJIX9ry$quYeM%hA6=;i$IA)Y!W4NMQbBLMD-DIARXgzZ)}7#?j}VRev|40& z!J_Az0L-(k2EBEPd)oI9JRpz4nu9Gpo*aQXiyd5M@^K#5F8XFN-|p8=_j37-q+AiKZ| z;|3xW*4LPp1DD_d$WB`Y?bRKy<#(VCujmq~1gd5vG_|dQy6I9INsd30!I=R=NXa|Y zfUr-JM{F`WruR9y9y>B8mzY46RG~hU$xoFAt%5zRU#i5Uh7>d1m;KQi$Msis>}nr> zZga-op2?TDe|^Kdd(s8hI*T0t{^==qt;wK_QvD7#i!LU7p3%G(*l){)QDzgqYLwy|4)IWdk{|c=b@IM$ghmK zYm*Tt#5nT@S^mtAzCP&u5~UD#Z`L#&jD#7(Yh+S-beEkjce9NM@JF5v|I`T3vI4E__AX z5uD`szw)gk7X?aoSXV~yZCBdmUr1(G>Rf0G@>OmFo!_IoM-uaWx`>|itXF=5mQxR zw%3fx1;#u?5 z^#=d)ZX;1(O{yGNn_~@No#*rNy?sExYXOyTqP9p_4-1Hug?zypv=XH_30}LP91&9S zG4pCQkKi$lV#RMa<$}rsi7M_8>eLN(EEw;9161%z9A#W| zNNmbWD2YBEI!v|ClVBA?NHV*V3kl-ei!+?UmIzHGMmANIJ)v3PCVH^n@^~}*;uQciSRdw)AH0&#qU8CC&7kdOjs|s7Cjg7XhRtxHN+%5u!CQp zVkuvp-TX+59J{-v46i<1Io&u${4$@pcS)-&c(@ea;wasT$2^nNfvFBJ1)21soBSHR z!`@-oYJrJK`Tm`o62)iePm~(+mgS18Dr>W51Ut2BvrhZa_S)YLq8Rw_w1o90M(g@n({?O+(WUdb`Y($c2&@_Cb2G|)e6r$r#P!XIVY>;_W3qIlNLj3dN=Evq zEY_OQ4;QO@>{G||X*;UbZlq5Xisi^@;LMlPXNaqz7kJLm1BdGoS4FFk-X^$HoWe1| z!SEIt$ZjDRemzg)?t>lqIEu%Dn$EO44twOAx<;P>#;ufF31~>a0@5S&Ltg`qIoR!V z)ptXh99rIGlP6AAiG0n7i}vaUJnG0mZAZTQZals-8|H+kL7MNPWu71=q7#h@*fg1c zwA}4^45>%*7DLA;1ju^19$?L9d)$%%^-k}bSz`J+YCn*t z6EW{nb52%)-C0)17Vq(Iw|`Ybz~1I;lQB!>ThNSRskVzm*RpH-TNoNmAj`ak+%ST+ zHK-uSRY6Y?h^S~2Y87JGvS5jDUlrxn;cj63^~46MCC=JEV=uMn`yZ}c8H_u_?9LX2 zCPvEnQ&{e3yP{ssC-Zq?z$F7+rjL_9MbD9gZ{k>% zNDI11%s*2t=|yK!3Hl80Cgw(A1u%|`e*0>D26|xMCUzzf7u?Td;IxZhis;MVvYu8T zQeZz3(C$SR6DJBXzrV*@A%mJ{&~3wSRFro6g&NU3Z5OJGep}LqkK+i_G3D>Ul)HQ5 z@xLg~p};mLdmrKoIxsQN_hLay_3`vdfIR_6uI-uTesrk-5|HzOae29nHQ>~9L|iq1 zo`I{^I}%}V>m0}_`oe92Q|9@RgGfzXrbiB%ngS<*5V$vJ`rPswAFRu10EJFRR! zO1HAD0%zEG$ZpWxFsRw!I`+;aLXflcscbOvx`(2muVB`OG(N}#c zUxa34P_^^qbTX*6e-G;8;7!3NsWm8?f!?tnrmw|MnGsaP8_@Pg*Kdu-S9iFd1s!AYUf42S{0 ze6fk?4yXYa9u-d=j8ljxz_@=Mu)?d0JYhV?3Sy}g3jYO5Kj*1Lyk^u=dpk9$OP!Ba z+YzsB2Q+d@H_(r^gcN6a5s2xLr^a=olZCy-fMnKLzt!zJF=ME9^&qnBGAdqz@IEDY zJIcX=XL-~g`SHk2@D93X`r!A#&iU-mqp*}ffi>jv&F*{(eF85#P}})TIo&4@h;E^5 z@X}?tOCb{~t+{;#Q~XuF1kK2-_PTY6f6QJaBz;~gNuMIv4ZV(BM`SjkQK6x~H~JA* zBUx=!%lZnFU&z@T0Z#!_YDBTX*kT>01l*C+>nJexkpoEg_|eA&{TORw$*>3sb;eGb zMz-Fh&IA2Nx<+EtFlLH^HBhXg+5=omAc^!W z?N0fEh;0BiK>91E>Z^PNnh|K#&QQ?#)3yC`P)UCck1E%f!)L%}Hr8ewB3LeLIXC4z z%-_qUIAZ6~&hV!50C&NI3!{xKJH+T>MWl>7R1J)Glvp?V=7IyngY;qgwLS7nLgWk# zJxyE-a0-znzEmyXuN<*r2`~nnIS$a5aLP}}LN_pnYKe{#Ou(O3v1n4CUyGE)W`+_F z_s2>n%vFhdjVQSPL1dq96xQ~ToB!r&S4{-Xn(_#?K?x#8KtI@3EJjwOXg5s9u6V`K}7_1!IFg9Y@4(Ie-c5 zOYj&`J3+d#$77J*cBBW58W(TNUKq*EVBR1Kv%i-P4Xh5?@xnl)lz&sqre&yn5}J{J z;Xa9arUu=oK-)hBNqEupPaONBqo$SnAd;zZ45ek}A z-c3NdC$UFg+1wuiy9moujudK)kjc6k*Z2Hpo6LCnXInx8U;y!<>vALiFe79uP*O*1 zb~{)LuT@d@ffgWobZaPXH$5A$uI?)#0`8+xs~H*AjpVyt1RRb(89BLFf7*8~lFbPN_Ic<^F$K<#y=`pd0+!zip#^D;}Onh|P^jRt&fJVe$ zTPt<%Yv>dLZGQktzoxwR-&-Lf%+*}pIdGLyF7pT^x4A7772=9A?Ww3 zXD{^k53h<7l=LZI#@nT{RSwGVB&JR|KAUc+0jbCHum|2Ile!V~gm3`>F}Y>yj4KjRXldpPahGj|`flZZnGndLIj zMY*%5Vh~wMHE#!z=cT4Y^cfHQJJ6_`b~l9R-Dz-fg-^ih?j18ti06tVica`)UPv+( zf<{O~MRZUMfctLHg1<=3;XFl8vz8qJ5sneQlsZTo***9wM&&!uh+b?^B}ZHUI1RjIup?l^VqCyUf;RUYIwblwR%xw}j6~t1xV>k4 zVhBgfb?;#>V~U4iH^$EgouFt3u?b#2^MLVABITJBCvFDF{emdWZFTZ&nJP2Ddy_Fi z6RlXL@Xw5cihvDirbG7`nxZn80R-L`$PYPRU z)A%pl?}La{5oWARWT}ZEFwf!?%Vz-c1|G_Un)46*`pDcKWF#F6Zwll|(Y1-MfSe8J z_tzI@l$Q{LYcO`we?`A6&ZGN_xf`bsWCX3f>g&}!2rYF5A$m7eLR=#vvMubt)FVxG zn*-WDFxMr>O%12Ou>kfz0W}V3a4qa&+0oL+a?6=9#b?HWO_}m}1jfJ>ro60a1ZmwT zXG1a8{%eI#N}-@UVH3{m5;N~v6i;$c^heGsOW_4XJZt5n+hyQF6Buuv3oUb5QePtX zv}1|Q-tfrA9mLK(ZQLR-L7+gFv_LOLqX#~NActPW*}Psbnd0~{*oNNm_%!I(R2kBZ zyu;J(>`4SmG59W?M9fkZ*Jlq8qiSGWwuMu%$_*bDe>3Tj=0IdTKg zHl`E~a1*7}%f>Mw;aR9;klQc2GXV-{_wtF=Ql|S+lN-RtMatR;7cs{Lz7CTilq5cb z3_@pmKDX{3?PL2KI0!McAP|2(&YIU$5A^LZ=BSU0qgyk!N#SzMMT0r9DnAz*k)3U< z)s5ZJE!SxK=R)m{XqlMWw{}@%73}HpMz@5TRujmU=BGN}$@edWzgF->+=l0!q^e>6iSs5K-Us|#vf52Wp&cFK|>h5LZuIWV4@TSsh# zaEPq(xG62ne>#aFFoRl-sulCBMO>!{a> z>#|C;y*j%W0P<&SOR;H=lS2Whj>sjBq~S&ljudwH=t`4BgIia)F5qF_KqjC@4RoPF za7cX&Plw|}@D#1PQE?`4|}vsq6b3OK$=9h#}nUsmO7bV=*p^jDp9Z&?(7pYy9l&Myq@?Rq+3aliWWI@ zsS#ztOoqu@cTe#?azr)vv?B#E2v9C+Ib9kVsS?$ikz65Ib#?onaY>Ft#k$bN1Zj_` z3eYb85C#H7)j)roMR7)ezSJtBi&szvdttH!yaDWATxxKZ{}7i37gTneH49fOB(uVJ zLNWO@L7Ljk2xllmFh{_SAF zq*~jmOPpIR{_wl#Gj!eZ`*h1$BBZ36(Uab-SG?$_e;rUB;jWoee_bU4HKI;h+o{_a z>kz2zZ9_~bLB3=sVwkd-&*HoyK)OW+Q4AKuI_6$#DYm|FTUisE!a37aB2pt_qRk?8 zW5`H<1JNW{R}X?XGc{a$IiLoqRyJ2hSBt0gn0 zDG^+>N93upDr-cfv$j#Uw}1u_2Zz9*gI+uRJ{^1L3Wj!ok$N9l+L7(_R;|+0TlLj$ zDVlWu($QnFvB|Ls$C8tiepuvAFlLhsc(Gncopl_!%ud9GRxG|)W9xolqKW%|FORisYCF4AUG+HAY1U1 zG;rCDmz4uhBtAO1{)9^WX+|BhQ&%0+;ZNJU0+C#9YLlpp6B5#wJBRTq=L4XB8WfC@ z+bT~6(P>SoD#54`P0U*Dyyr!BAHEp+=!)Tc6hrqmRL?O^UIMG(iBJwg^vUQuDFV6^ zW&3uUo&!%252}I}cpax-{}qi|CL$$Lf?}77T9mgpJ-^@yRpFGRA!SSLQR;7iQzsox z-v_7AK>xoZs+OX?inzF>qgM`M@sndhrr9}&X;PmokPx(NGeUQS2Uvi?3IfWvM{0}nOhhFLSbLXKN2tcMMszJ} zc%nr;U2Bo`hp)Y3beMh*OqXPf5Do`LfRB035P0Efg9r4XQFZ|o$JqWS(Jv1W^@y;3 z3sEJJ3aXGxql)!XGL_R3+qC=Kbk9kp71tJ-W-_%fnB9)EDa; zK^F{dW9d#HhnE|2gKL&SPs}qv;2r@tw12dS{aB$SRhuQRO;rL?Lt>S>`xH8Jp|+1t z?m=)jj*YU=9ZSZ8y+hoXoSFLWBPf@COTxe$U#(LKMa`&GYVR=ULXxx{ib?5s{ID_> z2Ii(FI1{XA0;ymS&QosBvlVgYH``4Q1a&=DZl2Fu+wFHU6Pc$oCdi=Is)k^UCP<|N zA%@9GU|?k%<=r=BFh{Jz0eC7{xA*%k{{deM1UWO?md*Js47l<-W~UO=8WFA3Hv{Op zQf&uy2@Rj%HOR$GMo$Cfooq+98$Fe-gNS`8^D+ICAj38pY(aTnG>cUtQX`U+`Ua`L zffrzdt^@rKJ5Z~Eg`^R);5y0`zTw@w!RDR_kD($gj#h!#TaLKT!!tjYvo~ zR_YGry2ex6ztNfH`|vRZY?Pr;?!WS0_rXiLlgwkf4Luv?Z+jWM>pC;=s)T8nZye*@ za-b%H@NG81io9H8=;cNQ?NG}W@ZBw^B@9O;jZd>3uu=(J&B#r5>gM3+hIefTZmkaZhB(0E0Wn_PVIrNz|P(mXH*g<16X;*^)l;m)ek`+W8hXO2ohYDN~aRo9KL zyTqpDHF772mWu|te7Bs-%fPDcW1;aB?4B#`4N zf?S;+0vA0e?K9_&fBThk=>7WAJ4xO;8uC48NPaJ2f}{gn z!K;MVEm+88ZZGmuiNfn!oA;mA9%lz+%fN0~I&-d*f|d`C zJik*0T&vMI!myd;&YVw_45NDKjubM60%C~1+&(wbtrm?U(Kl3qml+3vdl{hS`d=#h z8SmhYhTdf^QIzR~op_E3422I)qgUQRA~f{SBe=R8QDE}9%IBaVZAe{0NmrD$ye+7q zVCWf+7+tm(*$KBi+hnWj(whRCltcUcaqROdai|fA$Y!y+&4I2gYkOG^8^%mbOi^iK z-T`Ru;PAOZrqbTQy`AB)zf8e6VU;5Uc}o>@z--Uw)01ArC6*Js^5S=mLyXXnoLkg3 zuuN{s?mkIifYkYvV7-|={!3vRL5LW3IoY7>m6T7=U!Me|hk0n-Hv`v&T;iC7TZ0%G zj^QpX3qci*MN2!PGvvmF)|2`ij1;gdNgF*y<)$-CPt`!kv9+zP46pfTB=ppH2+=cM zLgw^5F!SyF@vZ(`d%?Qo@0Cd=?;IM-RF+|l=u0+>)s2eMm0|5K!)TO=$=Av{eC-!d z#h?J=y*;rM$Mo*P-sqIg9XKxLGL+F!1k97iTL``g=qJY%M}{;C#>qA_hmr|NbcW+| z8RF0@W8JnO9@sPxh&lP_Q~Al9nc|2E!<0oAKQ7*o(7K>N9H0?gblK{tH= zLn#w`vU-N)7RM3Sz3Y@#{SAI!id2E$Ml(v5t_c5AE>qQPDm0 z2v|0Y)eSV$6=AI}!eUs2>Aw}>zz$Te$i0sl28N@LZyQF2@4W<@23D@ao3o6*7NXJo z24*WkU;fHv`1%Q=LzwuQF}uO8=H$vJXnPCXL`{~HZ>10VI*y=~daaX&4%WxQt0FIl z&@zSTk%C7eWCb{U2I#X}2t&Q%#tV)_7#oqiLiMU$&;I(VBTBiOf?fUMUn-HW8Ocmn zfpr!5U;nQaSR-PYjlGT}{-*#jO!U7iFfSNx?h}`QaX$|UHH=6J0WH6vC0?`vG+;~< zfyruac7T1GBXQau!!Zc)Y{T8Pt@#~QE1wex2fSjek7FQ_7+rD8qV_gwmM@~M6^BCJ zIrKH!ghoxkVjv^Y2ri29HozNBgP6I9VZ?UN+L|XQh8JDWiBHhY`w@q;3&ww0@_GPz z4VM#B5>*ys4e50{PU4@!N&FAnVT~wuHjCBubLrY)t#5}VxCyn#0F*i`$Rs)fFy$Eyu zJ)YKSx$4HjpGPd8c1G2QsK*-8>U4eaKZc|b<0kaqEE7C78pX`#p>#aZb#^$> zE2p$FThFJ#j@a_1xDBH>_n|R;tmEBLpcYDP8v}ah%d3H)>9TNKJC~nTM>t>!-C`*_ z7g3BGbNU_8)~_HB*4F@i`o&NMZEGQj3wVy|-N)k)le^%^0dVE#U#0E0fN{t)=_O}k z@Knb4KlBDx!maX-(NhGf>M&fI)p;gTPp5uS{RVubxBN3bZ#`XK`~m7PJPf1(9NO5c z%aiH&39aWR{veA3)9{Xt<#6Svi+E=^Cif!v6+B2I;;I>AdF8G9{XmB^5d)KpJ{fb` zh)&Rt`eH+LVOa@Usu0n4w!c2fWBSLT3=o{qAVmCnfbr!28ks9x7~S|65GY~5%Y?w~Z+m)Fl+sj?*N z^gCT^{5NQgZ8fCd=}PiHrZvtHB1z{FF{v?uLQE-?#^3?YXBWm0CzHzB=a9?K0VxG< zqc@DR6rke^g-As)j)uc~Ftg#JW?@gF#I3~tJ}Qu{=|oHGGUtHW(B ziYhvk`tlw-)%7Z~-Gku?=fHGs6+BPg5L7P%E6;%ifG$5Cg)lV3&?Yn8s@H-+PImC)Ca zfT!+mlWxaO%XjP+gc5O#KGcBNcIPI)LKyeR4l@ub8-ds#n--}=p+@98T?**@e@Ok^ z*(R4yV8uhfSqqpjCI4nj8|(n)j(TaJ5`Y@g&D7m3(p^H(MxN}CpsKFe(n;$8#&C)Zw}R5@#4SCjm$ zuZYY6`@z^CubawAl%qB%HI|7ecBNa;mgNqudu5{?>DchtSbuFHeh_9E%dN2A7s^>S;`bJLhE zv)>w$(DRQ{AIX$R9OvCwtP+VD(RZxXUYXS$!q#>qmSoHR*D=d^Yn1@ij0&Uvm)qvUudhVv)>qzReFdj? zqE0Y*Getyib9^i-0Q#b9%rgY-RrvFSYsyA)ub3lI2}jMyF?Q<+v}wxL72vP z)B$-nF^^$c`T(Q?($t&O1>>*mR{Ayz);Awe2}X@bGd2s=<$ZJ?Z*2#odlWulJ;AL( z*Dm8YHBba@nH~P_sYH>3B&6+&@b)ol&b61pFa9XQ!CzEC zcd=%q9vBy(BiH{KA+KQ}ihdKf>5LsOD+k~gesXiYu}bi1NZDDa1K&R-&8J^ZulE%* zQz(pb|JFX{9AMnamPC)btu&$y$G=j!x4Bp&!j8>Cbt!bx!Vf=)+v`5z@9_!8J}WuN z%pu<#l(7~bAlfi0ngM(h4acxzKs+L2JuMnEr;3G*^f$$L91ibu+zJ-fAQnAGhI`Ba z>^Hq5dR4MUi#4M6*x0J;7qa~u+|6>+f%QGWnpw63Kh@U-T3>=ipXA(8u&xGq5p0?e zwX%T6R$p6gVipkW7@T=1ro+CEK0AP5-S&ThMj6FW9GN?sP@anmh1Kz{N=~xuLsKbo z`V6s@d7-zGKqBGwVdP~Rz9aKdOVv6D$y&e0S|j6_N&6GN~Hw3DO!N?F3TD70lRPoJXf~lowx|NFyhyg!Nx2M?omB^YW(!?fJ^qMqU2@!#5VTdb-Bq zed0@6-1^>eP&1FAs7xaDAud zLu7VaIS=kMzae4rk(^%sgI^!``L#!XTiYu#gd7+(8+(Gi8SffpDO>xsscfs*czLlC z>DRrRDR*g`zmd0Q?_kdqyDUHXVlU;z^KAMT8)A|h?+4zuq3s~|-}WXl#d8)6amVjq zS2n{vETFL$$ia6S+m;b6qFscZJ+sVB%W~cQGdn{FX#xxcCW)cCriBE zEz(Pm*GRcGC^K9nj=7Qga{kX>urtQd(I7HD@j6C7HPm$JQF#SCoO{;ComKxcAhtzI z^leg3x~*S&YGnk&@R9wkjH=$2i=VSo;=q1Z{gkQ8g#Az5g=d>CNEv+^3z{HSfOd#toLZM1m!ZL5@$e4wgK)=1NeT73@?}JqzZbduE$bBbinbV zEinW8!Z7&gQsqEzBVfPrO@U`j*AMproxNgoHoTm-jgSbuMo1DQw~3Jrqcu*zRC|H9 z3^n-Cp%3-X_5`~fDu=Sjl)XKdjvy|;whKOCb2;kH$d5|h|ELm4F-2#(VOte@57YU2 z-b%r*7FE$=p~@_eHriIhSG1#`{{64nH=s{=4XnQ<=Q7e!hL1aQA8tE9pMG_BXK?v= ztA60_0%Hp{*`5lP_EvC7Pa zQhH^O{Jf=UPRO*m7Zoq!bl@x-WiMi>TExo#!9CW$07*YZ`#E@z&q38#DYCM z58fW!oP`?|Gy($#mw{faiOahN?mW+oT3j4n1okY2fk##o6T0duh`JGS-E|3KFE}Y2K*tzW^5}erGB};*&LpOPzj9=&?22@Sh#c!n zP#w`8q~Md=&2Ezga%j%`?I`6fc!fhUw7F65j8gckMJ_d0J?mWC4QcuZ;Xh<(zzS|U zXs3#~++Oy+c@1Uhgm5`c9ziMyTqh2!$JplpvbsqIbV3WWh-w-8K_bDC5J1Os+hoBV zK4S3D8ASN|+5oa(ikw5^qvMh(cL(V^w@K4vf?&aXb3M@t)E1^c-YcSmLd9~ap$A-F`;ev?G^12n?xq<9D5cr7uaI( zvX#iRmo@s69D8;Xprv;P0i8?i-m`$TqU0Lkg~s6e1;3t{01W21JOZL8=$LA2*K8Te zl*Q_qN<|EK26o*QIg}ZCPmc>#TJhB*^s2nS0@JOnth|pM-MjP9=bs&qmZR-p)R>P< zEy)17%oYKx>@etUf$kU}lliw?TOu{0CX`xbp(mVn6uvj*j z??)KjgIAL4#$nXs0~>Y+QR%Is=Dc*ZD{^is0P$`szE^7W+A+~ zIdf1btcimDGQS3*rHzg5+gy%5JRu9Ohq){a9zW1$D(?WKCD-$#*!E!LGR71_Mf#!ZvH392#S@73n4Bna-XTY> zH)HI>Hvzpx_5De6KMNqNIFZ%FRez&&Dzekl9 z2lG%_N+~LV`7S?C@yjFDR~F)4Ujx#?N&G5CDst&t{FOZ$B#Akqh)qJ!u>#uG?&0a{ ze{NdD4u`ExoL|e=Cvw3#-$68}z6=;duVFPPDEU)?+_8(#{tnRT-t}) z3S$}cP)iKjjKAG5{;E=x{}=V)KcU=G)lDI7FQe&|KB|x~3hH4+g3GeI+<-q(ICE&AiDI6V(z-5jF3b6*=d(*}^$Jvh+$V#cW>k~HKS_5s=g@RlGyGKYrw z1W4BJy^%-U0rbs_#uIQoE|x|M+YHi8Isrl7>2oV7 zxgc29H$pBtBI3*xqvITn94EbX$_JCcU_F|T&6wJH} zMQn4W9?f$C*7bJ7)$Go-(wo_tH%~;tc<$=gLyG8}*f--E{{ILkEnKJ`t(BzeLX@^- zYkH?r6f8mS4H|>SBZ`u3l+U^ zS^sZRtak*i-7bDO6lv|svi7rz%tQ_XTYfnj#9=9TbvFv_5SSPsM|yz4x7HuGf6lA5 zu`g+P;ia%e_MXHllmc2k0;tM>HrI9^8V+bd8aJF$v^4M-5w*)uN^f<(Ty&D!3v}#o zifM%om@eJ;Ks*q6g=+oGt3D=sZZi>Y9#4oEK*uy%JRf`q;?ole;Z>lcPjj_4jN=&c zDZtxvO(4%@$HgbdBNj_xg_d5y%aj6IJvyhEs%w5)T13;Eji}Q9*yaP;=q+eaJM_?V z?_0Xoi25?{yh1v78GQpB9=cy5e7FIk`lU&-?-*kw2lon-qd{j|BZ+YzKgyD$%&~*} z+>@!<#KrA59Bi+j(!!MbsfRBtC!S*Tn|P!502-Gy zx@cVm$h+rPNI&nD4YxPaN1iE?2cs@v>y(ym^=Of1s&XG%AZt31qn;B+MgLN1_Hgq+ zy94pN(f0pVX)-$fs$Co^z4+cuwP2a~jtEpNqp@t8Q&Y6Jx1;+Ce^M_`^BO87xWI7Y5k9Mj?lA8k z2NFlvhaHIRky%?6xkp!nhe=8ytR@*z+hF`}zH{;CJ886ISh!Hil^8ZSjO^y2V+yCp zDF}_AKm8thTpz+SL5U**&yoS%c^!<=Id%K2gdPNysW|By3v_}8V$6T&8r|HBhR%U( zUQ}GFTa%2w?ht-GGT5U@e@sqD;K>*%Y&EXc?VyvmN6ApZ9fxYt}-+)Qj2J4rn-?;Yt`0pG&?JJ zyp;pOE~I30GHt-*)sDf_<7?vE4=#FTGaCn&|I zdX&J0+G_iEX&`dV01SrMD2~^2NoNhxTYuOdS@$eFBr9Nt>tw;o&Hc;Qt{vdY*{{9> zO?DY%>Dr2r$B(5Heb%sZjp)^L#XSxO(px3x(Mb#8HE4BgI+9eqq@~^e(sUxi*@qx+ zemApqh1M|-0vgV}{N!ygFvwZPGc+#6vgh2DZ;KS0k9vygqGzXi-A7{+iR>ptwY5i4;&SwVi7prFS zH(UJSHIeyRALx7dKn2`4sBaspODv5Fth};n)~hQ|ZSxcDXZ=$VrocT@w?-)x)gsTC zEmhfxuN}NJyj4B>IgfQy%yahLEpn`#4|#3%&rlefo(cA zK(F2DI{Br-**=5T!cmG$wFqHmDu+sH)m=?T=BArJ;^$@%6mAFC2x`5(0IC-w5J85&6PR?DY(gLH~hucJgek2C6!(@W` zt2;QDvlvHCN5j-6CRGrBwM0;>XuZc^t{0VlC)6X&sT_u{{Z455cfy%Lpa8n7lC;XM0wnK{rk&33-ix zz0QVs3-3ocg5_L-5?T~{bBaJWjxu)%5x-Vih>pp8W^%~2 z!KgQ&T#_(qQaJ;N?#PkT)v}P+;M~3-dcX;$wT)Z-JU~+H-XjcU0Wl?SLqds zwm#$^giz@8Ny>>y^)NfK%x=el z#Y6InM;9Z%aGv&fDJ`Zx$def!(>R5dVT-o?<_hAErS?RMqeVt9F*NT!n30np z=ze-5nsPJ;IQH=MH~Sw1?Yw(H$A@5NiIGd-`(#@nlcGU=)~;T1WJ6%XBCy<{nV=e& zkAaz~`&NQ%iVQh@IB?aS z{KY3Pg2nTB#P@)jKq0zKSucF##b_^u$*?@%D20o&hcDobo#14e+0`uE)}1b)?=0?Q zqO<7%Xmgff`~_?)~p_wkvj2eA8?)qB0apI24yt; zhf_XfXy2r90SC}oaffkXig-Yu7h-rF*ltHbv*)c79=j2LP(5`Lkv-Ut27Tf(SuhP5 zRIDL(o|viRXcTGT;{T##`o|z(p>hxO;TLZ$#%LFB-)|7u%SnC43J1wn`9|^G_(k2Z zwb5d$9jzkK&!-d9qmlFZPCopf8lLaXUv;}M8`pT>m0nKuoijf{Mx|JkU(CC|k~x^W{^yrxOUm+w@18fE_NXb|)Z?pZ-rF2N zgj-ne84ft(mz~$;=&ZMRcW~I%CiY%a-}|0X`OBOuq&0b$5#gl#y8%1%>*4|y`FVB3 zhkTL!=%S~SQKv$pKo9(QOX=rEEvl{s9Ai}Lvn>At1}l7s1G-f>2Jm5)Q{?uY1UplX zG08X#(Mhu^3FXiqx=0PLxfm??)yJKVII-^q&fH5F6^PKXmj~(rX|7W}%MGKqo_*^) z1a#=f@&M_1C%nk>MH6)W>tonH7k zID$Jd=RQ>WMARZLTR>~D_K8?;igwx6HsR8?!~^`vH=O3&+t;Oc)xKf@!?SN%jN8-c zw|BOFb#bfak0P>=e>G$agc$pk@DbQd*gAYw6!ggHwFoiTMUY(lU^H5HY|_5X$$|9d zkhK&UdX#kohzK+&BbhCU1ElEVj(|R$hZIC6gfgtzZMv3$DO-VLxonW0FVzhXh7UkO zAO#;Yn5o^sRrleVOaPj83HwdGFRP9Zg+P z49=@~7v1{f0PyMcsqkPLZ_pu1`VpL$GkUzhESYtF2{A5P%AGufZgT#(y{+DG6J}vF z%%uq_Ua^b@BwtJjkK9_+GJrhlL51jBW7*MOY2R6NM&Nu!oy}W0X00-8Lx0bIO$hsQ zomI5~S@ai(yA0IU+4rckK4HUfHU71T%Y%FF3-jzy*$Z4UMBh8_fUN?Izs9~UR|>}e zqAL3b7|luWXIr0L$4(sH`V;rJGkoh!9V&w zS}?u`7@hsFf2WRsb_uOBQVI;V>HDmNliqUSjdm7ykg1=9{fe=_b8tj&RueV{q(wld zm}S7-Eoeo9H!_$X-p9aK`Jq8oWDxG46bAlTrw(MRPQ>P_@C-LQumuCtn5=2)?zG zWm(Ir&$kNPs$T$eJU;8GWhq7Ae^KK5qpLJCS9N(;+f`~h$4X0&Px^HAcVC*qdsa^r zri(o;Y?)H{sYL}-y%mI7zy}{{rfEOI|HF^)sa?9?oOt<*j#!7%HJ(GSca|Amd-2VJ zZ&MBu><4qu&e#P(P-=Qr!%0_)L$ydvW)`aM*lKa8iDmE)95zPQ(dXvkZG>rs4;W@0 zAZV!xHa{vtiad1c^^~GeO}dV%X~|l?Q4>-4=Ty$Kn|jePoefenX#^b2cN^X*qaP5W zWIoyDSZAxk{SqN5{^R&Yr7Icmijq3ym?bK&WN3qiG#rnE!8q!qk2Mg??`gJpzI^NC@%0OG zLKcoD3#xv;AST!gZ_myL5#5D9I0VUH3z@)rGpwvy!UavWpi@;Y$LudqEnT&v%>Qtd z`SZtH&^U;SBi>cZ`45Hd%ut3-BD7?<(9(zCjb1y#7V-WU!E^M7mK#c8`4plUiM%V-r7 zq)dGY`qlX`;7FbD_DObv&Fb&I+r9O47EZr<7wB}NX?-E1zft7dJ??Lrr4*WK(rr|R zruK@wh7*%=zKq$;JiQ=iF-)Ob{HwSQP=Awvt<1R8f6B*ixus|&bH~;{Qwm7+C^srQ zY_+YVrq{|wClOo_t3aIuVw%(ju1r2$5O(E~!eZmyozFH-*1wj7z4pbuk32}6433q<5KfsrFc}2Mx(WS|6L+} zo?XGoM=b!=v6!Gw4@kLO^f3WtLiWs>MM@#49zDiV)#aDPe}Th}h_CvKGF0!+4(tPl!LJ%!R4H;>|~qM(@}C!>;kGBc7>m@>hhHWQB8u2stlqw zMMcwrD6frdVa(9kR4oY^y|5+^n{=-qhQc+rv!YOb$mqF>rtq5u4NC8OLv=$P4vD3z zdcU=5i>3pz(XAWJN(X^NHJ{an6!1q1;mtX!j4?WA@*@8oNgj{iAgfEzF(zT3>|)<@ zaG!VMn&R>b?$Pd{v}meDb}@&xbJhCB4SsV@h#IZ+a$%pjU^vfnm1*xCfP=1kEC`RRs$!YKfJmUWCf_6 znFUT0l&gZhcIjq%7K&rD?Mbytw;151LbZJNwe;lQg(8n)%DBluhsKZB+sp+eRRhTC z8AE7LVe*XDoo!x8qk9`{90=-?7F$3dr_+D_5AgFqTzqX=-Hza8+z5TqCy#9igu5ZZ8hduiY%V4DKu1LW`F(GuzcMZnq7*!DJM zjVa9AQ3pINR9#fm?%Zf1JpcHPdmV~}ZgLW6ybqYOoo$FDcb6OVmuj{BWB@aQ#n_7a&1*C&5#uF@B*WL|WU&0VmQh-4sy54v5%EREr{HzED*He(_%*?805^6M7Gykh2d#zHo=qLw3<8<^uMKm?ktxR1HWjj*k-r zqEkSpO$c5_PvH*U>mbNSnq@R8y41mQ-1%wBP;CYBje_`2Zn)#W&+Tt*w@s9>7%!N+oF<19L`*?K<2u`=G8a5 zUcunqAN$bXK-pKjAph<`aLbWVu1l*F}SyOCMoPrb7TcsW zc`@kGC%hZI@k%rZNwK&J40c80)Q1m_Z{-Z#0S5I=o;Ap_w1B5*(8QkxLj{zFy?TKC ziXs-odX%S+=(ez0>}-03la8NY^+`?SnH44;Z1ClX{)BH#hUvF42|8wXB~ntopb<%h zd+9mES5WT_eLs#OV>wa#^c!IL8%RdLC?VEd!O&Ukpz68K^w_)KFV`Z-ZMjEJv zZ&kHd*7B{ISjPY0TPb31jv;Fs2$ZwB953Qb9ti09SHjWmC!AlEqEJnul&T&+?Zl>u zDEu>-Ma#q;L@cJ2lMvj$kJG28jvxhXlR|yH9*9|o4>X5*#lR!shG`%l)CZlnUVhoq zGfOe3eKwI-rWB-Vk*3U{ky*8l7oMB?;DegAwqbaWhT%|{lqCY5C1CG3whK;geO|=} zI!AsInOfwAxX@bZ{v(Q@*Un5Xu*a#t9uGiqG^jWp(*-?Mj>1D&`#|V+Nygn!MlAd8 zyQA5rFNds^qE|g~mde*Ev>$p+EU|xl=()Rl!7`2zFXKD-R9?BQh*cn?RcDmKPc3ql z`65+yebQfG+M1*-p6^jSJ(zNY=LHP%V+i)E%(^*v-YxMAWKGyJVm?5aoHQhD`V zE46B3>HKqd+E^ho>gr)N!u0l(NwnLk2~QREv(~>xdHqz2re&tOFG_p2Tm${hf5xDI zFQZTJ5(w+*F0LLDY9I_?sI&e(Om5;7&J?B9P)&N3s$X(#z@esBL;2HJA~=n6n^7Zh zKj}sL)GT}k4Ujh8c$7mdD?@|Emk1(mfTe+nT*d8NagjXCRBYl=Sa#i(6grW?( zJsO(ohH&kKsNoZ0qf4hBF!*8^bqWX|iaC514J13({Cr{qOnJs(Tx6tCBcT+H>JiIe zN~&sNnRZIl^eWxB1BPH!0^bs((z6T<2=8FrsuDyJa>g~)77X)VCYoAAtcFvgi%2T0 z1UmZ9#DP{1K}6t2Tom!0TckLQ1PpGR&Fne5>EL5Pnw#Q0LZ80iA@NCLe)39SAd3X4 zbmIvvhdpf+&|Y+9^hZjetrjKC93I-yLfd*%w9Brx3757d9^g;D;WX#ozAnA1_7w{l zo_*6|+@4Oqy|eYJi(54v+9oXMC!g3@2J-HMyuLQswwW@9n=_V6RQ8 zuPVi$T68vZl9pNiyDX74BVn?M8^S^FF~EM{xEy99kQi8Zz3gH5*?fMNYd6 zu>zg}gKsys8%Bd_e>pes3Tz+pT&=l=fG6ut+Ka6PFZxj5NYLAcP7@LG9T)rW3GH_l zD^?`JJn`L1@vJ7zPF1EtdrCsn8-?F*n{;g&ckIoMnz*MJ+;K2FUWF+|pn9}Al`{;W zy!^olUk5GW`yPaE)LDGu5Qdt9M~4Ek!9W~FVfWGD0s6Y-kKaUM-q})MU{QwnOxn2u z;}b^J&cJ|yV(i1M`#Z%mg=p!)PLTf=DX@kNv4kuL$CI504tI7j?S)Z*^f(cfmjdRm zVv$5n{}cur{dy6w-|V08&CI1hvNP%YtDBtJ7%gW=5o0(Vq)YoEY-Jb}hiS+Qxakf8o{(j|U7`eQti(*Zf#Ul_68Lx!F$ zDLDPMuQVy-0^C!ZbXGiY0782hQ~=QdaJ@fN@{k~H99~8U?eWmvp*bznMk0nH$U?)= zLwU}GwL@j(&~?6|ukb#PpHo`Z)g$9Uv0OC*LaTsid|y#2OS)H>UJ5e!IQ4iQ&b@x# zy6mc9TEY=$IZ=TI6`f?pkB1sxHgR7;k}bL8wlUyPnQqB5pyRNapgl4+#>r(>Ku5r5 zj?U2&AinuW<&>Ut%MEMMO>*`YM_?@|q4xlt4JZ$!ER)iAo?@&UA;jpt3L|@vdX2|7 zo-pmT6gD%br%rgR4EC_gP{XR4#X?n=gtX0!ro%ppLF59Ru`(njB?I*@2g^acwW|(U z#5ZK&>?dH2Aix2i$ijhvaWCuI0)9>nSR}Pe3KT@+y-?{p%pll@0}7x&X)CQJoS=^E z(Hm>_f*3D|Wl*dHs6UbIJg4SDTnKoD8G;7TYXxy%DG*rP2L_ji>j>()hf;d0&6`*T zxk$=w+%N$wLMjM$f4i_l7ewcn)p&ZCVOd*3|MXbO`Y_>f*6`|hj2^T? z&KXba9ZP+l2&nr<*k8t_8WV>Hy|VLWoVqyUU2}hBt^PHo_*ak0sO^OQHnCG43>@J- z06Lza$pW`cLZ%PWTV*Zn;D(vrq2(BT)y7V&VAy*VFsR!X(Crlk*3bW9E)Ey*Tdg?_ z51*q#;t^Yd?h&95h*}52TI9u8kch@I0BwN0AWSsT0d0EhB|Eh_0_Y$+D&T~hiDZ~d zkb)~B7Q8oBx4FT*J2ojHO`$-VRZnPE3VXFEkQNJ7j;_$sIvOt42skhX=)wzD1bS(z zj}-4_Dl&tvJqmxp$_J8e*y8Nq=@HZ|IW%0-4Rpr)SpRq$b)hU0zN}t$T{f{|EkW|n zJAhF65%?|<*_heG;t=$wdsEhp6rPdEZ74l{F&S9F^NL_8GMm$YB!I$i1EnK~ekafw zCkG3BCLKy5+6R&X_pRx9Ngm1-(C-SR>{naBFO7Dy9^XHvxJ|nH$#)+> z69ji;hS@nOVZfmDDyyFPST;&dpO!ACu+o4>xZk*ADVKgjm(V3|G07=PkAmNs>Wsfs z3TO4`ppY5W@;iSIgNb~-JSjaUB?ZL<5|--_eeXP{4C2-OPQ%&6_gEkyX-9)TaUj;? z)N5N713?(j31P(2KZa(igRdh4cLKj^a*in=eZ7{r1eSYHc|XEo5|2PO9R9)`IB< zPnA9ZwFsvc3sn_PwM>tu*Yl`kk>W-H6q#NP?LzOs)D5@c{Kes^x6ZuQ*INm_XK8#y2A@0A=&aA z4cIaAj+j6GjfA`QK%CD(^XyvT_57Rcd~id?y%7Nn^fE)vPy#JL^Y!BKNJUg`K5-^p zf(H4Np^Wmyz&4L?iWE;wnS4P~=}nNn9RS}uCW7T~k*)34Cf^C7VxARnZo;a!&stGS z09hg!~ z7zOnxE-o(%EF{jg5KKRU^!U?pI-SDb9#0scw~j>12=+am@m1h`ZGjL{q0hEneDJ*} zkA8)}lucC1*$ZzU0?=}P7qxD^VOR?uH7;Z60nVhjR4XQsMCFN%V#r|Oz_GJ~NH%AX zMFOOGIhom5Jx=~M68YjkS>D~#|)$RzCucu-g1Ui=J2=|#i;dT%=U@s zcQVs->%iALY=N(o6*Dg^E)4PX)MrvJHL~h4xZ!Eao6`Hv_>=otm{P2(N$yqo3!rU+ zG@SRBZ-T_ow7eu1v4P0LsS!_py^EKZZXI0P^m#8DAm5Fc3k$Juwu0X8r?0BC8@_Xf zkcip7WoN;!f!i7}xxE~k<-HhL9B7B*fvwEA)W#f4@@P+X=*-Br4dIaC4D!+ig zKn5#K>*joqF~B+b-`6WsE(@XkW>(7Y3m_Ll&hQFB37zonsx=G*22Ieod44&N7;M>B z7t>P@bnqClUpqMJ@7|A5NdK@O%wy2g7-2&7=vU{cRhqC%l55keS`rdan zO5cK7RA6&UmEVH)aEyk34Fm&_lZkf)*|tPUZSlYiIsKbZkaF%m+S+R@8+6A8=o8la zzNDcePzru<0f@E(3e$b4U4-nw!OBGRVohA$enMzO6P#{CTpnX-L_|fXoI(!;9`zF_ zsDCvYlm|9`yn8`jpihIVq@V*8>%ulmz8&nU&32t^!tN1*Sti^;*zuR%(N`7#vuL4u z)ZV44o-EMvp_<Kl`iO(vhrWTD*hlrU?rsgS|Uyv3WKQuFL>xhR)&`- zSc)2p!Td5%HsP&P-jFP~7%iJO-qWkEd5FHVEvXTFQ478pM=6O*b#ud_=2O<*FCSXV z0cMXIL5>j-x&ER2^ay>|9AFR_&;TWaUy5RD!2|}V7si70!3evnMX^)!-vz$RUNhA~ zY5iA=Ol$!MY!zi$t>Eo^AlICM*L1g>;~E;C`j< zHiC4x5xK|%&P(9(tn zE0c0nOyBwAuecoOFe$NQIs$=a*; z!ECP+Vs^FNu>*kx4tHe2N4gFn06XYebq;xAz7f458!ETlzrh2^#vp}DeKHZ}K z0JI8)Y|ih7W_};A5{t|b6Wnm%hM9~zA1NYee)+Wi@QJ)e0NtVqH(X_2yg(wJ5gSjC zG6F5aBOm_;*`PyWR`Vb^t0LerFdBLa51!DW6!6M-67J~^XrF=eB#~sBaXvH(`Aoa7 zK>y7={dlG5SCcHPoq_)@=yztwC_Gt!Xkr~(9(8Srk80Rqki7_Z~zM-D7z+0S~saU}S5B{q}C>AQ%rZ*6%5M5lp{X~u4A>u2FX zz&5M)xUE70wz>6HlQQ5hQjY|@RMkK}7;^T(Q%wdjCjjZX@2EH2fJ>N4cR1Qa><3pUUR&15%pz|u}7vUlUGtLLq0oPLm> zhBkZmqCeX6q$k_PXT&2%IJ?ijMmG|SddcgkzK4|y9`JmK4 z@j>XH_@Jsd=Z_ zp%*6zd`6kL6^*5xz(sJ^QoqZ`of8c%2H@=LXB}D^oBb3zjnMYmsZW$X1oeo-ma47~Xiw8?Iu|59D>GUeMUXDTl!s?oJ>eXo z`_M`W8d~M3A3^NwlIyZj^nMckpm#@^>=WNXkJfsMsET*3Ag1Yfm#1^f#7!4)=7u3F7y{=wY7{wbmTiH4^oPO4m{BDb-N=H1iZyK`%6<#VDs}bS-LPnA#7`1-q9@!g8hHk6i?$OSG-xW+Z#UN>{vf_1N5;{Ypj&s;h}w_> z9dK?4^rSkcCfLX;PlUr(e(NWnyDJ5|dSqQo?M(Z3;rDCdPHuZK=(7i$-8s3#$mvoq zXl$7BF+p+}_MJ3eN^Kh=C+}(|PytANO?GkcUq?jj*n^(}I+S`nA3Q4rSs2jz)C<3l zOomrPu9O4zZ~f_nO^xWM{O?bFMQ+!vo$tmP3dL6edRrNEx1sJ}wy}S$HRpz339vHp z;v=sVeCFluuk4h9UQLp&s-V|)HJV=Gqt@UPZU05&3@S{{10=anD5jG1dRvYW@(=_V z)NH$hcC5gSpd0OZCrt7@0x1{01u4tWV}LvWuRytx&q1B*t&>kXCeb&S-+aW^jiWmQ zFI%isbP>sbPXPwFIeI~`3t~N_B)MOtjy~%0xV0TaY>%gaUMc&*zS8+&qLo>tip1vi zGxViO;jbo5S5+&Ig_g(Ea2~TExEq!2s|79F!7qr@=3dy}2Gg)h30G?PaH9!9RQ3sT!yp)O@`Y7$u!K13sY~uaAP{mYsfW@DQW3{Nzj;y zU5Wq{y)pxi(kGxEDOa0o__xV5ln-zZ(WVt+)N8Mf0zoa%@wR^UIt}Dypn0VSPGhuH zS9EzGV;(Hin{l2~u@5lV{O~n6xeM{$${`P+x?-7W2uep=u|er_Gritd{@$Kl`X;Vj z=oc{F+=Wb#4yAAEM8}*p5Hp>{pe^UE6RjL@ZM)*>oh!4~uy0 zSO6WH&u-!r!z3UOopg9gwNTZ* zpxt2C^mgC5m}MxCq6Z1~t^K_~aHy5;;o9J^xt2Q-oNRsYX6*Gt&0IiQ@iRCPKn{Ze zKIe))g29EuV8fwt=ko>#dGbR%>AW7=Kk^6~n|%Kox~$4Nm6o~GbfA}^W4eG&u@Q%2DrX;l znz@*8B*M`~=-X-ZL@jn#y3q?!dR_70*QF$@M=t-~KxCC#V$|ak9`KL?SveeY=fUO# z$&M-Wyl&kqmC|7D;auJ!Nc*GE`5(GlZ~-|E;(56^XD!^xtBXpJuO5X~<$hj^d`(Aw)C;(>NbBI1qn84zHVcu0ftiEC-TY1Z zK6%Rzpu(vxQi%BP6;VOlY#AR zB6}WTT4v4JLj(_X-3Ry%5wn(MPDC`-L2b+eUPVe>(sw`UtyQ04U-Q~dE|ko%_qhn5p(dC`s=oulg6JvKuq!d;U8TRpI-pkRemCtUnJ!`@B*k%xw1en{! z;_xo?z)FC_P4s887BUtDkmq|9IXI_6#%P%z0ULem(6LH)uokOFy0ug_t69tCXnM&P zSzVD$Tss8Uu6&@t`p~jXMi||Wn;c$qXnhK`Z^z)6g1 zM7;}G~=XEulvJd4EMxi7g8sG;m za|!|`LnZ329Fp+dMgupo`8V4g;U7oMav+ZCj zbF>pC3c475HeMOXNovtwEf%RfuxjthX?QU&jA?)yB~yWq9C6uY)fa{Aje5D4H&ipxbOX@sk9dOqVP?U&)KZUK3>)z@2+LD6*_Idu8~q(CP_Uyt@bR} z-)4xFZ^{i8q>V_J#1x!9{m@nij{m;-C#HvH_kkWeqMkhe`V}I62RxvXBh_`aMp_<# z{6V&KHoUgj;~UuaIGGr!<*^Jwv=6_5FiPxl5U@VY37I8i4Z%J2F{G(DmnsfneOki3 z%juPEawjK6cZtx{G-S;>BxrNl`X~b?|Pu9o8KrkW|GvS-)WZDM$r$$QqAN9zz5Vxu|`C5Q$I>2kK;E7wK&0X-+vw&bfIPBG(DI>cW z5+rQ?KaNh#Gt=u|ipYrgBQPsL1k1Y1%dmDm2~rn_=jAxRqfH| zzfC(H6^u{(Puz`SOX@$24DrX76l7#}1g`DaXLrlv5Zb>q3CohxH+m7&hlG!uB|c8( z!Fe~41N2JhFC8;XUw6?r&F4-TTFq1R9>c}>D5Y>#k3_1vSwPFZXgK#0>I29rJNnS1 zEZ|WWhE+=Gt8N3oSe!K{%sRBraEV_KE-`RMi(aE7j%(mUj2!+NV@6^iWbeF&iMzoO zSt;cNB+M@dmZOfyfL(M4bezd8U;^?=g4rqH*TRJE$x?bwNZ`2Ucx)gHpT0;=ZmI^o ziC%UBkS$b%9#n*!89~TH~V>~fJIREzd@&Mn~1~cZcjPaSdM<~ z{Biruc+Ta)B%8n`{q9$aV)H8IEBx`YxJl_sfv+AdRrQX>{KMy1x@rSl-y^{F|K(Tc zO8Awt8FkZGroypkIg)9F)|kLbAF_gwi&?Iv`dXeos;8cgPd4b4t5MkN{jgRSakm-V7g6ilpS0WD+bu?p! z9g5~$o+dw}49aF|5k}2Ps>aNlX`!s?P}UWoCVVF4IU}FY#V{XA z0|B*k;;!(@iU=GE{nP$IC{2tsQ;(FXa;Kr)N7D2bJF4*Cr^IDdMmoTz z#2D^=uqF#bR=XC$CFq#Wgj^H7Lv@s| z-Wop}g6#LPmtW3Q3VHQNl}l8Hy!I5hhC@CI_7p}%J*-G@S>~TlC5naPA-*LTdtv;n zg$qYkxe7WB^^Hs!NXrDFnBMxMSD-ImTrATUu=cwr>mLBOh}gtqDAWJJk}YYV8-@Yj zMBSLLCG_dfi5AxPr&?_R>A|B}fckd76%4`79AUZ2fq7B>>!`;Gg7R+M&ori2N}X31 zm)bXU8P@w}v-Fddf?qvyCP`H}Q@drM@$Cy!`uo)<5^x-$uNvS(K^~5ZM@Q$_muG;0 zZtjBJ1`=If2F#^qX1x(0bHVy7DL4N)yk20>x||89LnCDTrL`-Zz_21LAzvF3+}Ik$<_4fz>j*7c|g&W?|31H+DILCQ*kzH=vs*&7Vm@2Xr8y%n}Qru#y3tiGmu*@j0fNKzPM zjSr5jRtjSENSCU!BTGI!Z#_!OTfYZyEt&>HyAm5(fI;09K&`*AQdnFHbUw@OL|0~k z4%i}8^s(4I%;nC#)U5lt;DU#Jq&SMkrtWn(4!m=da4+x+EX+~jl*VEDZSMbJ?@fcE zI=imn#26AHiBW@yCSsgWQCe*#Cr*rl11b&?RE7>BwupcVh%%iR6>mkv85Qw31W_4U zWKs}XML>zYq?7Z*D$2t0&pP|sd#$zC zZb9~GG9iC*I1QaT#i{-b0efrjVhw5Nv=uc1q|RFVV+lmqKc&dTRR@I3EhSgF~cxvz|FnM=# zLa@epGd#7ig9DgT@67ZErM40^!Vrb6oyQ7HP{YPK@RyJ7km8vVanTBTKXelpXZ!_v zj_>K7;{$pQH=L&;xN;8*MOUEaQR$ypy$XzscoiP`VQ|u^ZC^CcQ&q4N3$dgn1C6v5yJyr z@kNzqxp7=e(fLB}x?Tv{#D?x4NJ0BoQ~&7927Tv_(|(Uxu0iTRkUdPkpRHyb)&`Fd z%zJV|+Pv(t#w*5SWQ;6r&!yYFFoHj@5{8<52BR68zB7{*DKWnse6SMrhbKcHO+mih z9eFksihn`e;`jF=oK>XipEWh=pU(6H%?9gz4d(PBbDCVGYb?^uVn8qE1;@7#K_?Gp zM)_rGx+_)dMt33|mGQzMd!S{`e|FJwb&7!DF7y}&Papo;E#p?fGwD-3Gq&&&#o9z2 z-t-^_%Hywv;JS4*dr3?jZEEzi_Qdpi5(XgupZp0z!Nu`IO1Io;krSq)E?7pMYP zjTCov5bCEyUS?I~=7h28?>4}{vUTN^+sV}Ze5q5%et5Lp-IH6XVX@AXgoTs?qt+d2 z6E{;0``A77#oGSLzK5{Wh<&WsP6}m;ggRXVMd(XbdJpAYxU**|$^dse-=P->aW)|j zkqYlwRnO7-Kf4exd0McUTX9-ljHhXg%tLW6rAhvdBOVkrf|Z6wJ_DRnC0FK!cY%VS z6nvfaO1#%inh(y24(~U^_zK7iM~waG7g97+BGy@1>nhg4snFg&D0ruj7c{Q!zMw{1 zz$XSDGi;r04ICW}3>?R7QlJSB&h6b78=Dw=dS7B<;>nZyVixU>KbVlPX!YW=tc5O1 zJy*Cab#$EX;OsGf$)fd+jz#WkO7A~^^k|`H!^`T2j~#h6k3Qe@`8acP^TD=p0~wtC z$FCf@GNkM^_}F0nR|cC6M$??bf5|!Q-8gu}o~OSW$&6U3t!Ur3nvH04p18pB%Qjd{ zS601zMG8MkWHzf=x^fLO{{q)>3~BiNm++g>Go3kLT-^F&4=y&j!D4FJ&XAd>tMWil zo(qr?XtdSw`#(1n&T3mk^f_`t?=(V9czcXYnObyIySO)Q@0&HG0Hs7X`!4`$`{&n3 zUmBnv0MPs#q6-);lO^w}um@{a=MqwQx!~Q{y$_zG+zmxDUM>ghAf?cfFkkQN@T1Qe zEkNI1Xi6jnC?z78m94J6u^E4XHI676pdSFx#KdMax@Df4doc@~7^x|ehdn~0{bk&J zc~)n&OGUmrYY&s6ks1kWmd=r)e}VU$Nu%)t(3l|CVD$$fs|r*8bCxRtSK^kj4$Sk{ zLVRaFjaw_8-~dZIHHB;uA8q(6;>!EO&=4uaqE{~%$>{l(Kk3~rO(a< zf&SYA1AGF4$G{n7LEyH)oolvxdHamfGO(-1FdTii1^etA zs#*!ykTb9(O@hmPK;A`f_28cx*S$)@Rri)J!NtYEbjm|UbtYi%ewd)fzMlxw5FIXU z$ZtkcIUp&&47uGH3B*m@TzH5=vWKk=4XT*;u_IZ{wV_D*($xk-bF2Ce>iiHqjv*Dw z&FbQ%-tYph&rz6z6)FdjRF7HQLmcnB$;Dbl`lCRphnLeHgK zw_U)Qcngg9v4FYlt9H#D1$Olu&R@U-OuI1O)H#`;o2e96xTw!{Zp|0&ST1@QB@S$s z%?xNe*ntLI0H&UphSxJ;^7HJTUNk!2d1irGK1(t5?S^5B)!H*bKNPD>NzqJ=@&yHB z-ArAyn?~QOvs;M9`RG+vhqHT7H{6wOeDp~iDYz-o!mQx#v2Ng|9gBJoZn$$VYSu1n<^`}cUaL$bOFfVO z5cl3N^Tn*{3Q{Ceqhs0WT4re>LEn)Gn_yQde|{k_eREjM83op7T%SxV=CN?@Az-?c zV6O9>x^)HteJ>Mz8t#+Ak{W$W=M)E8Ue!lf{w}Wu`dxtsE(>p=k;#qQ;GzsL8n#Uh zT+9IP)+HzJj{)2;=*$<4B!we2YL?FLwbfrh?Vm=|vmZduS_ryx9AffDSpBlQQHt(b z3QV_((z-t0qcynR%;dL_B9Ri=%3AlhgTH{T>O>>)1CS`#K%hAy@Q*@Fg)yfx8g}s#unC7 zH|?I{IH~$uQYcfSd(G6f@Y2kxz8Bu|h(oHDe86cDFFt8SHK8o5ZNHlQgxk34mJcF6qp8t;# zskbKuBqd_ie_nsU4#3% z9xt79WO*kxA`=9F$syjW__5k8mLjKjq~Qa$)QC^BboF4<6o9^WqD0)2?hdqE3})_U z1QWSCglB%>*`}sg!6@bDb$!_7wkv*%@7{VY;Tm!WcsQJVf9BY>v6*yB0JeZs7+@ZGC^RSfoHBV?nt(FL0H~K7((# zoFN47(y_ZhT7WMu^zS{=RCv>3olT|>+gzrA8<@a3ea zb05EFE?Et=?W91YL=3WmJ%DbHGu<`nI}l@1`;h!Hjwrcp8<%aCl<|wts(6E<)yIGM zthbmemk;n&!a-)w^*YjcYUmZFqBhRbRiC71ZheO&)OC!UT{hRDkuHdjcpAU^0mEvz z^;_9;!{Fu2b-f*O!t?mgpXH0u7@`*2fWEN40-yqED{ebWS~jT>eBg?zZe{Z?aAa-; z?ZW#27v5T5-1$(pnk5J9ucfS4#XZoEH2$~BP*MO=qVZVS=?Xx)Na}l$EN1~UpthGg z8nEp~Ruf)$lI54t4qrbF-i32gP*HNpG|@%{T-%uR>h%LsR8k}8*yy@~%>461pElEF z@dL_Yj2t%urn@xkb-6O$`s4TC7Bg5xlNN?9XKQRoVMvK;W23Wb120GX>EVp#G!8!i zhw9?)d!Mcnf~<)+d!1Z{6#Zx!D{Z?5-J4=5?@7gLH1(cnBR*_TZ;YBdsdVabFuqnJ z@54Ng_bBIqP0D2MBqt3!8-%^cC;%>HXdGc&$8+OOA@ciC1E~Kvt5HDoVe@BYM!7yi zqnX%>Qt;~LPT*DmSeXIm3Xb6|?VkbWJt1*7#YuhOg}U2V^6&_H;T`lYhwd(cevrr< zv#&`%2Wpfd8(jw~x+?2A|DG6tw*>WZFLokTNg1-{cm`M}(x#JKNBMh5K}d-TWNoLb zXOphU`rfdH_p8m!%uz*r){b(5BM=KE++D_r3Bp@9J+~KVI0t5=OF-6K%>*#s`^D&l z%DDJKqP;NhU3DKPbXWQfRuh<~GUvA)B-DWU<|)B@J$~p2NfJRwIkxF(prA$}CjK3u zmW5W#?zt)v68q%Ba>T^gP&l_>7pif%JGbTVO_ixOZOYz6yFZfj*{FM@@TW+5(ltSi zuEBaORT27s-8@SL74tX0kLYWvqOX~!TMi<(P%TX ziP{=``8QC?@zAa@$9gylY07jPwV+Rj5HJ!Wo4I1NO1p zVG7>Le00U)pYL(iPZoX8_{m|w)y);!ODZe;M@UJ*PmR!}^N~Qh0PA}JP5?%6&aeUp z;c$Yhn~n-D zNbdD>7{I>gvrG}%`!W_7nZN2o3pD0oIVDnL0oVicEcp$Du|Zz-83!VqkH~9KgEE)n z_iI|Bwa8ar8bZ3W2Tk}CG#|PjX{GD$KeGN(BAZ$3d^d%zzj|MPrT?e?wujt@EB)ty zX;(WEY8-iS7ijnm&G%vVpn-<9gj!jCy#;Jr9fh;E7#kwQ^A)$3HfFb!E_^{C0#L(Q z9>+nV)R^Xm<+EGp)NCnxsVo$d&7t)u3QzsZa!mMcsq3=3 z^SaRJ6S4!?v@XQ{xW&*B`Sm@}yfB{_6;IlPP^8l7O2yHo_#at{DG}+c?R3?O=~Ars zr5K9EEYVe?U3Z*Itg_X8TP<-#k&njJt4(iiqkWa#$FVPldP%*ZKqCe=*%YCf3^ft6&hU; z(iHa;yjpt)2z=gaaxoP$Zv30NI3$Ogd}Yee5rP0EWQ5zU4p)&@VTx2ax(Y9GSbo8M zWAo4xt8Z=Sf&SbjlSsl;QPy7O+${a(s%fG{yz~C)W~u=n{DYT ztnV-kmlOY~!c16&Q3EwM>3tc#R?4+d<@)tTB?6<<0qt%wgiv8kA))x77qW(nSn);KH_w_Agsdqu*+}x^{9xg#?;4X0yh+*?R zj(-|i3NksXaNgGzxa4}uTSm@Xl%Y(-zNtVN{cBU5yc?QkY3YeeMx%;It1(6T99@m+ zYD`KG&xDaG6p&#b`-;dT*gNb9V(ATZsVyW z*bOtT%bL_!T_+mT$=lx+4W2=PZDnA`6jd4Mu01aq)GQRIRuJ~;(`_;ZKNHamGCcB* zXzJ29_r8R8;IXrzT6-pl3w(hZJiy}+v)dqS2e@$TzM}aC^lpBqIJbuAJ#=&N&mBR< zP@!)5Y*aT%6`nbr7U}-~N407H@DCs0+x&m&iDyDzFBMgImaaRIbWg1JJ@M}(aZnQ8 z(lQ^IR<{!Gj14o-g8SfM5)oI%`J%nBal1cgSwqAS%zK|39x=fPY_FfX50ez+qxUpY z%&WQnU^_P;4&{K5(^V40Uj$4?{_@4?JS($W;i?Fnv8R{YEhDfyN^TyAgnnauoD|76 zu0XlCg;8)?YY;A1Nl=5RVsxWJb0tVo9*#yhJairp4|V2>;^nUS0T0k_<${hbkhw>WHAyv$YwQ&S`j za>8eoYis{Lg6p~DacI&m9_Ym`gKlM9O7o|k1kwOz7?_-_D`&)_s-ebhRHIQi`2tvJ?r4~K^)-#pXWh+pRp#Yv%0 zjcRAD>*Y?`JE7;^iH270Ds(-xu$yorlm}a&btiOB<qeQN=f}0|`<&My?4|-mC zz2pnjnEPiSlHm3H>K|Iuoy#%_nXwz*=zKk8_q!<%@9gr$4HPVlK(Q|kq{P@ZJ7EzCAHzLsilP?QZZ7k=0~Qu$eQcQN46tji(=VeMh4>>LM^o>EL?S1BdA@ zJ=rOr7oGXRb=);a*CC!Cs}X4zXaslqCOr48s@7?@^>atJp~+&iS`hUJ&%c9!4Z=58}I zdhErzljEX@#6Ko@@S?o%)Tx1ajy41=od;Xrl#`ZDN`xe97%ZA0${q@B;-2*Xlg4rmkR?GN?yC9#A%r8)ViP~*+KWpbi7lJl<`2W ztqR$9GQMQPv#|N+9uq<*qHj**8?YuD$VI?t(1J_}8sQJZdw7Q(!V?h&0ZID6=Z4Ls z*rrCGnxX4mIU3vgj_vS%<$ppJl+UB(W&6ja>5b@%ayzuQ5)h=S7Hec+>LK#`U*vuJ}h*Q>9x^DE+0M>T^Cpf-8mROE1 zjXcw>;`Q`~x1rJNq-bsWmG*qXP|$S}=S|;n6W5rxFNde-%x({ER;y(8q4=G%R;ZfOYh|>gltLtzb)p+Ppv{o0Fk6{ieL1d; z`^%MVDeE_@>Zl7~g_@uLDhC*?4MScEtAxAMyzLLN7rGNYaWUy@5e?V%r?RTa;7)%P z0Y$R`m7_+IeFifr5zVZbI(rYS{`^#RCjA+Fz-J&3$zkLTnv3MDVWkuMHQan2tk~O) z4K32VEu3H*V*iGNu<*iVu@2!2Lj~rJnJ(WU<3S4t=f{gc*cGelXD`4A#oKY9`;25p zOkP%Co%sC?$g(O~8Yzq^QQNGobu};27ti#*OL>b%8-{lXpP?rrRah9_J4e>d19z*F z=CS(YHe||v{hZUpIj1AlxoM0|nmamZu(C9&# zd0C8acLxoA zcFNnPi*B9C+;#qnNU5-k5a%BS?4JqS?8aWCX#a`bxzM!}=J3#`lPgTUiS3@D=(f(s zc~c|_9oW?JEVLcRyk49P!C}fye`gE9yLB0EVH6vhc=%P-fW|f5ohtS=i|V9|fZILr zllYuF+Klv*phP3IX6o9#(;A_^e-dI}0&}lmbvV0Yl2R!|^EH+DxSBmxG<&M5R8d_d z7or*^?~=ybWmc?mjeH@vF)tsheO%3_nlEn^~|$52-=wHA?q; zQ5?wuNEM#-RvD2ZnHu$xj-C3)1fAq_BuJ?F-_)&T2C&Q}MQk z@r51f<+3>N&J0XW%D5=(!O{tFEN8T)aEgydKX@O;&#+a-JLYGf22fq%A7BQZO$8{U#E(P|Uqs z0oOU7x=!4i-Wqg9Yhb!fn2~BeGpSK3;f$%93QymG*Y}DZlDHE;Gzn)3n?YZ?XCVv= z-ro<|KTdeF^VX>wl3Y@yrQb~&?+v8o1nX(jmvF!CbP~ApYWch@;6a?;(++C64Im62 z+$h>D|DqF3uj}J70dwjZ(aXA@8U9Ld`QW`Abb>tp@P0;0lLiX$W>-HxLR#jjku>3y zNyGb}5ptRESj)A%dC#?!tSBH9#%g&xa2LP4$WSdxt1FSg(etMQylhW#2L7cK)_V}v zi#3^~ELH@|OB1>MFF`?0Xn8(dFMU*5EVcbs%pLC`h_WKgQ`E4fc?yhT0z!OQv)uC) z5{x(4CNgw1@G$!TjGA7t2)sgFqeH^ z3#2`0^egM2Brwacie*a#{WLxpZ*jT_*R6+pKB)tBc&LQ89uv2Uo$Jw`0c?2CXgApM zSBsuhM0~T;HJ~tMam`Sz{x2D4`WxvdK#fjnqjNJu3q*Rp9G$crhunEJj;2%tKV_cg zIB>qqXh$>4fw5rdh$-PSdMZwv-36wnWGleD8$@x_S^1)NpqLD#*&6P}sj(r}?>;*n zn0TGby|ns{td=A8+j@#%_6HKYuXEwAzi{xtzU(p!;d(qKlGW?0V&NSp+s=?q?Jd*0 z9HSC4phJn0ihwvoIpb!{UU*8L?+noGljI8N#xHLK=aRXK;@hz#4~Y3_z@M4Qm)-9qTE z)n3qR9jirs;_|^ikfNR%;nYr7{h#h|^u5CgPgNtMsgO z#rd_#4B}v=t7kqGR}~$=C>$IbP4udMSs}jM+A-*TyyGhF(f$cEjdARH zp#RHy@etBf112S+s@57segjxC?KTnJ z3EcpzOgv7`A(ja0rV{EE0eg6zs%)7j_htiN_8-LA*P*WTc1qa2rnPAWyJH`7RR;!( zKNVp$0+1$!8*0;^7Q%O7n1ht-AY(%>8IGoM`|u*dS%nYc&eh(|RlbrD}K=$p7gd`3hm=erQv+@r|#XSd}t0r(7dU?MI(N*!X6XUe|NL|?QZ%97@ ziZoiC`~B&Ee%mvOZhJnY?TLl=fY$E7fRQ*6Ft=45wVwzMg^WAqN?=Vtu8Y40_5~v{ zZg(3e;&uw)m!M|EfdHaMgN3I{{czM{{YdeFHq;2|<-7F>i+T`8RCN^D3f4qIYuF04 z^D3+(ePHx1uqLN|6)rzpfY&N3tX+WV#OirOZXoAJQ-^djlsybbz4j+=exPGGv?RTWU32k~pvPwXd*aTfJ*6HB2M zyV=;#^(6Ry6W^bJHvwGmcZ?~^+E92Pph;yAq7@>4fp*Dyi+Pj|dj@M!oiD)BY&Ks=^^FaFkQH1|~!@fQ2HEh)rfT<@VJ@@50j=vPUe1`~ItgKXaTc=0b5y_4O|D=j> zct~XnD;G2l9l;p|w{ zT(E@rOv;r4)5fq(Q|r2S^}x%YMJ7@8JKzG;+O;W*f1aA4fPdBsaV4mYdIu^%nUlA)FK$q$pt)`ywA$Nc%#aA%RVIbK zE}Uj0stz0l>r1Z83tWMy?kdv`^cE?dMEgQ3KzkTpA@r1?U%ELL-b9NDb+7Z}*pPFe zF4tCwXM+xRut1FVEyCG%Mz04Gwnx6Wl5YE%cvh6kSHr%pUZ2|r>;G`o=tR;FfD)Pa zzt}OM*J1Tt{nC*eT8fCcxnNo9%T`SV9*b9z+%fKfSI zrv9J1jStJSWAds$2)i+ z;Tn`z1w8O#*%?jvntX+^bTyhe7ckvhSr$Vpyv<#<3MUKlfO91zMWtvKuloiJQ?74Z z2UJ??&s4VS3)W5z+Fh1y=6t)mYH;E0jjQ;B#;KtJ=+ze^R+4@OlqkeDGjz3k+RXa% zKLc0#Gx&hdpws@DYS=~|=nRJHR!x;iftZv4BSSZcWFtePucD51mE!W_^)sc{@HhZZ znKrnChrSH{J2`Fv4h$^WmND!Gv4?0mxfI4An4hTvrp>XCZQU*?$9vRRNj)Aq5wN$P ze7SCi0@?T0yaB;a1%mr$oc9@zK|y{A|XS z%>Hxqy8HK=*Im#Mlz$H`nCw&lE_#cL)GQ1LW`T1#k+8!Wq0aAPL&x(nDG2CoNA^hu zwW8SREF9fTT#pllLA$k9aFe|XJ8A+SO`7f_JPH zUe3m0w%Xw-d#cjWiTKAbn8fv41^fzFUyK?^`W5^y3eK=!TILhL4&E}x#!lxv)<3;> zvN520rw=)`THdYHd?NvPzHN4JbkDi>-Y z;*3q*-1&}=UzTlH>RsTzCgL}_k|T>M#eZFK!>`We2}t-!TBuBE=XVqo^5&&~8{T9e z+p@O*w9?ZyRKV`OS&_AU*3+!qJ3#1pyr3Me(AGoC;htq z7q#p^d|fs=3wiX{rSF_owA(u)bw0dfaIt>of{??!JqJ$x_Sv#%iEO!Hum}65rRUHr zzlZ0u2b89dJ|#%G>#?m_>|x1p8hh@`=I$roY_EyhWxRgotf|&pDt=rO+fW^JEf*}@M|#@`T{%C~pTtu@pP&YAQ|Xkus-pfRttyxr+t zEyUSTXUv4j1%XASA%lV(9v=Myvp;)YvVLn+#OabN4FvQ33Pjp>Ob+P>^}nc$|KWpT z>UxLv&u`jn3~0vdL!PVf)Not&JizR{oBnWBZ_J==HtRJfUas@rf=+5#4KmJ|YbNCI z61TkBK3CKlq;_+eD2(;1mVSO~?qZihqHb;f$^B0nlT0ThfVWjoZgfeegn6i9*xr6C zDrTQPx@1RAX}N6;a#Wc)u^T_RY>;uAGio|KWNpN`tP3GU(e<5Ya+1q!mYiBT^ zt)Vt|#n`8$-wQROIaB9LCDwmFHReH6V;?|`3CdLFc^Ymz@|BxRz0n`PZ24@pEY?{* z2nu^qeaM22H^3;J|Eb9t4SUN4@M>+p9gvU94iaHcu|kc5G@};IEENI3?XHHk&m~6_ z$HUD)QiyN&;YQ8d-icbOx2~H2q+uH{P@AUEV|MH977u0AA_{892 zhOM)$fuo~=f#aA>3N+!txxM>hV-sUf?@LTfJb7|o%%c7A2NMz&tzLYVwa{g$=L(ml zj*jykoIU0*S+w5KvB-T*>HX)A9xe22cv=1Mu_LeM(dU~!A7^fEKG-&HAcM32_?079 zhLpVq9~;d7%3!m>_cWeA0MBkYAPyKcFhuY&R8qz-H=Mjb*6!Tj+V|=XDF`W1qOELo z?doUF`13)yiU#3_fbal5%%9M1Dfqju4R4KCLNU!~HashS8zF+ulw2{;*2QA422V0b zT2rG0Tj?r+S<&yjo)4OW6ToO#bqzNGj1PZO+K$=~?3x^qo4)vZ*VAKof#!Q-c{N}k z1O0sbVftduRdU+KSDHvTRr2?5#qh4~H#qeZl(`@myQWQl3#Y^;EJV zo`G#5VTHnE#9M1yoi!@j^QPxz-OUQbapA~yxAPo$ zOJHXh-Dp8J;Ln^eeY$4R@kWhzWU)Q0`JRMCv}aKj8vRKJ*x=!SeMf{(OP|LE^LkG= zR>0dn?cmtW+`RB?VhWJAV9N$v9o@mrf3zHw#^kCWiJTV~1C$>{exTdwk^uyq{DkQ>q>;wf z|BDjiACRbXJPyr>>AQ_Z+6;_No{xuoZiNgk$UezCDT@=26cpTwgpNWEZ%aahF3-gA79V%fFtG@x%4$1v(1%WI` zRdt_4GYhT)=D=EEJhI~jJY)kmG&a0Lqr>+yQG@v>^l yb7LZ1?;%^F70>sG^Q=<7Z7vw`zhd*gq;o55nN!jLmJx28<_WGcHxcF?%G^E5w`<#o%+$%n+o1` zS7?gOS)~=~&K&G#l0ujoq0Ua%1U+~I`%iB}4CyxH1KN;qm;+DTW&zU;=RmDJ;H~U| zhdS0SR6J3Z1Jlu<4+NmsoxC43!~Xb!HWLDHChGH_=ByWgA|RFsBBgc z^t!$DG#d5srT-m`tb1~Bs#?kG$&+Ac){;wsE%2RIq*gv81t29dm(?s?r!1QE*GB-( z=$XzOFfMNWu?H8M+}QXq2PG6{4@NZrsSDBF0!&w%gglElDO5R&o$yV=WQcJWuqOmN zoxD%))zbZYkGEBm0+bR}O7|P&^em+J0L{kZ(Dyp*UCkB(tAo)~>EQ(XY{(1i-`s23 zTBnpcd2EOaeLCkvxPL;d5;bsGq2><*6GD8?^ksKHQ}I^faSx&bI$#z*K3W>ujO87! z2-dP$b|RUY6vou3RPjA2{RODZX*8AjUs9QWoZZF3*XXWh zbTBb1A?n5H`Qx9Tez2zSrpx$WaF`G(++R(4JqEhvs9@FM5&+F({(aB>{?22%xe{!< z9d>eL!7@Buxmt9hTbROA-Qoj^btK-(GRlkygks7VXMpq8P9KW0J9A9P^aLXoG<$M8r zr0p}dK^O7p$BMCU|6Lr@J`wOq@kosVL%+@?Oa8tS^dHHbR=x@w>L=%R0p1u9_j*hd z;<(F;H4f(0rt7cLJQlqlK z9DLnaL>hs5jzFJA!hEuJKnVi8V>#7J{~a*)G~v}eQV3F{sptwpdb?a7N0dK4!(F8< z=ms;Ky^f{AnjWU6?HY;-9l66nXye-bz3@psW-K68_-rYXRdkKJqX%YvMC0!>${e#= z@MZ_W`?`gg<#$oz`T(9s=tw?1@D|`2e#E^{)kjtqp)r9H=0<0G7#+Hy=TCEXVjVnP z1G8Y_HS9YzIaeMkIO1O6D8RfvO|$pN@YdgQJQfy^_@M0AmBFD2O_rm!Mx}{eGDxEd+C!-9{i?Tu@ur(2LmH z0>NFP@``0N1Y%1}EoscW9Yvaot|l;gV9`e){&8R#6{tW2N=8TfHR2Y*4m=OU#Y84! zxOI)TNqjxIc0TE&Op&6Z^Rz;{Z}hxLeAucopJO2cooki6?HP6vYuxd?PGEWy4e_1& z+CAgnoc7bIdQwKwjv7%#Xa5ad9re6AdUYQZgZf?NsFuyS5?KG@G%#HuHUq|QpR5GX z{&0O}-C)xCNR7av^YH?D$4bw^*wkFAK`Mn3m>1}khl*Zo9in!=_YCanM?#Ffj)-2a zyRU_0!A!w%Qb8b?VHN~uOZ^LD_*@Hqf39ymtcxbC zjns%QvveJ2=;R4K2V>J532Ly1#{j0k$vPM}s@A<4Qw{H48UAaJqL^S_cpXM;Bp8Q` zCv>B?9jaI+aO8Qg_TQ^l5^1xP45qWFk!E0N*3C3w{TGPsccN|GA7JZ_@s}dG0vWdu zuy^;@B}c6VLbs8F)(sEwojx^IF!b%1oL$0$ELT@JgKKq~o`ua{k%E&NoksWmlGY9N zoDvdM`I6t_q8Z3tjj>Eggcv4VOqu|iK+rP7v z{fC*SsdYHOh6akm0CQ^1h5-0pYgr(9Xk{)b0;v&hAQ`V)3rUwneJ_hK^SaUKVe|V^ z#H{O`8{mc(56U(oDBGk)_$Y=2BG8U;u9{*gXEt>@!R z%)Ay@D05%~iPVDwAr03QoMB+|)bpe59sps5aZKKc4sABsMMa}2DJZGYaOka>e@g$D z?TMeZ`m*3PEag8{OTIwDU*L>tcRRy=L$e)TN;oY$b%{ z>0^&%dN}+#URw)o23C8K0+AZcM)$Kb^aHKuK#ZBkN26QVB4Hrle>*B%!yl{;2apOs zv-GwnSd$5wF!)HXZqs@rtuvd*Y`Vk%@6y=kw;~H% zt68-me0{t@re}P~(lSVgGa{0*OM87j!0Qvf5YNtb0H@&g;kI3B z-mR!!H2Q#(!^50clam7O*?<&@_?U5wjjsmIH_{720cnM#NT{K6Q~oIfj#E@A;cS#o zFu$n(r_6%&lePL?L1g4wjtP$ZvdC1j3e6X9S1RiB`F%Ik#A<{`gqg+ zAH5%MI5;8@ziVE=0f;Jw~9d(`6-7T37}D#rNd2eo21 z|22Ox85U85^{laMG>pR**&FzNcQMOid0IJJut5=k7E^f9OV#-YrrTRoEw-oF}PMM zbO#r;d{0^(DUxw?J;6o8Q{Ukko{F>DRR!q!L4X-ybAyW$!ac4p(snwnxTiV~TKqKf z7Hru7k6~lALwCQb*^v~Q)TlT*-^-*QZheI2?@c5}^o@uQXP6Qt=GBxsPCzjG7rhc5 zLPb+{zJ@(y#GM*ax_kyDLXNeSu7VCDf4;V+^EN=kEfO&fvFq)wO8*&ClOG2O2+kyL63sEqP zc!YF9oKF! zGozR<lxP_r*JS82NQC7rzu)tm{%0fYtHQuM+R78%KutDlcl|2%a+E%p`>; zHM)@XEFIxVcL4eb&)+)$);%TK_pN3l+MKtb%E2{S1^pXi?^HUG;*T2HN9XcL4@dfl zzdt_vZXty83O++-o?hjz;axgA4TwE(lPU*~Tvg-KQ#Nrxv5t_V(WU8Qy++1p2P7}A z=7Xg0q(ld@o~bLd$+Q_`ZyyxA)5pvI%P)3cP@^s26N8T#w$8Q&j*bQfj$<|{(1Zu) z_U?;~O^iLgFEKIkTgUtrUw7uv9 z>_ssmG}dWJ9mLt! ziK`h~IM15QCIHi~I$f9SLaibvNQ8l0%e=$(C(mf#`1NO{2S`CojZ~!jX$V?c*K=uI z&;pDO8%skwIR3{)|30(5PWUpC41hB!(TA*IHl=Pe5R>`mS5XJLihe*9#p6{C!1QdV zbLVU^&dUx19A_zNYMFPwYoq<`QW>(ZFZTd2ZI*#Dfx1J9xG4vN6M0#Ti^}9xNmG5q zK})?~Tr4UEfdf7|+tc$4DQ>9|mf%RP8*b_FRef(x^K*fiyTRPkXX@5l+Go4H{G}}^ z`Y6$jtY_+6HR;|{&!254e+?4qi?f8CsNhWfVUV4fuH-woTFWYs6)^WDYOsoTYZ?)M zP3Augm|-Hc;5v5ey4cSP&$kHg^f;kZyB`troe8yq7vtc8Rmil;=b)wXYElGKBQMe9 z(%;&2{5!cM42cD`6@*&p>~|`Sv-l%5G=@yvQ~3!g{wUFutZZm<^Y6TZ@jL!FehUF} zl1q({1IoA0tJ3hD)#0-CJgcE1EsvC7z;7i*A|)!2HQZ>|t&^Nduc_(zTRw-QLIiKQ z7|3#Qp9k1aVu4ZM5y0H$k+DU7aQ8*-+>}PCxo0*ymH~3#umm?_(odTOE)~2Ngwh^} zB&0~CL=du`q3g^;&+7U<^WgCcP8W&*-)XURM6yK$;FpR(-tqx>$ASHU5vlD8-uC7_ zQZ)Jw&QC3L#XxTo(Zh>LUwcM^OyRy=-#fAOO3K^J+CJ^H{-jTmPl{Y>q$IlA{HJuA z{%N4L@qM?s|9`qoi&>THN%2RGR%E5?8&5ku^u2N>9K?rtz^pfPX=Iqt1N5@{;6kMo zJ(qrkoevBJjVB4-^c{yi@J$JB9wWtjh}m0&sl(Ed!el}mE=3E*?#(b(#kCz8RMp*6 zNVL~8m6&^l)(<66ZG6#KjM;1F_r*tWE-9iZ5ss{9>grsk5v}itc1u?y`90irmd{$i zR+PQPvG2P&(CAN1JgRIBG-nmRMG)qD-!VGOQ`co|Sp?2+IdD3VV7kYHiy7CSDICkx zWB)*-llzA>1suOkkOJtc0QLacx9^=) z0!-f=5Xq}}#)fu1&)9ib9yDtj2; zD_kf6OZ^Rx;17hx{GhD`lI?JH`yfcHEh>P2>6$j%Mgjk<^hBC;b@OeQtbleMl7 zzs+AjdNQX4`wtN8BbRHSYxywF83mv7v)P>ug!vEw!A#8sbH0CW{o4wMGZ<)*veamM z2PnRi4!jhYWv`0E?E)Jo8y*QA48k?*FB9YL7CQk?JSm|-!_Q>xO}BO?CUY{|71O|J zxlqoyVrb$qFL8i}!w4-OYyIn|J)~^`CCZewjjk*glo0-OU!N-t@DBiZN}&dxEfA-G zf*Zi+>?~&uQuL@E7;$*Dz~>G;g|5Udvw^jQJE0dnx2q)gDcH1If)q&~s~CG@@}eAS zxfa>kp%#6_i(Y?@6iMExcRGhEdC!qf*T|H`in|twYWB{#K^)Y*vvB(=*UF5- z$$Qg{q*`9A|JyIFkz$<^70lX7*Av24e*ycS2aWX)z`9exHoW(Yn#HR_GwSjo(hr?( zMlGs=U$F6uf-&uCyC|6aRR0c`e!IMNa3SdJM2cjmWvnZfdDS8?YkPB9cYnw^2|}oO zJ<_fC)9hL?s!2sO%;(u{Wk{<}-vuqCKZ^U9RM=%wBBxpDeBgslAJunaBHtFc%DLUF z=tTL;b@zwAo$^otr@87um77V+DkVahmF~OK^o0*Smvja0(oksd??*RSGyr&FxEwC_ znVY~H!&;uUFQMi(DHJJDzO0$LZmG~Oyxy0?G@Qi)M#jMO8}A%~t+3A3bU#xCt{>@V zO*}HGkosXeGl@sVeQ;a43#=$@aF=0C1BESUKEaHzGCY!SCgQS_RHnv^*ns&c4d>l@ ztqKO{9M`FJmG@Q>FbW_`iXSG0Gett0uEtjy&iW2#3-lmv-Wd)|ca;P2p}zJsB;zt6 zovh{>nRu8^;m9}m1GkYNzUjQ?fgG7Nm|*`aQiU~bT>SIBWFTACbv0?Br?M^{*Q>7Of2(2iQ!>r+dqni)W`Y&(|%$w!{K7b2IaKMMH?S1c2 z5OvoB82hXczEmRo!}|rkphqdYs=*Q-@KAdU^@WfB>fG@}GhtqL7np7|1MEAuR0q;! z2!D&ZI~OqRe0)>YMP{0w(k|OI%;6!CP2IP(fc|0{p&|t|HJTbz*Q!bbTHkwxgft}* z-ikM z?w!EMSC*Xfrk0ff3N-9X77O|uT!)mvP?pLe)#0Q_q(&XH)78mH%fI?wRGsE|gx;UQK zYSuUL)A+6mf#wz{Wve;u9oVMY*&t|2x(^sXbOa+%*z3?+l=V`B8O=b8U>o7!&)R@K zJPP7T} zIhwVp7Su+b2GWO7yDs@HixgyZw~dU+J35ts4Yl&8krkw00436zwVkeNFaLSjq?<*E*pC`&TBIRu9c;Kdy_HZLLO(hwU@FhMBkZN#S(}BX2){ni3}52o!sI(C7{7+RK^ns_JaD1F`Uu-|~QnQgy4DieNrX4JQIk zKxSH51u%VB#i-^O8+w4}J>AXMEn}@cWm<;r!Gpo1QJq$lD0;{S9%%0=jtgEC}Vk{B(hLuFN5nD6w)wyF&KJUDGhZ1-+%|AJ%<7Cl$Z zA4K?k#(s1Yu(v39UngZuA-4Ag=E7yD<73}j-}}^qGZhu zHSak}gkHnh$M2sVr8XNWjM@#7_p3Q3?P)$t=J3vUk8ijQ4cY;QiCckbI(7q0xE1wo zxDs0iC7y3YEzU@JMTFBuhJ8%}w+`s_$4%jO~EC zC|#;<2_y^8Uc9jc=S`mnLR-=31k)IqC>5wzHme3l%~1Z@Q!d#9`NO6v;N}N7UQR#P zXS_tl77vzBR(GKry?{!IMrVbrK|jr_{x&Ufx7(fGQrO-s_2YtRT?FrSbx8L4bz4TOLUhS&5knh?-aaF%G#5Z-=S6W8qf}im?vSJP;#pz=LH*Wp%i@9?d zKl%m-t@PQsAkcq%V1Q3R@E8c&1%cZFcdps)|b71iGv8HX5+e7QW4ZLXPrJ~b{zBQ;$F-SCHA$WTaQ9dl&y-_v+;7u zTh}rr*Vb*5W(kY9s>TY+lq`mb?IFm=om+c3GB$MiXQ>ePi0{KTCpMwchrEPf2Ekr; zC+D$tY?Y6bu^8_VS7XDt)1b?m1ybLjSG;@fSh-TJIMDpD5)9VAm2){Cnk|pw0&z zvB@jLDl-;5Z-p;aGgg^+__g+d0*eR*Z+CeWFmeu#=d(Cq4l})~O%8&`CiSt2!J(yJ3)8*j$V!`_NgX&k3 zZ?}_v2$U$aHah3Y(K?mBH$@5Xrr>`Z-$h&vTQOV7QS%)<>?b$%nsK#G*YS1Wg#v5O zhbrz)8Cv#5@UuWQ+j|u8v=v+T`XDeuC&FdjXEy<-y#N1W?_Hy!IJd6Rye8^4l8|T= z(P&4b5^tb#(N!uF{hqzQ^PT!ezr%6L^s#<87>=QXKl53&)|zY1Depf{I_y{hCzqfU#*;k(5j#h1*Igu26yO_e#mmri822 znLbYgC`0+ff0pNT%*34?wQ21iZ=d*#_BAlW+Ugu4!;T30{u=oc}wSm{Dq0r%+$^N zhcM|Q>@*ZW;OOz($zVB=mE2*nZqd2^to9O4C+IwHNy=c3tdY}CwSIuNFSJLFT^1lXn~f9EJ^^NETT5MOTXu7)?@vH`*cSu=ALN5jTP#=8q!wHQ#yeE#$rsLo>1JDHBVO;hyU2Di zSl1;*BScs?=$E!etA%r$y8DoBs0+3m($Y2pS%HQZYaD($OF%o4Nyk2-Rj@;!5GE#I zov+qeL6E+KJJLojj)XVpJiy!inKaCwD(0&};C`?_eS6`_@ye{zlzDd*nlJB6X+>Sm zk?H(fJC<*{6z1HpS2moCOc7_7gQ@pg;9>Ac#Wsn(Q9zjG@5okPbrR6XjWp}u*g>0p z2(HmqYi4-Xg}PR2D0F}4_9G!I&-4~Nlca6{RYn8z6nko+M6OQL@b{U@&;~ib$;j!7 zcTEK_C~grf@+Ntk95tHUZl`eb7RWp zb77nUBFf;#MeQ=@h12*d+DE_)*}6bil8Su<`d-z&6*&LJLMYV;qU6z$)Hq5QzKfK= z(7f_(vujH;)y3vVs0i!89~36PrGdIVI8wMp+`K>z3`RQ(fID33Y>p|)b?cLvghlb6 zfUjHZex@9r&rzXaT|oHit7a$$=~0M)!P@cO=X$7{Gcv&~(!qG5CZqzG=UjC39Wx^G z5||gNPOgYV%Cx68duDxcoEH7eP_zqmJvCs_ukYxefbAyxoZ&| zqa@QL*e%np;DB51)=G)yOJ- zq|9$mrP4LR&xmCp1m0Yx+*+g(*Q zYJl-2qkx7s&~hfXuRIkPnEWw_sZgu1Zyf+q_)(+8NQ#ZiJ?id5@K7rGdF{$=n%7+p zw}uluXMQ?}e3|>|nu7lk4`>|$et=58wF+4jke*vie% zp%MF9aHGiw_ITbvkA`&{R%%s$({_)upnU_(u)DfRy5@D2nH7cP;4 zML=CVG<<++_m@&4=m)@1!xe03=`e&{ zQU3(!?1{_=G1ZML-D>A2qKoqf3jthPb~cZ@N{fDG2wk1kCYBcO9{uJl`riWmv5%qN z>R%U^78ty^6w_T?hI+}G4oko(Tsu^20c?@&^3(HgHlHmyo_a`Drs0 z+2&`Ddq4|)MkriMcs<14Xucmenr#E9duS%)oASxbtqrLX&@HOQAUE~k*?RxfhP`$5 zk=;w1(TrTc`&~o{Z{5HB!=^Q&rG@IH^<3&XscIfDl_OF(Er*lc5XDn*Pggl~HR!-O z&A?^;*j+Zg?sxBM>iV(PH%h7y(;);cwwWPhbr+DcO^u$PthK#H-FN;sw%t_EU!EFl z0mf^`1~hab)tOz?X#@vm4qxIH;yNd zR@k5xz`?VP5VZI6SA@+6w~{*^cPfr4(rpD)4!2&o4NMI#Mk5qL*zS}aiF3*A~{@w5qJKBh%JGd%19T@9Ati2cqt`)oV^-CHy?C5NRbUiMln1)|*nny)E- z{d0w=6gDE;$BfXd5&P|^+fyE01imzZh6&*}sG+`(!b~+L2{9@$pW;8L`eiC{R4(?| zL-J?0ApQM8Rp_W*pvdhNX4zO%lL&a7Q*|JCIz0Czle?x;=9gZ&L*+?<3Mm{?l`-Q$ zUq%C1frnT5)oAC~gBM37(gL3uj@DY|(@YlldS3F&i{OHEHpJxO!9; z*2fp#AcvQ9sk`~T?XZ*I-w%yS>*7k6s?brLAp0ONYd>n2XI+V5gsPsL|DdDYIxuZx`gM2;)xLyN-&gGkatR+?BXLT*)xr@OQtdbJNs<9uJ^E*+DtX)6w zT)nh&a^PRO*=m1xxESVRy{rfLRVuP0H_cSKG#Qxxqg(>{ zUC80ukN!+U3wvfbTy}f;-tbqh{-lFxyP47?&Edv~LE$st0VI}x-7l!;QLAxfp$0L& z!v|+f^K&RT0UL;-z?Z4(%YpDpZw5u7!{8Cm!cbm;YYKXg@V)R<=Fxu$Om{O3dj;0r zdQDzbV+P#WwRZ*_1|v%*!cEW7g`khJNLLpUXc|mmAyYwVQhJgk%dH5WWPWvd+#)*Y z!&nL?s9QL`>bAXPeOL9p;_px)f{Z7?xVaJVoOjPB_{*Op;Mo#z*?-K8%$YCIM>ny2 zYII>WFtDT0X&H%>GrY%fr|MwCVqls()}$)?vd|G|1Cg6x zjA$QCr4uDf<>IGYu)N^>s16qeu>pr5-+Oh~Oj?jL!_8XjYKOzNHTn+n%jJ|wB)1y1 z8GIu*9PrSf8I6Q+w_7m9b&Rshi-he8e+{Qp-eo8hIzg8xr6aNolfmYF02r9Uknb42 zTDUvt=cdP;M9O@b6pb&qM+GYh>{2bHc{xZuszN@DDS8nB3=+t8Bsmoc3@^M044m3f zZU9^bj$oBPT>&m5via3 zM2mN3h}Z?tYhhi$7XSUbp%uf=yEgOSk6+&W#o1xY4o?sNugsjhwrZUitl$00-k!Zd zc#D-iH2jF**REBfvs(FGwa86S@l?&9oVJlNDvVEa8ZJ@g_&?>{DeVES8 z%kp0lNgN7%c@R;lbIb7m0lu ze%!CPWR3z`0VmXC;Mc~F!xM+|!y~~||GSjpdT?P*zWokEDnu=qI``XMwx{>BG)EJl z{3;7)$pVP)HSTn=W!e66fxo1z#^c?b1*nq(EM~NU0CfZzS z=xbSg!YB}smx00c$lQYQ3X~7m@At1mPPHXcse)}g*&lujI5_PiL@3u9exU4-1E`1(A1t2 zYxahm{kZLOT6H*NO&QqMSk2X0Z^-ggdXD+nAkv|{klXFBk>6hokR>1*7kR_;fv3*5 z2j zI_6V{44dI5{>wBh9BK&x@iv4CRH@w8pf7Re49_dMJ}!npJJc5;vfB=#;znfWanek(yU)=Jy!X)Prn$>PS)i zWj<9Ns!8v8C`6_0tp>2xz=OIJC+GNQf8gm`4&D`07@>sNq1w%7N?PVBw=Mw%c3y&IS!y9a)@ zmQ$kkHZcDBM@2vViOQh;_M1g!VpcQQISI@MqVYj~0pyWGSs5@Wj?N(G?AawhIoh?WuIW9a5o@ zrK0u*B6My~-fHlpJJC#;mF%fQ`hj0V7!}eF&&!}ND&}~#Yy^c{-*N&?ZSA#kl&F{U zuLgoL#m~rVAO%6~GgepaaC&a!rI1x$k|5Rm{3Lr#-~PjJi&@SeZA{nGz>8oeio2E0 zV=bHPs^?huu7M69k*1(-26)|d8W_YY9Q@6py2KWarkh=2l#kZ|V|>)2@ZD8MV5-|^ zej4OpMXory5qO0vBm|D3#0_0_ExGK#mGx=y2+6YD96nXMdmif zHK0LUa*HPwEqBa4`WydDnAQ+n^2w*mX_3wlE35Oqo~`P7j`Y}6rPllM&Cc>AG7R_y zf@}xj|Gu+aj_sjLIy-^#gU6<6$7;>is|Jxmg=HVM!Zi1s8?-mub7~Lq{e(hX(uEmH zC3q9g|NcN75P6Vj{`3RsXNyr8;ui;6jwPwkt|~CLlz$icTh7Suhx6(lw@-tTyv_%;|_3{N#Bvn1G= zqrbI#f)Gu1*}kUY{jqL#4;@M@DX1k`_w=(hw0LKPk+qtq>v0+Djic{_>i>3Ed5u!Q zvlt$&i_1`PUs)uw|>Q;%zebD#GNU|~um&@08VOSWH`10FO8Ai7daIC zcJ>c~w@({v*l>|sbGQ}hTSaBNQctQ=;rh}L@kd?KL3%Mf$z1xu1V7qO12gO`Tuti8 z-m?JW(hE_pE<%ng}xruUnqM;nPfC$GUT}E=6O=M z{|7Rl2+7X9?aRMikrHj=@lEQ^wOE=)R=7_#UJ9)Q6T*P`naAL4?x=AS_EQH3aU-5> zeayXp=j#V59jOq& z3*j?qo17J|NyB#@rrU>8B>Z%Y$wvXgKYXCnk zQX@;c74Qflp8Irygul-X4h(^6EN*sGRXa2cEGb6Y<{^81*2Wa!8>$Iy+VYtDBX7_` zof#4q8qw)rl4XF z9v9$_SAIAyAZ}d zKpONx7cjorEXbP{M4X0#!8_peCQ{(5K=)_*7G$E$nKEcnU-jLgn^T%L-$0jh754_O zH3nx=kBl_dJCxkL$*~fLmz}5>O|h?Q3x`p(XN}Cp280d75)kF177Tw#i*jbTRha(C zmhbnYQ&A?s0JY^-(04Tk@Hanb9Ob8Rh`6BOVm0VIH`uH+X1uQBY0wyaon7-&IXfnEX0`+GOx2c8n+ZSGVH*Mi*AXJIQcd z_!ZG!j~^C+%03YMgsK?`SCY|K70QPykXP~EeTBea4q4s?jJqUl$j|C)|EOG}928T7 zz#z?jiS>~Er=$Nw$v_Y@U?-ZnZc(er4Y=QjE67t*r(4oK4Mw2m3H1K3R7rm^2=fg>Ma!@l2gn>P4MD4|#u~_xZm}FP- zNzzXgaxg?}f zXjyZ1f_-1oXxo;m5Wo65C3Z3g?Rwsm-Gqj{7C%KhXO8a|{)VV;U9LqVTDU!Ez9(>6 zd>!h!tCwiDHD%61#wT(vfhUVIDG54EiQ2?-{azylP(-qSji|Vp4D0fF;q@j{b|8)r z(88G!*42`Q^LyiFQ}md0sK(9%MLv%G)X<+K#oT)^Cs4oM{|5E7UEKx4?xEfMKcs5m zYKZ3*A#p!%3JugCaV`&d?VNN@1wXkhN| zziLr9#jl1Zlac}m`N&R}o682JSJ3%czY15ytiQoo3{Gp@Nktd*>JV^qNL#4$F3SO$ z0c={&{(i$Z#=_l|hRg(~`9LIqo?xc8kNzgO zMDRBYD9PhtOS|?@N=XjsmEg5+*v*Yfl!RV-F+MN}2mKV}FXENjdZ?Bt_$irP*oY!< zHYb-_0~|V4ns1@5``MTgh-L+~eWS`m^-B!}$ngYMNFc9?ZYP_~+Or)}*3)~vC!`9rp zrO=F3JG_8-I4OKL5aXwaY{jAjypXzjkPj3^by8$dyDho&=@2n(&1Qt+v@+NAQr&9d zyKh09*cRk1T9DYH|2y3#*afFdz*8u!HWOjJfnzRD5cgC5VIUEIQe8tJw*Dv)bH@XP z(KXT0Pr+CvY@$c{E7nm>ey$2AM%Ca>)rMl=^|Ay=Tvh0>;uHrNy#Bhh&l&J1wHDobDhU;7Owz0s}#87x&BK3S==bSqB6%7|;3T${|aX;>a&j(PmQ) zc;d3$l-PPQuiV>ECBpcc^a+F5=cao zKoGQje_Vm94uC+Rfo8ILpbm}r^~9_LeS5^aCjCFRjP}{!hC93#i?q`mO+^>aw68y> zy^b-mp^9m6Yyqhq2FO)QozK45>ll5E=LtA1A{)2$j zWjV3E(a}3f4KKBKgIM*f+x8yh@c}RCbA`#ny;`M5+hb_2!EYF?ZT3wMfA|qCuo8=--h4t&((BN%qkm^SYZ{3oJ zw3hMnc4>sqoWa9Xd(Hj*ndOpHL6;WJex(|c7S0Tjo4R)67VP?5&xIEM%f9jE|6$+g zxd%oQj~d5$UhKF&d@co}_+}{tA|J3(k&08%;?oG>*YzSi<1WxBW3V%3UsA&Ra@cjW zR8Vw2rxtTrZd35v$@pXOpFep8{%hFxpAOqL>_c|8e2dw#Ar3mSA2rr+t+iH06DFI% z8Sv*nTS-CmW8ewxV7!+QA>Svo4lkEm3(#@b)3=MC2A!QaA*PzY;NEQtzl?K7Nt{IE zDBkMeJjxKD!`dOc*T>7vKP$mZ^rpS0@m{-wopQv+WOUS>c4UbsX;kHj{0eHWLzDLmm}<7Yos9lfUg!UzA3vA&9WcYDn(HhjWo?r5{2jO|&A%(qzt(e-792-E!iENkLRrbax(hz@O{!LvRaNP_9#r7U< zD=3*wVodl(BHrHPxowmgsRi@XH6VZ%%#1Lpmh%_ts5WA)OZC0sse|f@qhmF)T5jD{ z@kDSWQ6oOSNMUx{%}!uNX7)L&H_Hz^vA2P($7S{G-4)bLQsx;V;rsz^q+&KaU{-O= zZqYFXwsiS$DrZn>f5m%c(?~UJO+IuV?4?C9BMhgd?j@Nuuh93B{D?BS-i^h8Gq^vt z)Dgy?D%EIWfS0UVBV1jx&>GtlcXv>bFw1hRbdfr3Z#vAlzNIPO!$E!nesg1iVl~CR zaLg{Gyq*e?i_nM*n%A7Vq5!WH{#IzixblO-+k_!4m>D7@b#{|x!L09KPNDvleQge$ z3I6weO=!eEKQ(uVHbtWf<>J{>SH^>;FS(EH+%T)`d!&gwI>i)-LX_wnC+v4qpcoXp zp6smx%ufPYmSPbr|ybG${hbTbHh)LzAjGc-|hr57s`NUI)oij@qV1wDr>!<>XL&i%-C z3XRBdfTnWyUO4;u;QXs8J~c**S|sBmbHhKDso`?4PDRo=L0imYgow0&hSRz!^XLB! z@VtiIb-%@~+ZBertP*KcsnZmIw@4#PM<*ZnbjSq_(ia4;4675;{|R8X5b;OjH+0>? zJZ9)bovrv;I#J&TIM);s$t&f6LzD1%8or+j_6pZ%9V?r;G=gcu<-Ub^o+?;(qp-s{Bw;%ZYj6hX~x|E;85s9a>dsnw{8(O#iWnF z`Qcr7uD7=v`+ZIq?!Fqm2MCizS38%!@#)N)_;Cv@)|nw2VW^jG1(-c#)pxAd`KSen zSS{a0;h{keOO;%)1b7FI*^s;E2Jy8jx&NG?3mLHz^a{Q5qB_xGcQav_CRe1~ zxGexW`AbcsEP0o6Eynf&=-C``eiWUZn+0?;VWNwkud6}G*gE?{ zzm&zh>@WA_AG32qKIPul^6HbrRl&5Cn;GsDMG%)6(=}8h3`A`j9HHQ`wbYdEdc?_|CY&m{k#M0-k4>ZOG}Vh&=WPU2`___@ASJZcJ4?qv6X11Z|_F$PPkdy=zOFnh9%u%*Q@BXpkbM?)6# z-#w1!usD7T9M^rUDHdxNYp(6Uw-t@Zn|`2i)=rIG_yEN_0XCvG&CveiDsl#vCG6N zS}-$016o+>+V?_*%R4X1;VhWn0?aVG67i> z$42Ps`+`^VK(;heW(-}VH~9fch#Y;I7C#NFsI<1d^b2NN3hf4Jx8FUg43fv3YxMZ& zX6FTR4;Po#H>Gz~2Yx{|T zpfWJH9f;N`94yA}TC~wDVK22A|46ZDiol{;u$;FYwMMOpSOcUB)cnoqMe#Oh zIW*OsEmEhaK7<6EQ24c$KpUT|q95cKAqz^W*s~+IGQNIkW%sfPM z+OM?^m@jTB1H$_Q{H7lSnaSImqS}+eKF3`Yye-JQEv5BtgOq%Bpu{^-Ix9`(djs-qv>`l8B~$movu{wD!x zfoi!pgch2NFj^K1bsppY2HmGUTOI$0)p1_$T=OAcM{hXsAg-x&e;Q^4&%BpICFB?R zZFrc{+v)S4Tuw( z?<-uJ6KE023^}FyZlA57dcNDQb7?~FWCH0aG(JqpFVSZ9iol%9q+jZ?!G~VJc28$tHz4&#u%pvkj82-{aBXiNUZsk# z2AQr({#8meJ8G!yET?LLklSZA_1Re%g1hpAqy7y?X+g;dn`B|7>%8H^JTlj^~tg@H=3FI45tPdfTh@Z12e*{@QoK>Jo_9@?Cnm;C1exarKC{OWUBa56*^ z={nf3WmDhFW=}DJtfO{-x(Xoc%Dtd)+6eLojYf6chtti2%I=vDoda#J!&$qc!(K<8_uzX2#c z*l+k-e8bgoW$?auqCz06M%TDHRVIw-?3g*~(XE}D20OPAo>LB_9q7`ojkaB`TSkjY zW{4hZU1uLwETr$BZ*L!Rky_RbTs*oAi^1z;XVRD3iw;ZlavNW!MWa_o4Xu%b1v3nf z&hY>&8ucBGJ<&zL;AR;GjH_osJ$#3;s|a2at-3|!mS88o8?KEd+4LU5rD-u2dW2iGuuUS9fRZFNA3&w`84p+uqqqcTK zH-8BUR%O0$zAd#_-7XG}>5oJR?VjJdb_z~g>ltC9te{L&w*yf2QRsXB8*2gH)cWeB zm4aBHY7!r_JDo5!8Auz1z#_x_6;e1_G)p611w@jBbY&swAx)+(oku&4A>QPX)L9aN z@Fx0TLa`5|}gOqVDJC`Gj8EJyedU?p6aI?Mny?YbeH%hRq5t zpX3cb_J5w$tEO7WQtoBjfu&(T*^!9#h`dHtPkq}2o1n)Fr#_;6 z7>p2LmJ4-d8Q9!7y?+>~eca-|Or|`#t3P}a4UC(^fcb0#|EInnaeHXXIRF zch@#=iv}6)7ZL;WERG-jjl2aK5wJdZaLHHvY^qQCPheoz?@&-4>Q5#9)>v>B1_kVf z-BOBJ5~g+#5{5=3=P2-cN(y^}g%sDN4txZ7t4(7+zTG87BOY&Yt8JJL${f1qA*=Ce z&$2Qa-ndiEpYW3QEil8l>1-5i{_ZvZ+t|kGEgGj?ghmR*tJP*cNTteO%VUHpDu1Gd zA2Z~d&LS1obY0&|u|!s&jJawYIX=f?tYy+JK=QA8D9-)0ocpX#R7i_NW*9Zt1nbr< zv%$&wjzm`p8gWIl=Eju&I+ix&zsjW8wra84Wa7BJ$A1A>7I&FfXV8L?86s_gu3)re z>0Ld)ImiBF^+#xE2?H1pnTg=-^jt=M(%Q?jC~(40co4GEK1mW5H~EB-tp z13QDYDJe$@nZ{^#7rt{Ycv%*E8En0mCIy3ey~vUjvg9mRfrdtdaN_jOn^ImOJ$&%u z7&XJ|UXmFoc0?=#3(*LwsvUy~uXmG5uTUondO7WIL-2#~#{^ydwfg^%snhPuR(SgG z{I`F#0Pd}I>jq#0`;L)5X_ym>^tV8INZp;dJo~tvnwbyoRt(M$0_Y6)&Rv4(kRu>^#@0vBULbICw*F+q`EZYVV#MsVC}M3 zE7m(Tgns?UO~uoQkeS5FxXc~t+>xjFdUd45PhOONZ?QZNE zuGCETMU^kfoBTYhtgWf@*00nkssbIG&I}a@8}mv_eT;HLtu!^ip3d7SA8+lRw8~oX zt#VF?vM-JQ{mn~xma~PWHsYLMm;BB=Pj81gUe9lNE^y2Esaka|&FP+x(-T>1M(UF_ zk+H$#b>9XRbkpoy>lhIAB2|Wsbliy$-aYkB^UR+1RPEbq6vilDs65 z<_ID8pONAgBwm#IW78aQ(J7J1s!%uYc|qz{6aLq$!dHd+s6C?!<{pgduO0Sb-a#eE z%?y9?`|lldh~B5yi+JT16Bi{Sp%Vrc_aAiO1=Kv67BdrdFyDuTTFuqD5U`&-J@3R^Q>i@sL&z+d z6EETQNFVf}af*iFUyu|vbOgfH6MfOWMG8)+oU;m4r1bJPyR9Z8*BS1Ze_*C1Wq!{G z7xq3Btse-lLnH7D?S&lwd%k?| z-u-uR8~a@>{_ZWliyDE6teb;|0N)rj@AUoquZG{~iLTFbqIe6M#-f8JqChZ}eDol=y zC<1sT$$zjbdD-A{4gVBg{v|MWw%s5CgLfgOcag^wO)*NO$rH;3kr~My1p~`gH4C?+J+aI`DcPY5hZEm z8aWXpv7Y)R=3Ey?;q*N?Q*gd}9_0=K_mCqK!k^=#y+t2JT?{6;g=g;%zB~d`*3zP} zZ+wyDaAA1+LQXSSk>&}4gp~cBE6E+%|IiGVv?KP4@K@S|imNup*|hj)giN)x*4Yk_ zb-2{?VIlUvhXp^%8SuYPS0IIW4~1Paj#SpprZgG0ju{T>rM1LC0-2`h=5qSMEK9}m zmHlW$_)}6K>jY;5$K+2Sg)22b-y{z1pREwJq1-STM+m(#ZIoQG1W4Q}70PZZ&t?K; zzRdJCFju4uVEO&P_{&6TtK>y^v#b}QervxWNsD?$INblii2TlXW$a8a`7LJxq3lps zG?Iq(cp*+xH$J6gskwpHeH>0yb_(cAq!t0*^Fz^X;Pq}G{H%o%O!Ihdo2`l*T%??a3*O#0y{$UNR#wVpe(0^uf9~cLE7Z>6&om3nnT_FW$I#6 zxkE>CoRMYM(*kJVDF8MvfFLN$k#u;Tr4%?(r2%8k)}tr-npFM{PA7Yhuhoi~9y$)+ zPYZKKC~B*@x|-Lqy}rJ~T$3jd%5IRn4vgSWc5LOYjZtnr2n-VBF<6POn%6ST6C{>X zzUkzJXYwryljZ@`<`#&*lO!pQ#3wd7NzQR=L0GYwM<++Iv0?xlqOe*S(j%!0iAz*c zvSS)-fg^E*5MJ@$DMKT2_NuvM2hy_Y76Y3)SJ_&>IdX9#7Fso2f~b9(fLkBGsd)o@ z2NMh_a|>xQf8ly;jdnMBY3)}5v@e1gcHC0e7r|<)^!-IZszCfFFc<@jZ`-~Ol7gvH zAZdsG;6~R2ytuZWs4p&xG@n#6kI$v@)B*L~hLNDAjLP<<&|#viDNRPFRpR{p^_uj~ z7@WU18%!*rgtuN=XBTxMg}=pVxPn^r$e0mG>~yoWr9maNgAm`p+76>V6^0p|3|xO$ z>72jFR(yTOx28q5bfixMSQiAv8!3b^GVMqMa8~w@C3p*JYxr>BrPh)?XuP*5EFCQd z_3H;b{-p8*T^>R+SJLE~?VZCgv0jxx9h1N3Bp8&?1 z!*o)S@GcaLTy!i>1;Q&GcfkSD?6{p9;t>bJr~!V+W#U5(Z0oD6KWL=IG(!Zht^#qk z$m=_%H3A-m?vROOd1zbwEc9ZhX(aX>T(S~zlE9R4v#bDea7Yjkh=B3&jsB@4T7YJU zTAYuyX#z?*Wh%Asazt?}10F*iJW>CM*$tC~&jQApfx$xO<@- zGvN@tEcwYnhnoT=+7b&Xuz+(#c(3x?a{Q%jTyblJJ!1oEoz>7myiCs)$)pcAAV- z%4@@f`u3DO${OCqu8%1SJ{j{SzzQ8l*wZ4K5ysYPo~|tnTkiG0+$U=IH;e%9cPS8^ zO5gsx|HH)E=z-pmuvAmqVCRiK-E4Us7{6W!$TW2GsBvayVBK1TDlt=_4oGKX8bbL_ zUY!Vd71ddrKDi2vO}EZ=nFC~5#8ORWLpQJ`#-LY&fkPE_7#Qhw4KWto0*nW`0Wh zGMM3VVFrk97vSs~U*BIwY}$XX@kwV2)_Ry%`2SYxKTW<8nU-~AcuEiO%Uut$>w($Q z!SxHz!E~9ZPeI;#(EKt!&5*A`7Kf6;y9>AZme1*W5ndjoUEdt(5H@x^$mNv zIrDw79}9U2l{Fk-+(YqB1oxV#;gQ-MLJ$Ou!$-LJuZ#jGGfUlqw9>t-ORn>x2=Lw9k7k*!gYpYi!e;EUQ(U=ctHx456YKlr*0 z-H3pMkI2smnAq@3;k16*O3w^o%Xane&BJg_>HpX1CYi264mKafMbZEA9OtA^{Hrq? zsn^Gr29~wELrt4Ped#Qd)b5#uidl$=+4{p;Unh|c+QfGH)R;Q`&y^HIBhF^d9jZ680J1xi(5gOsJ6S|wF z2w;D0=f5T1ny>8@h)qZgDtT*oBO^ z1M0FUd2XzRBfeb+Uao(=4p?1o@tyA23;Y@b0ZE|^*98w-O1q6ryMp%zqZQEC=}{cI zocl(h?DP59>9ojah=bL2Lj#4R?^w6Vp5edUEn1yRCl&{ccTncv6s-@h1ib7vq>!vZ zL`Q!U*?}3P>z3Qf!Y>bsBio<}nW+EAwWR0{cP+QuRfaVJWg8k{HX<@NZjwM8w#Dh* znX2%sm<&ynf@wLyu0-)+H89?C9lUuPezVq4#< zdaQu>%j9w-& zABftOz~Iv<2R4^zss3w5Jqu`I%LpxMVXf9eg7JOoJ227j>s^VapR~bpnNlVCnHGzTka^IgM@KCF4HRmt zSaJSai1Q^Ij^5HgOZqtBY|ZQ zKz;757cXcN$)Q~W10y$E{N5XSOA>__W8FrSU)`znqz77AR3xvWfwuTDLPoL0@BM+F zPzyg;{9NxOMK(e7-Q!f;q(vVigplrw8#V+|-=~mPTM{3=Q2?Y1aQ^0W@8zEW*#?za z0}!4V(^0Zo`!Sw5w2niE$AyfLI2KT=r`uEv&$Zq;K{<&XMgE7Q$bl_}ASQv!PJzFJ+sm==)CkSscn$!u-Z$8Yt& z0Vz&^hKKIxV0#umJ8CGQ<@k<|uZW?AA2Xba&IvFq{PY`s6OgeWGZPJYN(p|fzIOu{ zf03&|ZO#DEAL-j82$%qaT&Xps1tT-;3B2K9`$W5ymo{!`9(8K%%^h9iFS<;>zO8NS zImdF-G@qVHaqbT$U)|jF`N=i<4MuUQ2D=W_1=C4n$s=;pUrFH~zN)0vx-MjfGJ%3W z9RX-o@Wx_1zb=$1%)VdlYRf3^6y0$kLFSI+Kw zv5A7>wL6hw+Stm4%&;puU)iuji+=ZsT>Oy4p?fwkT(Q-_C{5~h6ZCoXi-oBB>>alN z#G>Dd|HJ-<8Lq`jSNn68Ytct6{^y6fIeHL&s8dS8xfRgVcBUdVP0zj2rv?+=`4t(7vP^BxRSRqX`86>L1W}@J*y| z>4thwn)cCh?%#}Uv1GF$^pI`&&*E6uO(F~HfeqNxN=?q2ap2RGDc_Y{WD3K*=a$hA1H zl?!~ISJOiaM`qZU1-d$s&Ho!HT1K$r^;?YBt+Av-^|pF|L&3J$xm2@lsbHO73sP8s zZ!mJJ3i{p6edef+LhZp$w8ty@W|A2qMrTr*z1`OH&vvXo6^&5E=yEsr%E#JlCBe2A z0@|v`3=5<4(sBO0cfWL8!&b$&sEVGSw4=j3Yg#e0D(vN#B3G@+x(g{P#d0mi?l!6l z4;(XMwRY+F-Li&{Xi>=wBg4w6-WMl1*EBhjSBeU;lG<6L;Njx*4-Vd{_>2~Q%rG(V zR9CnC4%;f~`{Ys;cOMwsBu!yjmO0?P%*7vO00XjKjm1%(V@53ReM$+xavBs;Wp+*{ zKYSAf{ne{*T6i);$>@B#!*-1N-Z847&*mIpTmrUwdd+^NrD5!Mz2MX0k0BaH=gS?I zsMd1;YL2=ET+a}LUoI1>9JuW698+-HG-_z4wi1rnB&wi8;=I2Z5yMU|`u?Hzyu5-O zflypQ6$lUnHOTo_K>#I)LEY?rJwFMM-7`m(5wLp) z22HSUjv28@`*lV=UyP!KA0xDj8_8Ch~#-)rK8QZ!B&XnW1GC z>gwXe($@M8*RJAzWL-!rkoJL~T@6L}ta9K^j2z+r3T_@Z4P@kYlzf)2Rz#~E3eCq_ zz64M+7}wcCrx~<_MxRWWn^@~Q?657SzT;DKN>mU6%m@5bAb2nMC1%@#^F4wCbkVRv*tAZPuf z^zhsLZ@ZqD@Qq}46H=&{)`zV~JF=1#URj+ABq0DDw)Et89BnweAy#KW3rB`{9bFH| zStYDKR>*(DQ5@Kf5_2VKe+@B9@MmgTAHxBJV$?U9K=U&IBj0cI4BM z!1WibI6Q4xQsh?mGez+U$Fx@$-yMIsnih`CP&PU*d005=I~?E4)E%H(E!?dc#4^+3 z53G>gpaIXm)UAY!w0m0WQe2DS!u{NihA8Bio!P%*-E5P;*FyT8HwCG z=#)zofAUX*$iZvNt{4KibNokO?N79DWQ3lvG}m?K$X;ORdwq2ErySA>fji~rs#2KuA{i zil0)$2C2lC=MvbP!f4&>NcG~$Td6x7WC zue**Pv-{*>h~1E|^6h_ao4sRW63(AI+gq^gL^&+5Kg@5KLW@ggNFALev+N|UkGTBL zNgU=56EA$ImRm-VQa;1C{!RVSpMQp1Cw;beUcZ9!y&ys@0C>uS>6>fNij$FK)MZ*dUhs>Jh= zAFL`l{9w|z54&R;)lrlTzmtd5ng$7`%DkiJ*XSS7`;KMc$t5xfO=lu8jiOMjEakS4049c|1R zA#*IDKutG^x4HSdub6gh#e9p385;nig^F3!wA3RS;qEOSooGZ(Jun#ghsC+lp!wp# z*}{*%AYBZTnMITxg!QqHc@|^h;zv*FC{+hnL`D3NEgZw7v<;-9&| zKwwDm21ngZ^0tdQjP}={{lIut{cIroOhoY?JdsGsb7LZN-8n$`74?Tl=iw1>!MSw) zn+0d=Z~e4q>*mbRLps~Dv5lraBKJQU&D&}$joN|kh$2bi?7t@T8RIMZX}|Hzut65O z-XF1N8~O;q|NO?s9wJAFDaEDe@~}qnMBtL>BS#~w*A4LqPeHebYMMy?sKb0sF-jv5(X9uosA9Xv%gf@fDUpK@Rlq4%r;V2HE3=x?Ggd?ILqC`N5j1iE*gb=38=bZa@$M<>H+x4w4-HZz9%CUd@@VY3KDAb5{q#OJH z??&ODTY|>z9f6{emFRXBr~;0tvy^+K5g0esojui+fm|(mdsKAVJd+D{9VXacc>~Yd z-L6$D8`pni>2HO1FHs3p&8SNj>aKEF{tW_T=sI2g6Lk4nL?j<~NRAiDK?l9Cw?u+8 z?^fV;F@OU<<se$nyWa2nxk|(;q8on&U@{A zN*NP(ps8l6N&sp^ak7H5nR;A5Bn<5A{QM7l?eH1><kk*_qn-^qmACGReE}> zzTYK9|^;V40 z+pRZGS4%&kmiCq@&^y;^L2gp$t2(2aPIPAjh3yF8p<$!ar=4(>9t%x{WU22E)*AE- z4KvShZVe~VvuQ8@>noBp!u`fy7ssdQK`%qs| z9;9!Y1P!xKo7P%T2=YRy+~CUF=vCiSJjX@-Ac*8x1%r_2$BRBJHE&Xy@&D;Wo>d8G z4QW;Crf)CM^{847XvO&uA#G%NHms)G_RigRU&%}@xLN&NB?2`fR#{rBJMilesO{hM zZ&`f`N=RaLy(n6BxwzSR`aelHDc$dQ^Sde#T4_dJf{UYSPD;A(y0(|Wv#23T&upZy z6~)$aZp&?8Y$iQ>N)J4|@89mU_yjN**HuX6=7LNPr*RN{APc>WjO*ThWhOclSXOOV z6HQsHUvm#PlQOe=i=ra(r(FGbsbIUAG)5(eHKH_GsV)2K#(izCq?KhPdgsMH(CCEk z=12GdW4i^ufPLRi1TCko7v6P`ux^XG0`_iJutNu&j%n@OUcFi+05u~=S*hEd!ax4y6sm=eLj42^H7=YSw}JX-rQ!)M z0x5Qa^!-3!-u6!fS*Y~5Vl%;>_pS@U*twPy1+(wEwPA92K)n$SW4ZE~sSN3A8FF%q zH>d>$jF%Gw3T^w!y2_A3bXkt*zyc!)VyD1bMNiO;^hx}X&{;}8ODNYnsuJEBk*KVo zms`EQR|juxudi-HGHluTf7z-;J=i`{|E>av?Ew4W)KmvIK2p*;^vsE}=qVsX<_IU) z*R^VOSu}38HJA7&X;Lo(;!2ABZv5>Gm;Uy)(38O6_MlN{{{;PW1+r+R-qq8k_)R66 zHKKP}TC0m@UALg^X#SQp#7zYT!MvnSF?i`eVaNCh`u-nxtc*^-`CKIqH6l}4*{DmZ z!j1mFylF7eH4UH8G4YGW>8} ztp79^?KA%@5Dj46hs6w7pf3&2moJTfv-M5KCZ)yI+Iy5(CEhioiY-zb?~DI>yu0e~ z{wa8ei9Xf7V!W5=5`qliDCq(Q98ME>HfL;*tnBo$GWN@>R8l~_Ic3t|9V&%q>)hi3 zKaIl8q9042Rsw?=H8FTH(bsNJzQU>uTU{ELk0f&9a46}KrclVl33|Ra|**||d{u?iq$k&K`W@V#p7KX0UYkSAx zokcnpK_l&vTE{W9!iV5Y9>vL(0prQ`!)}@pHT~C)bati7X$apC4uE~DyO5IM7ZePf zWJ;fn@7^BABqg1bFTm{dk-aGKs1qqEk}(-3Fc<5B3y3G9*ZlHm=TQ5QyKL2smvYDB z(Liu7@Z7=zQ*y^<&ZD|=Bf5RV$MwdRe;V4T#JolXJF7+N9>lfQReLShO5Dry9}FZO?9=L zl{71`_r2t8inYVxmq(H}K{p=C9OvK-`do#H3~L?kO0l>y)Hu5$3O?Qml9x{kj!HwyPk_jlPUfSV9@`g z$lN;rY$%xlf_FL7700Or7P($z@+9glTIdGsotBzXCc=36cj9QX{JNn|$s;c^>*%3D%C+LY;?M0=f?6Z` zq7{sOQj`DIfm+*p84-ystNd^N`}xK^N_t7o>f&L0<~C$eQQI!x0>WHzzmc68)skX5 zwq*_>n&ulIzd>PhbAg3>OcuCkI(CW);VF~-ILLj)0PBjz>-(n#QFE0ZriUf+Se01T zj8wT;-E9wDSEB7*$?f>{|e1L5UjBlJs=T#RStE77KCMi6fr-^8IGYFD#YPSRYS#~crF@St?P0`jD z6$>kMXDG1Epq|xc_wR@4JNxNyuUS4>#xRJ;Z>huiMbxu2swUiM5_CYtesn<5n!jsO z`2;j0XD(K^oa;tYZGQqCFbOJua~o=!gI>+{DMU@z(of+{G+93#4S$wg3@9SCN7ZeeaIln~gYG87mWooyNom=-c26z!+A zt`@iz4H2)XuB#!GVh9*)+|1@r2Nsh-4nS7!AHWlra~?PV<8@sa)iZIZy)EM6a?X!; zWy)UNd@b!8mG3|!Lg>Fi(dYyyEpKaXucaL4&6eOJV6fk!_1lT|UQ{oS-hn4IVsEx) zDQZZe1!eJc-NskG*Gw$&>Bs#d-y$*weg|F}>!{v}OH;|_8K;dxuSKPR{xZO+z+*Ej z!9GILj=9B%+lMyfOxufu0>2LdAaD>ViTEMqy^OM0W_JnjXM?11c z+vq&q{a`EHy*4;uJX+-o(1-+UJzpnDm9G8I2&s-sm2sZ~g9(tPOg{h$@49$yKH0Gy zpc~`7>ya~8X&GSlo_k;^w8pkwHxqm_7-h&1*sKHhw~+@)lgkQVd|+!GdS(p5ND^Z^ z+U^L=JHgKU?(L=%sib|B=>6J8L(x3+8!CzEMsghbQTqqJ#9hF?ZrMR`%ETbwepvg! zSr9@E*&N1(z9{IU!$j;Pkb!+UKIhTTN`ZFC@$cGHz6Q+*w2Rd}52PCnw7xHLC9(WW zDRAiloc)tzo&ePw;R_htBLwr|S9P}wWBa+x-6`bDBbP&+7!{fINYzUit7#4w!=KHG z6q#1`-~~hW#m{I)T#s}l)Py3@u;rMyD9XGJ_vmA%IVh@XHss8?JAni8UIv8D1FSNB zQ`8e+aG2AD`%xAt4#ABC*H2uBEs|j?Hi?th{Bo{w00wY>{>E6Q@)c-Ctc8g&>XAK` ze}i4eFLVs%r!bh%%Nx-D(aU?43$>)M>ez;Qe7)j)+U zvdRC6nQQ{J_x7PwU_A3kIgmHQpxI*~PoQIAT<;W6C^d;G4MOXXQcSX!WJ125a#B*5 zmuf$otrFFmkz>_9HmnOw()QZU52b)XnJWjXQ8n9*TXMmfB8odu4~(x(46wCzVGl+) z!Xt$Oc78%Qo3i-H>wx~bQN(5ccG50GJ}xv02#yeb-ok7%f$2#8Vydb40gj+m*cs)} z`eB*EQx%YHG^466Qg;Va*Q97Wke4Qr0i?rHQ3tTN_Lc#U3oBD=ji#N*7~3C3&+qhW zbf%}HiK$es6#0U~3g7@e3fA1}qC@GANW!SXFp!M2CYgUoKlI}(Mfl2eRujdqXD#Ra zx@&19qq^9p%M0}f%xKup$4`Cz(n+}QCtxuvElxk{hwIb`r^<8;d90Rrvrkqp&VkH?~>#0JQx9G>W+rw^42Oe5~&*NGoyzKQ=lK1+}ALXDjpi zBM0Zw2EcnU#r~=Uu)O%LEfV|+*@pJckq_h%RTRtS{9x$Y<42$jtJg6wM!`XOjL8h) zJceIY_PdM_Ns@H!%nIb?DB?NE&U=THh&BLYkN2f%p+~8t?id+vm;Ld~{7?f39$j!; zmE6cjE-rVv704{m!CxtZus^ybFDB3^0Ea0Jwov)Ieb8$o%%80k096>EMH60+s6p za_u=WgFgD_Drzc|@3|dmb>8vlAQ}DK78su$0_$MczGy#)K1Q*Gub^pj!?1YDV!R^* zL<7dPfl7ONL)UtN(q1+*W$bR1-vNyXxz_X5{toC2mRio<$EAvpMkx;K^B(Vh@IC{$ zIf2e~za;mZaP2~~sr*V3Mod)*fq_FC8oPUL!;xf<$^#u8%#plup+L^+5xTpIa<4){A-VNeC!zOMNL*ge2|_h)1EyZcWlu<1yKgo`tR$`OV01CrL@ zPm2V*ByhWg6N5U{nRpDJ)3F|gVUOJPXcMpc_|M$#o6pZKh~nv(2et|a$rJG8PLCeI!r*z;Ee0$MLL=*&D(rQb0Q8(&A4!O$Za zEZ;9_s>yj9%?PiH)D~WKy^EHY?+x*CG_2i*vPgB5u@7e0Jh}vu{#gl+akT;CoUF5_ zeCnBPJZ=NH2@e`ob49pGExu@SnRE@sZ%3CZFt51{irr*X1vtWv-Oe>T?&U*9=ZOM; z<}qH%E&I2`h=atosI9BVQ7;n@w2l7&zq`CWq`i<1=4IoiW54Ngm79nKQ;MCRMdFaLEZXoT z_JBIS=9kn{L^QDoI0Sm*!sn^NEE2G&m)SUYRwCVUGq8gdx?T$dKbM&r8_-@-JH!9?%1Fn95M zLao)ZnlE5tsO3`1S3=-};@=9OaMkAzo{@}GbbBrmkM5y3OW7{M2ek-v*hhQV_v3}t zkfD@|uQf~H)y9f1fbrH8F&00WdTuQ(9%77wkqJg5^Js>DNK0b6VQD`%>9QX26#=XM zhkE1js=yD+u?BWyt>;^-X|mC=HQL_ByQPbf#zqtYd(#dg)xc?>81BZJNYDlJHzKbZ zLO5swV(ZVK^v^j+2;go)@kn48l~S-Ag^%L;|&2mN{dm1vOt z6Z2b@V`T7bMD2r0*F$%pFxEgz2lDHb!}cftp32$+uJZ}!z|mEQu*Xt`=PLb`NGZT}W1!&3wLN5Qqh_Fs_( zkcmpM9nGD<;7&w-0xhlUS|A3csxzJgVw0}>Z#hJ5Xg%8%eewcuQsnyZFH@xLgAR^D z>^D03WDuDGG7BlmZt~P^n45a&kvj+yL3@xaJ<+v;CI}2o7;WhlPuv6sjzRC^y3p!} zFj-aZd;Qn%%wg>6{X-ONgd_r^UsZx%BPy^y5aZohY$jqH8brx0xQAvTFTdV{%=Vc8Dq? z&lX+7ch9Jwjd%NA0k?vaC^_?b&lM3Bk#G0SAd1a)+fueg+0#$wedVkY_nOgV)sMW? z;a_w#*#TSyXhdiP`}vb`X{ZJ6hge9$8Dvzrb& zcJmY1P5Tz;NQkrG;dU~1UqlzLI;tE@E_#NB_yX2mhhO%eCM4%$UC}k6p@SR`-YB$& zbX;Y_XEA$0TV67sb9I30O}#*78^{+N;+Kg~c$Kyp?qb~$9|DX~xEYUEPe`s7lJ#}+ z7TJOc6qtMx&co&u`~ELJq1U}%y&+bY8p+QqlU_Tf8p&0{UPDT*uF?5VStxf)movKL zA);}0Y;F=AO(eL5kL2cO(-T=+dT|LQYCCs>*kP)esc=k$Ij!3Uu-3L0zoU0VCSx9e zv_z1-Hl^UK*R6=He#v-9d)P#u?E|9!R9ii2EO? z%>e5ug3(kLPn51N6vJ5|C2a_|)nD!bbzh6n7+Cn1rW>m~6$%%pG(lskoqDM&{MtUy zI&bKKEe}&kV~W7G)#an!Ao?xC-mif<2{0L9;2p9O|J^0BlFf`l>1<*X#ct-vxn^8o z5RsUl#qhlbdIw_UXGW5=0+Y}tf&=rybGtzNIj3a&0ku8GnmvGXdIW6oDEQ-&gf!}u zJH?{O&~2GU^LTRoEa94<4Y4FN@NBXgyGCW%*Nm2{_Bx6V^x6*kxIogevV_s&=#CAP z!IUQuCFgj<;|s60W(|50H--e^5_I8y1k9dC^vSWYL1GrG7wmjsC%j2wdWG_l1Niib z0pE2JKe%LlwX{1V(z(w~fYoeSPVDL88>A#@=lJR|ahq{zKX$NhnA zt=&-4p*O9lwFFR1>HWjc5({4#DwKAHVU?3Nt9k+uo0_Qmi`0!x(6RX1{siQ!0pb)= z3j`lPV1VFwo_t&*jFoyip%#C4WP-qnx-ghMi&8|&x0W*xZGkyAIK14@MP>41T&XCw z$dsB9u$R4?ye|{qq{@mBkc~Ab$zZ0=&~^ABafFX$vR4_@1)jt}D>AnU%J<h}FQ^lLl%8+!=OA&REp zHmBBRg3j9+E!z~xN-w|}l_aJuVs(S|V4`7rGxRR6yTJulDzMtES-G9!xO*@ogq?%m zJC-ko8rRJfK8srq91b_5VIvh_=u!n50@HP3Zj>g{X%YeAE9&N4OYO|Vb|G^d1 z$*xp#kW`j@hXPx%!VmCS(2V)hi2S;<9aL~&Whu4BOL1WknSsHLU9r~XkM8t<3xHQtv2T4sU99@QNEY^@7t9G-lW9PLT<#DV5Mj0@$f+orKtwT@nItxC$Czo18i zlU2}8|H!hA<3@NQgYOSU1_wTqpa%lufq=mTGinD*gy@0#K{TWsROnl_Q9_YPB_2;3 z+dW6VAY`qQh~zB#QsqtA#Tt=ab-sGT|Cn5y|9>K~3thMm5|Nj2AIjw9QW3|9gFinP zfb7Hh6h|@ug4Pf7yaP=-O9vgE%CN)5;7G-36SxPSRS879L2TcIZ4zWQHyID@LrPv5 zMdZXk5H9vS1cX+3WW+1+Y!0@E4t3fbigEXDtsxie-6Un-w|hd3iYd+ST8bPtQA)B4 zk?D~t>%N90S#@)AbYrWwkFAxLNk{8lJwX1Rx|_;JmcTf_Ygd41D`3=IdHkFYPWgCs z0@4N$Nkc7}z}lS!?#r>k9FoC$1}2nm%}OezJl~lYw4sJ4%_%>U{hGvD1IiUbeh+>u zWJ%zR`B@4q=dc3W9Wp33dLT3pOQKF)04y6(bb9;*eeQGa9K_-SvXV8R+$-;%r1A#m zV$Eo=YG1n7nTxd@`gIAwAX;oDXCDkXLXK*`FK!_n{b?;g)JvIPxcIm`T(NXZJ8diL zGU(dchqXSY%wP1^!7zMkv2QY7^Z{;8FUYss_(<5x)72ZAvK|=V9w6M zI8ykEV%#yED3C7$Cqjv5v4#?3U&fo;5=I(ToJEYw!PKI-gfat$bX9 znC07mE^ylx1d=wDliZ#G^jXgERdnLe<~JMX4vthPcgSZ9qQ>b5s6#MJ;n5&o_ySsM z(gP-h#BM^lX0N(wF&o+`(?--c!~&DS08C(z+tmZSu4e2JUL8bPd1v0l{=9lFuR63z z*a!W@zXs_2p`w?up062^6>h_-Nx|!Kp0s?1?ZDugY-I1WyfF&ul9 z2YUp4sNRZlZ)Cc;>qFot$N^IUOTcR^b{jA9x3aBpBO&3SqmNM%pWuwKOVw_Tmxx1uAi_897yb6Pb>y z(Q=%}rHL5qk9T>-x4%V#fZur_&VUo=k7kjgVjeKQ*TyQC5lBQg$){3SW)&L7cj^QS z-xLicQOL zpi{JAj$v++C>>-=xvm!;AC0U2c#f@TykWRX&}&9tg#r4y;{Km;j4Cp|8Vws~0uyeY z20(Mn9=>cANb0^KXJ9?(f)V+qJ$g`B*th=D;) zzPx&?kOidY@@uU|UCu-He{TWLOG>_+MVkh!a?EN3l! z65pg@p|ZxecN%=H67CvNTCEqT%gg8@K(u{0{nOev0a+QpFBR-QkqenQ@5BP64zVm6 z>?0i4c6A|<(T2~_wkGI}r&DOyvqzWVFD3GVKCp$sJO6^x^K1afi?2i0pu zm~4wW?0Ga0Wx^%c8u?3aaTM!c2dLb_$>riIsieUup>{0?d%K;$rrJr6l3}%Nv&2Z@ zp{ua3Vkp=LTgwyE&FifeBe&ZYE1i^n$oKbDJ`Bx>vx{uh{0_j8*Urw*|FG8%pV40) zy{16h!54a;o7*_r=&f3%r?=|+T~aizIQGQJ$jJD}%O~UGY09r#>t#TdQadb(h!<)5%R^+L(o9Qkk7<|h9}6p6P)%h;RxvDUQ9 zr48p0oE5ZFr{1NeXbOCB^>3MnDOM&ermJCXh9fAXvABNN#K(C z7l#gj!2=BN22FuiE}$D1~vu(dp(=$XX7-?2gh_2j4mxPGCDQ(*43` z;xlM9WibRj!144(*Q$X;A+!D<7UMu zFQ8Z!dX!2^e3aazESMrxB3dJ=td*78b{idSqvhjlEs_m0F5LwTZWh>?b08bQ(56lw z1%n$6D(+<@7x!TOD~7? zz=)513a|v4<1>Da$*EM(PB4JQH$D%|_jlaR*u$v&Rsr!nwRhM#mH5_-#A>0g`(0PD zwY_3LOMo$A_bNU9icUI6x0$b`lCFuL)Vycx=y-`jyao@8XC7@CL5qBHhz52OJD zuin9S8lTw&c3s*FL`hQITHqR74;KH?YzTYs8?MvcQx8Y@7JC4Q=ifMliAp?cNH zASy${80$}@J0l$Q_hmxj`9TN5ar7WC;QrKs#-__#VA9xHUIMgTTFlL_yB+fWTzsi{ zhgS%*sHJ*qR+pdB9dN%v-%BORHKUm74juo;D5lQwFlKlh)9=6eMmPC9YMgL{f@9ln zVlmNbYiS@CJZ&L;ai}YC(k9H!5O0~p=UjV$2cIt^x4yhhI$ksrpkyUw?kKHY5(_t( zBFu2ucRMV3o!x!RHi}g&c%_^kzle3v~~KSnJNBX?d?5_oq`hj~EZA zr{x_YjxS&yy&#y=0276?X8}c>5nM}JpYp($g+76<^b^qOa=PWk;OY)ZEnegeW*pk= z`V;uV6Z-&~W`?F=dHp5r=$OVXG=vRUA9%$yc)-3n6f7l?l0-0=R+65l~p;CB$%;5?mpauOK4 z8W_YTj3hq>aS#8)dY;PXq7kLldZF4Zy!BsCHk#;inm&PSe1!<$X!6DOd_y`qp{GSP=8WYb!dnV*_5$ zjp}*zqjFcfgDf!n1{26TDD%=oNwgj?o61QCNXe6JllcDcqv9C@&#B;_YUR;`Um_1c zCPw)Rp~t3j8>16$RPE$}+&~!cJ*sHh4mZl8DSBCh1ly6A9zvLS&yKV&P?)?`3RTVV zCW$Jah-P$I3w5*VbmCQMOWCB?lf4p)Z>PDDEmq48;mt;z3^WEcZlhZm zmu#C%2;-N1|_Wjp6SGdkY zHI?nSBWS$+C=Q$?AQ4kAUA9yujx{5ATB+NE>uR#L*W^DP!}$ui2cj{+VSNW(>G1L& z>l)NOSrq@7-fG^lDR+n#?zixSS;uPB7FM?x9v;?@x9o!5APM`5&a|06y zN9qqbKMWXK)BV$8V-&&~MsUo)C`77svwYY){Dn$zYexIDP}j1qE7IBy?z(U(Lb`Os z5a4Wx54ne8Z=)K^po@J}o@HHuH((~8!#z?(*opd17cz<_3rF=}T+GB~>G594N--h` z60xvmz|u^q)7EFpTfvynRpDq=JC)DNs=B2RH6=_JIj z?WCN>WeM3=J?4L&s07YjR>gL^VKc-);d;E%SrgkFlgcGG>6BG;~_~t;&QFz zSr3gNA=#UL2D{e%^3#@(3YkB=`#R1|(1k2!6$p@(uPKVn4?(Ag1_C!vz;c^DKYhKt z?56_$5nz0l*}@0?%mJJ(+I(k#kq1a=7nD%v1yMb}(|&C!6Qk9S7-%EKdg{`@N?|e} zM5@cd5a$x7CRS^lk)%J-ldsa0)*jLuM??Vk>Q z?;x`HJQYl}%U@o73=B>XxDC{c;IYfjAv7$w9CbLy37u~@g(%wi=I~~YZ|;i;GBigF zLPVzW9q_C%U54Ahv#p1GHgincWn2daSm^Omaj17Q+*OJ{EQ1D_jEc`ktHSd_jfkvP zYFl)5c-DG6*K)(fw-6q1@*Cn}z(5(^czGKs*&CAj{*635jy)5nzCJu-zFqI58C)@} z^H;=RUKFVKI<$jUgNB`vQ}7nlE8z8TXVnx;f(*kc=6sJ=imIdiiDm+3NVsxL&HUxF z1eJ)^hz@FHq3+U!4$<0<=(scqlJrE*7t=TkkS{@vKgk^f;FOwgS@-G!2s!21F|vK7 z*w!_DcxhL>&HH$wl6WF2v}%KGe4iO`n@=Jq3oexgd1gXiBLXa5HdSy3YaKkR?4l%M zr3vO}hD_CYZKd3nZAGm2h&>&z$U<9C|+yh8m5lVTEDc^mAi?U`q=dtf0V#&tC2#N2#pM8qq8*VaZi*G1}s zUF#L1PL&YWh_d)^#DVI}uv*T;xgGg$%DVAE5!HWJ&S3Xqyy~y4trvs#0`LT#k@-YO zF!x+Sd2^na{-7WnS;{aK7N2oxO6pOH9j`!2gwVelkq)o3Sj$XGa9%MfOcB3Ax6BCb zCLF~i>MZ~Ps|#&NcAwLbH^p+y1Qv__7#@}bq95c9l0w!{-6RDZ0J~_Hfp`F}+B-qY zLeh!O74ffBG~^P{&6hlP>KTiVnlOeG|$XHPG6y*Lw zp?a$?JbwHx{6lCHN-Lj-02ut1pPGxFf}C+`DoP#%MpgE7%=!&(M94XyEvgeuznvql zG?Ls0jWigh@`9@8j0VPbYlTwwrcJE;WPY$1)hm`cnGw-j3Z+=aD8neuR38a z5EedgeRPRl0U5j1rpHwv1OI;eltAwxmEOZV-oc= zv>$g4o09!9PRO6$cS4ZgXZpcEp61@iC?hjuUAl}>J*euP*A=NBpee? zesr#e`ha$383?8P(i~3qJ6tzisXS73gx8d-5{??t^Q_e0chT)_X*nz1*h69N;lLIg zY98n(u~bp+VhQ@S{{*XSPty&_cl=q7WE3!HHs_h77lndx0ESuekAu{$mbQ=6#qDzCMvDZ-{GB?T z4Go~z=wKzma4JpwZiIrH%Z1{}dw{iyd5%X$#{i3EXS}IgR~T$u!ehwLt2FX1mY2+T z;H_?FBh((Hbh3J(UX#kYtr0cR(neh$hOUj!dT4i2CZ#=iBe1xY<|At+y*3;1FVBj! zj~rC`HH#(n7Amo*85z$)-JMw-Z>H^7RGg;=+%fEO=s^jdoXZ`=eDu$e#z3)-PVTxX zqMdWJrJ5}{&O_g_yRHC(8f%LA_FKtd$q;&e9FOH!hn7#!#}*|eWblxZmk|O)PEHKi zi`Yt}uwN(@5``*(tQkShQr+212V`vra&Q>gUZ4;~PA z%5;Y5drOTVsFwyRLH)V>vlf-0){Hi%cFK$n)LIYf1~iOK@J7nZwLu>|Mt4T7v#f+-c10A*f#@P4=`3r#FvwRdiV>p+9jP2YW5_Ffg9Ej6UmEmG4>uTwU(zBWIl%3Og(lY;$N zj*UM5=DunE*;9}q{Djrjg z@?6TI#|3aa$9`ktLbX0mDY@;EX*p4la@0pD)HSXn=BR|TMufV5gOvCikjbGsZQ~QP zjTb$r#~~-ExW$v1y9&!@qznS%Z-9^fkPiXZ{PD~6^HpL|BRZSaLUl_k%met#1L*>E zSo{Pmx=Ca-l)xKljZiYaL!DYqisnhsLvwjcvdPECm@sMAIg&Dr0ege`;5EBVWP}rI zT_=zx0Fp4dupIv|a!F+m&JuZp`fcA9?S>7)&MIX=y=kLRdCbL9GwK{9Z`Iqjvt0Ps zgLs|}#Ge3SMX@mLt^`<221|kO2i%@M>7_;JONxE{tIa@un>5O)Jxl;&c`dL=U8=x# ztcWR{)PZ=_-WEIl+EId*yVOph9`q!7d)O8xO{@p6;uST>tOKWwxv<13eK-)(( zkpi2%S}81N!$hHn#BHUOpDfFH%1NKrdg9!U{38fDB0rxP=N{}rX0sF1zlcz3XU4y^<*6)_ z8qv-y7pu)^=@6>rWzsDbrqWv~ocO(UQ>dL|yP3_4xX#m?{8rWT_U4ET-=H4;0V3aR z{box*nIq^x()a71`|7STHEm~Q=LVHH)r>Tzc8Z{t4yRg<)3`1)%;bs;E=N>?rQco# zzU63GbNaM%HIQ}fbe^Cu$*;PQ zuLfcRZVq5}gMO^F7uCBP3EKkY3i`Z`nzbqcs3Gl1-BEv`+1mcZvt>Z-+YT< zKSXW&y*Q!OO{Ab9Z8(SKmf5lt^s$z^W`E@;`rvIpEM%tAsB+1d>g|pX}h(&EZz{G9=HF$KrtaLsiZn`gb?G!uWKMQSUfG-+znp5J2+hP0lJYsSz>h z-`G6VeWJB+g#VvUbWEr_$ZbVRL^JyF_38Z^NcQzjX@DOLlz~gjX%w8&4LuvpRKig+ z0?}f11tJ}zr0pg0SKuhSD8Z*RfoCDMo+w#nPd6CMw{%%^YCKtpraJhYH~{alM4=rt z@Zr@c|Iyt_($i(2qhBRNH6$OYz1X57J+-i6{;8+jF?dpeEFJ?CB-VPm+m>XMh0^^y zTHP~}Q!;Al&ePvcZSNo)rwM2vPXHt2W=Nqw=KwgNK2Y_W3qBGw>IfW zR#`Gd|h4B~>LXHKPluElmCm)<8Du3gxF1N-5lao(GIyfL-=`=e|>N zNE=31vsB_wLrRd^$Lw??x|WaVZgBlx-?m>!Sq!a;9lqpX{@LO4m(1nu{9`xnn6l3E za{w!1ZYhVW5|J9xfzjoRG|4@gKB2g4b&6hSfpW3kw_KnZ4EFVcJmy48LW5s86 zJe6S7j0$94zG*MvH#sRgr7jJcLR?elYEBJ#hPxorcl8s38$_u2PX z>#J2FQX`^|)qEYN{-1)#)A1|Fd*wiEMzIebs!y1vpa(b&`{MG<9{RBv^Pm5Y%9`Ej!T$FaNf?FVy}aMg?iq;?Rb?rW~~U-Kgrr!xxt zXi;Rw+t~-TpT`q!XZ*9~yQdG7vrg#ww~JI_Q6ox^`mQ%!D5=(C(O0@uChWyH-p8{* zjg2FLl!U>|T_Y0@f3M_*Ib*xOS4JqreBSh}N=#}<#!=fBtYgZxeEvSY;XSHXyPE@J zlVX9zetL*AhdOgynbPAi?ZT+mds3BBvfmrFb0S_`~fSaQB?dl){Q< zuk(zLA*(3oPQhxqGU2G2O}eRsv_=#jYxw0>57IV&gS9h59i%@2(lFsDSZV*Q+s6g{ zdnr7=5t+x^x%FWWQqrFwr`UH6!^GI{1h1K5t8!F_0$sFAX8f0)gr z;9;`;9`)!_fE5SaT_b&#)W4eFiQFZKn`R;ONFEf}trd8vg5Bp}6AV^U2)&>Vqz#em z`^(pP7Cs>Gs26c}Xgo}`T8^CD*CIiKNno`>-+x|+9BbXwOxf3&Qpw64;hzG2PUiuLr$d?!Pr=5^o8|i7-UBDF>M5%$VQ%9pJhK3}WNMiRdkguVJUPI2TBg zfPwjyv_P_Ibk^DgIDv|W(9=frQCK4_Dh|xe6pR$UfO78>GY%g55PflJxobR$5G?Q^ zkdOSV6g7fh&f22#foMi(vsU-hq1&C-_6MT4a(Pn3q=(nHF3ow`0s?0J{_!gN+lRF( zFHpkWkpDHmKV(PNdmUi<@A=+lfw}?)bYTC*0s9;EzSZ^hpVHS4O&%Q6e0S-uBOG6# zuN(5G@#8K&G^Y z6HFdzbPJzmp$yr*1CznO*v(tmx(EentnH!8Yqhn<|s?q6&u;K`w4} zV;4iK&baeUK%P!T@b1~AEn}}avwC7jlZVrld9@zCa&}02RP5%W_3ZW2BWx^yXN}!M z%208$)~`9i`O^M}-D!mt$BUlcT|33vErsg?*w_0q(-la`kLk~P(0fr-aG&{*$AG{nh_P!-!JM%zn{qb{MJ|(|VP$3SQCoO3C^MN~dn4$A;nIANK!{jfAyOpi ziJUGP$62>Gl`YL|hmHSx`Db%gA$pNU#7Ha1YO2Q->C9|ekLV!+8=Lp99kPI$s660O zjyjHfU@_5WJ6N4Ir<#&56n$8!iN{=?{F@_0zzdcfndi-C_};TQ7nt5hbp^v4M?yC2!Z(GR)a+54{JT0+hh5sG)w+|_+x>b{{k3Whx>(QVHc#>jZ{jQW#*Fx48p5pHd5^SV1Oep zxAt-K>52KyBVIK1h4A9W3vbI4!p>gjb;hJ8Mx8848s0dPW_v8T<8IGw`5B}3IWH=g zhV1gL*buAe5?2?nt>4CYTv_yeuE?vluw(Z)T5n|wy`kXN0DISg~UZ0+5?j+!PBVg}b5q6^A z<@6B3X{NYNP#@UeXrcIxEOS)g33qLdOem}$!fqU)l+1bjT?kE1cBV>>Vn2ez+#pnuokC=Wo6BJ zo&6vYTsU;eHd-0{eRueG^HjbF&8Wdph|sk|_8YFb?`#`;am&4Zyh&HL&%Cp{bK(`3 zO0)C>y;BlAil^S#(faj;&060M`2)u@O(e^NVm{2v?n zuIIkI$EjhlRBle|M?2M4Qxa&o`ts?;PH`BHThZQ7|fOs$~h4hQ|fcQhznBo z{MK@kW^xQX72O#Om|KMzVARc&?xgkzp3*xp zo=59Y`4}`J5nHJpBdwcxOW_W{6`h{^ID7@;T|2`nDLLVnkwAg=!fYe_Th3#L_uMAymF;S4cjgWYSr0&87qTT?5 z4gJ`;-Zu>2SWvNPDS3!wv4L^hmwbl1+Z&OWGkGR@ET8tW29%IqA)SV#unf4w6YTqM zou@A|8|21Wm{PY|(m+>Qo&K9d1+zYXCA}evU7&OwfB5a|)hh9>5k1#h?VWR7)1&ou zzVlCYem>(Cb*~+_0mh;Hv!_l|%sq>RX%u!NRF(n^_Fb-Mlpvdb25!61nZy%2$R3U3 zdjL;}>iZ6!@#l%~8QJ0=MT%iX)P{R`_&w^UHxjf!0=&zMhE|J_lht(}P${rj#N3;@ zXcN9VXXaP4vQSCVP(FzbdBSlzknrseyqWg+jZmqOY4Jhhs7LFJS9 zUzC?2OZqRy)XGL}#`JG+&&5K=27Lk>6qhFY*C&A5O2SXT5K@va9KcVR<-0iNgQ6kd zn2d9Z@EUQC0(;vC(y{=jT_i$IzDL8xRiprm_XJaV(Z4Et`UZ-8$}(F4ZV49h&~^PF z4cbII`7yFcV4QHuN8TaBc4Yh4}lN& zGMY-!B_i{?15F~69s(`A3#NTDh}{SQ(Pv4hS*(|{``X?nru&A8FCy3(u!j3h_nd~K zH!1NBlFH?q0+<{!Cofqo+ zU-Zy|zym1x!*Pd?+W|8bI3-nX2Y6PsSaqR&%iN@!2X>NcyMV#c98i!C*8-lK58_t6 zz<6T(1bts@bEEK4Dk5!&u%~0eADf@B(_g++3G)9%x%hvYAM5$*`XF>tnAXn&ePj}xyg)79zfU&rM zLDeK3zfMKhN8+>LHQdfHLCvsxMUOxWfjQVeiQ!7i+rfeXSosYP|G-rFC^VuETUn}m zM?$w7sr8TIPs+f1W#tzDe%Jp?<+te+j-~<^woSA5O!P+97I3HZxn=5b}B)w5sBAYZ4amQ-(ca~RoC=? zO4F}&y#04-y691q4Ba;kSoA2^2dzD;5<9{x1v@~*)h5{cuDdG;n+yizUP7cMXGPI%tSr58)iLh4RZ3=eu*P=wR61t0#eAE7-f46VQp2GN;7DVY`F% zDmuL$sj>tmaG`kf^w-(e=Ro*7Hu|BU8jXm=Ru<|ypDnHa`cav# zdo`c(YSjG{RP5V0hyF&yA2`Mr%~K%d8>n3KKwy+D8sRFyX7LfCX3p5qCAO4pa4hkK z0^Y!sU6$Fa#IZ*7T}wEls%P-|8#vx}>tOr|FjmZqv>z>2hHeX&RjTf!H6pKC&sTeO zOV@O0xxD)SSRAqLC`|cBdp!pj+l4}!!~-z=E?pwAISPD+*kl;p_{)+WWZTnP24MFI z&wi*!ilH|q)t1Ul1;|P7>)x$5ZOdU>7e+UOmeMD9(GJhks@<>LX zWC4Dh3_oiBWRBF08IlT;W!O~lBj-WHT$Tu$6yWggxeeZ#QelOBYq?zq z?Zaf36-IRLafUz9@1Z-d5!h6ZKBQz+QphN~R8SL;W(PBGPrK0@!Yj$>KfEslXTI$~ zR^oCrEI^=)8x@!y^Hi>jZ+QIq5tZ21h?Z)pwvSkMEl%69-MCI+qW^!``_iZ=&aLYk zqZlIzHyTAWN;E2o3aCs@P)36jDk@=+sYS#VQBavwhKf-!ib@ofC}Jx{QKlA|6ogU{ z5fNGtXy%r&fd*P=dhV*{dph^NZ}PqCtF`(r*H=luslO~1{MmJ$bI#spZ}pv^9q_%f zKZ%fC!v7V`W$EZK^1QnL__(m)E-4-7 zoDDGhWnOPyEjrJ7*{uVpJ)Yf<+O>g&{VxN~0GWd-K;8j#)Ac>(ny8p}lHG{yB?{IG zIKTNZLURe(H95rdb6bKrf1pvxnl40&Obbl<^PvRtMSUYnc4LC6I-9#=#K(RlAh&`F z^Z#%D2)}bU7Ur5-o6-%1)`R@NG>n-*tzq0>1`W;N8PfmkC+7XuPnfZCpP}RGR4lLN zUSzdj8qx&#SJHrWCsI`G>0Eh&!#5mYfI$E6`pW0#LOpO!OqENPDgTW6J|ofngB7H( zri7X_*Eq0=&UnyvSf@be3+Zlx!RtpGyLOgh>tviwL#!uu-XC!Odz8a|rgHEu}Hig752P@ZLo$1m*!S)N30J}~7zPa8rW zZifzHqpyVDaGn`19Y$;r#@YaNAla2n9kQedtND~rgcfF+T2j+CFWO#l-O`5slM%skKGoS-?dYo#EM`CVd0>7NLsHcA@9tsG}Un|_zRGC zk#xO&k9u9qf)|>}4K~1_whXH^PWc!(^e9-1HCCPg zYS#&*17t(f=_-lr=HNk`^@^e7s1L?QFb2uY7p>qW7Zu9|Gfhp^>4PzC?+N15<-Amk zU^zuz6sQK(<5zIw&E20VlguJLwno64-xvKI(!=S^c78nYR^>cyQYx=u$7LQ=1;swc zq3XF9h*uShpgBs${!%C%4eUb~z*FCJ5!{mT9?2e&R$oeJH**V3f&3R>qBqjT_dSZQ zvWiQSKr)IIsx^cm~>Flc`^Z;jd@(9plWkQ9&9P+|)-9g64&UE3e@TL}aj)ov$2BTNZ) zXu&~{FSoN@vFuV^K#fbaMaEZwTS^m6jB5Gdm_SZkOxt?1-S`EYF>{>F3trcAN zP%xmI!($TF z7!_dDIMkF*+0{lc{+_bSOXH)R_~w9Ye{^jc3>j0Oxy*j_<_PJVOcCRwDML@=PrLCK zjXVc|N_ed6tzy`)0~Ad#<7J+QJ6f=si1Yt99(lZ`ouqiAgz_=B)bw$tmyTL~{?Z}F z?blgC=NuNW59qgbj#9viII^-vhZKR7@Hgff2e{D))N%yA9i=pKjFV#5a8~Omv}uL& zXU`!7tJhTDA%!3{%nJ>{zsu(48N9n2Z#b36T}hO3qxC%uezUh86Inx+fNTY|yHw02 z8r%HRL$WsZg?~&yZn&s0vNIE4g?Z>pft?Kl?-8MOs7Fv|tD1mm7|~!&S`H~8V9YHw zC1B_oMH{jB`-~i>&t*NhN(h7TvCR)==j&r5JPyg!N60_1YiE&x5GGPnQV=x;AuWy6 z^1g7O1n8o-yInzJJ8`JN-%WyA!o;xJL&VmMJ5SVJn;XwGka8*TPL~QeT59SOLDxj> zu8EAUv0PT2o5Jvy7n4lBNZSJw>Sm*zi6&8SRC!&^%_J?0)Q~Bb^#1UF^Q`jw+nf&r zJ4+2c&}~4!^}#nHh6j2h;|{!h-0%;tk=(nRB%jOc$V{Wu$cve;YwqRg4Pg zzD$3EqRD8+Vt>2==qAb0pU|z<#p)QbYcm=QNb4gtEQ{tZ_M$)kGJHBM@_rAI_sf!D zvgvWhUlt+4^{$E`lf1hM{ zxAFWaVa`5=c(G9=)+}PK51p7hW&rz*u* zOEM6+8b*q_tw47@jE7kALM>0cJgPpC6pWNmFBZ^8Lo=-`efy&AV07z+1}?^f!Y=G= z7f}&;*Y4;7@6Gy0b^eJck|eCwXH5z;pbfpe)7TH^Tp!*mff>(d#HPRGng60@XjIF) z=aXU8j2eb!v8ImQv>A)GW0im{r9;bZ(3lBI8qe2&i9Kj2$hs2^FR(X%=-llGl|1*$ z=0=vIldt`ovUzc>gDf`F3Pu)C(qL+87DPYn+K$gKIT}R_Gq_?y3Fs(o0pg>$zS!17 zS8ek8xpiF>X{Drwv{|HSi@ESG5a2q79=_jW_;%}tuXm)9WqT~(Qr>wai`xY)J?Mz#8NMT74i$imXe-AEkDN+IWT^>Mi6EIG)ozd?>phpTG zz$teLP8^zfzuQan<`;b^L{pv$DTKiE@3RnzkExZ0_z+*WqVnxB6?jT`mI zL5Kt-)ZWTSy`@(DydBXrn-q~0Q8*fl(Eb8`s?+F)`#*fRf8S9GkRf=jwHF97Ri>>1 zx4HMh!{>A0xC2uzMme4PhXjg${&BAHYf?B;L*gu&ui-$ z@qJbsNs2>C*c;95oat~WZGWEy0f60uGWt99h|ju{7X>QOs2Hrqkno)_X85uSGTXir z8bit8Xig15L!Y(&Z(i^GK@#aT_);;R9SeOOtpVrf!kl&99{{*wEI&|vl@x;1a4?HC zZ4PNZTiYw5Td>OhQ?9ARD1GXLG24QUZwq-IQx2B#(p1vtMBJ?$MXQ_@w6Gtu=>**C z|7Hp8yxU)rB9tO-M$@Gu&0=diLdynlq;o?HQ24{c>uhDS?ADAAUYSk|&iH9$-oi

SM48P%hnYh>%+I+9|OB7#O!g$3PDYCAR?T?N=$6i3p6mCZzz<1w!`G^%FC zf6ds%soZQ*EK)h;6YU9 zIqEiIYKNN1Zmi{|kwTFgqGqwCydhmIwH=C$j7~JC5=DS-no7ZHwa2#NRyTld?!;hU zHoqw|j_-IftxAeb0|v>p?m@;^XQ}P#=Y8J!loX;A(KZ?%%+e>^TD~(cYwnN&gHP|F zo?CCK0ssrdvvdHA-!ZX_uXDIsqx=F_$EZ?dLrZ5)II;=llCCf;Oq7hcEP zc^je6&xYjOgBiQxo)9+&B}PlYozXVSKx}IWegtP+z$XSzbwxXZvQ%)Nxofb`ofNFp zFg%u;PUN%=kTyQ-zYBsG;R&GrIIsqD0>zSWOoLT3C1ddXA95OvKN~JE5 zFUsDWCw<5%;dCq@(rLGWzei+Y{BeAIgoIayuCtaWZBe>KmgBs<8D6)6K|{sp6oPqY zF9N>u&M)QcorzZ#1bTULd0T}P(fk3jlswfr0AxG4_d70c_Xdt(8dD$$2Qfi5nkP* zxxhFFdDze|X9yJ@2GNsscY+P>_wUR-ZgHRpx@RbbgxScvQ~R29K7N?3_IsI<+BJm~ zqtp;Z8cQ_kCO{i8`g;=~HLXV0HV>7l7;kDC8-?|&edp~_LF?2)6YgYE3{t}cE!LC? zqRC2a#Nhu`C)4G~(pG1&!&u>674w$|4N9a)Q3ebqrcW57H$L)vuG8*WOT{>Ab}`Tu zbRlOKjyb(`e=EGjwU>5!lERc4o(Q5(vu4%I^3Qj$oIu~={)e}?e}riZgrEHZE1dat z6R_PA@!~9`jlSn*{FzgAl)TMys^{s4ZkK8^l1KyK!E`#X( zo8#)n5{L36_Q~mWSfK;^e&l|FFgoAm-1~`#EhDKP3=>28R-dI*KwIkr`hw6p`w3%C zi<;zcbNcJrVNwbdvf~th*xbTW!%lz}dTKj}m1px#U?#bv^ZzARGWe>J)Pn==(+4Au}R+gEup{}`?^6(bQ`U=|+X4ax;^ z!7zkx%q(Ri5oZZEa5y8fZP zbmqeLvY#3MZ&!~t%gQQJ>`_A&nQK}!;S6MB6Bu;B$7}B=A0ND`MBBlKIvdPH6H2%ruBS+7iNjP)yXhK3lZ0ynK)yLva#K*7RvgQ}YcTVd(H#)6bwdz}2 zdyj9|uHL$8Rgt?x$>Z10o_*)pTvhw@#VStSvyXOs^p%m3k)Bn|NK^K)bBU)DKP!C; zKG6C0Q=OeUW^~bfkD?iW0w2GZP%E1vuJD3EI~w&0=w|eQ`yRHOP%u8HzzAn~wSAti zD76&knb!uYg72I}t>wa^2OPrz5Qt9&9-T;0agIrU^D9IC6vJ#ZE&{h}sO-UJ10`WQ z^L2KwJWy=_d-I{1~Qc{pp>;V!Bg!k4_;h7dT7d4&ZroH7n@R9@zCMszjgtp4!zB!V5Nq9veNYZ zhsE_z2dfbc*7pEwN*5YcV%RSvm_NIMI*=r5hmyRn1lat%QzjSDpl3*0mlVcKrvNi^ z2~ygkyeUDBz7#IMKJNPcQ6(O>*t)A=8dA1GezQQ-iA2GO^l)eox{ToGSjdr;Kmv3- zQS*uY(XNplO=*Ws#CGBs_5c=u&KQn+{_#}PGq#^d)JG~lC-jU-F;59gWdYj}&2)d3 ze*uGeXBzYGfqB88?O^M#nDaJ&Mwk|G0cXu1fd@w!x=* z4PSy%eKD)`@D4ogv8@NTu~xV&LLPm*xtuHd4w$V!m;+({Xb9CwN{-`$ta&(R(-z^a zjL3$Dm_R$p7+aBXq$6T+bI)e(<*|L9lcOj1sjZ`SW_@f%3U^AFF$+sg6pgT+KR9FMt8=+Rq8F2P}>s>kL&^N795LmBO%%AeWHQ<{nyFsvCCBdKY z0n;TY%}!afN*)?J?>zF-7`+49g%{zJR}-J+cOR6t1K|_wnOgV1SuM+VcMXBi)NjM`Cq^i&4cbV-lNlK+}Zj9m%a2zRkuSgDqDNg{0?fY`|OxH$Gp&p62$ zGhlG#cy{0M4SOB|v#-ROs6-p)o||j=!_I%sS z^|oPg;DVx>_Ykx*2C-Wr6y7rCz9Cvg{j24O)ln7*w*d!2CPZx6Zn(qATfzEve~5~0 z*bEG=);f2A&pBym!8=BJN_X_=;O!QD+u^3*J^zew_O(*9ZWUq&_6r`eGm@7)b>4fI-X!NwF z?LcmH7k8qI2(w-NY!&BAtA|8hJ@)hR(U)(|IP&R`da?Y?crNMkVG%XV-=f7Dj(c=Z ztnF|V+uUtPf>y%?fOD^V*XDu_qC}Vu8YhTYPl7gc<2DE|`?Y7$ZDwxy|oHhLto_V((UcDW-{H4Sw z_VGclMv-S#VkK}#IUrIMSly#Hfc9p#W1iWph|25^_{WEO7y((R`y+UTEV(dN{TMj* zPCHH3WG|wIWn84Gy9oUlX#J<4FJ~QKw1C4B_$7!OR-1KrUIBrPoq4KD{vL6WV9uD!U|5W_i-!FPfP zXM8+{1A{sJ*e@o%dDUQn+%Y9ma24+d2G{nb6P$e!&`)pd=CJA*f+^cEakTjhVyqxB zona$D!--tC+0|!nodT~_hM)oT+sIj7l>&j~UD#9&*AmP%59F*?ySIty_Rr$k(Jt20tbKM6|6NsGmrZW8GyLEArxGoE;Cn!zB0rDDp8 z10C^SRQ6qs&@4r04cNYR+x8q+NzYz(M%P4ojssUfm1qBGA;{_?m=Lx!J*vzF^k+{)l8-Jy+Fj-HPw+?XbL zVG6Lx(U#Nh@~`H;67e9oxzT%PUoi2g7B4u|&We+Y=viRkXc^nmC5_&&A~ zr>kY}LorhH?52|UHNmV)j@VzEXl>(Vh`AWwX+nc=`>1>|*Fu7px>(`YRYqxXBFv@& zZcBf#^G;IAt6m(|5L(#`Jl``(GZ3j7;`|Gk9c<(!Rkv#2(wA~ry{TI=Dk8d{llAv zXKG?_rtH`K7?FcBPNpU8{$Z7vlSU|SMpj&Sd}k~$Sm#vO5YU#1-Q+Ph$Ay$#go_*- z-j{R8zKF$?kgOIOhjYIDTEL~+f8ka56Z<1RTk{DNTjtlL)I33Q9!pnb>! zJVp>bbbdMa$F0BhM``*~Np&-@aiKtNU^!po{SEy#X!+X^pDIQg>ruE%dHu){Bn_z0 zC>IH5_K|A^TjF*bmh>S9K$3#pi9$>92M?+ogIL2cdW?4F$Ka=7n@1oPi&&K&i{5F$t+qpgYyVsVz6+DBr<3M=FQ$a+wVbc1xSf6%wEbQ1 zOH(4begE#1PMQJeACXLOlj?!N7ZZb<`C$Bl`oiEseS4UVBJ07Mp$bAgQJ$G1+&Qno?-o-?OpWTm3#9JUjAvRl-Ffn%*{Cb9$!8`U6_`KANtmf%A`P``Ystlip- zkG3`FW}O!yML(LH30}tKeP6?AdYP+&A3^@MNj%bzfFh<><4YB~`fK?n(=C-yZ!!_! zn|476b&)gEl)T7`(1GCWsbl*OSJuN%8_|y%i+{Lx3{-LGi;og8OeVwt}rc1|NSKts{~? z*!4ouzx?PiOaFS{FciZ_qhwINJQg}4aQfv*dvo3$9fGTyH@Cm6CjAyDVSFvDG?nnc zM7=+~6PiNL0`JiYdGsh*u3HFnE+2SI-E5jAM%zp7LECXM`OBPQe;FC>n5^H-s&%Nu(?3GS(E;S?Iq1N#upKKrj{UW$kr+~`R z9Q3rExwh|g;%)zj43j~k!epEcC2qjA{T5t&|6ieF`CAeHNXHC?&^Syv7BA`QYQQ`Q zVbHU599>daisIjcv~}LiF+ev_G@%_ljFc%@Pws6@C7wNR1G@-cHRXKhD(YWU1M->xjuHk>65SJ{sd&Oih!=^Rmq0@P2kv4 zfP4sV7snRNxG|=4JjW29stS;*ARSw^bfi5gxGAAyE#QT(hI1|5#%Os?YwIkz#0#Ws05Gn9ZNbGvzY4Y9%r}Kcxlb=c zH`Y&I9K2C|3lDD*onNSgJ^zQdr@kir7APWdHC3I_4}i8m0Fn;W^N<6Sk|p4rdvAAC zTfcz|`W89QkvNop%5#sLx#N+dXj#!}5gHx`4rde5`-USV3ZunS;5*Ui4z}M<>E>1e z-Oy`=GS2lTAJbdF=+isO?{L8_KC(KZK^Cy#x}SR=CLLlsA0r;f#fLNT@sT3TVhG)u zsc+n?7=%jybHi7DL%!?W31oW9Mf3k+EH1sj)OO^%!COKTzNy40-Tv+v8Rs?d1_BFU zPyw}N@&&{ug``M{804_P1%Lc4Za?q_7;Kk;>^=C?Tp4n71s^L$;Q7g-Z$v< z?IHC?aiEwjX4;$rHp<|LikP?1?zLHrO-lg+c)H%bso({B8QcYpLV!5D5}tkK$}$Jx zyqlEt$$V10Q^V9kDVk<0PP*OE_M-0x%|bdGdeG=0R(L;{gmc77xWKOzfrTUUF3pDc z*RM*hlrMHr=1pxxqq1=zvBo+3Hs6IgHanHV%L}K6tWy+-S;tJcSj%A|lgsau86ra% z*RZ#0{XHyRCFhjZ7+PVKIUt#k)~s@_jENfvzbu0zZt>-@K4dswKn*#oakc`Db8W|Y z3iM%M9&zn~uCBL@h+p9@e$#d!t`@QKX0-Zb0Gp59`uQpq&Png&f*rhEZy4wFqcPxO zrNF@5(e|n7ZJc>9lz16?9KAXPg_&g6_sCdYcn^Us^HS{<+rR1u6YE&zE?L2?m~+_T z+lDE|!4t+HbF2oT4lT0cBNi#rsbOR_M>?IVuH_v}8LD&Ebcn$o05c{zEA|u0#_U64 zUZQzzm>Li;T54*6OfPA) z9rGz{Xp{2;RtYb{H|T-2O3rITFOc((C^U|)4n`Bl@ z43wLm7lC0PqFxx@Q3;O_V|&>~#G!~z1rq0~MDxoLXWvu{SFp>WSdQ^KoX~Z8_}75b z34M8lYnOlMq-5Mf#|1)<5rLfoH5lPh#urtq!yvrOX2p|!64WrYi!>G1(=Cs-mw%sx z75GUWRG7K5pmWXB^Vvijbai^AGZat<4ZX(&S6WyQt1IFX31M!p#5BC4FlRS$Lx~VU zpfO?y3L5mICBt{nVQiO*)tbKpO4AYy`QVHI+=t?ww5pO&=XnhWQayuqKEaXZ%jgeL z#wivNi-1u){0iy_`^{DpgCjg-UW5EAvKYJG-#Y%Ur|l($KQ-j6#!MSdBWgdo6^xB#NL(UzMGg*i2N z$|vo5^&b`QO*e}$W5HFA80hBm`+(1tj9me*vcb$y0 zNx^E3-ro^^QXv2a{_MNJ=Rjrl%V$JOaVZ#Ss6=DXa}h#Adwfhz83;KD$J?g4;|dRk z-~(5HF0(>}Ud^p?oT>V?PXx6E{@9r7q$sC`Yqg?xH-8tIWqkS|13HBKwy#`-C_vy@ zAjx=#6s<5hBYx7W7S6NtXN9U_AGs8XSYA&PaE2k&3WyJTBq>>~Be?=}=~<}B?3*)g zAW6m9pj^8I9F<$1T^_rzmm!pK_IZiRM0)Kx z!ox45C0XqYwQTJtACaMcAw|rqxuyyOy0&Y1ZI3Q^fkutzXF^G(HSy5u#&bAoj>Mov z!Gbx!z+@zJJ=h6i&rim`tY0;R9IfJs^?_OV0tvofX0PJr4uQiPMzkLmV?tTrZK9`m z^@>@sNV=)=2G08S#!|qQ_CQ004?R+5aA7!G&92sxL-8KAPwih?s83;ic6?Mv3Uo?{ zSIhaDN@-~OCv6{2|Dc~F#=m2Et%%0Ceqv6}$mc2-@LE<;Btm8-uz>lg03O2?VQAOGyTCq5o!C|a-ZY3B1W3`b#S+6|){c1%?c<3B;hpRyLex~8V9M~jnULC6=l*#at_W*?bB}J&XU`DIHL+>F8J1jk^a8nzyGF2vAsl1JU1ifH)SSoq( zIJO?{=tI(p0kPP0pxg4T+1CSUj{osCF?IRJ^*{9m56YbJY2QFudycoroI}L!?hy z<$?|Gh)5aQ(HgU^Mvgr6hl(7}k1zPAi6ego4!dCT8}Bl7v#|^IoghTJBXQ1Pj-i?9 zsJv5=8|_uFhR<61Q7|dQsbO0+cj=~+2(`S17ve_BS4xK70BfPxDF`3Ll;F~H~$5wucM%JdCy6)>3K=o!)@T$ zV(EXm+O&prx;@Z~$X2%{eb)#(Qb<$7pjy(~n7_>ql0Ep}n#nrkFbMP~a!olzbYe<( z$_1b+EIDv9b z3EnK`iV>e6304SLH^Q156aoV&F9j^^pL3wUbj;F=us09k!@va&!MXQ1XQwH8;km-c zNDyC9FEc!up9R)d-NMoq<8*+R=HpD{${Socu-tYJb5I;ycpX zO$keCIbYL`n_e(#`$8rD4}myYg+)Z{lQKy7V*=pUIBwFp?|DvpO9`c2nhIOXZ-!)P zPm3iFhrM^^MFLl{zJ3K1{=l?nxpN9GtYFk-Dp>iF8nlNn8~~XS3f7IEK9QKrhemUn|yYJluc!E8~D-C)R z^kK*6^R74;SQee<%n0~*r%}mhsjx93)pLZDOR3{H??sG zc&~sFcqw-PvjNIB)Hgps2ueeS4PRGBr`w)X{=%5dK~=2jIlQ)&fYowOrYAuSoH3an z;OuWC*sJ@E=Jn>idL&ONM-tFv3E|9FON93a%}gfyAk3)YTg^13q3CESZT}!%>Ot$i zbq;K>cP&i9T=4ExLMs|YWLKalOjU;V@pzA-aJYN4Wo$2c;4pd)`Rog@ah*3FwW~8Q z=Z#^tQU~PcgT|`eCEWBx*1R}Sc;7Vgyf}LDS*Vw}HY7hmieyR%RSPpsZOLeFVQojU z;udai>GKSYNFmsj=E@QQ8q$iQ1FVcYf|?tL7b^uDT`iUv%0~(8XV$Rc*tx>DbKV(o zd>p#T#;xFxIHnq!x7tV;DD3lH773h1G0+}9lhYnkoXua0WT|&A#z}+$DW0hzL^a2= z#h<@1_n-!^Q_up&6Uw?g9~wb@uBuZZIH%;pgpdW`;C_Gn#wq69BXgXj zroX|tH8Gtx4$U$Rza|aeeC8GGY*w>C+R1dZ)lfJuch-E*(2e*toUOk#K*o8j_S9$` z!jnkx{1>A*>H4hg_1P^=fiyP$mU#0PNd~bP;IiQ@g-O<_W9+LcmKU246ziwwui=&W%*(gz6a73d*`kOx>^ZTC57%m~Nh z!M;fI9w6fk8%5;yEmqH#4XlrhNC8d_#c8f-pdZ~zYdgT7pTN=Esn85q)PY9X+B*p| z6`a?o46^bK*smu2<*DeL**eI2VZ~W6GqXL8z-FhNiO!3(tKP+seIb1$St&yJJrV|@ zZa{Xq&JDqm?Ua}I11Z6sBFq7A)g8$6e*jVix)~*erX?IfHFNv2T>R&EAkK6L@*W+C zI-+I+!7D@88N+C?>)jbZTmjPvTy0lW7@2nA?TFl-9Rvmpxx-2+;$?zMe44zPoB~>rVLq_QCyuY#w&xgLbZBS>Fp%K&hE7|#p9F2# z^A3v_n^xzU*P0?9SEX>o_$?&g<>j8Ten-X-}ESaTPPn^p^5 z*$A|oA82vXp@?DCbkRr)z_h(Pnv3n~&w!aA_u&_z8yC?89Ogm4 z_rqlh)70oZ&uJ>omq`aYPjsx5+p`9gs7pfaEnL!N_Nh{k4s22xdG^Cd(a9DcU=Shz zg7PXC(*Su)kAP7cQ5BPxVm`4y`VbR9On+N~A0fpwB^0ZLxyC1Yw5UdoQvZ1e(VK@g{;%d)hYt3}F_|S|IAxD=qmz?AKS2<1?=z)cCOHr9A_vPVp`| zLnr~`T(BWMC8~4lfgBhd=*MP`&U5;{1>BQ~vElhWt9u60XS6bX8r9v5k2i6K6xWon zq!w_#(5&&NS2fyRtL-ENYuQ=IiV|ij7x7lC%n9C5G~!?*jNV?8h6-_k$8Ob!@hiDp zM7PW(OSozH(bMo;nCM}oPU}Xu1N|b|J;P4$#nS=wH7MI(nZ07D-Zn)q3|C{hg{eGA zhGn=ep~CjjOj8*Qy_L~+EdS57Ba3A1cs#3i8fGfIl@Ymt7r4_+I2uQLGutrFJUlQU zTcAX;jnL}3P+5Lz8KIP59xwHw9^kDU?qu%I$4M2r<`l7^;saop zkzWWJrL0!B{ihECG|I@wxsO)?xKnRsnDAvWkI{Vo>S&QnDj3E1+Cj&(uX0?ZQvST`Ity@-Uv4eA9CCweMT2JQ4j~}*mu9R{kn^eAKVBcnFyD=uQ1YCN-DqmtX$eRO%t(ZyP zM4|8?4}?j%P#m+-V{(eIQr*G7J~=gk^i!aQS2fdAvrF4JYWt_)HiYWf#whY7+>j<= zAvhTUqh-W3IJ(trVt>Owf#)V)`4N$5A|6RB{Q7lvNM`xBJ)vE3l8=!(SkIdX!BL=# zolZ5cm3M#^QJiz;?Dja0e6w4AloZO8Fsc@2nnuLaP}X`V=K%Xpx$4k7 zPU>2~`R6slhmS_ZPmT^j^FV?3&N{u))l>ZRbYQ4;2v5GO^)~LPIdMnrp}t97nNEgIERhSuaZ1p8u{TWre3_c!Jc&%`k9bpJ!h zRVJT0wsja;6yde{ObPpt$7Dg{o-^v^V$V`>H7Ss(p(QoGf1qheZLi4jZ27;#tj&On zjP>ncFKjL{mEge0Jg4$35YfXk@ivg^@w1@7gq`zNfP4+s=E!-4&!7;-3A>ODm?D`y z{>s(^;XI1$n`V@dw41dA2GVD_;A;1;1k zirOYbOPU@M(q4AGe&p2{4|Q&lPz13|tiU}VJA z>xr!o%RV9Er%G`kiEGw4jDUgu|GIbU1y9qvbLWx8wNu zy}#*Tty>&a0p88Gfv)G|GR)Q_7ASWSFH5jm;JX(0M!fJ5Q(zR<$Cs20q#4-4kO}68 zVV8-1=yeiv3cJ?##SrTTbWsVFv$p631G8n3PT(kblb9Z0*c&5efgMTa_!}`vc#U#k`j2BIZ|(WPQwFbQS|?Q;|moG-D# zfMHap#MXl~wwD*mkk9oWWO*gRAEhI>kD&zk9+a@WB0k=f5wKpwV51U#UKTr@cpwk_ z-a1y@6hD1A(vP%sQ$jMDYaCckHxk;8?f6{q?@+k>x#J#p&l&fafJApy?;CSc3{peo zE!33CqnEzgj=`{~<`}U%GL2yVoSO{rW+L@@V!^^PP?(vEEN)lml^R{;Z4I`48c>l^ zSQLpw?iDMJim;so^QU|$+AoGIU6L;_Xt7pqPYM?mC#JJrg{ckFK8%s(k%E{S5>Dge zMjFK04&rT-rQ2 zT9S6~dJc?oJyzR~+O@NMv2dOxh;2zzB=myA>qoRdn*&^4oq1s`y<_K%>-rIpRenBS zo<&-lDI()EZZPOG6fNIR#Han96jg^bfIu5n0B?!X^i+BxdkfqFO9^q?`Wq^*Xb&}* z4_&`M2*Dii28!NB6U>9HQw=3Wa+Y5Xt|v$LI;-)Fd~q=1mrxjD8Hg3DLoC6w}XpDUWW_1g%0dCH$`Ti_E#$gd=lkA%L%fc%i zhXq52TA&Gh2OC!M!`YG0msL3vdQXl%^=uh5G~2&5PSP3(3>uEdi3T2x{vPi+)CHFi z((~W~DWEA~=FBZMt8$VVWy=>Db%)Tz^HarB{-Bh90$}!P-*9_&H z$4iC32r!wCg-^Hx!ZBpRQg|!@~hwj0W z)e#q-C+@Y3R||K(%abLNVHxIgQNdb3V|Wc&i-mtamW^pFzXz7{p+8KCp5XS?Ye4Lc zw_xcrjyQLm<)jZnStaz`Wx+d+#7r;4OW-gh-9mu=H)n#k4hkb89bupFYm+=#&T2mn z+lo;jb@zlZ(n3*YP&=&0U%ZwAQVdhVyqUvKMKcW3je)lBAl!lodlSA|4xI35kk1{p z!{sOG@Z53y3St0BB+L=NC~sx`@6<5e-{~Tcmdi2(vF(DpqTr9Q*n4CSqfS z)kO@LrCLDkSm>ax@@Y2zP;U$`9ZQEUjnm_vUs)kvdH00jR{KKpM#tgOKDl~DuwiBY zE7HPA4W+g~Q^^92TWv3#VIc&xoqM`eV8{R^aCbX%eiO)W$UgnVF2K1mcj1YS(3%Ye zTUzl#BBue38k;twb*BOe52+dJ8IReE)@^g|sDN8qpN|EZq?o0KL4yhdy4LkT_|^oVYSf*UKyHovr&X%oi;vVK&DFuLL}qCNe>L%(BUsCoPu0j%j=D(1Pz zkGl;Q&uwx1hVZm}<2XFnHcDM?ABu&pq|l{?D>K)aD>MJ|+XOSZO?Zzs!7Y85_X6lz z0E5rlCn1&~u;m@ARZ%Yjt}w1VO@vE*K;AWPrQY`~E>JM8c(h?HE`Xx3IZsV%GXeA9 z(|9Fo`fM2NX?xu@zYR%cgIoEf$o-ZGAZW#Mp?RC=U*>HU)*q}Q1vNFSndUtN4Qef? z8NzbF*}SxZm?1Pg4h4`~U z#2AxoYpX#n)Z{R$hSY`F%t9DOidjmivHxIU@E2HmO`{9(e^`i*Y}cD~=+%$95?w~3 z5?z-DldJMXEHrEF^#Jw83O`dlofLr7P+5yLT^KC<3lz;UGywlY04{hp-)zKJFhY5(Vf7(~I@ z7vYRYXKnBk7_!=dcn`R1QvMu5@#<%d(@3F64F|QDUZwtBBHqg{DUn&c23{#B%RB5Q zf*q#EN!>(r&let+YdyN3Zr^n>Be~{vn8j5PZrlpcz^=tcU zp8W}5+54EoVYdD|g``( z6-AR$%im)aRfEVC7lA=e0pQ&GK@c5;b6eOmj#OA}u?ovOwQy-kHw(t2cHu zGWg&c%z^$<371jN`a7#gQA!ERWNxLY<0njz`_m=Yo9Tt=d!W<}n$?am9uyL0!#l-j zFcD_w{lU%VqqZKCU#aP%tDn}DlY)^N`p8Pt7L^90wzsJHK`QkTx75(pM#(Ba5AR*8 zP@TMm1?z%|+!?POkMZHqB=2d`Cq*PRe3HigEPsK6l#O(Ce2?lVUZOM_(+FcT?EvTJ z9H({OAE@oGUJSiakwTCfx@eK6i8}P$uI)v!8P>t^&Iusbfhgtf4KJ4M(&{Q>vZDrMBZTp;QGuFj1HneAY%;09@mA z+Al44);Xtc9sNr{y$2yP4Jt_aNG$>prnf96MJ6?r(IQRTNE(^ij?CyiVkFcbXTTHv zWrwG#OsjC7+qr+-Uhe!^)IZMHev+442rV&n!!qtXAz(w9>copB#U@P`v5%cgJe~Mi z>09uD&bOcH?9`zzn%-wCl(vDu`hkBc;9j!MmM5rwwDm}ESRxnxq^fcWd==#E?11|@ zpDS5R-voPa=AP+-i})hDp5>%KrG_qoU4&*55ZX{p+ly$zT2%}WXZK=j zn#*_&xwBp$frdLeMO)4-AN|b}EDjs7__qbov5KaHq@bjP9WvK=K}6f7YC9+!Unxqk zK8$PFnBkd9JS#rINAYYh%VAvimto(}eEqHZJs-WWsgM+r)UZ5OnqJM(D@$!hWI0y^ z?IACNG;?6?$Nm*>j}^0-sUZ6Rs<5N!uy{9e^lpgT+KwAyAE z_%28Qf*K;zbfQHafNr{-jrA``p-2snqcP1*Ls8qIn4O?Nqbwv0UODjDXIxlMtXq%! z%k5_$`SiCd$*A>pj-+6uhS7oMIhu{uG^wcN61U<@Ko^-6ED&}9ACCh6&H6=fLoU5p zjgTR5F(urMg{7t^Xy$)`{IU;eUi&?G?M6>Ib`}`yhE9vmk9mSOITrypMuB~y?-7_# zw&kY2O}2xQGk-AnEgH2#X*y4k8QB4tn-n5es~}g2{W8J>2Cbt3cPCt(!&~YcfTKF2 z+=OUYoQnD2t=r~WIqO?_j|i&)2JRDsBdTSbFL&lDGPB!Os{^e~Yjjdcfldh(WI2Da zhNTuZ2!Fb~O^*ipdjLH?U5-YXD;?YdKxP4uzGF>@o;)v82xK0pjM?4Lfu=V|F~+}A zA`TB4#xTYfyg4OVtGbqrufXHkF`c7&Sr-_0(WN*e^ulvRagsoI3sdnc1iY{3M!Ena z{u7{^@eR}&Un-1g07>I_m0J~-LfkWbQ*(1rMl-iF7=BB)yVPvIy z7aBF{_Jn~5iT#}P>J2K+yX|F(>5L`$pwP8YmGr81$)y*D&}HX>u$;`7Z6qk@s zfq`OgJ?L)&ciDFNye`&;vHi#;>0h%s6t+9!9w&H-cZ2f88j9 zTV00!3_a3kgA($~a=xYt0!zz3|Jg92pN;o;Hr!GP^#}5sq0}S85^%v~nB|36C`_Z$ z6LXWG`&n8{=OOXx0#z%)+V0n13z#ksvbPi#5rfS@H?$ob2=+B)5>m(i!`_!hHFa<8 zx7ONgrPo%96m5-KEv*BnVQ|7@RZ0~#P7H#ODq=)bR3-)CT&qGAl{%uLL{UVUA~Gom zu_91Fi84jT6p%qefB>1#Is5;M_rCA#UF*%e@-EjuZC3LM_@p16-#&Zq=h@GLQDy05 z>$D0bngZ97v5@_77AWX?_S%SQ&9f01Gh3EgGaLAQJ_Tt$j?t94DA~*Xk zuvJ1zuu0-~*u$QUrS;A8MW$AFRY{9oUU``UEB{MsB1U1(*O7; zvCZ%#-r`9#<$_T(>ghxF!loG135g<=ak~lR2z*Ldr}5kxIq&EMh1%{;49*n#*t-1N znL_YDhOfdmV>$BmWWBO4fAYIM>Oxq%ty-$FInWKiW~*%>H0+Y~5rV%zQ5B-G@f4dn z4y-+6?35+Hp|GmHCMkzmkH2{8TKxl{0N3G18wNE3Qa3!CjkevYK^3F#fJ6bVk>^7s z(VTWXhBE6aTeEQLbEm!PwSwh`wNo|XP&Xu-wYFLq!?#%QeUIB={64> znT(ruytI}vF$E$A*uSjs+N{2ha+B5V(uhT!kYd(aTb7{=vp<{^^D(S)-eQ%rfTP43 zy0~n}biNmi5_a$X=1thXAh_$?hk5z+2Ny}Mxb+>h_522Pi3Wj(fkw06ebyf`W8TS=SYvgp{X)0c$AQ2Z+0n;A92GZD)%$BnDt)% z%TF|7@&6+wgg(ZWE4_EK0=7@InWsN@_!A75dnIpkxku94BBzDjSzyi{-MxSazuKfK zmj&5hSmu5u^v?Xl2L{e7okv%s;a}PLUAeIGq*vwxXFo`_Ao0wbRY$zj)@Ak@NMJH zsj4T^R~`7mulTT|saF%PTwV5~W-?Z4d}=yjnylw&JIEPM5B0HE{*OUUrS_zfs6DC1 zR*w?l2UkI!5<|&pi`r@Pn2Ty~?pg^aAA9aJbZCJ8p0F@{E)u70Rq^gNS5c0Y_Wa6a zs*tV7 zi5u`GiB#?@Ji_wFw0QqP+V1955~cnsl8>KiKa^&2R4U#P3-lqV0Lc!x)E_0gPtjKn z&8PaD$tbU=+~x`Lvx8?DeYB`u`R)`7_lX(2)UA%R_CG-$(+Fvu5MS1GZR@f@HLUND z&N@ahKDsl+Et247Oiu1PkZ&Yp4VY!F@?gfCmw0u)s)WRMzv$#wL*=u$yxYPXN?J~C z>PavwyTEt?c(SU z-6T)DX*ICYb3EY}gF5-6B}-+?N!Hu~3E4Li%&Nx*k`D_SLd0r<(DcIibd8TdCj_Cj z!O~{hUnNSWzMW+3u;|0>6jsJaND0?TVh$5b+2s$2N? zP-3a#aB4uZ44r^x9Nz`QxH;3l!{LK%&W(HJ?Ol0{(2BkdM|{+vXSy z@$|jZaZgdA>fec_vLIcI9p2K0N9^CLVh%%iJlG8dLw?II+e6{&peqvd3RCnTjFa%a zty$34j=Mbp(Z(TmORJm93l|C+A6kBX58Ga~<{lYMRwfNb^6?tf8W{uomji40$#m8D zbtLVQ=nl!dRwk0MH|Mvq6O(TZFD@SnCD0m?KXrb?A#|r1m*dF72J!>4P%Y1W+CuuXy zI{=^Nd)Nyq*b4z2EeZGj-B%;tb;6cf&(-#*+psp*cf7}@D*oBy`%|te_P6OnSYdA8 z0QZPRuCr6Fy2{6-pHM|+C|3=zPi*PtkePP#EXHZXi2f%1{G)3REsX8Iwjld4i z5t^goU%g{@4ff(To)3b${W8oA%)YwdLFEh%;SogzlUoiH;jWbpctFoy6v6{ytT3<$ zW7!XD3oL6_54f@4e{xj1#mRaA*DT1MYakfcq8$ZhhoyT)C|V znm53YnA>U*66NO&LhVlA-Ls^tBmeYJ~UBq@anX!2dQOKI+ow+iopQBE5i zKREJ)F~wW+35Pg8ojTi5hMx)CO**uqtxi8k>Zy#b>wZzWt4C3Lr-$x)j^)ySWoQAyX!>Nohro9Jy8)0h;9Qkg%{OLAM-ld{m#;5UO zB@HjL&m~%Z7+?}MKZaDBXz%$*Q}n<*bn&E%%{?+w)UwzcwwZeFpwt~Xgyr*lxE>Vm zx7@5LJ4i$;kxXtiK0CnV5`NP!y4lIS0FQ*a8Ps~rpKQb)Ag2RXHMhVW?02o@pQQ&5 z&;|Hyn2Wz)3dl{8WEJyxF`feJuTwcQD9dtt{#Gh-u;UJp8zr0?t~GVGu@;39*^sRL z>2rJUBzG<9rS&#Bv$PT5M)+6So&}-~rRfTfdP}T~wxTnAy(c+| zV)P{_g?KA&wuyNK9ZZ}ZIt4}_f!X5Yap6)tv-yCF>bepw=?`>_&}6+aZ?;ZYSsV1v zXj$9;1nzh)hA!qUx|pK4dN3+W7zAfAv>*H;Y%676^Q&_F1r>LhN5HCR>hxgIc2c%J zP-VJ^bC%?N>;xgmh-Or(Q|l@fyXzi=1AFtKbHyQ{lt)lvD!$#RCad=u#eyC*4NGuO zmjx8-;>TP1MpQqaJ|@mrFj$pH$l}?7i&$7MRLLu-Q^1V7JG8V;dDx-;x85WHqqB&v6B9GSc~UzppQ^p~9D1L-6KpqJ$-lXoa~dxvloSz|da&2Z%!9BD{-y zoDIsYWDEA5`WUHEN*>bK%;<)c)jF2m#!&C|yqAv(1V-w{UOYJ)d}~hBlU#zD#`A@hEq4<>jhYn9mKKUGHi^`bMsWvIx1 zz%5cAJ^#>6ax@}ZM+~gCjFh3a>pP;|>+pzUt8zee1zzn4dxR=;Rws3AV$sYyw;QG#)QV zPZ2`32=d{2a#!qKnk`;&-tX0?P<5{hTUv^bXuq8|eeAAU<|kd#9uFcfo`9zxf2k4j zx*=f=XCHqVjah7}_`i!dg^Kv=|9J`j_kR`f4XxO*opRpYUc{*$-NYSB`x$NyAVFqM zIhZxBw13>tSuk~QTL~ELkQnTuY@ zdSFUAlB_6u6>sQz$t93^Kf_04y^?=m<1);{o}13|3g=Sw&4SU{a3=_@y@Ow4g;7yy z@r<}~Zm9G|L7SsrKbF_e{Q$0*j6C5ojjgt!%sfejX#})RXh|!rZ;TAKLi!Hqylko$ zj8;k$gDMum`gJ*!M1|ZbCLj8xEcrn&o?f{MSpEuu1!caGVZX%tf_lN$b*1I1Mu6&s zTC}p&*1^SK+^g>Zy?V73k7%<~apN-K%s8S@7V-p-*d^s2&b7LzR;>E$t2?d{jXI+8 zv{iA~7!<2|PJA@DiT^8u>$_qfCK zirj-F5V8+q9>u3s{fJjDDf8$?;Y7U)9B3nX16{BH}u?A380XFP07zx@sMJ&#FpkAc|=itg$& zW5;X?i6*}CZhE8%mUNvEYgV?}(hvskReglzzr9!eeB*)sb-`UcEU|fKlP?ElTkTYV zGYw@;U32t$7f_WH-sNco|v5%B{wE>&iy=Crm%63cp4Fq9V9?U!q zsnf@F6TjYZ`_8W$A5qlUh35hN;k@yk%C&NKC`ZMOl~`V|=vKC8P$h|$=u)AfyN-9T z#jg&MC=u!rw$$6Ml)b(--z-R#$&1@v6viQkIFzk zyVzl&^XW(XtGXP@ex$uIA8MR2d5y-0p%dQAM(aQ=Bt87Y-F3|kefL}R-LV`ollQNK z{BAyjLlGnyMnI*9}%tebFyh!d?Sd*bb=r6IEMD&5&6wAFhsEShm^lueT|ZvsyH+W z1g55@Lg(&h5WAG(Jh|}b;;*l1p&wE7SLgcS-v*h6wkyL%MAUML;Sdh{Ex-Kw?B(vIeDu04{ zY-7OSTVT+)w2#c6eCY23YUFL6z&oO``ss)z)3!%8tb+BiNB;LJ*pf0MSaW}oDFvr) zfZ5nQ=ZB|3?nwj>@)o;*u(@HGMlkAzB(u>PjDG^RkZ?mCe2Y4m7tB+tG*+#K_o-jO`%Xz-I=`n+Ixw~-@ntAKhsZ0 z6J*BVz5lF@7MmO2(O4UGLYDm>4p9xCXFXR`l_h`?qn7m)l+Gmc#%}8>m$Qpm9jHt6 zx>37ABMf!Ia#`7G{fV~va~d26e)(SkKb-^K2-G`d$uWJMjqfZ;(VI#UFS-X9u+e%N#w%oiK~a z{mkkg@+S^5tf`?5>xcGd;rDU~c5Di8!x%`=F?afyM-ugbuCPek-8&)9^Os52H@AFpdab?}$-HZ5 zA+9!K6yAOMt47r6hLtg7vj1iLa@!{qkCO1KP;dCdOaY#<+wt0aIS7b1+Ttxn^iiB= zmWMu@l)52iw5AFTA838Ag{n$H^fnh@{cIegwp@B*?_pFPQ_G%p7Nh(x z{L3t~bARIqjfm6VWYMz##WT%Wm#x2Ya$ zN#3lr^U>Wzww!sZF412|W1a!YPPk+7k(x|=`uFxF8iA@C;znx=FvF~^@1;}7lyToj zW?$VWm!??e&e?9!UAc9?G7rkTeFm|DO9D8s)@6y>ykGi%Pq0BUM13!Qiw#m?!QUI(*bQf?o9CjIues`%u;sgwK| zIgKS6L8%i`NP8WT!TnR;YixsxZ5Fh?!VNO2RJ=V*>Z!fU2y>PBg`+Tm7z{EQx$m}G z^c(BZI9($qbwvGWn-p(2$I(Yj{`(xKB>XAxt}P5!3RaM~D5+-9U51Uk?+VI~ftfz@ z&>}+p<*xsz@f(eR)DicitwD|<^+O*4`TKi_hK&?%GYFzHc)X;;Qsw3HNri1i+T`o> zml++Uea~I3Hag~Feva3YJB!im&feF&R3kQZ!vLY?RXYaAP%QNkoBuABf^1-QftcOW zi;uYTEN$`$b#a_2u5#1}K;4i*S{rp6I!Jv4;O~p0yG%vH+PHk0yVOSJkRMaLukLVF z2e*wmeavT1)Vd)&vqAH>S|>D+^(<`?HWqM@wdLi(S3+uk9nYCzS+753ZhXw(W|FY+|CKMI{xtFOVx!zY6qBg$KVuw z@WqA2{12u4Q|bKCeNdVXepw1`_RK>sP;$(CrDzq<&pkcpTLZ!tt|?SHZwg2ar=F0g zz)n%U!_$ap-S9}Z+U}EV{sit;p$6&ZTP)rikc*qKTesjD{)MqX#cny)aZf3Hjn2|m z3M+5h{Nx!BsATVul;ECzXF%SAEhQrDJ!shXOhrzpXDk(a$GsLOJs}P@cBIMhBne#j zm3_a*CK4 z+}6Y1G;X?c_{)cvB?5<*vr)M1vtSduyU%)i7Sz=^Vnc9;4(=Br=F8{SH&;(hZ)1Ot z_rzO>Mg>h%?_nDk4ZN=rzq%o*Y_*-+43$*h@mogVo_p5={mE4_V{1O|Xwm}72i^SR z!_BMJ&1YdootH)|>V%ZCo~11o4b7*%W3jJ#jMKQaTqb89uEQfZrWF0*gB{byRCsSu$0N*Rcl2sRs!rG|Yh;b1-L}g>7w9`u zV~Z*C4h2l022b9>2K?NJoCYvkXBzm0DdFXuwVslh<|#{U%vX#>%d4lWsmdRc^V=Py zNY@{$VltbcXzN;j0u}uukNpgHA&P3}DrI=Y=o7f-0Y1oUN!f2~lPKv|xU)JxIqb-Y zn;L5`{Ym0^Y42S%`{O; z3G8gc2*>Wq-VW-w!7Zdikx%vj%~|AzcVbJwg!L{j5~$I`6|_+#Yp&O)kWZHH$dJ2; zxTb+VtRniInb3hBYkDGwNwrB;^iY*nqes`BC zGlsCG4F~)rU?eGLlB_k!pPGz3u|8L9n^;Uq&}%S}I12$jUi38y5ZckJ`FHr(dav>RVS2L=NqCM)k>~b zitj6B*SKbS(Lwf9>B^lqKr{6wzNR|ows3~<5$097C3rGL@1a;@J}a3Hixu5v*yei4 zbdkX0lRUT#>tbpvqen^HJAYaPRl%z$;UO^U7Jk72*8a!$d$2;uc|?623G@-n&w{jd z?G;i%Uf|@Ii?8HNgx|@)d zz|ZyLrR)~=(mkZ)nZ$DCurFTCyw{G^dDr1~zHro=+@fMV?%>h@WiPRJ5)5Yn#6OLh zziPFD=}6Jf4bMHkD6U*BH}m_tUt@3*Dyh1l*{rqgM+{pxy|3Ko1**_XE*9NeZy-n}zxqrMj>Lf!C@D@G5_+X0BjJ9q;HH=Mp{n+6&WY&^k?=kMF znnSCi*ZOOOqE0w8>p9wPgAGO)`d(307p(EaQ1>tcw^Lz=u;StG7>L)FdIRw`y#lIeSK{V5nPl{geb zF~RIBVC`9NGSVf3nzYqv4W2TnESI~qSax@Il+@4!B!k)%BOM$q?rUbs-L~UTH+Eu$ zH6qg`fux{@wjDBW3o9wX0()t&iNF|mv-Z}u<2@(@^5O+D1cYf4K?#`Icm$-LdJ6f~ z&5E9MFbaLhxp{nev4t&xD!a#0GmSZ=b9Kb&X)CKR41D_j0^9?TAyOmBF{fDfALO=| zG~(s2xQXx8nMK*8!VPB=A5d|^N_u}G%g zvaD%?4Z&WY^yn)cvwHXC1!VVe151DyUZQfSea8?^3|a< zr=H_)q?|`5&(!!TbVCPf?df3Xbo9N>C#&!XYC4#e!PYF92!A|{%Bfdjg+E%H%rcW~ zSy46mDw~-Lz5{}2JS3Tj6|tX&JAp*TL|YT?zB1fT*}aHaFc{NFM9T0vGr>LV^V{NX zitRHlN@`y-${i!_z7!Em9vC_K4)d`4!oz;pOLgf#erTkxMv&`<`lD;x&LfH5A0CPH zo}u)=Md@$I1S8TGIXaTOiITgk6DWC#Qg{J1^fS5G)2#R1|gkjJe~9II~vpG z=IMk9w9#7gj82~Za6G#h@cb5djt!(3yE}19c(BXE59F>Shb3d6usNZMV*Tx9AJLgm zs^C0?aLRw!@vNuN>HGjBkzi!Gg57J{2sgXSsGKSYJm8bU4Cuy|@|h~*(dhDocJKiE z5guXeMsdUWVA7y$jeCqo9D9MBBWrzo;c?G2rPV4b|L2-0Y#f`21^U4`)Luexm1NGf z9vc|8$*C2eV%T(Nh@uuyFsU??=4Jh7alP(vp9xd4LrC!g zX&($EQI<7=aZ&?k8=9jGYyP zERQl zj_m(bpbjDh>IE^*_~0IW>@GKONS#(m$(X8scCq=rrqRHXPst*&rC#KyEDO<%U6#~$ zqo@~z_rv`>RK(AILD5q%CA;NuLVmGBH}<+Yjq3@mD}HF4BVM6U97S5}YJxSZ{9)I$ zkkpRf5HbHe(I`YC(sjdzY8`oI7(?|P>8dhi@~xt61MDZk6w6g6#}1!e{=*OQrKt*s zEu03X2*Qc8KAp&1V|owT-5^_bW|o}mM~Vq(w%;APQPGAit$y8$uZ|T4Q^q4t8~{rx zACI^cySwHYzHXd^U>udj$hn`lR7MN&IgLu*p0H;GbCaouZ(uv^z`+gVUHLMk$X>vr z&}?cy$z+#C?4vnG{l_O2bm%yWb!6O12M7(V?>U}em zeM^rCF?m)S_bX98b(dnW6ch*Vg)QHVJP~?96^VB&mpNp&EJDU|ODX!NwTxBIj>D9N zszNN$LS(*=XS%a0=|1qp{$$`;Ff#Sz=Mk)nk8EYw(#B$?=?ahfI{^3(?TA8Q9`!+u8JAsvhKS?1k@S}mJJo>ufTqV*E6G{GhxgZ;cL4|_Nj7-?Nb7d z=N_NHRYkXr^#OwXTKqv6Zo;ND;r-G>QO0yCslLwE3xVPN#T8$-u}%Y4Nh-9qOa`r9oasFn|1OH`G$dgn1vBV#_FTm{cRnhz@=n>?|dHo^13dY)TLTV?d*39Yo z0PDOU;4zCG$bRVjY>3?wBE}=$_qBh_uTXi({c@JIN&|$*;d*sr3dQ>vhu}w&_Yb9+ zd@{Je`=i|l>jm#yB~zlAD(;v%71je)Cf-y|>u-33JwG=yqk|jUFR^41r!%uAADX?R zTrHuA2{-NepUXdb0lFbst+hP>HFWO!UjDlyRd`5ZQ68}FPs|cEQReevL`=AipB7Ea zb&{^EjU903!v+g*pNzLEFYQtAdt!1k8K3in+#gz~AKDYSaqb=P>f~*1_)RM2kut#s z$!|WrIf(xRzNN0!g|g+Fi0D$Z_vERe9R$NQwDJhrI$>E2+nUjTnc^OcVq8{H>KK=+ zmw{JDHAE^c-Nu!BkAAp<;5}y#B!=%!zk;xNY_kBG2ws0{SA3eUh?dA%m)yCN+5>D+ z?V#X1ynmFZ6qD@G6uN6^t-Xi9wg+bt?bzXgOl6^kbRn3dk!asjt^- ztogbjWo@)=`3>>|eXsekzp8~buigl2idW}Taub!T6E+De<1Cd9srAKD?C`w}`DE#V zqV)EYl4y91;LL6@P5xdU&{uMm`*a=TX9brJelYDaU&WquT7nf8^>&eyRqS7%g3_C^ zY(j>G^%n*AauzVNKfBG_UxNIMr_u=Z7r-ImZ%!J4t{V<^p0;PKhSUyy2fBMIm8X1< zWY_W_(FKoR0es%oe`aW(AgH5hF%gt~2DI;UwMT3A< zS_;?m!_3X%%gP{CG{&!C%8-GgD&E(=Kl+jjNy}9ax}*Ikjo0`RbVJ5!?G9&HYwG<= zXs66e-GQFs4?b>dEZ5;RVnHkzaRcoiF9CYy6`3>e)^Ld$d_>j?t^&n19e{k8rcB_b zQpYltf;lSVLuv1iepqB=V~jpG^{uE9r&tJWpc)Z zbKM}%QejI)NIMpl8#jR?2y0y=W1ld4jnnyY9U!&_bT9RORBrgtPxv`v+HCG=)*#}h zDsch#as?B0Kk{~NFMDj@c|`GshLOC|UaW#iRV|27unRkt!czQJs$5L53nP`nP${(L zcDbRkxbH##AWtb^mDS}QKVtdKIdu?Ug7x?=jp)}6FFV)J0R2@QoXf*sfRXueIc|5C z{l#wOS_S*?211Zjh3pAtn2d~WqxQB|OW$L)x%c9g`G~m6-A2Ydm0X|=g4Im)LD&IB z&z*+am#RX`nIc=qTKsn3!+mXNVs`F?FAgf$n_s-RDZ!I2FyU2IA&6`6C_Km~ zrF`vz!LX7Z+Ine?CDGWN56delFcJnMq2}k?3Xv1S-cE`iEW_7&R7?7?!XdJlQv>v` z^TA`lk%#w1FLrs6GiY9}Zup%XKC{(`e4Ws`HnR+s|F2T{-2+I5MW?0IJWa-5h6dW_ zdEoc@6kdmj*2J2=K%A;_6)wuyc(ocG25!j#(Lz+sXZy7)(!eO1ThHy4^Y&bKneuS8 zvX7ffCeLK@2k-RyH9%><9JNLF(Bv?MZ~66AXv+YOsnpmsP|`@L)-;me<_<(Qz$Tnx z?I(l4^g>`=FFMDyzy{bYLXL{N_15s>qHmzQW~cv>sSUBO4`PKSeFW~<0h^|e*_}uhcDmb3Fx#`ZUaH~cD+v_%~LWSK_T>xSahUgR+AkH0D(Z@4Odi>q?? zG$q=Cc4Db4Rk|2EyahGz`}eAt!=iEv4t7Jqkl*sl_E6{pbA^meGmwPAd;_#T5&l+E z4w*-wAp@EH7GmVb; z3;5=a&ugYX1T|Mi7e3FFGbz}Exkllf_a`v-(AH%b_Bi$bZ^_T*^xB3z*qsiN83#nhIq zKWsblZVEMKxH9V4(W94+e(}okyIcEy9`@~6XZxi#lS&r9%?s%G-S%@9^Cp$l#`xYd3)VR{SgC@gn4AZ7lSBbD(n9(d+6dB64b$ zbcsYYtbkgT^nja0EvuH{c`_t+C>U};yjf-KYg~?e(vZRB+%;T>?5{rlIun;A4&{>U zAuo!)DVXrz3O6ztLJ&hMiWTF6cn6$u*7W*AWM-Efr>MF!k1R^n0&r#YZ^#2v8-LFooNkcT$}p z4Zx34a!;5=jZK9;gHq(Druvavzts-hH<{x*g2RObqu5r+39ZFPZmO2dzTvqpye>n< z9&(|K;Tw|u?c?629?J#DfvtLxc)@e)3VF%p&e47FX)yAr8Z6&mp)}qh<~G;hpLnQN zc!ix=7?WR@9`fLRyP60N9x!pyh<@D=!Sl3T{uokv^?mvCyM-vR9GTkVg_NXnkbMK0 z82gf}+r1ckGgF=Zc!|0|vW+SbV^9vfyRO^$gr^GmlW;h%;e45EX3h>UFRU0G7~Q@p z24$MI^a6WxQyJ!v9LR>(pPogxT-aene3~7f9*(xI^Ga6FfM`T5A1gb=-E`=?qp44C z!%f%+e10p8LxFjt6l3HlaBNTd=Sws`1>La1wgzLhzX~^?PIp-P-{}tMT-W?R&ULeI zDA}>4TxIFlJ_SX;vS$D!H^YmSMaR)5{~QuO3qIUXM9m6Qy-?l|G5rp@SrRgi%6E_> zT#a3U#PXF?6AEgNx{;gdOt3z_dfFM5Cql`Pd1Cxi*w72^Tky$bhbe+~d?ZR|ND6?k*8&SKGudbsIbQ97 zdHfEyc@D(fk!I77C+64tc_48mn4Ir_*jYrd#|X_U(*2SStOYqDfQ8&N=2ml8d`Xv* z`$ZzqXGl#(T23cq7FlG;Hw#F#L&|=F+pU4ee5WbItH#bZW<0*eq(UWslRJ(H>Fjm*&v zJ*>4@$nZw={f($H1m)6A(JJ1o>!_x?Q#=oQHr4>U2e=+ld^)B2`W$aP{+I{+8_JC? zVNo#8q?YMI_&ZM_HjtO{ono0&KqZcG47(FUw&ex74{KW?l4eB`XWD%U-nEaBs7O+b zH=hoyU3??#6?ejMD8HP(T@ZQ_jO^qQ59dL=Enj)HhHZP`MP0it28Hm$d! za*cYqvGR6KC*hTqh01)%tNH3Ozg+aue2rk&2^nlXSKBGTun5w3u=hHU*!t!j(BMxA zY63+LQvBcpq;Uvr!_MYr=C>wPcRyHVip(^-0+j-bL7o!^y*N?1oAPpbk?12`#}s+y zytHj#;7;K}irwqcjVE^t0*WtEtbUl(Z#iYwBk`O5iCxyY9-J=XYT`{yBN<$x}n|YVC(b! zaqvsWQq}k!S$;%Y8WxUD-a{BF%Z;WU<(1t6k2#*i-daoqMrTi1CUKkP?3UV^DCEpM zhxt^^{GN;&8>kWaI$?fokmZDS(oaLt*L&pu?<>#$b|^fI??VT?)it2J3^D6f_3QyK z`tZddcNFrl9Xs+w-D!B#rs^cI1Pe077Xv%$?4uq$FB|uy?b{4z6_%ZNJ_34_BHrT0 zU~~d@0bY9&JGgEKu2v!rU@x2b45kLI3RJMm4ujbiq_qx6EmQnLAO_%s5iCfBV~S8d0tj%J=_}3`+mwh0mb|;q%+bK7XHet0b_K^@0Ik z`VRVvFn_OkbbFTu=yDEEKigfwg$n~0+- zxROV;DY@Ugw(dZ!Q3~YcD^Qlj>ro4yp=GJLsILUPg_XTRc*OJ@K+)&}Rk-p;S^-pz z9}CUs&>-GDk66&l9Z{B2H#&3f!P$87!;TXu2>OKjRamx9{zT)e&<*=*F#P<>*kY-~ zf?c8EktC~&YX@iwHR{aGRDA^Wa}^I?61?KVCt!{;5hE@Rvh5{7(6AnF>gR1d-QQLM zafG!1t?TpqkFHnXUywD{uN8tPm~_4U;{!b}R}i!Z`M!V*ZBZy)8CrBg3eZ>HJq=1v zU{+mtBqvHG3!;fD{>r|p15&j7DgW?|;b;FRCZG}gx}kt=wbsB{{qdg!y5W=X7M}!R zcuOCOJ@f{a>t`0K7jm|6lL!xuL#_@Js}u4sOBh9Xgln7&zJEgXMPRLYxt2d_gSiB` zz4f3w$%b;szXRSMce!QV0C9_u*|bYCzSCWhiiJxQeK~lAvmMq?mEaKsll>JM7~H3i zDcHY_Of&9OVjmV5j|@n?b8r%%X8%aeC*>M3uN&@nmbTk{1Fxm;v#-b1ZRE&XdDoj6}zP;@_82vb?+yQp&qe-7eu~)ar zwK>-|nl=PAp}XN@O%yUl!B?3@)z)$O2Xe=5e^A6hx(L4ya*sDBZB(E~(N+89R!xtB zt{bw~R%;JL!-qi6#n5kVfxBDZL{{uC2!#@M5AGO5ln0sQW6033xs8X9L%PtpSH8l# z2*z?d6`v);XQQLw7bHVAq#RA)2hgzGyc5ET*vKt?A!Z&%b!H=?i>>0il9kv*ST5X_ zT82kN<)_6rd1XNA5JwFYRJ9O4Ok=UFlJ8iIve-n9j~| z<9Xt(*OdZg8#2}!bQTBq;9EAz*@qA#_P)#M{wiK~ba7VaKn{UyfIgf4?sAPaUnh*O z%^Yo|{)WUly+`*D(keetF&PAJkAF>ODoC3^)x%sDS|c}~u_48cSU0S1%_oIZ#aydl z9;22}^m8P^n>FZePcY^IR?nW#bJ`02AIf=mJ1NTw$*7gx_#6}>kVdIP+!_Fq)$K@w{qG7U*L~eEk{mynFWm7K@w`#aL@Jn2Pnyc?8D0%A+8fz*m|DUJ(0osM9)`0H7*MFeC{i7z6`!L&u))I-u%A= zD+E6x+w;%SIWS7`dbGgrGH|)b4dqH_Oih8SISTkaLIX|?(s7Or44d;3&m4@|*v^go z#S|WJDz1RoPl89hRGxQC6D47Lh^qLsKF45cL%MN&4uwpC>N~j%#5mj*D%ViS_sP6A zd|RMT2JF34e-D;F3@6N|e{<5_eV2v0+}|<(T%qwT=!Oh7l>5I78T`Aec@HQN!npQtZkYLg&_W8#QQXj5Z4LiYcpG0t(zePM&CP{ z-@ASW6!=r-;#G(N4okyZMAPbTQEJyu60<$TMr>I3!#kVNt=6?Kz@r_VC1%@2M%UnD zdLd^iFw4(BdJaY-&K3~u)-R#dhFVK<9;MRa(3Fd2YrDemju5`@#05QY7csw|jy!Q` zi(o^Rzlt3vZ^yi|Y29#{@MC`X{MVZaGznxTy_?G20F$T8+Pwm9X5o!*&K<31PpQ%P zE_6Z*TU%)>iMF!-#$?>&xoA#-3s1fm#?B8ynsee6)1T>K>5T*;)ViKZMb$T3Vj56 zDqX$iLQ^-hZ%2&+=vUB^<~oTLE?YWY3`WPzq%tAQ*(6Zy1M>+Aj)Rc|*{Js8BSDqpQ?P&wp^tYBfFwoe;i;mF8cE@cn1B zdqFBr%tJf=Tq)ZfrG3fLi|T{RHZ>^O--fT>CC5jUWGM(RI~9x)fF}@%$e`rOQ81EJ z@rX0^kk+5r{|wEroNlhS-SqPy4jzcaS9@Ic5%(1kC-I<%VsBM`;S{IFG1Anc;BpqdY1;JF*{0RyWw+_ktgyLE7f0x`!hbDqwyK&hT)}a8--zD zc=de%P&%p1qj#JD`jmyh+cSv~+E;_q!graB%qJMf$ij}ps&lB!e;rEt#UQ6PdxxmF zKp*bR`}keFg$@p{57Bmmf5TM}3WBax@Hs=Y*x|+L=V5u++ROJDa)jonh40+ch-RHI zy4G4JIU0B>eMfWbAU?voPJ%~?7-{pfk(P6bRKXOOqoLDkWI#cBYqZSiKosp6Tq$bD zeg*H5O+0s;SWSiw;?L6J854TB!C_=_?rXY`u`&urOjkBed?3zq5q*X3yarJ&3_hah zDH%-B_xPmn8er`J%K{3Ie$~m1qjums+>7H^-P$xRYFv-Ho5}j|lVpv+*9}37#!&4} zcnxJ--+})>tt#vPW#IWAtIB*Zsyb8q@F6txGr#}gU`p@PPG8;^_x6H$nWHVL4FVl~NA;U5c851v z>~_L0RqSjeMDxTN!9H*;|A8d3EUp=wz=v<_!WHNMWt*}DuLyBYG}=1Nj>;KCQCvkS zlPB?Ed2C!gj<;as^eAj6uvFHN*NVaYvgiS585tn%=2h=0%B>M&lAI-B7k#?3k*y8|X7 z+166Ooqqe)@7e6-JyE?_SvS%0JD;5a-uouHTYk55bAb0UZ!f>C-V-gCE#2_1Up*|p z_x53J515FsxYBz!D`5LXYwh*$23knZ)iLg=GAys3`vF{8MWqAV>m|vFB;ek*8E)Q9 zLtf%!ve;n-59DhhpJe(sR*o)#TxddZi0)HnRWOt#=Ez~$2FWCEz2pe@=VU>N42(W% zz*5B~z=~nQV(N)Kf7*-r*|`Hse!C8$}S2v`mt+u46VSA$QjYMd1nlNM9 z-@!lG334zcb~q!Z`0^6fQlIrb3qt&OAhx4al$Uz|&=)RhhcLKqAz~fJ=d@Q4tnI>= z`*2*s2cvZlO8V*?d{RzepZek1B(FJyG`=;U0{W~nwlJ0Iyt@n3nb3P@bSpiF!X4XB z=0|;aYk02n14p&`r8#f3#yeMQolv6I*4hHzpy$mTcN%QQhNbzEV7JPeWwZ=Wh zBbG}_!E8)6$-3VqnwGnYDk<|_(}DZ5#SZlbb8czzvoF8w4g@^eX5?P|KCz zoIk#Yo@wZz-=>F_APa#DPq@i_5=)Be=i?FRY{`WvO%zsl^J^f)5;zS*0rq0SO_XcZ z3#}$2`B@MymmsfVWN^6}PqzzHv4wqdCbJFZ965UYh`HdZWzI8FEnHzJKiAZjpz^5$ zAX`~$D@mXICuq9E4M2ViAiG;ZG?%2ogI(_Fw|`Mn4t6+kj+)7Es^2 zg#U?K`LA%a|KL`_z~l0?sNC?une6pS_MuQX`zbK-Y@{98lN}=HMgpnJ5`uw(&7yKB zmZT`8FsuTl8T`CisWHa`EoXI7Otlq!{|Q_lw;5{bThvn3%#-#XN!6=`zJ(PmjWtv^ zOx`SQzu^WZPv2{3>`~Hq{hL(1rXj%~d(sN8cbNx~c?uO1i0HE!_m%O~NMA%iyGrpy z5BrWUV(;-<`K_h23h;p)Aao&^6*V)lTgY`TE~j4*BWGSViwZiJg3H8$UPZdGkkRM{ zUlM}Ue~cc4%xMJcHo@yZI zLNb3G=3(zwGega9-<~ivO5>~04ReRq9NLX&2IfxhUqveQAIx3p|IXYEM@qc@`IH~( z9$s*iktj)6iR^Ss31-Cfv7&SZapN~3KBBFrG4I)`W{}6J3B1#b`IjU4Zw_dV`Moz& zBeZqI;Aso(*>nH+?ZYHPqwyAvMhzRC&m{H6q21baV7^}O?Y8JY*)j{)Xt+n9~8u=D2`se@iqYw9A zQQ>Xy-iUWCZ5g&BzWZ*(i0>wDmE*DhkG(e!YwBFPhfi&#rK0pWA!<#XN);t4lc=z3 zEsj-GL_mays1XrS5mBaHt6~+ADk@cktyDw>5>c6lsHlhtQKrZk0Rc$}0Yc{N{d`Y) zhW2`|E59q}5-G3&3ujk(PeXn(|_3+Y>qtVd`(HD*;BqYSf9*tUdEbc^n{Id1S zf2DoDai!OqjVqTfUF_)Oxp>7g_oYjVH#?U+c=`D8_g+nvwU3@HWxsy>*|yK7nwgmy z+s1rCWga`5bUNwprEkDT28%}+>@XNZf^ra`jL!y67M)ay8H0VRkAMfg3ki;&h`nw+ zfBz%n4Z;ju>cdpU29{C0K-HatfNv*4O*aQu;OwvH8(30o`IZB{#t-SGN@3ycdNfP9 zG4AQERRE4~l(F(6jVRU)O=qLED((ZA;YjEHZwG_o6nvCRA6H2!IYzQ&az3&=xFZc`7i@>QLOa z6hy%RYWo#_p`VqAM{c9m5Mvy7Y|1;wGATu^gJVtH(D?V zNEh|mQrl$(*&pkBf85Y5rI~<2u;2z*4xIYlprJLua`TokhRUil`L6keJt zHjMhw0gkQgw3f4d0Dj7bWZyA}ioKB8M=SY9!|dI-SYRd>-7DT|39qfi4rb!9@{GJro*cX zbQ5ss?L;tVCDIsnL*7(#dzErHt2_)qp+jv2@aO??Q&s&)5B%A52IRYd*4If4V@!%H zion^qb~^$NQWfmIVG?-fRDo`Sj!Uzjzg0H_KZO`B)mUnE!@y~sGfQgQ^&R0Jk@zT2 zf?I~J6fgn%tKeG^CAhQa_#X(EP5Mc z%pzh?wa7;BE0utrMKyh>vK3g)cl1pwf3a{belu)&yLgh)EGwCYLpd0g@k+&h$(CT= zI1GU`x##Ifv4?*I6I=UK*pw60+FWXw3pnY=Mk9lufyUSuin{O@M67Qk8u_t==4KKU z-i`>>-9;Af(;qdWTsMRpv|7@#yRd!#3*c2`oBJQOxpRBxSPq#Q%fXIK7=P%fEs!pNWbh0l$C7M;lxnn*>?A#@SoXX&FgB!_C>zvHJtC)hbBYi zj$NQq*i>f>Olj^A`;WeqGwFn7L2lklmw{2rpA>LzQ!N6oGy+;TG@I6Co1EM9v26b_ zx6%CDU7^-N#=a_^qVfdm&;CsU5%`c>6{-<|I^oo;=4&f6pGWSt^!y|)J_vW3RDx1L z?rJ%E?;|Bwp!g>GLS}(^GjHKSdsNDv_R{)}2#R(cyqdE#!csRR**tAmu8_)j?^N#u z@=HIMFZ}=-Ndcw`kO*=Zgp6=f#R1EL#CZUEn%K2JvUP|r9FTJHwj{smgu~@CnF&KY zYmk0wSRB9>dv_9{{q*mgBZ5))YU}Wl%r>=PviP_}qXDh0Zm2J!>KXbJUmm>f0-djzsXO;y-dH^i5%wx<*1u1nuh zoF9a{Hlwt{a2fn2IK7Ks9*#^1Xc)dCw+`7hP0H6l9(M)$@{I z2Ks_XaZn(|K|(n@>yxLM$ANMt0!lB{0MkRAj^+RQw9oECh}}x|9fq9FVZJ*dM)R_s zutYF%_O1B}_$Gor-B^0-f?@R}BJbuZP?@0hujV$01+-PP7*8u9Ij)q;4oJt<{5;AHc^x zi2T?O;$!cTO~i12r?d_eJLQD}Rs}pnIPfY{_KLVDk_(hVM5Us4bWv2`$|)XG2s3ZK zl;%R$n?^ZBym7p_F+qQm(*#2(2?yJ=3eIhoMcyf|TXGpBtt_74?HX~c8`8>BYrQwQ z%F^=PuMC}4VHI%`C0{K#<)7q2MtamRyq+W5f8 zNYa^i|31+>y4gJN577ul-B4Fr zx2&Z7m%f7$nj8Id$Lb-kcR4osi=SO-@uO{7uG4riVE@#o2#M3I18w;J19Q0Z3vjau>N%&0%E5so@x zpsckHMjnV`)D|k(P*hz7lv^1dL*DP}5mOd0x)SR+D^aSv#VdImU3!UA3#mIlI?& z8o{U=Mr)3?P3yc5plS6b_pF22vmV1o`Tu^ogj!iuV#jyT2v?mDRo2iYR=XPjQW>c49l?c! zjrgfja4-kZ-ClT@Zl(3dxlDWPbFwqtZhX|(X)7|@g~YyB7xKRfa-iWSqq=B3Fpm+D zQLDmy>Qu~61+35VPVL#IF0&o!-5Sl}=Ieycva;1y(MsAN>pO1aJBbojH;Y4QxM#;h zijUnBg4#m_-R+y?j2{7%u|!R**J#Z$UniuLmDYvmUl`N3?e;_HO7Q>@0$ z3G$t_1yKd~;r6eR8B`T)95a%DOgAo9JG=$gnN=;>x3 z2DhV&eb>ch#a3;W%a(XT(ENxcwg>!0r`WCk$8u6(kl1W>|DS4r% zkDu*7F7&EmIOs?Lku6oA1}SOfa7-T^(FsECg72@U9#Qj4%YUvf(+Ec0@Jm`p8IZG& zK7#SjS0xk5ApP#q%`HdIiTCueTqInaHH)`tUEBGK@W$kavi9WEcSB=VWX7@565COL zEIFzQbY1rw<;*;3%u_JhrX4T_u$ETd%kfHJv{DNFxPLZJLmyTr+tWo5%t3Qxi!_1R zPB%=G)?thvfV_{?@(j zpi_#4u;=u=MFn?mMm@x(85Yq)RqFOK=cCsy8jGNAm>?T%W%s0pN#C*P=imF!MB3q- ztDju`=t)%`B-_sZ-oJ7|+i4?VAh-l1^BZVwaz%f~MW_8T{G7G4y7{^^i4(T<*@ zJXX_Y?V2OM3(Vp~##fWvJkPE@1GVqX+?M4U0je7U2hP;m5s&1&qUV|o^GA;dR`z~1P+CYQGU>A{P7}agS+q5q{)R@ z7U`o$DbvRuVVqgBeny}GTHNj5jQ;{ss6RAU5vvZ!wx=qP@?0@9pEt(S(e<{vuk0S( zHA^FCbwlrH&w7(NQhHuBf1kCh#9TSDUBJYP-f&cLj49nmoQHUt{+?>KeamZxMl|Y% z%+We}hjeAq_Y&HGV=hD)x>-K*-GiA!9)?BbS^cU$u^7*&`B@_hb;9CUS!*k}wE6&Q z;>V=mau9+`zw=L%3@pCbF~)Fh4eO%)eGe%;*YgjuU%&v8--Q|z zb{>Zdfuh%frayJC_?2!C)Pr>nuU6BI+1xog;$XC0?0f)uj62BB@gP3O9wkI7k7W|%n>LCo z?>^86g%CenueQ}#19if^*l2x#WAg#T+M1C790UNBJp{7=;iV^9K(Ql&BTLFr1M}#h zc_rvG8g<6uom`iZ7l@R@uQ0_WzN`WSR-FMBc-4k!VUib(5@z2pp-odmk&G!_BnC#; z;r3yvh=KCcPy5 zkQcx~$=+)|ZBCEZ0Hvj>gs}W9Eoh7(b&-p@Bp=NC>YTg?9a<)Miwmv@Bx-fWaz1B@Mi}aZ^09`eLE3evWM$UJ?)1-k%X}#siFK!- z)f1LBt_RMel$bY$zi{;QRN8qJMKytbkPGdbl%s*=_XPc!9l@NQFIuKV4G!B8z-SCG zowadReg3i@5eFDOPvHb)Z0A+F1^+6CH$ty}8tJGJ{W>9>tjHq#e_0apXYlhq#OMf4 zH>)V_e-`0&8JsH`VW<-d$r{R$$s+vMa9j=@P*Nyns4VWjcbO8ep#jU~zG?2B#Ub*F zBYa@W@CV`0gZU@F@G2M_{$(M^?na8IMms7CIzYsDp?kLKk(`zNcH{1Cpejv@wFE&P ze^}9z9l+FqP_TP@kR_?hw{*r_NbC0>#%xMOn&%{s7~K2(%2jq6xkA~$uFvgU;H zwDF^e`?GkJ78?n;v=tan?9%uIbi`X}s}d#KVSR6h|96#GC&ZOCyiF!6@n578!{}uS z_O-ecJMRY<<=6r9w%3(HXK9Bm`3f=EzV zrt{>qCPZa!c-mD=JdBw97TZzXE^Vf@Gt|h5*pnfgpWP@# ziXY$Z1P5`tY-dQ`(=T@t5odsrvIncGbYt-k;GR!Rtof&b!^&E>YH{sdwSS50GE+^l zrE?)qtBV^xvKEuI`2Sgpbwb@)&!10r#D9@As8Fe#LgN{O0tfR{qK&3xO&7C09WjS& z)O8?$)7q2=OlLOMW~=CjRASiI_9#r&Ob|G9^>UZgd2p+|JUNbR4V^2&Hb;r&oolg3D=^OBo!Qv4HI}Awe#9)s2|93lLXlAE_ zcEEbR9a)F}Ds@;){9cE<6}u;>*n}L74B~?VxBK*RKC82pdEz{h02143Pbd(v1RW*< z`;Rr40QxT+LQ0f4axNFjxtTm0yqy|PC~vd)%##ft<9yaG)U#TARq!I!m+BRM7&tFt z5@H1~dNj8x<}HwkycPf4Oi-tZP-;dyb|@_(=ETz^hV8{pwW!>4!X%2uLQIl%WFh|Y zEp_RQ{l5%ZJa(hw5}U~-@1YRuhO8qS;{Ve=0)HlrLnSx``<<-&Ewo7@rwq{YPfbeb z!@RRg%8rWn-!6Cxy03#tM4(kqNDUhKaW`fXgv-W&J?A{R{oE5)^8~b1)g}=1WTTP- z1Ja;0xH@?@AuMlJSi17Jqcu*Amu1*u?+$`fh92`kM+3TanH*V?Ho*Rkk;I+SgfjcE zpr=K`wQ)~F;!1v(4E^mR(;qd~VUnsN>+lCqhjl{L*}!WelB)ZQP<4MSiAAs*HVj(z zyRnAv%#mXi*fke!*Y?6+7SL+M)%C#W^M%scL|t-5k#xY}R;UQ8;hBP{bOn3PtA;+Q zSn(3|NMXp?d#BtcJ_W3=qa8&rK;mTcl$p6nQvcfDZ>C z%dVSp{&Jb5z}#I2xbs6n3z{=7eQw}5>gUOX8e-l;zB2+Eo; zSz|dSxjV8P|NmN!|5wKy^K`@A*^=e>uTqX1{0R!Tp9N!t?s#?i$gm<>AL_9K(Dzo2 zG0d(4-rGXp(cIPUTfoRqP$*$S&!vLxsFHs6!J$Cn1QEx2eXw>|-R$x)z{CZ;8sV?% z;VMHNzoXQ0arT{_6|WJWbdPU`r|`O+(#x`D=K{HKcC@%I1bl)a3VP1;mziM|{gAHv zN@;vRW9iiqU8n6>ND7JdTuA&Mo;uId2~THbt*u^y^ib4u{7sN5C@2myu>NKAaHq2J zy2k3K8;;CY+v-P}jp(Ct@(;5SB{G)EU=<}3aSwy=$8hb%Y(woYp;KPgK)2)7e~as> zyQL9|I^oHzpf*>#{VbUVsE<(mGf(y?<~h9Xb#7qF!I*r-#+(gBuG8K;fYu`$>}z-$ zVW=Cn%2rz#lBV1G4#S3S9I4dkknonl4{8fhX?ZZ1!gY9+gENTtw^+b*bz!npma84Nu#$xO>sfjo^#&E6r z{`TADO`m8gla{(6kgT&^cWjdAo&)fXD!rxW7Hip)s; z%ZRFYCH;tVXgd(}fnfiprwa25;H4U7c;F4JhFb>i=DmCVMWI|ABX=sc9Bchr&95hR zwP{N7n`@~XLTA3V$prI0fDB(>(!g#o26m@WO6|@bbn7f4`vy^d&7yqjx%LcTs#pRn z)BK1TLHpKmMoZwbd*e8+rtE>amO3GLtZcP)%^+uNeIIUW9DV~vW(Qpf`p+vMd(-!F z$HFYd7!FUkM`<$p-LBswTwWb*_*LVFTsQQ~d~My1$#GlX5gA{PMxGQ|fQA|1E$_@} z$Kj7c9fyQh?0mLk)~?Mr71-oie$3^+RKPXRck`Mw`W#y7gqE>}1{&IJBVpxsa0ooG zf4jH;@XrrjQKD_&V}p;VwobMNOP3lLEd6Sm42^$y>B!OO=!EDCM-vhfVq=d+Ejt!> zB0hfE`sKgUzTddgYt6=$OP4Nobn;xhVwwBWrNx__OCG#@{P=sXrpnq!&z7=ZKmKgn zXH(70%#3YgKA|%IrzFFX{D2SQ10Ej)V%TDHVtV>XXaT#`2U@q}GyNnjQC+7&8<2|a>b2^!Ney}1NyA`ZB6$(+R?}uN)JoP{^H%tM~8&( zf`Ok1=CVyv>`|*QOMVs2)ref3P(RjI+J5t`=Dq)K{%rD_KZtLBPl*z}ais=ir$m(3 znpAb5Tk8qTJDdmIF&R^ixXKPkqyhF<0RvEh`~;1pX1KJRz|m9bsVIIBm|S%9%O#p?ZdNA; zk_wo7JvupKV_#cq#8F_BEHa7c8)JAnUmn{BnfUHbrKXg^xmG$MovgKH;%zZpWSyv10SMafk7roSHoxU-J~qg%T3yFKA3aXvxhU*JbyCN*Jq)q_02&D& z68VEbzK0mc7FGPKjz3$IOUTYEn4LUq=dAksM2!1|>p++-=`(S#AevLnM>fw?iKhev zDXtONEEu=6Iqp6K>TWi$0Z#m!HlB<)Ps4FPr zG`<6!FmKjS385XsVf6vT-g=TXeGoOB9|5zKN?bX#V4`Z1X>&F>SwwLA>wxK%u|f9s z8`+{Lr+#FKfSs3kf=yU{zkQG4>0zo12ikCl48^F37$7*P3iK1gLu~U;`F2EO&s`RR zzQRtbf!wu7>7x+MxLt3?TZ%8 zqV$8e5`z6jF<@@zyEaQ%7x7lKXQrY*SM`cu+MW?bybe1U(~26j_m5C=P#$d}O*oqt z_$u>FMz}OZw&LqDLpQc9~B2wPP$ypAW@I3Yl!-0AbIy^s2 zm=BB$+^%RXCHROxtH63>Dc}F zse>x^oW;R_(gRzUuaCSkY#)VZz|Zk29YQLIL{HVdb0@&BYU|pvOCxeL0$(>wq>Z*WKjgke-#PT2 zk}mW{K@IUc6Il}@NADK?3_=co>)&#I5H4F&RZ-A96(&RZ@&^!TE_dagLwj%qm{vms z1kCw4C1XvB>ZLr{Si}-yhk6xR$arA-bxsfPm@h|;HaK#AIw5Joy2l3hu%@zzCx^2g zJ?lAwXn`8#ci(+pp%LXep(p=?efpgDU*0E><$Vz4-DPzLYT&Ym1=S(Y<8}w01K8~c zQ~{D$*ok=ZE4^OG&3v}@77qk++L(g=fCNx#69_^Bt~RDw2yBn{3mwo~m`v5{BTYs} z0?Qxf_ydpd6yo@fiOzUievroypM!azSscKD#$ZN2(Zt4OV6=xTP_z-$S$vBiU&JyE zvFW=3mPnxv-+b1XR87dY)(tPJb&9q%$&2dw4pOlUAkN`6K+pw(g9Kr@ict-*kPI4A z!-5A)0%zi^DDxXa8Le2zh_?5hJra4EG8U($7&<`m z-Zs@0)XFbbaF8^n!drx*M7gs7}8g z_P|F4Dp^A%bjz`V5O__OpHY|hr^AU~0UMLp- zDab(M;Ua9Abs>qFudTEZzJ~X{n2QAm$}lP3A^|#0FOL zVJTetjDW&~)N)|GIy@rRVWrP%2}LS)<^?m2L9YB%!W%BUt7whp(RQD1;LlV{c~z9m z!p{;?tY6K#E@4eb*I49r!@63NlCZyuEl~}U33v0G1vKt`ur+H>CV-I|9sWuhHx`uL z&baxo7u$#%eofF&6_{5PQL&D-ahmFREHL`CQhuItE8yeXo(&*-5kXxhyAa+D7nHk{ zU;&(AGd9F!RVXP(Xuxuue-3qbdveB3TEzqwEuR zjtC&W-zI{FeFI2wYZ?mKrJIeJ=+rwPZd2Sw#ffrj1%*%! zwaiwH1aVVeT6+@St6BN)pm|pxs&IAK%LFs7(Sf3!pg!G~Lg@xGh%5#`iXXX;=O1_* zlR)c#MudJ}qlguKj@$+JFd{$*JDv)6T1Peq-O2;m!4KgfQqdG|55lrBc2T_)^G;%f ztIYgnL_6jy&3-qzX-Y6l()dJlL(jrfd@U7Zq~<`+`~0UTq>!a@A+p=vqLD)r&q^J; zv2UJ(*-d>^sK6oaLnY-I5VEf$XgE8i3a4?2o1Faz$KX#B!YX#59xAigV%W`O<8;~d z+z3Z83>^(jM%UBM+c%o2U^~BsgF9)&vQ8LRn>pJ0kdWnG-^+bPBy8t9s4&zk0Y=aa zy-*{4(oLaBarW8`VB5+q->(lZlOKR;gi#)XPQ;FxFF=;OBnUP?9Gw;s3_N@Q(_`8k z#t({;@ALTwf$1rFGavNP`&pjibvOEHxd4}S)+UF~4k5aKq5RZbB0(z)XlMh$e7v!5 zsnV=pfkx$_D}B>0fqj^AB|sUAf$3woGP-d2le`X>iRv9ay>x=J#`mBbZWf+YX;<4x z1%kf62YwCrgycHH1I~d1Tnregx9S(%aj9>3+S_WyiFo$cEaLC`r_XWdDVWZcz;|&` z0%pg6vcE^PQ>vh(UO@oUta7kDXX~p;m=qZT!|~>Ll`CHz>PxZ^(8Eut)du&r{4G%v zqTzx>Ckq>Gjh)E~ulI=d;-hO!cFB=TA;?Hj^%!JtAy9*5XCFLxbD}Gv5v7#QMgUwh z=A~t$$6)DAOGEL!z~q&qCuUR4GEpfwpf#ogWh7@wDomtzKm$dBU3*T{afSm^hZRB@ zd+k~#JRk{`pau`+&K9cJ^@TF5uF$Po%YsfW<@LN-_ekqQ7Ph#Goz0sm@t}?U6iNkdG+;Gu_c=S{+!S%fqB`_- z%5CnL!^s&D>E$J2ZZd5fx3OfzhG{^YOR$>1i4I!S3A_UHx6;>tX+Cls)%ghlQ7mhb z1ZhOEZdg^Q&(RLWhBeGpp$kAdRO^#ls;J2{c zoBUP0Wo>MP*r|dy*30G@G-`ylPFPbbTWve;xgWqbWiqLT9E2Luqk}Me+RbVJmec+namQf#;o zr#VG|ANZ965x+K~*RfEM@ClXIsbHv-#HS^!a}PelPdx2HuSl{$2w3uNlTfsxc)-O0CqBcV=QDa7e-6oYR78bPfS-qIR&2U>Q>q=})P&w0v+!t`5Gwc*4<5YWYP^c?@fGU5fnzWT*F zph(6|vTF9jlOaV7%pq8)#Jm^BJssbUY_Ca{IQ`UKjFxV!nMB;}PV)0|R6^b0mYsb& zG(uM=e4>?&wl~aVI)T2|<9M+Wo48CJy_N~-l^j*F#qbWO`(P2ZnpHH?e6)7`GR$ zObf+9-7pB+nf#NuIlOF`F5WcW+)C}cy=#HcMq~BV31eqvr}cvO1Be`2MeYvZ(c}s> z6Ck6`X^i24^)je-xcO0|i$+Z9gdDT7)w=Wi0EVVXBqskuO#Tsr9v870WVgTrlj(h| z9~gbB;gRgxbifY!z%yN`U98Q*b zs*+PbTk_QxOrkl$zq}k;_R#?SwcKgi%Ok<-;tWJ^O24wN<+Vm|>V~J%+HQ|LY}Ipc zdW()K5xWsU3GY#lzq7|_B@vzn+FLef+)T}=@pPH?dU9L4%4v##0&)dV>M~shH3Fw+ zwRLC&s7}Z$E3GfD$p%x;0ovjrQD7tUlr$$5dv9PSO%)@Q2;X9Pr{+|=P_e&a5nK`F z$hYc5!HK5LX&Pav6Sm1p>#OJwz;=2K*<${OE#}6TFtNo$2GiMQ1JmbV zo1^cnH)=)q>fx14jrh|EF=VB6JRq5FrSE02K`5rh(;|!9svjh0++4h)%shIiN_{u{ zpKiRB5|=e2BhW5>Rpa`ue@r0^x4I4KPA*Wr5cQ7f2-wb z1fx#K9xJWWr^$dceFx+5)o)RQnjIXdBE1AGcYB7raEOy(YE4HMl4~_~Z~rpiS-bA2 zztx45dY}=Py5VwcwIw0vlKV(KBq9IUN2VedL11$))}lyLn3QnJgP|pNMq?*Z91?@m z#(6r9P>Yk_&S~7N36RhtTNk8_wYH=UIlSm09{)VN@M9DuShoog*pLLRJqRdji=tO$ zYJ}f^k)MH(`(gVY`hlHa+0N7YI{UqgGS(Q7W=n%HTWZ)eby;*3B_epvhUw)@Pq2UE z-HqJ|*sTPk3wBS!L+hlGw0d+kkV5aJ=P^oD)eLico2~<+8-891_SQcNcP|6;3b+Uqp{#ik<5(PBSwtdrNu7DiIz2X^g0_)M9-Z zE2BI-qQSq4>zl`%Hu8nVnt}-b)lYh){j9`pFg@oYM}f87m(ybE(Z8P#La6E^!jZXN zOEtbjoe)#jR@$1Lk;9w5_sbq>Fqd*7Fum`PC_D|OjRpKdoHaJuap7<&kgefF^;G6uZOTu~rosM%>_@;#xqiG#^&(O#OejByI zq5<$!nHJIFxoD5Nz3F*0M640lI^nde;mS)p(KJc8>N~FEnK<_uFdCyqwj}rkmI95@@6w z!G?ZLO_z{oZ0Zjne0k8iILR68sd}|BZkKY4Mo9k`Sui*@{L<_lZF|G?_`g< z6fWq>PhNOsgEQe(d+4fnXfHpB!M=3+@~R49TiFQQn z!O9JnMeRL4@(O3P_DWaUq0SA23q#c{gZTgNz|CU#Cd`81P zFrYs3I!_s!t??!N7m2q&UV@F4wzKQ|Z(3{&$PoI$yaW%%;-+}$MaE0nI1xDqVp9mo zSzyHaLN_0aa`C9|paXh6(udxy*<{GC|HMJ96QF1&ho&%Rp86r~5Z zwlKKxeDB#p_hsFJQ6+^^R(`LYM?o9SeB|o|hi`|T?K3|cXK3!ay-C4wZr*wK(KaeA z^1I}1)m3&?V>$|k7d#X~AIxCzz1j!!g72IHjju;1w4u!$ZC8<`&#}I@Mji};`{3WL zQ6re<4aC3wqv;>kNmcSPV|8A#wHe`yIyE*BR9)1D%g znAu6h90#W7R{~2_vm0pTRT^`_fn~=*`XUwP{ZZW0ypkA&`a0e-{_ALsPeLaYrp;V! zO-RV=`2R~!qC)sHm^KxN@5z6kgW;37>$m3~dhU)ZQJP!#X&aK^57=uJSWDEt&Hb05 zqijJpYJU$pjreWHE2^AUj)ab}?!BS`x;YMA)Uau-D87?mzuBfxV6E^5f4Z2)tTxX- zweljRvTEoiNkH~v`wHl`R$c@ef{9p86#_l;&)4MhXmE%1i^Hu|%18Av@z^d^i&{kg z%ePZTYkU?uAyaLvw0#y(0`T4)@r_A^(;yU1@z&ssB22}x(N~iFkpq?wHj>tQe zH3PXXxTKPqIVeqx!`1A zKPwzwKj$!JH$VbShAC-Ga5*`n$8}L`0;?2_GsgBENf z-=`n5f)*9?w}2-H)^XDC7aJX66c+oo2VN(OQK1GyX+kvA42F=uP;8?@{^PNj2Od0r zzISojDrMsE+kJh~qjW`KLUq z+BiNKMJQZ*bCgTe(|PF6lRY)QiT@%o4$1I;Zh5V2wYA_UP2=?aP4GQ>SSx_3q}oYL zgT-IQZAVvu*}Tdv5`LxI12sWx<=rqsBOY}_5JP@UJ0k7r&wVih(~2`<)S9{XzuLoO~=u{|AWLsibVhO1;PC68gPMGHRDctByN z6O#BpI1;yh|MP7GIo}RqzV(1qXSh{wQGfSu4y%`I z1mk~^WBn5t=WETelIBBtE)YH*Ek+F-WAZYA>DU(`K}uZW=Q;lL_^7;bR!;e+=2*}q z>SdgQaJmtCqyT=o7o@+@Tq0) zD%Z1~(RZgD8PTuS^|!C*e5MhKI%0gZ{bG{|So#jdd{Hnh*!Ay`-+tvqaOfak?liR- zMa)M&P=~R_2XHQGgrZK!9j*I2MOc1gKrctziO}@a&wLuZ%1=8+M^o<} zwf6$_E%y;l^23RRuG3y#18}^lcX`vO5uqeq!#s92>2%WHOW%Nx3>J?t*kM4jhl63p z#R`R)HH@7sC=y|dokNw=&4s||G|2iyaZr8ld}VQ+rXA$GIl7^1v_1}<_W{r~z9f}B z7%KY-lxgrLr+X-L#0Mg>WIG4w$miJM1Aix1&MEf(Q|1Bp#L0?mh)>a;z&^$ zs|wt|X?{Z8RUTYg-=`6cy5Vo^v`va2Kjiw3MvrayC{MMc`LgGx5RtUatWLr`+Oc5- zC#qIOU%Qf<69gsfqr#-LCTJkFZ5^jHIHg;CF?+JDbFxO5>V(^|hEDrhe#t+8ev`~5 z8_e+IAtop=bQC0loE@xc2*`ysV56L%yFn}Jt?i$-iBAIu(WjI~?!K-hzb8?wN%gNz z2+`lI)J_7UNJdig^wK_Le}sFGZ<>?*-WynFe+-bgX#z03#ny%YrLDHQcJiyQ?{zjR z2zPS-Qpt(s)83WbumIvbpd>CtVyHZo}+Csg}0^e{m$Bs9E%1q z7AbiOW*4(kqum%P?~vma1F8|zW|6!aM}+hK|xK3 zRk%02$6wQu>_J#QZbXCa_XpvIg(`{)Y_b|FI9Ugz&He32XQnC0=@lbKTW0|pj^x1e z&o7lX34T2qS+Ah3AI}eYgt8Ucp*vcM(6gyk!19~4G_+8)?Da&YE40Q~$;-5=Eu0JP z+??Ny-Nj+(kNp(WbdB)W4KHO&ZVUb@@Q?EEN2s}V@J{F=pg;Q@Mp9k{&?zPIN z?g(T_O~2ukYDA+>I4En#E@(G~k)4CScd?-*EDAp}A`J$d9!iu#e-=w6dh+}yPb=P_ z1rbE7C6l;Gm9^mPplqOS99$iFWrzhYWHVJ&^H?nirNwo(Xhf?{NGfZ%veFK%@87p^ z2kF~5s9WNOZV^Jr&}<|tmbHW!m7?M-k)!TIJgbT+*W=(JaSz%)wLxfpgfZssS=ObT zqT1}&s45WfSBX)3Xz}H}W*OBj@uT@`bu3y)r)QC!*a9Gw_ zJK~ZWQhi5dgTI_v&g7+xt(ig4f9=hLwl{Lt#o0&JnVb2Wl zNK7S=qZ5T_VW8X@fvoJQ9_zugKpOafccJ=P$G(znX-Q3^qS=^@L05dx~rR%6^QTF#XL z>>9V7qv9}vZ33P>KST~7_g8Bh`ZT{9hD_RjxG|$grpZ)2u3k^W6QFiKec_0tZ0;A z-uUNA>PFW2y!+HI|HhMv3LA*#Rui#$oO`iBS)~!ox}o0ev<0)x2atp4O12k+XfG!4 zA%K^?<(49)73VzoGantY$S2wY#HnK1^@GoWuN#b6dC1!B`szoDNk_ur`z5`|(RmFD zVANLuOs}Lmlm$1Scb}g_QCOCf?pO#+hV~1URM2%#H8tRV!9(KY9(9BebY^ATi#T45 zxe?f8Hjzz>lkDcBOTj_*%0@HQF;*23i>E3AQjVP3;5eksidn7BR5|l-jD^OBpc7h8 zdoNb9&(`;<9x7H+Ff&vZci&rpM*0=efaP-Ew6c?6ugz~?3j_m*OAkU=jw`vd8ZsV- z@*?)(!!lu6rxSIrnSgzD!}e?3tZ+Ho*CvrOfIdUr7h-KlabKb=xC7LCIu5MdVcd&^6Y(Y8KnOr@K17>m7!xHrFRn`DU;>2j>0$k@G4cEgm# z#pdd5%akv^jMw-ebVE^UeRfQ?LHhn6^3#<_$tv)cee6;up#NfTnmvUq#@^(YD)nV6;!p4uG?Jz1MNr&cL*J0=k0RO%(U0t`edKcGsYt`~{HK+Q~!+ z(-(_ojx3OI>6G-4toz{}M{a~bWxpL!H&BPz;U$#HQ3G-qp1q8zi5O*2#9@J zCSw}+fXW&-tFmowXO<0kQ>WqIhUJPa-==_LBnCPA9mw=D_|j4|YHFmX|L`FGZi z(A?$gggYfC-@lION&Inql+W*se)vV<70^co+)6pZId!aLE(qU-Hr4Gy?&T(Q!yA|V zQXp6)$GqnTv`ZPlC!QP@sZ-;aWJ78=4(yr##7wZ zaeEyh=X9o7q+W}@8T!@N8b1KKVO?PWkam+V*#_zR2Ou;}iA<Y!+eOO)bD^MpRw|45*Uv;-s$mz75DWViW4U z5qIiPG%N&`o1Z1t61IJ=S5qJ3%PLHadMJrS{UNw-294uRVSyPw#d2&iffNhBnh`DL z8x!<5=d*icDYBK*US@v3m4HI;3-;sIYkUGa;a#oa#H-yCAPtE0{Rt3aXfb`t2B*7W zz$qa7363&S+tKhu74~rQN}uR!c*}q|mM8s^5GS=d`Af<|nt@Ttk^P*b;Qpy&QFG&J z@}f9_r42OMIPN;IVvmFsUIrh*&ee>YpmW*=)Kku0cXmz-T2J%udO0!iP0*5mG(llpOVCD_aJd3DyfG`g zM+g^&Dq}5+BbM7lyvEsGRWOz!3T}y>oykN(h!Rd0kT?+Rz57;eX{=RYBQ4mi#&xqK za`v2S!3yp?K(Ci3gTs^JA@ikHsDJ0=`s!J@35@5Q^ZbR2Bot?hxRt;t<6HNXqVj|N zVn0T`zlz=4v1&^}MtEoAFc??}6%LY-lg?>;47wqO=WBc8Lv}y<{uut~ehdp~p@gxN z8O0dN=5hV+)_;LEu5JsO1v73(trv4+Q1@zan-LID#j%2~qasp={|sM3SSi8mL|1&- zh+~sGB9tkPo_?*!qF;U%2F9$0RN3CU1WZ$BoUn$`8t3^F1T+9caery=o~iIZp^~1O zdAOK?evK1RdG}o>sxzOrtsD77BldN|16$A6_7>UZ1Gq(=KnfxTA&6K*I7NGOp{d!x zZ(}*JPZ6+FDTIPc8_xsQV9Uhcfbvv2OAdE7HGFXK8J4qv)kMS!%5W|N2G(YdF${=9 zyNT<2dkD>%e4ouf`CKLsYsT+q*>v~Kq9EN~g`4gfSrlJeGX{<(Y ze0vkaLNH+!@(s$c!=+9A7t~|#*!89r8o{p{!q-mQb2<|I`d;|sBk@tr|LB7Hg^;c4 zvs4O&5;`Qbnhy}lQwT7vUjG~AdTPXcob4}B&@d6`-$f(n{aDK<96q{mGq9ZHm9bNJ zrI(8eXaS4Z;HB&V8krJHSazS`<9k(D0^sgaqV`jcWY`jxi+bnVfaSS`SMk`ibhteI zIMeIb?1iobR%|6_2DAff-&yr3eeEhZ`<`;0v_#`O&{<>HvRqz;3#~1@?yxKX-yJ{g(kiZ@j19t1Lz7=cE@at=Yy8L`dNmtRS= zP6eScvr+EZkXt$JWz@V=UdwN*nJ@b6v6>>u=UM8A|0U<(zsh<4({{M^8M~tbgg`;3 z$qK;}juau-Z=`U;*^l`-{-lf<*g?!CwhB^J>{nNb2L$zb-$mpG2%M*4@Ad3uyPw@# zG(d}|xsO8z3Q6*M$-9MD+&bwmEn*EWWfTzu+#@sEG@Z%t5m zo<~EAJ7C#Ink`yK@ zJnKy=YPlZgd8)7Qfi!qj^}G|s83c2-ve^Oh1ZFY@Xz0Q*?+oVhLv9jQc7GLiJsZr= z4g~5Qlz_z$pE`ymhN_?(?w1u~{WU^gCseRCss8!PZ zfrl*Fhl_vdPZ4ng8;LtAr)U+^Oo|$&nV$lAvgFiv^pk{eW1qyNh+Zws?Z3AtLy5~W z6D2I02+wMA2?JHp~PBF<`B>+-nflN!PK-D+!FnZ_A(jHt_R2)`W22$HL|6{2x6i82XrTgLAn2i9 zQT+_eTz|mDKPai2pd$@IUwe}QCIReW-LyH1R%Cnpl{VC=j*ngOr5jf#z+sy24zI(^ zk=`Lxl3O5s{|;1tU5Ct;ltaEnRAs=J|oY=Lm-cn7yYhj}XLL|bGQaGnbI zr8sQ}|2B_h5z#eM(X|u=GY=_;aa~pP*MaTyrqbu#A1jW#2ju&AS#A$`dH)dBmpg!t$$rCm*ZeEr4XAslBF3Z>19& z*hXt}J+cqdcl-~Ns<8Tv9cbzcV9j3&-a(VSIeo~I(+V_l7-P!hYsj>KHGqAGBY*yB zInKG>To0{7=I^r-AxqMpqmfa*p7qO&;SE9BWmb0`;iNDJC&76SWv|MK;R;NPns1>k zlWbi0>Vz$N?p&N48N?UT6w0_X{7ZHEr-%{zy-+LePfAM3)pZPJT9&q`7 zN4x5>!d~p`_=t(ENe%1c#k@rg+6y2N+=^7Q=8uzxIO2vZ)lhIH?>=VAMh~bSH56Mf zP=ngWeh8`&)H)%3{{!h8=`f||4Sgs>gv6g$Yn=~6-?RK8Vhs^{+Hv79DJx&~MD-Fi zm=VP9Mkf%vIFyrO&;<3LzUw$K3p-dGg%j$Mx(Ud7nYNQDMcg{&D!{FK=1~UjUnerK zJ2(AmiQu6$KHYCM2=9Qm@B9hC@>mV`9+K%y>w(vnCyZNB9JV}r{T?}T>hHcmnTpOY z0sE_k0k=|@%YJ$!S3id9Pp90__!xA<{A%qsMfN=UUg13&;PM|H0ng4ta(U1j1sO9} z%&8%cf3o0N1D*recAJSp1b}q^^tuU{oI%$!W!+%gjCmIiTZqZd%x!d z0vLUs-w8ry5zH=Lb2TvPmxE^T*@5)2P4ta%UHAiE9J}ZU4c%eF>oRMqTXoP5Zc-Fu z$|5!B3;T=@Xav1(NMC4*sh#+lTat`XI`;c@M> zJzyc%H~Nn1KUB;$D*F89tX^cvi*9WFc)!ovjaP4;35911QJUm(9hi8djMa(W$k>Tl zx0T$Xip^OYx;@=9iSJlkG%`XUW+m1+ZFUtaF#H@%jsG_?#Lw75iNjKH9o?5>N)*9b} zZirn=Z3S&s^WMLU>}*oiJP1{DC`^|jX0Ujn34XxxSyVX+u*ol7j>(_KBHtEW>3~ki zJurjzhp4vs!19OXmw>p3pe9A-B|c&Of9$<^R21jhJ(?J!@rWUj2%?D{HA>=y+DuBM zVhm2GNR&YtI*QsV3MwEfLLFnoC?au0MJUAqk)c&Uv=J(bf{M~%kOmrPkx9FOX6m`B z-urgW_x(=py0`A?v%Fs={iXh8^;-P1>v^AN@BQpYtXc1Yu3cT<>sb!0mz}8vd)6WL zVIE?){8tAIol5IsWfv`u8Ifk~j9yBd;q>R@cr1(Kx4^OQP7u$dr1JQ!H$#NrL3G-} zcY+d%QwHfFIo{_|Gl3R~%*dcdC(g4GA*SA4B)*1&V&w11QBkk30McL*Q&c6w<1!I- zFw0ehZdmply`!yajqtlNuF0`&#Jw9RaR`WGN&W*{Ngu`E^(wz9L5;>d@_;61iIj_&-3)?|plDHQWW1xB>1%A#m=Tq}%kA zicF8*jpjz#gI{~S^-1H@$j7AUmm(mTl`@HRZ-B?01p|dKX+X2%8d-F!W)85Pc)Nkh z%ccTfpM{pNyPfuZGrX4@v3rYQLA<|n;#9hN z4><`27R2owjWx!z_i|0W-uE7qqkFQRM*z{bxtl|7lqlrA`%tds^9>Xn=F}h6a%iE* zj0$P=88Mht|EHe>8NoKeZ_@;;_1LFf0G=K%mKyA|H#E{8-vH}RT?dR8P`}(mGNT23 z0xQ`;5mrQu0^c4Y33y>cm zAHMJ%5Veee?XT6PrhHmtGNJ(5IU4K!W*>S}f9RDi1v(2q0qAssH^FWO={U!L+5I3{ zL_6TuT)%nkzTs@BWPs!iEg~6`=Zs!Rv-|UFC6}$0Z&51~eVquP2PVldFA>ga2VI1Ep-*?W%UH$PFlg#yCcCTD_fb7s?-R%_rXAhXt2=j@~ z`@X>=BITlcPJSl}tJL})H~&%c)YWRk5`iQI(B5sfXGWVd`uS($woJXq`ev#0l!C;n zOZURCtJDxLo%HlcU}oj)@2amtM@G$!ZEzia^so>FHRBvmFU*N*K_dW>aC{{i0)&Bb-%gHHE7~@v z11Wl6{54SM5BR(CY&t?d3AUsxzA|tLjcY9*&=zz?)HpkPV+;C>zknJyhArs-VL{)w z)_mmdXFr;$%%r2i)(_4OfBm@ucv~Ncs%U}7jC|&3Y_QwRzd$E3gazJz2)r5H)42o2 z$FKV3esYtqpbv>`!rPIo)@!&-r+Aby?e@+-{ltA)OMX8kzL%S*G^)Rh-aM@%v-h3Tin+*!xFHyAG1_JJ< zPr(y~9veFiAVq60PV0PAfjV9J5nZx(Yd9gk4a_Dey=L`tq@^I3vVOg~Qv0oe!*ZGP z-eKCJ%8X{kHFo4-2Yyq3>m?m9M@$LkfbB{8OFE=M22}U5!GqV6zJEY$DRm1`YUcT$ z(@o8tMovz^?h)HPyjAm5NxWo^PSm|3tbr19)aaU3jQgdz56`CAAQgO0=d@DGn$d3v4$zumSXB4O%GNgiB&uuSRGhx7>Z7`m-M3glklXLkMLS-6D*pOHIi;x zJpRR`Bv!*TMLhmn!^}fJCG%8Bk=$2>Ubz+NNbt`r7g8a|fJK}ux5dzT^8F+|v}j~T zN}6SC=gB_drijKr2%BqKOIpz21}*NQ1+7sHlhSW)Z2IKbH{S1OJrie*8(jD}PXr!L z2hze?Xp_EYXSvlw3yC8z;Z-diMB!!!6S9)gYA2f=X5tWSN*Ac5KN`6B;<2M*N8S0S zPn1N_EXeWRq7nTjg82c|s{h(!?U>jgq=h9znv=1o?qNvGpKiqWXXVbfkUJ$q^d)$Q z6%{I}wOx&-)HfqVx=p}(+7elX>Q=(}(bC>GQ3pwzK22Q<^yg&<;+#F8Ih_={1MBEF z1BG7R&p>dG8+bTYJO0g3xD@z{q!1)&Z7SPiptoOh@SUZb-`_m*-s{z?#)3OnrDw01{y-dCGCMw}s*1LM1JKR?d4gW;C+WX_;K7kq~VA6U4 zg|~IvD$rZWl<1=%^qO1Wt|90S$w6R-?%{U=xQ*idN){S)nE_bHM*4V--9mm zkb-IfaI7u&{9?;|V*hxaRkRNQHG`eAKkuXc9vG3Z93Vqrq|IQ~pI`F5*^>VjB|oth z;`NCy;AVsZ(J!~xzJW;wD`a>h6<&VIrgBr#I1Tf>&v(i?eZztWqhv|)d(YX*^GOc;F3#iQ@B@651RSc+s8- ztMe>lb4*xVn)<8#g3}1kU7iQlYnuVrDML>+6S>od6(4c+Hybr^--q`oWcR0_fM~xR z{^(z)du(i9`p}k5W;7h5%O=}YnmRlqBM5IbE=Uep1y0zOQu20SmbldQ+xXP9)^$(n zkZmv|XVUCS64F0YTpE9(#U(>RjtC|=wK@9wQLZ=}7$1gRP(P-%Sr5}TcDf-}#*_l~X5dLj?*U??Z_;7hW4 zmXe|i%clZ)BtQo(IQ9*Pf^hs$Afdg*G>aL@#>rR$h#hrI{mqsHX`^yzk)2 z;sHgER=`}LQBwVu}DwwB@Bm20qX zk0ee&JNQ!~l~~h>%>)`V+KWOT&9uxso}inwx49g7qHA`9TfXk_W^L2PQ);LOS%w!l z1=!B2)sIamPDyI~{pd&h3&nX_*fOIH8GT)W%?&ff;`#6SotG}h9WsykR$sYq*xfPv z?YE1x&|^gRv7ceAmyI2VOc8p22nlO~?=}Z%Hn=s2W2Ae;E<)Tc1Ec(1PX{|V!*g@b zf_Ep90)DJ8$6eyQV=E7a(fGK0QUIdy00wDT6#y+W7teTI@2S z4YAlYpY(Sj<9%~MJTN0|Wj0yo_}$o=Z+p=g`EjL%W%zUAQYfZ&FTS@?>pV_iSA8~^ zxX$|_Jt;~<$@|dQPSHT&xvuka>Fki~^o6_HQu`rx$BpZLN`qbQbVh_Edpl$8AZ)~# zsn^}4BzU*eVyy^thCyMo#ysEnvi_FQ9~A}o1o>HvIt zN@p{f+lm+7K_|)NW_p`(D#2)q>-X5FYQy(^+Dl3#ucJ@OA^CS+=ctMMzzp-@14#)G zY;yadepVmee$^Iy721l-D>)RQjOVqY2-xkBpqeq+AfWE|q3Dj=b75*C6M8<&2mG&Y zZ2!#%NZpA@t^C^;uHG>^2))nhD^Af?QD!74uCdQJ8yarvRn%9B#s~zU0BqjV8{Y>* z5GVEUq~}0Tg-_1z&cV$M&{=;y0l$7t1pgq2ZVfrwEi=!Chrg16dA-6#uVlZWxYsR2jwrcRnAM|se* z7haz0^ahz%swGsU+A5mj_Psg%jrbpG@3`&hh#d%h1w7sh%%JUr_3`9^O;( zWGU089)umpJ!JT0TEH_RhS@_L8&|qnz?*vM4pRMh2eN~Aje2-h&%@F|P}qoJT7F7l zPhY`vu(J!dK{tCxrIR+d-vCtu3|bb#pk>)5UH+u^OE|TAI538+NBtC-iT$b8;#*bd z@$*3ak{9QyPpRfiF6f`PJQE=M>uceNH*4#vn;WwaEl(&OV3_l+fAV1wE!3G2-yjoV z9MswKC#DYd#Beem|6RWjQ!_|pKk*Pkb`Ib^6TV)3z8|~Tx;HwXJn@}Y>t5y?yJg6c z(66%1XJ(gEq6=FFuly7-DDD=$=ti&-yOev&yc&G6Y6aM-#gnJRg@UnJIF`{X6-bSD^Mh@Qv(6ic&WD*V!Iv##2YUPdITbL30AB2WB2Y z-r{IV-Nak?!@YaG0Z(>~)!PJkcTB9t?+ArQ^+?gf>y$!%)KPj;eS z(YJ0vqUDkpz{T6e7cCFdegTZ=dG_oV@V}aa{-ZHy=^?`X?r~ryZG~UJ%BjR1E%to0 zUK}bydn)%v6v@q^_ zpxgu0DnWYmXFy3J^IQu~7weLDi>#jR+|mG6tcxP&0Q~$}y#{dm`CWJ=Sg|;;;Ru{~ z)g|a~YJ0F(Lb32dpTSH#V*N;x_6uM}P_#3ad11SAQ-1@LVkHuu{t$R=0d_%Rf3>}m zgkItI$?g}|tX5!}k|tyxDAkG6WxSuq6ue%2Gq(^%dZdujIoB_@eh0Wq&MQc44S7gs z8`INR4y?T%a=`BL+>W_PKF`B?_T1DCHRQb3A0!XaLYfg_@jq}KIsN%P`g?4T{uVvD zTLy*XiFMK|u%>UA8Z`wpdlTwZa9o&^OL3&4R|bDecIxm-VNOCeNIUZ>F?~1WxO=|p;l*pgsUv3_ zR{%{qDbE6Cw)Mgs^%ETQzvz8|4hncO`zkQA5WfLBF@fE$?QalJh`q{NmTOmSDMtbn zH#9}}I?NSdRxHWa?0EtNKGip$1M8FRDzLQ)h%K(%Yz)vfSE)GEhtMqT98hD>JR`ZI zX_X?l^2UH`#NOz8-|Wn4>ivoY1}}0t6%_xM+1=X#)&-TI!WuK^Q&`3= zJIl_ON`qk9vhgz;+9!b-!4xjM8b_+LpMj}=2BmTWn>kx4uo2_G#S@~>by(AogQOf@ zt>rpFI&uDM#HGR>lS~U#=}LM6?B@gPi7NsBPP7gw8XD|fZhN`}`5<``-#<+g3l#pW5oIM!(-PLU9wgReJ&ly?cEn=ycLxYwmj;yI~9C zC#R69V9{69Lcho>=?k6OpF(lz(^9L=wBG?kI;ydLSeB1B_3uDe(v7TWlL1K|)>I-H zo~FhdL&b_(AQ8AZmj*oDMh>o>qr!FxfeRISyRGvQft_Cf_qXq$WfeYxknUd3&OIt* zF7K7Ms#B0D(H#KW2=^ufA+!Q;{ru#U>PpBhlPx@@UyRHT3dR)s^SBPG@10iB3Nbk7(uJk%3V0vfKP z+qZalAK0sCxuiDF5un>ua6`PH*qkshH-}aXEugLDjHs&)(~Yg>4u64UgGiRSc?;&o zcf%hB-45h5@Pu7@zB901X%${Di^Q55AK(*;(~*&w#72)beYcVjglN&-*|uGknaEfr zAw7Bt-f!klsmr$^)EtSSi>aEl~ ztrE{UzI9V6IDbtBe8+$-vW~$7672`G4sp;PaIBk4#aFm>`nDQAh*1+KzDM^#%w$HP zHTnt$d>&j}Lc?~fU$b@CKX#qhqs`#GLGRi+x;qY z4HeZ79?uumJp5qY2jgvQY|I_w2igjLI+k)I<>MzW!MlUzemH2upwa9H@fIJ%0T~*z zNN@Fm$0M+&1KT&^FzdtO4Gd4(OLk*T2@4nfu;n}I(z)agWQ$}c#b3T-EAWM#P~e*) ze*)d}Tqf-V;;;$RyH@ve(zGh?4>OSpHSsZAs6&EJ^{o6>TZ6Eq(Gw(U{z}Iyn^I9J!cA3{3zJd1xtm#6RxHFm2XpPR4XCDPq z?|gy^TOjDYw9*4`wiO&pxQ>)3QrOt0t7O83*sKYMlm*|ew*OkB8dAkU;b>ZrN+w)R zSGQ6wl;|T1v#KA4kIW-PGn#j+4*HSS|7;t{IRy6PP_dWWO7Ow{t_cMH^=*v$Nq;dv zx(glD8WFlrm;(Qi7dc$56-~b%K}iPye9FEo*G)ZN-&XN=t_qxlAtY91D=B~ zZmN+Y-OdZM3f8M<0q)m}>fUWhd{3Jo%t@?621TFnqf#Tav9dC8*0?5L*^e^A6VMAr z4yVOGGm5T*v5}GNqLZmV0bL7JNR*@lFN7_5f1Qrf*&Ity;V$hU!6VSaH(HKdLh~QW z9?IMwH&A(%eMr%(XW9qAI;#Wt{syr7OBV;mT_lX_YIj`ga=$ch%CfZ^R!qWJYgbsr1*EH zZ&fsv5a{fXTrf2l?uukh9$uKOK<0H;h(Z0*PEN9BH#HbsX;4U1D6tdB^MM(Dd7AJv zk`=P@^mVISt>uUmd$Zr;w)!yxqM>%g}YW?{`uDAq0WZHC;wqJ4}d?T5gO z)a%HGSpQvY576#l=3dQz26SE|?^5vmrN5yu-5s`lfO~nGY){lnq-adS3c0!Gwq}sh=tSYefyvts;0I!$l~|QYtd@>rJ|w{pZd=Srt0rx4}B3E&por?4A>FdtYnxQpFPr*hozY8g{_3s?7`pn9|XdHMgqCzXfu->iC zDqvQk1`X}d!daeEpogonAxDABirWv5UZJ2D|Kt&KTJnD;Gg7XjvA}0TI!zt;%k+qC z!C6R4UWW9`vemxLeb`0bYDyg1=k75o$gJ7?N=Wi@9CY_##WtBmj#aOzU@Fg@LiPtG z6z_>rA@>zibRc<$1#%9Y7%zjDVjcst>@04!G*1n;OF;9ptrWDfMZZv@%kW9JfhSO; zUxfqh?b@K{$PNSCwfRFrY3n>Qg09i$j99pvI^4VL^)^>V!#3ZR65Y_sB5Q$}jmie_ zf0nESKf>LTz3s>*$vFy_wg~b)Z&hzb&V%L^q`+Ir8|d#E?@*t_+0#$mSM~9>RB+P3 zCf+~n*0-TCwue8~w?JF|#UC0@cnh6RU+?^X(-uN6lY@l(l z+aH$GLY@(M*WP#Ur+a!yKxtolWYRBh?^z8agwuJj=XS zF^uXweor^A_w1*7n8_4EarZ`rf`s3crTS0)>4yO`cnp48&f%W~=U3R;pmWZaP`_z6 zMgDW`)9X@Dy&Ld-oa7SSX`OqAgyLp!b)xQ9r;CO5?I0kdR&d$FwmW#%Z%4-WDrAv? zmf_@*#va((zdT^2ro%tX17pI&<7n(%MV7`i^^z}-rf_pWLiCT-KSNGbOa<1rMZh`D zP5&y5R38VYM`n_rr)E;At4ST!;Y~~d*2|t{LKzFAR(O7~x9>bK+q+YbeS#3d-uiOF zJ>-QJSHh;oGI(k%Uw|Gjgv{rj9$;qW?C)v|<=`*Vf+lNHH4|2TF+Je=V#8V6zI?Nz zw0LJmxi$LSGTY*qI^H|QY9u%P8SpxXp37}1c>v57d&_VaTS9c>8}Bc^KB8BQKlKae zIJQE@6GdB#wPQ7yWV4nR@*ISp8(3VT0{kx%al-Zf6^=zn)k%u~K>&fRiReLNrV7lZ zlw9c;SYEcY4_`oNML%q4raXG(y3>#{`c4T>OTa6k%JU1NDi?iP9q(vh@mr@`w$oyt z8Oe5*vDthqjbrNA*F7TLE$^KNN@!lN?U2{Smw_+BFH*|=a4G9+f7d)&@@~%*xJ-_S z8?<=zBd|Uys(QW_*?&t;AOuWDzhzh5HxxWMgSR|EW87y?=E*P^<&T4&tpJ$0Qtr21 zLgW?I+mW3vK5*N75zva>NP<>U+$9<5K$%JjYO1Wf2Q*hd0gp9(jXGo=`P5r!a4q+K zFgl3#D_};rHQu|!`qxan<1af3%uY3ADH`unw5Qt5SOOxEEv83!H-8ocVHNh*YlJCp%!5IoMR*XU3o4wsDQ8KG-oRdcKYJ|oa^ALoK`Zz{zA(t@AAY@irW#u zLAS5f$A?OVcGd3LU4~`cu?c1yX>rbsWb454I)4|Vf^P^VeW~+Tg$@PW59*L1aw?Bs zi^dFH>t9z|3sx>Mi~glix5HMiXhj6P8x{c8Y=s(+(p$YR^ztr4rf|MKEBLXXlv*Sk zp%-Jlpw~}=-l0-YHd10MH9BKem2v`H(+!T~$0BdMza8KoG=TTiP|a@)8yrE4a%S|| zS;m?$Ss%WsSM#R_J5k+(7Q;%(ws6IG5*t22iAPJo@qdIZ9p;{P&YJR2K0*iOPI{q2 zPL-epfBMl->NP2f*5L*BVUofU*9VijkotRtTLJm&6LTF(bb`E6t*CaAa+%(yq8BY~ zarX;b8mza`ywVctbhO}F2J$sX?KrItQh^FTGUXLgQsxo zp0tGn{_dtQR$h57j6kl#lY4A4-SqWm6^J9=xQ0+A=)Hp=VQJCdHel&)=)svQ z9(&U7JW^V;z)8k!xN-sxU{KO?gD?0(+!VcXX>^ zA0?yt)6Z$~&y0}Eh6es^Vl#cO{$WqoFM0`;4%?lG2T+fuSbm^vb@^Kp_Ex(?3%_TCIyWHY0}!rQvWu`n#MO&!^?_$qijmjjPP zigLj4#Ae90>?Wn-yTBgH@CLd0X<@0FSV)#E=)(ijypKY5GQ7JqB}*}%TH2%YJ~~uU z0k;lMcw8mL*eg(%!)s_4Aos)d961_u;QLXNMTy~iYvcx-d~x(UKhmO_5q;HRy0Ob4 zYyg_6qq=Rd5}C7BFO7udI;>iGNiVHy#cct9I$Vna;%~7g{@f)FN=F&J=$z9)oZZ_5vqO}< zXkr}*pDL4`6K%=8PZiwvF4bo!OL$@)AD&*nn7cT*7cU4eMF$Bj=MXmEPxjK;+*&*h z9E11R?!eVTxJy3aPFLSPjr$a+VSNJQWgq+4odV^>d|>VJMlH~Bv%w`DBAEa?rA_ct z%-D^kQ%}=%5eLCDd4&+@tMCTykIZ^MrdZ;h^SJ0FD z6KXUqn3<7L?TnRC*+JFREA%6*0+?NIOolbO53inTehn!M*5M13*JFhlqcBmzHFWO{ zO6jb}*Lrid61_Ho<%MJ&uzuRmUV>DM?tmv>R#I~J9&~G+Ky?d*PS5A4U_Opup%bsw zQu<>7Ww1Xcq2vd&h-OAIbu^Y#WQSB!N3=Yu3vO6@i+Sd7$M1stZqlS*#7eA52>C*2 z$|~E6Z0i!W;aHnsuV(Mo5s^WpMIH&!uRy<=JlrL651IT(G4(VEo!Y9_Pbb|gNz}Q1 zU(B<*Fwo3X4pjz>l4n!on7gl zhG$>jfGe9XhtaUHADVZ(#ec(Mj-YLjty zo>KrQvsd@234xbM+0vC9%rnLn8bDQHGx9%ba- zOas;}6RB(@v^=+Mm3Bdb_+V(6p+q}r2-=WU=niM1L>mufmP;}5rbQP266&NdYROLk zby8orqqGfJ1d+IXgpB7DzKQ3O3zGeb?3SY(;&wKueT4t!Q>B!@E`HBbHdq8&4yEJK zVS40z($V_&eqXzL@se<$t;&puqxN>j3PCI_XzEqjSD?$+z1NOp z*3Sku@&=v!yoz_(?(~`HmC?zzerU>TZMqg8=_MIL^3T-lBw-`LI}$4#^O;6;Lmb_v zJ}U)blL}8FJ#(Pp@TV#zI<(dOr^3^q=Pqc*bEb6`C^qkU`g;<*?%M&ht915^=$m#9 z#*UTnCeNSFc8_J*?zdpO6CY7FS37VCy0~GteA0u0ald)~)DBZEqMWK|^LgRu#6+Lq zXl!w1$qkb)t~Ky*Qj{2Uo(CKw!7c$p7+B!vLvKWk7RaM_*6=&uH5`5fS^y7jkKlhD3}o%p$pfzIggEUF?G=Y z-$SXXGaz1J@Po_&X_JR1TLQ&oAU_b=Ji7hKQ&9IBzb22+l<^C8r#Ba(3qkvxi_Grd;zs8S`y#4MkNs7X8#DwJiA+9h+kYj{#_m|pqUXHxhx^~x7pdu07!l} zJ{X*znq^fFzNiP{R0BQz-GED+YV|*^pfyBC6FO*j13YtjXS3@A#bek0Xf>XrkLn}b zH$=zw`>RJONu%3wJ>eQc-J~Ab!eF^Gdut77?idf=p+z$@LL-dmHLg6f(z&UZ z=k!Oox!e_n?C^!hI&4it8!(H>O0mVB;$o+1nz{4mQx&&d{qZc%!Wy9lDLQn*4bmLw zaNxFKvK+q&Ry`v@7M)z;)xANtLES{ zfqbeSe>EeR^p>fs+(!&a$OX}tcP=7NXe$%&YlRLZvcICd6P^45*vGu7L0s0OMEjJu zaND50(HWXchJ56yC=o?hP+`Cg15mbeFjh=v`CU`*VtsFu@xY9Y06Pt&^C^Y8G*ZM^;wTx3G zT|xP-y{FsXbL;@H{x;`Re^)%&*2T8_QNM}e=Q^8e$aAeN z1J0wZh#n0haa2X@B>Tcf6gX!_3;N)79WVXattb2OJ$hT2F3D?m;gX(Hs;SP&Iwg#& zkE}zV2w$(h8%in~t`0@YB0DDykKPi{49m3qE3G{(keN~8W*Td)XAPAmU#2tkh)oeR zNOmGwZs;c<)mM+q^Ml#&R!jWrVrTuHx_2g8)q+n&bMM(zhveP85lj{Jp?gZ3ahH7H z_T_K(cbhq)fGpK`a9uLY(h@Bc1mCG?1pX3Rkx)E94Q;*Fr=+y%7+e%$ViGgj<1phd zz{QSXarqzOa^G6>k-MM$Xr?lgBUzx`(jUm@0T^Q>xfNLftS8Qogqx)T4{)H|v*lO# z+-D4v?58c1j0jwIvy6T2p%V6|ivycjK>mk-{Nw2`$top&3|McbxL+3kMDaD1R$gE! zya1eeb=ua<0-{lfoGx@ycOpfIM2<@F$JZ-->P|0VrQ_L zfQg&POB)FM4LVX5MICTQKu^yCmG^b|;OfBHAM`HW-5ZGt7ETZB&)2$nZjs-$v+T}DxQ^V+Q6cln;H9EP zVr?iCVYfmjcpyldwzL=`cbibLgbumzJ~IQYr#+l>jN@Nfr=h7MH&TMee3_qC)&qOa zhxK63V_@r>(AKlyL+O^fF(5l1Jcxd9>l^Xv%*2@=dVX)KdQ9<`pUgoU{J;Z=XUqsRLND31C}N0m;{V96dka zF}0`|9>J1_s6p$Hu*{<;L6j!;zRo=K_ThoWgFRie8^EHCFiSJs27Hn-Lk zxlCg?*{rC+{QUd%*w&|L%mZ=-G`f7>4$@Xr8d0pPznQ@+=-bq&p@k(QGM1gau`-s! zpN~oh7L{*-%E<2AX>sop2Hf4BS9XjRcZ{e`c235w!LWS2slV-!l&C_dM816hPaW*x zJA#|(AE+1Oec=2wF)t6?xaL;$yZQgf%myVbD47wF9F3irShC&}LHTd8{&{>0=#NeZ zx@T0ZPWQ}Q4Z<3B0N*$8RQ9`2JEGtKKeDR+BrP17(T-*rOFgm5yeY!*4^;gcQ1S?z zhe_ynT&_?FP4X3;0i!0b7{Rp+U;6Ut-p)xoUN($T0keOchUa~e2H+azkx;!z4^dj( z+S)~nQf34tCu6s`S(?ejQQG9zufuMIbnqOhzWC?IhQYTxc1>#fLZ6x5-sFe*Q}-1f zc`%`Lfd6=%VdgIKZCFnWO-3{%`+ zeCU?0ITSwv6d|c+vrLt=OPLB@q3>83CC=PJ9JP&{y`>Wd$U~wE3D}(_Q z{?@PHA*)?PbpW*~Y~clS!wyvLk(XRrgfgT07(c@Q1>AOSEWiF1{Ca~Iz(!^F04@Up^7?NQZV_e?evHv4MUWXw=U@P;>elj)C}mIjr7? z7LUw`L(ocRoO6lg;Z5;f|2H1<6RNN~=P1Q?a%e+M{@e$ExA90Axl8nq}+( zCAP6NMF9SRd2f1w{R$5#5ruGhSr4+0xDa9+${(!o{y65VeOYGX{6-DEBX}X?X+;-u zC7wU^z`=*~XxvGQPiB-M2V-3ue}Sto%h;~+ExO8QN}bJw(SVyF0;zebl*#i*IM}@N zwCV{h0{;h9AGkWSWPLC{Y~$w+MjrwF^KJ3V290JR_!bb9Z0bysfARhP38(Z4Jl~MM z9*w2^C+#Z!v{hn78YbiELr#!S(G?p)ro29PZc}(Qi^*L$a)XU{;?|O&Kd2odP;T>Snq0n zHO_CC_f zfY}IOo#Ud6c!3VDSN$ty@@lLwc}#lydBv_8iY&pvUKdc|lf&;z7zRGUv*O7n5HgQc zPVGaj2MXJ6QnXnia}jd+MC(MQhk$nJ^PR_fcp%>7#jc!*Tcx%h{UVYP`I^+W3BHJvy+v>c6T z&IVk+2&!_@@R5!^^YpOc8J06Ji4Nei7!kkhjc$0@WfW7d+lltzs4h~Ks#=G94=U@Z zyuB1U$mZCuXGZHeqwpIGsrHGQE77+eP33!++eGSZ^;2ECv8EI2)OgfkxPy{Wcu9>l z^(@lsf%Rp(YCRWtQ1z)KcF`f2I&uCR@AA?1HU@*tviHatw4i20KrR0W;nw{;r~(z~XjLa5j4UO9fSVr^N1!uD2vB#l1Qi&moHH zRYmP+?^%#J3)*8ZR*938?ioX&oY4;N)lFK1`ug{H=+zAgpx>}IxVZnFuW3Qeh~{Pw z8)xI#W42P8I;j6psVn}!Ds@^&Z)OjNQx9~lNRe&B5m)Dbs5rS2X%E)4>~J@1s%=}r z?JCswT!4itpOhB105hvfVUF#T!rs8L&J3Yyy_LUfgv)8e4Ef2o9|&j>&WK)TZ}cu9 zYYaDag#SO9?H+7RWIGHUIGmNj&j&*!_Ib6)qLUF|)7P8e68O);G+yIUQuKKOP_!ed z(>k@!ybC=$qVEuWJQsDd(o@Wn1Lw~^fd|#U)A#D+n_$24OkNQ%5w$BAvGLWzmHK!k zR{zSp417g&Aw_ch8@IKK2l%_Sd|~KVo?2Kuq=h~s(x5%;_Khs=tf9gLrRqN_Grn2W z|LItMpEK70;%7Vq-i709l}q&)O^DW}J_xg9S7=V8i69}tgHQ}@vrY}~ByL>aF|czAKQ`mR2f z;@5<~2_n{=uvf*qQ~Wys+ZVJtLFMXv0IK7!23dVf`w9FHij$CD`ETmo$=C!h2kxJ} zv+FP@lBHVyf1+B-6bq+GCiXt6KLgxdF9ekb>QDC#9a9D< z-IKX#uQn{H{E^6u>*G8v>;gWGS9n7GqW&YfR$qK8FRk|J)>y5da;{-`v6ZDHZ@zu+ zQ!OqHYUX^Z{Y9LJPm-@~jm*Rz9gOtVR2Me$R_BH&e!LcLvDeW~>*+6Lejat}B`;{>wu{s!i z*39uQ;E6J4zp}UZ%Kpz3asH@YG<~~NiRwcDe_L~f&n0p}6nPn#?dUO=+enHdDgK$4 zfnYAMEm1B)379|1frfn-I8!_d@IDr&8eFNWfyp|jHKD=eKArpQ2$=wiQI9@#$zQ8R z@;dsE8eqR=$dRu|(Qi|TwUt`zxEOzDgo6B7gUxMn`t3~TH-WbTZC@C!P>?XtCr-JH z9IUg!NYOSPd8%2cv)CLDW&pm=<105eDw0Wr5P&zOx7rCfmCXOaR!jTE{0~aP(1HEm z?-JM8){OmPOnxfKpn8!{p{{ki15N71E?#$==hhGnPhwjH^c+NYEOprfPHfn_wHqDO z{$<>VbY!Hh7>JhNB`}%jEYMKgCBOMn*x0UCH0FKZ$*qwxY@Gsr6U)Jm63_nK6==)` zt=Jj&dKrzv{=|lp+5ZYzrumBSmC) ztDsCIy`;nDzUb281?|9oDU1&~6$>s=x`f{Qk2q}xit6W8U!k<03L_%0!*pW}x9q24 z@}G)8r;?VSF@@2fxvw8}&O=vMJ=!s85^%qwhwg;pcWpb7LXD_9nzD#G6>zH`E>I@d7ncbX&(;V&xy3+{tg^DPI!mtf)S0X01=*`zt`Dx(PcOsQtUlo{f|Ps>I6Bkpmg5dcl1zR zbA0z)$HbSkUj!riv7PbJ8|-eGiO=nL1JF#>VPIsixde}m_M{x;sb>qnNfRFrFdn;kyi#nx@7q|RP{mp19!sh# z!PAl>WIO`7AU(EEo}h0cG0j9Eu?L5WQ$BmYVhpYe1KcI?dHA+Hj?2AE34ym-WN-e? z%o9Nk2)qY#&ck+H-m8*0WQ<|9y>WR6T{5iQbVg)fI~YJ~9Er+iYnwW{9~^8(_Y}U! z2mCvq=Q`HN)vb6J&nmpN+t3LUEwwLb3oSEZE!Wsh3+`XQ${xF%HgW-|=>)1AXV9iRf!5BGzpl4$?tgA(v*Rs+~m1_a-!j=QPi1zmUuI_|d@ z*OQ;TJVHig0<$ErBP&PnVb}=&T`7iD^v+otf)>Y&NV0Yg#@^ii(>eJKgEp`*ehU~! zr4jB~HSma5C8Q%>j~H?!qCMo)oFoFS@>Z>X5lV|gM)Xnkl(zZb=7@2AIB>~NtAx2R zj}MAafQ_yB*M8cz3flciJ4ie+krcx&@cyqx;lCGnrI~vCD$o{AB$0U!$sfEwHr&2= z?`0L;EqA-=jHq{ZQ2I7*!eO^;Ont)9pFTAzcGR5T8_Dp^H~NJeBQJ4d6dBDl{{tIpkbd^hm9EW!=`{q!(V@H zsE@ms)CSU`ks-;)*pZoaF`N1uE#IOS2vCCmTb;MPTj0B;Dbt3o>*Zc=I4fZOpiFc6c!6Y*J1y2W72g=Ml!4vPBT4~`+V79DMXm`f2 z4Kz2umhSe1-3&%l7yIeP9_(R9Y*Vj~iE0wtdlXo&rMQGo_$7Tv70>I~J8f36!jX3W z)I40EMj9&RNH=JG9({T=DXJwXal8zyo@r@cW2l`&M#(PG)=p-m8KYO%Sg@KrSPzmG zQ7UOEy0{^r>d}RFAGxc)5@Q?vSE0T@P*qi8L2)x)gUBAyVb@_QgDI%t+t#VH@MK1_ zVKXoPS8FzZ+^kexf%!X!9Vos}f*xCQzj233-5caO;LJ4P;pqeY!`63;2+@Tz9%5>R ztTAO;43u;@c~U@&Pi7w@n#ajSNq%*+Q%-!YLpr||II&3ZU2%phq z4V?Y+6I@_1By9aPLmI<4eglsdn9S%rM!)MUX=LiatXM!IE5uKMq!}pcgmaYXq!lEM zey;GT`t{MI;lJvtby!p{raKhmzG=!!13b^_oBU|u$&lz{Y*sLPc-++C2`}w#2CYbz zUlwnMR?&(~wzS`Phw`;}J*lD_YCc6Z5)LgG8Pa@=%`RZUXzF0p9~T!!!WHRIHQ2KQ ztW4PORi*F=u>NFO74kEfaOav^wjoUYYIK7;9VX%VMh47k_A`uaEZMo-)G_J1fjm)_ z38Vh+0=wrk)D=Fz`l!9MiuK+fQzQBm)2{IX6<2OP^dUDAHVx3?JGcWslZ8>alugK9 zQaQd49WqU}_^d%bA06H4NDEs=v>|)0vDy#|TT_Q^qAO|9N1(Rgu5xG<)&|B>>pi^N zIpK~yoXJO@ZdUQ+6_$k)y0LwZT@TP0n{zrewnH>fc&=+^fWGAWXIJ}?{T20!gbuKH z%bdOGl;%^dfGigVw)LqOqOsS<~*metIDQ20*nPxsW^V-K)+z+o=Int+N3frhN8EI%!eK zjEdx7?10ZYmP{R$L1DmsNCPS0!(4>B!q@#U&Bkw3>CxXKJcg-j+-Q-=kX~f$d^Gbf z&{A$R8>jqnw!axB4q4= zgqeSVp=JnM8Q-QdDs>!Stuusf^dj>x;xM{m0GW{(?j9Y1S6{h#TnoF#!DM|cZ9!y2 z7P7ZDHV={IGEK1{{?U7s2=^|A3-vsALbNT^zHdB&3F==a?c2+led>2zTZCWsf3YGK` z!x&-<-?HT?MZ z*Eh>Xom)Ne>V`JU(_UrMvVyzDBnR9ddvQ(E$HzQO9nHSsBpmBWTba!?eK`=_e2o-^ zFVfq7KgzA}>=g2j=2^~Nc!x%3<>gp-ME3~D`_Py(eVFTj&kls_-3>`9Z{TMLm{s0T z(Ar12j3`X@GmM?NSo^5SgEoUi@=H13z#vWm=s8QuXZ5)c6zaBcoe6C2lBmXB=WznN z>Qljcadmg~@!hZBQi+V`o`p75UAe1zCL5Iu@g2KUE6OuC_|7fw38SsIjEGS7MyG|d z-Gj+PcO7Z5LM814))ijfO0X%q7h990z(&N55+|R49dpA<&o7=8T-c(_?B-!$4v|oG zrFNIMbn@cBshmEzvpn$&*=Mw9Wk#1WI%I@Z08AaN>-!Pge7K?fsu8Y|Y@4Z)wxEg0 z_$}V#;pdkdj3wb4>Ymf0kr6%0e!8*GKAZ$yTtdTktY5Qr*gtli*Q3qgy+QBVI=VX! znm>Qgp!uJ#)1Zm>&+gkF7nc-wYJXBv(uouMV;B6Ca4<1(!S@T#@V@g}9I(u5@%;I7 zUETfXE?Tf^{`?}p6(zs^_VD3%0Sy(^4<64K)ja%Q-3Q}sY;4RO;|JObema(NB<15L zFTuNm=6*P6!=PC#*Yy@$SN=}IB_H16NqwOq`DdKSZKN2Jfx7js5Bkoa_1<99mRzjw zku8NZh*bwk{+;PT!8&{buvQ5Vk13e#W(bnavX|5Msm#b$4#rYptTteZ<@4X#fR)R6 zP&wI4L19flRs~c?aZvxT)+R&Cxq4uAJZ;%zM4_^WXBLbb@mcZI6jAs`LRPZ6H9|SK z3|%b%<-i^F)JRWDfOUQK;h)-XBIgQgb}0|oW=p}k9fatkAQ1RsgLnBn$&%l-tjh;q z&!z<`BU+Zd9qWQBUi3HNqS~Ohd65L}g@yvrFSnNwBX@W*N6Nb*#%DM;_$EF6@_|P zMWg7Rr0h;4IvFJ%ZJMY+_lf`o*ZWhZb;j--XE0PhelTzV9lGt9QNm^#>knjUSW|B- zd`sbBr4_HF&(Y&i6sAIBUL;0q0ly}!-2P@Cc4O;OwG{1D*|gsk9{$Pk#nz9aMu=c9 ze5g<-eM*8oDR$MF9$=*A^>{tj<-KFUzQwm+9QfT^SQe{FrA09_3YgJXYwTzI`K&@9 zTch8iM*G@lh;mHyR{3kwGO91hpA72Ft_{2ckFxP@!oRwSx#a0V+bp7%_@Ua6&~X#V{yC zi-I6isfY-OEeN!XEwgmfG*ge&RnPBfbKft%>-W|A`YzYorr*?`EOGgVyUugY+57Ar z7un{X;Z|>63i_@Q!uO$lUj%EMMEx(cDy?7_n52@~JRz(_l?9sv)@!$8B&njW#`+<} zVA0oY%wwvtp;zOWVBpep@ZbJvvW(?WCOayB00dnG{2S|27oY1w!*35zTY;JAEK0Ek zqWagdqk0ScdBFBG_Q)fF+(hB6x^TK49SP( ztBG~Ag;_6DneGO@jK6@v0~&g)E&Rh{?HncGQn_nkhUk0^ca2$mdeS}ZHg`&V-FaF( z>V*umW9d4~+5QFmQrS$S@CJ=S$S;kNcIhh6T?6l7Fz~&1MUHBbXF+X-c@+3?#a1A$ z)o{LV_OHkizb*oHFyt zu1;84%N458v`E$qk!EYJt7sewZQeSO_6dXJH$d_P-k>lA7=?%uJLKT;Zj%iknvB~0 zo0gd{Jyi8iS{&+yAG3pj%S_AqH(B@&YOpbP{w);`d=_~JxRszTBX6?C`K<$sQm0o^ z3J%eWJ+$z$5~)85(gc?B)W{59F(=@vkD`9nTgviHzrvk3WV^c=oa9eWoIKe8+lNIaBS^L=p$k(-lY zGbyR_62iNoQJ8o%O+W6GOC;85PaJoTS8t|8vz~Z4T}`!^4Vj@2Vjk^OG2RWYZ|koJ z`>^I#XBA#FfbR53SxaIEb~V`o6qsqy{5du@{Y$+a%?a^oKLVjP0go}@t0u|eK_t3f zgR=n3>MW!%$~8L%P91GTr6q{ka&L27^2;)nkxWZoDDQzLT2SkUnq%pz&4EqITknB~ zGClAc^uQj$8bLJzU5Y~C1^E{shg7r!Bd_t|t@n|~`%ireN-mS)qP! z3NPXQry~k5zBhP)7NX%dmG~<6A>P3+k=bEe(kW?)`pK7Amd&`pP#IFJWiooVlC(x$ z@O{_Eg{98v1<;`8t(RtZrZm4nX`WC_StNAh^)OuHHX2C8C%@zE+lP+W3(RHf>Z1kN z%%ecok1f6&;ME#aipa3Xd4Tmm2>k9ebr(MbMy1gIGYm~Z(|4~F*qoQ37(#YF8F10K zes_GtiZdGFcr9;tqGoms@L8+|aqY z{@02ws@jzH^1@C}Y@V*|3Da{Me9!&gwQwiEN`hx13+@Em#q6rUt>Ex^o7EI65A-`w zC3}mePCKwelhrX}im%Gxc6k zce5WxmTBEeQg@JBXd4y1P`=ak^e>AJld{sY(;wm>q`2ZPmP=m)NDbSrbpUUzj z@$h3#A%0a)G^$1)u89EDYAHhJsqggD;#)ryq0Sl%2H%E`?}&ETI#|w@-~~A#g6mw= zg?}NBk~=%yU#dtylh}iDdIvCmF);*~Eg#m-Q}cVj@p*RCDdavf9+k`jziHwE9W$VV!Fr2rc1KRm3 zlst019;|`eyK{kZZxZ`*0H68{4f07Tp$ZFjE+xGboyc()e>ONpXwVU`{WkR+Y8n{Y zkf}n}T)E^`&Lj9%MVki&-5d0> zDbZEP!E8zly*!Hrz-a7=NBAl9q--~dt>dEz6(8s`KKro(CQbYLMJO|XE|##+?!136Qa~nkn8$k zzl$jO>*Er1M0-^iE&$v$>(?dc-lTpHCGdmL8o=|8ZOunQ>8TiCwS2znWrP#kTr*Bv z(nW!jZ_$=?{cw~zdsQ?05<~wIJpP-Mqzp<)&O#{(=#)(VGLyQ}7k>(v_28OJ(Dqg5 z8hHXtM_rYrsRO*`rRy)IhGA;U2!-%ghYY=$V>5^~e@ix#9Gv1lPg&Q`e}NQ!d+QmH zXQJ0D*O*s@d8!7^ccQ#Z3|w3_=HA~)EDWM@4fkb@15QNYMa?E*buZg;QlQ1kEZy%Gm7 z@AahY0dh;;E>ZLU<&6ff6j&4jqi^KPjaB9s!_>(v_*XT*sKseuDcp%1$BwWl zngCcSHWdGcYTqL&l4DA8pF4nU599otd0%nR=KIBBbo|%@{j1@&@Ygzbt1%xXa;fL! z=HqHSOWlXbW=oJIe*ah+tl=u-K9ahw)bQ_hQzJ=yqA9!ex#ed012kI`pwK|~&R^yY zucL+bUyRyhmgI)sylg%W$;s-iSx_r=2(Y%X^LN!t1Ay5#VA&|6+5~l4B&gWg35@!F zhBn~aPK>TxlVR}?c(?J|HNY%r;+_6xH5SWhM#Vo(9~VR}{Sxr)m96;6yK6?PYE<$? zfHiR~6{l^<-8cNBmloA}p*HPj>bg_3w}1Ph6$?hR@&=-nnD5B3-mk6|9qYyt*w+=U zNTGNJOq8_}<&*=92c1}Nsj(Q?&QS7KKyqluv9M^eH5X2$4?w%9(yNLh`UUv>2)bZH%{@e&Sth>-&5_{4()YQ@T^ z-mV$obaxo+Te45BvUeen!e36SIFUtQbNwB65uya8FJErC9qG-RX2G_VBs2ervF_ARBej$9|!ANP5D&NX90vK zRfyo|FZDj4S9SZU8jC5x)g|M6?|@o9$l67*B&N6oy%|Cg{NB%=X3n`{6{@J%XGR1T zbKR{_#nPr-pl;P(FT&!V6DZc{B5)>W%tt1JF7+E(z-1O0skY!QO$XO*0FSNcr%zo6 z-O5X0H~;;V_ZHEDUO!x_gU(wS#^TJt2UVwK{g4`}QK89dER;>o0g2m7RKjio1cvxn zWlB5>0kN1(ZYm!y14bJL@B()r_$+7OsuC$KmkI1B*8U|Xqgbf{0!$@>(dI|;-_}fEEG@NjFE7vd!T1KVzL(8ako9kYAyG=$3e=v2`YSabG z$6C@kX!WF@+Aezp2?0nY)K zQ5JH^f{M#((?mDah?=0mn$@vt&InWX*sG{=Klw2z$tE8Z%Y^~>g@QAk8h-D$v1Gu# zHelp$${szrF1Y&PXt?y*V2bi+!kZ$Nmf4FD> zSsl_2Bz+**&kwH>4&f>G(VnIau!&wVg$oI||Vh5OTBN){{=ZhjD2< zO{YdHO!szt=WAM!>xWR){p5)C_O~}7%=YF@wm1LBYbvxsxC^v)YEYDqo~T?SO_5<& za-jcT#?#PkUnAcDziW8GX3FN^zxG~H`vNn6>2)-!CO#C#54H9B&-$|{Rj7}ps65hb;x+jA3)3Lha!1o=-g&Br-!Fzwfa*Clm^cuu+3JYeF2@l zu$3=e_2Ex+wckN6RIB|=U47k{z*<9ZaQ+`_8@H7tzr2k@ZaRqWgm)WN)j)j#M6V|5 zuzq0lZp8pT8XhQ(8+EKU3fyfaI!PqnnoRLUfFpJ4MK_vz8}%~Z3DpIsR5l7UA6mOa zsN$@z4n)QyXF->jW-GpK@1;sO`0l_sn5SrfyxL~J9Q*n?b>tq!GnatO zA6@V@Kq*GU1uO`4A0LwYo5qeegF+5gMsNblcu9EY(aJU00QVl;-4FkC%s*&BuNV5( zPUoaMhOaX8N8m{fRMH1bqOzW8IM1TTLvaFGEf-c(FnT1mhqCY^mdlZaY@l-KVx1Kd zSIOD2Vy(Zjk`o}pe}&hp`_v)oqWfxNZQrviv;ib`x)H)J0WcbEBW(u!%h@p3JeRcrmDW_7w}ZKlrvncO2@^$DMa?{-GIrn~>43V=N4HE)nh82>uTfvtqv4~U$um7w za8+5Q*-9RBVjrH1d?eh{20~p)SsT~44BRPEgL=h>N!{DJ_FG@Rd3q8stBDz^iq6R( z5>O*e|1IDWEJC70{hZ5=;>7W?{PYIR@t`~{LEConC}8?-nvhhC-d zmZ3{SZ%U(p@(ig6CT^KU1fgGo&>{>NZM{}uTxo(_1fBLFB#*B`_h#A%&Xe3Z_Y`X3 z`%s-0;cito&q4$JNd*%;B-p6&nsb@|5eaLS{Wwnzx5!ex1Xu&4GA;$ z8hZWr=y+}2Gn4Z>b-fjLfX+$cqrV)YxIfO7rc&6IFjX@A7|xW{E0C2x0FO=RG|m0_ zsjyWNdjW5F412@b`_c)`;i;MOZ)C)f0&3ayJNR|#+bRW`s{pS%ELQJ?&qgXP}D2!5k7B^oB!2ux6LvBDuyKPXMH*vnVeAj8t@VGofVx9@u>n zMf)u1h19j5r7P8C&#(Xnu4VXtY=ZuefM=b_W6-SuqbnbPZKG`(tWEVTpw!H>sfR%`fJ_btsW==2XdC370346A5Ee?Pn3S;4@l3KB&FX z!%JZ|M_2z}=A|(7m!gS+1s@^c(G^F-Evb`@0cIzpzCe-f1uw-1tb`QioToz&n^x~P>fZfbT=i=Gs*5H{Vn-XUc___P5*-pY?)W0-$YzBn<7nWL|;N@4$HqyQc z`eBB320yfXctCl0|WKn&Kg~)s@IF$2r2y7a@HNp|_e8gVv6tL4_;1JV^=x{OVk#96d&~ut1bs;6hehf+*)>BR$O~xxF%Z#hvOwFAsP)v&d4q5D=xj|y} z-7;(QZIKv<}+KeE%4q1||9=R9F8v_{8q^Aben$5LGc`WcRYY;uJd$n1Hj;gg1Nh`jurWT}dJ#~> z;_@dp_5yJFPA~TLOMX%3X1O_FwNcz(-vhNWM>h&9^HoU|a69A*w?lryGiVCMR>*9w z^*6{Yx?!rwHSp<2(8?+loH|MZGyCtMX=cmwxU_(9`AGyj0u~EDdO5vr&lT;#@9!I? z(>ioRVoMKGvHeV4<#Noj$k4x%*FAXlVf|?M*tNw#vYOy;->@#)J`x;`35b1!17$oF zoh93wpdL%y0{Q1b*$egKqkPa^2qaH|;B5Mju9{qD4z+XAKemQ>2vs%`%?8388Nd-` z^lfLjm3?rp65Rdp@%96*Q#>CQTtPhgVRjVPm3&ZQz6BhI-Beft8U1UfVmQT`2t3h7 zlCxyJr(oIM@+Q=t)Q-z&$kb7^Z-;(ZW!;%IW`%0tE7Ty$<<1PqA~{uzdB_CRy0B`3d&gq@E(UUoFSDLc~u1>8^ zgovl_yVHfeDEtNpg`lS{z)gD_hV3`~h4vfJ54)`M%81#Q8v4sncUXd|ua=@N*U@|C zmRXPiYY6}xyc=C&B^rZN5-pKQsiD13{2=hF9*hKYJqDCfz~xCRRDCueF~c6Nk>l6x zxV%y7F?j#dhnh&{9UdHwvsNA=>xc{99#%=rp#al z)zc<_u&*7zACY#aC$e#=_&Gw(Rax{xUbwCu^`%(Zyl8bV*6b3}Lyhdi=V;Btvq2IO z@sac8pE(0+B;I0v8t7|2Ns3E=*$*|d+9gtxQDezOH@_|r;>;$u)t4BnfUOn5zdn$R18lkqa@Fd^Ry%;dQo>RICc%hajb#ho-D!W8Yozyp*+r)z2d|p{UTy_tsrH(+mFBI{ zzJS$G19E4lDX$J9iu@+vUxTl?nIyiaMy2u^OeMLc!a`nB3kiIZas`z*wGUY+fswVI zLid08ornVJexxvAfuJEAJ?Sz(0TitAMLVwMJ%#J5kiLDk-JlDM`4808H# z4M0N_DWyqF&n$y_qr7@v4~Uy6C`h6n^p`@@(0HhcKmw1<0JX9lCG%TrYu|{Al z=VTNtE(S^ws_AqRoO~edI=+i~=eZTs-t`qzypiGq(;lNrDsjycz~f7R*~D*$3~fZW z-E2w$tH0_MbG$5%JLRf7U!5w%2|n3D_i(^Xr#@(gSvt?t%tvA1A4L&zNIjOj3x*E` zLea21GAx(aWZuzjCC0n^bxfv(dRmksfrJ~*#)-sC&zdQ~FA!XBLm+;cakQQ}+@|D`ZX^AvQ} z`BDM=pZ}QLZ&xX%^G8fS_fcuy_Lb4{v)E%T6ZaE)${yOULofWaot>^@IOE%8@Dm5L zH2TAkICP9Pl)Kn=Kmj;lH}kPrMLK-u<+%q<@3MV+IiKzd+&<4_QOvk z8$jsqX<;|_jsh+TFM-iWIlA)w)Dn1)zgs~~CGauhBN8;+AHk-bNntoujFz<{--FIg zGORgZEx|wafhPj==FKjLGL1{oF@6+5B89`7 zM9Cz2;UJK#0X{1QfgQ+0?&M3LV6dH6ek!dNsjvlw6n1arl&6{Y$H3tie6*|6hWwWX z9s7@{jdt#|UyXj~>AAW-49r(!=wHpB$Ip$W!anR?t?Mu8>4V6@{Z!<>q8ld(q&5#u z8+GQQ%Edh)ecLObIgy6~r%3D*OV9qRawND57zq#jY?{w@;>&^eHI714dbkzc=T)6G z)b%>L9<1IqG072{x)iD(tFab7bQCj&AvOz^dKcZ>7dya~D~cd7U84D1!~f6=pblb= z)!M4~{N~OUI6*ASoIrcoHdjAnway+GjMCN6KLzKnTG4P5c(c|6?tgTP{2T}(WFZo8 zDagc8D06upw44xf`UQ>CcO}ams*&^9W*}2=+MU?OE&_!tVE=9^@f<(es|P(XLClNL zjFuTI`A@;ESa9TFT>h<&(e)FosLO-?VsykE8K(_B^3Z=o>C#TH?xYRxVT9wkV?H|%I)N}R1P}|Sc^|pt>zM*43q75<<$*&AxM3hZzs(eug*yIX4 zW&-5k)y3=Es?ASkB?_d01^xG)^>pSaj0NBtqQO21DuEh{sRwohwIE&`RkFVf#$R6p zhe?Zq{#}4Or+E@wF*P=0A)oQOQB4`>b+JA!8!ZUCi1ghzmR|*CAEpp!{tYnBuAWr1 zt?T2MvLh71`&Uwmo&fSl1hj;CGF&Uyh!=g_LfaGRiL++5tbZ5PQqN|>qHMMVp9~k8 zhgOS~6)H|@KNwIE#&tEFeP zX$XT?G%kHvavrY)Y!+3HBgZ0rXB3E_8=Bco!Gcj@cigZWE)s5Du)h_FqDbA-HQ|K2gb4q zq#IIdPD5JX>x7n%DJS!zg#EDJ5%rVHXb^1&8xegFX)|?Z3+BFkM7uMHegi~%bijUR z2~^QRe{244x9!{Wliz8r6#%pOVM>0l7vStVeVW9k6ZllQ#SpgHyM^7z+6UDf!0(kF z?W#qf7-L$BBbAi`+aur0zRg$Fxr7L-KKsu@XT)f94bD!>hQg##h^ksJoEYz`j(fLwP4+$B|fRXAnbs8w9pE%|sl z?Khzpa@kgA%lFx{-u^eSlKCdy)vS5jervTkgB|~*+qna}=a7JTF zH9P}IJ{p(|SdRj(2ZAZ;C$Rxw>;@9Is|R-5Mjad73ern@c6FlR^DN;CQ*L)y!+pmV z0=5~!Uv%KGi@qJphdNQ*jSzOP?>Fu!K0ephuSNE)fz?P7@ZDm`gaSz4b6r;OGUJ#wFvbu>_q&1w^axEs%A3MzOkUkpW^N z^pjp156t>ILYI;J%O6XC*h9lP`?N=6j**ezVtjg&rPuSO1hC>3v>y6R9U@P>y~%3b z$t&qe5vke>dDV|bvuH7|7kbvtj;Z8-m!*maOorTCBS9l1E@|p4$S~cPK(P)q(cMvT zWX7zaI5kB-DkULF{mE~Q|Aee=_?GquMn>tK$i~( z5QAmNNpK2UtNA?vMx0@6Cnw2+rDH|XsRh?xoCg=O@=gGx@IjIQ$W>^6<<}?j77wC#=FD1KuHG_0n~)u zTNfE>9Ja$JrPj`Ue!Sb1r(CV{>rs*Mc3Rx)g}t=1)wT9A_qB$O`=0gwv#}_Yv?E}|Jq}fZI?gu=!v`C8cdx&e56nuIynawF>fg3+k@X;!!^wAhf5^t-ob9afXh^ zn9Z*gtDDKRjdII}I3Z>@x){wS0irvM8RFhxh}#UXFYc&;yout!nB$XGT!0K* zwLLpY3AYIgPCWOa1)^TKIJ?=pN|0E80e(7=0pc3~vA$GY93YWW+~4+XNnC?|qY*ZC zLRC?=Hjc+T`RE`ZAJo{8@Ss7(lWK3--r;Nj;x66-_eq5DSW6+G1{|pKCqmot83)ql zp6SuH3&sa!k+cBT4{UlfHzaOecrvot-Cg?|}f#mAPYce9xvs%-l zd)~dlwBXeXKWFQpD|ne*uA%q39*{IHHh)!qb3O!_H_p0F`Dydg%a#kZP|R3XQ%(y- z{m^E!bv2f@W$LJbpS6cPN5d)Tp<4=Im)r zd7!VF!zMwv!EG}s9XmC2`tUxmTzIL*o@#V9RX%VO&YRp#G$(~tX89V}mG?552 z_PCQ8vKbr+h7UZ9TiNIIvsdjTB!Jrsn^D1ly9A#ZUbBYcu7EK|3pJe8&?{$xNT@)P zL(dY}*GFVUVeN#k0%;z$vt>EF1Am$syqD~YRa5+F2hy<~&5NW8?WRD+9lC@T*m~i< zZ0&VbvNOG^p#wXn3vyq<3g8cEf?`2c{3nxdBsnkCdRor#uBO#A!vA+YtWFsY)_D5g zMc)+zpZI@gWWBODcK^Ry9A~rzKl6022$&C(ve3roXaG58-W6bE(P0hvH&z2qz}biU z_KH!fOqu^wW5xM1qsdSu%!`me+ZC%i33zYC_5(+EVdmEs5` zXnn_)5`3wWzoH+z=j{DY{*2>J@5!};)SZf2DIFr=zEdAnR(BOGvkoxub%2K&zV_~I z!V+*P^I1U|H5S|kM&h3VE6G~)rM0p+<$9$?!68&GPsE{XKw|r-70XHF;OZ)ycJsVX zH;m~wcHr!VhF>Q*va$2pL53HVl?!YH4^#V*I~xJZbL55nSD@lnF^J4ZI7xK8SwbwN%Vb)&&-;){I;6J1d4s103Xz$~njpRn0s|33AWe@5&fE1Qj`?D`h zcx60Ykymw}7J_yA3yW#1Uvnf5R`07CL;s-gpug%^J6|b`GXdoJJ+@T zP76=HkX8S|yu`?-47@v)Ajjb-{~#9BcTw1ebl-mS^T3Fe1{z_KQO)TEBURATuhqTb zS6W2shj`NcF}HpDGL%uwWBvw@c}ND?V-C#nV#~m;FnF&rpUS$n_|cIN@}6oXya8VZ z_0_)A7xC#o79D`t3~zf;K#NViP*S!I%&hajdAs!ItYahh(U8zVucsXiFUl+0+-Gjy z3An$Wr&v#`;pyPAe=MF|_bn|L^+F@rL6$(b&XUoY7tFR(IlX1dHb=raE_Q4g&XhBy>ck^x}!MMO@)M-oub!beABRw+kzHI_+# z&8u94mvnp*P)!~jKzG)H)UQ-8E&aqnB z^I4I4kPgl)y^u_{I)}wDOL#-<1^#SIg+Utb9!;e`)q2A;Vtlt2ekbJ5dT8ON9}Y;bVLJExcUnM2yJosLcJ$*AS*sBr!EvUW6byWC(wi%0zsLJqp# z;xXc7LoA1{_m@Q&G$FiRHy@bQl;JfqlHUcZyVTex9sT?T?yPpWHu}fN+TpZt)C&h> z2OnMCCUu4bGITh`C@AbJcqRWp!&Rn>?iNe&8WG6%0p-r#<)ZPiHs2ArR5^fsJ%cz5 z5J4k_w1G_aaZ#mQd9`m3i9O~Jd<~3L7{cjmparddm?4-Rr6Xt=Z(&1!)BTl%dT0+O zSl0=ZRa8Ky+9e|ABio;p@HMa9U)xNJL_IM=I#cLOcWK~AtdCR|8;jeq@b+4y;0GYC zC0Db@-w&P|9A6AxXxzuVEZwFh&f}VzCenhEp@Mk7M8zG8`=I0n_~(eP-ygAM1S5M} z@Ef*akA3XThtFf}?{-f{s z&mX+A>7CCkEGB8S=h|DI_^P4u5W)2|~iWKp%9K#ruUWIP3!cPjnIjm_mg@%V>+oW9fQ30o_F3dV!q4Jkf9PL~DZrL*=g`q)t%$ ze@zD=63%fakF#N(FE2e_r&zDrX>&X<(nJ(oy(~2d#v`LJE;DBkV~@9V3!CW~qTHjg z$RvQ7e?2(!T&=02B5hP)Trm=8;`p1Zb`UzzMD)_4Sx>}|uCfkh5Hj>Z$U{b&qZ+*4 zynYoJ?8RebUgJlvu?O6j#;Vnb`;@0&Yq>~?Z{rqPNa}_Bv9;5c{9#5Q1AOjZZ$ODk z0R{Kw6x3vty7NtFai<^tMt4mH!`~P<@M07ytl{v#XKxwQs@+hXNc;5rZagy3$7(Tv zcjD&$wY0Yr&^}8KJ_!H8?F4gaX5e@fcgv7470N?y7sle$gL{kAcvvksS@7?L`K@(z z6|}`sPwb7Z@iUACm!bEGXO?JOmL>P%hh*sayn=NUH#>*C@8ljnxWN5`hfp76EqTtO zMWcS`8wUoBf0uKJ_W51#2)CgP&36NW{P~-xTyz_I{P(+@hD>@DW3+k4^To7i)DLH) zJDJF=%nkgZ_JDDo7DxWbG2;Jr+btIqXKADwY+PXa@4_Sw2J*v-;;i2*(aI=)d*MI} zO#N^HCg3UI`rA;g}1TOIUa*qlpA`>*oc&? z$9iaU>AzC*x9_Nkok_6+m$BDIN}H&eVX zh@NN}vi4IkZx>Yme)@8HPU8^(myll!^!-E&UcIn9wmQemGV_k1gV%#c{2}H|MmK?H z918;5PS`Rg7>Ty~`>W8Yax6|?Dfw`hJL`426%@A(91Zu5R-iY_+9;#T- zhTlThRTcF@4twoV!8BSF>W8?|JsyA&2pQm<^Ct>}!%{R^{YarWM2=3q$+v=<40~aP zYujC@44UZqJd75HdLnFeJ-cD5pVl>Y9)hOS;6jqT%OSv2TY=Qf{^z7dT6M9-Guy zH=7oc`r&Ns>~-uF?fwGt3U5X?`3AblvQ6$$|M>3nEylw?&}K@cKH$?vOu`klKC~2e zy543pPqSe^&BA;lxN4b%;P;Z zKth`FPR?d?;dpRLaYiHHi@>_s^ z24-m!sJRpJk|LTRxiancvzK($5F$e#0Mz+4W&mjD04yb4K5R#&=*0aMXRc@u3=Up+ zW=0FYzZ#Fi>8vJ)k{UO0IipUuw(%M1h zu5NUuMWlXs6rBqqGoBduc#_(Qwv#IZGX2pdssA2NrsX|5K#M>9Fep0Xk9m*{upquZ zortAMbClpzxp+>9Pyb0PwmC8CSspF?^g^82!Mp|CobzD9{aZh&9?Gl+-(WRJoIq_* zc7z8Epl_BFoXBeA{IKx;;GIrobFHCttVMbh7zrFS+-z6%zSZQYJ8G!}a~k3utl_>) zU3L5DI6*B?D)AVN%V+Vo!L?&5OA5R9#ZvD}(PRbX+96q_*1qVKeA0s!(t06a?BPSL z8>Hc8=&eKAn1S>gK-wck9YRS-tY)ha^!ZTurFvwBXycmfZltg;R!#8}cCH4jM=F?x z(+;MLc{zFgm40l)#*kh#Tn2^Yp4pjPs*l9BdDWux0Cq3%+G1r z%}!xRu04T=!KJ3NLkL(zA?(~5kUB{6Z!B2qoqtnOtyRt?sqau9)T-B$E)U&-SwX>h z5JBt{M+!hgNF%2dh~+SC;^iO}l6+lcG1(YIr4xlx)IV8<+o<^4XE`+WEh3QUC%`CR zQ#A;*5$)UEgDez!5jVPTn^OZ|G2pJK9ssfzlubfJTHINgc?S=zkXEBf+O@>!-P7*T zei?e}90qRTS^<|?jI$ibiedhz@Sm~sAV{VmONjmtO%U^UzZmba(Q z?3o0F?tuf?hle$%RuLb-PHS!!P$U8)o3p9GWW{?KOJX~bLfIgC$do-At2d8~0amvp zBc-Ll$mPDZ01wMXOHVIwzeFM$9_R`dBd?-YLmq#=iuME14~fQ1seczuix|2ZW8J3I zuKKw2q9Kn5-Ne4d%{m^E1x_ZXizx|Hhp6Te{priMFfGZ-|PD7q+he_|3{6<>j z>4`7XRn5n&=L~#3H-SsG2FQit$Qd4g$m`QuDzj+OrysfusuFZtWiaG~A@-$z(q+Oh zDd@|jdilu-xGBEdWP=9Yy)C(0T}ul<{jg&WI^Vth1$Jpna=?FTN&F`O%OfQq!;<2z z;q_t7&i#Rk!@w-;XlN}EJ1fu;Bcm3WQ&7(L>w67_w20IXU#7d9k3pmXzQ}(f(nd5$ zu`WK{rwKSLhQa2w7LzINJEuXul6yJ%013~I=3lA%k`|15Vb5$Cf9&c1o9E&`!RUd= zLAi#1V}1)#82#8Tpc>5eyam)=6z9~#IJ17O)P8nC!*p6W>V^5TwbzyTV%kN+ZWlRi zPOvtvVUyLsCP04vztVNf-mjun+rv&yANo?=?co@;y#YSYuX9Wfi(AozCucxbaaehE z^sN?P%Om-{Imuqm-Wyus`y9QvzMZxp>V?;_wbylf!({6kVnKWzjr~r9#RQfJFK`C} zM?YysF(Qh$9cNEL>is+H`7K%?>W4qE*YyIE0iuBeaRWG93>q>>9MLl4ep1imwc|%C zwcG5dc{L~<4Cm;FN6{IEP!{;srBO2&BION;lz9q@7Xg~qh47pYZde&T;%c&M^oRlY zEFXPRO*^N|(GRHtSwkJy+J6Dj=_d>f-vEZhu^dI@&{n{jC}iVe>YDX&_ilOGr(eGc zeU!EeGH5HJei#-9ojXJZiUvNfsEY@YXPpBA;mk&)U7S1s6+m8{VBaQW15AMY2HGab z;fA|vd_xW`B=y6&z#^<$b!1{74ZK%uKC^^$DQ8pYXfc?*H#Ge{imOPVWc|FA<40$^ zQ}w;>-hYIXda9ZdX;G;k-bLqVC`N)~;B``56P@gaj!u^IvL1u@EI}865DjWU8Gdxwmy56QhMy$0ko@gzeHkqz^+U7hY^TL& z!VJ6=hCD~ZKhOQb?_Bz@)UdzQJKLqw^b#&N18ik;J=dv7C3) zkD5>ABt;y6QK1K~$d$aO&nTooZ4UNURNvJ~w1*W6m(c=KKU9m(MUmm24e_1+Qwkw; zE0##X&9i;qT((@O)#0Q+tq{?IPe1gE?)jli43vRC$uR^x$>p{QOYrwifkz*9MJ;f0 zkKlbDoG>is`VH-+?I$N|W9jfXS3f)pv%>jbtqXgdclH>hFii#Yc@u+Y>uSiXO%$=f zy(pFhX7{_LC77skO@f;?aDJs<Now zM#bFZvaf${6ZLO>n5PM zzphnc%`I1s2W^vC@~VZ6a;&-L^a3#am7Y85ob56*@IK8jCBNP8jL2zan_a(&s&Nj(epxT$&{ymSh(&fZd^$VO8pQrIv*J@U8I3` zkt#P5+c{UxlWMqo1_E=FA02=K3F2|JDJ=r^!@oG_Dv)423k`AA`1*7ml1aMDaGpKP z106PG$GL6=GUGbhZDI9C((=J|f+Sij>W7cf{T!9)8x6c1QpI94p`jXNC5DyP)Z4To z^G$$9H>h%L`wqZ0cv(xsR$4IXg@dt!;j_B+i>#S%f4ZK_^owuMFM4R#;Aj?@aT~dl z1Byjb50Rh&q)s0*`5~p)P>znU6DZG`hU@{X&okwqu^(&R7@#~WLkc=j1T2{{vts}` zlOI+4#jC~8sbvG9w9wTHgJU;S*Em~dF=Xg(dc8AYk`U&IpAyw+auz{dq1Z z+ilWlL3+yuu>0~EHqLG6>_&>eeLXO3zq>%t_F~bsoL34U(;N|9Xn_4p{qQ^Xy84kZ zWVa!r^-r=}S`Z8REGYqtIB$6xuzo2I{qZ@nv!WhQ!jLm-ArA*d04Es|Jpk- zul<|6_VOH+gyWtAeAZ=wKo~MQy5Q4$6{EKW~t^G{>P(5>XT^}*`HHP?jzrH@IXZNA@3LrU&#)U4IA%zb(a{P`+ z_?=J6yw6Z^L|^G>PAY*+M4A2Drp_B@5#5Y^zzk9|RMD{c;qc9-8qKmHt? z!wIZ40T>bBNWvx50$;yUkVy@_WQmN|>M+~9sLix^))P~tt05Y5JZ6Zc^!2A+EFD0m z3hVG54S)Ntz&_(?woYA9FFI{Jz(SeyN_2(Q+=u>0;1s39OTZH*J^;#P6-H-BY`HfZmbMz1Bp^MU`OJg zdI+0NsrfUnY@!4cpveZ?iQ@?K1s!f(Piy@x@B2luWGlB%$Va`Z;zLUtwC8K1eo_sm zg|S}vCtEvRm#NIqWr)T3&!J0rRfYFc1m&ciyZ%AIxhpKQatIyzX6c1bva{25B?S%K z-um2S!4%OqD5BN#tD*W>q(noHfHGoV>mkx5?l$z@4}iY=qoW@V2`e&>!3RLLqv86DxeOA0gf+Bssk zE*Z?xTLTkUCv~FX!%f-M&+E6gP^|Cggirx%VXB0nS7s+)koE`-=V3jdCFkY38MDAV zcT%?L#J+ny{lKU{2BJQga3Aw>U5Q)+;XHJO{3$J*^}}K@+u8rsr=71g3c*#5nn0hX zvkOM5pzhi9VMRYJ^z=ep+0D`Qev|1E46#Rjy^_ugrUU|nV*MDJBb)@5s0#;hyF|dU z+8u1-*hoai^A-W`RYBj8#lr-rD5Ac%H zo1`M+40K&ppf4%Cv`b=Mey7O`ObH#ZA<*~SrFm&QIbjE+8P<{si4?10uQIOxAtAl= zvnkt2`eC`26pLt`Fp(DfdLhNMni}2K4EBG4vlDlwLwdI&g;~UStM($X%SBI5l-xl^JkC}}_JQsnC{~J8 z$?u)IbEP25rPDl@Lv2mJ9u$Q}kQV6@U{({V=J#%_wh33a!WN@jlbrrzVJ$FHbT{}{ zW$k}g#h-Z%RH%eSz|8u>u$&GD()(I6rt0sHybE7~Pd0qQr~MlA!_(=$O8yH-X&4u% zH|eR%!j1r=;^@a<-)$VRnN>pmSK}x2h&1iUFGJG7)*^!?BZ0P`= zX#s!Asfj0dcHxPoWI(4M+Y{B4!9Lqv%uPE!AGErY&Deo7yI^vjmo=CPv^%)cVQXno ztsk~dXLovd=kV6IAdD^eo1i*3mHe+1_Ci&@?YJAm;f0qrtHZ&$@(e8u^~2NY3`3^P zHuN^z*HM@SjO>7!*SXm1qe%W!z8c%W&eoJ1bIN^J6d8Q9?uhH72DCcNFQD&=(q%q} zL`j%&G-t}prr<4(zSS)Ws=g=gTfc`_Hsp1@Ab~PX4!Z1Hej45CIs_SF`W%|{1%Sd{ zc;4`HJ8DCjy)4C^<4MkCsoLF~{hEfJF8m_XeP-`Qt>Z;WHRQX->ys_ z^YUXYSH17yyT@qZt{0NeZm!Pqw!gqCnxR?Vq`@Etgk?cnFwnP4Eerrlhj>q?SYO@1 zsFW$`1&P6_{YXp^-iB=sZU?9Lcz}H!2*_c1xWuc;wAn@_j+aut>dA1Gy>s&b z9!v6Pc9lBDy32VM0(`ruGS&i=%<%%hX8_?rXxj03zrP*epUzhU`FCLOM3YT+@_n^A zjIEtvIZo1ei#SXSHlauT+2h5NT~u(PGE{BuME5Ps{vV_qVG7yzoBg@FfBe|qPUmmo ztuIvUM=%SOH~AJ~6c1ECS7`86B7C!5sBvsy&!r^+H(SOW3htiJUNB7Ekv{p!h0H)f zY~t!^Qp#)f&K5G|bl_BcYSAX6&it#Hddgn6<6rod!@eDJOp*%U}8RRJ$YbZOU~~zjf|K$9r&0s!MD;&P-H2a$F+yeatr{IBeuhRet;r z34_0v^A@|XB&qKn!oxFvQ zc-y%UZkN_49O!x+>&SY1u(Tb)QrYQ0a&RC2md5#(drP9nzTdry%-nr7wrTY=v~}(% z;fY#lNzlIF(rx!ArPn#UUs`%oj;9TKXgM(XPFy4Y7dR?Qny%ju*X>ZGJoya zhmCtCtoUT|Y-H0jTfTF`(s8%28>es9@3R)|YaA2i>KZ_xBc^uYkquYbPWOkKYA0=C z!RNH{?AiZ=TeQoLH z+VH@h$h!KP6n+;uyX)fC=)leo{hHz@DE*dB4)o!1Gk4dI9Xr=y)AH`U&1Jshq_wVB zPCm)pc{u52J6wvc!Y>%}TiC+e(|T&=@~8T*Uap$>LF|LxaCW$}cW6fYMcEhyiB92n zp1#b3~Q%Lv6Dy{8ptX zPn~?xP}E6X%X`;e#s4jBM)0=WQ|6pTzEoI~yFc6CBB+FteWAjQ4y0XC2|v3|*~!q; zo?X+&Jjw2duhJfB4xQDn{p|lis`#}p3$kF$m*uqVqUXkzF(+4D-zpk^VcoQZEgj>| zx;?Q@^Y57)>vivwD;t_Wh+1jrgT3>h2kQvB^!%-9o9gl&N!HnwZ2Q@H;Hy@oC!{*^ z@!994e8sM39o0SOYw~6sJ9Pp4XjQlQMvo{i;y&^zBK|6D7n?Wm%LB2EcmUlqKTlGz zJGi_JyHxb9(S#GAZoMzDv7(?h;nZh4Q#(%oDz(Hiw_WiX5dB)X*3wH*-#EB-=8;eC zS%23nZ51cv7A(s{e@xx-bEj%`=D3KQFgL%!F)5D0t&K%B#piE1A`fQ#uwkar+0)Kh z%SPqR5RtvzF&)RRO^yHU`fzEDI6PK>DIj{06EdTTeZ@&!j(b2P3 zDiScI?FLcbXbwmjH*eBRNu>?i_!GhkvkxN*l9I*!AFf>{5Qwo$Ue?#Q_Dhh33zt-B zIO)m!>jPF#Ulim~$ijvb1CyS7gY3V4Of1~$lfv2YW7jpJ=x`1C!;al1qk_9NaJ66> zHIji};l+b|LWCYYsss`L%=Cl^{y(&dmTHT@V~0xpP+L z0NE`9m|eVCP&Qh_ozvusI`+Eo7B8;TD8}cu7<=>tM1tSP4q(k{iQ4qStoregf+2#d zacW3L#^+BnZ^nVB9j6^nY4d5W4VyHB_VLgQv;7}@5pR9a*}^Od-e}PAXs0YnJOC?Y z7c}eHOTHw`IrShmR?CoV`$eNLlci6zL_WHO7zLC38wHh=^Zg4%KQKFiLjF*U6h?Tu zS40!&(rz@re_OBd@kF~0V0OB^1Dcg%Yrv;I!iM*N*|h9OBf(tDG3o~OVkgPtPGT5f zeeb!OGKZ#s!xIjew}L_8Mo?c0cmikd{G8rJo6U)ZuDhIuc%OCD>iHTxCevA)+e3dn zeH_Ei)zv|bc_R${ji_(X65vZksq=Z#3*d;>zDjlmm=*kLCEB;^a#$q6Gwo_Nu8c=g zs7|XvSkYU6kjac?ae{taQ{HeP%w9)xz4q;&38yNpXxT~$g?p|L6RepEou zfq~C}+3zhfm!kt&rBiuOHCWlVlN7_#L)*-NfLd^B>P_lPD1I89_UR`j@>I%nDRr${ zYfx~8GW&)0VbBu+uj_FP^BEZWXK?(|I`YWJ1cyU{{s@q;13Z@oAOStTpgE*TDMS%UOCP5~l7p;Mp7Z7wt;N3;J67!^-o)ZA~N=8o8=L3lU1pk}oW-B8FZ$WpV`j6QB?(!PC_vE(as5!azZ+6^Pq$T*_q@mq@0<9KF-_W-}*V3%epJ_erU(~Jc6g8k@=Z}4Nn;ju91E#=XgD1PH~ z;IlJaG>fWAavWA41?-RAgE1_J8S>ja)N|2FHw|Osrr9-0H{&cfAT^d-rc~nhcL|&*#hQhEzOt0A}uMXKmKb@Mnr$%6#|bKCV4owOSo|3o0N(CFw zHy)S5M5z(G@O=>WOpi{!8`yxW216SssBFUIB^Bh@obwb=p#^S5X60dj@TQTzVahheGFWGkKjpWgZZS4xQe5{i^Ua&!6+hivJ43hgda zB^0Q*9pUnt4E=;Ooe|5SG#fT7tjyrg0Dj?N)VZe+I!)rPD`5=A#8yH&=$l}F7*>I8 z^MLIdI1o7xNEQwQKo=m5{z3bd8Q9v#lub?9h+A`6^974A=_1Us!MUR>5Pr0pgNVi< zTXAZ#md&d8A@xQuo%~^e531!mu-N?vc_ci1S^ADbQzRq~E$i9G-yHCZN9~y7T}5-Kpq3vDpdOYzy{8K>b0kj?z(DdtUlOm(T!nDFQ{D)m0}JCgC1?Q#aBon!%a zw@4VobyY9|gw%x*<^OyUoKRe{RbvJDe>n0Z;@!Z_C>EOZ z3!#9vMncG%u_7IH?lW@xkw2<5-+c^q7(dMr)t&hOks1TT5&Jl*98T?tVd3)-E+>|l z4C+!)YqgDG(KtciROJLhr(Po80%=OH07lvbg@RklK&{;rM?UyT5nh?XjD&c-5^19C z{K&k4W?{|m+Lv51E4QPg;wmtyqa|Yttx)VOzTiclfMwB(Pb}F6h=jEL+xI>-R@k7w zzy?)YvqU-2jj$gwxAI>bpHHIUcEGYX8F&xgiVmh`y)CU;6c&eMXV>0bRdgDe|g_j7|$}k2Fz}YY-_WU5e&mY2mx-{F_?~N>2_;mo(DSfbc zo`xx8?r>w^F&#*>(8TC5X6`KNT#c`&!$O)1g?roJqNraMP56Z3pJRSq(S-k+`IXfO zbLti9PIS*>&p>V}` zoJMu9Z%|M{Z{9nDCkVL2OalC444Ak1n#eVSx{rgED3g&1F(MS;A-U}zv#{bY^mJYr zr78{w&JmK-Oz^}^*#A;C=-~#cL^Y|Ibe&A-TIhRTx(HS*ivQ(NfR}v5b*1Y6=>u>a zZmx{E7R0u@v-M%@nOx)&2Xle}D9Q4T7Z|YV)`6K;*y+e0Fz3}N?4yYvXqQ)T{q>Vb zo(qnE=muLTXk()vG;19&>^Tob_Vh+Gea~TvRkYnbALBcqGu+^*inU5D>KeV5pxftx_mPh}UUno;J!=RQzjBVGlw+?FR`S~ z@S8Y{x4;!jq9Rhh^O{ILZkP&&P>Ya6y3FUm z7~s;4I|&Q)Ic|Ow$H$~!FSPZd zB#ya7p}s6S?g_;un;KTE{eO5{&$`OW$WtZXg57zL_#_oJ`jVNk!33T>hto3<{D$ZM zk@f&4-@FOzJyLRA;pZq2QiB>t6Xs)(AjUz68r}6x>K-hRPEn2~Z61M(66GzM6Zl;k z_u?l%SizbhFPW4n_=i_E^(8ztQ#DU50)#wy!LNJ}RRlk?qY9)3@8t8eqx#%h2vc%? z$GbT2mq)QxKr}3EPYVy<+t&M}E;*UoARli2<1hM}7WUSb9{Z&9?5vQenUxy{-(NICi6uhGz z2__w6+sr@nXf8N(6#~EDB+tO_#$`r<%TsU`;!hZ+#4r%6TEcxN<`4sGo_jN9&LRUi zuqV_ZK$3BFvqzS%Ptrov3(sLrXwg!?OiJxa?_PcB@3B-LM`vPrO8+B+npOh%(P~mV z02TUtYW78+T`ZE#G%-FOnhbbGMlM?&I0g}em{RE!y$S@-^P|89h@72>YaNK31u9%$ zdgqz6)C>WB*;JU>3Zeab>bRf7O0l5Lyq`FP%g^|&O2Ma&;rQ*^IU3_K;nY5m#1hs+ z;$8$_{3CtcAI;0ZDDsy_p_O0i>B5y-|Hs#Q+!U(pryfmP3@_XYPo;sRMx>p;$?sWl zvH~`pCh-gu2tVS6Y<&FMoZ$f+_*dKsy}G)J@V##dONBX zZx1ukAUe#E9Lj=cAJzbYu5irFHx45VJQ4eDoci9=lXo*p+2t3qse8z7tL~ymUmjI< z$-ybe$*zC<U4l}D@0X|72P2oAlu^0+6 z_D9NjNf|4xYjif^81Z{7pMXJ zfDsZuj)mP{1ZhmG5d-#x*E_?q3M1+xmDvaSZLDJ!*vRItEsBexeR(uk`K4~*uAu!- zuj>wu^C+?dvUZyQ5t<76pqefqqXL$FF$Bl|NUkuVVx#(>?oO~2E`;q&=do`+VE&;F zP@M={m1qMd7H|x5S|<1tK&l-Fp4Guk^NiY3DSFUAA7&FwKH>#a{6QcvytEISg+B=l z-GmZwd2)Q?GxMJphSi1#T%C&oeObiU6|)WZ-)HUW(gI6UGYq@SWaEV(+@a&y;xNgb zH9}xEj=`)ev{N=<*qeDY_bC2-wvr&503mTDo-{qgZzJ9bs59Dt4P^d@a3!S-irrn& z<^}VD4klgX?nboFiSe%)68~bhxdktnZBUso_)oJ9$q`yG+gL4_Z6^O=w&`3b^olln zOBTid@~ExI9__r*YdVtKSx#g!@b@50X*4gc4a9Uw#)-SyvMb}~@A zgfV5*ueeE(6Nbo;ntc+Y+ki1YPZPV2Q-rJ0Ee5oc*1eH~@Qa*Wn6QlsW6k@g-uv1k zpV}sc!((7n(D%e_tW6K#QhnKajxUjFZbepg1-#K<-j6w9@;O9!LXEK4NH0(QylLyAKwlokRc@(9O1b|5XTsL5P&9vm zqG1-ooX@XGA^YNi4Q#Zy9=h)stnFO{l@4I@4y+zC0d64Yq<#EB7hmL@bWAp3Kb}s1 zc%Kwt26*>}*JXL$N}eibVXf9))rU(VDU#}&qpe+~`H=}MLQ`Ih%VWk{CbA3SWxi(7 z%XcT1M@vQMm8G@kE0F%vd6N8=hmjW;i@wUs4>ydqtvfuHF zfxRnW`!P#WVgPii3!V9g(f4W0`tysH>*Y~Rm6nR_e}8cD%AV6--E(4Qqy+zBp>Z(b zHV!hVPK+0%<5^ai->9G$v6NX<0Sll4yG~FTIO~5T0?M`1#o6?(dFysygHl292t3EO z>Bxh72A?1giQ!xkz_a<0FHE1C0qkZ_pp6fc;MCm%b8d-ep`~ELzCGKeCXu{AZWvF1 zcsG=`&oN+s33jCfGo~7o%HD+1UNI8TK#^ zhaW~E?#059;qpT>5)4%Gm1zJRhX_CS&@|E^QA#s#dK_`NPee`hmstue43^g$R=F$+ z=;cvER|dK}Zh41k6mq)cxqzLZb4pCJ>8;O**hTeuoj_X>sq+2S8mg+=)Uy z<--_AbZ~kNu8{15vzdc!{m&w=tsCa0h z@%SOM3cV<#mq+)MT`DEM(s=yojR%tr^aUbL+FxuWD@IXxUUZUP1U^Lse>J>! z=Uf$x*l&eafs12#c{EJ9r4EvEC;t7`ERz-9?=SFv!=Xb!%HSy6?K_RCN))9$R!0(y zBq6%>WiyYTD3Pa5BV4>>xMaK%J_(|#*7OdBXBRjO374W@XmqCPVz5N(9W`MY3VlGBffLOkhe8 zgG7NjU9#70*noOjdHiS1mn!d3;*c;TkbrO*J6LQyH@pWyYcvykMy?Me22c}(WAW{1 z{o+Yf)l?oCi3oO=2WgNd&kQV$B%3xR=ju*N&D43T=FqBy@eAr9Fn`Xci(-Kj{a>pKG zQl7HN5ATzuVINm#@a;nzvAf4~=~7I>Ndt)v<6^ST@iv zOcgH@Id1BG4NL%W{07J^nUC`bt=v5grY?%-|6$_a%972Wj%Uiq|Bn2Tg_}LNSw$>3 z9=UIN63I4C7{Hsp_BE-RNgE*1LqFZvO;OMx)bl(?*2ZQ~RkSAH5-S>d4-wv2$s>`_ z&S1<~cs8#r70_oh(WThgBoDOS)5*LK^$T8W!lu=W=2#&vishg#RyvNqjaFiEbq?6@ z^%01pwgXy5Nr>0<(##Nui=@Gx{&ty02O-vjnmX?4P~l2w`?Sb$RdQLwTT5*u)^KKZ z7_tDyDfMhF3%t$Nq!)t1V@UA1e!luJSk*{z@+L2A#|W0f){9o?RLa6O=rPcQQPEI`4itvr0-e*-s<+dF+6a%HkfNhZ;7d6$=^A9y z*%kSPim}Bb>|R!MHPf#F=4>USm}2vX7^JBoRBERF4_aF!1JPIx*zMc5=##KKdf}4! zip8Dr?457~9naE1zII0BM z0T%PMT-X7=`f;__qS#(0{ct6)>hGeq{I~d?KqS70{C|q?8SDTGGIS5I3&(wfnqbcD ztR&17Dj#lD$$}_p^Y|MA;d9@8*>q?I7;$ci%=$nCoG>E@>uf(Uh49Tq&sS|*4ATnB zqaezz7)$>ym=4dL`PTpkW=#tao()$ZnQ1L*#OYKTb!`L@^Ms?J5;FI^Xcmw@;Tt|4 zPSJdAJdIeSpUXTF0Y}A zMoLCok=|Rf2)Ee-KnN|ChW;Q~%J;4f-)&VoIq>V`?(kB~sY=_0P9vZXY+e+~%c26F zKyD^3P0e0m{Qh_-FI;fe7$ddObt_TIuqdk;Ip0Yc6E*RWxY_||*0$kY6W*}*YUw6rLwg-ou>m9u)W-wd1#;ds}6iGn8kqbut{SeRt?DWbQ%TA02#ilVRjYl zmx}BRBs@V zTdJPE(u@4*u>XHnl4RbNf@nnMX>;R!VC?tFf%K@17R&n%2=(a)D6M}Ua3o@l)K?4qzgt?p3tb=8Ur+7(ljhVE6U7*kJ`3q^}0oIy-Z@{QWHT|aQ(;Q+GU=_ zTswg!c4)vhin(K`Dk2i~SE{xqNeHs}&3CzXzS9a8y*nZ`CMrJKg5mf2m8auSi>U-P zKX@ZC3odiWnYDM4PJ8LxX;Np$ZrXz;YM;658`y{qI@f6K!JSGr+w#?+A#VNhzQ4?jB z>f~GDLH_u2 zvc)z(VoYP-4vn>-B=^VNNuR?L;qrEWcx#!&U9HvdyS6!DiYDtVa`Ag)VhT?aMV4}7 z^YsW2Wr$e;1ghPOfuyHs)c6I)dUgE9j>RyJoEKXbJKs_ejV~Oe00S)Z9Gx|V*GWL~f6E@;Ct!8( z-HMk@r-$Yk*mtq;IGZpjEtjUj3d2_+Ovedr=AwDmipwJ=$}JVo$fobV{fvj;O3nT& zH5-WnPW$JrZ979B^k*n+AB%J^9u|`{3pCP*ronD&|h*~;!yK7vL- zF_d~g0i=Yp@Gr$j{k&#TYvUXyBg4?2bs?K4aX0HB-{c9XhB$~1hdDj6rUH}}dg^oS zt6nc!sh3GxTrxGilH~q}kBHsIG~jW}D2|11!nBi0;ODiSNHkdY5O7I+l&Nb4SAc46 z0hga%dgI{q(|vyp%sCxGV~vs9(~+eC0<8eXr6P^>)ind(FT)QYiK1i0Qu7vY`v?9(nQjl7(`Ge}9?QSSizgrA!w>ktC=F2&tSPxsp0{2D^gtsYnJv z%wz7yL;cF(Va=Vs&{m!6io&tdPuq zdW*~&2K*^0s(2|2_`E$#w2TDY>@vX|*e7)=@>{4dBJA-ol5;VZwDJR=0;Pap93zQ_ z-G3c&q1D2i;Rb4-Z3s+4PT4T3>Xp%WP5L!Sgoz&ZUajq5Wi8g^HyfH$)6 zg;`jF1e@^2wgMu?!JIaT^*Ow4!6Evc$V^`p%FCqjEj3|ug*pDyq0E{-L0*rXn%L&g zcA-8;F3QR9HKb{qyFA{wW&M!UJUQQ1i-;3kNav`eS1XTU5G$Q%DHGrr12&s@T&2#} zw6mPMVDQ(Q9V zyJ8Fa!$&p>2Ex;Ui;#Pl7m#-Gqt{`v2sNXd`KP?V9h*7ZogDnw3jKO-GTwh!uoM$5 z`#voS&1DhV8FXQJs;P z0+f4m)LRIlxyI4GWs3rHd2}-Ar2=zh#QM{LnH&!RAp;t7K%f+a^RDoL%NQDJXHP|U zxU}j2IFWnM{YGt~W{&3iu(`!cH*Xt=b%{170o;f>|d|YhUz$1~LyXOCemc z2DIX;{?i%uIskD8=UQsx{ETWE_ z{K_o-H<_jT%P#1|r};%yuSt>I=ZpxAH<=&aYXmKL==;4}7dug};qL#QA@O+?3#XZ-6CTLr^b<$xJMUUK6PuGZipB>#M4Yq4UEdtuT!Q&vOgI z!+Lntw=d>2QGx7GV17OW-UZRo4gE9Q$(qOy+#d-~hN3}cF*MOygbMVBYmQ==^DboJ zc&W=5u@K7}m>I`G^;Bpa3sOj6Cki9peRSOKaVx|5J0-x=)f828dou{LU4%(+XJ>}{ zCgQv||22>b}$`CR#-@jV4+rlP0G-uL#3)11KtLKkVQeEKN4pQ%CW*FVV zcyO+LjOH20o~^1O6(7K}S~c;?X|(y-0dJTFb+e3^Bh2Z!+ZYGoIkS9oamuqG-X!2KX`671*3qC*FmGF5)S8~>9$n?ua;s*iwN zbA5D(Ie2Q^cUK+Y=e_H*oJrN~qwIjZY2!JUN)&4P_OU5Cu^V&k^c3>D!B&Fv(K%J#|CeFp^aYco*pTJC&#ni zGG{xxY0l3>|WI%@M1L;Z&pjFkOKJ&@=ooMksKEs){Mr4Zn?- z6b5KjU|=IFm5QUz7>CoxTaho8{*I=5K{?x`D*SOHxfc%|@Ys1qy`GUxEqV;~dJ{c9 z+@Bn&DSw%uQJbo*E%i`Q;Tq9fHXduLzTKf516m(BaQ8qXBd~4<3k}SGB=%%YB*ow0 z*W5@Eiq;pBV;onw4OLT+bl;u9N-pQ*`2Dl%cB9GOQv~5wH;MF_d@pjONRPvW)VaN4 z?+4iHqQ`Y>5Z^l+Vk8If`s0H@g{=!wv997h-BJw4WRh}B@BN2g9R*ZQ9^2?lT z%&FldYgshr4WI#fD)FdvHp{yHA$=2mRyjeenvHyGn~oC+9Hk8p@ZbasJ&uiJw36^% z;HhiIUWEfaTHd9V*>oKKL3Wj@^migTfdzpI_%7!i-$>pYRA0}0w$>eMz)TtL#q19Z z1+_3nkaNpM3E3ezJ7 z?`cg1Xsw!L7I1Afwvqu-M7PZa7`~2#$bclrNQ}(Lr|8L@9;(v@BQSd^&RsNMViVmO zd8CN+Ior5lq#i`F%8w@xwMNFnI z)oe?ehj0d*+DSjlobATL6R(veHL57e0*wMQ$~UXaZGMm3s^B_-=j{DB=W3emeUSPN zo~&{*Q-#Tz4F88QB@+rHwojY}!GxR|Niub5LcHVTP^E!&QyxVldDM@KVRWFn$8q!G)d>GPd-i8XsSj2ZLXZ7 zNwrX;sXbeLazm;{lMG4Zww)MGd5zpt@6E9v{q6@|GWjJ;wH}4$s*>lnQ8@~I!e}hy z6~MqV2Ii*tQ2}fgM>%QMKcV=%+jOiwXYXpR5ndDA1{uGd9+iDB{m+)qj{gRQtY=>b zB#0EVFL1_hJe9PgdV?X2kX|y4*iZHKNr(4@i=O0$DkuP)u&_Xe4smEPq%S< z%r>fbZ;#t>_v!(n!sr*q7uFU?tu#Z+|K~GdpDZ7U;^F_6{oUrVD3hfqp;jjB{2@!S zySQ0I!4ExN=#)@jrMn@i{OSH)ODlZe$@|!}foY!M&>LlQKR_@cvqY4b**EfS5Z!L9 zdat~tt%igB?bShh#k~d23Ek zjgn}sGqs{g-EK!;cfMC`9q41q7*|%fpHy7Ehx%By?0rc1$2`EoeD4pB@~+CkaRZl8=qU6kfu9y)>9=N_DNFLFF#&*p2E zuf&Yib6$B7m5MmS0Yly~nS^mM=srLFo^l8wn6tX)UB6u$T*r-4xlftwZQSfh zt>|%1%O~|5USIZo69H#oHU9v2n@lO|KOp;gN{6%6JzBs!+DPEjP+xO_{o%r``^Nb{ zV>Erfr$-XX)F-oSu$F}Y<`YtpxQ$#mdq1Pnta3O#PhnP{I%iaR~??vky5yy~k= z^@&}H>cX_Ut7c!`U)3p7JtnRn7Z%24vi;YO!cL{QnO*xbD+}@mspQ>T&c!@*j_2Lk ztn+A0Y47%;uv9Aj^ZDPB3Cj5c;_s z-Q3Bxt1gs?5RPs|#YxBbTMmuo?RBp`xjQtHUuT=(r~5loh-nWGZS_ovJ-1hdS(`dgTDLCy!Z5N{c^j`gs7kUHv8>M?dkptSAUnykjrO3Pb@hROqhhm6Tw6Qj@MJpDwU9@Z8xIz)Xl64G8R zLlJ2{=q}Led8B)DKxJD+y98Hf{aLD$n!e%5BLBo&$cKv1O_7hs)={gVHm8mQS@8uy zQKqR-=C-+`fXq6=fY2J1J?9dWYn88-jIS?@%;Jez!qxrF%!`w@79u{ysyr%tE+%?QbH$zc zJsm7Iw%;&BlFuiG2xQb78(4qN1~bNPuiO6k@-H9ZPsEw{wA3Rq?+QXj%7F7y>Eli# zO)Zbd0}uHrhMe~n@AOK{Gi|(0!aHae(s)La+9Dj#min$&#A#rjE! zDi-Ss8ac?9W`_#$J#y5h7993jFMa*ti2%%Y3+)4C(+_m#Vp+yrIq_!(iJN~PkC=G= zQg=?PTl1Q_Qda0C0mqi{!H=0AieANrNmO~ed^%lU6uv*N?t*>&`rNvUeif(JIiJ;U zmCCIHEMiTARlc11dG7A*6Zt1p^3=S#GMo-vJl8GL>%E6F!!weO9j@!i>HZ_1}pvoEinJmn+0DO#wk z=v%$(kF|jpwE~(M*;#j=zr2B0_79y zC33?{zc<7j{oeR%z_xo&$B$i@Il*_7#Oqwrmp6Zm)+)Q^t0J<>XhT-#nxV~=cUi5; z8LLlw_T_=<=O{s}r*_309F#+SUV7_4xx?{tqR%$yhN{lQ+uC}LiUl4r+}$$GHS`RH zN~NUXI(_^RxccDbW`F)5HnqHrR@pT&Dm}aBrM~k!1y8dhZaaEi%`Hm8qPM=uruuR0 zmiN7bv(VE|Ac4=%=wGh~dyb61nHOQR<1w`z3_aew(U{ zxmkFYJXIa!QcI}a?KiK)v-iiBC*bc%H`P5Y#p4zSU;kJaMcfqL_R9b>r!6rY#CZY2OPvn>K%|74O`g!Z~iXAav!nfBtNy93K^l^9S zF`qpGyp$Y&+Qd{@qwQCjK5DtAVl91EgV^%f1LvDV1=paTe6t78E5K;hc-lSwYNTWto%KtTbXASN0sMZ4zu79 z*;}cKcW%J@O50md`x?W=JqMM29awK%{z7 zd46=4P@vb9P^f#Xeq)u^6`fA?^1G}Zx4wU} zSKnP7Kpx7>L9@c|I-dAAi{`Wl|LAygmVQs)_jVEeo|yoCgu1>t?V)Q^iu6$bLH$=a zuwtKnmN#Uvt=zLftB=EC=qt8@-^DJeeAnrWyimq5amMa?!@jl(Y^40B-#=NufTkQ~ zaivYeb_uSxsy*k!_kHwXk>oNJ54`T~p$Kz{JNMPw?#RsUql&NM%Gk4o5OokZihMav zg{Bti^sU}@^Phg+2r2vAa!^k59H&E&hQP-yC;{WMRmc1}9$gC7Vf*KcYq^AR8fH&k zZ*VBUq-=BuA9-c#yVu-p+nx>M~!cnlRIZeGo2Zi*>~{WV7u9TJnbcSjc{cR4=K zFW70aqqnx~i`0phJb6s)hcMlYBHY<^8tAin^39`0;!=e>%gT&bWxbPEZxtyE_pNV< z$~h+Z`)V42xGJ%Lk#|JU)-&<8_U7h_k9oS?r^WDnGDdh21>3Sxp3!$kg;>qD(+Tg6 zRu^2&xpL)cOn8Wp;+%ZG3=kc!(EQ6V?MR%N^&=%svm)~WmE7Sr~0ACkO$LBIO)OI`;Kn$Q7}5i_dc zVL#n;S))U($134^m-`We>med%eY*pc!RUpQ_dS@A944l`9ziwF>~oz*$G>)IPYOJ6bO&`*b4ql%%QM&@C$Sp#HdSUXaOJ zl!}cJ za?g^IbDoVJE82SIjE?^KHuw$IwITSne;~hqX+W6$Y>>_O_P1?&o%?K#XJkK@bbYlm zMN3#RB-rJ>(rtyDuKUajPe+HYdWQjB3RYil)aB53r@?x-x&OKHUO3C-yU zetal?dU%lZ@z@Q8;Y0Vhdhtnjw$6S1y-r%(`(|kFF~!=eqJez!q`W$1_o(VpDcXRE z`fS8I*`9P%zLnSAnm+$*EThBK{%O(WvZzJjKKpCE$G}K3}##w2$lQM`dSvbmhG^$itdm6j<#MMO6{a#nzLM(;j@(7%;gTE*BaIiM7~r9M78 zt|_zWYjqIclOuc;<8wyuN_O!ehqv~{77tKjL&I7>6h-H?xaWL~imKMMr2FA>&U;q6 z`(zAHiChlSxSN_@bY?hztY9?96_A|-)I1QnKQNn#*92?3LR!Zn^PZf92;1#QQc!Cu586Ruaon$5ZeZTX~0GkUW z;c2`zTGA!IR6#$XkUirL6_NX?WMH7inMxmOVvu-l%Ic?QIrZLGMGkvtdu@*BBs zhsIo#=X}ZR`L*2knsWJD`nLA>RZ6psG52D!bp$qFu?^WMa%8umf&5tXtA3e#4bg|c z(?_DrCZRohE z^=H+$tr@uoAIv7o0B&9BjxFJJUk@7&#}?c^m|}fPo`dl&u<5YERUMu;){1Fr4$>+| z)IP;!1}eTdPZ@JOyt$d_Rb_gtOeSEt}IcNpK%ieDc5Zye2{3Of3>^_zVY->mhgAgXjLCq^)&B zB8EF^*QqtPzfn~tuKg70$-P^bH)N`B|D%yNiZ_pMJa_ngSYchjbxD~|)9s2zO#;#U zHHT$C-QG9$_3XlbU6969PFWQ9=?}f`E_7%tS%)4Up{vF3?Ll+#MV#Z2|4k5^dkAE* zX8mQ&)iUveVFN*UQH)D@&d4Xp&b}ze%V_lv$DcW-TY7jLDkIM04j2SPa~6&}FxLoP zaTDb1-7{>Dsoy*ID6=dCW(mx2A9d-$5J6jPDP7FBwl?cwxT%)NX}t`-A0k zLEHnXMZ|LypP1D8VNxi9 z^#adz&-!C*@0?7pQYQ-OQmD@|Rt+Z~OdcuXG|X!^QP&&f5J^c!-SK{EOA~Q!CC5bT z%$2vOy^DIwS*kB?O?k^ntbDmm-1+gFpjDJRL*@E1Dtputqe}8-w>#dZ><=t)_ZX>Kr*An{b?h=}i}Iezdv!U@En+zjob!5W<^?a$-X43POIIJ_Lgrtu z^A3706p>xZMFwSloXTHiShF|Ubd5xwMThxayZ+g6LBo3kX4dQ0_8+eAi;_HW zN`F_F&b9GmU{n3Ov%_2$bA+m9Ew1$lomI~YI`0xB#B*xT*+gp#&XZrZ$IpI=4XSL0 zibeKT2X1_HTs)kA_?%)D!SvDg%fZ|f{Dt>VR5Ib+Z(q#hKn`DS;FFlRr(4Kddv+ac z`y42_N>JN`8oJ($P<770%#`C}b+-h$Q$VWMbrbs6tCvPJo66`rD%?(GZeN8_o{kpA z3C62ts!WRM8Xr?=pVl95{8`B|Tq6&ky1hE!hdXKg6Jb{6Nz1N$4zn-E-Un^T`BJ&_ zP6e=+1*_0l7{fqu`LW1AJlmnGdm88auvRZx@vCD!h5w~NS;(Q{m;{MduYzy06ls*; zHpezApX=B)siph0hwuIf?#p*EjN1LXIV5C6E5!4)=i8P$lLKe`TEA`?uYP3rilb`i zf}eKATXfD>!+O9k9iTEoP) zSGu)!4?E7+^EP{OQEZwzDd|1IeO^kBvz-!$1d{5wX1}R%#Z2eaUcFb(HCtF8AA#>a zANe@^ibjl9++{O8=}h4}lZ6?e-K$Fvbk#Zecbo6s{d(_D3!K+!5+(CZ+=sGP6u~ zt8+!HVy%yE(e+`w3z^eTYRl?Y1^1{QrN0WiRzetauM4~tMT$7Ot3Qy>_0fcFbYBI_+CqluO6-D-a(bkd{z{P6Zl-_amD@VWnXZf`yN7U2R`K+wC z_WjtV^HME^j?uO$>I&;@%{%z5cdafV<#^udX)3(ZZmXwqrT(3vSLXx1kie%gUXpa9 z!maqkUxg?AeWT-Sql$=9#h`U=He_9UvFTA zssEvMKc&!mt5Zy@t#9B&`i8Yt*&8eBz>u^mYEqih@!OY5?h5rLCEYbAT`0m)Un$pR zTy=_^Xnqy#o}npXX4#>z9k2HVQ{S$2i^tw?UX3S9{NV5^-Apc4U&*YUm5{*6@6ubk z_Fx|HMtNwqoy3{(>{LOxrR>A9$CWl0RtMhMQ{{TdkT+^_{CJ1R zR`We!{r7f7wGEmOcvTPg>&BaAzkh7^6U%xmL2j9XvL#aA?+V`KL*~i&b*tWXpSXp9 zqj=K;*DIgpelgbX>Z6o(PSxA!?g{FZ!u~Wkk74+fTQglnXNs<%Diw2frN_2l^gNt? zHYdEW;|;g4Q*3(e_Csinb|v#0kFD#z?-TaU((XMc+YgYquGgPYOVU5Gsj4ok%NVnZ z&-MKN(r;f=+}EA(=BrqpQCaEv>{haTu7QuV^WIWsQhd%!-B*XtS+bPQHzm^_U8fCY z(fv|5ulMR7wpVPl_o}xs4bc(0*=-iIdi47Cm`d}*b0WJ$&}PNG&e#4*R2l-8$^#wLE@;OxdPWVoWz`E@N{H7W-!bml*~2}N8HD6$@DnxlkV&+&c=`~GA7)$p|5P0Ty#TBS5&neUOp&HBhy#S^z{Ir^)`tZqmG;hgL##! z1x`+2J>FRDzqwkOxb9P3Yy0Ep;?*D3*Q8Fa>Q0%k-gS*$de5fK$jQKI^}}CVl*K>R zP3qV0`*0;PUQAxPe3P^|w^CKz&l{oZtc18WXJT@J!(w`+#n-d#X)|Ib_lx=`-|h^0 zmj31O<#d@$$z1{Li??*FKH_=q>8vNb?!k68Pd@$DqHu&;cueMIu#=!lPvlJv0scz` zx#w>3hvvLJx4FH`5%>FOVp44Cm&bLNpMF&1y87-z{I#$^A^EdIUxT;=Kekl0IKOcn z;QeZ)6T+onSN7npm-?Q2+#`JU#I}o7p60kaM>S3zF{{h*u%FF6_)4d5bw=>#9OY!( ze*D>W^+^el!Y%h`W&S;{4_niNw`ZR0JSXp@2mZ*Bhv4m*9dQKyVysPlJ znsFI}=^8{_=3Ml{R&95biM3{OlwPVu(WO-xd0D34(yCnEEQSo`8X5dq6kG+6?i9ha zRZ)2dUo`8i^8GcfE)Xp>$w*7zya2rjKZ>GRZds;2_Fc(>86K6=Y)6Ukuv91uB5QP7 zL|;SeV9V)6l3AV=P1gyc#3qQg?0R}5t)pUG+1#`^0-C=!wJd!G^4SYntQOk824yjH zsHL5#8eB~PMb{*YT$fGR5i3_Db%E>N>WJ%L9@jRvEgkXATbuBDs!GoEAP{<< z>z&|9%WTN5K)^TIwCj)C?s!(P0@fR!BL;qty?765TUJ2K@gBsER!U%@oM@XH(FT!Z zu3c<=AmW{UqNQc@o*B9tT!!zJQ4IA9s~YJ>pCG&ov%dwO5Gr?nbqrAm6@B7+#R)HY zyHecoB*e+&C%&fy7^;dk_rYcOK-_A#X`CS9ogt;ArQ5G85+|)>+GxKD{5iG5&*-iVR zC%{#pPgPx|b=%whO*U=I*uAPfl%ziwq!*FrK?KpX)oir0OjK_+9foT<(YiOERlPGW z{`lx((68G`+trdD2Fr@x8?vAK-0=-{zs?#xyh!&2(L~!*Sy9^dyp$EqzYfZZet|a! zw_7^%1wlpoLt#-`{0Fr~k$o*Mntz1~qhXq+FYEdJwE9?TxO@iT{f-|`Wk&I0dsJr> zZ(PT9M)87gTxS&SmBwX88(k=ewK}+UPcblo~~LSZb73tWl*= zT(Jg)MtPkW6dFZ%P-rym6B@6dPo^ha$mjfAX@jb-qx@WH!}_d){9G3dbNh3CuC%Q% z(>|u>O4|Yx*&sbv+7fJU+w@#%%enh)b>Rue+@;cfdFy>ab}nnQ4AfHBGzYHD%Flf0 zaMD_*2gkJh=px$to?Pp!lXG2-)>r-|IhXxh7PK$da@RYNpE|oO@}0f}nVc(akidVG zovVS{^j!8c`s00Z*LgwXhRgRozu)uNtIugWz;yXl`Ra`BvmM_(WKRiHs)t-hIqd1T@?(P0svz_hmD zv*TYYgEIF7n|6ubM?X3JL6vHmR-&LfZpS|mAAP78vog9B)hVvSOS7X%v)6ewsBB*irWslQh<#}gAeYJq~u-mOWSzo$jmC= zG1;#40Snuax224$GAu=lfCqWY=UU{pb=CvZBIASGdM&xo3!VkTEDRuFH>EQ@kJJKq z*c9z*;kM-!ud9V|=~0^ZGVcmrwE`J~d*^9>TNqb%6Q58K51TTF*lgLfEfcj?wE!NZ zH=@5SZ%XcZf%AO`+Wo?&BBIqr#qC~%Y}nMrpLxnP4a595r}*2FyI#P`2d5^b7NQ5f-$)1P z#$VnRYFcK!aHSBfMziQdirxK&$VLeU9p0@}l_0GQI{V#^hSu5EeI5clPDDKT-d2f^4x3%otw|Xk##KCUK3z4i^yT-_0X$CX*1|`J zEx^K%;e*3)8Op8`R!c{rk}^E+sN@=*{Xr$Ylm=;oTCRi4!VRlqq;1rJKD#K=(Og@g zdsD--%*(pB=qN(5k$T|0(l##KD$1ZUt+KFW*R7U*jxc>wBRN)4>ZF@XBdt(~7P1}p z_p%7jVV41md2ip)!p?d&bN!>CkI_()+`6`z4Q11K=nHO6TrDj#d*#!>d)>77ZQ0Fk z0_KaZog5rAfIS-)SMC0dF+3{FsQ78q9m7k122QV}xVG}%iDsM6#q0^|26en(`RZoXkhHlBnWaqJ+?qqq z7u?)(v;J6LQo!lUOi}$S^5JvG*P!Xi>5J`PWfddwHmtApFD_ocycR#ai1)rb)4Fz( z%Rsx;pabdq&5g=_ANgm!f1Azimgl~oEN9&w+_UJ$67x)V+_UHw4bwY!oq_neW|2{3 z+105U_xIlU=U%EEZ8R|mmm+&p1bbaKrC>wrgx=GuO(+H#qvVY6}#SjLSW@w~m|FsN+Jtb-*E4V>g`&Z@r>4-DMv`q9L21Y`V6r!&7Zu0UA;XcJ%$S zGa01ZCz?|E(a9+%xlb!pE|026g&TMn78|6ThCZ!OEF6Zs?|{Rwx-EDy?d?ZdQ)Kr&qrIw-F|^c)wlXLZ#9e8^N+ z{_2w)%BQF3xsW3NX;|zGR!LPJ#(a=~)X`uz7EUh038aogA=R10N1=ev`NNPL4^|ne zRmB_S)UOrA#Asri%JY@aPOip~R;Z*Ng+E8g^{X3J9LfBEO03EnW_~IJ>!fcsumlf3 zGNK2rMhrja7;9izD#M3)#?#TJPKWuz1YwzS%~B~dEM3<8#UP=}5H^lJ*+jTP{rR}| zJqgRJf$Y|gbtIOihY@JyiB-oDV4W*1TVNZx3HVcr!Dw9W)q6peC752n1voeHc;GbTCjxt@vE zxl-)4MtW9XW6?Cx%3a5nBZg(+D1WVio>NF_7+u?lbK1Dx!a=x^vJ=C=%D>vZH5PWPEm$>y1o&gbR4Pc8*#ZKvhDq{LOu$W8V>Xg zu=HQDn-Qj^dwJD2&@!c;ZN!|uilsEA zkuwUxGE1a6+Yv15o~KtSq?fW;)(9TtWkYyQqY{Wj>vVEO(X$_;#ooJcq&vi(&ii30&60FXV z)0AIAf~B*$&BO%Dun|``(5Jd(B!H_MaZEiY)IHZLk+cnGSE5x7qM~l1RUwV+=*O%G zh4hgjwhUwAiZ|suABIP3B*7{>Tp1al=d`QHrCeIDrHA8)_$19sWd~RbGbimcSBJ5} zWfU8ut!+pURhLiu-he8mybfSxm7m;{FV=`1x%UyQf-%h?2ke}Vy)Utq$ZKG^o2+A3 zhfarN`p`jr>U5}E3?Djz=f3XB-ko4^nc>cQ49jGP_njoOvRJK;3ek%gZ`*C zQOXtdTKKtGH`9=OP7F(e`rA0<-C;p^nZVDs=cvc93ZTA|Yc;IQz;2pm`mqEbvGXD? z+D&;xLq<8_e3zgI_#&L-KpnuUz})H1FWkUSmG}sq7oA+);(7?DtZzMEy#&?57nLH; zEd>bAkmm_@>61z-LVg z4;k8c2h?V0vtI{pk&nvm`$f`IOIoZqI>ZEO`yHR3TmaDrVUVG%-h&U*v(e4yFg+XHmJRc>wVF`ZhjnP*%^QK}AUhkfkIC6+ zIUFQsBX*RWjhBj1b~awJp3}4O6g^1K#w&#?YwE7$H4n>@`i?Y(gqrCmtm@oZC`Jl! z>$@bexY;d5g0kl8ETT;;SO?j&;pZrz1ogq^rJ7%QrA=E{l;`%AYpv^(tvgIh^L76` zNFH`->Z?)&ucBHjBb?zV2R(z01gbuBrYtrN%94LF_V(BXzwHG|D_5N3`=eT8;) z1!y&cb(0Dcs`3xJ05l<~Ak(thW?C6qObUjj^OIdyHn^(zY(9QGHOkCkE;rN4)6mYc z4XuI`y_-xQ{nsN-TV8~SmY!Irj$Y;7)L7=qGR>^M2|u>WYwCEV)q>#~WI72+_Ls$_ z8qNCoz#3ZkyiKnHtKze+I;Ni;5qZ^8B{0q1jNxi7W2Z3BRMF6C2=`Ysh=$D!*3kWL z(G`cJ{t%1i5FezaqSbU)M$fS3kT#}Oi5jy2Gpw9`EfSw$d81@WhKQEcFpEZr*7b(6 zMtBK7)SZ&|vcU)ShFV;g3dy23_$adzFYw3cTB*SYm1NAbVZ@SMZ0D zvLil9OV!}omR4j(Towhhoy!I{;OnHEZ%R)YSLNMo25M;OP-F8-gKIAg>nP)@RG;;8 zt=G@%q@vtPH<6wP9^VWr7o(gvidk93(mF`+bK$)Uo`4?s(lqqQnWn+DH_g(+<)R@Qqe@Q+m(EeX*KP1o9-{`Ab{X#}<1+1y^)!KLZVl?XqV$w;d5v#} ziv}MQux;_@LU}1hFe$A;&9_B##$`e2Y=L4LA{K?@j0?AnDmbuZJlTZkVFe6JCyUxi zphwQ*Ov`-w{vHzD@x{UP^bv|koOEZN&9uwSc<1xXxX%@gckYWbZig7gbqHG#y;{=N zq$b-cInsmpjE0u;txs}{s|nZShUyw8EX$&r+)NL0<2JM`Z|ib1{=964TIb_rpXS=F zrI*37$*`_VoTX-37wyZAyaCFlpSYZ7?bffsYecC}+xOg;?%aPg8IyJ+bPtS}GLcfv5S)(sE zTAEgEtTVZpRte&Z+>EO_wk9^f>!PlfTx_)RtgH4k4lmap>#E(lO>Dw9>Cx|ZQFsBP zOE6T)tCeNlBwi#(TGt9Mk|VCFy&uzyL2H#+@`~VK3|TkraQtfUSvPr@+(MRwXccMW zmz6-XAicceWC&SzIhdBitHE`=#odt>A7$8R@KM@oGK8$V3Y)UD)eWsqAaRR5e3Ub# z!F3>G5gqIxyEOS&TB-)u;c`WGzz^ja4zeRYDh|M=jYHl=`zyn^PMcz{4CAA;DGe^C zT$dfK7RTr-WqS0LGCfLz!?et7ROPN#h;2|VwWU=+Tuz+Qz{78p@lm>CGAeA7nsUuu ztf5DN7!5xBMj7w8``;H|MReHFZN2!$Ok289raOlAOs~hwk$9UsA84jsaH56tKoJ{v zaGQ!~wT!n7tdfFxADI@u{+{u+p_Q}0YlLYPHoi}{>u^J>$c>^v#+6gKZ@Tf+zf~h1 zXL^WX&UO}}!AGo@@wS1>Q1&z4HniN>`tUF=uD&eeZ38FOwhs^EA}`K9znE~gpl(ab z-~bLSw~39C_pur_wjeH{ud&%*X_XJQ4i3<95^Y;%+J+Wh<7FvfTII;inQ0qXRD}0k zZ9|JY=(va5`q0o1K5C)qBxt0~<#3-(*m$!=gBhaAfHoHq| z3|U)JLzr$K)rMYF!?ww6Xyx%3dhozrfb^E4klHrtCtRxnZc7rh?b91tC4jS#-H^as zu+`YcZmIK@7TKvRU@b&A(r?l`D;IumX_4J%zxQkmtCI2_h=4EzBJ^|71+0|5ts)ez z%8amZ(W)}nqC)bWt}_Tbh_Ev?GU5r?+3$CwCuNTOpAP|{(>+p zVg~#L0T?Rjuy3NjAH<5>spb7(Dfa%WS6&dNrJ2}Y5X5(F$nh5h@O{zNaC<|5-c}hw z>aPfjGNY}fmsBfEU?kipWtTg(n=d&TSKg9!ENjKBRXIWI`Mkrha?P%TiE@Z4N1kz@ zp;ZzU3v6dvW~uUkMa1`EN)n{ERV5CAv8Wb1b(*e8>v%mn1+bE%H5<_}O=H+bO!9=~sNzt}MHMktds_UsL zdz4M8X?&F9sKHe}$MSjuzOTwR5j0-tZJ5-QM46>0PWEY;H!!X5DrLO8v^2CFPS-f# zP!y}5Qi|J_1ru!wZ)ka!Wm7of`zD>8UEe@&GR11qH;SS?M{P?#ui&GzYcH(4O>byb zy~_0sG?eoa+3A|LM;jouYC8-2FEvKAyX-;rK zwr|pFc{M>8mjmg_20RRt6gQ0zGUqn5Owby;9hC)Gmu^RuH%)nCBiwxLn=+l3SC;XI z60EltfyPpF47(DkY5I5%@Ug-T0hhEQ$#;`2QSVpJ9lk@<{anTIRq4ALna8?L!IpF$sTxbe9ooSmpWQBMC5= zIvU@C<*t_3z{Bn4T(1O=Nx8xLZj<2Q-lx)WmamA9A~g*+%)OE%469^xR(OJ8aT{Vu zuz)?}m6j#BLw1(8m^Ofw-K!C&U%G@?8CK!LH^GhPF^|TNX&Fap;|DYr-4mw;Zd>^X z*y)U6RlCy)2Q~Cy2muB$x*7496~%nL&=A6CxRC=>Z-5Vtmw`cAMfKEysg=lr{0!^B zVB5+?pbQMcY7~pA3k*WHPGb|3yG&i~0ld?JMb7jd{*G-$cs`=YH(=dsU{PKy_YT=Z zdKj&DSQ)`PIsx@6$xV0KjUt7pbL*xcq>pN6DyM;al%JE*h5NnvqHK7yKR#j!dw~bv zo4=p?;9=OwK0Ri`qpj!RcBwbQS@!uU8y@Z5>MQMO>+;Woba;>2?x(|}#~$tt@J?^S zLpnU#zSIxDpAV1W>Q!QS>+;XTgm_PVzaLkhOAVK<$M?G)pAzD+$Ha3@T)LhgdPU)7 z?XV;+U-NYirIZq{(S_RB`0(QXN_xWOoOr~Jgr=R1$V+r5#iJd*FK^k5&hbZ^*PH&j2o`D_1?&TUN81BcUnw$ zXmXuTriZ1Ank`R#$=McV4%asxI-ZrDGPcDC%3EIrTkab4Ur)AvwRL)W5%2v#*M04+ zsNO1iD<1VG%aRk?@6SmO2X8?)>tXxg_v2mn&6DG?56OLt6B9u1zroP8MRyJwShka$tf^B)M|@DI zllD(1E)(qJj7BXkbD6p9jO!9BCOhMDP)+t&V>V8DP#v(LWuZrtoN4V2kOe1tesa~h z<%V78iOak!IonT*tLth1_#0dnZ*DmzFZNvyuu z%3Doj<#EzwfX#cDWGXY4f@l@}XPHJ@TFthW_>6IV*XM%6HvMcI4KNVE!Sx)ScTsLp<6-vQ(5JW@1L zL#w6~h0u4_{1zU~uuO}RNT3g-RWx1BecjTs09;iG;wq3W-KP7?6$teAToj4n1?+j9 zqDT#_@+g(bm}nIRa=ZFociA=KW?H0ANA~z^ag`_AHyljst1FY6@j(L67%>=Rg2+f; zWZdASQiv5pL&wU{O%B#96-&8>z=!^Wrhy*=zljagCR}e!TxRF~ zL~F?m$m|oBk;nu;Cnq5IltV?7=i~$}t;zyg7a11Am!^sp7)m2u6rdnPMWWyvZaXDj2g9<~OT_ZJcKZ-R?b3Vost5S2g(!fR(tAfc0R+L8U zbArDH77?3vUr6vNvzP%)Z_Gl02rSKD$wV6Z=zo4ia|}NxJtDJH+=Xv!&Ur-a*|NMf zT+G}^O{*kxt66!tZFMV}vlz9s&R?~+cD|FAIghGJz?`M43gpZcgvUd=QP+Of#^*_e zoK?w@R+S=(&oVrRX)enh7!j0ESlb$YohIMXUd)&&P+R+?p~mnocJ>7Q+4qnT_b z6WrYS(3l?NmLoe>(zX8Vb0B(_lGtQIHnLgP6v%h~Egc12x5|Gb(+)nHLM&P|GY@-ByrOp)9T2P1xbb#lDiln1Va56>N&FrSM0=7$&IUL767eMoYL7E9c z7{qn))*=kz(myV*Tr)(uoV3hIW}-K^Oq6A!H@HkkXrec`a*#90AvW@amF2uh&bazO zU2vv#iDeU<@Q1uZCV53iA1JcAnxG3^SzTJ$C9bS23~AzSU@{7!6UfFAGcNNUxzLR3 zvdShm zGka|{v@Z2&ax<>7%(>i5KbHE8SyKfb>}Q!?M95ANo9V|I*)9AW2brZSusoI6@u9(= z(>t`Zc3WL~jmu0{IiX|BlVrhlh`{Zx-q0#s*3U8xUiY-Q2&LOYbXCi8`t3SlQTPqE z=ufQfWYyKpEg{m=O+9jadVVZvN>-4P`HJOc`_mPLl+4T5w@X zzB{wC6*a!e5DPP^^Qmx?acxBws58B(NN;xsXd2ha`b-x3YIS7>GnFGwRW+N|T^Md% z;w}t+r`xWyZf+7lQ=LrFHhpLiW7_q2L7FOAzUKC`uNY2wyY!H$vLHTkV?mrsQ}!cx z_}r#tH(?rFRx>rNBTls@yOB_Q6x-#Mwadcz$l(NWsvg-75QS6LF?wB)9ekh#r8bz$&S6J^|K5r%O&nl23E z^760>Q_m@Jk`66Z7{ukER$&m=#c)g*IDAAIc3Na1S~;t@Bo!XknrvWM1=gj;qeqlc zr$ubWP18f3@07358+!1UbZC9<5N@txdYKE%*z^@TL=XOw4sFjJq78a_oeT1xeT5FugTJIh z`=~>($xp9yLEZ;{l@7s!zhpgq-W|}vBE8NA_h$MlbO#^%{$A%gagaY%_7KRflWBqz z0c8E{x=voPnPnS(M6rXkvRD)Bd=IS7{pvW`u&N%gwF}$Wqi(-@Zj;O=l~KgntsCA$ z-msN7fX--(xO=kr9zGW>(w1iyR6dR@7{Af8LGvM?MsS!@X71OsvuB!aJN{eAfvMT@ zRJcc|>YN7Nln;*`zti)BGo?MeNEce^&M))xDB`S>pIyu>Y+{w(kJCwa<&UUBmYX77iz!{G(y`~;mWm1)A6bQLkj zR?8mPV^HZGo0a(qiVQS`Z0a7^vg<%*{9ft`o&IW8*d*!71Cj0(tb z1)?C3F+t=(X0esqe@^j9Yu8Duyf?0IqE#BsqHdt$q7C1sZf;we)Lq?Z`=ay)Y~@K= zg}6k^h>UEVYG4)M6g48VX2=pTePe!aA_&h8-?_} zjm@ixHgne^=5Q}-YYWS9^kHXQx=i`71CH~h7ZLZrg zh=|M7xOEf@9^oFjUn03_T*v-fT^zg#Niusa3}wY9eY;vms0#Cx2j%F=K5{aqb4eOH z88^7jz?mH|5l^!4Up{xVZ7Vt#0w;P-vL3zPm=Zn>lcA6-PdQv}rMIGwyo~Aal!ji$ z4K6)XUFm@1+}VBCo5qvG^Se&?oPr9u@Dv?{W8Pq)b`%Da&@wcU&dM9)&7X7> zg%1+oXX7#-rwa%(arFZD z5CNT%^w%|iqo!^3(YvD*briq)zUyeC7x{6TU7du%98qG7NcLUshRPUKN9IXdj9`qa zBQqwDkz<6o9MU>S1y76gAG}Kyw{2@5yxE7eb`&!&bzO}cwaBV>mZyni!K_$vh(Pp1 zxIOy_CGhT^Cxm2tJEw$k`+!es$YurQjP_`#RhE0g6kT+@1PDh=U?ms`3GYB$#JSydEewRb%O`f&roy zCYiFVydHp`jrYB1%j>~#`39Og3zmSPq5B1|%KHH@EXIxh=QO>v3`=nX`{K%CJl2?R z;X#dgR(6uvLQ;Hb{G>;b4Lp*&G_w1;jiS#op0&JG)KguBrMy)&{A7}u+~BRM?t)8z z8$qi2kSk2Lv?z1!`CJ-W-I>()s^%lDJA&paVVYl>PP_8s_9G9;AxmB7y7w)ua$lQA zIjK7x>JIpF_IRZSacw-5#~ZH|WHVZ%6TjueZThK#lkKgVA&zL0_d?~Z0{m?I=znct z&r2}D$_FM+p@q|t`Y)gxBDmqIzuQx_j{8dwPgvAp@pCb%0~V;}qA@Kmx?8|Z)E{)D z=V4wx68kClpv}kJ%jX#L6yDJ` z!>L(eYon_eI@fSfudIAl6;`#SONZq=4Cl&NJ#`nTkld6J$QDMVPeEQSQ&^6A59J@s++R`(_9bORZls;wC3=I&8_JF3-kiSis+;K~lpFWX+NI*T;_IlNW# z!qRh3#Om4SexjVCU}pATmthjd{alWfJ7CwP?QYZGm`>uyEsb+4%7>2q$R0~b=Vuq; zUK2lVw;S766K)*{2m6Hg(>`8>?R9q>y-sV=E}#_^JN4A&Xi92N7=<7Af)UB4d(GbT3dJ>TEXTyX^(_B`J%Pv2vI~!) z+Q|yfyKoAHPD0bF7<1_(vSQbim+6KbBp^Y0j-w4~(>5BEUL7V|T3wUb=4OxJrL!D^ z<0#RPUbK78XqrCyO}nlUUZ+WX1?K^Cf2Cz1pVVo3klX-iv{s3s;kK2b^mtXsIt{MX zU>9}5&$&X89i~rZSe4c^lLAYjqNdHHK(O-o@&PASg&zBO6C8vTHr&Lj=`^1!fgK+! z5guOtu@o}L$k9`rvLn~<&oZ|iyd&7Qx~w*1Q$s7mS9wd|tQ6L$+%Nq#L3)^4 zx1mKIjq;wbB+AXp?n4?{nBCpp-O$Q2*54DRm2a%wJU6u3;+S2sp+~+1h|fBh!0eLT zcp6=?HTdY_8BfY5KDyRy@X@tqgUe(w`HrihWwy0^CDG98O3bb#8d{kI{1Oy#Gz<1` zxthk68)g|I!lj3o4-wiYPF(ud+7LCk98nvh2A8)fd59WXr*z6=)Zl7F%{c&RZSu<( z&rQp+c%iAh!AF<7cKGHb7E8|-8!E?og#-H3B$@17G`)4DMDdSW4_w^1sm2A6ZW-E<;8YuaZ1rg1gd z7Ns*TFFIZ8U~oKfbs}-4BaK5U{yIJw+s@mI>**^rnS7wZg8m>+c+b>?kXJKyo?dXvMfDU)<%xe z+R6B#T>Fd4!BBqUayR5EM?6Sp;G%MFT~_|hr{0E^L1pweu$ z`z!)nG#VskUmp zUhHhMyuPezhcviR=n=Gzjh7+4p(^>*G(6)GTYM7SvMe5(1Fx74GG4z9P?hBn9%z=S zl3BIKhOtCJ-WW^7g`-OuO1#(Ff;gsxHE$>w9u*lOJS4S7l!52gr76Ld6sBd~S^wM! zN4roj4<^x*x)RFiJDHV*X?-wR4w2FHjy!JJk(Yjht8_;`@OZ7a#Z|~{p~o#Q1B-m< z5f4c@yO*Ko)(2r?Ov~~jzMEir?tc$%pdxw(!&)x^D#OpI23k3k=gA&ko8DA)5jT=H z^ked>SV*`g=$8BhP+Yi{cd0)6Ib#K)qhccP0xjy^p}s)1*+HfXVs#~M)U^lyJ<@l zL~z(--FmAd*Vzp%?nk_O^SSJo zypwC}`(1?f^2s6eY*>fC-_?_t-sK`_%5HFZk88?qa8>er%l;7!{hXleqH8*{Z66o| z8d_X+h2zdR8P^4T4Yq0wXk4ncoThS3_5OKN&OBaeiD4CDl8di1EAK4hanJH=f-BBV zW^uB`wxPvc!Sw|n;e{5Je`^;Jmetr<0GxSdBS|VSrNTY+V9o065uv$pVVUMT47q27`3&v!OLJa`!cI(*3kX^-hJq9 zNU==XMRfzKEwYu-ZD@JOaP`e_v$ab=)EdC;K8gk(eVWS-X7inF zIbGQqAAOpPN3~$)jZy=vN!9{nmaUqfca>76h)uApF6vSfEmusNkeME&{8?78-|kTk zrpwK^{5)N7#^qqz0^8tnFk^OdTvo7G?nzxcgY1aQ^1oGf#ASLB+dnpVXGkp;#bi%l zciB_NLdVk!%F@5e>dP-1 z7+^(UZJB!_9G~~4fA$OMK3BBxz*^qW$|c>6rVTDrH{}rNhSoQ*_L(sbt0wJw8=#U)o{8}W;nO*t2$en zA*`WA%33#sHMIO1?I_yd+SFpJ1LGo8q;|6&p&?UA-$c~V+VWZ?L0tLO`<`a1S;Y5E ze45!D!su|hBwCH6Ss>B@(L{SS_;`uqdyDy0GkLuahgKzcTr!!qtThg<)+JtV?L5^b z7Ec@oVTI|jEOCBt5p91JEpJ-CifHqrXuMngf{44|1qy^|3oIA7-Duo-a$ZL=bL_ix z%*=+wh8`q8Cu;$29{Q4yX#uQe&3&hf!nll3cTwQv4ch@B3LVp>N0d3-G_;I1aY^71 zyX(6g7ln?z(kH6O!noRWxK|8(x43$@uI)t>Xj=Lr*nKp9c(A~}_^Vpm^qC&gJv`f- z@ymfVP^gfayU`?wCfyi8!oO{g=FHdrPZZlfwnJxd+K(y)l*{MM`v zRTgYq`nS0(3;0GHvvhDXZ*s(E*iI;6xOJU&+l0Y`+M!cAyD)&yu&T88&?XBvzKf}1 z$vdHj9u8^kB{@WOVpIyc*Gq?fdYj{qZBM!zn1CY4r< z(X5K6oFk@Zp#eT-xXkMWz%r{+x}D2%D}tI&tHAXz1jXLENrVuFm$Y>)`K-#w*zEytbEbv^(758jVRtz5d zwYme3UElA`a~W6KB_7oPSRQ--{x$l;58mJJ&~rUk+L|8K_UO;ezkh`e@q^uv`A&zP z>$&p&7Lu3M=iX^+zD9@e!C%m!=X$QZOI}`Pg#7#0=ny~n3p(^%&y{xD%gc;#|NJ$& zLy!G}-aHp`Qzea!f!S8n{K399^ZU6E*Bdl)~NB>zJnt#>^#pi18d~{e} zXN2Xg;^;r4L-gP;>CkhvcRo?9uQS5^``73YKluGULVVsMz)50#oe#dw*uW#--yOt$ z#nB_D!X(eQV-?PB=HrO|Ylo;In&$iJ8Bja=3*qN(%P z#0|t%k1y>nw8-oq<(VOGRX2b*}XNbGvEZ)c{s0YWSuw->10+ zJDDT$F)T~K+rzyh?@hZ54K7Q6*pTpEZO4$)z0*U&H+73(K?1yOI+RVWw2k;CP51Wx z(Z-<)T>RApE&* zJsP6Ure*Cb6NG8?ArwInpJgX4Fbqvh5li-ouZ(fw&sIc1S_iS(tsz>O&bDPpMim8d zG53Hdl@9Vo(%Y_Psk7;)ukv7fSM2x$Vw&a&s(8q;aTd!n$U>(Tu2H?S^wu(Xs$b(g zOJ5&{3;CR*`J7@PVYN(EV(ebuQmoU}OS^ozVU@v~A!N*cy_3p5CK;Z#YgoS^?{aRm zOe`;{jW5rSb(D8mKXtsFeoDM-4=>WapW8UDI=AuVY+K8rgGo3iA-10fxs4wc-A!&x zk3Bo{zN^CbnJ&VDe+Y&EC#j8^o=3)b7Hv%R)kx}YvZw=LksI>9Qfg4;%wbD1^-ud0x$3CO zn2a!R-60KuQ{BAA2+vzR-FDO5B7AmXkk`1OAw<7(&)2{zG%;WFHL&^)EqPNz%ZTrM zm)X$r*53ybm90Ipd?2A7Si&P&=V+J!r_B8<&0+?g!{(!XzKSh#ZgF^2}^A@6%0YO2zuvMH6ZMjFD>#9-qF7J?o7 z$%-4g%)E{1$npgu9ibkc7;vV`DE5=kHnbQ=A9IF9;*&D!Osm?1<{;D1(mT!vo<>I} zU0aSk0b?btRe3MM&_i&_tU~?k(AVP#Mn`t@4>z>TbrnB1Vn?VH*DuM~&?;HHdDk?w z8cg#YYG`RWtYeS3OiQ!ooK6$gyjn*Qbx5C$%Sag?A1v3UVYgk9YdPtv*D_^>z7Cad1Fh*AkH$JNO+2FFM?(*8v6PFno{Bic_aaZmmaq?^7908@R@BsjmYiKz|IQmV!XuisdOpG} ztxEySJzN%b*t6st#xV_M*oJ-xL`^S^&%3U;eIHqfj$q>IrX^|VL7YO1t77pMYDU(! zun%U~hJJ`~Eo!Nzyj@nzt7@rM+c`)jW*_?&*YyC3UJ%#OrFR-uGzo@dFvpVp5UUM! zlYJsRLu6V%m1NWQAlRd!<+YCMglM^5x=OGzmRtafPS9*QM~q7B%_~697$49}fZDeG zoL;k`brL^U3ga@vTQEBAZ&!N{jJN;$1;m<|OR|{<1KxZa#`)7*``& z^#bNjl_GMz=kNx8j$S4>=*bpzSPi}yb=04PP?C9((H=etF|MnU6%`^bJh9!Z4b`mT zEIdy?^^{H%wK&;5qwBCD;hLthVcLX)Tj}g>1Fjxrem_`FblB}aelj-LOtd`6_wtxm8={{3ro2#rni{{CfidiJCy zt5hdgB>(<3I)o37{*}Jdp=VF(Y9s1IicHhj>B`UQ$D;!^n|NMhMC|u}`QGq@zoHEw(8?@DeKVdU?M^e$~JMHFs( z<3?NZa^x01RJGVF|F_ zH%#=VBXL|3ZhH{t!*@aVle^eX)JiavmbZ0p^C&juDfOkvA|$a2UUIypFr%)=0y)Ocf=LVyK# zscvK~!a5at3j1rrvcy_;v}NNh1Tpm@of{){wX8R<>3lmX6OCETyBpo6?F~F)I|15_ zWq4Cz%=4Zv@_>dsRGkT24eIv(k2x|Ag~S#a(zNHjGfOhhl~PEBNC_ciR){h*ppzl9 zRHT$BLWPVaky(b4S*9}lpLPFdzwi6|eD-qJUQh0Q?tahtK6dT(dim&BynD#i6JzRh zO5bbv>>taNMwySEbh&L`VrTfSOT^2j%AC0cCC6=_6-_8E&vGz+Hg1}G(#=U9YOnT6 zFtR>Bbw%k&t7UOpoY#!{cf+uxM)7A_77t3;(AJ~x;4@`48yp__c|cyk8297VdJZcZ zx*KN7?f%&radT&&+ZMf&Gu_Un^hkC&y=+X$n{^MahZ!$8yu58;mq|bWZFgp+!{gZ< z8XY^<;Bjtjes0}IRbLK0QJDlyc{8*5&xcoh_O31d({oE{ukbg~%1CM{tG%X7CPCI$0XZg1&{`eHn^T4+yTgx0QinSZ}tSoX*%Cfzc^QmWT zi}>}ARX6U;9bbKE_L4UJ2RFF4Kkw#y)1EE;H<=}!IXCyRugUF@GcDhbKlrWe_4{rg z+Fdl;ckcA4jzO0j%&vaCb>G6qXX-Vs{pem~)TF8sYy0v+0RvuqzR}D)y4&*d!{Pg) z!*)7;$T~Ow-rSbXQ?3pRnX`4T>FtBlx=D<_Z&_$uP$TpGy-%i!2r`fb-9ZY8%*$K7^YQVrK+96mbVx&QNnvs*d6@zYZ! z%qorO|9yein!(2Y9p3-E9U}`*JMl#ku(9`by}P9=8qWOGtb4(NxjhtZ6Ppi?_qS}h z;ri8EJ&O(Rc#YU5JJKrBy_HkLn5HhZmgbsE2KcYAe>nVWfc@5C^*o(AtT*w)Z3`K(T1yC-tFAJutG1yc~aVrGZqDM&t*-0!`JPewRNP! zuJ2dP(~lO8aab2u);jV*=X)s$uAP5hKKm|5DYU z+C0B|pdxAb*!-*diG8=)J|6cvwq0tkZkd6ZW-r^DT=9JDyT!I@{O*i93%0d;e&}II zo+9(|T(i*zmDWb>LoI97b6aa3y7S|sHam=*hAm8d7kJ(IWnw2&)3iDX&5f-K)_p&= z5Q(o&TWSLLv5B=D^RaE|#l*7Z`eQsaV zc>bMnflX@c&ffemTsgp|OXln^#hW`j`FrfK^>LkD*)QZ)`p6qz@{XR4BQkcyj#|4t zq*bTmmt6IJG#p}ZC$Hg;`(wVotM(bZRe!a|?T*7t@|QnUtIYF``NoG{7}7L0;(E(T z<8B-r@vhT`td5cI{`D-J*5`qB%)35!796-avhe_~!7~H)%y-+?`atN2BipuL@7J)$ zhxoXeEp1!wp5#|uYv0^Xr4!9A--}t0I-x46L1Fcc(9az{S+u$(pC)f=RP+44$Co24 zTGfAi^P+y~s;v=|R9&_&^23J`FD?K1XXT~QSH|BRb}ZO9tlztzVlq&0S6Z9s1MpU^6@C!$C>IM#L`(Rlclcm~9(iTlKQGwo}!c zT-WQZn-ya(ae4>)j?>oVMZ9o07jN{@tGVG;>7%^gjxAFcq-PxQHlDo1zW40S4XavC zbX6P-{`c9O2cAo0ZT^|m#Xs+Lz0V2LR!@5K+wNi1(iV$j?hkA~Xx^*Lw~zcx-CqpK zd@#)a)F1of@7Mc8ueJ}1UHRJg=&(h;&3eqgl<{O;QfKEyQ4JHOTuGSnA-!+kkYjs# zzf#`IU)KKgybATxWsX7JQeAAmEGsK{{><$9hTXkgpPDS)V)q~{I{t}W`@%=Y4Uxtv9gUI< zj2~W8O{?W+ys4q=fvtDDjmF*%zBvbG_X+CZvDCYrMGf!Bs1*rI202C#IuOt+uS?*v z!<#NX^WU;#=giVM=O64pl0Wg#$!j)uY+|RWyhAJR`rBqTN(~FqGv49)Ah`F-_Vp$k zKOeSe&N83x6XgeMR4g9bDYN#owaz>6CH$?+oWZoVTFlh1>c47b<6m?VG)# za&7*rEva|AO(>M~X?t(`$C+ndE9-qcYd+Iz>cPgor+3dN4$tio(Pu*8`B{yh>2+Ow zSKU2n+Tfd^bEgDMm+rq9mss^~#zQ@mr0kQ^4fSirpB#PJHE(pcq&NE(ujm~3)8}B# z{iA}q?Tznq)bQq9y(g)0jU#M>To!aO)!q%5a?rPIdIy{LQ#1Fx>v=n2^x3HnM;1I< zALhQrJFQ{E^Zq*`PCj@!uz1f<&knZ7zMMIB_0!F>Wo=y|8(sIEuebZRrmA;kv#v*^ zM`qm&Puy!a&^55{=r;i`h7{j=b1O5oZ0t?%pvf7nu7;nVSc04EzG?j$Cm)in*|zJa zQhEIIqsp{e`c_sGn|~?II=5%$^VHSag4b34l{s^6b~$+9Lu~Bx)1mH9M;70zwcO^- zOS5qgf5cx(G3(^hvv%7riz7ZPxpN|;qLowefyB3+9bdMdH0eyusKl?a`t zQ@m%>O(idvJd#*kz4`EQ>ecRfe?P}Xe(%!li$`F-nOW@sC%w1ZKDV*@;AHo*V(jC@ z&&fVln>tQP*wFajSN$f2CKpGg9gT|{zx_^65+I=Cp(N^EP@pM~<_-ZF4pGeRK8SU3EL0RwYjO)7Puz6d7~amV+3w;Y zi;bO>j(yGV8Js%UWVd`mYwwgJi)*{57;SWGsz{$dBE@2`#i(H0JKq=A{t+?p$D+s) zwrfYVYCLv*C*vvhcfT*{tX<%}#{c(TNr>X(kJrOfJ`Yud^)(MQA6Q;78XwXcAC?x+ysFdU7gg(44Ghd1-REWMq)k3w zK3deaN$j8Tw(3yBA4di}YucdgvG=1VzI)xM$aiGLu#5Y8ecf~~*2gR%t66l8Qye>G~dj-&pJD0H2_x|1_D{PLn*h z^oXCE<;7Yb&lY)|`rvl|mS%hJ?^o*@S`K+N<^K7()(E* zhlg3-A2;ZbnP(g0v1UudHqF0s%wt^0px57z*w$Kg*t5wikM*m3#ys4$;%JRv>4(!3 znw#6s-f+-1Av%AaZO<`vf=e^5j#0SP>YY>~zaQCX(RuS#10I-%ey*wRFl?*WxPwpQ z{0@H2{k|aCb()#UG2eFMF7K?p__0C2cfXM8V8=k*LYRDQ!q&7&b6Xj`YS*%xfZ~N@9n_-)(vOUr=m#y?)ws?zGz>71R0w<5k`s&;#Wn9#fO@p!m zUnEzZGkK!gnpE<4gY#eGg;(A7=cdN%e|}N6ec$`yhsMXJOiUh9YxBva-Ay`q8c+YS z^z~Vfz*ddA2E8p<`sPiii*Xx=ea*dcT=P-xkzcg`m7m|46B$>=c6e-Kv@hc21*7Q` zBSwa(GuztSZF4$q_osPAvePe%#`J1>~fp12ytp8Zkp_aqbSE=);>ox2rzhC^2}sdFHExV8^gI(>&~Kd{54JFnjc!Z{~{Us&(_vIofUR zuRIWJP@a6P=E^w_FPvZ5s@$vj-0eSCUfOQh%y!1e$l9YW1noJxuhREjy;+V9y4JCJH)4si8Q$xkg;M|-K96*EsS`l z-zcH^kg9Ih2@g+Njw-6#s=c4rwH0B^7`gmB>^Z7vP}6{GDgJ{NO)5I^xR=9@ zr~_rca;CUUi%eU%+SGaNy$A8F?TUg%6-AscsvVZ=wmZA-vTqKvpT0H;Z**+UjcNL8 zN~7+ioc>^Sc*4Ag=U2`jd!_56kmJpq57;R@^lqPY{dH~I=JKFQGimR|krSFLyOzAK zQQr36t%covUUaLfusM2A?}m2s^K*ZnOWWDyzZzF?%j9eFxxj{2ao+hEYv-?VIQspK z)U1~}KR$2jx`?AMA9-Y)9T8;c7&pCD)!4_q585YMH|pb3y6$nLZNj;w4;LJL)G#(J z{MnW?rwtQYFC81b_PwI`>AufdO?xN!Jc%M0K z3})ROb>X$G-TFJ9F6DZSnAaihABU^2pXoL0-EPlN`w4z))a}zOl3tA{{U^lxMFIXc zoEG8b&wBRp7&0&YMvJzdzmB~4l`!D^&Dip8>pcoH&iblNO*Z8mU1QLugCxP>*7hXZ?R(h=|@Y(J*-QLZ9I+ z4El#(Eh_9~WaRSrZ%J6wvh*JHEN^v8iG8u`N-v}OuV+peuzp?s@qpd^+jMwzCb!nH zgJ-hJZ!Gy3-2SwMr2Y56`5o@1SU$1DO=4jIDH$;(!R_Dn*dBG@+^_NNzRxs%9KGdB zy+WD)zk#+jg5Hc?{5iexk$3$aE!K1x>U+BGddG74^&?x{@7teDi=Cf3^Fw@PANlHu ztHbA(cWl4Vd0FG}>k@h_AD(urSy-!#{RYjVi(5wBL0Wq{?EDgwy7Fd0){xh>UuOBt zDN5I>@SR(qu#Y}IZJnYeuSy2bAKdB5twB*+lH3Y2t{Igjl{QGUtM1~z+_+8j6~*s> z+P$8Sy%XT~B6s2G;Hn4f7Ol8qSGL7-h}ngsWm_gX87}j3aeey6^GV1TlhT6H8%~Dj zOaDAQ>AvB`UHfsJ3ijR@9CRor*zv<+d{X%|?tZUGxje$^O-9bY21flom*v^?b1=;_ zDy>yH=h4ymODDX1Q`YZ6Y4(xWhnF_F8n>O2ule@7RhwM*x2JnF&-_;Ck)CF9a&C3` zndI6Feex6^LuQq&v~5@5U;J}G(3Eul)R#SCWS3SC&nd&6c>`CqAO45Gjh|OO74Mc$ zrcEuZyc~j`l^^Q$>h=%o-fcVVDNP&~QuSj_>BUd|dyW6%@?`pnz5DjOE6c9z^U=kp zWSQ;DqQZB#Uhj;XyZ_}sts;vH7N1cpT7C7zr!isUFYK%Iv_6*;yesnRJ5&3%Z#I4X zZE!OwG2(hmlPyc1jch!`^WRGcj_GF~|2+KoxMly&syaBK(fIey+h;GX6`nKyZ)s>R zgDa~tsw;xqFHEy|d;i(Uz6;;BUf9d#;ojeK7IxAOS@>Xk*3Ly0mFDeBUM<+Idi=4T z>+3w%EuNp(Z(eh!z~jZE`WCq! zi;8L%sXjpcro+eCw}Z_ZxRp6K*sd`X;bX2#uA*|~&8mv>a( z_-B&qzs>=*o{xQ+sJv?3zFOjK)mJ}nt0E^l=w?CFqFsjMKzP|U0H%wU7 z=FbW9-f5-9f1MueFulK_){y!3UNdS(6;=QB?ze4;#C}Io&vUyXUv_uvUfZN)scTwQ zc9W!lU~7lOvf}E>Z&xb+%=P`W#MfhL-pzph3Wuta?LEJJGkR6f)B3^Jb5C|B&pPq5 zLx(zds}_}=ic9~!)XpOI^|Gx`UA``L^G)zOn{msgAox`;dz%{Zl+Ithu4YIqjXx;9r zVTUL8be^~8o@z^@>CFd4SoT_#*QH=z%Trx%Jvbj4wjlVA?`QWZx2uka?wnHeKDB<^ z#4c0xTFniv2rhj0pv0rWe9g&>D~d7lgsRbgqgtLmVEFTpfzyE&q27fBS0^|RkBKq} zpZTQS!2r`GPQGD_vcJd_tyMExT85Rm#9WGL8g$*x^X$XAhcjaPefaY6=|sbn{b%QF zyx!ln-BAy}rUtjOkE;jg&+HTAw>hd#^ahhWCr_)16YgeqbjUSrXq?>4p?cV-Hj`ai zgt}bY8D-GD)`MBDZp%L2b}|3$_V;4J?yr5#kM-Fc;Ad_*OBR*s9=fL3_vtD1p1jkQ zt*q0}rDWOW{4=TeYMZPX3hz&Adp>%4C`GQ&$}B6E1!OCZym;B7XISdET>S-G8alcS z4P7v}?1JgYW4^r~)*j>Rmbpj2#`sau(WB~hKYD1xm3MLf{JOi-X;i(^6K>m za&Oh3^lEOAZ>=`XPe`rDt&@60UHa@_)5bTxLAb%>9|h)?)hAU_ndQX?J6qQ;4oV1Z z*<$>VqP^QjtQ-8gw1@RV_3Fv;F?G6j=&)_ASI)2I4ZZyj{7^KLCB*m2xc@Zcs>ilx z$D1wr5HUWusnlng#l_nl7Jn&t;9S``H2z+0^Qc+g-dBvr4s>-s8{BkDRO;iSO-rp~ zmsmySb-CETr`xEs^>fZQ>pA3p`dU|mA(b6-EpI=oJ86wlZc&lqdL)zHcHTa%GcUk7;amUlm$K2b0IX%(4_>$(~kft4cs;|xO-gt7+ zj-0xWo{hdX=)I3+=dg6kQR!(8HAmK1aH>z%^4lieF7*BFVs7r&HE7}H_c2#;uQZMK zZ(irem=ce-rj4^ohJ_T3*_XcNYv#bkd*>t~#=Ve2iui2EYamF9E3|5+UH2&^B!`r#m z-)7(aSH(PzZ)>J~VqiM$_WR7t-~SApTzD(>LFn;DiOG@p^_XiXhr9SA>AkJ79%bV) z!^($vr=={dIc(~rUX9neejIY_v+spcbBn^{jM^)+4mQt`#m8Q}6`FrwuS3w43M0=k zL54?8KDJNKSv#!MZJpP`)`r3Ne*L;=o#LD3ek1%$`N10P{a$Rz{*lojZAsvy=w}N& zhi=MTTRsZ!5S@NWoK1Syep~q@=+7TR{Z$>Z3@Sr^WP6<0leN?TWV^mq>S1jvegy8# zTe>W%R_w2)Z*MP8(f<7V#A)^2yeH-}o@5!WSuk|nsyF9imKWUpHQ8Xzg7cFt%H)+% zn^rU(RkS?qm*4W^l9a2zXZBx~y2t(8>RaYN+`g-)*KoOv=N~gA#}D-1==Asg>mJ|g z<=0qUl;qgroYU%q7VCOc^qrXXWBKv+3S<1l=S(+RLWRifS27TXj4`l0AHn z-RY6;7Pm{d>U zI_GJSr`P(>8;1E8?%9`bc~f9()%%psizSbGzbVRQm&*1}DmxsiTKFS)Y`BHiW@&}j z_aj~A{n$08XZK~e$Dm(DpJBISttQv{>b$e=wJqyyI=6`%^SbwxH_4Ym+;@N9Sc3vJc1|OZ- zKSuNX-uCG>{%Zn4W6D1G2GtEK*yr?o%cc=y9J9;5)NL2@aC`WaSoQgP-E;NMw!bd;q%@}yQp^l&e~QO zGh>mT^^3(*)6U&*^z=hN*@us9R<5Y{_Ij(yuSomS-(PNzzG8Q>_6{4L!piVno#e~D z2iE-ab78SMIB=5o_u}1;wK0z;-*~_MP-JO%+LhS8H*>W|y=Fz(zje!9W!lMT@3hrL z=awJZVXDFQch%i{<$&bCys6FQt@nb#_-WsKmEEn+#}Ux+^qPKJG}#vzTWhn?OmSn z=1coQ0}eaP%CLwq*;V&_^^C1%VXxPvrdXy{F4|{qIdjRKK_BZrel0(3_xy3?%pTdd z%F<59#1E@|zgfd!kuhg_t#eB;oj&2kCWU)bql4SZ;v@?kT=e^%Hne>I%&qnC_zCf) z+C%0E@QnGXG7TX*F|2 zvwgLO4;;H&ufS$`=NomMA~h3@r`@sY6s1TtJy6gvy4ty`#~d&7SqD;wysOOUI47oI zsZH$uk-;CkJtX=ER25vhLkoVrkKR3GP&_z3Y*4kM!c2APQz-cjMH-FTQpWvd{dAOebg)#P1 zBS*Ha8@2mZmu9(M?PemhpSSNjPSb+F+4q(AO9 z@%#65Y`)*C{71*;m+Y<=o>^R!aO#ZS{jV_%r~2gAwy84r7*>G`BA?tidb{n?#M^g| zPW;m+sX8UEljg&gx^pgFTTrd{%A{Z10n71zMgwilQhMeWz5JP&p7-T*#-U*QoMX{< zt~4t0?Eie-Z^ILpT?=3B3W&VD?0ZbbFyGJs>&9)XUiMM?rg>Jne!d(b0=nWc-+m%#w`SY z32fLxb#}lMe~Z?yx=)|KtaX}qp{a4j?YZ&q$Im{h7e6;;_NL+S7RO$WY?NU134heM z+TyY4fHtu`)}J>Hy3{J>x%r8E*{%CTH?QHM3N|xc*vS0Mw1z7siSb1ND;pYm?$(R9 zPG}%?E3#XXWZ86TwPjoT<+E3vKi;7D@NL{Y2Dn7|>Aw%!{kNN=QTv#z zy|J6;z4Mwf!@>F3)z$8gCYD5BjPQ5X9Eu3BwYmK8R+r|#6m`m5`8s4bvaD9VD;jVm zJ>yF1;#t39U2iU3n!akB)4c84=Wp8AliRy~T|Fb`iC**opWUu0PPGsDSOo3em{iig zwQKRsBi{z*dihtKvRl!0hw(#$2CtgBeYI-Yq*nH_EsK0+xScqe)o);aucK9e8ZLT% zFh&32lqt?l_Pppb!PQ{EXSvHV(+5Yc{4m+LcFw!hq>9e9M*g_m(Q4tqxYgqq4ON@i zE?1N-yLe&R-8cJ8evhdUpV;i(fc~$-Lq3i-Kb5{wdZc7^wwG72OU=TkvXy651MS;I=uh3A zFn9BVOVyi}Pd+uTbnnaceI4spE<7%|F!FWN@5;DOJubcUZJt$hWHdq3~waF?;Sjz0vV)w;Ou2_q|-&bbaG@TUVsa^D}K^`}>r_ zH@^GjJ-Zs@`S%|__I2Ai=eC(TCm+hL@m|^g5f)AI8udTZwP(-Dw|lZ)HCkZnK4MJw z8;u?Z7eqh5^tZ;|_3wL~8M|fA+rZzYrJMgWj(E`iTx8i$x&DgyeW#`$jBVbj*Ui}Q z4?ia_Uod;mjSkNOzvflHowW9f-;{|teP&Syk&DU%hRNPm^ww z`{bwG&g#1&uUo>3pyjP6M+{6$Pi)Y3ditVg5B@wI(D7`Ht^0#-*5)NoE8o>9IpDrb zI`PT3kaD}(OU5n=YHTLgQ_c8c9_Kh>)Z}>3V{`_oZq}tz`-04BV_z+goHE4)yiFpOD~kyv-=H zrpd!%qmLF;WO(KpUwNI@?m{klQ_w!Z;y?`7S2!_8M&s7U6^!b(Y3Kn{hGNh3A!1sf%3Dgecga4UW7gj0eXrpk#|_%k>%evk3*&vJZ!SI$&1!je?C{<@9P4zga5}%Z z?Evc;=Anm1n(E1a^=O}aZbsz0!a5hzyA|JhSu-W?l0opNvFwX5-cbGSU=*vQ=e=a%f<9a-?E zc8K|gkZ+IrpY&*J(9xq)uc2kBd;P7nbu`!NI%U1D2!0oCXrXUdbluaXb&H|57w8ZB zeahFg@MuGy^(#_RDj%h8%1c<|dC+Fv^&mK>@ zv&N-X{H`Z<(`Co4JNYDyiQIkWuwz|E-}hthJvu+sH|XMe$LnTKzP;&O*sa?4;-CIC z@0sUZb{l%>M9R>}hMg|n=FG%_8*6jjFG#zymR-) z*7>I$-PO(YSMTp?T56H7SQ8R`%;SQMQc=;mtF3)2`+{9fB2JAmam>ye|M-K(H8=2V z^4Z)s2POADIM4PxQtekBXqVwqf7MgH#x3RrZ*sGDF+LR3q1j`no~u80RQ(?E?)dQr zW7-(ia%;2AW$KkR^QO06`#w23aMzKu@_(v>3~wBncsHbtO_v=BcRjDqZ+UZOr1Ij? zKp*^C&~NkE16H5vul5^pdETLOf8#fd8gFY}^s|2EnywoLIV@>%Tl#WDFGR-zy zS^d~}@>h;a!Zp8or>536lIPsWIo_&k(}M2n3#(3@Xt6l6j%-lHFRO{)gPK2i?GnDJ zZ2JP~{L0s%3qB7{_q~_XYOQ;{Aq&2j71j;^sp&iXME02%?W*4u_9-6iena!oRlBCU zt#z#lqld4&boQM8?wog~|Jtvw+dprCL5Dx527XL9RO{b~)jsPL$1iUWf0oj$hUJl5 zTetR4Q*Xxnm~v_Sg{U?LQJXAnR&=y|)W^uwX=Ut^xtRLCwAug zQTOeFL+WfyYJ9uHf~T_#zFaG9J=D#xR_ModSv^`-K3((bLE2h;#^SEJuK(Z?b@uD& z{$88Y0?RtQ{nlr<(Z-cco?T9~n{)qn{IeB*xmm~ zsQ>c^Hzye%E}zkO?tX_WvD?Re8P??ChpVr9tLptK2s!(0_uUh_agA@+#K#V6GQU>5 z9#M7@-wW%};%BCI!JK-2`*#ez_BXTC@RD)cOPf-TP49K7k^4VqWVIIt?wi-{TGPU~ z^HBy)M_pRpE13IgMDU8qvhn3{(x`upOAk5aKC(2tw6`*QbN-j|^11!(Kc+OFSDuqH z;^DPG$I@d@mpz|$W7$*_t3?ydN?ZJ$ko{n68z-w7#pc;g6`#8l&X4hI?PR*RYF0>C zsd;bb-w~y^*S3)7w*4}oalri{XZ3^67KG@Xt(aS5dO~TZ6_@V47?3{mtJ|!dC!e&g zUL$+={qsK`?#rMl_qm@*4Znno+b$12er1jS=^JyKcov@s%RCzG)HCC1&}qM< zx6>XUXmWDc+Oq{2>M1SsHM5KzpQ{(O&@VOnnmVcczW=}5T&K6t-_-t2t8Tsj9^V}p zUDPdOO4BB9merYiKUb<=<<>#((sQ3TdI2s`0|x#&vr?}*FI@6u@3-7fPt8(K^>Qgw zJ&wI&9#XsBpD`^Ctl!)_uORaN{#Cnfn#ad}wGaL1w#(&Zn4f>qyp-Jo->0iPpC{ zG`h(Nt1(;jn*qV)%Xj`f3FdOl$4ab5czJre5Aa(gnP`oHN-DKft0Zde|Ng_xYP9=wuOYsk zUW+7B37*WwZ$|gO-#FH5o?pOR53hL={1*?xfARnRQz=pYe|eBfqWZ719PH(@z-zv@ zhr5K#jFt51V>NDuyQjDBbo?GXnJ{YVOfQfB{TB?Gt(K_&|L+?zTO-lvTCGH@Yo*o_ zJpSil$ZV-pf`{&jOd^%BCvu7OzyFW;GKB;W-IpmP(*ImSQAzO7DQbz7{jWIz=OqF$XfO z1dsm|xwQlj-4m%q&K$^P5H_Iv=SwA zpu)c}%z;XZe|vOarjkkU`0w|q*m6pcj19H_Js zJpNPE))G8)PoxqxbD)+<@X#r8iJCc3D~G)f5`Iz=VXFb5j71P`487%&GKtptz% z6s@%c58V@~M9Um#WfDAeid>>)4zvmh9y&!S(J}{Gl>`r+qLyfx1Fc4ahfV>Im;l!~cv#W^YkMX8tySDd9%kd%t4aK(8l1x=}RDtId8OqGJDR7|C4 zVgD>iK~*ZI!WCz$6lA4hDqL~CN z8MscxRJh`7mx1e4Ooc1Xb{V)%rBmq-#+>ak`lB&ty9`{XVqXkbob57jor&aK+g!1J|i^D!4A=Y?p!SR7|BmwDZ>rT$gdS%fNLi_Qi0;*)9Xu zshA2^ob57jol2*I>oU%E8MscxRJh`7mx1e4Ooc1Xb{V)%#Zv6|OkjW#Bp$Q{jrUT?VdGF%_;j+hyQ76;t7gvt0(RQ|VN2UB=li1J|jT3Rj%% zGH{)Wsc^;FE(6!8m8MscxRJh`7 zmx1e4Ooc1Xb{V)%#Zv!uz#-P;5rpk;fk|e4z5!%6|Okj<={FMQ{jrUT@J2O=~QrC&e<*p z*QuBaSDfu~aGi>&aK+g!2iK{X3Rj%%a&VoBsc^;FE(h1CbSk(m=WLgQ>r_mIE6#Q~ zxK71XxZ-S=gX>gGg)7c>Ik-;6RJh`7mxJq6Iu%@(bGFODbt&aK+g!2iK{X3Rj%% za&VnWr-JKp&UQJtPQ_HX;%t|L>r_mIE6#Q~xK71XxZ-S=gX>gGg)7c>1-MT2pQ-@Y zsn}C|lajMt0j^Uq72l}jY*&EmR7}M;D>>U0;5rpk@eNDPb_KXjrBlIm1!ubgT&H3x zTyeH5z;!C7!WCz`0$itJDqL~4E5LOsrot6xy8>LN(y8FOg0o!#u2V6UzM;!bPywz} zF%_;j+ZEtC6;t7gvt0qMQ!y2;INKHAI+acZ*A<-Y3UHl@sc^;Ft^n7mmk7_x1-MSdRJh`7SAgqOOoc1Xb_KXj#Za;0$itJDqL~4E5LOsrot6xy8>LNVk%s5wkyDODyG5}XS)Ji zr_!n5x`MM^0j^Uq6|Okj72rA*Q{jrUT>-9BF%_;j+ZEtC6;t7gvt0qMQ|VN29Y6o# zPvMHQT>-9Bu`h-z&UOX3PQ_HX;%rxd>r_mIE6#QWxK71XxZ-SAfa_E`6LNVk%s5wkyDODyG5}XS)(yr}|G-g6mZ5DSrIJ*{%fFshEl%0dck~ z!F4L8;>SRo?MiT+imCWf5NEp*T&L2h;JT8tT?wvJF%_;j+m+xt6;t7gvt0?UQ!y2; zINO!rIu%plinCn_u2bn$a9zpSt_0Vqm`Xn?V<)Ht*QuBaSDfuiaGi>&aK+iK1lOsU z3Rj%%N^qS@r-JKB&UPiZPQ_HX;%rxf>r_mIE6#Q$xK71XxZ-SAg6mXFg)7c>CAdzd zQ^9p5XS)(yr(!BxakeYLbt&aK+iK1lOr_D!8uXY*&KoR7`~{&UPiZPQ_HX;%rxf z>r_mIE6#Q$xK71XxZ-SAg6mW|6^v=WJJj>r_m|kJvfeRp2@mQ}JVV z&UO{JPNh@9b$nEYKZPsKb``iz#l9G>INMd=Iu%plinCn>u2V4;t~lFO;5wB~1=m%a z?J97cimCJ=1pZoq>nhH66}V2tz8J1J+g0E?6;t7gvt0$QQ!y2;INMd=I+acZ*HxVD zDsY{Osr2Cp{#t?SD$aHlxK72s7_K&aK+iK0@taS3Rj%%DsY{Osc^;Ft^(JobSk*6;%rxe>r_mIE6#QmxK71XxZ-SA zf$LOEg)7c>6}V2tRJh`7SApwPIu%@3aki_#btu2V4;t~lFO;5rpk;fk|e1+G&u6|Okj zRp2_6P6gLhob4)bor&aK+iK0@taS3Rj%%DsY`jr-JJ$ z&UO{JPQ_HX;%rxe>r_mIE6#QmxK71XxZ-SAf$LOEg)7c>6}V3IpQ;Aesn}C|V2QI` z4X#r$6(3sSY^M)0{{Ig%;zNu0lpwfH#l9FHUE*w4gX>gG#mAR8+tuJYl}-iM)tv2W zaGi>&aK+iK2G^;W3Rj%%YH*#3sc^;Ft_Ihsm&aK+iK2G^;W3Rj%%YH*!Or-JKh&UQ7pPQ_IE*cpGV zz;!ieyBb`lVqXkbob76Gorr^@wTvv0ptHE_Drot6xyBb`lVk%s5wyVK)DyG5}XS*6) zr(!Bxaki_$bt;_-uB$oQ)!;f6Q{jrUT@9{NF%_;j+tuJY6;t7gvt13YQ!y2;INR0W zI+acZ*VUZuYH*#3sc^;Ft_IhsmuSz+ zHMma2RJh`7SA*+ROoc1Xb~U(8#Z&aK+iK0oSRR3Rj%%8gQM8sc^;Ft^wDnm4Y*FlRJh`7*MRF(Ooc1Xb`7{rrBlIm4QIOsT&H3x zTyeH*z;!C7!WCz`23)6NDqL~4Yru6Xrot6xy9QjR(y8FOhO=D*u2V4;t~lE@;5rpk z;fk|e1Flms6|OkjHQ+iGQ{jrUT?4LD=~QrC!`ZF@*QuBaSDft{aGi>&aK+iK0oSRR z3Rj%%8gQM8sc^;Ft_9br{!_K!Iu(10kJ)p!Yr%CYrsAXaob6h0orEx1m_RJh`7*MjR*Ooc1Xb}hJ0#Zr^@wT-S28 zYr%CYrot6xyB1uhVk%s5wrjz4DyG5}XS)_$r(!Bxakgv0bt;_-u4_5lwct7xQ{jrU zT??*LF%_;j+qK|26;t7gvt0|WQ!y2;INP=0I+acZ*R`DOT5z3;sc^;Ft_9brmsrosEx1m_RJh`7*MjR*Ooc1Xb}hJ0#Z}`no}6;>qbH}F{piUlr$2gf%K49;obm)f zPfmFTVB3qF@)ST%PI(TXC#O6K(34Z11?b5sPXqMil;;6@a>^3{Jvrr>fS#Q4R6tKo zc`jfPjhymiKu=D2HlQb`JRQ)JQ=Sj#$th0=^yHLh1bTAHQvy9X|nfJvrssfu5Z5^gvHed46Dh zkDT%ZK~GM3hM*^>JVnrxQ=TK}$th0~^yHLh33_tM(*!*^<#~dhobp6LPfmHJV6%{% z@>D@jPI<1NC#O7F(34Z1E$GQ9PZ#v$l;;b2a>^41JvrqWgPxr7ltE8UdCp+zk(~0R zK~GM3)}SY+JZ;dEQ=T{I$th19^yHLh4tjFRQwKdc<++2Nobu#BPfmIEU>}p5^7KJZ zPI>;IC#O7t(34Z1LFmaTPa*W=l;;q7a>|nkJvrrBgr1!8G(t~Kc^+X^l$`QJLQhV4 zCZQ*%JeAOsQ=Uuc$th1J^yHLh6MAyW(+NE}<@to3obrT1Pfmr5LJVMsRLCgMmIf?6 z(ZebIqDv33g9a=?(ZebI!oLDe@vnn0fK&WaCk)^ehbs)=6tAH$fKyoI1Ij2&gaJ7f zGK!XN@mz398TEg5Zz-ex&-N{4)c@JPrHuMN8@QBF|7Qo6GV1?q;ZjD4d$|8w#1%Jj zX$=>?gx8cZO5Db!Ra^{&*OW3!+{mSMTnvQQlrl=(%B7WD420K|GD_UcrL|lPgx8cZ zO5Dz+)m#h&r<76RhAyq=VjwuBj1sqWX+;+U!6{{wxT#BPx)=yfDWk+~U0T(}KyXSK zC2s7}x-JHSQ_3iDYnN7bF%X-Z z#BE<%^~FGNN*N_?{L;EF27*({C~@nTR(>%MoKi-Ko4>U7i-F*jGD_V3rPW^y1gDfy z;s!9S|6(9GrHm4{fN2F71Hma}l(-2@Yrq%?PAQ|rZD3jj#z1gN86|E6(>gE)f>X*U zaVwZsf-w-BQbviJ!L$~Pf#8%fO56^n)nE(+r<76RhA^!MV<0%Cj1sqmX+;|$*J%@iWZ465S&s* z3H!vz9&#$YkD_&A420K|GD_GgMo&(KjH0Dt420K|GD_GjMo&(K_ffQ3jDhf)Qbq|I z#^}kZkWsW?jARr}pE63=Ge%ENh4)dkW{iPw`jk<^wlR8gDr6Kb8)G1xK4p}!bBvyx z3h$$63qlE2b^yE~?C|XX&A994#r;HMIl+lw@;e8aXC}SX;K4p}!sf?bS3K>O<$`}Zz zPZ=fbE2Af;!uu#%SH?g%eaa|dYZ*N`6*7vJmN5`cpE63=T}Dq%h4)dkx{QHv`jk<^ z1~YncDr6KbFk>K`K4p}!$BaJ_l2hS*6s<91Ae=sBl(5Z=o}3C9Ma#?>2&YdOCG0e# zC#S;uC|YU8KsbHMC}Fc1JvkLJiWZyk=T+hKDWin_X7uD#cppXU%@_!$PZ=d_Iin}1 zLPpV&GX}!xQ$`89&gjXh@IH!GoiX62Ps`5ugEV(a>&_VP*OV5XG2o|9E6*5kr?m8p z0e?+t?HL1p`n33r0e4EP&lvF6l$M_{;HOXP&lm_!DWilfX!PV%$S7KZ#z1gN871sO zqbH|AM$sxX27*({C}ATSJvkLJiWZ_V5S&s*3476a*FjE&jH0z@420K|GD_HvMo&(K zjH2ae420K|GD_HyMo&(KjG`53420K|GD_H#Mo&(KjG{$pyeAS)pE63=mqt%cg^Z$g zX$*wZr;HM|rqPpAA){z%8Ux|3qlBGmyn!UALPpU_H3q`zQ$`7! z)#%BokWsW)je&6blu^QdHF|O?WE8DeV<4P9Wt6aGjh>te8AVIhczY|HK4p}!YmJ_q z3K>PK)))wte8AU7D7zn3N86|9DqbH|AM$sZR2Eyr6MhW}a_+9`x6*7v}u`v)% zpE63=%0^F4g^Z%5Yz&0cr;HMIv(b}NA){zD8w26=DWil9ZS>?+$S7LS#&;@&)2ECQ z_O#KHQz4^hO&bH@^eLl+ZEf`ARLCe=*2X|Meaa|dXB#~^6*7uewlUzRPfOeQ77BMt zYugy`*OV5wG2o|9tJ@fGr?k9{0e?+teH#OQ`n14}0e4C(+!*lJl$N+L;HOV(+!zQ> zDWimKZuI0-$S7Lo#z1gN871s=qbH|AM$t+)27*({C}Fc3JvkLJiWa*u5S&s*3H#mn zeiJzrGK$u_F%Vu;$|zyW8$CG{GK!YGF%Vu;$|zyi8$CG{GKyBcF%Vu;$|zyu8$CG{ zGKvIm7RLCe=`^G>xeaa|d`x`wu6*7vJzcCO_pE63=0Y^_xg^Z#V za14agr;HLd!O@dbA){y!90TF>DWimaaP;I<$S7I|$3QrJ$|zwg96dP|GK!YMF%V9l zGD_GD$F~m2sgO~$8jgW*`jk<^hB$h1Dr6Kbh+`m}K4p}!Cyt(+3K>Of;ur|0PZ=d_ zi=!u}LPpWDIKHtdoIYigurrRHoC+C5E8`dlr%xFrY>uNRr$R>2;y4Dv=~G4t`{U@z zsgO~$K8}HK`jk<^7CCxyDr6Kbkz*j7K4p}!OOBqL3K>PK^|*RLCe=G{^U-h0~{u686o}lT#t1Xx$tG;q)n^gspS*6%e)_bC zjsbT{tLPZ;*OZpgG2o|9>*yE=PAQ{=t#tI{RLCe=O2|5ERLCe= zYsWx1eaa|dyB$3_6*7vJ+c6MMpE63=amNph$f=M~wBn9|aQc){!lpZVaw=pLExKbM zoIYigu+To`r%xFrY`vo=r$R>2(mQ^nC7eEGl(74bo}3C9MXT=^2&YdO zC2YW>C#OP2(E>aM!s$~+348G9$*GW0v<8oXaQc){!Ztj5aw=pLEyH6VoIYiguoI7- zoC+C5EAbczr%xFrY{sJ}r$R>2Vmt=I=~G4t`|3qlE2w^yE~?C|aJ!KsbHMC}D>lJvkLJidN_`;HOVZ^!TwUcS>vY81UDW7U?nI zr%$W&7;vYwOpgJ7O=+DT1Ah9nP>%t3N-Omk@Yj@<>M`J_PiyrU2u>-Zgzb9t2iaiE`Q_3h|(;huJ6*7tz?J*FXQbq~;_V^hyITbRB*6lG6 zUQ@~_Ve1|}ITbRBmhLeSUQ@~_VfP+AITbRBR_`$oUQ@~_VFMpMITbRB7Vz;CaN+bR zql7(t^yE~?C|bkEKsbHMC}A5PJvkLJik9&)5Kf;mO4!LqPfmr5qLq9Mgwv;t5;pVE zlT#t1XfYoH;q)n^g#CQ<?YPM3qlC?W^yE~? zC|dl-=Td~zr;HNz|Iw3EA){#h9|Pg^DWim20ML_DA*1LL01SlFr;HNr0zgkrg^Z%B z05IUEPnQAU12fzyT?c>xe@*E^01Wu))0F@iaHn)B00#UurE38&;HOU)17N_N($xSM z@Yj?s2f%=zK3xxhf#8%fO1LEeJvkLJiY^JjKyXSKCEOK&o}3C9MOOu2AULIr5^fAY zPfmr5q6-5s5S&s*3HJuz(?#S|$SArt00ZGQrHm484?s^&g^Z%h127O?Q_3je4gvJ! zRLCg0LI4BdHKmLaZW2IGPKAu3iv;l5C*kxdqlEhe(34Xkqv$#T4209Cj1q1YKu=DE zjG{{gFc40kGD^5x06jSsGK#Jiz(6>C$|&K60rccl$SAsC00ZIlDWimY2GEmJA*1M; z0StuGr;HMA8$eG^g^Z%h1~3p#pE63ga{wO{Bd0<}(Uk)j2&YdOCEPrKo}3C9MHdfX zAe=sBlyLt5dU7gc6kR`nfpGeiQNk?*=*g*&QFI9bKE@`TK4p|}7Xf;5Dr6L0MSy{D z`jk<^jRfe)sgO~0Apr)$=~G4t_Y$Bdr$R>2wFDRlr%xFr+)jX=oC+C5mlI$hoIYig za7O`paw=pLT~UC6aQc){!c7I}$*GW0bWs5Y!s$~+3HKG?Gk@e%$SAt500ZIlDWim2 z3(%8OA*1Nh0t|%Hr;HNrEFfS*2HZGZuHN|zg8z+Y3k-T(uB`gFko2HYuKaex7TP3e*Y4EX8OH3t|7 zPAQ{=+YZo^Qz4`1vI7hRr<75`od@X2sgO~0WHq0)ljRhlJAIaYT^r4pBf*K@g-t1*B662?0SV z#iEoH1f@d|r0#eR>^;ZtfA4+%H+-H0-yC}{9A|#}tars+<4CaX!zfEiP>oY#6hR3R ztoty^@)A_z)EGrvf&}Y6jIz`O)i^aq5t<;ux(}l)J3&i?acYbrIzfVUA4XY%f@+)^ zqXpqOK+y$-n#;Gxi*aZpJeHdlw3#xHyj3RtNf^{E8Sq6h@oEoEu zV31(lhf$Wqpc<#fD1sQY7TvlJqb!d>HBOCD#4$*)?!zccWl)V%V-%qb60G|$%CZ?$ zENIp0vo%c5$LbZM&nB`2U)~^J!oC($XrC^pbp+~lGsy`k+DXbc&fl;b)8W^P- zr}`sog44h#)i@1|QjJsn5jMeTV3cZ{21cpIss4y=B0TAVGIJ_CNr-+;50BwHBJMg^zQ!z?{bzgYWvw`MRc#>dF#V85pRCtnLPK754=2VQ5 zU`~Z63FcIIl3-57C<*3Nc#>dFg(p3dF zg(nH-RE&~fPK75u=4noaCkf_MjFMnZg(nH-RCtnLPQ@q*=2Uo+U`~Z63FcIcl3-4S zCkf_Mc+&Hy=2VQ5U`~Z63FcIIl3-57C<*3Nc#>dFg(nH-RE&~fPK754=2Uo+5S$V* zp$B7wQz9lL1gAtyNC-}en2->h5-}kmI3;32LU2mNgoNOfhzSY7DG?JAf>RLF-niRAed7arN>Ha6Py~O^n3(@IfYSr79nf` zqqOAT1e_Y9w00fAoWdxr6SqxpYK+o?X9RN!qqMl#Ho>VeN~>fM%qfi0iqxypAIFiOjROu(rz zO6yn<%qfi0ni1Osr^YBPen2p%FiHyzY!jRsqjbj{!JNV<-JK4bz$o1WHUX!`DBaCO zFsCp|cMfe6oEoEa3k<=W!YJKtvQ2PmjM9A*1ak_bbdMrz0;6;*zyzEcqjXIh!JNV< zT|c%>aB7Uwg-`@@3Zrz<(Kf-UF-lj@5X>oz(v_;P35?POAro+FjM9}21ak_bbQQri z!KpDyr^5*56h`UP(>B4WF-qr92*IgNRrK4EAx)PrAOZ;T>hLhmrAFv@Z! zRO8eb_23uT8>5Jr&^v5SVU*=esK%)=D)txJTh4@D#HlfghzSWcr<_Mw&V*{58lz%= zwY}v`=tbt#7!~{L?JZ|Q(}7cCRP3*~x10&R$ebFZVt>uOBoEoEIf7QL^Oz1_N z8lz%=-M!^Z=tZ0wqhf#Mz2!`(ML0D^#s1oR%bC!NI5kEQF(JWzqF|KeOsHl~jZs8Q zNU)zM7-cyVs&Q(JB4R>hLW2E7!6?g_P>oY#6cG~=>~jjEEN4PB zPK{ASOh~YwC>Uiq6Z%l&)EGs?garGE;ylW7CRF3p7)8W{1pAzF9%VTbs&Q(JB4R>< z{p@odWjPb7acYbrVnRQ6wwHoYmNTImr^YBECL~z*VU*=esK%)=iiimb)_oXdITNaJ zYK$UcLV|T4Mp@2;YMdIQh?tOI-G@<@Goc!%#wa2tBv|)hl;upQ#;GxihzSYSeHdjq z6WTw?spU+lmQ%}_P%WpHGoe~eEoVZtoLbI=YB{x>3Dt6HITNbo)N&?N%cOh^dbCt^ZE_?!|kAtB5u z5fc(Z_lcO$ZasWXiI|XJPGOYgOsK}GF^Y%@3FZ_=SWV-yh+5^PRk zl;upQ#;Ki05iudby3cu(WV-yh+60G|$%5o-DWV-yh+ z60G|$%5o-DpqOKoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>W zV-yh+60G|$%5o-DpqOKoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+60G|$%5o-D1#PjZs8QNU-k1D9f2p zjZpqOKoC(!9HAWFJA;G#2 zqbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+5<>Thn9zlZ;FO3731Lo&n2->Y2dBm;A|@o*oWdx}nNW>WV-yh+5^PRkl;upQ z#;GxihzSWcr!dNLCRF3p7)8W{t}$8nVU*=esK%)=iiimb)_oXdITNaJYK$UcLV|T4 zMp@2;YMdIQh?tOI-G@<@Goc!%#wa2tBv|)hl;upQ#;GxihzSYSeHdjq6RL4)j3Qz} zf^{E8SpqOKoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>W zV-yh+x?E`8hf$U@p&F;gC?X~#SodL+p&F;gC?X~#m{S;K zITNaJYK$UcLV`JkQI<2I8mGo6A|@o5Qy67A6S{tnQ)3hn6B2ArVU*=esK%)=iiimb zHm5Mkawb&c)EGs?gan&Y7-cyVs&Q(JB4R>!7p(g*%5o-DoY#6cG~=toty^awb&c)EGs?gaqq8jIx{w z)i^aq5iudbx(}l)XF|7PaB7SqVnTv-A4XZugle1`qllQ0VBLpNmNTImr^YBECL~z* zVU*=esK%)=iiio_D6;OuD9f2pjZpqOKoC)1k z!>KWfhzSYSeHdjq6RL4)j3Qz}f^{E8SWV-yh+60G|$%5o-DW zV-yh+60G|$%5o-DoY#6cG~=toty^awb&c)EGs?gaqq8jIx{w z)i^aq5iudbx(}l)XF@ejjZs8QNU-k1D9f49@++JgqllQ0VBLpNmNTImr^YBECL~z* zVU*=esK%)=iiimb)_oXdITNaJYK$UcLW{$!`!LFKCRF3p7)8W{1nWMGvYZLkI5kEQ zF(JXa52Gw+LN!i}QAA8gupqOKoC(!9 zHAWFJA;G#2qbz4aE9r1*j3Qz}f^{E8SWV-yh+60G|$%5o-DW zV-yh+60G|$%5o-D{c7-cyVs&Q(JB4R>)HpRp5iudbx(}l)XF@ejjZs8QNU-k1D9f2pjZr>=gAQJ$HV9MRp&*B&Z+8r2+{7V&W{jvs=5F|bWT+lM2L1@bs>bP zQ`LnLqI0Uc2tu^`s*56+Q!z?w;-hn_8mEC#s&N_^r5dODBl^t=PZG?j@Fc;Uicu2G zsqiGhoC;48%&8b9!JGJ9;Yory6`mxRQ!z?{ITfBHm{Z|Nf;knVB$!j-NrE{Q zo+Ox4F-ng&m{Z|Nf;knQB$!h%N`g5Ro+Ox4;Yory6{94WQ{hR1ITfBHm{T!If;knQ z^xTCx6`mxRQ!z?{ITfBHm{Z|Nf;knVB$!j-NrE{Qo+Ox4F-n3t6`mxRQ{hPugqTw? zN`g5Ro+Ox4;Yory6{94WQ{hR1ITfBHm{T!If;knQB$!j-NrE{Qqx7VTITfBHm{Z|N zf;knVB$!j-NrE{Qo+Ox4F-n3t6`mxRQ{hR1ITfQMm{Z|NkIJ9;Yory6`u5Lk2w{iB$!j-NrE{Qo+Ox4F-n3t z6`mxRQ{hR1ITfQMm{Z|Nf;knQBm}2KOz5Gb;FO373Bf556B2?`A|@mRr$kIh2u_KZ zkPw^_F(Dy1C1OHCa7x64gy58j2?^#DMp@2;YMdIQh?tOIPGOYgOsK}GF^Y%@3FZ_= zSoY#6cG~=toty^awb&c z)EGs?gaqq8jIx{w)i^aq5iudbx(}l)XF@ejjZs8QNU-k1D9f2pjZoY#6cG~=toty^awb&c)EGs?gaqq8jIx{w)i^aq5iy}h z0j>Km%5o-DoY# z6cG~=toty^awb&c)EGs?gaqq8jIx{w)i^aq5iudbx(}l)XF|_S;?x*L#DoOvK8&)Q z3Dr0?MiDU~!MYElEN4PBPK{ASOh~Zq!zjy{P>oY#6cH18s?)j;qbz4aHBOCDL`+Dq z?!zd{nNW>WV-yh+60G|$%5o-DUFZ9>+v5r!Y#7KH4TYHAd+fJ_K_Lqx8I7*aSxDu{0BKYK+qJRS4!3M(J55+XSb^ zC_R*eU`}C_9)Ph;aB7UwlN<=<6h`T(iLeQb(!&WR;MC5ew8|dAoWdxrXtzypYUfc} znvGyiVU(6Z+a@@*^C+$7MKGr@N^57sCNN4%R87FCF-mJK5zHx!(z-_51gFL*EzmFJ6Py~Ov`hoRoWdwA ziLgy@YK+poeFSp~qjVoVYyzWnyV?Yt+If`jyCRrV7^Qohwh2z{JW4m~5X>oz(v30O z1gCZ$r8_(b<`hQhZc5k$M(L)72{<)I>FPUzIfYTW(rugI)EK2pwg~1FM(OgXZGux{ zl&C7tn&FS0)!JNV+O<9%B_Wto z7^Nc;+XSa}txsr`V2l#M5X>oz5-q~N0i(22HUX!`DD7Pk%qfi0PqJ--Q)84qk_hG$ zMydT_6BwmgHUX!`D7_uQoWdymXPe;E7)8W{1ak_bEN4PBPK{ASOh_=NFv@Z!^zY-; z7)8W{1e;UNqbz4aHBOCDL`+Dq?sFbxITNaJYK$UcLV|Ul^C-)iP>oY#6cH2p?rlzC zl;upQ#;GxihzSWcr!dNLCRF3p7)8W{1nWMGvYZLkI5kEQF(JXa52Gw+LN!i}QAA8g zupqOKoC$qYaB7SqVnTv-pYtfonNW>W zV-yh+60G~2M_JB< zbst7q&V*{58l#AqkYL@1QI<2IpL#j9oC(!(YB>|C<3hR-Px6B5iRjIx{w)i^aq5iudboWdx} znNW>WV-yh+63i)#vYZLkI5kEQF`>PoY#6cG~=toty^awb&c)EGs?gaqq8jIx{w)i^aq z5iudbx(}l)XF|xssWFO(2?^GH7-cyVs&Q(JB4R>pqOKoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+60G|$ z%5o-DpqOKoC(!9 zHAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+5<>Thn9xCAa7x64gfOQ>Oh^db zCt^ZEa7x64gfOQ>Oh^dbCt^ZEa7x64gfOQ>Oh^dbCt^Z^IfYS{Goc!%#wa2tB$!he zWjPb7acYbrVnTvBg;AC>p&F;gC?X~#m{S;KITJcU#;GxihzSWcr!dNLCRF3p7)8W{ z1e;SBWjPb7acYbrVnTw=DU7n53Dr0?MiDWg<9F*mjIx{w)i^aq5iudbx(}l)XF@ej zjZs8QNU-k1D9f2pjZWV-yh+60G|$%5o-DWV-yh+60G|$%5o-D3(oZ#Ds(} zr$kIh2;C=QLPBs##Ds(}r$kIh2;C=QLPBs##Ds(}r$kIh2;C=QLV`JkQI<2I8mGo6 zA|@o5Qy67A6RL4)j3Qz}f;ojzmNTImr^YBECM1|s7-cyVx;BDSV-yh+5^PRkl;upQ z#;GxihzSWcr!dNLCRF3p7)8W{1e;SBWjPb7acYbrVnSDLtoty^awb&c)EGs?gaqq8 zjIx{w)i^aq5iudbx(}l)XF@ejjZs8QNU-k1D9f2pjZpqOK zoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+60G|$%5o-DoY#6cG~=toty^awb&c)EGs?goMz2A|`a9 zH#j9?LPD5RA|@n+?h`Q~Avh&sLPD5RA|@n+?h`Q~Avh&sLPD5RA|@n+?h`Q~!JNV< z%b8G(Q)3hn6B5iRjIx{w)i^aq5iudboWdx}nNW>WV-yh+63i)#vYZKB700PDiiimb zHm5Mkawb&c)EGs?gan&Y7-cyVs&Q(JB4R><%_)qsoC(!9HAWFJp=oY#6cG~=toty^awb&c)EGs?gl@lB_hFRfOsK}GF^Y%@3D$iWWjPb7acYbr zVnTv-A4XZugle1`qllQ0VBLpNmNTImr^YBECL~z*VU*=esK%)=iiimb)_oXdITNaJ zYK$UcLV|T4Mp@2;?p5K`7)8W{1nWMGvYZLkI5kEQF(JXa52Gw+LN!i}QAA8guLjgle1`qllQ$-CFBD zjIx{w)i^aq5iudbx(}l)XF@ejjZs8QNU-k1D9f2pjZpqOK zoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+60G|$%5o-DoY#6cG~=toty^awb&c)EGs?gaqq8jIx{w z)i^aq5iublbf1U`E$#?TiI|WO=9GvD38DK$Oh^b$iI|WO=9GvD38DK$Oh^b$iI|WO z=9GvD38DK$Oh_=NFv@Z!RO8ebMZ|;za|)v@XF@ejjZs8QNHC``%5o-DoY#6cG~=toty^awb&c)EGs?gaqq8jIx{w)i^aq5iy}9SJr(PWjPb7acYbr zVnTv-A4XZugle1`qllQ0VBLpNmNTImr^YBECL~z*VU*=esK%)=iiimb)_oXdITNaJ zYK$UcLV|T4Mp@2;YMdIQh?tOI-G@<@GokfqI5kEQF(JXa52Gw+LN!i}QAA8gusyZJ+wEL>_BSf95E`Si7Q`H3# zqTN?r2qEfJbzy|)oT@H@5beI|q6p?xjM93;=$xv?X<(FUoCZdz#;N{@esjW;1am4p zNie5klmv4sJV`L8!jlAZDn>~#r^1sKLYhdFg(t1hG^b*e1am4pNie6vlLT`rMoBQI!jlAZDm+Orr(%=@ zb1FPZFsH(k1am4zY3Zmr6`mxRQ{hR1ITfQMm{Z|Nf;knQB$!h%N`g5Ro+Ox4;Yory z6{94WQ{hQ#TFt5OB*C1DQ4-9l@Fc;U3QrQusTd`}oC;48%&G7s!JLXw63nUaB*B~t zPg-niPQ@q*=2Uo+U`~Z63FcIcl3-4SCkf_Mc#>dF#V85pRCtnLPK754=2VQ*DqwRe zJV`L8!jlAZDn>~#r^1s2b1FPZFsEXa1am4pNie6vlLT`rMoBQI!jqOKn^WOQf;knV zB$!j-NrE{Qo+Ox4F-n3t6`mxRQ{hR1ITfQMm{Z|Nf;knQv~Jp*icu2GsqiGhoC;48 z%&8b9!JGp&F;gC?X~#m{S;KITKp_j#Fb45fc(@PGOYgOsK}GF^Y%@2{xxN%5o-D zpqOKoC(!9HAWFJA;G#2 zqbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+60G|$%5o-DpqOKoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>W zV-yh+dd$MQ52Gw+LN!i}QAA8gupqOK zoC(!9HAWFJA;G#2qbz4aHBOCDL`+Dq?!zd{nNW>WV-yh+60G|$%5o<3ObSkoQAA8g zupqOKoC(!9HAWFJp(kdn`!LFKCRF3p z7)8W{1nWMGvYZLkI5kEQF(JXa52Gw+LN!i}QAA8g2;C=QLXYwUr$kIh2y;rrgoMz2 zA|@mRr$kIh2y;rrgoMz2A|@mRr$kIh2y;rrgoMz2A|@o5Qy67A6RL4)j3Qz}f;ojz zmNTImr^YBECM1|s7-cyVs&Q(JB4R>oY#6cG~=toty^awb&c)EGs?gaqq8jIx{w)i^aq z5iudbx(}l)XF@ejjZs8QNU-k1D9f2pjZoY#6cG~=LidT7&_kTTDG?JA z!kiK@At7|1hzSY7DG?JA!kiK@At7|1hzSY7DG?JA!kiK@At7|1hzSYi6h>Ljgle1` zqllQ0U`}C_oY#6cH189@n}Lqbz4aHBOCDN`FAG z?!zc0EkrMP?C_U3{0#1!ldN>)ux(}oD zAh2zMQ)85#XhkrmFiKC4+9o(PM(Hs~1ak_b^vGe@1V-t}J`-?ijM5`&2<8+<>2WaI z1gFL*J=cU_PGOXuA+k+yYK+puFbL)pM(M$munCOP^BpGO)UNgEK?MYJ3ZwK;fNg?P zyVj@G?Fi-+MrkFvZGuy~)~6-W2<8+)1p>2XwW0V%gA(&GbrA26A6BwnnUMAqw7^Ou^2<8+UFZR=OaV zQy8UHCAJApjZs=2fnZKyl$IidO<$*9hhmM(H-OZGuy~)~EZO2<8+< z>E5Dkf>XQJr<-I5<`hQhhE#MD-SWwx$M=I%-C02h`%~S(KnPBCp8z2^)#Z4Eu$R(R zZ-n4f7nc!&Q(ePF2>VlADn$rRbwv`voWdww{R`G%lrFNFfKy|Xt`;GfQy8TyGqwp% zjZwP9fM8BxluqYu6Py~ObY6;JPGOYJ0mCLRN~c;T;MDF%>6`(oz(vd*e1V#zCCg9WVeiiimb=9Kd&%b8G( zQ)3hn6B5iRjIx{w)i^aq5iudbexhKM<%_)qsoC(!9HAWFJA;IPpMp@2;YMdIQh?tOI-G@<@Goc!%#wa2t z)CKE4=TVk3p&F;gC?X~#Sob-PvYZLkI5kEQF(JXa&v}&POsK}GF^Y%@3D$iWWjPb7 zacYbrVnTv-A4XZugle1`qllQ0VBLpNmNTImr^YBECL~z*VU*=e=p&0$V-yh+60G|$ z%5o-Dp&F;gC?X~#*qp*B%b8G( zQ)3hn6B2ArVU*=esK%)=iiimbHm5MkawfD}#HlfghzSYSea@pSXF@ejjZs8QNU-j6 z9%VTbs&Q(JB4R>)y&z!<2 z%b8G(Q)3hn6B5iRjIx{w)i^aq5iudboWdx}nNW>WV-yh+63i)#vYZLkI5kEQF(JX` z6h>Ljgle1`qllQ0U~>wiEN4PBPK{ASOh~Xfg;AC>p#x%^8l#AqkYL@1QI<2I8mGo6 zA|@nQ_hFRfOsK}GF^Y%@3D$iWWjPb7acYbrVnT=O)_oXdITNaJYK$UcLV|T4Mp@2; zYMdIQh?tOI-G@<@Goc!%#wa2tBv|)hl;upQ#;GxihzSYSeHdjq6RL4)j3Qz}f^{E8 zSrFY8l#AqkYL@1QI<2I8mGo6A|@nQ_hFRfOsK}GF^Y%@ z3D$iWWjPb7acYbrVnSzL)_oXdITNaJYK$UcLV|T4Mp@2;YMdIQh?tOI-G@<@Goc!% z#wa2tBv|)hl;upQ#;GxihzSYSeHdjq6RL4)j3Qz}f^{E8S~H8l#AqkYL@1QI<2I8mGo6A|@nQ_hFRfOsK}GF^Y%@3D$iWWjPb7acYbrVnQd; zq5DKkNC-}en2_*bPD_=_UA{}lF5T;NZPg|wLx~c(%h%B_Z;ZWoqL(W6?OC}_&sIHS zU#ZlPe<-rctkjTyC9=P))KK4SH1MEOLw%>ww1Y|w^=(F@4k|U&_ZZDNsMJv3U^L{Q zQbT=r(S(Ca4fU->;|=tG=NpUc7&XLAWVfgxb|M#-G{jG2m#86zB0EG4aTK|%q#>3f zJ3|fe6xkJOh^fd0B@J;E*$rwIa244JYKW`I?G6ob71;r5h^xr%PeWWqZggmftH`cT zLtI66d>Y~^a*IPlTt#+z8saLl%TqUS6}h>gA+933I}LFa+1Y7`tH^B)4RICO(P@aQ z$Zk$UTt#kZXo#!GE>1&SMRsr+;wo}0L!SyhPaCC&NReT@DxQgt`^y$P^WJjhUt|GTAG{jY8C#E5;BD*jR zaTU2)p&_m!yDtrK71?=dh%4>CVjrB)5Lb~Mmxj2C?6&k%f-CL09=;jaL}Lf^Dy||s zEDdp`eOBbnxQgto^eV0*yDANF6}c&)A+933DGhNI*-2@LtH|vL{j}mLvV+nPSCQS5 zhPaB{h|myMkzJF9aup31&`_?T(E=LERWw*YL%E8^3TP--(NF;mCvm%tczkwaj{*ozzi zGsa)!MuNud=A-!ljPYmtd3N;CbO2t*pY7?{)km`dcpZPXuV-f;O$Oj~{Mp`~-F-9{ zfYPsI~o9>_k)4x^Z$(T7dQ~RmOJ|NKd<92 zkbp(p8b3T@-Y;ah+V}UeePec!-ME!|BUe$fDpTcJNnQ+uQPuE z39Q}LIP@1NM4$NQ{rC%1VBxmL504Ug9e;rfv1_-ZPy6e2$Pj(lpE3Rd8e$i2M<4a) zb^HZ5#4g*8KIqTu_zQSoy|%_tYQ?VEjy~nj`|%eD!D4NVLw{jJ^bvo(A4o)>@Mlba z10`ZtYe%2&=XK3r^znYi@)v!&pRxQ!AMR(Y`HMc=&shGVkM?T}ETT{LGnT*TgZ+%< zFZx_RWBH3d*3Ve;7k#RqG5!KEVpnKKpXujy`~_yPG+X1)U#Jm%pkMC?8`0B=t@`cr&eej{HYZh2Y+gX#=)Ojp>go1 zR%jgjsTCRre`BXdL{h6}s>i{HYZh2Y+gX#=)Ojp>go1R%jgjsTCRr ze`BXdL{h6&eSBYK5)?27hXW#=)Ojp>go1R%jgjsTCRre`BXdL{h6&eSBYK6wZpIV{IlEI%^p>go1R%jgjsTCRre`BXdL{h z6&eSBYK6wZpIV`D@TXSjDrxYiR%jgjsTCRre`BXdL{h6&eSBYK6wZ zpIV`D@TXR29Q>&jx@a5xsTCRre`BXdL{h6&eSBYK6wZpIV`D@TXR2 z9Q>&j8V7%Bg{~n7e`BXdL{h6&eSBYK6wZpIV`D@TXR29Q>&j8V7%B zg~q|3TA@qY!Jk^8aqy>BXdL{(kLW^NE==Gr@Pk%p9Q8*lG>-bC6&gqV(F%>D{%D29 zQGc{TSJM%N;74@PE$_!);0LYHIQWAf(G|CPKm3R;xMhsLzzizH|y114x{sKQ}g~q`j{D`is<^A{z z{Gb&Y2Y>J*x~!J><1g@oR%jgj!H?*gTD>2BM3>Yu#$VtEtJTYe*6V~&u2?T_z_(`%NT!wAGAW_;17O8*Us{O`HL={Wh{Tum9vcH zFS>A+vHV5X&1wukqRVC(%U^WWEMxhLE}CU5f6+CwjO8!7WR@}h0zYVl#$o>lKceep zc|ZOFKWK%6;Hx$E?5-80rw-R`|&9+-RZ=Y#)!gZ6EEzR@E?li0^01S1wRaD9RRY+a1W zr-4$2^#5Z;4_~~%8`vr7%3|!_+&e=5fAST(_FDfV{*A~N_s|Kc;<_|f+X<-Vq8oR< zxLsO=|EKnRED>Tg4wu69Q=fsLFD^!Lfr;BHv486mMVvRc(Ta#(T%T81LXp^lJ1E?> z;v2y@=VYz(+|mweh|v+Pyta-jZU7|G|34fMrIzz0h< z^xg29+>t@WT}$ruvI>L$na`&DOVMm3)KA0$ArHlud%&SB{X%>Kj?mJ=js0c@}=vg`d9#QJ__~~`%&QI@bHU| zOXQ;v>k*%kFFtD2YKDLDY2c0mGZ}gMEr@_9M zFvh&@Uwj&3KQ;Qh+5fV);1Kcuc5m_jYd7(5=lB0@Hz6K_A1xHpRBBdqe4=aKYMc(7 zVxJWikhLx^_66Pm02xRAW`qAHUu?q{|3>7CC4;e_XKsLVi;KPt^u<#RY|m`+8t>&B<QZ-R*vmEz5kzIgz@oN(3#Tz_=^1;@a;VOiv4^%{2cHZ@Gtzvj@bj- zSL|mY_Ntxck-q<5e3AUfwDCFcFM97^EI^BX4)`qC7ytj*aqJnw!_UjZ&&7k!Sib+$ zK7!N6$UdTaOy_nz-^ieA3wd>H(7t2OnC|+!qgFFih|v)RM`2Mu z7hlPlz4oMO)z4o!IDX4FM=q{fzjsrbtcBMs-I4ml!DM%4Bx+EgQMN2M|2bX1$UkRp zoKDbp)6=b5Ca80w=!y%Kw~py_;F(X({q}Cwvww8xRjR}=kEJyWvvbq*GIrNr+~Y)e`H?U{|Q zT&O;)`jA(KH7I-j?F`#GW^DRh?|J{cd#}^#WErX*|7K_JI8U_8J><)K`Tpy4_0Ai_+*A|BkrFc z`Ngmy9rE^Tu=tnWy;>Zudv0O#PNP>hkNLFuhu5<#yZ85)_3_KxXjbP!qZvzg)$5nF zQs>q+nw?wyPR>e8+hzTvUA?&tQ@mPd;`{N>6#aGdYx_ngtv;~c-R?_k539TD-KP&8 zTXE#z3tu+Pd$q*n2FFs5`RQPfr@wo${JHP?pDJE|>ie5JX8bF`)DKD?_~7_wi-#6Y zQ~XBUMa@3ga4`F}{srP!zf)wz!W^BFr5~7}dD$Te%T@Ti@u=R96<>Sr*T%{F&N+8; zQp3%Q(rs?AW$fhM^V|2ilXFSsqrWa(H0XtI+muT?_oMNT?0+Fe^R7A9T_|vM=JK3X zQ~tbk?r+C_>{;h{s^)1LwH{mT^WJH)%=r2IifKo7lwV(={_t}pi%+jq|MdygiX6Y* zdwSn0<(3b~alXswc%^Q{Je{wk_AYNWeJ=CZ)T6pSy880r zYh9~dNwurRf%%WmY<{6tn--te{5NHXUs8{5{YKyUpN);*rOLn`_a02QWc=(ijkbT9 z_EzntgWj03D9PF9W{f`C`mgs#_RIM0#1!8rTe|7w(@RT@Ik)%soz<2XYv1anIZHMz zsWUXeQ#%`1$dPc~i1D+A&VOt1j=%GiD3r7ExBUTWRH!NkX!|Ml(u#yej~U8Km1vqvwfePn2t zCMnj&8Tw}GjISonQ?f?V2EXUr^k=Qjsds!4FYd^fE7afj=lmwMHh13C>yMgq2JPr@ z|Eo`1KKj#_n~G*j^ZUD{=j6Fxzxjoom7d+(u0!c#*E9a~*02G$b1h6=c>KVY=j(p7 zHsw2cUx~Y=^andu4mt5;s@LLAZ`)~X^#P?`edY5pe^1{%{k6B!t(bi*-L8&R&JN4d zt6u%}BMzr|q8GO%Ff)-p&0JN*>&Htz(MLaS}h9^jf;TZHCWo`b5v$rRv={U31pQe~pTNZ`My2 zp8xybmfi0h&o;Pp%#vHJ*H`@FB^!KBsGxivs|62Rv?P|W3Yj)2<88#)mGHv8PJh7xs+F z@YT0%K1zOV*v)kr-`mpXiOWw<`8Q6*%SRSoNHh7<&;LCZv-e=LzQqRT`KaZMYIP50 zUDcscqQoz)8~W7zdvg|6tTwyOo7Mh)saehQ#R?UeH{#WrExWh>D|3#wGG&-GBu>2f zzs;V0bJUXkO%ptk;Mr!g^B&HSDP_7Jd)4{pPXDp%8kd{0bZ6U?amS8$z0KMiPgdNT z~H$a%C#5DzL%}{(_N>g@0RmUmUY{5G_QWOc-3zUHlBX?m1LXm z7yf8wL zmId!+zL4_S8$Z93<=nzVN85GYa3;Z&FODBho`38+8^@HWGi`dSfBVhKoTtpw8Jdip z-}F?)`&(w5-8#C`-d@=o-A|nL^5^f2uTZpYt$W+@eRsR@>FJx(tjKf!i*Hh-O`Wc7 z`fY1I+EeqbHIHRT_ut`vmY$9?@s;hB4?lk8aQnu4OFcViV#@*vEA{MgcKhP~%jzV# zAGg?qBWd=QU$W=7Hx5s1lC{^NsU6ZjdvSB2<+U!g9=mW)-p=VKG)f=y)%73SJies# zKN*_+a&p4PBwK4dwX5_ST{EuEb}Mwi_d=;@+Y zx3tYWv^l`GV((k1(@-@e$9u+R2JjZ?gEZGO8hqv!qme*A{NRXl$A z?$8w@ze{ny@V?hyjv4XS%ab;?`Rk3m=LfbJHF(6wo!`wq_V&2%t|d%8=gk&_Kkj&C z-d_ps^&IeGwW5ble43-xv+F9vyIJ?+gdGQ8zWK-f_ugpu&o}Mne|frMjoE!(-d-c- z-Iqs|ZTr~RihB#>Ub%Q-kM?EW{&jJqzNLO#y0p*6__-_o^36{Tf0%r&=jzIZ*4}?6 zQHrsb;xsQezEPc~J6ks`*ly~+HJ5Te_5F>Oxt8AAH-FBee06SJzWd6K$rWGzE6*>F zEqZ>}BX2Hf`uXXnyO)?&^X>bcPu6&{#ikRJe`;1U$F=u=y8c)9Uhnlt{n6cnXII`n zn7Y^7`CiFY_uDj6|IGQ)qT0KUExb|jzg4Rroi{JToZ;!`&0BiA*6Szgo-Y2uw1qFe z^TC#v`wWV6yiAHCZ}dM^uE?ZDKP^d+B;OlXv&GxL{7kW`Uw)VN%6A*5zLsjw+(&P| zF?jli(|_98>C%VOzfJhgFS9PiD>J0%m9jT>_0E~A+-twKo4l<{(`P2Uup{G&6A6!B zo^rTW{p=~uAG{c|?!CS#*9`5x_Ju~X(q4RNf9vAio8+l^`TBp)tUB?|k-7~gmU*?| zxCY0Qk9+i5)$@T)|w|rIK%0p z{|vmlU@-YU6)p4HuoI8 z;m3b-{IU96voy0>JTju{?dhet733-qv*R#Lv1+PkTG-h4U-69=>q>g?D!iF5Nou))e=1U%g#--=&#(nnce;1P1U6u9G!hcozr0b3OSB9)ic5>srRrOB~shR8Qt+);Q zJdz@&X3VwWQ>*vdUh9P(`MOseo}^ZVWNqjC+GtRQPH*H`RJGBCKl`6vRj1^zWD^Tt zE%(@%W%qwfnBb$*qt@IUSM2hJab@4$`h3BjHRA5v8Rz=m>Tyf8*fON~gaLcIbbsUL z`F(~>jJI#t7hgBJQDgA9;i(RnJGrsS?Xw%!Cpb2{&$u4P3;*!O%Eh@i7klc%kDIj^ zHT-hU9Z9~tnXqHLW?v;vU1sarF==kDer8tgl`+3HNc-oEISVE{lKS`M%`aCh`u38- z$39B)?-MK1AFDCr!$03|)cnY(!CSjkd9G`vUaRZ3X_aJKf*CI*n6vKUe~ZUW{_nj~ zi}G){pE>XC&2xVqccS#go`;h(8-Drq{m)e@y>tAGQ&(O*cXH{a^6$TOX867SY^mjgGb+)amhJZQ>7Hbh~bw!8vc-|8d^^&b_a<__E^8(@7HPqTqug@eKdt z@*r1aA_w#3b!{)EbI%^Ss;5(g*maJt#E;YHEfF+IBU>fR=%2kV_Dj(bs|*jW7wFPvoi|#=UYRUWLW71iT6c(P(^LPb2LG=XRY!kqf^L_w7$aP~ z)}_>N>rJP0k$i#w&4pF2UPor`;c1Z8-RYXk|MooS$e?C@o-aK9#-PC!FCChYHhYh) z1%}=`JgwyFXNymHrug8THS*C`iBZ%o_1~by}}=#sgZwD&Q&WXr+Bq~ z{zC0ayxgNy?nR5ItXkRWT*qGqT{%0Z%YTJiH!8L4)cquz8r@&nbkE&oyUz5=ws_g; zef66B(C?YP{a(nu=dUqS`{!D?b5i|Y#dDAT<<%vJHYD!1>-M?i|GYDC^6e$@il68; zX+liVWp{Suxm)gPzAdMhtRA1@nL8&lcAWmhiVibpwR}C-$Pr~~70$D!d6p$bw(nW_ zXOCoG^{ZFeLiZ(aCk_rB)_Pa9RWQNcWeS5BOG=fdC5tj}?4L#aoeul4=&7e1RB zztvOy@^>kpu7CAEJI)+gqSJpbPx$!HxhGy4IXBn8qvvIQ@npYRoi~m;^lY7XGG^=0 z>RQ!adlJ9A@aIeuho?xJuWGIRg+43NeAU>dwZ6Fa+kmtQ62_ZWI9<{wAK#ett#Ol{ zUp=T$?!KGvZmhQa+tUl$Tui*X)A(ZX^Aw#tU`FZb9X`$3v3s$tg?_4gtxC!<#j+mm ze(GfQ?49%P-V*ceta=&0-gmU$pq8yOri#gwI8)Yve+;bJtj5^mTTg%3CfD|=#Y+`y zU1-#XnKh;#*pTe)a!;1t-0b4zg)?uLP5Je!8`_?Fyw9eaKjv;eYV!+&i|k(a(#EH5 zje7I&?uH}Jf79>cpdTye`lj#kT78Oql%jIUv%ePGU;k+3BYi$^_{+`o{l5Ei>fsN{ z&uhB$bniUf_gr6?X>*EPmm4*TH+gHDm=8yOHtue__a5(DIb+!ltvCGh^oTbH=c!*K zOX5juN^R|$a?+|>dB-Lk^y2VG@Y1+}>;ITg?4x!= zb~eA4{p)7C@8557@9M@4a}PbUyVl=FpBvck>q{%|tlYV&-_awvdhhOYTl@RpfA;m`sb1Q6^!4o9GTpp$`S{Dtw2*6!;w;Y9zU-Ojw( zwRxpEd#0wTk$!r&yaQSv>9=Lvv;=4JHm!R2R{ZG=b{Fq|X2{g%zb^gmm#<7}x$xeJ zzSEj4Ul;fIpJ^u)Ub;9{<3U$0q*`3$(D|!(ZcUkUa(s$amuAhVa<9v^?pe~mUhCwg z!2^pG$-49L@*fl%S#RL5Za*AMvTs(VyJ?qPoxc9!{2JBD=UAAx`yV%l)%+y)Q!BHM zxp<@c%DuhUG&&Y@sMMoZ=B=6fP31p7FYw!dHj7HPO+9);*4gtirYzBDSMfr>pHIGf zU#WQe{+qewOwF@LR}CAsIMwoXO*ULy`e)X0lbbDTaHv$WKfihGjWa(lo1S@W+)E4Q zf7;{t-_K-CcDLK=!H*?-yj8MVAH<(^taZYla{jPsQlA1{b|1_s}6PVGhxP- zGaYxft8pq}s+g6%Z`{6m@x3*dbFI3)K7Xy_Kb{{r=-=Oqt-rAP_l|vfeEZ?SmfW2>MZN2z z9$T9|RrTz<>cyWhdFR4;Z8M+R^HH~73v6w?wb{(VF(oHVpYzw>*XK1kU+l$vRccJ@ znDxvz)1PbI`-KHnmwxhWot$=<%-q0;UaDOR2Tyz>ipKQ6TE%%zWDt3(3gi*33Ay?yVQrH*2?h#;F8zwqJa* z#pSl^j%)>- zhkkqT@d6{}^{+pvRkb!#R!(0zIsUG%zesau+3`2e#!0xVb?TvKu6-T%&F^Ooez{$u zA3vV3A?b)X{W3pVq3q6Tk0vYFZ({O(t&ab5CGYb&vJFeybxZrnV=HysTDC>O(Ql8B zQ~Bcp<4X04JK#juw#)YQ?=$?L7ccZ*vF_vD%@Y*PR(#-_yJx3ev1iBV?h{62T>i!R zyIsCJaC7I)7IixOe6PjgOGDPbbNAz1>%0CuzFeF&bDvHy`;(96JW}L-WeMkL^Zn1`Pdyj^_Xr7rbBz-yWqU8BcRGQad?k|PsjcV2J zi8cM+K3C>aw>R(ZN>gj#+eKIG>7D)h^95#hx>&qvzILVmShJ|}iNt#fByIiC?eS&b z>Tpkc(XY!t_SN^j*WDi1Eycgto^9MW=4^(VA08We`AEfWciN4)v+lL`i%h-0_VskB zrf%7_{Et=FQ?GlXd9N9FQw@Hi^rwHsOFv@G<({JkzyJ5~MddR8(_m)bW*_7jz4OCH zM>kifJ>bvfBQq=+ns&sP?Wey_^!O7uUYjv}ZuP56GY-$PJzup2)w?9U)%laQn>v5l zwcEtFWeQwg`0FFH^KE?O_?4L6k7OUTX8Ths2d>`zcK(KSYCcwBY2D59=a=iUc~qlQ z3v;|P`0Tt>ZUq79d2k{ZXpkk6+&2yZ*w} z#q(ePJ#DT%Yl~lxQ|oe-zjh8SleuS-a(goM@AU3p<8~J*cy9BW?Fl-3cqiqS7Z-F| zJ-lS8zFDi?E!E-cvHRAJ{9{1PwJD#>RU=cbNAh2O_H^wm{np%nOWo;|GiTEmy6<_i z<=D70vs6zTuUdiwFHK+e=i*r#@6PUBab}LC88Ut``Te)+C3-6T$C)1;Id{~XMLx}v zzgn_01N(1!tJdTv`#hGp6L zeVp&BI@9XD_ImAa`wm|?JMW6><*HrY-|(^IeG?7MUgPM1Y8Un&ZE>{4XFCQh>7Bj7 z|lLhV19s9Cc z{J7Oh97wut!h{;_WQs0sO#q#iuEeao0CF++Zs-Fx_)Ro|Vv{^hO$2Rp~?$ULM` zz3Z)Z)LY$f^4x_bvUa>Wu)~IZtsndRgH22BZQ8MELXEkTH*PGuwDH&9&+K!xXwIvL zF8#1$(VCs>v;6b>v%Aw|{_3k?r$$|GIdFWfqD@yS(7duLyG|M-h#wryVZbM*v|X1X}7XwoaiR(<)!pnktzETqSBanV{g}Z|KX)un zuj)VUA3ikeh1v;*jk+2C?MtoNuj{|&aJhHC$-J%e*GGD%`XOVAm~15mPM?@KO@(cR zyHB{|>8|S}y{gJxOzF(UEaF?F@r~Lil z<#VkTw5)Zi!sfyaE94mY+`75P@}KyA%FXg87bZ%7@2B#6f6P;%`fFXgtmwNw%S-Kl zc=D-7tL7i_?Y7r%HT>$Ygq^M|z4+GYZTaH8o2Sc<33FfSpRoJh%9ZjZP1@?{TP@c& znO}9tvF61VB+QtwX03b~lD0oOG-<)-4(%#&?e!9OKB-%`^{%laM_;{ls^iE>!|NBD z^6p33j&6Rb?W;MS8F%(#>cm5yY=3D}%Fkz482I_<^*8Qre|^Po&5xZdu=Z@BAG*Hs zNYX!MSExC=*!oHtJ0x1!>&BfnyYdv76!Xr8KA(;4wR7a)EOnB%?U*h@s@r$=m&sqT z%(i8tGrgLy`_$y=K7Hn9OEg# zYnornAK!UPKT4VEKA*7W{7q+9?oK=N_eUS!(P+o)%9+Yk+1ave-44Sm{yM$wf?sc~ zEq6ED2YW8J`C!jS<$5hjlR5YQLETwKWx2KOn(kCWLRuOGlui|-1SCZylvI?K5+p@H zR5}Diq)SptT1rAt6e;OaNQ84uao4_1+wIw-U$z^HtYW;Cy{dg3KTqsc z4eA939DkpzMD?S}q($hx%xOhK;bv@dmq9GgpZSTYMml|xPWE1(j^9)RwlDw3)`Uq8 z$0T}la;Sj&e$D^GGhWCd>g`x37h40{618>cPE}oBPaPzmO!-; zg3#Qg@Ew!qr-sLcB=~WOb-qj2f#K5_G9bG=<{B>~k+SWh`tiM3$-;%O!DfSz6pqI~ z#6#lTvdCSpiYnfE8Ctde$sydjaezCU@sZUtGEpk2dA-oUuzALZJ==pR4m-|eZ#>HA zWE2HAV|Jbs&5!OT4S9J)49LAOKb)%3KRv8YdT6Pgg%v&ioOTmeGi-!Wd#6Q@rEj%` znt?XD3%jAzy~)g6C}81%jBJHWEPZ=IU>$`qML)jfDn9)E#jAxOsbL+tUz>Euw%jR;};)! z_Q-)5hWZ`eH!>M#rik2MZYV5~jIs2@WtTTRTq9aKPxO=cWfpsScf-Ren;rSyh(cjm zi#wjx9|X$WB&Al%*4>Q7Zhj!hC3un~-Mi$(eivyd5274%23Sef-ud$`;iOR;^>vN}YW=uwGCPzO z|5Y^hP3eS{+VjZjCvUL}6i0C)MewmkUWzp5ql}qPi#vU0SzH}~a$wPA4^P~Z9@w^EI z&&-0~au(<7wmM(pQu(_l@TAvg? zuXphm%e!=~vflF<51G`S-eDh|ZI*vQ-8H4e}xg@ z7vhr#Wofjrw`zDrfg*<=Z|7%Gr($JV-Gy#G0F-i{8&fMLcO~o zP?VFQwUzHmLLsFVH{4vYawhw^O(jdBaT{37KhtjI`1YkT;f}p zy`lFm&NzpawvPN*#C!6kaj}c88_}Bj$W@`>kW(6HttrYi1*j76p6W|o)Tdn@LBt_ZMAdSwtgR}g>}^9U4uP^d-tpp zwX4n>AL^u^7hlJYPij3?ICN8A+bUmECps_a+=L$YX4y6VNvC^GA7ohXu_)9}u9b&I z6iNy|)g9WosMONaDVCX+=1@=hKuLbDl7~@?0E^%HHddO$8zJXMrZElI@?J^E8s1H( z3sGjH0^i#6+us(neEOhh=f#sf(^C{A9i_h(KN$AAf4bT*q_vTxmS_La@nLd6c`Ns5 za%j@v_7<0b<+FRrr4np-n@@k&HSZsD2cP(N?Prf>dscA9Ua>K3_%7Tr|1di>W~7Nv zFgp6FnQE&ld2poS#>9O;ySS}yhdV~k%iY!=`+k_$nvYjKct6&_9oC5_V<>-?UCyHD zOJNCnLZh?pC8y?ZZ6xOM3E?WQ?PmX!FG-ZAe<@MAnE0{<( z{{0q}3z4;ZZPD`gRl?zohOSpzH{W<2Pb+ZPa4&g7M)~QyPB6)Raq%7=p^qJ{=vJlbmw+1RFdd5?eQPu$?NdbXjw zEpYXcKxbpm(74msn(lUM16@_g&IID880@6f#F zPpDO^bRyS?dP0RY?5{E5UvU5S(b1c?ahGdx?#57$Er&i6!8)}XdJ8Ko>9Iy3tF3(5 z9P=6RxirCzsHShYf`X5Tk7H}6C+*h8l*E5b$a=M!GEd@~Sjvq>V8u^i74o=`InXdf z=-|)S5X0o0rN!E{L@yjqzQX$3UFn8pm&^(ZZ(qiV=$bh4s5h~dInf7B-F+LzV2a`G(ayx?EfwM*sm z#dTvlA*ZF+sbBegPiNiM8efQ(75wGrI%iOIA+dRjNv`&8rB_2A*U=+;kE0ZgaleVc zxYT|>PyML!Ud?mtJ@89LQ?hw4g(K``6zv~Qm)-C<$FKf16GiK-Gz)L5BNV)+xGxw9 zKex_eBUU!Z4>*6<9arNsHhAH?DDz~hjO!)gWo7!A^s#H#*@_kkD!qP~Qb(G0ZF>B< z85A|Sk`~hWK-T6=^`7m|8b5VN;rqCt}zpyH15*MD^KJgnbZq zo7j&qWd|xE!J@b${DeDNtw{GgSuH+3c$V+3g)O?L7>A3+4iFDfGHT zHXEM`D5SF96(G~6Vjaa#n=G1i^faz@Q0_9~_G&GPA}+fmTVQ<~4@Wn_^~JBa6@#z2 z8dV-gEp_6>zlxu~&aB`4ekor{hxYcWZ?8=3pkT#sx##i96G|y6tmCCK5Bd^~EBB?| zoFi43*^KU$99_}#@t<>%x=-H`%O4XM$UiPYmh;v_^d6ly`*dtV40cfWSHZ)+#O%Re z<(3n%M}32)-yNj~?EHEx6iwA0&Dc}#+R2?EyrmvFw0wIYLYbny@+-Ukv~K+9Cmij$ zLEn3w-C{!rgidQ$O3wV;soN#J*_V8feQi?RVmv$gUaVYY^jo@iv1|EK#n>D4s!QXi z?fWgo8IAxS_`mUcVRpCLP9>Y}_79oLEBQu__th17BJyjO!ZTv9AM(#JCMC7<7OLBf zXqT{xsK*baR+pS!-J*B$p2T%|Ehp(TcHG36?!E8Lvjh(@0d zU{Sjz#|%C_Ho%_4O)t`_VqvQ&`0~`L)HK<+1gW1Er>FQB7Fj*cN2>q&HCa6HyZO!RXD5dl zUe@|L>G*fH^A8+@)q2lY4?2|>)f3}u;}rCEd~JFtZf3Nc-X%yfFWd6aL3aPXH{sQ( zC>L*kLe+bstjq!uHmxSQ--Zq}OK1w6b$ZAqDc-t1o)I&8u}v7(!zUX~u~W1!zvr^^ zfMqQSb~&-A~-K%coQ>_1%{e<%_#Qe%JEnhs$PZA80CgbEBw6r{>es zsiQB+jZ#!}PMsjolWfTx%EiU{xa@rKW%alfcBv9)X@Q<7LKKj=ro(9k%^ zHOs~y{aB<$jSMD_&dI3SsNFp3OI$TyZhoX4DM~PN;YXttgWA;_CvKKAlwDHdPrFTn z^YfGJZ43m^U`l6f(~730?_h`0>W{*AMGZ5_6$l8PIt8G7v{@zE-WaXV6lCnx1`KfM)r+>PPVBAsEiaHrRI zpFM1;m4Z)oej_{YpFMtQy&`#yLQ}0%Bic$-Rg`9A;stSr+{@~mn+rZ4KSzkKIOA#_ zi22kQAKc&Qc@~lP;Y4P#js$m%xBA#kd%>sF??3u8kVmfH6+1lMZn}T;3Fp!6&5@lB zvw9WjA6D7cUwJfYJrr$?%4KZ3YuweG1I}L-GH852l{=V^pQq7LQ0^f4{rUzAvsDqPw^`N<#j?R%Hjiaa`^Siu z^(thsYiZ5S|uIJ5JBxFt$ z-exo>@h?jj%6rU9^h{!eLfQR8e%=YgK^cbb7E?0Z9G3;lRpKX7D$-|JQ#(u>L^E&b ze@HUU5s4llr|WFfBEiwY9yPC_(%+^mvzBYa*lZ=Tz zHYlN8Y&xveA%M70ee`JHBoFtjV)W}LM>>gYE6WV)*NK;Rp6JDX&9$Ook!j_-Di!w5 zVJb|zwadQy>ZLiB1*sRi#_q9t?VX<2$U?5Soy-ak-W)HOx)m?4|B|LnJ>|;yU?00+ zS(Q;86DOXBvoU{>U&PC+)8AJHuZcHyZ>7-om}Z}^xp?Yz+w%RzU&9H?jE(xVzD^gV zzU6z4(z9nzOT@pa9McU|HCUos{mF&5AS0d`$(W)?a`_~7H^(~38&2k9y14l`n|8Uy zEu;1&H)eDV+I~L`v7b12@OHte;EA9|bO_7&Ym&Gxr8A{VxAJINio{%l{Q?Co_y6AeNfeiurrHfF)AtFkHwU1B&CBca=a z8sk4do%LxTjm&uAdy~bB)O8OAwmgSFypEo^GF{hga)11>L?zWQw4c;NkE zi~HBUc8KGuSMSJ_5xth~^UKZ6uPGibxL+352y2*UbUnWE>7>zyJXf~K_3-%U@Tec| zB61I7=H`FX1<{ZDpDur~c1|qME=qPp+i`zvOp=8QU+b|=@iCP#Hkz=QdyDO1sV|;x zDfdeB`N!XnxV_Ef8M-y$(|=Eh_DEp#2Kc#wjhI*EGIt)$RJdzjHzd}PxtzK0T~f<` zLGnq=(o3Ex70;tOd+jUhBR_=SekVUc{wRo`O>8kN&*2XxflBv*<()0Xle^(L4qyEr zbSNe?kj4w;#|+c=@i)nHDX?e|&}7_Ux}34VUT`OP6!clAe;m+#X~Xd@;K9XO zuYmS=lCEw>rn661Gb;*`CM5KQ&;H)>r(a(2+50?c<8LwPR5iXTKu>+Yh`g*<8hnRG z^mMrU2R0RFr%w!s#Lpc^tW64&Mb+1`p1-`D6YEPul&M*1pv0D3i5*z{Ija-rdtm%G z!A0f^0Y~>k6(2STPN!(~lZp)NoP5oHg)hF8kT7?-lvG4yY(^`wWwOG*GcKD^ar9w; zfY04Jze$Jk!uAE3Wu_#n=lvu8-}YA87g#ECred7fuhqZX*mYg^a2cB3pmWV7i0Ng& z@LB$Jk9|p#W!7_U6z#%5*dBF7YNw|i{F!UKW~ zQ?ggb4Bd7^Z`aBZ1g1^%o#3hDz0fgo>ZY1t#Vf9r3>Tsg5w7M2oS{DlTpBsZGM_j3 z7HX*2^bhS8E`KceCQp(XXd%Y-`GM0}BI?^e^K>pH?%hVwM;=XBBdqspqpj zaqZ2L1N;!5$$7=E5laTXR}N15IDTvlUVEh3#roz-!3CF{n+*hSMxLzT@k@1F<))Q7 zaf5+ewO25cQGr5GU(2c9`D-*ifgrv=U*tC;4Z0_aKMR%i8Wwv+W_dqHavu}B^>W;; zjAWCZNrr{PzjikBu)KX(IPj>v?2^g3Jx!kj_@C~1&%IN>-tBJa%V{=5dfuYfgF+SkIUl#uaNg&AeqDp4Jy0jyitvmx^BVT%6Vy3UUg0 zvP@yQdsU~rrj2b)9Hct-PRfmn)hHHhX3h9nd3Ds3oNtR?`qOG#Pp6%ud*ZQ}7C+VN zhqvF6g(clKaC;YcyX_}8X=3i#vvy=(F4*8>mn?f!*q6jxio`^3*%^n8mrP7)G+nb1 zOTITSe*Vjs-@k)ny*Gau=hp;)|FA7}j?3mrOSH{Q+^&i=w{JE!R&;_mR>8-JO<$kb zgOdwb`p=w~cZbDY9)w^~jn=SfsfDc+v4_{#oXfr^N5R$RKGPCh$TVynd}{Dmf;PU9 zg7=V3zcYPxb5rv&>t3N_+xwU1PdQi0E}A-arI0O- zx(gi~)J9n`m8f$WQaX@yUeyqP=k`#&JAET0X)@iIn@2aFoaJRml54|ts}%fOHQHzG zXWuk#doAqp?|av}=3e9@yC~T{5D>uonII@kr_|uBUY?tiNegSuiQ9wcc3n1a?BAyh zp40CeyBu~_TcJB`<5cownz1b_bs0Hx3x4wE{nrYnjE(flZ4!-&jlC=_!acSPR#GE?PtAvQ}r)5Bx}hv`J`<}lpQ` z>inIT?@EGKvF53di#0Ya^9=&iFE(?)ziyr_bRkYH zd{8bC8))I*V{yO5=8h2m85|1bL03EtHhX346pl3Ppc`+)-KlLOFQ;gyQ8&>4V)oRD?C+}?~?FagcVX4Ot-il|~YnG2XKfP(cIlaOhnBYSwGC)5decsSv z_X)4&fMu6-MxHw5u|*=eN3$oJ)vh`&5(%r3n=KL<#qh`XQG07Gy{lE7Yg9}W;>k8l z;35*{`t_{K#2Ey8nOB*^D`>X$07%& z!yfe?IO)>uWZsp^$Xfw_(1V*Rs$HTS)vVdA)T#Xkw(lt4btrO_;6xsC8f(sMyGG{~ zS7iIG58J5Pa*?R8FwgD5;9kFc&`DqZuBf1==_l<|af@uJ`>2gNUnIKsc0jsWW@(Q3#z}4G$ajEC~w8UD9F{d?yBgP;Dzl;8aG)4!Ie^naQ-oR2f@CNU{g|Cn> zl@H*(=+fZ*n*V+b*3E%;P5w*p&G@M71`HV>=Ese}yV3z-Y`}Xn0b+E(d%^)?d_ZLc zz<*Bz^vXdaRFekYLktk31m4gN5aR^j2`dfWg8Z)(sJH=$sh|Kq@eB}S1>dSF4c^rL z@57*c03gN+zHu0~9{l|%v_kDR;76&!MMao7fo>as7%T9GV}KYdFl&GqD==(;7%MPs zfEX(r zFmZqwD==|@7%N!UAr0O$|F0F8I6#aQm^eU;6__|cj1`zTxV#Eu1ttyrFmZqwD==|@7%MPwfEX(aImCE2+ zGmIOoR0fQZgO$pFF*Ade%78I?uu>T?@`D8_BL7|U(C07ib` z1i&q8$PXL=VB`nR05I|chX5G)fl~mC{J=2)M)QNk0U~JQ!%Ahq$Pb(ZVB`mm0xEFMt-oE zLj(l@tW*Y9;vqk96o8Q*I10eX4;%$xaA{!}_`#)xVc-Xs7KVWzTv~q_h6P+&7zTcDX<-=n!KH;^;0Ko$ zhJhbkS{R0YC^2BAGGOEfGXpeOq359=3Jp=18losQV5Kr(Y&%Sg8yc z;|D910b~4Nr7~cQAFNacmrY{)V5Kr(%=}=bGGL4!tW*Y!@q?AhfHCJQ2J_>8%C+Dd zBf%Xf&=2K@7|ajY1OM;ePYmV;kQ9`ii(L-_&QtpOuHm>;kQ{_pcJKVT0$hM^zI57=%E82Q2cfIaY-=b<0U57=%E z82Q2cfIaY-=b<0U57=%E82Q2cfIaYkpNIJYd*Cq){ZM|uc5A@M59SB#fyX=#{ZM|u zc5A@M59SB#fyX=#{ZM|uc5A@M59SA4T7RF1`2l<2F%11se!zBXz{n5g2V7d1=b<0U z57=%E82Q2cfIaY-=b<0U57=%E82Q2cfIaYkpNIJYmllShAIc9{*aR5)!Tf+r3-dhi zgG&p;zz;4h3+OyVV;M6C_iAkHDKfi^8+rezt6+`5JUL^+pPg3KbRk4C_iAkHDKfi^Fs{f z2W+%x^PnHf4_K)T7~=;kl>uY?V5Kr(%=}=bGGL4!tW*Y!nIEiF28{88 zmCE1>V9fc#N@c(pKUk>@7~=;kl>uYU7gj0*Mt(3q{!_^h+pPg3KbRl?spN;1%7Bp{ zeEspCN`BaG4Q?bxe(?3je=7N5r7~dT2VZ~ur;;C5Dg#D-FhBlN$q(DD0V6+{AOET3 zhn32Jksr*D|5WnBc5BcQhy1`%fOqaAA8-_a(Y(M>0RE2;DBU~zpYsGq0T}s!qX3M~ z6C4F#EFMt&g50V6+f6yT;w@&ow+F1|#5AU^;jKM>`Bksrtpz{n5e2Vmp}q8u>t1Ni|M`GNcZjQl`; z07iZw$^j!kkRRY4PUHvj12FOfQ4SdSf&2iB{6KyHMt&g50V6+o_ejq;pBR>%3fRP`Fa=^$BL^)vO2cjG>@&ow+82N!H2aNnclmkY7 zAj$zFKM>{MmQv&gq8u>t1Ni|M`GNcZjQl{914e!zKL8^?kRO1NAIJ~D$PeTPVB`n# z12FOf`2j9XMSdVZ03$z;AApe`$Pd8C4@5a&f40 zPv0;2cgMf^1lz4ar7y-0wp#IaPc zV19_B{D7+;F!F=>A&&9`u71GC59WtB$`82u0V6+{AL1xK;OYmA{9t~Fqx^uYA29NR z`5}(-1Fn9+$Pea+ILZ&W`T-+9m>;lU_22KO;OYmA{9t~Fqx^uYA29NR`2lN{|NeTI zAL1xK;OYmA&KKr~ILeQI8ezpze*9C!D~|F5u6}S`G4g}?0e)%;{dv$2IaPcV19_B{D7+;F!F=> zA&&9`u71GC59WtB$`82u0V6+{AL1xK;OYmA{9t~Fqx^uYA29NR`5}(-1Fn9+$Pea+ zILZ&W`T-+9m>;l_`|sx`%nxytA8_@9tE|y}f%zeh@&m4Z!07W2<_By>$NYZK59J43 z{eUrkaPIaPcV17uT{P?G#S_0(aqV$PeZR zY*5Dh{?HHQ2VDJtksr(taAy|gd6*yIjw-~^59J43{eY1l%nxwq5qciZ59J43{eY1l z%n#TK{nroX2e`8aG4wIX&k$PeZRxWfWH z5B*Snz|{{J`N8}EFBs7C&=2JYT>XHNAIuN%4JhV$m>=L9KE%)uXHNAAJ1*0tr12{ZM|u)eji?!TbOV4)Z+B53o=WLqC)saP@;b>yaPK z5AX?!o`-%YKj7*IjQn7JfWI($9{QpDfU6%c@`L#yf${^ce!$2N<_El6;_vyx{E$HT z0arg@{eY1l%nu2aA8_>pMqeK=KO|6oz|{{J%@5{>1j-M%`T-+9m>&`- zKj7*IjQn7Jz}q|i{(WG6z^flH4E<1kz|{{J`N8~vw*&lr9_9zUeF4MJ59J43{eY1l z%nu2aA8_>pMt(3q{^#0_fByRbT>XHNAAJ3Rx%eL5bPfGbe!$fa7~}U(p*-f+dvFIe z%n!_^_mH6<$`82u!SP}~|KREejPZl3A24Qq|CGv0qWplXAAB71`3F}&V9fmB>IaPc zV18g~D1i^m4@s0CaPnRST>XHNAIuMU1qbHi&=2JYT>XHN zAIuL)lpk>Q1IC;$T>XGCUmyQmxFCu01FnAX>5u&2>kmnkA8_>pMt(3qFqi9qzd!u< zD|jWzUtgFXk|;mm>IaPG2lE47kMZ|;`1(T<<;Oo40!X6#fU6&TIU+y!`a=@s$3OQb zz#9rMzaR8N`2klyVB`m1f52-_{yq=$LlWf&T>XHNAIuL)lpk>Q14icy^FtEl2VDJt z(fPvHACf3P;OYmA&KKr~B+3uC`T-+9m>-h==EwiL`SYJos=q%qiD~|X2mHTi{+#su zDiO2hb4W6G!^tEqmI6DdDQ&H6WmsFHZ@Z(Xn-;Ym<$?PDP;sy9?U^DQ9RFZrSTW~&NYmph{q=D|Pmw}>M~9JxAx)2%wXxyc zmlxk$&4mP-!Vfr0qql6eL=NX_6J}=L5}m}kMsw$C$mGw~PUE@x^5O zj;#}H^qsveRVi)P?Xc-P(p&iu-=Qo=<#tNu)8Z5UFQnez$w(HH7ftfM?)*#JJh7+t zYs!_%_aaaCnFln@Z6q2lc`18$-O+w#8M#-usqn?6cdI__EkB`T@0pY<+;VxT^Ah=& zu!HF&axY=a7bXO1QfydhS(QAz*!%K}_-Avn_syw;zwU5Y8j6O86-g(=M~0bxE6XSw z(m9?cDDdrLM*cGq*)$*GUTOISPeaNDLDKaYT(@o<-?`rkRt&ph1EO{VIj<8h9gj+P zZ%9=?{<^Q8W+5oRNKolUCuIWNsSM6eH&^Yaq%6tOl42nOArjH_0`#Ut`bs zox4enWBGI&PuL5i*So}`>&vbqM3#J^qKi(wtMf;56#EP%V#bb5-kKV}^tTsNt_?Kj zUfzhFS#U}_tnzx(aIHypKY2r?n!8Zkdt^Ly{+Fejw@#Z*55DyN!TVhc-~EM%BQ}5f z)9w^X%j$07zgx9_tI@rCw>wuo*=~_Ib95xs`-_)F-22uup2u$j6ctz)`45L{`23j1)W89eB8(s}jhU^4(e~krsG2sO=luD)8X4_xvrjJIJ6)WSG6)DB zPDn^NE$8DSZ&MC;x&vP($QLgOX$4Wbkh!?h6Wy3L% zc0tYU0qyqwT7B1#8?&-Xpz&(6x@kL}~{84BrwTHACEE5;sKd~DaQ?`*fMI2>=caV@{J#-a24j^N?g zb>U?o%1`yiec4jf#&6ok=eVe1zsQsA1x1dZ)wIbs$DwV_0?-RbJxwLDi2>r=1O|Yqy;w~uX8%$$P z+X%z8Zk6$-(~oZ!iYfS_bYA+J>8nGRj^T{4w{HrZiwk>wzkRb5k$PdwEY@j#w)uuo z5wmX=I~6_6_Y2LU?BrDSwG$*;XSPpfH|8;~WCi9O(VD(&{(5$5ea?wGRzJLpuO!jb zxArOZ=aWStV&XIksu!bB_OxX+G^*c73$|l#*qUFnwuQL7T?C>Z=ygC-RM6 zCb_0Yv)#=1oaXGgCCS+pLCd*17^HND`jXM%?DwjM(W1`k`}bTQN1k4J8ynHiBXCIv zS7LE>$D}y%QTu4SHVL+QfJc-Jj<_w)?8)8dUze$;E2gN{+uvZ7IA4xC-`W(UK^RF; z@i{=XSCcpGs-WRp95wCV-qk#-@1Gbmw)6-lsxLdL9!9cpZG^ntQXxG{&>~S)!+v@y z{7QsJ-K5aG*T#H<^W|8Qt>1b1EOU)lBeIzl_KxSPYd;M%^<4VOv2j6L^bGljFx6*Q zB32vCYQxn>Pp3IPQ@|oS{t2tOe_6Bkxf30mvf63(MMskuWRMe73UZ5RXBDdS4dAZHXQDb`muo;(`g#*Pu+zUOwlF6lwP(HSxjz4pl-JJPuIB6N z^SET9PTy-z#gnqq8Eoo|48;3hjWsQbQGM}?sv))glE$|qkLuf9Js#t)s$NC-ejac5 zdi>3OK?S?6vAc|0YFnhVR$60!-o{kN|LT`u<8z$sI?X*?R;k=^-Y-Vc>GYt#C=b25 zHI7fUb!pjWC&q)0SEa9=yky%ooW5}6TQ?lOZ|{F(qux$hI_}u!VOGCudGOO^F`c7Q zVY7XeeNyhUU7_Z)-ozN+pFD!G5A>^8v%D?~k8Ufb_Wq=b4R1dx9d;;9ic(3}eJ4=E z?M_oV;c$76;%#~L56Qaccr%eHYezD~>g?3lv#d*-ldD@e?DfjUfApqku1Aq_34hx1 z7HvGw|FFJLS|F>4z=DD2)Xdjc`6GMBaNd3jZznE$=kUR+HV})(%(OO}3tvgNRVN=e zK-@7=ma6u)&&cXn%9-gIZF4;@gSUqA^>Jhz#`71$lLgonVC5&4!>gJaV=)KM(iLlzeFI793T=eXNoO(t8PnsY4eMdH z=B6b7_3kkx!^?_yMM3?~wQOA_qy@Kio@;SEy=Hm!YruxR&rtq&|52>J+1*zupSh@J z)So)x#h$}io+SwHOk{nnPyHDkv)q9Li~q?~#yBeaYnMuX-*! z#jQmts?EP+741{1Xxou5_>5^n={f28-HJndovFJYSM7P283$slg?DeWCG9>p9&qD( zbXvH}-oJz9;BK`{?KNLjEKU5Fx?A{8O^F_Dgjcp=>+oM$Z{tnq9$)X62s$3tzAG3A ze(w{0pQzql7|XwKJ%0=rPe;P8xo&w4#{+~OKJhr`uNaaiSSL>fhh{rddMUqGO?dl0 zNfN)g7Kh{XnBtXcPiJk4y`=;!`oK1!uUK=O?^5dzW*_Ibx-nf&`us~~?^61s1M$?N z;3NB?tR>2ihTIRU8{-H~e%8v~Z#b6OQQ}!@!A;ugyry3JQpLjiI^BMk7-7tTkzM`O zqRP9!_tx}+cr5}BNc_0Xad|`wYJbIu2kS@7pDLxM-Vcr51eK|-^_@X^+L zhST&u*(Hg|oGmZRit;|Jr?P4jl53hu{!nit47+{JG#BD zDG$#+igVi{-fhWO+0^@-;H=1Y#;|5c$?NIOoZttizEY~yUwuwHGE?5b-t?MPhUbC? z8O}56uJr4~ySOBxb{D~~&`J4aNLOGlRqQKsgZ4?$+eMzDJ8MD3(S)ZILW+LYcg%|) zWm#@$X00$?GT@%KJuRSCbS0{DX7rmqk*kHhCnGQ0{mFDCPoHT@z0oF9V!^%PXr(6? z!U|%PaQOZZgy-GrKDKvDo*BPL$s#!R44$5{;tszFHny6k3TI07{l0{l8OJsU>qmHT zMr?JSc2RU(!X~dy{xm2IdNI3#r{YpEBId6zwA}Tl%>b)gUEkHOv8{OhkL89I4dIEY zja+xW<@=V_VqYYAsYHxR+-oS`jCPo((e^%PFe4$MG|UagBOyM)#bGqXD8QlA({FfX zIw`e4L&aNe#bB$kZ~pQ7H2zN;R6nz9zumtOeCBccY2BJ;ESg7jH}SkA(z4kPkTDu*RMl)dZ1**N(L_jpGq<+LTrPflxizf zB0_ISeK+c=;m*A0V$@aa;hCaL^#=NpQ#ed z>-<+0F0LN51)Hz3W6#o54G1yH-7)-f|N9SVrVCf456%s1^nK_t0)OK43%Lufb=bV6 zk_J0lGZrm=T;)vr77lgKzcScHPzu%H4GK?Z2oOJ1)Z{!V6*cNO6(*$~Y*#g`t$5}6 zL#s6YyVp*z>e%#*FdQexRsYF;Q$y>+aT>C|({v?mCi__ZZBf@LgL9kp#iXuR-fsrA zwVeUw>7P8qNsj4IsECDK9~`fj+OWO6-fJ{oanwLYvY4;ZG0s2}8{2#HMZ~$2nzH6g zekVE2d04o16AnF(ahvrm^c!7psAM&#L1oPVeO-88=;l z-G$5$(5|xG5*WyG(O)9@?6|(95W^TB1?kT!MUJMbp&!|V^`2rplxvq_%UB6<@9kSn zBCiq_|wcge15p&<%<|ifUwm>46E6#-edsM- zN_Wnb@-p6FBYoBI`e4vYAl-UJRhP)B$vn(LgXDOjvpK#@!Y$=`ngk*?UZTK>mq`r0 zB^#S(+Bb-^-(S4QI8~szNnh)H`);esK#ybXM3RiL(D6^ASw_Ka_ogW0PTn1& zq4PxXX%n_8CYRv(|4}w0E;N(y&Wsze$65VF|W_@zWRWOGC zy()EJ7Pb;~Aa+0!Cr<52>URtD-}dUu41QlO`@E7Q?5*F^ms_s37&dG3yTse~+3rb6 z+8d6tgj?V1cCkZa9a$oVW&>KU*C|e=zh~WakF8=QWPX~~uy%E@__V3&dvS^bM&Vm0 zoKstxsWv$J>}5z*wHLW#YGiZqm(Of+2a7YV)+NiN$v71R3#Y{f;n5V!?1AyW0mpw*fKkq$S`U+JY>Wx5m+T9&WDLZ5&J~Pp^ofuxBjw+Jf@nB~6e2;KFI9nv^tu%>hOq}WsK*;<`{gTm*+u|b}{+U9fz||iPgSV>}=`8 zv)=7ZEq|TAB(neR8f81X_8WIWiqN?4_9iw&HVvL`agVlZo)lIc61tz&=OLxCt1}8w zIyk+)=Th>8|8P#H(C~I^eLgm2(pX!B$qxQ|x&5SaskIP>h2-)dD!(rI&o_m>SI*R5 z*^#CHmDlC__L3ziAt7gC%PGE3L!$DVmo0EOechx(r=mSuCb+f{n|ZBkc6UH_qVPqP zBep90abwC;xRl49lFNyn4lC+=<^0pmas6lxUpKl-s!Snz<=&Et`-c;5$JA->TWO3> zn})3JxBqhLUu)9~Uowb0S}{14@Z8s5a(VJO88?qi-}RPT9W$wF*CcqgY(>I@?D6By zlBnH~;QezkEtOc(!PDpJ;~dVWx-N|%s;JPIb2$0$3Br@+*$bcF9#^KD$-TfBC++#o z__<3hEwz6_W?N@U@WtfVu*lsfg5n$QtXTtvjLWnUtP-p;yN8$Gzbo`1w4({vnKddQ zh>BX1my7xM!CeN6ZF~%Cede%1ko4nzP<7$MhnXA7*fHmD`KE}TR6U{^ z5p9n)a?}&3IraWSpo;g5$WSgNPpZ_MrJxPAZI-H#LTlT*huRfq!gaOYwLS_QY1^c` zKH`UEwe(geP)Xqa6t@j?=^e!>=ZQyyigppCJoNm_xB`s^E1j+f*Zn_}DhLh@&Hq_o z_%vJ^7(~6!6q_P#lu1=#c1X2YB>g$#1c_U1y+A)@@?&id`B6#fki(pk-CaHQgt`gp za{aA!72=@d;qCn{ap|4xCwQWEG;2BB_g$*5^-y~3?=#s|T(ha?aX)i%%q8r4sr*c@ zR^dknv);^V9%WLekU#y-@=V$`I@dN9Z?Ixsp@{%QT6s?<6Zs7Z)!a=8S1?S z{T{Yr2d}<-vVhg>MI*(4<;>N5Z*NYMfoyM6ljjpJk#9|@Vvj@ zPsA?X?DKh>s2r20!fb8a8EHb_61P8)>5D}etiNpfa2Ma={hhpzz5|~vU1Ydsn5_SZ zC;RNn6K)NZv3Bit9IDRczVQF^<-O#9hsDkXu^i5Zi6j;`oCkyKRXJO?IepC={PK$9 z^%Ik99F{&X$nVXWCQLHwcezIXd7&Qv?8@xo1Me@)pp&H>OQ7(j%gXrgarx-V$ca01 z=Y09r$kfmGWj{+!@Z6_QHRAd~yvBI@GV$6G4NmF2;z3JW5Eco}3A{85Cl4z=%Wkhp z0uhF>=()&=@G#E+qljUdlovtgLMh5}jyiHZNxD{3wjMgY_5+?coa{`YSnaaOpTD|;9?JaBgYf{ zLBLe>@k;xjxX`a3C3k2q$M83o-XAktv9ZK474(zLTH4L>zNBs-VeKGS@_;`}E-}V< z5?5b;z}siT@j+tV;PIU-zP6bd;}*M5_ulU83}s&B_?{Gr|EJ{-tD!(n?gx992eDi@ zhi>P;2LxpQ!F~|dPfTmXGi<+L?mWZrl5>X7W=LIe>!EScAv{i^}T|Pm1?{T{pMpdT9W~rzp9qM z45hrfqg&xo@i_T`P7=v`cDfhmEvp0B*e-onRg&L-V$iGVS}l5XYsfst$FO{kK)ck(e*N2F)Ft2!%FKT-_<%8rw684KiLUhc_DtyRt5L__^FbItI;)9 zlQ>tSV)o9b-(mMq4zm6rDjwz-{vu$&NbsFub?8o4y0 zxLQ2sDABp8&97h%DwO?rx|}8*#rG>YU+3nC2~*=QQb)9M-WY8bG2|Ga?3^XDe7s!7@X#5@41)aYNfzwQ*0+CtrdE1Xb#AKO z>}d26Q|+EQ!w>1;#HXujtrAtLz62$uj1LpOGEMq7XQZ!xbK6Vak-OXR)I{)MSNOI( z#f!;TT{4RxuY3`dgN;oHJ1BMKyGG3pBu9;$4o^gNb@3^lT> zy5elgOR^V-ebZXL+?Pn)v}h-It%&(SW^UA$iwl=r2>5NoM+pLX#(bzkN!|>vN(v8rq*}jIk9%K+ zicNYQMtnv5>|or1a&ih${is2+<6;~v<)L?xGn9ieps7@3#CqQfFj|`>LzA0fgCG^n93)=BCD^} z-nu<>Memwx+R`Ae7moAy^Z-1^;PbuMQiY**y7vSKeIM1_ZBvN%#jRh#egD<2Bqi&T zbhz(lvWuSlEn}TCZfbK9Uvy|{#felT{EWC5n4`Myf5TVK9}5cW8k#fBX^&16Q*|4! zJ)!<`#wyD|>6}J2_9^@GZ#Al?9w~56WwFc`Jvfup$j?~Bul;Sdi*(NP%9ZkKp#@)F z#l7^|)Zk95@te=!kkxuC^IR+7 z?)KGjG?n?n`O@SX>&EoK+oip$a~GVC>dw52pj}RFFdhCs%)NOymRtDuZ3>ApCSxix zBr;{l91%^%REDA`WeyoKq(VrMp$wHWQ-&g`q(X*Lq%uork|CKgJ?FaK-@exM{_z~o z^VfU4|LlEy_oeN-&wJhLd!P3{*Jp+3KJBJ9BU zJ#0`?R=mWgXJ@PHBqXl2bAtY{sXUFyiB1~!(tAgh7CtylXwFTswyZaLwKqJr^7zV* zjftPdYhOoBo?Wr_O6rGQyL|?Ruh;e`Tg?fFuw?FVp5Pm$U#h+R;SSf?Plwjw_6 z!MOLISmBf1VZY@@TMBy8^|w|jSF48ZepLBg^sA?CYOLmd|99`)IcMM9zSB3v_{TuT zV!Nuy&b9-4q#mC1eJQ3PUTTn{k!={rHr=Io<^1&Vj>SB!rj&vOtDGHE<-DT<)2sr$ z*^1##Tio~XS z#>@9lcWMre^uO}VJr&)`C%ye!$$_4~LbQAB6_mtE@1$(Yw3=UYqL-Ot$rZ@2$?Coe z2c*h2Jnj4(6hyD&T{)GuD~@|9PN+pTEifx&O^Lr*4eidZ*G%g*&Fv@auRYZtTD^X3 z>&WJHu>y-xsW17BlcaK9^Cc-IuWnXOF*am9EN1>xBWu$~>9eO2c*PYToxhxxU7C>k zUgf|tC+?{1^)6jB{oAd(z_ntBq^y+OkY#g#pKpx<{lN%?tkR> zkE8Wk+b`3Cvr8v(X`>r98r)%hl^2#67QZHk-+wVpPsel5S3#6cwh@2b=y!_j-pS`? z^i1reI%ieP_2}a zc7E@Y5hIJ}BLNBfk5vUjspnofD)Xy6+{e<$(oW}UA!Fo!O7Ind;^P( zn$_W}PwLhW33}#BW?iaevj|*!^M{P9vNC($j9Rm3)c01YJyW+z(!NNX{V=Jsp=#&f ztCMMeYiG9ic;{Hj&t(PO~snGIee)ZH~1_4S*;9}PWu>nabEq#HkvAM`zQ&tt|pa@!96oO36-JA%BXwjP+fdihj) zRcE>K^NxXsQ3cm#HA{>bX++lv&}3}fB)u+dWMKIZt)oF4n+MiiH1U_3oo9?I7_J=B zkl2=c{c@?<@x0=hjhxABrbj$YhZMHP<)%f?8Xns^q_xCvDtz-)pU7QnOV#)X0Zx;{ zZ%lP)bDJ11M3g&bwjDKn*EF0QU@WuWtyeeuQ1LC@7}v_l3(jkp!d?%#?6uA-0;et={8n+-4QMeftDj^m4CKe}yY zq0j`E)7XrG)kY_qiVFvvb_0K)7K9RRROXPK(XJ)Got>iDp z3!_J`UV8YK_V~3Ke_1ZZqpNs+?%~-NayOPK?lW8%^6hdGxAE{fH%F%xRtMMkl~gP^ zv?dL9zZ^G8{Tbt#B4}J-9TXaCX64g$d`m%e@w3+6FwH)h+n&{^$MA9?AG>oB>VW|-YbS3Wv^~n3^9D=$C%kB z!L?`PZDH{9wR-JNe?*;^U0_dLDdLmiBmP4Ewe5pZdWkC2s>h+;RnD=qf!?)0`nNM# z>kId?>Mr;5yU(w?P&E6lBFFfR=h4Z*oA#nBFU=k0Kc6M@^xDFmhX*-BX*T_%XSj3K zFsG~kZFGy~ulF;p&*@jp(+kV3n75qRCFXI~G|^G%=!wZICJxD(Y|2XoG`xc?&O0y?x=AI znZwb+p53lK`yQm9>WQ;6DA9O$$6sYL59>bj=ZD#q^1tMSe5MJ`Dq*hcVz{BKKEsjC zn|{PsfmP<|E2o5;y1VkO`)$p?ULo)B;Gom41CH=!<9~iG$rq^^m%JbUf9a9Vb+6{%>Yu1+TIX3x)d$emfH8M=Yu6^`p z^7PU4_6dtqJ?Zzq$Pdde#=UzP6seOZmAIQPOX}Mn!#9rVUmCSite&iv9AS(;{5Yws z`>D*Xm+qnuHoVMy7gXM}y|B``cvd1_$huMV!t>*<+xgdsoajEx?&TQPRv!PBmCe)4 z^0SRd^85wu`l4!>Gv_E#{0^`g_BjJ{7JLbNY9rYT;aDn~b@@ zu)%ZRy<$6FuM}`*2xkv>(!Te2#UbU}Q_L14wF(&$M?aYd^41P>w1{mwm~y6Z%Uk{{ z>n^mau6HnubB~coq5Dmfy5T3wS*~pc=5OS;gk-qJzvVb~+5f4k0r#?>PX+|5H+_(* zQC;trxR^4)ZL#Qc`LJqU-7i6%73Re)s_XOjv8hf+G)@1?IFd7U$xH8ziTAQ^5qWwB zS!o*@_|wcz$G%QnjFni^kmh^2PjE0t&0s*RfyV3dVI`w7z(CI5H`O`NXCWo;T4nUJ zX2*szX6^S|#v>jV+lkdNKmNNa$8*j?O&GwH`KQ$ZT)F?p83woE{q=I^WEPa`z0k92 z7W7x0P3W&zm8S9s)_hs;?r|snSQ7eUy3(7IeQ)?B5dY%1%?oQyh==Pwp1Ba5;qKZP zoTOfAm-&?=dhE$J!RYkg=;TJX4Yn&6V zGWy7De8Pk6dBBEGqiseXRr`Wz^pyi_|F;-SG}ZdwKqm!*`QP;L|1Aa+20-^6@jT{w zTI7GmQcaI}xp{j!9P@(v>ScGh!2|U7|L-onheImlfGj#*kB={)!}a*^0y@NLz$#2n7;-|x`Od*kfbX( zy#tbT1p~eyNmnp?4U%*Pqt_rwS1@@El5_=w*C0t(Fn0}-bOmGAa5R*31yk1`Nmnp* z4U%*PGuI$VS1@u7l5_5)*wk&Flh~vbOnRfAW2s+XAP2c1!LAANmnqc4U%*PliDCjS1_mzl5_=g+Hg#k zbOj3>BL)x`K5Ml5_0SFq4QlCEH(gCt$SLI+8@f`tx8 zhDlej&_R-}V4;H~UBN;JNxFiC4w7^Q3mqis3Klv@(iJRpkfbYE=pac~u+Tx0u3(|V z={3?7EOd~hD_H0tNmsDYL6WXup@Sq{!9oW~x`Krcl5_0SFq4QlCEH(gCt$SLI+8@f`tx}bOj3?BYX$1CC0q^Pr_EG`w>jd^v0q^Vt_EG`w?F9Bx0q^bv_EG`w?*#Tz0q^hx_EG`w z@dWl#fwIe^ZC-)8&7-{T>nI;FLT0vLb>UX!3O>u$KyW%a=oYz5?F!5kU?#`O+eS9BA^j zMFcs}xgKmkVpBFKTp{!j=g;1ECrIndZ2iU9>21Bf688v8>* zpn!vbz+NigBtQf?c#i9bvOoc60V2qOCf^>2AO{-zLveuE8vk?52odB!V}B?R5L<(M z4*n2ZgVf*;u{B5y^+Rk8QiDIl)*vodk3I;_S42U2H8v8@h zpopUZ5#&H)e<&OjaX27?9BAwh#e*V_2Sktqjs2m3P{aX&2y&pYKNJy)I3f^14m9?M zLV|)-LIgR`*dK}s3RVdb`A5J3(!_J=})f>k20mlUiLfxV<)l@LJ=jyhw1 zC^#rsB}9+|js2nMpkS2{K@K$bhr)w`RU)vL6s!^=$iZ{G{!o5Uuu25>l7dwtu$L69 z5`n#>V3i2$B?YTQU@s|HB?5a%!735hOA1zrz+O_YN(Ak20mlUiLfxV<)l?d!5 z1*=40FDY0h0((ipDj|X#P(#S~FM++JV3iO-4xW?mUjlnc!73qw96TrMM_?~0SS3V| zgQMu={(=Z{pvl*lz+O_YN{Ao_&&k)9z+O_YN{Ao_&&k&p5#&H)e<(jFSS3V|1C9Nm z{Gec!2<#;VtAq%0KuN*=P<~LbN{Ao_8v8@-0|l#u2y&pYKa?L7tP+8}q+pd0K@Of{ ze<(jFSS12`Nx>>1f*ep=us@U^6s!^=$brWGP<~LbN{Ao_8v8@}LBT2!*h>ml2@&Mr zIrfM0gMw8eu$L695^9(MC4l{*{Gec!P}2+=`$H`S1*?P_XVBOmYAPsLB?5a%!78El z8J=T*sIQ=4l?d!51*?QwXrS6)e<(jFSS8d%gU0?)eo(MVsEr1V{h|DzV3i2$B?YU5 zI%#;0{h|DzV3i2$B?YU5nrWcyV1Fn-C|D)bPJ_n&P<~LbN~oa*js2ngfCm1*JVh-v zXmWo>JvC_T59J56i{#Iv{D4LcYvd2-2kNUqlb;VzV+|VnL-_$8$nl>?{&0Q}*h~1p ziJv2XI6qK#4I2AHT?c%CA%7mV9q@qxYvd2-2Z6nWK*Z0HKb#)~_7XOH{2cki`9WYW zDOe@cX2Ww_Ka?NvhQ)s#`NRDOfxUzU`QLK_dkG5wYg9kne-PM9_z%R-QT=fLL0~T_ zSS12`Nx>=+*h>mliNIb`uu25>l7dx2JvaPu><@jg4N(dT`MA_rqHQG`YS|7Y-B+%I`)&Pyy7rZq<>x{)Ew*&N(-9wM_?~i@Ry7P_EH7sKY_he!Cx~H*h>|h{{;3@ z1?NA3y;Q;ZPhc-qaQ+k6OBI~|1olz|=RbkHRKfX=T63WMko7~YIcTzes5J*o)(^Gj zpvn57)*LihKh&CoChLbZ!KsmzxptPW|Ka?LTI6nyNr3%gu)SAO{ z><{IK3eFGInuEsvP=2W3{6MWaXzUN=hYHRQ)S3fz3Hw9&p@Q=RwdSC4{ZM|W;QTZ!ps_!cA1XLM z2<)W_&JWa@!*l%lqWn<7`9WYWRd9X~*h>|hAE-5lpU3MD<%bH+4+49sg7X8l=I|W* zL;0bC^8>Z!pmF_BeyHI5K&?4wTtAc_DmXt-YYrOM59Nmn&JWa@10@UB59Nmn&JWa@ zgU0?)eyHI5K&?4w><{IK3eFGInuEsvP=2W3{6MWaXzUN=hYHRQ)S3ge3;RR)p^EbZ zwdSC)Ka?M;I6qKp4jTJI`JsyQ1GVO$u|Jd_syIJTYYrOwL;0bK^8>Z!KoP_KP=2W5 z{6MWaXzUN=hbqnw)S83F{!o6X;`|`6m#R2FP-_m)@&1SMLlx%-YRy68^@s9973T+m zy;Q~dL0~UcaeffkOI4g71ol!D=LdnkRK@v0U@uj1eh}D8Rh%CL_L6b|B!Ru8UI7WE z1`$PFbxf2q#=Af}ZlpmB^AyI1%8v8@}LAe(awdSC)Ka?Mon;}ta z4jTJI`9ZlG61C<)p~L=Aeo$_QM6Ee!><{%Hl=~r3YYrOwL-|3uAriIbps_!cACx;H zQELtw`$PFbxg`>{=0L^6{!o5U?ukULIcV$;A=Af}ZlpoYvBT;@(uZ=|g z2ld`a)PGPfjzszK|GGI6`NR2vT656k=K}(JNxeK0myNX4w}q20((ih zKoYg)@SNOVP-_kv*AL|fInghiU*AL|f=ocw%6U@s{bNut&q zo@0L~KPXp864*=1U6P1+49~GYlpmDaBoXl#sEXJh<>x{8vBF%0FC`Yet^dQ zptPW|KZs_~*dLS@H1-Gi0UG;*`~Z#pL1}?HiTyz|gC_kU>?LT@AHrUOCjBAoC1}zg z!d`+V{UPinXwo0TUV?KezNq-1?2^#x@(t^hRptPW|KPW9| z><>x{8vBFNg2w)!w4kv+C@pC04@wIf`-9Q~l@t4e(t^hRptPW|KPW9|><>x{8vBFN zg2w)!w4kv+C@pC04@wIf`-9Sg#{QtRKncbEptPW|KPW9|><>x{8vBFNg2w)!w4kv+ zC@pC04@wIf`-9Sg#{QtRps_zFEl^9bKPW9|><>x{8vBFNg2w)!w4kv+C@pC04@wIf z`-9Sg#{QtRps_zFEokfyN(&U#|Ht3|0c(j&{Wk?kVlC1C3;I7|E!%8tQaa0upEcjt zmWg}0JC=u&q3YhhnGHT2T-)w_+T9U9pxd7LRINS1dZ$2L#dkNYWZLDdqU`LSd|1@a z@^@BViSSbmR6Qe?Jp1R1U$u;nwB3h4OPd?pN9^A`JAYGCJ!$FOQkqs^ElZhwf>lJK zl76v-O1|f_9OsWRm-2q`m;KiAo2*Y_va{?Wwi+kC#~NxW3_2&~M1!qW0; zyhiWS=fC^HwK-hMC4RjVAFhZj6FJrYuc_D|GV4M8z;^|iULK3moP||4zM5ui;Fj0W zSfOI_nYBOU%R3MK104e<;gMEjA|F4BT}pMYdG*rcG@I%Trc=eTW@VE*xpg=;rC84X zV6Br(Nqu+emqKf-ouu=2u9hcPb{;#a@G8|fp<*|;_>6D8af;B3Ti;^*UhF;X(vvt) zzfG^Y=Gv3oC(UV%p=Y|K9Zl)(tNpo^KGigyS9H^?-lO}6Z)BAG%xmG@@!tk&&JOFZ ze6_;0s!(V~=t%mCQTp#Mo_znQ|6{Pu;pC+Qe(Ha-7{14VRgT>eW3fruT|+ODZD)r z&%G<|r3x`BvK?9Nd2*>HkHt1RCh+uK<0ST;`f1}b9s$|^Wo=GYO zOvU(mhgJUu7l*Txf)@tzlWxw(EEsEMirrFt%ei)9mGYZA7aZO$HU!P=T=bA!S_*Cn zDgUEcoSmrC61`%kxpRB#KycY`Bk#hbXVt%l!H+6>PVHA-2&#O1xRdAJ&Z@xq*tq?} zlY5>$?Nb#|NwwSjY3|LNp9RAunHNHyhkNOX?CqZCZ{mFW_qCfj%otpk_FNxmzBKq(vV6-Rzk8D1CO5k_Zj~S5 zpZ-+4lm_|v>|InG%{$fT+H7QX;bFUfaBa#d?>AHXHGX|cVhu7W(=YR@d8-m3>RncK zPEMoK<>P(ce;-f!Hyp9C_UV%`Q?{uxy;vz@bH255#8D(7eIs*(9PhH+>&#=dm2X8? zFa45O7Nf1+^^ATo_tL5I-U1tL#h$1WEPEJe>NC!t-$5hnrd&0Ba>~B+$!Sye8@>N} zv~!c~_AS1jUJCx2xi(Tf^JZY2e-B-up=*QX+@|`ip1od(l%U^KHg${zu1Fu4420B5|S1Tc%jW zerKfN_Hpx-iEfvMCmZy))6?)6y5)AtN~}6DXD9tBDMi3%sXwE4=NapxiXrR~;c?Zs zGtS@jh)@-gI@w^DY5ldaTx!?9omEcL$GBt9pFaD>a?V!sy^2hwhlg?Jjm+zFnlFM{ zif*JapX%;9w|0kX#naHfe=$*eJ`AcBw2t~uT0P0ReJUd+SgPV~ec4=Q%5KKF&goFC z)iei<#Q8&b7sTcqAC9D{XEaSu7^=~nzGk3EBR3K8db4mYuS;7~l&f&BQKH|Yidny} z>v_9=PiS-(T0V8G*(??)JGgpd_Mu~MBL?Yrt>fcX>?{hRta zD)V|Qre0$|>Z*4FbSE*WK#uuG-3B^MPNQYC#=0MwKMM}nDoL`d^Y4*gW5rogE8@sz z0DnK-m&HD@K8@**n@gF^z2NG#)%TSTO?g%IPIq45bbs{vvmAX}@{n3Au z%UZ3^r#`XvT$;Yi74)#HL2H8b3Gd%09Xkz}4Mo-)F>)H4%VewymohfJ_*%R6^u%gg z)*Qnfi(~JjX?f~Zj+=avU(GL(dn#KZ_eIz1va~Lr@TRVk^v(YUlKaC7J~UcNS$#Ta$C#<#2?bpOrKJ7jjKsX- zia95`<7Gb|v7 zOLOCCpFwGsQ+-ia>6AUIA9WPZ4ZrtXcpR=o-~4&W^&{8#^&4@r%O%w_4ZEIYnLgGL zO}?OLACi5@v@Rs?$7)8S250%HHU;syb&R124)PNFHh14*pXe_xdvLnqJC`tL;Hu3F z$=8h3bB4skn%<>6buH-o@_2=KF5mKNk|Qd2tOTzb{bFR_v~liB)J^NVceQig$8$1; z=KZR(Ek0^Do#VpOZmW7B>L$0~v+vS8iaBpx-$kgYl%Dq4xyfM%?a_@1PRCZf2(bL2 zvfMR?_4PpiGwIUb=`kj4&b_^Tm&S*74QRW!GwK$X?6}a#Axj%poHZ$DCYP?2!Xu;8 z;}UXR<#j&P+je%>-bZk65l5}c^|Mk=uFl&og z8!^&JJvhm1e>sug*g5HBMeH>{_gy=er9YVVJ)8Eg|?gUd{6yhk5RvG=}v#f{lS^e&prUPW&zX&a!H}ipeJTx*r$sIfbYijm?8L z^jxoP_R(BRaMBXxqml0Jrg`VU+~(NYsJ2WuBr7hox}{r*Rj$?iJ6`OcWmX@;ePPyqmw6p4Du)NrYJ0b=_p%~-|%r0b9ma^MHa^DVxt57hE{nM zJNnxl&yLOx{XTHrX<>@T@k@7}*zNd+YcGwWG|UrO*C(F4$1y8qpOE*E`)|ga)v{#+ z8AYe|jjOFM%zNqV6x7o2t@fZ$*1N8>qKgOoCQmOF*n1ddWC`rs!`{lo@U!;e%eo5< zhm+Vp?6Z<|q=|?N8s=HKPH6G1%_${+=a9m#nvaNo8N*((T(Olgi2<^u9%jp?C8! z_5*)T`POuqpPvfwnQD={`Tcvxe6sSCn(>aL@|Q`c`>Yq*Vm9Ulzie4G@iE2Zp43Bk z?}HaVa`wyabYf2)AF*0I=vpoyy4|*{y;CTxWz+L0!!S=D?X$G}r;18WRX3jKUM?lh zTRI_RJ{#SdJXSZ%kt#Jezr5hV=lfgq4i>-U`Q*6p^}51l`{c)a`&KopCyHNSo@ab? z>zS5rpQ>l_N(Q~&a*-`_mz(b%;(l8*M04Iw*_erC{U{tePkf_h+%0>)y!J(SS8#!| zw5QEj7uRd0Nvm+5mBAK$(%IvmR>j^fy4Iq5Pb}PNxYBmB`i_-z^}CNaPua4p*rT~R zTP&lhT4vV~dWK~FD{2gSQ_Adt)xy%BCzb^~c9%~o(RyxOFQUyI9H#xMNzBuDOtwKw z+AAZ^BR@8&b6`1uSo_`8uX6qFp&6SLS^9f2 z$zH3YS$x%cz+i9;$IO147EVuiBsStGtk~-%EGIM(skV0{=t&)izH8J(&HU+z?q&Ce z84OB}1X^?5c+lGAz0aw!&pN}}{aiuW_L^PKWkcH<-Wlw*F}M88p?A-%^N08*yQV!Q z-&NejM()b?=6XeE_@p}sI&HD>(ohMtvQBZH?^yiS*=d{BZC0~O_FtyLBhxM172?l! zEn||JJSn(1@ATuM-;@*YQ^`*HPz$M#X1nbUt@XA(cJg0^^40#ZS_|DCOFKie@#4X{ z)V9OLeFMY8D?fVwdGpw@S$Sr9>)dR|S%0RXuU~KXowoPTk@^;UJhfpvC;fXr%QLwl z`}XN9i6*(r#g8@4)raT|E^tIg44yTy`V-XiGdjW`Wit5py0x1s4=lEnuGAHdh*c}B z@ZC`nJ};yGXMh>bW$3XTlF>gKf{mQ~y!@4W4d zbgshUr^{)h%7>&A6pQE0;>Tr{&c#R8@I(f=7BNdNJy>X60SrU&{@G&LA}?_^$vJvj zQ+a0gH(es^UgyoNZun`IZY(~Kq!HrCZ~gwm&Cid1M2N3je6=MsV~B}u&6WbXa|&Nq zZEAn?dPT~XKeZE2p2xXQmF(epy>VqF6X%X0&xynv;otTdpAjxTvzg-!8|$jX&P{jk zNqOxsW1+dacYn@KCYtrv1!x9Z7I*cWb*I05c`9(!aSOxx=ZEXHbsl)p>o>91ZvL%) ze<<5H@Pn?BjB2CKNx{xnd%Tvr)qRXn_!#9vZIG+) z&Fz_Io#K7-H}}WsVR5=A#Y^Kqcb#@NI1?-IB6C}S4(%7S{`l%piE+m8lH-5s z1Z88~~<%HUpmBfoL+HY>5D-i8mV zrK?ANS8HsZ(Mfq#ocSop;#J1RyMNZiUmHLE^!2~rZ%aj9w&!FI?Lyb>3EmqOYK9xrZ;CYd`npmYW{5BDX{17DVH-%{yryuwa?CdFh9I^zl2j#*n>A) z%np~EiO1=@*R)^v{$Y`c-0tnOV|D8MQoG|D{L~ej48qlYZM&>`Gz2K=HcukSryjqi{-;!<}{XOsI8#_4yp1&w%-^IitWe>mCcKN|HgUVR1 zkYkUVqK-58Jd+Ne3Vs`4*W{+%(HG3K+vVdYC*2(1;a{7MW<5>0ez88<>F0?2b*uR+ z%)N|JeODjT(x%S|*XXf}G$`xz2^-SMcI8bU*2o=*D_PK++&X1o-KcM+VYp3BOYD~W za7X+>mYOxTZ3&}Am(HryavZ4VD+{W1ZU`&8lC5XCdt1tV_l=MH8`B&)qslpHpQ={$ zMA2zacN+20bUZly_k3{C#6smsLnqITVVi!@pGt^c(9>Bv9D6;#fH6~Odi7>^Po8h1 z8*c93Tt+wPvCl?G`8=!FK8>wMQ@3w--fAn%@^<5DWzqf$0R2jtihS=dgV*@47d@S% z=HPIzrpT7njJx=0GSUQSgl`%&86^7H1{Rny)ajl7r~fN}e*YVt{JQvvoE9PRZoR(_ zK1=*7jbiFOehmg0&M)5U9kI-*E(lilYTLcxZ9PKhj_ILrJHN>Kfx~&hZQnDk3X4KMw1O z7MDw06R<(ETV~6owx`S9!SVOY>Q37_NoQt#GuC6?E6eG0cefs!TD2a-1#OM`-Sx?P z%{}ZFe`h|K^Yh7Fsdc}2?9(=%wf`i2+XW_D2NS=D_}(~2_c}XKoSws^kxfr7f6&s+ zgm0>8WZd2En`3`$->2{k7J_%hK3&|tcH~F*dcW@3UmBWQcdI8n&~$>YD{L#WS-Gb7 z&s_T5K0R~t_ahl+vmMdP*hcJirCp6{ykq(zm$B_w6DSaz+ovt&6BG6)<$aWC6$@59S-WpQ9erUls-_Q9_Q**Za!!tdND}I0WWZIl=e7J1zpU`59 z#X}aR^p|c&*yghKOCH|xC$4bHO3c_ctI9+FNZg*gt!Gp>kFI=dk7)*+WPRU|SHi^XZTBqbJ&U6&dNWC9Ya$a{&cj9bR z-O;A(Zp(+WBM|*7q_i*M8M9*LlOH%#9<)3M=-iuZ|Tv__TWSHOH+Y zecK*fSxKi?sLUJ~)7jW^;`6s%bIn(7_h)Qb77?r^CuA5A;wBR5x4rldU69!uSve2g zn~`Jn86}e1GOx5<8kmkAKJ&puzUg@2sUH%2zsG%+S?v8cnHit*fqP@vrM^jraUH4p zlM{OjR>|EGvD@zQPkY}9TY9++%iLBH1>Vr`xJqAXJE5btM2qiZoB6maYyU5PJz zGi=kcqSozE&y!<$yPw|OAfm9JQSX35Ypu_B-tT`Ihp#K__iwJVz0#bjHs@|*6S}a6 z_wq}&O&zptpMT$n>jg&J{}|Q<=9R{Gj%3_?- zW^!H`Dm3^sN4`3`OPv3aoJK!=WJ23n^SBCGt}kIF(bjkVN$glWQtqQJb}6^xLXy4S zuWw0x`VJln>+Mda(9fT{=w~~S`+1K*lyhgZTdzpv-_EEQ>tnr}8i%LsW$9gbI~k&c zv%{8|+>aTp%l~I?Y4`qd>jAodtT87Zm3I^mDzR)U+LN(RAk(|9J|xkl{K7tdW$9uW zp-tjf^DAQ;g{IFY#TqFcdUDUXd%H)ZTC;1pwcVpbf~(@kMs6KFfp$?j{fgZlmmDbhuy3Bgo?K>G+GPIy0v-BxQ&+t|V9_{_)on^jlx9vU2 z&TWb`33ggO+gQC~Zk$){TfS%g>ZSD^CDkJA{cxm=&wv+t#1Gd(M zAzmL{GfcM3D5f6WC-SdYXPqNk-Ost@J59WPiGQf^NH71|G-j!;opS<@X zKH}Av6ZiLp=@j*}(S#mXue?#Ot^L87zS`ILvuR=JVDl%9ZNaV6MMGalHY+Z>DE?Gl zNIK%8OHqW%%aRgkfbAD$mS$~!);&*?{o;OJe7=7^=ek4k#YZDq$6MJAQ)0GF81AmA z>|3#0Z1w1!ys{nZAM^;g>JJ_m&9v7_c=&MP-eCGRC)0Ht`_fIT&;9Hg%8jt{EAfy1 zxHhx(BL~~y=D)&|#rxKcybF3DwfdgYt=J3h8*MpR;4AFrJ1x`9dJ*S8#N=pj9FZDo zO}x_)=sPs^Hg~NKg^fJXldHoM9iG)@zN-Xd4yL{I0?6qqz{{?Rq z8+`n=|3~V1ukm}W=K%V%JeT|4ZRY!}+zfw?$v@q?6TSwzc#_%tgnd)*(!%uMRLgFI zh;w^y88I?Qg$ZaySlueQamBKGUYDV_ph#1AjPvv?{X^z+qQg`B2i*O67ianAloQ{E z?M-?t^u|d_q0(K{apH2=vu_SkJ>I^@O{I#mzDsBE5A{3bjal1|?^}OYK;qmkrJl>q z{<71jy@ndmr7U~R_hmrE{5L4p$+|3U zbi;I?>BxSkjB1+j*iciQu$<0UeD)hf@?7^PC^z?oUDWel@kZxt;0JTx<13}|wiR)_ ztub3Jqn=K{PhY=?_ze{FB@(jy&}>u6{6R~ee@x7 zVZ-d9g;i_JCz5S;MZP@ojE1T0jnIv-OP<5$RpKwYYsPPL`BML?KUnX>R;$!A>A`x{ zt&(y=A`uTUVH^xl`%|<89CW34!w~&9>HDb=<4Enm4nfY=^Wt-w8!K zOg)Z^B_7FfLS+ zG`61jY-KtfQOj_U_K2YGw(TD8JjX@(H`S(xH*c+4Ijh##%@gpxvChoA-Ocs-p*J-- zyGp-tMmn@G-ezQ3T9;UTCgFDKgK_ijkF`t7tWNay7LC3aI;bos$@)F$P>IC86P@a8 z9ByR?gtYbN!rPeojwuX0;&H7D7db6MyHitej@yVXZhtLn$O?UJi>nJm8Ecg|MuyVg zN!yQaTkj^ozQ?AKjrsdS>pT(mtDPaYu08Di+}oQYcJ{|zk!7K==S*osk9Q7uL|hNe zDcgKwHf>pxpVAaV{)!J>dE!N%64raqZslE9ue6ri*S9AyqQWt%>)5ufi*rm)OJ1WV ze?%Oc+F?<=;6JfLOmwHST6~mBm#;?)*PfH-($2MBs*#NBD>P9}NaLo7AGpTC_~1xZ zZQqsDRB>Z&y6z8A@_aNAJ%zLp2gb|%?HkriY8Wv$sdUwqp;C>krX3 zOV6I#t1M)XYI?WCJpLynD-@N_aiY^INdAim!$w~D1Kbh!T=p@4%1slw-CwlMvE&hZ zZf757=?53@m)yE;OG^gEZGSRexklN4Uls6urM_=?S<*43vgtXW?tI(#%|(BB84Vp| zPn2K2`z^lLL$`QF{Cx$R@E7a)>Yy~SD+LRB-?vT$2S4nX9&Z0R+169Px50m{mY9PU z$D^19xrz9;5!12R3fgInn#41gzh!6nWvP6h_2q1iDE`qCm~Jw0edRlVSH5aKzTGIy zKt$YgOOU5(V)VG){jIh63}?^Ijov@(GEyL~O7q1mIxh5F#7Blp5n>zi`7)F1m9ien z1kmv9Y&4z{w@LU@@93o}_()$&%Du1bdl6%^sIpKRJB#t>!OsWWw#u=^zvqja*vJ*7 zU@CUV;mh7w!BO393D>S(95jFSF;VOBQ%3QcNxp#g`@WpZ4JX|_T0&mlHND2jYX1D= zmRAK_2V6Ebj;z`=VE3Tg-haX3^rTMIv-t1XYy1b^IIT^MIi$kUEVlaF9oJXoW}Q!$+nF8SC1;{$weOAptM!gDB^?G0?2cV; zmtv*#^$+E=*6p!7-WetwC_ZkkxwSgrSzzhWy<30vCVd(UoT^;z^Fnf$Ovj7Th?)(# z4+?e0#QE52liKvk_N&#J=^qkUa;FbeEL+~KBXv}XXPu;|dVbmIqFYjBwd;p0Qrb98 zpNTuU{Y_Gv^^mO!s!M#nH!iV)^~zlN@DC%Gv6pp4dk5YraMo%h-5+IJWR|*KU?bXg z?elGSslAVmPlU+?W{+JvT63GN$15Rw*iqcu#q7Du)I$dkqxCidt@MMPJAUOyHVvFE z5P$Koc=3^cN>~y%!*9JyL2AtGKRQI%Jwoqx{G?f~^QLQekj#VB)8C9-qhnufw6<~k z^mJZ$M*WrJu>+1X8fsf6Sj?4N9rl(Ud}(pE+^^tcG~3jZf~}i}uibV3O0V1fBYwksN(A2}i&h+c zF5+K7yTLi`j=ySz^V;md=Nz-wJ6kf9UB(u>&(LG@24`2L24vj+g#& z-9M>wzbf7^i~q)Njb54F+-Mi&#sT4-l4l031Y;t4I^2W#Y1X*%%Vs*OxG3eaEiqnr zu&~Ilx0J4-uTV z+!MiVKQww>KYMwL-d!oYoKIYVuaiNXE9w`==FY<&M(%gmCB`joD$?n_+t~BYt?ey8 zi@}0h@-@Z8h5Mohf&6#s+yXM=)B@Xcfx?T-4Zw;2?Q(Ntd zh91xL{eB}b^&599Y6U^Qy&o;Gpq%M<|HlaX? zA-K|JWc)%|5=VK|%WJ>Q^y4_?(pWy|)14JPnIC)iQqT}b^1Iyz&byCE$?jZS^M}5t z=frfuaS!7RA18BOYiUO(tJU3~_lz?5c-9?qwrm}@JbtkFk>vX_HmNV}#@Dsr{{Y)- zn3Tm#T5b7};nZBb;1c}hV;VPIe5j=qGka)C*HZFVX({){njgv1hy5#cK8l8QmCDz( zb$#XGWUZSC{~e?nZ@uADc)N4ViTJmt>giUx@AABSnzquzZi{eSk7%0Zxa|C zxuZ%st{$T2RI$uxO7Fie+LW~*8q+@ddB4O+)i13D^JBBy4s5hLv+9x9Ihyz7N_29K zJH^_{RX?Rn?)|4xspYuJ#%{Y2`&RDIrr!d*u>+qUW&EoB*c4taTj#p3H2E%HKu?;k zn3m)3<{AFZQah8!=XD=S?VqkwP=22yxz{asHd`>Nj^jY5$ZEs)mWg|Xd-lHaT<;{% zXc7PVO^xhu{U64D0pEQJkMhIaTAqh||HK%Uv%Ie5zSmQiRp-rgQVy!DN%?iG?URN~ z-r=@~T_bgOcZ6z<$!4pC?q;mqxmI@Np`Xi^=N@Eb`)&I-X*e(}oaV+UiJ9bW<;@?Y zH{Rh}61De`&oCEYo&OSDQkj!&8FOOI9#Q9CL%~1$xsR13nZ|9o!Q4{&Jz28G`HR*3 zy3QjmF==$!o@|xC0=7*)^y>4Ckw8DMReNl{_Rse$2r%X5qms2C%HkJfitNI%bxGS17MAD_XwghK)tlX*d7syu2Fb z9iL(>&KBsDt7fESS)}!dTUQmXRydG-ekuL6+RuL1kK?wgtF!O06m6Z?YcZ)^q3O}1 zxqL2{vEcV~`a|EdZ-bc}%x3~7F(7pJw@k$PJF=P&Wp=h7m%j*__^epcZ#c(&)#q}bSnkMAK@;=4&oaF9dahhLKEhEk`pKehXE*z| z2+J#9=iuM8`)vz+@3vVrVo3O^?7W?cN8G}1!F3Gvb*C>&oQ#tl6s$fJ7t<$vb#85D zUSFs|Zo`EIiCm_XXm%S1Eu*>(9dCoK32wM_Az0h2BNovmOV$GK(SmrU=cHwHnWN@K z@YRwB=$}3zp6L_M{t$oeNtMjDBj{f<@FHt$Pw6!ers+MUr#$COfJ-@XVQJIA+80_T ze5))MBlB9^dpIf9kcv2NJl#~D3aCSkE2?@)tCU;RFllE?1bn5=|60Ty{L z0YH!CD$^1D-wQ>kC^#MRuyk1P$ZxpN zjk_*3PU%I4rWtDg+usaIo~*LwD1m+t?TC5c8k|C^$uvLyd!0>RkxHCbC+ATSjR2oELucvnSph^Mz$XRJIeL7~3{eR1DKi+7 z21yRd!i+RX(hZDAgCy<1gfvLf4-80yBn`oQG)Qtj7RICD$O1XO3)9gc$?07fjs{5% z@4{>}NOE=;Mx#NJu3$16BNxFg&Xpp2Un1BXJx`F{{ z;5(46VE!2-=?cc5L6WXuupA`m3g*f|lCEH^93<%qrpiH*u3)GfBqjFu3(xRBV2B(f=?Z4ZL6WZEoD4|P6`ViINLO$|1|;bU4#T2}sfvY$qT|SFoReBwfLV z0+MtE8wyC$6>KOVNmsC;z~Lg&6>KOVNmsC;fFxbPh60jw1se)T(iLndAW2uSp@1Y^ z!G;2obOjp6 z9PRUP*c)r)kFwFDogNM|A1hKS#x*Z1!lkhr_7&IVvAzyGQ#y9KIx< zqYWPpH)4(a;T@k~Ny6bh{2ckidp^OEgu`k0Ir4{heS#$khp+H+@CS#Tum*o{xCm?T z2Zwn`jkbO`JcBj(gTpFVL;c`z2-e^a4u@b3^;5>%Kf#hz#{0h<3IJss00c`?87F`o ziU4IC0R&4@8E1eT3ISyt0t8D^8K;08iUDOD0|ZM_8Rvi;3Ib&u1O!V`87Be3l2pb~ zAcwL*8D{~(l2pcFK(Hj0aT>^>I8erMK(Hj0aURH_Kv2ekAcqn`87G1qiUegG334bC zlyN4=p-@o9p&*A+K^dol9Et^H91C(N7nE@>$f00R#=$_aB$aV8$f0OZ#?e5qB$aVC z$f0mh#^FG)B$aVG$f0;p#_>R~B$aVK$f1Bx#sNXFB$aVO$f1Z(#t}iVB$aVS$f1x> z#vwtlBq=N-ITRBVmJz{{q_B+SP*6}NDc)Dg=IvrBq=N-ITRffmJz{{q_B+SPh+s)lSVja(lEN|~ zSdtW$5y6tAu#5KiC5BZ4JKVHwGz z&Vj-*B3P0XmJz{{q_B+SQS(4y84)Z=3d=|ywGR}Q5y6tAu#DtUeo$CO1WS^_G9p-# z6qb=Z>LDmBBZ4JKVHpuDNeatI9_0sxWkj$fDJ&y-lphq95y6tAu#DtUD?woy5iCgx z%ZOk}QdmavsGFd$j0lz_g=IvrBq=N-bo~PSJej`)OOnDeLRT=rbMo^6!IGq~jL(e?<2?z;o;mwkFWnALIwLL)ag2 z79aPI=#B??j{Om5@p1o%Zh3&`*dOEvXzUNRCeYX)d<_jk(71k(AE2>6=s!T?*B7=X(AXd32WadM`VY|9A8bvau|LQU(AXbrO`x$q$PZ{2 zu|L?FKx2Q9AE2>6*qT6Nf6#w`#{OVy0*(Daet^dQU}=NK{$Oc?#{OVwgU0?~X+!&p z{lU@(js3yW295o}(guzF!O{ke{lU@(js3yW295o}(guzF!O{ke{lU@(js3yWhIShJ zgQX1``-7zo8vBE#4I2A{r41VUgQX1``-7zo8vBE#4I2A{r41VUgQX1``-7zo?LGDf zOB*!y2TL0?_6JKFH1-Ee8#MO!znDAoa4Ork-y1@dF*F!6h00LKkVu3g84}T8N|cZ} zbEQZ!B{C-x8B(FlLjx+5A!DW_WX@2geO~sj`&#dD?Du&0e|!J)9LMKatDeuZEa&&R z*ShZS32$v+!Vh&x0uz3yOA?syLtT=XHP;e(=@?#(wbD2F8By)&|CY@YV*#e(=_Yk3X;XHP;ekecCMgG6%qx?V@`2-_BoFAx55*YiT{6H7^#Pg9K z&JVQa0T}zC{6H7^#Pg9K&JWZj35@+vexQr|f6qtxfiCh1Mt(RyP?sby_CxuBF7k=z zBR`xUsM-e@`=R_m7x~2VksrXHN|{7{!9d>l;texNQ%V8Rb|Ndgmos7n%<`29d@9)Jly)Flaw{ZM|8>{>)!lEByx zyv@ zL-|3ndJ(O80LFeOKS-7@qBRe|*bn6g$@)dK<^dS{q3aKl1&nCT12FbO`9ZRR5v_Ru z#(wDf16}0*dq1H3Albr*x+LM_d;If7*B>N%7*UrbF#h?X{2 zX9U0hvY!$BNEbAs>krZmjp+J=bVVb&{vg@W2;VsaP78sWPJ#Mlqz2g$-l z_-r0A_CxtWva%5!yaC33C_hM+Ho|A2h_N5a50bTw@Yx<>?1!#DNESE3XIF@^AIcAs z)s6634Pxwv@`Ge~BRYlyjQvo4kgRV+2XTP0AIcAs1&-(_4lwpZ*B>M+9MNGMVC;wT zgJg*#I*tR3{ZM|8tZ_sKa)1fHwJu4LMUHD-k|diP*SaK0RynS9Ns{bxT|WS8Swmn6w9$F(j=l3k8#U6Lfb9MRbv_&SjI{Y8g!fQi=+oz4L!et*&N z9AM)0L+5kg>qBC`paVL<#OsGn=l~P*1s%}=CSE^uMhBRfFX)gCFn;||evs^PM8|Z1 zu^-A0l3kAIpbjwhL-|3n%Ml&b0mgnPKS*{tqQg4C*bn6g$u389Tn8BYq5L4(<%kaK z0AoLtA0)dR(UBcs?1%D$WS1j4v;&O&P=1i?azw{=fUzIS50YJu=->`8_CxtWvda-2 z-2ujaC_hMcIikZmz}OGv2gxo+bbJRG`=R_G+2x21@Bm{!lpp_gIsOk_l1TdBDM+GA z5`J0#=Pt?a()&+Wt52N)IYNMsC&O z`~3Z-vO>R7>^}GPj@5@OR;SOF(iTqdUhEl~d0rPQx3jaLUZ#8V*Rx)Gy^Q&l$jYmt zheHS7cCCuYXjOS-+J2C;r`Y`TL)G6Xuab-*HMSDl>nDYHp0<~83Vq1*`1b2;m?6`$L7@lG*{^Wbf4%Cw`b< z?4;&-nG^LPg`a<@XkYxsAL2 zlrVJLhX$xg+k4G-yHFne_OWwd*T?M8JP+>YjpQ45s;K@bnn|&tP1o>M*tY5Ov)9Qp zSyhp&E(f3doZMT#)iCYtA)08plFpPYI~MtcJHeZ7T(D!L762Q+J=tpzMzKSvuck zdN}<(bRFX^-St;qG4$Ln>$Qt+`><7nq}ri{3mx9OZ+AUT8yIKaNn3hHqL-ZALosRL zFvRKd>&fR~A8r|$P#IlVI+pkNL7iIGj~m8^V?27q3~9yl zWyeIH);3qE4m@HXvQp*djrK0Lpqkgay@~8hhgm&yD6d66*8rzeLdmRSSi|OyYmIf` z_Fa$TwRX9TeUDnbe{kpibJEpeXYvZXbX)C$XBLJ>FUl9z%U$p<@&aV7*nR9A*#mi~GQQ=T~xz&VERQc)J)zzc*E0HDT?H506 zv#Azbnzrc?`}09)@rSlsVcTvc*M?TN(NEK5op$%5+s_9@RO}P?5p#dgeQEG03pY7k z)tGs{NsoBLZP$WlOiT;MZP#rnso6x6OhLA;j*r#veT&s$dhzB>59y_7^$nSG;t}qq8oyFEyz+bscL7ka` zc)RC1))6j)e(hJ>;u0!FQ@_LS+tsGpgL}H{GmQ-sYd3qo?J!Op2rNnUt^4bH+Wxuc zLP2Jx^@7K1Rk$mKX2;g`yJ#E_mKl66<#7t_3wgABNPbiLO5bDQ^_jn`|CD`5eI1+X z+Rn(+n>)M9DV(idotiEEm=L?Qorpd(E*d9kZfRAhH5j~!_7B~`$#Mgh%7--~ zX6>^3H8@ibWyue>4wb~nZQc0rLf=3Jf2FYZtVYRIZgEe|{UV-&O);ZEOZw8Cy9_57 zjni#+=C7l&=Xss`hpFILN&=mc>eOAYx>PsC^FK`+Hit44ecsgf?5eyAcizIugIlfr z`tnsDCfd0M57t#ml`cO?e$3#PY+$j}Yv$ti?yXio@A-X&U$)-xqLF)Y*h05@+jbY> zBX!c0tm0yPLUFevw6|~mJIy8^tL3$llmI<@XHT~XXo)0Q5* zb4jk|!*7K%IbTn9zFx}ml4|=ER=KTf`;_FCOTr^+zctQ{otIdeoZ9$Us7iO_fD2#V zD?4qGOBH?joEw$9UWsV+1hF*dH z+j!mQlBV>cYj%%h`nfxN5idSHx9$m*(df9C$+)}#tK4PRa+e!w^y5kFvH{_XZ5u^9 zQ=dKY6L*a~^5fL4;S6^hLD?t`(<2f`c2ctBvUAXq$GPnMx=o9c_gz(rbJoy3ed^H@ zrovy(*cUC%s{e^TUrPmKU(49HYa6X9rC8wVujJ}&Gb$y{M)Mr&Biop6>6jgo-XzX(6S{B~ zO<4YtsrqfqUuN6CJE+rM2-qk(4MtXnAR6gnzJxg^S zE|=bvp2K+d^0}AaCAK`LG`Bsj9Bt{IUZd^v+EiX%ID=(Is6r#FAv{J^^AZbBpVYcD z!_78t`fuMqUe7Q;^UZttX>d3z#pEkN24x$O?{t3qrpJoQ8WK&*kR#199k|fr_tBDDIucLe`FA9uhi1Nw0@Y`p5OcD z>TC-`>!}w<*Ps91zcD2~VB>9xEfM=TzNc^K8IP~%a<6A^FHz8t(}+qEtzuy9E9=)l~iPs{%9JDen#xeF^P`T6HfH`2yJ zd(h1ZHNH~{88o>H+{5c~w*{r2F!(ETn1^Fnc+2gp`+K#h*Jobi;5{Se+P#>w==bMB z_q$ID>s8KWM{Q&K2V`)u>Q_a$kGyQ7Zq~k?MEbKmPTgZ4dc6e(&&L40nLgR@Ntn zFD>z!@5$U96|-UD@$!%Wzab^fWJl!F%HS2@5dj&|igZ@4?t~z{()Dh^pZG1MLym{X zhC~NngBmcJ-R|Rm6#MF5tGV)+5z3?=)qO9; zx3{cc>F7=V<=fXZsckG7Z=-PjdRa}q>fHw#4s5e*gOincS}B|xGFZ!&qz&hWe(iAN z;~wD|Qk4-m+o|Nn?b_5d9e;qfLG=DmCCe+C;}q#SzwM^d^aUvW(k?TS?Jqu^RcP(7 zI=EpeEpjv4dh#<`)YL~ixX%SX*vw(lao)GX)#t8sY)R_9uijfjHLspvIP0}XB*P}? zbMrfSZzQCs@=a!QF zb4It|_i4em>exriM8>ZCD)^z#|A^hjF8=z0Eafn*<1R7hFE`N5bB{UpCyL1w#@L;% zH+|V;(&K*Pw^Y`SJwOd7oRM1^`d98R1ya#zWF z#q;?S&HkmQd6f&F^~h?CdRRVrJzL@Wz9mRSUgEHKef;47f8X8r8R%5^@*EHJ5Ntga z@w$XR@*-KueSY5U#R0OnJf9M?k;9BJ) z@zm=S;hpq!l1c4$yYmxh?ZvJ|en>p;zMb0?>l=1N3)&oY zU{yOX8lqrUTwY+^&0gjXgYfqy3(pI~kI97F7WxIb$O04X$QJSrIbQG<;TJj3shC;h zQ&oF_ZlmuW)SPj;vx3=i&%K)6#&K+iR{Z67uatLPenDOEo%dd?Sg%IStz%JfH+qLe zO~&hAne)q5-^tF~Eqf!!*@Pnm6;{6^qcOTI$3@vh>giBv(E^-Ard zg01&=IVaR^{CYkjG}(cLvXYkXQCH56c1D%Ul!;fK-SgwR3zJmx!hOM#!Hxuhw?7os z?RYB&-d>76-Ib$cW?Y%FZBxXJ^5>TBd!Ugis@iiG1z*I=g!}>ZpoqK#UCENd<@U!W zC2rG^lda)e?`=hW7!B1q_evgJs*f8kr8u*{tJ@}kBO*-ouIj9L&`#;Qvvx1WJpa73 z$S)ieHMt}+sw2jnalxSI)~%a2elCt^1xCfPb60F~*U+vxs#Zz+wm(L-QO14UD~-;H zT3U_wK71EA7R%3yH{6KHc6EF9j3eV}s@ddc{XN1=2RoCQq?L@Xxt=M0nYy^QGXJ>t z5zPb2{+faQ1&qN80$jToM0_V{^@`t?2-79(6p40_59mC2q)qJe(IaXt^JB3pM~oEy zu_=9`KaCXrD*2L)qXPZn*rTNYrfw+S6j!Bd~u(DE#=);K^7+s#no!v+!f^> z6=(E$>Ld$GZ$CR)IC+C_>d3KFhimG|vvG(0oEpw6Lo26X7w_bNc|clZL1BHEW;;*K zg(KADDK|LQ@g1{a>C&qj)R&W^PZn09*(>>L+0?_FO=BtU<58=gfC;<8aK?vWsxQNs zz4m@cbmM6?*&kbGV)4Uj`~Yv3^^flC4cfceCj>@b9TX}tPG>qdyCCw)l8LwI)xqSR zr=Ft%!d9g^j5=@KQ*Ln#ShQA;&E1nr`gYP!<5;GdU&Zd?7I{y)Ac~4p8!kOE;GL1X zQsK0pE!QK%->vyux3yPp`PrU*okz7)=D#W=L_3&!i!Nwx3VtgdG^g0hqCurTVEnL& zMz0`ICYdwK_wSbE9g(RHAw1 z=+1<$)XWc55pk-Wy%Y_HPQ6~S+h)V&{irO`_^8e&b(6}BxBcY?J9xsTX70)NCm~Z!0e#6{0SFM3A0_?IVq>IeS{x-TMyf9BiK- ztk!;B**`zHOv!n{zxpms|D{4?c`1FS*8AUGd_BX+I4lZktR`ra45VV@mrxess9+0DNBvFM_oR^aDGuhx-!)2U$z+OjP7|q&mv?XWp## zEEb#1+x^x1a!0Ayb#*F3kDkGavB$*|_1jNRy`TN7n5y~f^5==7Upow1HgoLTkdZ-8 zyMBlEZkEldV-oaxR@SYvTTT8VXr~nQnP#!aO1wEp-krzRBX*O zyUfo(4Vr|s_xOCfcR|HE$M2~-X&RbiuI;M(Bm3#uu$|z=B{t(9W;11;1_`^)h|5G5 zYV5vjuIn_VWaJNJIY(7jWQ^7gPH_8kUi3^2Aqy|3r}+Nl_F{a_;pDj+?ipmt0uGeQ zZ`5>dv=}~TYuZH9r5Ww(ucRzOe(C;Gy*HsBN?EUng+#}VnCE8qNNzvgt#w`~KG43K zEnZ{S8O?Q*e}%WwYKu=d)2C+(dRA}VHy_NLw?3O;olI@avE~W+zjZsRY(?6qhm9#x zv)yv%+vLcPe_7YiXFT+sj)pvne!uVm>dd<80v|K#%)bR!^))oKZ-!nu?jV}Cz_0s) zo<%(|epI*Sy-ODq9z8E0SDBfj{(AbNHIEQIMaGUWsg0`jG7@i0bt-ISX?NH@{z3O_ zdw6a9ZT;!rQ4u_4|ufrC*gM zh0p9=o=oRHtOBW^ z)zj#VbhYvQbVeyNqPZdZc+S!R&+hKr?R)8FQrc?hSkgzdHP#=KX7^3|>lNDkG@yU( z^5Dj%#=j|_^Xv2r66fY&Bzc4@(%3xf?B6MtGFp8|c&Y#eVcNG!R0YbfTxD#KpHN`)IV_|XIjg7Z@I3DoZ`3eN7KLf*ug!@~ zdxqO|TK-h7?CXAi`Nf#QqbD2oYxE`aQC%0;+zbErFKb`I+b^K~w9r~#OUFXul4@vu zNd*}l%cuA5be@Tx9=BUO6E=j>#$-O8;9QXNxc&KZ+>TGu>@4x|@Vw8i3zjM0llWZTwhm~o9?{57*ufixcr_&M-TOCo9j?g@jaV(G)Xo%u|+DbU-ZS> zO3Tu(iN9Xv^(sp_!}^Q&A=z^YE_)Td{S)*qjD!`$UL8Nn%%0sgn&i&v81!d|J*U~g zd+}Od#=HI;RTZ8vdGoW!4;{b5qX-Rd9WzdTy&i6_UtNEk6g}#>|68F-t|ND~u95q( zzEnyo<}WnD<_7{Sq*t;=hhH-acCQ{vlyB;5TfW+4wwzJjU6%50dPQsZlKQxZK9{S; z#>f+&3x)TGWPj^3Zl>va&#md=F!kX1`{+_OnH}t#g;Yuo?!8yq!XH-lNA=deALSns z{iAmkC=9bYoaZtz-Y|dADkMNDZ9A88pnyGDkX-u1vU~SKE{1+ji=@$J-@jedv0d|nkNrE1ATeVhD0Sv$o3oUv3Ew+=WG zaivk~#Loi}i6(K?iV2z7L*5*Rj_ef`z9QDrtm;+d;m+r{V5I4JbsOiB9CgP^L`d{I z&G$Z;ag1|ko#hXI>&xYFQ54QkAC8V^l}XGlbxwX*_u4VUy>RZx(g-)#SST+Hq2!ILVNi|rNDeP{Bb1ZHa`b=&7Y(T57`ln$MGB`g(WR1z-SPkr5j z&5?@YqO$#wNQET{IfQ_Z@jgU`GrJpCAZP8lqvQYy0c2`)&ipQ z=X{=3u*Oc9#HX4cu=_3--j_W|?Sb%h1Hw@v)rwRL^qb46vQndy%sBgXkn zdp9I<3Z2j7p^y4Bl*vsIFRmoO{qfB1oejYn2LuK!{Y`uxT{d2@_!``rsmWQ_a#D1D zuzi~)rB)#G2v5=2`a^yDOU?Bh67yaO>*mmFZI{#}Ki)hb9t4GtU-I)-&Am%MB=%pt z*HE;&b$dp9!MxVCb$ll|n9LdCvgQ&`D5f$h+iBlyIT^znU~{Fd(myo^ z9#F;%kaCVrDj@7>Suc)5eJxx!g1F_OZ6 zU*ZXeJ-kfIU49jREy+$;*lO)ODZ8MOWqFSG)NB9kKbSs@P@M|e&R-#=TdrDP$-Uut zZvUp|@g+@R7l*ZJ&PAPx3h6mn&sZdUGb3=`Zle+-TZYZm3}LBHMkS%P1C&SJON3Wd z?9@oRM&9z4X5-4-vqM~Tb!NV|Jl#h_#|INtstWC+>6i=zc>DrAI_pQ4jM;AORNTbA z+pW8l>o~3H&p)H>Y#x+c0&2sKPC~uIW)!hv+@CZq`Siz5OiT}(+Pk)!BxriXxctdG z;9(u{df;?tPNI)%PwZ zPW3Yz98DRDg|fwC>ko>=aJmk9`&QTPx*QhL9aohlEC#N z?|MP4h%WZ&e8a>Rxrs^VO-Zzyi!W#`r7?Ut81Q6_Ix6re z*F8f89gT-Ev0)V#o1)xbcT>;~m+kcyG7z#aF%^*c=&?n-X~Z*_az9t6q6d9RB}30~ z$4kxE+h{{n)Vd3m-^?ZFoYOqp5uM3Y<|^>*sDl5tCdv%DZDeOvjG=HH=muud) z#Dj-MW?kljBj2!6Z)Z75MU|4u!I~l@nVA~h^7|Cc`<5f>dpf%*JP%4npD;XhKv*K; z(R%sZsVQMa6D`hdUv=)jI4(#v>N9eW@8Pw1!4k)lXEO}*#lNR8PJiifZnR2h@Ntuj zj_sAT3pl?yxR_YL5+S{ra#@i$*o1@)=FMmPGm|^lg}N2e}5_Z_lswi z9vzQ~pE$QIb2VILcZux}?bg7l+iE3ZIzOdE4Yk4{UT9$R5s?Y&#*5L=d&H7RA`c!KZM#d}L4#vOBxr^U85+3fi8?f1;S~UcVRK2Xc(8p0z?!iE1xaHpYlJL>%UEcQ(U+)`8 zwS30g|EiMD_SEw?jy|?g!o?v!**7?e-R!tel7ncZrCKjb~05(h*~SpL%uCPg~=GUTfS;Pwgq4 z{JF}%JPKZR+2W1?J;A@~T@AMdnOVpi^FAp#K*sEJH@!vm<;PnF>mmm{7`Z|>)Euc` z>!MQC$wpM1SXT@iQbLCmtej3N2_W{Av%?2MS9H$NVrd&F5n|b@hH#GI!qF#xB zO3Xl>JHAEVvXrmC|JqZyp__Kp@WeNVO-U4%@e6vD*N;q7a_es5iTa*)XwGD3Rn`__pd#aw@*T(tchymGTiH@`;8yQ~~2U&B@2YWXo+bZK(wN9lY z2Qp%GSY0f9n!66Mx#;RN*i5Eve`R@W=a$RM1Fl;3%f8H4pPFRMpOf817Q z*64QIC$N#CF5Tpep3@fVh+aa@hmIr%HB61y>C|aU51Ekq)~i? za1V8$gtX1#sN|T!*2SPXyI=cGjNk927t_-tYt-LatDo#RoVbzJO4#`!QW%-U5UA}|Lp!_N|$mi`gMQv z|Ggiu>8HB3rD*^|y#PzkBW*=`CUUk@JpsBW#I_Cu(b?Tu9lh$ZQku$BL(^tzVU#LA zQ-a-=vP$2!f_){N!TMjG#f!eVKA798@W4u^cbBec5(ErW3p3N!%3lD~sRaDI>HQ&UY zjB3eXp}XkGFy>o7c=ANbuZc6W&8BRoafj7hdSdPG+>Y-Yx+*kq^jWWE|77WH*Jn~j z3u^t}+$AG2ydWk+&609*utwBE4 zddtsySzfo^EcuYTr(w$ge~?60*4(LOF0})LUGEirZzX-$!R)lRf@@I8$JCN%zOLae zYx7OoP@(Y~Lma`rET^yf?Tjg;ESRA%-D%ZnV_jD{m-`|;bV4`EXX0_1mlxapJAJCR zW%eodtHrd0KCfAgH`3tU8g%vhOW{qQXm<;Hd@gKhicf8zD)V`>Z~IF74#TIKA@9^G z<=*!Dt3H(pTSvj~eW>nF&^$kTXVCF6$6F^ehrgRYnyZPoOl8_S_{frJ`?i9E0=6nC z+hpvsI+lZri+{1V{G>ki`cP8sp)29xlwB{qv`+f%{nhmL{5QAyMcU5x!1mqm_NYXk zZf27^<8s)q`65a*bv%*=5Zq=(}-0 zZ1h`j9fqQ_Ulz{PjaHiK$aCjl z&I}n=H%uS5C*#l@JVHguXT-5FvFl(s)&6t4zFJRjIQRb2SXSyo$1U0-N2qA{j5#>@ z>V-42%EGRY|6%NS)bPw<>v=`)D@?+BBCd6*XFYIcDh@g$(HdTs`g11wt!rM!45`KO~ds;Np%^j zs3f`7nSueQ9M7fK7oGAr1W!&2K2{;(5OLxM@+YRoRUQ>!-h5hRivn;~a~o z8id$~`0HMf^EL91W#`elNMy8_ZVUg zrerzTq1>Oo-D<(z(0$v@O}jg`tUT@%Yfz;cf34ejx?UxNj{GdyJ!)!IFPSZGILVEd zH@7d4H`i9}ZO)GN-@ooqWB$h2`<45&4ddeI=D1=zKIz-#eQgrc(odNXcH5|3>PepI zmzgV(b}K)2w(WA6Z)^C%p0RfqlxHTsUwrZ2m96PnoN)8I@!S{ojvQlikxu048|Noa zZhO4RrXz-1+FRG=)H_e-V(yEwn?2Ry=bvvYG_vJh$uhhYk?>dS`EI>Szcn}PX3!br*bBHiZS0S@>|j@$4ZXRZQE1hGz|*rM)9Gd zEtCT4qAhjq!W=`U?*+}2PGrz5mcNtPIjA+5Q#TubWXkAQ{E7Fh8@aa~p;#}f�{W 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 literal 0 HcmV?d00001 diff --git a/doc/game/image/arrow/dl.png b/doc/game/image/arrow/dl.png new file mode 100644 index 0000000000000000000000000000000000000000..c46632d7200e7afd5c6c9153328f5599cb5e457b GIT binary patch literal 6896 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 literal 0 HcmV?d00001 diff --git a/doc/game/image/arrow/qm.png b/doc/game/image/arrow/qm.png new file mode 100644 index 0000000000000000000000000000000000000000..0bcf7d92df5f25651218689a095034292173541c GIT binary patch literal 24497 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 JPDHLkV1m<;l1Bgl literal 0 HcmV?d00001 diff --git a/doc/game/image/arrow/ur.png b/doc/game/image/arrow/ur.png new file mode 100644 index 0000000000000000000000000000000000000000..408e8d8923b71a507ef993e13ea29a23427154ea GIT binary patch literal 6313 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�~ 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 DV7V0D?d~Xm~zJfjz(1 z;;rE0zQ-4_p!#6B(gT^{`Pz5kB{w=$^&EoxfZE1y4Eh1k0|X8=<=#@Z_giS6NIE-~ z`$Tr&D!93Ou4`;Nw=t|~Xx6ep5Z|H)V16pV803**CMQtWe+DgohVbwn?JjSNh&nhO zO6)4(!Hm?v1d05rrcPzo5?tDYd`{{3m~vFrU5$}m(c`S2!aoG&s#+nH3HXMezhb%V z#2aey^lCQdyXgj#*oKk)%dh&SekW9>&Y6=~5FKEC-J7`XTy+w;N1I1AkH7f9P++t; z8sdCpkH}Ox@o~njmJ*`$A6WjbH=;JX1>(lMnA}BSt?l`)1!1_ogpp_>290Rb<~w{5 z4^nk@RrZlx&8&xdZ)=NP5;<(~J_%xNFqx1PaZA=>DEWpMuhQ!*jqw&@yh=!37s{p-GEt#d};0UY@s zn$G59!8S-651w`G2I6E9O<xQt_bW2ciwpWl}EE0OqK}kzhAr42;t5;O#c99_{v3s zedW{PAKce})hOf_$40S!=8(d6{7C$P3AKU5x6XAxd@Do?=jmzKN`a)b=+hs{8^0bE ze2lR~C2^YS96O#l=(|sKe-x`MzOE*LHwl< zZES@zuD3T*NBN-`JRW1?AR+H)9^nVePss&K?Je;W;y^#aJO(3WYfIUw4RGxQPvlkH zH=PTI!2bYnMQ{gQK0yBf1S=i4=$9Xm)9*~3u82@zV3`{D29x(FdZnl7IQ(?~0KX_S zhMrEp${)m(Ndh6VqtvdX%yX>Kt)H2M#f~66(S5KJV{R4{_AEea1iPQ;@Ne z6dZKd_$fSt-hbE447?pYJi?AzGC_@&1Hn<*VG__l@!>Jr{{Z$V6SuHG5kK`x88bz8 z(`AMRzts`=KtydU1RX&d>PR#95%?e*1GEfi{>V{*^o+ORG5Dy#rchh-Ih7X@;_cjq zbLFdpc=@Ik*7s{saXuhV;1yc3jdQ3d=c+t1PaWW&`|6Np({;eMO+uYpj>h@8JNT)7 zo#F}8$PK@D0amWj0n7pqa0nlgQR%UcaV}t=FdZI#=QTJ^(vp@I$$O`_1pK)P?R8%ZGmUP%T6b@2RER@>__t{c9QpKgtl#C%bzX6BtDBu0}w z{{RHFL`4L)WZWxrU!X0334^E_%zS^n0=Ie&s@=P`SlbAb`bRb8-uaMpG1(FCbHE|S zM3M3NCIi!w@u1{RlN@;VLalO|_h!7=bAUPmKm@ptB7Ef)?ybSwC7{8H`X)!=%4&B9 zL;y>4pU(5uSIMv04%2g|lo~4Exxx@}Yk_Yvoe-u4}v9tr_ zGC#N@)arvv9jG(g-6kXQc&l&&V#bZfVf`e7=0A+1dqC7o@dy3rZN#P{bB~ZC_yVMD zVA|FZ1I|%8Af*6+1Zm)ZxjR5H0LS|O0Ivx%DDkur+eJ29Ej*BXfpU^D1&&grjUe_X z=lm7^jrJjw$7i@UrV!%Yq?=v&tndPUl<6N8n0C |$bl`ATv&jnDw?q5lBC0r?ct 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ⅈ#dZ} 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�|BN+lc60^njwn-ox&?_@2*>g*Mz{qyf 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∨K~yFuJHxp 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

n6Ab|mvN)&D*QA9>52;%Ewuzmt8d3N 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

}`yJ;~tB!-3X7H_g$U925%)r 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

}IjHERDn)q@nhDsE;-J_#FOy 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 literal 0 HcmV?d00001 diff --git a/doc/game_old/piu new codes.pdf b/doc/game_old/piu new codes.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c47d955d43f0961996fa950ded1844d7ed8b5f9e GIT binary patch literal 737680 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

yk_xsI$nyu9rf)U`<;8b-9_8fQ@4%B6;WzO7%X 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

I0nz=e)>b%gJd6Q@N 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 z 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

kYCFpr{PN%8gnedTsXXu0n#Tt&X{PRZJ; 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 literal 0 HcmV?d00001 diff --git a/doc/game_old/piu old coes.pdf b/doc/game_old/piu old coes.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b0b56e85bbb53a9cf0554d1b5368e54b137ec0e2 GIT binary patch literal 682352 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%0D8TEuiQPViS7UgG-K?Sflu~ppI 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�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℞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 z z1r3s1RHj9yHJiZD2z|RO?Wj)<0kWOeh(>sa$d885rRGQTFe>)(s2Z) zRp~GS(`nIuP+)p=eUuoET<(h*Q_wiPF8!WKYm|F$Hd*LAaO9A1Vl5VfR-UiLK}Yuk zJ4O3v!70f#TcEPYIV?IY(wH*OYtf?>CSgj865|X;x*ryFeUx-yG3kkhz?oFHLiOjr z?v}*@Hbxj2TV@O$5mlN~rf2bEL~Fjv^r#DOZr1Hq*4aepTF<9 z7P`Gw&Z~E@AO%y5)9@VNBt#o}bdQzyO|RGKXkLSs&R37El4q$$S6X>zpgBtZhm~Mv zxn{6-`5p!boUj;YfL^avqaZ& zDU+e;nRpHp7@J%lggm{6MJIJ?t;s<{Jlo`8LCSCD_cdu$+OEKGzH$zePEUIZ5lVZi z^f39pFlXp~fOLrufn7=643|SIbp~)3lG9o<+g89#vbq;Xeh`X=D4DvmIK^c&97*zUurnA(63gkZPpc2ZvuX8Z#q+HNJ%t#v%m_^!j zc+eX8kof5JalkdDF2Z9^S5jSW|neQhn?baU~5 zY;2tt?<;9i3u8mbP#p+H>H<2vhO~*nncy)Id!+*^?i-X1oVpwbHcro?Dugh&xFp@{ zU=9*y<~sw4O!q?vgGg+Nslzh{IxDfy&wWJ)?!elAH@*a70Z zMz{*(n(^HPk^x}FL>rJiQZLcLI;XpDg#Ijf2|Nl?2f;;vH7?%Qgl#4a*F(N9G(9t8 z7HKo#x~WpH%x7fM8%U;@;Ea~%hL2Q`EW_~YC# zAADaluNmegJ&T)87<3TA4B)b2Ex5gO&&?(c$ptffn{uzr@aqv~F-hA`2M?{(n{*Z> zSjAc_@KP`aXQ>>g`xQ0G#MfXMNF7dRF{sE>W;(!0l5AARA@{{%QssW)Su^Q>I#8b+ z2alUp@@y=`LCOVSFiJAdfp4j(FPdbUSMLCBOyeLzX&h`O!i+?JFfQRGlXJje5O)iT ztx3vInD)5o;#ufd@+_h8lO3;zPm9(Et}E|3q%S6sbLjO_hlA9DyIziinMdn`xTJ9= zRnnPxpCM9E3Mw#*gY>(e=?NO0!&fF34wY6uEwVsacH z!t`W|gR3DzD4&HxLcWI%dI^mKjng<>L3u`C9MWG5j|>Eem=}a9^#d>i5VRbpgP@ie zZlPSC9_}z2_nWiSBdAW}pkoq-uPzaWketL|y3n~nQgO=Ea?S07d|nSnT8BXxsVv#z>+6I=aR7)FitI_&csLH-_2Qb)0OJ$!=VeyH39 zIfu$!khH6TwIFR+U=Y=r*9Q!OL1GpMX=|w51!VnXIyYcsLnut@8^A15&w*P-wL-}J zd%z^UV4PXHXl?IhO6{2q~fcr$36YV9DNh0GIt z4Q~PO4UL1ekQm$S@PcS0zXwJ>EnrY|==Wg2NeuQ8y@!!>M_4Yu$wNVk4ZVknd{sCh zWM;^DVMx)upi|ldGwI`S!;yUsLj%T!oCC6v_8zGLLT|zbkgrc+w9lXnDf2Ln;xh`P zeTEN!?v@d&mhX$>kbD<`6TS<$Mbg)TC!wZ`J%CSv?u-%MG`aV{q^||i65bK{drFgK zOxoQr0!V*`at|_+&%*ITYcW7Qqj45#N8$I#Hh{6uIU-=E(r1ZraL&m&Od2W6khx&u zGiSXM(FM}~fT_=AX66S_W2M}}I0R?qI0P7Iuap5ywY!8BNpfc{5o zF~cDt*8)GB)c+8kpyh!w>d10H5yXt77c*k{^uACNX%5(aJPwwWTr-RV zNq=V8Op-?clYTBpP&h&5??GpveL*4~tpz%Rd^cz>bT5GsZ6I@t^c_Z#XxyMaP>jak#ndd7Q$Fg!xc`t88BX-5IA^CxFDi8)^SDqydTPYV*t~1?poDk8FN@Jw8An%_sXwdRKaP?^| zxW2Sz_#-6G!CMeNg(pbrz~E}+j{pXvSgr-`U5SC&(ffj7(ffjNNWBwIWy;F{2Fe%n zf;ecO5%VJ6t`f-US-4~vg9R+-&{D0I7P;cmucw9TE%O^J$|a4AUMjuHf3 zGd#wUo*^knE+CceH{(ns1CVe_@&nN$9)}Dc9$^DeNH^Xq*n_lJ zDgj@v1*x1g4p*P{3Z}i>E48I^955NrgBV0MiI^8(!o z96U*KUfh29zNl~_9)@@x$pu8aX|E8^<2^vgkoF2w&|V?DD(MC82-3}9fzh2-W*+US zO3aY&i!kSJFzL&{Mc^7cP_y)pBemNgeRIHA$Ap?gIxwmTWUL(O5Cn)^vzcmNkzE3- ziN>*x3CbYZh{^)q0~B`9zCfJQ89|+-GlC;TVn|mZ`34q2`Zz33vYn0K&yq&~lfD}* zBmmji@MiNkgkmI(!`vrXhI|zs$MI=6pDC9e&I1?+;yi%S{-LIe?gAvd^t0mk%w(s) z!$UGku~^!B`0Hr@;D46#NU6_~M*!nJ;9O^LgWv3_2`Q~|4-m(ecOTX&k3$L&y@#1{ z5m8C@n>_`8re{&3DCrr}oc9ziEx8BC${^Wef-ghvDKPR!fV;?e0IV|JQ(&|Qurz3| z;Q8lqN`n#m3{#xsG(uT)_rY@L?j!C;cOOSdvPi6 z-;CorVU^ECdw^+wgOOhaOCdT%+9V05<-<>dV{QH}@#!jvNdk1B+%+ynfeb0F;Z8%)|;s`gsOr%{?g`4$S3@)8*J z8p7Lh-55%Kq|5^Vgoei;hmc`f8?MxrFe4HPDGPE<|0^ijZ}MK+VdBtHN~IiKLLNZ}Rl3ry;^7^j!A zLZ`uQ(X*IE@F9$&7(FoZAp=8UzFZ5Ym3yy})Fr(DlX3ycwU4EX#ZeXNFD|+4Zkna>S?cFLeTp{siF5pnkvl;o=x*Y zz|lTisD=Y!4U%uLqA2%QVKgsdhBWVQ;)8GmahvV;KOI zOZw5_;Xx{Z+!v?}Qf@&C5>CVe-m=Y_OGfq}5({-OAg=7oz#@*&k^fu7~wnqVa43qtiE z)nO=1>f^wuP7@Lej7Y8-?gOD0W1MOtomp0(tej*mFg_3E7?95@0u?umwA zS&=S}SfKP7f%srx$~j;P(Y&gWs~m?~U)mS0hgI1x(*L3`lG8AgiPs_Y#Onhurae$i zvE=%|cj?_Y2CjO&NIMi5JiOxffYJV`c4=~6#0Tkq03%+fN{A$nKy-_EF)-=V!eO8? zORf*PGW{O3R>==g7ftpmDs)ID1Cw^VVyC1J!Q)1E6_|`)s@^taPs24Q^Fc5U2A6y{ zv{I4uhgcxpRcJoMOOUQ7eTTTvFb?D#$myUnH?f|BSRl^}@kVRLw#fSdElm1j5jY_q zl;QPuNKXVN{o`ns#`>;`4@#N@#`EI( z%DqP?De`Xslm2^X%9OhW>^J)Y)lteL^dus_h6)p2A7U)@9x!Jl4S~h-c_6q=^CE>x z(gwO!kqlL?W_lJTJ3Wio39SXKPH9i!E|&bthyo;f7P5f>&b3#7Fm zi9qsfRRc(KAk-`A4-pK~L2xU1PZ8*p_XD+pBx?~pqPq%=Y+dxuBD+GlOK1*|J-r8t zgXlewLMrbJQnBf70V919wSsita8>DyP%B9K5K^*e|CET5YX(OA9;t}r2SK_3@n>MP zr|@jjT>#r4e*`e%SIA0}aVA)ZNOlo&8gW13SExiL9S$CD(&2y+-J`Ub^lX%M5S;=e zI)xQLwkaZBL|4d!AYUYI4Dk|pG5L%Tn3QydG$XS2!HP-00w&{}%1R*_imVLM8Gw;& zgoQ10A)rW6&8WhN$D;a!WEmpwq}u|ceSwFEe0?}wqEleBFQ^M7euaLy#EXIPz93y$ z(jPkPlRb@X=6!+sN6#Y0C;22OlJ^BHTk>plB_W+381D-{Mncb`L{`!eSQFi8kOtjf zgw=@tfbqV7#wD*qsWj1_DxaqH;Sx$YjZAx9AA-X49^l0^FLY(vXRs2%$5oF!X{!OF zdI*I{dQoZ8lD`0>`~!tadIm-{>#w2omT;~d}D9J{JNgfM~@*d#4r#xSUNxKXf z`Tk*qB04M92TbPqVjTGefKk4W!lYjc9y0Rb0fQkg=Y?e<_y)!??ZV?B^$kR^Dc-Fx z>5o;t9HkBijQR*GOzI54D31q9BKOP$#`7YbQ1CTGD#@p%FrF8@SnxV9MDjl?jORrf z6wQl}lDtQ#7?t)13SdazP(3N7{~26^dO!f9+DO&AQp$5+R09q7E;y>74Mdrwj}hZ2 zFA}9A)YnRtlStVEjK1>&jPg)$c_}6W3~79FeK0TOo}v_h=f#%F^H8xn$s?emOPQxW zW5V--)zQ3&=gB**664A1uy1t`DDRWwP(&$t4i1Uo6|F+ar=JTLbr zgjPcJ0l=_Z@_kX%Kx>BiMr-DnoC+;Uf1<*qKT(AnNuH}RFPfKY|5b-P8JhscvInjk z;+?2yB|Zr^y0nuK`lMc+z|cfP>=o2Cl6i==@w~{rl)N2LI-d78{8W``(!44IP_6~+ zK%NoYr$kq(6)Qapi;JFx#FVswR7v6+z=&_)J6+PBqld>_+S3XnK8_nhHVH^v+VP6) zr5z89`--c&JK8_cuGDGNQfLq0@RWBS@i($vP{kts8@T1v8%SYv7vLr&9*Zn8o);@<{Na{8$(`ly|5w=}Q9!2`t|YE?=4#&Rlw5l;+Z!(N~C`g_$Rx z1=p26UzHt8_OzY9vcqKiK?9YK@8 zNIx*+>pyZ|5Njjb9vJa)xI0PCpf4xS3q?%Q3$lx43P!0m78GyF5rKM7-&g|Er5Yz> zJCa{OMav}J1EZV{a8u%)ib|#ajE=J8$3$cThOKyCoVe8QLE%&*feT1}TlF;{nL_{v z5AOjQ^~$^;gGLoh%C$gFOAM|c$#d{wcj}h`D}ed{A)OFaL}CtA_D&c=q=N4%Q%K4l zq#}}!428{9YYB|%Nbw~w(y0yD6&c?`B0J^MAt*^Y5(E_0+rtE-dk&1glMbg3)l%Tg zY{U=X6<}I}3M}t0JOz~VgbssbpR2BeQt!kqqTbueYb#}$>P{$qRUkf!O9C@Xo`}Yu z)GHgxI7SNEz%X7Pf4d9XIHaR|77Ues4`#fuaX?i#5b-Q7u+%Y;LP|b(n7Wili-bi4 z!R7BkMUpg*hozp4z&6>xz?kR2UX{9!>ZU+AM+-cu|ZQH-Tc6*cPghP@kqGI#p=}Ql=m`kJb#^fOw9w z1LRpkm#4E-db{M~(7mNE1D*nP%bjl2Gj`3 zVF53`;$$4Q}h&!k&A-$?!{HzDmGM5wq6%FdHMJlJ{U zdsUe9fdZpCaHx~iZ%$!E&)_bSKjU;MFGFD@D^$o|z6ZSW(%*zn1O6AbSAjA8ac&Cy zH0Vqs-WM40N!2z$-XqoOMe+?`(hm&Hk#rwm)NfN^#K&Pa65S&*A$_XwBcTJEd=KSt zB8=*pAlz{1G>&=d)}}Q*J0QmU+O4p5ZqmdRFE3@(u!%etGN))eFJD#&QN2*|o~$EBU<&S^owj zI#5aKlAfV;${bDANrm)m`1Q!&4po%&CSXL*aPbh&R%s*hEP>G(LBi90Ln0pW17M^x zfV&W#s^l$6yTC{XhToCS7p5fLb6_(5q5P9X2kPV6k~Vgv!AzTnZz-7^*Vq_sGeT{sTNq-yAo1pP%%0gxW~=hBzl3 z6CqcM^}-!SHVH7^100d07xYA+djyPVO||ToG^Er<^T<^2W6Azc((Mf->N4Ef*@HXzzip#=H9s<*n_D@b3GAHawY!Q3Yv z3yw%U78vm%953-$XhZyN+$RAqOMO3ZDPahR^8iM=D9W}egGzm94 z=^(&}hTz2{UX0u=dN*KX&){`Q&LDS--VGStL3Q=z8KKPt-49^IUl7kDIfIVrWIF>R z8baKU_z24vPi`NI=h@^2?$-HI=J$aVM>LZ;2Bt$v`cA0d3V5IZI z^rQO=cOCBm)NILf5Wgfn2mR6c_f()$+-bx)`FxS6MehsRl{BtcyOcfnIkK&Q(Vd3o zNW2&+kmTQ0X_1otU}2N&LF*klH`R_u>OP3Wl6?tIO#2Ls_8HQW{09h8k<0@|x)0*I zyay=ZmHP}aUqa)!mmU%(sDH7-h!;Z&5VpQ1z8$PE$?H&INBX$x?jw1&y3sNgqcAB4k-UrIL$PL* z#mKxRjH7rmOf|}JK$AOu7MPTS7)LsY!lVv@G8?J|1;+0NKkGl&JUpO}x9@-e>w5L< z>vZrQJ-{ArM1!@xy?vebetyH%f8n6)+y6qE5ApO<2(BTJ`t_}c4et{$d{n>yPissC OGsL=5C6_i$t^W^;Ef0JE literal 0 HcmV?d00001 diff --git a/doc/hook/exchook.md b/doc/hook/exchook.md new file mode 100644 index 0000000..f680a60 --- /dev/null +++ b/doc/hook/exchook.md @@ -0,0 +1,54 @@ +# exchook: Exceed +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Additional notable features +* Full MK5IO emulation with API hook: Keyboard, MK6 PIUIO or your own custom IO +* Fixed infamous hold glitch, i.e. make the damn game playable, finally + +## Versions supported +* 20040325 +* 20040408 + +Any other version won't work, period. Pumptools has to memory patch various things like I/O because hooking them is not +possible (at least not right now). + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* libGL.so.1 +* libGLU.so.1 +* libpthread.so.0 +* libasound.so.2 +* libz.so.1 +* libpng12.so.0 +* libc.so.6 +* libm.so.6 +* libX11.so.6 +* libstdc++.so.5 + +Additionally, when using `piuio.so`, you need the following library as well: +* libusb-1.0.so.0 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libusb-1.0-0 +* libx11-6 +* zlib1g +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), this game requires all +files and folders in the `game` folder to be in **UPPERCASE** on a case-sensitive file system. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +### The game crashes when using the sound device hw:0 +The game's sound manager relies on hardware mixing using the same device which is not supported by newer versions of +alsa anymore. Instead, you have to use software mixing using the `dmix` device, +[see here](#the-game's-music-plays-too-fast-or-sounds-weird). \ No newline at end of file diff --git a/doc/hook/f2hook.md b/doc/hook/f2hook.md new file mode 100644 index 0000000..a526997 --- /dev/null +++ b/doc/hook/f2hook.md @@ -0,0 +1,96 @@ +# Notable features + +* Runs on recent kernel versions thanks to various fixes +* Runs on 32-bit and 64-bit distros (64-bit distros require additional 32-bit libs to be installed) +* Full dongle emulation +* Remove HDD checks to run this on "non legit" drives +* Full MK6IO emulation with API hook: Keyboard or your own custom IO +* Real IO passthrough (for MK6 usb io) + +# Versions supported +All known versions supported. + +# Data setup +You are expected to get a clean set of data from a prestine drive. Ensure that +the game version matches one of the supported versions listed. + +You need two main folders: +* data +* settings + +## Data folder +Contents of the folder: +* game: The binaries of the custom "AMFS". File names must be lower case. +* lib: Put any libraries (especially older versions of libraries that can't be +installed anymore using the package manager) the game uses and aren't installed +on your system in here. +* piu: The piu executable + +## Settings folder +The contents of the folder are auto generated if the files don't exist. +Otherwise, this folder contains: +* PIUFESTA2.INI +* RANK.DATA + +## Executable dependencies +All dependencies must be compiled as 32-bit binaries. Here is a list of +dependencies (with versions) required to run the game: +* libGL.so.1 +* libGLU.so.1 +* libasound.so.2 +* libusb-0.1.so.4 +* libmad.so.0 +* libmpeg2.so.0 +* libmpeg2convert.so.0 +* libftgl.so.2 +* libstdc++.so.6 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libX11.so.6 +* libpthread.so.0 +* libdl.so.2 +* librt.so.1 +* libnvidia-tls.so.340.96 +* libnvidia-glcore.so.340.96 +* libXext.so.6 +* libusb-1.0.so.0 +* libfreetype.so.6 +* libxcb.so.1 +* libudev.so.1 +* libz.so.1 +* libbz2.so.1.0 +* libpng16.so.16 +* libharfbuzz.so.0 +* libXau.so.6 +* libXdmcp.so.6 +* libcap.so.2 +* libresolv.so.2 +* libglib-2.0.so.0 +* libgraphite2.so.3 +* libpcre.so.1 + +# Hook module configuration file +Checkout the usage information of the hook and set the option values according +to your needs. Here is an example option configuration file: +``` +log_file_path=/tmp/pumptools.log +log_level=3 +enable_file_monitor=0 +enable_io_monitor=0 +piuio_emu_lib_path=/pumptools/lib/piuio-emu.so +piuio_exit_test_service=1 +game_settings_path=/save/f2 +sound_device=hw:0 +keyboard_dev=/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse +halt_on_segv=0 +``` + +# Run the game +Ensure you are running an X screen. Otherwise, you have to start one along with the game. Various library/system-calls +require root privileges. Make sure to run the game as root or with sudo (otherwise you get various sorts of errors, +typically permission denied). Use the included *run.sh* file to start the game on a desktop environment. + +# Further notes +## Vsync +The game is required to run with vsync on. \ No newline at end of file diff --git a/doc/hook/fexhook.md b/doc/hook/fexhook.md new file mode 100644 index 0000000..95139e1 --- /dev/null +++ b/doc/hook/fexhook.md @@ -0,0 +1,88 @@ +# Notable features + +* Runs on recent kernel versions thanks to various fixes +* Runs on 32-bit and 64-bit distros (64-bit distros require additional 32-bit libs to be installed) +* Full dongle emulation +* Remove HDD checks to run this on "non legit" drives +* Full MK6IO emulation with API hook: Keyboard or your own custom IO +* Real IO passthrough (for MK6 usb io) + +# Versions supported +All known versions supported. + +# Data setup +You are expected to get a clean set of data from a prestine drive. Ensure that +the game version matches one of the supported versions listed. + +You need two main folders: +* data +* settings + +## Data folder +Contents of the folder: +* game: The binaries of the custom "Fiesta FS". These are stored in raw areas +of the HDD and have to be extraced. File names must be lower case. +* lib: Put any libraries (especially older versions of libraries that can't be +installed anymore using the package manager) the game uses and aren't installed +on your system in here. +* piu: The piu executable + +## Settings folder +The contents of the folder are auto generated if the files don't exist. +Otherwise, this folder contains: +* PIUFESTAEX.INI +* RANK.DATA + +## Executable dependencies +All dependencies must be compiled as 32-bit binaries. Here is a list of +dependencies (with versions) required to run the game: +* libGL.so.1 +* libGLU.so.1 +* libasound.so.2 +* libusb-0.1.so.4 +* libmad.so.0 +* libmpeg2.so.0 +* libmpeg2convert.so.0 +* libstdc++.so.6 +* libm.so.6 +* libgcc_s.so.1 +* libc.so.6 +* libX11.so.6 +* libpthread.so.0 +* libdl.so.2 +* librt.so.1 +* libnvidia-tls.so.340.96 +* libnvidia-glcore.so.340.96 +* libXext.so.6 +* libusb-1.0.so.0 +* libxcb.so.1 +* libudev.so.1 +* libXau.so.6 +* libXdmcp.so.6 +* libcap.so.2 +* libresolv.so.2 + +# Hook module configuration file +Checkout the usage information of the hook and set the option values according +to your needs. Here is an example option configuration file: +``` +log_file_path=/tmp/pumptools.log +log_level=3 +enable_file_monitor=0 +enable_io_monitor=0 +piuio_emu_lib_path=/pumptools/lib/piuio-emu.so +piuio_exit_test_service=1 +game_settings_path=/save/fex +sound_device=hw:0 +keyboard_dev=/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse +halt_on_segv=0 +``` + +# Run the game +Ensure you are running an X screen. Otherwise, you have to start one along with the game. Various library/system-calls +require root privileges. Make sure to run the game as root or with sudo (otherwise you get various sorts of errors, +typically permission denied). Use the included *run.sh* file to start the game on a desktop environment. + +# Further notes +## Vsync +The game is required to run with vsync on. \ No newline at end of file diff --git a/doc/hook/fsthook.md b/doc/hook/fsthook.md new file mode 100644 index 0000000..9f355a7 --- /dev/null +++ b/doc/hook/fsthook.md @@ -0,0 +1,89 @@ +# Notable features + +* Runs on recent kernel versions thanks to various fixes +* Runs on 32-bit and 64-bit distros (64-bit distros require additional 32-bit libs to be installed) +* Full dongle emulation +* Remove HDD checks to run this on "non legit" drives +* Full MK6IO emulation with API hook: Keyboard or your own custom IO +* Real IO passthrough (for MK6 usb io) + +# Versions supported +All known versions supported. + +# Data setup +You are expected to get a clean set of data from a prestine drive. Ensure that +the game version matches one of the supported versions listed. + +You need two main folders: +* data +* settings + +## Data folder +Contents of the folder: +* game: The binaries of the custom "Fiesta FS". These are stored in raw areas +of the HDD and have to be extraced. File names must be lower case. +* lib: Put any libraries (especially older versions of libraries that can't be +installed anymore using the package manager) the game uses and aren't installed +on your system in here. +* piu: The piu executable + +## Settings folder +The contents of the folder are auto generated if the files don't exist. +Otherwise, this folder contains: +* PIUFESTA.INI +* RANK.DATA + +## Executable dependencies +All dependencies must be compiled as 32-bit binaries. Here is a list of +dependencies (with versions) required to run the game: +* libGL.so.1 +* libGLU.so.1 +* libasound.so.2 +* libusb-0.1.so.4 +* libmad.so.0 +* libmpeg2.so.0 +* libmpeg2convert.so.0 +* libstdc++.so.6 +* libm.so.6 +* libgcc_s.so.1 +* libc.so.6 +* libX11.so.6 +* libpthread.so.0 +* libdl.so.2 +* librt.so.1 +* libnvidia-tls.so.340.96 +* libnvidia-glcore.so.340.96 +* libXext.so.6 +* libusb-1.0.so.0 +* libxcb.so.1 +* libudev.so.1 +* libXau.so.6 +* libXdmcp.so.6 +* libcap.so.2 +* libresolv.so.2 + +# Hook module configuration file +Checkout the usage information of the hook and set the option values according +to your needs. Here is an example option configuration file: +``` +log_file_path=/tmp/pumptools.log +log_level=3 +enable_file_monitor=0 +enable_io_monitor=0 +piuio_emu_lib_path=/pumptools/lib/piuio-emu.so +piuio_exit_test_service=1 +game_settings_path=/save/fst +sound_device=hw:0 +keyboard_dev=/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse +halt_on_segv=0 +``` + +# Run the game +Ensure you are running an X screen. Run the game using +Ensure you are running an X screen. Otherwise, you have to start one along with the game. Various library/system-calls +require root privileges. Make sure to run the game as root or with sudo (otherwise you get various sorts of errors, +typically permission denied). Use the included *run.sh* file to start the game on a desktop environment. + +# Further notes +## Vsync +The game is required to run with vsync on. \ No newline at end of file diff --git a/doc/hook/hook.md b/doc/hook/hook.md new file mode 100644 index 0000000..a247f38 --- /dev/null +++ b/doc/hook/hook.md @@ -0,0 +1,201 @@ +# Pumptool's hook libraries +A collection of libraries that need to be pre-loaded when running vanilla dumps of Pump It Up games. These hooks allow +you to run any of the supported games on any* Linux distribution and hardware. + +Each game might require a different hook library as the software evolved as well as the hardware and original +operating system changed a few times as well. + +## General features +A few notable features: + +* Run any supported gam on recent kernel versions thanks to various fixes +* Run any supported game on 32-bit and 64-bit distros (64-bit distros require additional 32-bit libs to be installed) +* Full dongle emulation +* Remove HDD checks to run this on "non legit" drives +* Full IO hardware emulation: MK6 PIUIO, Pro Button board (PIUBTN) +* Real IO passthrough +* API: Implement support for your own custom IO + +## Supported games and versions +Check each of the dedicated hook readmes which games and versions are supported. + +## Hardware, operating system and environment +A general outline is given by [this readme](os.md) if you want to setup something yourself. Otherwise, you should +checkout the `pumpos` project in a repository nearby which takes care of installing a fully configured OS to a physical +disk to run the games on dedicated hardware for cabinets. + +## Quick start: how to run (official release) +The following steps apply to any game of the "officially" supported release data. + +1. Install the required dependencies which can vary per game. Check the section "required dependencies" in the dedicated +readme files of each hook. +1. Unpack `game.zip` and `lib-local.zip` to a folder of your choice. +1. Your folder should contain the following files and folders: `game`, `lib`, `piu`, `version` +1. Unpack the hook which supports the game you have chosen, e.g. for Exceed use `exchook.zip`, from the +`pumptools-X.XX.zip` release package next to the `piu` executable +1. Unpack the `piuio.zip` from the `pumptools-X.XX.zip` release package next to the `piu` executable +1. Rename the hook library, e.g. for Exceed `exchook.so`, to `hook.so` and the hook configuration file, e.g. for +Exceed `exchook.conf`, to `hook.conf` +1. Open `hook.conf` with a text editor and set the `patch.piuio.emu_lib` property accordingly: + * For keyboard usage: `patch.piuio.emu_lib=./ptapi-io-piuio-keyboard.so` and + `patch_hook_main_loop.x11_input_handler=./ptapi-io-piuio-keyboard.so"` + * Configure your keyboard mappings using `./ptapi-io-piuio-keyboard-conf` + * For USB PIUIO usage: Do not set the `patch.piuio.emu_lib` property and have the hardware plugged in. +1. Run the game as logged in root user: `./piueb run` or if you have `sudo` installed and configured: `sudo ./piueb run` + +Details to specific games are given in the hook read files dedicated to each supported version. Further general +configuration and technical details as well as troubleshooting known issues are described in following sections. + +## Dependencies +A list of dependencies is provided in the dedicated hook readme files for each game. The following is a general guide +on how dependencies of the games can be resolved to run them. + +Right now, there are two methods for resolving the dependencies and which dependencies to use for the game: +* __Method 1__: Install as many dependencies as possible using the package manager of your distribution. Usually, you want +to go for method 1 and if the game runs, you don't have to bother with method 2. A few less common libraries are +provided with the official data release and are loaded from the local `lib` folder instead. +* __Method 2__: Provide **all** libraries except GPU related ones and a dedicated ld-linux loader with the game +independent from your system. Theoretically, this gives you full distribution independence but it is more complicated +and comes with a few unresolved issues so far. If method 1 doesn't work for you, try this method. For details, see the +[following section](#local-data-folder). + +## Data setup +You are expected to get a clean set of data from a pristine drive. Ensure that the game is supported by one of the +hook libraries coming with pumptools and the game's version is on the list supported versions. + +You are not required to have the pulled data in the same locations as on the original drive as the hook library can +be configured to have everything in a single local folder. These settings can be found and tweaked in the `hook.conf` +file which is created after you started the game once. + +### Local data folder +Your local data folder must contain the following folders and files: +* `game`: The `game` asset folder from the HDD. Filename casing depends on the games and is relevant on case-sensitive +file systems. Exact requirements are explained in the readme files of each hook. Otherwise, the game crashes because of +files/folders it cannot find. Furthermore, put any additional files/folders that are game assets and not located in +the original `game` folder into the `game` folder, e.g. `mission.txt`, `SCRIPT` folder etc. which are located in +the cramfs on some games. +* `lib`: Put any libraries (especially older versions of libraries that can't be installed anymore using the package +manager) the game uses and aren't installed on your system in here. Using piueb, you have two options with potential +different (in-)compatibility issues: + 1. Have **all** libraries the game requires to run (except GPU driver specific libs) with compatible version in that + folder including a dedicated `ld-linux.so`. See [piueb script header documentation](../../dist/piueb). + 1. Have only additional libraries that are not common/available on with your package manager **without** a dedicated + `ld-linux.so`. +* `save`: Empty folder where the the game stores configuration. These files are created by the game automatically and +contain default values if missing. +* `piu`: The Linux port `piu` executable. + +## Configure IO +The hooks allow you to hook any implementation of [pumptools's API](../api/api.md) to the game to drive any type of IO +hardware. See the [dedicated readme](../api/io/piuio.md) on how to configure the PIUIO with the different types +of implementations available, e.g. keyboard, joystick, ... + +## Troubleshooting and FAQ +The following sub-sections apply to all hooks. + +### USB 3.0 vs 2.0 issues with USB thumb drives/profiles +This affects *ALL* games that make use of USB thumb drives for storing player profile related data. + +Due to how the Linux kernel treats bus-port mappings for USB 3.0 and USB 2.0 different, it is recommended to limit the +usage of USB thumb drives either to 3.0 or 2.0 drives only after having configured the port assignment for the affected +games. + +For example, you use a USB 2.0 thumb drive to assign one physical USB ports on your machine to each player side using +NX2's operator menu configuration option. However, the configured assignment is only working for USB 2.0 drives. If +you repeat this configuration step with a USB 3.0 drive (if your mainboard supports them because it has a USB 3.0 +host controller), you will get different `bus:port` values shown on the configuration screen. Keep this in mind when +setting up the game, assigning the ports and using USB thumb drives with the games. + +### My USB thumb drive is not detected by the game at all +Which means you cannot use it to even map the USB ports in the test menu. + +Make sure to try at least another one by a different brand. There have been reports of some thumb drives simply not +working, e.g. a fairly old Kingston 1GB. In general, everything that gets detected fine by Linux should work. + +### My USB thumb drive works when mapping the ports in the test menu but is not recognized on the game login screen +Might be the same issue as [here](#my-usb-thumb-drive-is-not-detected-by-the-game-at-all). Try out different USB thumb +drives. Be aware of the [USB 3.0 vs 2.0 issue](#usb-30-vs-20-issues-with-usb-thumb-drivesprofiles) as well. + +### The game enters the operator menu when I start it +This is known to happen consistently on NX but was observed on other versions like Exceed 2 and Zero in the past. The +cause for this is unknown so far. Even with all usb emulation layers removed from pumptools and a real MK6 PIUIO +attached this still happens. If the game is run without the PIUIO attached, everything's fine. Therefore, we suspect +this is a bug within the game's PIUIO driver, likely some uninitialized buffers (due to the randomness of this bug +being triggered). + +### How to I generate a fresh configuration file with default values +If you deleted your `hook.conf` file or you just want a clean start with default values, the hook creates a clean +`hook.conf` file if none exists once you run `piueb`. + +### What are the command line arguments supported by the hook +Just run `piueb run -h` to get help output from the hook library. This also provides you with shortened command line +parameters for all options available from the configuration file. + +### How do I provide command line arguments to quickly change configuration settings for the game +Just run `piueb run` with the shortened command line parameter, e.g. `piueb run -w`. + +### The game's music plays too fast, too slow, or sounds weird +Depending on the game version you play, the audio subsystem is set to either render to an output device with a +frequency of 44100hz or 48000hz in SE16_LE format. Alsa needs to be configured accordingly to play back the audio +data at the right sample rate to make it sound right. + +Games and audio settings required: +* 44100hz: MK3 Linux ports 1st to Prex 3, Exceed (1), Pro 1 and Pro 2 +* 48000hz: Exceed 2 and newer + +One possibility to fix that is change the values in your config, e.g. `/usr/share/alsa/pcm/dmix.conf` when using the +`dmix` device (the location and config can differ depending on your setup). In case you have to set them to 48000hz, +search for the following configuration values and replace them with these values: +``` +format S16_LE +rate 48000 +``` + +If the contents of the files are just variables, check `/usr/share/alsa/alsa.conf` something similar like this: +```text +defaults.pcm.dmix.rate 44100 +defaults.pcm.dmix.format "S16_LE" +``` + +The same method applies to replacing 44100hz with 48000hz. + +### How do I figure out which sound device to select +You can list the currently connected devices/sound cards using the following command: +```shell script +cat /proc/asound/cards +``` + +Example output: +```text + 0 [PCH ]: HDA-Intel - HDA Intel PCH + HDA Intel PCH at 0xfb610000 irq 51 + 1 [NVidia ]: HDA-Intel - HDA NVidia + HDA NVidia at 0xfb080000 irq 52 +``` + +You can see two audio devices available: `0` being the built-in sound chip and `1` the audio output on the installed +GPU (i.e. HDMI audio out). + +To route the audio to the device of your choice, e.g. device `0`, add the number to the `hw:` path: `hw:0` for device +`0`. Set `hw:0` in the configuration file: + +```text +patch.sound.device=hw:0 +``` + +### The game plays/renders too fast +The game relies on vsync to lock to the target framerate of 60 FPS. Ensure vsync is turned on in your GPU settings. + +### libGL.so.1: cannot open shared object file: No such file or directory +Install your GPU drivers. This library depends on the GPU driver and is not included with the distributed data. + +### There's no sound at all, even with the correct sound device selected +On certain setups, the sound output only seems to work after already having attempted to use the sound device once. +In a shell, try running the following command twice: + +```shell script +aplay -q /usr/share/sounds/alsa/Front_Center.wav +``` + +If after a fresh boot the sound plays after the second attempt, your setup suffers from this issue. +Simply putting the above command once in a boot script will make sure the sound device is activated. \ No newline at end of file diff --git a/doc/hook/mk3hook.md b/doc/hook/mk3hook.md new file mode 100644 index 0000000..329d98b --- /dev/null +++ b/doc/hook/mk3hook.md @@ -0,0 +1,283 @@ +# mk3hook: 1st to Prex 3/Premiere 3 Linux ports +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +First and foremost, the MK3 Linux ports are runnable without this hook as well. The ports were created from the original +fully disassembled DOS binaries and reassembled for 32-bit Linux. To make the games run on modern non-MK3 hardware, +additional features were added to the disassembly: +* Software lockchip emulation +* ISA PIUIO to USB PIUIO (over libusb) +* MP3 audio decoding and playback using fmodex +* Software sound effect playback +* Software EEPROM data reading/writing + +However, since modifying the (decompiled) source code is a very complex task, various additional features and fixes +are applied using a hook library. This lacks certain flexibility but is so far sufficient to fix various bugs and add +some more quality of life features. + +## Additional notable features +* Audio subsystem using fmodex: Bugfixes and audio device selection +* Relocate game data to `game` sub-folder to have identical data layout to newer generation games +* Additional development/debugging features, e.g. file, io, open logging and tracing +* Hardcoded OpenGL bugfix +* Utilize pumptools configuration infrastructure to unify configuration of all games + +## Versions supported +Basically, "all" versions are supported considering there was only one Linux binary per game released so far. + +## Quick start: how to run (official release), additional steps +Start with the quick start guide from the [main hook readme](../hook.md#quick-start-how-to-run-official-release) and +add the additional steps at the very end: +1. **1st and 2nd only**: Open the `hook.conf` file and set the following property: `game.1st_2nd_fs=1`. For details, see +[this section](#1st-or-2nd-errors-about-failed-resource-loading) +1. **1st only**: Go straight to the operator menu by pressing `G` on your keyboard. Go to `GAME OPTION`, select and +confirm `DEFAULT SETTING` and `SAVE AND EXIT`. Next, go to `COIN OPTION`, `DEFAULT SETTING` and `SAVE AND EXIT`. See +[this section](#1st-crashes-right-after-the-andamiro-logo-or-the-intro-sequence-when-i-should-see-the-title-screen-with-a-floating-point-exception) +for details. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required by all Linux ports: +* libGL.so.1 +* libX11.so.6 +* libXxf86vm.so.1 +* libXrandr.so.2 +* libpthread.so.0 +* libXi.so.6 +* libXcursor.so.1 +* libXinerama.so.1 +* libm.so.6 +* libncurses.so.5 +* libtinfo.so.5 +* libfmodex.so +* libconfig.so.9 +* libusb-0.1.so.4 +* libc.so.6 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libusb-0.1-4 +* libconfig++9v5 +* tinfo5 +* ncurses5 +* libxcursor1 +* libxinerama1 +* libxi6 +* libxrandr2 +* libxxf86vm1 +* libx11-6 +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), the following information +goes for a clean set of data from a pristine/non-bootleg CD. + +If you have the official release, this might not be relevant to you as it just explains some important technical details +about the data. + +In general, get a clean set of data from a pristine/non-bootleg CD. + +However, 1st, 2nd and 3rd and Extra (IIRC) are the exception here. These games have their textures packed in an odd +format (IIRC something about an odd color format and/or textures being flipped) that cannot be used with the Linux port +versions. These versions require file modification and repacking to make everything look correct with the linux +binaries. + +Furthermore, because the old games ran on case-insensitive file systems, everything goes with file naming depending on +the version of the game, e.g. full upper/lower-case files, folders and even mixed ones, e.g. Stage.cfg (*sigh*). +In order to make this less painful for the the hook library, some file names were modified to create some sort of +consistency. + +You are not required to have the pulled data in the same location and layout as given by the original layout on the +disc as this can be configured with the hook library. Everything can be located locally in a single folder. The settings +for this can be found and tweaked in the `hook.conf` file which is created after you started the game once +([see below](#mk3hook-features)). + +#### The game data subfolder +This differs slightly from newer generation games, i.e. MK6-based and newer. The hook library takes care of this by +implementing a consistent directory structure on all versions of the game. Therefore, all game data from the CD of MK3 +games goes into a `game` folder as well. Example of `games` contents for Prex 3: +* `AUDIO` +* `BGA` +* `STEP` +* `TITLE` +* `PIU.BIN` +* `STAGE.CFG` + +Furthermore, the game needs to have the sound effects available as files. These were stored on a ROM chip on the MK3 +hardware. Luckily, newer PC-based games have these as normal files with the correct naming in the `game/WAVE` subfolder. +These also go into `game/EFFECTS`. + +Some other and older versions come with different files and folders but the process is identical. The first three games, +1st, 2nd and 3rd, had their audio files stored on disc as PCM audio data next to the other game assets. These audio +files need to be ripped and provided as MP3 encoded audio files in the sub-folder `game/track`. + +## Linux port features +This section covers the features that were added to the Linux ports and therefore not available on the original DOS +versions. + +### Configuration file +A configuration file with different options can be provided to the game's bare executable. The configuration is provided +as a command line argument when running the game, e.g. +``` +./piu ./save/config.cfg +``` + +Example contents: +``` +fullscreen = 1; +allow_exit = 1; +save_file = "./save/EEPROM.BIN"; +effect_path = "./EFFECTS/"; +track_path = "./track/"; +sync_offset = 115; +sync_multiplier = 4.16666666666666696272613990004; +music_volume = 1.0; +sfx_volume = 1.0; +``` + +Most entries are self-explanatory. However, there are two parameters that can be tweaked to control synchronisation of +the stepchart to the music. + +The `sync_offset` parameter (in ms) is used to offset the stepchart to the music. However, as you might be used to such +a parameter from other music games, this offset is **NOT** entirely identical to adjusting the music to your sound +system's latency. You can use this value to shift the synchronisation point forward and backward but keep in mind that +it will not match any other offset values you determined in other games. + +The `sync_multiplier` is also a variable that was depending on the sound hardware of the target platform. It was +already determined and there should be **NO** reason to change it unless you know what it does and how it is used in +synchronizing the stepchart to the song in the engine. + +All these configuration values are exposed via the `hook.conf` file and hooked to the pumptools configuration +infrastructure. Usually, there is no need to deal with this directly, so this is section is mainly for documenting its +presence. + +### Built-in keyboard controls +Ignore this section if you are using the `mk3hook` because it will disable this feature entirely. See +[this section](#configure-io). + +The following keyboard controls are available with the Linux ports. + +PIUIO hooked controls: +``` +Test: Key G +Service: Key H +Clear: Key J +Coin 1: Key K +Coin 2: Key L + +Pads (Player 2 on numpad): +Q E 7 9 + S 5 +Z C 1 3 +``` + +Keyboard controls supported by the game engine (won't work on very early versions of the game, e.g. 1st, 2nd, 3rd): +``` +Test: F1 +Service: F2 +Clear: F3 +``` + +### USB PIUIO +Ignore this section if you are using the `mk3hook` because it will disable this feature entirely. See +[this section](#configure-io). + +When a USB PIUIO is plugged it, the game will automatically detect and use it. + +### Exit the game +Use `Test` + `Service` on the USB PIUIO (controls) to exit the game. This can also be blocked in the configuration. + +## mk3hook features +Check the `hook.conf` file which is located in the same folder as the `piu` executable once you have started the game. +The available settings are explained in the `hook.conf` file. + +### Configure IO +See [this section of the main hook readme](../hook.md#configure-io). + +### Select another audio device +If the default sound card is not working, e.g. see [here](#no-sound-and-fmod-errors-in-log), you might want to +select another audio device/card instead. + +In order to find out which cards are available and which configuration value to set, you have to run the game once. +Check the log and you will see a list of available devices printed somewhere at the beginning of the log, for example: +``` +Output type: 11 +Num available drivers 43 +Driver 0: default +Driver 1: null +Driver 2: jack +Driver 3: sysdefault:CARD=PCH +Driver 4: front:CARD=PCH,DEV=0 +... +``` + +By default and if you have not configured any sound device, yet, this will pick the first, usually, `default` device. +Pick another one by copying the name, e.g. `sysdefault:CARD=PCH`, and setting it in the `hook.conf` file: +``` +patch.sound.device=sysdefault:CARD=PCH +``` + +When you restart the game, check the log if the device got picked up properly. This is indicated by a log message +right after the device list is printed. + +### Debugging fmodex issues +You can also debug issues with fmodex, e.g. why +[the selected sound device does not work](#no-sound-and-fmod-errors-in-log). + +You need to replace the normal `fmodex.so` library in the game local `lib` folder with a `fmodexL.so` version. Just +rename the "L"-version to `fmodex.so` and have it in the game local `lib` folder. Furthermore, you have to enable +debug output by setting the following configuration value in the `hook.conf` file: +``` +patch.sound.debug_output=0 +``` + +After that's done, you should see additional log output by fmodex on the console. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +### No sound and FMOD errors in log +If you see one or multiple of the following error messages in the log output +``` +FMOD error! (60) Error initializing output device. +FMOD error! (79) This command failed because System::init or System::setDriver was not called. +FMOD error! (37) An invalid parameter was passed to this function. +``` +it is very likely that fmod cannot use the default/currently selected audio device for playback. This can have various +reasons from non suitable configuration to device being used by another process and therefore blocked if not supporting +software mixing. + +Choose another device for playback instead, see [this section](#select-another-audio-device), or you can enable +fmodex debug output to further debug this issue, see [this section](#debugging-fmodex-issues). + +### 1st/2nd is missing the "Insert Coin" text on the title screen and several other graphics, e.g. life bar during gameplay +This is a known bug and we do not have a fix for this so far. However, this is not always triggered and if you keep +restarting the game (with a few seconds of waiting between restarts), you will start the game without this bug being +active eventually. + +### 1st or 2nd errors about failed resource loading +For example: +``` +FAIL: res_load( piu.dat ) +``` + +This error indicates that one or multiple game files are not placed in the right location(s), your configured `game` +sub-directory path is not correct or you forgot to switch on the "1st/2nd filesystem" feature switch in the hook +configuration. For the latter, set the following in your `hook.conf` file: +``` +game.1st_2nd_fs=1 +``` + +### 1st crashes right after the Andamiro logo or the intro sequence when I should see the title screen with a floating point exception +1st does not detect if no EEPROM data is available and does not write defaults on first start or when you deleted the +`save/EEPROM.BIN` file. Therefore, all settings values for the game are considered "0". This is fine with all settings +except the coin settings. This causes the floating point exception though I assume it was actually caused by a division +by zero. + +To fix this, go right to the operator menu when you booted up the game and are still on the Andamiro logo screen. Go +to `GAME OPTION`, select and confirm `DEFAULT SETTING` and `SAVE AND EXIT`. Next, go to `COIN OPTION`, `DEFAULT SETTING` +and `SAVE AND EXIT`. This writes a fresh `EEPROM.bin` file with all default settings and you are good to go. \ No newline at end of file diff --git a/doc/hook/nx2hook.md b/doc/hook/nx2hook.md new file mode 100644 index 0000000..9ef978e --- /dev/null +++ b/doc/hook/nx2hook.md @@ -0,0 +1,154 @@ +# nx2hook: NX2 +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Additional notable features +* Removed USB flash drive vendor lock, i.e. use _ANY_ USB flash drive to store game profiles +* Auto generate new profiles if no profile is found on the connected USB flash drive + +## Versions supported +All known versions supported. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* libfreetype.so.6 +* librt.so.1 +* libGL.so.1 +* libGLU.so.1 +* libusb-0.1.so.4 +* libpthread.so.0 +* libXxf86vm.so.1 +* libpng12.so.0 +* libasound.so.2 +* libmad.so.0 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libX11.so.6 +* libstdc++.so.6 +* libz.so.1 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libx11-6 +* zlib1g +* libusb-0.1-4 +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), this game requires all +files and folders from the original `game` folder to be in **UPPERCASE** on a case-sensitive file system with the +exception of `*.txt` and `*.ttf` files in the root of game. Further game asset files and folders from cramfs need to be +copied to the `game` directory. `nx.ttf`, `nxcn.ttf`, `nxpt.ttf`, `nxtw.ttf` and `mission.txt` must be **lowercase** but +`SCRIPT` and its contents must be **UPPERCASE**. + +## Pumpnet setup +Instead of using plain usb profiles like on the vanilla version without pumptools (which is still possible with +pumptools), pumptools provides a patch module to upload/download usb profiles to/from a remote server over TCP IP +networks. + +This feature can be enabled by setting the following configuration properties in the `hook.conf` file: +```text +patch.net_profile.server= +patch.net_profile.machine_id= +``` + +If the network offers or even requires secure communication using https, you should have received a package with a +client certificate, a client key and a certificate authority bundle. Place the files named `ca-bundle-crt.pem`, +`client-crt.pem` and `client-key.pem` in a folder, e.g. `cert` next to the `piu` executable and configure the hook +to use these for the encrypted communication by setting the property key `patch.net_profile.cert_dir_path` +accordingly, e.g. `patch.net_profile.cert_dir_path=./cert`. Note: The server URL that you set for the properties key +`patch.net_profile.server` has to be a https based URL in order to work correctly, e.g. `https://localhost`. Your +network provided of your choice should provide you the URL you have to use. + +When everything's configured correctly, the log tells you so: +```text +Initialized pumpnet for game 20, serveraddr localhost:8080, main endpoint version /usbprofile/v1 +Initialized: game 20, server XXXXXXX, machine id XXXXXXX +``` + +How you acquire an address to a remote server and a machine ID is out of this document's scope. + +Once these parameters are present, pumptools is looking for a file called `pumpnet.bin` on connected usb sticks. As +long as this file is in the root directory of your usb drive, the game will ignore the the regular `nx2save.bin` and +`nx2rank.bin` files and always try to connect to the remote server. When you remove `pumpnet.bin`, it will pick up the +local profiles and not connect to the server, even if enabled. + +`pumpnet.bin` contains an identifier for the player to login. This file needs to be provided by the network service +somehow. The how is out of the scope of this document. + +Ensure you have mapped the usb ports in the game correctly. Go to the operator menu and the "usb drive" item. Plug +**exactly one** usb thumb drive into the usb port you want to assign as P1 and hit the test button. The menu item +should change from `---` to a numerical value, e.g. `03:00` which describes the bus and port the drive got detected on. +Repeat this for P2. + +When you start the game, have your usb stick plugged in and it is recognized correctly by the game, the log output +tells you if it found the `pumpnet.bin` file and connected to the server correctly for downloading your profile data: +```text +Found pumpnet profile file /mnt/0/pumpnet.bin +Profile file player 0, file_type 0, refId XXXXXXXXXXXXXX downloading from server... +Downloading file player 0, file_type 0, refId XXXXXXXXXXXXXX successful +``` + +If it cannot connect to the server, the log tells you that as well and retries to connect to it a few times before +giving up: +```text +Performing curl request failed: Couldn't connect to server +Failed, http code 0, retrying (0)... +... +``` + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +### How do I unlock 'Tell Me' on the non korean version? +Put an empty file called `KEY.LUA` into the `game/SCRIPT` folder and change the language to korean in the operator menu. +This loads the korean version of the game (yes, that's how it actually worked originally) and 'Tell Me' will be +available. + +Note: You can't switch back to English unless you delete the file `game/SCRIPT/KEY.LUA`. + +### When using pumpnet, the game does not detect any usb sticks +Make sure that you have configured the usb ports in the game's operator menu `USB DRIVE` menu item. For instructions, +refer to the [above section](#pumpnet-setup). + +### When using pumpnet, the game tells me to register my usb drive on login +If you see the message "Please REGISTER your USB drive at www.piugame.com prior to using the product." when logging in +with pumpnet enable, your login got rejected for one of the following reasons: +* Your machine ID is invalid or not whitelisted on the server +* Your player ID is invalid or no such player exists on the server +* No NX2 profile was created for the player ID on the server + +On any of the above cases, verify that you ensured you have configured everything correctly on the user web interface +of pumpnet. Otherwise, contact the server administrator. + +### When using pumpnet, the game apparently gets stuck on the usb drive login screen +This can happen if the game cannot reach the server or on some other errors that might be temporarily. Therefore, the +game retries for up to ten times currently to reach the server or complete an outstanding operation. This is also +reflected in the logs with warning messages telling you the game is retrying. + +### Curl requests fail: Problem with the SSL CA cert +When you get the following error message: +```text +Performing curl request failed: Problem with the SSL CA cert (path? access rights?) +``` + +Make sure the path you configured for the property key `patch.net_profile.cert_dir_path` is pointing to an existing +directory containing the files `ca-bundle-crt.pem`, `client-crt.pem` and `client-key.pem` that you received from the +the network you are trying to connect to. + +### Curl requests fail: SSL peer certificate or SSH remote key was not OK +When you get the following error message: +```text +Performing curl request failed: SSL peer certificate or SSH remote key was not OK +``` + +Make sure that you have the files `ca-bundle-crt.pem`, `client-crt.pem` and `client-key.pem` that you have received +from the network you are trying to connect to placed in a directory. The path to the **directory** needs to be set in +the hook configuration file by setting the key `patch.net_profile.cert_dir_path`, e.g. +`patch.net_profile.cert_dir_path=./cert` if the files are placed next to the `piu` exec in the folder `cert`. \ No newline at end of file diff --git a/doc/hook/nxahook.md b/doc/hook/nxahook.md new file mode 100644 index 0000000..df9f414 --- /dev/null +++ b/doc/hook/nxahook.md @@ -0,0 +1,55 @@ +# nxahook: NXA +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Additional notable features +* Removed USB flash drive vendor lock, i.e. use _ANY_ USB flash drive to store game profiles +* Auto generate new profiles if no profile is found on the connected USB flash drive + +# Versions supported +All known versions supported. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* libfreetype.so.6 +* librt.so.1 +* libGL.so.1 +* libGLU.so.1 +* libusb-0.1.so.4 +* libpthread.so.0 +* libXxf86vm.so.1 +* libpng12.so.0 +* libasound.so.2 +* libmad.so.0 +* libboost_regex-mt.so.3 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libX11.so.6 +* libdl.so.2 +* libstdc++.so.6 +* libz.so.1 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libx11-6 +* zlib1g +* libusb-0.1-4 +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), this game requires all +files and folders from the original `game` folder to be in **UPPERCASE** on a case-sensitive file system. Further game +asset files and folders from cramfs need to be copied to the `game` directory. `nx.ttf`, `nxcn.ttf`, `nxpt.ttf`, +`nxtw.ttf`, `mission.txt` and `ufo.txt` must be **lowercase** but `SCRIPT` and its contents must be **UPPERCASE**. + +The `config` (or `CONFIG`) folder and its contents must be available in **UPPER** _AND_ **lowercase**. The `BrainQuest` +folder name must be kept like this and its contents must be **lowercase**. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. \ No newline at end of file diff --git a/doc/hook/nxhook.md b/doc/hook/nxhook.md new file mode 100644 index 0000000..69eeec5 --- /dev/null +++ b/doc/hook/nxhook.md @@ -0,0 +1,52 @@ +# nxhook: NX +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Versions supported +All known versions supported. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* librt.so.1 +* liblua50.so.5.0 +* liblualib50.so.5.0 +* libGL.so.1 +* libGLU.so.1 +* libusb-0.1.so.4 +* libpthread.so.0 +* libpng12.so.0 +* libasound.so.2 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libXext.so.6 +* libX11.so.6 +* libstdc++.so.5 +* libz.so.1 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libx11-6 +* zlib1g +* libusb-0.1-4 +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), this game requires all +files and folders in the `game` folder to be in **UPPERCASE** on a case-sensitive file system. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +### Fully unlock the game +This hook has an option to fully unlock the game by setting the following property in the configuration file: +```text +game.force_unlock=1 +``` + +This will unlock all missions in "World Tour" as well any locked songs in "Special Zone", and the song "FAEP 2-2". \ No newline at end of file diff --git a/doc/hook/os.md b/doc/hook/os.md new file mode 100644 index 0000000..66b49dd --- /dev/null +++ b/doc/hook/os.md @@ -0,0 +1,59 @@ +# Hardware +Everything runs on original hardware MK6 and up. However, newer games might be slightly more demanding and will not +run smoothly on the old MK6 anymore. + +As for custom hardware, everything that's at least of MK6 specs should do the job. GPU-wise you are not bound to nVidia +cards. Though, the card of your choice has to support at least the OpenGL 2.0 standard. + +However, not that we have seen graphical glitches on AMD and Intel GPUs with NX2 which we haven't seen on older pump +versions. The game starts and runs but after some time you might encounter graphical glitches. + +You can also run the games in a VM. Recommended settings: 2 vCPUs, 2 GB RAM, OpenGL 2.0 hardware acceleration enabled +(requires installing drivers/kernel modules on your guest). + +# Operating system and environment setup +This document outlines common stuff that is required to run any of the games supported by pumptools. Make sure to follow +these properly and have your system prepared for the hooks before you continue with their dedicated readme files. + +## Linux distributions supported +If you have the required knowledge, you should be able to get this to run on any distribution available. However, there +are a few things to consider: +* The game is a 32-bit binary, you need to be able to run 32-bit binaries +* Naturally, the game requires 32-bit versions of the libraries it depends on +* The game is built with glibc. You might have a hard time on distributions not shipping with them by default, e.g. +Alpine Linux +* Kernel-wise, the latest kernels and everything that's not pre 2.6 should work. Due to various hook sub-modules, many +quirks in different games have been fixed to run all games on the latest upstream kernel versions of Linux. + +Recommendation: Use a 64-bit Linux distribution of your choice. You can also use a 32-bit distribution as this is the +arch these games were built for but it does not come with any benefits. Prepare yourself to upgrade to 64-bit once any +of the newer games (finally) moves to that target architecture. + +## Dependencies +Each game and hook comes with a list of dependencies you might have to install. This depends on which type of dependency +resolution you pick. + +When running this on a 64-bit Ubuntu, all packages must be installed as lib32 packages! When you are on Debian/Ubuntu +(based) distros and you are using apt, you have to enable multiarch support first: +```shell script +sudo dpkg --add-architecture i386 +apt update +``` + +Then, install the 32-bit packages like this where `` must be replaced accordingly: +```shell script +apt install pkgname:i386 +``` + +Note: The `:386` postfix does not apply to packages like `gccmultilib` as this already covers the i386 part. + +## GPU drivers +For `libGL`, you need to install a GPU driver and have hardware acceleration enabled. The `libGL` library provided also +needs to be 32-bit compatible. + +To check if everything's installed and HW acceleration is working, just run `glxgears`. If that doesn't error and you +see the rendered gears spinning, you should be fine. + +## Sound drivers +Naturally, you also have to have sound stuff installed. Having alsa with its libraries available is sufficient. Pulse +and similar audio systems are not required, e.g. when running on a cabinet. \ No newline at end of file diff --git a/doc/hook/prihook.md b/doc/hook/prihook.md new file mode 100644 index 0000000..2c6e23a --- /dev/null +++ b/doc/hook/prihook.md @@ -0,0 +1,108 @@ +# Notable features + +* Runs on recent kernel versions thanks to various fixes +* Runs on 32-bit and 64-bit distros (64-bit distros require additional 32-bit libs to be installed) +* Full dongle emulation +* Remove HDD checks to run this on "non legit" drives +* Full MK6IO emulation with API hook: Keyboard or your own custom IO +* Real IO passthrough (for MK6 usb io) + +# Versions supported +All known versions supported. + +# Data setup +You are expected to get a clean set of data from a prestine drive. Ensure that +the game version matches one of the supported versions listed. + +You need two main folders: +* data +* settings + +## Data folder +Contents of the folder: +* game: The binaries of the custom "AMFS". File names must be lower case. +* lib: Put any libraries (especially older versions of libraries that can't be +installed anymore using the package manager) the game uses and aren't installed +on your system in here. +* piu: The piu executable + +## Settings folder +The contents of the folder are auto generated if the files don't exist. +Otherwise, this folder contains: +* PIUPRIME.INI +* RANK.DATA + +## Executable dependencies +All dependencies must be compiled as 32-bit binaries. Here is a list of +dependencies (with versions) required to run the game: +* libGL.so.1 +* libGLU.so.1 +* libasound.so.2 +* libcurl.so.4 +* libsodium.so.13 +* libusb-0.1.so.4 +* libmad.so.0 +* libmpeg2.so.0 +* libmpeg2convert.so.0 +* libftgl.so.2 +* libstdc++.so.6 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libXext.so.6 +* libX11.so.6 +* libpthread.so.0 +* libdl.so.2 +* librt.so.1 +* libnvidia-tls.so.340.96 +* libnvidia-glcore.so.340.96 +* libidn.so.11 +* libssh2.so.1 +* libssl.so.1.0.0 +* libcrypto.so.1.0.0 +* libgssapi_krb5.so.2 +* libkrb5.so.3 +* libk5crypto.so.3 +* libcom_err.so.2 +* libz.so.1 +* libusb-1.0.so.0 +* libfreetype.so.6 +* libxcb.so.1 +* libkrb5support.so.0 +* libkeyutils.so.1 +* libresolv.so.2 +* libudev.so.1 +* libbz2.so.1.0 +* libpng16.so.16 +* libharfbuzz.so.0 +* libXau.so.6 +* libXdmcp.so.6 +* libcap.so.2 +* libglib-2.0.so.0 +* libgraphite2.so.3 +* libpcre.so.1 + +# Hook module configuration file +Checkout the usage information of the hook and set the option values according +to your needs. Here is an example option configuration file: +``` +log_file_path=/tmp/pumptools.log +log_level=3 +enable_file_monitor=0 +enable_io_monitor=0 +piuio_emu_lib_path=/pumptools/lib/piuio-emu.so +piuio_exit_test_service=1 +game_settings_path=/save/pri +sound_device=hw:0 +keyboard_dev=/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse +halt_on_segv=0 +``` + +# Run the game +Ensure you are running an X screen. Otherwise, you have to start one along with the game. Various library/system-calls +require root privileges. Make sure to run the game as root or with sudo (otherwise you get various sorts of errors, +typically permission denied). Use the included *run.sh* file to start the game on a desktop environment. + +# Further notes +## Vsync +The game is required to run with vsync on. \ No newline at end of file diff --git a/doc/hook/pro2hook.md b/doc/hook/pro2hook.md new file mode 100644 index 0000000..05e7dee --- /dev/null +++ b/doc/hook/pro2hook.md @@ -0,0 +1,91 @@ +# Notable features + +* Runs on recent kernel versions +* Runs on 32-bit and 64-bit distros (64-bit distros require additional 32-bit libs to be installed) +* Dongle stuff must be patched out +* You need decrypted data zips to run this +* Full MK6IO emulation with API hook: Keyboard or your own custom IO +* Full PIUBTN emulation with API hook: Keyboard or your own custom IO +* Real IO passthrough (for MK6 usb io and PIUBTN) + +# Versions supported +Currently, only the latest revision is supported (I think that's R5?) + +# Data setup +A clean set of data won't work here. Glenn protected the data with his own life +(pretty much) and made it as obnoxious as possible to unpack it. So good luck +getting the original data out of a drive image (if you didn't get it already +from somewhere). + +All access to files and folders are detoured to two folders which makes setting +up everything easier. + +You need one main folder: +* game/pro2 (contains all the game data, stepmania layout) + +## Executable dependencies +All dependencies must be compiled as 32-bit binaries. Here is a list of +dependencies (with versions) required to run the game: +* libXtst.so.6 +* libXrandr.so.2 +* libGL.so.1 +* libGLU.so.1 +* libdl.so.2 +* libavformat.so.51 +* libavcodec.so.51 +* libavutil.so.49 +* libusb-0.1.so.4 +* libpthread.so.0 +* librt.so.1 +* libstdc++.so.5 +* libm.so.6 +* libgcc_s.so.1 +* libc.so.6 +* libX11.so.6 +* libXext.so.6 +* libXi.so.6 +* libXrender.so.1 +* libnvidia-tls.so.340.106 +* libnvidia-glcore.so.340.106 +* libstdc++.so.6 +* libxcb.so.1 +* libXau.so.6 +* libXdmcp.so.6 + +# Hook module configuration file +Checkout the usage information of the hook and set the option values according +to your needs. Here is an example option configuration file: +``` +log_file_path=./pumptools.log +log_level=3 +enable_file_monitor=0 +enable_io_monitor=0 +piubtn_emu_lib_path= +piubtn_real_passthrough=1 +piuio_emu_lib_path=./piuio.so +piuio_real_passthrough=1 +piuio_exit_test_service=1 +game_data_path=./game +``` + +# Run the game +Ensure you are running an X screen. Run the game using +Ensure you are running an X screen. Otherwise, you have to start one along with the game. Various library/system-calls +require root privileges. Make sure to run the game as root or with sudo (otherwise you get various sorts of errors, +typically permission denied). Use the included *run.sh* file to start the game on a desktop environment. + +# Further notes +## ITG2 PIUIO kernel module hack +If you don't have the original kernel module installed and you are running a +real PIUIO, you have to hook the *piuio.so* lib which implements the piuio api. +The "emulation" part which simply calls back to a real piuio driver takes +care of handling the kernel hack path then. If you run on a real IO without +hooking that module, you won't get an inputs or outputs. + +## The game is crashing very early +This is probably due to not having the right IO hardware connected/emulated. +The game doesn't have any proper error handling if either the PIUIO or the +button IO is missing/not connected (or not emulated). + +## Vsync +The game is required to run with vsync on. \ No newline at end of file diff --git a/doc/hook/prohook.md b/doc/hook/prohook.md new file mode 100644 index 0000000..886134c --- /dev/null +++ b/doc/hook/prohook.md @@ -0,0 +1,107 @@ +# prohook: Pro (1) +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Versions supported +All known versions supported if no-dongle patched at this time. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* libXtst.so.6 +* libXrandr.so.2 +* libGL.so.1 +* libGLU.so.1 +* libdl.so.2 +* libavformat.so.51 +* libavcodec.so.51 +* libavutil.so.49 +* libusb-0.1.so.4 +* libpthread.so.0 +* librt.so.1 +* libstdc++.so.5 +* libm.so.6 +* libgcc_s.so.1 +* libc.so.6 +* libX11.so.6 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libx11-6 +* libusb-0.1-4 +* libasound2 + +## Data setup +A clean set of data won't work here. You need the decrypted data zip files and a patched executable that uses plain zip +files instead of encrypted ones. + +All access to files and folders are detoured to two folders which makes setting up everything easier. + +You need two main folders: +* `game` folder with the following contents + * All data zip files (e.g. `data0.zip`, `data1.zip`, ..., `encore.zip`) + * An empty file `FX` (if you run this on a FX or other cabinet with a widescreen monitor) +* `save ` folder. Contents are generated automatically if empty. + +## USB thumb drive/profile support +Without any patches, the game's way of handling USB thumb drives is incompatible to the kernels of the last years. +This is fixed by prohook but requires some additional configuration effort. + +1. Decide which physical USB ports of your machine you are going to use for the player 1 and player 2 sides. +1. Plug in *one* USB thumb drive into the player 1 port. Now you have to figure out two things: + 1. The device node the drive got assigned to by the kernel, e.g. `sdb`. For example, use the command `fdisk` or + `lsblk` for this and take a note. + 1. The USB bus and port number the thumb drive is plugged into. `ls -la /sys/block` shows you all currently + available block devices, including USB thumb drives. Find the thumb drive you plugged into the physical port and + check the path the symlink gets resolved to. For example: + `sdc -> ../devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1:1.0/host7/target7:0:0/7:0:0:0/block/sdd` + You can identify the bus and port by taking a look at the part after the `usb2` directory here: `2-2`. The format + is `bus-port` which means that in this example the drive is plugged into port 1 of bus 2. Take a note of that. +1. Repeat the previous step for the physical port you consider using for player 2. +1. Create two folders that will serve as mount points for the two player sides in the `/mnt` directory, e.g. +`mkdir /mnt/0 && mkdir /mnt/1` (or re-using these folders if they already exist from other piu games). +1. Add the following entry to the `/etc/fstab` file on the machine you want to run the game on: +```text +/dev/sdb1 /mnt/0 auto noauto,owner 0 0 +/dev/sdc1 /mnt/1 auto noauto,owner 0 0 +``` +Note: This does not create a fixed assignment of `/dev/sdb1` or `/dev/sdc1` to a specific physical USB port. It just +ensures that any block device that gets enumerated as `/dev/sdb` will get its first partition mounted to `/mnt/0` +(same concept applies to `/dev/sdc1/`). +1. Modify the `hook.conf` file used with `prohook.so` by inserting the device nodes and bus-port combinations into the +respective fields, for example: +```text +patch.usb_profile.p1.bus_port=2-1 +patch.usb_profile.p2.bus_port=2-2 +# Note: No partitions, e.g. sdb1, here +patch.usb_profile.dev_nodes=sdb,sdc +``` + +Once you plug-in a USB thumb drive to the configured ports, it should show up on the correct player side. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +## Enable log output from the game +If you run into any issues, consider enabling the game's log output to console which might help you figuring out +what's going on. This can be done by editing the `data.Static.ini` file in the `data0.zip` file. Go to the section +`[Options-arcade]` and change the property `ShowLogOutput=0` to `ShowLogOutput=1`. + +## Switch screen aspect ratio: 4:3 and 16:9 +The game supports 4:3 and 16:9 aspect ratios. To enable 16:9 mode, ensure that an empty file called `FX` is placed +next to the data zip files inside the `game` directory. For 4:3 mode, simply delete the `FX` file if it exists. + +## ITG2 PIUIO kernel module hack +If you don't have the original kernel module installed and you are running a real PIUIO, you have to hook the +`ptapi-io-piuio-real.so` lib which implements the piuio api. The "emulation" part which simply calls back to a real +piuio driver takes care of handling the kernel hack path then. If you run on a real IO without hooking that module, +you won't get any inputs or outputs. + +## The game is crashing very early +The log might show something about "ptrace failing" and not being able to "load libformat". However, the actual problem +is probably not having all the necessary IO hardware connected (or emulation enabled). The game doesn't have any proper +error handling if either the PIUIO or the button IO is missing/not connected (or not emulated). \ No newline at end of file diff --git a/doc/hook/x2hook.md b/doc/hook/x2hook.md new file mode 100644 index 0000000..2fad993 --- /dev/null +++ b/doc/hook/x2hook.md @@ -0,0 +1,60 @@ +# x2hook: Exceed 2 +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Versions supported +* 102 + +Any other version won't work, period. The hook has to memory patch a weird bug causing the sound thread to crash. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* libGL.so.1 +* libGLU.so.1 +* libpthread.so.0 +* libmad.so.0 +* libasound.so.2 +* libz.so.1 +* libpng12.so.0 +* libmpeg2.so.0 +* libmpeg2convert.so.0 +* libusb-0.1.so.4 +* liblua50.so.5.0 +* liblualib50.so.5.0 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libX11.so.6 +* libstdc++.so.5 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libx11-6 +* zlib1g +* libusb-0.1-4 +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), this game requires all +files and folders in the `game` folder to be in **UPPERCASE** on a case-sensitive file system. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +### Fully unlock the game +This hook has an option to fully unlock the game (well, unlock Canon-D Full Mix without entering the code because that's +the only permanent unlock) by setting the following property in the configuration file: +```text +game.force_unlock=1 +``` + +### Using the unlock option to unlock Canon-D full remix does not work when enabled +When the game cannot read from an existing `PIUEXCEED.INI` file, the settings are created in-memory and written to disk. +Therefore, the unlock mechanism of the hook cannot apply this to the contents in-memory but only when the +`PIUEXCEED.INI` file is re-loaded. To achieve this, once you started the game to create a new `PIUEXCEED.INI` with +default values, simply quit the game and restart. \ No newline at end of file diff --git a/doc/hook/zerohook.md b/doc/hook/zerohook.md new file mode 100644 index 0000000..b31f20b --- /dev/null +++ b/doc/hook/zerohook.md @@ -0,0 +1,50 @@ +# zerohook: Zero +This readme covers any matters that are relevant for this hook, only. Anything that applies to **all** hooks is covered +in a [main hook readme file](../hook.md) including general data setup and a quick start guide. + +## Versions supported +All known versions supported. + +## Dependencies +Make sure to read the different methods of dependency resolution available in the [main hook readme file](../hook.md), +first. + +The following **direct** dependencies (cmd: `readelf -d piu`) are required: +* libGL.so.1 +* libGLU.so.1 +* libpthread.so.0 +* libasound.so.2 +* libz.so.1 +* libpng12.so.0 +* libusb-0.1.so.4 +* liblua50.so.5.0 +* liblualib50.so.5.0 +* libgcc_s.so.1 +* libc.so.6 +* libm.so.6 +* libX11.so.6 +* libstdc++.so.5 + +As for method 1, when using Ubuntu, the dependencies can be found in the following packages: +* libc-bin (or gcc-multilib on a 64-bit platform) +* libx11-6 +* zlib1g +* libusb-0.1-4 +* libasound2 + +## Data setup +In additional to the [general information applying to **all** hooks](../hook.md#data-setup), this game requires all +files and folders in the `game` folder to be in **UPPERCASE** on a case-sensitive file system. + +## Troubleshooting and FAQ +Make sure to also check the +[troubleshooting and FAQ section of the main hook readme](../hook.md#troubleshooting-and-faq). This covers various +things that apply to **all** hooks. The following sub-sections apply mainly to this hook. + +### Fully unlock the game +This hook has an option to fully unlock the game by setting the following property in the configuration file: +```text +game.force_unlock=1 +``` + +This will unlock all missions on mission station as well as any locked songs and stepcharts. \ No newline at end of file diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh new file mode 100755 index 0000000..da24dd0 --- /dev/null +++ b/scripts/run-tests.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +for i in "$1"/bin/test-*; do + test="$(basename $i)" + + echo "Running test $test..." + + "$i" || exit 1 +done + +echo "All tests successful" + +exit 0 \ No newline at end of file diff --git a/src/api/ptapi/io/piubtn.h b/src/api/ptapi/io/piubtn.h new file mode 100644 index 0000000..62d8e60 --- /dev/null +++ b/src/api/ptapi/io/piubtn.h @@ -0,0 +1,105 @@ +/** + * Common API to use for any devices implementing piu (pro) button controls + * (e.g. keyboard emulation, custom IOs) + */ +#ifndef PTAPI_IO_PIUBTN_H +#define PTAPI_IO_PIUBTN_H + +#include +#include + +/** + * Button inputs of a single player + */ +struct ptapi_io_piubtn_inputs { + bool start; + bool back; + bool left; + bool right; +}; + +/** + * Button light outputs of a single player + */ +struct ptapi_io_piubtn_outputs { + bool start; + bool back; + bool left; + bool right; +}; + +typedef const char* (*ptapi_io_piubtn_ident_t)(void); +typedef bool (*ptapi_io_piubtn_open_t)(void); +typedef void (*ptapi_io_piubtn_close_t)(void); +typedef bool (*ptapi_io_piubtn_recv_t)(void); +typedef bool (*ptapi_io_piubtn_send_t)(void); +typedef void (*ptapi_io_piubtn_get_input_t)(uint8_t player, struct ptapi_io_piubtn_inputs* inputs); +typedef void (*ptapi_io_piubtn_set_output_t)(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs); + +/** + * API functions in a struct to make them easier to handle and have less boilerplate + */ +struct ptapi_io_piubtn_api { + ptapi_io_piubtn_ident_t ident; + ptapi_io_piubtn_open_t open; + ptapi_io_piubtn_close_t close; + ptapi_io_piubtn_recv_t recv; + ptapi_io_piubtn_send_t send; + ptapi_io_piubtn_get_input_t get_input; + ptapi_io_piubtn_set_output_t set_output; +}; + +/** + * Return an identifier of the implementation. Used for logging and debugging. + * + * @return Identifier string for your implementation (e.g. "my-custom-btnio") + */ +const char* ptapi_io_piubtn_ident(void); + +/** + * Open the piubtn device + * + * Open any file handles, spawn threads and/or initialize your device or emulation code to be ready to accept further + * commands. + * + * @return True if opening/initializing your implementation was sucessful, false on failure + */ +bool ptapi_io_piubtn_open(void); + +/** + * Close and cleanup your device, shut down threads, free resources etc + */ +void ptapi_io_piubtn_close(void); + +/** + * Get _ALL_ readable data from your device in this single recv call. + * + * @return True on success, false on error + */ +bool ptapi_io_piubtn_recv(void); + +/** + * Send any output data (e.g. lights) to your device + * + * @return True on success, false on error + */ +bool ptapi_io_piubtn_send(void); + +/** + * Get buffered button input data + * + * @param player Player id (0, 1) + * @param inputs Pointer to buffer to copy inputs to. Every time this is invoked, this buffer is nulled. If you do not + * write any data to this, all inputs remain un-triggered. + */ +void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* inputs); + +/** + * Set button light outputs (i.e. buffer them) + * + * @param player Player id (0, 1) + * @param outputs Pointer to output data to copy to your private buffers. + */ +void ptapi_io_piubtn_set_output(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs); + +#endif \ No newline at end of file diff --git a/src/api/ptapi/io/piuio.h b/src/api/ptapi/io/piuio.h new file mode 100644 index 0000000..95964cd --- /dev/null +++ b/src/api/ptapi/io/piuio.h @@ -0,0 +1,163 @@ +/** + * Common API to use for any devices implementing (MK6) piuio controls + * (e.g. keyboard emulation, custom IOs) + */ +#ifndef PTAPI_IO_PIUIO_H +#define PTAPI_IO_PIUIO_H + +#include +#include + +/** + * Enum for pad input sensor groups (four sensors per button/panel) + */ +enum ptapi_io_piuio_sensor_group { + PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT = 0, + PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT = 1, + PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN = 2, + PTAPI_IO_PIUIO_SENSOR_GROUP_UP = 3, + PTAPI_IO_PIUIO_SENSOR_GROUP_NUM = 4, +}; + +/** + * Inputs of all arrows of a single pad (per sensor group) + */ +struct ptapi_io_piuio_pad_inputs { + bool lu; + bool ru; + bool cn; + bool ld; + bool rd; +}; + +/** + * System/operator inputs + */ +struct ptapi_io_piuio_sys_inputs { + bool test; + bool service; + bool clear; + bool coin; + bool coin2; +}; + +/** + * Pad light outputs + */ +struct ptapi_io_piuio_pad_outputs { + bool lu; + bool ru; + bool cn; + bool ld; + bool rd; +}; + +/** + * Cabinet light outputs + */ +struct ptapi_io_piuio_cab_outputs { + bool bass; + bool halo_r2; + bool halo_r1; + bool halo_l2; + bool halo_l1; +}; + +typedef const char* (*ptapi_io_piuio_ident_t)(void); +typedef bool (*ptapi_io_piuio_open_t)(void); +typedef void (*ptapi_io_piuio_close_t)(void); +typedef bool (*ptapi_io_piuio_recv_t)(void); +typedef bool (*ptapi_io_piuio_send_t)(void); +typedef void (*ptapi_io_piuio_get_input_pad_t)(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs); +typedef void (*ptapi_io_piuio_get_input_sys_t)(struct ptapi_io_piuio_sys_inputs* inputs); +typedef void (*ptapi_io_piuio_set_output_pad_t)(uint8_t player, struct ptapi_io_piuio_pad_outputs* outputs); +typedef void (*ptapi_io_piuio_set_output_cab_t)(const struct ptapi_io_piuio_cab_outputs* outputs); + +/** + * API functions in a struct to make them easier to handle and have less boilerplate + */ +struct ptapi_io_piuio_api { + ptapi_io_piuio_ident_t ident; + ptapi_io_piuio_open_t open; + ptapi_io_piuio_close_t close; + ptapi_io_piuio_recv_t recv; + ptapi_io_piuio_send_t send; + ptapi_io_piuio_get_input_pad_t get_input_pad; + ptapi_io_piuio_get_input_sys_t get_input_sys; + ptapi_io_piuio_set_output_pad_t set_output_pad; + ptapi_io_piuio_set_output_cab_t set_output_cab; +}; + +/** + * Return an identifier of the implementation. Used for logging and debugging. + * + * @return Identifier string for your implementation (e.g. "my-custom-io") + */ +const char* ptapi_io_piuio_ident(void); + +/** + * Open the piuio device + * + * Open any file handles, spawn threads and/or initialize your device or emulation code to be ready to accept further + * commands. + * + * @return True if opening/initializing your implementation was sucessful, false on failure + */ +bool ptapi_io_piuio_open(void); + +/** + * Close and cleanup your device, shut down threads, free resources etc + */ +void ptapi_io_piuio_close(void); + +/** + * Get _ALL_ readable data from your device in this single recv call. If you have to address single sensores like the + * real piuio, you have to do this on a single call to this function. + * + * @return True on success, false on error + */ +bool ptapi_io_piuio_recv(void); + +/** + * Send any output data (e.g. lights) to your device + * + * @return True on success, false on error + */ +bool ptapi_io_piuio_send(void); + +/** + * Get buffered pad input data + * + * @param player Player id (0, 1) + * @param sensor_group Sensor group states to get + * @param inputs Pointer to buffer to copy inputs of the selected sensor group to. Every time this is invoked, this + * buffer is nulled. If you do not write any data to this, all inputs remain un-triggered. + */ +void ptapi_io_piuio_get_input_pad(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs); + +/** + * Get buffered system (test, service, clear, coin) inputs + * + * @param inputs Pointer to buffer to copy inputs to. Every time this is invoked, this buffer is nulled. If you do not + * write any data to this, all inputs remain un-triggered. + */ +void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs); + +/** + * Set pad light outputs (i.e. buffer them) + * + * @param player Player id (0, 1) + * @param outputs Pointer to output data to copy to your private buffers. + */ +void ptapi_io_piuio_set_output_pad(uint8_t player, const struct ptapi_io_piuio_pad_outputs* outputs); + +/** + * Set cabinet light outputs (i.e. buffer them) + * + * @param outputs Pointer to output data to copy to your private buffers. + */ +void ptapi_io_piuio_set_output_cab(const struct ptapi_io_piuio_cab_outputs* outputs); + +#endif \ No newline at end of file diff --git a/src/api/ptapi/io/x11-input-hook.h b/src/api/ptapi/io/x11-input-hook.h new file mode 100644 index 0000000..2a4d02a --- /dev/null +++ b/src/api/ptapi/io/x11-input-hook.h @@ -0,0 +1,39 @@ +/** + * Pumptools hooks into the X11 event dispatch loop to grab different events and exposes + * keyboard input events. This allows external modules to react to these inputs. + */ +#ifndef PTAPI_IO_X11_INPUT_HOOK_H +#define PTAPI_IO_X11_INPUT_HOOK_H + +#include + +/** + * Input hooking structure with dispatch functions. + * Set functions you do not use to NULL. + */ +struct ptapi_io_x11_input_hook_handler { + /** + * Dispatch the key press event + * + * @param key Key pressed + */ + void (*dispatch_key_press)(KeySym key); + + /** + * Dispatch the key release event + * + * @param key Key released + */ + void (*dispatch_key_release)(KeySym key); +}; + +typedef const struct ptapi_io_x11_input_hook_handler* (*ptapi_io_x11_input_handler_hook_t)(void); + +/** + * Get an input hook handler to receive keyboard inputs from the X11 event loop. + * + * @return Either a valid handler structure with dispatch functions or NULL if unused. + */ +const struct ptapi_io_x11_input_hook_handler* ptapi_io_x11_input_handler_hook(void); + +#endif diff --git a/src/imports/cmocka/cmocka.c b/src/imports/cmocka/cmocka.c new file mode 100644 index 0000000..e0d7cc4 --- /dev/null +++ b/src/imports/cmocka/cmocka.c @@ -0,0 +1,3522 @@ +/* + * Copyright 2008 Google Inc. + * Copyright 2014-2018 Andreas Schneider + * Copyright 2015 Jakub Hrozek + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" + +#ifdef HAVE_MALLOC_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This allows to add a platform specific header file. Some embedded platforms + * sometimes miss certain types and definitions. + * + * Example: + * + * typedef unsigned long int uintptr_t + * #define _UINTPTR_T 1 + * #define _UINTPTR_T_DEFINED 1 + */ +#ifdef CMOCKA_PLATFORM_INCLUDE +# include "cmocka_platform.h" +#endif /* CMOCKA_PLATFORM_INCLUDE */ + +#include +#include + +/* Size of guard bytes around dynamically allocated blocks. */ +#define MALLOC_GUARD_SIZE 16 +/* Pattern used to initialize guard blocks. */ +#define MALLOC_GUARD_PATTERN 0xEF +/* Pattern used to initialize memory allocated with test_malloc(). */ +#define MALLOC_ALLOC_PATTERN 0xBA +#define MALLOC_FREE_PATTERN 0xCD +/* Alignment of allocated blocks. NOTE: This must be base2. */ +#define MALLOC_ALIGNMENT sizeof(size_t) + +/* Printf formatting for source code locations. */ +#define SOURCE_LOCATION_FORMAT "%s:%u" + +#if defined(HAVE_GCC_THREAD_LOCAL_STORAGE) +# define CMOCKA_THREAD __thread +#elif defined(HAVE_MSVC_THREAD_LOCAL_STORAGE) +# define CMOCKA_THREAD __declspec(thread) +#else +# define CMOCKA_THREAD +#endif + +#ifdef HAVE_CLOCK_REALTIME +#define CMOCKA_CLOCK_GETTIME(clock_id, ts) clock_gettime((clock_id), (ts)) +#else +#define CMOCKA_CLOCK_GETTIME(clock_id, ts) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif + +/** + * POSIX has sigsetjmp/siglongjmp, while Windows only has setjmp/longjmp. + */ +#ifdef HAVE_SIGLONGJMP +# define cm_jmp_buf sigjmp_buf +# define cm_setjmp(env) sigsetjmp(env, 1) +# define cm_longjmp(env, val) siglongjmp(env, val) +#else +# define cm_jmp_buf jmp_buf +# define cm_setjmp(env) setjmp(env) +# define cm_longjmp(env, val) longjmp(env, val) +#endif + + +/* + * Declare and initialize the pointer member of ValuePointer variable name + * with ptr. + */ +#define declare_initialize_value_pointer_pointer(name, ptr) \ + ValuePointer name ; \ + name.value = 0; \ + name.x.pointer = (void*)(ptr) + +/* + * Declare and initialize the value member of ValuePointer variable name + * with val. + */ +#define declare_initialize_value_pointer_value(name, val) \ + ValuePointer name ; \ + name.value = val + +/* Cast a LargestIntegralType to pointer_type via a ValuePointer. */ +#define cast_largest_integral_type_to_pointer( \ + pointer_type, largest_integral_type) \ + ((pointer_type)((ValuePointer*)&(largest_integral_type))->x.pointer) + +/* Used to cast LargetIntegralType to void* and vice versa. */ +typedef union ValuePointer { + LargestIntegralType value; + struct { +#if defined(WORDS_BIGENDIAN) && (WORDS_SIZEOF_VOID_P == 4) + unsigned int padding; +#endif + void *pointer; + } x; +} ValuePointer; + +/* Doubly linked list node. */ +typedef struct ListNode { + const void *value; + int refcount; + struct ListNode *next; + struct ListNode *prev; +} ListNode; + +/* Debug information for malloc(). */ +struct MallocBlockInfoData { + void* block; /* Address of the block returned by malloc(). */ + size_t allocated_size; /* Total size of the allocated block. */ + size_t size; /* Request block size. */ + SourceLocation location; /* Where the block was allocated. */ + ListNode node; /* Node within list of all allocated blocks. */ +}; + +typedef union { + struct MallocBlockInfoData *data; + char *ptr; +} MallocBlockInfo; + +/* State of each test. */ +typedef struct TestState { + const ListNode *check_point; /* Check point of the test if there's a */ + /* setup function. */ + void *state; /* State associated with the test. */ +} TestState; + +/* Determines whether two values are the same. */ +typedef int (*EqualityFunction)(const void *left, const void *right); + +/* Value of a symbol and the place it was declared. */ +typedef struct SymbolValue { + SourceLocation location; + LargestIntegralType value; +} SymbolValue; + +/* + * Contains a list of values for a symbol. + * NOTE: Each structure referenced by symbol_values_list_head must have a + * SourceLocation as its' first member. + */ +typedef struct SymbolMapValue { + const char *symbol_name; + ListNode symbol_values_list_head; +} SymbolMapValue; + +/* Where a particular ordering was located and its symbol name */ +typedef struct FuncOrderingValue { + SourceLocation location; + const char * function; +} FuncOrderingValue; + +/* Used by list_free() to deallocate values referenced by list nodes. */ +typedef void (*CleanupListValue)(const void *value, void *cleanup_value_data); + +/* Structure used to check the range of integer types.a */ +typedef struct CheckIntegerRange { + CheckParameterEvent event; + LargestIntegralType minimum; + LargestIntegralType maximum; +} CheckIntegerRange; + +/* Structure used to check whether an integer value is in a set. */ +typedef struct CheckIntegerSet { + CheckParameterEvent event; + const LargestIntegralType *set; + size_t size_of_set; +} CheckIntegerSet; + +/* Used to check whether a parameter matches the area of memory referenced by + * this structure. */ +typedef struct CheckMemoryData { + CheckParameterEvent event; + const void *memory; + size_t size; +} CheckMemoryData; + +static ListNode* list_initialize(ListNode * const node); +static ListNode* list_add(ListNode * const head, ListNode *new_node); +static ListNode* list_add_value(ListNode * const head, const void *value, + const int count); +static ListNode* list_remove( + ListNode * const node, const CleanupListValue cleanup_value, + void * const cleanup_value_data); +static void list_remove_free( + ListNode * const node, const CleanupListValue cleanup_value, + void * const cleanup_value_data); +static int list_empty(const ListNode * const head); +static int list_find( + ListNode * const head, const void *value, + const EqualityFunction equal_func, ListNode **output); +static int list_first(ListNode * const head, ListNode **output); +static ListNode* list_free( + ListNode * const head, const CleanupListValue cleanup_value, + void * const cleanup_value_data); + +static void add_symbol_value( + ListNode * const symbol_map_head, const char * const symbol_names[], + const size_t number_of_symbol_names, const void* value, const int count); +static int get_symbol_value( + ListNode * const symbol_map_head, const char * const symbol_names[], + const size_t number_of_symbol_names, void **output); +static void free_value(const void *value, void *cleanup_value_data); +static void free_symbol_map_value( + const void *value, void *cleanup_value_data); +static void remove_always_return_values(ListNode * const map_head, + const size_t number_of_symbol_names); + +static size_t check_for_leftover_values_list(const ListNode * head, + const char * const error_message); + +static size_t check_for_leftover_values( + const ListNode * const map_head, const char * const error_message, + const size_t number_of_symbol_names); + +static void remove_always_return_values_from_list(ListNode * const map_head); + +/* + * This must be called at the beginning of a test to initialize some data + * structures. + */ +static void initialize_testing(const char *test_name); + +/* This must be called at the end of a test to free() allocated structures. */ +static void teardown_testing(const char *test_name); + +static enum cm_message_output cm_get_output(void); + +static int cm_error_message_enabled = 1; +static CMOCKA_THREAD char *cm_error_message; + +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +/* + * Keeps track of the calling context returned by setenv() so that the fail() + * method can jump out of a test. + */ +static CMOCKA_THREAD cm_jmp_buf global_run_test_env; +static CMOCKA_THREAD int global_running_test = 0; + +/* Keeps track of the calling context returned by setenv() so that */ +/* mock_assert() can optionally jump back to expect_assert_failure(). */ +jmp_buf global_expect_assert_env; +int global_expecting_assert = 0; +const char *global_last_failed_assert = NULL; +static int global_skip_test; + +/* Keeps a map of the values that functions will have to return to provide */ +/* mocked interfaces. */ +static CMOCKA_THREAD ListNode global_function_result_map_head; +/* Location of the last mock value returned was declared. */ +static CMOCKA_THREAD SourceLocation global_last_mock_value_location; + +/* Keeps a map of the values that functions expect as parameters to their + * mocked interfaces. */ +static CMOCKA_THREAD ListNode global_function_parameter_map_head; +/* Location of last parameter value checked was declared. */ +static CMOCKA_THREAD SourceLocation global_last_parameter_location; + +/* List (acting as FIFO) of call ordering. */ +static CMOCKA_THREAD ListNode global_call_ordering_head; +/* Location of last call ordering that was declared. */ +static CMOCKA_THREAD SourceLocation global_last_call_ordering_location; + +/* List of all currently allocated blocks. */ +static CMOCKA_THREAD ListNode global_allocated_blocks; + +static enum cm_message_output global_msg_output = CM_OUTPUT_STDOUT; + +static const char *global_test_filter_pattern; + +static const char *global_skip_filter_pattern; + +#ifndef _WIN32 +/* Signals caught by exception_handler(). */ +static const int exception_signals[] = { + SIGFPE, + SIGILL, + SIGSEGV, +#ifdef SIGBUS + SIGBUS, +#endif +#ifdef SIGSYS + SIGSYS, +#endif +}; + +/* Default signal functions that should be restored after a test is complete. */ +typedef void (*SignalFunction)(int signal); +static SignalFunction default_signal_functions[ + ARRAY_SIZE(exception_signals)]; + +#else /* _WIN32 */ + +/* The default exception filter. */ +static LPTOP_LEVEL_EXCEPTION_FILTER previous_exception_filter; + +/* Fatal exceptions. */ +typedef struct ExceptionCodeInfo { + DWORD code; + const char* description; +} ExceptionCodeInfo; + +#define EXCEPTION_CODE_INFO(exception_code) {exception_code, #exception_code} + +static const ExceptionCodeInfo exception_codes[] = { + EXCEPTION_CODE_INFO(EXCEPTION_ACCESS_VIOLATION), + EXCEPTION_CODE_INFO(EXCEPTION_ARRAY_BOUNDS_EXCEEDED), + EXCEPTION_CODE_INFO(EXCEPTION_DATATYPE_MISALIGNMENT), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_DENORMAL_OPERAND), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_DIVIDE_BY_ZERO), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_INEXACT_RESULT), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_INVALID_OPERATION), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_OVERFLOW), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_STACK_CHECK), + EXCEPTION_CODE_INFO(EXCEPTION_FLT_UNDERFLOW), + EXCEPTION_CODE_INFO(EXCEPTION_GUARD_PAGE), + EXCEPTION_CODE_INFO(EXCEPTION_ILLEGAL_INSTRUCTION), + EXCEPTION_CODE_INFO(EXCEPTION_INT_DIVIDE_BY_ZERO), + EXCEPTION_CODE_INFO(EXCEPTION_INT_OVERFLOW), + EXCEPTION_CODE_INFO(EXCEPTION_INVALID_DISPOSITION), + EXCEPTION_CODE_INFO(EXCEPTION_INVALID_HANDLE), + EXCEPTION_CODE_INFO(EXCEPTION_IN_PAGE_ERROR), + EXCEPTION_CODE_INFO(EXCEPTION_NONCONTINUABLE_EXCEPTION), + EXCEPTION_CODE_INFO(EXCEPTION_PRIV_INSTRUCTION), + EXCEPTION_CODE_INFO(EXCEPTION_STACK_OVERFLOW), +}; +#endif /* !_WIN32 */ + +enum CMUnitTestStatus { + CM_TEST_NOT_STARTED, + CM_TEST_PASSED, + CM_TEST_FAILED, + CM_TEST_ERROR, + CM_TEST_SKIPPED, +}; + +struct CMUnitTestState { + const ListNode *check_point; /* Check point of the test if there's a setup function. */ + const struct CMUnitTest *test; /* Point to array element in the tests we get passed */ + void *state; /* State associated with the test */ + const char *error_message; /* The error messages by the test */ + enum CMUnitTestStatus status; /* PASSED, FAILED, ABORT ... */ + double runtime; /* Time calculations */ +}; + +/* Exit the currently executing test. */ +static void exit_test(const int quit_application) +{ + const char *env = getenv("CMOCKA_TEST_ABORT"); + int abort_test = 0; + + if (env != NULL && strlen(env) == 1) { + abort_test = (env[0] == '1'); + } + + if (global_skip_test == 0 && + abort_test == 1) { + print_error("%s", cm_error_message); + abort(); + } else if (global_running_test) { + cm_longjmp(global_run_test_env, 1); + } else if (quit_application) { + exit(-1); + } +} + +void _skip(const char * const file, const int line) +{ + cm_print_error(SOURCE_LOCATION_FORMAT ": Skipped!\n", file, line); + global_skip_test = 1; + exit_test(1); +} + +/* Initialize a SourceLocation structure. */ +static void initialize_source_location(SourceLocation * const location) { + assert_non_null(location); + location->file = NULL; + location->line = 0; +} + + +/* Determine whether a source location is currently set. */ +static int source_location_is_set(const SourceLocation * const location) { + assert_non_null(location); + return location->file && location->line; +} + + +/* Set a source location. */ +static void set_source_location( + SourceLocation * const location, const char * const file, + const int line) { + assert_non_null(location); + location->file = file; + location->line = line; +} + + +static int c_strreplace(char *src, + size_t src_len, + const char *pattern, + const char *repl, + int *str_replaced) +{ + char *p = NULL; + + p = strstr(src, pattern); + if (p == NULL) { + return -1; + } + + do { + size_t of = p - src; + size_t l = strlen(src); + size_t pl = strlen(pattern); + size_t rl = strlen(repl); + + /* overflow check */ + if (src_len <= l + MAX(pl, rl) + 1) { + return -1; + } + + if (rl != pl) { + memmove(src + of + rl, src + of + pl, l - of - pl + 1); + } + + memcpy(src + of, repl, rl); + + if (str_replaced != NULL) { + *str_replaced = 1; + } + p = strstr(src, pattern); + } while (p != NULL); + + return 0; +} + +static int c_strmatch(const char *str, const char *pattern) +{ + int ok; + + if (str == NULL || pattern == NULL) { + return 0; + } + + for (;;) { + /* Check if pattern is done */ + if (*pattern == '\0') { + /* If string is at the end, we're good */ + if (*str == '\0') { + return 1; + } + + return 0; + } + + if (*pattern == '*') { + /* Move on */ + pattern++; + + /* If we are at the end, everything is fine */ + if (*pattern == '\0') { + return 1; + } + + /* Try to match each position */ + for (; *str != '\0'; str++) { + ok = c_strmatch(str, pattern); + if (ok) { + return 1; + } + } + + /* No match */ + return 0; + } + + /* If we are at the end, leave */ + if (*str == '\0') { + return 0; + } + + /* Check if we have a single wildcard or matching char */ + if (*pattern != '?' && *str != *pattern) { + return 0; + } + + /* Move string and pattern */ + str++; + pattern++; + } + + return 0; +} + +/* Create function results and expected parameter lists. */ +void initialize_testing(const char *test_name) { + (void)test_name; + list_initialize(&global_function_result_map_head); + initialize_source_location(&global_last_mock_value_location); + list_initialize(&global_function_parameter_map_head); + initialize_source_location(&global_last_parameter_location); + list_initialize(&global_call_ordering_head); + initialize_source_location(&global_last_parameter_location); +} + + +static void fail_if_leftover_values(const char *test_name) { + int error_occurred = 0; + (void)test_name; + remove_always_return_values(&global_function_result_map_head, 1); + if (check_for_leftover_values( + &global_function_result_map_head, + "%s() has remaining non-returned values.\n", 1)) { + error_occurred = 1; + } + + remove_always_return_values(&global_function_parameter_map_head, 2); + if (check_for_leftover_values( + &global_function_parameter_map_head, + "'%s' parameter still has values that haven't been checked.\n", + 2)) { + error_occurred = 1; + } + + remove_always_return_values_from_list(&global_call_ordering_head); + if (check_for_leftover_values_list(&global_call_ordering_head, + "%s function was expected to be called but was not.\n")) { + error_occurred = 1; + } + if (error_occurred) { + exit_test(1); + } +} + + +static void teardown_testing(const char *test_name) { + (void)test_name; + list_free(&global_function_result_map_head, free_symbol_map_value, + (void*)0); + initialize_source_location(&global_last_mock_value_location); + list_free(&global_function_parameter_map_head, free_symbol_map_value, + (void*)1); + initialize_source_location(&global_last_parameter_location); + list_free(&global_call_ordering_head, free_value, + (void*)0); + initialize_source_location(&global_last_call_ordering_location); +} + +/* Initialize a list node. */ +static ListNode* list_initialize(ListNode * const node) { + node->value = NULL; + node->next = node; + node->prev = node; + node->refcount = 1; + return node; +} + + +/* + * Adds a value at the tail of a given list. + * The node referencing the value is allocated from the heap. + */ +static ListNode* list_add_value(ListNode * const head, const void *value, + const int refcount) { + ListNode * const new_node = (ListNode*)malloc(sizeof(ListNode)); + assert_non_null(head); + assert_non_null(value); + new_node->value = value; + new_node->refcount = refcount; + return list_add(head, new_node); +} + + +/* Add new_node to the end of the list. */ +static ListNode* list_add(ListNode * const head, ListNode *new_node) { + assert_non_null(head); + assert_non_null(new_node); + new_node->next = head; + new_node->prev = head->prev; + head->prev->next = new_node; + head->prev = new_node; + return new_node; +} + + +/* Remove a node from a list. */ +static ListNode* list_remove( + ListNode * const node, const CleanupListValue cleanup_value, + void * const cleanup_value_data) { + assert_non_null(node); + node->prev->next = node->next; + node->next->prev = node->prev; + if (cleanup_value) { + cleanup_value(node->value, cleanup_value_data); + } + return node; +} + + +/* Remove a list node from a list and free the node. */ +static void list_remove_free( + ListNode * const node, const CleanupListValue cleanup_value, + void * const cleanup_value_data) { + assert_non_null(node); + free(list_remove(node, cleanup_value, cleanup_value_data)); +} + + +/* + * Frees memory kept by a linked list The cleanup_value function is called for + * every "value" field of nodes in the list, except for the head. In addition + * to each list value, cleanup_value_data is passed to each call to + * cleanup_value. The head of the list is not deallocated. + */ +static ListNode* list_free( + ListNode * const head, const CleanupListValue cleanup_value, + void * const cleanup_value_data) { + assert_non_null(head); + while (!list_empty(head)) { + list_remove_free(head->next, cleanup_value, cleanup_value_data); + } + return head; +} + + +/* Determine whether a list is empty. */ +static int list_empty(const ListNode * const head) { + assert_non_null(head); + return head->next == head; +} + + +/* + * Find a value in the list using the equal_func to compare each node with the + * value. + */ +static int list_find(ListNode * const head, const void *value, + const EqualityFunction equal_func, ListNode **output) { + ListNode *current; + assert_non_null(head); + for (current = head->next; current != head; current = current->next) { + if (equal_func(current->value, value)) { + *output = current; + return 1; + } + } + return 0; +} + +/* Returns the first node of a list */ +static int list_first(ListNode * const head, ListNode **output) { + ListNode *target_node = NULL; + assert_non_null(head); + if (list_empty(head)) { + return 0; + } + target_node = head->next; + *output = target_node; + return 1; +} + + +/* Deallocate a value referenced by a list. */ +static void free_value(const void *value, void *cleanup_value_data) { + (void)cleanup_value_data; + assert_non_null(value); + free((void*)value); +} + + +/* Releases memory associated to a symbol_map_value. */ +static void free_symbol_map_value(const void *value, + void *cleanup_value_data) { + SymbolMapValue * const map_value = (SymbolMapValue*)value; + const LargestIntegralType children = cast_ptr_to_largest_integral_type(cleanup_value_data); + assert_non_null(value); + list_free(&map_value->symbol_values_list_head, + children ? free_symbol_map_value : free_value, + (void *) ((uintptr_t)children - 1)); + free(map_value); +} + + +/* + * Determine whether a symbol name referenced by a symbol_map_value matches the + * specified function name. + */ +static int symbol_names_match(const void *map_value, const void *symbol) { + return !strcmp(((SymbolMapValue*)map_value)->symbol_name, + (const char*)symbol); +} + +/* + * Adds a value to the queue of values associated with the given hierarchy of + * symbols. It's assumed value is allocated from the heap. + */ +static void add_symbol_value(ListNode * const symbol_map_head, + const char * const symbol_names[], + const size_t number_of_symbol_names, + const void* value, const int refcount) { + const char* symbol_name; + ListNode *target_node; + SymbolMapValue *target_map_value; + assert_non_null(symbol_map_head); + assert_non_null(symbol_names); + assert_true(number_of_symbol_names); + symbol_name = symbol_names[0]; + + if (!list_find(symbol_map_head, symbol_name, symbol_names_match, + &target_node)) { + SymbolMapValue * const new_symbol_map_value = + (SymbolMapValue*)malloc(sizeof(*new_symbol_map_value)); + new_symbol_map_value->symbol_name = symbol_name; + list_initialize(&new_symbol_map_value->symbol_values_list_head); + target_node = list_add_value(symbol_map_head, new_symbol_map_value, + 1); + } + + target_map_value = (SymbolMapValue*)target_node->value; + if (number_of_symbol_names == 1) { + list_add_value(&target_map_value->symbol_values_list_head, + value, refcount); + } else { + add_symbol_value(&target_map_value->symbol_values_list_head, + &symbol_names[1], number_of_symbol_names - 1, value, + refcount); + } +} + + +/* + * Gets the next value associated with the given hierarchy of symbols. + * The value is returned as an output parameter with the function returning the + * node's old refcount value if a value is found, 0 otherwise. This means that + * a return value of 1 indicates the node was just removed from the list. + */ +static int get_symbol_value( + ListNode * const head, const char * const symbol_names[], + const size_t number_of_symbol_names, void **output) { + const char* symbol_name = NULL; + ListNode *target_node = NULL; + assert_non_null(head); + assert_non_null(symbol_names); + assert_true(number_of_symbol_names); + assert_non_null(output); + symbol_name = symbol_names[0]; + + if (list_find(head, symbol_name, symbol_names_match, &target_node)) { + SymbolMapValue *map_value = NULL; + ListNode *child_list = NULL; + int return_value = 0; + assert_non_null(target_node); + assert_non_null(target_node->value); + + map_value = (SymbolMapValue*)target_node->value; + child_list = &map_value->symbol_values_list_head; + + if (number_of_symbol_names == 1) { + ListNode *value_node = NULL; + return_value = list_first(child_list, &value_node); + assert_true(return_value); + /* Add a check to silence clang analyzer */ + if (return_value == 0) { + goto out; + } + *output = (void*) value_node->value; + return_value = value_node->refcount; + if (value_node->refcount - 1 == 0) { + list_remove_free(value_node, NULL, NULL); + } else if (value_node->refcount > WILL_RETURN_ONCE) { + --value_node->refcount; + } + } else { + return_value = get_symbol_value( + child_list, &symbol_names[1], number_of_symbol_names - 1, + output); + } + if (list_empty(child_list)) { + list_remove_free(target_node, free_symbol_map_value, (void*)0); + } + return return_value; + } +out: + cm_print_error("No entries for symbol %s.\n", symbol_name); + return 0; +} + +/** + * Taverse a list of nodes and remove first symbol value in list that has a + * refcount < -1 (i.e. should always be returned and has been returned at + * least once). + */ + +static void remove_always_return_values_from_list(ListNode * const map_head) +{ + ListNode * current = NULL; + ListNode * next = NULL; + assert_non_null(map_head); + + for (current = map_head->next, next = current->next; + current != map_head; + current = next, next = current->next) { + if (current->refcount < -1) { + list_remove_free(current, free_value, NULL); + } + } +} + +/* + * Traverse down a tree of symbol values and remove the first symbol value + * in each branch that has a refcount < -1 (i.e should always be returned + * and has been returned at least once). + */ +static void remove_always_return_values(ListNode * const map_head, + const size_t number_of_symbol_names) { + ListNode *current; + assert_non_null(map_head); + assert_true(number_of_symbol_names); + current = map_head->next; + while (current != map_head) { + SymbolMapValue * const value = (SymbolMapValue*)current->value; + ListNode * const next = current->next; + ListNode *child_list; + assert_non_null(value); + child_list = &value->symbol_values_list_head; + + if (!list_empty(child_list)) { + if (number_of_symbol_names == 1) { + ListNode * const child_node = child_list->next; + /* If this item has been returned more than once, free it. */ + if (child_node->refcount < -1) { + list_remove_free(child_node, free_value, NULL); + } + } else { + remove_always_return_values(child_list, + number_of_symbol_names - 1); + } + } + + if (list_empty(child_list)) { + list_remove_free(current, free_value, NULL); + } + current = next; + } +} + +static size_t check_for_leftover_values_list(const ListNode * head, + const char * const error_message) +{ + ListNode *child_node; + size_t leftover_count = 0; + if (!list_empty(head)) + { + for (child_node = head->next; child_node != head; + child_node = child_node->next, ++leftover_count) { + const FuncOrderingValue *const o = + (const FuncOrderingValue*) child_node->value; + cm_print_error(error_message, "%s", o->function); + cm_print_error(SOURCE_LOCATION_FORMAT + ": note: remaining item was declared here\n", + o->location.file, o->location.line); + } + } + return leftover_count; +} + +/* + * Checks if there are any leftover values set up by the test that were never + * retrieved through execution, and fail the test if that is the case. + */ +static size_t check_for_leftover_values( + const ListNode * const map_head, const char * const error_message, + const size_t number_of_symbol_names) { + const ListNode *current; + size_t symbols_with_leftover_values = 0; + assert_non_null(map_head); + assert_true(number_of_symbol_names); + + for (current = map_head->next; current != map_head; + current = current->next) { + const SymbolMapValue * const value = + (SymbolMapValue*)current->value; + const ListNode *child_list; + assert_non_null(value); + child_list = &value->symbol_values_list_head; + + if (!list_empty(child_list)) { + if (number_of_symbol_names == 1) { + const ListNode *child_node; + cm_print_error(error_message, "%s", value->symbol_name); + + for (child_node = child_list->next; child_node != child_list; + child_node = child_node->next) { + const SourceLocation * const location = + (const SourceLocation*)child_node->value; + cm_print_error(SOURCE_LOCATION_FORMAT + ": note: remaining item was declared here\n", + location->file, location->line); + } + } else { + cm_print_error("%s: ", value->symbol_name); + check_for_leftover_values(child_list, error_message, + number_of_symbol_names - 1); + } + symbols_with_leftover_values ++; + } + } + return symbols_with_leftover_values; +} + + +/* Get the next return value for the specified mock function. */ +LargestIntegralType _mock(const char * const function, const char* const file, + const int line) { + void *result; + const int rc = get_symbol_value(&global_function_result_map_head, + &function, 1, &result); + if (rc) { + SymbolValue * const symbol = (SymbolValue*)result; + const LargestIntegralType value = symbol->value; + global_last_mock_value_location = symbol->location; + if (rc == 1) { + free(symbol); + } + return value; + } else { + cm_print_error(SOURCE_LOCATION_FORMAT ": error: Could not get value " + "to mock function %s\n", file, line, function); + if (source_location_is_set(&global_last_mock_value_location)) { + cm_print_error(SOURCE_LOCATION_FORMAT + ": note: Previously returned mock value was declared here\n", + global_last_mock_value_location.file, + global_last_mock_value_location.line); + } else { + cm_print_error("There were no previously returned mock values for " + "this test.\n"); + } + exit_test(1); + } + return 0; +} + +/* Ensure that function is being called in proper order */ +void _function_called(const char *const function, + const char *const file, + const int line) +{ + ListNode *first_value_node = NULL; + ListNode *value_node = NULL; + int rc; + + rc = list_first(&global_call_ordering_head, &value_node); + first_value_node = value_node; + if (rc) { + FuncOrderingValue *expected_call; + int cmp; + + expected_call = (FuncOrderingValue *)value_node->value; + + cmp = strcmp(expected_call->function, function); + if (value_node->refcount < -1) { + /* + * Search through value nodes until either function is found or + * encounter a non-zero refcount greater than -2 + */ + if (cmp != 0) { + value_node = value_node->next; + expected_call = (FuncOrderingValue *)value_node->value; + + cmp = strcmp(expected_call->function, function); + while (value_node->refcount < -1 && + cmp != 0 && + value_node != first_value_node->prev) { + value_node = value_node->next; + if (value_node == NULL) { + break; + } + expected_call = (FuncOrderingValue *)value_node->value; + if (expected_call == NULL) { + continue; + } + cmp = strcmp(expected_call->function, function); + } + + if (expected_call == NULL || value_node == first_value_node->prev) { + cm_print_error(SOURCE_LOCATION_FORMAT + ": error: No expected mock calls matching " + "called() invocation in %s", + file, line, + function); + exit_test(1); + } + } + } + + if (cmp == 0) { + if (value_node->refcount > -2 && --value_node->refcount == 0) { + list_remove_free(value_node, free_value, NULL); + } + } else { + cm_print_error(SOURCE_LOCATION_FORMAT + ": error: Expected call to %s but received called() " + "in %s\n", + file, line, + expected_call->function, + function); + exit_test(1); + } + } else { + cm_print_error(SOURCE_LOCATION_FORMAT + ": error: No mock calls expected but called() was " + "invoked in %s\n", + file, line, + function); + exit_test(1); + } +} + +/* Add a return value for the specified mock function name. */ +void _will_return(const char * const function_name, const char * const file, + const int line, const LargestIntegralType value, + const int count) { + SymbolValue * const return_value = + (SymbolValue*)malloc(sizeof(*return_value)); + assert_true(count != 0); + return_value->value = value; + set_source_location(&return_value->location, file, line); + add_symbol_value(&global_function_result_map_head, &function_name, 1, + return_value, count); +} + + +/* + * Add a custom parameter checking function. If the event parameter is NULL + * the event structure is allocated internally by this function. If event + * parameter is provided it must be allocated on the heap and doesn't need to + * be deallocated by the caller. + */ +void _expect_check( + const char* const function, const char* const parameter, + const char* const file, const int line, + const CheckParameterValue check_function, + const LargestIntegralType check_data, + CheckParameterEvent * const event, const int count) { + CheckParameterEvent * const check = + event ? event : (CheckParameterEvent*)malloc(sizeof(*check)); + const char* symbols[] = {function, parameter}; + check->parameter_name = parameter; + check->check_value = check_function; + check->check_value_data = check_data; + set_source_location(&check->location, file, line); + add_symbol_value(&global_function_parameter_map_head, symbols, 2, check, + count); +} + +/* + * Add an call expectations that a particular function is called correctly. + * This is used for code under test that makes calls to several functions + * in depended upon components (mocks). + */ + +void _expect_function_call( + const char * const function_name, + const char * const file, + const int line, + const int count) +{ + FuncOrderingValue *ordering; + + assert_non_null(function_name); + assert_non_null(file); + assert_true(count != 0); + + ordering = (FuncOrderingValue *)malloc(sizeof(*ordering)); + + set_source_location(&ordering->location, file, line); + ordering->function = function_name; + + list_add_value(&global_call_ordering_head, ordering, count); +} + +/* Returns 1 if the specified float values are equal, else returns 0. */ +static int float_compare(const float left, + const float right, + const float epsilon) { + float absLeft; + float absRight; + float largest; + float relDiff; + + float diff = left - right; + diff = (diff >= 0.f) ? diff : -diff; + + // Check if the numbers are really close -- needed + // when comparing numbers near zero. + if (diff <= epsilon) { + return 1; + } + + absLeft = (left >= 0.f) ? left : -left; + absRight = (right >= 0.f) ? right : -right; + + largest = (absRight > absLeft) ? absRight : absLeft; + relDiff = largest * FLT_EPSILON; + + if (diff > relDiff) { + return 0; + } + return 1; +} + +/* Returns 1 if the specified float values are equal. If the values are not equal + * an error is displayed and 0 is returned. */ +static int float_values_equal_display_error(const float left, + const float right, + const float epsilon) { + const int equal = float_compare(left, right, epsilon); + if (!equal) { + cm_print_error(FloatPrintfFormat " != " + FloatPrintfFormat "\n", left, right); + } + return equal; +} + +/* Returns 1 if the specified float values are different. If the values are equal + * an error is displayed and 0 is returned. */ +static int float_values_not_equal_display_error(const float left, + const float right, + const float epsilon) { + const int not_equal = (float_compare(left, right, epsilon) == 0); + if (!not_equal) { + cm_print_error(FloatPrintfFormat " == " + FloatPrintfFormat "\n", left, right); + } + return not_equal; +} + +/* Returns 1 if the specified values are equal. If the values are not equal + * an error is displayed and 0 is returned. */ +static int values_equal_display_error(const LargestIntegralType left, + const LargestIntegralType right) { + const int equal = left == right; + if (!equal) { + cm_print_error(LargestIntegralTypePrintfFormat " != " + LargestIntegralTypePrintfFormat "\n", left, right); + } + return equal; +} + +/* + * Returns 1 if the specified values are not equal. If the values are equal + * an error is displayed and 0 is returned. */ +static int values_not_equal_display_error(const LargestIntegralType left, + const LargestIntegralType right) { + const int not_equal = left != right; + if (!not_equal) { + cm_print_error(LargestIntegralTypePrintfFormat " == " + LargestIntegralTypePrintfFormat "\n", left, right); + } + return not_equal; +} + + +/* + * Determine whether value is contained within check_integer_set. + * If invert is 0 and the value is in the set 1 is returned, otherwise 0 is + * returned and an error is displayed. If invert is 1 and the value is not + * in the set 1 is returned, otherwise 0 is returned and an error is + * displayed. + */ +static int value_in_set_display_error( + const LargestIntegralType value, + const CheckIntegerSet * const check_integer_set, const int invert) { + int succeeded = invert; + assert_non_null(check_integer_set); + { + const LargestIntegralType * const set = check_integer_set->set; + const size_t size_of_set = check_integer_set->size_of_set; + size_t i; + for (i = 0; i < size_of_set; i++) { + if (set[i] == value) { + /* If invert = 0 and item is found, succeeded = 1. */ + /* If invert = 1 and item is found, succeeded = 0. */ + succeeded = !succeeded; + break; + } + } + if (succeeded) { + return 1; + } + cm_print_error(LargestIntegralTypePrintfFormatDecimal + " is %sin the set (", + value, invert ? "" : "not "); + for (i = 0; i < size_of_set; i++) { + cm_print_error(LargestIntegralTypePrintfFormat ", ", set[i]); + } + cm_print_error(")\n"); + } + return 0; +} + + +/* + * Determine whether a value is within the specified range. If the value is + * within the specified range 1 is returned. If the value isn't within the + * specified range an error is displayed and 0 is returned. + */ +static int integer_in_range_display_error( + const LargestIntegralType value, const LargestIntegralType range_min, + const LargestIntegralType range_max) { + if (value >= range_min && value <= range_max) { + return 1; + } + cm_print_error(LargestIntegralTypePrintfFormatDecimal + " is not within the range " + LargestIntegralTypePrintfFormatDecimal "-" + LargestIntegralTypePrintfFormatDecimal "\n", + value, range_min, range_max); + return 0; +} + + +/* + * Determine whether a value is within the specified range. If the value + * is not within the range 1 is returned. If the value is within the + * specified range an error is displayed and zero is returned. + */ +static int integer_not_in_range_display_error( + const LargestIntegralType value, const LargestIntegralType range_min, + const LargestIntegralType range_max) { + if (value < range_min || value > range_max) { + return 1; + } + cm_print_error(LargestIntegralTypePrintfFormatDecimal + " is within the range " + LargestIntegralTypePrintfFormatDecimal "-" + LargestIntegralTypePrintfFormatDecimal "\n", + value, range_min, range_max); + return 0; +} + + +/* + * Determine whether the specified strings are equal. If the strings are equal + * 1 is returned. If they're not equal an error is displayed and 0 is + * returned. + */ +static int string_equal_display_error( + const char * const left, const char * const right) { + if (strcmp(left, right) == 0) { + return 1; + } + cm_print_error("\"%s\" != \"%s\"\n", left, right); + return 0; +} + + +/* + * Determine whether the specified strings are equal. If the strings are not + * equal 1 is returned. If they're not equal an error is displayed and 0 is + * returned + */ +static int string_not_equal_display_error( + const char * const left, const char * const right) { + if (strcmp(left, right) != 0) { + return 1; + } + cm_print_error("\"%s\" == \"%s\"\n", left, right); + return 0; +} + + +/* + * Determine whether the specified areas of memory are equal. If they're equal + * 1 is returned otherwise an error is displayed and 0 is returned. + */ +static int memory_equal_display_error(const char* const a, const char* const b, + const size_t size) { + size_t differences = 0; + size_t i; + for (i = 0; i < size; i++) { + const char l = a[i]; + const char r = b[i]; + if (l != r) { + if (differences < 16) { + cm_print_error("difference at offset %" PRIdS " 0x%02x 0x%02x\n", + i, l, r); + } + differences ++; + } + } + if (differences > 0) { + if (differences >= 16) { + cm_print_error("...\n"); + } + cm_print_error("%"PRIdS " bytes of %p and %p differ\n", + differences, (void *)a, (void *)b); + return 0; + } + return 1; +} + + +/* + * Determine whether the specified areas of memory are not equal. If they're + * not equal 1 is returned otherwise an error is displayed and 0 is + * returned. + */ +static int memory_not_equal_display_error( + const char* const a, const char* const b, const size_t size) { + size_t same = 0; + size_t i; + for (i = 0; i < size; i++) { + const char l = a[i]; + const char r = b[i]; + if (l == r) { + same ++; + } + } + if (same == size) { + cm_print_error("%"PRIdS "bytes of %p and %p the same\n", + same, (void *)a, (void *)b); + return 0; + } + return 1; +} + + +/* CheckParameterValue callback to check whether a value is within a set. */ +static int check_in_set(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + return value_in_set_display_error(value, + cast_largest_integral_type_to_pointer(CheckIntegerSet*, + check_value_data), 0); +} + + +/* CheckParameterValue callback to check whether a value isn't within a set. */ +static int check_not_in_set(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + return value_in_set_display_error(value, + cast_largest_integral_type_to_pointer(CheckIntegerSet*, + check_value_data), 1); +} + + +/* Create the callback data for check_in_set() or check_not_in_set() and + * register a check event. */ +static void expect_set( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType values[], const size_t number_of_values, + const CheckParameterValue check_function, const int count) { + CheckIntegerSet * const check_integer_set = + (CheckIntegerSet*)malloc(sizeof(*check_integer_set) + + (sizeof(values[0]) * number_of_values)); + LargestIntegralType * const set = (LargestIntegralType*)( + check_integer_set + 1); + declare_initialize_value_pointer_pointer(check_data, check_integer_set); + assert_non_null(values); + assert_true(number_of_values); + memcpy(set, values, number_of_values * sizeof(values[0])); + check_integer_set->set = set; + check_integer_set->size_of_set = number_of_values; + _expect_check( + function, parameter, file, line, check_function, + check_data.value, &check_integer_set->event, count); +} + + +/* Add an event to check whether a value is in a set. */ +void _expect_in_set( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType values[], const size_t number_of_values, + const int count) { + expect_set(function, parameter, file, line, values, number_of_values, + check_in_set, count); +} + + +/* Add an event to check whether a value isn't in a set. */ +void _expect_not_in_set( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType values[], const size_t number_of_values, + const int count) { + expect_set(function, parameter, file, line, values, number_of_values, + check_not_in_set, count); +} + + +/* CheckParameterValue callback to check whether a value is within a range. */ +static int check_in_range(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + CheckIntegerRange * const check_integer_range = + cast_largest_integral_type_to_pointer(CheckIntegerRange*, + check_value_data); + assert_non_null(check_integer_range); + return integer_in_range_display_error(value, check_integer_range->minimum, + check_integer_range->maximum); +} + + +/* CheckParameterValue callback to check whether a value is not within a range. */ +static int check_not_in_range(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + CheckIntegerRange * const check_integer_range = + cast_largest_integral_type_to_pointer(CheckIntegerRange*, + check_value_data); + assert_non_null(check_integer_range); + return integer_not_in_range_display_error( + value, check_integer_range->minimum, check_integer_range->maximum); +} + + +/* Create the callback data for check_in_range() or check_not_in_range() and + * register a check event. */ +static void expect_range( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType minimum, const LargestIntegralType maximum, + const CheckParameterValue check_function, const int count) { + CheckIntegerRange * const check_integer_range = + (CheckIntegerRange*)malloc(sizeof(*check_integer_range)); + declare_initialize_value_pointer_pointer(check_data, check_integer_range); + check_integer_range->minimum = minimum; + check_integer_range->maximum = maximum; + _expect_check(function, parameter, file, line, check_function, + check_data.value, &check_integer_range->event, count); +} + + +/* Add an event to determine whether a parameter is within a range. */ +void _expect_in_range( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType minimum, const LargestIntegralType maximum, + const int count) { + expect_range(function, parameter, file, line, minimum, maximum, + check_in_range, count); +} + + +/* Add an event to determine whether a parameter is not within a range. */ +void _expect_not_in_range( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType minimum, const LargestIntegralType maximum, + const int count) { + expect_range(function, parameter, file, line, minimum, maximum, + check_not_in_range, count); +} + + +/* CheckParameterValue callback to check whether a value is equal to an + * expected value. */ +static int check_value(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + return values_equal_display_error(value, check_value_data); +} + + +/* Add an event to check a parameter equals an expected value. */ +void _expect_value( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType value, const int count) { + _expect_check(function, parameter, file, line, check_value, value, NULL, + count); +} + + +/* CheckParameterValue callback to check whether a value is not equal to an + * expected value. */ +static int check_not_value(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + return values_not_equal_display_error(value, check_value_data); +} + + +/* Add an event to check a parameter is not equal to an expected value. */ +void _expect_not_value( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType value, const int count) { + _expect_check(function, parameter, file, line, check_not_value, value, + NULL, count); +} + + +/* CheckParameterValue callback to check whether a parameter equals a string. */ +static int check_string(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + return string_equal_display_error( + cast_largest_integral_type_to_pointer(char*, value), + cast_largest_integral_type_to_pointer(char*, check_value_data)); +} + + +/* Add an event to check whether a parameter is equal to a string. */ +void _expect_string( + const char* const function, const char* const parameter, + const char* const file, const int line, const char* string, + const int count) { + declare_initialize_value_pointer_pointer(string_pointer, + discard_const(string)); + _expect_check(function, parameter, file, line, check_string, + string_pointer.value, NULL, count); +} + + +/* CheckParameterValue callback to check whether a parameter is not equals to + * a string. */ +static int check_not_string(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + return string_not_equal_display_error( + cast_largest_integral_type_to_pointer(char*, value), + cast_largest_integral_type_to_pointer(char*, check_value_data)); +} + + +/* Add an event to check whether a parameter is not equal to a string. */ +void _expect_not_string( + const char* const function, const char* const parameter, + const char* const file, const int line, const char* string, + const int count) { + declare_initialize_value_pointer_pointer(string_pointer, + discard_const(string)); + _expect_check(function, parameter, file, line, check_not_string, + string_pointer.value, NULL, count); +} + +/* CheckParameterValue callback to check whether a parameter equals an area of + * memory. */ +static int check_memory(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + CheckMemoryData * const check = cast_largest_integral_type_to_pointer( + CheckMemoryData*, check_value_data); + assert_non_null(check); + return memory_equal_display_error( + cast_largest_integral_type_to_pointer(const char*, value), + (const char*)check->memory, check->size); +} + + +/* Create the callback data for check_memory() or check_not_memory() and + * register a check event. */ +static void expect_memory_setup( + const char* const function, const char* const parameter, + const char* const file, const int line, + const void * const memory, const size_t size, + const CheckParameterValue check_function, const int count) { + CheckMemoryData * const check_data = + (CheckMemoryData*)malloc(sizeof(*check_data) + size); + void * const mem = (void*)(check_data + 1); + declare_initialize_value_pointer_pointer(check_data_pointer, check_data); + assert_non_null(memory); + assert_true(size); + memcpy(mem, memory, size); + check_data->memory = mem; + check_data->size = size; + _expect_check(function, parameter, file, line, check_function, + check_data_pointer.value, &check_data->event, count); +} + + +/* Add an event to check whether a parameter matches an area of memory. */ +void _expect_memory( + const char* const function, const char* const parameter, + const char* const file, const int line, const void* const memory, + const size_t size, const int count) { + expect_memory_setup(function, parameter, file, line, memory, size, + check_memory, count); +} + + +/* CheckParameterValue callback to check whether a parameter is not equal to + * an area of memory. */ +static int check_not_memory(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + CheckMemoryData * const check = cast_largest_integral_type_to_pointer( + CheckMemoryData*, check_value_data); + assert_non_null(check); + return memory_not_equal_display_error( + cast_largest_integral_type_to_pointer(const char*, value), + (const char*)check->memory, + check->size); +} + + +/* Add an event to check whether a parameter doesn't match an area of memory. */ +void _expect_not_memory( + const char* const function, const char* const parameter, + const char* const file, const int line, const void* const memory, + const size_t size, const int count) { + expect_memory_setup(function, parameter, file, line, memory, size, + check_not_memory, count); +} + + +/* CheckParameterValue callback that always returns 1. */ +static int check_any(const LargestIntegralType value, + const LargestIntegralType check_value_data) { + (void)value; + (void)check_value_data; + return 1; +} + + +/* Add an event to allow any value for a parameter. */ +void _expect_any( + const char* const function, const char* const parameter, + const char* const file, const int line, const int count) { + _expect_check(function, parameter, file, line, check_any, 0, NULL, + count); +} + + +void _check_expected( + const char * const function_name, const char * const parameter_name, + const char* file, const int line, const LargestIntegralType value) { + void *result = NULL; + const char* symbols[] = {function_name, parameter_name}; + const int rc = get_symbol_value(&global_function_parameter_map_head, + symbols, 2, &result); + if (rc) { + CheckParameterEvent * const check = (CheckParameterEvent*)result; + int check_succeeded; + global_last_parameter_location = check->location; + check_succeeded = check->check_value(value, check->check_value_data); + if (rc == 1) { + free(check); + } + if (!check_succeeded) { + cm_print_error(SOURCE_LOCATION_FORMAT + ": error: Check of parameter %s, function %s failed\n" + SOURCE_LOCATION_FORMAT + ": note: Expected parameter declared here\n", + file, line, + parameter_name, function_name, + global_last_parameter_location.file, + global_last_parameter_location.line); + _fail(file, line); + } + } else { + cm_print_error(SOURCE_LOCATION_FORMAT ": error: Could not get value " + "to check parameter %s of function %s\n", file, line, + parameter_name, function_name); + if (source_location_is_set(&global_last_parameter_location)) { + cm_print_error(SOURCE_LOCATION_FORMAT + ": note: Previously declared parameter value was declared here\n", + global_last_parameter_location.file, + global_last_parameter_location.line); + } else { + cm_print_error("There were no previously declared parameter values " + "for this test.\n"); + } + exit_test(1); + } +} + + +/* Replacement for assert. */ +void mock_assert(const int result, const char* const expression, + const char* const file, const int line) { + if (!result) { + if (global_expecting_assert) { + global_last_failed_assert = expression; + longjmp(global_expect_assert_env, result); + } else { + cm_print_error("ASSERT: %s\n", expression); + _fail(file, line); + } + } +} + + +void _assert_true(const LargestIntegralType result, + const char * const expression, + const char * const file, const int line) { + if (!result) { + cm_print_error("%s\n", expression); + _fail(file, line); + } +} + +void _assert_return_code(const LargestIntegralType result, + size_t rlen, + const LargestIntegralType error, + const char * const expression, + const char * const file, + const int line) +{ + LargestIntegralType valmax; + + + switch (rlen) { + case 1: + valmax = 255; + break; + case 2: + valmax = 32767; + break; + case 4: + valmax = 2147483647; + break; + case 8: + default: + if (rlen > sizeof(valmax)) { + valmax = 2147483647; + } else { + valmax = 9223372036854775807L; + } + break; + } + + if (result > valmax - 1) { + if (error > 0) { + cm_print_error("%s < 0, errno(" + LargestIntegralTypePrintfFormatDecimal "): %s\n", + expression, error, strerror((int)error)); + } else { + cm_print_error("%s < 0\n", expression); + } + _fail(file, line); + } +} + +void _assert_float_equal(const float a, + const float b, + const float epsilon, + const char * const file, + const int line) { + if (!float_values_equal_display_error(a, b, epsilon)) { + _fail(file, line); + } +} + +void _assert_float_not_equal(const float a, + const float b, + const float epsilon, + const char * const file, + const int line) { + if (!float_values_not_equal_display_error(a, b, epsilon)) { + _fail(file, line); + } +} + +void _assert_int_equal( + const LargestIntegralType a, const LargestIntegralType b, + const char * const file, const int line) { + if (!values_equal_display_error(a, b)) { + _fail(file, line); + } +} + + +void _assert_int_not_equal( + const LargestIntegralType a, const LargestIntegralType b, + const char * const file, const int line) { + if (!values_not_equal_display_error(a, b)) { + _fail(file, line); + } +} + + +void _assert_string_equal(const char * const a, const char * const b, + const char * const file, const int line) { + if (!string_equal_display_error(a, b)) { + _fail(file, line); + } +} + + +void _assert_string_not_equal(const char * const a, const char * const b, + const char *file, const int line) { + if (!string_not_equal_display_error(a, b)) { + _fail(file, line); + } +} + + +void _assert_memory_equal(const void * const a, const void * const b, + const size_t size, const char* const file, + const int line) { + if (!memory_equal_display_error((const char*)a, (const char*)b, size)) { + _fail(file, line); + } +} + + +void _assert_memory_not_equal(const void * const a, const void * const b, + const size_t size, const char* const file, + const int line) { + if (!memory_not_equal_display_error((const char*)a, (const char*)b, + size)) { + _fail(file, line); + } +} + + +void _assert_in_range( + const LargestIntegralType value, const LargestIntegralType minimum, + const LargestIntegralType maximum, const char* const file, + const int line) { + if (!integer_in_range_display_error(value, minimum, maximum)) { + _fail(file, line); + } +} + +void _assert_not_in_range( + const LargestIntegralType value, const LargestIntegralType minimum, + const LargestIntegralType maximum, const char* const file, + const int line) { + if (!integer_not_in_range_display_error(value, minimum, maximum)) { + _fail(file, line); + } +} + +void _assert_in_set(const LargestIntegralType value, + const LargestIntegralType values[], + const size_t number_of_values, const char* const file, + const int line) { + CheckIntegerSet check_integer_set; + check_integer_set.set = values; + check_integer_set.size_of_set = number_of_values; + if (!value_in_set_display_error(value, &check_integer_set, 0)) { + _fail(file, line); + } +} + +void _assert_not_in_set(const LargestIntegralType value, + const LargestIntegralType values[], + const size_t number_of_values, const char* const file, + const int line) { + CheckIntegerSet check_integer_set; + check_integer_set.set = values; + check_integer_set.size_of_set = number_of_values; + if (!value_in_set_display_error(value, &check_integer_set, 1)) { + _fail(file, line); + } +} + + +/* Get the list of allocated blocks. */ +static ListNode* get_allocated_blocks_list(void) { + /* If it initialized, initialize the list of allocated blocks. */ + if (!global_allocated_blocks.value) { + list_initialize(&global_allocated_blocks); + global_allocated_blocks.value = (void*)1; + } + return &global_allocated_blocks; +} + +static void *libc_calloc(size_t nmemb, size_t size) +{ +#undef calloc + return calloc(nmemb, size); +#define calloc test_calloc +} + +static void libc_free(void *ptr) +{ +#undef free + free(ptr); +#define free test_free +} + +static void *libc_realloc(void *ptr, size_t size) +{ +#undef realloc + return realloc(ptr, size); +#define realloc test_realloc +} + +static void vcm_print_error(const char* const format, + va_list args) CMOCKA_PRINTF_ATTRIBUTE(1, 0); + +/* It's important to use the libc malloc and free here otherwise + * the automatic free of leaked blocks can reap the error messages + */ +static void vcm_print_error(const char* const format, va_list args) +{ + char buffer[1024]; + size_t msg_len = 0; + va_list ap; + int len; + va_copy(ap, args); + + len = vsnprintf(buffer, sizeof(buffer), format, args); + if (len < 0) { + /* TODO */ + goto end; + } + + if (cm_error_message == NULL) { + /* CREATE MESSAGE */ + + cm_error_message = libc_calloc(1, len + 1); + if (cm_error_message == NULL) { + /* TODO */ + goto end; + } + } else { + /* APPEND MESSAGE */ + char *tmp; + + msg_len = strlen(cm_error_message); + tmp = libc_realloc(cm_error_message, msg_len + len + 1); + if (tmp == NULL) { + goto end; + } + cm_error_message = tmp; + } + + if (((size_t)len) < sizeof(buffer)) { + /* Use len + 1 to also copy '\0' */ + memcpy(cm_error_message + msg_len, buffer, len + 1); + } else { + vsnprintf(cm_error_message + msg_len, len, format, ap); + } +end: + va_end(ap); + +} + +static void vcm_free_error(char *err_msg) +{ + libc_free(err_msg); +} + +/* Use the real malloc in this function. */ +#undef malloc +void* _test_malloc(const size_t size, const char* file, const int line) { + char *ptr = NULL; + MallocBlockInfo block_info; + ListNode * const block_list = get_allocated_blocks_list(); + size_t allocate_size; + char *block = NULL; + + allocate_size = size + (MALLOC_GUARD_SIZE * 2) + + sizeof(struct MallocBlockInfoData) + MALLOC_ALIGNMENT; + assert_true(allocate_size > size); + + block = (char *)malloc(allocate_size); + assert_non_null(block); + + /* Calculate the returned address. */ + ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData) + + MALLOC_ALIGNMENT) & ~(MALLOC_ALIGNMENT - 1)); + + /* Initialize the guard blocks. */ + memset(ptr - MALLOC_GUARD_SIZE, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE); + memset(ptr + size, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE); + memset(ptr, MALLOC_ALLOC_PATTERN, size); + + block_info.ptr = ptr - (MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData)); + set_source_location(&block_info.data->location, file, line); + block_info.data->allocated_size = allocate_size; + block_info.data->size = size; + block_info.data->block = block; + block_info.data->node.value = block_info.ptr; + list_add(block_list, &block_info.data->node); + return ptr; +} +#define malloc test_malloc + + +void* _test_calloc(const size_t number_of_elements, const size_t size, + const char* file, const int line) { + void* const ptr = _test_malloc(number_of_elements * size, file, line); + if (ptr) { + memset(ptr, 0, number_of_elements * size); + } + return ptr; +} +#define calloc test_calloc + + +/* Use the real free in this function. */ +#undef free +void _test_free(void* const ptr, const char* file, const int line) { + unsigned int i; + char *block = discard_const_p(char, ptr); + MallocBlockInfo block_info; + + if (ptr == NULL) { + return; + } + + _assert_true(cast_ptr_to_largest_integral_type(ptr), "ptr", file, line); + block_info.ptr = block - (MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData)); + /* Check the guard blocks. */ + { + char *guards[2] = {block - MALLOC_GUARD_SIZE, + block + block_info.data->size}; + for (i = 0; i < ARRAY_SIZE(guards); i++) { + unsigned int j; + char * const guard = guards[i]; + for (j = 0; j < MALLOC_GUARD_SIZE; j++) { + const char diff = guard[j] - MALLOC_GUARD_PATTERN; + if (diff) { + cm_print_error(SOURCE_LOCATION_FORMAT + ": error: Guard block of %p size=%lu is corrupt\n" + SOURCE_LOCATION_FORMAT ": note: allocated here at %p\n", + file, + line, + ptr, + (unsigned long)block_info.data->size, + block_info.data->location.file, + block_info.data->location.line, + (void *)&guard[j]); + _fail(file, line); + } + } + } + } + list_remove(&block_info.data->node, NULL, NULL); + + block = discard_const_p(char, block_info.data->block); + memset(block, MALLOC_FREE_PATTERN, block_info.data->allocated_size); + free(block); +} +#define free test_free + +#undef realloc +void *_test_realloc(void *ptr, + const size_t size, + const char *file, + const int line) +{ + MallocBlockInfo block_info; + char *block = ptr; + size_t block_size = size; + void *new_block; + + if (ptr == NULL) { + return _test_malloc(size, file, line); + } + + if (size == 0) { + _test_free(ptr, file, line); + return NULL; + } + + block_info.ptr = block - (MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData)); + + new_block = _test_malloc(size, file, line); + if (new_block == NULL) { + return NULL; + } + + if (block_info.data->size < size) { + block_size = block_info.data->size; + } + + memcpy(new_block, ptr, block_size); + + /* Free previous memory */ + _test_free(ptr, file, line); + + return new_block; +} +#define realloc test_realloc + +/* Crudely checkpoint the current heap state. */ +static const ListNode* check_point_allocated_blocks(void) { + return get_allocated_blocks_list()->prev; +} + + +/* Display the blocks allocated after the specified check point. This + * function returns the number of blocks displayed. */ +static size_t display_allocated_blocks(const ListNode * const check_point) { + const ListNode * const head = get_allocated_blocks_list(); + const ListNode *node; + size_t allocated_blocks = 0; + assert_non_null(check_point); + assert_non_null(check_point->next); + + for (node = check_point->next; node != head; node = node->next) { + const MallocBlockInfo block_info = { + .ptr = discard_const(node->value), + }; + assert_non_null(block_info.ptr); + + if (allocated_blocks == 0) { + cm_print_error("Blocks allocated...\n"); + } + cm_print_error(SOURCE_LOCATION_FORMAT ": note: block %p allocated here\n", + block_info.data->location.file, + block_info.data->location.line, + block_info.data->block); + allocated_blocks++; + } + return allocated_blocks; +} + + +/* Free all blocks allocated after the specified check point. */ +static void free_allocated_blocks(const ListNode * const check_point) { + const ListNode * const head = get_allocated_blocks_list(); + const ListNode *node; + assert_non_null(check_point); + + node = check_point->next; + assert_non_null(node); + + while (node != head) { + const MallocBlockInfo block_info = { + .ptr = discard_const(node->value), + }; + node = node->next; + free(discard_const_p(char, block_info.data) + + sizeof(struct MallocBlockInfoData) + + MALLOC_GUARD_SIZE); + } +} + + +/* Fail if any any blocks are allocated after the specified check point. */ +static void fail_if_blocks_allocated(const ListNode * const check_point, + const char * const test_name) { + const size_t allocated_blocks = display_allocated_blocks(check_point); + if (allocated_blocks > 0) { + free_allocated_blocks(check_point); + cm_print_error("ERROR: %s leaked %zu block(s)\n", test_name, + allocated_blocks); + exit_test(1); + } +} + + +void _fail(const char * const file, const int line) { + enum cm_message_output output = cm_get_output(); + + switch(output) { + case CM_OUTPUT_STDOUT: + cm_print_error("[ LINE ] --- " SOURCE_LOCATION_FORMAT ": error: Failure!", file, line); + break; + default: + cm_print_error(SOURCE_LOCATION_FORMAT ": error: Failure!", file, line); + break; + } + exit_test(1); +} + + +#ifndef _WIN32 +static void exception_handler(int sig) { + const char *sig_strerror = ""; + +#ifdef HAVE_STRSIGNAL + sig_strerror = strsignal(sig); +#endif + + cm_print_error("Test failed with exception: %s(%d)", + sig_strerror, sig); + exit_test(1); +} + +#else /* _WIN32 */ + +static LONG WINAPI exception_filter(EXCEPTION_POINTERS *exception_pointers) { + EXCEPTION_RECORD * const exception_record = + exception_pointers->ExceptionRecord; + const DWORD code = exception_record->ExceptionCode; + unsigned int i; + for (i = 0; i < ARRAY_SIZE(exception_codes); i++) { + const ExceptionCodeInfo * const code_info = &exception_codes[i]; + if (code == code_info->code) { + static int shown_debug_message = 0; + fflush(stdout); + cm_print_error("%s occurred at %p.\n", code_info->description, + exception_record->ExceptionAddress); + if (!shown_debug_message) { + cm_print_error( + "\n" + "To debug in Visual Studio...\n" + "1. Select menu item File->Open Project\n" + "2. Change 'Files of type' to 'Executable Files'\n" + "3. Open this executable.\n" + "4. Select menu item Debug->Start\n" + "\n" + "Alternatively, set the environment variable \n" + "UNIT_TESTING_DEBUG to 1 and rebuild this executable, \n" + "then click 'Debug' in the popup dialog box.\n" + "\n"); + shown_debug_message = 1; + } + exit_test(0); + return EXCEPTION_EXECUTE_HANDLER; + } + } + return EXCEPTION_CONTINUE_SEARCH; +} +#endif /* !_WIN32 */ + +void cm_print_error(const char * const format, ...) +{ + va_list args; + va_start(args, format); + if (cm_error_message_enabled) { + vcm_print_error(format, args); + } else { + vprint_error(format, args); + } + va_end(args); +} + +/* Standard output and error print methods. */ +void vprint_message(const char* const format, va_list args) { + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), format, args); + printf("%s", buffer); + fflush(stdout); +#ifdef _WIN32 + OutputDebugString(buffer); +#endif /* _WIN32 */ +} + + +void vprint_error(const char* const format, va_list args) { + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), format, args); + fprintf(stderr, "%s", buffer); + fflush(stderr); +#ifdef _WIN32 + OutputDebugString(buffer); +#endif /* _WIN32 */ +} + + +void print_message(const char* const format, ...) { + va_list args; + va_start(args, format); + vprint_message(format, args); + va_end(args); +} + + +void print_error(const char* const format, ...) { + va_list args; + va_start(args, format); + vprint_error(format, args); + va_end(args); +} + +/* New formatter */ +static enum cm_message_output cm_get_output(void) +{ + enum cm_message_output output = global_msg_output; + char *env; + + env = getenv("CMOCKA_MESSAGE_OUTPUT"); + if (env != NULL) { + if (strcasecmp(env, "STDOUT") == 0) { + output = CM_OUTPUT_STDOUT; + } else if (strcasecmp(env, "SUBUNIT") == 0) { + output = CM_OUTPUT_SUBUNIT; + } else if (strcasecmp(env, "TAP") == 0) { + output = CM_OUTPUT_TAP; + } else if (strcasecmp(env, "XML") == 0) { + output = CM_OUTPUT_XML; + } + } + + return output; +} + +enum cm_printf_type { + PRINTF_TEST_START, + PRINTF_TEST_SUCCESS, + PRINTF_TEST_FAILURE, + PRINTF_TEST_ERROR, + PRINTF_TEST_SKIPPED, +}; + +static int xml_printed; +static int file_append; + +static void cmprintf_group_finish_xml(const char *group_name, + size_t total_executed, + size_t total_failed, + size_t total_errors, + size_t total_skipped, + double total_runtime, + struct CMUnitTestState *cm_tests) +{ + FILE *fp = stdout; + int file_opened = 0; + int multiple_files = 0; + char *env; + size_t i; + + env = getenv("CMOCKA_XML_FILE"); + if (env != NULL) { + char buf[1024]; + int rc; + + snprintf(buf, sizeof(buf), "%s", env); + + rc = c_strreplace(buf, sizeof(buf), "%g", group_name, &multiple_files); + if (rc < 0) { + snprintf(buf, sizeof(buf), "%s", env); + } + + fp = fopen(buf, "r"); + if (fp == NULL) { + fp = fopen(buf, "w"); + if (fp != NULL) { + file_append = 1; + file_opened = 1; + } else { + fp = stderr; + } + } else { + fclose(fp); + if (file_append) { + fp = fopen(buf, "a"); + if (fp != NULL) { + file_opened = 1; + xml_printed = 1; + } else { + fp = stderr; + } + } else { + fp = stderr; + } + } + } + + if (!xml_printed || (file_opened && !file_append)) { + fprintf(fp, "\n"); + if (!file_opened) { + xml_printed = 1; + } + } + + fprintf(fp, "\n"); + fprintf(fp, " \n", + group_name, + total_runtime, /* seconds */ + (unsigned)total_executed, + (unsigned)total_failed, + (unsigned)total_errors, + (unsigned)total_skipped); + + for (i = 0; i < total_executed; i++) { + struct CMUnitTestState *cmtest = &cm_tests[i]; + + fprintf(fp, " \n", + cmtest->test->name, cmtest->runtime); + + switch (cmtest->status) { + case CM_TEST_ERROR: + case CM_TEST_FAILED: + if (cmtest->error_message != NULL) { + fprintf(fp, " \n", + cmtest->error_message); + } else { + fprintf(fp, " \n"); + } + break; + case CM_TEST_SKIPPED: + fprintf(fp, " \n"); + break; + + case CM_TEST_PASSED: + case CM_TEST_NOT_STARTED: + break; + } + + fprintf(fp, " \n"); + } + + fprintf(fp, " \n"); + fprintf(fp, "\n"); + + if (file_opened) { + fclose(fp); + } +} + +static void cmprintf_group_start_standard(const size_t num_tests) +{ + print_message("[==========] Running %u test(s).\n", + (unsigned)num_tests); +} + +static void cmprintf_group_finish_standard(size_t total_executed, + size_t total_passed, + size_t total_failed, + size_t total_errors, + size_t total_skipped, + struct CMUnitTestState *cm_tests) +{ + size_t i; + + print_message("[==========] %u test(s) run.\n", (unsigned)total_executed); + print_error("[ PASSED ] %u test(s).\n", + (unsigned)(total_passed)); + + if (total_skipped) { + print_error("[ SKIPPED ] %"PRIdS " test(s), listed below:\n", total_skipped); + for (i = 0; i < total_executed; i++) { + struct CMUnitTestState *cmtest = &cm_tests[i]; + + if (cmtest->status == CM_TEST_SKIPPED) { + print_error("[ SKIPPED ] %s\n", cmtest->test->name); + } + } + print_error("\n %u SKIPPED TEST(S)\n", (unsigned)(total_skipped)); + } + + if (total_failed) { + print_error("[ FAILED ] %"PRIdS " test(s), listed below:\n", total_failed); + for (i = 0; i < total_executed; i++) { + struct CMUnitTestState *cmtest = &cm_tests[i]; + + if (cmtest->status == CM_TEST_FAILED) { + print_error("[ FAILED ] %s\n", cmtest->test->name); + } + } + print_error("\n %u FAILED TEST(S)\n", + (unsigned)(total_failed + total_errors)); + } +} + +static void cmprintf_standard(enum cm_printf_type type, + const char *test_name, + const char *error_message) +{ + switch (type) { + case PRINTF_TEST_START: + print_message("[ RUN ] %s\n", test_name); + break; + case PRINTF_TEST_SUCCESS: + print_message("[ OK ] %s\n", test_name); + break; + case PRINTF_TEST_FAILURE: + if (error_message != NULL) { + print_error("[ ERROR ] --- %s\n", error_message); + } + print_message("[ FAILED ] %s\n", test_name); + break; + case PRINTF_TEST_SKIPPED: + print_message("[ SKIPPED ] %s\n", test_name); + break; + case PRINTF_TEST_ERROR: + if (error_message != NULL) { + print_error("%s\n", error_message); + } + print_error("[ ERROR ] %s\n", test_name); + break; + } +} + +static void cmprintf_group_start_tap(const size_t num_tests) +{ + print_message("1..%u\n", (unsigned)num_tests); +} + +static void cmprintf_group_finish_tap(const char *group_name, + size_t total_executed, + size_t total_passed, + size_t total_skipped) +{ + const char *status = "not ok"; + if (total_passed + total_skipped == total_executed) { + status = "ok"; + } + print_message("# %s - %s\n", status, group_name); +} + +static void cmprintf_tap(enum cm_printf_type type, + uint32_t test_number, + const char *test_name, + const char *error_message) +{ + switch (type) { + case PRINTF_TEST_START: + break; + case PRINTF_TEST_SUCCESS: + print_message("ok %u - %s\n", (unsigned)test_number, test_name); + break; + case PRINTF_TEST_FAILURE: + print_message("not ok %u - %s\n", (unsigned)test_number, test_name); + if (error_message != NULL) { + char *msg; + char *p; + + msg = strdup(error_message); + if (msg == NULL) { + return; + } + p = msg; + + while (p[0] != '\0') { + char *q = p; + + p = strchr(q, '\n'); + if (p != NULL) { + p[0] = '\0'; + } + + print_message("# %s\n", q); + + if (p == NULL) { + break; + } + p++; + } + libc_free(msg); + } + break; + case PRINTF_TEST_SKIPPED: + print_message("not ok %u # SKIP %s\n", (unsigned)test_number, test_name); + break; + case PRINTF_TEST_ERROR: + print_message("not ok %u - %s %s\n", + (unsigned)test_number, test_name, error_message); + break; + } +} + +static void cmprintf_subunit(enum cm_printf_type type, + const char *test_name, + const char *error_message) +{ + switch (type) { + case PRINTF_TEST_START: + print_message("test: %s\n", test_name); + break; + case PRINTF_TEST_SUCCESS: + print_message("success: %s\n", test_name); + break; + case PRINTF_TEST_FAILURE: + print_message("failure: %s", test_name); + if (error_message != NULL) { + print_message(" [\n%s\n]\n", error_message); + } + break; + case PRINTF_TEST_SKIPPED: + print_message("skip: %s\n", test_name); + break; + case PRINTF_TEST_ERROR: + print_message("error: %s [ %s ]\n", test_name, error_message); + break; + } +} + +static void cmprintf_group_start(const size_t num_tests) +{ + enum cm_message_output output; + + output = cm_get_output(); + + switch (output) { + case CM_OUTPUT_STDOUT: + cmprintf_group_start_standard(num_tests); + break; + case CM_OUTPUT_SUBUNIT: + break; + case CM_OUTPUT_TAP: + cmprintf_group_start_tap(num_tests); + break; + case CM_OUTPUT_XML: + break; + } +} + +static void cmprintf_group_finish(const char *group_name, + size_t total_executed, + size_t total_passed, + size_t total_failed, + size_t total_errors, + size_t total_skipped, + double total_runtime, + struct CMUnitTestState *cm_tests) +{ + enum cm_message_output output; + + output = cm_get_output(); + + switch (output) { + case CM_OUTPUT_STDOUT: + cmprintf_group_finish_standard(total_executed, + total_passed, + total_failed, + total_errors, + total_skipped, + cm_tests); + break; + case CM_OUTPUT_SUBUNIT: + break; + case CM_OUTPUT_TAP: + cmprintf_group_finish_tap(group_name, total_executed, total_passed, total_skipped); + break; + case CM_OUTPUT_XML: + cmprintf_group_finish_xml(group_name, + total_executed, + total_failed, + total_errors, + total_skipped, + total_runtime, + cm_tests); + break; + } +} + +static void cmprintf(enum cm_printf_type type, + size_t test_number, + const char *test_name, + const char *error_message) +{ + enum cm_message_output output; + + output = cm_get_output(); + + switch (output) { + case CM_OUTPUT_STDOUT: + cmprintf_standard(type, test_name, error_message); + break; + case CM_OUTPUT_SUBUNIT: + cmprintf_subunit(type, test_name, error_message); + break; + case CM_OUTPUT_TAP: + cmprintf_tap(type, test_number, test_name, error_message); + break; + case CM_OUTPUT_XML: + break; + } +} + +void cmocka_set_message_output(enum cm_message_output output) +{ + global_msg_output = output; +} + +void cmocka_set_test_filter(const char *pattern) +{ + global_test_filter_pattern = pattern; +} + +void cmocka_set_skip_filter(const char *pattern) +{ + global_skip_filter_pattern = pattern; +} + +/**************************************************************************** + * TIME CALCULATIONS + ****************************************************************************/ + +#ifdef HAVE_STRUCT_TIMESPEC +static struct timespec cm_tspecdiff(struct timespec time1, + struct timespec time0) +{ + struct timespec ret; + int xsec = 0; + int sign = 1; + + if (time0.tv_nsec > time1.tv_nsec) { + xsec = (int) ((time0.tv_nsec - time1.tv_nsec) / (1E9 + 1)); + time0.tv_nsec -= (long int) (1E9 * xsec); + time0.tv_sec += xsec; + } + + if ((time1.tv_nsec - time0.tv_nsec) > 1E9) { + xsec = (int) ((time1.tv_nsec - time0.tv_nsec) / 1E9); + time0.tv_nsec += (long int) (1E9 * xsec); + time0.tv_sec -= xsec; + } + + ret.tv_sec = time1.tv_sec - time0.tv_sec; + ret.tv_nsec = time1.tv_nsec - time0.tv_nsec; + + if (time1.tv_sec < time0.tv_sec) { + sign = -1; + } + + ret.tv_sec = ret.tv_sec * sign; + + return ret; +} + +static double cm_secdiff(struct timespec clock1, struct timespec clock0) +{ + double ret; + struct timespec diff; + + diff = cm_tspecdiff(clock1, clock0); + + ret = diff.tv_sec; + ret += (double) diff.tv_nsec / (double) 1E9; + + return ret; +} +#endif /* HAVE_STRUCT_TIMESPEC */ + +/**************************************************************************** + * CMOCKA TEST RUNNER + ****************************************************************************/ +static int cmocka_run_one_test_or_fixture(const char *function_name, + CMUnitTestFunction test_func, + CMFixtureFunction setup_func, + CMFixtureFunction teardown_func, + void ** const volatile state, + const void *const heap_check_point) +{ + const ListNode * const volatile check_point = (const ListNode*) + (heap_check_point != NULL ? + heap_check_point : check_point_allocated_blocks()); + int handle_exceptions = 1; + void *current_state = NULL; + int rc = 0; + + /* FIXME check only one test or fixture is set */ + + /* Detect if we should handle exceptions */ +#ifdef _WIN32 + handle_exceptions = !IsDebuggerPresent(); +#endif /* _WIN32 */ +#ifdef UNIT_TESTING_DEBUG + handle_exceptions = 0; +#endif /* UNIT_TESTING_DEBUG */ + + + if (handle_exceptions) { +#ifndef _WIN32 + unsigned int i; + for (i = 0; i < ARRAY_SIZE(exception_signals); i++) { + default_signal_functions[i] = signal( + exception_signals[i], exception_handler); + } +#else /* _WIN32 */ + previous_exception_filter = SetUnhandledExceptionFilter( + exception_filter); +#endif /* !_WIN32 */ + } + + /* Init the test structure */ + initialize_testing(function_name); + + global_running_test = 1; + + if (cm_setjmp(global_run_test_env) == 0) { + if (test_func != NULL) { + test_func(state != NULL ? state : ¤t_state); + + fail_if_blocks_allocated(check_point, function_name); + rc = 0; + } else if (setup_func != NULL) { + rc = setup_func(state != NULL ? state : ¤t_state); + + /* + * For setup we can ignore any allocated blocks. We just need to + * ensure they're deallocated on tear down. + */ + } else if (teardown_func != NULL) { + rc = teardown_func(state != NULL ? state : ¤t_state); + + fail_if_blocks_allocated(check_point, function_name); + } else { + /* ERROR */ + } + fail_if_leftover_values(function_name); + global_running_test = 0; + } else { + /* TEST FAILED */ + global_running_test = 0; + rc = -1; + } + teardown_testing(function_name); + + if (handle_exceptions) { +#ifndef _WIN32 + unsigned int i; + for (i = 0; i < ARRAY_SIZE(exception_signals); i++) { + signal(exception_signals[i], default_signal_functions[i]); + } +#else /* _WIN32 */ + if (previous_exception_filter) { + SetUnhandledExceptionFilter(previous_exception_filter); + previous_exception_filter = NULL; + } +#endif /* !_WIN32 */ + } + + return rc; +} + +static int cmocka_run_group_fixture(const char *function_name, + CMFixtureFunction setup_func, + CMFixtureFunction teardown_func, + void **state, + const void *const heap_check_point) +{ + int rc; + + if (setup_func != NULL) { + rc = cmocka_run_one_test_or_fixture(function_name, + NULL, + setup_func, + NULL, + state, + heap_check_point); + } else { + rc = cmocka_run_one_test_or_fixture(function_name, + NULL, + NULL, + teardown_func, + state, + heap_check_point); + } + + return rc; +} + +static int cmocka_run_one_tests(struct CMUnitTestState *test_state) +{ +#ifdef HAVE_STRUCT_TIMESPEC + struct timespec start = { + .tv_sec = 0, + .tv_nsec = 0, + }; + struct timespec finish = { + .tv_sec = 0, + .tv_nsec = 0, + }; +#endif + int rc = 0; + + /* Run setup */ + if (test_state->test->setup_func != NULL) { + /* Setup the memory check point, it will be evaluated on teardown */ + test_state->check_point = check_point_allocated_blocks(); + + rc = cmocka_run_one_test_or_fixture(test_state->test->name, + NULL, + test_state->test->setup_func, + NULL, + &test_state->state, + test_state->check_point); + if (rc != 0) { + test_state->status = CM_TEST_ERROR; + cm_print_error("Test setup failed"); + } + } + + /* Run test */ +#ifdef HAVE_STRUCT_TIMESPEC + CMOCKA_CLOCK_GETTIME(CLOCK_REALTIME, &start); +#endif + + if (rc == 0) { + rc = cmocka_run_one_test_or_fixture(test_state->test->name, + test_state->test->test_func, + NULL, + NULL, + &test_state->state, + NULL); + if (rc == 0) { + test_state->status = CM_TEST_PASSED; + } else { + if (global_skip_test) { + test_state->status = CM_TEST_SKIPPED; + global_skip_test = 0; /* Do not skip the next test */ + } else { + test_state->status = CM_TEST_FAILED; + } + } + rc = 0; + } + + test_state->runtime = 0.0; + +#ifdef HAVE_STRUCT_TIMESPEC + CMOCKA_CLOCK_GETTIME(CLOCK_REALTIME, &finish); + test_state->runtime = cm_secdiff(finish, start); +#endif + + /* Run teardown */ + if (rc == 0 && test_state->test->teardown_func != NULL) { + rc = cmocka_run_one_test_or_fixture(test_state->test->name, + NULL, + NULL, + test_state->test->teardown_func, + &test_state->state, + test_state->check_point); + if (rc != 0) { + test_state->status = CM_TEST_ERROR; + cm_print_error("Test teardown failed"); + } + } + + test_state->error_message = cm_error_message; + cm_error_message = NULL; + + return rc; +} + +int _cmocka_run_group_tests(const char *group_name, + const struct CMUnitTest * const tests, + const size_t num_tests, + CMFixtureFunction group_setup, + CMFixtureFunction group_teardown) +{ + struct CMUnitTestState *cm_tests; + const ListNode *group_check_point = check_point_allocated_blocks(); + void *group_state = NULL; + size_t total_tests = 0; + size_t total_failed = 0; + size_t total_passed = 0; + size_t total_executed = 0; + size_t total_errors = 0; + size_t total_skipped = 0; + double total_runtime = 0; + size_t i; + int rc; + + /* Make sure LargestIntegralType is at least the size of a pointer. */ + assert_true(sizeof(LargestIntegralType) >= sizeof(void*)); + + cm_tests = libc_calloc(1, sizeof(struct CMUnitTestState) * num_tests); + if (cm_tests == NULL) { + return -1; + } + + /* Setup cmocka test array */ + for (i = 0; i < num_tests; i++) { + if (tests[i].name != NULL && + (tests[i].test_func != NULL + || tests[i].setup_func != NULL + || tests[i].teardown_func != NULL)) { + if (global_test_filter_pattern != NULL) { + int match; + + match = c_strmatch(tests[i].name, global_test_filter_pattern); + if (!match) { + continue; + } + } + if (global_skip_filter_pattern != NULL) { + int match; + + match = c_strmatch(tests[i].name, global_skip_filter_pattern); + if (match) { + continue; + } + } + cm_tests[total_tests] = (struct CMUnitTestState) { + .test = &tests[i], + .status = CM_TEST_NOT_STARTED, + .state = NULL, + }; + total_tests++; + } + } + + cmprintf_group_start(total_tests); + + rc = 0; + + /* Run group setup */ + if (group_setup != NULL) { + rc = cmocka_run_group_fixture("cmocka_group_setup", + group_setup, + NULL, + &group_state, + group_check_point); + } + + if (rc == 0) { + /* Execute tests */ + for (i = 0; i < total_tests; i++) { + struct CMUnitTestState *cmtest = &cm_tests[i]; + size_t test_number = i + 1; + + cmprintf(PRINTF_TEST_START, test_number, cmtest->test->name, NULL); + + if (group_state != NULL) { + cmtest->state = group_state; + } else if (cmtest->test->initial_state != NULL) { + cmtest->state = cmtest->test->initial_state; + } + + rc = cmocka_run_one_tests(cmtest); + total_executed++; + total_runtime += cmtest->runtime; + if (rc == 0) { + switch (cmtest->status) { + case CM_TEST_PASSED: + cmprintf(PRINTF_TEST_SUCCESS, + test_number, + cmtest->test->name, + cmtest->error_message); + total_passed++; + break; + case CM_TEST_SKIPPED: + cmprintf(PRINTF_TEST_SKIPPED, + test_number, + cmtest->test->name, + cmtest->error_message); + total_skipped++; + break; + case CM_TEST_FAILED: + cmprintf(PRINTF_TEST_FAILURE, + test_number, + cmtest->test->name, + cmtest->error_message); + total_failed++; + break; + default: + cmprintf(PRINTF_TEST_ERROR, + test_number, + cmtest->test->name, + "Internal cmocka error"); + total_errors++; + break; + } + } else { + char err_msg[2048] = {0}; + + snprintf(err_msg, sizeof(err_msg), + "Could not run test: %s", + cmtest->error_message); + + cmprintf(PRINTF_TEST_ERROR, + test_number, + cmtest->test->name, + err_msg); + total_errors++; + } + } + } else { + if (cm_error_message != NULL) { + print_error("[ ERROR ] --- %s\n", cm_error_message); + vcm_free_error(cm_error_message); + cm_error_message = NULL; + } + cmprintf(PRINTF_TEST_ERROR, 0, + group_name, "[ FAILED ] GROUP SETUP"); + total_errors++; + } + + /* Run group teardown */ + if (group_teardown != NULL) { + rc = cmocka_run_group_fixture("cmocka_group_teardown", + NULL, + group_teardown, + &group_state, + group_check_point); + if (rc != 0) { + if (cm_error_message != NULL) { + print_error("[ ERROR ] --- %s\n", cm_error_message); + vcm_free_error(cm_error_message); + cm_error_message = NULL; + } + cmprintf(PRINTF_TEST_ERROR, 0, + group_name, "[ FAILED ] GROUP TEARDOWN"); + } + } + + cmprintf_group_finish(group_name, + total_executed, + total_passed, + total_failed, + total_errors, + total_skipped, + total_runtime, + cm_tests); + + for (i = 0; i < total_tests; i++) { + vcm_free_error(discard_const_p(char, cm_tests[i].error_message)); + } + libc_free(cm_tests); + fail_if_blocks_allocated(group_check_point, "cmocka_group_tests"); + + return total_failed + total_errors; +} + +/**************************************************************************** + * DEPRECATED TEST RUNNER + ****************************************************************************/ + +int _run_test( + const char * const function_name, const UnitTestFunction Function, + void ** const volatile state, const UnitTestFunctionType function_type, + const void* const heap_check_point) { + const ListNode * const volatile check_point = (const ListNode*) + (heap_check_point ? + heap_check_point : check_point_allocated_blocks()); + void *current_state = NULL; + volatile int rc = 1; + int handle_exceptions = 1; +#ifdef _WIN32 + handle_exceptions = !IsDebuggerPresent(); +#endif /* _WIN32 */ +#ifdef UNIT_TESTING_DEBUG + handle_exceptions = 0; +#endif /* UNIT_TESTING_DEBUG */ + + cm_error_message_enabled = 0; + + if (handle_exceptions) { +#ifndef _WIN32 + unsigned int i; + for (i = 0; i < ARRAY_SIZE(exception_signals); i++) { + default_signal_functions[i] = signal( + exception_signals[i], exception_handler); + } +#else /* _WIN32 */ + previous_exception_filter = SetUnhandledExceptionFilter( + exception_filter); +#endif /* !_WIN32 */ + } + + if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) { + print_message("[ RUN ] %s\n", function_name); + } + initialize_testing(function_name); + global_running_test = 1; + if (cm_setjmp(global_run_test_env) == 0) { + Function(state ? state : ¤t_state); + fail_if_leftover_values(function_name); + + /* If this is a setup function then ignore any allocated blocks + * only ensure they're deallocated on tear down. */ + if (function_type != UNIT_TEST_FUNCTION_TYPE_SETUP) { + fail_if_blocks_allocated(check_point, function_name); + } + + global_running_test = 0; + + if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) { + print_message("[ OK ] %s\n", function_name); + } + rc = 0; + } else { + global_running_test = 0; + print_message("[ FAILED ] %s\n", function_name); + } + teardown_testing(function_name); + + if (handle_exceptions) { +#ifndef _WIN32 + unsigned int i; + for (i = 0; i < ARRAY_SIZE(exception_signals); i++) { + signal(exception_signals[i], default_signal_functions[i]); + } +#else /* _WIN32 */ + if (previous_exception_filter) { + SetUnhandledExceptionFilter(previous_exception_filter); + previous_exception_filter = NULL; + } +#endif /* !_WIN32 */ + } + + return rc; +} + + +int _run_tests(const UnitTest * const tests, const size_t number_of_tests) { + /* Whether to execute the next test. */ + int run_next_test = 1; + /* Whether the previous test failed. */ + int previous_test_failed = 0; + /* Whether the previous setup failed. */ + int previous_setup_failed = 0; + /* Check point of the heap state. */ + const ListNode * const check_point = check_point_allocated_blocks(); + /* Current test being executed. */ + size_t current_test = 0; + /* Number of tests executed. */ + size_t tests_executed = 0; + /* Number of failed tests. */ + size_t total_failed = 0; + /* Number of setup functions. */ + size_t setups = 0; + /* Number of teardown functions. */ + size_t teardowns = 0; + size_t i; + /* + * A stack of test states. A state is pushed on the stack + * when a test setup occurs and popped on tear down. + */ + TestState* test_states = + (TestState*)malloc(number_of_tests * sizeof(*test_states)); + /* The number of test states which should be 0 at the end */ + long number_of_test_states = 0; + /* Names of the tests that failed. */ + const char** failed_names = (const char**)malloc(number_of_tests * + sizeof(*failed_names)); + void **current_state = NULL; + + /* Count setup and teardown functions */ + for (i = 0; i < number_of_tests; i++) { + const UnitTest * const test = &tests[i]; + + if (test->function_type == UNIT_TEST_FUNCTION_TYPE_SETUP) { + setups++; + } + + if (test->function_type == UNIT_TEST_FUNCTION_TYPE_TEARDOWN) { + teardowns++; + } + } + + print_message("[==========] Running %"PRIdS " test(s).\n", + number_of_tests - setups - teardowns); + + /* Make sure LargestIntegralType is at least the size of a pointer. */ + assert_true(sizeof(LargestIntegralType) >= sizeof(void*)); + + while (current_test < number_of_tests) { + const ListNode *test_check_point = NULL; + TestState *current_TestState; + const UnitTest * const test = &tests[current_test++]; + if (!test->function) { + continue; + } + + switch (test->function_type) { + case UNIT_TEST_FUNCTION_TYPE_TEST: + if (! previous_setup_failed) { + run_next_test = 1; + } + break; + case UNIT_TEST_FUNCTION_TYPE_SETUP: { + /* Checkpoint the heap before the setup. */ + current_TestState = &test_states[number_of_test_states++]; + current_TestState->check_point = check_point_allocated_blocks(); + test_check_point = current_TestState->check_point; + current_state = ¤t_TestState->state; + *current_state = NULL; + run_next_test = 1; + break; + } + case UNIT_TEST_FUNCTION_TYPE_TEARDOWN: + /* Check the heap based on the last setup checkpoint. */ + assert_true(number_of_test_states); + current_TestState = &test_states[--number_of_test_states]; + test_check_point = current_TestState->check_point; + current_state = ¤t_TestState->state; + break; + default: + print_error("Invalid unit test function type %d\n", + test->function_type); + exit_test(1); + break; + } + + if (run_next_test) { + int failed = _run_test(test->name, test->function, current_state, + test->function_type, test_check_point); + if (failed) { + failed_names[total_failed] = test->name; + } + + switch (test->function_type) { + case UNIT_TEST_FUNCTION_TYPE_TEST: + previous_test_failed = failed; + total_failed += failed; + tests_executed ++; + break; + + case UNIT_TEST_FUNCTION_TYPE_SETUP: + if (failed) { + total_failed ++; + tests_executed ++; + /* Skip forward until the next test or setup function. */ + run_next_test = 0; + previous_setup_failed = 1; + } + previous_test_failed = 0; + break; + + case UNIT_TEST_FUNCTION_TYPE_TEARDOWN: + /* If this test failed. */ + if (failed && !previous_test_failed) { + total_failed ++; + } + break; + default: +#ifndef _HPUX + assert_null("BUG: shouldn't be here!"); +#endif + break; + } + } + } + + print_message("[==========] %"PRIdS " test(s) run.\n", tests_executed); + print_error("[ PASSED ] %"PRIdS " test(s).\n", tests_executed - total_failed); + + if (total_failed > 0) { + print_error("[ FAILED ] %"PRIdS " test(s), listed below:\n", total_failed); + for (i = 0; i < total_failed; i++) { + print_error("[ FAILED ] %s\n", failed_names[i]); + } + } else { + print_error("\n %"PRIdS " FAILED TEST(S)\n", total_failed); + } + + if (number_of_test_states != 0) { + print_error("[ ERROR ] Mismatched number of setup %"PRIdS " and " + "teardown %"PRIdS " functions\n", setups, teardowns); + total_failed = (size_t)-1; + } + + free(test_states); + free((void*)failed_names); + + fail_if_blocks_allocated(check_point, "run_tests"); + return (int)total_failed; +} + +int _run_group_tests(const UnitTest * const tests, const size_t number_of_tests) +{ + UnitTestFunction setup = NULL; + const char *setup_name; + size_t num_setups = 0; + UnitTestFunction teardown = NULL; + const char *teardown_name = NULL; + size_t num_teardowns = 0; + size_t current_test = 0; + size_t i; + + /* Number of tests executed. */ + size_t tests_executed = 0; + /* Number of failed tests. */ + size_t total_failed = 0; + /* Check point of the heap state. */ + const ListNode * const check_point = check_point_allocated_blocks(); + const char **failed_names = NULL; + void **current_state = NULL; + TestState group_state = { + .check_point = NULL, + }; + + if (number_of_tests == 0) { + return -1; + } + + failed_names = (const char **)malloc(number_of_tests * + sizeof(*failed_names)); + if (failed_names == NULL) { + return -2; + } + + /* Find setup and teardown function */ + for (i = 0; i < number_of_tests; i++) { + const UnitTest * const test = &tests[i]; + + if (test->function_type == UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP) { + if (setup == NULL) { + setup = test->function; + setup_name = test->name; + num_setups = 1; + } else { + print_error("[ ERROR ] More than one group setup function detected\n"); + exit_test(1); + } + } + + if (test->function_type == UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN) { + if (teardown == NULL) { + teardown = test->function; + teardown_name = test->name; + num_teardowns = 1; + } else { + print_error("[ ERROR ] More than one group teardown function detected\n"); + exit_test(1); + } + } + } + + print_message("[==========] Running %"PRIdS " test(s).\n", + number_of_tests - num_setups - num_teardowns); + + if (setup != NULL) { + int failed; + + group_state.check_point = check_point_allocated_blocks(); + current_state = &group_state.state; + *current_state = NULL; + failed = _run_test(setup_name, + setup, + current_state, + UNIT_TEST_FUNCTION_TYPE_SETUP, + group_state.check_point); + if (failed) { + failed_names[total_failed] = setup_name; + } + + total_failed += failed; + tests_executed++; + } + + while (current_test < number_of_tests) { + int run_test = 0; + const UnitTest * const test = &tests[current_test++]; + if (test->function == NULL) { + continue; + } + + switch (test->function_type) { + case UNIT_TEST_FUNCTION_TYPE_TEST: + run_test = 1; + break; + case UNIT_TEST_FUNCTION_TYPE_SETUP: + case UNIT_TEST_FUNCTION_TYPE_TEARDOWN: + case UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP: + case UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN: + break; + default: + print_error("Invalid unit test function type %d\n", + test->function_type); + break; + } + + if (run_test) { + int failed; + + failed = _run_test(test->name, + test->function, + current_state, + test->function_type, + NULL); + if (failed) { + failed_names[total_failed] = test->name; + } + + total_failed += failed; + tests_executed++; + } + } + + if (teardown != NULL) { + int failed; + + failed = _run_test(teardown_name, + teardown, + current_state, + UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN, + group_state.check_point); + if (failed) { + failed_names[total_failed] = teardown_name; + } + + total_failed += failed; + tests_executed++; + } + + print_message("[==========] %"PRIdS " test(s) run.\n", tests_executed); + print_error("[ PASSED ] %"PRIdS " test(s).\n", tests_executed - total_failed); + + if (total_failed) { + print_error("[ FAILED ] %"PRIdS " test(s), listed below:\n", total_failed); + for (i = 0; i < total_failed; i++) { + print_error("[ FAILED ] %s\n", failed_names[i]); + } + } else { + print_error("\n %"PRIdS " FAILED TEST(S)\n", total_failed); + } + + free((void*)failed_names); + fail_if_blocks_allocated(check_point, "run_group_tests"); + + return (int)total_failed; +} diff --git a/src/imports/cmocka/cmocka.h b/src/imports/cmocka/cmocka.h new file mode 100644 index 0000000..5dd6d62 --- /dev/null +++ b/src/imports/cmocka/cmocka.h @@ -0,0 +1,2389 @@ +/* + * Copyright 2008 Google Inc. + * Copyright 2014-2018 Andreas Schneider + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef CMOCKA_H_ +#define CMOCKA_H_ + +#include +#include +#include +#include + +#ifdef _WIN32 +# ifdef _MSC_VER + +#define __func__ __FUNCTION__ + +# ifndef inline +#define inline __inline +# endif /* inline */ + +# if _MSC_VER < 1500 +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +int __stdcall IsDebuggerPresent(); +# ifdef __cplusplus +} /* extern "C" */ +# endif /* __cplusplus */ +# endif /* _MSC_VER < 1500 */ +# endif /* _MSC_VER */ +#endif /* _WIN32 */ + +/** + * @defgroup cmocka The CMocka API + * + * These headers or their equivalents MUST be included prior to including + * this header file. + * @code + * #include + * #include + * #include + * #include + * @endcode + * + * This allows test applications to use custom definitions of C standard + * library functions and types. + * + * @{ + */ + +/* If __WORDSIZE is not set, try to figure it out and default to 32 bit. */ +#ifndef __WORDSIZE +# if (defined(__x86_64__) && !defined(__ILP32__)) || defined(__sparc_v9__) || defined(__sparcv9) +# define __WORDSIZE 64 +# else +# define __WORDSIZE 32 +# endif +#endif + +#ifdef DOXYGEN +/** + * Largest integral type. This type should be large enough to hold any + * pointer or integer supported by the compiler. + */ +typedef uintmax_t LargestIntegralType; +#else /* DOXGEN */ +#ifndef LargestIntegralType +# if __WORDSIZE == 64 && !defined(_WIN64) +# define LargestIntegralType unsigned long int +# else +# define LargestIntegralType unsigned long long int +# endif +#endif /* LargestIntegralType */ +#endif /* DOXYGEN */ + +/* Printf format used to display LargestIntegralType as a hexidecimal. */ +#ifndef LargestIntegralTypePrintfFormat +# ifdef _WIN32 +# define LargestIntegralTypePrintfFormat "0x%I64x" +# else +# if __WORDSIZE == 64 +# define LargestIntegralTypePrintfFormat "%#lx" +# else +# define LargestIntegralTypePrintfFormat "%#llx" +# endif +# endif /* _WIN32 */ +#endif /* LargestIntegralTypePrintfFormat */ + +/* Printf format used to display LargestIntegralType as a decimal. */ +#ifndef LargestIntegralTypePrintfFormatDecimal +# ifdef _WIN32 +# define LargestIntegralTypePrintfFormatDecimal "%I64u" +# else +# if __WORDSIZE == 64 +# define LargestIntegralTypePrintfFormatDecimal "%lu" +# else +# define LargestIntegralTypePrintfFormatDecimal "%llu" +# endif +# endif /* _WIN32 */ +#endif /* LargestIntegralTypePrintfFormat */ + +#ifndef FloatPrintfFormat +# define FloatPrintfFormat "%f" +#endif /* FloatPrintfFormat */ + +/* Perform an unsigned cast to LargestIntegralType. */ +#define cast_to_largest_integral_type(value) \ + ((LargestIntegralType)(value)) + +/* Smallest integral type capable of holding a pointer. */ +#if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) +# if defined(_WIN32) + /* WIN32 is an ILP32 platform */ + typedef unsigned int uintptr_t; +# elif defined(_WIN64) + typedef unsigned long int uintptr_t; +# else /* _WIN32 */ + +/* ILP32 and LP64 platforms */ +# ifdef __WORDSIZE /* glibc */ +# if __WORDSIZE == 64 + typedef unsigned long int uintptr_t; +# else + typedef unsigned int uintptr_t; +# endif /* __WORDSIZE == 64 */ +# else /* __WORDSIZE */ +# if defined(_LP64) || defined(_I32LPx) + typedef unsigned long int uintptr_t; +# else + typedef unsigned int uintptr_t; +# endif +# endif /* __WORDSIZE */ +# endif /* _WIN32 */ + +# define _UINTPTR_T +# define _UINTPTR_T_DEFINED +#endif /* !defined(_UINTPTR_T) || !defined(_UINTPTR_T_DEFINED) */ + +/* Perform an unsigned cast to uintptr_t. */ +#define cast_to_pointer_integral_type(value) \ + ((uintptr_t)((size_t)(value))) + +/* Perform a cast of a pointer to LargestIntegralType */ +#define cast_ptr_to_largest_integral_type(value) \ +cast_to_largest_integral_type(cast_to_pointer_integral_type(value)) + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define CMOCKA_PRINTF_ATTRIBUTE(a,b) \ + __attribute__ ((__format__ (__printf__, a, b))) +#else +#define CMOCKA_PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +#if defined(__GNUC__) +#define CMOCKA_DEPRECATED __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define CMOCKA_DEPRECATED __declspec(deprecated) +#else +#define CMOCKA_DEPRECATED +#endif + +#define WILL_RETURN_ALWAYS -1 +#define WILL_RETURN_ONCE -2 + +/** + * @defgroup cmocka_mock Mock Objects + * @ingroup cmocka + * + * Mock objects mock objects are simulated objects that mimic the behavior of + * real objects. Instead of calling the real objects, the tested object calls a + * mock object that merely asserts that the correct methods were called, with + * the expected parameters, in the correct order. + * + *
    + *
  • will_return(function, value) - The will_return() macro + * pushes a value onto a stack of mock values. This macro is intended to be + * used by the unit test itself, while programming the behaviour of the mocked + * object.
  • + * + *
  • mock() - the mock macro pops a value from a stack of + * test values. The user of the mock() macro is the mocked object that uses it + * to learn how it should behave.
  • + *
+ * + * Because the will_return() and mock() are intended to be used in pairs, the + * cmocka library would fail the test if there are more values pushed onto the + * stack using will_return() than consumed with mock() and vice-versa. + * + * The following unit test stub illustrates how would a unit test instruct the + * mock object to return a particular value: + * + * @code + * will_return(chef_cook, "hotdog"); + * will_return(chef_cook, 0); + * @endcode + * + * Now the mock object can check if the parameter it received is the parameter + * which is expected by the test driver. This can be done the following way: + * + * @code + * int chef_cook(const char *order, char **dish_out) + * { + * check_expected(order); + * } + * @endcode + * + * For a complete example please take a look + *
here. + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Retrieve a return value of the current function. + * + * @return The value which was stored to return by this function. + * + * @see will_return() + */ +LargestIntegralType mock(void); +#else +#define mock() _mock(__func__, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Retrieve a typed return value of the current function. + * + * The value would be casted to type internally to avoid having the + * caller to do the cast manually. + * + * @param[in] #type The expected type of the return value + * + * @return The value which was stored to return by this function. + * + * @code + * int param; + * + * param = mock_type(int); + * @endcode + * + * @see will_return() + * @see mock() + * @see mock_ptr_type() + */ +#type mock_type(#type); +#else +#define mock_type(type) ((type) mock()) +#endif + +#ifdef DOXYGEN +/** + * @brief Retrieve a typed return value of the current function. + * + * The value would be casted to type internally to avoid having the + * caller to do the cast manually but also casted to uintptr_t to make + * sure the result has a valid size to be used as a pointer. + * + * @param[in] #type The expected type of the return value + * + * @return The value which was stored to return by this function. + * + * @code + * char *param; + * + * param = mock_ptr_type(char *); + * @endcode + * + * @see will_return() + * @see mock() + * @see mock_type() + */ +type mock_ptr_type(#type); +#else +#define mock_ptr_type(type) ((type) (uintptr_t) mock()) +#endif + + +#ifdef DOXYGEN +/** + * @brief Store a value to be returned by mock() later. + * + * @param[in] #function The function which should return the given value. + * + * @param[in] value The value to be returned by mock(). + * + * @code + * int return_integer(void) + * { + * return (int)mock(); + * } + * + * static void test_integer_return(void **state) + * { + * will_return(return_integer, 42); + * + * assert_int_equal(my_function_calling_return_integer(), 42); + * } + * @endcode + * + * @see mock() + * @see will_return_count() + */ +void will_return(#function, LargestIntegralType value); +#else +#define will_return(function, value) \ + _will_return(#function, __FILE__, __LINE__, \ + cast_to_largest_integral_type(value), 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Store a value to be returned by mock() later. + * + * @param[in] #function The function which should return the given value. + * + * @param[in] value The value to be returned by mock(). + * + * @param[in] count The parameter indicates the number of times the value should + * be returned by mock(). If count is set to -1, the value + * will always be returned but must be returned at least once. + * If count is set to -2, the value will always be returned + * by mock(), but is not required to be returned. + * + * @see mock() + */ +void will_return_count(#function, LargestIntegralType value, int count); +#else +#define will_return_count(function, value, count) \ + _will_return(#function, __FILE__, __LINE__, \ + cast_to_largest_integral_type(value), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Store a value that will be always returned by mock(). + * + * @param[in] #function The function which should return the given value. + * + * @param[in] #value The value to be returned by mock(). + * + * This is equivalent to: + * @code + * will_return_count(function, value, -1); + * @endcode + * + * @see will_return_count() + * @see mock() + */ +void will_return_always(#function, LargestIntegralType value); +#else +#define will_return_always(function, value) \ + will_return_count(function, (value), WILL_RETURN_ALWAYS) +#endif + +#ifdef DOXYGEN +/** + * @brief Store a value that may be always returned by mock(). + * + * This stores a value which will always be returned by mock() but is not + * required to be returned by at least one call to mock(). Therefore, + * in contrast to will_return_always() which causes a test failure if it + * is not returned at least once, will_return_maybe() will never cause a test + * to fail if its value is not returned. + * + * @param[in] #function The function which should return the given value. + * + * @param[in] #value The value to be returned by mock(). + * + * This is equivalent to: + * @code + * will_return_count(function, value, -2); + * @endcode + * + * @see will_return_count() + * @see mock() + */ +void will_return_maybe(#function, LargestIntegralType value); +#else +#define will_return_maybe(function, value) \ + will_return_count(function, (value), WILL_RETURN_ONCE) +#endif +/** @} */ + +/** + * @defgroup cmocka_param Checking Parameters + * @ingroup cmocka + * + * Functionality to store expected values for mock function parameters. + * + * In addition to storing the return values of mock functions, cmocka provides + * functionality to store expected values for mock function parameters using + * the expect_*() functions provided. A mock function parameter can then be + * validated using the check_expected() macro. + * + * Successive calls to expect_*() macros for a parameter queues values to check + * the specified parameter. check_expected() checks a function parameter + * against the next value queued using expect_*(), if the parameter check fails + * a test failure is signalled. In addition if check_expected() is called and + * no more parameter values are queued a test failure occurs. + * + * The following test stub illustrates how to do this. First is the the function + * we call in the test driver: + * + * @code + * static void test_driver(void **state) + * { + * expect_string(chef_cook, order, "hotdog"); + * } + * @endcode + * + * Now the chef_cook function can check if the parameter we got passed is the + * parameter which is expected by the test driver. This can be done the + * following way: + * + * @code + * int chef_cook(const char *order, char **dish_out) + * { + * check_expected(order); + * } + * @endcode + * + * For a complete example please take a look + * here + * + * @{ + */ + +/* + * Add a custom parameter checking function. If the event parameter is NULL + * the event structure is allocated internally by this function. If event + * parameter is provided it must be allocated on the heap and doesn't need to + * be deallocated by the caller. + */ +#ifdef DOXYGEN +/** + * @brief Add a custom parameter checking function. + * + * If the event parameter is NULL the event structure is allocated internally + * by this function. If the parameter is provided it must be allocated on the + * heap and doesn't need to be deallocated by the caller. + * + * @param[in] #function The function to add a custom parameter checking + * function for. + * + * @param[in] #parameter The parameters passed to the function. + * + * @param[in] #check_function The check function to call. + * + * @param[in] check_data The data to pass to the check function. + */ +void expect_check(#function, #parameter, #check_function, const void *check_data); +#else +#define expect_check(function, parameter, check_function, check_data) \ + _expect_check(#function, #parameter, __FILE__, __LINE__, check_function, \ + cast_to_largest_integral_type(check_data), NULL, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value is part of the provided + * array. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value_array[] The array to check for the value. + * + * @see check_expected(). + */ +void expect_in_set(#function, #parameter, LargestIntegralType value_array[]); +#else +#define expect_in_set(function, parameter, value_array) \ + expect_in_set_count(function, parameter, value_array, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value is part of the provided + * array. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value_array[] The array to check for the value. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_in_set_count(#function, #parameter, LargestIntegralType value_array[], size_t count); +#else +#define expect_in_set_count(function, parameter, value_array, count) \ + _expect_in_set(#function, #parameter, __FILE__, __LINE__, value_array, \ + sizeof(value_array) / sizeof((value_array)[0]), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value is not part of the + * provided array. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value_array[] The array to check for the value. + * + * @see check_expected(). + */ +void expect_not_in_set(#function, #parameter, LargestIntegralType value_array[]); +#else +#define expect_not_in_set(function, parameter, value_array) \ + expect_not_in_set_count(function, parameter, value_array, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value is not part of the + * provided array. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value_array[] The array to check for the value. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_not_in_set_count(#function, #parameter, LargestIntegralType value_array[], size_t count); +#else +#define expect_not_in_set_count(function, parameter, value_array, count) \ + _expect_not_in_set( \ + #function, #parameter, __FILE__, __LINE__, value_array, \ + sizeof(value_array) / sizeof((value_array)[0]), count) +#endif + + +#ifdef DOXYGEN +/** + * @brief Add an event to check a parameter is inside a numerical range. + * The check would succeed if minimum <= value <= maximum. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] minimum The lower boundary of the interval to check against. + * + * @param[in] maximum The upper boundary of the interval to check against. + * + * @see check_expected(). + */ +void expect_in_range(#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum); +#else +#define expect_in_range(function, parameter, minimum, maximum) \ + expect_in_range_count(function, parameter, minimum, maximum, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check a parameter is inside a + * numerical range. The check would succeed if minimum <= value <= maximum. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] minimum The lower boundary of the interval to check against. + * + * @param[in] maximum The upper boundary of the interval to check against. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_in_range_count(#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum, size_t count); +#else +#define expect_in_range_count(function, parameter, minimum, maximum, count) \ + _expect_in_range(#function, #parameter, __FILE__, __LINE__, minimum, \ + maximum, count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check a parameter is outside a numerical range. + * The check would succeed if minimum > value > maximum. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] minimum The lower boundary of the interval to check against. + * + * @param[in] maximum The upper boundary of the interval to check against. + * + * @see check_expected(). + */ +void expect_not_in_range(#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum); +#else +#define expect_not_in_range(function, parameter, minimum, maximum) \ + expect_not_in_range_count(function, parameter, minimum, maximum, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check a parameter is outside a + * numerical range. The check would succeed if minimum > value > maximum. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] minimum The lower boundary of the interval to check against. + * + * @param[in] maximum The upper boundary of the interval to check against. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_not_in_range_count(#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum, size_t count); +#else +#define expect_not_in_range_count(function, parameter, minimum, maximum, \ + count) \ + _expect_not_in_range(#function, #parameter, __FILE__, __LINE__, \ + minimum, maximum, count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if a parameter is the given value. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value The value to check. + * + * @see check_expected(). + */ +void expect_value(#function, #parameter, LargestIntegralType value); +#else +#define expect_value(function, parameter, value) \ + expect_value_count(function, parameter, value, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check if a parameter is the given value. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value The value to check. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_value_count(#function, #parameter, LargestIntegralType value, size_t count); +#else +#define expect_value_count(function, parameter, value, count) \ + _expect_value(#function, #parameter, __FILE__, __LINE__, \ + cast_to_largest_integral_type(value), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if a parameter isn't the given value. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value The value to check. + * + * @see check_expected(). + */ +void expect_not_value(#function, #parameter, LargestIntegralType value); +#else +#define expect_not_value(function, parameter, value) \ + expect_not_value_count(function, parameter, value, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check if a parameter isn't the given value. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] value The value to check. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_not_value_count(#function, #parameter, LargestIntegralType value, size_t count); +#else +#define expect_not_value_count(function, parameter, value, count) \ + _expect_not_value(#function, #parameter, __FILE__, __LINE__, \ + cast_to_largest_integral_type(value), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value is equal to the + * provided string. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] string The string value to compare. + * + * @see check_expected(). + */ +void expect_string(#function, #parameter, const char *string); +#else +#define expect_string(function, parameter, string) \ + expect_string_count(function, parameter, string, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value is equal to the + * provided string. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] string The string value to compare. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_string_count(#function, #parameter, const char *string, size_t count); +#else +#define expect_string_count(function, parameter, string, count) \ + _expect_string(#function, #parameter, __FILE__, __LINE__, \ + (const char*)(string), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value isn't equal to the + * provided string. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] string The string value to compare. + * + * @see check_expected(). + */ +void expect_not_string(#function, #parameter, const char *string); +#else +#define expect_not_string(function, parameter, string) \ + expect_not_string_count(function, parameter, string, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter value isn't equal to the + * provided string. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] string The string value to compare. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_not_string_count(#function, #parameter, const char *string, size_t count); +#else +#define expect_not_string_count(function, parameter, string, count) \ + _expect_not_string(#function, #parameter, __FILE__, __LINE__, \ + (const char*)(string), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter does match an area of memory. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] memory The memory to compare. + * + * @param[in] size The size of the memory to compare. + * + * @see check_expected(). + */ +void expect_memory(#function, #parameter, void *memory, size_t size); +#else +#define expect_memory(function, parameter, memory, size) \ + expect_memory_count(function, parameter, memory, size, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check if the parameter does match an area + * of memory. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] memory The memory to compare. + * + * @param[in] size The size of the memory to compare. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_memory_count(#function, #parameter, void *memory, size_t size, size_t count); +#else +#define expect_memory_count(function, parameter, memory, size, count) \ + _expect_memory(#function, #parameter, __FILE__, __LINE__, \ + (const void*)(memory), size, count) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to check if the parameter doesn't match an area of + * memory. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] memory The memory to compare. + * + * @param[in] size The size of the memory to compare. + * + * @see check_expected(). + */ +void expect_not_memory(#function, #parameter, void *memory, size_t size); +#else +#define expect_not_memory(function, parameter, memory, size) \ + expect_not_memory_count(function, parameter, memory, size, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check if the parameter doesn't match an + * area of memory. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] memory The memory to compare. + * + * @param[in] size The size of the memory to compare. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_not_memory_count(#function, #parameter, void *memory, size_t size, size_t count); +#else +#define expect_not_memory_count(function, parameter, memory, size, count) \ + _expect_not_memory(#function, #parameter, __FILE__, __LINE__, \ + (const void*)(memory), size, count) +#endif + + +#ifdef DOXYGEN +/** + * @brief Add an event to check if a parameter (of any value) has been passed. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @see check_expected(). + */ +void expect_any(#function, #parameter); +#else +#define expect_any(function, parameter) \ + expect_any_count(function, parameter, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to always check if a parameter (of any value) has been passed. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @see check_expected(). + */ +void expect_any_always(#function, #parameter); +#else +#define expect_any_always(function, parameter) \ + expect_any_count(function, parameter, WILL_RETURN_ALWAYS) +#endif + +#ifdef DOXYGEN +/** + * @brief Add an event to repeatedly check if a parameter (of any value) has + * been passed. + * + * The event is triggered by calling check_expected() in the mocked function. + * + * @param[in] #function The function to add the check for. + * + * @param[in] #parameter The name of the parameter passed to the function. + * + * @param[in] count The count parameter returns the number of times the value + * should be returned by check_expected(). If count is set + * to -1 the value will always be returned. + * + * @see check_expected(). + */ +void expect_any_count(#function, #parameter, size_t count); +#else +#define expect_any_count(function, parameter, count) \ + _expect_any(#function, #parameter, __FILE__, __LINE__, count) +#endif + +#ifdef DOXYGEN +/** + * @brief Determine whether a function parameter is correct. + * + * This ensures the next value queued by one of the expect_*() macros matches + * the specified variable. + * + * This function needs to be called in the mock object. + * + * @param[in] #parameter The parameter to check. + */ +void check_expected(#parameter); +#else +#define check_expected(parameter) \ + _check_expected(__func__, #parameter, __FILE__, __LINE__, \ + cast_to_largest_integral_type(parameter)) +#endif + +#ifdef DOXYGEN +/** + * @brief Determine whether a function parameter is correct. + * + * This ensures the next value queued by one of the expect_*() macros matches + * the specified variable. + * + * This function needs to be called in the mock object. + * + * @param[in] #parameter The pointer to check. + */ +void check_expected_ptr(#parameter); +#else +#define check_expected_ptr(parameter) \ + _check_expected(__func__, #parameter, __FILE__, __LINE__, \ + cast_ptr_to_largest_integral_type(parameter)) +#endif + +/** @} */ + +/** + * @defgroup cmocka_asserts Assert Macros + * @ingroup cmocka + * + * This is a set of useful assert macros like the standard C libary's + * assert(3) macro. + * + * On an assertion failure a cmocka assert macro will write the failure to the + * standard error stream and signal a test failure. Due to limitations of the C + * language the general C standard library assert() and cmocka's assert_true() + * and assert_false() macros can only display the expression that caused the + * assert failure. cmocka's type specific assert macros, assert_{type}_equal() + * and assert_{type}_not_equal(), display the data that caused the assertion + * failure which increases data visibility aiding debugging of failing test + * cases. + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Assert that the given expression is true. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if expression is false (i.e., compares equal to + * zero). + * + * @param[in] expression The expression to evaluate. + * + * @see assert_int_equal() + * @see assert_string_equal() + */ +void assert_true(scalar expression); +#else +#define assert_true(c) _assert_true(cast_to_largest_integral_type(c), #c, \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the given expression is false. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if expression is true. + * + * @param[in] expression The expression to evaluate. + * + * @see assert_int_equal() + * @see assert_string_equal() + */ +void assert_false(scalar expression); +#else +#define assert_false(c) _assert_true(!(cast_to_largest_integral_type(c)), #c, \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the return_code is greater than or equal to 0. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the return code is smaller than 0. If the function + * you check sets an errno if it fails you can pass it to the function and + * it will be printed as part of the error message. + * + * @param[in] rc The return code to evaluate. + * + * @param[in] error Pass errno here or 0. + */ +void assert_return_code(int rc, int error); +#else +#define assert_return_code(rc, error) \ + _assert_return_code(cast_to_largest_integral_type(rc), \ + sizeof(rc), \ + cast_to_largest_integral_type(error), \ + #rc, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the given pointer is non-NULL. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the pointer is NULL. + * + * @param[in] pointer The pointer to evaluate. + * + * @see assert_null() + */ +void assert_non_null(void *pointer); +#else +#define assert_non_null(c) _assert_true(cast_ptr_to_largest_integral_type(c), #c, \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the given pointer is NULL. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the pointer is non-NULL. + * + * @param[in] pointer The pointer to evaluate. + * + * @see assert_non_null() + */ +void assert_null(void *pointer); +#else +#define assert_null(c) _assert_true(!(cast_ptr_to_largest_integral_type(c)), #c, \ +__FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given pointers are equal. + * + * The function prints an error message and terminates the test by calling + * fail() if the pointers are not equal. + * + * @param[in] a The first pointer to compare. + * + * @param[in] b The pointer to compare against the first one. + */ +void assert_ptr_equal(void *a, void *b); +#else +#define assert_ptr_equal(a, b) \ + _assert_int_equal(cast_ptr_to_largest_integral_type(a), \ + cast_ptr_to_largest_integral_type(b), \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given pointers are not equal. + * + * The function prints an error message and terminates the test by calling + * fail() if the pointers are equal. + * + * @param[in] a The first pointer to compare. + * + * @param[in] b The pointer to compare against the first one. + */ +void assert_ptr_not_equal(void *a, void *b); +#else +#define assert_ptr_not_equal(a, b) \ + _assert_int_not_equal(cast_ptr_to_largest_integral_type(a), \ + cast_ptr_to_largest_integral_type(b), \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given integers are equal. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the integers are not equal. + * + * @param[in] a The first integer to compare. + * + * @param[in] b The integer to compare against the first one. + */ +void assert_int_equal(int a, int b); +#else +#define assert_int_equal(a, b) \ + _assert_int_equal(cast_to_largest_integral_type(a), \ + cast_to_largest_integral_type(b), \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given integers are not equal. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the integers are equal. + * + * @param[in] a The first integer to compare. + * + * @param[in] b The integer to compare against the first one. + * + * @see assert_int_equal() + */ +void assert_int_not_equal(int a, int b); +#else +#define assert_int_not_equal(a, b) \ + _assert_int_not_equal(cast_to_largest_integral_type(a), \ + cast_to_largest_integral_type(b), \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given float are equal given an epsilon. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the float are not equal (given an epsilon). + * + * @param[in] a The first float to compare. + * + * @param[in] b The float to compare against the first one. + * + * @param[in] epsilon The epsilon used as margin for float comparison. + */ +void assert_float_equal(float a, float b, float epsilon); +#else +#define assert_float_equal(a, b, epsilon) \ + _assert_float_equal((float)a, \ + (float)b, \ + (float)epsilon, \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given float are not equal given an epsilon. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the float are not equal (given an epsilon). + * + * @param[in] a The first float to compare. + * + * @param[in] b The float to compare against the first one. + * + * @param[in] epsilon The epsilon used as margin for float comparison. + */ +void assert_float_not_equal(float a, float b, float epsilon); +#else +#define assert_float_not_equal(a, b, epsilon) \ + _assert_float_not_equal((float)a, \ + (float)b, \ + (float)epsilon, \ + __FILE__, __LINE__) +#endif + + +#ifdef DOXYGEN +/** + * @brief Assert that the two given strings are equal. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the strings are not equal. + * + * @param[in] a The string to check. + * + * @param[in] b The other string to compare. + */ +void assert_string_equal(const char *a, const char *b); +#else +#define assert_string_equal(a, b) \ + _assert_string_equal((const char*)(a), (const char*)(b), __FILE__, \ + __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given strings are not equal. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the strings are equal. + * + * @param[in] a The string to check. + * + * @param[in] b The other string to compare. + */ +void assert_string_not_equal(const char *a, const char *b); +#else +#define assert_string_not_equal(a, b) \ + _assert_string_not_equal((const char*)(a), (const char*)(b), __FILE__, \ + __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given areas of memory are equal, otherwise fail. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the memory is not equal. + * + * @param[in] a The first memory area to compare + * (interpreted as unsigned char). + * + * @param[in] b The second memory area to compare + * (interpreted as unsigned char). + * + * @param[in] size The first n bytes of the memory areas to compare. + */ +void assert_memory_equal(const void *a, const void *b, size_t size); +#else +#define assert_memory_equal(a, b, size) \ + _assert_memory_equal((const void*)(a), (const void*)(b), size, __FILE__, \ + __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the two given areas of memory are not equal. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if the memory is equal. + * + * @param[in] a The first memory area to compare + * (interpreted as unsigned char). + * + * @param[in] b The second memory area to compare + * (interpreted as unsigned char). + * + * @param[in] size The first n bytes of the memory areas to compare. + */ +void assert_memory_not_equal(const void *a, const void *b, size_t size); +#else +#define assert_memory_not_equal(a, b, size) \ + _assert_memory_not_equal((const void*)(a), (const void*)(b), size, \ + __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the specified value is not smaller than the minimum + * and and not greater than the maximum. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if value is not in range. + * + * @param[in] value The value to check. + * + * @param[in] minimum The minimum value allowed. + * + * @param[in] maximum The maximum value allowed. + */ +void assert_in_range(LargestIntegralType value, LargestIntegralType minimum, LargestIntegralType maximum); +#else +#define assert_in_range(value, minimum, maximum) \ + _assert_in_range( \ + cast_to_largest_integral_type(value), \ + cast_to_largest_integral_type(minimum), \ + cast_to_largest_integral_type(maximum), __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the specified value is smaller than the minimum or + * greater than the maximum. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if value is in range. + * + * @param[in] value The value to check. + * + * @param[in] minimum The minimum value to compare. + * + * @param[in] maximum The maximum value to compare. + */ +void assert_not_in_range(LargestIntegralType value, LargestIntegralType minimum, LargestIntegralType maximum); +#else +#define assert_not_in_range(value, minimum, maximum) \ + _assert_not_in_range( \ + cast_to_largest_integral_type(value), \ + cast_to_largest_integral_type(minimum), \ + cast_to_largest_integral_type(maximum), __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the specified value is within a set. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if value is not within a set. + * + * @param[in] value The value to look up + * + * @param[in] values[] The array to check for the value. + * + * @param[in] count The size of the values array. + */ +void assert_in_set(LargestIntegralType value, LargestIntegralType values[], size_t count); +#else +#define assert_in_set(value, values, number_of_values) \ + _assert_in_set(value, values, number_of_values, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Assert that the specified value is not within a set. + * + * The function prints an error message to standard error and terminates the + * test by calling fail() if value is within a set. + * + * @param[in] value The value to look up + * + * @param[in] values[] The array to check for the value. + * + * @param[in] count The size of the values array. + */ +void assert_not_in_set(LargestIntegralType value, LargestIntegralType values[], size_t count); +#else +#define assert_not_in_set(value, values, number_of_values) \ + _assert_not_in_set(value, values, number_of_values, __FILE__, __LINE__) +#endif + +/** @} */ + +/** + * @defgroup cmocka_call_order Call Ordering + * @ingroup cmocka + * + * It is often beneficial to make sure that functions are called in an + * order. This is independent of mock returns and parameter checking as both + * of the aforementioned do not check the order in which they are called from + * different functions. + * + *
    + *
  • expect_function_call(function) - The + * expect_function_call() macro pushes an expectation onto the stack of + * expected calls.
  • + * + *
  • function_called() - pops a value from the stack of + * expected calls. function_called() is invoked within the mock object + * that uses it. + *
+ * + * expect_function_call() and function_called() are intended to be used in + * pairs. Cmocka will fail a test if there are more or less expected calls + * created (e.g. expect_function_call()) than consumed with function_called(). + * There are provisions such as ignore_function_calls() which allow this + * restriction to be circumvented in tests where mock calls for the code under + * test are not the focus of the test. + * + * The following example illustrates how a unit test instructs cmocka + * to expect a function_called() from a particular mock, + * chef_sing(): + * + * @code + * void chef_sing(void); + * + * void code_under_test() + * { + * chef_sing(); + * } + * + * void some_test(void **state) + * { + * expect_function_call(chef_sing); + * code_under_test(); + * } + * @endcode + * + * The implementation of the mock then must check whether it was meant to + * be called by invoking function_called(): + * + * @code + * void chef_sing() + * { + * function_called(); + * } + * @endcode + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Check that current mocked function is being called in the expected + * order + * + * @see expect_function_call() + */ +void function_called(void); +#else +#define function_called() _function_called(__func__, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Store expected call(s) to a mock to be checked by function_called() + * later. + * + * @param[in] #function The function which should should be called + * + * @param[in] times number of times this mock must be called + * + * @see function_called() + */ +void expect_function_calls(#function, const int times); +#else +#define expect_function_calls(function, times) \ + _expect_function_call(#function, __FILE__, __LINE__, times) +#endif + +#ifdef DOXYGEN +/** + * @brief Store expected single call to a mock to be checked by + * function_called() later. + * + * @param[in] #function The function which should should be called + * + * @see function_called() + */ +void expect_function_call(#function); +#else +#define expect_function_call(function) \ + _expect_function_call(#function, __FILE__, __LINE__, 1) +#endif + +#ifdef DOXYGEN +/** + * @brief Expects function_called() from given mock at least once + * + * @param[in] #function The function which should should be called + * + * @see function_called() + */ +void expect_function_call_any(#function); +#else +#define expect_function_call_any(function) \ + _expect_function_call(#function, __FILE__, __LINE__, -1) +#endif + +#ifdef DOXYGEN +/** + * @brief Ignores function_called() invocations from given mock function. + * + * @param[in] #function The function which should should be called + * + * @see function_called() + */ +void ignore_function_calls(#function); +#else +#define ignore_function_calls(function) \ + _expect_function_call(#function, __FILE__, __LINE__, -2) +#endif + +/** @} */ + +/** + * @defgroup cmocka_exec Running Tests + * @ingroup cmocka + * + * This is the way tests are executed with CMocka. + * + * The following example illustrates this macro's use with the unit_test macro. + * + * @code + * void Test0(void **state); + * void Test1(void **state); + * + * int main(void) + * { + * const struct CMUnitTest tests[] = { + * cmocka_unit_test(Test0), + * cmocka_unit_test(Test1), + * }; + * + * return cmocka_run_group_tests(tests, NULL, NULL); + * } + * @endcode + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Forces the test to fail immediately and quit. + */ +void fail(void); +#else +#define fail() _fail(__FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Forces the test to not be executed, but marked as skipped + */ +void skip(void); +#else +#define skip() _skip(__FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Forces the test to fail immediately and quit, printing the reason. + * + * @code + * fail_msg("This is some error message for test"); + * @endcode + * + * or + * + * @code + * char *error_msg = "This is some error message for test"; + * fail_msg("%s", error_msg); + * @endcode + */ +void fail_msg(const char *msg, ...); +#else +#define fail_msg(msg, ...) do { \ + print_error("ERROR: " msg "\n", ##__VA_ARGS__); \ + fail(); \ +} while (0) +#endif + +#ifdef DOXYGEN +/** + * @brief Generic method to run a single test. + * + * @deprecated This function was deprecated in favor of cmocka_run_group_tests + * + * @param[in] #function The function to test. + * + * @return 0 on success, 1 if an error occured. + * + * @code + * // A test case that does nothing and succeeds. + * void null_test_success(void **state) { + * } + * + * int main(void) { + * return run_test(null_test_success); + * } + * @endcode + */ +int run_test(#function); +#else +#define run_test(f) _run_test(#f, f, NULL, UNIT_TEST_FUNCTION_TYPE_TEST, NULL) +#endif + +static inline void _unit_test_dummy(void **state) { + (void)state; +} + +/** Initializes a UnitTest structure. + * + * @deprecated This function was deprecated in favor of cmocka_unit_test + */ +#define unit_test(f) { #f, f, UNIT_TEST_FUNCTION_TYPE_TEST } + +#define _unit_test_setup(test, setup) \ + { #test "_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_SETUP } + +/** Initializes a UnitTest structure with a setup function. + * + * @deprecated This function was deprecated in favor of cmocka_unit_test_setup + */ +#define unit_test_setup(test, setup) \ + _unit_test_setup(test, setup), \ + unit_test(test), \ + _unit_test_teardown(test, _unit_test_dummy) + +#define _unit_test_teardown(test, teardown) \ + { #test "_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_TEARDOWN } + +/** Initializes a UnitTest structure with a teardown function. + * + * @deprecated This function was deprecated in favor of cmocka_unit_test_teardown + */ +#define unit_test_teardown(test, teardown) \ + _unit_test_setup(test, _unit_test_dummy), \ + unit_test(test), \ + _unit_test_teardown(test, teardown) + +/** Initializes a UnitTest structure for a group setup function. + * + * @deprecated This function was deprecated in favor of cmocka_run_group_tests + */ +#define group_test_setup(setup) \ + { "group_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP } + +/** Initializes a UnitTest structure for a group teardown function. + * + * @deprecated This function was deprecated in favor of cmocka_run_group_tests + */ +#define group_test_teardown(teardown) \ + { "group_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN } + +/** + * Initialize an array of UnitTest structures with a setup function for a test + * and a teardown function. Either setup or teardown can be NULL. + * + * @deprecated This function was deprecated in favor of + * cmocka_unit_test_setup_teardown + */ +#define unit_test_setup_teardown(test, setup, teardown) \ + _unit_test_setup(test, setup), \ + unit_test(test), \ + _unit_test_teardown(test, teardown) + + +/** Initializes a CMUnitTest structure. */ +#define cmocka_unit_test(f) { #f, f, NULL, NULL, NULL } + +/** Initializes a CMUnitTest structure with a setup function. */ +#define cmocka_unit_test_setup(f, setup) { #f, f, setup, NULL, NULL } + +/** Initializes a CMUnitTest structure with a teardown function. */ +#define cmocka_unit_test_teardown(f, teardown) { #f, f, NULL, teardown, NULL } + +/** + * Initialize an array of CMUnitTest structures with a setup function for a test + * and a teardown function. Either setup or teardown can be NULL. + */ +#define cmocka_unit_test_setup_teardown(f, setup, teardown) { #f, f, setup, teardown, NULL } + +/** + * Initialize a CMUnitTest structure with given initial state. It will be passed + * to test function as an argument later. It can be used when test state does + * not need special initialization or was initialized already. + * @note If the group setup function initialized the state already, it won't be + * overridden by the initial state defined here. + */ +#define cmocka_unit_test_prestate(f, state) { #f, f, NULL, NULL, state } + +/** + * Initialize a CMUnitTest structure with given initial state, setup and + * teardown function. Any of these values can be NULL. Initial state is passed + * later to setup function, or directly to test if none was given. + * @note If the group setup function initialized the state already, it won't be + * overridden by the initial state defined here. + */ +#define cmocka_unit_test_prestate_setup_teardown(f, setup, teardown, state) { #f, f, setup, teardown, state } + +#define run_tests(tests) _run_tests(tests, sizeof(tests) / sizeof((tests)[0])) +#define run_group_tests(tests) _run_group_tests(tests, sizeof(tests) / sizeof((tests)[0])) + +#ifdef DOXYGEN +/** + * @brief Run tests specified by an array of CMUnitTest structures. + * + * @param[in] group_tests[] The array of unit tests to execute. + * + * @param[in] group_setup The setup function which should be called before + * all unit tests are executed. + * + * @param[in] group_teardown The teardown function to be called after all + * tests have finished. + * + * @return 0 on success, or the number of failed tests. + * + * @code + * static int setup(void **state) { + * int *answer = malloc(sizeof(int)); + * if (*answer == NULL) { + * return -1; + * } + * *answer = 42; + * + * *state = answer; + * + * return 0; + * } + * + * static int teardown(void **state) { + * free(*state); + * + * return 0; + * } + * + * static void null_test_success(void **state) { + * (void) state; + * } + * + * static void int_test_success(void **state) { + * int *answer = *state; + * assert_int_equal(*answer, 42); + * } + * + * int main(void) { + * const struct CMUnitTest tests[] = { + * cmocka_unit_test(null_test_success), + * cmocka_unit_test_setup_teardown(int_test_success, setup, teardown), + * }; + * + * return cmocka_run_group_tests(tests, NULL, NULL); + * } + * @endcode + * + * @see cmocka_unit_test + * @see cmocka_unit_test_setup + * @see cmocka_unit_test_teardown + * @see cmocka_unit_test_setup_teardown + */ +int cmocka_run_group_tests(const struct CMUnitTest group_tests[], + CMFixtureFunction group_setup, + CMFixtureFunction group_teardown); +#else +# define cmocka_run_group_tests(group_tests, group_setup, group_teardown) \ + _cmocka_run_group_tests(#group_tests, group_tests, sizeof(group_tests) / sizeof((group_tests)[0]), group_setup, group_teardown) +#endif + +#ifdef DOXYGEN +/** + * @brief Run tests specified by an array of CMUnitTest structures and specify + * a name. + * + * @param[in] group_name The name of the group test. + * + * @param[in] group_tests[] The array of unit tests to execute. + * + * @param[in] group_setup The setup function which should be called before + * all unit tests are executed. + * + * @param[in] group_teardown The teardown function to be called after all + * tests have finished. + * + * @return 0 on success, or the number of failed tests. + * + * @code + * static int setup(void **state) { + * int *answer = malloc(sizeof(int)); + * if (*answer == NULL) { + * return -1; + * } + * *answer = 42; + * + * *state = answer; + * + * return 0; + * } + * + * static int teardown(void **state) { + * free(*state); + * + * return 0; + * } + * + * static void null_test_success(void **state) { + * (void) state; + * } + * + * static void int_test_success(void **state) { + * int *answer = *state; + * assert_int_equal(*answer, 42); + * } + * + * int main(void) { + * const struct CMUnitTest tests[] = { + * cmocka_unit_test(null_test_success), + * cmocka_unit_test_setup_teardown(int_test_success, setup, teardown), + * }; + * + * return cmocka_run_group_tests_name("success_test", tests, NULL, NULL); + * } + * @endcode + * + * @see cmocka_unit_test + * @see cmocka_unit_test_setup + * @see cmocka_unit_test_teardown + * @see cmocka_unit_test_setup_teardown + */ +int cmocka_run_group_tests_name(const char *group_name, + const struct CMUnitTest group_tests[], + CMFixtureFunction group_setup, + CMFixtureFunction group_teardown); +#else +# define cmocka_run_group_tests_name(group_name, group_tests, group_setup, group_teardown) \ + _cmocka_run_group_tests(group_name, group_tests, sizeof(group_tests) / sizeof((group_tests)[0]), group_setup, group_teardown) +#endif + +/** @} */ + +/** + * @defgroup cmocka_alloc Dynamic Memory Allocation + * @ingroup cmocka + * + * Memory leaks, buffer overflows and underflows can be checked using cmocka. + * + * To test for memory leaks, buffer overflows and underflows a module being + * tested by cmocka should replace calls to malloc(), calloc() and free() to + * test_malloc(), test_calloc() and test_free() respectively. Each time a block + * is deallocated using test_free() it is checked for corruption, if a corrupt + * block is found a test failure is signalled. All blocks allocated using the + * test_*() allocation functions are tracked by the cmocka library. When a test + * completes if any allocated blocks (memory leaks) remain they are reported + * and a test failure is signalled. + * + * For simplicity cmocka currently executes all tests in one process. Therefore + * all test cases in a test application share a single address space which + * means memory corruption from a single test case could potentially cause the + * test application to exit prematurely. + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Test function overriding malloc. + * + * @param[in] size The bytes which should be allocated. + * + * @return A pointer to the allocated memory or NULL on error. + * + * @code + * #ifdef UNIT_TESTING + * extern void* _test_malloc(const size_t size, const char* file, const int line); + * + * #define malloc(size) _test_malloc(size, __FILE__, __LINE__) + * #endif + * + * void leak_memory() { + * int * const temporary = (int*)malloc(sizeof(int)); + * *temporary = 0; + * } + * @endcode + * + * @see malloc(3) + */ +void *test_malloc(size_t size); +#else +#define test_malloc(size) _test_malloc(size, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Test function overriding calloc. + * + * The memory is set to zero. + * + * @param[in] nmemb The number of elements for an array to be allocated. + * + * @param[in] size The size in bytes of each array element to allocate. + * + * @return A pointer to the allocated memory, NULL on error. + * + * @see calloc(3) + */ +void *test_calloc(size_t nmemb, size_t size); +#else +#define test_calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Test function overriding realloc which detects buffer overruns + * and memoery leaks. + * + * @param[in] ptr The memory block which should be changed. + * + * @param[in] size The bytes which should be allocated. + * + * @return The newly allocated memory block, NULL on error. + */ +void *test_realloc(void *ptr, size_t size); +#else +#define test_realloc(ptr, size) _test_realloc(ptr, size, __FILE__, __LINE__) +#endif + +#ifdef DOXYGEN +/** + * @brief Test function overriding free(3). + * + * @param[in] ptr The pointer to the memory space to free. + * + * @see free(3). + */ +void test_free(void *ptr); +#else +#define test_free(ptr) _test_free(ptr, __FILE__, __LINE__) +#endif + +/* Redirect malloc, calloc and free to the unit test allocators. */ +#ifdef UNIT_TESTING +#define malloc test_malloc +#define realloc test_realloc +#define calloc test_calloc +#define free test_free +#endif /* UNIT_TESTING */ + +/** @} */ + + +/** + * @defgroup cmocka_mock_assert Standard Assertions + * @ingroup cmocka + * + * How to handle assert(3) of the standard C library. + * + * Runtime assert macros like the standard C library's assert() should be + * redefined in modules being tested to use cmocka's mock_assert() function. + * Normally mock_assert() signals a test failure. If a function is called using + * the expect_assert_failure() macro, any calls to mock_assert() within the + * function will result in the execution of the test. If no calls to + * mock_assert() occur during the function called via expect_assert_failure() a + * test failure is signalled. + * + * @{ + */ + +/** + * @brief Function to replace assert(3) in tested code. + * + * In conjuction with check_assert() it's possible to determine whether an + * assert condition has failed without stopping a test. + * + * @param[in] result The expression to assert. + * + * @param[in] expression The expression as string. + * + * @param[in] file The file mock_assert() is called. + * + * @param[in] line The line mock_assert() is called. + * + * @code + * #ifdef UNIT_TESTING + * extern void mock_assert(const int result, const char* const expression, + * const char * const file, const int line); + * + * #undef assert + * #define assert(expression) \ + * mock_assert((int)(expression), #expression, __FILE__, __LINE__); + * #endif + * + * void increment_value(int * const value) { + * assert(value); + * (*value) ++; + * } + * @endcode + * + * @see assert(3) + * @see expect_assert_failure + */ +void mock_assert(const int result, const char* const expression, + const char * const file, const int line); + +#ifdef DOXYGEN +/** + * @brief Ensure that mock_assert() is called. + * + * If mock_assert() is called the assert expression string is returned. + * + * @param[in] fn_call The function will will call mock_assert(). + * + * @code + * #define assert mock_assert + * + * void showmessage(const char *message) { + * assert(message); + * } + * + * int main(int argc, const char* argv[]) { + * expect_assert_failure(show_message(NULL)); + * printf("succeeded\n"); + * return 0; + * } + * @endcode + * + */ +void expect_assert_failure(function fn_call); +#else +#define expect_assert_failure(function_call) \ + { \ + const int result = setjmp(global_expect_assert_env); \ + global_expecting_assert = 1; \ + if (result) { \ + print_message("Expected assertion %s occurred\n", \ + global_last_failed_assert); \ + global_expecting_assert = 0; \ + } else { \ + function_call ; \ + global_expecting_assert = 0; \ + print_error("Expected assert in %s\n", #function_call); \ + _fail(__FILE__, __LINE__); \ + } \ + } +#endif + +/** @} */ + +/* Function prototype for setup, test and teardown functions. */ +typedef void (*UnitTestFunction)(void **state); + +/* Function that determines whether a function parameter value is correct. */ +typedef int (*CheckParameterValue)(const LargestIntegralType value, + const LargestIntegralType check_value_data); + +/* Type of the unit test function. */ +typedef enum UnitTestFunctionType { + UNIT_TEST_FUNCTION_TYPE_TEST = 0, + UNIT_TEST_FUNCTION_TYPE_SETUP, + UNIT_TEST_FUNCTION_TYPE_TEARDOWN, + UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP, + UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN, +} UnitTestFunctionType; + +/* + * Stores a unit test function with its name and type. + * NOTE: Every setup function must be paired with a teardown function. It's + * possible to specify NULL function pointers. + */ +typedef struct UnitTest { + const char* name; + UnitTestFunction function; + UnitTestFunctionType function_type; +} UnitTest; + +typedef struct GroupTest { + UnitTestFunction setup; + UnitTestFunction teardown; + const UnitTest *tests; + const size_t number_of_tests; +} GroupTest; + +/* Function prototype for test functions. */ +typedef void (*CMUnitTestFunction)(void **state); + +/* Function prototype for setup and teardown functions. */ +typedef int (*CMFixtureFunction)(void **state); + +struct CMUnitTest { + const char *name; + CMUnitTestFunction test_func; + CMFixtureFunction setup_func; + CMFixtureFunction teardown_func; + void *initial_state; +}; + +/* Location within some source code. */ +typedef struct SourceLocation { + const char* file; + int line; +} SourceLocation; + +/* Event that's called to check a parameter value. */ +typedef struct CheckParameterEvent { + SourceLocation location; + const char *parameter_name; + CheckParameterValue check_value; + LargestIntegralType check_value_data; +} CheckParameterEvent; + +/* Used by expect_assert_failure() and mock_assert(). */ +extern int global_expecting_assert; +extern jmp_buf global_expect_assert_env; +extern const char * global_last_failed_assert; + +/* Retrieves a value for the given function, as set by "will_return". */ +LargestIntegralType _mock(const char * const function, const char* const file, + const int line); + +void _expect_function_call( + const char * const function_name, + const char * const file, + const int line, + const int count); + +void _function_called(const char * const function, const char* const file, + const int line); + +void _expect_check( + const char* const function, const char* const parameter, + const char* const file, const int line, + const CheckParameterValue check_function, + const LargestIntegralType check_data, CheckParameterEvent * const event, + const int count); + +void _expect_in_set( + const char* const function, const char* const parameter, + const char* const file, const int line, const LargestIntegralType values[], + const size_t number_of_values, const int count); +void _expect_not_in_set( + const char* const function, const char* const parameter, + const char* const file, const int line, const LargestIntegralType values[], + const size_t number_of_values, const int count); + +void _expect_in_range( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType minimum, + const LargestIntegralType maximum, const int count); +void _expect_not_in_range( + const char* const function, const char* const parameter, + const char* const file, const int line, + const LargestIntegralType minimum, + const LargestIntegralType maximum, const int count); + +void _expect_value( + const char* const function, const char* const parameter, + const char* const file, const int line, const LargestIntegralType value, + const int count); +void _expect_not_value( + const char* const function, const char* const parameter, + const char* const file, const int line, const LargestIntegralType value, + const int count); + +void _expect_string( + const char* const function, const char* const parameter, + const char* const file, const int line, const char* string, + const int count); +void _expect_not_string( + const char* const function, const char* const parameter, + const char* const file, const int line, const char* string, + const int count); + +void _expect_memory( + const char* const function, const char* const parameter, + const char* const file, const int line, const void* const memory, + const size_t size, const int count); +void _expect_not_memory( + const char* const function, const char* const parameter, + const char* const file, const int line, const void* const memory, + const size_t size, const int count); + +void _expect_any( + const char* const function, const char* const parameter, + const char* const file, const int line, const int count); + +void _check_expected( + const char * const function_name, const char * const parameter_name, + const char* file, const int line, const LargestIntegralType value); + +void _will_return(const char * const function_name, const char * const file, + const int line, const LargestIntegralType value, + const int count); +void _assert_true(const LargestIntegralType result, + const char* const expression, + const char * const file, const int line); +void _assert_return_code(const LargestIntegralType result, + size_t rlen, + const LargestIntegralType error, + const char * const expression, + const char * const file, + const int line); +void _assert_float_equal(const float a, const float n, + const float epsilon, const char* const file, + const int line); +void _assert_float_not_equal(const float a, const float n, + const float epsilon, const char* const file, + const int line); +void _assert_int_equal( + const LargestIntegralType a, const LargestIntegralType b, + const char * const file, const int line); +void _assert_int_not_equal( + const LargestIntegralType a, const LargestIntegralType b, + const char * const file, const int line); +void _assert_string_equal(const char * const a, const char * const b, + const char * const file, const int line); +void _assert_string_not_equal(const char * const a, const char * const b, + const char *file, const int line); +void _assert_memory_equal(const void * const a, const void * const b, + const size_t size, const char* const file, + const int line); +void _assert_memory_not_equal(const void * const a, const void * const b, + const size_t size, const char* const file, + const int line); +void _assert_in_range( + const LargestIntegralType value, const LargestIntegralType minimum, + const LargestIntegralType maximum, const char* const file, const int line); +void _assert_not_in_range( + const LargestIntegralType value, const LargestIntegralType minimum, + const LargestIntegralType maximum, const char* const file, const int line); +void _assert_in_set( + const LargestIntegralType value, const LargestIntegralType values[], + const size_t number_of_values, const char* const file, const int line); +void _assert_not_in_set( + const LargestIntegralType value, const LargestIntegralType values[], + const size_t number_of_values, const char* const file, const int line); + +void* _test_malloc(const size_t size, const char* file, const int line); +void* _test_realloc(void *ptr, const size_t size, const char* file, const int line); +void* _test_calloc(const size_t number_of_elements, const size_t size, + const char* file, const int line); +void _test_free(void* const ptr, const char* file, const int line); + +void _fail(const char * const file, const int line); + +void _skip(const char * const file, const int line); + +int _run_test( + const char * const function_name, const UnitTestFunction Function, + void ** const volatile state, const UnitTestFunctionType function_type, + const void* const heap_check_point); +CMOCKA_DEPRECATED int _run_tests(const UnitTest * const tests, + const size_t number_of_tests); +CMOCKA_DEPRECATED int _run_group_tests(const UnitTest * const tests, + const size_t number_of_tests); + +/* Test runner */ +int _cmocka_run_group_tests(const char *group_name, + const struct CMUnitTest * const tests, + const size_t num_tests, + CMFixtureFunction group_setup, + CMFixtureFunction group_teardown); + +/* Standard output and error print methods. */ +void print_message(const char* const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); +void print_error(const char* const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); +void vprint_message(const char* const format, va_list args) CMOCKA_PRINTF_ATTRIBUTE(1, 0); +void vprint_error(const char* const format, va_list args) CMOCKA_PRINTF_ATTRIBUTE(1, 0); + +enum cm_message_output { + CM_OUTPUT_STDOUT, + CM_OUTPUT_SUBUNIT, + CM_OUTPUT_TAP, + CM_OUTPUT_XML, +}; + +/** + * @brief Function to set the output format for a test. + * + * The ouput format for the test can either be set globally using this + * function or overriden with environment variable CMOCKA_MESSAGE_OUTPUT. + * + * The environment variable can be set to either STDOUT, SUBUNIT, TAP or XML. + * + * @param[in] output The output format to use for the test. + * + */ +void cmocka_set_message_output(enum cm_message_output output); + + +/** + * @brief Set a pattern to only run the test matching the pattern. + * + * This allows to filter tests and only run the ones matching the pattern. The + * pattern can include two wildards. The first is '*', a wildcard that matches + * zero or more characters, or ‘?’, a wildcard that matches exactly one + * character. + * + * @param[in] pattern The pattern to match, e.g. "test_wurst*" + */ +void cmocka_set_test_filter(const char *pattern); + +/** + * @brief Set a pattern to skip tests matching the pattern. + * + * This allows to filter tests and skip the ones matching the pattern. The + * pattern can include two wildards. The first is '*', a wildcard that matches + * zero or more characters, or ‘?’, a wildcard that matches exactly one + * character. + * + * @param[in] pattern The pattern to match, e.g. "test_wurst*" + */ +void cmocka_set_skip_filter(const char *pattern); + +/** @} */ + +#endif /* CMOCKA_H_ */ diff --git a/src/imports/cmocka/cmocka_private.h b/src/imports/cmocka/cmocka_private.h new file mode 100644 index 0000000..d20d841 --- /dev/null +++ b/src/imports/cmocka/cmocka_private.h @@ -0,0 +1,163 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CMOCKA_PRIVATE_H_ +#define CMOCKA_PRIVATE_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef _WIN32 +#include + +# ifdef _MSC_VER +# include /* _snprintf */ + +# undef inline +# define inline __inline + +# ifndef va_copy +# define va_copy(dest, src) (dest = src) +# endif + +# define strcasecmp _stricmp +# define strncasecmp _strnicmp + +# if defined(HAVE__SNPRINTF_S) +# undef snprintf +# define snprintf(d, n, ...) _snprintf_s((d), (n), _TRUNCATE, __VA_ARGS__) +# else /* HAVE__SNPRINTF_S */ +# if defined(HAVE__SNPRINTF) +# undef snprintf +# define snprintf _snprintf +# else /* HAVE__SNPRINTF */ +# if !defined(HAVE_SNPRINTF) +# error "no snprintf compatible function found" +# endif /* HAVE_SNPRINTF */ +# endif /* HAVE__SNPRINTF */ +# endif /* HAVE__SNPRINTF_S */ + +# if defined(HAVE__VSNPRINTF_S) +# undef vsnprintf +# define vsnprintf(s, n, f, v) _vsnprintf_s((s), (n), _TRUNCATE, (f), (v)) +# else /* HAVE__VSNPRINTF_S */ +# if defined(HAVE__VSNPRINTF) +# undef vsnprintf +# define vsnprintf _vsnprintf +# else +# if !defined(HAVE_VSNPRINTF) +# error "No vsnprintf compatible function found" +# endif /* HAVE_VSNPRINTF */ +# endif /* HAVE__VSNPRINTF */ +# endif /* HAVE__VSNPRINTF_S */ +# endif /* _MSC_VER */ + +/* + * Backwards compatibility with headers shipped with Visual Studio 2005 and + * earlier. + */ +WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID); + +#ifndef PRIdS +# define PRIdS "Id" +#endif + +#ifndef PRIu64 +# define PRIu64 "I64u" +#endif + +#ifndef PRIuMAX +# define PRIuMAX PRIu64 +#endif + +#ifndef PRIxMAX +#define PRIxMAX "I64x" +#endif + +#ifndef PRIXMAX +#define PRIXMAX "I64X" +#endif + +#else /* _WIN32 */ + +#ifndef __PRI64_PREFIX +# if __WORDSIZE == 64 +# define __PRI64_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# endif +#endif + +#ifndef PRIdS +# define PRIdS "zd" +#endif + +#ifndef PRIu64 +# define PRIu64 __PRI64_PREFIX "u" +#endif + +#ifndef PRIuMAX +# define PRIuMAX __PRI64_PREFIX "u" +#endif + +#ifndef PRIxMAX +#define PRIxMAX __PRI64_PREFIX "x" +#endif + +#ifndef PRIXMAX +#define PRIXMAX __PRI64_PREFIX "X" +#endif + +#endif /* _WIN32 */ + +/** Free memory space */ +#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0) + +/** Zero a structure */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/** Zero a structure given a pointer to the structure */ +#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0) + +/** Get the size of an array */ +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/** Overwrite the complete string with 'X' */ +#define BURN_STRING(x) do { if ((x) != NULL) memset((x), 'X', strlen((x))); } while(0) + +/** + * This is a hack to fix warnings. The idea is to use this everywhere that we + * get the "discarding const" warning by the compiler. That doesn't actually + * fix the real issue, but marks the place and you can search the code for + * discard_const. + * + * Please use this macro only when there is no other way to fix the warning. + * We should use this function in only in a very few places. + * + * Also, please call this via the discard_const_p() macro interface, as that + * makes the return type safe. + */ +#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) + +/** + * Type-safe version of discard_const + */ +#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) + +#endif /* CMOCKA_PRIVATE_H_ */ diff --git a/src/imports/cmocka/config.h b/src/imports/cmocka/config.h new file mode 100644 index 0000000..67f7c7a --- /dev/null +++ b/src/imports/cmocka/config.h @@ -0,0 +1,6 @@ +#pragma once + +#define HAVE_MALLOC_H +#define HAVE_INTTYPES_H +#define HAVE_SIGNAL_H +#define HAVE_STRINGS_H \ No newline at end of file diff --git a/src/imports/fmodex/fmod.h b/src/imports/fmodex/fmod.h new file mode 100644 index 0000000..2c80462 --- /dev/null +++ b/src/imports/fmodex/fmod.h @@ -0,0 +1,2499 @@ +/*$ preserve start $*/ + +/* ============================================================================================ */ +/* FMOD Ex - Main C/C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* This header is the base header for all other FMOD headers. If you are programming in C */ +/* use this exclusively, or if you are programming C++ use this in conjunction with FMOD.HPP */ +/* */ +/* ============================================================================================ */ + +#ifndef _FMOD_H +#define _FMOD_H + +/* + FMOD version number. Check this against FMOD::System::getVersion. + 0xaaaabbcc -> aaaa = major version number. bb = minor version number. cc = development version number. +*/ + +#define FMOD_VERSION 0x00044464 + +/* + Compiler specific settings. +*/ + +#if defined(__CYGWIN32__) + #define F_CDECL __cdecl + #define F_STDCALL __stdcall + #define F_DECLSPEC __declspec + #define F_DLLEXPORT ( dllexport ) +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) + #define F_CDECL _cdecl + #define F_STDCALL _stdcall + #define F_DECLSPEC __declspec + #define F_DLLEXPORT ( dllexport ) +#elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) + #define F_CDECL + #define F_STDCALL + #define F_DECLSPEC + #define F_DLLEXPORT __attribute__ ((visibility("default"))) +#else + #define F_CDECL + #define F_STDCALL + #define F_DECLSPEC + #define F_DLLEXPORT +#endif + +#ifdef DLL_EXPORTS + #if defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) + #define F_API __attribute__ ((visibility("default"))) + #else + #define F_API __declspec(dllexport) F_STDCALL + #endif +#else + #define F_API F_STDCALL +#endif + +#define F_CALLBACK F_STDCALL + +/* + FMOD types. +*/ + +typedef int FMOD_BOOL; +typedef struct FMOD_SYSTEM FMOD_SYSTEM; +typedef struct FMOD_SOUND FMOD_SOUND; +typedef struct FMOD_CHANNEL FMOD_CHANNEL; +typedef struct FMOD_CHANNELGROUP FMOD_CHANNELGROUP; +typedef struct FMOD_SOUNDGROUP FMOD_SOUNDGROUP; +typedef struct FMOD_REVERB FMOD_REVERB; +typedef struct FMOD_DSP FMOD_DSP; +typedef struct FMOD_DSPCONNECTION FMOD_DSPCONNECTION; +typedef struct FMOD_POLYGON FMOD_POLYGON; +typedef struct FMOD_GEOMETRY FMOD_GEOMETRY; +typedef struct FMOD_SYNCPOINT FMOD_SYNCPOINT; +typedef struct FMOD_ASYNCREADINFO FMOD_ASYNCREADINFO; +typedef unsigned int FMOD_MODE; +typedef unsigned int FMOD_TIMEUNIT; +typedef unsigned int FMOD_INITFLAGS; +typedef unsigned int FMOD_CAPS; +typedef unsigned int FMOD_DEBUGLEVEL; +typedef unsigned int FMOD_MEMORY_TYPE; + +/*$ fmod result start $*/ +/* +[ENUM] +[ + [DESCRIPTION] + error codes. Returned from every function. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] +] +*/ +typedef enum +{ + FMOD_OK, /* No errors. */ + FMOD_ERR_ALREADYLOCKED, /* Tried to call lock a second time before unlock was called. */ + FMOD_ERR_BADCOMMAND, /* Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). */ + FMOD_ERR_CDDA_DRIVERS, /* Neither NTSCSI nor ASPI could be initialised. */ + FMOD_ERR_CDDA_INIT, /* An error occurred while initialising the CDDA subsystem. */ + FMOD_ERR_CDDA_INVALID_DEVICE, /* Couldn't find the specified device. */ + FMOD_ERR_CDDA_NOAUDIO, /* No audio tracks on the specified disc. */ + FMOD_ERR_CDDA_NODEVICES, /* No CD/DVD devices were found. */ + FMOD_ERR_CDDA_NODISC, /* No disc present in the specified drive. */ + FMOD_ERR_CDDA_READ, /* A CDDA read error occurred. */ + FMOD_ERR_CHANNEL_ALLOC, /* Error trying to allocate a channel. */ + FMOD_ERR_CHANNEL_STOLEN, /* The specified channel has been reused to play another sound. */ + FMOD_ERR_COM, /* A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. */ + FMOD_ERR_DMA, /* DMA Failure. See debug output for more information. */ + FMOD_ERR_DSP_CONNECTION, /* DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). */ + FMOD_ERR_DSP_FORMAT, /* DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. */ + FMOD_ERR_DSP_NOTFOUND, /* DSP connection error. Couldn't find the DSP unit specified. */ + FMOD_ERR_DSP_RUNNING, /* DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. */ + FMOD_ERR_DSP_TOOMANYCONNECTIONS,/* DSP connection error. The unit being connected to or disconnected should only have 1 input or output. */ + FMOD_ERR_FILE_BAD, /* Error loading file. */ + FMOD_ERR_FILE_COULDNOTSEEK, /* Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. */ + FMOD_ERR_FILE_DISKEJECTED, /* Media was ejected while reading. */ + FMOD_ERR_FILE_EOF, /* End of file unexpectedly reached while trying to read essential data (truncated data?). */ + FMOD_ERR_FILE_NOTFOUND, /* File not found. */ + FMOD_ERR_FILE_UNWANTED, /* Unwanted file access occured. */ + FMOD_ERR_FORMAT, /* Unsupported file or audio format. */ + FMOD_ERR_HTTP, /* A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. */ + FMOD_ERR_HTTP_ACCESS, /* The specified resource requires authentication or is forbidden. */ + FMOD_ERR_HTTP_PROXY_AUTH, /* Proxy authentication is required to access the specified resource. */ + FMOD_ERR_HTTP_SERVER_ERROR, /* A HTTP server error occurred. */ + FMOD_ERR_HTTP_TIMEOUT, /* The HTTP request timed out. */ + FMOD_ERR_INITIALIZATION, /* FMOD was not initialized correctly to support this function. */ + FMOD_ERR_INITIALIZED, /* Cannot call this command after System::init. */ + FMOD_ERR_INTERNAL, /* An error occured that wasn't supposed to. Contact support. */ + FMOD_ERR_INVALID_ADDRESS, /* On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) */ + FMOD_ERR_INVALID_FLOAT, /* Value passed in was a NaN, Inf or denormalized float. */ + FMOD_ERR_INVALID_HANDLE, /* An invalid object handle was used. */ + FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function. */ + FMOD_ERR_INVALID_POSITION, /* An invalid seek position was passed to this function. */ + FMOD_ERR_INVALID_SPEAKER, /* An invalid speaker was passed to this function based on the current speaker mode. */ + FMOD_ERR_INVALID_SYNCPOINT, /* The syncpoint did not come from this sound handle. */ + FMOD_ERR_INVALID_VECTOR, /* The vectors passed in are not unit length, or perpendicular. */ + FMOD_ERR_MAXAUDIBLE, /* Reached maximum audible playback count for this sound's soundgroup. */ + FMOD_ERR_MEMORY, /* Not enough memory or resources. */ + FMOD_ERR_MEMORY_CANTPOINT, /* Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. */ + FMOD_ERR_MEMORY_SRAM, /* Not enough memory or resources on console sound ram. */ + FMOD_ERR_NEEDS2D, /* Tried to call a command on a 3d sound when the command was meant for 2d sound. */ + FMOD_ERR_NEEDS3D, /* Tried to call a command on a 2d sound when the command was meant for 3d sound. */ + FMOD_ERR_NEEDSHARDWARE, /* Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). */ + FMOD_ERR_NEEDSSOFTWARE, /* Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. */ + FMOD_ERR_NET_CONNECT, /* Couldn't connect to the specified host. */ + FMOD_ERR_NET_SOCKET_ERROR, /* A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. */ + FMOD_ERR_NET_URL, /* The specified URL couldn't be resolved. */ + FMOD_ERR_NET_WOULD_BLOCK, /* Operation on a non-blocking socket could not complete immediately. */ + FMOD_ERR_NOTREADY, /* Operation could not be performed because specified sound/DSP connection is not ready. */ + FMOD_ERR_OUTPUT_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ + FMOD_ERR_OUTPUT_CREATEBUFFER, /* Error creating hardware sound buffer. */ + FMOD_ERR_OUTPUT_DRIVERCALL, /* A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. */ + FMOD_ERR_OUTPUT_ENUMERATION, /* Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. */ + FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). */ + FMOD_ERR_OUTPUT_INIT, /* Error initializing output device. */ + FMOD_ERR_OUTPUT_NOHARDWARE, /* FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. */ + FMOD_ERR_OUTPUT_NOSOFTWARE, /* Attempted to create a software sound but no software channels were specified in System::init. */ + FMOD_ERR_PAN, /* Panning only works with mono or stereo sound sources. */ + FMOD_ERR_PLUGIN, /* An unspecified error has been returned from a 3rd party plugin. */ + FMOD_ERR_PLUGIN_INSTANCES, /* The number of allowed instances of a plugin has been exceeded. */ + FMOD_ERR_PLUGIN_MISSING, /* A requested output, dsp unit type or codec was not available. */ + FMOD_ERR_PLUGIN_RESOURCE, /* A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) */ + FMOD_ERR_PRELOADED, /* The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. */ + FMOD_ERR_PROGRAMMERSOUND, /* The specified sound is still in use by the event system, wait for the event which is using it finish with it. */ + FMOD_ERR_RECORD, /* An error occured trying to initialize the recording device. */ + FMOD_ERR_REVERB_INSTANCE, /* Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. */ + FMOD_ERR_SUBSOUND_ALLOCATED, /* This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. */ + FMOD_ERR_SUBSOUND_CANTMOVE, /* Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. */ + FMOD_ERR_SUBSOUND_MODE, /* The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. */ + FMOD_ERR_SUBSOUNDS, /* The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. */ + FMOD_ERR_TAGNOTFOUND, /* The specified tag could not be found or there are no tags. */ + FMOD_ERR_TOOMANYCHANNELS, /* The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. */ + FMOD_ERR_UNIMPLEMENTED, /* Something in FMOD hasn't been implemented when it should be! contact support! */ + FMOD_ERR_UNINITIALIZED, /* This command failed because System::init or System::setDriver was not called. */ + FMOD_ERR_UNSUPPORTED, /* A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. */ + FMOD_ERR_UPDATE, /* An error caused by System::update occured. */ + FMOD_ERR_VERSION, /* The version number of this file format is not supported. */ + + FMOD_ERR_EVENT_FAILED, /* An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. */ + FMOD_ERR_EVENT_INFOONLY, /* Can't execute this command on an EVENT_INFOONLY event. */ + FMOD_ERR_EVENT_INTERNAL, /* An error occured that wasn't supposed to. See debug log for reason. */ + FMOD_ERR_EVENT_MAXSTREAMS, /* Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. */ + FMOD_ERR_EVENT_MISMATCH, /* FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. */ + FMOD_ERR_EVENT_NAMECONFLICT, /* A category with the same name already exists. */ + FMOD_ERR_EVENT_NOTFOUND, /* The requested event, event group, event category or event property could not be found. */ + FMOD_ERR_EVENT_NEEDSSIMPLE, /* Tried to call a function on a complex event that's only supported by simple events. */ + FMOD_ERR_EVENT_GUIDCONFLICT, /* An event with the same GUID already exists. */ + FMOD_ERR_EVENT_ALREADY_LOADED, /* The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. */ + + FMOD_ERR_MUSIC_UNINITIALIZED, /* Music system is not initialized probably because no music data is loaded. */ + FMOD_ERR_MUSIC_NOTFOUND, /* The requested music entity could not be found. */ + FMOD_ERR_MUSIC_NOCALLBACK, /* The music callback is required, but it has not been set. */ + + FMOD_RESULT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_RESULT; +/*$ fmod result end $*/ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a point in 3D space. + + [REMARKS] + FMOD uses a left handed co-ordinate system by default.
+ To use a right handed co-ordinate system specify FMOD_INIT_3D_RIGHTHANDED from FMOD_INITFLAGS in System::init. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::set3DListenerAttributes + System::get3DListenerAttributes + Channel::set3DAttributes + Channel::get3DAttributes + Channel::set3DCustomRolloff + Channel::get3DCustomRolloff + Sound::set3DCustomRolloff + Sound::get3DCustomRolloff + Geometry::addPolygon + Geometry::setPolygonVertex + Geometry::getPolygonVertex + Geometry::setRotation + Geometry::getRotation + Geometry::setPosition + Geometry::getPosition + Geometry::setScale + Geometry::getScale + FMOD_INITFLAGS +] +*/ +typedef struct +{ + float x; /* X co-ordinate in 3D space. */ + float y; /* Y co-ordinate in 3D space. */ + float z; /* Z co-ordinate in 3D space. */ +} FMOD_VECTOR; + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a globally unique identifier. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getDriverInfo +] +*/ +typedef struct +{ + unsigned int Data1; /* Specifies the first 8 hexadecimal digits of the GUID */ + unsigned short Data2; /* Specifies the first group of 4 hexadecimal digits. */ + unsigned short Data3; /* Specifies the second group of 4 hexadecimal digits. */ + unsigned char Data4[8]; /* Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits. */ +} FMOD_GUID; + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure that is passed into FMOD_FILE_ASYNCREADCALLBACK. Use the information in this structure to perform + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
+ Members marked with [w] mean the variable can be written to. The user can set the value.
+
+ Instructions: write to 'buffer', and 'bytesread' BEFORE setting 'result'.
+ As soon as result is set, FMOD will asynchronously continue internally using the data provided in this structure.
+
+ Set 'result' to the result expected from a normal file read callback.
+ If the read was successful, set it to FMOD_OK.
+ If it read some data but hit the end of the file, set it to FMOD_ERR_FILE_EOF.
+ If a bad error occurred, return FMOD_ERR_FILE_BAD
+ If a disk was ejected, return FMOD_ERR_FILE_DISKEJECTED.
+ + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_FILE_ASYNCREADCALLBACK + FMOD_FILE_ASYNCCANCELCALLBACK +] +*/ +struct FMOD_ASYNCREADINFO +{ + void *handle; /* [r] The file handle that was filled out in the open callback. */ + unsigned int offset; /* [r] Seek position, make sure you read from this file offset. */ + unsigned int sizebytes; /* [r] how many bytes requested for read. */ + int priority; /* [r] 0 = low importance. 100 = extremely important (ie 'must read now or stuttering may occur') */ + + void *buffer; /* [w] Buffer to read file data into. */ + unsigned int bytesread; /* [w] Fill this in before setting result code to tell FMOD how many bytes were read. */ + FMOD_RESULT result; /* [r/w] Result code, FMOD_OK tells the system it is ready to consume the data. Set this last! Default value = FMOD_ERR_NOTREADY. */ + + void *userdata; /* [r] User data pointer. */ + + const void (*done)(FMOD_ASYNCREADINFO *info, FMOD_RESULT result); /* FMOD file system wake up function. Use instead of 'result' with FMOD_INIT_ASYNCREAD_FAST to get semaphore based performance improvement. Call this when user file read is finished. Pass result of file read as a parameter. */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These output types are used with System::setOutput / System::getOutput, to choose which output method to use. + + [REMARKS] + To pass information to the driver when initializing fmod use the extradriverdata parameter in System::init for the following reasons.
+
  • FMOD_OUTPUTTYPE_WAVWRITER - extradriverdata is a pointer to a char * filename that the wav writer will output to. +
  • FMOD_OUTPUTTYPE_WAVWRITER_NRT - extradriverdata is a pointer to a char * filename that the wav writer will output to. +
  • FMOD_OUTPUTTYPE_DSOUND - extradriverdata is a pointer to a HWND so that FMOD can set the focus on the audio for a particular window. +
  • FMOD_OUTPUTTYPE_PS3 - extradriverdata is a pointer to a FMOD_PS3_EXTRADRIVERDATA struct. This can be found in fmodps3.h. +
  • FMOD_OUTPUTTYPE_GC - extradriverdata is a pointer to a FMOD_GC_INFO struct. This can be found in fmodgc.h. +
  • FMOD_OUTPUTTYPE_WII - extradriverdata is a pointer to a FMOD_WII_INFO struct. This can be found in fmodwii.h. +
  • FMOD_OUTPUTTYPE_ALSA - extradriverdata is a pointer to a FMOD_LINUX_EXTRADRIVERDATA struct. This can be found in fmodlinux.h.
    +
  • FMOD_OUTPUTTYPE_PULSEAUDIO - extradriverdata is a const char * representing the name of the application to appear in PulseAudio mixer GUIs.
    +
    + Currently these are the only FMOD drivers that take extra information. Other unknown plugins may have different requirements. +

    + Note! If FMOD_OUTPUTTYPE_WAVWRITER_NRT or FMOD_OUTPUTTYPE_NOSOUND_NRT are used, and if the System::update function is being called + very quickly (ie for a non realtime decode) it may be being called too quickly for the FMOD streamer thread to respond to. + The result will be a skipping/stuttering output in the captured audio.
    +
    + To remedy this, disable the FMOD Ex streamer thread, and use FMOD_INIT_STREAM_FROM_UPDATE to avoid skipping in the output stream, + as it will lock the mixer and the streamer together in the same thread. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setOutput + System::getOutput + System::setSoftwareFormat + System::getSoftwareFormat + System::init + System::update + FMOD_INITFLAGS +] +*/ +typedef enum +{ + FMOD_OUTPUTTYPE_AUTODETECT, /* Picks the best output mode for the platform. This is the default. */ + + FMOD_OUTPUTTYPE_UNKNOWN, /* All - 3rd party plugin, unknown. This is for use with System::getOutput only. */ + FMOD_OUTPUTTYPE_NOSOUND, /* All - All calls in this mode succeed but make no sound. */ + FMOD_OUTPUTTYPE_WAVWRITER, /* All - Writes output to fmodoutput.wav by default. Use the 'extradriverdata' parameter in System::init, by simply passing the filename as a string, to set the wav filename. */ + FMOD_OUTPUTTYPE_NOSOUND_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_NOSOUND. User can drive mixer with System::update at whatever rate they want. */ + FMOD_OUTPUTTYPE_WAVWRITER_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_WAVWRITER. User can drive mixer with System::update at whatever rate they want. */ + + FMOD_OUTPUTTYPE_DSOUND, /* Win32/Win64 - DirectSound output. (Default on Windows XP and below) */ + FMOD_OUTPUTTYPE_WINMM, /* Win32/Win64 - Windows Multimedia output. */ + FMOD_OUTPUTTYPE_WASAPI, /* Win32 - Windows Audio Session API. (Default on Windows Vista and above) */ + FMOD_OUTPUTTYPE_ASIO, /* Win32 - Low latency ASIO 2.0 driver. */ + FMOD_OUTPUTTYPE_OSS, /* Linux/Linux64 - Open Sound System output. (Default on Linux, third preference) */ + FMOD_OUTPUTTYPE_ALSA, /* Linux/Linux64 - Advanced Linux Sound Architecture output. (Default on Linux, second preference if available) */ + FMOD_OUTPUTTYPE_ESD, /* Linux/Linux64 - Enlightment Sound Daemon output. */ + FMOD_OUTPUTTYPE_PULSEAUDIO, /* Linux/Linux64 - PulseAudio output. (Default on Linux, first preference if available) */ + FMOD_OUTPUTTYPE_COREAUDIO, /* Mac - Macintosh CoreAudio output. (Default on Mac) */ + FMOD_OUTPUTTYPE_XBOX360, /* Xbox 360 - Native Xbox360 output. (Default on Xbox 360) */ + FMOD_OUTPUTTYPE_PSP, /* PSP - Native PSP output. (Default on PSP) */ + FMOD_OUTPUTTYPE_PS3, /* PS3 - Native PS3 output. (Default on PS3) */ + FMOD_OUTPUTTYPE_NGP, /* NGP - Native NGP output. (Default on NGP) */ + FMOD_OUTPUTTYPE_WII, /* Wii - Native Wii output. (Default on Wii) */ + FMOD_OUTPUTTYPE_3DS, /* 3DS - Native 3DS output (Default on 3DS) */ + FMOD_OUTPUTTYPE_AUDIOTRACK, /* Android - Java Audio Track output. (Default on Android 2.2 and below) */ + FMOD_OUTPUTTYPE_OPENSL, /* Android - OpenSL ES output. (Default on Android 2.3 and above) */ + FMOD_OUTPUTTYPE_NACL, /* Native Client - Native Client output. (Default on Native Client) */ + FMOD_OUTPUTTYPE_WIIU, /* Wii U - Native Wii U output. (Default on Wii U) */ + FMOD_OUTPUTTYPE_ASOUND, /* BlackBerry - Native BlackBerry asound output. (Default on BlackBerry) */ + FMOD_OUTPUTTYPE_AUDIOOUT, /* Orbis - Audio Out output. (Default on Orbis) */ + FMOD_OUTPUTTYPE_XAUDIO, /* Durango - XAudio2 output. */ + + FMOD_OUTPUTTYPE_MAX, /* Maximum number of output types supported. */ + FMOD_OUTPUTTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_OUTPUTTYPE; + + +/* +[DEFINE] +[ + [NAME] + FMOD_CAPS + + [DESCRIPTION] + Bit fields to use with System::getDriverCaps to determine the capabilities of a card / output device. + + [REMARKS] + It is important to check FMOD_CAPS_HARDWARE_EMULATED on windows machines, to then adjust System::setDSPBufferSize to (1024, 10) to compensate for the higher latency. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getDriverCaps + System::setDSPBufferSize +] +*/ +#define FMOD_CAPS_NONE 0x00000000 /* Device has no special capabilities. */ +#define FMOD_CAPS_HARDWARE 0x00000001 /* Device supports hardware mixing. */ +#define FMOD_CAPS_HARDWARE_EMULATED 0x00000002 /* User has device set to 'Hardware acceleration = off' in control panel, and now extra 200ms latency is incurred. */ +#define FMOD_CAPS_OUTPUT_MULTICHANNEL 0x00000004 /* Device can do multichannel output, ie greater than 2 channels. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM8 0x00000008 /* Device can output to 8bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM16 0x00000010 /* Device can output to 16bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM24 0x00000020 /* Device can output to 24bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM32 0x00000040 /* Device can output to 32bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCMFLOAT 0x00000080 /* Device can output to 32bit floating point PCM. */ +#define FMOD_CAPS_REVERB_LIMITED 0x00002000 /* Device supports some form of limited hardware reverb, maybe parameterless and only selectable by environment. */ +#define FMOD_CAPS_LOOPBACK 0x00004000 /* Device is a loopback recording device */ +/* [DEFINE_END] */ + +/* +[DEFINE] +[ + [NAME] + FMOD_DEBUGLEVEL + + [DESCRIPTION] + Bit fields to use with FMOD::Debug_SetLevel / FMOD::Debug_GetLevel to control the level of tty debug output with logging versions of FMOD (fmodL). + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Debug_SetLevel + Debug_GetLevel +] +*/ +#define FMOD_DEBUG_LEVEL_NONE 0x00000000 +#define FMOD_DEBUG_LEVEL_LOG 0x00000001 /* Will display generic logging messages. */ +#define FMOD_DEBUG_LEVEL_ERROR 0x00000002 /* Will display errors. */ +#define FMOD_DEBUG_LEVEL_WARNING 0x00000004 /* Will display warnings that are not fatal. */ +#define FMOD_DEBUG_LEVEL_HINT 0x00000008 /* Will hint to you if there is something possibly better you could be doing. */ +#define FMOD_DEBUG_LEVEL_ALL 0x000000FF +#define FMOD_DEBUG_TYPE_MEMORY 0x00000100 /* Show FMOD memory related logging messages. */ +#define FMOD_DEBUG_TYPE_THREAD 0x00000200 /* Show FMOD thread related logging messages. */ +#define FMOD_DEBUG_TYPE_FILE 0x00000400 /* Show FMOD file system related logging messages. */ +#define FMOD_DEBUG_TYPE_NET 0x00000800 /* Show FMOD network related logging messages. */ +#define FMOD_DEBUG_TYPE_EVENT 0x00001000 /* Show FMOD Event related logging messages. */ +#define FMOD_DEBUG_TYPE_ALL 0x0000FFFF +#define FMOD_DEBUG_DISPLAY_TIMESTAMPS 0x01000000 /* Display the timestamp of the log entry in milliseconds. */ +#define FMOD_DEBUG_DISPLAY_LINENUMBERS 0x02000000 /* Display the FMOD Ex source code line numbers, for debugging purposes. */ +#define FMOD_DEBUG_DISPLAY_COMPRESS 0x04000000 /* If a message is repeated more than 5 times it will stop displaying it and instead display the number of times the message was logged. */ +#define FMOD_DEBUG_DISPLAY_THREAD 0x08000000 /* Display the thread ID of the calling function that caused this log entry to appear. */ +#define FMOD_DEBUG_DISPLAY_ALL 0x0F000000 +#define FMOD_DEBUG_ALL 0xFFFFFFFF +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_MEMORY_TYPE + + [DESCRIPTION] + Bit fields for memory allocation type being passed into FMOD memory callbacks. + + [REMARKS] + Remember this is a bitfield. You may get more than 1 bit set (ie physical + persistent) so do not simply switch on the types! You must check each bit individually or clear out the bits that you do not want within the callback.
    + Bits can be excluded if you want during Memory_Initialize so that you never get them. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_MEMORY_ALLOCCALLBACK + FMOD_MEMORY_REALLOCCALLBACK + FMOD_MEMORY_FREECALLBACK + Memory_Initialize + +] +*/ +#define FMOD_MEMORY_NORMAL 0x00000000 /* Standard memory. */ +#define FMOD_MEMORY_STREAM_FILE 0x00000001 /* Stream file buffer, size controllable with System::setStreamBufferSize. */ +#define FMOD_MEMORY_STREAM_DECODE 0x00000002 /* Stream decode buffer, size controllable with FMOD_CREATESOUNDEXINFO::decodebuffersize. */ +#define FMOD_MEMORY_SAMPLEDATA 0x00000004 /* Sample data buffer. Raw audio data, usually PCM/MPEG/ADPCM/XMA data. */ +#define FMOD_MEMORY_DSP_OUTPUTBUFFER 0x00000008 /* DSP memory block allocated when more than 1 output exists on a DSP node. */ +#define FMOD_MEMORY_XBOX360_PHYSICAL 0x00100000 /* Requires XPhysicalAlloc / XPhysicalFree. */ +#define FMOD_MEMORY_PERSISTENT 0x00200000 /* Persistent memory. Memory will be freed when System::release is called. */ +#define FMOD_MEMORY_SECONDARY 0x00400000 /* Secondary memory. Allocation should be in secondary memory. For example RSX on the PS3. */ +#define FMOD_MEMORY_ALL 0xFFFFFFFF +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the System::setSpeakerMode or System::getSpeakerMode command. + + [REMARKS] + These are important notes on speaker modes in regards to sounds created with FMOD_SOFTWARE.
    + Note below the phrase 'sound channels' is used. These are the subchannels inside a sound, they are not related and + have nothing to do with the FMOD class "Channel".
    + For example a mono sound has 1 sound channel, a stereo sound has 2 sound channels, and an AC3 or 6 channel wav file have 6 "sound channels".
    +
    + FMOD_SPEAKERMODE_RAW
    + ---------------------
    + This mode is for output devices that are not specifically mono/stereo/quad/surround/5.1 or 7.1, but are multichannel.
    + Use System::setSoftwareFormat to specify the number of speakers you want to address, otherwise it will default to 2 (stereo).
    + Sound channels map to speakers sequentially, so a mono sound maps to output speaker 0, stereo sound maps to output speaker 0 & 1.
    + The user assumes knowledge of the speaker order. FMOD_SPEAKER enumerations may not apply, so raw channel indices should be used.
    + Multichannel sounds map input channels to output channels 1:1.
    + Channel::setPan and Channel::setSpeakerMix do not work.
    + Speaker levels must be manually set with Channel::setSpeakerLevels.
    +
    + FMOD_SPEAKERMODE_MONO
    + ---------------------
    + This mode is for a 1 speaker arrangement.
    + Panning does not work in this speaker mode.
    + Mono, stereo and multichannel sounds have each sound channel played on the one speaker unity.
    + Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels.
    + Channel::setSpeakerMix does not work.
    +
    + FMOD_SPEAKERMODE_STEREO
    + -----------------------
    + This mode is for 2 speaker arrangements that have a left and right speaker.
    +
  • Mono sounds default to an even distribution between left and right. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the middle, or full left in the left speaker and full right in the right speaker. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds have each sound channel played on each speaker at unity.
    +
  • Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but only front left and right parameters are used, the rest are ignored.
    +
    + FMOD_SPEAKERMODE_QUAD
    + ------------------------
    + This mode is for 4 speaker arrangements that have a front left, front right, rear left and a rear right speaker.
    +
  • Mono sounds default to an even distribution between front left and front right. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right.
    +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input.
    +
  • Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but side left, side right, center and lfe are ignored.
    +
    + FMOD_SPEAKERMODE_SURROUND
    + ------------------------
    + This mode is for 5 speaker arrangements that have a left/right/center/rear left/rear right.
    +
  • Mono sounds default to the center speaker. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input. +
  • Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but side left / side right are ignored.
    +
    + FMOD_SPEAKERMODE_5POINT1
    + ------------------------
    + This mode is for 5.1 speaker arrangements that have a left/right/center/rear left/rear right and a subwoofer speaker.
    +
  • Mono sounds default to the center speaker. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input. +
  • Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but side left / side right are ignored.
    +
    + FMOD_SPEAKERMODE_7POINT1
    + ------------------------
    + This mode is for 7.1 speaker arrangements that have a left/right/center/rear left/rear right/side left/side right + and a subwoofer speaker.
    +
  • Mono sounds default to the center speaker. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input. +
  • Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works and every parameter is used to set the balance of a sound in any speaker.
    +
    + FMOD_SPEAKERMODE_SRS5_1_MATRIX
    + ------------------------------------------------------
    + This mode is for mono, stereo, 5.1 and 6.1 speaker arrangements, as it is backwards and forwards compatible with + stereo, but to get a surround effect a SRS 5.1, Prologic or Prologic 2 hardware decoder / amplifier is needed or + a compatible SRS equipped device (e.g., laptop, TV, etc.) or accessory (e.g., headphone).
    + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1.
    +
    + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten.
    +
    + Output rate must be 44100, 48000 or 96000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned.
    +
    + FMOD_SPEAKERMODE_DOLBY5_1_MATRIX
    + ------------------------------------------------------
    + This mode is for 5.1 speaker arrangements using a stereo signal, to get a surround effect a Dolby Pro Logic II + hardware decoder / amplifier is needed.
    + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1.
    +
    + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten.
    +
    + Output rate must be 32000, 44100 or 48000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned.
    +
    + FMOD_SPEAKERMODE_MYEARS
    + ------------------------------------------------------
    + This mode is for headphones. This will attempt to load a MyEars profile (see myears.net.au) and use it to generate + surround sound on headphones using a personalized HRTF algorithm, for realistic 3d sound.
    + Pan behavior is the same as FMOD_SPEAKERMODE_7POINT1.
    + MyEars speaker mode will automatically be set if the speakermode is FMOD_SPEAKERMODE_STEREO and the MyEars profile exists.
    + If this mode is set explicitly, FMOD_INIT_DISABLE_MYEARS_AUTODETECT has no effect.
    + If this mode is set explicitly and the MyEars profile does not exist, FMOD_ERR_OUTPUT_DRIVERCALL will be returned. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setSpeakerMode + System::getSpeakerMode + System::getDriverCaps + System::setSoftwareFormat + Channel::setSpeakerLevels +] +*/ +typedef enum +{ + FMOD_SPEAKERMODE_RAW, /* There is no specific speakermode. Sound channels are mapped in order of input to output. Use System::setSoftwareFormat to specify speaker count. See remarks for more information. */ + FMOD_SPEAKERMODE_MONO, /* The speakers are monaural. */ + FMOD_SPEAKERMODE_STEREO, /* The speakers are stereo (DEFAULT). */ + FMOD_SPEAKERMODE_QUAD, /* 4 speaker setup. This includes front left, front right, rear left, rear right. */ + FMOD_SPEAKERMODE_SURROUND, /* 5 speaker setup. This includes front left, front right, center, rear left, rear right. */ + FMOD_SPEAKERMODE_5POINT1, /* 5.1 speaker setup. This includes front left, front right, center, rear left, rear right and a subwoofer. */ + FMOD_SPEAKERMODE_7POINT1, /* 7.1 speaker setup. This includes front left, front right, center, rear left, rear right, side left, side right and a subwoofer. */ + + FMOD_SPEAKERMODE_SRS5_1_MATRIX, /* Stereo compatible output, embedded with surround information. SRS 5.1/Prologic/Prologic2 decoders will split the signal into a 5.1 speaker set-up or SRS virtual surround will decode into a 2-speaker/headphone setup. See remarks about limitations.*/ + FMOD_SPEAKERMODE_DOLBY5_1_MATRIX, /* Stereo compatible output, embedded with surround information. Dolby Pro Logic II decoders will split the signal into a 5.1 speaker set-up. */ + FMOD_SPEAKERMODE_MYEARS, /* Stereo output, but data is encoded using personalized HRTF algorithms. See myears.net.au */ + + FMOD_SPEAKERMODE_MAX, /* Maximum number of speaker modes supported. */ + FMOD_SPEAKERMODE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SPEAKERMODE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the Channel::setSpeakerLevels command. + It can also be used for speaker placement in the System::set3DSpeakerPosition command. + + [REMARKS] + If you are using FMOD_SPEAKERMODE_RAW and speaker assignments are meaningless, just cast a raw integer value to this type.
    + For example (FMOD_SPEAKER)7 would use the 7th speaker (also the same as FMOD_SPEAKER_SIDE_RIGHT).
    + Values higher than this can be used if an output system has more than 8 speaker types / output channels. 15 is the current maximum.
    +
    + NOTE: On Playstation 3 in 7.1, the extra 2 speakers are not side left/side right, they are 'surround back left'/'surround back right' which + locate the speakers behind the listener instead of to the sides like on PC. FMOD_SPEAKER_SBL/FMOD_SPEAKER_SBR are provided to make it + clearer what speaker is being addressed on that platform. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_SPEAKERMODE + Channel::setSpeakerLevels + Channel::getSpeakerLevels + System::set3DSpeakerPosition + System::get3DSpeakerPosition +] +*/ +typedef enum +{ + FMOD_SPEAKER_FRONT_LEFT, + FMOD_SPEAKER_FRONT_RIGHT, + FMOD_SPEAKER_FRONT_CENTER, + FMOD_SPEAKER_LOW_FREQUENCY, + FMOD_SPEAKER_BACK_LEFT, + FMOD_SPEAKER_BACK_RIGHT, + FMOD_SPEAKER_SIDE_LEFT, + FMOD_SPEAKER_SIDE_RIGHT, + + FMOD_SPEAKER_MAX, /* Maximum number of speaker types supported. */ + FMOD_SPEAKER_MONO = FMOD_SPEAKER_FRONT_LEFT, /* For use with FMOD_SPEAKERMODE_MONO and Channel::SetSpeakerLevels. Mapped to same value as FMOD_SPEAKER_FRONT_LEFT. */ + FMOD_SPEAKER_NULL = 65535, /* A non speaker. Use this with ASIO mapping to ignore a speaker. */ + FMOD_SPEAKER_SBL = FMOD_SPEAKER_SIDE_LEFT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + FMOD_SPEAKER_SBR = FMOD_SPEAKER_SIDE_RIGHT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + FMOD_SPEAKER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SPEAKER; + + +/* +[ENUM] +[ + [DESCRIPTION] + These are plugin types defined for use with the System::getNumPlugins, + System::getPluginInfo and System::unloadPlugin functions. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getNumPlugins + System::getPluginInfo + System::unloadPlugin +] +*/ +typedef enum +{ + FMOD_PLUGINTYPE_OUTPUT, /* The plugin type is an output module. FMOD mixed audio will play through one of these devices */ + FMOD_PLUGINTYPE_CODEC, /* The plugin type is a file format codec. FMOD will use these codecs to load file formats for playback. */ + FMOD_PLUGINTYPE_DSP, /* The plugin type is a DSP unit. FMOD will use these plugins as part of its DSP network to apply effects to output or generate sound in realtime. */ + + FMOD_PLUGINTYPE_MAX, /* Maximum number of plugin types supported. */ + FMOD_PLUGINTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_PLUGINTYPE; + + +/* +[DEFINE] +[ + [NAME] + FMOD_INITFLAGS + + [DESCRIPTION] + Initialization flags. Use them with System::init in the flags parameter to change various behavior. + + [REMARKS] + Use System::setAdvancedSettings to adjust settings for some of the features that are enabled by these flags. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::init + System::update + System::setAdvancedSettings + Channel::set3DOcclusion +] +*/ +#define FMOD_INIT_NORMAL 0x00000000 /* All platforms - Initialize normally */ +#define FMOD_INIT_STREAM_FROM_UPDATE 0x00000001 /* All platforms - No stream thread is created internally. Streams are driven from System::update. Mainly used with non-realtime outputs. */ +#define FMOD_INIT_3D_RIGHTHANDED 0x00000002 /* All platforms - FMOD will treat +X as right, +Y as up and +Z as backwards (towards you). */ +#define FMOD_INIT_SOFTWARE_DISABLE 0x00000004 /* All platforms - Disable software mixer to save memory. Anything created with FMOD_SOFTWARE will fail and DSP will not work. */ +#define FMOD_INIT_OCCLUSION_LOWPASS 0x00000008 /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which is automatically used when Channel::set3DOcclusion is used or the geometry API. */ +#define FMOD_INIT_HRTF_LOWPASS 0x00000010 /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which causes sounds to sound duller when the sound goes behind the listener. Use System::setAdvancedSettings to adjust cutoff frequency. */ +#define FMOD_INIT_DISTANCE_FILTERING 0x00000200 /* All platforms - All FMOD_SOFTWARE with FMOD_3D based voices will add a software lowpass and highpass filter effect into the DSP chain which will act as a distance-automated bandpass filter. Use System::setAdvancedSettings to adjust the center frequency. */ +#define FMOD_INIT_REVERB_PREALLOCBUFFERS 0x00000040 /* All platforms - FMOD Software reverb will preallocate enough buffers for reverb per channel, rather than allocating them and freeing them at runtime. */ +#define FMOD_INIT_ENABLE_PROFILE 0x00000020 /* All platforms - Enable TCP/IP based host which allows FMOD Designer or FMOD Profiler to connect to it, and view memory, CPU and the DSP network graph in real-time. */ +#define FMOD_INIT_VOL0_BECOMES_VIRTUAL 0x00000080 /* All platforms - Any sounds that are 0 volume will go virtual and not be processed except for having their positions updated virtually. Use System::setAdvancedSettings to adjust what volume besides zero to switch to virtual at. */ +#define FMOD_INIT_WASAPI_EXCLUSIVE 0x00000100 /* Win32 Vista only - for WASAPI output - Enable exclusive access to hardware, lower latency at the expense of excluding other applications from accessing the audio hardware. */ +#define FMOD_INIT_PS3_PREFERDTS 0x00800000 /* PS3 only - Prefer DTS over Dolby Digital if both are supported. Note: 8 and 6 channel LPCM is always preferred over both DTS and Dolby Digital. */ +#define FMOD_INIT_PS3_FORCE2CHLPCM 0x01000000 /* PS3 only - Force PS3 system output mode to 2 channel LPCM. */ +#define FMOD_INIT_DISABLEDOLBY 0x00100000 /* Wii / 3DS - Disable Dolby Pro Logic surround. Speakermode will be set to STEREO even if user has selected surround in the system settings. */ +#define FMOD_INIT_SYSTEM_MUSICMUTENOTPAUSE 0x00200000 /* Xbox 360 / PS3 - The "music" channelgroup which by default pauses when custom 360 dashboard / PS3 BGM music is played, can be changed to mute (therefore continues playing) instead of pausing, by using this flag. */ +#define FMOD_INIT_SYNCMIXERWITHUPDATE 0x00400000 /* Win32/Wii/PS3/Xbox/Xbox 360 - FMOD Mixer thread is woken up to do a mix when System::update is called rather than waking periodically on its own timer. */ +#define FMOD_INIT_GEOMETRY_USECLOSEST 0x04000000 /* All platforms - With the geometry engine, only process the closest polygon rather than accumulating all polygons the sound to listener line intersects. */ +#define FMOD_INIT_DISABLE_MYEARS_AUTODETECT 0x08000000 /* Win32 - Disables automatic setting of FMOD_SPEAKERMODE_STEREO to FMOD_SPEAKERMODE_MYEARS if the MyEars profile exists on the PC. MyEars is HRTF 7.1 downmixing through headphones. */ +#define FMOD_INIT_PS3_DISABLEDTS 0x10000000 /* PS3 only - Disable DTS output mode selection */ +#define FMOD_INIT_PS3_DISABLEDOLBYDIGITAL 0x20000000 /* PS3 only - Disable Dolby Digital output mode selection */ +#define FMOD_INIT_7POINT1_DOLBYMAPPING 0x40000000 /* PS3/PS4 only - FMOD uses the WAVEFORMATEX Microsoft 7.1 speaker mapping where the last 2 pairs of speakers are 'rears' then 'sides', but on PS3/PS4 these are mapped to 'surrounds' and 'backs'. Use this flag to swap fmod's last 2 pair of speakers on PS3/PS4 to avoid needing to do a special case for these platforms. */ +#define FMOD_INIT_ASYNCREAD_FAST 0x80000000 /* All platforms - Rather than setting FMOD_ASYNCREADINFO::result, call FMOD_ASYNCREADINFO::done to enable a semaphore based wait inside fmod, rather than the older method which can incur up to 10ms delay per read. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the type of song being played. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getFormat +] +*/ +typedef enum +{ + FMOD_SOUND_TYPE_UNKNOWN, /* 3rd party / unknown plugin format. */ + FMOD_SOUND_TYPE_AIFF, /* AIFF. */ + FMOD_SOUND_TYPE_ASF, /* Microsoft Advanced Systems Format (ie WMA/ASF/WMV). */ + FMOD_SOUND_TYPE_AT3, /* Sony ATRAC 3 format */ + FMOD_SOUND_TYPE_CDDA, /* Digital CD audio. */ + FMOD_SOUND_TYPE_DLS, /* Sound font / downloadable sound bank. */ + FMOD_SOUND_TYPE_FLAC, /* FLAC lossless codec. */ + FMOD_SOUND_TYPE_FSB, /* FMOD Sample Bank. */ + FMOD_SOUND_TYPE_GCADPCM, /* Nintendo GameCube/Wii ADPCM */ + FMOD_SOUND_TYPE_IT, /* Impulse Tracker. */ + FMOD_SOUND_TYPE_MIDI, /* MIDI. extracodecdata is a pointer to an FMOD_MIDI_EXTRACODECDATA structure. */ + FMOD_SOUND_TYPE_MOD, /* Protracker / Fasttracker MOD. */ + FMOD_SOUND_TYPE_MPEG, /* MP2/MP3 MPEG. */ + FMOD_SOUND_TYPE_OGGVORBIS, /* Ogg vorbis. */ + FMOD_SOUND_TYPE_PLAYLIST, /* Information only from ASX/PLS/M3U/WAX playlists */ + FMOD_SOUND_TYPE_RAW, /* Raw PCM data. */ + FMOD_SOUND_TYPE_S3M, /* ScreamTracker 3. */ + FMOD_SOUND_TYPE_SF2, /* Sound font 2 format. */ + FMOD_SOUND_TYPE_USER, /* User created sound. */ + FMOD_SOUND_TYPE_WAV, /* Microsoft WAV. */ + FMOD_SOUND_TYPE_XM, /* FastTracker 2 XM. */ + FMOD_SOUND_TYPE_XMA, /* Xbox360 XMA */ + FMOD_SOUND_TYPE_VAG, /* PlayStation Portable ADPCM VAG format. */ + FMOD_SOUND_TYPE_AUDIOQUEUE, /* iPhone hardware decoder, supports AAC, ALAC and MP3. extracodecdata is a pointer to an FMOD_AUDIOQUEUE_EXTRACODECDATA structure. */ + FMOD_SOUND_TYPE_XWMA, /* Xbox360 XWMA */ + FMOD_SOUND_TYPE_BCWAV, /* 3DS BCWAV container format for DSP ADPCM and PCM */ + FMOD_SOUND_TYPE_AT9, /* NGP ATRAC 9 format */ + FMOD_SOUND_TYPE_VORBIS, /* Raw vorbis */ + FMOD_SOUND_TYPE_MEDIA_FOUNDATION,/* Microsoft Media Foundation wrappers, supports ASF/WMA */ + + FMOD_SOUND_TYPE_MAX, /* Maximum number of sound types supported. */ + FMOD_SOUND_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUND_TYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the native format of the hardware or software buffer that will be used. + + [REMARKS] + This is the format the native hardware or software buffer will be or is created in. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createSound + Sound::getFormat +] +*/ +typedef enum +{ + FMOD_SOUND_FORMAT_NONE, /* Unitialized / unknown. */ + FMOD_SOUND_FORMAT_PCM8, /* 8bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM16, /* 16bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM24, /* 24bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM32, /* 32bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCMFLOAT, /* 32bit floating point PCM data. */ + FMOD_SOUND_FORMAT_GCADPCM, /* Compressed Nintendo 3DS/Wii DSP data. */ + FMOD_SOUND_FORMAT_IMAADPCM, /* Compressed IMA ADPCM data. */ + FMOD_SOUND_FORMAT_VAG, /* Compressed PlayStation Portable ADPCM data. */ + FMOD_SOUND_FORMAT_HEVAG, /* Compressed PSVita ADPCM data. */ + FMOD_SOUND_FORMAT_XMA, /* Compressed Xbox360 XMA data. */ + FMOD_SOUND_FORMAT_MPEG, /* Compressed MPEG layer 2 or 3 data. */ + FMOD_SOUND_FORMAT_CELT, /* Compressed CELT data. */ + FMOD_SOUND_FORMAT_AT9, /* Compressed PSVita ATRAC9 data. */ + FMOD_SOUND_FORMAT_XWMA, /* Compressed Xbox360 xWMA data. */ + FMOD_SOUND_FORMAT_VORBIS, /* Compressed Vorbis data. */ + + FMOD_SOUND_FORMAT_MAX, /* Maximum number of sound formats supported. */ + FMOD_SOUND_FORMAT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUND_FORMAT; + + +/* +[DEFINE] +[ + [NAME] + FMOD_MODE + + [DESCRIPTION] + Sound description bitfields, bitwise OR them together for loading and describing sounds. + + [REMARKS] + By default a sound will open as a static sound that is decompressed fully into memory to PCM. (ie equivalent of FMOD_CREATESAMPLE)
    + To have a sound stream instead, use FMOD_CREATESTREAM, or use the wrapper function System::createStream.
    + Some opening modes (ie FMOD_OPENUSER, FMOD_OPENMEMORY, FMOD_OPENMEMORY_POINT, FMOD_OPENRAW) will need extra information.
    + This can be provided using the FMOD_CREATESOUNDEXINFO structure. +
    + Specifying FMOD_OPENMEMORY_POINT will POINT to your memory rather allocating its own sound buffers and duplicating it internally.
    + This means you cannot free the memory while FMOD is using it, until after Sound::release is called. + With FMOD_OPENMEMORY_POINT, for PCM formats, only WAV, FSB, and RAW are supported. For compressed formats, only those formats supported by FMOD_CREATECOMPRESSEDSAMPLE are supported.
    + With FMOD_OPENMEMORY_POINT and FMOD_OPENRAW or PCM, if using them together, note that you must pad the data on each side by 16 bytes. This is so fmod can modify the ends of the data for looping/interpolation/mixing purposes. If a wav file, you will need to insert silence, and then reset loop points to stop the playback from playing that silence.
    + With FMOD_OPENMEMORY_POINT, For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used.
    +
    + Xbox 360 memory On Xbox 360 Specifying FMOD_OPENMEMORY_POINT to a virtual memory address will cause FMOD_ERR_INVALID_ADDRESS + to be returned. Use physical memory only for this functionality.
    +
    + FMOD_LOWMEM is used on a sound if you want to minimize the memory overhead, by having FMOD not allocate memory for certain + features that are not likely to be used in a game environment. These are :
    + 1. Sound::getName functionality is removed. 256 bytes per sound is saved.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createSound + System::createStream + Sound::setMode + Sound::getMode + Channel::setMode + Channel::getMode + Sound::set3DCustomRolloff + Channel::set3DCustomRolloff + Sound::getOpenState +] +*/ +#define FMOD_DEFAULT 0x00000000 /* Default for all modes listed below. FMOD_LOOP_OFF, FMOD_2D, FMOD_HARDWARE */ +#define FMOD_LOOP_OFF 0x00000001 /* For non looping sounds. (DEFAULT). Overrides FMOD_LOOP_NORMAL / FMOD_LOOP_BIDI. */ +#define FMOD_LOOP_NORMAL 0x00000002 /* For forward looping sounds. */ +#define FMOD_LOOP_BIDI 0x00000004 /* For bidirectional looping sounds. (only works on software mixed static sounds). */ +#define FMOD_2D 0x00000008 /* Ignores any 3d processing. (DEFAULT). */ +#define FMOD_3D 0x00000010 /* Makes the sound positionable in 3D. Overrides FMOD_2D. */ +#define FMOD_HARDWARE 0x00000020 /* Attempts to make sounds use hardware acceleration. (DEFAULT). Note on platforms that don't support FMOD_HARDWARE (only 3DS, PS Vita, PSP, Wii and Wii U support FMOD_HARDWARE), this will be internally treated as FMOD_SOFTWARE. */ +#define FMOD_SOFTWARE 0x00000040 /* Makes the sound be mixed by the FMOD CPU based software mixer. Overrides FMOD_HARDWARE. Use this for FFT, DSP, compressed sample support, 2D multi-speaker support and other software related features. */ +#define FMOD_CREATESTREAM 0x00000080 /* Decompress at runtime, streaming from the source provided (ie from disk). Overrides FMOD_CREATESAMPLE and FMOD_CREATECOMPRESSEDSAMPLE. Note a stream can only be played once at a time due to a stream only having 1 stream buffer and file handle. Open multiple streams to have them play concurrently. */ +#define FMOD_CREATESAMPLE 0x00000100 /* Decompress at loadtime, decompressing or decoding whole file into memory as the target sample format (ie PCM). Fastest for FMOD_SOFTWARE based playback and most flexible. */ +#define FMOD_CREATECOMPRESSEDSAMPLE 0x00000200 /* Load MP2/MP3/IMAADPCM/CELT/Vorbis/AT9 or XMA into memory and leave it compressed. CELT/Vorbis/AT9 encoding only supported in the FSB file format. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. Overrides FMOD_CREATESAMPLE. If the sound data is not one of the supported formats, it will behave as if it was created with FMOD_CREATESAMPLE and decode the sound into PCM. */ +#define FMOD_OPENUSER 0x00000400 /* Opens a user created static sample or stream. Use FMOD_CREATESOUNDEXINFO to specify format and/or read callbacks. If a user created 'sample' is created with no read callback, the sample will be empty. Use Sound::lock and Sound::unlock to place sound data into the sound if this is the case. */ +#define FMOD_OPENMEMORY 0x00000800 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. If used with FMOD_CREATESAMPLE or FMOD_CREATECOMPRESSEDSAMPLE, FMOD duplicates the memory into its own buffers. Your own buffer can be freed after open. If used with FMOD_CREATESTREAM, FMOD will stream out of the buffer whose pointer you passed in. In this case, your own buffer should not be freed until you have finished with and released the stream.*/ +#define FMOD_OPENMEMORY_POINT 0x10000000 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. This differs to FMOD_OPENMEMORY in that it uses the memory as is, without duplicating the memory into its own buffers. For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used, as sound hardware on the other platforms (ie PC) cannot access main ram. Cannot be freed after open, only after Sound::release. Will not work if the data is compressed and FMOD_CREATECOMPRESSEDSAMPLE is not used. */ +#define FMOD_OPENRAW 0x00001000 /* Will ignore file format and treat as raw pcm. Use FMOD_CREATESOUNDEXINFO to specify format. Requires at least defaultfrequency, numchannels and format to be specified before it will open. Must be little endian data. */ +#define FMOD_OPENONLY 0x00002000 /* Just open the file, dont prebuffer or read. Good for fast opens for info, or when sound::readData is to be used. */ +#define FMOD_ACCURATETIME 0x00004000 /* For System::createSound - for accurate Sound::getLength/Channel::setPosition on VBR MP3, and MOD/S3M/XM/IT/MIDI files. Scans file first, so takes longer to open. FMOD_OPENONLY does not affect this. */ +#define FMOD_MPEGSEARCH 0x00008000 /* For corrupted / bad MP3 files. This will search all the way through the file until it hits a valid MPEG header. Normally only searches for 4k. */ +#define FMOD_NONBLOCKING 0x00010000 /* For opening sounds and getting streamed subsounds (seeking) asyncronously. Use Sound::getOpenState to poll the state of the sound as it opens or retrieves the subsound in the background. */ +#define FMOD_UNIQUE 0x00020000 /* Unique sound, can only be played one at a time */ +#define FMOD_3D_HEADRELATIVE 0x00040000 /* Make the sound's position, velocity and orientation relative to the listener. */ +#define FMOD_3D_WORLDRELATIVE 0x00080000 /* Make the sound's position, velocity and orientation absolute (relative to the world). (DEFAULT) */ +#define FMOD_3D_INVERSEROLLOFF 0x00100000 /* This sound will follow the inverse rolloff model where mindistance = full volume, maxdistance = where sound stops attenuating, and rolloff is fixed according to the global rolloff factor. (DEFAULT) */ +#define FMOD_3D_LINEARROLLOFF 0x00200000 /* This sound will follow a linear rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ +#define FMOD_3D_LINEARSQUAREROLLOFF 0x00400000 /* This sound will follow a linear-square rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ +#define FMOD_3D_CUSTOMROLLOFF 0x04000000 /* This sound will follow a rolloff model defined by Sound::set3DCustomRolloff / Channel::set3DCustomRolloff. */ +#define FMOD_3D_IGNOREGEOMETRY 0x40000000 /* Is not affect by geometry occlusion. If not specified in Sound::setMode, or Channel::setMode, the flag is cleared and it is affected by geometry again. */ +#define FMOD_UNICODE 0x01000000 /* Filename is double-byte unicode. */ +#define FMOD_IGNORETAGS 0x02000000 /* Skips id3v2/asf/etc tag checks when opening a sound, to reduce seek/read overhead when opening files (helps with CD performance). */ +#define FMOD_LOWMEM 0x08000000 /* Removes some features from samples to give a lower memory overhead, like Sound::getName. See remarks. */ +#define FMOD_LOADSECONDARYRAM 0x20000000 /* Load sound into the secondary RAM of supported platform. On PS3, sounds will be loaded into RSX/VRAM. */ +#define FMOD_VIRTUAL_PLAYFROMSTART 0x80000000 /* For sounds that start virtual (due to being quiet or low importance), instead of swapping back to audible, and playing at the correct offset according to time, this flag makes the sound play from the start. */ + +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These values describe what state a sound is in after FMOD_NONBLOCKING has been used to open it. + + [REMARKS] + With streams, if you are using FMOD_NONBLOCKING, note that if the user calls Sound::getSubSound, a stream will go into FMOD_OPENSTATE_SEEKING state and sound related commands will return FMOD_ERR_NOTREADY.
    + With streams, if you are using FMOD_NONBLOCKING, note that if the user calls Channel::getPosition, a stream will go into FMOD_OPENSTATE_SETPOSITION state and sound related commands will return FMOD_ERR_NOTREADY.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getOpenState + FMOD_MODE +] +*/ +typedef enum +{ + FMOD_OPENSTATE_READY = 0, /* Opened and ready to play. */ + FMOD_OPENSTATE_LOADING, /* Initial load in progress. */ + FMOD_OPENSTATE_ERROR, /* Failed to open - file not found, out of memory etc. See return value of Sound::getOpenState for what happened. */ + FMOD_OPENSTATE_CONNECTING, /* Connecting to remote host (internet sounds only). */ + FMOD_OPENSTATE_BUFFERING, /* Buffering data. */ + FMOD_OPENSTATE_SEEKING, /* Seeking to subsound and re-flushing stream buffer. */ + FMOD_OPENSTATE_PLAYING, /* Ready and playing, but not possible to release at this time without stalling the main thread. */ + FMOD_OPENSTATE_SETPOSITION, /* Seeking within a stream to a different position. */ + + FMOD_OPENSTATE_MAX, /* Maximum number of open state types. */ + FMOD_OPENSTATE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_OPENSTATE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These flags are used with SoundGroup::setMaxAudibleBehavior to determine what happens when more sounds + are played than are specified with SoundGroup::setMaxAudible. + + [REMARKS] + When using FMOD_SOUNDGROUP_BEHAVIOR_MUTE, SoundGroup::setMuteFadeSpeed can be used to stop a sudden transition. + Instead, the time specified will be used to cross fade between the sounds that go silent and the ones that become audible. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + SoundGroup::setMaxAudibleBehavior + SoundGroup::getMaxAudibleBehavior + SoundGroup::setMaxAudible + SoundGroup::getMaxAudible + SoundGroup::setMuteFadeSpeed + SoundGroup::getMuteFadeSpeed +] +*/ +typedef enum +{ + FMOD_SOUNDGROUP_BEHAVIOR_FAIL, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will simply fail during System::playSound. */ + FMOD_SOUNDGROUP_BEHAVIOR_MUTE, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will be silent, then if another sound in the group stops the sound that was silent before becomes audible again. */ + FMOD_SOUNDGROUP_BEHAVIOR_STEALLOWEST, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will steal the quietest / least important sound playing in the group. */ + + FMOD_SOUNDGROUP_BEHAVIOR_MAX, /* Maximum number of open state types. */ + FMOD_SOUNDGROUP_BEHAVIOR_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUNDGROUP_BEHAVIOR; + + +/* +[ENUM] +[ + [DESCRIPTION] + These callback types are used with Channel::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as int unique to the type of callback.
    + See reference to FMOD_CHANNEL_CALLBACK to determine what they might mean for each type of callback.
    +
    + Note! Currently the user must call System::update for these callbacks to trigger! + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Channel::setCallback + FMOD_CHANNEL_CALLBACK + System::update +] +*/ +typedef enum +{ + FMOD_CHANNEL_CALLBACKTYPE_END, /* Called when a sound ends. */ + FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE, /* Called when a voice is swapped out or swapped in. */ + FMOD_CHANNEL_CALLBACKTYPE_SYNCPOINT, /* Called when a syncpoint is encountered. Can be from wav file markers. */ + FMOD_CHANNEL_CALLBACKTYPE_OCCLUSION, /* Called when the channel has its geometry occlusion value calculated. Can be used to clamp or change the value. */ + + FMOD_CHANNEL_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ + FMOD_CHANNEL_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_CHANNEL_CALLBACKTYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These callback types are used with System::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as void* unique to the type of callback.
    + See reference to FMOD_SYSTEM_CALLBACK to determine what they might mean for each type of callback.
    +
    + Note! Using FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED (on Mac only) requires the application to be running an event loop which will allow external changes to device list to be detected by FMOD. +
    + Note! The 'system' object pointer will be null for FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED callback. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setCallback + FMOD_SYSTEM_CALLBACK + System::update + DSP::addInput +] +*/ +typedef enum +{ + FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED, /* Called from System::update when the enumerated list of devices has changed. */ + FMOD_SYSTEM_CALLBACKTYPE_DEVICELOST, /* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ + FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED, /* Called directly when a memory allocation fails somewhere in FMOD. (NOTE - 'system' will be NULL in this callback type.)*/ + FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED, /* Called directly when a thread is created. */ + FMOD_SYSTEM_CALLBACKTYPE_BADDSPCONNECTION, /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ + FMOD_SYSTEM_CALLBACKTYPE_BADDSPLEVEL, /* Called when too many effects were added exceeding the maximum tree depth of 128. This is most likely caused by accidentally adding too many DSP effects. Usually called from mixer thread because that is where the connections are made. */ + FMOD_SYSTEM_CALLBACKTYPE_THREADDESTROYED, /* Called directly when a thread is destroyed. */ + + FMOD_SYSTEM_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ + FMOD_SYSTEM_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SYSTEM_CALLBACKTYPE; + + +/* + FMOD Callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_SYSTEM_CALLBACK) (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACKTYPE type, void *commanddata1, void *commanddata2); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_CHANNEL_CALLBACK) (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_NONBLOCKCALLBACK)(FMOD_SOUND *sound, FMOD_RESULT result); +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMREADCALLBACK)(FMOD_SOUND *sound, void *data, unsigned int datalen); +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMSETPOSCALLBACK)(FMOD_SOUND *sound, int subsound, unsigned int position, FMOD_TIMEUNIT postype); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_OPENCALLBACK) (const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_CLOSECALLBACK) (void *handle, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_READCALLBACK) (void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_SEEKCALLBACK) (void *handle, unsigned int pos, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_ASYNCREADCALLBACK)(FMOD_ASYNCREADINFO *info, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_ASYNCCANCELCALLBACK)(void *handle, void *userdata); + +typedef void * (F_CALLBACK *FMOD_MEMORY_ALLOCCALLBACK) (unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr); +typedef void * (F_CALLBACK *FMOD_MEMORY_REALLOCCALLBACK)(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr); +typedef void (F_CALLBACK *FMOD_MEMORY_FREECALLBACK) (void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr); + +typedef float (F_CALLBACK *FMOD_3D_ROLLOFFCALLBACK) (FMOD_CHANNEL *channel, float distance); + + +/* +[ENUM] +[ + [DESCRIPTION] + List of windowing methods used in spectrum analysis to reduce leakage / transient signals intefering with the analysis.
    + This is a problem with analysis of continuous signals that only have a small portion of the signal sample (the fft window size).
    + Windowing the signal with a curve or triangle tapers the sides of the fft window to help alleviate this problem. + + [REMARKS] + Cyclic signals such as a sine wave that repeat their cycle in a multiple of the window size do not need windowing.
    + I.e. If the sine wave repeats every 1024, 512, 256 etc samples and the FMOD fft window is 1024, then the signal would not need windowing.
    + Not windowing is the same as FMOD_DSP_FFT_WINDOW_RECT, which is the default.
    + If the cycle of the signal (ie the sine wave) is not a multiple of the window size, it will cause frequency abnormalities, so a different windowing method is needed.
    + +
    + FMOD_DSP_FFT_WINDOW_RECT.
    +
    +
    + FMOD_DSP_FFT_WINDOW_TRIANGLE.
    +
    +
    + FMOD_DSP_FFT_WINDOW_HAMMING.
    +
    +
    + FMOD_DSP_FFT_WINDOW_HANNING.
    +
    +
    + FMOD_DSP_FFT_WINDOW_BLACKMAN.
    +
    +
    + FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS.
    + +
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getSpectrum + Channel::getSpectrum +] +*/ +typedef enum +{ + FMOD_DSP_FFT_WINDOW_RECT, /* w[n] = 1.0 */ + FMOD_DSP_FFT_WINDOW_TRIANGLE, /* w[n] = TRI(2n/N) */ + FMOD_DSP_FFT_WINDOW_HAMMING, /* w[n] = 0.54 - (0.46 * COS(n/N) ) */ + FMOD_DSP_FFT_WINDOW_HANNING, /* w[n] = 0.5 * (1.0 - COS(n/N) ) */ + FMOD_DSP_FFT_WINDOW_BLACKMAN, /* w[n] = 0.42 - (0.5 * COS(n/N) ) + (0.08 * COS(2.0 * n/N) ) */ + FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS, /* w[n] = 0.35875 - (0.48829 * COS(1.0 * n/N)) + (0.14128 * COS(2.0 * n/N)) - (0.01168 * COS(3.0 * n/N)) */ + + FMOD_DSP_FFT_WINDOW_MAX, /* Maximum number of FFT window types supported. */ + FMOD_DSP_FFT_WINDOW_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_FFT_WINDOW; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of interpolation types that the FMOD Ex software mixer supports. + + [REMARKS] + The default resampler type is FMOD_DSP_RESAMPLER_LINEAR.
    + Use System::setSoftwareFormat to tell FMOD the resampling quality you require for FMOD_SOFTWARE based sounds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setSoftwareFormat + System::getSoftwareFormat +] +*/ +typedef enum +{ + FMOD_DSP_RESAMPLER_NOINTERP, /* No interpolation. High frequency aliasing hiss will be audible depending on the sample rate of the sound. */ + FMOD_DSP_RESAMPLER_LINEAR, /* Linear interpolation (default method). Fast and good quality, causes very slight lowpass effect on low frequency sounds. */ + FMOD_DSP_RESAMPLER_CUBIC, /* Cubic interpolation. Slower than linear interpolation but better quality. */ + FMOD_DSP_RESAMPLER_SPLINE, /* 5 point spline interpolation. Slowest resampling method but best quality. */ + + FMOD_DSP_RESAMPLER_MAX, /* Maximum number of resample methods supported. */ + FMOD_DSP_RESAMPLER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_RESAMPLER; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of tag types that could be stored within a sound. These include id3 tags, metadata from netstreams and vorbis/asf data. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef enum +{ + FMOD_TAGTYPE_UNKNOWN = 0, + FMOD_TAGTYPE_ID3V1, + FMOD_TAGTYPE_ID3V2, + FMOD_TAGTYPE_VORBISCOMMENT, + FMOD_TAGTYPE_SHOUTCAST, + FMOD_TAGTYPE_ICECAST, + FMOD_TAGTYPE_ASF, + FMOD_TAGTYPE_MIDI, + FMOD_TAGTYPE_PLAYLIST, + FMOD_TAGTYPE_FMOD, + FMOD_TAGTYPE_USER, + + FMOD_TAGTYPE_MAX, /* Maximum number of tag types supported. */ + FMOD_TAGTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_TAGTYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of data types that can be returned by Sound::getTag + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef enum +{ + FMOD_TAGDATATYPE_BINARY = 0, + FMOD_TAGDATATYPE_INT, + FMOD_TAGDATATYPE_FLOAT, + FMOD_TAGDATATYPE_STRING, + FMOD_TAGDATATYPE_STRING_UTF16, + FMOD_TAGDATATYPE_STRING_UTF16BE, + FMOD_TAGDATATYPE_STRING_UTF8, + FMOD_TAGDATATYPE_CDTOC, + + FMOD_TAGDATATYPE_MAX, /* Maximum number of tag datatypes supported. */ + FMOD_TAGDATATYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_TAGDATATYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Types of delay that can be used with Channel::setDelay / Channel::getDelay. + + [REMARKS] + If you haven't called Channel::setDelay yet, if you call Channel::getDelay with FMOD_DELAYTYPE_DSPCLOCK_START it will return the + equivalent global DSP clock value to determine when a channel started, so that you can use it for other channels to sync against.
    +
    + Use System::getDSPClock to also get the current dspclock time, a base for future calls to Channel::setDelay.
    +
    + Use FMOD_64BIT_ADD or FMOD_64BIT_SUB to add a hi/lo combination together and cope with wraparound. +
    + If FMOD_DELAYTYPE_END_MS is specified, the value is not treated as a 64 bit number, just the delayhi value is used and it is treated as milliseconds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Channel::setDelay + Channel::getDelay + System::getDSPClock +] +*/ +typedef enum +{ + FMOD_DELAYTYPE_END_MS, /* Delay at the end of the sound in milliseconds. Use delayhi only. Channel::isPlaying will remain true until this delay has passed even though the sound itself has stopped playing.*/ + FMOD_DELAYTYPE_DSPCLOCK_START, /* Time the sound started if Channel::getDelay is used, or if Channel::setDelay is used, the sound will delay playing until this exact tick. */ + FMOD_DELAYTYPE_DSPCLOCK_END, /* Time the sound should end. If this is non-zero, the channel will go silent at this exact tick. */ + FMOD_DELAYTYPE_DSPCLOCK_PAUSE, /* Time the sound should pause. If this is non-zero, the channel will pause at this exact tick. */ + + FMOD_DELAYTYPE_MAX, /* Maximum number of tag datatypes supported. */ + FMOD_DELAYTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DELAYTYPE; + + +#define FMOD_64BIT_ADD(_hi1, _lo1, _hi2, _lo2) _hi1 += ((_hi2) + ((((_lo1) + (_lo2)) < (_lo1)) ? 1 : 0)); (_lo1) += (_lo2); +#define FMOD_64BIT_SUB(_hi1, _lo1, _hi2, _lo2) _hi1 -= ((_hi2) + ((((_lo1) - (_lo2)) > (_lo1)) ? 1 : 0)); (_lo1) -= (_lo2); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a piece of tag data. + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag + FMOD_TAGTYPE + FMOD_TAGDATATYPE +] +*/ +typedef struct FMOD_TAG +{ + FMOD_TAGTYPE type; /* [r] The type of this tag. */ + FMOD_TAGDATATYPE datatype; /* [r] The type of data that this tag contains */ + char *name; /* [r] The name of this tag i.e. "TITLE", "ARTIST" etc. */ + void *data; /* [r] Pointer to the tag data - its format is determined by the datatype member */ + unsigned int datalen; /* [r] Length of the data contained in this tag */ + FMOD_BOOL updated; /* [r] True if this tag has been updated since last being accessed with Sound::getTag */ +} FMOD_TAG; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a CD/DVD table of contents + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef struct FMOD_CDTOC +{ + int numtracks; /* [r] The number of tracks on the CD */ + int min[100]; /* [r] The start offset of each track in minutes */ + int sec[100]; /* [r] The start offset of each track in seconds */ + int frame[100]; /* [r] The start offset of each track in frames */ +} FMOD_CDTOC; + + +/* +[DEFINE] +[ + [NAME] + FMOD_TIMEUNIT + + [DESCRIPTION] + List of time types that can be returned by Sound::getLength and used with Channel::setPosition or Channel::getPosition. + + [REMARKS] + FMOD_TIMEUNIT_SENTENCE_MS, FMOD_TIMEUNIT_SENTENCE_PCM, FMOD_TIMEUNIT_SENTENCE_PCMBYTES, FMOD_TIMEUNIT_SENTENCE and FMOD_TIMEUNIT_SENTENCE_SUBSOUND are only supported by Channel functions. + Do not combine flags except FMOD_TIMEUNIT_BUFFERED. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getLength + Channel::setPosition + Channel::getPosition +] +*/ +#define FMOD_TIMEUNIT_MS 0x00000001 /* Milliseconds. */ +#define FMOD_TIMEUNIT_PCM 0x00000002 /* PCM samples, related to milliseconds * samplerate / 1000. */ +#define FMOD_TIMEUNIT_PCMBYTES 0x00000004 /* Bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ +#define FMOD_TIMEUNIT_RAWBYTES 0x00000008 /* Raw file bytes of (compressed) sound data (does not include headers). Only used by Sound::getLength and Channel::getPosition. */ +#define FMOD_TIMEUNIT_PCMFRACTION 0x00000010 /* Fractions of 1 PCM sample. Unsigned int range 0 to 0xFFFFFFFF. Used for sub-sample granularity for DSP purposes. */ +#define FMOD_TIMEUNIT_MODORDER 0x00000100 /* MOD/S3M/XM/IT. Order in a sequenced module format. Use Sound::getFormat to determine the PCM format being decoded to. */ +#define FMOD_TIMEUNIT_MODROW 0x00000200 /* MOD/S3M/XM/IT. Current row in a sequenced module format. Sound::getLength will return the number of rows in the currently playing or seeked to pattern. */ +#define FMOD_TIMEUNIT_MODPATTERN 0x00000400 /* MOD/S3M/XM/IT. Current pattern in a sequenced module format. Sound::getLength will return the number of patterns in the song and Channel::getPosition will return the currently playing pattern. */ +#define FMOD_TIMEUNIT_SENTENCE_MS 0x00010000 /* Currently playing subsound in a sentence time in milliseconds. */ +#define FMOD_TIMEUNIT_SENTENCE_PCM 0x00020000 /* Currently playing subsound in a sentence time in PCM Samples, related to milliseconds * samplerate / 1000. */ +#define FMOD_TIMEUNIT_SENTENCE_PCMBYTES 0x00040000 /* Currently playing subsound in a sentence time in bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ +#define FMOD_TIMEUNIT_SENTENCE 0x00080000 /* Currently playing sentence index according to the channel. */ +#define FMOD_TIMEUNIT_SENTENCE_SUBSOUND 0x00100000 /* Currently playing subsound index in a sentence. */ +#define FMOD_TIMEUNIT_BUFFERED 0x10000000 /* Time value as seen by buffered stream. This is always ahead of audible time, and is only used for processing. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + When creating a multichannel sound, FMOD will pan them to their default speaker locations, for example a 6 channel sound will default to one channel per 5.1 output speaker.
    + Another example is a stereo sound. It will default to left = front left, right = front right.
    +
    + This is for sounds that are not 'default'. For example you might have a sound that is 6 channels but actually made up of 3 stereo pairs, that should all be located in front left, front right only. + + [REMARKS] + For full flexibility of speaker assignments, use Channel::setSpeakerLevels. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_CREATESOUNDEXINFO + Channel::setSpeakerLevels +] +*/ +typedef enum +{ + FMOD_SPEAKERMAPTYPE_DEFAULT, /* This is the default, and just means FMOD decides which speakers it puts the source channels. */ + FMOD_SPEAKERMAPTYPE_ALLMONO, /* This means the sound is made up of all mono sounds. All voices will be panned to the front center by default in this case. */ + FMOD_SPEAKERMAPTYPE_ALLSTEREO, /* This means the sound is made up of all stereo sounds. All voices will be panned to front left and front right alternating every second channel. */ + FMOD_SPEAKERMAPTYPE_51_PROTOOLS /* Map a 5.1 sound to use protools L C R Ls Rs LFE mapping. Will return an error if not a 6 channel sound. */ +} FMOD_SPEAKERMAPTYPE; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Use this structure with System::createSound when more control is needed over loading.
    + The possible reasons to use this with System::createSound are:
    +
  • Loading a file from memory. +
  • Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. +
  • To create a user created / non file based sound. +
  • To specify a starting subsound to seek to within a multi-sample sounds (ie FSB/DLS/SF2) when created as a stream. +
  • To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. +
  • To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. +
  • To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + See below on what members to fill for each of the above types of sound you want to create. + + [REMARKS] + This structure is optional! Specify 0 or NULL in System::createSound if you don't need it!
    +
    + Loading a file from memory.
    +
  • Create the sound using the FMOD_OPENMEMORY flag.
    +
  • Mandatory. Specify 'length' for the size of the memory block in bytes. +
  • Other flags are optional. +
    +
    + Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length.
    +
  • Mandatory. Specify 'fileoffset' and 'length'. +
  • Other flags are optional. +
    +
    + To create a user created / non file based sound.
    +
  • Create the sound using the FMOD_OPENUSER flag. +
  • Mandatory. Specify 'defaultfrequency, 'numchannels' and 'format'. +
  • Other flags are optional. +
    +
    + To specify a starting subsound to seek to and flush with, within a multi-sample stream (ie FSB/DLS/SF2).
    +
    +
  • Mandatory. Specify 'initialsubsound'. +
    +
    + To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk.
    +
    +
  • Mandatory. Specify 'inclusionlist' and 'inclusionlistnum'. +
    +
    + To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played.
    +
    +
  • Mandatory. Specify 'pcmreadcallback' and 'pcmseekcallback'. +
    +
    + To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file.
    +
    +
  • Mandatory. Specify 'dlsname'. +
    +
    + Setting the 'decodebuffersize' is for cpu intensive codecs that may be causing stuttering, not file intensive codecs (ie those from CD or netstreams) which are normally + altered with System::setStreamBufferSize. As an example of cpu intensive codecs, an mp3 file will take more cpu to decode than a PCM wav file.
    + If you have a stuttering effect, then it is using more cpu than the decode buffer playback rate can keep up with. Increasing the decode buffersize will most likely solve this problem.
    +
    +
    + FSB codec. If inclusionlist and numsubsounds are used together, this will trigger a special mode where subsounds are shuffled down to save memory. (useful for large FSB + files where you only want to load 1 sound). There will be no gaps, ie no null subsounds. As an example, if there are 10,000 subsounds and there is an inclusionlist with only 1 entry, + and numsubsounds = 1, then subsound 0 will be that entry, and there will only be the memory allocated for 1 subsound. Previously there would still be 10,000 subsound pointers and other + associated codec entries allocated along with it multiplied by 10,000.
    +
    + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createSound + System::setStreamBufferSize + FMOD_MODE + FMOD_SOUND_FORMAT + FMOD_SOUND_TYPE + FMOD_SPEAKERMAPTYPE +] +*/ +typedef struct FMOD_CREATESOUNDEXINFO +{ + int cbsize; /* [w] Size of this structure. This is used so the structure can be expanded in the future and still work on older versions of FMOD Ex. */ + unsigned int length; /* [w] Optional. Specify 0 to ignore. Size in bytes of file to load, or sound to create (in this case only if FMOD_OPENUSER is used). Required if loading from memory. If 0 is specified, then it will use the size of the file (unless loading from memory then an error will be returned). */ + unsigned int fileoffset; /* [w] Optional. Specify 0 to ignore. Offset from start of the file to start loading from. This is useful for loading files from inside big data files. */ + int numchannels; /* [w] Optional. Specify 0 to ignore. Number of channels in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. */ + int defaultfrequency; /* [w] Optional. Specify 0 to ignore. Default frequency of sound in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the frequency determined by the file format. */ + FMOD_SOUND_FORMAT format; /* [w] Optional. Specify 0 or FMOD_SOUND_FORMAT_NONE to ignore. Format of the sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the format determined by the file format. */ + unsigned int decodebuffersize; /* [w] Optional. Specify 0 to ignore. For streams. This determines the size of the double buffer (in PCM samples) that a stream uses. Use this for user created streams if you want to determine the size of the callback buffer passed to you. Specify 0 to use FMOD's default size which is currently equivalent to 400ms of the sound format created/loaded. */ + int initialsubsound; /* [w] Optional. Specify 0 to ignore. In a multi-sample file format such as .FSB/.DLS/.SF2, specify the initial subsound to seek to, only if FMOD_CREATESTREAM is used. */ + int numsubsounds; /* [w] Optional. Specify 0 to ignore or have no subsounds. In a sound created with FMOD_OPENUSER, specify the number of subsounds that are accessable with Sound::getSubSound. If not created with FMOD_OPENUSER, this will limit the number of subsounds loaded within a multi-subsound file. If using FSB, then if FMOD_CREATESOUNDEXINFO::inclusionlist is used, this will shuffle subsounds down so that there are not any gaps. It will mean that the indices of the sounds will be different. */ + int *inclusionlist; /* [w] Optional. Specify 0 to ignore. In a multi-sample format such as .FSB/.DLS/.SF2 it may be desirable to specify only a subset of sounds to be loaded out of the whole file. This is an array of subsound indices to load into memory when created. */ + int inclusionlistnum; /* [w] Optional. Specify 0 to ignore. This is the number of integers contained within the inclusionlist array. */ + FMOD_SOUND_PCMREADCALLBACK pcmreadcallback; /* [w] Optional. Specify 0 to ignore. Callback to 'piggyback' on FMOD's read functions and accept or even write PCM data while FMOD is opening the sound. Used for user sounds created with FMOD_OPENUSER or for capturing decoded data as FMOD reads it. */ + FMOD_SOUND_PCMSETPOSCALLBACK pcmsetposcallback; /* [w] Optional. Specify 0 to ignore. Callback for when the user calls a seeking function such as Channel::setTime or Channel::setPosition within a multi-sample sound, and for when it is opened.*/ + FMOD_SOUND_NONBLOCKCALLBACK nonblockcallback; /* [w] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag. Also called duing seeking, when setPosition is called or a stream is restarted. */ + const char *dlsname; /* [w] Optional. Specify 0 to ignore. Filename for a DLS or SF2 sample set when loading a MIDI file. If not specified, on Windows it will attempt to open /windows/system32/drivers/gm.dls or /windows/system32/drivers/etc/gm.dls, on Mac it will attempt to load /System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls, otherwise the MIDI will fail to open. Current DLS support is for level 1 of the specification. */ + const char *encryptionkey; /* [w] Optional. Specify 0 to ignore. Key for encrypted FSB file. Without this key an encrypted FSB file will not load. */ + int maxpolyphony; /* [w] Optional. Specify 0 to ignore. For sequenced formats with dynamic channel allocation such as .MID and .IT, this specifies the maximum voice count allowed while playing. .IT defaults to 64. .MID defaults to 32. */ + void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the sound during creation. Access via Sound::getUserData. Note: This is not passed to FMOD_FILE_OPENCALLBACK, that is a different userdata that is file specific. */ + FMOD_SOUND_TYPE suggestedsoundtype; /* [w] Optional. Specify 0 or FMOD_SOUND_TYPE_UNKNOWN to ignore. Instead of scanning all codec types, use this to speed up loading by making it jump straight to this codec. */ + FMOD_FILE_OPENCALLBACK useropen; /* [w] Optional. Specify 0 to ignore. Callback for opening this file. */ + FMOD_FILE_CLOSECALLBACK userclose; /* [w] Optional. Specify 0 to ignore. Callback for closing this file. */ + FMOD_FILE_READCALLBACK userread; /* [w] Optional. Specify 0 to ignore. Callback for reading from this file. */ + FMOD_FILE_SEEKCALLBACK userseek; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_FILE_ASYNCREADCALLBACK userasyncread; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_SPEAKERMAPTYPE speakermap; /* [w] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_SPEAKERMAPTYPE for more. */ + FMOD_SOUNDGROUP *initialsoundgroup; /* [w] Optional. Specify 0 to ignore. Specify a sound group if required, to put sound in as it is created. */ + unsigned int initialseekposition;/* [w] Optional. Specify 0 to ignore. For streams. Specify an initial position to seek the stream to. */ + FMOD_TIMEUNIT initialseekpostype; /* [w] Optional. Specify 0 to ignore. For streams. Specify the time unit for the position set in initialseekposition. */ + int ignoresetfilesystem;/* [w] Optional. Specify 0 to ignore. Set to 1 to use fmod's built in file system. Ignores setFileSystem callbacks and also FMOD_CREATESOUNEXINFO file callbacks. Useful for specific cases where you don't want to use your own file system but want to use fmod's file system (ie net streaming). */ + int cddaforceaspi; /* [w] Optional. Specify 0 to ignore. For CDDA sounds only - if non-zero use ASPI instead of NTSCSI to access the specified CD/DVD device. */ + unsigned int audioqueuepolicy; /* [w] Optional. Specify 0 or FMOD_AUDIOQUEUE_CODECPOLICY_DEFAULT to ignore. Policy used to determine whether hardware or software is used for decoding, see FMOD_AUDIOQUEUE_CODECPOLICY for options (iOS >= 3.0 required, otherwise only hardware is available) */ + unsigned int minmidigranularity; /* [w] Optional. Specify 0 to ignore. Allows you to set a minimum desired MIDI mixer granularity. Values smaller than 512 give greater than default accuracy at the cost of more CPU and vice versa. Specify 0 for default (512 samples). */ + int nonblockthreadid; /* [w] Optional. Specify 0 to ignore. Specifies a thread index to execute non blocking load on. Allows for up to 5 threads to be used for loading at once. This is to avoid one load blocking another. Maximum value = 4. */ +} FMOD_CREATESOUNDEXINFO; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a reverb environment.
    + + [REMARKS] + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset.
    + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are always linear.
    +
    + The numerical values listed below are the maximum, minimum and default values for each variable respectively.
    +
    + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't.
    + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE).
    + PSP means Playstation Portable hardware reverb (must use FMOD_HARDWARE).
    + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds.
    + --- means unsupported/deprecated. Will either be removed or supported by SFX in the future. +
    + Nintendo Wii Notes:
    + This structure supports only limited parameters, and maps them to the Wii hardware reverb as follows.
    + DecayTime = 'time'
    + ReverbDelay = 'predelay'
    + ModulationDepth = 'damping'
    + Reflections = 'coloration'
    + EnvDiffusion = 'crosstalk'
    + Room = 'mix'
    +
    + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + Members marked with [r/w] are either read or write depending on if you are using System::setReverbProperties (w) or System::getReverbProperties (r). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setReverbProperties + System::getReverbProperties + FMOD_REVERB_PRESETS + FMOD_REVERB_FLAGS +] +*/ +typedef struct FMOD_REVERB_PROPERTIES +{ /* MIN MAX DEFAULT DESCRIPTION */ + int Instance; /* [w] 0 3 0 Environment Instance. (SUPPORTED:SFX(4 instances) and Wii (3 instances)) */ + int Environment; /* [r/w] -1 25 -1 Sets all listener properties. -1 = OFF. (SUPPORTED:SFX(-1 only)/PSP) */ + float EnvDiffusion; /* [r/w] 0.0 1.0 1.0 Environment diffusion (SUPPORTED:WII) */ + int Room; /* [r/w] -10000 0 -1000 Room effect level (at mid frequencies) (SUPPORTED:SFX/WII/PSP) */ + int RoomHF; /* [r/w] -10000 0 -100 Relative room effect level at high frequencies (SUPPORTED:SFX) */ + int RoomLF; /* [r/w] -10000 0 0 Relative room effect level at low frequencies (SUPPORTED:SFX) */ + float DecayTime; /* [r/w] 0.1 20.0 1.49 Reverberation decay time at mid frequencies (SUPPORTED:SFX/WII) */ + float DecayHFRatio; /* [r/w] 0.1 2.0 0.83 High-frequency to mid-frequency decay time ratio (SUPPORTED:SFX) */ + float DecayLFRatio; /* [r/w] 0.1 2.0 1.0 Low-frequency to mid-frequency decay time ratio (SUPPORTED:---) */ + int Reflections; /* [r/w] -10000 1000 -2602 Early reflections level relative to room effect (SUPPORTED:SFX/WII) */ + float ReflectionsDelay; /* [r/w] 0.0 0.3 0.007 Initial reflection delay time (SUPPORTED:SFX) */ + int Reverb; /* [r/w] -10000 2000 200 Late reverberation level relative to room effect (SUPPORTED:SFX) */ + float ReverbDelay; /* [r/w] 0.0 0.1 0.011 Late reverberation delay time relative to initial reflection (SUPPORTED:SFX/WII) */ + float ModulationTime; /* [r/w] 0.04 4.0 0.25 Modulation time (SUPPORTED:---) */ + float ModulationDepth; /* [r/w] 0.0 1.0 0.0 Modulation depth (SUPPORTED:WII) */ + float HFReference; /* [r/w] 20.0 20000.0 5000.0 Reference high frequency (hz) (SUPPORTED:SFX) */ + float LFReference; /* [r/w] 20.0 1000.0 250.0 Reference low frequency (hz) (SUPPORTED:SFX) */ + float Diffusion; /* [r/w] 0.0 100.0 100.0 Value that controls the echo density in the late reverberation decay. (SUPPORTED:SFX) */ + float Density; /* [r/w] 0.0 100.0 100.0 Value that controls the modal density in the late reverberation decay (SUPPORTED:SFX) */ + unsigned int Flags; /* [r/w] FMOD_REVERB_FLAGS - modifies the behavior of above properties (SUPPORTED:WII) */ +} FMOD_REVERB_PROPERTIES; + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the FMOD_REVERB_PROPERTIES structure. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_REVERB_PROPERTIES +] +*/ +#define FMOD_REVERB_FLAGS_HIGHQUALITYREVERB 0x00000400 /* Wii. Use high quality reverb */ +#define FMOD_REVERB_FLAGS_HIGHQUALITYDPL2REVERB 0x00000800 /* Wii. Use high quality DPL2 reverb */ +#define FMOD_REVERB_FLAGS_HARDWAREONLY 0x00001000 /* Don't create an SFX reverb for FMOD_SOFTWARE channels, hardware reverb only */ +#define FMOD_REVERB_FLAGS_DEFAULT 0x00000000 +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS.
    + These are used to initialize an FMOD_REVERB_PROPERTIES structure statically.
    + i.e.
    + FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_GENERIC; + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setReverbProperties +] +*/ +/* Inst Env Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel Revb RevDel ModTm ModDp HFRef LFRef Diffus Densty FLAGS */ +#define FMOD_PRESET_OFF { 0, -1, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 0.0f, 0.0f, 0x33f } +#define FMOD_PRESET_GENERIC { 0, 0, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PADDEDCELL { 0, 1, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, 207, 0.002f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_ROOM { 0, 2, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, 53, 0.003f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_BATHROOM { 0, 3, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, 1030, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 60.0f, 0x3f } +#define FMOD_PRESET_LIVINGROOM { 0, 4, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, -1104, 0.004f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_STONEROOM { 0, 5, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, 83, 0.017f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_AUDITORIUM { 0, 6, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, -289, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CONCERTHALL { 0, 7, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, -2, 0.029f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CAVE { 0, 8, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, -302, 0.022f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_ARENA { 0, 9, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, 16, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_HANGAR { 0, 10, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, 198, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CARPETTEDHALLWAY { 0, 11, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, -1630, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_HALLWAY { 0, 12, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, 441, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_STONECORRIDOR { 0, 13, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, 395, 0.020f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_ALLEY { 0, 14, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, -4, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_FOREST { 0, 15, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, -229, 0.088f, 0.25f, 0.000f, 5000.0f, 250.0f, 79.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CITY { 0, 16, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, -1691, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 50.0f, 100.0f, 0x3f } +#define FMOD_PRESET_MOUNTAINS { 0, 17, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, -1434, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 27.0f, 100.0f, 0x1f } +#define FMOD_PRESET_QUARRY { 0, 18, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, 500, 0.025f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PLAIN { 0, 19, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, -1926, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 21.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PARKINGLOT { 0, 20, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, -1153, 0.012f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_SEWERPIPE { 0, 21, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, 1023, 0.021f, 0.25f, 0.000f, 5000.0f, 250.0f, 80.0f, 60.0f, 0x3f } +#define FMOD_PRESET_UNDERWATER { 0, 22, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, 1700, 0.011f, 1.18f, 0.348f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } + +/* PlayStation Portable Only presets */ +#define FMOD_PRESET_PSP_ROOM { 0, 1, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_STUDIO_A { 0, 2, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_STUDIO_B { 0, 3, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_STUDIO_C { 0, 4, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_HALL { 0, 5, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_SPACE { 0, 6, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_ECHO { 0, 7, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_DELAY { 0, 8, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_PIPE { 0, 9, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FMOD channel.
    +
    + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset.
    + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
    + PORTABILITY: Each member has the platform it supports in braces ie (win32/wii).
    +
    + The numerical values listed below are the maximum, minimum and default values for each variable respectively.
    + + [REMARKS] + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't.
    + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE).
    + PSP means Playstation Portable hardware reverb (must use FMOD_HARDWARE).
    + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds.
    + --- means unsupported/deprecated. Will either be removed or supported by SFX in the future. +
    +
    + 'ConnectionPoint' Parameter. This parameter is for the FMOD software reverb only (known as SFX in the list above).
    + By default the dsp network connection for a channel and its reverb is between the 'SFX Reverb' unit, and the channel's wavetable/resampler/dspcodec/oscillator unit (the unit below the channel DSP head). NULL can be used for this parameter to make it use this default behaviour.
    + This parameter allows the user to connect the SFX reverb to somewhere else internally, for example the channel DSP head, or a related channelgroup. The event system uses this so that it can have the output of an event going to the reverb, instead of just the output of the event's channels (thereby ignoring event effects/submixes etc).
    + Do not use if you are unaware of DSP network connection issues. Leave it at the default of NULL instead.
    +
    + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + Members marked with [r/w] are either read or write depending on if you are using Channel::setReverbProperties (w) or Channel::getReverbProperties (r). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Channel::setReverbProperties + Channel::getReverbProperties + FMOD_REVERB_CHANNELFLAGS +] +*/ +typedef struct FMOD_REVERB_CHANNELPROPERTIES +{ /* MIN MAX DEFAULT DESCRIPTION */ + int Direct; /* [r/w] -10000 1000 0 Direct path level (SUPPORTED:SFX) */ + int Room; /* [r/w] -10000 1000 0 Room effect level (SUPPORTED:SFX) */ + unsigned int Flags; /* [r/w] FMOD_REVERB_CHANNELFLAGS - modifies the behavior of properties (SUPPORTED:SFX) */ + FMOD_DSP *ConnectionPoint; /* [r/w] See remarks. DSP network location to connect reverb for this channel. (SUPPORTED:SFX).*/ +} FMOD_REVERB_CHANNELPROPERTIES; + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the FMOD_REVERB_CHANNELPROPERTIES structure. + + [REMARKS] + For SFX Reverb, there is support for multiple reverb environments.
    + Use FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT0 to FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT3 in the flags member + of FMOD_REVERB_CHANNELPROPERTIES to specify which environment instance(s) to target.
    + - If you do not specify any instance the first reverb instance will be used.
    + - If you specify more than one instance with getReverbProperties, the first instance will be used.
    + - If you specify more than one instance with setReverbProperties, it will set more than 1 instance at once.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_REVERB_CHANNELPROPERTIES +] +*/ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE0 0x00000010 /* SFX/Wii. Specify channel to target reverb instance 0. Default target. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE1 0x00000020 /* SFX/Wii. Specify channel to target reverb instance 1. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE2 0x00000040 /* SFX/Wii. Specify channel to target reverb instance 2. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE3 0x00000080 /* SFX. Specify channel to target reverb instance 3. */ + +#define FMOD_REVERB_CHANNELFLAGS_DEFAULT FMOD_REVERB_CHANNELFLAGS_INSTANCE0 +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Settings for advanced features like configuring memory and cpu usage for the FMOD_CREATECOMPRESSEDSAMPLE feature. + + [REMARKS] + maxMPEGcodecs / maxADPCMcodecs / maxXMAcodecs will determine the maximum cpu usage of playing realtime samples. Use this to lower potential excess cpu usage and also control memory usage.
    +
    + maxPCMcodecs is for use with PS3 only. It will determine the maximum number of PCM voices that can be played at once. This includes streams of any format and all sounds created + *without* the FMOD_CREATECOMPRESSEDSAMPLE flag. +
    + Memory will be allocated for codecs 'up front' (during System::init) if these values are specified as non zero. If any are zero, it allocates memory for the codec whenever a file of the type in question is loaded. So if maxMPEGcodecs is 0 for example, it will allocate memory for the mpeg codecs the first time an mp3 is loaded or an mp3 based .FSB file is loaded.
    +
    + Due to inefficient encoding techniques on certain .wav based ADPCM files, FMOD can can need an extra 29720 bytes per codec. This means for lowest memory consumption. Use FSB as it uses an optimal/small ADPCM block size.
    +
    + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + Members marked with [r/w] are either read or write depending on if you are using System::setAdvancedSettings (w) or System::getAdvancedSettings (r). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setAdvancedSettings + System::getAdvancedSettings + System::init + FMOD_MODE +] +*/ +typedef struct FMOD_ADVANCEDSETTINGS +{ + int cbsize; /* [w] Size of this structure. Use sizeof(FMOD_ADVANCEDSETTINGS) NOTE: This must be set before calling System::getAdvancedSettings! */ + int maxMPEGcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Mpeg codecs consume 21,684 bytes per instance and this number will determine how many mpeg channels can be played simultaneously. Default = 32. */ + int maxADPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. ADPCM codecs consume 2,136 bytes per instance and this number will determine how many ADPCM channels can be played simultaneously. Default = 32. */ + int maxXMAcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. XMA codecs consume 14,836 bytes per instance and this number will determine how many XMA channels can be played simultaneously. Default = 32. */ + int maxCELTcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. CELT codecs consume 11,500 bytes per instance and this number will determine how many CELT channels can be played simultaneously. Default = 32. */ + int maxVORBIScodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Vorbis codecs consume 12,000 bytes per instance and this number will determine how many Vorbis channels can be played simultaneously. Default = 32. */ + int maxAT9Codecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. AT9 codecs consume 8,720 bytes per instance and this number will determine how many AT9 channels can be played simultaneously. Default = 32. */ + int maxPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with PS3 only. PCM codecs consume 12,672 bytes per instance and this number will determine how many streams and PCM voices can be played simultaneously. Default = 16. */ + int ASIONumChannels; /* [r/w] Optional. Specify 0 to ignore. Number of channels available on the ASIO device. */ + char **ASIOChannelList; /* [r/w] Optional. Specify 0 to ignore. Pointer to an array of strings (number of entries defined by ASIONumChannels) with ASIO channel names. */ + FMOD_SPEAKER *ASIOSpeakerList; /* [r/w] Optional. Specify 0 to ignore. Pointer to a list of speakers that the ASIO channels map to. This can be called after System::init to remap ASIO output. */ + int max3DReverbDSPs; /* [r/w] Optional. Specify 0 to ignore. The max number of 3d reverb DSP's in the system. (NOTE: CURRENTLY DISABLED / UNUSED) */ + float HRTFMinAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function begins to have an effect. 0 = in front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 180.0. */ + float HRTFMaxAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function has maximum effect. 0 = front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 360.0. */ + float HRTFFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_HRTF_LOWPASS. The cutoff frequency of the HRTF's lowpass filter function when at maximum effect. (i.e. at HRTFMaxAngle). Default = 4000.0. */ + float vol0virtualvol; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_VOL0_BECOMES_VIRTUAL. If this flag is used, and the volume is 0.0, then the sound will become virtual. Use this value to raise the threshold to a different point where a sound goes virtual. */ + int eventqueuesize; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD Event system only. Specifies the number of slots available for simultaneous non blocking loads, across all threads. Default = 32. */ + unsigned int defaultDecodeBufferSize; /* [r/w] Optional. Specify 0 to ignore. For streams. This determines the default size of the double buffer (in milliseconds) that a stream uses. Default = 400ms */ + char *debugLogFilename; /* [r/w] Optional. Specify 0 to ignore. Gives fmod's logging system a path/filename. Normally the log is placed in the same directory as the executable and called fmod.log. When using System::getAdvancedSettings, provide at least 256 bytes of memory to copy into. */ + unsigned short profileport; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_ENABLE_PROFILE. Specify the port to listen on for connections by the profiler application. */ + unsigned int geometryMaxFadeTime; /* [r/w] Optional. Specify 0 to ignore. The maximum time in miliseconds it takes for a channel to fade to the new level when its occlusion changes. */ + unsigned int maxSpectrumWaveDataBuffers; /* [r/w] Optional. Specify 0 to ignore. Tells System::init to allocate a pool of wavedata/spectrum buffers to prevent memory fragmentation, any additional buffers will be allocated normally. */ + unsigned int musicSystemCacheDelay; /* [r/w] Optional. Specify 0 to ignore. The delay the music system should allow for loading a sample from disk (in milliseconds). Default = 400 ms. */ + float distanceFilterCenterFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_DISTANCE_FILTERING. The default center frequency in Hz for the distance filtering effect. Default = 1500.0. */ + unsigned int stackSizeStream; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD Stream thread in bytes. Useful for custom codecs that use excess stack. Default 49,152 (48kb) */ + unsigned int stackSizeNonBlocking; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD_NONBLOCKING loading thread. Useful for custom codecs that use excess stack. Default 65,536 (64kb) */ + unsigned int stackSizeMixer; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD mixer thread. Useful for custom dsps that use excess stack. Default 49,152 (48kb) */ +} FMOD_ADVANCEDSETTINGS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Special channel index values for FMOD functions. + + [REMARKS] + To get 'all' of the channels, use System::getMasterChannelGroup. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::playSound + System::playDSP + System::getChannel + System::getMasterChannelGroup +] +*/ +typedef enum +{ + FMOD_CHANNEL_FREE = -1, /* For a channel index, FMOD chooses a free voice using the priority system. */ + FMOD_CHANNEL_REUSE = -2 /* For a channel index, re-use the channel handle that was passed in. */ +} FMOD_CHANNELINDEX; + +#include "fmod_codec.h" +#include "fmod_dsp.h" +#include "fmod_memoryinfo.h" + +/* ========================================================================================== */ +/* FUNCTION PROTOTYPES */ +/* ========================================================================================== */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + FMOD global system functions (optional). +*/ + +FMOD_RESULT F_API FMOD_Memory_Initialize (void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags); +FMOD_RESULT F_API FMOD_Memory_GetStats (int *currentalloced, int *maxalloced, FMOD_BOOL blocking); +FMOD_RESULT F_API FMOD_Debug_SetLevel (FMOD_DEBUGLEVEL level); +FMOD_RESULT F_API FMOD_Debug_GetLevel (FMOD_DEBUGLEVEL *level); +FMOD_RESULT F_API FMOD_File_SetDiskBusy (int busy); +FMOD_RESULT F_API FMOD_File_GetDiskBusy (int *busy); + +/* + FMOD System factory functions. Use this to create an FMOD System Instance. below you will see FMOD_System_Init/Close to get started. +*/ + +FMOD_RESULT F_API FMOD_System_Create (FMOD_SYSTEM **system); +FMOD_RESULT F_API FMOD_System_Release (FMOD_SYSTEM *system); + +/*$ preserve end $*/ + +/* + 'System' API +*/ + +/* + Pre-init functions. +*/ + +FMOD_RESULT F_API FMOD_System_SetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE output); +FMOD_RESULT F_API FMOD_System_GetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE *output); +FMOD_RESULT F_API FMOD_System_GetNumDrivers (FMOD_SYSTEM *system, int *numdrivers); +FMOD_RESULT F_API FMOD_System_GetDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *controlpaneloutputrate, FMOD_SPEAKERMODE *controlpanelspeakermode); +FMOD_RESULT F_API FMOD_System_SetDriver (FMOD_SYSTEM *system, int driver); +FMOD_RESULT F_API FMOD_System_GetDriver (FMOD_SYSTEM *system, int *driver); +FMOD_RESULT F_API FMOD_System_SetHardwareChannels (FMOD_SYSTEM *system, int numhardwarechannels); +FMOD_RESULT F_API FMOD_System_SetSoftwareChannels (FMOD_SYSTEM *system, int numsoftwarechannels); +FMOD_RESULT F_API FMOD_System_GetSoftwareChannels (FMOD_SYSTEM *system, int *numsoftwarechannels); +FMOD_RESULT F_API FMOD_System_SetSoftwareFormat (FMOD_SYSTEM *system, int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); +FMOD_RESULT F_API FMOD_System_GetSoftwareFormat (FMOD_SYSTEM *system, int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); +FMOD_RESULT F_API FMOD_System_SetDSPBufferSize (FMOD_SYSTEM *system, unsigned int bufferlength, int numbuffers); +FMOD_RESULT F_API FMOD_System_GetDSPBufferSize (FMOD_SYSTEM *system, unsigned int *bufferlength, int *numbuffers); +FMOD_RESULT F_API FMOD_System_SetFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, FMOD_FILE_ASYNCREADCALLBACK userasyncread, FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign); +FMOD_RESULT F_API FMOD_System_AttachFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); +FMOD_RESULT F_API FMOD_System_SetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); +FMOD_RESULT F_API FMOD_System_GetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); +FMOD_RESULT F_API FMOD_System_SetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE speakermode); +FMOD_RESULT F_API FMOD_System_GetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE *speakermode); +FMOD_RESULT F_API FMOD_System_SetCallback (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK callback); + +/* + Plug-in support +*/ + +FMOD_RESULT F_API FMOD_System_SetPluginPath (FMOD_SYSTEM *system, const char *path); +FMOD_RESULT F_API FMOD_System_LoadPlugin (FMOD_SYSTEM *system, const char *filename, unsigned int *handle, unsigned int priority); +FMOD_RESULT F_API FMOD_System_UnloadPlugin (FMOD_SYSTEM *system, unsigned int handle); +FMOD_RESULT F_API FMOD_System_GetNumPlugins (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int *numplugins); +FMOD_RESULT F_API FMOD_System_GetPluginHandle (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); +FMOD_RESULT F_API FMOD_System_GetPluginInfo (FMOD_SYSTEM *system, unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); +FMOD_RESULT F_API FMOD_System_SetOutputByPlugin (FMOD_SYSTEM *system, unsigned int handle); +FMOD_RESULT F_API FMOD_System_GetOutputByPlugin (FMOD_SYSTEM *system, unsigned int *handle); +FMOD_RESULT F_API FMOD_System_CreateDSPByPlugin (FMOD_SYSTEM *system, unsigned int handle, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_RegisterCodec (FMOD_SYSTEM *system, FMOD_CODEC_DESCRIPTION *description, unsigned int *handle, unsigned int priority); +FMOD_RESULT F_API FMOD_System_RegisterDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, unsigned int *handle); + +/* + Init/Close +*/ + +FMOD_RESULT F_API FMOD_System_Init (FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); +FMOD_RESULT F_API FMOD_System_Close (FMOD_SYSTEM *system); + +/* + General post-init system functions +*/ + +FMOD_RESULT F_API FMOD_System_Update (FMOD_SYSTEM *system); + +FMOD_RESULT F_API FMOD_System_Set3DSettings (FMOD_SYSTEM *system, float dopplerscale, float distancefactor, float rolloffscale); +FMOD_RESULT F_API FMOD_System_Get3DSettings (FMOD_SYSTEM *system, float *dopplerscale, float *distancefactor, float *rolloffscale); +FMOD_RESULT F_API FMOD_System_Set3DNumListeners (FMOD_SYSTEM *system, int numlisteners); +FMOD_RESULT F_API FMOD_System_Get3DNumListeners (FMOD_SYSTEM *system, int *numlisteners); +FMOD_RESULT F_API FMOD_System_Set3DListenerAttributes(FMOD_SYSTEM *system, int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_System_Get3DListenerAttributes(FMOD_SYSTEM *system, int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_System_Set3DRolloffCallback (FMOD_SYSTEM *system, FMOD_3D_ROLLOFFCALLBACK callback); +FMOD_RESULT F_API FMOD_System_Set3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float x, float y, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_System_Get3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float *x, float *y, FMOD_BOOL *active); + +FMOD_RESULT F_API FMOD_System_SetStreamBufferSize (FMOD_SYSTEM *system, unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); +FMOD_RESULT F_API FMOD_System_GetStreamBufferSize (FMOD_SYSTEM *system, unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); + +/* + System information functions. +*/ + +FMOD_RESULT F_API FMOD_System_GetVersion (FMOD_SYSTEM *system, unsigned int *version); +FMOD_RESULT F_API FMOD_System_GetOutputHandle (FMOD_SYSTEM *system, void **handle); +FMOD_RESULT F_API FMOD_System_GetChannelsPlaying (FMOD_SYSTEM *system, int *channels); +FMOD_RESULT F_API FMOD_System_GetHardwareChannels (FMOD_SYSTEM *system, int *numhardwarechannels); +FMOD_RESULT F_API FMOD_System_GetCPUUsage (FMOD_SYSTEM *system, float *dsp, float *stream, float *geometry, float *update, float *total); +FMOD_RESULT F_API FMOD_System_GetSoundRAM (FMOD_SYSTEM *system, int *currentalloced, int *maxalloced, int *total); +FMOD_RESULT F_API FMOD_System_GetNumCDROMDrives (FMOD_SYSTEM *system, int *numdrives); +FMOD_RESULT F_API FMOD_System_GetCDROMDriveName (FMOD_SYSTEM *system, int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); +FMOD_RESULT F_API FMOD_System_GetSpectrum (FMOD_SYSTEM *system, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_System_GetWaveData (FMOD_SYSTEM *system, float *wavearray, int numvalues, int channeloffset); + +/* + Sound/DSP/Channel/FX creation and retrieval. +*/ + +FMOD_RESULT F_API FMOD_System_CreateSound (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_System_CreateStream (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_System_CreateDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateDSPByType (FMOD_SYSTEM *system, FMOD_DSP_TYPE type, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateChannelGroup (FMOD_SYSTEM *system, const char *name, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_System_CreateSoundGroup (FMOD_SYSTEM *system, const char *name, FMOD_SOUNDGROUP **soundgroup); +FMOD_RESULT F_API FMOD_System_CreateReverb (FMOD_SYSTEM *system, FMOD_REVERB **reverb); + +FMOD_RESULT F_API FMOD_System_PlaySound (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_SOUND *sound, FMOD_BOOL paused, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_PlayDSP (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_DSP *dsp, FMOD_BOOL paused, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_GetChannel (FMOD_SYSTEM *system, int channelid, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_GetMasterChannelGroup (FMOD_SYSTEM *system, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_System_GetMasterSoundGroup (FMOD_SYSTEM *system, FMOD_SOUNDGROUP **soundgroup); + +/* + Reverb API +*/ + +FMOD_RESULT F_API FMOD_System_SetReverbProperties (FMOD_SYSTEM *system, const FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_GetReverbProperties (FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_SetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_GetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); + +/* + System level DSP access. +*/ + +FMOD_RESULT F_API FMOD_System_GetDSPHead (FMOD_SYSTEM *system, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_AddDSP (FMOD_SYSTEM *system, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); +FMOD_RESULT F_API FMOD_System_LockDSP (FMOD_SYSTEM *system); +FMOD_RESULT F_API FMOD_System_UnlockDSP (FMOD_SYSTEM *system); +FMOD_RESULT F_API FMOD_System_GetDSPClock (FMOD_SYSTEM *system, unsigned int *hi, unsigned int *lo); + +/* + Recording API. +*/ + +FMOD_RESULT F_API FMOD_System_GetRecordNumDrivers (FMOD_SYSTEM *system, int *numdrivers); +FMOD_RESULT F_API FMOD_System_GetRecordDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetRecordDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetRecordDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); +FMOD_RESULT F_API FMOD_System_GetRecordPosition (FMOD_SYSTEM *system, int id, unsigned int *position); + +FMOD_RESULT F_API FMOD_System_RecordStart (FMOD_SYSTEM *system, int id, FMOD_SOUND *sound, FMOD_BOOL loop); +FMOD_RESULT F_API FMOD_System_RecordStop (FMOD_SYSTEM *system, int id); +FMOD_RESULT F_API FMOD_System_IsRecording (FMOD_SYSTEM *system, int id, FMOD_BOOL *recording); + +/* + Geometry API. +*/ + +FMOD_RESULT F_API FMOD_System_CreateGeometry (FMOD_SYSTEM *system, int maxpolygons, int maxvertices, FMOD_GEOMETRY **geometry); +FMOD_RESULT F_API FMOD_System_SetGeometrySettings (FMOD_SYSTEM *system, float maxworldsize); +FMOD_RESULT F_API FMOD_System_GetGeometrySettings (FMOD_SYSTEM *system, float *maxworldsize); +FMOD_RESULT F_API FMOD_System_LoadGeometry (FMOD_SYSTEM *system, const void *data, int datasize, FMOD_GEOMETRY **geometry); +FMOD_RESULT F_API FMOD_System_GetGeometryOcclusion (FMOD_SYSTEM *system, const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); + +/* + Network functions. +*/ + +FMOD_RESULT F_API FMOD_System_SetNetworkProxy (FMOD_SYSTEM *system, const char *proxy); +FMOD_RESULT F_API FMOD_System_GetNetworkProxy (FMOD_SYSTEM *system, char *proxy, int proxylen); +FMOD_RESULT F_API FMOD_System_SetNetworkTimeout (FMOD_SYSTEM *system, int timeout); +FMOD_RESULT F_API FMOD_System_GetNetworkTimeout (FMOD_SYSTEM *system, int *timeout); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_System_SetUserData (FMOD_SYSTEM *system, void *userdata); +FMOD_RESULT F_API FMOD_System_GetUserData (FMOD_SYSTEM *system, void **userdata); + +FMOD_RESULT F_API FMOD_System_GetMemoryInfo (FMOD_SYSTEM *system, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Sound' API +*/ + +FMOD_RESULT F_API FMOD_Sound_Release (FMOD_SOUND *sound); +FMOD_RESULT F_API FMOD_Sound_GetSystemObject (FMOD_SOUND *sound, FMOD_SYSTEM **system); + +/* + Standard sound manipulation functions. +*/ + +FMOD_RESULT F_API FMOD_Sound_Lock (FMOD_SOUND *sound, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +FMOD_RESULT F_API FMOD_Sound_Unlock (FMOD_SOUND *sound, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); +FMOD_RESULT F_API FMOD_Sound_SetDefaults (FMOD_SOUND *sound, float frequency, float volume, float pan, int priority); +FMOD_RESULT F_API FMOD_Sound_GetDefaults (FMOD_SOUND *sound, float *frequency, float *volume, float *pan, int *priority); +FMOD_RESULT F_API FMOD_Sound_SetVariations (FMOD_SOUND *sound, float frequencyvar, float volumevar, float panvar); +FMOD_RESULT F_API FMOD_Sound_GetVariations (FMOD_SOUND *sound, float *frequencyvar, float *volumevar, float *panvar); +FMOD_RESULT F_API FMOD_Sound_Set3DMinMaxDistance (FMOD_SOUND *sound, float min, float max); +FMOD_RESULT F_API FMOD_Sound_Get3DMinMaxDistance (FMOD_SOUND *sound, float *min, float *max); +FMOD_RESULT F_API FMOD_Sound_Set3DConeSettings (FMOD_SOUND *sound, float insideconeangle, float outsideconeangle, float outsidevolume); +FMOD_RESULT F_API FMOD_Sound_Get3DConeSettings (FMOD_SOUND *sound, float *insideconeangle, float *outsideconeangle, float *outsidevolume); +FMOD_RESULT F_API FMOD_Sound_Set3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR *points, int numpoints); +FMOD_RESULT F_API FMOD_Sound_Get3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR **points, int *numpoints); +FMOD_RESULT F_API FMOD_Sound_SetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND *subsound); +FMOD_RESULT F_API FMOD_Sound_GetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND **subsound); +FMOD_RESULT F_API FMOD_Sound_GetSubSoundParent (FMOD_SOUND *sound, FMOD_SOUND **parentsound); +FMOD_RESULT F_API FMOD_Sound_SetSubSoundSentence (FMOD_SOUND *sound, int *subsoundlist, int numsubsounds); +FMOD_RESULT F_API FMOD_Sound_GetName (FMOD_SOUND *sound, char *name, int namelen); +FMOD_RESULT F_API FMOD_Sound_GetLength (FMOD_SOUND *sound, unsigned int *length, FMOD_TIMEUNIT lengthtype); +FMOD_RESULT F_API FMOD_Sound_GetFormat (FMOD_SOUND *sound, FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); +FMOD_RESULT F_API FMOD_Sound_GetNumSubSounds (FMOD_SOUND *sound, int *numsubsounds); +FMOD_RESULT F_API FMOD_Sound_GetNumTags (FMOD_SOUND *sound, int *numtags, int *numtagsupdated); +FMOD_RESULT F_API FMOD_Sound_GetTag (FMOD_SOUND *sound, const char *name, int index, FMOD_TAG *tag); +FMOD_RESULT F_API FMOD_Sound_GetOpenState (FMOD_SOUND *sound, FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, FMOD_BOOL *starving, FMOD_BOOL *diskbusy); +FMOD_RESULT F_API FMOD_Sound_ReadData (FMOD_SOUND *sound, void *buffer, unsigned int lenbytes, unsigned int *read); +FMOD_RESULT F_API FMOD_Sound_SeekData (FMOD_SOUND *sound, unsigned int pcm); + +FMOD_RESULT F_API FMOD_Sound_SetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP *soundgroup); +FMOD_RESULT F_API FMOD_Sound_GetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP **soundgroup); + +/* + Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. +*/ + +FMOD_RESULT F_API FMOD_Sound_GetNumSyncPoints (FMOD_SOUND *sound, int *numsyncpoints); +FMOD_RESULT F_API FMOD_Sound_GetSyncPoint (FMOD_SOUND *sound, int index, FMOD_SYNCPOINT **point); +FMOD_RESULT F_API FMOD_Sound_GetSyncPointInfo (FMOD_SOUND *sound, FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); +FMOD_RESULT F_API FMOD_Sound_AddSyncPoint (FMOD_SOUND *sound, unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); +FMOD_RESULT F_API FMOD_Sound_DeleteSyncPoint (FMOD_SOUND *sound, FMOD_SYNCPOINT *point); + +/* + Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. +*/ + +FMOD_RESULT F_API FMOD_Sound_SetMode (FMOD_SOUND *sound, FMOD_MODE mode); +FMOD_RESULT F_API FMOD_Sound_GetMode (FMOD_SOUND *sound, FMOD_MODE *mode); +FMOD_RESULT F_API FMOD_Sound_SetLoopCount (FMOD_SOUND *sound, int loopcount); +FMOD_RESULT F_API FMOD_Sound_GetLoopCount (FMOD_SOUND *sound, int *loopcount); +FMOD_RESULT F_API FMOD_Sound_SetLoopPoints (FMOD_SOUND *sound, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); +FMOD_RESULT F_API FMOD_Sound_GetLoopPoints (FMOD_SOUND *sound, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + +/* + For MOD/S3M/XM/IT/MID sequenced formats only. +*/ + +FMOD_RESULT F_API FMOD_Sound_GetMusicNumChannels (FMOD_SOUND *sound, int *numchannels); +FMOD_RESULT F_API FMOD_Sound_SetMusicChannelVolume (FMOD_SOUND *sound, int channel, float volume); +FMOD_RESULT F_API FMOD_Sound_GetMusicChannelVolume (FMOD_SOUND *sound, int channel, float *volume); +FMOD_RESULT F_API FMOD_Sound_SetMusicSpeed (FMOD_SOUND *sound, float speed); +FMOD_RESULT F_API FMOD_Sound_GetMusicSpeed (FMOD_SOUND *sound, float *speed); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Sound_SetUserData (FMOD_SOUND *sound, void *userdata); +FMOD_RESULT F_API FMOD_Sound_GetUserData (FMOD_SOUND *sound, void **userdata); + +FMOD_RESULT F_API FMOD_Sound_GetMemoryInfo (FMOD_SOUND *sound, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Channel' API +*/ + +FMOD_RESULT F_API FMOD_Channel_GetSystemObject (FMOD_CHANNEL *channel, FMOD_SYSTEM **system); + +FMOD_RESULT F_API FMOD_Channel_Stop (FMOD_CHANNEL *channel); +FMOD_RESULT F_API FMOD_Channel_SetPaused (FMOD_CHANNEL *channel, FMOD_BOOL paused); +FMOD_RESULT F_API FMOD_Channel_GetPaused (FMOD_CHANNEL *channel, FMOD_BOOL *paused); +FMOD_RESULT F_API FMOD_Channel_SetVolume (FMOD_CHANNEL *channel, float volume); +FMOD_RESULT F_API FMOD_Channel_GetVolume (FMOD_CHANNEL *channel, float *volume); +FMOD_RESULT F_API FMOD_Channel_SetFrequency (FMOD_CHANNEL *channel, float frequency); +FMOD_RESULT F_API FMOD_Channel_GetFrequency (FMOD_CHANNEL *channel, float *frequency); +FMOD_RESULT F_API FMOD_Channel_SetPan (FMOD_CHANNEL *channel, float pan); +FMOD_RESULT F_API FMOD_Channel_GetPan (FMOD_CHANNEL *channel, float *pan); +FMOD_RESULT F_API FMOD_Channel_SetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); +FMOD_RESULT F_API FMOD_Channel_GetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); +FMOD_RESULT F_API FMOD_Channel_SetSpeakerMix (FMOD_CHANNEL *channel, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); +FMOD_RESULT F_API FMOD_Channel_GetSpeakerMix (FMOD_CHANNEL *channel, float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); +FMOD_RESULT F_API FMOD_Channel_SetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_GetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_SetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_GetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_SetMute (FMOD_CHANNEL *channel, FMOD_BOOL mute); +FMOD_RESULT F_API FMOD_Channel_GetMute (FMOD_CHANNEL *channel, FMOD_BOOL *mute); +FMOD_RESULT F_API FMOD_Channel_SetPriority (FMOD_CHANNEL *channel, int priority); +FMOD_RESULT F_API FMOD_Channel_GetPriority (FMOD_CHANNEL *channel, int *priority); +FMOD_RESULT F_API FMOD_Channel_SetPosition (FMOD_CHANNEL *channel, unsigned int position, FMOD_TIMEUNIT postype); +FMOD_RESULT F_API FMOD_Channel_GetPosition (FMOD_CHANNEL *channel, unsigned int *position, FMOD_TIMEUNIT postype); +FMOD_RESULT F_API FMOD_Channel_SetReverbProperties (FMOD_CHANNEL *channel, const FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_Channel_GetReverbProperties (FMOD_CHANNEL *channel, FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_Channel_SetLowPassGain (FMOD_CHANNEL *channel, float gain); +FMOD_RESULT F_API FMOD_Channel_GetLowPassGain (FMOD_CHANNEL *channel, float *gain); + +FMOD_RESULT F_API FMOD_Channel_SetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_Channel_GetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_Channel_SetCallback (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACK callback); + +/* + 3D functionality. +*/ + +FMOD_RESULT F_API FMOD_Channel_Set3DAttributes (FMOD_CHANNEL *channel, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_Channel_Get3DAttributes (FMOD_CHANNEL *channel, FMOD_VECTOR *pos, FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_Channel_Set3DMinMaxDistance (FMOD_CHANNEL *channel, float mindistance, float maxdistance); +FMOD_RESULT F_API FMOD_Channel_Get3DMinMaxDistance (FMOD_CHANNEL *channel, float *mindistance, float *maxdistance); +FMOD_RESULT F_API FMOD_Channel_Set3DConeSettings (FMOD_CHANNEL *channel, float insideconeangle, float outsideconeangle, float outsidevolume); +FMOD_RESULT F_API FMOD_Channel_Get3DConeSettings (FMOD_CHANNEL *channel, float *insideconeangle, float *outsideconeangle, float *outsidevolume); +FMOD_RESULT F_API FMOD_Channel_Set3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); +FMOD_RESULT F_API FMOD_Channel_Get3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); +FMOD_RESULT F_API FMOD_Channel_Set3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR *points, int numpoints); +FMOD_RESULT F_API FMOD_Channel_Get3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR **points, int *numpoints); +FMOD_RESULT F_API FMOD_Channel_Set3DOcclusion (FMOD_CHANNEL *channel, float directocclusion, float reverbocclusion); +FMOD_RESULT F_API FMOD_Channel_Get3DOcclusion (FMOD_CHANNEL *channel, float *directocclusion, float *reverbocclusion); +FMOD_RESULT F_API FMOD_Channel_Set3DSpread (FMOD_CHANNEL *channel, float angle); +FMOD_RESULT F_API FMOD_Channel_Get3DSpread (FMOD_CHANNEL *channel, float *angle); +FMOD_RESULT F_API FMOD_Channel_Set3DPanLevel (FMOD_CHANNEL *channel, float level); +FMOD_RESULT F_API FMOD_Channel_Get3DPanLevel (FMOD_CHANNEL *channel, float *level); +FMOD_RESULT F_API FMOD_Channel_Set3DDopplerLevel (FMOD_CHANNEL *channel, float level); +FMOD_RESULT F_API FMOD_Channel_Get3DDopplerLevel (FMOD_CHANNEL *channel, float *level); +FMOD_RESULT F_API FMOD_Channel_Set3DDistanceFilter (FMOD_CHANNEL *channel, FMOD_BOOL custom, float customLevel, float centerFreq); +FMOD_RESULT F_API FMOD_Channel_Get3DDistanceFilter (FMOD_CHANNEL *channel, FMOD_BOOL *custom, float *customLevel, float *centerFreq); + +/* + DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. +*/ + +FMOD_RESULT F_API FMOD_Channel_GetDSPHead (FMOD_CHANNEL *channel, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_Channel_AddDSP (FMOD_CHANNEL *channel, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_Channel_IsPlaying (FMOD_CHANNEL *channel, FMOD_BOOL *isplaying); +FMOD_RESULT F_API FMOD_Channel_IsVirtual (FMOD_CHANNEL *channel, FMOD_BOOL *isvirtual); +FMOD_RESULT F_API FMOD_Channel_GetAudibility (FMOD_CHANNEL *channel, float *audibility); +FMOD_RESULT F_API FMOD_Channel_GetCurrentSound (FMOD_CHANNEL *channel, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_Channel_GetSpectrum (FMOD_CHANNEL *channel, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_Channel_GetWaveData (FMOD_CHANNEL *channel, float *wavearray, int numvalues, int channeloffset); +FMOD_RESULT F_API FMOD_Channel_GetIndex (FMOD_CHANNEL *channel, int *index); + +/* + Functions also found in Sound class but here they can be set per channel. +*/ + +FMOD_RESULT F_API FMOD_Channel_SetMode (FMOD_CHANNEL *channel, FMOD_MODE mode); +FMOD_RESULT F_API FMOD_Channel_GetMode (FMOD_CHANNEL *channel, FMOD_MODE *mode); +FMOD_RESULT F_API FMOD_Channel_SetLoopCount (FMOD_CHANNEL *channel, int loopcount); +FMOD_RESULT F_API FMOD_Channel_GetLoopCount (FMOD_CHANNEL *channel, int *loopcount); +FMOD_RESULT F_API FMOD_Channel_SetLoopPoints (FMOD_CHANNEL *channel, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); +FMOD_RESULT F_API FMOD_Channel_GetLoopPoints (FMOD_CHANNEL *channel, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Channel_SetUserData (FMOD_CHANNEL *channel, void *userdata); +FMOD_RESULT F_API FMOD_Channel_GetUserData (FMOD_CHANNEL *channel, void **userdata); + +FMOD_RESULT F_API FMOD_Channel_GetMemoryInfo (FMOD_CHANNEL *channel, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'ChannelGroup' API +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_Release (FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_ChannelGroup_GetSystemObject (FMOD_CHANNELGROUP *channelgroup, FMOD_SYSTEM **system); + +/* + Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_SetVolume (FMOD_CHANNELGROUP *channelgroup, float volume); +FMOD_RESULT F_API FMOD_ChannelGroup_GetVolume (FMOD_CHANNELGROUP *channelgroup, float *volume); +FMOD_RESULT F_API FMOD_ChannelGroup_SetPitch (FMOD_CHANNELGROUP *channelgroup, float pitch); +FMOD_RESULT F_API FMOD_ChannelGroup_GetPitch (FMOD_CHANNELGROUP *channelgroup, float *pitch); +FMOD_RESULT F_API FMOD_ChannelGroup_Set3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float directocclusion, float reverbocclusion); +FMOD_RESULT F_API FMOD_ChannelGroup_Get3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float *directocclusion, float *reverbocclusion); +FMOD_RESULT F_API FMOD_ChannelGroup_SetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL paused); +FMOD_RESULT F_API FMOD_ChannelGroup_GetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *paused); +FMOD_RESULT F_API FMOD_ChannelGroup_SetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL mute); +FMOD_RESULT F_API FMOD_ChannelGroup_GetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *mute); + +/* + Channelgroup override values. (recursively overwrites whatever settings the channels had) +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_Stop (FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideVolume (FMOD_CHANNELGROUP *channelgroup, float volume); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideFrequency(FMOD_CHANNELGROUP *channelgroup, float frequency); +FMOD_RESULT F_API FMOD_ChannelGroup_OverridePan (FMOD_CHANNELGROUP *channelgroup, float pan); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideReverbProperties(FMOD_CHANNELGROUP *channelgroup, const FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_ChannelGroup_Override3DAttributes(FMOD_CHANNELGROUP *channelgroup, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideSpeakerMix(FMOD_CHANNELGROUP *channelgroup, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + +/* + Nested channel groups. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_AddGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP *group); +FMOD_RESULT F_API FMOD_ChannelGroup_GetNumGroups (FMOD_CHANNELGROUP *channelgroup, int *numgroups); +FMOD_RESULT F_API FMOD_ChannelGroup_GetGroup (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNELGROUP **group); +FMOD_RESULT F_API FMOD_ChannelGroup_GetParentGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP **group); + +/* + DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_GetDSPHead (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_ChannelGroup_AddDSP (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_GetName (FMOD_CHANNELGROUP *channelgroup, char *name, int namelen); +FMOD_RESULT F_API FMOD_ChannelGroup_GetNumChannels (FMOD_CHANNELGROUP *channelgroup, int *numchannels); +FMOD_RESULT F_API FMOD_ChannelGroup_GetChannel (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_ChannelGroup_GetSpectrum (FMOD_CHANNELGROUP *channelgroup, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_ChannelGroup_GetWaveData (FMOD_CHANNELGROUP *channelgroup, float *wavearray, int numvalues, int channeloffset); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_SetUserData (FMOD_CHANNELGROUP *channelgroup, void *userdata); +FMOD_RESULT F_API FMOD_ChannelGroup_GetUserData (FMOD_CHANNELGROUP *channelgroup, void **userdata); + +FMOD_RESULT F_API FMOD_ChannelGroup_GetMemoryInfo (FMOD_CHANNELGROUP *channelgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'SoundGroup' API +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_Release (FMOD_SOUNDGROUP *soundgroup); +FMOD_RESULT F_API FMOD_SoundGroup_GetSystemObject (FMOD_SOUNDGROUP *soundgroup, FMOD_SYSTEM **system); + +/* + SoundGroup control functions. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int maxaudible); +FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int *maxaudible); +FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR behavior); +FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR *behavior); +FMOD_RESULT F_API FMOD_SoundGroup_SetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float speed); +FMOD_RESULT F_API FMOD_SoundGroup_GetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float *speed); +FMOD_RESULT F_API FMOD_SoundGroup_SetVolume (FMOD_SOUNDGROUP *soundgroup, float volume); +FMOD_RESULT F_API FMOD_SoundGroup_GetVolume (FMOD_SOUNDGROUP *soundgroup, float *volume); +FMOD_RESULT F_API FMOD_SoundGroup_Stop (FMOD_SOUNDGROUP *soundgroup); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_GetName (FMOD_SOUNDGROUP *soundgroup, char *name, int namelen); +FMOD_RESULT F_API FMOD_SoundGroup_GetNumSounds (FMOD_SOUNDGROUP *soundgroup, int *numsounds); +FMOD_RESULT F_API FMOD_SoundGroup_GetSound (FMOD_SOUNDGROUP *soundgroup, int index, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_SoundGroup_GetNumPlaying (FMOD_SOUNDGROUP *soundgroup, int *numplaying); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_SetUserData (FMOD_SOUNDGROUP *soundgroup, void *userdata); +FMOD_RESULT F_API FMOD_SoundGroup_GetUserData (FMOD_SOUNDGROUP *soundgroup, void **userdata); + +FMOD_RESULT F_API FMOD_SoundGroup_GetMemoryInfo (FMOD_SOUNDGROUP *soundgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'DSP' API +*/ + +FMOD_RESULT F_API FMOD_DSP_Release (FMOD_DSP *dsp); +FMOD_RESULT F_API FMOD_DSP_GetSystemObject (FMOD_DSP *dsp, FMOD_SYSTEM **system); + +/* + Connection / disconnection / input and output enumeration. +*/ + +FMOD_RESULT F_API FMOD_DSP_AddInput (FMOD_DSP *dsp, FMOD_DSP *target, FMOD_DSPCONNECTION **connection); +FMOD_RESULT F_API FMOD_DSP_DisconnectFrom (FMOD_DSP *dsp, FMOD_DSP *target); +FMOD_RESULT F_API FMOD_DSP_DisconnectAll (FMOD_DSP *dsp, FMOD_BOOL inputs, FMOD_BOOL outputs); +FMOD_RESULT F_API FMOD_DSP_Remove (FMOD_DSP *dsp); +FMOD_RESULT F_API FMOD_DSP_GetNumInputs (FMOD_DSP *dsp, int *numinputs); +FMOD_RESULT F_API FMOD_DSP_GetNumOutputs (FMOD_DSP *dsp, int *numoutputs); +FMOD_RESULT F_API FMOD_DSP_GetInput (FMOD_DSP *dsp, int index, FMOD_DSP **input, FMOD_DSPCONNECTION **inputconnection); +FMOD_RESULT F_API FMOD_DSP_GetOutput (FMOD_DSP *dsp, int index, FMOD_DSP **output, FMOD_DSPCONNECTION **outputconnection); + +/* + DSP unit control. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetActive (FMOD_DSP *dsp, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_DSP_GetActive (FMOD_DSP *dsp, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_DSP_SetBypass (FMOD_DSP *dsp, FMOD_BOOL bypass); +FMOD_RESULT F_API FMOD_DSP_GetBypass (FMOD_DSP *dsp, FMOD_BOOL *bypass); +FMOD_RESULT F_API FMOD_DSP_SetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_DSP_GetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_DSP_Reset (FMOD_DSP *dsp); + +/* + DSP parameter control. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetParameter (FMOD_DSP *dsp, int index, float value); +FMOD_RESULT F_API FMOD_DSP_GetParameter (FMOD_DSP *dsp, int index, float *value, char *valuestr, int valuestrlen); +FMOD_RESULT F_API FMOD_DSP_GetNumParameters (FMOD_DSP *dsp, int *numparams); +FMOD_RESULT F_API FMOD_DSP_GetParameterInfo (FMOD_DSP *dsp, int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); +FMOD_RESULT F_API FMOD_DSP_ShowConfigDialog (FMOD_DSP *dsp, void *hwnd, FMOD_BOOL show); + +/* + DSP attributes. +*/ + +FMOD_RESULT F_API FMOD_DSP_GetInfo (FMOD_DSP *dsp, char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); +FMOD_RESULT F_API FMOD_DSP_GetType (FMOD_DSP *dsp, FMOD_DSP_TYPE *type); +FMOD_RESULT F_API FMOD_DSP_SetDefaults (FMOD_DSP *dsp, float frequency, float volume, float pan, int priority); +FMOD_RESULT F_API FMOD_DSP_GetDefaults (FMOD_DSP *dsp, float *frequency, float *volume, float *pan, int *priority); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetUserData (FMOD_DSP *dsp, void *userdata); +FMOD_RESULT F_API FMOD_DSP_GetUserData (FMOD_DSP *dsp, void **userdata); + +FMOD_RESULT F_API FMOD_DSP_GetMemoryInfo (FMOD_DSP *dsp, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'DSPConnection' API +*/ + +FMOD_RESULT F_API FMOD_DSPConnection_GetInput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **input); +FMOD_RESULT F_API FMOD_DSPConnection_GetOutput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **output); +FMOD_RESULT F_API FMOD_DSPConnection_SetMix (FMOD_DSPCONNECTION *dspconnection, float volume); +FMOD_RESULT F_API FMOD_DSPConnection_GetMix (FMOD_DSPCONNECTION *dspconnection, float *volume); +FMOD_RESULT F_API FMOD_DSPConnection_SetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_DSPConnection_GetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_DSPConnection_SetUserData (FMOD_DSPCONNECTION *dspconnection, void *userdata); +FMOD_RESULT F_API FMOD_DSPConnection_GetUserData (FMOD_DSPCONNECTION *dspconnection, void **userdata); + +FMOD_RESULT F_API FMOD_DSPConnection_GetMemoryInfo (FMOD_DSPCONNECTION *dspconnection, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Geometry' API +*/ + +FMOD_RESULT F_API FMOD_Geometry_Release (FMOD_GEOMETRY *geometry); + +/* + Polygon manipulation. +*/ + +FMOD_RESULT F_API FMOD_Geometry_AddPolygon (FMOD_GEOMETRY *geometry, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); +FMOD_RESULT F_API FMOD_Geometry_GetNumPolygons (FMOD_GEOMETRY *geometry, int *numpolygons); +FMOD_RESULT F_API FMOD_Geometry_GetMaxPolygons (FMOD_GEOMETRY *geometry, int *maxpolygons, int *maxvertices); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonNumVertices(FMOD_GEOMETRY *geometry, int index, int *numvertices); +FMOD_RESULT F_API FMOD_Geometry_SetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, const FMOD_VECTOR *vertex); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, FMOD_VECTOR *vertex); +FMOD_RESULT F_API FMOD_Geometry_SetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float *directocclusion, float *reverbocclusion, FMOD_BOOL *doublesided); + +/* + Object manipulation. +*/ + +FMOD_RESULT F_API FMOD_Geometry_SetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_Geometry_GetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_Geometry_SetRotation (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_Geometry_GetRotation (FMOD_GEOMETRY *geometry, FMOD_VECTOR *forward, FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_Geometry_SetPosition (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *position); +FMOD_RESULT F_API FMOD_Geometry_GetPosition (FMOD_GEOMETRY *geometry, FMOD_VECTOR *position); +FMOD_RESULT F_API FMOD_Geometry_SetScale (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *scale); +FMOD_RESULT F_API FMOD_Geometry_GetScale (FMOD_GEOMETRY *geometry, FMOD_VECTOR *scale); +FMOD_RESULT F_API FMOD_Geometry_Save (FMOD_GEOMETRY *geometry, void *data, int *datasize); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Geometry_SetUserData (FMOD_GEOMETRY *geometry, void *userdata); +FMOD_RESULT F_API FMOD_Geometry_GetUserData (FMOD_GEOMETRY *geometry, void **userdata); + +FMOD_RESULT F_API FMOD_Geometry_GetMemoryInfo (FMOD_GEOMETRY *geometry, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Reverb' API +*/ + +FMOD_RESULT F_API FMOD_Reverb_Release (FMOD_REVERB *reverb); + +/* + Reverb manipulation. +*/ + +FMOD_RESULT F_API FMOD_Reverb_Set3DAttributes (FMOD_REVERB *reverb, const FMOD_VECTOR *position, float mindistance, float maxdistance); +FMOD_RESULT F_API FMOD_Reverb_Get3DAttributes (FMOD_REVERB *reverb, FMOD_VECTOR *position, float *mindistance, float *maxdistance); +FMOD_RESULT F_API FMOD_Reverb_SetProperties (FMOD_REVERB *reverb, const FMOD_REVERB_PROPERTIES *properties); +FMOD_RESULT F_API FMOD_Reverb_GetProperties (FMOD_REVERB *reverb, FMOD_REVERB_PROPERTIES *properties); +FMOD_RESULT F_API FMOD_Reverb_SetActive (FMOD_REVERB *reverb, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_Reverb_GetActive (FMOD_REVERB *reverb, FMOD_BOOL *active); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Reverb_SetUserData (FMOD_REVERB *reverb, void *userdata); +FMOD_RESULT F_API FMOD_Reverb_GetUserData (FMOD_REVERB *reverb, void **userdata); + +FMOD_RESULT F_API FMOD_Reverb_GetMemoryInfo (FMOD_REVERB *reverb, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); +/*$ preserve start $*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/*$ preserve end $*/ diff --git a/src/imports/fmodex/fmod.hpp b/src/imports/fmodex/fmod.hpp new file mode 100644 index 0000000..df19647 --- /dev/null +++ b/src/imports/fmodex/fmod.hpp @@ -0,0 +1,609 @@ +/* ========================================================================================== */ +/* FMOD Ex - C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header in conjunction with fmod.h (which contains all the constants / callbacks) */ +/* to develop using C++ classes. */ +/* ========================================================================================== */ + +#ifndef _FMOD_HPP +#define _FMOD_HPP + +#include "fmod.h" + +/* + Constant and defines +*/ + +/* + FMOD Namespace +*/ +namespace FMOD +{ + class System; + class Sound; + class Channel; + class ChannelGroup; + class SoundGroup; + class Reverb; + class DSP; + class DSPConnection; + class Geometry; + + /* + FMOD global system functions (optional). + */ + inline FMOD_RESULT Memory_Initialize(void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags = FMOD_MEMORY_ALL) { return FMOD_Memory_Initialize(poolmem, poollen, useralloc, userrealloc, userfree, memtypeflags); } + inline FMOD_RESULT Memory_GetStats (int *currentalloced, int *maxalloced, bool blocking = true) { return FMOD_Memory_GetStats(currentalloced, maxalloced, blocking); } + inline FMOD_RESULT Debug_SetLevel(FMOD_DEBUGLEVEL level) { return FMOD_Debug_SetLevel(level); } + inline FMOD_RESULT Debug_GetLevel(FMOD_DEBUGLEVEL *level) { return FMOD_Debug_GetLevel(level); } + inline FMOD_RESULT File_SetDiskBusy(int busy) { return FMOD_File_SetDiskBusy(busy); } + inline FMOD_RESULT File_GetDiskBusy(int *busy) { return FMOD_File_GetDiskBusy(busy); } + + /* + FMOD System factory functions. + */ + inline FMOD_RESULT System_Create(System **system) { return FMOD_System_Create((FMOD_SYSTEM **)system); } + + /* + 'System' API + */ + + class System + { + private: + + System(); /* Constructor made private so user cannot statically instance a System class. + System_Create must be used. */ + public: + + FMOD_RESULT F_API release (); + + // Pre-init functions. + FMOD_RESULT F_API setOutput (FMOD_OUTPUTTYPE output); + FMOD_RESULT F_API getOutput (FMOD_OUTPUTTYPE *output); + FMOD_RESULT F_API getNumDrivers (int *numdrivers); + FMOD_RESULT F_API getDriverInfo (int id, char *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getDriverInfoW (int id, short *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getDriverCaps (int id, FMOD_CAPS *caps, int *controlpaneloutputrate, FMOD_SPEAKERMODE *controlpanelspeakermode); + FMOD_RESULT F_API setDriver (int driver); + FMOD_RESULT F_API getDriver (int *driver); + FMOD_RESULT F_API setHardwareChannels (int numhardwarechannels); + FMOD_RESULT F_API setSoftwareChannels (int numsoftwarechannels); + FMOD_RESULT F_API getSoftwareChannels (int *numsoftwarechannels); + FMOD_RESULT F_API setSoftwareFormat (int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); + FMOD_RESULT F_API getSoftwareFormat (int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); + FMOD_RESULT F_API setDSPBufferSize (unsigned int bufferlength, int numbuffers); + FMOD_RESULT F_API getDSPBufferSize (unsigned int *bufferlength, int *numbuffers); + FMOD_RESULT F_API setFileSystem (FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, FMOD_FILE_ASYNCREADCALLBACK userasyncread, FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign); + FMOD_RESULT F_API attachFileSystem (FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); + FMOD_RESULT F_API setAdvancedSettings (FMOD_ADVANCEDSETTINGS *settings); + FMOD_RESULT F_API getAdvancedSettings (FMOD_ADVANCEDSETTINGS *settings); + FMOD_RESULT F_API setSpeakerMode (FMOD_SPEAKERMODE speakermode); + FMOD_RESULT F_API getSpeakerMode (FMOD_SPEAKERMODE *speakermode); + FMOD_RESULT F_API setCallback (FMOD_SYSTEM_CALLBACK callback); + + // Plug-in support + FMOD_RESULT F_API setPluginPath (const char *path); + FMOD_RESULT F_API loadPlugin (const char *filename, unsigned int *handle, unsigned int priority = 0); + FMOD_RESULT F_API unloadPlugin (unsigned int handle); + FMOD_RESULT F_API getNumPlugins (FMOD_PLUGINTYPE plugintype, int *numplugins); + FMOD_RESULT F_API getPluginHandle (FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); + FMOD_RESULT F_API getPluginInfo (unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); + FMOD_RESULT F_API setOutputByPlugin (unsigned int handle); + FMOD_RESULT F_API getOutputByPlugin (unsigned int *handle); + FMOD_RESULT F_API createDSPByPlugin (unsigned int handle, DSP **dsp); + FMOD_RESULT F_API registerCodec (FMOD_CODEC_DESCRIPTION *description, unsigned int *handle, unsigned int priority = 0); + FMOD_RESULT F_API registerDSP (FMOD_DSP_DESCRIPTION *description, unsigned int *handle); + + // Init/Close + FMOD_RESULT F_API init (int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); + FMOD_RESULT F_API close (); + + // General post-init system functions + FMOD_RESULT F_API update (); /* IMPORTANT! CALL THIS ONCE PER FRAME! */ + + FMOD_RESULT F_API set3DSettings (float dopplerscale, float distancefactor, float rolloffscale); + FMOD_RESULT F_API get3DSettings (float *dopplerscale, float *distancefactor, float *rolloffscale); + FMOD_RESULT F_API set3DNumListeners (int numlisteners); + FMOD_RESULT F_API get3DNumListeners (int *numlisteners); + FMOD_RESULT F_API set3DListenerAttributes(int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); + FMOD_RESULT F_API get3DListenerAttributes(int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); + FMOD_RESULT F_API set3DRolloffCallback (FMOD_3D_ROLLOFFCALLBACK callback); + FMOD_RESULT F_API set3DSpeakerPosition (FMOD_SPEAKER speaker, float x, float y, bool active); + FMOD_RESULT F_API get3DSpeakerPosition (FMOD_SPEAKER speaker, float *x, float *y, bool *active); + + FMOD_RESULT F_API setStreamBufferSize (unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); + FMOD_RESULT F_API getStreamBufferSize (unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); + + // System information functions. + FMOD_RESULT F_API getVersion (unsigned int *version); + FMOD_RESULT F_API getOutputHandle (void **handle); + FMOD_RESULT F_API getChannelsPlaying (int *channels); + FMOD_RESULT F_API getHardwareChannels (int *numhardwarechannels); + FMOD_RESULT F_API getCPUUsage (float *dsp, float *stream, float *geometry, float *update, float *total); + FMOD_RESULT F_API getSoundRAM (int *currentalloced, int *maxalloced, int *total); + FMOD_RESULT F_API getNumCDROMDrives (int *numdrives); + FMOD_RESULT F_API getCDROMDriveName (int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + + // Sound/DSP/Channel/FX creation and retrieval. + FMOD_RESULT F_API createSound (const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound); + FMOD_RESULT F_API createStream (const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound); + FMOD_RESULT F_API createDSP (FMOD_DSP_DESCRIPTION *description, DSP **dsp); + FMOD_RESULT F_API createDSPByType (FMOD_DSP_TYPE type, DSP **dsp); + FMOD_RESULT F_API createChannelGroup (const char *name, ChannelGroup **channelgroup); + FMOD_RESULT F_API createSoundGroup (const char *name, SoundGroup **soundgroup); + FMOD_RESULT F_API createReverb (Reverb **reverb); + + FMOD_RESULT F_API playSound (FMOD_CHANNELINDEX channelid, Sound *sound, bool paused, Channel **channel); + FMOD_RESULT F_API playDSP (FMOD_CHANNELINDEX channelid, DSP *dsp, bool paused, Channel **channel); + FMOD_RESULT F_API getChannel (int channelid, Channel **channel); + FMOD_RESULT F_API getMasterChannelGroup (ChannelGroup **channelgroup); + FMOD_RESULT F_API getMasterSoundGroup (SoundGroup **soundgroup); + + // Reverb API + FMOD_RESULT F_API setReverbProperties (const FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API getReverbProperties (FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API setReverbAmbientProperties(FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API getReverbAmbientProperties(FMOD_REVERB_PROPERTIES *prop); + + // System level DSP access. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + FMOD_RESULT F_API lockDSP (); + FMOD_RESULT F_API unlockDSP (); + FMOD_RESULT F_API getDSPClock (unsigned int *hi, unsigned int *lo); + + // Recording API. + FMOD_RESULT F_API getRecordNumDrivers (int *numdrivers); + FMOD_RESULT F_API getRecordDriverInfo (int id, char *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getRecordDriverInfoW (int id, short *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getRecordDriverCaps (int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); + FMOD_RESULT F_API getRecordPosition (int id, unsigned int *position); + + FMOD_RESULT F_API recordStart (int id, Sound *sound, bool loop); + FMOD_RESULT F_API recordStop (int id); + FMOD_RESULT F_API isRecording (int id, bool *recording); + + // Geometry API. + FMOD_RESULT F_API createGeometry (int maxpolygons, int maxvertices, Geometry **geometry); + FMOD_RESULT F_API setGeometrySettings (float maxworldsize); + FMOD_RESULT F_API getGeometrySettings (float *maxworldsize); + FMOD_RESULT F_API loadGeometry (const void *data, int datasize, Geometry **geometry); + FMOD_RESULT F_API getGeometryOcclusion (const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); + + // Network functions. + FMOD_RESULT F_API setNetworkProxy (const char *proxy); + FMOD_RESULT F_API getNetworkProxy (char *proxy, int proxylen); + FMOD_RESULT F_API setNetworkTimeout (int timeout); + FMOD_RESULT F_API getNetworkTimeout (int *timeout); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'Sound' API + */ + class Sound + { + private: + + Sound(); /* Constructor made private so user cannot statically instance a Sound class. + Appropriate Sound creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Standard sound manipulation functions. + FMOD_RESULT F_API lock (unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); + FMOD_RESULT F_API unlock (void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + FMOD_RESULT F_API setDefaults (float frequency, float volume, float pan, int priority); + FMOD_RESULT F_API getDefaults (float *frequency, float *volume, float *pan, int *priority); + FMOD_RESULT F_API setVariations (float frequencyvar, float volumevar, float panvar); + FMOD_RESULT F_API getVariations (float *frequencyvar, float *volumevar, float *panvar); + FMOD_RESULT F_API set3DMinMaxDistance (float min, float max); + FMOD_RESULT F_API get3DMinMaxDistance (float *min, float *max); + FMOD_RESULT F_API set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume); + FMOD_RESULT F_API get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume); + FMOD_RESULT F_API set3DCustomRolloff (FMOD_VECTOR *points, int numpoints); + FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); + FMOD_RESULT F_API setSubSound (int index, Sound *subsound); + FMOD_RESULT F_API getSubSound (int index, Sound **subsound); + FMOD_RESULT F_API getSubSoundParent (Sound **parentsound); + FMOD_RESULT F_API setSubSoundSentence (int *subsoundlist, int numsubsounds); + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getLength (unsigned int *length, FMOD_TIMEUNIT lengthtype); + FMOD_RESULT F_API getFormat (FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); + FMOD_RESULT F_API getNumSubSounds (int *numsubsounds); + FMOD_RESULT F_API getNumTags (int *numtags, int *numtagsupdated); + FMOD_RESULT F_API getTag (const char *name, int index, FMOD_TAG *tag); + FMOD_RESULT F_API getOpenState (FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, bool *starving, bool *diskbusy); + FMOD_RESULT F_API readData (void *buffer, unsigned int lenbytes, unsigned int *read); + FMOD_RESULT F_API seekData (unsigned int pcm); + + FMOD_RESULT F_API setSoundGroup (SoundGroup *soundgroup); + FMOD_RESULT F_API getSoundGroup (SoundGroup **soundgroup); + + // Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. + FMOD_RESULT F_API getNumSyncPoints (int *numsyncpoints); + FMOD_RESULT F_API getSyncPoint (int index, FMOD_SYNCPOINT **point); + FMOD_RESULT F_API getSyncPointInfo (FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); + FMOD_RESULT F_API addSyncPoint (unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); + FMOD_RESULT F_API deleteSyncPoint (FMOD_SYNCPOINT *point); + + // Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. + FMOD_RESULT F_API setMode (FMOD_MODE mode); + FMOD_RESULT F_API getMode (FMOD_MODE *mode); + FMOD_RESULT F_API setLoopCount (int loopcount); + FMOD_RESULT F_API getLoopCount (int *loopcount); + FMOD_RESULT F_API setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); + FMOD_RESULT F_API getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + + // For MOD/S3M/XM/IT/MID sequenced formats only. + FMOD_RESULT F_API getMusicNumChannels (int *numchannels); + FMOD_RESULT F_API setMusicChannelVolume (int channel, float volume); + FMOD_RESULT F_API getMusicChannelVolume (int channel, float *volume); + FMOD_RESULT F_API setMusicSpeed (float speed); + FMOD_RESULT F_API getMusicSpeed (float *speed); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'Channel' API. + */ + class Channel + { + private: + + Channel(); /* Constructor made private so user cannot statically instance a Channel class. + Appropriate Channel creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API getSystemObject (System **system); + + FMOD_RESULT F_API stop (); + FMOD_RESULT F_API setPaused (bool paused); + FMOD_RESULT F_API getPaused (bool *paused); + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API setFrequency (float frequency); + FMOD_RESULT F_API getFrequency (float *frequency); + FMOD_RESULT F_API setPan (float pan); + FMOD_RESULT F_API getPan (float *pan); + FMOD_RESULT F_API setDelay (FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); + FMOD_RESULT F_API getDelay (FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); + FMOD_RESULT F_API setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + FMOD_RESULT F_API getSpeakerMix (float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); + FMOD_RESULT F_API setSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API getSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API setInputChannelMix (float *levels, int numlevels); + FMOD_RESULT F_API getInputChannelMix (float *levels, int numlevels); + FMOD_RESULT F_API setMute (bool mute); + FMOD_RESULT F_API getMute (bool *mute); + FMOD_RESULT F_API setPriority (int priority); + FMOD_RESULT F_API getPriority (int *priority); + FMOD_RESULT F_API setPosition (unsigned int position, FMOD_TIMEUNIT postype); + FMOD_RESULT F_API getPosition (unsigned int *position, FMOD_TIMEUNIT postype); + FMOD_RESULT F_API setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API setLowPassGain (float gain); + FMOD_RESULT F_API getLowPassGain (float *gain); + + FMOD_RESULT F_API setChannelGroup (ChannelGroup *channelgroup); + FMOD_RESULT F_API getChannelGroup (ChannelGroup **channelgroup); + FMOD_RESULT F_API setCallback (FMOD_CHANNEL_CALLBACK callback); + + // 3D functionality. + FMOD_RESULT F_API set3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); + FMOD_RESULT F_API get3DAttributes (FMOD_VECTOR *pos, FMOD_VECTOR *vel); + FMOD_RESULT F_API set3DMinMaxDistance (float mindistance, float maxdistance); + FMOD_RESULT F_API get3DMinMaxDistance (float *mindistance, float *maxdistance); + FMOD_RESULT F_API set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume); + FMOD_RESULT F_API get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume); + FMOD_RESULT F_API set3DConeOrientation (FMOD_VECTOR *orientation); + FMOD_RESULT F_API get3DConeOrientation (FMOD_VECTOR *orientation); + FMOD_RESULT F_API set3DCustomRolloff (FMOD_VECTOR *points, int numpoints); + FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); + FMOD_RESULT F_API set3DOcclusion (float directocclusion, float reverbocclusion); + FMOD_RESULT F_API get3DOcclusion (float *directocclusion, float *reverbocclusion); + FMOD_RESULT F_API set3DSpread (float angle); + FMOD_RESULT F_API get3DSpread (float *angle); + FMOD_RESULT F_API set3DPanLevel (float level); + FMOD_RESULT F_API get3DPanLevel (float *level); + FMOD_RESULT F_API set3DDopplerLevel (float level); + FMOD_RESULT F_API get3DDopplerLevel (float *level); + FMOD_RESULT F_API set3DDistanceFilter (bool custom, float customLevel, float centerFreq); + FMOD_RESULT F_API get3DDistanceFilter (bool *custom, float *customLevel, float *centerFreq); + + // DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + + // Information only functions. + FMOD_RESULT F_API isPlaying (bool *isplaying); + FMOD_RESULT F_API isVirtual (bool *isvirtual); + FMOD_RESULT F_API getAudibility (float *audibility); + FMOD_RESULT F_API getCurrentSound (Sound **sound); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + FMOD_RESULT F_API getIndex (int *index); + + // Functions also found in Sound class but here they can be set per channel. + FMOD_RESULT F_API setMode (FMOD_MODE mode); + FMOD_RESULT F_API getMode (FMOD_MODE *mode); + FMOD_RESULT F_API setLoopCount (int loopcount); + FMOD_RESULT F_API getLoopCount (int *loopcount); + FMOD_RESULT F_API setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); + FMOD_RESULT F_API getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'ChannelGroup' API + */ + class ChannelGroup + { + private: + + ChannelGroup(); /* Constructor made private so user cannot statically instance a ChannelGroup class. + Appropriate ChannelGroup creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API setPitch (float pitch); + FMOD_RESULT F_API getPitch (float *pitch); + FMOD_RESULT F_API set3DOcclusion (float directocclusion, float reverbocclusion); + FMOD_RESULT F_API get3DOcclusion (float *directocclusion, float *reverbocclusion); + FMOD_RESULT F_API setPaused (bool paused); + FMOD_RESULT F_API getPaused (bool *paused); + FMOD_RESULT F_API setMute (bool mute); + FMOD_RESULT F_API getMute (bool *mute); + + // Channelgroup override values. (recursively overwrites whatever settings the channels had) + FMOD_RESULT F_API stop (); + FMOD_RESULT F_API overrideVolume (float volume); + FMOD_RESULT F_API overrideFrequency (float frequency); + FMOD_RESULT F_API overridePan (float pan); + FMOD_RESULT F_API overrideReverbProperties(const FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API override3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); + FMOD_RESULT F_API overrideSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + + // Nested channel groups. + FMOD_RESULT F_API addGroup (ChannelGroup *group); + FMOD_RESULT F_API getNumGroups (int *numgroups); + FMOD_RESULT F_API getGroup (int index, ChannelGroup **group); + FMOD_RESULT F_API getParentGroup (ChannelGroup **group); + + // DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + + // Information only functions. + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getNumChannels (int *numchannels); + FMOD_RESULT F_API getChannel (int index, Channel **channel); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'SoundGroup' API + */ + class SoundGroup + { + private: + + SoundGroup(); /* Constructor made private so user cannot statically instance a SoundGroup class. + Appropriate SoundGroup creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // SoundGroup control functions. + FMOD_RESULT F_API setMaxAudible (int maxaudible); + FMOD_RESULT F_API getMaxAudible (int *maxaudible); + FMOD_RESULT F_API setMaxAudibleBehavior (FMOD_SOUNDGROUP_BEHAVIOR behavior); + FMOD_RESULT F_API getMaxAudibleBehavior (FMOD_SOUNDGROUP_BEHAVIOR *behavior); + FMOD_RESULT F_API setMuteFadeSpeed (float speed); + FMOD_RESULT F_API getMuteFadeSpeed (float *speed); + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API stop (); + + // Information only functions. + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getNumSounds (int *numsounds); + FMOD_RESULT F_API getSound (int index, Sound **sound); + FMOD_RESULT F_API getNumPlaying (int *numplaying); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'DSP' API + */ + class DSP + { + private: + + DSP(); /* Constructor made private so user cannot statically instance a DSP class. + Appropriate DSP creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Connection / disconnection / input and output enumeration. + FMOD_RESULT F_API addInput (DSP *target, DSPConnection **connection); + FMOD_RESULT F_API disconnectFrom (DSP *target); + FMOD_RESULT F_API disconnectAll (bool inputs, bool outputs); + FMOD_RESULT F_API remove (); + FMOD_RESULT F_API getNumInputs (int *numinputs); + FMOD_RESULT F_API getNumOutputs (int *numoutputs); + FMOD_RESULT F_API getInput (int index, DSP **input, DSPConnection **inputconnection); + FMOD_RESULT F_API getOutput (int index, DSP **output, DSPConnection **outputconnection); + + // DSP unit control. + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + FMOD_RESULT F_API setBypass (bool bypass); + FMOD_RESULT F_API getBypass (bool *bypass); + FMOD_RESULT F_API setSpeakerActive (FMOD_SPEAKER speaker, bool active); + FMOD_RESULT F_API getSpeakerActive (FMOD_SPEAKER speaker, bool *active); + FMOD_RESULT F_API reset (); + + + // DSP parameter control. + FMOD_RESULT F_API setParameter (int index, float value); + FMOD_RESULT F_API getParameter (int index, float *value, char *valuestr, int valuestrlen); + FMOD_RESULT F_API getNumParameters (int *numparams); + FMOD_RESULT F_API getParameterInfo (int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); + FMOD_RESULT F_API showConfigDialog (void *hwnd, bool show); + + // DSP attributes. + FMOD_RESULT F_API getInfo (char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); + FMOD_RESULT F_API getType (FMOD_DSP_TYPE *type); + FMOD_RESULT F_API setDefaults (float frequency, float volume, float pan, int priority); + FMOD_RESULT F_API getDefaults (float *frequency, float *volume, float *pan, int *priority); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'DSPConnection' API + */ + class DSPConnection + { + private: + + DSPConnection(); /* Constructor made private so user cannot statically instance a DSPConnection class. + Appropriate DSPConnection creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API getInput (DSP **input); + FMOD_RESULT F_API getOutput (DSP **output); + FMOD_RESULT F_API setMix (float volume); + FMOD_RESULT F_API getMix (float *volume); + FMOD_RESULT F_API setLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API getLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'Geometry' API + */ + class Geometry + { + private: + + Geometry(); /* Constructor made private so user cannot statically instance a Geometry class. + Appropriate Geometry creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API release (); + + // Polygon manipulation. + FMOD_RESULT F_API addPolygon (float directocclusion, float reverbocclusion, bool doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); + FMOD_RESULT F_API getNumPolygons (int *numpolygons); + FMOD_RESULT F_API getMaxPolygons (int *maxpolygons, int *maxvertices); + FMOD_RESULT F_API getPolygonNumVertices (int index, int *numvertices); + FMOD_RESULT F_API setPolygonVertex (int index, int vertexindex, const FMOD_VECTOR *vertex); + FMOD_RESULT F_API getPolygonVertex (int index, int vertexindex, FMOD_VECTOR *vertex); + FMOD_RESULT F_API setPolygonAttributes (int index, float directocclusion, float reverbocclusion, bool doublesided); + FMOD_RESULT F_API getPolygonAttributes (int index, float *directocclusion, float *reverbocclusion, bool *doublesided); + + // Object manipulation. + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + FMOD_RESULT F_API setRotation (const FMOD_VECTOR *forward, const FMOD_VECTOR *up); + FMOD_RESULT F_API getRotation (FMOD_VECTOR *forward, FMOD_VECTOR *up); + FMOD_RESULT F_API setPosition (const FMOD_VECTOR *position); + FMOD_RESULT F_API getPosition (FMOD_VECTOR *position); + FMOD_RESULT F_API setScale (const FMOD_VECTOR *scale); + FMOD_RESULT F_API getScale (FMOD_VECTOR *scale); + FMOD_RESULT F_API save (void *data, int *datasize); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'Reverb' API + */ + class Reverb + { + private: + + Reverb(); /* Constructor made private so user cannot statically instance a Reverb class. + Appropriate Reverb creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API release (); + + // Reverb manipulation. + FMOD_RESULT F_API set3DAttributes (const FMOD_VECTOR *position, float mindistance, float maxdistance); + FMOD_RESULT F_API get3DAttributes (FMOD_VECTOR *position, float *mindistance,float *maxdistance); + FMOD_RESULT F_API setProperties (const FMOD_REVERB_PROPERTIES *properties); + FMOD_RESULT F_API getProperties (FMOD_REVERB_PROPERTIES *properties); + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; +} + +#endif diff --git a/src/imports/fmodex/fmod_codec.h b/src/imports/fmodex/fmod_codec.h new file mode 100644 index 0000000..cd6c282 --- /dev/null +++ b/src/imports/fmodex/fmod_codec.h @@ -0,0 +1,159 @@ +/* ==================================================================================================== */ +/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you are wanting to develop your own file format plugin to use with */ +/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */ +/* can register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ==================================================================================================== */ + +#ifndef _FMOD_CODEC_H +#define _FMOD_CODEC_H + +typedef struct FMOD_CODEC_STATE FMOD_CODEC_STATE; +typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT; + +/* + Codec callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPENCALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSECALLBACK) (FMOD_CODEC_STATE *codec_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READCALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATACALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT) (FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating a codec, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value.
    + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_CODEC_STATE +] +*/ +typedef struct FMOD_CODEC_DESCRIPTION +{ + const char *name; /* [in] Name of the codec. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int defaultasstream; /* [in] Tells FMOD to open the file as a stream when calling System::createSound, and not a static sample. Should normally be 0 (FALSE), because generally the user wants to decode the file into memory when using System::createSound. Mainly used for formats that decode for a very long time, or could use large amounts of memory when decoded. Usually sequenced formats such as mod/s3m/xm/it/midi fall into this category. It is mainly to stop users that don't know what they're doing from getting FMOD_ERR_MEMORY returned from createSound when they should have in fact called System::createStream or used FMOD_CREATESTREAM in System::createSound. */ + FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these time formats will be passed to the codec. Use bitwise OR to accumulate different types. */ + FMOD_CODEC_OPENCALLBACK open; /* [in] Open callback for the codec for when FMOD tries to open a sound using this codec. */ + FMOD_CODEC_CLOSECALLBACK close; /* [in] Close callback for the codec for when FMOD tries to close a sound using this codec. */ + FMOD_CODEC_READCALLBACK read; /* [in] Read callback for the codec for when FMOD tries to read some data from the file to the destination format (specified in the open callback). */ + FMOD_CODEC_GETLENGTHCALLBACK getlength; /* [in] Callback to return the length of the song in whatever format required when Sound::getLength is called. */ + FMOD_CODEC_SETPOSITIONCALLBACK setposition; /* [in] Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition. */ + FMOD_CODEC_GETPOSITIONCALLBACK getposition; /* [in] Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition. */ + FMOD_CODEC_SOUNDCREATECALLBACK soundcreate; /* [in] Sound creation callback for the codec when FMOD finishes creating the sound. (So the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc). */ + FMOD_CODEC_GETWAVEFORMAT getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a particular subsound. This is to save memory, rather than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the codec, the codec might have a more optimal way of storing this information. */ +} FMOD_CODEC_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Set these values marked 'in' to tell fmod what sort of sound to create.
    + The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2.
    + Members marked as 'out' are set by fmod. Do not modify these. Simply specify 0 for these values when declaring the structure, FMOD will fill in the values for you after creation with the correct function pointers.
    + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value.
    + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    +
    + An FMOD file might be from disk, memory or network, however the file may be opened by the user.
    +
    + 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.
    + 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain instruments).
    + The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute.
    + When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_SOUND_FORMAT + FMOD_FILE_READCALLBACK + FMOD_FILE_SEEKCALLBACK + FMOD_CODEC_METADATACALLBACK + Sound::getSubSound + Sound::getNumSubSounds +] +*/ +struct FMOD_CODEC_WAVEFORMAT +{ + char name[256]; /* [in] Name of sound.*/ + FMOD_SOUND_FORMAT format; /* [in] Format for (decompressed) codec output, ie FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/ + int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo = 2. */ + int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */ + unsigned int lengthbytes; /* [in] Length in bytes of the source data. */ + unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the file, ie length in seconds * frequency. Used for Sound::getLength and for memory allocation of static decompressed sample data. */ + int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal decode chunk size for this format. The codec read callback will be called in multiples of this value. */ + int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */ + int loopend; /* [in] Loopend in decompressed, PCM samples of file. */ + FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default load as looping, non looping, 2d or 3d. */ + unsigned int channelmask; /* [in] Microsoft speaker channel mask, as defined for WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at 0 to play in natural speaker order. */ +}; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Codec plugin structure that is passed into each callback.
    +
    + Set these numsubsounds and waveformat members when called in FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create.
    +
    + The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2.
    + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value.
    + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    +
    + An FMOD file might be from disk, memory or internet, however the file may be opened by the user.
    +
    + 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.
    + 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), DLS (contain instruments).
    + The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute.
    + When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_SOUND_FORMAT + FMOD_FILE_READCALLBACK + FMOD_FILE_SEEKCALLBACK + FMOD_CODEC_METADATACALLBACK + Sound::getSubSound + Sound::getNumSubSounds +] +*/ +struct FMOD_CODEC_STATE +{ + int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc which contain 1 or more su bsounds). For most normal, single sound codec such as WAV/AIFF/MP3, this should be 0 as they are not a container for subsounds, they are the sound by itself. */ + FMOD_CODEC_WAVEFORMAT *waveformat; /* [in] Pointer to an array of format structures containing information about each sample. Can be 0 or NULL if FMOD_CODEC_GETWAVEFORMAT callback is preferred. The number of entries here must equal the number of subsounds defined in the subsound parameter. If numsubsounds = 0 then there should be 1 instance of this structure. */ + void *plugindata; /* [in] Plugin writer created data the codec author wants to attach to this object. */ + + void *filehandle; /* [out] This will return an internal FMOD file handle to use with the callbacks provided. */ + unsigned int filesize; /* [out] This will contain the size of the file in bytes. */ + FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD file function to use from codec. */ + FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD file function to use from codec. */ + FMOD_CODEC_METADATACALLBACK metadata; /* [out] This will return a callable FMOD metadata function to use from codec. */ +}; + +#endif + + diff --git a/src/imports/fmodex/fmod_dsp.h b/src/imports/fmodex/fmod_dsp.h new file mode 100644 index 0000000..0779c32 --- /dev/null +++ b/src/imports/fmodex/fmod_dsp.h @@ -0,0 +1,746 @@ +/* ========================================================================================== */ +/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you are interested in delving deeper into the FMOD software mixing / */ +/* DSP engine. In this header you can find parameter structures for FMOD system reigstered */ +/* DSP effects and generators. */ +/* Also use this header if you are wanting to develop your own DSP plugin to use with FMOD's */ +/* dsp system. With this header you can make your own DSP plugin that FMOD can */ +/* register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ========================================================================================== */ + +#ifndef _FMOD_DSP_H +#define _FMOD_DSP_H + +typedef struct FMOD_DSP_STATE FMOD_DSP_STATE; + +/* + DSP callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_CREATECALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RELEASECALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RESETCALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_READCALLBACK) (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPOSITIONCALLBACK)(FMOD_DSP_STATE *dsp_state, unsigned int pos); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float value); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_GETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_DIALOGCALLBACK) (FMOD_DSP_STATE *dsp_state, void *hwnd, int show); + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions can be used for creating FMOD defined special effects or DSP units. + + [REMARKS] + To get them to be active, first create the unit, then add it somewhere into the DSP network, either at the front of the network near the soundcard unit to affect the global output (by using System::getDSPHead), or on a single channel (using Channel::getDSPHead). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createDSPByType +] +*/ +typedef enum +{ + FMOD_DSP_TYPE_UNKNOWN, /* This unit was created via a non FMOD plugin so has an unknown purpose. */ + FMOD_DSP_TYPE_MIXER, /* This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. */ + FMOD_DSP_TYPE_OSCILLATOR, /* This unit generates sine/square/saw/triangle or noise tones. */ + FMOD_DSP_TYPE_LOWPASS, /* This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. */ + FMOD_DSP_TYPE_ITLOWPASS, /* This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). */ + FMOD_DSP_TYPE_HIGHPASS, /* This unit filters sound using a resonant highpass filter algorithm. */ + FMOD_DSP_TYPE_ECHO, /* This unit produces an echo on the sound and fades out at the desired rate. */ + FMOD_DSP_TYPE_FLANGE, /* This unit produces a flange effect on the sound. */ + FMOD_DSP_TYPE_DISTORTION, /* This unit distorts the sound. */ + FMOD_DSP_TYPE_NORMALIZE, /* This unit normalizes or amplifies the sound to a certain level. */ + FMOD_DSP_TYPE_PARAMEQ, /* This unit attenuates or amplifies a selected frequency range. */ + FMOD_DSP_TYPE_PITCHSHIFT, /* This unit bends the pitch of a sound without changing the speed of playback. */ + FMOD_DSP_TYPE_CHORUS, /* This unit produces a chorus effect on the sound. */ + FMOD_DSP_TYPE_VSTPLUGIN, /* This unit allows the use of Steinberg VST plugins */ + FMOD_DSP_TYPE_WINAMPPLUGIN, /* This unit allows the use of Nullsoft Winamp plugins */ + FMOD_DSP_TYPE_ITECHO, /* This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. */ + FMOD_DSP_TYPE_COMPRESSOR, /* This unit implements dynamic compression (linked multichannel, wideband) */ + FMOD_DSP_TYPE_SFXREVERB, /* This unit implements SFX reverb */ + FMOD_DSP_TYPE_LOWPASS_SIMPLE, /* This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. */ + FMOD_DSP_TYPE_DELAY, /* This unit produces different delays on individual channels of the sound. */ + FMOD_DSP_TYPE_TREMOLO, /* This unit produces a tremolo / chopper effect on the sound. */ + FMOD_DSP_TYPE_LADSPAPLUGIN, /* This unit allows the use of LADSPA standard plugins. */ + FMOD_DSP_TYPE_HIGHPASS_SIMPLE, /* This unit filters sound using a simple highpass with no resonance, but has flexible cutoff and is fast. */ + FMOD_DSP_TYPE_HARDWARE = 1000, /* Offset that platform specific FMOD_HARDWARE DSPs will start at. */ + FMOD_DSP_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_TYPE; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure to define a parameter for a DSP unit. + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createDSP + DSP::setParameter +] +*/ +typedef struct FMOD_DSP_PARAMETERDESC +{ + float min; /* [w] Minimum value of the parameter (ie 100.0). */ + float max; /* [w] Maximum value of the parameter (ie 22050.0). */ + float defaultval; /* [w] Default value of parameter. */ + char name[16]; /* [w] Name of the parameter to be displayed (ie "Cutoff frequency"). */ + char label[16]; /* [w] Short string to be put next to value to denote the unit type (ie "hz"). */ + const char *description; /* [w] Description of the parameter to be displayed as a help item / tooltip for this parameter. */ +} FMOD_DSP_PARAMETERDESC; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating a DSP unit, declare one of these and provide the relevant callbacks and name for FMOD to use when it creates and uses a DSP unit of this type. + + [REMARKS] +
    + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    +
    + IMPORTANT: The 'paramdesc' member should point to static memory, as FMOD references the data internally using the pointer provided. Do not store these parameter description structures on the stack, or in heap memory that is freed while FMOD is using it.
    +
    + There are 2 different ways to change a parameter in this architecture.
    + One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used.
    + The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createDSP + FMOD_DSP_STATE +] +*/ +typedef struct FMOD_DSP_DESCRIPTION +{ + char name[32]; /* [w] Name of the unit to be displayed in the network. */ + unsigned int version; /* [w] Plugin writer's version number. */ + int channels; /* [w] Number of channels. Use 0 to process whatever number of channels is currently in the network. >0 would be mostly used if the unit is a unit that only generates sound. */ + FMOD_DSP_CREATECALLBACK create; /* [w] Create callback. This is called when DSP unit is created. Can be null. */ + FMOD_DSP_RELEASECALLBACK release; /* [w] Release callback. This is called just before the unit is freed so the user can do any cleanup needed for the unit. Can be null. */ + FMOD_DSP_RESETCALLBACK reset; /* [w] Reset callback. This is called by the user to reset any history buffers that may need resetting for a filter, when it is to be used or re-used for the first time to its initial clean state. Use to avoid clicks or artifacts. */ + FMOD_DSP_READCALLBACK read; /* [w] Read callback. Processing is done here. Can be null. */ + FMOD_DSP_SETPOSITIONCALLBACK setposition; /* [w] Set position callback. This is called if the unit wants to update its position info but not process data, or reset a cursor position internally if it is reading data from a certain source. Can be null. */ + + int numparameters; /* [w] Number of parameters used in this filter. The user finds this with DSP::getNumParameters */ + FMOD_DSP_PARAMETERDESC *paramdesc; /* [w] Variable number of parameter structures. */ + FMOD_DSP_SETPARAMCALLBACK setparameter; /* [w] This is called when the user calls DSP::setParameter. Can be null. */ + FMOD_DSP_GETPARAMCALLBACK getparameter; /* [w] This is called when the user calls DSP::getParameter. Can be null. */ + FMOD_DSP_DIALOGCALLBACK config; /* [w] This is called when the user calls DSP::showConfigDialog. Can be used to display a dialog to configure the filter. Can be null. */ + int configwidth; /* [w] Width of config dialog graphic if there is one. 0 otherwise.*/ + int configheight; /* [w] Height of config dialog graphic if there is one. 0 otherwise.*/ + void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the DSP unit during creation. Access via DSP::getUserData. */ +} FMOD_DSP_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + DSP plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + Members marked with [w] mean the variable can be written to. The user can set the value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_DSP_DESCRIPTION +] +*/ +struct FMOD_DSP_STATE +{ + FMOD_DSP *instance; /* [r] Handle to the DSP hand the user created. Not to be modified. C++ users cast to FMOD::DSP to use. */ + void *plugindata; /* [w] Plugin writer created data the output author wants to attach to this object. */ + unsigned short speakermask; /* [w] Specifies which speakers the DSP effect is active on */ +}; + + +/* + =================================================================================================== + + FMOD built in effect parameters. + Use DSP::setParameter with these enums for the 'index' parameter. + + =================================================================================================== +*/ + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_OSCILLATOR filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_OSCILLATOR_TYPE, /* Waveform type. 0 = sine. 1 = square. 2 = sawup. 3 = sawdown. 4 = triangle. 5 = noise. */ + FMOD_DSP_OSCILLATOR_RATE /* Frequency of the sinewave in hz. 1.0 to 22000.0. Default = 220.0. */ +} FMOD_DSP_OSCILLATOR; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_LOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0. */ + FMOD_DSP_LOWPASS_RESONANCE /* Lowpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ +} FMOD_DSP_LOWPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITLOWPASS filter.
    + This is different to the default FMOD_DSP_TYPE_ITLOWPASS filter in that it uses a different quality algorithm and is + the filter used to produce the correct sounding playback in .IT files.
    + FMOD Ex's .IT playback uses this filter.
    + + [REMARKS] + Note! This filter actually has a limited cutoff frequency below the specified maximum, due to its limited design, + so for a more open range filter use FMOD_DSP_LOWPASS or if you don't mind not having resonance, + FMOD_DSP_LOWPASS_SIMPLE.
    + The effective maximum cutoff is about 8060hz. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_ITLOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0/ */ + FMOD_DSP_ITLOWPASS_RESONANCE /* Lowpass resonance Q value. 0.0 to 127.0. Default = 1.0. */ +} FMOD_DSP_ITLOWPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_HIGHPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_HIGHPASS_CUTOFF, /* Highpass cutoff frequency in hz. 1.0 to output 22000.0. Default = 5000.0. */ + FMOD_DSP_HIGHPASS_RESONANCE /* Highpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ +} FMOD_DSP_HIGHPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ECHO filter. + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer.
    + Larger echo delays result in larger amounts of memory allocated.
    +
    + 'maxchannels' also dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the echo unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel echo, etc.
    + If the echo effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes.
    + When the echo is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count.
    + If a channel echo is set to a lower number than the sound's channel count that is coming in, it will not echo the sound.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_ECHO_DELAY, /* Echo delay in ms. 10 to 5000. Default = 500. */ + FMOD_DSP_ECHO_DECAYRATIO, /* Echo decay per delay. 0 to 1. 1.0 = No decay, 0.0 = total decay (ie simple 1 line delay). Default = 0.5. */ + FMOD_DSP_ECHO_MAXCHANNELS, /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ + FMOD_DSP_ECHO_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 1.0. */ + FMOD_DSP_ECHO_WETMIX /* Volume of echo signal to pass to output. 0.0 to 1.0. Default = 1.0. */ +} FMOD_DSP_ECHO; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DELAY filter. + + [REMARKS] + Note. Every time MaxDelay is changed, the plugin re-allocates the delay buffer. This means the delay will dissapear at that time while it refills its new buffer.
    + A larger MaxDelay results in larger amounts of memory allocated.
    + Channel delays above MaxDelay will be clipped to MaxDelay and the delay buffer will not be resized.
    +
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_DELAY_CH0, /* Channel #0 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH1, /* Channel #1 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH2, /* Channel #2 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH3, /* Channel #3 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH4, /* Channel #4 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH5, /* Channel #5 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH6, /* Channel #6 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH7, /* Channel #7 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH8, /* Channel #8 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH9, /* Channel #9 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH10, /* Channel #10 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH11, /* Channel #11 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH12, /* Channel #12 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH13, /* Channel #13 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH14, /* Channel #14 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH15, /* Channel #15 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_MAXDELAY /* Maximum delay in ms. 0 to 10000. Default = 10. */ +} FMOD_DSP_DELAY; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_FLANGE filter. + + [REMARKS] + Flange is an effect where the signal is played twice at the same time, and one copy slides back and forth creating a whooshing or flanging effect.
    + As there are 2 copies of the same signal, by default each signal is given 50% mix, so that the total is not louder than the original unaffected signal.
    +
    + Flange depth is a percentage of a 10ms shift from the original signal. Anything above 10ms is not considered flange because to the ear it begins to 'echo' so 10ms is the highest value possible.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_FLANGE_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.45. */ + FMOD_DSP_FLANGE_WETMIX, /* Volume of flange signal to pass to output. 0.0 to 1.0. Default = 0.55. */ + FMOD_DSP_FLANGE_DEPTH, /* Flange depth (percentage of 40ms delay). 0.01 to 1.0. Default = 1.0. */ + FMOD_DSP_FLANGE_RATE /* Flange speed in hz. 0.0 to 20.0. Default = 0.1. */ +} FMOD_DSP_FLANGE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_TREMOLO filter. + + [REMARKS] + The tremolo effect varies the amplitude of a sound. Depending on the settings, this unit can produce a tremolo, chopper or auto-pan effect.
    +
    + The shape of the LFO (low freq. oscillator) can morphed between sine, triangle and sawtooth waves using the FMOD_DSP_TREMOLO_SHAPE and FMOD_DSP_TREMOLO_SKEW parameters.
    + FMOD_DSP_TREMOLO_DUTY and FMOD_DSP_TREMOLO_SQUARE are useful for a chopper-type effect where the first controls the on-time duration and second controls the flatness of the envelope.
    + FMOD_DSP_TREMOLO_SPREAD varies the LFO phase between channels to get an auto-pan effect. This works best with a sine shape LFO.
    + The LFO can be synchronized using the FMOD_DSP_TREMOLO_PHASE parameter which sets its instantaneous phase.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_TREMOLO_FREQUENCY, /* LFO frequency in Hz. 0.1 to 20. Default = 4. */ + FMOD_DSP_TREMOLO_DEPTH, /* Tremolo depth. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SHAPE, /* LFO shape morph between triangle and sine. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SKEW, /* Time-skewing of LFO cycle. -1 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_DUTY, /* LFO on-time. 0 to 1. Default = 0.5. */ + FMOD_DSP_TREMOLO_SQUARE, /* Flatness of the LFO shape. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_PHASE, /* Instantaneous LFO phase. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SPREAD /* Rotation / auto-pan effect. -1 to 1. Default = 0. */ +} FMOD_DSP_TREMOLO; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DISTORTION filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_DISTORTION_LEVEL /* Distortion value. 0.0 to 1.0. Default = 0.5. */ +} FMOD_DSP_DISTORTION; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_NORMALIZE filter. + + [REMARKS] + Normalize amplifies the sound based on the maximum peaks within the signal.
    + For example if the maximum peaks in the signal were 50% of the bandwidth, it would scale the whole sound by 2.
    + The lower threshold value makes the normalizer ignores peaks below a certain point, to avoid over-amplification if a loud signal suddenly came in, and also to avoid amplifying to maximum things like background hiss.
    +
    + Because FMOD is a realtime audio processor, it doesn't have the luxury of knowing the peak for the whole sound (ie it can't see into the future), so it has to process data as it comes in.
    + To avoid very sudden changes in volume level based on small samples of new data, fmod fades towards the desired amplification which makes for smooth gain control. The fadetime parameter can control this.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_NORMALIZE_FADETIME, /* Time to ramp the silence to full in ms. 0.0 to 20000.0. Default = 5000.0. */ + FMOD_DSP_NORMALIZE_THRESHHOLD, /* Lower volume range threshold to ignore. 0.0 to 1.0. Default = 0.1. Raise higher to stop amplification of very quiet signals. */ + FMOD_DSP_NORMALIZE_MAXAMP /* Maximum amplification allowed. 1.0 to 100000.0. Default = 20.0. 1.0 = no amplifaction, higher values allow more boost. */ +} FMOD_DSP_NORMALIZE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PARAMEQ filter. + + [REMARKS] + Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies.
    +
    + To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each.
    +
    + When a frequency has its gain set to 1.0, the sound will be unaffected and represents the original signal exactly.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_PARAMEQ_CENTER, /* Frequency center. 20.0 to 22000.0. Default = 8000.0. */ + FMOD_DSP_PARAMEQ_BANDWIDTH, /* Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0. */ + FMOD_DSP_PARAMEQ_GAIN /* Frequency Gain. 0.05 to 3.0. Default = 1.0. */ +} FMOD_DSP_PARAMEQ; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter. + + [REMARKS] + This pitch shifting unit can be used to change the pitch of a sound without speeding it up or slowing it down.
    + It can also be used for time stretching or scaling, for example if the pitch was doubled, and the frequency of the sound was halved, the pitch of the sound would sound correct but it would be twice as slow.
    +
    + Warning! This filter is very computationally expensive! Similar to a vocoder, it requires several overlapping FFT and IFFT's to produce smooth output, and can require around 440mhz for 1 stereo 48khz signal using the default settings.
    + Reducing the signal to mono will half the cpu usage.
    + Reducing this will lower audio quality, but what settings to use are largely dependant on the sound being played. A noisy polyphonic signal will need higher fft size compared to a speaking voice for example.
    +
    + This pitch shifter is based on the pitch shifter code at http://www.dspdimension.com, written by Stephan M. Bernsee.
    + The original code is COPYRIGHT 1999-2003 Stephan M. Bernsee .
    +
    + 'maxchannels' dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the pitch shift unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel pitch shift, etc.
    + If the pitch shift effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes.
    + When the pitch shift is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count.
    + If a channel pitch shift is set to a lower number than the sound's channel count that is coming in, it will not pitch shift the sound.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_PITCHSHIFT_PITCH, /* Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */ + FMOD_DSP_PITCHSHIFT_FFTSIZE, /* FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */ + FMOD_DSP_PITCHSHIFT_OVERLAP, /* Removed. Do not use. FMOD now uses 4 overlaps and cannot be changed. */ + FMOD_DSP_PITCHSHIFT_MAXCHANNELS /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ +} FMOD_DSP_PITCHSHIFT; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_CHORUS filter. + + [REMARKS] + Chrous is an effect where the sound is more 'spacious' due to 1 to 3 versions of the sound being played along side the original signal but with the pitch of each copy modulating on a sine wave.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_CHORUS_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX1, /* Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX2, /* Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX3, /* Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_DELAY, /* Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms. */ + FMOD_DSP_CHORUS_RATE, /* Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz. */ + FMOD_DSP_CHORUS_DEPTH /* Chorus modulation depth. 0.0 to 1.0. Default = 0.03. */ +} FMOD_DSP_CHORUS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITECHO filter.
    + This is effectively a software based echo filter that emulates the DirectX DMO echo effect. Impulse tracker files can support this, and FMOD will produce the effect on ANY platform, not just those that support DirectX effects!
    + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer.
    + Larger echo delays result in larger amounts of memory allocated.
    +
    + As this is a stereo filter made mainly for IT playback, it is targeted for stereo signals.
    + With mono signals only the FMOD_DSP_ITECHO_LEFTDELAY is used.
    + For multichannel signals (>2) there will be no echo on those channels.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP +] +*/ +typedef enum +{ + FMOD_DSP_ITECHO_WETDRYMIX, /* Ratio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0.0 through 100.0 (all wet). The default value is 50. */ + FMOD_DSP_ITECHO_FEEDBACK, /* Percentage of output fed back into input, in the range from 0.0 through 100.0. The default value is 50. */ + FMOD_DSP_ITECHO_LEFTDELAY, /* Delay for left channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + FMOD_DSP_ITECHO_RIGHTDELAY, /* Delay for right channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + FMOD_DSP_ITECHO_PANDELAY /* Value that specifies whether to swap left and right delays with each successive echo. The default value is zero, meaning no swap. Possible values are defined as 0.0 (equivalent to FALSE) and 1.0 (equivalent to TRUE). CURRENTLY NOT SUPPORTED. */ +} FMOD_DSP_ITECHO; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_COMPRESSOR unit. + This is a simple linked multichannel software limiter that is uniform across the whole spectrum.
    + + [REMARKS] + The limiter is not guaranteed to catch every peak above the threshold level, + because it cannot apply gain reduction instantaneously - the time delay is + determined by the attack time. However setting the attack time too short will + distort the sound, so it is a compromise. High level peaks can be avoided by + using a short attack time - but not too short, and setting the threshold a few + decibels below the critical level. +
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP +] +*/ +typedef enum +{ + FMOD_DSP_COMPRESSOR_THRESHOLD, /* Threshold level (dB) in the range from -60 through 0. The default value is 0. */ + FMOD_DSP_COMPRESSOR_ATTACK, /* Gain reduction attack time (milliseconds), in the range from 10 through 200. The default value is 50. */ + FMOD_DSP_COMPRESSOR_RELEASE, /* Gain reduction release time (milliseconds), in the range from 20 through 1000. The default value is 50. */ + FMOD_DSP_COMPRESSOR_GAINMAKEUP /* Make-up gain (dB) applied after limiting, in the range from 0 through 30. The default value is 0. */ +} FMOD_DSP_COMPRESSOR; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_SFXREVERB unit.
    + + [REMARKS] + This is a high quality I3DL2 based reverb.
    + On top of the I3DL2 property set, "Dry Level" is also included to allow the dry mix to be changed.
    +
    + These properties can be set with presets in FMOD_REVERB_PRESETS. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP + FMOD_REVERB_PRESETS +] +*/ +typedef enum +{ + FMOD_DSP_SFXREVERB_DRYLEVEL, /* Dry Level : Mix level of dry signal in output in mB. Ranges from -10000.0 to 0.0. Default is 0. */ + FMOD_DSP_SFXREVERB_ROOM, /* Room : Room effect level at low frequencies in mB. Ranges from -10000.0 to 0.0. Default is -10000.0. */ + FMOD_DSP_SFXREVERB_ROOMHF, /* Room HF : Room effect high-frequency level re. low frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_DECAYTIME, /* Decay Time : Reverberation decay time at low-frequencies in seconds. Ranges from 0.1 to 20.0. Default is 1.0. */ + FMOD_DSP_SFXREVERB_DECAYHFRATIO, /* Decay HF Ratio : High-frequency to low-frequency decay time ratio. Ranges from 0.1 to 2.0. Default is 0.5. */ + FMOD_DSP_SFXREVERB_REFLECTIONSLEVEL, /* Reflections : Early reflections level relative to room effect in mB. Ranges from -10000.0 to 1000.0. Default is -10000.0. */ + FMOD_DSP_SFXREVERB_REFLECTIONSDELAY, /* Reflect Delay : Delay time of first reflection in seconds. Ranges from 0.0 to 0.3. Default is 0.02. */ + FMOD_DSP_SFXREVERB_REVERBLEVEL, /* Reverb : Late reverberation level relative to room effect in mB. Ranges from -10000.0 to 2000.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_REVERBDELAY, /* Reverb Delay : Late reverberation delay time relative to first reflection in seconds. Ranges from 0.0 to 0.1. Default is 0.04. */ + FMOD_DSP_SFXREVERB_DIFFUSION, /* Diffusion : Reverberation diffusion (echo density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + FMOD_DSP_SFXREVERB_DENSITY, /* Density : Reverberation density (modal density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + FMOD_DSP_SFXREVERB_HFREFERENCE, /* HF Reference : Reference high frequency in Hz. Ranges from 20.0 to 20000.0. Default is 5000.0. */ + FMOD_DSP_SFXREVERB_ROOMLF, /* Room LF : Room effect low-frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_LFREFERENCE /* LF Reference : Reference low-frequency in Hz. Ranges from 20.0 to 1000.0. Default is 250.0. */ +} FMOD_DSP_SFXREVERB; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS_SIMPLE filter.
    + This is a very simple low pass filter, based on two single-pole RC time-constant modules. + The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering.
    + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_LOWPASS_SIMPLE_CUTOFF /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0 */ +} FMOD_DSP_LOWPASS_SIMPLE; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_HIGHPASS_SIMPLE filter.
    + This is a very simple single-order high pass filter. + The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering.
    + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_HIGHPASS_SIMPLE_CUTOFF /* Highpass cutoff frequency in hz. 10.0 to 22000.0. Default = 1000.0 */ +} FMOD_DSP_HIGHPASS_SIMPLE; + +#endif + diff --git a/src/imports/fmodex/fmod_errors.h b/src/imports/fmodex/fmod_errors.h new file mode 100644 index 0000000..36c8a6f --- /dev/null +++ b/src/imports/fmodex/fmod_errors.h @@ -0,0 +1,127 @@ +/*$ preserve start $*/ + +/* ============================================================================================== */ +/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you want to store or display a string version / english explanation of */ +/* the FMOD error codes. */ +/* */ +/* ============================================================================================== */ + +#ifndef _FMOD_ERRORS_H +#define _FMOD_ERRORS_H + +#include "fmod.h" + +#ifdef __GNUC__ +static const char *FMOD_ErrorString(FMOD_RESULT errcode) __attribute__((unused)); +#endif + +static const char *FMOD_ErrorString(FMOD_RESULT errcode) +{ + switch (errcode) + { +/*$ preserve end $*/ + case FMOD_ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. "; + case FMOD_ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). "; + case FMOD_ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. "; + case FMOD_ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. "; + case FMOD_ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. "; + case FMOD_ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. "; + case FMOD_ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. "; + case FMOD_ERR_CDDA_NODISC: return "No disc present in the specified drive. "; + case FMOD_ERR_CDDA_READ: return "A CDDA read error occurred. "; + case FMOD_ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. "; + case FMOD_ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. "; + case FMOD_ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. "; + case FMOD_ERR_DMA: return "DMA Failure. See debug output for more information. "; + case FMOD_ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). "; + case FMOD_ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. "; + case FMOD_ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. "; + case FMOD_ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. "; + case FMOD_ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. "; + case FMOD_ERR_EVENT_ALREADY_LOADED: return "The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. "; + case FMOD_ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. "; + case FMOD_ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. "; + case FMOD_ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. "; + case FMOD_ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. "; + case FMOD_ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. "; + case FMOD_ERR_EVENT_MISMATCH: return "FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. "; + case FMOD_ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. "; + case FMOD_ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. "; + case FMOD_ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. "; + case FMOD_ERR_FILE_BAD: return "Error loading file. "; + case FMOD_ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. "; + case FMOD_ERR_FILE_DISKEJECTED: return "Media was ejected while reading. "; + case FMOD_ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). "; + case FMOD_ERR_FILE_NOTFOUND: return "File not found. "; + case FMOD_ERR_FILE_UNWANTED: return "Unwanted file access occured. "; + case FMOD_ERR_FORMAT: return "Unsupported file or audio format. "; + case FMOD_ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. "; + case FMOD_ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. "; + case FMOD_ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. "; + case FMOD_ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. "; + case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out. "; + case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. "; + case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init. "; + case FMOD_ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. "; + case FMOD_ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) "; + case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. "; + case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used. "; + case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. "; + case FMOD_ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. "; + case FMOD_ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. "; + case FMOD_ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle. "; + case FMOD_ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. "; + case FMOD_ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. "; + case FMOD_ERR_MEMORY: return "Not enough memory or resources. "; + case FMOD_ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. "; + case FMOD_ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. "; + case FMOD_ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. "; + case FMOD_ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found. "; + case FMOD_ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. "; + case FMOD_ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. "; + case FMOD_ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. "; + case FMOD_ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). "; + case FMOD_ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. "; + case FMOD_ERR_NET_CONNECT: return "Couldn't connect to the specified host. "; + case FMOD_ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. "; + case FMOD_ERR_NET_URL: return "The specified URL couldn't be resolved. "; + case FMOD_ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. "; + case FMOD_ERR_NOTREADY: return "Operation could not be performed because specified sound/DSP connection is not ready. "; + case FMOD_ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. "; + case FMOD_ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. "; + case FMOD_ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. "; + case FMOD_ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. "; + case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). "; + case FMOD_ERR_OUTPUT_INIT: return "Error initializing output device. "; + case FMOD_ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. "; + case FMOD_ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. "; + case FMOD_ERR_PAN: return "Panning only works with mono or stereo sound sources. "; + case FMOD_ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. "; + case FMOD_ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded. "; + case FMOD_ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. "; + case FMOD_ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) "; + case FMOD_ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. "; + case FMOD_ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. "; + case FMOD_ERR_RECORD: return "An error occured trying to initialize the recording device. "; + case FMOD_ERR_REVERB_INSTANCE: return "Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. "; + case FMOD_ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. "; + case FMOD_ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. "; + case FMOD_ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. "; + case FMOD_ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. "; + case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. "; + case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. "; + case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! "; + case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. "; + case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. "; + case FMOD_ERR_UPDATE: return "An error caused by System::update occured. "; + case FMOD_ERR_VERSION: return "The version number of this file format is not supported. "; + case FMOD_OK: return "No errors."; + default : return "Unknown error."; +/*$ preserve start $*/ + }; +} + +#endif +/*$ preserve end $*/ diff --git a/src/imports/fmodex/fmod_memoryinfo.h b/src/imports/fmodex/fmod_memoryinfo.h new file mode 100644 index 0000000..0a40a28 --- /dev/null +++ b/src/imports/fmodex/fmod_memoryinfo.h @@ -0,0 +1,201 @@ +/* ============================================================================================= */ +/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2016. */ +/* */ +/* Use this header if you are interested in getting detailed information on FMOD's memory */ +/* usage. See the documentation for more details. */ +/* */ +/* ============================================================================================= */ + +#ifndef _FMOD_MEMORYINFO_H +#define _FMOD_MEMORYINFO_H + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure to be filled with detailed memory usage information of an FMOD object + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes.
    +
    + Members marked with [in] mean the user sets the value before passing it to the function.
    + Members marked with [out] mean FMOD sets the value to be used after the function exits.
    + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getMemoryInfo + EventSystem::getMemoryInfo + FMOD_MEMBITS + FMOD_EVENT_MEMBITS +] +*/ +typedef struct FMOD_MEMORY_USAGE_DETAILS +{ + unsigned int other; /* [out] Memory not accounted for by other types */ + unsigned int string; /* [out] String data */ + unsigned int system; /* [out] System object and various internals */ + unsigned int plugins; /* [out] Plugin objects and internals */ + unsigned int output; /* [out] Output module object and internals */ + unsigned int channel; /* [out] Channel related memory */ + unsigned int channelgroup; /* [out] ChannelGroup objects and internals */ + unsigned int codec; /* [out] Codecs allocated for streaming */ + unsigned int file; /* [out] File buffers and structures */ + unsigned int sound; /* [out] Sound objects and internals */ + unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */ + unsigned int soundgroup; /* [out] SoundGroup objects and internals */ + unsigned int streambuffer; /* [out] Stream buffer memory */ + unsigned int dspconnection; /* [out] DSPConnection objects and internals */ + unsigned int dsp; /* [out] DSP implementation objects */ + unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */ + unsigned int profile; /* [out] Profiler memory footprint. */ + unsigned int recordbuffer; /* [out] Buffer used to store recorded data from microphone */ + unsigned int reverb; /* [out] Reverb implementation objects */ + unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */ + unsigned int geometry; /* [out] Geometry objects and internals */ + unsigned int syncpoint; /* [out] Sync point memory. */ + unsigned int eventsystem; /* [out] EventSystem and various internals */ + unsigned int musicsystem; /* [out] MusicSystem and various internals */ + unsigned int fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */ + unsigned int memoryfsb; /* [out] Data loaded with preloadFSB */ + unsigned int eventproject; /* [out] EventProject objects and internals */ + unsigned int eventgroupi; /* [out] EventGroup objects and internals */ + unsigned int soundbankclass; /* [out] Objects used to manage wave banks */ + unsigned int soundbanklist; /* [out] Data used to manage lists of wave bank usage */ + unsigned int streaminstance; /* [out] Stream objects and internals */ + unsigned int sounddefclass; /* [out] Sound definition objects */ + unsigned int sounddefdefclass; /* [out] Sound definition static data objects */ + unsigned int sounddefpool; /* [out] Sound definition pool data */ + unsigned int reverbdef; /* [out] Reverb definition objects */ + unsigned int eventreverb; /* [out] Reverb objects */ + unsigned int userproperty; /* [out] User property objects */ + unsigned int eventinstance; /* [out] Event instance base objects */ + unsigned int eventinstance_complex; /* [out] Complex event instance objects */ + unsigned int eventinstance_simple; /* [out] Simple event instance objects */ + unsigned int eventinstance_layer; /* [out] Event layer instance objects */ + unsigned int eventinstance_sound; /* [out] Event sound instance objects */ + unsigned int eventenvelope; /* [out] Event envelope objects */ + unsigned int eventenvelopedef; /* [out] Event envelope definition objects */ + unsigned int eventparameter; /* [out] Event parameter objects */ + unsigned int eventcategory; /* [out] Event category objects */ + unsigned int eventenvelopepoint; /* [out] Event envelope point objects */ + unsigned int eventinstancepool; /* [out] Event instance pool memory */ +} FMOD_MEMORY_USAGE_DETAILS; + + +/* +[DEFINE] +[ + [NAME] + FMOD_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class. + Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage. + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_EVENT_MEMBITS + System::getMemoryInfo +] +*/ +#define FMOD_MEMBITS_OTHER 0x00000001 /* Memory not accounted for by other types */ +#define FMOD_MEMBITS_STRING 0x00000002 /* String data */ + +#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals */ +#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */ +#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals */ +#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */ +#define FMOD_MEMBITS_CHANNELGROUP 0x00000040 /* ChannelGroup objects and internals */ +#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */ +#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */ +#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */ +#define FMOD_MEMBITS_SOUND_SECONDARYRAM 0x00000400 /* Sound data stored in secondary RAM */ +#define FMOD_MEMBITS_SOUNDGROUP 0x00000800 /* SoundGroup objects and internals */ +#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */ +#define FMOD_MEMBITS_DSPCONNECTION 0x00002000 /* DSPConnection objects and internals */ +#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */ +#define FMOD_MEMBITS_DSPCODEC 0x00008000 /* Realtime file format decoding DSP objects */ +#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */ +#define FMOD_MEMBITS_RECORDBUFFER 0x00020000 /* Buffer used to store recorded data from microphone */ +#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */ +#define FMOD_MEMBITS_REVERBCHANNELPROPS 0x00080000 /* Reverb channel properties structs */ +#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */ +#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */ +#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */ +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_EVENT_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class. + Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage. + + [REMARKS] + Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_MEMBITS + System::getMemoryInfo +] +*/ +#define FMOD_EVENT_MEMBITS_EVENTSYSTEM 0x00000001 /* EventSystem and various internals */ +#define FMOD_EVENT_MEMBITS_MUSICSYSTEM 0x00000002 /* MusicSystem and various internals */ +#define FMOD_EVENT_MEMBITS_FEV 0x00000004 /* Definition of objects contained in all loaded projects e.g. events, groups, categories */ +#define FMOD_EVENT_MEMBITS_MEMORYFSB 0x00000008 /* Data loaded with preloadFSB */ +#define FMOD_EVENT_MEMBITS_EVENTPROJECT 0x00000010 /* EventProject objects and internals */ +#define FMOD_EVENT_MEMBITS_EVENTGROUPI 0x00000020 /* EventGroup objects and internals */ +#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS 0x00000040 /* Objects used to manage wave banks */ +#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST 0x00000080 /* Data used to manage lists of wave bank usage */ +#define FMOD_EVENT_MEMBITS_STREAMINSTANCE 0x00000100 /* Stream objects and internals */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS 0x00000200 /* Sound definition objects */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS 0x00000400 /* Sound definition static data objects */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL 0x00000800 /* Sound definition pool data */ +#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects */ +#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */ +#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE 0x00008000 /* Event instance base objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX 0x00010000 /* Complex event instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE 0x00020000 /* Simple event instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER 0x00040000 /* Event layer instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND 0x00080000 /* Event sound instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF 0x00200000 /* Event envelope definition objects */ +#define FMOD_EVENT_MEMBITS_EVENTPARAMETER 0x00400000 /* Event parameter objects */ +#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT 0x01000000 /* Event envelope point object+s */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL 0x02000000 /* Event instance pool data */ +#define FMOD_EVENT_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Event System */ + +/* All event instance memory */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP (FMOD_EVENT_MEMBITS_EVENTINSTANCE | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND) + +/* All sound definition memory */ +#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP (FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | \ + FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \ + FMOD_EVENT_MEMBITS_SOUNDDEFPOOL) +/* [DEFINE_END] */ + +#endif diff --git a/src/imports/fmodex/fmod_output.h b/src/imports/fmodex/fmod_output.h new file mode 100644 index 0000000..33748a7 --- /dev/null +++ b/src/imports/fmodex/fmod_output.h @@ -0,0 +1,93 @@ +/* ==================================================================================================== */ +/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you are wanting to develop your own output plugin to use with */ +/* FMOD's output system. With this header you can make your own output plugin that FMOD */ +/* can register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ==================================================================================================== */ + +#ifndef _FMOD_OUTPUT_H +#define _FMOD_OUTPUT_H + +#include "fmod.h" + +typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE; + +/* + Output callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int *numdrivers); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_INITCALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, int outputchannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int dspnumbuffers, void *extradriverdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK) (FMOD_OUTPUT_STATE *output_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK) (FMOD_OUTPUT_STATE *output_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int *pcm); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_READFROMMIXER) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating an output, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file of this type. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value.
    + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_OUTPUT_STATE +] +*/ +typedef struct FMOD_OUTPUT_DESCRIPTION +{ + const char *name; /* [in] Name of the output. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and call getposition / lock / unlock for feeding data. If 0, the output is probably callback based, so all the plugin needs to do is call readfrommixer to the appropriate pointer. */ + FMOD_OUTPUT_GETNUMDRIVERSCALLBACK getnumdrivers; /* [in] For sound device enumeration. This callback is to give System::getNumDrivers somthing to return. */ + FMOD_OUTPUT_GETDRIVERNAMECALLBACK getdrivername; /* [in] For sound device enumeration. This callback is to give System::getDriverName somthing to return. */ + FMOD_OUTPUT_GETDRIVERCAPSCALLBACK getdrivercaps; /* [in] For sound device enumeration. This callback is to give System::getDriverCaps somthing to return. */ + FMOD_OUTPUT_INITCALLBACK init; /* [in] Initialization function for the output device. This is called from System::init. */ + FMOD_OUTPUT_CLOSECALLBACK close; /* [in] Cleanup / close down function for the output device. This is called from System::close. */ + FMOD_OUTPUT_UPDATECALLBACK update; /* [in] Update function that is called once a frame by the user. This is called from System::update. */ + FMOD_OUTPUT_GETHANDLECALLBACK gethandle; /* [in] This is called from System::getOutputHandle. This is just to return a pointer to the internal system device object that the system may be using.*/ + FMOD_OUTPUT_GETPOSITIONCALLBACK getposition; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This returns a position value in samples so that FMOD knows where and when to fill its buffer. */ + FMOD_OUTPUT_LOCKCALLBACK lock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This function provides a pointer to data that FMOD can write to when software mixing. */ + FMOD_OUTPUT_UNLOCKCALLBACK unlock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This optional function accepts the data that has been mixed and copies it or does whatever it needs to before sending it to the hardware. */ +} FMOD_OUTPUT_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Output plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value.
    + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_OUTPUT_DESCRIPTION +] +*/ +struct FMOD_OUTPUT_STATE +{ + void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */ + FMOD_OUTPUT_READFROMMIXER readfrommixer; /* [out] Function to update mixer and write the result to the provided pointer. Used from callback based output only. Polling based output uses lock/unlock/getposition. */ +}; + +#endif + + diff --git a/src/imports/fmodex/fmodlinux.h b/src/imports/fmodex/fmodlinux.h new file mode 100644 index 0000000..22bfc6a --- /dev/null +++ b/src/imports/fmodex/fmodlinux.h @@ -0,0 +1,36 @@ +/* =========================================================================================== */ +/* FMOD Linux Specific header file. Copyright (c), Firelight Technologies Pty, Ltd. 2005-2016. */ +/* =========================================================================================== */ + +#ifndef _FMODLINUX_H +#define _FMODLINUX_H + +#include "fmod.h" + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Use this structure with System::init to set the information required for linux + initialisation. + + Pass this structure in as the "extradriverdata" parameter in System::init. + + [REMARKS] + + [PLATFORMS] + Linux, Linux64 + + [SEE_ALSO] + System::init +] +*/ +typedef struct FMOD_LINUX_EXTRADRIVERDATA +{ + const char *output_driver_arguments; /* ALSA Only - Arguments to apply to the selected output driver */ + const char *record_driver_arguments; /* ALSA Only - Arguments to apply to the selected input (record) driver */ +} FMOD_LINUX_EXTRADRIVERDATA; + +#endif + diff --git a/src/main/asset/f2/lib/usb-rank.c b/src/main/asset/f2/lib/usb-rank.c new file mode 100644 index 0000000..ebb90d7 --- /dev/null +++ b/src/main/asset/f2/lib/usb-rank.c @@ -0,0 +1,49 @@ +#include "util/adler32.h" + +#include "usb-rank.h" + +#define ENC_DEC_INIT_SEED 0xEBADA1 + +struct asset_f2_usb_rank* asset_f2_usb_rank_new(void) +{ + // TODO + return malloc(sizeof(struct asset_f2_usb_rank)); +} + +void asset_f2_usb_rank_finalize(struct asset_f2_usb_rank* rank) +{ + /* don't include the checksum field */ + /* + rank->header.adler32 = util_adler32_calc(rank->header.adler_seed, + &rank->header.adler_seed, + sizeof(struct f2_profile_rank) - sizeof(uint32_t)); + */ +} + +char* asset_f2_usb_rank_to_string(const struct asset_f2_usb_rank* rank) +{ + // TODO + return ""; +} + +void asset_f2_usb_rank_decrypt(uint8_t* buf, size_t len) +{ + uint32_t seed = ENC_DEC_INIT_SEED; + + for (int i = 0; i < len; i++){ + uint8_t smbuff = buf[i]; + buf[i] ^= (seed >> 8) & 0xff ; + seed = 0x68993 * (smbuff + seed) + 0x4FDCF; + } +} + +void asset_f2_usb_rank_encrypt(uint8_t* buf, size_t len) +{ + uint32_t seed = ENC_DEC_INIT_SEED; + + for (size_t i = 0; i < len; i++){ + uint8_t smbuff = buf[i] ^ ((seed >> 8) & 0xff); + buf[i] = smbuff ; + seed = 0x68993 * (smbuff + seed) + 0x4FDCF; + } +} \ No newline at end of file diff --git a/src/main/asset/f2/lib/usb-rank.h b/src/main/asset/f2/lib/usb-rank.h new file mode 100644 index 0000000..9eb279c --- /dev/null +++ b/src/main/asset/f2/lib/usb-rank.h @@ -0,0 +1,21 @@ +#ifndef ASSET_F2_USB_RANK_H +#define ASSET_F2_USB_RANK_H + +#include + +struct asset_f2_usb_rank { + // TODO +} __attribute__((__packed__)); + +struct asset_f2_usb_rank* asset_f2_usb_rank_new(void); + +// update checksum and prepare profile to get encrypted +void asset_f2_usb_rank_finalize(struct asset_f2_usb_rank* rank); + +char* asset_f2_usb_rank_to_string(const struct asset_f2_usb_rank* rank); + +void asset_f2_usb_rank_decrypt(uint8_t* buf, size_t len); + +void asset_f2_usb_rank_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/f2/lib/usb-save.c b/src/main/asset/f2/lib/usb-save.c new file mode 100644 index 0000000..5fd8b5e --- /dev/null +++ b/src/main/asset/f2/lib/usb-save.c @@ -0,0 +1,47 @@ +#include "util/adler32.h" + +#include "usb-save.h" + +#define ENC_DEC_INIT_SEED 0xEBADA1 + +struct asset_f2_usb_save* asset_f2_usb_save_new(void) +{ + // TODO + return malloc(sizeof(struct asset_f2_usb_save)); +} + +void asset_f2_usb_save_finalize(struct asset_f2_usb_save* save) +{ + /* don't include the checksum field */ + save->header.adler32 = util_adler32_calc(save->header.adler_seed, + &save->header.adler_seed, + sizeof(struct asset_f2_usb_save) - sizeof(uint32_t)); +} + +char* asset_f2_usb_save_to_string(const struct asset_f2_usb_save* save) +{ + // TODO + return ""; +} + +void asset_f2_usb_save_decrypt(uint8_t* buf, size_t len) +{ + uint32_t seed = ENC_DEC_INIT_SEED; + + for (int i = 0; i < len; i++){ + uint8_t smbuff = buf[i]; + buf[i] ^= (seed >> 8) & 0xff ; + seed = 0x68993 * (smbuff + seed) + 0x4FDCF; + } +} + +void asset_f2_usb_save_encrypt(uint8_t* buf, size_t len) +{ + uint32_t seed = ENC_DEC_INIT_SEED; + + for (size_t i = 0; i < len; i++){ + uint8_t smbuff = buf[i] ^ (seed >> 8) & 0xff; + buf[i] = smbuff ; + seed = 0x68993 * (smbuff + seed) + 0x4FDCF; + } +} \ No newline at end of file diff --git a/src/main/asset/f2/lib/usb-save.h b/src/main/asset/f2/lib/usb-save.h new file mode 100644 index 0000000..0bc84fc --- /dev/null +++ b/src/main/asset/f2/lib/usb-save.h @@ -0,0 +1,105 @@ +#ifndef ASSET_F2_USB_SAVE_H +#define ASSET_F2_USB_SAVE_H + +#include +#include + +struct asset_f2_usb_save_machine_stats { + uint32_t beginner_mode_play_count; + uint32_t maniac_mode_play_count; + uint32_t unkn; + uint32_t unkn2; + uint32_t battle_mode_play_count; + uint32_t mission_zone_play_count; + uint32_t skill_zone_play_count; + uint32_t coop_mission_play_count; +} __attribute__((__packed__)); + +struct asset_f2_usb_save_machine_info { + /* NULL terminated */ + char version[8]; + /* NULL terminated */ + char cpu[128]; + /* NULL terminated */ + char motherboard[128]; + /* NULL terminated */ + char gfxcard[128]; + /* NULL terminated */ + char hdd[32]; + uint32_t total_ram_bytes; + uint32_t haspkey_id; +} __attribute__((__packed__)); + +struct asset_f2_usb_save_header { + uint32_t adler32; + uint32_t adler_seed; + /* NULL terminated */ + char player_id[8]; + uint32_t region; + uint32_t avatar_id; + uint32_t level; + float total_calories; + float total_v02; + uint64_t num_running_steps; + uint64_t num_games_played; + uint64_t exp; + uint64_t arcade_score; + uint32_t num_missions_completed; + uint32_t num_coop_missions_completed; + uint32_t battle_count_wins; + uint32_t battle_count_loses; + uint32_t battle_count_draws; + /* TODO: modifier stuff? */ + uint64_t unlock; + uint32_t unlock_seed; +} __attribute__((__packed__)); + +struct asset_f2_usb_save_machine_highscore_entry { + uint32_t song_id; + uint8_t difficulty; + uint8_t mode; + uint8_t grade; + uint8_t clear_state; + uint32_t score_total; + uint32_t play_count; + uint32_t unkn; + /* NULL terminated */ + char player_id[8]; + uint32_t unkn2; + uint32_t null_padding; +} __attribute__((__packed__)); + +struct asset_f2_usb_save_highscore_entry { + uint32_t song_id; + uint8_t difficulty; + uint8_t mode; + uint8_t grade; + uint8_t clear_and_unlock_state; + uint32_t score_total; + uint32_t play_count; + uint32_t null_padding; +} __attribute__((__packed__)); + +struct asset_f2_usb_save { + /* start offset: 0x00 */ + struct asset_f2_usb_save_header header; + /* start offset: 0x120 */ + struct asset_f2_usb_save_machine_info machine_info; + struct asset_f2_usb_save_machine_stats machine_stats; + /* start offset: 0x2F0 */ + + // TODO continue +} __attribute__((__packed__)); + +struct asset_f2_usb_save* asset_f2_usb_save_new(void); + +// update checksum and prepare profile to get encrypted +void asset_f2_usb_save_finalize(struct asset_f2_usb_save* save); + +char* asset_f2_usb_save_to_string(const struct asset_f2_usb_save* save); + +void asset_f2_usb_save_decrypt(uint8_t* buf, size_t len); + +void asset_f2_usb_save_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/f2/lib/util.c b/src/main/asset/f2/lib/util.c new file mode 100644 index 0000000..3d69017 --- /dev/null +++ b/src/main/asset/f2/lib/util.c @@ -0,0 +1,96 @@ +#define LOG_MODULE "asset-f2-util" + +#include + +#include "util/fs.h" +#include "util/log.h" + +#include "util.h" + +struct asset_f2_usb_rank* asset_f2_util_rank_usb_load_from_file(const char* path, bool encrypted) +{ + struct asset_f2_usb_rank* rank; + size_t size; + + if (!util_file_load(path, (void**) &rank, &size, false)) { + log_error("Loading f2 rank file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_f2_usb_rank)) { + log_error("Invalid size of f2 rank file %s: %d != %d", path, size, + sizeof(struct asset_f2_usb_rank)); + free(rank); + return NULL; + } + + if (encrypted) { + asset_f2_usb_rank_decrypt((uint8_t*) rank, size); + } + + return rank; +} + +bool asset_f2_util_rank_usb_save_to_file(const char* path, const struct asset_f2_usb_rank* rank, bool encrypt) +{ + struct asset_f2_usb_rank rank_enc; + + memcpy(&rank_enc, rank, sizeof(struct asset_f2_usb_rank)); + + if (encrypt) { + asset_f2_usb_rank_encrypt((uint8_t*) &rank_enc, + sizeof(struct asset_f2_usb_rank)); + } + + if (!util_file_save(path, (void**) &rank_enc, + sizeof(struct asset_f2_usb_rank))) { + log_error("Storing f2 rank data to %s failed", path); + return false; + } + + return true; +} + +struct asset_f2_usb_save* asset_f2_util_usb_save_load_from_file(const char* path, bool encrypted) +{ + struct asset_f2_usb_save* save; + size_t size; + + if (!util_file_load(path, (void**) &save, &size, false)) { + log_error("Loading f2 save file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_f2_usb_save)) { + log_error("Invalid size of f2 save file %s: %d != %d", path, size, + sizeof(struct asset_f2_usb_save)); + free(save); + return NULL; + } + + if (encrypted) { + asset_f2_usb_save_decrypt((uint8_t*) save, size); + } + + return save; +} + +bool asset_f2_util_usb_save_save_to_file(const char* path, const struct asset_f2_usb_save* save, bool encrypt) +{ + struct asset_f2_usb_save save_enc; + + memcpy(&save_enc, save, sizeof(struct asset_f2_usb_save)); + + if (encrypt) { + asset_f2_usb_save_encrypt((uint8_t*) &save_enc, + sizeof(struct asset_f2_usb_save)); + } + + if (!util_file_save(path, (const void*) &save_enc, + sizeof(struct asset_f2_usb_save))) { + log_error("Storing f2 save data to %s failed", path); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/main/asset/f2/lib/util.h b/src/main/asset/f2/lib/util.h new file mode 100644 index 0000000..7870793 --- /dev/null +++ b/src/main/asset/f2/lib/util.h @@ -0,0 +1,21 @@ +#ifndef ASSET_F2_UTIL_H +#define ASSET_F2_UTIL_H + +#include + +#include "usb-rank.h" +#include "usb-save.h" + +// load from file and decrypt, returns decrypted struct +struct asset_f2_usb_rank* asset_f2_util_usb_rank_load_from_file(const char* path, bool encrypted); + +// takes decrypted rank data, encrypts it and writes it to file +bool asset_f2_util_usb_rank_save_to_file(const char* path, const struct asset_f2_usb_rank* rank, bool encrypt); + +// load from file and decrypt, returns decrypted struct +struct asset_f2_usb_save* asset_f2_util_usb_save_load_from_file(const char* path, bool encrypted); + +// takes decrypted save data, encrypts it and writes it to file +bool asset_f2_util_usb_save_save_to_file(const char* path, const struct asset_f2_usb_save* save, bool encrypt); + +#endif \ No newline at end of file diff --git a/src/main/asset/fex/lib/usb-rank.c b/src/main/asset/fex/lib/usb-rank.c new file mode 100644 index 0000000..4d0515c --- /dev/null +++ b/src/main/asset/fex/lib/usb-rank.c @@ -0,0 +1,32 @@ +#define LOG_MODULE "fex-profile-rank" + +#include "usb-rank.h" + +struct asset_fex_usb_rank* asset_fex_usb_rank_new(void) +{ + return malloc(sizeof(struct asset_fex_usb_rank)); +} + +void asset_fex_usb_rank_finalize(struct asset_fex_usb_rank* rank) +{ + +} + +char* asset_fex_usb_rank_to_string(const struct asset_fex_usb_rank* rank) +{ + return malloc(0); +} + +void asset_fex_usb_rank_decrypt(uint8_t* buf, size_t len) +{ + for (size_t a = len - 1; a > 0; --a) { + buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8); + } +} + +void asset_fex_usb_rank_encrypt(uint8_t* buf, size_t len) +{ + for (size_t a = 1; a < len; ++a) { + buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1]; + } +} \ No newline at end of file diff --git a/src/main/asset/fex/lib/usb-rank.h b/src/main/asset/fex/lib/usb-rank.h new file mode 100644 index 0000000..3154275 --- /dev/null +++ b/src/main/asset/fex/lib/usb-rank.h @@ -0,0 +1,28 @@ +#ifndef ASSET_FEX_USB_RANK_H +#define ASSET_FEX_USB_RANK_H + +#include +#include + +struct asset_fex_usb_rank_header { + uint32_t adler32; + /* NULL terminated */ + char player_id[8]; +} __attribute__((__packed__)); + +struct asset_fex_usb_rank { + struct asset_fex_usb_rank_header header; +} __attribute__((__packed__)); + +struct asset_fex_usb_rank* asset_fex_usb_rank_new(void); + +// update checksum and prepare profile to get encrypted +void asset_fex_usb_rank_finalize(struct asset_fex_usb_rank* rank); + +char* asset_fex_usb_rank_to_string(const struct asset_fex_usb_rank* rank); + +void asset_fex_usb_rank_decrypt(uint8_t* buf, size_t len); + +void asset_fex_usb_rank_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/fex/lib/usb-save.c b/src/main/asset/fex/lib/usb-save.c new file mode 100644 index 0000000..9d4007a --- /dev/null +++ b/src/main/asset/fex/lib/usb-save.c @@ -0,0 +1,339 @@ +#include +#include + +#include "util/adler32.h" +#include "util/mem.h" +#include "util/str.h" + +#include "usb-save.h" + +static char* fex_profile_save_header_to_string( + const struct asset_fex_usb_save_header* header) +{ + char* buffer; + + buffer = (char*) util_xmalloc(256); + memset(buffer, 0, 256); + + util_str_format(buffer, 256, + "-------------- header --------------\n" + "adler32: %X\n" + "usb_serial: %s\n" + "dongle_serial: %X\n", + header->adler32, + header->usb_serial, + header->dongle_serial); + + return buffer; +} + +static char* fex_profile_save_player_to_string( + const struct asset_fex_usb_save_player* player) +{ + char* buffer; + + buffer = (char*) util_xmalloc(1024); + memset(buffer, 0, 1024); + + util_str_format(buffer, 1024, + "-------------- player --------------\n" + "unkn: %X\n" + "unkn2: %X\n" + "avatar_id: %d\n" + "player_lvl: %d\n" + "unkn3: %X\n" + "player_id: %s\n" + "unkn4: %X\n" + "unkn5: %X\n" + "unkn6: %X\n" + "unkn7: %X\n" + "unkn8: %X\n" + "unkn9: %X\n" + "unkn10: %X\n" + "unkn11: %X\n" + "unkn12: %X\n" + "unkn13: %X\n" + "unkn14: %X\n" + "unkn15: %X\n" + "total_step: %d\n" + "play_count: %d\n" + "exp: %d\n" + "num_quest_world_passed: %d\n" + "unkn16: %X\n" + "arcade_score: %d\n" + "num_battle_wins: %d\n" + "num_battle_loss: %d\n" + "num_battle_draw: %d\n", + player->unkn, + player->unkn2, + player->avatar_id, + player->player_lvl, + player->unkn3, + player->player_id, + player->unkn4, + player->unkn5, + player->unkn6, + player->unkn7, + player->unkn8, + player->unkn9, + player->unkn10, + player->unkn11, + player->unkn12, + player->unkn13, + player->unkn14, + player->unkn15, + player->total_step, + player->play_count, + player->exp, + player->num_quest_world_passed, + player->unkn16, + player->arcade_score, + player->num_battle_wins, + player->num_battle_loss, + player->num_battle_draw); + + return buffer; +} + +static char* fex_profile_save_mods_to_string( + const struct asset_fex_usb_save_player_mods* mods) +{ + char* buffer; + + buffer = (char*) util_xmalloc(128); + memset(buffer, 0, 128); + + util_str_format(buffer, 128, + "-------------- modifiers --------------\n" + "modifiers: %X\n" + "half_speed_mod: %X\n" + "noteskin: %X\n", + mods->modifiers, + mods->half_speed_mod, + mods->noteskin); + + return buffer; +} + +static char* fex_profile_save_mod_unlocks_to_string( + const struct asset_fex_usb_save_mod_unlocks* unlocks) +{ + char* merged; + char* buffer; + char* tmp; + const size_t buf_size = 512; + + merged = (char*) util_xmalloc(buf_size); + memset(merged, 0, buf_size); + + buffer = (char*) util_xmalloc(buf_size); + memset(buffer, 0, buf_size); + + util_str_format(buffer, buf_size, + "-------------- mod unlocks --------------\n" ); + + tmp = util_str_merge(merged, buffer); + free(merged); + merged = tmp; + + for (uint32_t i = 0; i < 0x12; i++) { + util_str_format(buffer, buf_size, + "unkn0[%d]: %d\n", + i, + unlocks->unkn0[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + util_str_format(buffer, buf_size, + "display_va: %d\n", + unlocks->display_va); + + tmp = util_str_merge(merged, buffer); + free(merged); + merged = tmp; + + for (uint32_t i = 0; i < 0x0D; i++) { + util_str_format(buffer, buf_size, + "unkn1[%d]: %d\n", + i, + unlocks->unkn1[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < 0x10; i++) { + util_str_format(buffer, buf_size, + "noteskins[%d]: %d\n", + i, + unlocks->noteskins[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < 0x04; i++) { + util_str_format(buffer, buf_size, + "unkn2[%d]: %d\n", + i, + unlocks->unkn2[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < 0x03; i++) { + util_str_format(buffer, buf_size, + "path[%d]: %d\n", + i, + unlocks->path[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < 0x06; i++) { + util_str_format(buffer, buf_size, + "unkn3[%d]: %d\n", + i, + unlocks->unkn3[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + util_str_format(buffer, buf_size, + "xj: %d\n", + unlocks->xj); + + tmp = util_str_merge(merged, buffer); + free(merged); + merged = tmp; + + for (uint32_t i = 0; i < 0x02; i++) { + util_str_format(buffer, buf_size, + "system[%d]: %d\n", + i, + unlocks->system[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < 0x08; i++) { + util_str_format(buffer, buf_size, + "rush[%d]: %d\n", + i, + unlocks->rush[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < 0x1A; i++) { + util_str_format(buffer, buf_size, + "unkn4[%d]: %d\n", + i, + unlocks->unkn4[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + return merged; +} + +static char* fex_profile_save_mission_state_to_string( + const struct asset_fex_usb_save_mission_state* state) +{ + char* buffer; + + buffer = (char*) util_xmalloc(128); + memset(buffer, 0, 128); + + util_str_format(buffer, 128, + "-------------- mission state --------------\n" + "quest_world_location: %X\n" + "skill_up_zone_location: %X\n", + state->quest_world_location, + state->skill_up_zone_location); + + return buffer; +} + +struct asset_fex_usb_save* asset_fex_usb_save_new(void) +{ + return malloc(sizeof(struct asset_fex_usb_save)); +} + +void asset_fex_usb_save_finalize(struct asset_fex_usb_save* save) +{ + +} + +char* asset_fex_usb_save_to_string(const struct asset_fex_usb_save* save) +{ + char* header; + char* player; + char* mods; + char* unlocks; + char* mission_state; + char* merged; + char* merged2; + + header = fex_profile_save_header_to_string(&save->header); + player = fex_profile_save_player_to_string(&save->player); + mods = fex_profile_save_mods_to_string(&save->mods); + unlocks = fex_profile_save_mod_unlocks_to_string(&save->mod_unlocks); + mission_state = fex_profile_save_mission_state_to_string(&save->mission_state); + + merged = util_str_merge(header, player); + merged2 = util_str_merge(merged, mods); + free(merged); + merged = util_str_merge(merged2, unlocks); + free(merged2); + merged2 = util_str_merge(merged, mission_state); + free(merged); + + free(header); + free(player); + free(mods); + free(unlocks); + free(mission_state); + + return merged2; +} + +void asset_fex_usb_save_decrypt(uint8_t* buf, size_t len) +{ + for (size_t a = len - 1; a > 0; --a) { + buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8); + } +} + +void asset_fex_usb_save_encrypt(uint8_t* buf, size_t len) +{ + for (size_t a = 1; a < len; ++a) { + buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1]; + } +} \ No newline at end of file diff --git a/src/main/asset/fex/lib/usb-save.h b/src/main/asset/fex/lib/usb-save.h new file mode 100644 index 0000000..fd509ef --- /dev/null +++ b/src/main/asset/fex/lib/usb-save.h @@ -0,0 +1,191 @@ +#ifndef ASSET_FEX_USB_SAVE_H +#define ASSET_FEX_USB_SAVE_H + +#include +#include + +enum asset_fex_usb_save_noteskins { + ASSET_FEX_USB_SAVE_SKIN_DEFAULT = 0x00, + ASSET_FEX_USB_SAVE_SKIN_HANAFUDA = 0x01, + ASSET_FEX_USB_SAVE_SKIN_CLASSIC = 0x02, + ASSET_FEX_USB_SAVE_SKIN_CANDY = 0x03, + ASSET_FEX_USB_SAVE_SKIN_PORING = 0x04, + ASSET_FEX_USB_SAVE_SKIN_MUSICAL_NOTES = 0x05, + ASSET_FEX_USB_SAVE_SKIN_CANON_D = 0x06, + ASSET_FEX_USB_SAVE_SKIN_PLAYING_CARDS = 0x07, + ASSET_FEX_USB_SAVE_SKIN_NX = 0x08, + ASSET_FEX_USB_SAVE_SKIN_DIGNITY = 0x09, + ASSET_FEX_USB_SAVE_SKIN_HORSE_HEAD = 0x0A, + ASSET_FEX_USB_SAVE_SKIN_DOG = 0x0B, + ASSET_FEX_USB_SAVE_SKIN_GIRL = 0x0C, + ASSET_FEX_USB_SAVE_SKIN_FIRE = 0x0D, + ASSET_FEX_USB_SAVE_SKIN_ICE = 0x0E, + ASSET_FEX_USB_SAVE_SKIN_WIND = 0x0F, + ASSET_FEX_USB_SAVE_SKIN_RED_DP = 0x10, + ASSET_FEX_USB_SAVE_SKIN_BLUE_DP = 0x11, + ASSET_FEX_USB_SAVE_SKIN_YELLOW_DP = 0x12, + ASSET_FEX_USB_SAVE_SKIN_NXA = 0x13, + ASSET_FEX_USB_SAVE_SKIN_NX2 = 0x14, + ASSET_FEX_USB_SAVE_SKIN_ELECTRIC_FIESTA = 0x15, + ASSET_FEX_USB_SAVE_SKIN_DRUM = 0x16, + ASSET_FEX_USB_SAVE_SKIN_BULLET = 0x17, + ASSET_FEX_USB_SAVE_SKIN_BLUE_DRUM = 0x18, + ASSET_FEX_USB_SAVE_SKIN_RED_DRUM = 0x19, + ASSET_FEX_USB_SAVE_SKIN_YELLOW_DRUM = 0x1A, + ASSET_FEX_USB_SAVE_SKIN_WORLD_CUP = 0x1B, + ASSET_FEX_USB_SAVE_SKIN_PREX3 = 0x1C, + ASSET_FEX_USB_SAVE_SKIN_FIESTA_BASIC = 0x1D, +}; + +struct asset_fex_usb_save_header { + /* 0x00 */ + uint32_t adler32; + /* 0x04: NULL terminated */ + char usb_serial[0x40]; + /* 0x44: Deprecated from old games */ + uint32_t dongle_serial; +} __attribute__((__packed__)); + +struct asset_fex_usb_save_player { + /* 0x48 */ + uint32_t unkn; + /* 0x4C */ + uint32_t unkn2; + /* 0x50 */ + uint8_t avatar_id; + /* 0x51: Range: 0x00 - 0x21 */ + uint8_t player_lvl; + /* 0x52: PumBi sets it to 0xC4 */ + uint16_t unkn3; + /* 0x54: NULL terminated */ + char player_id[8]; + /* 0x5C */ + uint32_t unkn4; + /* 0x60 */ + uint32_t unkn5; + /* 0x64: Each time you save, it inc. by 6... */ + uint32_t unkn6; + /* 0x68 */ + uint32_t unkn7; + /* 0x6C */ + uint32_t unkn8; + /* 0x70 */ + uint32_t unkn9; + /* 0x74 */ + uint32_t unkn10; + /* 0x78 */ + uint32_t unkn11; + /* 0x7C */ + uint32_t unkn12; + /* 0x80 */ + uint32_t unkn13; + /* 0x84 */ + uint32_t unkn14; + /* 0x88 */ + uint32_t unkn15; + /* 0x8C */ + uint32_t total_step; + /* 0x90 */ + uint32_t play_count; + /* 0x94 */ + uint32_t exp; + /* 0x98 */ + uint32_t num_quest_world_passed; + /* 0x9C */ + uint32_t unkn16; + /* 0xA0 */ + uint32_t arcade_score; + /* 0xA8 */ + uint32_t num_battle_wins; + /* 0xAC */ + uint32_t num_battle_loss; + /* 0xB0 */ + uint32_t num_battle_draw; +} __attribute__((__packed__)); + +struct asset_fex_usb_save_player_mods { + /* 0xB4: The first set of saved modifiers (see MOD_1 below) */ + uint32_t modifiers; + /* 0xB8: If the +0.5x mod is enabled (boolean) */ + uint32_t half_speed_mod; + /* 0xBC: Which noteskin is currently selected (see NOTE_S below) */ + uint32_t noteskin; +} __attribute__((__packed__)); + +struct asset_fex_usb_save_mod_unlocks { + /* 0xC0: Unknown Unlocks Area */ + uint8_t unkn0[0x12]; + /* 0xD2: Boolean for unlocking VA Mod. */ + uint8_t display_va; + /* 0xD3: Unknown Unlocks Area */ + uint8_t unkn1[0x0D]; + /* 0xE0: Array of bools - Which Noteskins are Unlocked. */ + uint8_t noteskins[0x10]; + /* 0xF0: Unknown Unlocks Area */ + uint8_t unkn2[0x04]; + /* 0xF4: Array of bools - Which Path Mods are Unlocked. */ + uint8_t path[0x03]; + /* 0xF7: Unknown Unlocks Area */ + uint8_t unkn3[0x06]; + /* 0xFE: Boolean for unlocking XJ */ + uint8_t xj; + /* 0x100: Array of bools - Which System Mods are Unlocked. */ + uint8_t system[0x02]; + /* 0x102: Array of bools - Which Rush/NOT Modes are Unlocked. */ + uint8_t rush[0x08]; + /* 0x10A: Unknown Unlocks Area */ + uint8_t unkn4[0x1A]; +} __attribute__((__packed__)); + +struct asset_fex_usb_save_mission_state { + /* 0x124 */ + uint32_t quest_world_location; + /* 0x128 */ + uint32_t skill_up_zone_location; +} __attribute__((__packed__)); + +struct asset_fex_usb_save { + struct asset_fex_usb_save_header header; + struct asset_fex_usb_save_player player; + struct asset_fex_usb_save_player_mods mods; + struct asset_fex_usb_save_mod_unlocks mod_unlocks; + struct asset_fex_usb_save_mission_state mission_state; + + /* Not verified, yet. just notes from old tools */ + + /* 0x17AD (0x0A): Quest world inventory */ + /* 0x17B7: ??? */ + /* 0x17B8 (0x1C): Quest world warp unlocks */ + + /* 0x17AC (0x11): QW inventory */ + + /* 0x17D4 or 0x17D5 ? (0x14): favorites channel */ + /* 0x2E48 - 0x1A5EF: step chart blacklist */ + /* 0x2E48 - 0x1A5EF: step chart unlocks = blacklist */ + + /* pumbi stepcharts */ + /* 0x6047: pumbi stepchart 1009 Level S15 */ + /* 0x6083 */ + /* 0x60AB */ + /* 0x647F */ + /* 0x64BB */ + /* 0x64CF */ + /* 0x650B */ + /* 0x6533 */ + /* 0x655B */ + /* 0x65AB */ + /* 0x660F */ +} __attribute__((__packed__)); + +struct asset_fex_usb_save* asset_fex_usb_save_new(void); + +// update checksum and prepare profile to get encrypted +void asset_fex_usb_save_finalize(struct asset_fex_usb_save* save); + +char* asset_fex_usb_save_to_string(const struct asset_fex_usb_save* save); + +void asset_fex_usb_save_decrypt(uint8_t* buf, size_t len); + +void asset_fex_usb_save_encrypt(uint8_t* buf, size_t len); + +#endif diff --git a/src/main/asset/fex/lib/util.c b/src/main/asset/fex/lib/util.c new file mode 100644 index 0000000..c61ac46 --- /dev/null +++ b/src/main/asset/fex/lib/util.c @@ -0,0 +1,100 @@ +#define LOG_MODULE "asset-fex-util" + +#include + +#include "util/fs.h" +#include "util/log.h" + +#include "util.h" + +struct asset_fex_usb_rank* asset_fex_usb_rank_load_from_file(const char* path, + bool encrypted) +{ + struct asset_fex_usb_rank* rank; + size_t size; + + if (!util_file_load(path, (void**) &rank, &size, false)) { + log_error("Loading fex rank file %s failed", path); + return NULL; + } + + // if (size != sizeof(struct fex_profile_rank)) { + // log_error("Invalid size of fex rank file %s: %d != %d", path, size, + // sizeof(struct fex_profile_rank)); + // free(rank); + // return NULL; + // } + + if (encrypted) { + asset_fex_usb_rank_decrypt((uint8_t*) rank, size); + } + + return rank; +} + +bool asset_fex_usb_rank_save_to_file(const char* path, + const struct asset_fex_usb_rank* rank, bool encrypt) +{ + struct asset_fex_usb_rank rank_enc; + + memcpy(&rank_enc, rank, sizeof(struct asset_fex_usb_rank)); + + if (encrypt) { + asset_fex_usb_rank_encrypt((uint8_t*) &rank_enc, + sizeof(struct asset_fex_usb_rank)); + } + + if (!util_file_save(path, (void**) &rank_enc, + sizeof(struct asset_fex_usb_rank))) { + log_error("Storing fex rank data to %s failed", path); + return false; + } + + return true; +} + +struct asset_fex_usb_save* asset_fex_usb_save_load_from_file(const char* path, + bool encrypted) +{ + struct asset_fex_usb_save* save; + size_t size; + + if (!util_file_load(path, (void**) &save, &size, false)) { + log_error("Loading fex save file %s failed", path); + return NULL; + } + + // if (size != sizeof(struct fex_profile_save)) { + // log_error("Invalid size of fex save file %s: %d != %d", path, size, + // sizeof(struct fex_profile_save)); + // free(save); + // return NULL; + // } + + if (encrypted) { + asset_fex_usb_save_decrypt((uint8_t*) save, size); + } + + return save; +} + +bool asset_fex_usb_save_save_to_file(const char* path, + const struct asset_fex_usb_save* save, bool encrypt) +{ + struct asset_fex_usb_save save_enc; + + memcpy(&save_enc, save, sizeof(struct asset_fex_usb_save)); + + if (encrypt) { + asset_fex_usb_save_encrypt((uint8_t*) &save_enc, + sizeof(struct asset_fex_usb_save)); + } + + if (!util_file_save(path, (const void*) &save_enc, + sizeof(struct asset_fex_usb_save))) { + log_error("Storing fex save data to %s failed", path); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/main/asset/fex/lib/util.h b/src/main/asset/fex/lib/util.h new file mode 100644 index 0000000..be9cbb2 --- /dev/null +++ b/src/main/asset/fex/lib/util.h @@ -0,0 +1,21 @@ +#ifndef ASSET_FEX_UTIL_H +#define ASSET_FEX_UTIL_H + +#include + +#include "usb-rank.h" +#include "usb-save.h" + +// load from file and decrypt, returns decrypted struct +struct asset_fex_usb_rank* asset_fex_usb_rank_load_from_file(const char* path, bool encrypted); + +// takes decrypted rank data, encrypts it and writes it to file +bool asset_fex_usb_rank_save_to_file(const char* path, const struct asset_fex_usb_rank* rank, bool encrypt); + +// load from file and decrypt, returns decrypted struct +struct asset_fex_usb_save* asset_fex_usb_save_load_from_file(const char* path, bool encrypted); + +// takes decrypted save data, encrypts it and writes it to file +bool asset_fex_usb_save_save_to_file(const char* path, const struct asset_fex_usb_save* save, bool encrypt); + +#endif \ No newline at end of file diff --git a/src/main/asset/fex/tool/usb-profile.c b/src/main/asset/fex/tool/usb-profile.c new file mode 100644 index 0000000..7ffa44d --- /dev/null +++ b/src/main/asset/fex/tool/usb-profile.c @@ -0,0 +1,154 @@ +/** + * Tool for FiestaEX profiles: decrypt, encrypt, print profile data + */ +#include +#include +#include + +#include "asset/fex/lib/util.h" + +#include "util/str.h" + +int main(int argc, char** argv) +{ + int ret; + char* rank_path; + char* save_path; + + if (argc < 3) { + printf("Usage: %s [cmd: new, dec, enc, dump] " + "[path containing fiestaex_rank.bin fiestaex_save.bin]\n", argv[0]); + return -1; + } + + ret = 0; + + rank_path = util_str_merge(argv[2], "fiestaex_rank.bin"); + save_path = util_str_merge(argv[2], "fiestaex_save.bin"); + + if (!strcmp(argv[1], "new")) { + struct asset_fex_usb_rank* rank = asset_fex_usb_rank_new(); + struct asset_fex_usb_save* save = asset_fex_usb_save_new(); + + asset_fex_usb_rank_finalize(rank); + asset_fex_usb_save_finalize(save); + + if (!asset_fex_usb_rank_save_to_file(rank_path, rank, true)) { + fprintf(stderr, "Creating rank file %s failed\n", rank_path); + ret = -2; + } + + if (!asset_fex_usb_save_save_to_file(save_path, save, true)) { + fprintf(stderr, "Creating save file %s failed\n", save_path); + ret = -3; + } + + free(rank); + free(save); + } else { + struct asset_fex_usb_rank* rank; + struct asset_fex_usb_save* save; + bool encrypted; + + if (!strcmp(argv[1], "enc")) { + char* tmp; + + encrypted = false; + + tmp = util_str_merge(rank_path, ".dec"); + free(rank_path); + rank_path = tmp; + + tmp = util_str_merge(save_path, ".dec"); + free(save_path); + save_path = tmp; + } else { + encrypted = true; + } + + rank = asset_fex_usb_rank_load_from_file(rank_path, encrypted); + save = asset_fex_usb_save_load_from_file(save_path, encrypted); + + if (!rank) { + fprintf(stderr, "Loading %s failed", rank_path); + ret = -4; + goto cleanup; + } + + if (!save) { + fprintf(stderr, "Loading %s failed", save_path); + ret = -5; + free(rank); + goto cleanup; + } + + if (!strcmp(argv[1], "dec")) { + char* rank_path_dec; + char* save_path_dec; + + rank_path_dec = util_str_merge(rank_path, ".dec"); + save_path_dec = util_str_merge(save_path, ".dec"); + + if (!asset_fex_usb_rank_save_to_file(rank_path_dec, rank, false)) { + fprintf(stderr, "Saving decrypted rank file to %s failed\n", + rank_path_dec); + ret = -6; + } + + if (!asset_fex_usb_save_save_to_file(save_path_dec, save, false)) { + fprintf(stderr, "Saving decrypted save file to %s failed\n", + save_path_dec); + ret = -7; + } + + free(rank_path_dec); + free(save_path_dec); + } else if (!strcmp(argv[1], "enc")) { + char* rank_path_enc; + char* save_path_enc; + + rank_path_enc = util_str_merge(rank_path, ".enc"); + save_path_enc = util_str_merge(save_path, ".enc"); + + if (!asset_fex_usb_rank_save_to_file(rank_path_enc, rank, true)) { + fprintf(stderr, "Saving encrypted rank file to %s failed\n", + rank_path_enc); + ret = -6; + } + + if (!asset_fex_usb_save_save_to_file(save_path_enc, save, true)) { + fprintf(stderr, "Saving encrypted save file to %s failed\n", + save_path_enc); + ret = -7; + } + + free(rank_path_enc); + free(save_path_enc); + } else if (!strcmp(argv[1], "dump")) { + char* rank_str; + char* save_str; + + rank_str = asset_fex_usb_rank_to_string(rank); + save_str = asset_fex_usb_save_to_string(save); + + printf("----------------- rank -----------------\n" + "%s----------------- save -----------------\n%s", + rank_str, save_str); + + free(rank_str); + free(save_str); + } else { + fprintf(stderr, "Unknown command %s\n", argv[1]); + ret = -4; + } + + free(rank); + free(save); + } + +cleanup: + free(rank_path); + free(save_path); + + return ret; +} \ No newline at end of file diff --git a/src/main/asset/game-version.h b/src/main/asset/game-version.h new file mode 100644 index 0000000..c6ff8df --- /dev/null +++ b/src/main/asset/game-version.h @@ -0,0 +1,38 @@ +#ifndef ASSET_GAME_VERSION_H +#define ASSET_GAME_VERSION_H + +/* Note: Version IDs must be sync with server code */ +enum asset_game_version { + ASSET_GAME_VERSION_INVALID = 0, + ASSET_GAME_VERSION_FIRST = 1, + ASSET_GAME_VERSION_SECOND = 2, + ASSET_GAME_VERSION_OBG = 3, + ASSET_GAME_VERSION_OBG_SE = 4, + ASSET_GAME_VERSION_THE_COLLECTION = 5, + ASSET_GAME_VERSION_PERFECT_COLLECTION = 6, + ASSET_GAME_VERSION_EXTRA = 7, + ASSET_GAME_VERSION_PREMIERE_1 = 8, + ASSET_GAME_VERSION_PREX_1 = 9, + ASSET_GAME_VERSION_REBIRTH = 10, + ASSET_GAME_VERSION_PREMIERE_2 = 11, + ASSET_GAME_VERSION_PREX_2 = 12, + ASSET_GAME_VERSION_PREMIERE_3 = 13, + ASSET_GAME_VERSION_PREX_3 = 14, + ASSET_GAME_VERSION_EXCEED = 15, + ASSET_GAME_VERSION_EXCEED_2 = 16, + ASSET_GAME_VERSION_ZERO = 17, + ASSET_GAME_VERSION_NX = 18, + ASSET_GAME_VERSION_PRO = 19, + ASSET_GAME_VERSION_NX2 = 20, + ASSET_GAME_VERSION_NXA = 21, + ASSET_GAME_VERSION_FIESTA = 22, + ASSET_GAME_VERSION_PRO2 = 23, + ASSET_GAME_VERSION_FIESTA_EX = 24, + ASSET_GAME_VERSION_FIESTA_2 = 25, + ASSET_GAME_VERSION_INFINITY = 26, + ASSET_GAME_VERSION_PRIME = 27, + ASSET_GAME_VERSION_PRIME_2 = 28, + ASSET_GAME_VERSION_XX = 29 +}; + +#endif diff --git a/src/main/asset/nx/lib/settings.c b/src/main/asset/nx/lib/settings.c new file mode 100644 index 0000000..f4ddbba --- /dev/null +++ b/src/main/asset/nx/lib/settings.c @@ -0,0 +1,68 @@ +#include + +#include "asset/nx/lib/settings.h" + +#include "util/adler32.h" +#include "util/mem.h" + +struct asset_nx_settings* asset_nx_settings_new(void) +{ + struct asset_nx_settings* settings; + + settings = util_xmalloc(sizeof(struct asset_nx_settings)); + + memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad)); + memcpy(settings->ident, "NX10", 4); + /* Updated using finalize */ + settings->adler32 = 0; + settings->total_uptime = 0; + settings->language = ASSET_NX_SETTINGS_LANG_ENG; + memset(settings->song_play_count, 0, sizeof(uint32_t) * ASSET_NX_SETTINGS_MAX_SONGS); + settings->game_option_default_station = ASSET_NX_SETTINGS_STATION_TRAIN; + settings->game_mode = ASSET_NX_SETTINGS_GAME_MODE_NORMAL; + settings->game_level = ASSET_NX_SETTINGS_LEVEL_NORMAL; + settings->game_stage_break = ASSET_NX_SETTINGS_STAGE_BREAK_2ND; + settings->game_demo_sound = 1; + settings->game_show_help = 1; + settings->game_mercy_ticket = 0; + settings->game_score_per_ticket = 0; + settings->coin_limit = 0; + settings->coin1_setting = 1; + settings->coin2_setting = 1; + memset(settings->unknown_unlock_flags, 0, ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS); + settings->unkn2 = 0x2A; + settings->unkn3 = 0; + settings->bookkeeping_coin1_total = 0; + settings->bookkeeping_coin2_total = 0; + settings->bookkeeping_service_total = 0; + settings->bookkeeping_play_total = 0; + settings->bookkeeping_faep21_play_count = 0; + settings->bookkeeping_ticket_1 = 0; + settings->bookkeeping_ticket_2 = 0; + settings->region = 0xFF; + memset(settings->censor_table, 0, ASSET_NX_SETTINGS_MAX_SONGS); + + return settings; +} + +void asset_nx_settings_finalize(struct asset_nx_settings* settings) +{ + /* Seems odd, but they just checksum the game settings part...*/ + settings->adler32 = util_adler32_calc(1, (const uint8_t*) &settings->game_mode, 8); +} + +void asset_nx_settings_unlock_all(struct asset_nx_settings* settings) +{ + /* FAEP 2-1 must be played at least 100 times to unlock FAEP 2-2 */ + settings->bookkeeping_faep21_play_count = 100; + + /* To unlock all world tour missions and special zone songs, set this to 20k. + The first 10k unlock only the first half of the missions while another 10k unlocks the second half (wtf) */ + settings->bookkeeping_play_total = 20000; +} + +char* asset_nx_settings_to_string(const struct asset_nx_settings* settings) +{ + // TODO + return ""; +} \ No newline at end of file diff --git a/src/main/asset/nx/lib/settings.h b/src/main/asset/nx/lib/settings.h new file mode 100644 index 0000000..12c2ffb --- /dev/null +++ b/src/main/asset/nx/lib/settings.h @@ -0,0 +1,101 @@ +#ifndef ASSET_NX_SETTINGS_H +#define ASSET_NX_SETTINGS_H + +#include + +#define ASSET_NX_SETTINGS_FILE_NAME "PIUNX.INI" +#define ASSET_NX_SETTINGS_MAX_SONGS 200 +#define ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS 59 + +enum asset_nx_settings_language { + ASSET_NX_SETTINGS_LANG_KOR = 0, + ASSET_NX_SETTINGS_LANG_ENG = 1, + ASSET_NX_SETTINGS_LANG_SP = 2, + ASSET_NX_SETTINGS_LANG_CH = 3, +}; + +enum asset_nx_settings_station { + ASSET_NX_SETTINGS_STATION_TRAIN = 0, + ASSET_NX_SETTINGS_STATION_ARCADE = 1, + ASSET_NX_SETTINGS_STATION_WORLD = 2, + ASSET_NX_SETTINGS_STATION_SPECIAL = 3, +}; + +enum asset_nx_settings_game_mode { + ASSET_NX_SETTINGS_GAME_MODE_NORMAL = 0, + ASSET_NX_SETTINGS_GAME_MODE_EVENT = 1, +}; + +enum asset_nx_settings_level { + ASSET_NX_SETTINGS_LEVEL_EASY = 0, + ASSET_NX_SETTINGS_LEVEL_NORMAL = 1, + ASSET_NX_SETTINGS_LEVEL_HARD = 2, +}; + +enum asset_nx_settings_stage_break { + ASSET_NX_SETTINGS_STAGE_BREAK_OFF = 0, + ASSET_NX_SETTINGS_STAGE_BREAK_1ST = 1, + ASSET_NX_SETTINGS_STAGE_BREAK_2ND = 2, + ASSET_NX_SETTINGS_STAGE_BREAK_3RD = 3, + ASSET_NX_SETTINGS_STAGE_BREAK_4TH = 4, +}; + +struct asset_nx_settings { + /* Padding to fill up to 4k EEPROM legacy size */ + uint8_t ff_pad[0xB9D]; + /* NX10 */ + char ident[4]; + uint32_t adler32; + uint32_t total_uptime; + uint8_t language; + uint32_t song_play_count[ASSET_NX_SETTINGS_MAX_SONGS]; + uint32_t game_option_default_station; + uint8_t game_mode; + uint8_t game_level; + uint8_t game_stage_break; + /* 0 off, 1 on */ + uint8_t game_demo_sound; + /* 0 off, 1 on */ + uint8_t game_show_help; + /* 0 off, 1 on */ + uint8_t game_mercy_ticket; + /* 0 off, 1 - 6 for score */ + uint8_t game_score_per_ticket; + /* 0 none */ + uint8_t coin_limit; // 0 none + /* 0 freeplay */ + uint8_t coin1_setting; + /* 0 freeplay */ + uint8_t coin2_setting; + /* Unlock flags for world tour missions? setting them to 1 doesn't unlock anything. + 64 missions total, 55 unlock flags, 0 = locked, 1 = unlocked */ + uint8_t unknown_unlock_flags[ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS]; + /* Default value 0x2A */ + uint32_t unkn2; + uint32_t unkn3; + uint32_t bookkeeping_coin1_total; + uint32_t bookkeeping_coin2_total; + uint32_t bookkeeping_service_total; + uint32_t bookkeeping_play_total; + /* Separate counter for FAEP 2-1 play counts. Once this hits 100, FAEP 2-2 is unlocked in arcade station */ + uint32_t bookkeeping_faep21_play_count; + uint32_t bookkeeping_ticket_1; + uint32_t bookkeeping_ticket_2; + /* FF -> not used, censoring globally disabled. unused feature though */ + uint8_t region; + /* 0 = censoring of song off */ + uint8_t censor_table[ASSET_NX_SETTINGS_MAX_SONGS]; +} __attribute__((__packed__)); + +struct asset_nx_settings* asset_nx_settings_new(void); + +// update checksum +void asset_nx_settings_finalize(struct asset_nx_settings* settings); + +// unlocks FAEP 2-2 by setting the play count to 100 +// and sets all missions cleared to unlock special stage songs and other missions +void asset_nx_settings_unlock_all(struct asset_nx_settings* settings); + +char* asset_nx_settings_to_string(const struct asset_nx_settings* settings); + +#endif diff --git a/src/main/asset/nx/lib/util.c b/src/main/asset/nx/lib/util.c new file mode 100644 index 0000000..28b8062 --- /dev/null +++ b/src/main/asset/nx/lib/util.c @@ -0,0 +1,35 @@ +#include + +#include "asset/nx/lib/util.h" + +#include "util/fs.h" +#include "util/log.h" + +struct asset_nx_settings* asset_nx_util_load_settings_from_file(const char* path) +{ + struct asset_nx_settings* settings; + size_t size; + + if (!util_file_load(path, (void**) &settings, &size, false)) { + log_error("Loading nx setting file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_nx_settings)) { + log_error("Invalid size of nx setting file %s: %d != %d", path, size, sizeof(struct asset_nx_settings)); + free(settings); + return NULL; + } + + return settings; +} + +bool asset_nx_util_save_settings_to_file(const char* path, const struct asset_nx_settings* settings) +{ + if (!util_file_save(path, (void**) settings, sizeof(struct asset_nx_settings))) { + log_error("Storing nx settings data to %s failed", path); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/main/asset/nx/lib/util.h b/src/main/asset/nx/lib/util.h new file mode 100644 index 0000000..37342b9 --- /dev/null +++ b/src/main/asset/nx/lib/util.h @@ -0,0 +1,12 @@ +#ifndef ASSET_NX_UTIL_H +#define ASSET_NX_UTIL_H + +#include + +#include "asset/nx/lib/settings.h" + +struct asset_nx_settings* asset_nx_util_load_settings_from_file(const char* path); + +bool asset_nx_util_save_settings_to_file(const char* path, const struct asset_nx_settings* settings); + +#endif diff --git a/src/main/asset/nx/tool/settings.c b/src/main/asset/nx/tool/settings.c new file mode 100644 index 0000000..d32709e --- /dev/null +++ b/src/main/asset/nx/tool/settings.c @@ -0,0 +1,88 @@ +/** + * Tool for NX settings files + */ +#include +#include +#include + +#include "asset/nx/lib/settings.h" +#include "asset/nx/lib/util.h" + +static int main_settings(char* cmd, char* file); + +int main(int argc, char** argv) +{ + int ret; + char* cmd; + char* type; + char* file; + + if (argc < 4) { + printf("Usage: %s [cmd: new, dump, unlock] [type: ini, mrank, rank] [file]\n", argv[0]); + return -1; + } + + cmd = argv[1]; + type = argv[2]; + file = argv[3]; + + if (!strcmp(type, "ini")) { + ret = main_settings(cmd, file); + } else { + fprintf(stderr, "Unknown file type %s\n", type); + ret = -1; + } + + return ret; +} + +static int main_settings(char* cmd, char* file) +{ + int ret; + + ret = 0; + + if (!strcmp(cmd, "new")) { + struct asset_nx_settings* settings = asset_nx_settings_new(); + + asset_nx_settings_finalize(settings); + + if (!asset_nx_util_save_settings_to_file(file, settings)) { + fprintf(stderr, "Creating nx settings file %s failed\n", file); + ret = -1; + } + + free(settings); + } else { + struct asset_nx_settings* settings = asset_nx_util_load_settings_from_file(file); + + if (!settings) { + fprintf(stderr, "Loading %s failed", file); + ret = -1; + } + + if (!strcmp(cmd, "dump")) { + char* str = asset_nx_settings_to_string(settings); + + printf("----------------- settings -----------------\n%s\n", str); + + free(str); + } else if (!strcmp(cmd, "unlock")) { + asset_nx_settings_unlock_all(settings); + + asset_nx_settings_finalize(settings); + + if (!asset_nx_util_save_settings_to_file(file, settings)) { + fprintf(stderr, "Saving nx settings file %s failed\n", file); + ret = -1; + } + } else { + fprintf(stderr, "Unknown command %s\n", cmd); + ret = -1; + } + + free(settings); + } + + return ret; +} \ No newline at end of file diff --git a/src/main/asset/nx2/lib/usb-rank.c b/src/main/asset/nx2/lib/usb-rank.c new file mode 100644 index 0000000..d11c50c --- /dev/null +++ b/src/main/asset/nx2/lib/usb-rank.c @@ -0,0 +1,93 @@ +#include + +#include "util/adler32.h" +#include "util/mem.h" +#include "util/str.h" + +#include "usb-rank.h" + +struct asset_nx2_usb_rank* asset_nx2_usb_rank_new(void) +{ + struct asset_nx2_usb_rank* rank; + + rank = (struct asset_nx2_usb_rank*) + util_xmalloc(sizeof(struct asset_nx2_usb_rank)); + + memset(rank, 0, sizeof(struct asset_nx2_usb_rank)); + + return rank; +} + +void asset_nx2_usb_rank_finalize(struct asset_nx2_usb_rank* rank) +{ + rank->adler32 = util_adler32_calc(1, ((const uint8_t*) rank) + 4, + sizeof(struct asset_nx2_usb_rank) - 4); +} + +char* asset_nx2_usb_rank_to_string(const struct asset_nx2_usb_rank* rank) +{ + char* buffer; + char* buffer2; + char* merged; + + buffer = (char*) util_xmalloc(128); + memset(buffer, 0, 128); + + util_str_format(buffer, 128, + "adler32: 0x%X\n" + "num_rankings: %d\n" + "ranking entries:\n", + rank->adler32, + rank->num_rankings); + + for (uint32_t i = 0; i < ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES; i++) { + + for (uint32_t j = 0; j < ASSET_NX2_USB_RANK_MAX_STAGES; j++) { + buffer2 = (char*) util_xmalloc(512); + memset(buffer2, 0, 512); + + util_str_format(buffer2, 512, + "%d/%d:\n" + "game_mode: %d\n" + "play_order: %d\n" + "play_score: %d\n" + "grade: %d\n" + "mileage: %d\n" + "play_time: %f\n" + "kcal: %f\n" + "v02: %f\n", + i, j, + rank->entries[i][j].game_mode, + rank->entries[i][j].play_order, + rank->entries[i][j].play_score, + rank->entries[i][j].grade, + rank->entries[i][j].mileage, + rank->entries[i][j].play_time, + rank->entries[i][j].kcal, + rank->entries[i][j].v02); + + merged = util_str_merge(buffer, buffer2); + + free(buffer); + free(buffer2); + + buffer = merged; + } + } + + return buffer; +} + +void asset_nx2_usb_rank_decrypt(uint8_t* buf, size_t len) +{ + for (size_t a = len - 1; a > 0; --a) { + buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8); + } +} + +void asset_nx2_usb_rank_encrypt(uint8_t* buf, size_t len) +{ + for (size_t a = 1; a < len; ++a) { + buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1]; + } +} \ No newline at end of file diff --git a/src/main/asset/nx2/lib/usb-rank.h b/src/main/asset/nx2/lib/usb-rank.h new file mode 100644 index 0000000..a06da6c --- /dev/null +++ b/src/main/asset/nx2/lib/usb-rank.h @@ -0,0 +1,42 @@ +#ifndef ASSET_NX2_USB_RANK_H +#define ASSET_NX2_USB_RANK_H + +#include +#include + +#define ASSET_NX2_USB_RANK_SIZE 12296 + +enum asset_nx2_usb_rank_sizes { + ASSET_NX2_USB_RANK_MAX_STAGES = 3, + ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES = 128, +}; + +struct asset_nx2_usb_rank_entry { + int32_t game_mode; + int32_t play_order; + int32_t play_score; + int32_t grade; + int32_t mileage; + float play_time; + float kcal; + float v02; +} __attribute__((__packed__)); + +struct asset_nx2_usb_rank { + uint32_t adler32; + uint32_t num_rankings; + struct asset_nx2_usb_rank_entry entries[ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES][ASSET_NX2_USB_RANK_MAX_STAGES]; +} __attribute__((__packed__)); + +struct asset_nx2_usb_rank* asset_nx2_usb_rank_new(void); + +// update checksum and prepare profile to get encrypted +void asset_nx2_usb_rank_finalize(struct asset_nx2_usb_rank* rank); + +char* asset_nx2_usb_rank_to_string(const struct asset_nx2_usb_rank* rank); + +void asset_nx2_usb_rank_decrypt(uint8_t* buf, size_t len); + +void asset_nx2_usb_rank_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/nx2/lib/usb-save.c b/src/main/asset/nx2/lib/usb-save.c new file mode 100644 index 0000000..0588f43 --- /dev/null +++ b/src/main/asset/nx2/lib/usb-save.c @@ -0,0 +1,370 @@ +#include +#include + +#include "util/adler32.h" +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +#include "usb-save.h" + +static char* asset_nx2_usb_save_time_to_string( + const struct asset_nx2_usb_save_time* time) +{ + char* buffer; + + buffer = (char*) util_xmalloc(128); + memset(buffer, 0, 128); + + util_str_format(buffer, 128, + "year: %d\n" + "month: %d\n" + "day: %d\n" + "hour: %d\n" + "min: %d\n" + "ms: %d\n", + time->year, + time->month, + time->day, + time->hour, + time->min, + time->ms); + + return buffer; +} + +static char* asset_nx2_usb_save_review_to_string( + const struct asset_nx2_usb_save_review* review) +{ + char* buffer; + char* land; + char* mission; + + buffer = (char*) util_xmalloc(1024); + memset(buffer, 0, 1024); + + land = util_str_buffer((const uint8_t*) review->worldmax_current_land, + ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX); + mission = util_str_buffer((const uint8_t*) review->worldmax_current_mission, + ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX); + + util_str_format(buffer, 1024, + ">>> review:\n" + "player_id: %s\n" + "mileage: %d\n" + "reward_count: %d\n" + "worldmax_count: %d\n" + "play_count: %d\n" + "worldmax_current_land: %s\n" + "worldmax_current_mission: %s\n" + "kcal: %d\n" + "v02: %d\n", + review->player_id, + review->mileage, + review->reward_count, + review->worldmax_count, + review->play_count, + land, + mission, + review->kcal, + review->v02); + + free(land); + free(mission); + + return buffer; +} + +static char* asset_nx2_usb_save_stats_to_string( + const struct asset_nx2_usb_save_stats* stats) +{ + char* merged; + char* buffer; + char* timestamp; + char* tmp; + const size_t buf_size = 512; + + merged = (char*) util_xmalloc(buf_size); + memset(merged, 0, buf_size); + + buffer = (char*) util_xmalloc(buf_size); + memset(buffer, 0, buf_size); + + timestamp = asset_nx2_usb_save_time_to_string(&stats->timestamp); + + util_str_format(merged, buf_size, + ">>> stats:\n" + "adler32: 0x%X\n" + "usb_serial: %s\n" + "timestamp: %s" + "avatar_id: %d\n" + "rank: %d\n" + "country_id: %d\n" + "player_id: %s\n" + "mileage: %d\n" + "play_count: %d\n" + "kcal: %d\n" + "v02: %d\n" + "worldmax_map_position: 0x%X\n" + "reward_count: %d\n" + "worldmax_count: %d\n", + stats->adler32, + stats->usb_serial, + timestamp, + stats->avatar_id, + stats->rank, + stats->country_id, + stats->player_id, + stats->mileage, + stats->play_count, + stats->kcal, + stats->v02, + stats->worldmax_map_position, + stats->reward_count, + stats->worldmax_count); + + free(timestamp); + + tmp = util_str_merge(merged, "song_unlocks:\n"); + + free(merged); + merged = tmp; + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_SONG_MAX; i++) { + + util_str_format(buffer, buf_size, + "song slot: %d\n" + "mode: 0x%X\n" + "unused: 0x%X\n" + "song: %d\n" + "reveal: %d\n", + i, + stats->song_unlocks[i].mode, + stats->song_unlocks[i].unused, + stats->song_unlocks[i].song, + stats->song_unlocks[i].reveal); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) { + + util_str_format(buffer, buf_size, + "mission slot: %d\n" + "clear_flags_directions: 0x%X\n" + "clear_flag_mission: %d\n" + "unused: 0x%X\n", + i, + stats->worldmax_mission_unlocks[i].clear_flags_directions, + stats->worldmax_mission_unlocks[i].clear_flag_mission, + stats->worldmax_mission_unlocks[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_high_score %d: %d\n", + i, + stats->worldmax_high_score[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_challenge %d: %d\n", + i, + stats->worldmax_challenge[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_BARRICADE_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_barricade %d:\n" + "flag_open: %d\n" + "unused: 0x%X\n", + i, + stats->worldmax_barricade[i].flag_open, + stats->worldmax_barricade[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_EVENT_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_event %d:\n" + "flag_cleared: %d\n" + "unused: 0x%X\n", + i, + stats->worldmax_event[i].flag_cleared, + stats->worldmax_event[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WARP_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_warp %d:\n" + "direction_clear: 0x%X\n" + "clear: %d\n", + "unused: 0x%X\n", + i, + stats->worldmax_warp[i].direction_clear, + stats->worldmax_warp[i].clear, + stats->worldmax_warp[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_current_land %d: %d\n", + i, + stats->worldmax_current_land[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_current_mission %d: %d\n", + i, + stats->worldmax_current_mission[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_SONG_MAX; i++) { + + for (uint32_t j = 0; j < ASSET_NX2_USB_SAVE_NUM_MODES; j++) { + util_str_format(buffer, buf_size, + "song_scores %d/%d:\n" + "score: %d\n" + "player_id: %s\n", + i, + j, + stats->song_scores[i][j].score, + stats->song_scores[i][j].player_id); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + } + + free(buffer); + + return merged; +} + +struct asset_nx2_usb_save* asset_nx2_usb_save_new(void) +{ + struct asset_nx2_usb_save* save; + char name[10]; + + save = (struct asset_nx2_usb_save*) util_xmalloc( + sizeof(struct asset_nx2_usb_save)); + + memset(save, 0, sizeof(struct asset_nx2_usb_save)); + + sprintf(name, "NX%06d", rand() % 1000000); + strcpy(save->review.player_id, name); + strcpy(save->stats.player_id, name); + + /* default world map position */ + save->stats.worldmax_map_position = 0xEF001; + + /* nx2 release date as default timestamp */ + save->stats.timestamp.year = 2008; + save->stats.timestamp.month = 1; + save->stats.timestamp.day = 21; + save->stats.timestamp.hour = 0; + save->stats.timestamp.min = 0; + save->stats.timestamp.ms = 0; + + return save; +} + +void asset_nx2_usb_save_finalize(struct asset_nx2_usb_save* save) +{ + /* checksum update */ + save->stats.adler32 = util_adler32_calc(1, + ((const uint8_t*) &save->stats) + 4, + sizeof(struct asset_nx2_usb_save_stats) - 4); +} + +char* asset_nx2_usb_save_to_string(const struct asset_nx2_usb_save* save) +{ + char* review; + char* stats; + char* merged; + + review = asset_nx2_usb_save_review_to_string(&save->review); + stats = asset_nx2_usb_save_stats_to_string(&save->stats); + + merged = util_str_merge(review, stats); + + free(review); + free(stats); + + return merged; +} + +void asset_nx2_usb_save_decrypt(uint8_t* buf, size_t len) +{ + /* skip non encrypted review area */ + buf += sizeof(struct asset_nx2_usb_save_review); + len -= sizeof(struct asset_nx2_usb_save_review); + + for (size_t a = len - 1; a > 0; --a) { + buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8); + } +} + +void asset_nx2_usb_save_encrypt(uint8_t* buf, size_t len) +{ + /* skip non encrypted review area */ + buf += sizeof(struct asset_nx2_usb_save_review); + len -= sizeof(struct asset_nx2_usb_save_review); + + for (size_t a = 1; a < len; ++a) { + buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1]; + } +} \ No newline at end of file diff --git a/src/main/asset/nx2/lib/usb-save.h b/src/main/asset/nx2/lib/usb-save.h new file mode 100644 index 0000000..01e71b9 --- /dev/null +++ b/src/main/asset/nx2/lib/usb-save.h @@ -0,0 +1,122 @@ +#ifndef ASSET_NX2_USB_SAVE_H +#define ASSET_NX2_USB_SAVE_H + +#include +#include + +#define ASSET_NX2_USB_SAVE_SIZE 30780 + +enum asset_nx2_usb_save_limits { + ASSET_NX2_USB_SAVE_SERIAL_ID_MAX = 64, + ASSET_NX2_USB_SAVE_PLAYER_ID_MAX = 12, + ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX = 128, + ASSET_NX2_USB_SAVE_SONG_MAX = 256, + ASSET_NX2_USB_SAVE_MISSION_MAX = 1024, + ASSET_NX2_USB_SAVE_BARRICADE_MAX = 16, + ASSET_NX2_USB_SAVE_EVENT_MAX = 128, + ASSET_NX2_USB_SAVE_WARP_MAX = 8, + ASSET_NX2_USB_SAVE_NUM_MODES = 5, +}; + +struct asset_nx2_usb_save_time { + int16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint16_t ms; +} __attribute__((__packed__)); + +struct asset_nx2_usb_save_review { + char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX]; + int32_t mileage; + int32_t reward_count; + int32_t worldmax_count; + int32_t play_count; + char worldmax_current_land[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX]; + char worldmax_current_mission[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX]; + int32_t kcal; + int32_t v02; +} __attribute__((__packed__)); + +struct asset_nx2_usb_save_stats { + uint32_t adler32; + char usb_serial[ASSET_NX2_USB_SAVE_SERIAL_ID_MAX]; + struct asset_nx2_usb_save_time timestamp; + int32_t avatar_id; + int32_t rank; + int32_t country_id; + char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX]; + int32_t mileage; + int32_t play_count; + int32_t kcal; + int32_t v02; + int32_t worldmax_map_position; + int32_t reward_count; + int32_t worldmax_count; + + struct { + /* bits 0-4 for modes/stepcharts */ + uint8_t mode : 5; + /* unused bit */ + uint8_t unused : 1; + /* bit 6 song itself */ + uint8_t song : 1; + /* bit 7 reveal flag */ + uint8_t reveal : 1; + } song_unlocks[ASSET_NX2_USB_SAVE_SONG_MAX] __attribute__((__packed__)); + + struct { + uint8_t clear_flags_directions : 4; + uint8_t clear_flag_mission : 1; + uint8_t unused : 3; + } worldmax_mission_unlocks[ASSET_NX2_USB_SAVE_MISSION_MAX] + __attribute__((__packed__)); + + int32_t worldmax_high_score[ASSET_NX2_USB_SAVE_MISSION_MAX]; + int32_t worldmax_challenge[ASSET_NX2_USB_SAVE_MISSION_MAX]; + + struct { + uint8_t flag_open : 1; + uint8_t unused : 7; + } worldmax_barricade[ASSET_NX2_USB_SAVE_BARRICADE_MAX] + __attribute__((__packed__)); + + struct { + uint8_t flag_cleared : 1; + uint8_t unused : 7; + } worldmax_event[ASSET_NX2_USB_SAVE_EVENT_MAX] __attribute__((__packed__)); + + struct { + uint8_t direction_clear : 4; + uint8_t clear : 1; + uint8_t unused : 3; + } worldmax_warp[ASSET_NX2_USB_SAVE_WARP_MAX] __attribute__((__packed__)); + + char worldmax_current_land[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX]; + char worldmax_current_mission[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX]; + + struct { + int32_t score; + char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX]; + } song_scores[ASSET_NX2_USB_SAVE_SONG_MAX][ASSET_NX2_USB_SAVE_NUM_MODES] + __attribute__((__packed__)); +} __attribute__((__packed__)); + +struct asset_nx2_usb_save { + struct asset_nx2_usb_save_review review; + struct asset_nx2_usb_save_stats stats; +} __attribute__((__packed__)); + +struct asset_nx2_usb_save* asset_nx2_usb_save_new(void); + +// update checksum and prepare profile to get encrypted +void asset_nx2_usb_save_finalize(struct asset_nx2_usb_save* save); + +char* asset_nx2_usb_save_to_string(const struct asset_nx2_usb_save* save); + +void asset_nx2_usb_save_decrypt(uint8_t* buf, size_t len); + +void asset_nx2_usb_save_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/nx2/lib/util.c b/src/main/asset/nx2/lib/util.c new file mode 100644 index 0000000..ca8b04f --- /dev/null +++ b/src/main/asset/nx2/lib/util.c @@ -0,0 +1,100 @@ +#define LOG_MODULE "asset-nx2-util" + +#include + +#include "util/fs.h" +#include "util/log.h" + +#include "util.h" + +struct asset_nx2_usb_rank* asset_nx2_usb_rank_load_from_file(const char* path, + bool encrypted) +{ + struct asset_nx2_usb_rank* rank; + size_t size; + + if (!util_file_load(path, (void**) &rank, &size, false)) { + log_error("Loading nx2 rank file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_nx2_usb_rank)) { + log_error("Invalid size of nx2 rank file %s: %d != %d", path, size, + sizeof(struct asset_nx2_usb_rank)); + free(rank); + return NULL; + } + + if (encrypted) { + asset_nx2_usb_rank_decrypt((uint8_t*) rank, size); + } + + return rank; +} + +bool asset_nx2_usb_rank_save_to_file(const char* path, + const struct asset_nx2_usb_rank* rank, bool encrypt) +{ + struct asset_nx2_usb_rank rank_enc; + + memcpy(&rank_enc, rank, sizeof(struct asset_nx2_usb_rank)); + + if (encrypt) { + asset_nx2_usb_rank_encrypt((uint8_t*) &rank_enc, + sizeof(struct asset_nx2_usb_rank)); + } + + if (!util_file_save(path, (void**) &rank_enc, + sizeof(struct asset_nx2_usb_rank))) { + log_error("Storing nx2 rank data to %s failed", path); + return false; + } + + return true; +} + +struct asset_nx2_usb_save* asset_nx2_usb_save_load_from_file(const char* path, + bool encrypted) +{ + struct asset_nx2_usb_save* save; + size_t size; + + if (!util_file_load(path, (void**) &save, &size, false)) { + log_error("Loading nx2 save file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_nx2_usb_save)) { + log_error("Invalid size of nx2 save file %s: %d != %d", path, size, + sizeof(struct asset_nx2_usb_save)); + free(save); + return NULL; + } + + if (encrypted) { + asset_nx2_usb_save_decrypt((uint8_t*) save, size); + } + + return save; +} + +bool asset_nx2_usb_save_save_to_file(const char* path, + const struct asset_nx2_usb_save* save, bool encrypt) +{ + struct asset_nx2_usb_save save_enc; + + memcpy(&save_enc, save, sizeof(struct asset_nx2_usb_save)); + + if (encrypt) { + asset_nx2_usb_save_encrypt((uint8_t*) &save_enc, + sizeof(struct asset_nx2_usb_save)); + } + + if (!util_file_save(path, (const void*) &save_enc, + sizeof(struct asset_nx2_usb_save))) { + log_error("Storing nx2 save data to %s failed", path); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/main/asset/nx2/lib/util.h b/src/main/asset/nx2/lib/util.h new file mode 100644 index 0000000..1a42d6d --- /dev/null +++ b/src/main/asset/nx2/lib/util.h @@ -0,0 +1,21 @@ +#ifndef ASSET_NX2_UTIL_H +#define ASSET_NX2_UTIL_H + +#include + +#include "usb-rank.h" +#include "usb-save.h" + +// load from file and decrypt, returns decrypted struct +struct asset_nx2_usb_rank* asset_nx2_usb_rank_load_from_file(const char* path, bool encrypted); + +// takes decrypted rank data, encrypts it and writes it to file +bool asset_nx2_usb_rank_save_to_file(const char* path, const struct asset_nx2_usb_rank* rank, bool encrypt); + +// load from file and decrypt, returns decrypted struct +struct asset_nx2_usb_save* asset_nx2_usb_save_load_from_file(const char* path, bool encrypted); + +// takes decrypted save data, encrypts it and writes it to file +bool asset_nx2_usb_save_save_to_file(const char* path, const struct asset_nx2_usb_save* save, bool encrypt); + +#endif \ No newline at end of file diff --git a/src/main/asset/nx2/tool/usb-profile.c b/src/main/asset/nx2/tool/usb-profile.c new file mode 100644 index 0000000..ba54629 --- /dev/null +++ b/src/main/asset/nx2/tool/usb-profile.c @@ -0,0 +1,154 @@ +/** + * Tool for NX2 profiles: decrypt, encrypt, print profile data + */ +#include +#include +#include + +#include "asset/nx2/lib/util.h" + +#include "util/str.h" + +int main(int argc, char** argv) +{ + int ret; + char* rank_path; + char* save_path; + + if (argc < 3) { + printf("Usage: %s [cmd: new, dec, enc, dump] " + "[path containing nx2rank.bin nx2save.bin]\n", argv[0]); + return -1; + } + + ret = 0; + + rank_path = util_str_merge(argv[2], "nx2rank.bin"); + save_path = util_str_merge(argv[2], "nx2save.bin"); + + if (!strcmp(argv[1], "new")) { + struct asset_nx2_usb_rank* rank = asset_nx2_usb_rank_new(); + struct asset_nx2_usb_save* save = asset_nx2_usb_save_new(); + + asset_nx2_usb_rank_finalize(rank); + asset_nx2_usb_save_finalize(save); + + if (!asset_nx2_usb_rank_save_to_file(rank_path, rank, true)) { + fprintf(stderr, "Creating rank file %s failed\n", rank_path); + ret = -2; + } + + if (!asset_nx2_usb_save_save_to_file(save_path, save, true)) { + fprintf(stderr, "Creating save file %s failed\n", save_path); + ret = -3; + } + + free(rank); + free(save); + } else { + struct asset_nx2_usb_rank* rank; + struct asset_nx2_usb_save* save; + bool encrypted; + + if (!strcmp(argv[1], "enc")) { + char* tmp; + + encrypted = false; + + tmp = util_str_merge(rank_path, ".dec"); + free(rank_path); + rank_path = tmp; + + tmp = util_str_merge(save_path, ".dec"); + free(save_path); + save_path = tmp; + } else { + encrypted = true; + } + + rank = asset_nx2_usb_rank_load_from_file(rank_path, encrypted); + save = asset_nx2_usb_save_load_from_file(save_path, encrypted); + + if (!rank) { + fprintf(stderr, "Loading %s failed", rank_path); + ret = -4; + goto cleanup; + } + + if (!save) { + fprintf(stderr, "Loading %s failed", save_path); + ret = -5; + free(rank); + goto cleanup; + } + + if (!strcmp(argv[1], "dec")) { + char* rank_path_dec; + char* save_path_dec; + + rank_path_dec = util_str_merge(rank_path, ".dec"); + save_path_dec = util_str_merge(save_path, ".dec"); + + if (!asset_nx2_usb_rank_save_to_file(rank_path_dec, rank, false)) { + fprintf(stderr, "Saving decrypted rank file to %s failed\n", + rank_path_dec); + ret = -6; + } + + if (!asset_nx2_usb_save_save_to_file(save_path_dec, save, false)) { + fprintf(stderr, "Saving decrypted save file to %s failed\n", + save_path_dec); + ret = -7; + } + + free(rank_path_dec); + free(save_path_dec); + } else if (!strcmp(argv[1], "enc")) { + char* rank_path_enc; + char* save_path_enc; + + rank_path_enc = util_str_merge(rank_path, ".enc"); + save_path_enc = util_str_merge(save_path, ".enc"); + + if (!asset_nx2_usb_rank_save_to_file(rank_path_enc, rank, true)) { + fprintf(stderr, "Saving encrypted rank file to %s failed\n", + rank_path_enc); + ret = -6; + } + + if (!asset_nx2_usb_save_save_to_file(save_path_enc, save, true)) { + fprintf(stderr, "Saving encrypted save file to %s failed\n", + save_path_enc); + ret = -7; + } + + free(rank_path_enc); + free(save_path_enc); + } else if (!strcmp(argv[1], "dump")) { + char* rank_str; + char* save_str; + + rank_str = asset_nx2_usb_rank_to_string(rank); + save_str = asset_nx2_usb_save_to_string(save); + + printf("----------------- rank -----------------\n" + "%s----------------- save -----------------\n%s", + rank_str, save_str); + + free(rank_str); + free(save_str); + } else { + fprintf(stderr, "Unknown command %s\n", argv[1]); + ret = -4; + } + + free(rank); + free(save); + } + +cleanup: + free(rank_path); + free(save_path); + + return ret; +} \ No newline at end of file diff --git a/src/main/asset/nxa/lib/usb-rank.c b/src/main/asset/nxa/lib/usb-rank.c new file mode 100644 index 0000000..2f17ce2 --- /dev/null +++ b/src/main/asset/nxa/lib/usb-rank.c @@ -0,0 +1,103 @@ +#include +#include + +#include "util/adler32.h" + +#include "util/mem.h" +#include "util/str.h" + +#include "usb-rank.h" + +struct asset_nxa_usb_rank* asset_nxa_usb_rank_new(void) +{ + struct asset_nxa_usb_rank* rank; + + rank = (struct asset_nxa_usb_rank*) + util_xmalloc(sizeof(struct asset_nxa_usb_rank)); + + memset(rank, 0, sizeof(struct asset_nxa_usb_rank)); + + return rank; +} + +void asset_nxa_usb_rank_finalize(struct asset_nxa_usb_rank* rank) +{ + rank->adler32 = util_adler32_calc(1, ((const uint8_t*) rank) + 4, + sizeof(struct asset_nxa_usb_rank) - 4); +} + +char* asset_nxa_usb_rank_to_string(const struct asset_nxa_usb_rank* rank) +{ + char* buffer; + char* buffer2; + char* merged; + char* usb_ser; + + buffer = (char*) util_xmalloc(512); + memset(buffer, 0, 512); + + usb_ser = util_str_buffer((const uint8_t*) rank->usb_serial, + ASSET_NXA_USB_RANK_USB_SERIAL_LEN); + + util_str_format(buffer, 512, + "adler32: 0x%X\n" + // "usb_serial: %s\n", + "num_rankings: %d\n" + "ranking entries:\n", + rank->adler32, + // usb_ser, + rank->num_rankings); + + for (uint32_t i = 0; i < ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES; i++) { + + for (uint32_t j = 0; j < ASSET_NXA_USB_RANK_MAX_STAGES; j++) { + buffer2 = (char*) util_xmalloc(512); + memset(buffer2, 0, 512); + + util_str_format(buffer2, 512, + "%d/%d:\n" + "game_mode: %d\n" + "play_order: %d\n" + "play_score: %d\n" + "grade: %d\n" + "mileage: %d\n" + "play_time: %f\n" + "kcal: %f\n" + "v02: %f\n", + i, j, + rank->entries[i][j].game_mode, + rank->entries[i][j].play_order, + rank->entries[i][j].play_score, + rank->entries[i][j].grade, + rank->entries[i][j].mileage, + rank->entries[i][j].play_time, + rank->entries[i][j].kcal, + rank->entries[i][j].v02); + + merged = util_str_merge(buffer, buffer2); + + free(buffer); + free(buffer2); + + buffer = merged; + } + } + + free(usb_ser); + + return buffer; +} + +void asset_nxa_usb_rank_decrypt(uint8_t* buf, size_t len) +{ + for (size_t a = len - 1; a > 0; --a) { + buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8); + } +} + +void asset_nxa_usb_rank_encrypt(uint8_t* buf, size_t len) +{ + for (size_t a = 1; a < len; ++a) { + buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1]; + } +} \ No newline at end of file diff --git a/src/main/asset/nxa/lib/usb-rank.h b/src/main/asset/nxa/lib/usb-rank.h new file mode 100644 index 0000000..58d2b96 --- /dev/null +++ b/src/main/asset/nxa/lib/usb-rank.h @@ -0,0 +1,43 @@ +#ifndef ASSET_NXA_USB_RANK_H +#define ASSET_NXA_USB_RANK_H + +#include +#include + +enum asset_nxa_usb_rank_sizes { + ASSET_NXA_USB_RANK_MAX_STAGES = 3, + ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES = 256, + ASSET_NXA_USB_RANK_USB_SERIAL_LEN = 64, +}; + +struct asset_nxa_usb_rank_entry { + int32_t game_mode; + int32_t play_order; + int32_t play_score; + int32_t grade; + int32_t mileage; + float play_time; + float kcal; + float v02; +} __attribute__((__packed__)); + +struct asset_nxa_usb_rank { + uint32_t adler32; + char usb_serial[ASSET_NXA_USB_RANK_USB_SERIAL_LEN]; + uint32_t num_rankings; + struct asset_nxa_usb_rank_entry + entries[ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES][ASSET_NXA_USB_RANK_MAX_STAGES]; +} __attribute__((__packed__)); + +struct asset_nxa_usb_rank* asset_nxa_usb_rank_new(void); + +// update checksum and prepare profile to get encrypted +void asset_nxa_usb_rank_finalize(struct asset_nxa_usb_rank* rank); + +char* asset_nxa_usb_rank_to_string(const struct asset_nxa_usb_rank* rank); + +void asset_nxa_usb_rank_decrypt(uint8_t* buf, size_t len); + +void asset_nxa_usb_rank_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/nxa/lib/usb-save.c b/src/main/asset/nxa/lib/usb-save.c new file mode 100644 index 0000000..3376128 --- /dev/null +++ b/src/main/asset/nxa/lib/usb-save.c @@ -0,0 +1,457 @@ +#include +#include + +#include "util/adler32.h" + +#include "util/mem.h" +#include "util/str.h" + +#include "usb-save.h" + +static char* asset_nxa_usb_save_time_to_string( + const struct asset_nxa_usb_save_time* time) +{ + char* buffer; + + buffer = (char*) util_xmalloc(128); + memset(buffer, 0, 128); + + util_str_format(buffer, 128, + "year: %d\n" + "month: %d\n" + "day: %d\n" + "hour: %d\n" + "min: %d\n" + "ms: %d\n", + time->year, + time->month, + time->day, + time->hour, + time->min, + time->ms); + + return buffer; +} + +static char* asset_nxa_usb_save_review_to_string( + const struct asset_nxa_usb_save_review* review) +{ + char* buffer; + char* land; + char* mission; + char* timestamp; + + buffer = (char*) util_xmalloc(1024); + memset(buffer, 0, 1024); + + land = util_str_buffer((const uint8_t*) review->worldmax_current_land, + ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX); + mission = util_str_buffer((const uint8_t*) review->worldmax_current_mission, + ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX); + timestamp = asset_nxa_usb_save_time_to_string(&review->timestamp); + + util_str_format(buffer, 1024, + ">>> review:\n" + "player_id: %s\n" + "mileage: %d\n" + "reward_count: %d\n" + "worldmax_count: %d\n" + "play_count: %d\n" + "worldmax_current_land: %s\n" + "worldmax_current_mission: %s\n" + "kcal: %d\n" + "v02: %d\n", + "timestamp: \n%s", + "running_step: %d\n", + "play_time_minutes: %f\n", + "total_completion_percentage: %f\n", + "arcade_percentage: %f\n", + "brain_shower_percentage: %f\n", + "special_percentage: %f\n", + review->player_id, + review->mileage, + review->reward_count, + review->worldmax_count, + review->play_count, + land, + mission, + review->kcal, + review->v02, + timestamp, + review->running_step, + review->play_time_minutes, + review->total_completion_percentage, + review->arcade_percentage, + review->brain_shower_percentage, + review->special_percentage); + + free(land); + free(mission); + free(timestamp); + + return buffer; +} + +static char* asset_nxa_usb_save_stats_to_string( + const struct asset_nxa_usb_save_stats* stats) +{ + char* merged; + char* buffer; + char* timestamp; + char* tmp; + char* tmp2; + const size_t buf_size = 16384; + + merged = (char*) util_xmalloc(buf_size); + memset(merged, 0, buf_size); + + buffer = (char*) util_xmalloc(buf_size); + memset(buffer, 0, buf_size); + + timestamp = asset_nxa_usb_save_time_to_string(&stats->timestamp); + + util_str_format(merged, buf_size, + ">>> stats:\n" + "adler32: 0x%X\n" + "usb_serial: %s\n" + "timestamp: %s" + "avatar_id: %d\n" + "rank: %d\n" + "country_id: %d\n" + "player_id: %s\n" + "mileage: %d\n" + "play_count: %d\n" + "kcal: %d\n" + "v02: %d\n" + "worldmax_map_position: 0x%X\n" + "reward_count: %d\n" + "worldmax_count: %d\n", + stats->adler32, + stats->usb_serial, + timestamp, + stats->avatar_id, + stats->rank, + stats->country_id, + stats->player_id, + stats->mileage, + stats->play_count, + stats->kcal, + stats->v02, + stats->worldmax_map_position, + stats->reward_count, + stats->worldmax_count); + + free(timestamp); + + tmp = util_str_merge(merged, "song_unlocks:\n"); + + free(merged); + merged = tmp; + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_SONG_MAX; i++) { + + util_str_format(buffer, buf_size, + "song slot: %d\n" + "mode: 0x%X\n" + "unused: 0x%X\n" + "song: %d\n" + "reveal: %d\n", + i, + stats->song_unlocks[i].mode, + stats->song_unlocks[i].unused, + stats->song_unlocks[i].song, + stats->song_unlocks[i].reveal); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) { + + util_str_format(buffer, buf_size, + "mission slot: %d\n" + "clear_flags_directions: 0x%X\n" + "clear_flag_mission: %d\n" + "unused: 0x%X\n", + i, + stats->worldmax_mission_unlocks[i].clear_flags_directions, + stats->worldmax_mission_unlocks[i].clear_flag_mission, + stats->worldmax_mission_unlocks[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_high_score %d: %d\n", + i, + stats->worldmax_high_score[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_challenge %d: %d\n", + i, + stats->worldmax_challenge[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_BARRICADE_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_barricade %d:\n" + "flag_open: %d\n" + "unused: 0x%X\n", + i, + stats->worldmax_barricade[i].flag_open, + stats->worldmax_barricade[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_EVENT_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_event %d:\n" + "flag_cleared: %d\n" + "unused: 0x%X\n", + i, + stats->worldmax_event[i].flag_cleared, + stats->worldmax_event[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WARP_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_warp %d:\n" + "direction_clear: 0x%X\n" + "clear: %d\n", + "unused: 0x%X\n", + i, + stats->worldmax_warp[i].direction_clear, + stats->worldmax_warp[i].clear, + stats->worldmax_warp[i].unused); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_current_land %d: %d\n", + i, + stats->worldmax_current_land[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX; i++) { + + util_str_format(buffer, buf_size, + "worldmax_current_mission %d: %d\n", + i, + stats->worldmax_current_mission[i]); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + + for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_SONG_MAX; i++) { + + for (uint32_t j = 0; j < ASSET_NXA_USB_SAVE_NUM_MODES; j++) { + util_str_format(buffer, buf_size, + "song_scores %d/%d:\n" + "score: %d\n" + "player_id: %s\n", + i, + j, + stats->song_scores[i][j].score, + stats->song_scores[i][j].player_id); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + } + } + + /* ------------- */ + util_str_format(buffer, buf_size, + "security_dongle_mfgid 0x%X\n" + "unlock_signal: 0x%X\n" + "running_steps: %d\n" + "total_play_time_min: %f\n" + "total_completion_percentage: %f\n" + "arcade_completion_percentage: %f\n" + "brain_shower_completion_percentage: %f\n" + "special_stage_completion_percentage: %f\n", + stats->security_dongle_mfgid, + stats->unlock_signal, + stats->running_steps, + stats->total_play_time_min, + stats->total_completion_percentage, + stats->arcade_completion_percentage, + stats->brain_shower_completion_percentage, + stats->special_stage_completion_percentage); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + + /* ------------- */ + tmp2 = util_str_buffer(stats->unkn_some_map_scores_to_song_ids, + 4096); + + util_str_format(buffer, buf_size, + "unkn_some_map_scores_to_song_ids: %s\n", + tmp2); + + tmp = util_str_merge(merged, buffer); + + free(tmp2); + free(merged); + merged = tmp; + + /* ------------- */ + tmp2 = util_str_buffer(stats->unkn2, sizeof(stats->unkn2)); + + util_str_format(buffer, buf_size, + "unkn2: %s\n", + tmp2); + + tmp = util_str_merge(merged, buffer); + + free(tmp2); + free(merged); + merged = tmp; + + /* ------------- */ + util_str_format(buffer, buf_size, + "break_item_slot 0x%X\n" + "func_item_slot: 0x%X\n" + "bga_item_slot: 0x%X\n" + "time_item_slot: 0x%X\n" + "unknown: 0x%X\n", + stats->break_item_slot, + stats->func_item_slot, + stats->bga_item_slot, + stats->time_item_slot, + stats->unknown); + + tmp = util_str_merge(merged, buffer); + + free(merged); + merged = tmp; + + free(buffer); + + return merged; +} + +struct asset_nxa_usb_save* asset_nxa_usb_save_new(void) +{ + struct asset_nxa_usb_save* save; + char name[10]; + + save = (struct asset_nxa_usb_save*) util_xmalloc( + sizeof(struct asset_nxa_usb_save)); + + memset(save, 0, sizeof(struct asset_nxa_usb_save)); + + sprintf(name, "NX%06d", rand() % 1000000); + strcpy(save->review.player_id, name); + strcpy(save->stats.player_id, name); + + /* default world map position */ + save->stats.worldmax_map_position = 0xEF001; + + /* nxa release date as default timestamp */ + save->stats.timestamp.year = 2008; + save->stats.timestamp.month = 12; + save->stats.timestamp.day = 26; + save->stats.timestamp.hour = 0; + save->stats.timestamp.min = 0; + save->stats.timestamp.ms = 0; + + return save; +} + +void asset_nxa_usb_save_finalize(struct asset_nxa_usb_save* save) +{ + /* checksum update, expected size for area to checksum: 90540 */ + save->stats.adler32 = util_adler32_calc(1, + ((const uint8_t*) &save->stats) + 4, + sizeof(struct asset_nxa_usb_save_stats) - 4); +} + +char* asset_nxa_usb_save_to_string(const struct asset_nxa_usb_save* save) +{ + char* review; + char* stats; + char* merged; + + review = asset_nxa_usb_save_review_to_string(&save->review); + stats = asset_nxa_usb_save_stats_to_string(&save->stats); + + merged = util_str_merge(review, stats); + + free(review); + free(stats); + + return merged; +} + +void asset_nxa_usb_save_decrypt(uint8_t* buf, size_t len) +{ + /* skip non encrypted review area */ + buf += sizeof(struct asset_nxa_usb_save_review); + len -= sizeof(struct asset_nxa_usb_save_review); + + for (size_t a = len - 1; a > 0; --a) { + buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8); + } +} + +void asset_nxa_usb_save_encrypt(uint8_t* buf, size_t len) +{ + /* skip non encrypted review area */ + buf += sizeof(struct asset_nxa_usb_save_review); + len -= sizeof(struct asset_nxa_usb_save_review); + + for (size_t a = 1; a < len; ++a) { + buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1]; + } +} \ No newline at end of file diff --git a/src/main/asset/nxa/lib/usb-save.h b/src/main/asset/nxa/lib/usb-save.h new file mode 100644 index 0000000..6b04118 --- /dev/null +++ b/src/main/asset/nxa/lib/usb-save.h @@ -0,0 +1,275 @@ +#ifndef ASSET_NXA_USB_SAVE_H +#define ASSET_NXA_USB_SAVE_H + +#include +#include + +enum asset_nxa_usb_save_limits { + ASSET_NXA_USB_SAVE_SERIAL_ID_MAX = 64, + ASSET_NXA_USB_SAVE_PLAYER_ID_MAX = 12, + ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX = 128, + ASSET_NXA_USB_SAVE_SONG_MAX = 256, + ASSET_NXA_USB_SAVE_MISSION_MAX = 1024, + ASSET_NXA_USB_SAVE_BARRICADE_MAX = 16, + ASSET_NXA_USB_SAVE_EVENT_MAX = 128, + ASSET_NXA_USB_SAVE_WARP_MAX = 8, + ASSET_NXA_USB_SAVE_NUM_MODES = 5, +}; + +struct asset_nxa_usb_save_time { + int16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint16_t ms; +} __attribute__((__packed__)); + +/* Not encrypted and read only, offset 0x00 to 0x144 (excl) */ +struct asset_nxa_usb_save_review { + /* 0x00, 12 byte char array: max char length is 8 which gets displayed + ingame */ + char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX]; + /* 0x0C, 4 byte int */ + uint32_t mileage; + /* 0x10, 4 byte int: achieved reward count, max 65 */ + uint32_t reward_count; + /* 0x14, 4 byte int: successful mission count, max 634 */ + uint32_t worldmax_count; + /* 0x18, 4 byte int */ + uint32_t play_count; + /* 0x1C, 128 byte char array */ + char worldmax_current_land[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX]; + /* 0x9C, 128 byte char array */ + char worldmax_current_mission[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX]; + /* 0x11C, 4 byte int */ + uint32_t kcal; + /* 0x120, 4 byte int */ + uint32_t v02; + /* 0x124, 8 byte */ + struct asset_nxa_usb_save_time timestamp; + /* 0x12C, 4 byte int */ + uint32_t running_step; + /* 0x130, 4 byte float */ + float play_time_minutes; + /* 0x134, 4 byte float */ + float total_completion_percentage; + /* 0x138, 4 byte float */ + float arcade_percentage; + /* 0x13C, 4 byte float */ + float brain_shower_percentage; + /* 0x140, 4 byte float */ + float special_percentage; +} __attribute__((__packed__)); + +struct asset_nxa_usb_save_stats { + /* 0x144, 4 byte int */ + uint32_t adler32; + /* 0x148, 64 byte */ + char usb_serial[ASSET_NXA_USB_SAVE_SERIAL_ID_MAX]; + /* 0x188, 8 byte */ + struct asset_nxa_usb_save_time timestamp; + /* 0x190, 4 byte int */ + int32_t avatar_id; + /* 0x194, 4 byte int: setting this non null will give you a trophy */ + int32_t rank; + /* 0x198, 4 byte int: seems unused */ + int32_t country_id; + /* 0x19C, 12 byte char array */ + char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX]; + /* 0x1A8, 4 byte int */ + int32_t mileage; + /* 0x1AD, 4 byte int */ + int32_t play_count; + /* 0x1B0, 4 byte int */ + int32_t kcal; + /* 0x1B4, 4 byte int */ + int32_t v02; + /* 0x1B8, 4 byte int */ + int32_t worldmax_map_position; + /* 0x1BC, 4 byte int: achieved reward count, max 65 */ + int32_t reward_count; + /* 0x1C0, 4 byte int: successful mission count, max 634 */ + int32_t worldmax_count; + + /* 0x1C4, 256 bytes */ + struct { + /* bits 0-4 for modes/stepcharts */ + uint8_t mode : 5; + /* unused bit */ + uint8_t unused : 1; + /* bit 6 song itself */ + uint8_t song : 1; + /* bit 7 reveal flag */ + uint8_t reveal : 1; + } song_unlocks[ASSET_NXA_USB_SAVE_SONG_MAX] __attribute__((__packed__)); + + /* 0x2C4, 1024 bytes */ + struct { + uint8_t clear_flags_directions : 4; + uint8_t clear_flag_mission : 1; + uint8_t unused : 3; + } worldmax_mission_unlocks[ASSET_NXA_USB_SAVE_MISSION_MAX] + __attribute__((__packed__)); + + /* 0x6C4, 4 byte int * 1024: high score for each mission */ + int32_t worldmax_high_score[ASSET_NXA_USB_SAVE_MISSION_MAX]; + + /* 0x16C4, 4 byte int * 1024 */ + int32_t worldmax_challenge[ASSET_NXA_USB_SAVE_MISSION_MAX]; + + /* 0x26C4, 16 bytes + 0x00 for barricade clear and 0x01 for block */ + struct { + uint8_t flag_open : 1; + uint8_t unused : 7; + } worldmax_barricade[ASSET_NXA_USB_SAVE_BARRICADE_MAX] + __attribute__((__packed__)); + + /* 0x26D4, 128 bytes + 0x00 for event clear and 0x01 for not cleared */ + struct { + uint8_t flag_cleared : 1; + uint8_t unused : 7; + } worldmax_event[ASSET_NXA_USB_SAVE_EVENT_MAX] __attribute__((__packed__)); + + /* 0x2754, 8 bytes + bit 0~3: clear bit for each direction bit:4 clear */ + struct { + uint8_t direction_clear : 4; + uint8_t clear : 1; + uint8_t unused : 3; + } worldmax_warp[ASSET_NXA_USB_SAVE_WARP_MAX] __attribute__((__packed__)); + + /* 0x275C, 128 byte char array */ + char worldmax_current_land[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX]; + + /* 0x27DC, 128 byte char array */ + char worldmax_current_mission[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX]; + + /* 0x285C */ + struct { + int32_t score; + char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX]; + } song_scores[ASSET_NXA_USB_SAVE_SONG_MAX][ASSET_NXA_USB_SAVE_NUM_MODES] + __attribute__((__packed__)); + + /* 0x785C, 4 byte int */ + uint32_t security_dongle_mfgid; + + /* 0x7860, 4 byte int: <=3 Tells game to unlock new song */ + uint32_t unlock_signal; + + /* 0x7864, 4 byte int */ + uint32_t running_steps; + + /* 0x7868, 4 byte float */ + float total_play_time_min; + + /* 0x786C, 4 byte float */ + float total_completion_percentage; + + /* 0x7870, 4 byte float */ + float arcade_completion_percentage; + + /* 0x7874, 4 byte float */ + float brain_shower_completion_percentage; + + /* 0x7878, 4 byte float */ + float special_stage_completion_percentage; + + /* 0x787C TODO unknown + 0x787C, 1 byte char * 4096 - Used by GetSongIndex - + Assuming Maps Scores to Song IDs */ + uint8_t unkn_some_map_scores_to_song_ids[4096]; + + /* 0x887C TODO unknown + 0x887C, 1 byte char * 576 - Song Locks/Unlocks - 0x40 Unlocks (Special Zone, etc.) + 0x8A70 , 1 byte char * 36 - WorldMax Keys and various other events for completion + 0x8A9C, 8 byte char* - A Worldmax ID (Perhaps one to mark progress in Space) + 0x8AA4, 1 byte char * 24 - More WorldMax Event Switches */ + uint8_t unkn2[576]; + + /* 0x8ABC, 4 byte int: possible values + 0x1 - grey + 0x2 - red + 0x3 - yellow + 0x4 - green + 0x5 - Dark Green + 0x6 - aqua + 0x7 - blue + 0x8 - purple + 0x9 - pink + 0xA - light grey + 0xB - Black + 0xC - Orange + */ + uint32_t break_item_slot; + + /* 0x8AC0, 4 byte int + 0x1 - Shield + 0x2 - PermaShield + 0x3 - Line Searcher + 0x4 - Perma Line Searcher + 0x5 - Life Up + 0x6 - Perma Life Up + 0x7 - Lucky + 0x8 - Perma Lucky + 0x9 - Portal Pass + */ + uint32_t func_item_slot; + + /* 0x8AC4, 4 byte int + 0x1 - BGA OFF + 0x2 - Perma BGA OFF + */ + uint32_t bga_item_slot; + + /* 0x8AC4, 4 byte int + 0x1 - 10+ + 0x2 - 20+ + 0x3 - 30+ + */ + uint32_t time_item_slot; + + /* 0x8AC8, 4 byte int */ + uint32_t unknown; + + /* 0x8ACC, unknown stuff: More WorldMax Event Switches (Unused)? */ + uint8_t unknown2[12]; + + /* 0x8AD8, 4 byte float - Unknown What this Does (Unused) */ + float unknown3; + + /* 0x8ADC, totally unknown stuff, just nulls */ + uint8_t unknown4[0x7F8]; + + /* 0x92D4 */ + uint8_t unknown5[0xD01C]; + + /* TODO missing switches for dark/light world stuff + 0x8ACC, 1 byte char - More WorldMax Event Switches (Unused) + 0x8AD8 , 4 byte float - Unknown What this Does (Unused) + 0x92D4, High Score Table [See Below] + 0x132D0, 5216 bytes - Unknown Table (Unused) + 0x162D0, 24 bytes - Unknown Footer (Unused by Game - Most Likely PumBI) + */ +} __attribute__((__packed__)); + +struct asset_nxa_usb_save { + struct asset_nxa_usb_save_review review; + struct asset_nxa_usb_save_stats stats; +} __attribute__((__packed__)); + +struct asset_nxa_usb_save* asset_nxa_usb_save_new(void); + +/* update checksum and prepare profile to get encrypted */ +void asset_nxa_usb_save_finalize(struct asset_nxa_usb_save* save); + +char* asset_nxa_usb_save_to_string(const struct asset_nxa_usb_save* save); + +void asset_nxa_usb_save_decrypt(uint8_t* buf, size_t len); + +void asset_nxa_usb_save_encrypt(uint8_t* buf, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/asset/nxa/lib/util.c b/src/main/asset/nxa/lib/util.c new file mode 100644 index 0000000..0f1c485 --- /dev/null +++ b/src/main/asset/nxa/lib/util.c @@ -0,0 +1,100 @@ +#define LOG_MODULE "asset-nxa-util" + +#include + +#include "util/fs.h" +#include "util/log.h" + +#include "util.h" + +struct asset_nxa_usb_rank* asset_nxa_usb_rank_load_from_file(const char* path, + bool encrypted) +{ + struct asset_nxa_usb_rank* rank; + size_t size; + + if (!util_file_load(path, (void**) &rank, &size, false)) { + log_error("Loading nxa rank file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_nxa_usb_rank)) { + log_error("Invalid size of nxa rank file %s: %d != %d", path, size, + sizeof(struct asset_nxa_usb_rank)); + free(rank); + return NULL; + } + + if (encrypted) { + asset_nxa_usb_rank_decrypt((uint8_t*) rank, size); + } + + return rank; +} + +bool asset_nxa_usb_rank_save_to_file(const char* path, + const struct asset_nxa_usb_rank* rank, bool encrypt) +{ + struct asset_nxa_usb_rank rank_enc; + + memcpy(&rank_enc, rank, sizeof(struct asset_nxa_usb_rank)); + + if (encrypt) { + asset_nxa_usb_rank_encrypt((uint8_t*) &rank_enc, + sizeof(struct asset_nxa_usb_rank)); + } + + if (!util_file_save(path, (void**) &rank_enc, + sizeof(struct asset_nxa_usb_rank))) { + log_error("Storing nxa rank data to %s failed", path); + return false; + } + + return true; +} + +struct asset_nxa_usb_save* asset_nxa_usb_save_load_from_file(const char* path, + bool encrypted) +{ + struct asset_nxa_usb_save* save; + size_t size; + + if (!util_file_load(path, (void**) &save, &size, false)) { + log_error("Loading nxa save file %s failed", path); + return NULL; + } + + if (size != sizeof(struct asset_nxa_usb_save)) { + log_error("Invalid size of nxa save file %s: %d != %d", path, size, + sizeof(struct asset_nxa_usb_save)); + free(save); + return NULL; + } + + if (encrypted) { + asset_nxa_usb_save_decrypt((uint8_t*) save, size); + } + + return save; +} + +bool asset_nxa_usb_save_save_to_file(const char* path, + const struct asset_nxa_usb_save* save, bool encrypt) +{ + struct asset_nxa_usb_save save_enc; + + memcpy(&save_enc, save, sizeof(struct asset_nxa_usb_save)); + + if (encrypt) { + asset_nxa_usb_save_encrypt((uint8_t*) &save_enc, + sizeof(struct asset_nxa_usb_save)); + } + + if (!util_file_save(path, (const void*) &save_enc, + sizeof(struct asset_nxa_usb_save))) { + log_error("Storing nxa save data to %s failed", path); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/main/asset/nxa/lib/util.h b/src/main/asset/nxa/lib/util.h new file mode 100644 index 0000000..15ccd9c --- /dev/null +++ b/src/main/asset/nxa/lib/util.h @@ -0,0 +1,21 @@ +#ifndef ASSET_NXA_UTIL_H +#define ASSET_NXA_UTIL_H + +#include + +#include "usb-rank.h" +#include "usb-save.h" + +// load from file and decrypt, returns decrypted struct +struct asset_nxa_usb_rank* asset_nxa_usb_rank_load_from_file(const char* path, bool encrypted); + +// takes decrypted rank data, encrypts it and writes it to file +bool asset_nxa_usb_rank_save_to_file(const char* path, const struct asset_nxa_usb_rank* rank, bool encrypt); + +// load from file and decrypt, returns decrypted struct +struct asset_nxa_usb_save* asset_nxa_usb_save_load_from_file(const char* path, bool encrypted); + +// takes decrypted save data, encrypts it and writes it to file +bool asset_nxa_usb_save_save_to_file(const char* path, const struct asset_nxa_usb_save* save, bool encrypt); + +#endif \ No newline at end of file diff --git a/src/main/asset/nxa/tool/usb-profile.c b/src/main/asset/nxa/tool/usb-profile.c new file mode 100644 index 0000000..0cf75ae --- /dev/null +++ b/src/main/asset/nxa/tool/usb-profile.c @@ -0,0 +1,154 @@ +/** + * Tool for NXA profiles: decrypt, encrypt, print profile data + */ +#include +#include +#include + +#include "asset/nxa/lib/util.h" + +#include "util/str.h" + +int main(int argc, char** argv) +{ + int ret; + char* rank_path; + char* save_path; + + if (argc < 3) { + printf("Usage: %s [cmd: new, dec, enc, dump] " + "[path containing nxarank.bin nxasave.bin]\n", argv[0]); + return -1; + } + + ret = 0; + + rank_path = util_str_merge(argv[2], "nxarank.bin"); + save_path = util_str_merge(argv[2], "nxasave.bin"); + + if (!strcmp(argv[1], "new")) { + struct asset_nxa_usb_rank* rank = asset_nxa_usb_rank_new(); + struct asset_nxa_usb_save* save = asset_nxa_usb_save_new(); + + asset_nxa_usb_rank_finalize(rank); + asset_nxa_usb_save_finalize(save); + + if (!asset_nxa_usb_rank_save_to_file(rank_path, rank, true)) { + fprintf(stderr, "Creating rank file %s failed\n", rank_path); + ret = -2; + } + + if (!asset_nxa_usb_save_save_to_file(save_path, save, true)) { + fprintf(stderr, "Creating save file %s failed\n", save_path); + ret = -3; + } + + free(rank); + free(save); + } else { + struct asset_nxa_usb_rank* rank; + struct asset_nxa_usb_save* save; + bool encrypted; + + if (!strcmp(argv[1], "enc")) { + char* tmp; + + encrypted = false; + + tmp = util_str_merge(rank_path, ".dec"); + free(rank_path); + rank_path = tmp; + + tmp = util_str_merge(save_path, ".dec"); + free(save_path); + save_path = tmp; + } else { + encrypted = true; + } + + rank = asset_nxa_usb_rank_load_from_file(rank_path, encrypted); + save = asset_nxa_usb_save_load_from_file(save_path, encrypted); + + if (!rank) { + fprintf(stderr, "Loading %s failed", rank_path); + ret = -4; + goto cleanup; + } + + if (!save) { + fprintf(stderr, "Loading %s failed", save_path); + ret = -5; + free(rank); + goto cleanup; + } + + if (!strcmp(argv[1], "dec")) { + char* rank_path_dec; + char* save_path_dec; + + rank_path_dec = util_str_merge(rank_path, ".dec"); + save_path_dec = util_str_merge(save_path, ".dec"); + + if (!asset_nxa_usb_rank_save_to_file(rank_path_dec, rank, false)) { + fprintf(stderr, "Saving decrypted rank file to %s failed\n", + rank_path_dec); + ret = -6; + } + + if (!asset_nxa_usb_save_save_to_file(save_path_dec, save, false)) { + fprintf(stderr, "Saving decrypted save file to %s failed\n", + save_path_dec); + ret = -7; + } + + free(rank_path_dec); + free(save_path_dec); + } else if (!strcmp(argv[1], "enc")) { + char* rank_path_enc; + char* save_path_enc; + + rank_path_enc = util_str_merge(rank_path, ".enc"); + save_path_enc = util_str_merge(save_path, ".enc"); + + if (!asset_nxa_usb_rank_save_to_file(rank_path_enc, rank, true)) { + fprintf(stderr, "Saving encrypted rank file to %s failed\n", + rank_path_enc); + ret = -6; + } + + if (!asset_nxa_usb_save_save_to_file(save_path_enc, save, true)) { + fprintf(stderr, "Saving encrypted save file to %s failed\n", + save_path_enc); + ret = -7; + } + + free(rank_path_enc); + free(save_path_enc); + } else if (!strcmp(argv[1], "dump")) { + char* rank_str; + char* save_str; + + rank_str = asset_nxa_usb_rank_to_string(rank); + save_str = asset_nxa_usb_save_to_string(save); + + printf("----------------- rank -----------------\n" + "%s----------------- save -----------------\n%s", + rank_str, save_str); + + free(rank_str); + free(save_str); + } else { + fprintf(stderr, "Unknown command %s\n", argv[1]); + ret = -4; + } + + free(rank); + free(save); + } + +cleanup: + free(rank_path); + free(save_path); + + return ret; +} \ No newline at end of file diff --git a/src/main/asset/x2/lib/settings.c b/src/main/asset/x2/lib/settings.c new file mode 100644 index 0000000..978b919 --- /dev/null +++ b/src/main/asset/x2/lib/settings.c @@ -0,0 +1,87 @@ +#include + +#include "asset/x2/lib/settings.h" + +#include "util/adler32.h" +#include "util/mem.h" + +static const char* _asset_x2_settings_defaut_high_score_names[] = { + "MKII", + "YAHP", + "KANN", + "ZINY", + "PIAH", + "AHN ", + "PIYO", + "HIKO", + "HALO", + "BAJI", + "YUTE", + "SS ", + "SIHO", + "AZKI", + "JUNE", + "GOON", + "ARI*", + "TAMA", + "YSMA", + "PIU " +}; + +struct asset_x2_settings* asset_x2_settings_new(void) +{ + struct asset_x2_settings* settings; + + settings = util_xmalloc(sizeof(struct asset_x2_settings)); + + memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad)); + memset(settings->unkn, 0, sizeof(settings->unkn)); + settings->unlock_canond_full = 0; + settings->total_uptime = 0; + settings->unkn69 = 0x69; + memset(settings->song_blacklist, 0, ASSET_X2_SETTINGS_MAX_SONGS); + memset(settings->unkn3, 0, sizeof(settings->unkn3)); + memcpy(settings->ident, "EX02", 4); + /* Updated using finalize */ + settings->adler32 = 0; + memset(settings->song_play_count, 0, sizeof(uint16_t) * ASSET_X2_SETTINGS_MAX_SONGS); + settings->padding = 0; + + for (uint8_t i = 0; i < ASSET_X2_SETTINGS_HIGH_SCORE_COUNT; i++) { + settings->high_score_scores[i] = 10000u - (500u * i); + memcpy(&settings->high_score_names[i], &_asset_x2_settings_defaut_high_score_names[i], + ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN); + } + + settings->coin_limit = 0; + settings->game_mode = ASSET_X2_SETTINGS_GAME_MODE_NORMAL; + settings->game_level = ASSET_X2_SETTINGS_LEVEL_NORMAL; + settings->game_stage_break = ASSET_X2_SETTINGS_STAGE_BREAK_2ND; + settings->language = ASSET_X2_SETTINGS_LANG_ENG; + settings->game_demo_sound = 1; + settings->game_show_help = 1; + settings->coin1_setting = 1; + settings->coin2_setting = 1; + settings->bookkeeping_coin1_total = 0; + settings->bookkeeping_coin2_total = 0; + settings->bookkeeping_service_total = 0; + + return settings; +} + +void asset_x2_settings_finalize(struct asset_x2_settings* settings) +{ + /* Seems odd, but they just checksum the game settings part...*/ + settings->adler32 = util_adler32_calc(1, (const uint8_t*) &settings->game_mode, 8); +} + +void asset_x2_settings_unlock_all(struct asset_x2_settings* settings) +{ + settings->unlock_canond_full = 1; +} + +char* asset_x2_settings_to_string(const struct asset_x2_settings* settings) +{ + // TODO + return ""; +} \ No newline at end of file diff --git a/src/main/asset/x2/lib/settings.h b/src/main/asset/x2/lib/settings.h new file mode 100644 index 0000000..6fad54d --- /dev/null +++ b/src/main/asset/x2/lib/settings.h @@ -0,0 +1,82 @@ +#ifndef ASSET_X2_SETTINGS_H +#define ASSET_X2_SETTINGS_H + +#include + +#define ASSET_X2_SETTINGS_FILE_NAME "PIUEXCEED.INI" +#define ASSET_X2_SETTINGS_MAX_SONGS 139 +#define ASSET_X2_SETTINGS_HIGH_SCORE_COUNT 20 +#define ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN 4 + +enum asset_x2_settings_language { + ASSET_X2_SETTINGS_LANG_KOR = 0, + ASSET_X2_SETTINGS_LANG_ENG = 1, + ASSET_X2_SETTINGS_LANG_SP = 2, + ASSET_X2_SETTINGS_LANG_CH = 3, +}; + +enum asset_x2_settings_game_mode { + ASSET_X2_SETTINGS_GAME_MODE_NORMAL = 0, + ASSET_X2_SETTINGS_GAME_MODE_EVENT = 1, +}; + +enum asset_x2_settings_level { + ASSET_X2_SETTINGS_LEVEL_EASY = 0, + ASSET_X2_SETTINGS_LEVEL_NORMAL = 1, + ASSET_X2_SETTINGS_LEVEL_HARD = 2, +}; + +enum asset_x2_settings_stage_break { + ASSET_X2_SETTINGS_STAGE_BREAK_OFF = 0, + ASSET_X2_SETTINGS_STAGE_BREAK_1ST = 1, + ASSET_X2_SETTINGS_STAGE_BREAK_2ND = 2, + ASSET_X2_SETTINGS_STAGE_BREAK_3RD = 3, + ASSET_X2_SETTINGS_STAGE_BREAK_4TH = 4, +}; + +struct asset_x2_settings { + /* Padding to fill up to 4k EEPROM legacy size */ + uint8_t ff_pad[0x51B]; + uint8_t unkn[10]; + uint8_t unlock_canond_full; + uint32_t total_uptime; + uint8_t unkn69; + uint8_t song_blacklist[ASSET_X2_SETTINGS_MAX_SONGS]; + uint8_t unkn3[0x75]; + /* EX02 */ + char ident[4]; + uint32_t adler32; + uint16_t song_play_count[ASSET_X2_SETTINGS_MAX_SONGS]; + uint16_t padding; + uint32_t high_score_scores[ASSET_X2_SETTINGS_HIGH_SCORE_COUNT]; + /* 20 names a 4 chars for the default high score list */ + char high_score_names[ASSET_X2_SETTINGS_HIGH_SCORE_COUNT][ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN]; + /* 0 none */ + uint8_t coin_limit; + uint8_t game_mode; + uint8_t game_level; + uint8_t game_stage_break; + uint8_t language; + /* 0 off, 1 on */ + uint8_t game_demo_sound; + /* 0 off, 1 on */ + uint8_t game_show_help; + /* 0 freeplay */ + uint8_t coin1_setting; + /* 0 freeplay */ + uint8_t coin2_setting; + uint32_t bookkeeping_coin1_total; + uint32_t bookkeeping_coin2_total; + uint32_t bookkeeping_service_total; +} __attribute__((__packed__)); + +struct asset_x2_settings* asset_x2_settings_new(void); + +// update checksum +void asset_x2_settings_finalize(struct asset_x2_settings* settings); + +void asset_x2_settings_unlock_all(struct asset_x2_settings* settings); + +char* asset_x2_settings_to_string(const struct asset_x2_settings* settings); + +#endif diff --git a/src/main/asset/zero/lib/settings.c b/src/main/asset/zero/lib/settings.c new file mode 100644 index 0000000..049d4c3 --- /dev/null +++ b/src/main/asset/zero/lib/settings.c @@ -0,0 +1,62 @@ +#include + +#include "asset/zero/lib/settings.h" + +#include "util/adler32.h" +#include "util/mem.h" + +struct asset_zero_settings* asset_zero_settings_new(void) +{ + struct asset_zero_settings* settings; + + settings = util_xmalloc(sizeof(struct asset_zero_settings)); + + memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad)); + memcpy(settings->ident, "ZERO", 4); + /* Updated using finalize */ + settings->adler32 = 0; + settings->total_uptime = 0; + settings->language = ASSET_ZERO_SETTINGS_LANG_ENG; + memset(settings->song_play_count, 0, sizeof(uint32_t) * ASSET_ZERO_SETTINGS_MAX_SONGS); + settings->game_option_default_station = ASSET_ZERO_SETTINGS_STATION_EASY; + settings->game_mode = ASSET_ZERO_SETTINGS_GAME_MODE_NORMAL; + settings->game_level = ASSET_ZERO_SETTINGS_LEVEL_NORMAL; + settings->game_stage_break = ASSET_ZERO_SETTINGS_STAGE_BREAK_2ND; + settings->game_demo_sound = 1; + settings->game_show_help = 1; + settings->game_mercy_ticket = 0; + settings->game_score_per_ticket = 0; + settings->coin_limit = 0; + settings->coin1_setting = 1; + settings->coin2_setting = 1; + memset(settings->mission_unlock_flags, 0, ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS); + settings->unkn2 = 0x2A; + settings->unkn3 = 0; + settings->bookkeeping_coin1_total = 0; + settings->bookkeeping_coin2_total = 0; + settings->bookkeeping_service_total = 0; + settings->bookkeeping_ticket_1 = 0; + settings->bookkeeping_ticket_2 = 0; + settings->region = 0xFF; + memset(settings->censor_table, 0, ASSET_ZERO_SETTINGS_MAX_SONGS); + + return settings; +} + +void asset_zero_settings_finalize(struct asset_zero_settings* settings) +{ + /* Seems odd, but they just checksum the game settings part...*/ + settings->adler32 = util_adler32_calc(1, (const uint8_t*) &settings->game_mode, 8); +} + +void asset_zero_settings_unlock_all(struct asset_zero_settings* settings) +{ + /* Mark all missions cleared to unlock all missions and content locked by some missions */ + memset(settings->mission_unlock_flags, 1, ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS); +} + +char* asset_zero_settings_to_string(const struct asset_zero_settings* settings) +{ + // TODO + return ""; +} \ No newline at end of file diff --git a/src/main/asset/zero/lib/settings.h b/src/main/asset/zero/lib/settings.h new file mode 100644 index 0000000..b675902 --- /dev/null +++ b/src/main/asset/zero/lib/settings.h @@ -0,0 +1,95 @@ +#ifndef ASSET_ZERO_SETTINGS_H +#define ASSET_ZERO_SETTINGS_H + +#include + +#define ASSET_ZERO_SETTINGS_FILE_NAME "PIUZERO.INI" +#define ASSET_ZERO_SETTINGS_MAX_SONGS 200 +#define ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS 59 + +enum asset_zero_settings_language { + ASSET_ZERO_SETTINGS_LANG_KOR = 0, + ASSET_ZERO_SETTINGS_LANG_ENG = 1, + ASSET_ZERO_SETTINGS_LANG_SP = 2, + ASSET_ZERO_SETTINGS_LANG_CH = 3, +}; + +enum asset_zero_settings_station { + ASSET_ZERO_SETTINGS_STATION_EASY = 0, + ASSET_ZERO_SETTINGS_STATION_ARCADE = 1, + ASSET_ZERO_SETTINGS_STATION_REMIX = 2, +}; + +enum asset_zero_settings_game_mode { + ASSET_ZERO_SETTINGS_GAME_MODE_NORMAL = 0, + ASSET_ZERO_SETTINGS_GAME_MODE_EVENT = 1, +}; + +enum asset_zero_settings_level { + ASSET_ZERO_SETTINGS_LEVEL_EASY = 0, + ASSET_ZERO_SETTINGS_LEVEL_NORMAL = 1, + ASSET_ZERO_SETTINGS_LEVEL_HARD = 2, +}; + +enum asset_zero_settings_stage_break { + ASSET_ZERO_SETTINGS_STAGE_BREAK_OFF = 0, + ASSET_ZERO_SETTINGS_STAGE_BREAK_1ST = 1, + ASSET_ZERO_SETTINGS_STAGE_BREAK_2ND = 2, + ASSET_ZERO_SETTINGS_STAGE_BREAK_3RD = 3, + ASSET_ZERO_SETTINGS_STAGE_BREAK_4TH = 4, +}; + +struct asset_zero_settings { + /* Padding to fill up to 4k EEPROM legacy size */ + uint8_t ff_pad[0xBA4]; + /* ZERO */ + char ident[4]; + uint32_t adler32; + uint32_t total_uptime; + uint8_t language; + uint32_t song_play_count[ASSET_ZERO_SETTINGS_MAX_SONGS]; + uint32_t game_option_default_station; + uint8_t game_mode; + uint8_t game_level; + uint8_t game_stage_break; + /* 0 off, 1 on */ + uint8_t game_demo_sound; + /* 0 off, 1 on */ + uint8_t game_show_help; + /* 0 off, 1 on */ + uint8_t game_mercy_ticket; + /* 0 off, 1 - 6 for score */ + uint8_t game_score_per_ticket; + /* 0 none */ + uint8_t coin_limit; // 0 none + /* 0 freeplay */ + uint8_t coin1_setting; + /* 0 freeplay */ + uint8_t coin2_setting; + /* Unlock flags for missions (total of 30) */ + uint8_t mission_unlock_flags[ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS]; + /* Default value 0x2A */ + uint32_t unkn2; + uint32_t unkn3; + uint32_t bookkeeping_coin1_total; + uint32_t bookkeeping_coin2_total; + uint32_t bookkeeping_service_total; + uint32_t bookkeeping_ticket_1; + uint32_t bookkeeping_ticket_2; + /* FF -> not used, censoring globally disabled. unused feature though */ + uint8_t region; + /* 0 = censoring of song off */ + uint8_t censor_table[ASSET_ZERO_SETTINGS_MAX_SONGS]; +} __attribute__((__packed__)); + +struct asset_zero_settings* asset_zero_settings_new(void); + +// update checksum +void asset_zero_settings_finalize(struct asset_zero_settings* settings); + +// sets all missions cleared to unlock special stage songs and other missions +void asset_zero_settings_unlock_all(struct asset_zero_settings* settings); + +char* asset_zero_settings_to_string(const struct asset_zero_settings* settings); + +#endif diff --git a/src/main/capnhook/hook/common.h b/src/main/capnhook/hook/common.h new file mode 100644 index 0000000..59221b0 --- /dev/null +++ b/src/main/capnhook/hook/common.h @@ -0,0 +1,12 @@ +/** + * Common stuff for capnhook/hook module + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_COMMON_H +#define CAPNHOOK_COMMON_H + +#define _countof(array) (sizeof(array) / sizeof((array)[0])) + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hook/filehook.c b/src/main/capnhook/hook/filehook.c new file mode 100644 index 0000000..7d47b9a --- /dev/null +++ b/src/main/capnhook/hook/filehook.c @@ -0,0 +1,662 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "capnhook/hook/common.h" +#include "capnhook/hook/filehook.h" +#include "capnhook/hook/lib.h" + +#include "util/time.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Real funcs typedefs */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +typedef FILE* (*cnh_filehook_fopen_t)(const char* filename, const char* mode); +typedef int (*cnh_filehook_fclose_t)(FILE* stream); +typedef size_t (*cnh_filehook_fread_t)(void* ptr, size_t size, size_t nmemb, FILE* stream); +typedef size_t (*cnh_filehook_fwrite_t)(const void* ptr, size_t size, size_t nmemb, FILE* stream); +typedef char* (*cnh_filehook_fgets_t)(char* s, int size, FILE* stream); +typedef int (*cnh_filehook_fseek_t)(FILE* stream, long offset, int whence); +typedef long (*cnh_filehook_ftell_t)(FILE* stream); +typedef int (*cnh_filehook_feof_t)(FILE* stream); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private helpers */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_filehook_init(void); + +static enum cnh_result _cnh_filehook_invoke_real(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_fopen(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_fclose(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_fread(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_fwrite(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_fgets(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_fseek(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_ftell(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_filehook_invoke_real_feof(struct cnh_filehook_irp *irp); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private state */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static cnh_filehook_fopen_t _cnh_filehook_real_fopen; +static cnh_filehook_fclose_t _cnh_filehook_real_fclose; +static cnh_filehook_fread_t _cnh_filehook_real_fread; +static cnh_filehook_fwrite_t _cnh_filehook_real_fwrite; +static cnh_filehook_fgets_t _cnh_filehook_real_fgets; +static cnh_filehook_fseek_t _cnh_filehook_real_fseek; +static cnh_filehook_ftell_t _cnh_filehook_real_ftell; +static cnh_filehook_feof_t _cnh_filehook_real_feof; + +static const cnh_filehook_fn_t _cnh_filehook_real_handlers[8] = { + [CNH_FILEHOOK_IRP_OP_OPEN] = _cnh_filehook_invoke_real_fopen, + [CNH_FILEHOOK_IRP_OP_CLOSE] = _cnh_filehook_invoke_real_fclose, + [CNH_FILEHOOK_IRP_OP_READ] = _cnh_filehook_invoke_real_fread, + [CNH_FILEHOOK_IRP_OP_WRITE] = _cnh_filehook_invoke_real_fwrite, + [CNH_FILEHOOK_IRP_OP_FGETS] = _cnh_filehook_invoke_real_fgets, + [CNH_FILEHOOK_IRP_OP_SEEK] = _cnh_filehook_invoke_real_fseek, + [CNH_FILEHOOK_IRP_OP_TELL] = _cnh_filehook_invoke_real_ftell, + [CNH_FILEHOOK_IRP_OP_EOF] = _cnh_filehook_invoke_real_feof, +}; + +static atomic_int _cnh_filehook_initted = ATOMIC_VAR_INIT(0); +static atomic_int _cnh_filehook_init_in_progress = ATOMIC_VAR_INIT(0); +static pthread_mutex_t _cnh_filehook_lock; +static cnh_filehook_fn_t *_cnh_filehook_handlers; +static size_t _cnh_filehook_nhandlers; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Public module functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_filehook_push_handler(cnh_filehook_fn_t fn) +{ + cnh_filehook_fn_t *new_array; + size_t new_size; + enum cnh_result result; + + assert(fn != NULL); + + _cnh_filehook_init(); + pthread_mutex_lock(&_cnh_filehook_lock); + + new_size = _cnh_filehook_nhandlers + 1; + new_array = realloc(_cnh_filehook_handlers, new_size * sizeof(cnh_filehook_fn_t)); + + if (new_array != NULL) { + _cnh_filehook_handlers = new_array; + _cnh_filehook_handlers[_cnh_filehook_nhandlers++] = fn; + result = CNH_RESULT_SUCCESS; + } else { + result = CNH_RESULT_OUT_OF_MEMORY; + } + + pthread_mutex_unlock(&_cnh_filehook_lock); + + return result; +} + +enum cnh_result cnh_filehook_invoke_next(struct cnh_filehook_irp *irp) +{ + cnh_filehook_fn_t handler; + enum cnh_result result; + + assert(irp != NULL); + assert(_cnh_filehook_initted > 0); + + pthread_mutex_lock(&_cnh_filehook_lock); + + assert(irp->next_handler <= _cnh_filehook_nhandlers); + + if (irp->next_handler < _cnh_filehook_nhandlers) { + handler = _cnh_filehook_handlers[irp->next_handler]; + irp->next_handler++; + } else { + handler = _cnh_filehook_invoke_real; + irp->next_handler = (size_t) -1; + } + + pthread_mutex_unlock(&_cnh_filehook_lock); + + result = handler(irp); + + if (result != CNH_RESULT_SUCCESS) { + irp->next_handler = (size_t) -1; + } + + return result; +} + +FILE* cnh_filehook_open_dummy_file_handle() +{ + _cnh_filehook_init(); + + /* We need to return some sort of valid FD to the + caller, since we're simulating a device that + doesn't exist. Open an FD on /dev/null. */ + + return _cnh_filehook_real_fopen("/dev/null", "r"); +} + +void cnh_filehook_close_dummy_file_handle(FILE* file) +{ + _cnh_filehook_init(); + + /* Avoid hooking pipeline when using dummy handles */ + _cnh_filehook_real_fclose(file); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooked functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +FILE* fopen(const char* filename, const char* mode) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (filename == NULL || mode == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return NULL; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_OPEN; + irp.file = NULL; + irp.open_filename = filename; + irp.open_mode = mode; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return NULL; + } + + errno = 0; + + return irp.file; +} + +int fclose(FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (stream == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return EOF; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_CLOSE; + irp.file = stream; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return EOF; + } + + errno = 0; + + return 0; +} + +size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (ptr == NULL || stream == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return 0; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_READ; + irp.file = stream; + irp.read.bytes = ptr; + irp.read.nbytes = size * nmemb; + irp.read.pos = 0; + /* To ensure we don't mess up any calls that are just passed through, we have to drag along the original size + and nmemb parameters and apply them to the real call at the end of the chain if the iobuffer was not + modified */ + irp.orig_read_write_size = size; + irp.orig_read_write_nmemb = nmemb; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return 0; + } + + errno = 0; + + return irp.read.pos / size; +} + +size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_WRITE; + irp.file = stream; + irp.write.bytes = ptr; + irp.write.nbytes = size * nmemb; + irp.write.pos = 0; + /* To ensure we don't mess up any calls that are just passed through, we have to drag along the original size + and nmemb parameters and apply them to the real call at the end of the chain if the iobuffer was not + modified */ + irp.orig_read_write_size = size; + irp.orig_read_write_nmemb = nmemb; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return 0; + } + + errno = 0; + + return irp.write.pos / size; +} + +char* fgets(char* s, int size, FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (s == NULL || stream == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return NULL; + } + + /* Redirect this to fread */ + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_FGETS; + irp.file = stream; + irp.read.bytes = (uint8_t*) s; + irp.read.nbytes = (size_t) size; + irp.read.pos = 0; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return NULL; + } + + errno = 0; + + return (char*) irp.read.bytes; +} + +int fseek(FILE* stream, long offset, int whence) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (stream == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_SEEK; + irp.file = stream; + irp.seek_origin = whence; + irp.seek_offset = offset; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +void rewind(FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (stream == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return; + } + + /* Seek to beginning */ + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_SEEK; + irp.file = stream; + irp.seek_origin = SEEK_SET; + irp.seek_offset = 0; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return; + } +} + +long ftell(FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (stream == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_TELL; + irp.file = stream; + /* Return value */ + irp.tell_offset = 0; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return (long) irp.tell_offset; +} + +int feof(FILE* stream) +{ + struct cnh_filehook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_filehook_init(); + + if (stream == NULL) { + /* Must be EBADF according to man pages */ + errno = EBADF; + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FILEHOOK_IRP_OP_EOF; + irp.file = stream; + /* Return value */ + irp.eof = false; + + result = cnh_filehook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + /* Function is never supposed to fail and EBADF is the only allowed error code */ + errno = EBADF; + return -1; + } + + errno = 0; + + return irp.eof ? 1 : 0; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Helper functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_filehook_init(void) +{ + int expected; + + if (atomic_load(&_cnh_filehook_initted) > 0) { + return; + } + + expected = 0; + + if (!atomic_compare_exchange_strong(&_cnh_filehook_init_in_progress, &expected, 1)) { + while (atomic_load(&_cnh_filehook_init_in_progress) > 1) { + util_time_sleep_us(100); + } + + return; + } + + /* Check again to ensure the current thread yielded between the init'd check and setting init in progress */ + if (atomic_load(&_cnh_filehook_initted) > 0) { + /* Revert init in progress, because nothing to do anymore */ + atomic_store(&_cnh_filehook_init_in_progress, 0); + return; + } + + _cnh_filehook_real_fopen = (cnh_filehook_fopen_t) cnh_lib_get_func_addr("fopen"); + _cnh_filehook_real_fclose = (cnh_filehook_fclose_t) cnh_lib_get_func_addr("fclose"); + _cnh_filehook_real_fread = (cnh_filehook_fread_t) cnh_lib_get_func_addr("fread"); + _cnh_filehook_real_fwrite = (cnh_filehook_fwrite_t) cnh_lib_get_func_addr("fwrite"); + _cnh_filehook_real_fgets = (cnh_filehook_fgets_t) cnh_lib_get_func_addr("fgets"); + _cnh_filehook_real_fseek = (cnh_filehook_fseek_t) cnh_lib_get_func_addr("fseek"); + _cnh_filehook_real_ftell = (cnh_filehook_ftell_t) cnh_lib_get_func_addr("ftell"); + _cnh_filehook_real_feof = (cnh_filehook_feof_t) cnh_lib_get_func_addr("feof"); + + pthread_mutex_init(&_cnh_filehook_lock, NULL); + + atomic_store(&_cnh_filehook_initted, 1); + atomic_store(&_cnh_filehook_init_in_progress, 0); +} + +static enum cnh_result _cnh_filehook_invoke_real(struct cnh_filehook_irp *irp) +{ + cnh_filehook_fn_t handler; + + assert(irp != NULL); + assert(irp->op < _countof(_cnh_filehook_real_handlers)); + + handler = _cnh_filehook_real_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_filehook_invoke_real_fopen(struct cnh_filehook_irp *irp) +{ + FILE* file; + + assert(irp != NULL); + + file = _cnh_filehook_real_fopen(irp->open_filename, irp->open_mode); + + if (!file) { + return cnh_errno_to_result(errno); + } + + irp->file = file; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_filehook_invoke_real_fclose(struct cnh_filehook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_filehook_real_fclose(irp->file); + + if (res == EOF) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_filehook_invoke_real_fread(struct cnh_filehook_irp *irp) +{ + size_t read; + + assert(irp != NULL); + + /* Check if any previous hook modified the buffer and use original parameters otherwise to ensure the original + call is correctly applied to the real function */ + if (irp->read.pos != 0 || irp->read.nbytes != irp->orig_read_write_nmemb * irp->orig_read_write_size) { + read = _cnh_filehook_real_fread(&irp->read.bytes[irp->read.pos], irp->read.nbytes - irp->read.pos, 1, + irp->file); + + if (read < 1 && ferror(irp->file) != 0) { + return cnh_errno_to_result(errno); + } + + irp->read.pos += irp->read.nbytes - irp->read.pos; + } else { + read = _cnh_filehook_real_fread(irp->read.bytes, irp->orig_read_write_size, irp->orig_read_write_nmemb, + irp->file); + + if (read < 1 && ferror(irp->file) != 0) { + return cnh_errno_to_result(errno); + } + + irp->read.pos = read * irp->orig_read_write_size; + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_filehook_invoke_real_fwrite(struct cnh_filehook_irp *irp) +{ + size_t written; + + assert(irp != NULL); + + /* Check if any previous hook modified the buffer and use original parameters otherwise to ensure the original + call is correctly applied to the real function */ + if (irp->write.pos != 0 || irp->write.nbytes != irp->orig_read_write_nmemb * irp->orig_read_write_size) { + written = _cnh_filehook_real_fwrite(&irp->write.bytes[irp->write.pos], irp->write.nbytes - irp->write.pos, 1, + irp->file); + + if (written < 1 && ferror(irp->file) != 0) { + return cnh_errno_to_result(errno); + } + + irp->write.pos += irp->write.nbytes - irp->write.pos; + } else { + written = _cnh_filehook_real_fwrite(irp->write.bytes, irp->orig_read_write_size, irp->orig_read_write_nmemb, + irp->file); + + if (written < 1 && ferror(irp->file) != 0) { + return cnh_errno_to_result(errno); + } + + irp->write.pos += written * irp->orig_read_write_size; + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_filehook_invoke_real_fgets(struct cnh_filehook_irp *irp) +{ + char* res; + + res = _cnh_filehook_real_fgets((char*) irp->read.bytes, irp->read.nbytes, irp->file); + + if (res == NULL) { + /* eof */ + if (errno == 0) { + irp->read.bytes = NULL; + return CNH_RESULT_SUCCESS; + } else { + return cnh_errno_to_result(errno); + } + } else { + return CNH_RESULT_SUCCESS; + } +} + +static enum cnh_result _cnh_filehook_invoke_real_fseek(struct cnh_filehook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_filehook_real_fseek(irp->file, (long) irp->seek_offset, irp->seek_origin); + + if (res != 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_filehook_invoke_real_ftell(struct cnh_filehook_irp *irp) +{ + long res; + + assert(irp != NULL); + + res = _cnh_filehook_real_ftell(irp->file); + + if (res < 0) { + return cnh_errno_to_result(errno); + } + + irp->tell_offset = (uint64_t) res; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_filehook_invoke_real_feof(struct cnh_filehook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_filehook_real_feof(irp->file); + + if (res < 0) { + return cnh_errno_to_result(errno); + } + + irp->eof = res > 0; + + return CNH_RESULT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/capnhook/hook/filehook.h b/src/main/capnhook/hook/filehook.h new file mode 100644 index 0000000..94233c8 --- /dev/null +++ b/src/main/capnhook/hook/filehook.h @@ -0,0 +1,90 @@ +/** + * Hook module for hooking file related calls, e.g. fopen, fread, fwrite, etc. + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_FILEHOOK_H +#define CAPNHOOK_FILEHOOK_H + +#include +#include +#include +#include + +#include "capnhook/hook/iobuf.h" + +/** + * Available operations to hook + */ +enum cnh_filehook_irp_op { + CNH_FILEHOOK_IRP_OP_OPEN = 0, + CNH_FILEHOOK_IRP_OP_CLOSE = 1, + CNH_FILEHOOK_IRP_OP_READ = 2, + CNH_FILEHOOK_IRP_OP_WRITE = 3, + CNH_FILEHOOK_IRP_OP_FGETS = 4, + CNH_FILEHOOK_IRP_OP_SEEK = 5, + CNH_FILEHOOK_IRP_OP_TELL = 6, + CNH_FILEHOOK_IRP_OP_EOF = 7, +}; + +/** + * I/O request packet + */ +struct cnh_filehook_irp { + enum cnh_filehook_irp_op op; + size_t next_handler; + FILE* file; + const char *open_filename; + const char* open_mode; + struct cnh_iobuf read; + struct cnh_const_iobuf write; + size_t orig_read_write_size; + size_t orig_read_write_nmemb; + int seek_origin; + int64_t seek_offset; + uint64_t tell_offset; + bool eof; +}; + +/** + * Hook function type + */ +typedef enum cnh_result (*cnh_filehook_fn_t)(struct cnh_filehook_irp *irp); + +/** + * Add a new hook handler to the hook module. + * The handler added is getting called on every hooked operation. + * + * @param fn Pointer to hook function to add + * @return Result/error code if hooking was successful + */ +enum cnh_result cnh_filehook_push_handler(cnh_filehook_fn_t fn); + +/** + * Invoke the next hooked function registered in the hook module. + * Call this from your hook handler if you want to pass on execution to further + * hooked calls reaching the original function at the end of the hook chain. + * + * @param irp I/O request package to dispatch + * @return Result of the following function dispatching the request package + */ +enum cnh_result cnh_filehook_invoke_next(struct cnh_filehook_irp *irp); + +/** + * Create a dummy file handle. Use this function for file access virtualization. + * Do not execute real operations on the handle returned. + * + * @return Actual file handle instance pointing to a dummy endpoint. + */ +FILE* cnh_filehook_open_dummy_file_handle(); + +/** + * Close a dummy file handle. Make sure to free your previously allocated handles + * to avoid resource leaks. Do not free them using the real close function. + * + * @param file Dummy file handle to free + */ +void cnh_filehook_close_dummy_file_handle(FILE* file); + +#endif diff --git a/src/main/capnhook/hook/fshook.c b/src/main/capnhook/hook/fshook.c new file mode 100644 index 0000000..7e01bf5 --- /dev/null +++ b/src/main/capnhook/hook/fshook.c @@ -0,0 +1,447 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "capnhook/hook/common.h" +#include "capnhook/hook/fshook.h" +#include "capnhook/hook/lib.h" + +#include "util/time.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Real funcs typedefs */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +typedef DIR* (*cnh_fshook_opendir_t)(const char* name); +typedef int (*cnh_fshook_lxstat_t)(int version, const char* file, struct stat* buf); +typedef int (*cnh_fshook_xstat_t)(int version, const char* file, struct stat* buf); +typedef int (*cnh_fshook_rename_t)(const char* old, const char* new); +typedef int (*cnh_fshook_remove_t)(const char* pathname); +typedef int (*cnh_fshook_access_t)(const char* path, int amode); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private helpers */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_fshook_init(void); + +static enum cnh_result _cnh_fshook_invoke_real(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_fshook_invoke_real_opendir(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_fshook_invoke_real_lxstat(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_fshook_invoke_real_xstat(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_fshook_invoke_real_rename(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_fshook_invoke_real_remove(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_fshook_invoke_real_access(struct cnh_fshook_irp *irp); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private state */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static cnh_fshook_opendir_t _cnh_fshook_real_opendir; +static cnh_fshook_lxstat_t _cnh_fshook_real_lxstat; +static cnh_fshook_xstat_t _cnh_fshook_real_xstat; +static cnh_fshook_rename_t _cnh_fshook_real_rename; +static cnh_fshook_remove_t _cnh_fshook_real_remove; +static cnh_fshook_access_t _cnh_fshook_real_access; + +static const cnh_fshook_fn_t _cnh_fshook_real_handlers[6] = { + [CNH_FSHOOK_IRP_OP_DIR_OPEN] = _cnh_fshook_invoke_real_opendir, + [CNH_FSHOOK_IRP_OP_LXSTAT] = _cnh_fshook_invoke_real_lxstat, + [CNH_FSHOOK_IRP_OP_XSTAT] = _cnh_fshook_invoke_real_xstat, + [CNH_FSHOOK_IRP_OP_RENAME] = _cnh_fshook_invoke_real_rename, + [CNH_FSHOOK_IRP_OP_REMOVE] = _cnh_fshook_invoke_real_remove, + [CNH_FSHOOK_IRP_OP_ACCESS] = _cnh_fshook_invoke_real_access, +}; + +static atomic_int _cnh_fshook_initted = ATOMIC_VAR_INIT(0); +static atomic_int _cnh_fshook_init_in_progress = ATOMIC_VAR_INIT(0); +static pthread_mutex_t _cnh_fshook_lock; +static cnh_fshook_fn_t *_cnh_fshook_handlers; +static size_t _cnh_fshook_nhandlers; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Public module functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_fshook_push_handler(cnh_fshook_fn_t fn) +{ + cnh_fshook_fn_t *new_array; + size_t new_size; + enum cnh_result result; + + assert(fn != NULL); + + _cnh_fshook_init(); + + pthread_mutex_lock(&_cnh_fshook_lock); + + new_size = _cnh_fshook_nhandlers + 1; + new_array = realloc(_cnh_fshook_handlers, new_size * sizeof(cnh_fshook_fn_t)); + + if (new_array != NULL) { + _cnh_fshook_handlers = new_array; + _cnh_fshook_handlers[_cnh_fshook_nhandlers++] = fn; + result = CNH_RESULT_SUCCESS; + } else { + result = CNH_RESULT_OUT_OF_MEMORY; + } + + pthread_mutex_unlock(&_cnh_fshook_lock); + + return result; +} + +enum cnh_result cnh_fshook_invoke_next(struct cnh_fshook_irp *irp) +{ + cnh_fshook_fn_t handler; + enum cnh_result result; + + assert(irp != NULL); + assert(_cnh_fshook_initted > 0); + + pthread_mutex_lock(&_cnh_fshook_lock); + + assert(irp->next_handler <= _cnh_fshook_nhandlers); + + if (irp->next_handler < _cnh_fshook_nhandlers) { + handler = _cnh_fshook_handlers[irp->next_handler]; + irp->next_handler++; + } else { + handler = _cnh_fshook_invoke_real; + irp->next_handler = (size_t) -1; + } + + pthread_mutex_unlock(&_cnh_fshook_lock); + + result = handler(irp); + + if (result != CNH_RESULT_SUCCESS) { + irp->next_handler = (size_t) -1; + } + + return result; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooked functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +DIR* opendir(const char* name) +{ + struct cnh_fshook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_fshook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FSHOOK_IRP_OP_DIR_OPEN; + irp.opendir_name = name; + irp.opendir_ret = NULL; + + result = cnh_fshook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return NULL; + } + + errno = 0; + + return irp.opendir_ret; +} + +int __lxstat(int version, const char* file, struct stat* buf) +{ + struct cnh_fshook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_fshook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FSHOOK_IRP_OP_LXSTAT; + irp.xstat_version = version; + irp.xstat_file = file; + irp.xstat_buf = buf; + + result = cnh_fshook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +int __xstat(int version, const char* file, struct stat* buf) +{ + struct cnh_fshook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_fshook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FSHOOK_IRP_OP_XSTAT; + irp.xstat_version = version; + irp.xstat_file = file; + irp.xstat_buf = buf; + + result = cnh_fshook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +int rename(const char* old, const char* new) +{ + struct cnh_fshook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_fshook_init(); + + if (old == NULL || new == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FSHOOK_IRP_OP_RENAME; + irp.rename_old = old; + irp.rename_new = new; + + result = cnh_fshook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +int remove(const char* pathname) +{ + struct cnh_fshook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_fshook_init(); + + if (pathname == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FSHOOK_IRP_OP_REMOVE; + irp.remove_pathname = pathname; + + result = cnh_fshook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +int access(const char* path, int amode) +{ + struct cnh_fshook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_fshook_init(); + + if (path == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_FSHOOK_IRP_OP_ACCESS; + irp.access_path = path; + irp.access_amode = amode; + + result = cnh_fshook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Helper functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_fshook_init(void) +{ + int expected; + + if (atomic_load(&_cnh_fshook_initted) > 0) { + return; + } + + expected = 0; + + if (!atomic_compare_exchange_strong(&_cnh_fshook_init_in_progress, &expected, 1)) { + while (atomic_load(&_cnh_fshook_init_in_progress) > 1) { + util_time_sleep_us(100); + } + + return; + } + + /* Check again to ensure the current thread yielded between the init'd check and setting init in progress */ + if (atomic_load(&_cnh_fshook_initted) > 0) { + /* Revert init in progress, because nothing to do anymore */ + atomic_store(&_cnh_fshook_init_in_progress, 0); + return; + } + + _cnh_fshook_real_opendir = (cnh_fshook_opendir_t) cnh_lib_get_func_addr("opendir"); + _cnh_fshook_real_lxstat = (cnh_fshook_lxstat_t) cnh_lib_get_func_addr("__lxstat"); + _cnh_fshook_real_xstat = (cnh_fshook_xstat_t) cnh_lib_get_func_addr("__xstat"); + _cnh_fshook_real_rename = (cnh_fshook_rename_t) cnh_lib_get_func_addr("rename"); + _cnh_fshook_real_remove = (cnh_fshook_remove_t) cnh_lib_get_func_addr("remove"); + _cnh_fshook_real_access = (cnh_fshook_access_t) cnh_lib_get_func_addr("access"); + + pthread_mutex_init(&_cnh_fshook_lock, NULL); + + atomic_store(&_cnh_fshook_initted, 1); + atomic_store(&_cnh_fshook_init_in_progress, 0); +} + +static enum cnh_result _cnh_fshook_invoke_real(struct cnh_fshook_irp *irp) +{ + cnh_fshook_fn_t handler; + + assert(irp != NULL); + assert(irp->op < _countof(_cnh_fshook_real_handlers)); + + handler = _cnh_fshook_real_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_fshook_invoke_real_opendir(struct cnh_fshook_irp *irp) +{ + DIR* dir; + + assert(irp != NULL); + + dir = _cnh_fshook_real_opendir(irp->opendir_name); + + if (dir == NULL) { + return cnh_errno_to_result(errno); + } + + irp->opendir_ret = dir; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_fshook_invoke_real_lxstat(struct cnh_fshook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_fshook_real_lxstat(irp->xstat_version, irp->xstat_file, irp->xstat_buf); + + if (res != 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_fshook_invoke_real_xstat(struct cnh_fshook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_fshook_real_xstat(irp->xstat_version, irp->xstat_file, irp->xstat_buf); + + if (res != 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_fshook_invoke_real_rename(struct cnh_fshook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_fshook_real_rename(irp->rename_old, irp->rename_new); + + if (res != 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_fshook_invoke_real_remove(struct cnh_fshook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_fshook_real_remove(irp->remove_pathname); + + if (res != 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_fshook_invoke_real_access(struct cnh_fshook_irp *irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_fshook_real_access(irp->access_path, irp->access_amode); + + if (res != 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/capnhook/hook/fshook.h b/src/main/capnhook/hook/fshook.h new file mode 100644 index 0000000..4b3c85c --- /dev/null +++ b/src/main/capnhook/hook/fshook.h @@ -0,0 +1,72 @@ +/** + * Hook module for hooking file system related calls, + * not counting calls operating on actual opened files, e.g. + * fopen, fread, fwrite etc. + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_FSHOOK_H +#define CAPNHOOK_FSHOOK_H + +#include +#include +#include + +#include "capnhook/hook/result.h" + +/** + * Available operations to hook + */ +enum cnh_fshook_irp_op { + CNH_FSHOOK_IRP_OP_DIR_OPEN = 0, + CNH_FSHOOK_IRP_OP_LXSTAT = 1, + CNH_FSHOOK_IRP_OP_XSTAT = 2, + CNH_FSHOOK_IRP_OP_RENAME = 3, + CNH_FSHOOK_IRP_OP_REMOVE = 4, + CNH_FSHOOK_IRP_OP_ACCESS = 5, +}; + +/** + * I/O request packet + */ +struct cnh_fshook_irp { + enum cnh_fshook_irp_op op; + size_t next_handler; + const char* opendir_name; + DIR* opendir_ret; + int xstat_version; + const char* xstat_file; + struct stat* xstat_buf; + const char* rename_old; + const char* rename_new; + const char* remove_pathname; + const char* access_path; + int access_amode; +}; + +/** + * Hook function type + */ +typedef enum cnh_result (*cnh_fshook_fn_t)(struct cnh_fshook_irp *irp); + +/** + * Add a new hook handler to the hook module. + * The handler added is getting called on every hooked operation. + * + * @param fn Pointer to hook function to add + * @return Result/error code if hooking was successful + */ +enum cnh_result cnh_fshook_push_handler(cnh_fshook_fn_t fn); + +/** + * Invoke the next hooked function registered in the hook module. + * Call this from your hook handler if you want to pass on execution to further + * hooked calls reaching the original function at the end of the hook chain. + * + * @param irp I/O request package to dispatch + * @return Result of the following function dispatching the request package + */ +enum cnh_result cnh_fshook_invoke_next(struct cnh_fshook_irp *irp); + +#endif diff --git a/src/main/capnhook/hook/iobuf.c b/src/main/capnhook/hook/iobuf.c new file mode 100644 index 0000000..fdfc9d3 --- /dev/null +++ b/src/main/capnhook/hook/iobuf.c @@ -0,0 +1,253 @@ +#include +#include + +#include "capnhook/hook/iobuf.h" + +void cnh_iobuf_flip(struct cnh_const_iobuf *child, struct cnh_iobuf *parent) +{ + assert(child != NULL); + assert(parent != NULL); + + child->bytes = parent->bytes; + child->pos = 0; + child->nbytes = parent->pos; +} + +size_t cnh_iobuf_move(struct cnh_iobuf *dest, struct cnh_const_iobuf *src) +{ + size_t dest_avail; + size_t src_avail; + size_t chunksz; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + + assert(src != NULL); + assert(src->bytes != NULL || src->nbytes == 0); + assert(src->pos <= src->nbytes); + + dest_avail = dest->nbytes - dest->pos; + src_avail = src->nbytes - src->pos; + chunksz = dest_avail < src_avail ? dest_avail : src_avail; + + memcpy(&dest->bytes[dest->pos], &src->bytes[src->pos], chunksz); + + dest->pos += chunksz; + src->pos += chunksz; + + return chunksz; +} + +size_t cnh_iobuf_shift(struct cnh_iobuf *dest, struct cnh_iobuf *src) +{ + struct cnh_const_iobuf span; + + assert(dest != NULL); + assert(src != NULL); + + cnh_iobuf_flip(&span, src); + cnh_iobuf_move(dest, &span); + + memmove(src->bytes, &src->bytes[span.pos], span.nbytes - span.pos); + src->pos -= span.pos; + + return span.pos; +} + +enum cnh_result cnh_iobuf_read(struct cnh_const_iobuf *src, void *bytes, size_t nbytes) +{ + assert(src != NULL); + assert(bytes != NULL || nbytes == 0); + + if (src->pos + nbytes > src->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + memcpy(bytes, &src->bytes[src->pos], nbytes); + src->pos += nbytes; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_read_8(struct cnh_const_iobuf *src, uint8_t *out) +{ + assert(src != NULL); + assert(out != NULL); + + if (src->pos + sizeof(uint8_t) > src->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + *out = src->bytes[src->pos++]; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_read_be16(struct cnh_const_iobuf *src, uint16_t *out) +{ + uint16_t value; + + assert(src != NULL); + assert(out != NULL); + + if (src->pos + sizeof(uint16_t) > src->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + value = src->bytes[src->pos++] << 8; + value |= src->bytes[src->pos++]; + + *out = value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_read_be32(struct cnh_const_iobuf *src, uint32_t *out) +{ + uint32_t value; + + assert(src != NULL); + assert(out != NULL); + + if (src->pos + sizeof(uint32_t) > src->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + value = src->bytes[src->pos++] << 24; + value |= src->bytes[src->pos++] << 16; + value |= src->bytes[src->pos++] << 8; + value |= src->bytes[src->pos++]; + + *out = value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_read_le16(struct cnh_const_iobuf *src, uint16_t *out) +{ + uint16_t value; + + assert(src != NULL); + assert(out != NULL); + + if (src->pos + sizeof(uint16_t) > src->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + value = src->bytes[src->pos++]; + value |= src->bytes[src->pos++] << 8; + + *out = value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_read_le32(struct cnh_const_iobuf *src, uint32_t *out) +{ + uint32_t value; + + assert(src != NULL); + assert(out != NULL); + + if (src->pos + sizeof(uint32_t) > src->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + value = src->bytes[src->pos++]; + value |= src->bytes[src->pos++] << 8; + value |= src->bytes[src->pos++] << 16; + value |= src->bytes[src->pos++] << 24; + + *out = value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_write(struct cnh_iobuf *dest, const void *bytes, size_t nbytes) +{ + assert(dest != NULL); + assert(bytes != NULL || nbytes == 0); + + if (dest->pos + nbytes > dest->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + memcpy(&dest->bytes[dest->pos], bytes, nbytes); + dest->pos += nbytes; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_write_8(struct cnh_iobuf *dest, uint8_t value) +{ + assert(dest != NULL); + + if (dest->pos + sizeof(uint8_t) > dest->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + dest->bytes[dest->pos++] = value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_write_be16(struct cnh_iobuf *dest, uint16_t value) +{ + assert(dest != NULL); + + if (dest->pos + sizeof(uint16_t) > dest->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + dest->bytes[dest->pos++] = (uint8_t) (value >> 8); + dest->bytes[dest->pos++] = (uint8_t) value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_write_be32(struct cnh_iobuf *dest, uint32_t value) +{ + assert(dest != NULL); + + if (dest->pos + sizeof(uint32_t) > dest->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + dest->bytes[dest->pos++] = (uint8_t) (value >> 24); + dest->bytes[dest->pos++] = (uint8_t) (value >> 16); + dest->bytes[dest->pos++] = (uint8_t) (value >> 8); + dest->bytes[dest->pos++] = (uint8_t) value; + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_write_le16(struct cnh_iobuf *dest, uint16_t value) +{ + assert(dest != NULL); + + if (dest->pos + sizeof(uint16_t) > dest->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + dest->bytes[dest->pos++] = (uint8_t) value; + dest->bytes[dest->pos++] = (uint8_t) (value >> 8); + + return CNH_RESULT_SUCCESS; +} + +enum cnh_result cnh_iobuf_write_le32(struct cnh_iobuf *dest, uint32_t value) +{ + assert(dest != NULL); + + if (dest->pos + sizeof(uint32_t) > dest->nbytes) { + return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER; + } + + dest->bytes[dest->pos++] = (uint8_t) value; + dest->bytes[dest->pos++] = (uint8_t) (value >> 8); + dest->bytes[dest->pos++] = (uint8_t) (value >> 16); + dest->bytes[dest->pos++] = (uint8_t) (value >> 24); + + return CNH_RESULT_SUCCESS; +} diff --git a/src/main/capnhook/hook/iobuf.h b/src/main/capnhook/hook/iobuf.h new file mode 100644 index 0000000..0f2e459 --- /dev/null +++ b/src/main/capnhook/hook/iobuf.h @@ -0,0 +1,162 @@ +/** + * Implementation of an I/O buffer used by hooking modules + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_IOBUF_H +#define CAPNHOOK_IOBUF_H + +#include +#include + +#include "capnhook/hook/result.h" + +/** + * I/O buffer + */ +struct cnh_iobuf { + uint8_t *bytes; + size_t nbytes; + size_t pos; +}; + +/** + * I/O buffer + */ +struct cnh_const_iobuf { + const uint8_t *bytes; + size_t nbytes; + size_t pos; +}; + +/** + * Flip the I/O buffer. Set the current pos as size and reset the position. + * + * @param child Flipped I/O buffer + * @param parent I/O buffer to flip + */ +void cnh_iobuf_flip(struct cnh_const_iobuf *child, struct cnh_iobuf *parent); + +/** + * Move the contents currently enclosed by pos and end of an I/O buffer to a destination. + * + * @param dest Destination buffer to move the source to, starting at current pos + * @param src Source to move to the destination, starting at current pos up to end of the buffer + * @return Number of bytes copied to destination + */ +size_t cnh_iobuf_move(struct cnh_iobuf *dest, struct cnh_const_iobuf *src); + +size_t cnh_iobuf_shift(struct cnh_iobuf *dest, struct cnh_iobuf *src); + +/** + * Read data from an I/O buffer + * + * @param src Source to read from (starting at current position) + * @param bytes Target to read to + * @param nbytes Number of bytes to read + * @return Result of operation + */ +enum cnh_result cnh_iobuf_read(struct cnh_const_iobuf *src, void *bytes, size_t nbytes); + +/** + * Read a byte from an I/O buffer + * + * @param src Source to read from (starting at current position) + * @param value Pointer to variable to read the data into + * @return Result of operation + */ +enum cnh_result cnh_iobuf_read_8(struct cnh_const_iobuf *src, uint8_t *value); + +/** + * Read a 2 byte value, big endian byte order, from an I/O buffer + * + * @param src Source to read from (starting at current position) + * @param value Pointer to variable to read the data into + * @return Result of operation + */ +enum cnh_result cnh_iobuf_read_be16(struct cnh_const_iobuf *src, uint16_t *value); + +/** + * Read a 4 byte value, big endian byte order, from an I/O buffer + * + * @param src Source to read from (starting at current position) + * @param value Pointer to variable to read the data into + * @return Result of operation + */ +enum cnh_result cnh_iobuf_read_be32(struct cnh_const_iobuf *src, uint32_t *value); + +/** + * Read a 2 byte value, little endian byte order, from an I/O buffer + * + * @param src Source to read from (starting at current position) + * @param value Pointer to variable to read the data into + * @return Result of operation + */ +enum cnh_result cnh_iobuf_read_le16(struct cnh_const_iobuf *src, uint16_t *value); + +/** + * Read a 4 byte value, little endian byte order, from an I/O buffer + * + * @param src Source to read from (starting at current position) + * @param value Pointer to variable to read the data into + * @return Result of operation + */ +enum cnh_result cnh_iobuf_read_le32(struct cnh_const_iobuf *src, uint32_t *value); + +/** + * Write data to an I/O buffer + * + * @param dest I/O buffer to write to (starting at current position) + * @param bytes Pointer to data to write + * @param nbytes Number of bytes to write + * @return Result of operation + */ +enum cnh_result cnh_iobuf_write(struct cnh_iobuf *dest, const void *bytes, size_t nbytes); + +/** + * Write a byte to an I/O buffer + * + * @param dest Destination I/O buffer to write to (starting at current position) + * @param value Value to write + * @return Result of operation + */ +enum cnh_result cnh_iobuf_write_8(struct cnh_iobuf *dest, uint8_t value); + +/** + * Write a 2 byte value, big endian byte order, to an I/O buffer + * + * @param dest Destination I/O buffer to write to (starting at current position) + * @param value Value to write + * @return Result of operation + */ +enum cnh_result cnh_iobuf_write_be16(struct cnh_iobuf *dest, uint16_t value); + +/** + * Write a 4 byte value, big endian byte order, to an I/O buffer + * + * @param dest Destination I/O buffer to write to (starting at current position) + * @param value Value to write + * @return Result of operation + */ +enum cnh_result cnh_iobuf_write_be32(struct cnh_iobuf *dest, uint32_t value); + +/** + * Write a 2 byte value, little endian byte order, to an I/O buffer + * + * @param dest Destination I/O buffer to write to (starting at current position) + * @param value Value to write + * @return Result of operation + */ +enum cnh_result cnh_iobuf_write_le16(struct cnh_iobuf *dest, uint16_t value); + +/** + * Write a 4 byte value, little endian byte order, to an I/O buffer + * + * @param dest Destination I/O buffer to write to (starting at current position) + * @param value Value to write + * @return Result of operation + */ +enum cnh_result cnh_iobuf_write_le32(struct cnh_iobuf *dest, uint32_t value); + +#endif diff --git a/src/main/capnhook/hook/iohook.c b/src/main/capnhook/hook/iohook.c new file mode 100644 index 0000000..faa87cc --- /dev/null +++ b/src/main/capnhook/hook/iohook.c @@ -0,0 +1,552 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "capnhook/hook/common.h" +#include "capnhook/hook/iohook.h" +#include "capnhook/hook/lib.h" + +#include "util/time.h" + +#define INVALID_FILE_DEVICE (-1) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Real funcs typedefs */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +typedef int (*cnh_iohook_open_t)(const char* path, int oflag); +typedef FILE* (*cnh_iohook_fdopen_t)(int fd, const char* mode); +typedef ssize_t (*cnh_iohook_write_t)(int fd, const void* buf, size_t count); +typedef ssize_t (*cnh_iohook_read_t)(int fd, void* buf, size_t count); +typedef off_t (*cnh_iohook_lseek_t)(int fildes, off_t offset, int whence); +typedef int (*cnh_iohook_ioctl_t)(int fd, int request, void* data); +typedef int (*cnh_iohook_close_t)(int fd); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private helpers */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_iohook_init(void); + +static enum cnh_result _cnh_iohook_invoke_real(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_open(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_fdopen(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_close(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_read(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_write(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_seek(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_iohook_invoke_real_ioctl(struct cnh_iohook_irp *irp); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private state */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static cnh_iohook_open_t _cnh_iohook_real_open; +static cnh_iohook_fdopen_t _cnh_iohook_real_fdopen; +static cnh_iohook_close_t _cnh_iohook_real_close; +static cnh_iohook_read_t _cnh_iohook_real_read; +static cnh_iohook_write_t _cnh_iohook_real_write; +static cnh_iohook_lseek_t _cnh_iohook_real_lseek; +static cnh_iohook_ioctl_t _cnh_iohook_real_ioctl; + +static const cnh_iohook_fn_t _cnh_iohook_real_handlers[7] = { + [CNH_IOHOOK_IRP_OP_OPEN] = _cnh_iohook_invoke_real_open, + [CNH_IOHOOK_IRP_OP_FDOPEN] = _cnh_iohook_invoke_real_fdopen, + [CNH_IOHOOK_IRP_OP_CLOSE] = _cnh_iohook_invoke_real_close, + [CNH_IOHOOK_IRP_OP_READ] = _cnh_iohook_invoke_real_read, + [CNH_IOHOOK_IRP_OP_WRITE] = _cnh_iohook_invoke_real_write, + [CNH_IOHOOK_IRP_OP_SEEK] = _cnh_iohook_invoke_real_seek, + [CNH_IOHOOK_IRP_OP_IOCTL] = _cnh_iohook_invoke_real_ioctl, +}; + +static atomic_int _cnh_iohook_initted = ATOMIC_VAR_INIT(0); +static atomic_int _cnh_iohook_init_in_progress = ATOMIC_VAR_INIT(0); +static pthread_mutex_t _cnh_iohook_lock; +static cnh_iohook_fn_t *_cnh_iohook_handlers; +static size_t _cnh_iohook_nhandlers; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Public module functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_iohook_push_handler(cnh_iohook_fn_t fn) +{ + cnh_iohook_fn_t *new_array; + size_t new_size; + enum cnh_result result; + + assert(fn != NULL); + + _cnh_iohook_init(); + pthread_mutex_lock(&_cnh_iohook_lock); + + new_size = _cnh_iohook_nhandlers + 1; + new_array = realloc(_cnh_iohook_handlers, new_size * sizeof(cnh_iohook_fn_t)); + + if (new_array != NULL) { + _cnh_iohook_handlers = new_array; + _cnh_iohook_handlers[_cnh_iohook_nhandlers++] = fn; + result = CNH_RESULT_SUCCESS; + } else { + result = CNH_RESULT_OUT_OF_MEMORY; + } + + pthread_mutex_unlock(&_cnh_iohook_lock); + + return result; +} + +enum cnh_result cnh_iohook_invoke_next(struct cnh_iohook_irp *irp) +{ + cnh_iohook_fn_t handler; + enum cnh_result result; + + assert(irp != NULL); + assert(_cnh_iohook_initted > 0); + + pthread_mutex_lock(&_cnh_iohook_lock); + + assert(irp->next_handler <= _cnh_iohook_nhandlers); + + if (irp->next_handler < _cnh_iohook_nhandlers) { + handler = _cnh_iohook_handlers[irp->next_handler]; + irp->next_handler++; + } else { + handler = _cnh_iohook_invoke_real; + irp->next_handler = (size_t) -1; + } + + pthread_mutex_unlock(&_cnh_iohook_lock); + + result = handler(irp); + + if (result != CNH_RESULT_SUCCESS) { + irp->next_handler = (size_t) -1; + } + + return result; +} + +int cnh_iohook_open_dummy_fd() +{ + _cnh_iohook_init(); + + /* We need to return some sort of valid FD to the + caller, since we're simulating a device that + doesn't exist. Open an FD on /dev/null. */ + + /* Open read only */ + return _cnh_iohook_real_open("/dev/null", 0); +} + +void cnh_iohook_close_dummy_fd(int fd) +{ + _cnh_iohook_init(); + + /* Avoid hooking pipeline when using dummy handles */ + _cnh_iohook_real_close(fd); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooked functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +int open(const char* path, int oflag) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (path == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return INVALID_FILE_DEVICE; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_OPEN; + irp.fd = INVALID_FILE_DEVICE; + irp.open_filename = path; + irp.open_flags = oflag; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return INVALID_FILE_DEVICE; + } + + errno = 0; + + return irp.fd; +} + +FILE* fdopen(int fd, const char* mode) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (fd == -1 || mode == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return NULL; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_FDOPEN; + irp.fdopen_fd = fd; + irp.fdopen_mode = mode; + irp.fdopen_res = NULL; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return NULL; + } + + errno = 0; + + return irp.fdopen_res; +} + +int close(int fd) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (fd == INVALID_FILE_DEVICE) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_CLOSE; + irp.fd = fd; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return 0; +} + +ssize_t read(int fd, void* buf, size_t count) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (fd == INVALID_FILE_DEVICE || buf == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_READ; + irp.fd = fd; + irp.read.bytes = buf; + irp.read.nbytes = count; + irp.read.pos = 0; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + assert(irp.read.pos <= irp.read.nbytes); + + errno = 0; + + return irp.read.pos; +} + +ssize_t write(int fd, const void* buf, size_t count) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (fd == INVALID_FILE_DEVICE || buf == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_WRITE; + irp.fd = fd; + irp.write.bytes = buf; + irp.write.nbytes = count; + irp.write.pos = 0; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + assert(irp.write.pos <= irp.write.nbytes); + + errno = 0; + + return irp.write.pos; +} + +off_t lseek(int fd, off_t offset, int whence) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (fd == INVALID_FILE_DEVICE) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_SEEK; + irp.fd = fd; + irp.seek_origin = whence; + irp.seek_offset = offset; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return (off_t) irp.seek_pos; +} + +int ioctl(int fd, int request, void* data) +{ + struct cnh_iohook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_iohook_init(); + + if (fd == INVALID_FILE_DEVICE) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + return -1; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_IOHOOK_IRP_OP_IOCTL; + irp.fd = fd; + irp.ioctl_req = request; + irp.ioctl.bytes = data; + + result = cnh_iohook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return -1; + } + + errno = 0; + + return irp.ioctl.pos; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Helper functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_iohook_init(void) +{ + int expected; + + if (atomic_load(&_cnh_iohook_initted) > 0) { + return; + } + + expected = 0; + + if (!atomic_compare_exchange_strong(&_cnh_iohook_init_in_progress, &expected, 1)) { + while (atomic_load(&_cnh_iohook_init_in_progress) > 1) { + util_time_sleep_us(100); + } + + return; + } + + /* Check again to ensure the current thread yielded between the init'd check and setting init in progress */ + if (atomic_load(&_cnh_iohook_initted) > 0) { + /* Revert init in progress, because nothing to do anymore */ + atomic_store(&_cnh_iohook_init_in_progress, 0); + return; + } + + _cnh_iohook_real_open = (cnh_iohook_open_t) cnh_lib_get_func_addr("open"); + _cnh_iohook_real_fdopen = (cnh_iohook_fdopen_t) cnh_lib_get_func_addr("fdopen"); + _cnh_iohook_real_close = (cnh_iohook_close_t) cnh_lib_get_func_addr("close"); + _cnh_iohook_real_read = (cnh_iohook_read_t) cnh_lib_get_func_addr("read"); + _cnh_iohook_real_write = (cnh_iohook_write_t) cnh_lib_get_func_addr("write"); + _cnh_iohook_real_lseek = (cnh_iohook_lseek_t) cnh_lib_get_func_addr("lseek"); + _cnh_iohook_real_ioctl = (cnh_iohook_ioctl_t) cnh_lib_get_func_addr("ioctl"); + + pthread_mutex_init(&_cnh_iohook_lock, NULL); + + atomic_store(&_cnh_iohook_initted, 1); + atomic_store(&_cnh_iohook_init_in_progress, 0); +} + +static enum cnh_result _cnh_iohook_invoke_real(struct cnh_iohook_irp *irp) +{ + cnh_iohook_fn_t handler; + + assert(irp != NULL); + assert(irp->op < _countof(_cnh_iohook_real_handlers)); + + handler = _cnh_iohook_real_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_iohook_invoke_real_open(struct cnh_iohook_irp *irp) +{ + int fd; + + assert(irp != NULL); + + fd = _cnh_iohook_real_open(irp->open_filename, irp->open_flags); + + if (fd == INVALID_FILE_DEVICE) { + return cnh_errno_to_result(errno); + } + + irp->fd = fd; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_iohook_invoke_real_fdopen(struct cnh_iohook_irp *irp) +{ + FILE* file; + + assert(irp != NULL); + + file = _cnh_iohook_real_fdopen(irp->fdopen_fd, irp->fdopen_mode); + + if (file == NULL) { + return cnh_errno_to_result(errno); + } + + irp->fdopen_res = file; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_iohook_invoke_real_close(struct cnh_iohook_irp *irp) +{ + int ok; + + assert(irp != NULL); + + ok = _cnh_iohook_real_close(irp->fd); + + if (ok < 0) { + return cnh_errno_to_result(errno); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_iohook_invoke_real_read(struct cnh_iohook_irp *irp) +{ + ssize_t read; + + assert(irp != NULL); + + read = _cnh_iohook_real_read(irp->fd, &irp->read.bytes[irp->read.pos], irp->read.nbytes - irp->read.pos); + + if (read < 0) { + return cnh_errno_to_result(errno); + } + + irp->read.pos += read; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_iohook_invoke_real_write(struct cnh_iohook_irp *irp) +{ + ssize_t written; + + assert(irp != NULL); + + written = _cnh_iohook_real_write(irp->fd, &irp->write.bytes[irp->write.pos], irp->write.nbytes - irp->write.pos); + + if (written < 0) { + return cnh_errno_to_result(errno); + } + + irp->write.pos += written; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_iohook_invoke_real_seek(struct cnh_iohook_irp *irp) +{ + off_t result; + + assert(irp != NULL); + + result = _cnh_iohook_real_lseek(irp->fd, (off_t) irp->seek_offset, irp->seek_origin); + + if (result < 0) { + return cnh_errno_to_result(errno); + } + + irp->seek_pos = result; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_iohook_invoke_real_ioctl(struct cnh_iohook_irp *irp) +{ + int result; + + assert(irp != NULL); + + result = _cnh_iohook_real_ioctl(irp->fd, irp->ioctl_req, irp->ioctl.bytes); + + if (result < 0) { + return cnh_errno_to_result(errno); + } + + irp->ioctl.pos = (size_t) result; + + return CNH_RESULT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/capnhook/hook/iohook.h b/src/main/capnhook/hook/iohook.h new file mode 100644 index 0000000..83d7eea --- /dev/null +++ b/src/main/capnhook/hook/iohook.h @@ -0,0 +1,90 @@ +/** + * Hook module for hooking I/O related calls, e.g. open, read, write etc. + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_IOHOOK_H +#define CAPNHOOK_IOHOOK_H + +#include +#include +#include + +#include "capnhook/hook/iobuf.h" + +/** + * Available operations to hook + */ +enum cnh_iohook_irp_op { + CNH_IOHOOK_IRP_OP_OPEN = 0, + CNH_IOHOOK_IRP_OP_FDOPEN = 1, + CNH_IOHOOK_IRP_OP_CLOSE = 2, + CNH_IOHOOK_IRP_OP_READ = 3, + CNH_IOHOOK_IRP_OP_WRITE = 4, + CNH_IOHOOK_IRP_OP_SEEK = 5, + CNH_IOHOOK_IRP_OP_IOCTL = 6, +}; + +/** + * I/O request packet + */ +struct cnh_iohook_irp { + enum cnh_iohook_irp_op op; + size_t next_handler; + int fd; + const char *open_filename; + int open_flags; + int fdopen_fd; + const char* fdopen_mode; + FILE* fdopen_res; + struct cnh_iobuf read; + struct cnh_const_iobuf write; + int seek_origin; + int64_t seek_offset; + uint64_t seek_pos; + int ioctl_req; + struct cnh_iobuf ioctl; +}; + +/** + * Hook function type + */ +typedef enum cnh_result (*cnh_iohook_fn_t)(struct cnh_iohook_irp *irp); + +/** + * Add a new hook handler to the hook module. + * The handler added is getting called on every hooked operation. + * + * @param fn Pointer to hook function to add + * @return Result/error code if hooking was successful + */ +enum cnh_result cnh_iohook_push_handler(cnh_iohook_fn_t fn); + +/** + * Invoke the next hooked function registered in the hook module. + * Call this from your hook handler if you want to pass on execution to further + * hooked calls reaching the original function at the end of the hook chain. + * + * @param irp I/O request package to dispatch + * @return Result of the following function dispatching the request package + */ +enum cnh_result cnh_iohook_invoke_next(struct cnh_iohook_irp *irp); + +/** + * Create a dummy file handle. Use this function for file access virtualization. + * Do not execute real operations on the handle returned. + * + * @return Actual file handle instance pointing to a dummy endpoint. + */ +int cnh_iohook_open_dummy_fd(); + +/** + * Close a dummy file handle. Make sure to free your previously allocated handles + * to avoid resource leaks. Do not free them using the real close function. + * + * @param file Dummy file handle to free + */ +void cnh_iohook_close_dummy_fd(int fd); + +#endif diff --git a/src/main/capnhook/hook/lib-main.h b/src/main/capnhook/hook/lib-main.h new file mode 100644 index 0000000..74f4965 --- /dev/null +++ b/src/main/capnhook/hook/lib-main.h @@ -0,0 +1,57 @@ +/** + * Provides a set of macros to hook into an application right before its + * main function is called. + */ +#ifndef CNH_LIB_MAIN_H +#define CNH_LIB_MAIN_H + +#include +#include +#include + +#include + +#include "util/log.h" + +#define LIB_MAIN_CONSTRUCTOR(func) __attribute__((constructor)) void lib_constructor() { func(); } + +#define LIB_MAIN_DESTRUCTOR(func) __attribute__((destructor)) void lib_destructor() { func(); } + +#define LIB_MAIN_TRAP_MAIN(func_before_main, func_after_main) \ +typedef int (*func_libc_start_main_t)(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)); \ +typedef int* (*func_main_t)(int, char**, char**); \ +typedef void (*func_init_t)(void); \ +static func_main_t orig_main; \ +static func_init_t orig_init; \ +static bool trapped; \ +\ +int* trap_main(int argc, char** argv, char** envp) \ +{ \ + log_debug("Trap before main (%s): argc %d", argv[0], argc); \ + func_before_main(argc, argv); \ + log_debug("Calling orig_init"); \ + orig_init(); \ + log_debug("Calling real main (%s): argc %d", argv[0], argc); \ + int* ret = orig_main(argc, argv, envp); \ + log_debug("Calling cleanup after main (%s): ret %d", argv[0], ret); \ + func_after_main(); \ + return ret; \ +} \ +\ +void dummy_init(void) {} \ +\ +int __libc_start_main(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) \ +{ \ + func_libc_start_main_t start = (func_libc_start_main_t) dlsym(RTLD_NEXT, "__libc_start_main"); \ + if (start == NULL) { \ + printf("ERROR finding orig func __libc_start_main\n"); \ + } \ + orig_main = main; \ + main = trap_main; \ + orig_init = init; \ + init = dummy_init; \ + trapped = true; \ + return (*start)(main, argc, ubp_av, init, fini, rtld_fini, stack_end); \ +} + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hook/lib.c b/src/main/capnhook/hook/lib.c new file mode 100644 index 0000000..9ce9435 --- /dev/null +++ b/src/main/capnhook/hook/lib.c @@ -0,0 +1,179 @@ +#define LOG_MODULE "hook-lib" + +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/rand.h" + +typedef void* (*cnh_lib_load_t)(const char* lib); +typedef void* (*cnh_lib_get_func_addr_handle_t)(void* lib_handle, const char* func_name); +typedef void (*cnh_lib_unload_t)(void* handle); +typedef void* (*cnh_lib_get_func_addr_t)(const char* func_name); + +static void* _cnh_lib_load(const char* lib); +static void* _cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name); +static void _cnh_lib_unload(void* handle); +static void* _cnh_lib_get_func_addr(const char* func_name); + +static void* _cnh_lib_load_test(const char* lib); +static void* _cnh_lib_get_func_addr_handle_test(void* lib_handle, const char* func_name); +static void _cnh_lib_unload_test(void* handle); +static void* _cnh_lib_get_func_addr_test(const char* func_name); + +struct cnh_lib_interface { + cnh_lib_load_t load; + cnh_lib_get_func_addr_handle_t get_func_addr_handle; + cnh_lib_unload_t unload; + cnh_lib_get_func_addr_t get_func_addr; +}; + +static struct cnh_lib_interface _cnh_lib_interface = { + .load = _cnh_lib_load, + .get_func_addr_handle = _cnh_lib_get_func_addr_handle, + .unload = _cnh_lib_unload, + .get_func_addr = _cnh_lib_get_func_addr, +}; + +static struct cnh_lib_unit_test_func_mocks* _cnh_lib_func_mocks; +size_t _cnh_lib_func_mocks_cnt; + +static void* _cnh_lib_load(const char* lib) +{ + void* so = dlopen(lib, RTLD_NOW); + + if (so == NULL) { + log_warn("Failed to open library %s: %s", lib, dlerror()); + } else { + log_debug("Opened lib %s, handle %p", lib, so); + } + + return so; +} + +static void* _cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name) +{ + void* ret = dlsym(lib_handle, func_name); + + if (ret == NULL) { + log_warn("Could not find func %s in library %p", func_name, lib_handle); + } + + return ret; +} + +static void _cnh_lib_unload(void* handle) +{ + dlclose(handle); + log_debug("Closed lib handle %p", handle); +} + +static void* _cnh_lib_get_func_addr(const char* func_name) +{ + void* ret = dlsym(RTLD_NEXT, func_name); + + if (ret == NULL) { + log_warn("Could not find func %s", func_name); + } + + return ret; +} + +static void* _cnh_lib_load_test(const char* lib) +{ + log_warn("Loading lib %s not supported in test", lib); + + if (sizeof(void*) == 4) { + return (void*) util_rand_gen_32(); + } else { + log_die_illegal_state(); + } +} + +static void* _cnh_lib_get_func_addr_handle_test(void* lib_handle, const char* func_name) +{ + return _cnh_lib_get_func_addr_test(func_name); +} + +static void _cnh_lib_unload_test(void* handle) +{ + log_warn("Unloading lib %p not supported in test", handle); +} + +static void* _cnh_lib_get_func_addr_test(const char* func_name) +{ + for (size_t i = 0; i < _cnh_lib_func_mocks_cnt; i++) { + if (!strcmp(_cnh_lib_func_mocks[i].name, func_name)) { + return _cnh_lib_func_mocks->func; + } + } + + log_warn("Could not find func %s", func_name); + + return NULL; +} + +struct cnh_lib_unit_test_func_mocks* cnh_lib_allocate_func_mocks(size_t count) +{ + log_assert(count >= 0); + + struct cnh_lib_unit_test_func_mocks* func_mocks; + + func_mocks = util_xmalloc(sizeof(struct cnh_lib_unit_test_func_mocks) * count); + + memset(func_mocks, 0, sizeof(struct cnh_lib_unit_test_func_mocks) * count); + + return func_mocks; +} + +void cnh_lib_init_unit_test(struct cnh_lib_unit_test_func_mocks* func_mocks, size_t func_mocks_cnt) +{ + log_warn("Setting up %d unit test func mocks", func_mocks_cnt); + + _cnh_lib_func_mocks = func_mocks; + _cnh_lib_func_mocks_cnt = func_mocks_cnt; + + _cnh_lib_interface.load = _cnh_lib_load_test; + _cnh_lib_interface.get_func_addr_handle = _cnh_lib_get_func_addr_handle_test; + _cnh_lib_interface.unload = _cnh_lib_unload_test; + _cnh_lib_interface.get_func_addr = _cnh_lib_get_func_addr_test; +} + +void cnh_lib_init() +{ + log_warn("Setting up real interface"); + + _cnh_lib_interface.load = _cnh_lib_load; + _cnh_lib_interface.get_func_addr_handle = _cnh_lib_get_func_addr_handle; + _cnh_lib_interface.unload = _cnh_lib_unload; + _cnh_lib_interface.get_func_addr = _cnh_lib_get_func_addr; +} + +void cnh_lib_shutdown_unit_test() +{ + log_assert(_cnh_lib_func_mocks); + + util_xfree((void**) &_cnh_lib_func_mocks); +} + +void* cnh_lib_load(const char* lib) +{ + return _cnh_lib_interface.load(lib); +} + +void* cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name) +{ + return _cnh_lib_interface.get_func_addr_handle(lib_handle, func_name); +} + +void cnh_lib_unload(void* handle) +{ + _cnh_lib_interface.unload(handle); +} + +void* cnh_lib_get_func_addr(const char* func_name) +{ + return _cnh_lib_interface.get_func_addr(func_name); +} \ No newline at end of file diff --git a/src/main/capnhook/hook/lib.h b/src/main/capnhook/hook/lib.h new file mode 100644 index 0000000..f314d5c --- /dev/null +++ b/src/main/capnhook/hook/lib.h @@ -0,0 +1,84 @@ +/** + * Various functions related to library hooking + */ +#ifndef CAPNHOOK_LIB_H +#define CAPNHOOK_LIB_H + +#include + +/** + * Provide a mock function key'd by it's name and pointing to your actual mock implementation. + */ +struct cnh_lib_unit_test_func_mocks { + const char* name; + void* func; +}; + +/** + * Allocate memory for a list of mock functions to pass to cnh_lib_init_unit_test. + * + * @param count The size of the list. + * @return Allocated memory with the specified number of entries. + */ +struct cnh_lib_unit_test_func_mocks* cnh_lib_allocate_func_mocks(size_t count); + +/** + * Initialize this module when using it in a unit-test. This allows you to add function mocks that are returned on the + * various calls to get function pointers from real library functions. Use this to mock them to test various patching + * modules. + * + * Use the cnh_lib_allocate_func_mocks function to allocate a list that you can fill in. + * + * @param func_mocks A list of functions mocks with function names and pointers to the test mocks you set up. Ensure + * that the function signatures match, otherwise things might crash when getting called. The module + * will cleanup the memory allocated of this for you. + * @param func_mocks_cnt The length of the list of func_mocks. + */ +void cnh_lib_init_unit_test(struct cnh_lib_unit_test_func_mocks* func_mocks, size_t func_mocks_cnt); + +/** + * Optional, used for unit testing. Switch to the default backend that utilizes loading real libraries and getting real + * function pointers from them. This is enabled by default. + */ +void cnh_lib_init(); + +/** + * Cleanup any memory allocated/used on cnh_lib_init_unit_test. + */ +void cnh_lib_shutdown_unit_test(); + +/** + * Load a dynamic library + * + * @param lib Path to library file to load + * @return Pointer to a handle on success, NULL on failure + */ +void* cnh_lib_load(const char* lib); + +/** + * Get the address of a function from a library + * + * @param lib_handle Handle of an opened library + * @param func_name Name of the function to get + * @return Function ptr on success, false on error (function not found) + */ +void*cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name); + +/** + * Unload a loaded dynamic library + * + * @param handle Handle of the loaded lib to unload + */ +void cnh_lib_unload(void* handle); + +/** + * Get the adress of a function (from a dynamic library) + * + * Note: This will return the first function found matching the specified name + * + * @param func_name Name of the function + * @return Valid ptr to function on success, false on error (not found) + */ +void* cnh_lib_get_func_addr(const char* func_name); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hook/result.c b/src/main/capnhook/hook/result.c new file mode 100644 index 0000000..3bbbf3f --- /dev/null +++ b/src/main/capnhook/hook/result.c @@ -0,0 +1,99 @@ +#define LOG_MODULE "capnhook" + +#include + +#include "capnhook/hook/result.h" + +#include "util/log.h" + +int cnh_result_to_errno(enum cnh_result result) +{ + switch (result) { + case CNH_RESULT_SUCCESS: + return 0; + case CNH_RESULT_ERROR_INSUFFICIENT_BUFFER: + return EIO; + case CNH_RESULT_INVALID_PARAMETER: + return EINVAL; + case CNH_RESULT_OUT_OF_MEMORY: + return ENOMEM; + case CNH_RESULT_REPEAT_OPERATION: + return EAGAIN; + case CNH_RESULT_NO_SUCH_FILE_OR_DIR: + return ENOENT; + case CNH_RESULT_NOT_TTY: + return ENOTTY; + case CNH_RESULT_BUSY: + return EBUSY; + case CNH_RESULT_IS_A_DIRECTORY: + return EISDIR; + case CNH_RESULT_PERMISSION_DENIED: + return EACCES; + case CNH_RESULT_DIRECTORY_NOT_EMPTY: + return ENOTEMPTY; + case CNH_RESULT_OPERATION_NOT_PERMITTED: + return EPERM; + case CNH_RESULT_NO_SUCH_DEVICE: + return ENODEV; + case CNH_RESULT_BAD_FILE_NUMBER: + return EBADF; + case CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE: + return EBADFD; + case CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE: + return EOVERFLOW; + case CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS: + return ENXIO; + case CNH_RESULT_BROKEN_PIPE: + return EPIPE; + case CNH_RESULT_TIMER_EXPIRED: + return ETIME; + default: + log_warn("Unhandled other error %d to errno convert might cause bugs", result); + return EIO; + } +} + +enum cnh_result cnh_errno_to_result(int errn) +{ + switch (errn) { + case 0: + return CNH_RESULT_SUCCESS; + case EINVAL: + return CNH_RESULT_INVALID_PARAMETER; + case ENOMEM: + return CNH_RESULT_OUT_OF_MEMORY; + case EAGAIN: + return CNH_RESULT_REPEAT_OPERATION; + case ENOENT: + return CNH_RESULT_NO_SUCH_FILE_OR_DIR; + case ENOTTY: + return CNH_RESULT_NOT_TTY; + case EBUSY: + return CNH_RESULT_BUSY; + case EISDIR: + return CNH_RESULT_IS_A_DIRECTORY; + case EACCES: + return CNH_RESULT_PERMISSION_DENIED; + case ENOTEMPTY: + return CNH_RESULT_DIRECTORY_NOT_EMPTY; + case EPERM: + return CNH_RESULT_OPERATION_NOT_PERMITTED; + case ENODEV: + return CNH_RESULT_NO_SUCH_DEVICE; + case EBADF: + return CNH_RESULT_BAD_FILE_NUMBER; + case EBADFD: + return CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE; + case EOVERFLOW: + return CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE; + case ENXIO: + return CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS; + case EPIPE: + return CNH_RESULT_BROKEN_PIPE; + case ETIME: + return CNH_RESULT_TIMER_EXPIRED; + default: + log_warn("Unhandled errno to general error convert might cause bugs, errno: %d", errn); + return CNH_RESULT_OTHER_ERROR; + } +} \ No newline at end of file diff --git a/src/main/capnhook/hook/result.h b/src/main/capnhook/hook/result.h new file mode 100644 index 0000000..e2f5b0b --- /dev/null +++ b/src/main/capnhook/hook/result.h @@ -0,0 +1,52 @@ +/** + * Results for returning errors on hook modules, converting them to errno and vice versa + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_RESULT_H +#define CAPNHOOK_RESULT_H + +/** + * Result values for hook functions + */ +enum cnh_result { + CNH_RESULT_SUCCESS = 0, + CNH_RESULT_ERROR_INSUFFICIENT_BUFFER = 1, + CNH_RESULT_INVALID_PARAMETER = 2, + CNH_RESULT_OUT_OF_MEMORY = 3, + CNH_RESULT_REPEAT_OPERATION = 4, + CNH_RESULT_NO_SUCH_FILE_OR_DIR = 5, + CNH_RESULT_OTHER_ERROR = 6, + CNH_RESULT_NOT_TTY = 7, + CNH_RESULT_BUSY = 8, + CNH_RESULT_IS_A_DIRECTORY = 9, + CNH_RESULT_PERMISSION_DENIED = 10, + CNH_RESULT_DIRECTORY_NOT_EMPTY = 11, + CNH_RESULT_OPERATION_NOT_PERMITTED = 12, + CNH_RESULT_NO_SUCH_DEVICE = 13, + CNH_RESULT_BAD_FILE_NUMBER = 14, + CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE = 15, + CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE = 16, + CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS = 17, + CNH_RESULT_BROKEN_PIPE = 18, + CNH_RESULT_TIMER_EXPIRED = 19, +}; + +/** + * Convert a hook function result to errno + * + * @param result Result to convert + * @return errno value + */ +int cnh_result_to_errno(enum cnh_result result); + +/** + * Convert an errno value to a hook function result + * + * @param errn errno value to convert + * @return Hook function result + */ +enum cnh_result cnh_errno_to_result(int errn); + +#endif diff --git a/src/main/capnhook/hook/sig.c b/src/main/capnhook/hook/sig.c new file mode 100644 index 0000000..f149b17 --- /dev/null +++ b/src/main/capnhook/hook/sig.c @@ -0,0 +1,58 @@ +#define LOG_MODULE "cnh-sig" + +#include "capnhook/hook/lib.h" +#include "capnhook/hook/sig.h" + +#include "util/log.h" + +typedef int (*cnh_sig_handler_sigaction_t) (int sig, const struct sigaction* act, struct sigaction* oact); + +static void _cnh_signal_handler(int sig); + +static cnh_sig_handler_sigaction_t _cnh_sig_handler_real_sigaction; + +static cnh_sig_handler_t _cnh_signal_handlers[32]; +static __sighandler_t _cnh_signal_orig_handlers[32]; + +void cnh_sig_install(int sig, cnh_sig_handler_t handler) +{ + if (sig < 0 || sig >= 32) { + log_die("Can't register handler for invalid signal number %d", sig); + } + + /* Ensure that the application does not install it's own handler */ + _cnh_signal_handlers[sig] = handler; + + /* Install a little detour as our signal handler */ + signal(sig, _cnh_signal_handler); + + log_info("Installed signal handler %p for %d", handler, sig); +} + +int sigaction(int sig, const struct sigaction* act, struct sigaction* oact) +{ + if (_cnh_signal_handlers[sig]) { + log_info("Enforce own signal handler on signal: %d", sig); + + /* save the original handler, we might need it */ + _cnh_signal_orig_handlers[sig] = ((struct sigaction*) act)->sa_handler; + + /* swap */ + ((struct sigaction*) act)->sa_handler = (__sighandler_t) _cnh_signal_handler; + + log_debug("Original handler %p for signal %d", _cnh_signal_orig_handlers[sig], sig); + } + + if (!_cnh_sig_handler_real_sigaction) { + _cnh_sig_handler_real_sigaction = (cnh_sig_handler_sigaction_t) cnh_lib_get_func_addr("sigaction"); + } + + return _cnh_sig_handler_real_sigaction(sig, act, oact); +} + +static void _cnh_signal_handler(int sig) +{ + if (_cnh_signal_handlers[sig]) { + _cnh_signal_handlers[sig](sig, _cnh_signal_orig_handlers[sig]); + } +} \ No newline at end of file diff --git a/src/main/capnhook/hook/sig.h b/src/main/capnhook/hook/sig.h new file mode 100644 index 0000000..8bb9548 --- /dev/null +++ b/src/main/capnhook/hook/sig.h @@ -0,0 +1,26 @@ +/** + * Hook and intercept signal handlers + */ +#ifndef CAPNHOOK_SIG_H +#define CAPNHOOK_SIG_H + +#include + +/** + * Special callback for signal allowing access to a signal handler installed + * by the application + * + * @param signal Signal to handle + * @param orig_handler Original handler of application or NULL if non exists + */ +typedef void (*cnh_sig_handler_t)(int signal, __sighandler_t orig_handler); + +/** + * Install our own signal handler (and possibly override existing handlers) + * + * @param sig Signal to handle + * @param handler Handler to install for specified signal + */ +void cnh_sig_install(int sig, cnh_sig_handler_t handler); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hook/usbhook.c b/src/main/capnhook/hook/usbhook.c new file mode 100644 index 0000000..89ba9c2 --- /dev/null +++ b/src/main/capnhook/hook/usbhook.c @@ -0,0 +1,624 @@ +#define LOG_MODULE "cnh-usbhook" + +#include +#include +#include +#include +#include +#include + +#include "capnhook/hook/common.h" +#include "capnhook/hook/lib.h" +#include "capnhook/hook/usbhook.h" + +#include "util/time.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Real funcs typedefs */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +typedef int (*cnh_usbhook_usb_init_t)(void); +typedef int (*cnh_usbhook_usb_find_devices_t)(void); +typedef int (*cnh_usbhook_usb_find_busses_t)(void); +typedef usb_dev_handle* (*cnh_usbhook_usb_open_t)(struct usb_device* dev); +typedef int (*cnh_usbhook_usb_close_t)(usb_dev_handle* dev); +typedef int (*cnh_usbhook_usb_reset_t)(usb_dev_handle* dev); +typedef int (*cnh_usbhook_usb_set_altinterface_t)(usb_dev_handle* dev, int interface); +typedef int (*cnh_usbhook_usb_set_configuration_t)(usb_dev_handle* dev, int configuration); +typedef int (*cnh_usbhook_usb_claim_interface_t)(usb_dev_handle* dev, int interface); +typedef int (*cnh_usbhook_usb_control_msg_t)(usb_dev_handle* dev, int requesttype, int request, int value, int index, + char* bytes, int nbytes, int timeout); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private helpers */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_usbhook_init(void); + +static enum cnh_result _cnh_usbhook_invoke_real(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_init(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_find_busses(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_find_devices(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_open(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_close(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_reset(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_set_altinterface(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_set_configuration(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_claim_interface(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbhook_invoke_real_ctrl_msg(struct cnh_usbhook_irp* irp); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private state */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static cnh_usbhook_usb_init_t _cnh_usbhook_real_init; +static cnh_usbhook_usb_find_devices_t _cnh_usbhook_real_find_devices; +static cnh_usbhook_usb_find_busses_t _cnh_usbhook_real_find_busses; +static cnh_usbhook_usb_open_t _cnh_usbhook_real_open; +static cnh_usbhook_usb_close_t _cnh_usbhook_real_close; +static cnh_usbhook_usb_reset_t _cnh_usbhook_real_reset; +static cnh_usbhook_usb_set_altinterface_t _cnh_usbhook_real_set_altinterface; +static cnh_usbhook_usb_set_configuration_t _cnh_usbhook_real_set_configuration; +static cnh_usbhook_usb_claim_interface_t _cnh_usbhook_real_claim_interface; +static cnh_usbhook_usb_control_msg_t _cnh_usbhook_real_control_msg; + +static const cnh_usbhook_fn_t _cnh_usbhook_real_handlers[10] = { + [CNH_USBHOOK_IRP_OP_INIT] = _cnh_usbhook_invoke_real_init, + [CNH_USBHOOK_IRP_OP_FIND_BUSSES ]= _cnh_usbhook_invoke_real_find_busses, + [CNH_USBHOOK_IRP_OP_FIND_DEVICES] = _cnh_usbhook_invoke_real_find_devices, + [CNH_USBHOOK_IRP_OP_OPEN] = _cnh_usbhook_invoke_real_open, + [CNH_USBHOOK_IRP_OP_CLOSE] = _cnh_usbhook_invoke_real_close, + [CNH_USBHOOK_IRP_OP_RESET] = _cnh_usbhook_invoke_real_reset, + [CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE] = _cnh_usbhook_invoke_real_set_altinterface, + [CNH_USBHOOK_IRP_OP_SET_CONFIGURATION] = _cnh_usbhook_invoke_real_set_configuration, + [CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE] = _cnh_usbhook_invoke_real_claim_interface, + [CNH_USBHOOK_IRP_OP_CTRL_MSG] = _cnh_usbhook_invoke_real_ctrl_msg, +}; + +static atomic_int _cnh_usbhook_initted = ATOMIC_VAR_INIT(0); +static atomic_int _cnh_usbhook_init_in_progress = ATOMIC_VAR_INIT(0); +static pthread_mutex_t _cnh_usbhook_lock; +static cnh_usbhook_fn_t *_cnh_usbhook_handlers; +static size_t _cnh_usbhook_nhandlers; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Public module functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_usbhook_push_handler(cnh_usbhook_fn_t fn) +{ + cnh_usbhook_fn_t *new_array; + size_t new_size; + enum cnh_result result; + + assert(fn != NULL); + + _cnh_usbhook_init(); + pthread_mutex_lock(&_cnh_usbhook_lock); + + new_size = _cnh_usbhook_nhandlers + 1; + new_array = realloc(_cnh_usbhook_handlers, new_size * sizeof(cnh_usbhook_fn_t)); + + if (new_array != NULL) { + _cnh_usbhook_handlers = new_array; + _cnh_usbhook_handlers[_cnh_usbhook_nhandlers++] = fn; + result = CNH_RESULT_SUCCESS; + } else { + result = CNH_RESULT_OUT_OF_MEMORY; + } + + pthread_mutex_unlock(&_cnh_usbhook_lock); + + return result; +} + +enum cnh_result cnh_usbhook_invoke_next(struct cnh_usbhook_irp *irp) +{ + cnh_usbhook_fn_t handler; + enum cnh_result result; + + assert(irp != NULL); + assert(_cnh_usbhook_initted > 0); + + pthread_mutex_lock(&_cnh_usbhook_lock); + + assert(irp->next_handler <= _cnh_usbhook_nhandlers); + + if (irp->next_handler < _cnh_usbhook_nhandlers) { + handler = _cnh_usbhook_handlers[irp->next_handler]; + irp->next_handler++; + } else { + handler = _cnh_usbhook_invoke_real; + irp->next_handler = (size_t) -1; + } + + pthread_mutex_unlock(&_cnh_usbhook_lock); + + result = handler(irp); + + if (result != CNH_RESULT_SUCCESS) { + irp->next_handler = (size_t) -1; + } + + return result; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooked functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +void usb_init(void) +{ + struct cnh_usbhook_irp irp; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_INIT; + + cnh_usbhook_invoke_next(&irp); + + /* No return value, results ignored */ +} + +int usb_find_busses(void) +{ + struct cnh_usbhook_irp irp; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_FIND_BUSSES; + irp.find_busses_res_num_busses = 0; + + cnh_usbhook_invoke_next(&irp); + + /* No errors processed */ + + return irp.find_busses_res_num_busses; +} + +int usb_find_devices(void) +{ + struct cnh_usbhook_irp irp; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_FIND_DEVICES; + irp.find_devices_res_num_devices = 0; + + cnh_usbhook_invoke_next(&irp); + + /* No errors processed */ + + return irp.find_devices_res_num_devices; +} + +usb_dev_handle* usb_open(struct usb_device* dev) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL) { + /* No errno is set here (from libusbcompat impl) */ + return NULL; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_OPEN; + irp.open_usb_dev = dev; + irp.handle = NULL; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + return NULL; + } + + return irp.handle; +} + +int usb_close(usb_dev_handle* dev) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + /* Always return negative errno on errors */ + return -errno; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_CLOSE; + irp.handle = dev; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + /* Always return negative errno on errors */ + return -errno; + } + + return 0; +} + +int usb_reset(usb_dev_handle* dev) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + /* Always return negative errno on errors */ + return -errno; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_RESET; + irp.handle = dev; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + /* Always return negative errno on errors */ + return -errno; + } + + return 0; +} + +int usb_set_altinterface(usb_dev_handle* dev, int interface) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + /* Always return negative errno on errors */ + return -errno; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE; + irp.handle = dev; + irp.set_altinterface = interface; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + /* Always return negative errno on errors */ + return -errno; + } + + return 0; +} + +int usb_set_configuration(usb_dev_handle* dev, int configuration) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + /* Always return negative errno on errors */ + return -errno; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_SET_CONFIGURATION; + irp.handle = dev; + irp.set_configuration = configuration; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + /* Always return negative errno on errors */ + return -errno; + } + + return 0; +} + +int usb_claim_interface(usb_dev_handle* dev, int interface) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + /* Always return negative errno on errors */ + return -errno; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE; + irp.handle = dev; + irp.claim_interface = interface; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + /* Always return negative errno on errors */ + return -errno; + } + + return 0; +} + +int usb_control_msg(usb_dev_handle* dev, int requesttype, int request, int value, int index, char* bytes, int nbytes, + int timeout) +{ + struct cnh_usbhook_irp irp; + enum cnh_result result; + + /* Ensure module is initialized */ + _cnh_usbhook_init(); + + if (dev == NULL || bytes == NULL) { + errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER); + /* Always return negative errno on errors */ + return -errno; + } + + memset(&irp, 0, sizeof(irp)); + irp.op = CNH_USBHOOK_IRP_OP_CTRL_MSG; + irp.handle = dev; + irp.ctrl_req_type = requesttype; + irp.ctrl_req = request; + irp.ctrl_value = value; + irp.ctrl_index = index; + irp.ctrl_buffer.bytes = (uint8_t*) bytes; + irp.ctrl_buffer.nbytes = (size_t) nbytes; + irp.ctrl_buffer.pos = 0; + irp.ctrl_timeout = timeout; + + result = cnh_usbhook_invoke_next(&irp); + + if (result != CNH_RESULT_SUCCESS) { + errno = cnh_result_to_errno(result); + /* Always return negative errno on errors */ + return -errno; + } + + return irp.ctrl_buffer.pos; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Helper functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_usbhook_init(void) +{ + int expected; + + if (atomic_load(&_cnh_usbhook_initted) > 0) { + return; + } + + expected = 0; + + if (!atomic_compare_exchange_strong(&_cnh_usbhook_init_in_progress, &expected, 1)) { + while (atomic_load(&_cnh_usbhook_init_in_progress) > 1) { + util_time_sleep_us(100); + } + + return; + } + + /* Check again to ensure the current thread yielded between the init'd check and setting init in progress */ + if (atomic_load(&_cnh_usbhook_initted) > 0) { + /* Revert init in progress, because nothing to do anymore */ + atomic_store(&_cnh_usbhook_init_in_progress, 0); + return; + } + + _cnh_usbhook_real_init = (cnh_usbhook_usb_init_t) cnh_lib_get_func_addr("usb_init"); + _cnh_usbhook_real_find_devices = (cnh_usbhook_usb_find_devices_t) cnh_lib_get_func_addr("usb_find_devices"); + _cnh_usbhook_real_find_busses = (cnh_usbhook_usb_find_busses_t) cnh_lib_get_func_addr("usb_find_busses"); + _cnh_usbhook_real_open = (cnh_usbhook_usb_open_t) cnh_lib_get_func_addr("usb_open"); + _cnh_usbhook_real_close = (cnh_usbhook_usb_close_t) cnh_lib_get_func_addr("usb_close"); + _cnh_usbhook_real_reset = (cnh_usbhook_usb_reset_t) cnh_lib_get_func_addr("usb_reset"); + _cnh_usbhook_real_set_altinterface = + (cnh_usbhook_usb_set_altinterface_t) cnh_lib_get_func_addr("usb_set_altinterface"); + _cnh_usbhook_real_set_configuration = + (cnh_usbhook_usb_set_configuration_t) cnh_lib_get_func_addr("usb_set_configuration"); + _cnh_usbhook_real_claim_interface = + (cnh_usbhook_usb_claim_interface_t) cnh_lib_get_func_addr("usb_claim_interface"); + _cnh_usbhook_real_control_msg = (cnh_usbhook_usb_control_msg_t) cnh_lib_get_func_addr("usb_control_msg"); + + pthread_mutex_init(&_cnh_usbhook_lock, NULL); + + atomic_store(&_cnh_usbhook_initted, 1); + atomic_store(&_cnh_usbhook_init_in_progress, 0); +} + +static enum cnh_result _cnh_usbhook_invoke_real(struct cnh_usbhook_irp* irp) +{ + cnh_usbhook_fn_t handler; + + assert(irp != NULL); + assert(irp->op < _countof(_cnh_usbhook_real_handlers)); + + handler = _cnh_usbhook_real_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_usbhook_invoke_real_init(struct cnh_usbhook_irp* irp) +{ + assert(irp != NULL); + + _cnh_usbhook_real_init(); + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_find_busses(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_find_busses(); + + irp->find_busses_res_num_busses = res; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_find_devices(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_find_devices(); + + irp->find_devices_res_num_devices = res; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_open(struct cnh_usbhook_irp* irp) +{ + usb_dev_handle* res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_open(irp->open_usb_dev); + + if (res == NULL) { + irp->handle = NULL; + return cnh_errno_to_result(errno); + } + + irp->handle = res; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_close(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_close(irp->handle); + + if (res < 0) { + return cnh_errno_to_result(res); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_reset(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_reset(irp->handle); + + if (res < 0) { + return cnh_errno_to_result(res); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_set_altinterface(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_set_altinterface(irp->handle, irp->set_altinterface); + + if (res < 0) { + return cnh_errno_to_result(res); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_set_configuration(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_set_configuration(irp->handle, irp->set_configuration); + + if (res < 0) { + return cnh_errno_to_result(res); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_claim_interface(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_claim_interface(irp->handle, irp->claim_interface); + + if (res < 0) { + return cnh_errno_to_result(res); + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usbhook_invoke_real_ctrl_msg(struct cnh_usbhook_irp* irp) +{ + int res; + + assert(irp != NULL); + + res = _cnh_usbhook_real_control_msg(irp->handle, irp->ctrl_req_type, irp->ctrl_req, irp->ctrl_value, + irp->ctrl_index, (char*) irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_timeout); + + irp->ctrl_buffer.pos = 0; + + if (res < 0) { + return cnh_errno_to_result(res); + } + + irp->ctrl_buffer.pos = (size_t) res; + + return CNH_RESULT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/capnhook/hook/usbhook.h b/src/main/capnhook/hook/usbhook.h new file mode 100644 index 0000000..1cd4bf4 --- /dev/null +++ b/src/main/capnhook/hook/usbhook.h @@ -0,0 +1,75 @@ +/** + * Hook module for hooking libusb 0.1 + * + * Based on original capnhook code for windows by decafcode: + * https://github.com/decafcode/capnhook + */ +#ifndef CAPNHOOK_USBHOOK_H +#define CAPNHOOK_USBHOOK_H + +#include + +#include "capnhook/hook/iobuf.h" + +/** + * Available operations to hook + */ +enum cnh_usbhook_irp_op { + CNH_USBHOOK_IRP_OP_INIT = 0, + CNH_USBHOOK_IRP_OP_FIND_BUSSES = 1, + CNH_USBHOOK_IRP_OP_FIND_DEVICES = 2, + CNH_USBHOOK_IRP_OP_OPEN = 3, + CNH_USBHOOK_IRP_OP_CLOSE = 4, + CNH_USBHOOK_IRP_OP_RESET = 5, + CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE = 6, + CNH_USBHOOK_IRP_OP_SET_CONFIGURATION = 7, + CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE = 8, + CNH_USBHOOK_IRP_OP_CTRL_MSG = 9 +}; + +/** + * I/O request packet + */ +struct cnh_usbhook_irp { + enum cnh_usbhook_irp_op op; + size_t next_handler; + int find_busses_res_num_busses; + int find_devices_res_num_devices; + struct usb_device* open_usb_dev; + usb_dev_handle* handle; + int set_altinterface; + int set_configuration; + int claim_interface; + int ctrl_req_type; + int ctrl_req; + int ctrl_value; + int ctrl_index; + struct cnh_iobuf ctrl_buffer; + int ctrl_timeout; +}; + +/** + * Hook function type + */ +typedef enum cnh_result (*cnh_usbhook_fn_t)(struct cnh_usbhook_irp *irp); + +/** + * Add a new hook handler to the hook module. + * The handler added is getting called on every hooked operation. + * + * @param fn Pointer to hook function to add + * @return Result/error code if hooking was successful + */ +enum cnh_result cnh_usbhook_push_handler(cnh_usbhook_fn_t fn); + +/** + * Invoke the next hooked function registered in the hook module. + * Call this from your hook handler if you want to pass on execution to further + * hooked calls reaching the original function at the end of the hook chain. + * + * @param irp I/O request package to dispatch + * @return Result of the following function dispatching the request package + */ +enum cnh_result cnh_usbhook_invoke_next(struct cnh_usbhook_irp *irp); + +#endif diff --git a/src/main/capnhook/hooklib/filehook-mon.c b/src/main/capnhook/hooklib/filehook-mon.c new file mode 100644 index 0000000..63aec36 --- /dev/null +++ b/src/main/capnhook/hooklib/filehook-mon.c @@ -0,0 +1,57 @@ +#define LOG_MODULE "cnh-filehook-mon" + +#include "capnhook/hooklib/filehook-mon.h" + +#include "util/log.h" + +static const char* _cnh_filehook_mon_str_empty = ""; +static const char* _cnh_filehook_mon_irp_op_str[] = { + "fopen", + "fclose", + "fread", + "fwrite", + "fgets", + "fseek", + "ftell", + "feof" +}; + +enum cnh_result cnh_filehook_mon(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + /* Skip writes to log file because this results in infinite recursion */ + if (irp->file == util_log_get_file_handle()) { + return cnh_filehook_invoke_next(irp); + } + + log_debug("[before][%s] next_handler %d, file %p, open_filename %s, open_mode %s, read(bytes %p, nbytes %d, pos %d)" + ", write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, orig_read_write_nmemb %d, seek_origin %d, " + "seek_offset %d, tell_offset %llu, eof %d", _cnh_filehook_mon_irp_op_str[irp->op], irp->next_handler, + irp->file, irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty, + irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty, irp->read.bytes, irp->read.nbytes, + irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->orig_read_write_size, + irp->orig_read_write_nmemb, irp->seek_origin, irp->seek_offset, irp->tell_offset, irp->eof); + + result = cnh_filehook_invoke_next(irp); + + if (result != CNH_RESULT_SUCCESS) { + log_error("[after][%s] result %d, next_handler %d, file %p, open_filename %s, open_mode %s, read(bytes %p, " + "nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, orig_read_write_nmemb %d," + " seek_origin %d, seek_offset %d, tell_offset %llu, eof %d", _cnh_filehook_mon_irp_op_str[irp->op], + result, irp->next_handler, irp->file, irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty, + irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty, irp->read.bytes, irp->read.nbytes, + irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->orig_read_write_size, + irp->orig_read_write_nmemb, irp->seek_origin, irp->seek_offset, irp->tell_offset, irp->eof); + } else { + log_debug("[after][%s] result %d, next_handler %d, file %p, open_filename %s, open_mode %s, read(bytes %p, " + "nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, orig_read_write_nmemb %d," + " seek_origin %d, seek_offset %d, tell_offset %llu, eof %d", _cnh_filehook_mon_irp_op_str[irp->op], + result, irp->next_handler, irp->file, irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty, + irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty, irp->read.bytes, irp->read.nbytes, + irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->orig_read_write_size, + irp->orig_read_write_nmemb, irp->seek_origin, irp->seek_offset, irp->tell_offset, irp->eof); + } + + return result; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/filehook-mon.h b/src/main/capnhook/hooklib/filehook-mon.h new file mode 100644 index 0000000..1299dee --- /dev/null +++ b/src/main/capnhook/hooklib/filehook-mon.h @@ -0,0 +1,17 @@ +/** + * Hook implementation to monitor file related calls, e.g. fopen, fread, fwrite etc. + */ +#ifndef CAPNHOOK_FILEHOOK_MON_H +#define CAPNHOOK_FILEHOOK_MON_H + +#include "capnhook/hook/filehook.h" + +/** + * Hook function to add to the hook module for monitoring file related calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_filehook_mon(struct cnh_filehook_irp *irp); + +#endif diff --git a/src/main/capnhook/hooklib/fileopen-mon.c b/src/main/capnhook/hooklib/fileopen-mon.c new file mode 100644 index 0000000..53cb574 --- /dev/null +++ b/src/main/capnhook/hooklib/fileopen-mon.c @@ -0,0 +1,96 @@ +#include "capnhook/hook/filehook.h" +#include "capnhook/hook/fshook.h" +#include "capnhook/hook/iohook.h" + +#include "util/log.h" + +enum cnh_result cnh_fileopen_mon_filehook(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN) { + log_debug("[before][fopen]: %s %s", irp->open_filename, irp->open_mode); + + result = cnh_filehook_invoke_next(irp); + + log_debug("[after][fopen]: %s %s -> %d (%d)", irp->open_filename, irp->open_mode, irp->file, result); + } else { + result = cnh_filehook_invoke_next(irp); + } + + return result; +} + +enum cnh_result cnh_fileopen_mon_fshook(struct cnh_fshook_irp *irp) +{ + enum cnh_result result; + + switch (irp->op) { + case CNH_FSHOOK_IRP_OP_DIR_OPEN: + log_debug("[before][diropen]: %s", irp->opendir_name); + break; + case CNH_FSHOOK_IRP_OP_LXSTAT: + log_debug("[before][lxstat]: %s", irp->xstat_file); + break; + case CNH_FSHOOK_IRP_OP_XSTAT: + log_debug("[before][xstat]: %s", irp->xstat_file); + break; + case CNH_FSHOOK_IRP_OP_RENAME: + log_debug("[before][rename]: %s %s", irp->rename_old, irp->rename_new); + break; + case CNH_FSHOOK_IRP_OP_REMOVE: + log_debug("[before][remove]: %s", irp->remove_pathname); + break; + case CNH_FSHOOK_IRP_OP_ACCESS: + log_debug("[before][access]: %s", irp->access_path); + break; + default: + log_die("Unhandled case: %d", irp->op); + break; + } + + result = cnh_fshook_invoke_next(irp); + + switch (irp->op) { + case CNH_FSHOOK_IRP_OP_DIR_OPEN: + log_debug("[after][diropen]: %s -> %d", irp->opendir_name, result); + break; + case CNH_FSHOOK_IRP_OP_LXSTAT: + log_debug("[after][lxstat]: %s -> %d", irp->xstat_file, result); + break; + case CNH_FSHOOK_IRP_OP_XSTAT: + log_debug("[after][xstat]: %s -> %d", irp->xstat_file, result); + break; + case CNH_FSHOOK_IRP_OP_RENAME: + log_debug("[after][rename]: %s %s -> %d", irp->rename_old, irp->rename_new, result); + break; + case CNH_FSHOOK_IRP_OP_REMOVE: + log_debug("[after][remove]: %s -> %d", irp->remove_pathname, result); + break; + case CNH_FSHOOK_IRP_OP_ACCESS: + log_debug("[after][access]: %s -> %d", irp->access_path, result); + break; + default: + log_die("Unhandled case: %d", irp->op); + break; + } + + return result; +} + +enum cnh_result cnh_fileopen_mon_iohook(struct cnh_iohook_irp *irp) +{ + enum cnh_result result; + + if (irp->op == CNH_IOHOOK_IRP_OP_OPEN) { + log_debug("[before][open]: %s %d", irp->open_filename, irp->open_flags); + + result = cnh_iohook_invoke_next(irp); + + log_debug("[after][open]: %s %d -> %d (%d)", irp->open_filename, irp->open_flags, irp->fd, result); + } else { + result = cnh_iohook_invoke_next(irp); + } + + return result; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/fileopen-mon.h b/src/main/capnhook/hooklib/fileopen-mon.h new file mode 100644 index 0000000..bebc145 --- /dev/null +++ b/src/main/capnhook/hooklib/fileopen-mon.h @@ -0,0 +1,35 @@ +/** + * Hook implementation to monitor different kinds of operations opening a file + */ +#ifndef CAPNHOOK_FILEOPEN_MON_H +#define CAPNHOOK_FILEOPEN_MON_H + +#include "capnhook/hook/filehook.h" +#include "capnhook/hook/fshook.h" +#include "capnhook/hook/iohook.h" + +/** + * Hook function to add to the hook module for monitoring open file calls on file operations + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_fileopen_mon_filehook(struct cnh_filehook_irp *irp); + +/** + * Hook function to add to the hook module for monitoring open file calls on file system related operations + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_fileopen_mon_fshook(struct cnh_fshook_irp *irp); + +/** + * Hook function to add to the hook module for monitoring open file/device calls on I/O operations + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_fileopen_mon_iohook(struct cnh_iohook_irp *irp); + +#endif diff --git a/src/main/capnhook/hooklib/fshook-mon.c b/src/main/capnhook/hooklib/fshook-mon.c new file mode 100644 index 0000000..26b30a2 --- /dev/null +++ b/src/main/capnhook/hooklib/fshook-mon.c @@ -0,0 +1,43 @@ +#define LOG_MODULE "cnh-fshook-mon" + +#include "capnhook/hooklib/fshook-mon.h" + +#include "util/log.h" + +static const char* _cnh_fshook_mon_irp_op_str[] = { + "diropen", + "lxstat", + "xstat", + "rename", + "remove", + "access" +}; + +enum cnh_result cnh_fshook_mon(struct cnh_fshook_irp *irp) +{ + enum cnh_result result; + + log_debug("[before][%s] next_handler %d, opendir_name %s, opendir_ret %p, xstat_version %d, xstat_file %s, " + "xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, access_path %s, access_amode %d", + _cnh_fshook_mon_irp_op_str[irp->op], irp->next_handler, irp->opendir_name, irp->opendir_ret, + irp->xstat_version, irp->xstat_file, irp->xstat_buf, irp->rename_old, irp->rename_new, irp->remove_pathname, + irp->access_path, irp->access_amode); + + result = cnh_fshook_invoke_next(irp); + + if (result != CNH_RESULT_SUCCESS) { + log_error("[before][%s] result %d, next_handler %d, opendir_name %s, opendir_ret %p, xstat_version %d, " + "xstat_file %s, xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, access_path %s, " + "access_amode %d", _cnh_fshook_mon_irp_op_str[irp->op], result, irp->next_handler, irp->opendir_name, + irp->opendir_ret, irp->xstat_version, irp->xstat_file, irp->xstat_buf, irp->rename_old, irp->rename_new, + irp->remove_pathname, irp->access_path, irp->access_amode); + } else { + log_debug("[before][%s] result %d, next_handler %d, opendir_name %s, opendir_ret %p, xstat_version %d, " + "xstat_file %s, xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, access_path %s, " + "access_amode %d", _cnh_fshook_mon_irp_op_str[irp->op], result, irp->next_handler, irp->opendir_name, + irp->opendir_ret, irp->xstat_version, irp->xstat_file, irp->xstat_buf, irp->rename_old, irp->rename_new, + irp->remove_pathname, irp->access_path, irp->access_amode); + } + + return result; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/fshook-mon.h b/src/main/capnhook/hooklib/fshook-mon.h new file mode 100644 index 0000000..5a5e8e2 --- /dev/null +++ b/src/main/capnhook/hooklib/fshook-mon.h @@ -0,0 +1,17 @@ +/** + * Hook implementation to monitor file system related calls + */ +#ifndef CAPNHOOK_FSHOOK_MON_H +#define CAPNHOOK_FSHOOK_MON_H + +#include "capnhook/hook/fshook.h" + +/** + * Hook function to add to the hook module for monitoring file system related calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_fshook_mon(struct cnh_fshook_irp *irp); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hooklib/iohook-mon.c b/src/main/capnhook/hooklib/iohook-mon.c new file mode 100644 index 0000000..9b617a7 --- /dev/null +++ b/src/main/capnhook/hooklib/iohook-mon.c @@ -0,0 +1,54 @@ +#define LOG_MODULE "cnh-iohook-mon" + +#include "capnhook/hooklib/iohook-mon.h" + +#include "util/log.h" + +static const char* _cnh_iohook_mon_str_empty = ""; +static const char* _cnh_iohook_mon_irp_op_str[] = { + "open", + "fdopen", + "close", + "read", + "write", + "seek", + "ioctl" +}; + +enum cnh_result cnh_iohook_mon(struct cnh_iohook_irp *irp) +{ + enum cnh_result result; + + log_debug("[before][%s] next_handler %d, fd %d, open_filename %s, open_flags %d, fdopen_fd %d, fdopen_mode %s, " + "fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), seek_origin %d, " + "seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, pos %d)", + _cnh_iohook_mon_irp_op_str[irp->op], irp->next_handler, irp->fd, + irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty, irp->open_flags, irp->fdopen_fd, + irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty, irp->fdopen_res, irp->read.bytes, + irp->read.nbytes, irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->seek_origin, + irp->seek_offset, irp->seek_pos, irp->ioctl_req, irp->ioctl.bytes, irp->ioctl.nbytes, irp->ioctl.pos); + + result = cnh_iohook_invoke_next(irp); + + if (result != CNH_RESULT_SUCCESS) { + log_error("[after][%s] next_handler %d, res: %d, fd %d, open_filename %s, open_flags %d, fdopen_fd %d, " + "fdopen_mode %s, fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), " + "seek_origin %d, seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, pos %d)", + _cnh_iohook_mon_irp_op_str[irp->op], irp->next_handler, result, irp->fd, + irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty, irp->open_flags, irp->fdopen_fd, + irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty, irp->fdopen_res, irp->read.bytes, + irp->read.nbytes, irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->seek_origin, + irp->seek_offset, irp->seek_pos, irp->ioctl_req, irp->ioctl.bytes, irp->ioctl.nbytes, irp->ioctl.pos); + } else { + log_debug("[after][%s] next_handler %d, res %d, fd %d, open_filename %s, open_flags %d, fdopen_fd %d, " + "fdopen_mode %s, fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), " + "seek_origin %d, seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, pos %d)", + _cnh_iohook_mon_irp_op_str[irp->op], irp->next_handler, result, irp->fd, + irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty, irp->open_flags, irp->fdopen_fd, + irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty, irp->fdopen_res, irp->read.bytes, + irp->read.nbytes, irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->seek_origin, + irp->seek_offset, irp->seek_pos, irp->ioctl_req, irp->ioctl.bytes, irp->ioctl.nbytes, irp->ioctl.pos); + } + + return result; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/iohook-mon.h b/src/main/capnhook/hooklib/iohook-mon.h new file mode 100644 index 0000000..ddb10f6 --- /dev/null +++ b/src/main/capnhook/hooklib/iohook-mon.h @@ -0,0 +1,17 @@ +/** + * Hook implementation to monitor I/O calls, e.g. open, read, write etc. + */ +#ifndef CAPNHOOK_IOHOOK_MON_H +#define CAPNHOOK_IOHOOK_MON_H + +#include "capnhook/hook/iohook.h" + +/** + * Hook function to add to the hook module for monitoring I/O calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_iohook_mon(struct cnh_iohook_irp *irp); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hooklib/redir.c b/src/main/capnhook/hooklib/redir.c new file mode 100644 index 0000000..258d6d3 --- /dev/null +++ b/src/main/capnhook/hooklib/redir.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include +#include + +#include "capnhook/hook/fshook.h" +#include "capnhook/hook/filehook.h" +#include "capnhook/hook/iohook.h" + +#include "util/log.h" +#include "util/str.h" +#include "util/time.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to fshook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static enum cnh_result _cnh_redir_fshook_diropen(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_redir_fshook_lxstat(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_redir_fshook_xstat(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_redir_fshook_rename(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_redir_fshook_remove(struct cnh_fshook_irp *irp); +static enum cnh_result _cnh_redir_fshook_access(struct cnh_fshook_irp *irp); + +static const cnh_fshook_fn_t _cnh_redir_fshook_handlers[6] = { + [CNH_FSHOOK_IRP_OP_DIR_OPEN] = _cnh_redir_fshook_diropen, + [CNH_FSHOOK_IRP_OP_LXSTAT] = _cnh_redir_fshook_lxstat, + [CNH_FSHOOK_IRP_OP_XSTAT] = _cnh_redir_fshook_xstat, + [CNH_FSHOOK_IRP_OP_RENAME] = _cnh_redir_fshook_rename, + [CNH_FSHOOK_IRP_OP_REMOVE] = _cnh_redir_fshook_remove, + [CNH_FSHOOK_IRP_OP_ACCESS] = _cnh_redir_fshook_access, +}; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to filehook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static enum cnh_result _cnh_redir_filehook_default(struct cnh_filehook_irp *irp); +static enum cnh_result _cnh_redir_filehook_fopen(struct cnh_filehook_irp *irp); + +static const cnh_filehook_fn_t _cnh_redir_filehook_handlers[8] = { + [CNH_FILEHOOK_IRP_OP_OPEN] = _cnh_redir_filehook_fopen, + [CNH_FILEHOOK_IRP_OP_CLOSE] = _cnh_redir_filehook_default, + [CNH_FILEHOOK_IRP_OP_READ] = _cnh_redir_filehook_default, + [CNH_FILEHOOK_IRP_OP_WRITE] = _cnh_redir_filehook_default, + [CNH_FILEHOOK_IRP_OP_FGETS] = _cnh_redir_filehook_default, + [CNH_FILEHOOK_IRP_OP_SEEK] = _cnh_redir_filehook_default, + [CNH_FILEHOOK_IRP_OP_TELL] = _cnh_redir_filehook_default, + [CNH_FILEHOOK_IRP_OP_EOF] = _cnh_redir_filehook_default, +}; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to iohook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static enum cnh_result _cnh_redir_iohook_default(struct cnh_iohook_irp *irp); +static enum cnh_result _cnh_redir_iohook_open(struct cnh_iohook_irp *irp); + +static const cnh_iohook_fn_t _cnh_redir_iohook_handlers[7] = { + [CNH_IOHOOK_IRP_OP_OPEN] = _cnh_redir_iohook_open, + [CNH_IOHOOK_IRP_OP_FDOPEN] = _cnh_redir_iohook_default, + [CNH_IOHOOK_IRP_OP_CLOSE] = _cnh_redir_iohook_default, + [CNH_IOHOOK_IRP_OP_READ] = _cnh_redir_iohook_default, + [CNH_IOHOOK_IRP_OP_WRITE] = _cnh_redir_iohook_default, + [CNH_IOHOOK_IRP_OP_SEEK] = _cnh_redir_iohook_default, + [CNH_IOHOOK_IRP_OP_IOCTL] = _cnh_redir_iohook_default, +}; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private state */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +struct cnh_redir_redir { + char* src; + char* dest; +}; + +static atomic_int _cnh_redir_initted = ATOMIC_VAR_INIT(0); +static atomic_int _cnh_redir_init_in_progress = ATOMIC_VAR_INIT(0); +static pthread_mutex_t _cnh_redir_lock; +static struct cnh_redir_redir* _cnh_redir_redirs; +static size_t _cnh_redir_nredirs; + +static void _cnh_redir_init(); +static char* _cnh_redir_check(const char* src); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Public module functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +void cnh_redir_add(const char* src, const char* dest) +{ + struct cnh_redir_redir *new_array; + size_t new_size; + + assert(src != NULL); + assert(dest != NULL); + + /* Ensure module is initialized */ + _cnh_redir_init(); + + pthread_mutex_lock(&_cnh_redir_lock); + + new_size = _cnh_redir_nredirs + 1; + new_array = realloc(_cnh_redir_redirs, new_size * sizeof(struct cnh_redir_redir)); + + if (new_array != NULL) { + _cnh_redir_redirs = new_array; + } + + _cnh_redir_redirs[_cnh_redir_nredirs].src = util_str_dup(src); + _cnh_redir_redirs[_cnh_redir_nredirs].dest = util_str_dup(dest); + + _cnh_redir_nredirs++; + + pthread_mutex_unlock(&_cnh_redir_lock); + + log_info("Added path redirect %s -> %s", src, dest); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to fshook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp* irp) +{ + cnh_fshook_fn_t handler; + + handler = _cnh_redir_fshook_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_redir_fshook_diropen(struct cnh_fshook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->opendir_name); + + if (res != NULL) { + irp->opendir_name = res; + } + + return cnh_fshook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_fshook_lxstat(struct cnh_fshook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->xstat_file); + + if (res != NULL) { + irp->xstat_file = res; + } + + return cnh_fshook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_fshook_xstat(struct cnh_fshook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->xstat_file); + + if (res != NULL) { + irp->xstat_file = res; + } + + return cnh_fshook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_fshook_rename(struct cnh_fshook_irp *irp) +{ + char* res_old; + char* res_new; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res_old = _cnh_redir_check(irp->rename_old); + res_new = _cnh_redir_check(irp->rename_old); + + if (res_old != NULL) { + irp->rename_old = res_old; + } + + if (res_new != NULL) { + irp->rename_new = res_new; + } + + return cnh_fshook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_fshook_remove(struct cnh_fshook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->remove_pathname); + + if (res != NULL) { + irp->remove_pathname = res; + } + + return cnh_fshook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_fshook_access(struct cnh_fshook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->access_path); + + if (res != NULL) { + irp->access_path = res; + } + + return cnh_fshook_invoke_next(irp); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to iohook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp* irp) +{ + cnh_iohook_fn_t handler; + + handler = _cnh_redir_iohook_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_redir_iohook_default(struct cnh_iohook_irp *irp) +{ + return cnh_iohook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_iohook_open(struct cnh_iohook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->open_filename); + + if (res != NULL) { + irp->open_filename = res; + } + + return cnh_iohook_invoke_next(irp); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to filehook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +enum cnh_result cnh_redir_filehook(struct cnh_filehook_irp* irp) +{ + cnh_filehook_fn_t handler; + + handler = _cnh_redir_filehook_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_redir_filehook_default(struct cnh_filehook_irp *irp) +{ + return cnh_filehook_invoke_next(irp); +} + +static enum cnh_result _cnh_redir_filehook_fopen(struct cnh_filehook_irp *irp) +{ + char* res; + + /* Ensure module is initialized */ + _cnh_redir_init(); + + res = _cnh_redir_check(irp->open_filename); + + if (res != NULL) { + irp->open_filename = res; + } + + return cnh_filehook_invoke_next(irp); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Helper functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_redir_init() +{ + int expected; + + if (atomic_load(&_cnh_redir_initted) > 0) { + return; + } + + expected = 0; + + if (!atomic_compare_exchange_strong(&_cnh_redir_init_in_progress, &expected, 1)) { + while (atomic_load(&_cnh_redir_init_in_progress) > 1) { + util_time_sleep_us(100); + } + + return; + } + + /* Check again to ensure the current thread yielded between the init'd check and setting init in progress */ + if (atomic_load(&_cnh_redir_initted) > 0) { + /* Revert init in progress, because nothing to do anymore */ + atomic_store(&_cnh_redir_init_in_progress, 0); + return; + } + + pthread_mutex_init(&_cnh_redir_lock, NULL); + + atomic_store(&_cnh_redir_initted, 1); + atomic_store(&_cnh_redir_init_in_progress, 0); +} + +static char* _cnh_redir_check(const char* src) +{ + const char* redir_src; + const char* redir_dest; + char* res; + + res = NULL; + + pthread_mutex_lock(&_cnh_redir_lock); + + for (size_t i = 0; i < _cnh_redir_nredirs; i++) { + redir_src = _cnh_redir_redirs[i].src; + redir_dest = _cnh_redir_redirs[i].dest; + + if (strncmp(src, redir_src, strlen(redir_src)) == 0) { + // FIXME memory leak + res = util_str_merge(redir_dest, &src[strlen(redir_src)]); + log_debug("Redirect %s -> %s", src, res); + break; + } + } + + pthread_mutex_unlock(&_cnh_redir_lock); + + return res; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/redir.h b/src/main/capnhook/hooklib/redir.h new file mode 100644 index 0000000..ce55dbd --- /dev/null +++ b/src/main/capnhook/hooklib/redir.h @@ -0,0 +1,44 @@ +/** + * Hook implementation to redirect files/paths passed as parameters on various file, file system and I/O calls + */ +#ifndef CAPNHOOK_REDIR_H +#define CAPNHOOK_REDIR_H + +#include "capnhook/hook/fshook.h" +#include "capnhook/hook/filehook.h" +#include "capnhook/hook/iohook.h" + +/** + * Add a new path/file redirect to the module + * + * @param src Source path/file to redirect. This does not have to match the full path. + * Postfix, e.g. just the filename is sufficient as well + * @param dest Destination to redirect the original path to. Recommended to use absolute paths here. + */ +void cnh_redir_add(const char* src, const char* dest); + +/** + * Hook function to add to the hook module for redirecting file system related calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp* irp); + +/** + * Hook function to add to the hook module for redirecting I/O calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp* irp); + +/** + * Hook function to add to the hook module for redirecting file related calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_redir_filehook(struct cnh_filehook_irp* irp); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hooklib/usb-emu.c b/src/main/capnhook/hooklib/usb-emu.c new file mode 100644 index 0000000..aca314f --- /dev/null +++ b/src/main/capnhook/hooklib/usb-emu.c @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include +#include + +#include "capnhook/hooklib/usb-emu.h" + +#include "util/log.h" +#include "util/time.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private helpers */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static void _cnh_usb_emu_init(void); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooks to usbhook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static enum cnh_result _cnh_usb_emu_usbhook_default(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_noop(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_find_busses(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_find_devices(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_open(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_close(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_reset(struct cnh_usbhook_irp *irp); +static enum cnh_result _cnh_usb_emu_usbhook_ctrl_msg(struct cnh_usbhook_irp *irp); + +static const cnh_usbhook_fn_t _cnh_usb_emu_usb_handlers[10] = { + [CNH_USBHOOK_IRP_OP_INIT] = _cnh_usb_emu_usbhook_default, + [CNH_USBHOOK_IRP_OP_FIND_BUSSES] = _cnh_usb_emu_usbhook_find_busses, + [CNH_USBHOOK_IRP_OP_FIND_DEVICES] = _cnh_usb_emu_usbhook_find_devices, + [CNH_USBHOOK_IRP_OP_OPEN] = _cnh_usb_emu_usbhook_open, + [CNH_USBHOOK_IRP_OP_CLOSE] = _cnh_usb_emu_usbhook_close, + [CNH_USBHOOK_IRP_OP_RESET] = _cnh_usb_emu_usbhook_reset, + [CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE] = _cnh_usb_emu_usbhook_noop, + [CNH_USBHOOK_IRP_OP_SET_CONFIGURATION] = _cnh_usb_emu_usbhook_noop, + [CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE] = _cnh_usb_emu_usbhook_noop, + [CNH_USBHOOK_IRP_OP_CTRL_MSG] = _cnh_usb_emu_usbhook_ctrl_msg, +}; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Private state */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +struct usb_dev_handle { + struct cnh_usb_emu_virtdev* virtdev; +}; + +struct cnh_usb_emu_virtdev { + const struct cnh_usb_emu_virtdev_ep* ep; + bool real_dev_avail; + bool enumerated; + struct usb_dev_handle usb_dev_handle; +}; + +static atomic_int _cnh_usb_emu_initted = ATOMIC_VAR_INIT(0); +static atomic_int _cnh_usb_emu_init_in_progress = ATOMIC_VAR_INIT(0); +static pthread_mutex_t _cnh_usb_emu_virtdevs_lock; +static struct cnh_usb_emu_virtdev *_cnh_usb_emu_virtdevs; +static size_t _cnh_usb_emu_nvirtdevs; + +static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev(uint16_t vid, uint16_t pid); +static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev_by_handle(usb_dev_handle* handle); +static struct usb_device* _cnh_usb_emu_create_fakedev(uint16_t vid, uint16_t pid); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Public module functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +void cnh_usb_emu_add_virtdevep(const struct cnh_usb_emu_virtdev_ep* virtdevep) +{ + struct cnh_usb_emu_virtdev *new_array; + size_t new_size; + + assert(virtdevep->enumerate); + assert(virtdevep->open); + assert(virtdevep->reset); + assert(virtdevep->control_msg); + assert(virtdevep->close); + + /* Ensure initialized */ + _cnh_usb_emu_init(); + + pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock); + + new_size = _cnh_usb_emu_nvirtdevs + 1; + new_array = realloc(_cnh_usb_emu_virtdevs, new_size * sizeof(struct cnh_usb_emu_virtdev)); + + if (new_array != NULL) { + _cnh_usb_emu_virtdevs = new_array; + + _cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].enumerated = false; + _cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].real_dev_avail = false; + _cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].ep = virtdevep; + _cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].usb_dev_handle.virtdev = &_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs]; + _cnh_usb_emu_nvirtdevs++; + } else { + log_die("Out of memory"); + } + + pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock); +} + +enum cnh_result cnh_usb_emu(struct cnh_usbhook_irp *irp) +{ + cnh_usbhook_fn_t handler; + + /* Ensure initialized */ + _cnh_usb_emu_init(); + + handler = _cnh_usb_emu_usb_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Hooked functions to usbhook module */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +static enum cnh_result _cnh_usb_emu_usbhook_default(struct cnh_usbhook_irp *irp) +{ + return cnh_usbhook_invoke_next(irp); +} + +static enum cnh_result _cnh_usb_emu_usbhook_noop(struct cnh_usbhook_irp *irp) +{ + struct cnh_usb_emu_virtdev* virtdev; + + assert(irp->handle); + + virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle); + + /* Not a virtual device handle, probably real handle from libusb */ + if (virtdev == NULL) { + return cnh_usbhook_invoke_next(irp); + } + + /* No-op */ + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usb_emu_usbhook_find_busses(struct cnh_usbhook_irp *irp) +{ + enum cnh_result result; + + result = cnh_usbhook_invoke_next(irp); + + // inject another custom bus for virtual devices + if (result == CNH_RESULT_SUCCESS) { + log_debug("Injecting usb bus for virtual devices"); + irp->find_busses_res_num_busses++; + } + + return result; +} + +static enum cnh_result _cnh_usb_emu_usbhook_find_devices(struct cnh_usbhook_irp *irp) +{ + enum cnh_result result; + struct usb_bus* it; + int fakedev_count; + + fakedev_count = 0; + + /* first, populate the list with real devices */ + result = cnh_usbhook_invoke_next(irp); + + /* Iterate to the end of the list and add our stuff keeping real devices */ + it = usb_get_busses(); + + /* Iterate all busses */ + do { + /* First, iterate all devices on each bus and check for all real + devices connected which are also part of our hook list */ + if (it != NULL) { + /* Iterate devices on the current bus */ + struct usb_device* dev = it->devices; + + while (dev != NULL) { + struct cnh_usb_emu_virtdev* virt_dev = _cnh_usb_emu_get_virtdev((uint16_t) dev->descriptor.idVendor, + (uint16_t) dev->descriptor.idProduct); + + /* Real device connected for a hook */ + if (virt_dev) { + log_debug("Detected real %04X:%04X device for virtual one", dev->descriptor.idVendor, + dev->descriptor.idProduct); + virt_dev->real_dev_avail = true; + } + + dev = dev->next; + } + } + + /* it == NULL, nothing found on current bus which is our last bus + we added on usb_find_busses. We put our fakedevs on that bus */ + if (it == NULL || it->next == NULL) { + struct usb_bus* fakebus; + struct usb_device* fakebus_dev_tail; + + /* Create an additional bus for our fakedevs */ + fakebus = (struct usb_bus*) util_xmalloc(sizeof(struct usb_bus)); + memset(fakebus, 0, sizeof(struct usb_bus)); + + /* Make sure to modify the linked list correctly. If we fuck up, + this works fine until Fiesta where they started to iterate + everything in a different manner (-> crash) */ + if (it == NULL) { + usb_busses = fakebus; + /* Bus empty, no prev bus */ + fakebus->prev = NULL; + } else { + /* Append at end of bus chain */ + it->next = fakebus; + /* Keep doubly linked list intact */ + fakebus->prev = it->next; + } + + fakebus_dev_tail = NULL; + + pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock); + + for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) { + struct cnh_usb_emu_virtdev* virtdev = &_cnh_usb_emu_virtdevs[i]; + + virtdev->enumerated = virtdev->ep->enumerate(virtdev->real_dev_avail); + + if (virtdev->enumerated) { + if (virtdev->real_dev_avail) { + /* Suppress real device and detour everything to + our hook */ + log_debug("Suppressing real device %04X:%04X", virtdev->ep->vid, virtdev->ep->pid); + } else { + /* Create a fakedev and add it to the bus */ + struct usb_device* fakedev; + + { + /* Print this once. Pump Pro calls this + function every second */ + static int counter = 0; + + if (counter++ == 0) { + log_info("Injecting fake usb device %04X:%04X into bus", virtdev->ep->vid, + virtdev->ep->pid); + } else { + counter = 1; + } + } + + fakedev = _cnh_usb_emu_create_fakedev(virtdev->ep->vid, virtdev->ep->pid); + + /* Append to linked list */ + if (!fakebus->devices) { + /* Set root on bus */ + fakebus->devices = fakedev; + } + + /* Cur element */ + fakedev->prev = fakebus_dev_tail; + fakedev->next = NULL; + + /* Update prev element's next */ + if (fakebus_dev_tail) { + fakebus_dev_tail->next = fakedev; + } + + /* tail update */ + fakebus_dev_tail = fakedev; + + fakedev_count++; + } + } else { + log_debug("Reject enumerate hook for %04X:%04X", virtdev->ep->vid, virtdev->ep->pid); + } + } + + pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock); + + break; + } + /* End of if block which handles fakedevs and hooking */ + + it = it->next; + } + while (it != NULL); + + { + /* Print this once. Pump Pro calls this + function every second */ + static int counter = 0; + + if (counter++ == 0) { + log_info("Added %d fakedevs to usb bus", fakedev_count); + } else { + counter = 1; + } + } + + /* include our fakedev count as well */ + return result + fakedev_count; +} + +static enum cnh_result _cnh_usb_emu_usbhook_open(struct cnh_usbhook_irp *irp) +{ + struct cnh_usb_emu_virtdev* virtdev; + enum cnh_result result; + + virtdev = _cnh_usb_emu_get_virtdev((uint16_t) irp->open_usb_dev->descriptor.idVendor, + (uint16_t) irp->open_usb_dev->descriptor.idProduct); + + if (virtdev == NULL) { + return cnh_usbhook_invoke_next(irp); + } + + if (!virtdev->enumerated) { + log_debug("Virtdev %04X:%04X not enumerated, skipping open", virtdev->ep->vid, virtdev->ep->pid); + return cnh_usbhook_invoke_next(irp); + } + + result = virtdev->ep->open(); + + if (result == CNH_RESULT_SUCCESS) { + /* Return handle, use virtual device as fake handle */ + irp->handle = &virtdev->usb_dev_handle; + } + + return result; +} + +static enum cnh_result _cnh_usb_emu_usbhook_close(struct cnh_usbhook_irp *irp) +{ + struct cnh_usb_emu_virtdev* virtdev; + + assert(irp->handle); + + virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle); + + /* Not a virtual device handle, probably real handle from libusb */ + if (virtdev == NULL) { + return cnh_usbhook_invoke_next(irp); + } + + virtdev->ep->close(); + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _cnh_usb_emu_usbhook_reset(struct cnh_usbhook_irp *irp) +{ + struct cnh_usb_emu_virtdev* virtdev; + + assert(irp->handle); + + virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle); + + /* Not a virtual device handle, probably real handle from libusb */ + if (virtdev == NULL) { + return cnh_usbhook_invoke_next(irp); + } + + return virtdev->ep->reset(); +} + +static enum cnh_result _cnh_usb_emu_usbhook_ctrl_msg(struct cnh_usbhook_irp *irp) +{ + struct cnh_usb_emu_virtdev* virtdev; + + assert(irp->handle); + + virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle); + + /* Not a virtual device handle, probably real handle from libusb */ + if (virtdev == NULL) { + return cnh_usbhook_invoke_next(irp); + } + + return virtdev->ep->control_msg(irp->ctrl_req_type, irp->ctrl_req, irp->ctrl_value, irp->ctrl_index, + &irp->ctrl_buffer, irp->ctrl_timeout); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Helper functions */ +/* ------------------------------------------------------------------------------------------------------------------ */ + +void _cnh_usb_emu_init(void) +{ + int expected; + + if (atomic_load(&_cnh_usb_emu_initted) > 0) { + return; + } + + expected = 0; + + if (!atomic_compare_exchange_strong(&_cnh_usb_emu_init_in_progress, &expected, 1)) { + while (atomic_load(&_cnh_usb_emu_init_in_progress) > 1) { + util_time_sleep_us(100); + } + + return; + } + + /* Check again to ensure the current thread yielded between the init'd check and setting init in progress */ + if (atomic_load(&_cnh_usb_emu_initted) > 0) { + /* Revert init in progress, because nothing to do anymore */ + atomic_store(&_cnh_usb_emu_init_in_progress, 0); + return; + } + + pthread_mutex_init(&_cnh_usb_emu_virtdevs_lock, NULL); + + atomic_store(&_cnh_usb_emu_initted, 1); + atomic_store(&_cnh_usb_emu_init_in_progress, 0); +} + +static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev(uint16_t vid, uint16_t pid) +{ + struct cnh_usb_emu_virtdev* virtdev; + struct cnh_usb_emu_virtdev* tmp; + + virtdev = NULL; + + pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock); + + for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) { + tmp = &_cnh_usb_emu_virtdevs[i]; + + if (tmp->ep->vid == vid && tmp->ep->pid == pid) { + virtdev = tmp; + break; + } + } + + pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock); + + return virtdev; +} + +static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev_by_handle(usb_dev_handle* handle) +{ + struct cnh_usb_emu_virtdev* virtdev; + struct cnh_usb_emu_virtdev* tmp; + + virtdev = NULL; + + pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock); + + for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) { + tmp = &_cnh_usb_emu_virtdevs[i]; + + if (tmp == handle->virtdev) { + virtdev = tmp; + break; + } + } + + pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock); + + return virtdev; +} + +static struct usb_device* _cnh_usb_emu_create_fakedev(uint16_t vid, uint16_t pid) +{ + struct usb_device* fakedev = (struct usb_device*) util_xmalloc(sizeof(struct usb_device)); + memset(fakedev, 0, sizeof(struct usb_device)); + + /* Populate fakedev */ + fakedev->descriptor.idVendor = vid; + fakedev->descriptor.idProduct = pid; + + /* Mark as fakedev */ + fakedev->descriptor.bcdDevice = 0xBEEF; + + fakedev->config = (struct usb_config_descriptor*) util_xmalloc( + sizeof(struct usb_config_descriptor)); + memset(fakedev->config, 0, sizeof(struct usb_config_descriptor)); + + fakedev->config->interface = (struct usb_interface*) util_xmalloc( + sizeof(struct usb_interface)); + memset(fakedev->config->interface, 0, sizeof(struct usb_interface)); + + fakedev->config->interface->altsetting = (struct usb_interface_descriptor*) + util_xmalloc(sizeof(struct usb_interface_descriptor)); + memset(fakedev->config->interface->altsetting, 0, + sizeof(struct usb_interface_descriptor)); + + return fakedev; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/usb-emu.h b/src/main/capnhook/hooklib/usb-emu.h new file mode 100644 index 0000000..a980567 --- /dev/null +++ b/src/main/capnhook/hooklib/usb-emu.h @@ -0,0 +1,42 @@ +/** + * Hook implementation for emulating usb devices on libusb 0.1 + */ +#ifndef CNH_USB_EMU_H +#define CNH_USB_EMU_H + +#include +#include + +#include "capnhook/hook/iobuf.h" +#include "capnhook/hook/usbhook.h" + +/** + * Virtual device endpoint + */ +struct cnh_usb_emu_virtdev_ep { + uint16_t pid; + uint16_t vid; + bool (*enumerate)(bool real_exists); + enum cnh_result (*open)(void); + enum cnh_result (*reset)(void); + enum cnh_result (*control_msg)(int request_type, int request, int value, int index, struct cnh_iobuf* buffer, + int timeout); + void (*close)(void); +}; + +/** + * Add a pointer to a virtual device endpoint implementing handler functions + * + * @param virtdevep Virtual device endpoint to add + */ +void cnh_usb_emu_add_virtdevep(const struct cnh_usb_emu_virtdev_ep* virtdevep); + +/** + * Hook function to add to the hook module for emulating usb devices + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_usb_emu(struct cnh_usbhook_irp *irp); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hooklib/usb-init-fix.c b/src/main/capnhook/hooklib/usb-init-fix.c new file mode 100644 index 0000000..eb1b176 --- /dev/null +++ b/src/main/capnhook/hooklib/usb-init-fix.c @@ -0,0 +1,80 @@ +#include + +#include "capnhook/hooklib/usb-init-fix.h" + +#include "util/log.h" + +static enum cnh_result _cnh_usb_init_fix_default(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usb_init_fix_init(struct cnh_usbhook_irp* irp); +static enum cnh_result _cnh_usbio_emu_find_busses(struct cnh_usbhook_irp* irp); + +static const cnh_usbhook_fn_t _hook_usb_init_fix_handlers[10] = { + [CNH_USBHOOK_IRP_OP_INIT] = _cnh_usb_init_fix_init, + [CNH_USBHOOK_IRP_OP_FIND_BUSSES] = _cnh_usbio_emu_find_busses, + [CNH_USBHOOK_IRP_OP_FIND_DEVICES] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_OPEN] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_CLOSE] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_RESET] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_SET_CONFIGURATION] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE] = _cnh_usb_init_fix_default, + [CNH_USBHOOK_IRP_OP_CTRL_MSG] = _cnh_usb_init_fix_default, +}; + +static int _cnh_usb_init_fix_init_count = 0; + +enum cnh_result cnh_usb_init_fix(struct cnh_usbhook_irp *irp) +{ + cnh_usbhook_fn_t handler; + + handler = _hook_usb_init_fix_handlers[irp->op]; + + assert(handler != NULL); + + return handler(irp); +} + +static enum cnh_result _cnh_usb_init_fix_default(struct cnh_usbhook_irp* irp) +{ + return cnh_usbhook_invoke_next(irp); +} + +static enum cnh_result _cnh_usb_init_fix_init(struct cnh_usbhook_irp* irp) +{ + /* On NXA, one programmer/multiple programmers had the bright idea to call + usb_init twice for reasons... + This breaks stuff in the usb-0.1 backend resulting in usb_find_busses + not even finding native devices anymore. + Make sure we call the real usb_init ONCE ONLY to fix that fuck up */ + _cnh_usb_init_fix_init_count++; + + if (_cnh_usb_init_fix_init_count <= 1) { + return cnh_usbhook_invoke_next(irp); + } else { + /* Pump Pro is even worse and calls usb_init approx. every second... + avoid overflow of counter if we really leave this running forever. + Furthermore, this avoids printing the log message below with ever + init call */ + if (_cnh_usb_init_fix_init_count > 2) { + _cnh_usb_init_fix_init_count = 2; + } else { + log_info("usb_init called multiple times, blocking further calls..."); + } + + return CNH_RESULT_SUCCESS; + } +} + +static enum cnh_result _cnh_usbio_emu_find_busses(struct cnh_usbhook_irp* irp) +{ + enum cnh_result result; + + /* Fixes quirks with usb_init called multiple times on NXA */ + if (_cnh_usb_init_fix_init_count <= 1) { + result = cnh_usbhook_invoke_next(irp); + } else { + result = CNH_RESULT_SUCCESS; + } + + return result; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/usb-init-fix.h b/src/main/capnhook/hooklib/usb-init-fix.h new file mode 100644 index 0000000..0c74bf2 --- /dev/null +++ b/src/main/capnhook/hooklib/usb-init-fix.h @@ -0,0 +1,17 @@ +/** + * Hook implementation to fix buggy applications that call usb_init repeatetly + */ +#ifndef CNH_USB_INIT_FIX_H +#define CNH_USB_INIT_FIX_H + +#include "capnhook/hook/usbhook.h" + +/** + * Hook function to add to the hook module to fix the usb_init bug + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_usb_init_fix(struct cnh_usbhook_irp *irp); + +#endif \ No newline at end of file diff --git a/src/main/capnhook/hooklib/usbhook-mon.c b/src/main/capnhook/hooklib/usbhook-mon.c new file mode 100644 index 0000000..a87b748 --- /dev/null +++ b/src/main/capnhook/hooklib/usbhook-mon.c @@ -0,0 +1,55 @@ +#define LOG_MODULE "cnh-usbhook-mon" + +#include "capnhook/hooklib/usbhook-mon.h" + +#include "util/log.h" + +static const char* _cnh_usbhook_mon_irp_op_str[] = { + "init", + "find_busses", + "find_devices", + "open", + "close", + "reset", + "set_altinterface", + "set_configuration", + "claim_interface", + "ctrl_msg" +}; + +enum cnh_result cnh_usbhook_mon(struct cnh_usbhook_irp *irp) +{ + enum cnh_result result; + + log_debug("[before][%s] next_handler %d, find_busses_res_num_busses %d, find_devices_res_num_devices %d, " + "open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, claim_interface %d, ctrl_req_type %d, " + "ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, nbytes %d, pos %d), ctrl_timeout %d", + _cnh_usbhook_mon_irp_op_str[irp->op], irp->next_handler, irp->find_busses_res_num_busses, + irp->find_devices_res_num_devices, irp->open_usb_dev, irp->handle, irp->set_altinterface, + irp->set_configuration, irp->claim_interface, irp->ctrl_req_type, irp->ctrl_req, irp->ctrl_value, + irp->ctrl_index, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_buffer.pos, irp->ctrl_timeout); + + result = cnh_usbhook_invoke_next(irp); + + if (result != CNH_RESULT_SUCCESS) { + log_error("[after][%s] result %d, next_handler %d, find_busses_res_num_busses %d, " + "find_devices_res_num_devices %d, open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, " + "claim_interface %d, ctrl_req_type %d, ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, " + "nbytes %d, pos %d), ctrl_timeout %d", _cnh_usbhook_mon_irp_op_str[irp->op], result, irp->next_handler, + irp->find_busses_res_num_busses, irp->find_devices_res_num_devices, irp->open_usb_dev, irp->handle, + irp->set_altinterface, irp->set_configuration, irp->claim_interface, irp->ctrl_req_type, irp->ctrl_req, + irp->ctrl_value, irp->ctrl_index, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_buffer.pos, + irp->ctrl_timeout); + } else { + log_debug("[after][%s] result %d, next_handler %d, find_busses_res_num_busses %d, " + "find_devices_res_num_devices %d, open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, " + "claim_interface %d, ctrl_req_type %d, ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, " + "nbytes %d, pos %d), ctrl_timeout %d", _cnh_usbhook_mon_irp_op_str[irp->op], result, irp->next_handler, + irp->find_busses_res_num_busses, irp->find_devices_res_num_devices, irp->open_usb_dev, irp->handle, + irp->set_altinterface, irp->set_configuration, irp->claim_interface, irp->ctrl_req_type, irp->ctrl_req, + irp->ctrl_value, irp->ctrl_index, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_buffer.pos, + irp->ctrl_timeout); + } + + return result; +} \ No newline at end of file diff --git a/src/main/capnhook/hooklib/usbhook-mon.h b/src/main/capnhook/hooklib/usbhook-mon.h new file mode 100644 index 0000000..d8c58bf --- /dev/null +++ b/src/main/capnhook/hooklib/usbhook-mon.h @@ -0,0 +1,17 @@ +/** + * Hook implementation to monitor libusb 0.1 calls + */ +#ifndef CAPNHOOK_USBHOOK_MON_H +#define CAPNHOOK_USBHOOK_MON_H + +#include "capnhook/hook/usbhook.h" + +/** + * Hook function to add to the hook module for monitoring libusb calls + * + * @param irp I/O request package of hook module received + * @return Result of operation + */ +enum cnh_result cnh_usbhook_mon(struct cnh_usbhook_irp *irp); + +#endif diff --git a/src/main/crypt/aes.c b/src/main/crypt/aes.c new file mode 100644 index 0000000..a20301c --- /dev/null +++ b/src/main/crypt/aes.c @@ -0,0 +1,29 @@ +#define LOG_MODULE "crypt-aes" + +#include "lib/rijndael.h" + +#include "aes.h" + +void crypt_aes_enc(uint8_t* key, enum crypt_aes_key_length key_len, + uint8_t* out, const uint8_t* in, size_t nbytes) +{ + unsigned long rk[RKLENGTH(128)]; + int nrounds; + + nrounds = rijndaelSetupEncrypt(rk, key, key_len * 8); + for (size_t i = 0; i < nbytes / key_len; i++) { + rijndaelEncrypt(rk, nrounds, &in[i * key_len], &out[i * key_len]); + } +} + +void crypt_aes_dec(uint8_t* key, enum crypt_aes_key_length key_len, + uint8_t* out, const uint8_t* in, size_t nbytes) +{ + unsigned long rk[RKLENGTH(128)]; + int nrounds; + + nrounds = rijndaelSetupDecrypt(rk, key, key_len * 8); + for (size_t i = 0; i < nbytes / key_len; i++) { + rijndaelDecrypt(rk, nrounds, &in[i * key_len], &out[i * key_len]); + } +} \ No newline at end of file diff --git a/src/main/crypt/aes.h b/src/main/crypt/aes.h new file mode 100644 index 0000000..cb3c782 --- /dev/null +++ b/src/main/crypt/aes.h @@ -0,0 +1,43 @@ +#ifndef CRYPT_AES_H +#define CRYPT_AES_H + +#include +#include + +/** + * AES enc/dec key lengths + */ +enum crypt_aes_key_length { + /* 128 bit */ + CRYPT_AES_KEY_LENGTH_16_BYTES = 16, + /* 192 bit */ + CRYPT_AES_KEY_LENGTH_24_BYTES = 24, + /* 256 bit */ + CRYPT_AES_KEY_LENGTH_32_BYTES = 32, +}; + +/** + * Encrypt data + * + * @param key AES key to use + * @param key_len Length of the key + * @param out Output buffer encrypted data + * @param in Input buffer to encrypt + * @param nbytes Number of bytes of input buffer to encrypt + */ +void crypt_aes_enc(uint8_t* key, enum crypt_aes_key_length key_len, + uint8_t* out, const uint8_t* in, size_t nbytes); + +/** + * Decrypt data + * + * @param key AES key to use + * @param key_len Length of the key + * @param out Output buffer for decrypted data + * @param in Input buffer to decrypt + * @param nbytes Number of bytes of input buffer to decrypt + */ +void crypt_aes_dec(uint8_t* key, enum crypt_aes_key_length key_len, + uint8_t* out, const uint8_t* in, size_t nbytes); + +#endif \ No newline at end of file diff --git a/src/main/crypt/lib/md5.c b/src/main/crypt/lib/md5.c new file mode 100644 index 0000000..a8565de --- /dev/null +++ b/src/main/crypt/lib/md5.c @@ -0,0 +1,333 @@ +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include "md5.h" + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform (uint32_t [4], unsigned char [64]); +static void Encode(unsigned char *, uint32_t *, unsigned int); +static void Decode(uint32_t *, unsigned char *, unsigned int); +static void MD5_memcpy(uint8_t *, uint8_t *, unsigned int); +static void MD5_memset(uint8_t *, int, unsigned int); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned int inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((uint32_t)inputLen << 3)) + + < ((uint32_t)inputLen << 3)) + context->count[1]++; + context->count[1] += ((uint32_t)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + MD5_memcpy + ((uint8_t *)&context->buffer[index], (uint8_t *)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((uint8_t *)&context->buffer[index], (uint8_t *)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + MD5_memset ((uint8_t *)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +uint32_t state[4]; +unsigned char block[64]; +{ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + +*/ + MD5_memset ((uint8_t *)x, 0, sizeof (x)); +} + +/* Encodes input (uint32_t) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +uint32_t *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (uint32_t). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +uint32_t *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | + (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (output, input, len) +uint8_t * output; +uint8_t * input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +uint8_t * output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} \ No newline at end of file diff --git a/src/main/crypt/lib/md5.h b/src/main/crypt/lib/md5.h new file mode 100644 index 0000000..5cf313f --- /dev/null +++ b/src/main/crypt/lib/md5.h @@ -0,0 +1,35 @@ +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include + +/* MD5 context. */ +typedef struct { + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init(MD5_CTX *); +void MD5Update(MD5_CTX *, unsigned char *, unsigned int); +void MD5Final(unsigned char [16], MD5_CTX *); + diff --git a/src/main/crypt/lib/rijndael.c b/src/main/crypt/lib/rijndael.c new file mode 100644 index 0000000..5a1ecda --- /dev/null +++ b/src/main/crypt/lib/rijndael.c @@ -0,0 +1,1208 @@ +#define FULL_UNROLL + +#include "rijndael.h" + +typedef unsigned long u32; +typedef unsigned char u8; + +static const u32 Te0[256] = +{ + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; + +static const u32 Te1[256] = +{ + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; + +static const u32 Te2[256] = +{ + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; + +static const u32 Te3[256] = +{ + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; + +static const u32 Te4[256] = +{ + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; + +static const u32 Td0[256] = +{ + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; + +static const u32 Td1[256] = +{ + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; + +static const u32 Td2[256] = +{ + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; + +static const u32 Td3[256] = +{ + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; + +static const u32 Td4[256] = +{ + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; + +static const u32 rcon[] = +{ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +#define GETU32(plaintext) (((u32)(plaintext)[0] << 24) ^ \ + ((u32)(plaintext)[1] << 16) ^ \ + ((u32)(plaintext)[2] << 8) ^ \ + ((u32)(plaintext)[3])) + +#define PUTU32(ciphertext, st) { (ciphertext)[0] = (u8)((st) >> 24); \ + (ciphertext)[1] = (u8)((st) >> 16); \ + (ciphertext)[2] = (u8)((st) >> 8); \ + (ciphertext)[3] = (u8)(st); } + +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int rijndaelSetupEncrypt(u32 *rk, const u8 *key, int keybits) +{ + int i = 0; + u32 temp; + + rk[0] = GETU32(key ); + rk[1] = GETU32(key + 4); + rk[2] = GETU32(key + 8); + rk[3] = GETU32(key + 12); + if (keybits == 128) + { + for (;;) + { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) + return 10; + rk += 4; + } + } + rk[4] = GETU32(key + 16); + rk[5] = GETU32(key + 20); + if (keybits == 192) + { + for (;;) + { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) + return 12; + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(key + 24); + rk[7] = GETU32(key + 28); + if (keybits == 256) + { + for (;;) + { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) + return 14; + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int rijndaelSetupDecrypt(u32 *rk, const u8 *key, int keybits) +{ + int nrounds, i, j; + u32 temp; + + /* expand the cipher key: */ + nrounds = rijndaelSetupEncrypt(rk, key, keybits); + /* invert the order of the round keys: */ + for (i = 0, j = 4*nrounds; i < j; i += 4, j -= 4) + { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < nrounds; i++) + { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return nrounds; +} + +void rijndaelEncrypt(const u32 *rk, int nrounds, const u8 plaintext[16], + u8 ciphertext[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; + #ifndef FULL_UNROLL + int r; + #endif /* ?FULL_UNROLL */ + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(plaintext ) ^ rk[0]; + s1 = GETU32(plaintext + 4) ^ rk[1]; + s2 = GETU32(plaintext + 8) ^ rk[2]; + s3 = GETU32(plaintext + 12) ^ rk[3]; + #ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (nrounds > 10) + { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (nrounds > 12) + { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += nrounds << 2; + #else /* !FULL_UNROLL */ + /* + * nrounds - 1 full rounds: + */ + r = nrounds >> 1; + for (;;) + { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + rk += 8; + if (--r == 0) + break; + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } + #endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(ciphertext , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(ciphertext + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(ciphertext + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(ciphertext + 12, s3); +} + +void rijndaelDecrypt(const u32 *rk, int nrounds, const u8 ciphertext[16], + u8 plaintext[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; + #ifndef FULL_UNROLL + int r; + #endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ciphertext ) ^ rk[0]; + s1 = GETU32(ciphertext + 4) ^ rk[1]; + s2 = GETU32(ciphertext + 8) ^ rk[2]; + s3 = GETU32(ciphertext + 12) ^ rk[3]; + #ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (nrounds > 10) + { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (nrounds > 12) + { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += nrounds << 2; + #else /* !FULL_UNROLL */ + /* + * nrounds - 1 full rounds: + */ + r = nrounds >> 1; + for (;;) + { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + rk += 8; + if (--r == 0) + break; + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } + #endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(plaintext , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(plaintext + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(plaintext + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(plaintext + 12, s3); +} + + diff --git a/src/main/crypt/lib/rijndael.h b/src/main/crypt/lib/rijndael.h new file mode 100644 index 0000000..9394a5b --- /dev/null +++ b/src/main/crypt/lib/rijndael.h @@ -0,0 +1,17 @@ +#ifndef H__RIJNDAEL +#define H__RIJNDAEL + +int rijndaelSetupEncrypt(unsigned long *rk, const unsigned char *key, + int keybits); +int rijndaelSetupDecrypt(unsigned long *rk, const unsigned char *key, + int keybits); +void rijndaelEncrypt(const unsigned long *rk, int nrounds, + const unsigned char plaintext[16], unsigned char ciphertext[16]); +void rijndaelDecrypt(const unsigned long *rk, int nrounds, + const unsigned char ciphertext[16], unsigned char plaintext[16]); + +#define KEYLENGTH(keybits) ((keybits)/8) +#define RKLENGTH(keybits) ((keybits)/8+28) +#define NROUNDS(keybits) ((keybits)/32+6) + +#endif diff --git a/src/main/crypt/md5.c b/src/main/crypt/md5.c new file mode 100644 index 0000000..418c03a --- /dev/null +++ b/src/main/crypt/md5.c @@ -0,0 +1,14 @@ +#define LOG_MODULE "crypt-md5" + +#include "lib/md5.h" + +#include "md5.h" + +void crypt_md5_hash(uint8_t* out, const uint8_t* in, size_t nbytes) +{ + MD5_CTX ctx; + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*) in, (unsigned int) nbytes); + MD5Final(out, &ctx); +} \ No newline at end of file diff --git a/src/main/crypt/md5.h b/src/main/crypt/md5.h new file mode 100644 index 0000000..dbdf982 --- /dev/null +++ b/src/main/crypt/md5.h @@ -0,0 +1,16 @@ +#ifndef CRYPT_MD5_H +#define CRYPT_MD5_H + +#include +#include + +/** + * Create an MD5 hash + * + * @param out Output buffer + * @param in Input buffer to hash + * @param nbytes Number of bytes of input buffer to process + */ +void crypt_md5_hash(uint8_t* out, const uint8_t* in, size_t nbytes); + +#endif \ No newline at end of file diff --git a/src/main/hook/core/options.c b/src/main/hook/core/options.c new file mode 100644 index 0000000..4b4d8b8 --- /dev/null +++ b/src/main/hook/core/options.c @@ -0,0 +1,50 @@ +#include "hook/core/options.h" + +#include "util/options.h" + +#define HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def hook_core_options_def[] = { + { + .name = HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs hook_core_options_defs = { + .usage_header = "", + // Just use something because this is not relevant/required here + .usage_param = '\r', + .defs = hook_core_options_def, + .ndefs = lengthof(hook_core_options_def) +}; + +void hook_core_options_init(int argc, char** argv, struct hook_core_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&hook_core_options_defs); + + if (!options_opt) { + return; + } + + options->log.file = util_options_get_str(options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); +} \ No newline at end of file diff --git a/src/main/hook/core/options.h b/src/main/hook/core/options.h new file mode 100644 index 0000000..f610765 --- /dev/null +++ b/src/main/hook/core/options.h @@ -0,0 +1,15 @@ +#ifndef HOOK_CORE_OPTIONS_H +#define HOOK_CORE_OPTIONS_H + +#include "util/log.h" + +struct hook_core_options { + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +void hook_core_options_init(int argc, char** argv, struct hook_core_options* options); + +#endif diff --git a/src/main/hook/core/piu-utils.c b/src/main/hook/core/piu-utils.c new file mode 100644 index 0000000..44069d0 --- /dev/null +++ b/src/main/hook/core/piu-utils.c @@ -0,0 +1,133 @@ +#define LOG_MODULE "hook-core-piu-utils" + +#include +#include +#include + +#include "hook/core/options.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/log.h" +#include "util/proc.h" +#include "util/str.h" +#include "util/sys-info.h" + +static void hook_core_piu_log_application_args(int argc, char** argv) +{ + const char* sep = "\n"; + char* str = util_str_dup(""); + char* tmp; + + for (int i = 0; i < argc; i++) { + if (strlen(str) > 0) { + tmp = util_str_merge(str, sep); + free(str); + str = tmp; + } + + tmp = util_str_merge(str, argv[i]); + free(str); + str = tmp; + } + + log_info("Application arguments (%d):\n%s", argc, str); + free(str); +} + +void hook_core_piu_log_init(int argc, char** argv) +{ + struct hook_core_options options; + + hook_core_options_init(argc, argv, &options); + + util_log_set_file(options.log.file, false); + util_log_set_level(options.log.level); +} + +void hook_core_piu_log_info(int argc, char** argv) +{ + log_info("\n" + " _ _ \n" + " _ __ _ _ _ __ ___ _ __ | |_ ___ ___ | |___ \n" + " | '_ \\| | | | '_ ` _ \\| '_ \\| __/ _ \\ / _ \\| / __|\n" + " | |_) | |_| | | | | | | |_) | || (_) | (_) | \\__ \\\n" + " | .__/ \\__,_|_| |_| |_| .__/ \\__\\___/ \\___/|_|___/\n" + " |_| |_| "); + + log_info("Pumptools build " __DATE__ " " __TIME__ " gitrev %s", STRINGIFY(GITREV)); + + util_sys_info_log(); + util_proc_log_info(); + util_glibc_info_log(); + hook_core_piu_log_application_args(argc, argv); +} + +char* hook_core_piu_utils_get_and_verify_game_data_path(int argc, char** argv) +{ + if (argc < 2) { + log_error("Missing game data path, usage for piu (stock args): piu (e.g. piu ./game)"); + exit(0); + } + + char* game_data_path = util_str_dup(argv[1]); + + log_info("Game data path: %s", game_data_path); + + /* remove trailing / for the hook. however, the game crashes without it */ + if (util_str_ends_with(game_data_path, "/")) { + game_data_path[strlen(game_data_path) - 1] = '\0'; + } else { + log_error("Game data path '%s' does not end with a trailing /, exiting because the game is going to " + "crash anyway!", game_data_path); + exit(0); + } + + /* depending on the version, the game also just crashes if the game folder or files within it were not found */ + if (!util_fs_path_exists(game_data_path)) { + log_error("Game data path '%s' does not exist, exiting", game_data_path); + exit(0); + } + + return game_data_path; +} + +void hook_core_piu_utils_verify_root_user() +{ + log_info("Verifying process is running as root user."); + + if (!util_proc_is_running_as_root()) { + log_error("Process not running as root which is required for the game to work correctly."); + //exit(0); + } +} + +void hook_core_piu_utils_fix_locale() +{ + log_info("Fixing locale settings."); + + if (setenv("LC_ALL", "C", 1) != 0) { + log_warn("Setting locale LC_ALL failed."); + } + + if (unsetenv("LANGUAGE") != 0) { + log_warn("Unsetting LANGUAGE env var failed."); + } +} + +bool hook_core_piu_block_non_piu_process_recursion(int argc, char** argv) +{ + /* Sanity check for arguments. If further child processes are started + from the current process, and using LD_PRELOAD on the current process, + all children are also getting the preloaded library. This causes + multiple calls to the trap main function and just crashes our + application at some point. + The executable file is required to contain the "piu" substring to make + this work properly */ + if (!strstr(argv[0], "piu")) { + log_warn("Not attaching to non piu process %s", argv[0]); + return true; + } else { + return false; + } +} \ No newline at end of file diff --git a/src/main/hook/core/piu-utils.h b/src/main/hook/core/piu-utils.h new file mode 100644 index 0000000..3608c09 --- /dev/null +++ b/src/main/hook/core/piu-utils.h @@ -0,0 +1,53 @@ +#ifndef HOOK_CORE_PIU_UTILS_H +#define HOOK_CORE_PIU_UTILS_H + +/** + * Initialize the logging system as early as possible to allow recording everything to a log file as well. + */ +void hook_core_piu_log_init(int argc, char** argv); + +/** + * Log process and system relevant information. + */ +void hook_core_piu_log_info(int argc, char** argv); + +/** + * Check and verify the game data path argument passed to the game via argv + * + * Executes various checks and catches errors that might result in the game + * simply crashing without any error indication. + * + * @param argc Argc from piu main + * @param argv Argv from piu main + * @return New string with game data path extracted from argv (caller has to free) + */ +char* hook_core_piu_utils_get_and_verify_game_data_path(int argc, char** argv); + +/** + * Verify that the current process is running as root user because the game + * needs access to various devices that require higher privileges. + * + * Does not return and errors if not running as root user. + */ +void hook_core_piu_utils_verify_root_user(); + +/** + * Fix the locale configuration for Fiesta 2 and newer. + */ +void hook_core_piu_utils_fix_locale(); + +/** + * If further child processes are started from the current process, and using + * LD_PRELOAD on the current process, all children are also getting the preloaded + * library. This causes multiple calls to the trap main function and just crashes our + * application at some point. The executable file is required to contain the "piu" + * substring to make this work properly. + * + * @param argc Argc from piu main + * @param argv Argv from piu main + * @return True if we have to block this call by another process, + * false if the process calling this is the piu process. + */ +bool hook_core_piu_block_non_piu_process_recursion(int argc, char** argv); + +#endif diff --git a/src/main/hook/exc/eeprom.c b/src/main/hook/exc/eeprom.c new file mode 100644 index 0000000..460d0f6 --- /dev/null +++ b/src/main/hook/exc/eeprom.c @@ -0,0 +1,98 @@ +#define LOG_MODULE "exchook-eeprom" + +#include +#include +#include + +#include "hook/exc/mempatch.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/patch.h" + +static int32_t exchook_eeprom_read(uint8_t* buffer, int32_t len); +static int32_t exchook_eeprom_write(const uint8_t* buffer, int32_t len); + +static char* exchook_eeprom_file; +static uint8_t exchook_eeprom_buffer[8192]; + +void exchook_eeprom_init(const struct exchook_mempatch_table* patch_table, const char* eeprom_file) +{ + void* buffer; + size_t len; + + exchook_eeprom_file = util_fs_get_abs_path(eeprom_file); + + /* EEPROM file does not exist, create new */ + if (!exchook_eeprom_file) { + memset(exchook_eeprom_buffer, 0xFF, sizeof(exchook_eeprom_buffer)); + + FILE* file = fopen(eeprom_file, "wb+"); + + if (file == NULL) { + log_error("Creating new eeprom file %s failed: %s", eeprom_file, strerror(errno)); + } + + fwrite(exchook_eeprom_buffer, sizeof(exchook_eeprom_buffer), 1, file); + fclose(file); + + exchook_eeprom_file = util_fs_get_abs_path(eeprom_file); + len = (size_t) -1; + } else { + if (util_file_load(exchook_eeprom_file, &buffer, &len, false)) { + if (len > sizeof(exchook_eeprom_buffer)) { + log_error("Contents of %s eeprom file exceed the max eeprom buffer " + " size of %d bytes", eeprom_file, + sizeof(exchook_eeprom_buffer)); + free(buffer); + return; + } + + /* copy read contents */ + memcpy(exchook_eeprom_buffer, buffer, len); + free(buffer); + } else { + log_error("Loading eeprom file %s failed", exchook_eeprom_file); + } + } + + log_assert(exchook_eeprom_file); + + /* Hook eeprom */ + util_patch_function(patch_table->addr_eeprom_read, exchook_eeprom_read); + util_patch_function(patch_table->addr_eeprom_write, exchook_eeprom_write); + + log_info("Initizlied (%s), eeprom file %s", len == -1 ? "new" : "loaded", eeprom_file); +} + +static int32_t exchook_eeprom_read(uint8_t* buffer, int32_t len) +{ + if (len > sizeof(exchook_eeprom_buffer)) { + log_error("Eeprom read %d exceeds buffer size %d", len, + sizeof(exchook_eeprom_buffer)); + return 0; + } + + memcpy(buffer, exchook_eeprom_buffer, len); + + return len; +} + +static int32_t exchook_eeprom_write(const uint8_t* buffer, int32_t len) +{ + if (len > sizeof(exchook_eeprom_buffer)) { + log_error("Eeprom write %d exceeds buffer size %d", len, + sizeof(exchook_eeprom_buffer)); + return 0; + } + + memcpy(exchook_eeprom_buffer, buffer, len); + + /* Write back to file */ + if (!util_file_save(exchook_eeprom_file, exchook_eeprom_buffer, len)) { + log_error("Storing eeprom contents to file %s failed", + exchook_eeprom_file); + } + + return len; +} \ No newline at end of file diff --git a/src/main/hook/exc/eeprom.h b/src/main/hook/exc/eeprom.h new file mode 100644 index 0000000..e7f0955 --- /dev/null +++ b/src/main/hook/exc/eeprom.h @@ -0,0 +1,19 @@ +/** + * Patch module emulating the MK5 (hardware) eeprom chip used to store + * game settings to on Exceed + */ +#ifndef EXCHOOK_EEPROM_H +#define EXCHOOK_EEPROM_H + +#include "hook/exc/mempatch.h" + +/** + * Init eeprom emulation for exceed + * + * @param patch_table Patch table with memory addresses + * @param eeprom_file Path to existing eeprom file to read from and new eeprom + * file to store to + */ +void exchook_eeprom_init(const struct exchook_mempatch_table* patch_table, const char* eeprom_file); + +#endif \ No newline at end of file diff --git a/src/main/hook/exc/io.c b/src/main/hook/exc/io.c new file mode 100644 index 0000000..e0b1a4a --- /dev/null +++ b/src/main/hook/exc/io.c @@ -0,0 +1,505 @@ +#define LOG_MODULE "exchook-io" + +#include + +#include "ptapi/io/piuio.h" +#include "ptapi/io/piuio/util/lib.h" + +#include "hook/exc/mempatch.h" + +#include "util/log.h" +#include "util/patch.h" + +/* Taken from ioarcade.hpp nx2 src dump */ +#define GI_P1_1 0x00000001 +#define GI_P1_3 0x00000002 +#define GI_P1_5 0x00000004 +#define GI_P1_7 0x00000008 +#define GI_P1_9 0x00000010 + +#define GI_P2_1 0x00000100 +#define GI_P2_3 0x00000200 +#define GI_P2_5 0x00000400 +#define GI_P2_7 0x00000800 +#define GI_P2_9 0x00001000 + +#define GI_TEST 0x00010000 +#define GI_SERVICE 0x00020000 +#define GI_CLEAR 0x00040000 + +#define GI_COIN 0x00100000 +#define GI_COIN2 0x00200000 + +struct exchook_io_sensores { + uint32_t lu : 4; + uint32_t ru : 4; + uint32_t cn : 4; + uint32_t ld : 4; + uint32_t rd : 4; + uint32_t padding : 12; +}; + +static const uint8_t exchook_io_sensor_mappings[] = { + 1, 2, 3, 0 +}; + +static struct ptapi_io_piuio_api exchook_piuio_api; + +static uint16_t exchook_io_check(void* obj); +static int32_t exchook_io_light_all(void* obj, uint8_t on); +static int32_t exchook_io_light_neon(void* obj, uint8_t on); +static int32_t exchook_io_light_halogan(void* obj, uint8_t on, uint16_t light_id); +static int32_t exchook_io_light_p1_ccfl(void* obj, uint8_t on, uint16_t cmd); +static int32_t exchook_io_light_p2_ccfl(void* obj, uint8_t on, uint16_t cmd); +static int32_t exchook_io_input(void* obj); +static int32_t exchook_io_coin_input(void* obj); +static int32_t exchook_io_coin_input_2(void* obj); +static int32_t exchook_io_coin_counter_2(void* obj); + +static uint32_t* exchook_io_game_input_stat; +static uint32_t* exchook_io_game_input_down; +static uint32_t* exchook_io_game_input_up; + +static uint32_t exchook_io_game_input_stat_prev; + +static struct exchook_io_sensores exchook_io_sensores_p1; +static struct exchook_io_sensores exchook_io_sensores_p2; +static struct ptapi_io_piuio_pad_outputs exchook_io_out_pad_p1; +static struct ptapi_io_piuio_pad_outputs exchook_io_out_pad_p2; +static struct ptapi_io_piuio_pad_outputs exchook_io_out_pad_press_p1; +static struct ptapi_io_piuio_pad_outputs exchook_io_out_pad_press_p2; +static struct ptapi_io_piuio_cab_outputs exchook_io_out_cab; + +static bool exchook_io_exit_on_service_test; + +void exchook_io_init(const struct exchook_mempatch_table* patch_table, const char* piuio_lib_path, + bool exit_on_service_test) +{ + if (!piuio_lib_path) { + log_error("NULL piuio (emu) lib path. Check that you have set-up and configured a piuio API implementation " + "correctly."); + return; + } + + /* Load piuio library funcs */ + log_info("Loading piuio api implementation %s", piuio_lib_path); + + if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &exchook_piuio_api)) { + log_error("Loading piuio API from file %s failed", piuio_lib_path); + return; + } + + exchook_io_exit_on_service_test = exit_on_service_test; + + log_info("Service + Test exit %d", exchook_io_exit_on_service_test); + + /* Hook MK5IO engine calls */ + /* Why so many functions you might ask? Because the MK5 IO code is a pile + of shit created by a monkey */ + + util_patch_function(patch_table->addr_io_check, exchook_io_check); + util_patch_function(patch_table->addr_io_light_all, exchook_io_light_all); + util_patch_function(patch_table->addr_io_light_neon, exchook_io_light_neon); + util_patch_function(patch_table->addr_io_light_halogan, exchook_io_light_halogan); + util_patch_function(patch_table->addr_io_light_p1_ccfl, exchook_io_light_p1_ccfl); + util_patch_function(patch_table->addr_io_light_p2_ccfl, exchook_io_light_p2_ccfl); + util_patch_function(patch_table->addr_io_input, exchook_io_input); + util_patch_function(patch_table->addr_io_coin_input, exchook_io_coin_input); + util_patch_function(patch_table->addr_io_coin_input_2, exchook_io_coin_input_2); + util_patch_function(patch_table->addr_io_coin_counter_2, exchook_io_coin_counter_2); + + exchook_io_game_input_stat = ((uint32_t*) patch_table->addr_io_game_input_stat); + exchook_io_game_input_down = ((uint32_t*) patch_table->addr_io_game_input_down); + exchook_io_game_input_up = ((uint32_t*) patch_table->addr_io_game_input_up); + + /* there is an io init method but obviously requires another address to be + hooked...just init our backend here */ + if (!exchook_piuio_api.open()) { + log_error("Opening io failed"); + return; + } + + log_info("Initialized"); +} + +void exchook_io_shutdown(void) +{ + +} + +/* check? why can't you just call it get_fucking_inputs... */ +static uint16_t exchook_io_check(void* obj) +{ + struct ptapi_io_piuio_pad_inputs p1_pad_in; + struct ptapi_io_piuio_pad_inputs p2_pad_in; + + /* Sensor states are expected to be returned using the object */ + struct exchook_io_sensores* sensores_p1 = + (struct exchook_io_sensores*) obj; + struct exchook_io_sensores* sensores_p2 = + (struct exchook_io_sensores*) (((uint32_t*) obj) + 1); + + /* execute polling here */ + + /* might delay output for a frame but whatever */ + if (!exchook_piuio_api.send()) { + log_error("Piuio send failed"); + } + + if (!exchook_piuio_api.recv()) { + log_error("Piuio receive failed"); + } + + /* MK5 inputs state reset */ + exchook_io_sensores_p1.lu = 0; + exchook_io_sensores_p1.ru = 0; + exchook_io_sensores_p1.cn = 0; + exchook_io_sensores_p1.ld = 0; + exchook_io_sensores_p1.rd = 0; + + exchook_io_sensores_p2.lu = 0; + exchook_io_sensores_p2.ru = 0; + exchook_io_sensores_p2.cn = 0; + exchook_io_sensores_p2.ld = 0; + exchook_io_sensores_p2.rd = 0; + + // State reset + memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs)); + memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs)); + + /* cycle all sensores */ + for (uint8_t i = 0; i < 4; i++) { + exchook_piuio_api.get_input_pad(0, i, &p1_pad_in); + exchook_piuio_api.get_input_pad(1, i, &p2_pad_in); + + /* process inputs */ + + /* Player 1 */ + if (p1_pad_in.lu) { + exchook_io_sensores_p1.lu |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p1_pad_in.ru) { + exchook_io_sensores_p1.ru |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p1_pad_in.cn) { + exchook_io_sensores_p1.cn |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p1_pad_in.ld) { + exchook_io_sensores_p1.ld |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p1_pad_in.rd) { + exchook_io_sensores_p1.rd |= (1 << exchook_io_sensor_mappings[i]); + } + + /* Player 2 */ + if (p2_pad_in.lu) { + exchook_io_sensores_p2.lu |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p2_pad_in.ru) { + exchook_io_sensores_p2.ru |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p2_pad_in.cn) { + exchook_io_sensores_p2.cn |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p2_pad_in.ld) { + exchook_io_sensores_p2.ld |= (1 << exchook_io_sensor_mappings[i]); + } + + if (p2_pad_in.rd) { + exchook_io_sensores_p2.rd |= (1 << exchook_io_sensor_mappings[i]); + } + } + + memcpy(sensores_p1, &exchook_io_sensores_p1, sizeof(exchook_io_sensores_p1)); + memcpy(sensores_p2, &exchook_io_sensores_p2, sizeof(exchook_io_sensores_p2)); + + return 0; +} + +static int32_t exchook_io_light_all(void* obj, uint8_t on) +{ + if (on) { + memset(&exchook_io_out_pad_p1, 1, sizeof(exchook_io_out_pad_p1)); + memset(&exchook_io_out_pad_p2, 1, sizeof(exchook_io_out_pad_p2)); + memset(&exchook_io_out_cab, 1, sizeof(exchook_io_out_cab)); + } else { + memset(&exchook_io_out_pad_p1, 0, sizeof(exchook_io_out_pad_p1)); + memset(&exchook_io_out_pad_p2, 0, sizeof(exchook_io_out_pad_p2)); + memset(&exchook_io_out_cab, 0, sizeof(exchook_io_out_cab)); + } + + exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_p1); + exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_p2); + exchook_piuio_api.set_output_cab(&exchook_io_out_cab); + + return 0; +} + +static int32_t exchook_io_light_neon(void* obj, uint8_t on) +{ + if (on) { + exchook_io_out_cab.bass = true; + } else { + exchook_io_out_cab.bass = false; + } + + exchook_piuio_api.set_output_cab(&exchook_io_out_cab); + + return 0; +} + +static int32_t exchook_io_light_halogan(void* obj, uint8_t on, uint16_t light_id) +{ + if (light_id & 0x0400) { + exchook_io_out_cab.halo_l1 = on; + } + + if (light_id & 0x0200) { + exchook_io_out_cab.halo_l2 = on; + } + + if (light_id & 0x0100) { + exchook_io_out_cab.halo_r1 = on; + } + + if (light_id & 0x0080) { + exchook_io_out_cab.halo_r2 = on; + } + + exchook_piuio_api.set_output_cab(&exchook_io_out_cab); + + return 0; +} + +static int32_t exchook_io_light_p1_ccfl(void* obj, uint8_t on, uint16_t cmd) +{ + if (cmd & 0x0004) { + exchook_io_out_pad_p1.lu = on; + } + + if (cmd & 0x0008) { + exchook_io_out_pad_p1.ru = on; + } + + if (cmd & 0x0010) { + exchook_io_out_pad_p1.cn = on; + } + + if (cmd & 0x0020) { + exchook_io_out_pad_p1.ld = on; + } + + if (cmd & 0x040) { + exchook_io_out_pad_p1.rd = on; + } + + return 0; +} + +static int32_t exchook_io_light_p2_ccfl(void* obj, uint8_t on, uint16_t cmd) +{ + if (cmd & 0x0004) { + exchook_io_out_pad_p2.lu = on; + } + + if (cmd & 0x0008) { + exchook_io_out_pad_p2.ru = on; + } + + if (cmd & 0x0010) { + exchook_io_out_pad_p2.cn = on; + } + + if (cmd & 0x0020) { + exchook_io_out_pad_p2.ld = on; + } + + if (cmd & 0x040) { + exchook_io_out_pad_p2.rd = on; + } + + return 0; +} + +static int32_t exchook_io_input(void* obj) +{ + uint32_t stat; + uint32_t stat_down; + uint32_t stat_up; + + struct ptapi_io_piuio_sys_inputs sys_in; + + memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs)); + + exchook_piuio_api.get_input_sys(&sys_in); + + /* For game loaders and stuff */ + if (exchook_io_exit_on_service_test) { + if (sys_in.test && sys_in.service) { + log_info("Exit on service + test enabled and hit, bye"); + exit(0); + } + } + + /* process final input states for the game as well as service, test, clear + and coin which can't be handled in the check function */ + + stat = 0; + stat_down = 0; + stat_up = 0; + + /* Player 1 */ + if (exchook_io_sensores_p1.lu) { + stat |= GI_P1_7; + } + + if (exchook_io_sensores_p1.ru) { + stat |= GI_P1_9; + } + + if (exchook_io_sensores_p1.cn) { + stat |= GI_P1_5; + } + + if (exchook_io_sensores_p1.ld) { + stat |= GI_P1_1; + } + + if (exchook_io_sensores_p1.rd) { + stat |= GI_P1_3; + } + + /* Player 2 */ + if (exchook_io_sensores_p2.lu) { + stat |= GI_P2_7; + } + + if (exchook_io_sensores_p2.ru) { + stat |= GI_P2_9; + } + + if (exchook_io_sensores_p2.cn) { + stat |= GI_P2_5; + } + + if (exchook_io_sensores_p2.ld) { + stat |= GI_P2_1; + } + + if (exchook_io_sensores_p2.rd) { + stat |= GI_P2_3; + } + + /* Sys */ + if (sys_in.test) { + stat |= GI_TEST; + } + + if (sys_in.service) { + stat |= GI_SERVICE; + } + + /* Taken from source but doesn't seem to work (on some versions?) */ + if (sys_in.clear) { + stat |= GI_CLEAR; + } + + if (sys_in.coin) { + stat |= GI_COIN; + } + + if (sys_in.coin2) { + stat |= GI_COIN2; + } + + /* iterate bits for up and down events */ + for (uint8_t i = 0; i < 32; i++) { + + if (!(exchook_io_game_input_stat_prev & (1 << i)) && + (stat & (1 << i))) { + /* New push down */ + stat_down |= (1 << i); + } else if ((exchook_io_game_input_stat_prev & (1 << i)) && + !(stat & (1 << i))) { + /* New release */ + stat_up |= (1 << i); + } + } + + /* Extremely bad IO subsystem design */ + *exchook_io_game_input_stat |= stat; + *exchook_io_game_input_down |= stat_down; + *exchook_io_game_input_up = stat_up; + + /* swap for next iterateion */ + exchook_io_game_input_stat_prev = *exchook_io_game_input_stat; + + /* Welp, the game expects us to do output setting if a button is pressed + here...fuck that mess. Merge (i.e. |= not =) with other states set + by the game */ + + memset(&exchook_io_out_pad_press_p1, 0, sizeof(exchook_io_out_pad_press_p1)); + memset(&exchook_io_out_pad_press_p2, 0, sizeof(exchook_io_out_pad_press_p2)); + + /* Player 1 */ + exchook_io_out_pad_press_p1.lu |= exchook_io_sensores_p1.lu; + exchook_io_out_pad_press_p1.ru |= exchook_io_sensores_p1.ru; + exchook_io_out_pad_press_p1.cn |= exchook_io_sensores_p1.cn; + exchook_io_out_pad_press_p1.ld |= exchook_io_sensores_p1.ld; + exchook_io_out_pad_press_p1.rd |= exchook_io_sensores_p1.rd; + + /* Player 2 */ + exchook_io_out_pad_press_p2.lu |= exchook_io_sensores_p2.lu; + exchook_io_out_pad_press_p2.ru |= exchook_io_sensores_p2.ru; + exchook_io_out_pad_press_p2.cn |= exchook_io_sensores_p2.cn; + exchook_io_out_pad_press_p2.ld |= exchook_io_sensores_p2.ld; + exchook_io_out_pad_press_p2.rd |= exchook_io_sensores_p2.rd; + + /* merge */ + /* Player 1 */ + exchook_io_out_pad_press_p1.lu |= exchook_io_out_pad_p1.lu; + exchook_io_out_pad_press_p1.ru |= exchook_io_out_pad_p1.ru; + exchook_io_out_pad_press_p1.cn |= exchook_io_out_pad_p1.cn; + exchook_io_out_pad_press_p1.ld |= exchook_io_out_pad_p1.ld; + exchook_io_out_pad_press_p1.rd |= exchook_io_out_pad_p1.rd; + + /* Player 2 */ + exchook_io_out_pad_press_p2.lu |= exchook_io_out_pad_p2.lu; + exchook_io_out_pad_press_p2.ru |= exchook_io_out_pad_p2.ru; + exchook_io_out_pad_press_p2.cn |= exchook_io_out_pad_p2.cn; + exchook_io_out_pad_press_p2.ld |= exchook_io_out_pad_p2.ld; + exchook_io_out_pad_press_p2.rd |= exchook_io_out_pad_p2.rd; + + exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_press_p1); + exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_press_p2); + + return 0; +} + +static int32_t exchook_io_coin_input(void* obj) +{ + /* Stub */ + + return 0; +} + +static int32_t exchook_io_coin_input_2(void* obj) +{ + /* Stub */ + + return 0; +} + +static int32_t exchook_io_coin_counter_2(void* obj) +{ + /* Stub */ + + return 0; +} \ No newline at end of file diff --git a/src/main/hook/exc/io.h b/src/main/hook/exc/io.h new file mode 100644 index 0000000..248986f --- /dev/null +++ b/src/main/hook/exc/io.h @@ -0,0 +1,26 @@ +/** + * Patch module hooking the MK5IO engine code of exceed to inject our own + * IO code to run the game on newer versions of the piuio as well as custom + * IO devices + */ +#ifndef EXCHOOK_IO_H +#define EXCHOOK_IO_H + +#include "hook/exc/mempatch.h" + +/** + * Initialize MK5IO emulation for exceed + * + * @param patch_table Patch table with memory addresses + * @param piuio_lib_path Path to piuio lib to use for emulation + * @parma exit_on_service_test Exit the game when pressing service + test + */ +void exchook_io_init(const struct exchook_mempatch_table* patch_table, const char* piuio_lib_path, + bool exit_on_service_test); + +/** + * Shut down io emulation + */ +void exchook_io_shutdown(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/exc/lockchip.c b/src/main/hook/exc/lockchip.c new file mode 100644 index 0000000..9c5b844 --- /dev/null +++ b/src/main/hook/exc/lockchip.c @@ -0,0 +1,43 @@ +#define LOG_MODULE "exchook-lockchip" + +#include + +#include "sec/lockchip/lockchip.h" +#include "sec/lockchip/lockchip-defs.h" + +#include "util/log.h" +#include "util/patch.h" + +#include "lockchip.h" + +static void exchook_lockchip_dec_chunk(uint8_t len, const uint8_t* src, + uint8_t* dest); + +void exchook_lockchip_init(const struct exchook_mempatch_table* patch_table) +{ + sec_lockchip_init( + sec_lockchip_defs_transforms[SEC_LOCK_CHIP_DEFS_GAME_EXCEED]); + + /* Hook lockchip */ + util_patch_function(patch_table->addr_lockchip_dec_chunk, exchook_lockchip_dec_chunk); + + log_info("Initialized"); +} + +static void exchook_lockchip_dec_chunk(uint8_t len, const uint8_t* src, + uint8_t* dest) +{ + sec_lockchip_start(); + + uint8_t last_res = sec_lockchip_step(src[0] ^ 0xFF); + + for (size_t i = 1; i < len; i++) + { + uint8_t result = sec_lockchip_step(src[i] ^ 0xFF); + dest[i - 1] = (uint8_t)((last_res >> 3) ^ (result << 5)); + last_res = result; + } + + uint8_t last_byte = sec_lockchip_step(0); + dest[len - 1] = (uint8_t)((last_res >> 3) ^ (last_byte << 5)); +} \ No newline at end of file diff --git a/src/main/hook/exc/lockchip.h b/src/main/hook/exc/lockchip.h new file mode 100644 index 0000000..0721981 --- /dev/null +++ b/src/main/hook/exc/lockchip.h @@ -0,0 +1,19 @@ +/** + * Patch module hooking lockchip calls to a lockchip emulator to decrypt + * game assets and run the game + */ +#ifndef EXCHOOK_LOCKCHIP_H +#define EXCHOOK_LOCKCHIP_H + +#include + +#include "hook/exc/mempatch.h" + +/** + * Initialize lockchip emulation for exceed + * + * @param patch_table Patch table with memory addresses + */ +void exchook_lockchip_init(const struct exchook_mempatch_table* patch_table); + +#endif \ No newline at end of file diff --git a/src/main/hook/exc/main.c b/src/main/hook/exc/main.c new file mode 100644 index 0000000..54bd09d --- /dev/null +++ b/src/main/hook/exc/main.c @@ -0,0 +1,256 @@ +/** + * Hook library for Pump It Up: Exceed + */ +#define LOG_MODULE "exchook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/asound-fix.h" +#include "hook/patch/gfx.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/patch.h" +#include "util/str.h" +#include "util/sys-info.h" + +#include "eeprom.h" +#include "io.h" +#include "lockchip.h" +#include "mempatch.h" +#include "options.h" + +static void exchook_bootstrapping(int argc, char** argv, struct exchook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!exchook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void exchook_game_version_mempatch_table_init( + struct exchook_options* options, + const struct exchook_mempatch_table** patch_table) +{ + log_assert(options); + log_assert(patch_table); + + if (!options->game.version) { + log_die("No game version specified"); + } else { + log_info("Game version configured: %s", options->game.version); + } + + *patch_table = exchook_mempatch_get_table(options->game.version); + + if (*patch_table == NULL) { + log_die("Unsupported game version %s", options->game.version); + } +} + +static void exchook_patch_fs_init(struct exchook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void exchook_fs_redir_settings(struct exchook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void exchook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); +} + +static void exchook_patch_gfx_init(struct exchook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void exchook_patch_main_loop_init(struct exchook_options* options) +{ + log_assert(options); + + patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void exchook_patch_sound_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table) +{ + log_assert(options); + log_assert(patch_table); + + /* exceed crashes with its default device hw:0. use dmix instead */ + if (strcmp(options->patch.sound.device, "dmix") != 0) { + log_warn("Game might crash with selected sound device %s, use 'dmix' instead if that happens", + options->patch.sound.device); + } + + patch_sound_init(options->patch.sound.device); + patch_asound_fix_init(); + + /* return from StopAllEffects to avoid killing the sound thread */ + util_patch_write_memory_byte(patch_table->addr_stop_all_effects_return, 0xC3); +} + +static void exchook_patch_sigsegv_init(struct exchook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void exchook_patch_lockchip_init(const struct exchook_mempatch_table* patch_table) +{ + log_assert(patch_table); + + exchook_lockchip_init(patch_table); +} + +static void exchook_patch_eeprom_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table) +{ + log_assert(options); + log_assert(patch_table); + + char* eeprom_path; + + if (options->game.settings) { + char* abs_path = util_fs_get_abs_path(options->game.settings); + + eeprom_path = util_str_merge(abs_path, "/eeprom.bin"); + free(abs_path); + } else { + eeprom_path = util_str_dup("/tmp/eeprom.bin"); + log_warn("No settings path specified to store eeprom data, defaulting to %s", eeprom_path); + } + + exchook_eeprom_init(patch_table, eeprom_path); + free(eeprom_path); +} + +static void exchook_patch_piuio_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table) +{ + log_assert(options); + log_assert(patch_table); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + exchook_io_init(patch_table, abs_path_iolib, options->patch.piuio.exit_test_serv); + free(abs_path_iolib); + } +} + +void exchook_constructor(void) +{ + /* Nothing here */ +} + +void exchook_destructor(void) +{ + /* Nothing here */ +} + +void exchook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct exchook_options options; + const struct exchook_mempatch_table* mempatch_table; + + exchook_bootstrapping(argc, argv, &options, &game_data_path); + exchook_game_version_mempatch_table_init(&options, &mempatch_table); + exchook_patch_fs_init(&options); + exchook_fs_redir_settings(&options); + exchook_fs_redir_usb(); + exchook_patch_gfx_init(&options); + exchook_patch_main_loop_init(&options); + exchook_patch_sound_init(&options, mempatch_table); + exchook_patch_sigsegv_init(&options); + exchook_patch_lockchip_init(mempatch_table); + exchook_patch_eeprom_init(&options, mempatch_table); + exchook_patch_piuio_init(&options, mempatch_table); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void exchook_trap_after_main(void) +{ + exchook_io_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(exchook_constructor); +LIB_MAIN_DESTRUCTOR(exchook_destructor); +LIB_MAIN_TRAP_MAIN(exchook_trap_before_main, exchook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/exc/mempatch.c b/src/main/hook/exc/mempatch.c new file mode 100644 index 0000000..4f10f2f --- /dev/null +++ b/src/main/hook/exc/mempatch.c @@ -0,0 +1,62 @@ +#include +#include + +#include "hook/exc/mempatch.h" + +#include "util/defs.h" + +static const struct exchook_mempatch_table _exchook_mempatch_table[] = { + { + .version = "20040325", + .addr_eeprom_read = 0x080716E0, + .addr_eeprom_write = 0x08071620, + .addr_io_check = 0x0806DEB0, + .addr_io_light_all = 0x0806E5A0, + .addr_io_light_neon = 0x0806E600, + .addr_io_light_halogan = 0x0806E630, + .addr_io_light_p1_ccfl = 0x0806E660, + .addr_io_light_p2_ccfl = 0x0806E690, + .addr_io_input = 0x0806E6C0, + .addr_io_coin_input = 0x0806EE20, + .addr_io_coin_input_2 = 0x0806EEE0, + .addr_io_coin_counter_2 = 0x0806EFA0, + .addr_io_game_input_stat = 0x080B9410, + .addr_io_game_input_down = 0x080B9408, + .addr_io_game_input_up = 0x080B940C, + .addr_lockchip_dec_chunk = 0x08071E80, + .addr_stop_all_effects_return = 0x0806F6E0, + }, + { + .version = "20040408", + .addr_eeprom_read = 0x08071CC0, + .addr_eeprom_write = 0x08071C00, + .addr_io_check = 0x0806E550, + .addr_io_light_all = 0x0806EC40, + .addr_io_light_neon = 0x0806ECA0, + .addr_io_light_halogan = 0x0806ECD0, + .addr_io_light_p1_ccfl = 0x0806ED00, + .addr_io_light_p2_ccfl = 0x0806ED30, + .addr_io_input = 0x0806ED60, + .addr_io_coin_input = 0x0806F4C0, + .addr_io_coin_input_2 = 0x0806F580, + .addr_io_coin_counter_2 = 0x0806F640, + .addr_io_game_input_stat = 0x080B5290, + .addr_io_game_input_down = 0x080B5288, + .addr_io_game_input_up = 0x080B528C, + .addr_lockchip_dec_chunk = 0x08072460, + .addr_stop_all_effects_return = 0x0806FD80, + }, +}; + +const struct exchook_mempatch_table* exchook_mempatch_get_table(const char* version) +{ + size_t entries = lengthof(_exchook_mempatch_table); + + for (uint32_t i = 0; i < entries; i++) { + if (!strcmp(_exchook_mempatch_table[i].version, version)) { + return &_exchook_mempatch_table[i]; + } + } + + return NULL; +} \ No newline at end of file diff --git a/src/main/hook/exc/mempatch.h b/src/main/hook/exc/mempatch.h new file mode 100644 index 0000000..5926952 --- /dev/null +++ b/src/main/hook/exc/mempatch.h @@ -0,0 +1,29 @@ +#ifndef EXCHOOK_MEMPATCH_H +#define EXCHOOK_MEMPATCH_H + +#include + +struct exchook_mempatch_table { + const char* version; + uintptr_t addr_eeprom_read; + uintptr_t addr_eeprom_write; + uintptr_t addr_io_check; + uintptr_t addr_io_light_all; + uintptr_t addr_io_light_neon; + uintptr_t addr_io_light_halogan; + uintptr_t addr_io_light_p1_ccfl; + uintptr_t addr_io_light_p2_ccfl; + uintptr_t addr_io_input; + uintptr_t addr_io_coin_input; + uintptr_t addr_io_coin_input_2; + uintptr_t addr_io_coin_counter_2; + uintptr_t addr_io_game_input_stat; + uintptr_t addr_io_game_input_down; + uintptr_t addr_io_game_input_up; + uintptr_t addr_lockchip_dec_chunk; + uintptr_t addr_stop_all_effects_return; +}; + +const struct exchook_mempatch_table* exchook_mempatch_get_table(const char* version); + +#endif \ No newline at end of file diff --git a/src/main/hook/exc/options.c b/src/main/hook/exc/options.c new file mode 100644 index 0000000..e25cbdd --- /dev/null +++ b/src/main/hook/exc/options.c @@ -0,0 +1,184 @@ +#include "hook/exc/options.h" + +#include "util/options.h" + +#define EXCHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define EXCHOOK_OPTIONS_STR_GAME_VERSION "game.version" +#define EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +static const struct util_options_def exchook_options_def[] = { + { + .name = EXCHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = EXCHOOK_OPTIONS_STR_GAME_VERSION, + .description = "Version of the game (format YYYYMMDD). Make sure this matches exactly the version you are" + " running because the hook lib has to apply memory patches.", + .param = 'v', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "20040408", + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +static const struct util_options_defs exchook_options_defs = { + .usage_header = + "Pumptools exchook for Pump It Up: Exceed, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./exchook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = exchook_options_def, + .ndefs = lengthof(exchook_options_def) +}; + +bool exchook_options_init(int argc, char** argv, struct exchook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&exchook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_SETTINGS); + options->game.version = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_VERSION); + options->patch.gfx.windowed = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.piuio.api_lib = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/exc/options.h b/src/main/hook/exc/options.h new file mode 100644 index 0000000..c16ead8 --- /dev/null +++ b/src/main/hook/exc/options.h @@ -0,0 +1,55 @@ +#ifndef EXCHOOK_OPTIONS_H +#define EXCHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct exchook_options { + struct game { + const char* settings; + const char* version; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool exchook_options_init(int argc, char** argv, struct exchook_options* options); + +#endif diff --git a/src/main/hook/f2/f2hook.hasp.key b/src/main/hook/f2/f2hook.hasp.key new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/f2/f2hook.hasp.key @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/f2/f2hook.hdd.raw b/src/main/hook/f2/f2hook.hdd.raw new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/f2/f2hook.hdd.raw @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/f2/main.c b/src/main/hook/f2/main.c new file mode 100644 index 0000000..ed144c8 --- /dev/null +++ b/src/main/hook/f2/main.c @@ -0,0 +1,244 @@ +/** + * Hook library for Pump It Up: Fiesta 2 + */ +#define LOG_MODULE "f2hook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/amixer-block.h" +#include "hook/patch/gfx.h" +#include "hook/patch/hasp.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/mounts.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/usb-mnt.h" +#include "hook/patch/usbfs.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/sys-info.h" + +#include "options.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_f2hook_hdd_raw_start[]; +extern const uint8_t _binary_f2hook_hdd_raw_end[]; +extern const uint8_t _binary_f2hook_hasp_key_start[]; +extern const uint8_t _binary_f2hook_hasp_key_end[]; + +static void f2hook_bootstrapping(int argc, char** argv, struct f2hook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!f2hook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + hook_core_piu_utils_fix_locale(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void f2hook_patch_fs_init(struct f2hook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void f2hook_fs_redir_settings(struct f2hook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void f2hook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); + patch_usbfs_init(); +} + +static void f2hook_fs_redirs_init(struct f2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + f2hook_fs_redir_settings(options); + + f2hook_fs_redir_usb(); +} + +static void f2hook_patch_fs_mounting_init() +{ + patch_mounts_init(); + + patch_usb_mnt_init(); +} + +static void f2hook_patch_gfx_init(struct f2hook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void f2hook_patch_main_loop_init(struct f2hook_options* options) +{ + log_assert(options); + + patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void f2hook_patch_sound_init(struct f2hook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); + patch_axmier_block_init(); +} + +static void f2hook_patch_sigsegv_init(struct f2hook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void f2hook_patch_dongle_init() +{ + patch_hasp_init((const uint8_t*) _binary_f2hook_hasp_key_start, + ((uintptr_t) &_binary_f2hook_hasp_key_end - (uintptr_t) &_binary_f2hook_hasp_key_start)); +} + +static void f2hook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_f2hook_hdd_raw_start, + ((uintptr_t) &_binary_f2hook_hdd_raw_end - (uintptr_t) &_binary_f2hook_hdd_raw_start)); +} + +static void f2hook_patch_piuio_init(struct f2hook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +void f2hook_constructor(void) +{ + /* Nothing here */ +} + +void f2hook_destructor(void) +{ + /* Nothing here */ +} + +void f2hook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct f2hook_options options; + + f2hook_bootstrapping(argc, argv, &options, &game_data_path); + f2hook_patch_fs_init(&options); + f2hook_fs_redirs_init(&options, game_data_path); + f2hook_patch_fs_mounting_init(); + f2hook_patch_gfx_init(&options); + f2hook_patch_main_loop_init(&options); + f2hook_patch_sound_init(&options); + f2hook_patch_sigsegv_init(&options); + f2hook_patch_dongle_init(); + f2hook_patch_hdd_check_init(); + f2hook_patch_piuio_init(&options); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void f2hook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(f2hook_constructor); +LIB_MAIN_DESTRUCTOR(f2hook_destructor); +LIB_MAIN_TRAP_MAIN(f2hook_trap_before_main, f2hook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/f2/options.c b/src/main/hook/f2/options.c new file mode 100644 index 0000000..0e9995c --- /dev/null +++ b/src/main/hook/f2/options.c @@ -0,0 +1,195 @@ +#include "hook/f2/options.h" + +#include "util/options.h" + +#define F2HOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server" +#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id" +#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def f2hook_options_def[] = { + { + .name = F2HOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER, + .description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)", + .param = 'n', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID, + .description = "Machine id for pumpnet", + .param = 'm', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "0", + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs f2hook_options_defs = { + .usage_header = + "Pumptools f2hook for Pump It Up: Fiesta 2, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./f2hook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = f2hook_options_def, + .ndefs = lengthof(f2hook_options_def) +}; + +bool f2hook_options_init(int argc, char** argv, struct f2hook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&f2hook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.net.server = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER); + options->patch.net.machine_id = strtoul( + util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID), + NULL, + 16); + options->patch.piuio.api_lib = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/f2/options.h b/src/main/hook/f2/options.h new file mode 100644 index 0000000..65c03d9 --- /dev/null +++ b/src/main/hook/f2/options.h @@ -0,0 +1,59 @@ +#ifndef F2HOOK_OPTIONS_H +#define F2HOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct f2hook_options { + struct game { + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct net { + const char* server; + uint32_t machine_id; + } net; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool f2hook_options_init(int argc, char** argv, struct f2hook_options* options); + +#endif diff --git a/src/main/hook/fex/fexhook.dog.key b/src/main/hook/fex/fexhook.dog.key new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/fex/fexhook.dog.key @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/fex/fexhook.hdd.raw b/src/main/hook/fex/fexhook.hdd.raw new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/fex/fexhook.hdd.raw @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/fex/main.c b/src/main/hook/fex/main.c new file mode 100644 index 0000000..25cde24 --- /dev/null +++ b/src/main/hook/fex/main.c @@ -0,0 +1,242 @@ +/** + * Hook library for Pump It Up: FiestaEX + */ +#define LOG_MODULE "fexhook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/amixer-block.h" +#include "hook/patch/gfx.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog40.h" +#include "hook/patch/mounts.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/usb-mnt.h" +#include "hook/patch/usbfs.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/sys-info.h" + +#include "options.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_fexhook_hdd_raw_start[]; +extern const uint8_t _binary_fexhook_hdd_raw_end[]; +extern const uint8_t _binary_fexhook_dog_key_start[]; +extern const uint8_t _binary_fexhook_dog_key_end[]; + +static void fexhook_bootstrapping(int argc, char** argv, struct fexhook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!fexhook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void fexhook_patch_fs_init(struct fexhook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void fexhook_fs_redir_settings(struct fexhook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void fexhook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); + patch_usbfs_init(); +} + +static void fexhook_fs_redirs_init(struct fexhook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + fexhook_fs_redir_settings(options); + + fexhook_fs_redir_usb(); +} + +static void fexhook_patch_fs_mounting_init() +{ + patch_mounts_init(); + + patch_usb_mnt_init(); +} + +static void fexhook_patch_gfx_init(struct fexhook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void fexhook_patch_main_loop_init(struct fexhook_options* options) +{ + log_assert(options); + + patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void fexhook_patch_sound_init(struct fexhook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); + patch_axmier_block_init(); +} + +static void fexhook_patch_sigsegv_init(struct fexhook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void fexhook_patch_dongle_init() +{ + patch_microdog40_init((const uint8_t*) _binary_fexhook_dog_key_start, + ((uintptr_t) &_binary_fexhook_dog_key_end - (uintptr_t) &_binary_fexhook_dog_key_start)); +} + +static void fexhook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_fexhook_hdd_raw_start, + ((uintptr_t) &_binary_fexhook_hdd_raw_end - (uintptr_t) &_binary_fexhook_hdd_raw_start)); +} + +static void fexhook_patch_piuio_init(struct fexhook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +void fexhook_constructor(void) +{ + /* Nothing here */ +} + +void fexhook_destructor(void) +{ + /* Nothing here */ +} + +void fexhook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct fexhook_options options; + + fexhook_bootstrapping(argc, argv, &options, &game_data_path); + fexhook_patch_fs_init(&options); + fexhook_fs_redirs_init(&options, game_data_path); + fexhook_patch_fs_mounting_init(); + fexhook_patch_gfx_init(&options); + fexhook_patch_main_loop_init(&options); + fexhook_patch_sound_init(&options); + fexhook_patch_sigsegv_init(&options); + fexhook_patch_dongle_init(); + fexhook_patch_hdd_check_init(); + fexhook_patch_piuio_init(&options); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void fexhook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(fexhook_constructor); +LIB_MAIN_DESTRUCTOR(fexhook_destructor); +LIB_MAIN_TRAP_MAIN(fexhook_trap_before_main, fexhook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/fex/options.c b/src/main/hook/fex/options.c new file mode 100644 index 0000000..525b8e1 --- /dev/null +++ b/src/main/hook/fex/options.c @@ -0,0 +1,195 @@ +#include "hook/fex/options.h" + +#include "util/options.h" + +#define FEXHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server" +#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id" +#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def fexhook_options_def[] = { + { + .name = FEXHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER, + .description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)", + .param = 'n', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID, + .description = "Machine id for pumpnet", + .param = 'm', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "0", + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs fexhook_options_defs = { + .usage_header = + "Pumptools fexhook for Pump It Up: FiestaEX, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./fexhook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = fexhook_options_def, + .ndefs = lengthof(fexhook_options_def) +}; + +bool fexhook_options_init(int argc, char** argv, struct fexhook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&fexhook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.net.server = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER); + options->patch.net.machine_id = strtoul( + util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID), + NULL, + 16); + options->patch.piuio.api_lib = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/fex/options.h b/src/main/hook/fex/options.h new file mode 100644 index 0000000..1d97a29 --- /dev/null +++ b/src/main/hook/fex/options.h @@ -0,0 +1,59 @@ +#ifndef FEXHOOK_OPTIONS_H +#define FEXHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct fexhook_options { + struct game { + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct net { + const char* server; + uint32_t machine_id; + } net; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool fexhook_options_init(int argc, char** argv, struct fexhook_options* options); + +#endif diff --git a/src/main/hook/fst/fsthook.dog.key b/src/main/hook/fst/fsthook.dog.key new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/fst/fsthook.dog.key @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/fst/fsthook.hdd.raw b/src/main/hook/fst/fsthook.hdd.raw new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/fst/fsthook.hdd.raw @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/fst/main.c b/src/main/hook/fst/main.c new file mode 100644 index 0000000..389328c --- /dev/null +++ b/src/main/hook/fst/main.c @@ -0,0 +1,242 @@ +/** + * Hook library for Pump It Up: Fiesta + */ +#define LOG_MODULE "fsthook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/amixer-block.h" +#include "hook/patch/gfx.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog40.h" +#include "hook/patch/mounts.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/usb-mnt.h" +#include "hook/patch/usbfs.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/sys-info.h" + +#include "options.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_fsthook_hdd_raw_start[]; +extern const uint8_t _binary_fsthook_hdd_raw_end[]; +extern const uint8_t _binary_fsthook_dog_key_start[]; +extern const uint8_t _binary_fsthook_dog_key_end[]; + +static void fsthook_bootstrapping(int argc, char** argv, struct fsthook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!fsthook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void fsthook_patch_fs_init(struct fsthook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void fsthook_fs_redir_settings(struct fsthook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void fsthook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); + patch_usbfs_init(); +} + +static void fsthook_fs_redirs_init(struct fsthook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + fsthook_fs_redir_settings(options); + + fsthook_fs_redir_usb(); +} + +static void fsthook_patch_fs_mounting_init() +{ + patch_mounts_init(); + + patch_usb_mnt_init(); +} + +static void fsthook_patch_gfx_init(struct fsthook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void fsthook_patch_main_loop_init(struct fsthook_options* options) +{ + log_assert(options); + + patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void fsthook_patch_sound_init(struct fsthook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); + patch_axmier_block_init(); +} + +static void fsthook_patch_sigsegv_init(struct fsthook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void fsthook_patch_dongle_init() +{ + patch_microdog40_init((const uint8_t*) _binary_fsthook_dog_key_start, + ((uintptr_t) &_binary_fsthook_dog_key_end - (uintptr_t) &_binary_fsthook_dog_key_start)); +} + +static void fsthook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_fsthook_hdd_raw_start, + ((uintptr_t) &_binary_fsthook_hdd_raw_end - (uintptr_t) &_binary_fsthook_hdd_raw_start)); +} + +static void fsthook_patch_piuio_init(struct fsthook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +void fsthook_constructor(void) +{ + /* Nothing here */ +} + +void fsthook_destructor(void) +{ + /* Nothing here */ +} + +void fsthook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct fsthook_options options; + + fsthook_bootstrapping(argc, argv, &options, &game_data_path); + fsthook_patch_fs_init(&options); + fsthook_fs_redirs_init(&options, game_data_path); + fsthook_patch_fs_mounting_init(); + fsthook_patch_gfx_init(&options); + fsthook_patch_main_loop_init(&options); + fsthook_patch_sound_init(&options); + fsthook_patch_sigsegv_init(&options); + fsthook_patch_dongle_init(); + fsthook_patch_hdd_check_init(); + fsthook_patch_piuio_init(&options); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void fsthook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(fsthook_constructor); +LIB_MAIN_DESTRUCTOR(fsthook_destructor); +LIB_MAIN_TRAP_MAIN(fsthook_trap_before_main, fsthook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/fst/options.c b/src/main/hook/fst/options.c new file mode 100644 index 0000000..5343c73 --- /dev/null +++ b/src/main/hook/fst/options.c @@ -0,0 +1,195 @@ +#include "hook/fst/options.h" + +#include "util/options.h" + +#define FSTHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server" +#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id" +#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def fsthook_options_def[] = { + { + .name = FSTHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER, + .description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)", + .param = 'n', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID, + .description = "Machine id for pumpnet", + .param = 'm', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "0", + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs fsthook_options_defs = { + .usage_header = + "Pumptools fsthook for Pump It Up: Fiesta, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./fsthook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = fsthook_options_def, + .ndefs = lengthof(fsthook_options_def) +}; + +bool fsthook_options_init(int argc, char** argv, struct fsthook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&fsthook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.net.server = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER); + options->patch.net.machine_id = strtoul( + util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID), + NULL, + 16); + options->patch.piuio.api_lib = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/fst/options.h b/src/main/hook/fst/options.h new file mode 100644 index 0000000..c4bde17 --- /dev/null +++ b/src/main/hook/fst/options.h @@ -0,0 +1,59 @@ +#ifndef FSTHOOK_OPTIONS_H +#define FSTHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct fsthook_options { + struct game { + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct net { + const char* server; + uint32_t machine_id; + } net; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool fsthook_options_init(int argc, char** argv, struct fsthook_options* options); + +#endif diff --git a/src/main/hook/mk3/1st-2nd-fs-fix.c b/src/main/hook/mk3/1st-2nd-fs-fix.c new file mode 100644 index 0000000..4ac50fe --- /dev/null +++ b/src/main/hook/mk3/1st-2nd-fs-fix.c @@ -0,0 +1,41 @@ +#define LOG_MODULE "mk3hook-1st-2nd-fs-fix" + +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" +#include "util/str.h" + +typedef int (*cnh_fshook_chdir_t)(const char *path); +static cnh_fshook_chdir_t mk3hook_1st_2nd_fs_fix_real_chdir; + +static char* mk3hook_1st_2nd_fs_fix_path_game_dir_abs; + +int chdir(const char *path) +{ + if (!mk3hook_1st_2nd_fs_fix_real_chdir) { + mk3hook_1st_2nd_fs_fix_real_chdir = (cnh_fshook_chdir_t) cnh_lib_get_func_addr("chdir"); + } + + // This seems to be some kind of probe the game is doing to determine something...I assume which folder layout to + // use? When we change directory to our "game" dir which contains all stuff at that point, everything's fine. + // If we do not do that, the game will error not being able to find any files. When loading files, the code also + // does some odd iterating the file system starting at / at that point. I assume that this is some sort of search + // trying to look for the file on the filesystem. However, that breaks a lot of other stuf with the hooking code + // and therefore should not be triggered. + if (mk3hook_1st_2nd_fs_fix_path_game_dir_abs && !strcmp(path, "/datas/bga")) { + log_debug("Trapping /datas/bga chdir, chdir to %s", mk3hook_1st_2nd_fs_fix_path_game_dir_abs); + + return mk3hook_1st_2nd_fs_fix_real_chdir(mk3hook_1st_2nd_fs_fix_path_game_dir_abs); + } else { + return mk3hook_1st_2nd_fs_fix_real_chdir(path); + } +} + +void mk3hook_1st_2nd_fs_fix_init(const char* path_game_dir_abs) +{ + mk3hook_1st_2nd_fs_fix_path_game_dir_abs = util_str_dup(path_game_dir_abs); + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/mk3/1st-2nd-fs-fix.h b/src/main/hook/mk3/1st-2nd-fs-fix.h new file mode 100644 index 0000000..5a8d429 --- /dev/null +++ b/src/main/hook/mk3/1st-2nd-fs-fix.h @@ -0,0 +1,14 @@ +/** + * Fixes an issue with the engine of 1st and 2nd when redirecting all game data to one game folder, e.g. ./game/. + */ +#ifndef MK3HOOK_1ST_2ND_FS_FIX_H +#define MK3HOOK_1ST_2ND_FS_FIX_H + +/** + * Initialize the module. + * + * @param path_game_dir_abs The absolute path to the "game" dir containing all game assets. + */ +void mk3hook_1st_2nd_fs_fix_init(const char* path_game_dir_abs); + +#endif diff --git a/src/main/hook/mk3/config.c b/src/main/hook/mk3/config.c new file mode 100644 index 0000000..8b77efc --- /dev/null +++ b/src/main/hook/mk3/config.c @@ -0,0 +1,136 @@ +#define LOG_MODULE "mk3hook-config" + +#include + +#include "hook/mk3/options.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/str.h" + +static int mk3hook_config_sync_offset; +static double mk3hook_config_sync_multiplier; +static double mk3hook_config_music_volume; +static double mk3hook_config_sfx_volume; +static int mk3hook_config_fullscreen; +static int mk3hook_config_allow_exit; +static const char* mk3hook_config_save_file; + +int config_read_file(config_t *config, const char *filename) +{ + // Just stub file loading + log_debug("config_read_file: %s", filename); + + return 1; +} + +int config_lookup_int(const config_t *config, const char *path, int *value) +{ + log_debug("config_lookup_int: %s", path); + + if (!strcmp(path, "sync_offset")) { + *value = mk3hook_config_sync_offset; + } else { + log_error("Unsupported int entry read: %s", path); + } + + return 1; +} + +int config_lookup_float(const config_t *config, const char *path, double *value) +{ + log_debug("config_lookup_float: %s", path); + + if (!strcmp(path, "sync_multiplier")) { + *value = mk3hook_config_sync_multiplier; + } else if (!strcmp(path, "music_volume")) { + *value = mk3hook_config_music_volume; + } else if (!strcmp(path, "sfx_volume")) { + *value = mk3hook_config_sfx_volume; + } else { + log_error("Unsupported float entry read: %s", path); + } + + return 1; +} + +int config_lookup_bool(const config_t *config, const char *path, int *value) +{ + log_debug("config_lookup_bool: %s", path); + + if (!strcmp(path, "fullscreen")) { + *value = mk3hook_config_fullscreen; + } else if (!strcmp(path, "allow_exit")) { + *value = mk3hook_config_allow_exit; + } else { + log_error("Unsupported bool entry read: %s", path); + } + + return 1; +} + +int config_lookup_string(const config_t *config, const char *path, const char **value) +{ + log_debug("config_lookup_string: %s", path); + + if (!strcmp(path, "save_file")) { + // Note: This is fine as the size of the string pointed to by the returned address is not relevant for any + // operations using them, e.g. there is no merging/copying with limited stack'd buffer sizes involved like + // below. + *value = mk3hook_config_save_file; + } else if (!strcmp(path, "effect_path")) { + // Needs to be hardcoded because the stack buffer for this is only 128 bytes large. This is likely fine for most + // paths and even when resolving relative paths to absolute ones. Still, this is a risk for a buffer overflow. + // Utilize the redirect module in the main lib hook function to redirect this to something like a local game dir + // and resolve this to an absolute path + *value = "EFFECTS/"; + } else if (!strcmp(path, "track_path")) { + // Needs to be hardcoded because the stack buffer for this is only 32 bytes large. When combining it with the + // "Track%02i.mp3" part, the buffer will overflow when this path is longer or even resolved to an absolute path. + // Utilize the redirect module in the main lib hook function to redirect this to something like a local game dir + // and resolve this to an absolute path + *value = "track/"; + } else { + log_error("Unsupported string entry read: %s", path); + } + + return 1; +} + +static void mk3hook_config_assign_save_file(const struct mk3hook_options* options) +{ + const char* folder = options->game.settings; + + if (!util_fs_path_exists(folder)) { + log_info("Settings path %s does not exist, creating", folder); + + if (!util_fs_mkdir(folder)) { + log_error("Creating directory %s failed", folder); + } + } + + char* folder_abs = util_fs_get_abs_path(folder); + + if (!folder_abs) { + log_error("Failed to resolve absolute path for settings folder"); + return; + } + + // Don't free this one after assigning the result value as this will still be read from. Keep memory leak. + mk3hook_config_save_file = util_str_merge(folder_abs, "/EEPROM.BIN"); + free(folder_abs); +} + +void mk3hook_config_init(const struct mk3hook_options* options) +{ + mk3hook_config_sync_offset = options->game.sync_offset; + mk3hook_config_sync_multiplier = options->game.sync_multiplier; + mk3hook_config_music_volume = options->game.music_vol; + mk3hook_config_sfx_volume = options->game.sfx_vol; + mk3hook_config_fullscreen = !options->patch.gfx.windowed; + mk3hook_config_allow_exit = options->patch.piuio.exit_test_serv; + + mk3hook_config_assign_save_file(options); + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/mk3/config.h b/src/main/hook/mk3/config.h new file mode 100644 index 0000000..ad4e9d8 --- /dev/null +++ b/src/main/hook/mk3/config.h @@ -0,0 +1,17 @@ +/** + * Patch the configuration file handling which uses libconfig. This hooks libconfig up to pumptools configuration + * infrastructure. + */ +#ifndef MK3HOOK_CONFIG_H +#define MK3HOOK_CONFIG_H + +#include "options.h" + +/** + * Initialize this module. + * + * @param options The options provided to the hook which are injected into libconfig config value reading. + */ +void mk3hook_config_init(const struct mk3hook_options* options); + +#endif diff --git a/src/main/hook/mk3/fmodex.c b/src/main/hook/mk3/fmodex.c new file mode 100644 index 0000000..1d6e58c --- /dev/null +++ b/src/main/hook/mk3/fmodex.c @@ -0,0 +1,126 @@ +#define LOG_MODULE "mk3hook-fmodex" + +#include +#include + +#include "capnhook/hook/lib.h" + +#include "hook/mk3/fmodex.h" + +#include "util/log.h" +#include "util/str.h" + +typedef FMOD_RESULT (*FMOD_System_Init_t)(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); + +static FMOD_System_Init_t mk3hook_fmodex_real_FMOD_System_Init; + +static bool mk3hook_fmodex_debug_output; +static const char* mk3hook_fmodex_sound_device; + +FMOD_RESULT FMOD_System_Init(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata) +{ + if (!mk3hook_fmodex_real_FMOD_System_Init) { + mk3hook_fmodex_real_FMOD_System_Init = (FMOD_System_Init_t) cnh_lib_get_func_addr("FMOD_System_Init"); + } + + FMOD_RESULT res; + + unsigned int version; + + res = FMOD_System_GetVersion(system, &version); + + if (res != FMOD_OK) { + log_error("FMOD_System_GetVersion failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + + log_info("fmodex version: %d.%d.%d", (version >> 16) & 0xFFFF, (version >> 8) & 0xFF, version & 0xFF); + + if (mk3hook_fmodex_debug_output) { + res = FMOD_Debug_SetLevel(FMOD_DEBUG_ALL); + + if (res != FMOD_OK) { + log_error("FMOD_Debug_SetLevel failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + } + + res = FMOD_System_SetOutput(system, FMOD_OUTPUTTYPE_ALSA); + + if (res != FMOD_OK) { + log_error("FMOD_System_SetOutput failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + + FMOD_OUTPUTTYPE output_type; + + res = FMOD_System_GetOutput(system, &output_type); + + if (res != FMOD_OK) { + log_error("FMOD_System_GetOutput failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + + log_info("Output type: %d", output_type); + + int num_drivers; + res = FMOD_System_GetNumDrivers(system, &num_drivers); + + if (res != FMOD_OK) { + log_error("FMOD_System_GetNumDrivers failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + + log_info("Num available drivers %d", num_drivers); + + char buffer[4096]; + FMOD_GUID guid; + int selected_driver = -1; + + for (int i = 0; i < num_drivers; i++) { + res = FMOD_System_GetDriverInfo(system, i, buffer, sizeof(buffer), &guid); + + if (res != FMOD_OK) { + log_error("FMOD_System_GetDriverInfo failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + break; + } + + log_info("Driver %d: %s", i, buffer); + + if (mk3hook_fmodex_sound_device && !strcmp(buffer, mk3hook_fmodex_sound_device)) { + selected_driver = i; + } + } + + if (selected_driver == -1) { + log_info("Selecting default driver (0) because either the selected driver was not found or no driver was " + "selected"); + selected_driver = 0; + } else { + log_info("Found selected driver %s, id %d", mk3hook_fmodex_sound_device, selected_driver); + } + + res = FMOD_System_SetDriver(system, selected_driver); + + if (res != FMOD_OK) { + log_error("FMOD_System_SetDriver failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + + res = FMOD_System_SetSpeakerMode(system, FMOD_SPEAKERMODE_STEREO); + + if (res != FMOD_OK) { + log_error("FMOD_System_SetSpeakerMode failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res)); + return res; + } + + return mk3hook_fmodex_real_FMOD_System_Init(system, maxchannels, flags, extradriverdata); +} + +void mk3hook_fmodex_init(bool debug_output, const char* sound_device) +{ + mk3hook_fmodex_debug_output = debug_output; + mk3hook_fmodex_sound_device = sound_device; + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/mk3/fmodex.h b/src/main/hook/mk3/fmodex.h new file mode 100644 index 0000000..e623a5e --- /dev/null +++ b/src/main/hook/mk3/fmodex.h @@ -0,0 +1,19 @@ +/** + * This patch module fixes a bunch of issues with fmodex which is used by the MK3 Linux ports to re-implement + * the sound hardware in software. + */ +#ifndef MK3HOOK_FMODEX_H +#define MK3HOOK_FMODEX_H + +#include + +/** + * Initialize this patch module. + * + * @param debug_output True to enable fmodex's debug output which requires the usage of fmodexL.so instead of fmodex.so. + * @param sound_device Provide a sound device to pick from the list of devices available with fmodex. NULL to go with + * with default device selected automatically by fmodex. + */ +void mk3hook_fmodex_init(bool debug_output, const char* sound_device); + +#endif diff --git a/src/main/hook/mk3/main.c b/src/main/hook/mk3/main.c new file mode 100644 index 0000000..dbd4cc9 --- /dev/null +++ b/src/main/hook/mk3/main.c @@ -0,0 +1,251 @@ +/** + * Hook library for MK3 linux ports of Pump It Up. + */ +#define LOG_MODULE "mk3hook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" +#include "hook/mk3/1st-2nd-fs-fix.h" +#include "hook/mk3/config.h" +#include "hook/mk3/fmodex.h" +#include "hook/mk3/options.h" +#include "hook/patch/asound-fix.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/log.h" +#include "util/patch.h" +#include "util/proc.h" +#include "util/str.h" +#include "util/sys-info.h" + +static void mk3hook_bootstrapping(int argc, char** argv, struct mk3hook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (!mk3hook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_init(argc, argv); + + hook_core_piu_log_info(argc, argv); + + // Have different arguments to align with newer pump games + // argv[1]: game folder path + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void mk3hook_patch_config_init(struct mk3hook_options* options) +{ + mk3hook_config_init(options); +} + +static void mk3hook_patch_fs_init(struct mk3hook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void mk3hook_1st_2nd_fs_redirs(const char* game_data_path_abs) +{ + log_assert(game_data_path_abs); + + // The "datas" directory does not require a redirect as the game uses chdir to move to that folder. For this, the + // additional patch module "1st-2nd-fs-fix" is required (see below). All files usually local to the piu executable, + // which are outside of the "datas" folder, have to be redirected. + cnh_redir_add("INTRO.ANI", util_str_merge(game_data_path_abs, "/INTRO.ANI")); + cnh_redir_add("intro.ani", util_str_merge(game_data_path_abs, "/INTRO.ANI")); + cnh_redir_add("spr.res", util_str_merge(game_data_path_abs, "/SPR.RES")); + cnh_redir_add("SPR.RES", util_str_merge(game_data_path_abs, "/SPR.RES")); + cnh_redir_add("piu.bin", util_str_merge(game_data_path_abs, "/PIU.BIN")); + cnh_redir_add("PIU.BIN", util_str_merge(game_data_path_abs, "/PIU.BIN")); + cnh_redir_add("stage.cfg", util_str_merge(game_data_path_abs, "/STAGE.CFG")); + cnh_redir_add("STAGE.CFG", util_str_merge(game_data_path_abs, "/STAGE.CFG")); + + // For redirecting additional files for linux ports. Configurable via MK3 linux ports config.cfg but causes stack + // overflow on long paths. Redirecting the paths afterwards is save. + cnh_redir_add("EFFECTS", util_str_merge(game_data_path_abs, "/EFFECTS/")); + cnh_redir_add("track", util_str_merge(game_data_path_abs, "/track/")); + + mk3hook_1st_2nd_fs_fix_init(game_data_path_abs); +} + +static void mk3hook_3rd_and_up_fs_redirs(const char* game_data_path_abs) +{ + log_assert(game_data_path_abs); + + // Sometimes, the game decides to read stuff using lower case, sometimes upper case *shrug* + // Also, we don't are about cleaning up the resulting merged strings here. Have some memory leaks! + cnh_redir_add(".", util_str_merge(game_data_path_abs, "/")); + cnh_redir_add("audio", util_str_merge(game_data_path_abs, "/AUDIO")); + cnh_redir_add("AUDIO", util_str_merge(game_data_path_abs, "/AUDIO")); + cnh_redir_add("bga", util_str_merge(game_data_path_abs, "/BGA")); + cnh_redir_add("BGA", util_str_merge(game_data_path_abs, "/BGA")); + cnh_redir_add("step", util_str_merge(game_data_path_abs, "/STEP")); + cnh_redir_add("STEP", util_str_merge(game_data_path_abs, "/STEP")); + cnh_redir_add("title", util_str_merge(game_data_path_abs, "/TITLE")); + cnh_redir_add("TITLE", util_str_merge(game_data_path_abs, "/TITLE")); + cnh_redir_add("piu.bin", util_str_merge(game_data_path_abs, "/PIU.BIN")); + cnh_redir_add("PIU.BIN", util_str_merge(game_data_path_abs, "/PIU.BIN")); + cnh_redir_add("stage.cfg", util_str_merge(game_data_path_abs, "/STAGE.CFG")); + cnh_redir_add("STAGE.CFG", util_str_merge(game_data_path_abs, "/STAGE.CFG")); + // Special treatment for extra because keeping the name stage.cfg was not good enough... + cnh_redir_add("game.cfg", util_str_merge(game_data_path_abs, "/GAME.CFG")); + cnh_redir_add("GAME.CFG", util_str_merge(game_data_path_abs, "/GAME.CFG")); + + // For redirecting additional files for linux ports. Configurable via MK3 linux ports config.cfg but causes stack + // overflow on long paths. Redirecting the paths afterwards is save. + cnh_redir_add("EFFECTS", util_str_merge(game_data_path_abs, "/EFFECTS/")); + cnh_redir_add("track", util_str_merge(game_data_path_abs, "/track/")); +} + +static void mk3hook_patch_1st_and_2nd_fs_init(struct mk3hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* game_data_path_abs = util_fs_get_abs_path(game_data_path); + + if (options->game.fs_1st_2nd) { + mk3hook_1st_2nd_fs_redirs(game_data_path_abs); + } else { + mk3hook_3rd_and_up_fs_redirs(game_data_path_abs); + } + + free(game_data_path_abs); +} + +static void mk3hook_patch_main_loop_init(struct mk3hook_options* options) +{ + log_assert(options); + + patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, true); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void mk3hook_patch_sound_init(struct mk3hook_options* options) +{ + log_assert(options); + + patch_asound_fix_init(); + mk3hook_fmodex_init(options->patch.sound.debug_output, options->patch.sound.device); +} + +static void mk3hook_patch_sigsegv_init(struct mk3hook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void mk3hook_patch_piuio_init(struct mk3hook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +static void mk3hook_fix_argv(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + // Game exec main expects the following arguments + // argv[1]: cfg1 path + // argv[2]: cfg2 path (optional) + // Config loading is stubbed, so just provide something + + argv[1] = "./save/config.cfg"; + + if (argc > 2) { + argv[2] = "./save/config.cfg"; + } +} + +void mk3hook_constructor(void) +{ + /* Nothing here */ +} + +void mk3hook_destructor(void) +{ + /* Nothing here */ +} + +void mk3hook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + struct mk3hook_options options; + char* game_data_path; + + mk3hook_bootstrapping(argc, argv, &options, &game_data_path); + mk3hook_patch_config_init(&options); + mk3hook_patch_fs_init(&options); + mk3hook_patch_1st_and_2nd_fs_init(&options, game_data_path); + mk3hook_patch_main_loop_init(&options); + mk3hook_patch_sound_init(&options); + mk3hook_patch_sigsegv_init(&options); + mk3hook_patch_piuio_init(&options); + mk3hook_fix_argv(argc, argv); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void mk3hook_trap_after_main(void) +{ + +} + +LIB_MAIN_CONSTRUCTOR(mk3hook_constructor); +LIB_MAIN_DESTRUCTOR(mk3hook_destructor); +LIB_MAIN_TRAP_MAIN(mk3hook_trap_before_main, mk3hook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/mk3/ogl-fix.c b/src/main/hook/mk3/ogl-fix.c new file mode 100644 index 0000000..ec03789 --- /dev/null +++ b/src/main/hook/mk3/ogl-fix.c @@ -0,0 +1,37 @@ +/** + * Module to fix weird OpenGL error that only appears on all MK3 linux ports. + * + * If OpenGL is not forced into single threaded mode, the backend will run in + * multi-threaded mode for some reason and crash in __glDispatchCheckMultithreaded + * when the game calls glXChooseVisual in its GFX init function. + * + * The fix is quite simple (luckily) by just setting the environment variable __GL_SINGLETHREADED. + */ + +#include +#include + +#include "capnhook/hook/lib.h" + +typedef char* (*getenv_t) (const char* name); + +static getenv_t _mk3hook_ogl_fix_real_getenv; + +char* getenv(const char* name) +{ + if (!_mk3hook_ogl_fix_real_getenv) { + _mk3hook_ogl_fix_real_getenv = (getenv_t) cnh_lib_get_func_addr("getenv"); + } + + char* ret = _mk3hook_ogl_fix_real_getenv(name); + + if (!strcmp(name, "__GL_SINGLETHREADED")) { + if (ret == NULL || strcmp(name, "1") != 0) { + printf("!!! mk3hook: __GL_SINGLETHREADED not set or enabled, force patching OpenGL to single " + "threaded to avoid crash !!!\n"); + return "1"; + } + } + + return ret; +} \ No newline at end of file diff --git a/src/main/hook/mk3/options.c b/src/main/hook/mk3/options.c new file mode 100644 index 0000000..a7f0892 --- /dev/null +++ b/src/main/hook/mk3/options.c @@ -0,0 +1,230 @@ +#include "hook/mk3/options.h" + +#include "util/options.h" + +#define MK3HOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define MK3HOOK_OPTIONS_STR_GAME_SYNC_OFFSET "game.sync_offset" +#define MK3HOOK_OPTIONS_STR_GAME_SYNC_MULTIPLIER "game.sync_multiplier" +#define MK3HOOK_OPTIONS_STR_GAME_MUSIC_VOL "game.music_vol" +#define MK3HOOK_OPTIONS_STR_GAME_SFX_VOL "game.sfx_vol" +#define MK3HOOK_OPTIONS_STR_GAME_1ST_2ND_FS "game.1st_2nd_fs" +#define MK3HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT "patch.sound.debug_output" +#define MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +static const struct util_options_def mk3hook_options_def[] = { + { + .name = MK3HOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = MK3HOOK_OPTIONS_STR_GAME_SYNC_OFFSET, + .description = "Sync offset in ms", + .param = 'y', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = 115, + }, + { + .name = MK3HOOK_OPTIONS_STR_GAME_SYNC_MULTIPLIER, + .description = "Sync multiplier", + .param = 'v', + .type = UTIL_OPTIONS_TYPE_DOUBLE, + .default_value.d = 4.16666666666666696272613990004, + }, + { + .name = MK3HOOK_OPTIONS_STR_GAME_MUSIC_VOL, + .description = "Volume of music playback", + .param = 'm', + .type = UTIL_OPTIONS_TYPE_DOUBLE, + .default_value.d = 1.0, + }, + { + .name = MK3HOOK_OPTIONS_STR_GAME_SFX_VOL, + .description = "Volume of sound effects playback", + .param = 'c', + .type = UTIL_OPTIONS_TYPE_DOUBLE, + .default_value.d = 1.0, + }, + { + .name = MK3HOOK_OPTIONS_STR_GAME_1ST_2ND_FS, + .description = "Enable this option when running 1st or 2nd. This uses different file system redirects for the " + "game directory as well as enables a fix. Without this, the game throws errors about not finding files", + .param = 'x', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT, + .description = "Enable debug output for the fmod library. This requires you to use the fmodexL.so instead of " + "the standard fmodex.so", + .param = 'r', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +static const struct util_options_defs mk3hook_options_defs = { + .usage_header = + "Pumptools mk3hook for Pump It Up MK3 Linux ports, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./mk3hook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = mk3hook_options_def, + .ndefs = lengthof(mk3hook_options_def) +}; + +bool mk3hook_options_init(int argc, char** argv, struct mk3hook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&mk3hook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_GAME_SETTINGS); + options->game.sync_offset = util_options_get_int(options_opt, MK3HOOK_OPTIONS_STR_GAME_SYNC_OFFSET); + options->game.sync_multiplier = util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_SYNC_MULTIPLIER); + options->game.music_vol = util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_MUSIC_VOL); + options->game.sfx_vol = util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_SFX_VOL); + options->game.fs_1st_2nd = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_GAME_1ST_2ND_FS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.piuio.api_lib = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sound.debug_output = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/mk3/options.h b/src/main/hook/mk3/options.h new file mode 100644 index 0000000..ead48f5 --- /dev/null +++ b/src/main/hook/mk3/options.h @@ -0,0 +1,60 @@ +#ifndef MK3HOOK_OPTIONS_H +#define MK3HOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct mk3hook_options { + struct game { + const char* settings; + int32_t sync_offset; + double sync_multiplier; + double music_vol; + double sfx_vol; + bool fs_1st_2nd; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + bool debug_output; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool mk3hook_options_init(int argc, char** argv, struct mk3hook_options* options); + +#endif diff --git a/src/main/hook/nx/main.c b/src/main/hook/nx/main.c new file mode 100644 index 0000000..70aa7a0 --- /dev/null +++ b/src/main/hook/nx/main.c @@ -0,0 +1,272 @@ +/** + * Hook library for Pump It Up: NX + */ +#define LOG_MODULE "nxhook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/gfx.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog34.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/str.h" +#include "util/sys-info.h" + +#include "options.h" +#include "unlock.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_nxhook_hdd_raw_start[]; +extern const uint8_t _binary_nxhook_hdd_raw_end[]; +extern const uint8_t _binary_nxhook_dog_key_start[]; +extern const uint8_t _binary_nxhook_dog_key_end[]; + +static void nxhook_bootstrapping(int argc, char** argv, struct nxhook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!nxhook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void nxhook_patch_fs_init(struct nxhook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void nxhook_fs_redir_settings(struct nxhook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void nxhook_fs_redir_script(struct nxhook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + path_tmp = util_str_merge(game_data_path, "/SCRIPT"); + cnh_redir_add("/SCRIPT", path_tmp); + free(path_tmp); +} + +static void nxhook_fs_redir_fonts(struct nxhook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + path_tmp = util_str_merge(game_data_path, "/MICROGBE.TTF"); + cnh_redir_add("MICROGBE.TTF", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/NXTW.TTF"); + cnh_redir_add("NXTW.TTF", path_tmp); + free(path_tmp); +} + +static void nxhook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); +} + +static void nxhook_fs_redirs_init(struct nxhook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + /* Expecting all assets in the piu game (asset) folder. redirects for files + that are not in there by default for reasons */ + nxhook_fs_redir_settings(options); + nxhook_fs_redir_script(options, game_data_path); + nxhook_fs_redir_fonts(options, game_data_path); + + nxhook_fs_redir_usb(); +} + +static void nxhook_patch_gfx_init(struct nxhook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void nxhook_patch_game_init(struct nxhook_options* options) +{ + log_assert(options); + + if (options->game.force_unlock) { + hook_nx_unlock_init(); + } +} + +static void nxhook_patch_main_loop_init(struct nxhook_options* options) +{ + log_assert(options); + + patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void nxhook_patch_sound_init(struct nxhook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); +} + +static void nxhook_patch_sigsegv_init(struct nxhook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void nxhook_patch_dongle_init() +{ + patch_microdog34_init((const uint8_t*) _binary_nxhook_dog_key_start, + ((uintptr_t) &_binary_nxhook_dog_key_end - (uintptr_t) &_binary_nxhook_dog_key_start)); +} + +static void nxhook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_nxhook_hdd_raw_start, + ((uintptr_t) &_binary_nxhook_hdd_raw_end - (uintptr_t) &_binary_nxhook_hdd_raw_start)); +} + +static void nxhook_patch_piuio_init(struct nxhook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +void nxhook_constructor(void) +{ + /* Nothing here */ +} + +void nxhook_destructor(void) +{ + /* Nothing here */ +} + +void nxhook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct nxhook_options options; + + nxhook_bootstrapping(argc, argv, &options, &game_data_path); + nxhook_patch_fs_init(&options); + nxhook_fs_redirs_init(&options, game_data_path); + nxhook_patch_gfx_init(&options); + nxhook_patch_game_init(&options); + nxhook_patch_main_loop_init(&options); + nxhook_patch_sound_init(&options); + nxhook_patch_sigsegv_init(&options); + nxhook_patch_dongle_init(); + nxhook_patch_hdd_check_init(); + nxhook_patch_piuio_init(&options); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void nxhook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(nxhook_constructor); +LIB_MAIN_DESTRUCTOR(nxhook_destructor); +LIB_MAIN_TRAP_MAIN(nxhook_trap_before_main, nxhook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/nx/nxhook.dog.key b/src/main/hook/nx/nxhook.dog.key new file mode 100644 index 0000000000000000000000000000000000000000..fba1b2e22edef491edde4336f22b27280018d818 GIT binary patch literal 66876 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 MXb6mkz#t0&0Kha7)c^nh literal 0 HcmV?d00001 diff --git a/src/main/hook/nx/options.c b/src/main/hook/nx/options.c new file mode 100644 index 0000000..e365210 --- /dev/null +++ b/src/main/hook/nx/options.c @@ -0,0 +1,183 @@ +#include "hook/nx/options.h" + +#include "util/options.h" + +#define NXHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK "game.force_unlock" +#define NXHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define NXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define NXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +static const struct util_options_def nxhook_options_def[] = { + { + .name = NXHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK, + .description = "Force unlock the game. Modifies the current and any new PIUNX.INI settings file permanently", + .param = 'z', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +static const struct util_options_defs nxhook_options_defs = { + .usage_header = + "Pumptools nxhook for Pump It Up: NX, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./nxhook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = nxhook_options_def, + .ndefs = lengthof(nxhook_options_def) +}; + +bool nxhook_options_init(int argc, char** argv, struct nxhook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&nxhook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.force_unlock = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK); + options->game.settings = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.piuio.api_lib = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/nx/options.h b/src/main/hook/nx/options.h new file mode 100644 index 0000000..45272ad --- /dev/null +++ b/src/main/hook/nx/options.h @@ -0,0 +1,55 @@ +#ifndef NXHOOK_OPTIONS_H +#define NXHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct nxhook_options { + struct game { + bool force_unlock; + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool nxhook_options_init(int argc, char** argv, struct nxhook_options* options); + +#endif diff --git a/src/main/hook/nx/unlock.c b/src/main/hook/nx/unlock.c new file mode 100644 index 0000000..272342c --- /dev/null +++ b/src/main/hook/nx/unlock.c @@ -0,0 +1,81 @@ +#define LOG_MODULE "hook-nx-unlock" + +#include +#include + +#include "asset/nx/lib/settings.h" + +#include "capnhook/hook/filehook.h" + +#include "util/log.h" +#include "util/str.h" + +static FILE* _hook_nx_unlock_settings_file = NULL; + +static enum cnh_result _hook_nx_unlock_filehook(struct cnh_filehook_irp *irp); + +void hook_nx_unlock_init(void) +{ + cnh_filehook_push_handler(_hook_nx_unlock_filehook); + + log_info("Initialized"); +} + +static enum cnh_result _hook_nx_unlock_filehook(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + assert(irp); + + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != _hook_nx_unlock_settings_file) { + return cnh_filehook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_FILEHOOK_IRP_OP_OPEN: + { + /* Let it open the real file */ + result = cnh_filehook_invoke_next(irp); + + if (util_str_ends_with(irp->open_filename, ASSET_NX_SETTINGS_FILE_NAME)) { + if (result == CNH_RESULT_SUCCESS) { + log_debug("Intercepting settings file open"); + _hook_nx_unlock_settings_file = irp->file; + } + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_READ: + { + /* Let it read the real file */ + result = cnh_filehook_invoke_next(irp); + + if (result == CNH_RESULT_SUCCESS) { + struct asset_nx_settings* settings = (struct asset_nx_settings*) irp->read.bytes; + + asset_nx_settings_unlock_all(settings); + + log_debug("Applied unlock patch to loaded settings (buffer size %d)", irp->read.pos); + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_CLOSE: + { + _hook_nx_unlock_settings_file = NULL; + + result = cnh_filehook_invoke_next(irp); + + break; + } + + default: + result = cnh_filehook_invoke_next(irp); + break; + } + + return result; +} \ No newline at end of file diff --git a/src/main/hook/nx/unlock.h b/src/main/hook/nx/unlock.h new file mode 100644 index 0000000..5e63b4c --- /dev/null +++ b/src/main/hook/nx/unlock.h @@ -0,0 +1,12 @@ +/** + * Patch module to force unlock all songs/features of the game without modifying the configuration stored on disk. + */ +#ifndef HOOK_NX_UNLOCK_H +#define HOOK_NX_UNLOCK_H + +/** + * Initialize the patch module force unlocking all locked game content. + */ +void hook_nx_unlock_init(void); + +#endif diff --git a/src/main/hook/nx2/main.c b/src/main/hook/nx2/main.c new file mode 100644 index 0000000..6bf5e5f --- /dev/null +++ b/src/main/hook/nx2/main.c @@ -0,0 +1,320 @@ +#define LOG_MODULE "nx2hook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/gfx.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog40.h" +#include "hook/patch/mounts.h" +#include "hook/patch/net-profile.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/usb-mnt.h" +#include "hook/patch/usb-unlock.h" +#include "hook/patch/usbfs.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/str.h" +#include "util/sys-info.h" + +#include "options.h" +#include "profile-gen.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_nx2hook_hdd_raw_start[]; +extern const uint8_t _binary_nx2hook_hdd_raw_end[]; +extern const uint8_t _binary_nx2hook_dog_key_start[]; +extern const uint8_t _binary_nx2hook_dog_key_end[]; + +static void nx2hook_bootstrapping(int argc, char** argv, struct nx2hook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!nx2hook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void nx2hook_patch_fs_init(struct nx2hook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void nx2hook_fs_redir_settings(struct nx2hook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void nx2hook_fs_redir_script(struct nx2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + path_tmp = util_str_merge(game_data_path, "/SCRIPT"); + cnh_redir_add("/SCRIPT", path_tmp); + free(path_tmp); +} + +static void nx2hook_fs_redir_fonts(struct nx2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + /* Fonts, game expects lower case files */ + path_tmp = util_str_merge(game_data_path, "/nx.ttf"); + cnh_redir_add("nx.ttf", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/nxcn.ttf"); + cnh_redir_add("nxcn.ttf", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/nxpt.ttf"); + cnh_redir_add("nxpt.ttf", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/nxtw.ttf"); + cnh_redir_add("nxtw.ttf", path_tmp); + free(path_tmp); +} + +static void nx2hook_fs_redir_mission(struct nx2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + /* mission.txt, game expects lower case file */ + path_tmp = util_str_merge(game_data_path, "/mission.txt"); + cnh_redir_add("/mission.txt", path_tmp); + free(path_tmp); +} + +static void nx2hook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); + patch_usbfs_init(); +} + +static void nx2hook_fs_redirs_init(struct nx2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + /* Expecting all assets in the piu game (asset) folder. redirects for files + that are not in there by default for reasons */ + nx2hook_fs_redir_settings(options); + nx2hook_fs_redir_script(options, game_data_path); + nx2hook_fs_redir_fonts(options, game_data_path); + nx2hook_fs_redir_mission(options, game_data_path); + + nx2hook_fs_redir_usb(); +} + +static void nx2hook_patch_fs_mounting_init() +{ + patch_mounts_init(); + + patch_usb_mnt_init(); + patch_usb_unlock_init(); +} + +static void nx2hook_patch_gfx_init(struct nx2hook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void nx2hook_patch_main_loop_init(struct nx2hook_options* options) +{ + log_assert(options); + + patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void nx2hook_patch_sound_init(struct nx2hook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); +} + +static void nx2hook_patch_sigsegv_init(struct nx2hook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void nx2hook_patch_dongle_init() +{ + patch_microdog40_init((const uint8_t*) _binary_nx2hook_dog_key_start, + ((uintptr_t) &_binary_nx2hook_dog_key_end - (uintptr_t) &_binary_nx2hook_dog_key_start)); +} + +static void nx2hook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_nx2hook_hdd_raw_start, + ((uintptr_t) &_binary_nx2hook_hdd_raw_end - (uintptr_t) &_binary_nx2hook_hdd_raw_start)); +} + +static void nx2hook_patch_piuio_init(struct nx2hook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +static void nx2hook_patch_profile() +{ + nx2hook_profile_gen_init(); +} + +static void nx2hook_patch_pumpnet(struct nx2hook_options* options) +{ + if (options->patch.net.server && options->patch.net.machine_id != 0) { + patch_net_profile_init( + ASSET_GAME_VERSION_NX2, + options->patch.net.server, + options->patch.net.machine_id, + options->patch.net.cert_dir_path, + options->patch.net.verbose_log_output); + } +} + +void nx2hook_constructor(void) +{ + /* Nothing here */ +} + +void nx2hook_destructor(void) +{ + /* Nothing here */ +} + +void nx2hook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct nx2hook_options options; + + nx2hook_bootstrapping(argc, argv, &options, &game_data_path); + nx2hook_patch_fs_init(&options); + nx2hook_fs_redirs_init(&options, game_data_path); + nx2hook_patch_fs_mounting_init(); + nx2hook_patch_gfx_init(&options); + nx2hook_patch_main_loop_init(&options); + nx2hook_patch_sound_init(&options); + nx2hook_patch_sigsegv_init(&options); + nx2hook_patch_dongle_init(); + nx2hook_patch_hdd_check_init(); + nx2hook_patch_piuio_init(&options); + // Init order of pumpnet and auto profile generating important: pumpnet hook, if active, needs to be applied before + // the auto gen profile hook. Otherwise, the game detects that no profile is available and auto generates one even + // it should take the pumpnet route to grab a profile from a remote server + nx2hook_patch_pumpnet(&options); + nx2hook_patch_profile(); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void nx2hook_trap_after_main(void) +{ + patch_net_profile_shutdown(); + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(nx2hook_constructor); +LIB_MAIN_DESTRUCTOR(nx2hook_destructor); +LIB_MAIN_TRAP_MAIN(nx2hook_trap_before_main, nx2hook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/nx2/nx2hook.dog.key b/src/main/hook/nx2/nx2hook.dog.key new file mode 100755 index 0000000000000000000000000000000000000000..0b887a540a3ded1ca689a60523d7c3c0b8fb4d42 GIT binary patch literal 91424 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 literal 0 HcmV?d00001 diff --git a/src/main/hook/nx2/nx2hook.hdd.raw b/src/main/hook/nx2/nx2hook.hdd.raw new file mode 100755 index 0000000000000000000000000000000000000000..a4fc99fa30cd0098cf4a709dced66f5d00388292 GIT binary patch literal 5120 zcmZQz7zHCa1OiHP3luy{6haHE6#OELNDd0dAr2HM1SAL8Ak*L+", + .usage_param = 'h', + .defs = nx2hook_options_def, + .ndefs = lengthof(nx2hook_options_def) +}; + +bool nx2hook_options_init(int argc, char** argv, struct nx2hook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&nx2hook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.net.server = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER); + options->patch.net.machine_id = strtoull( + util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID), + NULL, + 16); + options->patch.net.verbose_log_output = + util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_VERBOSE_LOG_OUTPUT); + options->patch.net.cert_dir_path = + util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_CERT_DIR_PATH); + options->patch.piuio.api_lib = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/nx2/options.h b/src/main/hook/nx2/options.h new file mode 100644 index 0000000..65a28b9 --- /dev/null +++ b/src/main/hook/nx2/options.h @@ -0,0 +1,61 @@ +#ifndef NX2HOOK_OPTIONS_H +#define NX2HOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct nx2hook_options { + struct game { + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct net { + const char* server; + uint64_t machine_id; + bool verbose_log_output; + const char* cert_dir_path; + } net; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool nx2hook_options_init(int argc, char** argv, struct nx2hook_options* options); + +#endif diff --git a/src/main/hook/nx2/profile-gen.c b/src/main/hook/nx2/profile-gen.c new file mode 100644 index 0000000..7994653 --- /dev/null +++ b/src/main/hook/nx2/profile-gen.c @@ -0,0 +1,70 @@ +#define LOG_MODULE "nx2hook-profile-gen" + +#include + +#include "capnhook/hook/filehook.h" + +#include "asset/nx2/lib/util.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/str.h" + +static bool nx2hook_profile_gen_is_creating_file; + +// Do not use util_fs_path_exists here as this fopens and causes an endless recursion +static bool nx2hook_profile_gen_check_if_exists(const char* path) +{ + return access(path, F_OK) != -1; +} + +static enum cnh_result nx2hook_profile_gen_filehook(struct cnh_filehook_irp *irp) +{ + // nx2hook_profile_gen_is_creating_file: Avoid recursion of any file calls when creating the save/rank files + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN || nx2hook_profile_gen_is_creating_file) { + return cnh_filehook_invoke_next(irp); + } + + if (util_str_ends_with(irp->open_filename, "nx2save.bin") && + !nx2hook_profile_gen_check_if_exists(irp->open_filename)) { + nx2hook_profile_gen_is_creating_file = true; + + struct asset_nx2_usb_save* save = asset_nx2_usb_save_new(); + asset_nx2_usb_save_finalize(save); + + log_info("No %s file found, generate new", irp->open_filename); + + if (!asset_nx2_usb_save_save_to_file(irp->open_filename, save, true)) { + log_error("Saving generated nx2save.bin file to %s failed", irp->open_filename); + } + + free(save); + + nx2hook_profile_gen_is_creating_file = false; + } + + if (util_str_ends_with(irp->open_filename, "nx2rank.bin") && + !nx2hook_profile_gen_check_if_exists(irp->open_filename)) { + nx2hook_profile_gen_is_creating_file = true; + + struct asset_nx2_usb_rank* rank = asset_nx2_usb_rank_new(); + asset_nx2_usb_rank_finalize(rank); + + log_info("No %s file found, generate new", irp->open_filename); + + if (!asset_nx2_usb_rank_save_to_file(irp->open_filename, rank, true)) { + log_error("Saving generated nx2rank.bin file to %s failed", irp->open_filename); + } + + free(rank); + + nx2hook_profile_gen_is_creating_file = false; + } + + return cnh_filehook_invoke_next(irp); +} + +void nx2hook_profile_gen_init(void) +{ + cnh_filehook_push_handler(nx2hook_profile_gen_filehook); +} \ No newline at end of file diff --git a/src/main/hook/nx2/profile-gen.h b/src/main/hook/nx2/profile-gen.h new file mode 100644 index 0000000..d02c04e --- /dev/null +++ b/src/main/hook/nx2/profile-gen.h @@ -0,0 +1,14 @@ +/** + * Patch module for NX2 to enable auto generating of save files on empty/non + * Andamiro usb drives + */ +#ifndef NX2HOOK_PROFILE_GEN_H +#define NX2HOOK_PROFILE_GEN_H + +/** + * Initialize this patch module to allow auto generation of new/empty profiles + * on usb sticks that do not contain stock NX2 profile data + */ +void nx2hook_profile_gen_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/nxa/main.c b/src/main/hook/nxa/main.c new file mode 100644 index 0000000..9b20e1b --- /dev/null +++ b/src/main/hook/nxa/main.c @@ -0,0 +1,310 @@ +/** + * Hook library for Pump It Up: NXA + */ +#define LOG_MODULE "nxahook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/gfx.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog40.h" +#include "hook/patch/mounts.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/usb-mnt.h" +#include "hook/patch/usb-unlock.h" +#include "hook/patch/usbfs.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/str.h" +#include "util/sys-info.h" + +#include "options.h" +#include "profile-gen.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_nxahook_hdd_raw_start[]; +extern const uint8_t _binary_nxahook_hdd_raw_end[]; +extern const uint8_t _binary_nxahook_dog_key_start[]; +extern const uint8_t _binary_nxahook_dog_key_end[]; + +static void nxahook_bootstrapping(int argc, char** argv, struct nxahook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!nxahook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void nxahook_patch_fs_init(struct nxahook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void nxahook_fs_redir_settings(struct nxahook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void nxahook_fs_redir_script(struct nxahook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + path_tmp = util_str_merge(game_data_path, "/SCRIPT"); + cnh_redir_add("/SCRIPT", path_tmp); + free(path_tmp); +} + +static void nxahook_fs_redir_fonts(struct nxahook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + /* Fonts, game expects lower case files */ + path_tmp = util_str_merge(game_data_path, "/nx.ttf"); + cnh_redir_add("nx.ttf", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/nxcn.ttf"); + cnh_redir_add("nxcn.ttf", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/nxpt.ttf"); + cnh_redir_add("nxpt.ttf", path_tmp); + free(path_tmp); + + path_tmp = util_str_merge(game_data_path, "/nxtw.ttf"); + cnh_redir_add("nxtw.ttf", path_tmp); + free(path_tmp); +} + +static void nxahook_fs_redir_mission(struct nxahook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + /* mission.txt, game expects lower case file */ + path_tmp = util_str_merge(game_data_path, "/mission.txt"); + cnh_redir_add("/mission.txt", path_tmp); + free(path_tmp); + + /* ufo.txt, game expects lower case file */ + path_tmp = util_str_merge(game_data_path, "/ufo.txt"); + cnh_redir_add("/ufo.txt", path_tmp); + free(path_tmp); +} + +static void nxahook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); + patch_usbfs_init(); +} + +static void nxahook_fs_redirs_init(struct nxahook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + /* Expecting all assets in the piu game (asset) folder. redirects for files + that are not in there by default for reasons */ + nxahook_fs_redir_settings(options); + nxahook_fs_redir_script(options, game_data_path); + nxahook_fs_redir_fonts(options, game_data_path); + nxahook_fs_redir_mission(options, game_data_path); + + nxahook_fs_redir_usb(); +} + +static void nxahook_patch_fs_mounting_init() +{ + patch_mounts_init(); + + patch_usb_mnt_init(); + patch_usb_unlock_init(); +} + +static void nxahook_patch_gfx_init(struct nxahook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void nxahook_patch_main_loop_init(struct nxahook_options* options) +{ + log_assert(options); + + patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void nxahook_patch_sound_init(struct nxahook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); +} + +static void nxahook_patch_sigsegv_init(struct nxahook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void nxahook_patch_dongle_init() +{ + patch_microdog40_init((const uint8_t*) _binary_nxahook_dog_key_start, + ((uintptr_t) &_binary_nxahook_dog_key_end - (uintptr_t) &_binary_nxahook_dog_key_start)); +} + +static void nxahook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_nxahook_hdd_raw_start, + ((uintptr_t) &_binary_nxahook_hdd_raw_end - (uintptr_t) &_binary_nxahook_hdd_raw_start)); +} + +static void nxahook_patch_piuio_init(struct nxahook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +static void nxahook_patch_profile() +{ + nxahook_profile_gen_init(); +} + +void nxahook_constructor(void) +{ + /* Nothing here */ +} + +void nxahook_destructor(void) +{ + /* Nothing here */ +} + +void nxahook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct nxahook_options options; + + nxahook_bootstrapping(argc, argv, &options, &game_data_path); + nxahook_patch_fs_init(&options); + nxahook_fs_redirs_init(&options, game_data_path); + nxahook_patch_fs_mounting_init(); + nxahook_patch_gfx_init(&options); + nxahook_patch_main_loop_init(&options); + nxahook_patch_sound_init(&options); + nxahook_patch_sigsegv_init(&options); + nxahook_patch_dongle_init(); + nxahook_patch_hdd_check_init(); + nxahook_patch_piuio_init(&options); + nxahook_patch_profile(); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void nxahook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(nxahook_constructor); +LIB_MAIN_DESTRUCTOR(nxahook_destructor); +LIB_MAIN_TRAP_MAIN(nxahook_trap_before_main, nxahook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/nxa/nxahook.dog.key b/src/main/hook/nxa/nxahook.dog.key new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/nxa/nxahook.dog.key @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/nxa/nxahook.hdd.raw b/src/main/hook/nxa/nxahook.hdd.raw new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/nxa/nxahook.hdd.raw @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/nxa/options.c b/src/main/hook/nxa/options.c new file mode 100644 index 0000000..c3e6451 --- /dev/null +++ b/src/main/hook/nxa/options.c @@ -0,0 +1,195 @@ +#include "hook/nxa/options.h" + +#include "util/options.h" + +#define NXAHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define NXAHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server" +#define NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id" +#define NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define NXAHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def nxahook_options_def[] = { + { + .name = NXAHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER, + .description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)", + .param = 'n', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID, + .description = "Machine id for pumpnet", + .param = 'm', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = 0, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs nxahook_options_defs = { + .usage_header = + "Pumptools nxahook for Pump It Up: NXA, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./nxahook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = nxahook_options_def, + .ndefs = lengthof(nxahook_options_def) +}; + +bool nxahook_options_init(int argc, char** argv, struct nxahook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&nxahook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.net.server = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER); + options->patch.net.machine_id = strtoul( + util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID), + NULL, + 16); + options->patch.piuio.api_lib = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/nxa/options.h b/src/main/hook/nxa/options.h new file mode 100644 index 0000000..32030e5 --- /dev/null +++ b/src/main/hook/nxa/options.h @@ -0,0 +1,59 @@ +#ifndef NXAHOOK_OPTIONS_H +#define NXAHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct nxahook_options { + struct game { + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct net { + const char* server; + uint32_t machine_id; + } net; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool nxahook_options_init(int argc, char** argv, struct nxahook_options* options); + +#endif diff --git a/src/main/hook/nxa/profile-gen.c b/src/main/hook/nxa/profile-gen.c new file mode 100644 index 0000000..c9e93ce --- /dev/null +++ b/src/main/hook/nxa/profile-gen.c @@ -0,0 +1,108 @@ +#define LOG_MODULE "nxahook-profile-gen" + +#include + +#include "capnhook/hook/filehook.h" + +#include "asset/nxa/lib/util.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/str.h" + +static bool nxahook_profile_gen_is_creating_file; + +// Do not use util_fs_path_exists here as this fopens and causes an endless recursion +static bool nxahook_profile_gen_check_if_exists(const char* path) +{ + return access(path, F_OK) != -1; +} + +static enum cnh_result nxahook_profile_gen_filehook(struct cnh_filehook_irp *irp) +{ + // nx2hook_profile_gen_is_creating_file: Avoid recursion of any file calls when creating the save/rank files + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN || nxahook_profile_gen_is_creating_file) { + return cnh_filehook_invoke_next(irp); + } + + if (util_str_ends_with(irp->open_filename, "nxasave.bin") && + !nxahook_profile_gen_check_if_exists(irp->open_filename)) { + char* path_only; + char* path_nx2; + struct asset_nxa_usb_save* save; + + nxahook_profile_gen_is_creating_file = true; + + /* Check if a nx2save.bin exists and skip generating a new nxasave + file because the game migrates everything from the nx2 file */ + path_only = util_fs_get_path_to_file(irp->open_filename); + path_nx2 = util_str_merge(path_only, "/nx2save.bin"); + free(path_only); + + if (util_fs_path_exists(path_nx2)) { + free(path_nx2); + log_info("nx2save.bin exists, don't create new nxasave.bin"); + nxahook_profile_gen_is_creating_file = false; + return cnh_filehook_invoke_next(irp); + } + + free(path_nx2); + + save = asset_nxa_usb_save_new(); + asset_nxa_usb_save_finalize(save); + + log_info("No %s file found, generate new", irp->open_filename); + + if (!asset_nxa_usb_save_save_to_file(irp->open_filename, save, true)) { + log_error("Saving generated nxasave.bin file to %s failed", irp->open_filename); + } + + free(save); + + nxahook_profile_gen_is_creating_file = false; + } + + if (util_str_ends_with(irp->open_filename, "nxarank.bin") && + !nxahook_profile_gen_check_if_exists(irp->open_filename)) { + char* path_only; + char* path_nx2; + struct asset_nxa_usb_rank* rank; + + nxahook_profile_gen_is_creating_file = true; + + /* Check if a nx2rank.bin exists and skip generating a new nxarank + file because the game migrates everything from the nx2 file */ + path_only = util_fs_get_path_to_file(irp->open_filename); + path_nx2 = util_str_merge(path_only, "/nx2rank.bin"); + free(path_only); + + if (util_fs_path_exists(path_nx2)) { + free(path_nx2); + log_info("nx2rank.bin exists, don't create new nxarank.bin"); + nxahook_profile_gen_is_creating_file = false; + return cnh_filehook_invoke_next(irp); + } + + free(path_nx2); + + rank = asset_nxa_usb_rank_new(); + asset_nxa_usb_rank_finalize(rank); + + log_info("No %s file found, generate new", irp->open_filename); + + if (!asset_nxa_usb_rank_save_to_file(irp->open_filename, rank, true)) { + log_error("Saving generated nxarank.bin file to %s failed", irp->open_filename); + } + + free(rank); + + nxahook_profile_gen_is_creating_file = false; + } + + return cnh_filehook_invoke_next(irp); +} + +void nxahook_profile_gen_init(void) +{ + cnh_filehook_push_handler(nxahook_profile_gen_filehook); +} \ No newline at end of file diff --git a/src/main/hook/nxa/profile-gen.h b/src/main/hook/nxa/profile-gen.h new file mode 100644 index 0000000..cf8fbe2 --- /dev/null +++ b/src/main/hook/nxa/profile-gen.h @@ -0,0 +1,14 @@ +/** + * Patch module for NXA to enable auto generating of save files on empty/non + * Andamiro usb drives + */ +#ifndef NXAHOOK_PROFILE_GEN_H +#define NXAHOOK_PROFILE_GEN_H + +/** + * Initialize this patch module to allow auto generation of new/empty profiles + * on usb sticks that do not contain stock NXA profile data + */ +void nxahook_profile_gen_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/amixer-block.c b/src/main/hook/patch/amixer-block.c new file mode 100644 index 0000000..6f65140 --- /dev/null +++ b/src/main/hook/patch/amixer-block.c @@ -0,0 +1,53 @@ +#define LOG_MODULE "patch-amixer-block" + +#include "capnhook/hook/lib.h" + +#include "util/log.h" +#include "util/str.h" + +typedef int (*system_t)(const char* command); +typedef int (*execv_t)(const char* path, char* const argv[]); + +static bool patch_axmier_block_initialized; +static system_t patch_amixer_block_real_system; +static execv_t patch_amixer_block_real_execv; + +// for fst and fex +int system(const char* command) +{ + if (!patch_amixer_block_real_system) { + patch_amixer_block_real_system = (system_t) cnh_lib_get_func_addr("system"); + } + + if (patch_axmier_block_initialized) { + if (util_str_starts_with(command, "amixer")) { + log_info("Blocking call to amixer: %s", command); + return 0; + } + } + + return patch_amixer_block_real_system(command); +} + +// for f2 and prime (yes, they figured using system() isn't a great idea...) +int execv(const char* path, char* const argv[]) +{ + if (!patch_amixer_block_real_execv) { + patch_amixer_block_real_execv = (execv_t) cnh_lib_get_func_addr("execv"); + } + + if (patch_axmier_block_initialized) { + if (util_str_starts_with(path, "/usr/bin/amixer")) { + log_info("Blocking call to amixer: %s", path); + return 0; + } + } + + return patch_amixer_block_real_execv(path, argv); +} + +void patch_axmier_block_init(void) +{ + patch_axmier_block_initialized = true; + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/amixer-block.h b/src/main/hook/patch/amixer-block.h new file mode 100644 index 0000000..b820169 --- /dev/null +++ b/src/main/hook/patch/amixer-block.h @@ -0,0 +1,13 @@ +/** + * Block the system call to amixer which messes with the volume levels + * (relevant for Fiesta and up) + */ +#ifndef PATCH_AMIXER_BLOCK_H +#define PATCH_AMIXER_BLOCK_H + +/** + * Initialize patch module + */ +void patch_axmier_block_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/asound-fix.c b/src/main/hook/patch/asound-fix.c new file mode 100644 index 0000000..37ebe71 --- /dev/null +++ b/src/main/hook/patch/asound-fix.c @@ -0,0 +1,147 @@ +#define LOG_MODULE "patch-asound-fix" + +#include +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +typedef int (*getgrnam_r_t)(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result); + +static getgrnam_r_t patch_asound_fix_real_getgrnam_r; + +static char** patch_asound_fix_split_user_list_str(const char* user_list_str) +{ + char* user_list_str_cpy = util_str_dup(user_list_str); + char** user_list = util_xmalloc(sizeof(char*)); + size_t len_list = 1; + + char* ptr = strtok(user_list_str_cpy, ","); + + while (ptr != NULL) { + // last token will likely read beyond newline to next : token for next group entry + char* new_line_char = strstr(ptr, "\n"); + + if (new_line_char) { + *new_line_char = '\0'; + } + + len_list++; + user_list = util_xrealloc(user_list, len_list * sizeof(char*)); + + user_list[len_list - 2] = util_str_dup(ptr); + user_list[len_list - 1] = NULL; + + ptr = strtok(NULL, ","); + } + + free(user_list_str_cpy); + + return user_list; +} + +static char* patch_asound_fix_user_list_to_str(char** user_list) +{ + char** ptr = user_list; + char* str = util_str_dup("\0"); + + while (*ptr != NULL) { + char* mrg = util_str_merge(str, *ptr); + free(str); + str = util_str_merge(mrg, ","); + free(mrg); + + ptr++; + } + + return str; +} + +int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result) +{ + if (!patch_asound_fix_real_getgrnam_r) { + patch_asound_fix_real_getgrnam_r = (getgrnam_r_t) cnh_lib_get_func_addr("getgrnam_r"); + } + + // We expect to use the standard "audio" group here, otherwise detection of this is not possible. Intercept + // and execute the following re-implementation of the reading logic from file. I don't know if getgrnam_r usually + // reads from a cached version of /etc/group but I suppose that doesn't matter here. + if (!strcmp(name, "audio")) { + log_debug("Trapping getgrnam_r for audio group of libasound"); + + FILE* file = fopen("/etc/group", "r"); + + fseek(file, 0, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + char* buffer = (char*) util_xmalloc(file_size); + + if (fread(buffer, file_size, 1, file) != 1) { + log_error("Reading /etc/group file failed: %s", strerror(errno)); + free(buffer); + *result = NULL; + return -1; + } + + char* str_audio_pos = strstr(buffer, name); + + if (str_audio_pos == NULL) { + log_error("Could not find 'audio' group in /etc/group required by libasound likely for defaults.pcm.ipc_gid" + " from asound.conf. Make sure the group exists."); + free(buffer); + *result = NULL; + return -1; + } + + char* tok = strtok(str_audio_pos, ":"); + uint8_t cnt = 0; + + while (tok != NULL) { + switch (cnt) { + case 0: + grp->gr_name = util_str_dup(tok); + break; + + case 1: + grp->gr_passwd = util_str_dup(tok); + break; + + case 2: + grp->gr_gid = strtol(tok, NULL, 10); + break; + + case 3: + grp->gr_mem = patch_asound_fix_split_user_list_str(tok); + break; + + default: + log_error("audio group entry format in /etc/group invalid. Check your /etc/group file!"); + free(buffer); + *result = NULL; + return -1; + } + + cnt++; + tok = strtok(NULL, ":"); + } + + char* grp_mem_str = patch_asound_fix_user_list_to_str(grp->gr_mem); + log_debug("Resulting group struct: %s %s %d %s", grp->gr_name, grp->gr_passwd, grp->gr_gid, grp_mem_str); + free(grp_mem_str); + + *result = grp; + + return 0; + } + + return patch_asound_fix_real_getgrnam_r(name, grp, buf, buflen, result); +} + +void patch_asound_fix_init() +{ + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/asound-fix.h b/src/main/hook/patch/asound-fix.h new file mode 100644 index 0000000..67b8983 --- /dev/null +++ b/src/main/hook/patch/asound-fix.h @@ -0,0 +1,25 @@ +/** + * Fix a quirk with getgrnam_r in the asound library always failing when loading the asound.conf file and reading the + * /etc/group file. For some reason, it cannot find the audio group entry even if it is available and can be read + * by other applications just fine. + * + * Your typical asound.conf, which is loaded by libasound in a application that uses it, contains the following line: + * defaults.pcm.ipc_gid audio + * + * Finding documentation about what this stuff does it difficult but judging by the name, this seems to be related to + * setting up shared memory IPC for reading and writing data to the sound driver. + * For some reason, this "fails" when the function getgrnam_r is called by libasound. The function itself returns + * successful but with no result. This function reads the entry from /etc/group. libsound queries the "audio" group + * in that case and even if the entry exists, the result is empty for some unknown reason. + * + * This module fixes that issue. + */ +#ifndef PATCH_ASOUND_FIX_H +#define PATCH_ASOUND_FIX_H + +/** + * Initialize the patch module + */ +void patch_asound_fix_init(); + +#endif diff --git a/src/main/hook/patch/blacklist-url.c b/src/main/hook/patch/blacklist-url.c new file mode 100644 index 0000000..cd28d99 --- /dev/null +++ b/src/main/hook/patch/blacklist-url.c @@ -0,0 +1,66 @@ +#define LOG_MODULE "patch-blacklist-url" + +#include + +#include "capnhook/hook/lib.h" + +#include "util/list.h" +#include "util/log.h" +#include "util/mem.h" + +struct patch_blacklist_url_list_elem { + struct util_list_node head; + const char* url; +}; + +typedef int (*curl_easy_setopt_t)(int* handle, int option, void* param); + +static bool patch_blacklist_url_initialized; +static curl_easy_setopt_t patch_blacklist_url_real_curl_easy_setopt; +static struct util_list patch_blacklist_url_list; + +int curl_easy_setopt(int* handle, int option, void* param) +{ + if (!patch_blacklist_url_real_curl_easy_setopt) { + patch_blacklist_url_real_curl_easy_setopt = (curl_easy_setopt_t) cnh_lib_get_func_addr("curl_easy_setopt"); + } + + if (patch_blacklist_url_initialized) { + + /* option == 10002 to identify that param has a string */ + if (option == 10002) { + + struct util_list_node* pos; + struct patch_blacklist_url_list_elem* elem; + + for (pos = patch_blacklist_url_list.head; pos != NULL; pos = pos->next) { + elem = containerof(pos, struct patch_blacklist_url_list_elem, head); + + if (!memcmp(param, elem->url, strlen(elem->url))) { + log_debug("Blocking url %s", elem->url); + return patch_blacklist_url_real_curl_easy_setopt(handle, option, (void*) "does-not-exist"); + } + } + } + } + + return patch_blacklist_url_real_curl_easy_setopt(handle, option, param); +} + +void patch_blacklist_url_init(void) +{ + util_list_init(&patch_blacklist_url_list); + patch_blacklist_url_initialized = true; + log_info("Initialized"); +} + +void patch_blacklist_url_add(const char* url) +{ + struct patch_blacklist_url_list_elem* elem; + + elem = util_xmalloc(sizeof(struct patch_blacklist_url_list_elem)); + elem->url = strdup(url); + + util_list_append(&patch_blacklist_url_list, &elem->head); + log_info("Add url %s to blacklist", url); +} \ No newline at end of file diff --git a/src/main/hook/patch/blacklist-url.h b/src/main/hook/patch/blacklist-url.h new file mode 100644 index 0000000..5e69d7d --- /dev/null +++ b/src/main/hook/patch/blacklist-url.h @@ -0,0 +1,19 @@ +/** + * Blacklist calls to offical update and game server (Prime and up). + */ +#ifndef PATCH_BLACKLIST_URL_H +#define PATCH_BLACKLIST_URL_H + +/** + * Initialize patch module + */ +void patch_blacklist_url_init(void); + +/** + * Add an url to block to the blacklist + * + * @param url Url to block + */ +void patch_blacklist_url_add(const char* url); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/block-keyboard-grab.c b/src/main/hook/patch/block-keyboard-grab.c new file mode 100644 index 0000000..7614fed --- /dev/null +++ b/src/main/hook/patch/block-keyboard-grab.c @@ -0,0 +1,36 @@ +#define LOG_MODULE "block-keyboard-grab" + +#include +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" + +typedef int (*XGrabKeyboard_t)(Display* display, Window window, Bool owner_events, int pointer_mode, int keyboard_mode, + Time time); + +static XGrabKeyboard_t _patch_main_loop_real_XGrabKeyboard; + +static bool _patch_block_keyboard_grab_enable; + +int XGrabKeyboard(Display* display, Window window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time) +{ + if (!_patch_main_loop_real_XGrabKeyboard) { + _patch_main_loop_real_XGrabKeyboard = (XGrabKeyboard_t) cnh_lib_get_func_addr("XGrabKeyboard"); + } + + if (_patch_block_keyboard_grab_enable) { + log_debug("Block keyboard grabbing"); + return 0; + } + + return _patch_main_loop_real_XGrabKeyboard(display, window, owner_events, pointer_mode, keyboard_mode, time); +} + +void patch_block_keyboard_grab_init() +{ + _patch_block_keyboard_grab_enable = true; + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/block-keyboard-grab.h b/src/main/hook/patch/block-keyboard-grab.h new file mode 100644 index 0000000..1b9d767 --- /dev/null +++ b/src/main/hook/patch/block-keyboard-grab.h @@ -0,0 +1,10 @@ +#ifndef PATCH_BLOCK_KEYBOARD_GRAB_H +#define PATCH_BLOCK_KEYBOARD_GRAB_H + +/** + * Enable blocking of X11 keyboard grabbing which causes Prime to not go to window mode and behave weird on desktop + * machines. + */ +void patch_block_keyboard_grab_init(); + +#endif diff --git a/src/main/hook/patch/gfx.c b/src/main/hook/patch/gfx.c new file mode 100644 index 0000000..e093bbe --- /dev/null +++ b/src/main/hook/patch/gfx.c @@ -0,0 +1,125 @@ +#define LOG_MODULE "patch-gfx" + +#include +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" +#include "util/str.h" + +#include "gfx.h" + +typedef Window (*XCreateWindow_t)(Display *display, Window parent, int x, int y, unsigned int width, + unsigned int height, unsigned int border_width, int depth, unsigned int _class, Visual *visual, + unsigned long valuemask, XSetWindowAttributes *attributes); +typedef Display* (*XOpenDisplay_t)(const char *display_name); +typedef XVisualInfo* (*glXChooseVisual_t)(Display *dpy, int screen, int *attribList); + +static bool patch_gfx_force_window = false; + +static bool patch_gfx_initialized; +static XCreateWindow_t patch_gfx_real_XCreateWindow; +static XOpenDisplay_t patch_gfx_real_XOpenDisplay; +static glXChooseVisual_t patch_gfx_real_GlXChooseVisual; + +static char* patch_gfx_attrib_list_to_str(int* attrib_list) +{ + int* ptr = attrib_list; + char* str = util_str_dup(""); + char buf[32]; + + while (*ptr != None) { + sprintf(buf, "%d, ", *ptr); + + char* tmp = util_str_merge(str, buf); + + free(str); + str = tmp; + + ptr++; + } + + return str; +} + +Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, + unsigned int border_width, int depth, unsigned int _class, Visual *visual, unsigned long valuemask, + XSetWindowAttributes *attributes) +{ + log_debug("XCreateWindow"); + + if (!patch_gfx_real_XCreateWindow) { + patch_gfx_real_XCreateWindow = (XCreateWindow_t) cnh_lib_get_func_addr("XCreateWindow"); + } + + if (patch_gfx_initialized) { + + if (valuemask == 0x80A) { + log_info("Patching to enable usage of non nvidia cards."); + /* enables usage of non nvidia cards and newer nvidia models */ + valuemask = 0x280A; + } + } + + if (patch_gfx_force_window) { + log_info("Forcing window mode"); + attributes->override_redirect = 0; + } + + return patch_gfx_real_XCreateWindow(display, parent, x, y, width, height, border_width, depth, _class, visual, + valuemask, attributes); +} + +Display *XOpenDisplay(const char *display_name) +{ + if (!patch_gfx_real_XOpenDisplay) { + patch_gfx_real_XOpenDisplay = (XOpenDisplay_t) cnh_lib_get_func_addr("XOpenDisplay"); + } + + log_info("XOpenDisplay: %s", display_name); + + Display* res = patch_gfx_real_XOpenDisplay(display_name); + + if (!res) { + log_error("XOpenDisplay returned NULL. This might indicate that your environment is not properly setup. Check " + " that you have GPU drivers installed and configured properly and that OpenGL hardware acceleration is " + " working (use the command line tool \"glxinfo\")."); + } + + return res; +} + +XVisualInfo* glXChooseVisual(Display *dpy, int screen, int *attribList) +{ + if (!patch_gfx_real_GlXChooseVisual) { + patch_gfx_real_GlXChooseVisual = (glXChooseVisual_t) cnh_lib_get_func_addr("glXChooseVisual"); + } + + char* attrib_list_str =patch_gfx_attrib_list_to_str(attribList); + + log_info("glXChooseVisual: dpy %p, screen %d, attribList %s", dpy, screen, attrib_list_str); + + free(attrib_list_str); + + XVisualInfo* res = patch_gfx_real_GlXChooseVisual(dpy, screen, attribList); + + if (!res) { + log_error("glXChooseVisual returned NULL. It is likely that your current environment does support hardware" + "acceleration. Either you do not have any GPU drivers installed or the drivers are not configured " + "properly. Fix that and use the command line tool \"glxinfo\" for debugging this."); + } + + return res; +} + +void patch_gfx_init() +{ + patch_gfx_initialized = true; + log_info("Initialized"); +} + +void patch_gfx_force_window_mode() +{ + patch_gfx_force_window = true; +} \ No newline at end of file diff --git a/src/main/hook/patch/gfx.h b/src/main/hook/patch/gfx.h new file mode 100644 index 0000000..1065794 --- /dev/null +++ b/src/main/hook/patch/gfx.h @@ -0,0 +1,17 @@ +/** + * Hook module to run the games on non NVIDIA cards + */ +#ifndef PATCH_GFX_H +#define PATCH_GFX_H + +/** + * Initialize the patch module + */ +void patch_gfx_init(); + +/** + * Force the game into window mode + */ +void patch_gfx_force_window_mode(); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/hasp.c b/src/main/hook/patch/hasp.c new file mode 100644 index 0000000..a90177e --- /dev/null +++ b/src/main/hook/patch/hasp.c @@ -0,0 +1,63 @@ +#define LOG_MODULE "patch-hasp" + +#include "sec/hasp/old/hasp.h" + +#include "util/log.h" +#include "util/patch.h" + +static const uint8_t patch_hasp_login_sig[] = { + 0x00, 0xB8, 0x16, 0x00, + 0x00, 0x00, 0x8B, 0x4C, + 0x24, 0x14, 0x8B, 0x74, + 0x24, 0x10, 0x8B, 0x54 +}; + +static const uint8_t patch_hasp_id_sig[] = { + 0x53, 0x83, 0xEC, 0x48, + 0xC7, 0x44, 0x24, 0x10 +}; + +void patch_hasp_init(const uint8_t* key_data, size_t len) +{ + void* func_api_login; + void* func_api_logout; + void* func_api_decrypt; + void* func_api_getid; + + func_api_login = util_patch_find_signiture(patch_hasp_login_sig, + sizeof(patch_hasp_login_sig), -16, (void*) 0x80c0000, (void*) 0x80f0000, + 16); + + if (!func_api_login) { + log_error("Could not find ApiLogin address"); + return; + } + + log_debug("ApiLogin at %p", func_api_login); + + func_api_logout = (void*) (((size_t) func_api_login) - 0x130); + log_debug("assuming ApiLogout at %p", func_api_logout); + + func_api_decrypt = (void*) (((size_t) func_api_login) - 0x200); + log_debug("assuming ApiDecrypt at %p", func_api_decrypt); + + func_api_getid = util_patch_find_signiture(patch_hasp_id_sig, + sizeof(patch_hasp_id_sig), 0, (void*) 0x8060000, (void*) 0x8090000, + 16); + + if (!func_api_getid) { + log_error("Could not find ApiGetid address"); + return; + } + + log_debug("ApiGetid at %p", func_api_getid); + + util_patch_function((uintptr_t) func_api_login, sec_hasp_api_login); + util_patch_function((uintptr_t) func_api_logout, sec_hasp_api_logout); + util_patch_function((uintptr_t) func_api_decrypt, sec_hasp_api_decrypt); + util_patch_function((uintptr_t) func_api_getid, sec_hasp_api_getid); + + sec_hasp_init(key_data, len); + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/hasp.h b/src/main/hook/patch/hasp.h new file mode 100644 index 0000000..7c5c5f4 --- /dev/null +++ b/src/main/hook/patch/hasp.h @@ -0,0 +1,15 @@ +/** + * Patch module to install the dongle emulator for a hasp dongle + */ +#ifndef PATCH_HASP_H +#define PATCH_HASP_H + +/** + * Initialize the patch module + * + * @param key_data Pointer to loaded key data (key table) + * @param len Length of the buffer + */ +void patch_hasp_init(const uint8_t* key_data, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/hasp2.c b/src/main/hook/patch/hasp2.c new file mode 100644 index 0000000..81e8e81 --- /dev/null +++ b/src/main/hook/patch/hasp2.c @@ -0,0 +1,40 @@ +#define LOG_MODULE "patch-hasp" + +#include + +#include "sec/hasp/server.h" + +#include "util/log.h" + +static pthread_t patch_hasp_thread; + +static void* patch_hasp_thread_run(void* args) +{ + log_info("Running hasp server thread"); + + sec_hasp_server_run(); + + log_info("Finished hasp server thread"); + + return NULL; +} + +void patch_hasp_init(const uint8_t* key_data, size_t len) +{ + sec_hasp_server_init(key_data, len); + + /* Run the daemon in another thread */ + pthread_create(&patch_hasp_thread, NULL, + patch_hasp_thread_run, NULL); + + log_info("Initialized"); +} + +void patch_hasp_shutdown(void) +{ + log_info("Shutting down"); + + sec_hasp_server_shutdown(); + + pthread_join(patch_hasp_thread_run, NULL); +} \ No newline at end of file diff --git a/src/main/hook/patch/hasp2.h b/src/main/hook/patch/hasp2.h new file mode 100644 index 0000000..4d0e1d6 --- /dev/null +++ b/src/main/hook/patch/hasp2.h @@ -0,0 +1,22 @@ +/** + * Patch module to install the dongle emulator for a hasp dongle (runs a local server) + */ +#ifndef PATCH_HASP2_H +#define PATCH_HASP2_H + +#include + +/** + * Initialize the patch module and run the hasp server + * + * @param key_data Pointer to loaded key data (attributes and key table) + * @param len Length of the buffer + */ +void patch_hasp_init(const uint8_t* key_data, size_t len); + +/** + * Shutdown and remove the emulator + */ +void patch_hasp_shutdown(void); + +#endif diff --git a/src/main/hook/patch/hdd-check.c b/src/main/hook/patch/hdd-check.c new file mode 100644 index 0000000..7ee692e --- /dev/null +++ b/src/main/hook/patch/hdd-check.c @@ -0,0 +1,257 @@ +#define LOG_MODULE "patch-hdd-check" + +#include +#include +#include +#include + +#include "capnhook/hook/filehook.h" +#include "capnhook/hook/iohook.h" + +#include "util/log.h" + +static const uint8_t* patch_hdd_check_boot_area; + +static int patch_hdd_check_fd = -1; +static FILE* patch_hdd_check_file = NULL; +static size_t patch_hdd_check_boot_area_size; +static size_t patch_hdd_check_boot_area_fp; + +static enum cnh_result patch_hdd_check_filehook(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + result = CNH_RESULT_SUCCESS; + + assert(irp); + + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && (!patch_hdd_check_file || irp->file != patch_hdd_check_file)) { + return cnh_filehook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_FILEHOOK_IRP_OP_OPEN: + { + if (!strcmp(irp->open_filename, "/dev/hdd")) { + patch_hdd_check_file = cnh_filehook_open_dummy_file_handle(); + irp->file = patch_hdd_check_file; + + log_debug("/dev/hdd fopened: %p", patch_hdd_check_file); + } else { + return cnh_filehook_invoke_next(irp); + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_READ: + { + uint32_t len; + + log_debug("fread, pos 0x%X, bytes %d", patch_hdd_check_boot_area_fp, irp->read.nbytes); + + /* read up to eof, only */ + if (patch_hdd_check_boot_area_fp + irp->read.nbytes < patch_hdd_check_boot_area_size) { + len = irp->read.nbytes; + } else { + len = patch_hdd_check_boot_area_size - patch_hdd_check_boot_area_fp; + } + + memcpy(irp->read.bytes, patch_hdd_check_boot_area + patch_hdd_check_boot_area_fp, len); + + patch_hdd_check_boot_area_fp += len; + irp->read.pos = len; + + break; + } + + case CNH_FILEHOOK_IRP_OP_WRITE: + { + // Apparently, Prime starts writing to /dev/hdd, stub + log_debug("fwrite"); + + break; + } + + case CNH_FILEHOOK_IRP_OP_SEEK: + { + /* TODO this is not verified to work, yet + not needed on older games as it seems (zero for example) + patch seeking for CRED file so we can avoid a huge hdd file */ + if (irp->seek_offset == 0x1F70000) { + log_debug("fseek: fake for hdd (0x1F70000)"); + irp->seek_offset = 1024; + irp->seek_origin = SEEK_SET; + } else if (irp->seek_offset == 0x1F70800) { + log_debug("fseek: fake for hdd (0x1F70800)"); + irp->seek_offset = 1024 + 2048; + irp->seek_origin = SEEK_SET; + } + + switch (irp->seek_origin) { + case SEEK_SET: + patch_hdd_check_boot_area_fp = (size_t) irp->seek_offset; + break; + + case SEEK_CUR: + patch_hdd_check_boot_area_fp += irp->seek_offset; + break; + + case SEEK_END: + patch_hdd_check_boot_area_fp = patch_hdd_check_boot_area_size; + patch_hdd_check_boot_area_fp += irp->seek_offset; + break; + + default: + log_die("Unhandled origin %d", irp->seek_origin); + break; + } + + log_debug("fseek, offset 0x%X, origin %d", irp->seek_offset, irp->seek_origin); + + break; + } + + case CNH_FILEHOOK_IRP_OP_CLOSE: + patch_hdd_check_file = NULL; + + log_debug("/dev/hdd fclosed"); + + /* Actually close dummy handle */ + return cnh_filehook_invoke_next(irp); + + default: + log_warn("Unhandled file op: %d", irp->op); + break; + } + + return result; +} + +static enum cnh_result patch_hdd_check_iohook(struct cnh_iohook_irp *irp) +{ + enum cnh_result result; + + result = CNH_RESULT_SUCCESS; + + assert(irp); + + if ((irp->op != CNH_IOHOOK_IRP_OP_OPEN && irp->fd != patch_hdd_check_fd) && + (irp->op != CNH_IOHOOK_IRP_OP_FDOPEN || irp->fdopen_fd != patch_hdd_check_fd)) { + return cnh_iohook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_IOHOOK_IRP_OP_OPEN: + { + if (!strcmp(irp->open_filename, "/dev/hdd")) { + patch_hdd_check_fd = cnh_iohook_open_dummy_fd(); + irp->fd = patch_hdd_check_fd; + + log_debug("/dev/hdd opened: %d", patch_hdd_check_fd); + } else { + return cnh_iohook_invoke_next(irp); + } + + break; + } + + case CNH_IOHOOK_IRP_OP_FDOPEN: + { + patch_hdd_check_file = cnh_filehook_open_dummy_file_handle(); + irp->fdopen_res = patch_hdd_check_file; + + log_debug("/dev/hdd fdopen: %p", patch_hdd_check_file); + + break; + } + + case CNH_IOHOOK_IRP_OP_READ: + { + uint32_t len; + + log_debug("read, pos 0x%X, bytes %d", patch_hdd_check_boot_area_fp, irp->read.nbytes); + + /* read up to eof, only */ + if (patch_hdd_check_boot_area_fp + irp->read.nbytes < patch_hdd_check_boot_area_size) { + len = irp->read.nbytes; + } else { + len = patch_hdd_check_boot_area_size - patch_hdd_check_boot_area_fp; + } + + memcpy(irp->read.bytes, patch_hdd_check_boot_area + patch_hdd_check_boot_area_fp, len); + + patch_hdd_check_boot_area_fp += len; + irp->read.pos = len; + + break; + } + + case CNH_IOHOOK_IRP_OP_SEEK: + { + log_debug("Seek: offset %d, orig %d", irp->seek_offset, irp->seek_origin); + + switch (irp->seek_origin) { + case SEEK_SET: + patch_hdd_check_boot_area_fp = (size_t) irp->seek_offset; + break; + + case SEEK_CUR: + patch_hdd_check_boot_area_fp += irp->seek_offset; + break; + + case SEEK_END: + patch_hdd_check_boot_area_fp = patch_hdd_check_boot_area_size; + patch_hdd_check_boot_area_fp += irp->seek_offset; + break; + + default: + log_die("Unhandled origin %d", irp->seek_origin); + break; + } + + irp->seek_pos = patch_hdd_check_boot_area_fp; + + break; + } + + case CNH_IOHOOK_IRP_OP_IOCTL: + { + /* hdd information request */ + if (irp->ioctl_req == HDIO_GET_IDENTITY) { + log_info("ioctl: fake ioctl for hdd (0x30D)"); + /* just return empty data instead of real data */ + struct hd_driveid* drid = (struct hd_driveid*) irp->ioctl.bytes; + memset(drid, 0, sizeof(struct hd_driveid)); + irp->ioctl.pos = 0; + } + + break; + } + + case CNH_IOHOOK_IRP_OP_CLOSE: + patch_hdd_check_fd = -1; + + log_debug("/dev/hdd closed"); + + /* Actually close dummy handle */ + return cnh_iohook_invoke_next(irp); + + default: + log_warn("Unhandled io op: %d", irp->op); + break; + } + + return result; +} + +void patch_hdd_check_init(const uint8_t* boot_area_buffer, size_t len) +{ + patch_hdd_check_boot_area = boot_area_buffer; + patch_hdd_check_boot_area_size = len; + + cnh_iohook_push_handler(patch_hdd_check_iohook); + cnh_filehook_push_handler(patch_hdd_check_filehook); + + log_info("Initialized: boot area size %d", patch_hdd_check_boot_area_size); +} \ No newline at end of file diff --git a/src/main/hook/patch/hdd-check.h b/src/main/hook/patch/hdd-check.h new file mode 100644 index 0000000..a2822ab --- /dev/null +++ b/src/main/hook/patch/hdd-check.h @@ -0,0 +1,16 @@ +/** + * Patch the HDD check which (normally) ensures that the game is running on a + * real HDD with valid data written to the boot area + */ +#ifndef PATCH_HDD_CHECK_H +#define PATCH_HDD_CHECK_H + +/** + * Initialize the patch module + * + * @param boot_area_buffer Buffer with boot area sections of a real drive + * @param len Length of buffer provided + */ +void patch_hdd_check_init(const uint8_t* boot_area_buffer, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/hook-mon.c b/src/main/hook/patch/hook-mon.c new file mode 100644 index 0000000..b08a29e --- /dev/null +++ b/src/main/hook/patch/hook-mon.c @@ -0,0 +1,36 @@ +#define LOG_MODULE "patch-hook-mon" + +#include "capnhook/hooklib/filehook-mon.h" +#include "capnhook/hooklib/fileopen-mon.h" +#include "capnhook/hooklib/fshook-mon.h" +#include "capnhook/hooklib/iohook-mon.h" +#include "capnhook/hooklib/usbhook-mon.h" + +#include "util/log.h" + +void patch_hook_mon_init(bool monitor_io, bool monitor_file, bool monitor_fs, bool monitor_usb, bool monitor_open) +{ + if (monitor_open) { + cnh_iohook_push_handler(cnh_fileopen_mon_iohook); + cnh_filehook_push_handler(cnh_fileopen_mon_filehook); + cnh_fshook_push_handler(cnh_fileopen_mon_fshook); + } + + if (monitor_io) { + cnh_iohook_push_handler(cnh_iohook_mon); + } + + if (monitor_file) { + cnh_filehook_push_handler(cnh_filehook_mon); + } + + if (monitor_fs) { + cnh_fshook_push_handler(cnh_fshook_mon); + } + + if (monitor_usb) { + cnh_usbhook_push_handler(cnh_usbhook_mon); + } + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/hook-mon.h b/src/main/hook/patch/hook-mon.h new file mode 100644 index 0000000..4c5a1c6 --- /dev/null +++ b/src/main/hook/patch/hook-mon.h @@ -0,0 +1,20 @@ +/** + * Patch module for monitoring various system calls. For development and debugging purpose. + */ +#ifndef PATCH_HOOK_MON_H +#define PATCH_HOOK_MON_H + +#include + +/** + * Initialize the module + * + * @param monitor_io True to enable monitoring of I/O calls + * @param monitor_file True to enable monitoring of file related calls + * @param monitor_fs True to enable monitoring of file system related calls + * @param monitor_usb True to enable monitoring of usb calls + * @param monitor_open True to enable monitoring of any file/device open calls + */ +void patch_hook_mon_init(bool monitor_io, bool monitor_file, bool monitor_fs, bool monitor_usb, bool monitor_open); + +#endif diff --git a/src/main/hook/patch/main-loop.c b/src/main/hook/patch/main-loop.c new file mode 100644 index 0000000..bdcc7ff --- /dev/null +++ b/src/main/hook/patch/main-loop.c @@ -0,0 +1,235 @@ +#define LOG_MODULE "patch-main-loop" + +#include +#include +#include + +#include "ptapi/io/x11-input-hook.h" + +#include "capnhook/hook/lib.h" +#include "capnhook/hook/sig.h" + +#include "hook/patch/main-loop.h" + +#include "util/log.h" + +typedef int (*XPending_t)(Display* display); +typedef int (*XNextEvent_t)(Display* display, XEvent* event_return); + +typedef const struct ptapi_io_x11_input_hook_handler* (*ptapi_io_x11_input_handler_hook_t)(void); + +static XPending_t _patch_main_loop_real_XPending; +static XNextEvent_t _patch_main_loop_real_XNextEvent; + +static void _patch_main_loop_sigalarm_handler(int signal, __sighandler_t orig_handler); +static bool _patch_main_loop_is_key_repeated(Display* display, XEvent* event); + +static __sighandler_t _patch_main_loop_sigalarm_orig_handler; +static bool _patch_main_loop_disable_built_in_inputs; +static bool _patch_main_loop_disable_mk3_linux_ports_built_in_inputs; +static pthread_mutex_t _patch_main_loop_input_handlers_lock; +static const struct ptapi_io_x11_input_hook_handler** _patch_main_loop_input_handlers; +static size_t _patch_main_loop_num_input_handlers; + +void patch_main_loop_init(bool fix_sigalarm_main_loop, bool disable_built_in_inputs, bool disable_mk3_linux_port_inputs) +{ + _patch_main_loop_disable_built_in_inputs = disable_built_in_inputs; + _patch_main_loop_disable_mk3_linux_ports_built_in_inputs = disable_mk3_linux_port_inputs; + + _patch_main_loop_sigalarm_orig_handler = NULL; + + if (fix_sigalarm_main_loop) { + log_info("Applying sigalarm handler fix"); + cnh_sig_install(SIGALRM, _patch_main_loop_sigalarm_handler); + } + + pthread_mutex_init(&_patch_main_loop_input_handlers_lock, NULL); + + log_info("Initialized, disable built-in inputs %d", disable_built_in_inputs); +} + +void patch_main_loop_add_x11_input_handler(const char* lib_with_handler_impl) +{ + const struct ptapi_io_x11_input_hook_handler** new_array; + size_t new_size; + void* lib_handle; + ptapi_io_x11_input_handler_hook_t input_handler_hook_func; + const struct ptapi_io_x11_input_hook_handler* input_handler_hook; + + if (!lib_with_handler_impl) { + log_die("No library path with input handler implementation specified"); + } + + log_info("Loading library with x11-input-handler api implementation %s", lib_with_handler_impl); + + lib_handle = cnh_lib_load(lib_with_handler_impl); + + input_handler_hook_func = (ptapi_io_x11_input_handler_hook_t) + cnh_lib_get_func_addr_handle(lib_handle, "ptapi_io_x11_input_handler_hook"); + + input_handler_hook = input_handler_hook_func(); + + if (!input_handler_hook) { + log_warn("Library impl %s returned NULL hook handler, skipping", lib_with_handler_impl); + return; + } + + pthread_mutex_lock(&_patch_main_loop_input_handlers_lock); + + new_size = _patch_main_loop_num_input_handlers + 1; + new_array = realloc(_patch_main_loop_input_handlers, new_size * sizeof(struct ptapi_io_input_hook_handler*)); + + if (new_array != NULL) { + _patch_main_loop_input_handlers = new_array; + + _patch_main_loop_input_handlers[_patch_main_loop_num_input_handlers++] = input_handler_hook; + } else { + log_die("Out of memory"); + } + + pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock); + + log_debug("Added input handler %p of lib %s", input_handler_hook, lib_with_handler_impl); +} + +int XPending(Display* display) +{ + if (!_patch_main_loop_real_XPending) { + _patch_main_loop_real_XPending = (XPending_t) cnh_lib_get_func_addr("XPending"); + } + + /* poll the original SIGALRM handler to drive the pump engine */ + if (_patch_main_loop_sigalarm_orig_handler) { + _patch_main_loop_sigalarm_orig_handler(SIGALRM); + } + + return _patch_main_loop_real_XPending(display); +} + +int XNextEvent(Display* display, XEvent* event_return) +{ + int res; + KeySym key; + + if (!_patch_main_loop_real_XNextEvent) { + _patch_main_loop_real_XNextEvent = (XNextEvent_t) cnh_lib_get_func_addr("XNextEvent"); + } + + /* Trap KeyPress and KeyRelease events */ + res = _patch_main_loop_real_XNextEvent(display, event_return); + + switch (event_return->type) { + case KeyPress: + { + /* Mask out the modifier states X11 sets and read again */ + event_return->xkey.state &= ~ShiftMask; + event_return->xkey.state &= ~LockMask; + + XLookupString(&event_return->xkey, 0, 0, &key, 0); + + /* Swallow some keys to disable them */ + if (_patch_main_loop_disable_built_in_inputs) { + if (key == XK_F1 || key == XK_F2 || key == XK_F3) { + event_return->type = GenericEvent; + } + } + + /* Swallow all built-in inputs of the MK3 ports */ + if (_patch_main_loop_disable_mk3_linux_ports_built_in_inputs) { + if (key == XK_g || key == XK_h || key == XK_j || key == XK_k || key == XK_l || + key == XK_q || key == XK_e || key == XK_s || key == XK_z || key == XK_c || + key == XK_KP_7 || key == XK_KP_9 || key == XK_KP_5 || key == XK_KP_1 || key == XK_KP_3) { + event_return->type = GenericEvent; + } + } + + /* Dispatch to external input handlers */ + if (_patch_main_loop_num_input_handlers > 0) { + pthread_mutex_lock(&_patch_main_loop_input_handlers_lock); + + for (size_t i = 0; i < _patch_main_loop_num_input_handlers; i++) { + if (_patch_main_loop_input_handlers[i]->dispatch_key_press) { + _patch_main_loop_input_handlers[i]->dispatch_key_press(key); + } + } + + pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock); + } + + break; + } + + case KeyRelease: + { + /* Mask out the modifier states X11 sets and read again */ + event_return->xkey.state &= ~ShiftMask; + event_return->xkey.state &= ~LockMask; + + XLookupString(&event_return->xkey, 0, 0, &key, 0); + + /* Swallow some keys to disable them */ + if (_patch_main_loop_disable_built_in_inputs) { + if (key == XK_F1 || key == XK_F2 || key == XK_F3) { + event_return->type = GenericEvent; + } + } + + /* Swallow all built-in inputs of the MK3 ports */ + if (_patch_main_loop_disable_mk3_linux_ports_built_in_inputs) { + if (key == XK_g || key == XK_h || key == XK_j || key == XK_k || key == XK_l || + key == XK_q || key == XK_e || key == XK_s || key == XK_z || key == XK_c || + key == XK_KP_7 || key == XK_KP_9 || key == XK_KP_5 || key == XK_KP_1 || key == XK_KP_3) { + event_return->type = GenericEvent; + } + } + + /* Dispatch to external input handlers */ + if (_patch_main_loop_num_input_handlers > 0) { + /* Dispatch release if key is not repeated */ + if (!_patch_main_loop_is_key_repeated(display, event_return)) { + pthread_mutex_lock(&_patch_main_loop_input_handlers_lock); + + for (size_t i = 0; i < _patch_main_loop_num_input_handlers; i++) { + if (_patch_main_loop_input_handlers[i]->dispatch_key_release) { + _patch_main_loop_input_handlers[i]->dispatch_key_release(key); + } + } + + pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock); + } + } + + break; + } + + default: + break; + } + + return res; +} + +static void _patch_main_loop_sigalarm_handler(int signal, __sighandler_t orig_handler) +{ + /* do nothing on sigalrm */ + _patch_main_loop_sigalarm_orig_handler = orig_handler; +} + +static bool _patch_main_loop_is_key_repeated(Display* display, XEvent* event) +{ + /* When a key is repeated, there will be two events: released, followed by another immediate pressed. + So check to see if another pressed is present */ + if (!_patch_main_loop_real_XPending(display)) { + return false; + } + + XEvent e; + XPeekEvent(display, &e); + + if (e.type == KeyPress && e.xkey.keycode == event->xkey.keycode && (e.xkey.time - event->xkey.time) < 2) { + _patch_main_loop_real_XNextEvent(display, &e); + return true; + } + + return false; +} \ No newline at end of file diff --git a/src/main/hook/patch/main-loop.h b/src/main/hook/patch/main-loop.h new file mode 100644 index 0000000..83f9e2d --- /dev/null +++ b/src/main/hook/patch/main-loop.h @@ -0,0 +1,59 @@ +/** + * This module fixes different things on the main loop of the game. + * + * First, it hooks into the X11 event loop to grab and dispatch inputs for + * further IO hooks or input emulation. + * + * The second thing is quite stupid and fixes crashing on newer kernels + * because AM used sigalarm to drive certain parts of their engine. + * This only applies to one generation of the game engine which includes the + * releases: Exceed, Exceed2, Zero and NX + * + * Detailed analysis: + * + * AM decided to poll the CPIU::Update function which contains updating + * the render state as well as decoding sound data, using the signal SIGALRM. + * This signal is triggered periodically and drives the whole engine. + * But, starting kernel versions newer than 2.4.27 something changed which + * causes the game to deadlock an _ALL_ kernels newer than said version. Trying + * to fix the deadlock issue makes things even worse and only introduces + * segfaults with random crashes. So this is not the right approach. + * Starting NX2 AM used a newer kernel and apparently got the same problem + * with their OS. They fixed it by moving music_send_data from CPIU::Update() + * to the IO thread. Splitting CPIU::Update that way, this seems to work fine. + * However, trying this with the old games lacking the patch, we are getting + * segfaults (again). + * It looks like there is an issue with firing and/or handling of SIGALRM in + * another thread than the main thread (don't ask me why). This leads to the + * solution of the problem: moving the call of CPIU::Update()to the main + * thread which is only pumping XEvents (i.e. nothing). + * So let's give the main thread some work: Detouring XPending and calling + * the registered signal handler for SIGALRM of the game in there and muting + * signal handling for SIGALRM. This solves all deadlocking and segfault + * issues which are related to audio playback in combination with decoding a + * video. + */ +#ifndef PATCH_MAIN_LOOP_H +#define PATCH_MAIN_LOOP_H + +#include +#include + +/** + * Initialize the patch module + * + * @param fix_sigalarm_main_loop True to enable the sigalarm thread fix (doc see above) + * @param disable_built_in_inputs Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3) + * @param disable_mk3_linux_port_inputs Disable the built-in keyboard inputs on the MK3 linux ports + */ +void patch_main_loop_init(bool fix_sigalarm_main_loop, bool disable_built_in_inputs, + bool disable_mk3_linux_port_inputs); + +/** + * Register a handler (multiple possible) to receive X11 input events, e.g. key pressed, released + * + * @param lib_with_handler_impl Path to a library implementing the x11-input-handler API + */ +void patch_main_loop_add_x11_input_handler(const char* lib_with_handler_impl); + +#endif diff --git a/src/main/hook/patch/microdog34.c b/src/main/hook/patch/microdog34.c new file mode 100644 index 0000000..110734c --- /dev/null +++ b/src/main/hook/patch/microdog34.c @@ -0,0 +1,72 @@ +#define LOG_MODULE "patch-microdog34" + +#define USBDOG_ENDPOINT "/dev/usbdog" + +#include +#include +#include + +#include "capnhook/hook/iohook.h" + +#include "sec/microdog34/microdog34.h" + +#include "util/log.h" + +static int _patch_microdog34_fd = -1; + +enum cnh_result patch_microdog34_iohook(struct cnh_iohook_irp *irp); + +void patch_microdog34_init(const uint8_t* key_data, size_t len) +{ + sec_microdog34_init(key_data, len); + + cnh_iohook_push_handler(patch_microdog34_iohook); + log_info("Initialized"); +} + +enum cnh_result patch_microdog34_iohook(struct cnh_iohook_irp *irp) +{ + if (irp->op != CNH_IOHOOK_IRP_OP_OPEN && irp->fd != _patch_microdog34_fd) { + return cnh_iohook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_IOHOOK_IRP_OP_OPEN: + { + if (!strcmp(irp->open_filename, USBDOG_ENDPOINT)) { + _patch_microdog34_fd = cnh_iohook_open_dummy_fd(); + irp->fd = _patch_microdog34_fd; + return CNH_RESULT_SUCCESS; + } + + return cnh_iohook_invoke_next(irp); + } + + case CNH_IOHOOK_IRP_OP_CLOSE: + { + assert(irp->fd); + + cnh_iohook_close_dummy_fd(irp->fd); + _patch_microdog34_fd = -1; + + return CNH_RESULT_SUCCESS; + } + + case CNH_IOHOOK_IRP_OP_READ: + { + /* Just stub and return success */ + return CNH_RESULT_SUCCESS; + } + + case CNH_IOHOOK_IRP_OP_IOCTL: + { + irp->ioctl.pos = (size_t) sec_microdog34_process(irp->ioctl_req, irp->ioctl.bytes); + + return CNH_RESULT_SUCCESS; + } + + default: + log_die("Unhandled operation: %d", irp->op); + return CNH_RESULT_OTHER_ERROR; + } +} \ No newline at end of file diff --git a/src/main/hook/patch/microdog34.h b/src/main/hook/patch/microdog34.h new file mode 100644 index 0000000..9ec63c4 --- /dev/null +++ b/src/main/hook/patch/microdog34.h @@ -0,0 +1,15 @@ +/** + * Patch module to install the dongle emulator for a microdog 3.4 + */ +#ifndef PATCH_MICRODOG34_H +#define PATCH_MICRODOG34_H + +/** + * Initialize the patch module + * + * @param key_data Pointer to loaded key data (dog attributes, key table) + * @param len Length of the buffer + */ +void patch_microdog34_init(const uint8_t* key_data, size_t len); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/microdog40.c b/src/main/hook/patch/microdog40.c new file mode 100644 index 0000000..0f53168 --- /dev/null +++ b/src/main/hook/patch/microdog40.c @@ -0,0 +1,40 @@ +#define LOG_MODULE "patch-microdog40" + +#include + +#include "sec/microdog40/microdog40d.h" + +#include "util/log.h" + +static pthread_t patch_microdog40_thread; + +static void* patch_microdog40_thread_run(void* args) +{ + log_info("Running daemon thread"); + + sec_microdog40d_run(); + + log_info("Finished daemon thread"); + + return NULL; +} + +void patch_microdog40_init(const uint8_t* key_data, size_t len) +{ + sec_microdog40d_init(key_data, len); + + /* Run the daemon in another thread */ + pthread_create(&patch_microdog40_thread, NULL, + patch_microdog40_thread_run, NULL); + + log_info("Initialized"); +} + +void patch_microdog40_shutdown(void) +{ + log_info("Shutting down"); + + sec_microdog40d_shutdown(); + + pthread_join(patch_microdog40_thread, NULL); +} \ No newline at end of file diff --git a/src/main/hook/patch/microdog40.h b/src/main/hook/patch/microdog40.h new file mode 100644 index 0000000..4cef422 --- /dev/null +++ b/src/main/hook/patch/microdog40.h @@ -0,0 +1,20 @@ +/** + * Patch module to install the dongle emulator for a microdog 4.0 + */ +#ifndef PATCH_MICRODOG34_H +#define PATCH_MICRODOG34_H + +/** + * Initialize the patch module + * + * @param key_data Pointer to loaded key data (dog attributes, key table) + * @param len Length of the buffer + */ +void patch_microdog40_init(const uint8_t* key_data, size_t len); + +/** + * Shutdown and remove the emulator + */ +void patch_microdog40_shutdown(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/mounts.c b/src/main/hook/patch/mounts.c new file mode 100644 index 0000000..cd8f8c0 --- /dev/null +++ b/src/main/hook/patch/mounts.c @@ -0,0 +1,105 @@ +#define LOG_MODULE "patch-mounts" + +#include +#include +#include +#include + +#include "capnhook/hook/filehook.h" + +#include "util/log.h" + +/* looks odd but hddd is intentional */ +static const char* patch_mount_proc_mount_file = "/dev/hddd /mnt/hd"; + +static FILE* patch_mount_file = NULL; +static bool patch_mount_eof; + +static enum cnh_result patch_hdd_check_filehook(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + result = CNH_RESULT_SUCCESS; + + assert(irp); + + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != patch_mount_file) { + return cnh_filehook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_FILEHOOK_IRP_OP_OPEN: + { + if (!strcmp(irp->open_filename, "/proc/mounts")) { + patch_mount_file = cnh_filehook_open_dummy_file_handle(); + irp->file = patch_mount_file; + + patch_mount_eof = false; + + log_debug("/proc/mounts opened: %p", irp->file); + } else { + return cnh_filehook_invoke_next(irp); + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_FGETS: + { + size_t size; + + log_info("/proc/mounts fake read"); + + size = strlen(patch_mount_proc_mount_file) + 1; + + /* +1: copy the null terminator, too */ + memcpy(&irp->read.bytes[irp->read.pos], patch_mount_proc_mount_file, size); + irp->read.pos += size; + + patch_mount_eof = true; + + break; + } + + case CNH_FILEHOOK_IRP_OP_SEEK: + { + /* Ignore seeking */ + + break; + } + + case CNH_FILEHOOK_IRP_OP_TELL: + { + /* Return size */ + irp->tell_offset = strlen(patch_mount_proc_mount_file) + 1; + + break; + } + + case CNH_FILEHOOK_IRP_OP_EOF: + { + irp->eof = patch_mount_eof; + break; + } + + case CNH_FILEHOOK_IRP_OP_CLOSE: + { + patch_mount_file = NULL; + + /* Actually close dummy handle */ + return cnh_filehook_invoke_next(irp); + } + + default: + log_warn("Unhandled file op: %d", irp->op); + break; + } + + return result; +} + +void patch_mounts_init(void) +{ + cnh_filehook_push_handler(patch_hdd_check_filehook); + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/mounts.h b/src/main/hook/patch/mounts.h new file mode 100644 index 0000000..6651c7c --- /dev/null +++ b/src/main/hook/patch/mounts.h @@ -0,0 +1,13 @@ +/** + * Starting NX2, the game is checking /proc/mounts for the entry + * "/dev/hddd /mnt/hd" -> hook and inject that + */ +#ifndef PATCH_MOUNTS_H +#define PATCH_MOUNTS_H + +/** + * Initialize the patch module + */ +void patch_mounts_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/net-profile.c b/src/main/hook/patch/net-profile.c new file mode 100644 index 0000000..7a9b038 --- /dev/null +++ b/src/main/hook/patch/net-profile.c @@ -0,0 +1,594 @@ +#define LOG_MODULE "patch-net-profile" + +#include +#include + +#include "asset/nx2/lib/usb-rank.h" +#include "asset/nx2/lib/usb-save.h" + +#include "capnhook/hook/filehook.h" + +#include "pumpnet/lib/profile-token.h" +#include "pumpnet/lib/pumpnet.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/time.h" + +#define PUMPNET_MAX_NUM_PLAYERS 2 +#define PUMPNET_PROFILE_FILE_NAME "pumpnet.bin" +#define PUMPNET_TRY_CONNECT_TIMEOUT_MS 2000 + +struct profile_virtual_mnt_point_file_info { + int player; + enum pumpnet_lib_file_type file_type; + const char* file_path; + size_t file_size; +}; + +struct profile_virtual_mnt_point_info { + struct { + struct profile_virtual_mnt_point_file_info file_info[PUMPNET_LIB_FILE_TYPE_COUNT]; + } player[PUMPNET_MAX_NUM_PLAYERS]; +}; + +struct profile_virtual_file { + uint64_t player_ref_id; + FILE* handle; + const struct profile_virtual_mnt_point_file_info* file_info; + size_t buffer_pos; + uint8_t* buffer; + bool is_written; +}; + +struct profile_virtual_mnt_point { + struct profile_virtual_file files[PUMPNET_LIB_FILE_TYPE_COUNT]; +}; + +static enum cnh_result _patch_net_profile_filehook(struct cnh_filehook_irp* irp); +static enum cnh_result _patch_net_profile_fopen(struct cnh_filehook_irp* irp); +static enum cnh_result _patch_net_profile_fclose(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file); +static enum cnh_result _patch_net_profile_fread(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file); +static enum cnh_result _patch_net_profile_fwrite(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file); +static enum cnh_result _patch_net_profile_fseek(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file); +static enum cnh_result _patch_net_profile_ftell(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file); +static enum cnh_result _patch_net_profile_feof(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file); + +static struct profile_virtual_file* _patch_net_profile_get_virtual_mnt_point(FILE* handle); +static bool _patch_net_profile_determine_is_profile_and_player_and_file_type( + struct cnh_filehook_irp* irp, + uint8_t* player, + enum pumpnet_lib_file_type* file_type); +static enum cnh_result _patch_net_profile_open_pumpnet_profile_file( + struct cnh_filehook_irp* irp, + uint8_t player, + enum pumpnet_lib_file_type file_type); +static bool _patch_net_profile_close_pumpnet_profile_file(struct profile_virtual_file* virtual_file); + +static const struct profile_virtual_mnt_point_info _patch_net_profile_virtual_mnt_point_infos[] = { + { + .player = { + { + .file_info = { + { + .player = 0, + .file_type = PUMPNET_LIB_FILE_TYPE_SAVE, + .file_path = "/mnt/0/nx2save.bin", + .file_size = ASSET_NX2_USB_SAVE_SIZE + }, + { + .player = 0, + .file_type = PUMPNET_LIB_FILE_TYPE_RANK, + .file_path = "/mnt/0/nx2rank.bin", + .file_size = ASSET_NX2_USB_RANK_SIZE + } + } + }, + { + .file_info = { + { + .player = 1, + .file_type = PUMPNET_LIB_FILE_TYPE_SAVE, + .file_path = "/mnt/1/nx2save.bin", + .file_size = ASSET_NX2_USB_SAVE_SIZE + }, + { + .player = 1, + .file_type = PUMPNET_LIB_FILE_TYPE_RANK, + .file_path = "/mnt/1/nx2rank.bin", + .file_size = ASSET_NX2_USB_RANK_SIZE + } + } + }, + } + } +}; + +static const struct profile_virtual_mnt_point_info* _patch_net_profile_file_info_ref; +static struct profile_virtual_mnt_point _patch_net_profile_virtual_mnt_points[PUMPNET_MAX_NUM_PLAYERS]; +static pthread_mutex_t _patch_net_profile_mutex; + +static enum cnh_result _patch_net_profile_filehook(struct cnh_filehook_irp* irp) +{ + if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN) { + return _patch_net_profile_fopen(irp); + } else { + struct profile_virtual_file* virt_file = _patch_net_profile_get_virtual_mnt_point(irp->file); + + if (virt_file != NULL) { + switch (irp->op) { + case CNH_FILEHOOK_IRP_OP_CLOSE: + return _patch_net_profile_fclose(irp, virt_file); + + case CNH_FILEHOOK_IRP_OP_READ: + return _patch_net_profile_fread(irp, virt_file); + + case CNH_FILEHOOK_IRP_OP_WRITE: + return _patch_net_profile_fwrite(irp, virt_file); + + case CNH_FILEHOOK_IRP_OP_FGETS: + log_die("Unsupported operation"); + return CNH_RESULT_OTHER_ERROR; + + case CNH_FILEHOOK_IRP_OP_SEEK: + return _patch_net_profile_fseek(irp, virt_file); + + case CNH_FILEHOOK_IRP_OP_TELL: + return _patch_net_profile_ftell(irp, virt_file); + + case CNH_FILEHOOK_IRP_OP_EOF: + return _patch_net_profile_feof(irp, virt_file); + + default: + log_die("Unhandled switch case"); + return CNH_RESULT_OTHER_ERROR; + } + } else { + return cnh_filehook_invoke_next(irp); + } + } +} + +static enum cnh_result _patch_net_profile_fopen(struct cnh_filehook_irp* irp) +{ + uint8_t player; + enum pumpnet_lib_file_type file_type; + player = -1; + file_type = PUMPNET_LIB_FILE_TYPE_COUNT; + + // not a profile file, pass + if (!_patch_net_profile_determine_is_profile_and_player_and_file_type(irp, &player, &file_type)) { + return cnh_filehook_invoke_next(irp); + } + + return _patch_net_profile_open_pumpnet_profile_file(irp, player, file_type); +} + +static enum cnh_result _patch_net_profile_fclose(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file) +{ + log_debug("fclose %s", virtual_file->file_info->file_path); + + return _patch_net_profile_close_pumpnet_profile_file(virtual_file) ? CNH_RESULT_SUCCESS : CNH_RESULT_OTHER_ERROR; +} + +static enum cnh_result _patch_net_profile_fread(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file) +{ + uint32_t len; + + pthread_mutex_lock(&_patch_net_profile_mutex); + + log_debug("fread %s, pos 0x%X, bytes %d", virtual_file->file_info->file_path, virtual_file->buffer_pos, + irp->read.nbytes); + + /* read up to eof, only */ + if (virtual_file->buffer_pos + irp->read.nbytes < virtual_file->file_info->file_size) { + len = irp->read.nbytes; + } else { + len = virtual_file->file_info->file_size - virtual_file->buffer_pos; + } + + memcpy(&irp->read.bytes[irp->read.pos], virtual_file->buffer + virtual_file->buffer_pos, len); + + virtual_file->buffer_pos += len; + irp->read.pos += len; + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_net_profile_fwrite(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file) +{ + uint32_t len; + + pthread_mutex_lock(&_patch_net_profile_mutex); + + log_debug("fwrite %s, pos 0x%X, bytes %d", virtual_file->file_info->file_path, virtual_file->buffer_pos, + irp->read.nbytes); + + /* write up to eof, only */ + if (virtual_file->buffer_pos + irp->write.nbytes < virtual_file->file_info->file_size) { + len = irp->write.nbytes; + } else { + len = virtual_file->file_info->file_size - virtual_file->buffer_pos; + } + + memcpy(virtual_file->buffer + virtual_file->buffer_pos, irp->write.bytes, len); + + virtual_file->buffer_pos += len; + virtual_file->is_written = true; + irp->write.pos += len; + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_net_profile_fseek(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file) +{ + pthread_mutex_lock(&_patch_net_profile_mutex); + + switch (irp->seek_origin) { + case SEEK_SET: + virtual_file->buffer_pos = (size_t) irp->seek_offset; + break; + + case SEEK_CUR: + virtual_file->buffer_pos += (size_t) irp->seek_offset; + break; + + case SEEK_END: + virtual_file->buffer_pos = virtual_file->file_info->file_size; + virtual_file->buffer_pos += (size_t) irp->seek_offset; + break; + + default: + log_die("Unhandled origin %d", irp->seek_origin); + break; + } + + log_debug("fseek %s, offset 0x%X, origin %d", virtual_file->file_info->file_path, irp->seek_offset, + irp->seek_origin); + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_net_profile_ftell(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file) +{ + pthread_mutex_lock(&_patch_net_profile_mutex); + + irp->tell_offset = virtual_file->buffer_pos; + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_net_profile_feof(struct cnh_filehook_irp* irp, + struct profile_virtual_file* virtual_file) +{ + pthread_mutex_lock(&_patch_net_profile_mutex); + + irp->eof = virtual_file->buffer_pos == virtual_file->file_info->file_size; + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_SUCCESS; +} + +// ===================================================================================================================== + +static struct profile_virtual_file* _patch_net_profile_get_virtual_mnt_point(FILE* handle) +{ + for (int i = 0; i < PUMPNET_MAX_NUM_PLAYERS; i++) { + for (int j = 0; j < PUMPNET_LIB_FILE_TYPE_COUNT; j++) { + if (_patch_net_profile_virtual_mnt_points->files[j].handle == handle) { + return &_patch_net_profile_virtual_mnt_points->files[j]; + } + } + } + + return NULL; +} + +static bool _patch_net_profile_determine_is_profile_and_player_and_file_type( + struct cnh_filehook_irp* irp, + uint8_t* player, + enum pumpnet_lib_file_type* file_type) +{ + log_assert(irp); + log_assert(player); + log_assert(file_type); + + // compare to static string to avoid slowing everything down + for (int i = 0; i < PUMPNET_MAX_NUM_PLAYERS; i++) { + for (int j = 0; j < PUMPNET_LIB_FILE_TYPE_COUNT; j++) { + if (!strcmp(irp->open_filename, + _patch_net_profile_virtual_mnt_point_infos->player[i].file_info[j].file_path)) { + *player = i; + *file_type = (enum pumpnet_lib_file_type) j; + return true; + } + } + } + + return false; +} + +static struct profile_virtual_file* _patch_net_profile_setup_virtual_file( + uint8_t player, + enum pumpnet_lib_file_type file_type, + uint64_t player_ref_id) +{ + struct profile_virtual_file* virtual_file; + + log_debug("Setup virtual file, player %d, file_type %d", player, file_type); + + virtual_file = &_patch_net_profile_virtual_mnt_points[player].files[file_type]; + + // sanity checks + log_assert(!virtual_file->handle); + log_assert(!virtual_file->file_info); + log_assert(!virtual_file->buffer); + + virtual_file->player_ref_id = player_ref_id; + virtual_file->handle = cnh_filehook_open_dummy_file_handle(); + virtual_file->file_info = &_patch_net_profile_virtual_mnt_point_infos->player[player].file_info[file_type]; + virtual_file->buffer_pos = 0; + virtual_file->is_written = false; + + virtual_file->buffer = (uint8_t*) malloc(virtual_file->file_info->file_size); + + log_debug("Setup virtual file done, size %d", virtual_file->file_info->file_size); + + return virtual_file; +} + +static void _patch_net_profile_destroy_virtual_file(uint8_t player, enum pumpnet_lib_file_type file_type) +{ + struct profile_virtual_file* virtual_file; + + log_debug("Destroying virtual file, player %d, file_type %d", player, file_type); + + virtual_file = &_patch_net_profile_virtual_mnt_points[player].files[file_type]; + + // sanity checks + log_assert(virtual_file->handle); + log_assert(virtual_file->file_info); + log_assert(virtual_file->buffer); + + cnh_filehook_close_dummy_file_handle(virtual_file->handle); + virtual_file->handle = NULL; + virtual_file->file_info = NULL; + free(virtual_file->buffer); + virtual_file->buffer = NULL; +} + +static bool _patch_net_profile_get_token(int player, uint64_t* player_ref_id) +{ + log_assert(player_ref_id); + log_assert(player >= 0); + log_assert(player <= 1); + + char path_profile_token[128]; + + *player_ref_id = 0; + + sprintf(path_profile_token, "/mnt/%d/%s", player, PUMPNET_PROFILE_FILE_NAME); + + if (util_fs_path_exists(path_profile_token)) { + log_info("Found pumpnet profile file %s", path_profile_token); + + if (pumpnet_lib_profile_token_load(path_profile_token, player_ref_id)) { + return true; + } else { + log_error("Loading pumpnet profile token %s failed, fallback to local profiles", path_profile_token); + } + } else { + log_info("No pumpnet profile found, fallback to local profile"); + } + + return false; +} + +static bool _patch_net_profile_download_profile_file(struct profile_virtual_file* virtual_file) +{ + int player; + enum pumpnet_lib_file_type file_type; + uint64_t player_ref_id; + + player = virtual_file->file_info->player; + file_type = virtual_file->file_info->file_type; + player_ref_id = virtual_file->player_ref_id; + + log_info("Profile file player %d, file_type %d, refId %llX downloading from server...", + player, + file_type, + player_ref_id); + + if (!pumpnet_lib_get(file_type, player_ref_id, virtual_file->buffer, virtual_file->file_info->file_size)) { + log_error("Downloading file player %d, file_type %d, refId %llX failed", + player, + file_type, + player_ref_id); + return false; + } + + log_info("Downloading file player %d, file_type %d, refId %llX successful", + player, + file_type, + player_ref_id); + return true; +} + +static enum cnh_result _patch_net_profile_open_pumpnet_profile_file( + struct cnh_filehook_irp* irp, + uint8_t player, + enum pumpnet_lib_file_type file_type) +{ + uint64_t player_ref_id; + + log_debug("open %s %d %d", irp->open_filename, player, file_type); + + // check if pumpnet.bin token is available and server reachable + // download all profile files on the first file request and hook all following files to virtual endpoints of + // the already downloaded and buffered data + if (_patch_net_profile_get_token(player, &player_ref_id)) { + struct profile_virtual_file* virtual_file = + _patch_net_profile_setup_virtual_file(player, file_type, player_ref_id); + + if (_patch_net_profile_download_profile_file(virtual_file)) { + irp->file = virtual_file->handle; + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_SUCCESS; + } else { + _patch_net_profile_destroy_virtual_file(player, file_type); + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return CNH_RESULT_NO_SUCH_FILE_OR_DIR; + } + } + + return cnh_filehook_invoke_next(irp); +} + +static bool _patch_net_profile_upload_profile_file(struct profile_virtual_file* virtual_file) +{ + int player; + enum pumpnet_lib_file_type file_type; + uint64_t player_ref_id; + + player = virtual_file->file_info->player; + file_type = virtual_file->file_info->file_type; + player_ref_id = virtual_file->player_ref_id; + + log_info("Profile file player %d, file_type %d, refId %llX uploading to server...", + player, + file_type, + player_ref_id); + + if (!pumpnet_lib_put(file_type, player_ref_id, virtual_file->buffer, virtual_file->file_info->file_size)) { + log_error("Uploading file player %d, file_type %d, refId %llX failed", + player, + file_type, + player_ref_id); + return false; + } + + log_info("Uploading file player %d, file_type %d, refId %llX successful", + player, + file_type, + player_ref_id); + return true; +} + +static bool _patch_net_profile_close_pumpnet_profile_file(struct profile_virtual_file* virtual_file) +{ + bool res = true; + + pthread_mutex_lock(&_patch_net_profile_mutex); + + if (virtual_file->is_written) { + res = _patch_net_profile_upload_profile_file(virtual_file); + } + + _patch_net_profile_destroy_virtual_file(virtual_file->file_info->player, virtual_file->file_info->file_type); + + pthread_mutex_unlock(&_patch_net_profile_mutex); + + return res; +} + +// ===================================================================================================================== + +void patch_net_profile_init( + enum asset_game_version game, + const char* pumpnet_server_addr, + uint64_t machine_id, + const char* cert_dir_path, + bool verbose_debug_log) +{ + uint8_t idx; + + /* use a switch instead of offset'ing the enum for additional safety and block unsupported games */ + switch (game) { + case ASSET_GAME_VERSION_NX2: + idx = 0; + break; + +// case PUMPNET_LIB_GAME_NXA: +// idx = 1; +// break; +// +// case PUMPNET_LIB_GAME_FST: +// idx = 2; +// break; +// +// case PUMPNET_LIB_GAME_FEX: +// idx = 3; +// break; +// +// case PUMPNET_LIB_GAME_F2: +// idx = 4; +// break; + case ASSET_GAME_VERSION_NXA: + case ASSET_GAME_VERSION_FIESTA: + case ASSET_GAME_VERSION_FIESTA_EX: + case ASSET_GAME_VERSION_FIESTA_2: + + default: + log_error("Unsupported game version %d specified, disabled network service", game); + return; + } + + _patch_net_profile_file_info_ref = &_patch_net_profile_virtual_mnt_point_infos[idx]; + + size_t max_data_size = 0; + + // determine max file size for network buffers, file sizes identical on for all players. + for (int i = 0; i < PUMPNET_LIB_FILE_TYPE_COUNT; i++) { + max_data_size += _patch_net_profile_file_info_ref->player[0].file_info[i].file_size; + } + + // set buffers to NULL to detect illegal states + for (int i = 0; i < PUMPNET_LIB_FILE_TYPE_COUNT; i++) { + for (int j = 0; j < PUMPNET_MAX_NUM_PLAYERS; j++) { + _patch_net_profile_virtual_mnt_points[j].files[i].player_ref_id = 0; + _patch_net_profile_virtual_mnt_points[j].files[i].handle = NULL; + _patch_net_profile_virtual_mnt_points[j].files[i].file_info = NULL; + _patch_net_profile_virtual_mnt_points[j].files[i].buffer = NULL; + } + } + + pumpnet_lib_init(game, pumpnet_server_addr, machine_id, cert_dir_path, verbose_debug_log); + + cnh_filehook_push_handler(_patch_net_profile_filehook); + + pthread_mutex_init(&_patch_net_profile_mutex, NULL); + + log_info("Initialized: game %d, server %s, machine id %llX", game, pumpnet_server_addr, machine_id); +} + +void patch_net_profile_shutdown() +{ + pumpnet_lib_shutdown(); + + pthread_mutex_destroy(&_patch_net_profile_mutex); + + log_info("Shut down"); +} \ No newline at end of file diff --git a/src/main/hook/patch/net-profile.h b/src/main/hook/patch/net-profile.h new file mode 100644 index 0000000..2d5e254 --- /dev/null +++ b/src/main/hook/patch/net-profile.h @@ -0,0 +1,31 @@ +/** + * Patch module to redirect profile saving and loading to a pumpnet server (NX2 to Fiesta 2). + */ +#ifndef HOOK_PATCH_NET_PROFILE_H +#define HOOK_PATCH_NET_PROFILE_H + +#include "pumpnet/lib/pumpnet.h" + +/** + * Initialize the module. + * + * @param game Game version to run this module on + * @param pumpnet_server_addr Server address of pumpnet to connect to + * @param machine_id Machine ID to use for authentication + * @param cert_dir_path Path to a directory containing the client cert, client key and CA cert bundle to enable https + * communication + * @param verbose_debug_log Enable verbose debug log output, e.g. network backend logging/traffic. + */ +void patch_net_profile_init( + enum asset_game_version game, + const char* pumpnet_server_addr, + uint64_t machine_id, + const char* cert_dir_path, + bool verbose_debug_log); + +/** + * Shut down the module. + */ +void patch_net_profile_shutdown(); + +#endif diff --git a/src/main/hook/patch/network.c b/src/main/hook/patch/network.c new file mode 100644 index 0000000..aea31dc --- /dev/null +++ b/src/main/hook/patch/network.c @@ -0,0 +1,96 @@ +#define LOG_MODULE "patch-network" + +#include +#include + +#include "capnhook/hook/lib.h" + +#include "util/list.h" +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +struct patch_network_redirect_elem { + struct util_list_node head; + char* orig_ipv4; + char* new_ipv4; + uint16_t new_port; +}; + +typedef int (*connect_t) (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len); + +static connect_t patch_network_real_connect; + +static bool patch_network_initialized; +static struct util_list patch_network_redirect_list; + +int connect(int fd, __CONST_SOCKADDR_ARG addr, socklen_t len) +{ + if (!patch_network_real_connect) { + patch_network_real_connect = (connect_t) cnh_lib_get_func_addr("connect"); + } + + if (patch_network_initialized) { + if (addr.__sockaddr__->sa_family == AF_INET) { + log_debug("connect ipv4 %d.%d.%d.%d:%d", + addr.__sockaddr_in__->sin_addr.s_addr & 0xFF, + addr.__sockaddr_in__->sin_addr.s_addr >> 8 & 0xFF, + addr.__sockaddr_in__->sin_addr.s_addr >> 16 & 0xFF, + addr.__sockaddr_in__->sin_addr.s_addr >> 24 & 0xFF, + addr.__sockaddr_in__->sin_port); + + struct util_list_node* pos; + struct patch_network_redirect_elem* elem; + struct sockaddr_in tmp; + + for (pos = patch_network_redirect_list.head; pos != NULL; pos = pos->next) { + elem = containerof(pos, struct patch_network_redirect_elem, head); + + inet_aton(elem->orig_ipv4, &tmp.sin_addr); + + if (addr.__sockaddr_in__->sin_addr.s_addr == tmp.sin_addr.s_addr) { + char* tmp_old = inet_ntoa(addr.__sockaddr_in__->sin_addr); + log_info("Redirect %s:%d -> %s:%d", tmp_old, + ((struct sockaddr_in*) addr.__sockaddr_in__)->sin_port, elem->new_ipv4, + elem->new_port != 0xFFFF ? elem->new_port : + ((struct sockaddr_in*) addr.__sockaddr_in__)->sin_port); + + inet_aton(elem->new_ipv4, &((struct sockaddr_in*) addr.__sockaddr_in__)->sin_addr); + + if (elem->new_port != 0xFFFF) { + ((struct sockaddr_in*) addr.__sockaddr_in__)->sin_port = htons(elem->new_port); + } + } + } + } else { + log_debug("connect, addr family: %d", addr.__sockaddr__->sa_family); + } + } + + return patch_network_real_connect(fd, addr, len); +} + +void patch_network_init() +{ + util_list_init(&patch_network_redirect_list); + patch_network_initialized = true; + log_info("Initialized"); +} + +void patch_network_redirect_server_address(const char* orig_ipv4, const char* new_ipv4, uint16_t new_port) +{ + struct patch_network_redirect_elem* elem; + + elem = util_xmalloc(sizeof(struct patch_network_redirect_elem)); + elem->orig_ipv4 = util_str_dup(orig_ipv4); + elem->new_ipv4 = util_str_dup(new_ipv4); + elem->new_port = new_port; + + util_list_append(&patch_network_redirect_list, &elem->head); + + if (new_port != 0xFFFF) { + log_info("Add network redirect: %s -> %s:%d", orig_ipv4, new_ipv4, new_port); + } else { + log_info("Add network redirect: %s -> %s", orig_ipv4, new_ipv4); + } +} diff --git a/src/main/hook/patch/network.h b/src/main/hook/patch/network.h new file mode 100644 index 0000000..3548ff9 --- /dev/null +++ b/src/main/hook/patch/network.h @@ -0,0 +1,23 @@ +/** + * Redirect network traffic for game server (Prime and up). + */ +#ifndef PATCH_NETWORK_H +#define PATCH_NETWORK_H + +#include + +/** + * Initialize patch module + */ +void patch_network_init(); + +/** + * Redirect a server address + * + * @param orig_ipv4 IPV4 address of the original server + * @param new_ipv4 IPV4 address of the new server to redirect to + * @param new_port Port of server to redirect to (-1 to keep old port) + */ +void patch_network_redirect_server_address(const char* orig_ipv4, const char* new_ipv4, uint16_t new_port); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/piubtn.c b/src/main/hook/patch/piubtn.c new file mode 100644 index 0000000..3a8526b --- /dev/null +++ b/src/main/hook/patch/piubtn.c @@ -0,0 +1,292 @@ +#define LOG_MODULE "patch-piubtn" + +#include +#include +#include +#include + +#include "capnhook/hook/lib.h" +#include "capnhook/hooklib/usb-emu.h" + +#include "io/piubtn/defs.h" + +#include "ptapi/io/piubtn.h" + +#include "util/log.h" + +static bool _patch_piubtn_enumerate(bool real_exists); +static enum cnh_result _patch_piubtn_open(void); +static enum cnh_result _patch_piubtn_reset(void); +static enum cnh_result _patch_piubtn_control_msg(int request_type, int request, int value, int index, + struct cnh_iobuf* buffer, int timeout); +static void _patch_piubtn_close(void); + +static enum cnh_result _patch_piubtn_process_inputs(struct cnh_iobuf* buffer); +static enum cnh_result _patch_piubtn_process_outputs(struct cnh_iobuf* buffer); + +static ptapi_io_piubtn_ident_t _patch_piubtn_ptapi_io_piubtn_ident; +static ptapi_io_piubtn_open_t _patch_piubtn_ptapi_io_piubtn_open; +static ptapi_io_piubtn_close_t _patch_piubtn_ptapi_io_piubtn_close; +static ptapi_io_piubtn_recv_t _patch_piubtn_ptapi_io_piubtn_recv; +static ptapi_io_piubtn_send_t _patch_piubtn_ptapi_io_piubtn_send; +static ptapi_io_piubtn_get_input_t _patch_piubtn_ptapi_io_piubtn_get_input; +static ptapi_io_piubtn_set_output_t _patch_piubtn_ptapi_io_piubtn_set_output; + +static const struct cnh_usb_emu_virtdev_ep _patch_piubtn_virtdev = { + .pid = PIUBTN_DRV_PID, + .vid = PIUBTN_DRV_VID, + .enumerate = _patch_piubtn_enumerate, + .open = _patch_piubtn_open, + .reset = _patch_piubtn_reset, + .control_msg = _patch_piubtn_control_msg, + .close = _patch_piubtn_close, +}; + +static void* _patch_piubtn_api_lib_handle; + +void patch_piubtn_init(const char* piubtn_lib_path) +{ + if (!piubtn_lib_path) { + log_die("No piubtn emulation library path specified"); + } + + /* Load piubtn library funcs */ + log_info("Loading piubtn api implementation %s", piubtn_lib_path); + + _patch_piubtn_api_lib_handle = cnh_lib_load(piubtn_lib_path); + + _patch_piubtn_ptapi_io_piubtn_ident = (ptapi_io_piubtn_ident_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_ident"); + + _patch_piubtn_ptapi_io_piubtn_open = (ptapi_io_piubtn_open_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_open"); + _patch_piubtn_ptapi_io_piubtn_close = (ptapi_io_piubtn_close_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_close"); + _patch_piubtn_ptapi_io_piubtn_recv = (ptapi_io_piubtn_recv_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_recv"); + _patch_piubtn_ptapi_io_piubtn_send = (ptapi_io_piubtn_send_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_send"); + _patch_piubtn_ptapi_io_piubtn_get_input = (ptapi_io_piubtn_get_input_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_get_input"); + _patch_piubtn_ptapi_io_piubtn_set_output = (ptapi_io_piubtn_set_output_t) + cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_set_output"); + + cnh_usb_emu_add_virtdevep(&_patch_piubtn_virtdev); + + log_info("Initialized"); +} + +void patch_piubtn_shutdown(void) +{ + +} + +static bool _patch_piubtn_enumerate(bool real_exists) +{ + if (real_exists) { + log_info("Real PIUBTN exists but emulation enabled, blocking real"); + } else { + log_info("Enumerating PIUBTN emulation"); + } + + return true; +} + +static enum cnh_result _patch_piubtn_open(void) +{ + log_info("Opening PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident()); + + if (!_patch_piubtn_ptapi_io_piubtn_open()) { + log_error("Opening api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident()); + return CNH_RESULT_OTHER_ERROR; + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piubtn_reset(void) +{ + log_info("Resetting PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident()); + + _patch_piubtn_ptapi_io_piubtn_close(); + + if (!_patch_piubtn_ptapi_io_piubtn_open()) { + log_error("Resetting api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident()); + return CNH_RESULT_OTHER_ERROR; + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piubtn_control_msg(int request_type, int request, int value, int index, + struct cnh_iobuf* buffer, int timeout) +{ + if (request_type == PIUBTN_DRV_USB_CTRL_TYPE_IN && request == PIUBTN_DRV_USB_CTRL_REQUEST) { + if (buffer->nbytes != PIUBTN_DRV_BUFFER_SIZE) { + log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes); + return CNH_RESULT_INVALID_PARAMETER; + } + + return _patch_piubtn_process_inputs(buffer); + } else if (request_type == PIUBTN_DRV_USB_CTRL_TYPE_OUT && request == PIUBTN_DRV_USB_CTRL_REQUEST) { + if (buffer->nbytes != PIUBTN_DRV_BUFFER_SIZE) { + log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes); + return CNH_RESULT_INVALID_PARAMETER; + } + + return _patch_piubtn_process_outputs(buffer); + } else { + log_error("Invalid usb control request to PIUBTN: 0x%02X", request); + return CNH_RESULT_INVALID_PARAMETER; + } +} + +static void _patch_piubtn_close(void) +{ + log_info("Closing PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident()); + + _patch_piubtn_ptapi_io_piubtn_close(); +} + +static enum cnh_result _patch_piubtn_process_inputs(struct cnh_iobuf* buffer) +{ + struct ptapi_io_piubtn_inputs p1; + struct ptapi_io_piubtn_inputs p2; + + if (!_patch_piubtn_ptapi_io_piubtn_recv()) { + log_error("Receiving inputs on api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident()); + return CNH_RESULT_OTHER_ERROR; + } + + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + + _patch_piubtn_ptapi_io_piubtn_get_input(0, &p1); + _patch_piubtn_ptapi_io_piubtn_get_input(1, &p2); + + memset(buffer->bytes, 0, PIUBTN_DRV_BUFFER_SIZE); + + /* + byte 0: + bit 0: P1 back (red) + bit 1: P1 left + bit 2: P1 right + bit 3: P1 start (green) + bit 4: P2 back (red) + bit 5: P2 left + bit 6: P2 right + bit 7: P2 start (green) + */ + + /* Player 1 */ + if (p1.back) { + buffer->bytes[0] |= (1 << 0); + } + + if (p1.left) { + buffer->bytes[0] |= (1 << 1); + } + + if (p1.right) { + buffer->bytes[0] |= (1 << 2); + } + + if (p1.start) { + buffer->bytes[0] |= (1 << 3); + } + + /* Player 2 */ + if (p2.back) { + buffer->bytes[0] |= (1 << 4); + } + + if (p2.left) { + buffer->bytes[0] |= (1 << 5); + } + + if (p2.right) { + buffer->bytes[0] |= (1 << 6); + } + + if (p2.start) { + buffer->bytes[0] |= (1 << 7); + } + + /* xor inputs because pullup active */ + for (int i = 0; i < PIUBTN_DRV_BUFFER_SIZE; i++) { + buffer->bytes[i] ^= 0xFF; + } + + buffer->pos = PIUBTN_DRV_BUFFER_SIZE; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piubtn_process_outputs(struct cnh_iobuf* buffer) +{ + struct ptapi_io_piubtn_outputs p1; + struct ptapi_io_piubtn_outputs p2; + + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + + /* + byte 0: + bit 0: p1 start (green) + bit 1: p1 right + bit 2: p1 left + bit 3: p1 back (red) + bit 4: p2 start (green) + bit 5: p2 right + bit 6: p2 left + bit 7: p2 back (red) + */ + + /* Player 1 */ + + if (buffer->bytes[0] & (1 << 0)) { + p1.start = true; + } + + if (buffer->bytes[0] & (1 << 1)) { + p1.back = true; + } + + if (buffer->bytes[0] & (1 << 2)) { + p1.left = true; + } + + if (buffer->bytes[0] & (1 << 3)) { + p1.right = true; + } + + /* Player 2 */ + + if (buffer->bytes[0] & (1 << 4)) { + p2.start = true; + } + + if (buffer->bytes[0] & (1 << 5)) { + p2.right = true; + } + + if (buffer->bytes[0] & (1 << 6)) { + p2.left = true; + } + + if (buffer->bytes[0] & (1 << 7)) { + p2.back = true; + } + + _patch_piubtn_ptapi_io_piubtn_set_output(0, &p1); + _patch_piubtn_ptapi_io_piubtn_set_output(1, &p2); + + if (!_patch_piubtn_ptapi_io_piubtn_send()) { + log_error("Sending outputs on api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident()); + return CNH_RESULT_OTHER_ERROR; + } + + buffer->pos = PIUBTN_DRV_BUFFER_SIZE; + + return CNH_RESULT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/hook/patch/piubtn.h b/src/main/hook/patch/piubtn.h new file mode 100644 index 0000000..31b0b56 --- /dev/null +++ b/src/main/hook/patch/piubtn.h @@ -0,0 +1,32 @@ +/** + * Patch libusb-0.1 calls to intercept with piubtn (pump pro buttons) + * communication and hook our API with emulation code + */ +#ifndef PATCH_PIUBTN_H +#define PATCH_PIUBTN_H + +#include "ptapi/io/x11-input-hook.h" + +#include "util/options.h" + +/** + * Initialize the patch module + * + * @param piubtn_lib_path Path to a library implementing the piubtn API + * @param real_passthrough True to ignore the library and disable any emulation + */ +void patch_piubtn_init(const char* piubtn_lib_path); + +/** + * Get the input hook handler provided by the piubtn library. + * + * @return Input hook handler for main-loop patch module or NULL if none is used. + */ +const struct pumptools_input_hook_handler* patch_piubtn_get_input_hook_handler(void); + +/** + * Shut down the patch module + */ +void patch_piubtn_shutdown(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/piuio-exit.c b/src/main/hook/patch/piuio-exit.c new file mode 100644 index 0000000..1ddd8eb --- /dev/null +++ b/src/main/hook/patch/piuio-exit.c @@ -0,0 +1,87 @@ + +#include "capnhook/hook/usbhook.h" + +#include "io/piuio/defs.h" + +#include "util/log.h" + +static enum cnh_result patch_piuio_exit_usbhook(struct cnh_usbhook_irp *irp); + +static usb_dev_handle* _patch_piuio_exit_usb_handle; + +void patch_piuio_exit_init() +{ + cnh_usbhook_push_handler(patch_piuio_exit_usbhook); + log_info("Initialized"); +} + +static enum cnh_result patch_piuio_exit_usbhook(struct cnh_usbhook_irp *irp) +{ + enum cnh_result result; + + if (irp->op != CNH_USBHOOK_IRP_OP_OPEN && _patch_piuio_exit_usb_handle != irp->handle) { + return cnh_usbhook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_USBHOOK_IRP_OP_OPEN: + { + if (_patch_piuio_exit_usb_handle) { + log_warn("Already detected PIUIO previously, ignore re-detection?"); + result = cnh_usbhook_invoke_next(irp); + break; + } + + if (irp->open_usb_dev->descriptor.idVendor == PIUIO_DRV_VID && + irp->open_usb_dev->descriptor.idProduct == PIUIO_DRV_PID) { + log_info("Detected PIUIO"); + + result = cnh_usbhook_invoke_next(irp); + + if (result == CNH_RESULT_SUCCESS) { + _patch_piuio_exit_usb_handle = irp->handle; + } + } else { + result = cnh_usbhook_invoke_next(irp); + } + + break; + } + + case CNH_USBHOOK_IRP_OP_CTRL_MSG: + { + result = cnh_usbhook_invoke_next(irp); + + /* Post process inputs */ + if (irp->ctrl_req_type == PIUIO_DRV_USB_CTRL_TYPE_IN && irp->ctrl_req == PIUIO_DRV_USB_CTRL_REQUEST) { + if (irp->ctrl_buffer.nbytes != PIUIO_DRV_BUFFER_SIZE) { + log_error("Invalid buffer size for ctrl in: %d", irp->ctrl_buffer.nbytes); + } else { + /* Service + Test button pressed */ + /* Invert data -> pull up active */ + if (((~irp->ctrl_buffer.bytes[1]) & (1 << 1)) && ((~irp->ctrl_buffer.bytes[1]) & (1 << 6))) { + log_info("Exit on service + test enabled and hit, bye"); + exit(0); + } + } + } + + break; + } + + case CNH_USBHOOK_IRP_OP_CLOSE: + { + _patch_piuio_exit_usb_handle = NULL; + + result = cnh_usbhook_invoke_next(irp); + + break; + } + + default: + result = cnh_usbhook_invoke_next(irp); + break; + } + + return result; +} \ No newline at end of file diff --git a/src/main/hook/patch/piuio-exit.h b/src/main/hook/patch/piuio-exit.h new file mode 100644 index 0000000..74f40bb --- /dev/null +++ b/src/main/hook/patch/piuio-exit.h @@ -0,0 +1,12 @@ +/** + * Patch module to allow exiting the game using the PIUIO, e.g. pressing service + test. + */ +#ifndef PATCH_PIUIO_EXIT_H +#define PATCH_PIUIO_EXIT_H + +/** + * Enable the module + */ +void patch_piuio_exit_init(); + +#endif diff --git a/src/main/hook/patch/piuio.c b/src/main/hook/patch/piuio.c new file mode 100644 index 0000000..29bcbdb --- /dev/null +++ b/src/main/hook/patch/piuio.c @@ -0,0 +1,572 @@ +#define LOG_MODULE "patch-piuio" + +#include +#include +#include +#include + +#include "capnhook/hooklib/usb-emu.h" + +#include "io/piuio/defs.h" + +#include "ptapi/io/piuio.h" +#include "ptapi/io/piuio/util/lib.h" + +#include "util/log.h" + +static bool _patch_piuio_enumerate(bool real_exists); +static enum cnh_result _patch_piuio_open(void); +static enum cnh_result _patch_piuio_reset(void); +static enum cnh_result _patch_piuio_control_msg(int request_type, int request, int value, int index, + struct cnh_iobuf* buffer, int timeout); +static void _patch_piuio_close(void); + +static enum cnh_result _patch_piuio_process_inputs(struct cnh_iobuf* buffer); +static enum cnh_result _patch_piuio_process_outputs(struct cnh_iobuf* buffer); +static enum cnh_result _patch_piuio_process_itg_kernel_module_hack(struct cnh_iobuf* buffer); + +static const struct cnh_usb_emu_virtdev_ep _patch_piuio_virtdev = { + .pid = PIUIO_DRV_PID, + .vid = PIUIO_DRV_VID, + .enumerate = _patch_piuio_enumerate, + .open = _patch_piuio_open, + .reset = _patch_piuio_reset, + .control_msg = _patch_piuio_control_msg, + .close = _patch_piuio_close, +}; + +static struct ptapi_io_piuio_api _patch_piuio_api; +static enum ptapi_io_piuio_sensor_group _patch_piuio_sensor_group; + +void patch_piuio_init(const char* piuio_lib_path) +{ + if (!piuio_lib_path) { + log_die("No piuio emulation library path specified"); + } + + /* Load piuio library funcs */ + log_info("Loading piuio api implementation %s", piuio_lib_path); + + if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &_patch_piuio_api)) { + log_error("Loading PIUIO API from %s failed", piuio_lib_path); + return; + } + + cnh_usb_emu_add_virtdevep(&_patch_piuio_virtdev); + + log_info("Initialized"); +} + +void patch_piuio_shutdown(void) +{ + +} + +static bool _patch_piuio_enumerate(bool real_exists) +{ + if (real_exists) { + log_info("Real PIUIO exists but emulation enabled, blocking real"); + } else { + log_info("Enumerating PIUIO emulation"); + } + + return true; +} + +static enum cnh_result _patch_piuio_open(void) +{ + log_info("Opening PIUIO: %s", _patch_piuio_api.ident()); + + if (!_patch_piuio_api.open()) { + log_error("Opening api piuio %s failed", _patch_piuio_api.ident()); + return CNH_RESULT_OTHER_ERROR; + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piuio_reset(void) +{ + log_info("Resetting PIUIO: %s", _patch_piuio_api.ident()); + + _patch_piuio_api.close(); + + if (!_patch_piuio_api.open()) { + log_error("Resetting api piuio %s failed", _patch_piuio_api.ident()); + return CNH_RESULT_OTHER_ERROR; + } + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piuio_control_msg(int request_type, int request, int value, int index, + struct cnh_iobuf* buffer, int timeout) +{ + if (request_type == PIUIO_DRV_USB_CTRL_TYPE_IN && request == PIUIO_DRV_USB_CTRL_REQUEST) { + if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) { + log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes); + return CNH_RESULT_INVALID_PARAMETER; + } + + return _patch_piuio_process_inputs(buffer); + } else if (request_type == PIUIO_DRV_USB_CTRL_TYPE_OUT && request == PIUIO_DRV_USB_CTRL_REQUEST) { + if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) { + log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes); + return CNH_RESULT_INVALID_PARAMETER; + } + + return _patch_piuio_process_outputs(buffer); + } else if (request_type == 0 && request == 0) { + /* ITG 2/PIU Pro kernel hack */ + if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE * 4) { + log_error("Invalid buffer size for kernel hack: %d", buffer->nbytes); + return CNH_RESULT_INVALID_PARAMETER; + } + + return _patch_piuio_process_itg_kernel_module_hack(buffer); + } else { + log_error("Invalid usb control request to PIUIO: 0x%02X", request); + return CNH_RESULT_INVALID_PARAMETER; + } +} + +static void _patch_piuio_close(void) +{ + log_info("Closing PIUIO: %s", _patch_piuio_api.ident()); + + _patch_piuio_api.close(); +} + +static enum cnh_result _patch_piuio_process_inputs(struct cnh_iobuf* buffer) +{ + struct ptapi_io_piuio_pad_inputs p1_pad_in; + struct ptapi_io_piuio_pad_inputs p2_pad_in; + struct ptapi_io_piuio_sys_inputs sys_in; + + if (!_patch_piuio_api.recv()) { + log_error("Receiving inputs on api piuio %s failed", _patch_piuio_api.ident()); + return CNH_RESULT_OTHER_ERROR; + } + + memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs)); + memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs)); + memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs)); + + _patch_piuio_api.get_input_pad(0, _patch_piuio_sensor_group, &p1_pad_in); + _patch_piuio_api.get_input_pad(1, _patch_piuio_sensor_group, &p2_pad_in); + + _patch_piuio_api.get_input_sys(&sys_in); + + /* + byte 0: + bit 0: sensor p1: LU + bit 1: sensor p1: RU + bit 2: sensor p1: CN + bit 3: sensor p1: LD + bit 4: sensor p1: RD + bit 5: + bit 6: + bit 7: + + byte 1: + bit 0: + bit 1: test + bit 2: coin 1 + bit 3: + bit 4: + bit 5: + bit 6: service + bit 7: clear + + byte 2: + bit 0: sensor p2: LU + bit 1: sensor p2: RU + bit 2: sensor p2: CN + bit 3: sensor p2: LD + bit 4: sensor p2: RD + bit 5: + bit 6: + bit 7: + + byte 3: + bit 0: + bit 1: + bit 2: coin 2 + bit 3: + bit 4: + bit 5: + bit 6: + bit 7: + + bytes 4 - 7 dummy + */ + + /* Player 1 */ + buffer->bytes[0] = 0; + + if (p1_pad_in.lu) { + buffer->bytes[0] |= (1 << 0); + } + + if (p1_pad_in.ru) { + buffer->bytes[0] |= (1 << 1); + } + + if (p1_pad_in.cn) { + buffer->bytes[0] |= (1 << 2); + } + + if (p1_pad_in.ld) { + buffer->bytes[0] |= (1 << 3); + } + + if (p1_pad_in.rd) { + buffer->bytes[0] |= (1 << 4); + } + + buffer->bytes[0] ^= 0xFF; + + buffer->bytes[2] = 0; + + /* Player 2 */ + if (p2_pad_in.lu) { + buffer->bytes[2] |= (1 << 0); + } + + if (p2_pad_in.ru) { + buffer->bytes[2] |= (1 << 1); + } + + if (p2_pad_in.cn) { + buffer->bytes[2] |= (1 << 2); + } + + if (p2_pad_in.ld) { + buffer->bytes[2] |= (1 << 3); + } + + if (p2_pad_in.rd) { + buffer->bytes[2] |= (1 << 4); + } + + buffer->bytes[2] ^= 0xFF; + + buffer->bytes[1] = 0; + + /* Sys */ + if (sys_in.test) { + buffer->bytes[1] |= (1 << 1); + } + + if (sys_in.service) { + buffer->bytes[1] |= (1 << 6); + } + + if (sys_in.clear) { + buffer->bytes[1] |= (1 << 7); + } + + if (sys_in.coin) { + buffer->bytes[1] |= (1 << 2); + } + + buffer->bytes[1] ^= 0xFF; + + /* Apparently, "touching" byte 3 as a whole causes some random and weird input triggering + which results in the service menu popping up. Don't clear the whole byte, touch coin2 only to avoid this */ + if (!sys_in.coin2) { + buffer->bytes[3] |= (1 << 2); + } else { + buffer->bytes[3] &= ~(1 << 2); + } + + buffer->pos = PIUIO_DRV_BUFFER_SIZE; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piuio_process_outputs(struct cnh_iobuf* buffer) +{ + struct ptapi_io_piuio_pad_outputs p1_pad_out; + struct ptapi_io_piuio_pad_outputs p2_pad_out; + struct ptapi_io_piuio_cab_outputs cab_out; + + memset(&p1_pad_out, 0, sizeof(struct ptapi_io_piuio_pad_outputs)); + memset(&p2_pad_out, 0, sizeof(struct ptapi_io_piuio_pad_outputs)); + memset(&cab_out, 0, sizeof(struct ptapi_io_piuio_cab_outputs)); + + /* + byte 0: + bit 0: sensor id bit 0 select sensor to be read for next input request: + bit 1: sensor id bit 1 00 = sens1, 01 = sens2, 10 = sens3, 11 = sens4 + bit 2: pad light p1: LU + bit 3: pad light p1: RU + bit 4: pad light p1: CN + bit 5: pad light p1: LD + bit 6: pad light p1: RD + bit 7: + + byte 1: + bit 0: + bit 1: + bit 2: light neons + bit 3: coin counter 2 (front usb ports enable) + bit 4: + bit 5: + bit 6: + bit 7: + + byte 2: + bit 0: + bit 1: + bit 2: pad light p2: LU + bit 3: pad light p2: RU + bit 4: pad light p2: CN + bit 5: pad light p2: LD + bit 6: pad light p2: RD + bit 7: halogen R2 + + byte 3: + bit 0: halogen R1 + bit 1: halogen L2 + bit 2: halogen L1 + bit 3: + bit 4: coin counter 1 + bit 5: + bit 6: + bit 7: + + bytes 4 - 7 dummy + */ + + _patch_piuio_sensor_group = (enum ptapi_io_piuio_sensor_group) (buffer->bytes[0] & 0x03); + + /* Player 1 */ + + if (buffer->bytes[0] & (1 << 2)) { + p1_pad_out.lu = true; + } + + if (buffer->bytes[0] & (1 << 3)) { + p1_pad_out.ru = true; + } + + if (buffer->bytes[0] & (1 << 4)) { + p1_pad_out.cn = true; + } + + if (buffer->bytes[0] & (1 << 5)) { + p1_pad_out.ld = true; + } + + if (buffer->bytes[0] & (1 << 6)) { + p1_pad_out.rd = true; + } + + /* Player 2 */ + + if (buffer->bytes[2] & (1 << 2)) { + p2_pad_out.lu = true; + } + + if (buffer->bytes[2] & (1 << 3)) { + p2_pad_out.ru = true; + } + + if (buffer->bytes[2] & (1 << 4)) { + p2_pad_out.cn = true; + } + + if (buffer->bytes[2] & (1 << 5)) { + p2_pad_out.ld = true; + } + + if (buffer->bytes[2] & (1 << 6)) { + p2_pad_out.rd = true; + } + + /* Cabinet */ + + if (buffer->bytes[1] & (1 << 2)) { + cab_out.bass = true; + } + + if (buffer->bytes[2] & (1 << 7)) { + cab_out.halo_r2 = true; + } + + if (buffer->bytes[3] & (1 << 0)) { + cab_out.halo_r1 = true; + } + + if (buffer->bytes[3] & (1 << 1)) { + cab_out.halo_l2 = true; + } + + if (buffer->bytes[3] & (1 << 2)) { + cab_out.halo_l1 = true; + } + + _patch_piuio_api.set_output_pad(0, &p1_pad_out); + _patch_piuio_api.set_output_pad(1, &p2_pad_out); + _patch_piuio_api.set_output_cab(&cab_out); + + if (!_patch_piuio_api.send()) { + log_error("Sending outputs on api piuio %s failed", _patch_piuio_api.ident()); + return CNH_RESULT_OTHER_ERROR; + } + + buffer->pos = PIUIO_DRV_BUFFER_SIZE; + + return CNH_RESULT_SUCCESS; +} + +static enum cnh_result _patch_piuio_process_itg_kernel_module_hack(struct cnh_iobuf* buffer) +{ + /* Instead of calling four times, one call for each sensor set, a special + kernel module is loaded which traps the following call: + usb_control_msg(dev_handle, 0, 0, 0, 0, buffer, 32, 10011); + All four sensor sets are polled in a single context switch and returned + as one big buffer instead of four smalle ones (8 bytes each). + Pump Pro relies on this, so we have to support it here */ + + struct ptapi_io_piuio_pad_inputs p1_pad_in[4]; + struct ptapi_io_piuio_pad_inputs p2_pad_in[4]; + struct ptapi_io_piuio_sys_inputs sys_in; + + /* The output duplicated 4 times (4 * 8) in the buffer. Write it once */ + _patch_piuio_process_outputs(buffer); + + if (!_patch_piuio_api.recv()) { + log_error("Receiving inputs on api piuio %s failed", _patch_piuio_api.ident()); + return CNH_RESULT_OTHER_ERROR; + } + + memset(buffer->bytes, 0, PIUIO_DRV_BUFFER_SIZE * 4); + + memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs)); + + for (uint8_t i = 0; i < 4; i++) { + memset(&p1_pad_in[i], 0, sizeof(struct ptapi_io_piuio_pad_inputs)); + memset(&p2_pad_in[i], 0, sizeof(struct ptapi_io_piuio_pad_inputs)); + + _patch_piuio_api.get_input_pad(0, (enum ptapi_io_piuio_sensor_group) i, &p1_pad_in[i]); + _patch_piuio_api.get_input_pad(1, (enum ptapi_io_piuio_sensor_group) i, &p2_pad_in[i]); + } + + _patch_piuio_api.get_input_sys(&sys_in); + + /* + byte 0: + bit 0: sensor p1: LU + bit 1: sensor p1: RU + bit 2: sensor p1: CN + bit 3: sensor p1: LD + bit 4: sensor p1: RD + bit 5: + bit 6: + bit 7: + + byte 1: + bit 0: + bit 1: test + bit 2: coin 1 + bit 3: + bit 4: + bit 5: + bit 6: service + bit 7: clear + + byte 2: + bit 0: sensor p2: LU + bit 1: sensor p2: RU + bit 2: sensor p2: CN + bit 3: sensor p2: LD + bit 4: sensor p2: RD + bit 5: + bit 6: + bit 7: + + byte 3: + bit 0: + bit 1: + bit 2: coin 2 + bit 3: + bit 4: + bit 5: + bit 6: + bit 7: + + bytes 4 - 7 dummy + */ + + for (uint8_t i = 0; i < 4; i++) { + /* Player 1 */ + if (p1_pad_in[i].lu) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 0] |= (1 << 0); + } + + if (p1_pad_in[i].ru) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 0] |= (1 << 1); + } + + if (p1_pad_in[i].cn) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 0] |= (1 << 2); + } + + if (p1_pad_in[i].ld) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 0] |= (1 << 3); + } + + if (p1_pad_in[i].rd) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 0] |= (1 << 4); + } + + /* Player 2 */ + if (p2_pad_in[i].lu) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 2] |= (1 << 0); + } + + if (p2_pad_in[i].ru) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 2] |= (1 << 1); + } + + if (p2_pad_in[i].cn) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 2] |= (1 << 2); + } + + if (p2_pad_in[i].ld) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 2] |= (1 << 3); + } + + if (p2_pad_in[i].rd) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 2] |= (1 << 4); + } + + /* Sys */ + if (sys_in.test) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 1] |= (1 << 1); + } + + if (sys_in.service) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 1] |= (1 << 6); + } + + if (sys_in.clear) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 1] |= (1 << 7); + } + + if (sys_in.coin) { + buffer->bytes[PIUIO_DRV_BUFFER_SIZE * i + 1] |= (1 << 2); + } + } + + /* xor inputs because pullup active */ + for (int i = 0; i < PIUIO_DRV_BUFFER_SIZE * 4; i++) { + buffer->bytes[i] ^= 0xFF; + } + + buffer->nbytes = PIUIO_DRV_BUFFER_SIZE * 4; + + return CNH_RESULT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/hook/patch/piuio.h b/src/main/hook/patch/piuio.h new file mode 100644 index 0000000..c2c2a3e --- /dev/null +++ b/src/main/hook/patch/piuio.h @@ -0,0 +1,22 @@ +/** + * Patch libusb-0.1 calls to intercept with piuio communication and hook + * our API with emulation code + */ +#ifndef PATCH_PIUIO_H +#define PATCH_PIUIO_H + +#include "util/options.h" + +/** + * Initialize the patch module + * + * @param piuio_lib_path Path to a library implementing the piuio API + */ +void patch_piuio_init(const char* piuio_lib_path); + +/** + * Shut down the patch module + */ +void patch_piuio_shutdown(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/ram-wipe.c b/src/main/hook/patch/ram-wipe.c new file mode 100644 index 0000000..db97aae --- /dev/null +++ b/src/main/hook/patch/ram-wipe.c @@ -0,0 +1,25 @@ +#define LOG_MODULE "patch-ram-wipe" + +#include + +#include "capnhook/hook/filehook.h" + +#include "util/log.h" + +static enum cnh_result _patch_ram_wipe_filehook(struct cnh_filehook_irp *irp); + +void patch_ram_wipe_init(void) +{ + cnh_filehook_push_handler(_patch_ram_wipe_filehook); + log_info("Initialized"); +} + +static enum cnh_result _patch_ram_wipe_filehook(struct cnh_filehook_irp *irp) +{ + if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN && !strcmp(irp->open_filename, "/dev/ram0")) { + log_info("Killing ram wipe"); + return CNH_RESULT_NO_SUCH_FILE_OR_DIR; + } else { + return cnh_filehook_invoke_next(irp); + } +} \ No newline at end of file diff --git a/src/main/hook/patch/ram-wipe.h b/src/main/hook/patch/ram-wipe.h new file mode 100644 index 0000000..a052495 --- /dev/null +++ b/src/main/hook/patch/ram-wipe.h @@ -0,0 +1,13 @@ +/** + * Starting with Prime the game executes a ram wipe. We don't want that + * to happen. + */ +#ifndef PATCH_RAM_WIPE_H +#define PATCH_RAM_WIPE_H + +/** + * Initialize patch module + */ +void patch_ram_wipe_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/redir.c b/src/main/hook/patch/redir.c new file mode 100644 index 0000000..148acf4 --- /dev/null +++ b/src/main/hook/patch/redir.c @@ -0,0 +1,14 @@ +#define LOG_MODULE "patch-redir" + +#include "capnhook/hooklib/redir.h" + +#include "util/log.h" + +void patch_redir_init() +{ + cnh_fshook_push_handler(cnh_redir_fshook); + cnh_filehook_push_handler(cnh_redir_filehook); + cnh_iohook_push_handler(cnh_redir_iohook); + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/redir.h b/src/main/hook/patch/redir.h new file mode 100644 index 0000000..fa32093 --- /dev/null +++ b/src/main/hook/patch/redir.h @@ -0,0 +1,12 @@ +/** + * Module to enable the redirect hook module to redirect file/device open paths. + */ +#ifndef PATCH_REDIR_H +#define PATCH_REDIR_H + +/** + * Enable module + */ +void patch_redir_init(); + +#endif //PATCH_REDIR_H diff --git a/src/main/hook/patch/sigsegv.c b/src/main/hook/patch/sigsegv.c new file mode 100644 index 0000000..aed619c --- /dev/null +++ b/src/main/hook/patch/sigsegv.c @@ -0,0 +1,53 @@ +#define LOG_MODULE "patch-sigsegv" + +#include +#include +#include +#include + +#include "capnhook/hook/sig.h" + +#include "util/log.h" + +#include "sigsegv.h" + +static bool patch_sigsevc_halt_on_segv; + +static void patch_sigsegv_handler(int signal, __sighandler_t orig_handler) +{ + log_error("==================="); + log_error("!!!!! SIGSEGV !!!!!"); + + void* array[128]; + size_t size; + char** strings; + + size = (size_t) backtrace(array, sizeof(array)); + strings = backtrace_symbols(array, size); + + log_error("Backtrace (%d frames):", size); + + for (int i = 0; i < size; i++) { + log_error("%s", strings[i]); + } + + free(strings); + + if (patch_sigsevc_halt_on_segv) { + log_error("Halting for debugger..."); + + while (true) { + sleep(1); + } + } + + exit(-1); +} + +void patch_sigsegv_init(bool halt_on_segv) +{ + patch_sigsevc_halt_on_segv = halt_on_segv; + + cnh_sig_install(SIGSEGV, patch_sigsegv_handler); + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/sigsegv.h b/src/main/hook/patch/sigsegv.h new file mode 100644 index 0000000..8bd5230 --- /dev/null +++ b/src/main/hook/patch/sigsegv.h @@ -0,0 +1,16 @@ +/** + * Install a proper signal handler to enhance error output on crashes + */ +#ifndef PATCH_SIGSEGV_H +#define PATCH_SIGSEGV_H + +#include + +/** + * Initialize the patch module + * + * @param halt_on_segv Halt on segv to attach a debugger to the application + */ +void patch_sigsegv_init(bool halt_on_segv); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/sound.c b/src/main/hook/patch/sound.c new file mode 100644 index 0000000..a2bf707 --- /dev/null +++ b/src/main/hook/patch/sound.c @@ -0,0 +1,66 @@ +#define LOG_MODULE "patch-sound" + +#include +#include + #include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" + +typedef int (*snd_pcm_open_t)(snd_pcm_t** pcmp, const char* name, + snd_pcm_stream_t stream, int mode); + +static snd_pcm_open_t patch_sound_real_snd_pcm_open; + +static const char* patch_sound_dev_name; + +int snd_pcm_open(snd_pcm_t** pcmp, const char* name, snd_pcm_stream_t stream, int mode) +{ + int ret = 0; + int retry_count = 5; + + log_debug("snd_pcm_open: %s, stream %d, mode %d", name, stream, mode); + + if (!patch_sound_real_snd_pcm_open) { + patch_sound_real_snd_pcm_open = (snd_pcm_open_t) cnh_lib_get_func_addr("snd_pcm_open"); + } + + if (patch_sound_dev_name) { + log_info("Opening sound device %s instead of %s", patch_sound_dev_name, name); + + name = patch_sound_dev_name; + } + + /* + Notes about exceed and how it fucked up using alsa: + - Opening the same (hw:0) device multiple times without closing + - Opening and closing the device on each effect play + - No proper error handling on snd_pcm_open return + */ + + /* Using dmix instead of hw:0 on exceed, snd_pcm_open sometimes returns + with a bad fd but after another retry, everything's fine */ + while (retry_count > 0) { + ret = patch_sound_real_snd_pcm_open(pcmp, name, stream, mode); + + if (ret < 0) { + retry_count--; + } else { + break; + } + } + + if (ret < 0) { + log_error("snd_pcm_open failed: %s", snd_strerror(ret)); + } + + return ret; +} + +void patch_sound_init(const char* dev_name) +{ + patch_sound_dev_name = dev_name; + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/sound.h b/src/main/hook/patch/sound.h new file mode 100644 index 0000000..77a98ec --- /dev/null +++ b/src/main/hook/patch/sound.h @@ -0,0 +1,15 @@ +/** + * Patch the sound device to open for sound output. Allows us to use a + * different device than hw:0 (e.g. HDMI sound output) + */ +#ifndef PATCH_SOUND_H +#define PATCH_SOUND_H + +/** + * Initialize the patch module + * + * @param dev_name Sound device name to open instead of whatever pump decides + */ +void patch_sound_init(const char* dev_name); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/usb-emu.c b/src/main/hook/patch/usb-emu.c new file mode 100644 index 0000000..9d9e54c --- /dev/null +++ b/src/main/hook/patch/usb-emu.c @@ -0,0 +1,12 @@ +#define LOG_MODULE "patch-usb-emu" + +#include "capnhook/hooklib/usb-emu.h" + +#include "util/log.h" + +void patch_usb_emu_init() +{ + cnh_usbhook_push_handler(&cnh_usb_emu); + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/usb-emu.h b/src/main/hook/patch/usb-emu.h new file mode 100644 index 0000000..9560a97 --- /dev/null +++ b/src/main/hook/patch/usb-emu.h @@ -0,0 +1,12 @@ +/** + * Initialize the hook module for usb device emulation. + */ +#ifndef PATCH_USB_EMU_H +#define PATCH_USB_EMU_H + +/** + * Initialize module. + */ +void patch_usb_emu_init(); + +#endif diff --git a/src/main/hook/patch/usb-init-fix.c b/src/main/hook/patch/usb-init-fix.c new file mode 100644 index 0000000..12a45b7 --- /dev/null +++ b/src/main/hook/patch/usb-init-fix.c @@ -0,0 +1,12 @@ +#define LOG_MODULE "patch-usb-init-fix" + +#include "capnhook/hooklib/usb-init-fix.h" + +#include "util/log.h" + +void patch_usb_init_fix_init() +{ + cnh_usbhook_push_handler(&cnh_usb_init_fix); + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/usb-init-fix.h b/src/main/hook/patch/usb-init-fix.h new file mode 100644 index 0000000..b0a0381 --- /dev/null +++ b/src/main/hook/patch/usb-init-fix.h @@ -0,0 +1,12 @@ +/** + * Initialize the hook module for fixing multiple usb_init calls. + */ +#ifndef PATCH_USB_INIT_FIX_H +#define PATCH_USB_INIT_FIX_H + +/** + * Initialize module. + */ +void patch_usb_init_fix_init(); + +#endif diff --git a/src/main/hook/patch/usb-mnt.c b/src/main/hook/patch/usb-mnt.c new file mode 100644 index 0000000..98f69ad --- /dev/null +++ b/src/main/hook/patch/usb-mnt.c @@ -0,0 +1,29 @@ +#define LOG_MODULE "patch-usb-mnt" + +#include "util/fs.h" +#include "util/log.h" + +#include "usb-mnt.h" + +static const char* patch_usb_mnt_player[2] = {"/mnt/0", "/mnt/1"}; +// Invalid files are used to detect if mounting the usb stick was successful +static const char* patch_usb_mnt_player_invalid[2] = {"/mnt/0/invalid", "/mnt/1/invalid"}; + +void patch_usb_mnt_init(void) +{ + for (uint8_t i = 0; i < 2; i++) { + if (!util_fs_path_exists(patch_usb_mnt_player[i])) { + log_info("%s does not exist, creating", patch_usb_mnt_player[i]); + + if (!util_fs_mkdir(patch_usb_mnt_player[i])) { + log_error("Creating directory %s failed", patch_usb_mnt_player[i]); + } + + if (!util_fs_mkfile(patch_usb_mnt_player_invalid[i])) { + log_error("Creating invalid indicator file %s failed", patch_usb_mnt_player_invalid[i]); + } + } + } + + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/usb-mnt.h b/src/main/hook/patch/usb-mnt.h new file mode 100644 index 0000000..ce4c750 --- /dev/null +++ b/src/main/hook/patch/usb-mnt.h @@ -0,0 +1,13 @@ +/** + * Ensures that the mount points /mnt/0 and /mnt/1 exist to allow mounting + * of connected usb sticks with profile data + */ +#ifndef PATCH_USB_MNT_H +#define PATCH_USB_MNT_H + +/** + * Initialize the patch module + */ +void patch_usb_mnt_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/usb-unlock.c b/src/main/hook/patch/usb-unlock.c new file mode 100644 index 0000000..17581b3 --- /dev/null +++ b/src/main/hook/patch/usb-unlock.c @@ -0,0 +1,73 @@ +#define LOG_MODULE "patch-usb-unlock" + +#include +#include +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" + +#include "usb-unlock.h" + +#define SERIAL_UNLOCK_TOKEN "PUMPToken\0" + +typedef int (*sscanf_t)(const char *str, const char *format, ...); +typedef int (*strcasecmp_t)(const char *s1, const char *s2); + +static sscanf_t patch_usb_unlock_real_sscanf; +static strcasecmp_t patch_usb_unlock_real_strcasecmp; + +int sscanf(const char *str, const char *format, ...) +{ + if (!patch_usb_unlock_real_sscanf) { + patch_usb_unlock_real_sscanf = (sscanf_t) cnh_lib_get_func_addr("sscanf"); + } + + va_list ap; + va_start(ap, format); + + if (!strcmp(format, "P: Vendor=%4x ProdID=%4x")) { + log_debug("Spoofing VID 0x058f for usb stick"); + + /* unpack argument list, we know we got 2 arguments here */ + /* VID */ + *va_arg(ap, int*) = 0x058f; + /* PID */ + *va_arg(ap, int*) = 0; + + va_end(ap); + return 2; + } + + if (!strcmp(format, "S: SerialNumber=%s")) { + log_debug("Spoofing serial number of usb stick to kill serial number locking of profile in a moment..."); + memcpy(va_arg(ap, char*), SERIAL_UNLOCK_TOKEN, strlen(SERIAL_UNLOCK_TOKEN) + 1); + + va_end(ap); + return 1; + } + + int ret = vsscanf(str, format, ap); + va_end(ap); + return ret; +} + +int strcasecmp(const char *s1, const char *s2) +{ + if (!patch_usb_unlock_real_strcasecmp) { + patch_usb_unlock_real_strcasecmp = (strcasecmp_t) cnh_lib_get_func_addr("strcasecmp"); + } + + if (!strcmp(s2, SERIAL_UNLOCK_TOKEN)) { + log_debug("Caught serial unlock token...unlocking profile"); + return 0; + } + + return patch_usb_unlock_real_strcasecmp(s1, s2); +} + +void patch_usb_unlock_init(void) +{ + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/usb-unlock.h b/src/main/hook/patch/usb-unlock.h new file mode 100644 index 0000000..6a9afbd --- /dev/null +++ b/src/main/hook/patch/usb-unlock.h @@ -0,0 +1,13 @@ +/** + * Remove the vendor id lock check for usb sticks limiting nx2 and nxa to + * a specific brand of usb sticks to save profile data to + */ +#ifndef PATCH_USB_UNLOCK_H +#define PATCH_USB_UNLOCK_H + +/** + * Initialize the patch module + */ +void patch_usb_unlock_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/usbfs.c b/src/main/hook/patch/usbfs.c new file mode 100644 index 0000000..899d297 --- /dev/null +++ b/src/main/hook/patch/usbfs.c @@ -0,0 +1,130 @@ +#define LOG_MODULE "patch-usbfs" + +#include +#include +#include +#include + +#include "capnhook/hook/lib.h" + +#include "util/fs.h" +#include "util/log.h" + +typedef int (*vsprintf_t)(char* str, const char* format, va_list ap); +typedef int (*sprintf_t)(char *str, const char *format, ...); + +static vsprintf_t patch_usbfs_vsprintf_orig; +static sprintf_t patch_usbfs_sprintf_orig; + +static const char* patch_usbfs_usb_str = "/sys/bus/usb/devices/"; + +int sprintf(char *str, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + int ret = vsprintf(str, format, ap); + va_end(ap); + return ret; +} + +int __sprintf_chk(char *dest, int flags, size_t dest_len_from_compiler, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + + /* fuck...why did you guys have to switch from sprintf to sprintf_chk? + everything was perfectly fine... and you give a shit about "safe" code, + which doesn't make this mess better... */ + ret = vsprintf(dest, format, ap); + + va_end(ap); + return ret; +} + +int vsprintf(char* str, const char* format, va_list ap) +{ + if (!patch_usbfs_vsprintf_orig) { + patch_usbfs_vsprintf_orig = (vsprintf_t) cnh_lib_get_func_addr("vsprintf"); + } + + if (!patch_usbfs_sprintf_orig) { + patch_usbfs_sprintf_orig = (sprintf_t) cnh_lib_get_func_addr("sprintf"); + } + + /* This path does not work on newer kernels (not sure which version it + started but everything > 3.18 doesn't work) */ + + // nx2/nxa path: + // /sys/bus/usb/devices/%d-%d/%d-%d:1.0/host*/target*:0:0/*:0:0:0/block:sd* + // fiesta and newer: + // /sys/bus/usb/devices/%d-%d:1.0/host*/target*:0:0/*:0:0:0/block/sd* + + if (!strncmp(patch_usbfs_usb_str, format, strlen(patch_usbfs_usb_str))) { + /* unpack argument list, we know we got 4 arguments here + the second pair is a dupe of the first one */ + uint8_t bus = (uint8_t) va_arg(ap, int); + uint8_t port = (uint8_t) va_arg(ap, int); + + // Removed because it spams the log. Put it back when debugging usb profile mounting related issues + // log_debug("Patching lookup of '%s' device node for bus %d, port %d.", format, bus, port); + + /* note: ports start with 1 (not 0) in sysfs */ + + /* because the linux kernel likes to change things here often, we have to consider different paths. + for each path we encountered so far (add more if missing from different kernel versions) just + check if the path exists and use it */ + + int counter = 0; + + while (counter <= 2) { + switch (counter) { + case 0: + patch_usbfs_sprintf_orig(str, "/sys/bus/usb/devices/%d-1.%d:1.0/host*/" + "target*:0:0/*:0:0:0/block/sd*", bus, port); + break; + + case 1: + patch_usbfs_sprintf_orig(str, "/sys/bus/usb/devices/%d-%d:1.0/host*/" + "target*:0:0/*:0:0:0/block/sd*", bus, port); + break; + + case 2: + // Discovered that the string needs to be changed on 5.5.6. Probably changed slightly before that + // version + patch_usbfs_sprintf_orig(str, "/sys/bus/usb/devices/%d-%d/%d-%d:1.0/host*/" + "target*:0:0/*:0:0:0/block/sd*", bus, port, bus, port); + break; + + default: + log_error("Could not find path in sys-fs to lookup usb drive block device. Likely, you have a " + "kernel version that uses a (slightly) different path. This (new) path must be added in " + "order to get usb drives showing up in the game."); + break; + } + + glob_t gl; + + // Pump does the same after returning from this hooked call. Because there are different file system + // layouts depending on the kernel version, try the above list using the same method with glob + if (!glob(str, 4, NULL, &gl)) { + globfree(&gl); + break; + } + + globfree(&gl); + + counter++; + } + + /* original argument count */ + return 4; + } + + return patch_usbfs_vsprintf_orig(str, format, ap); +} + +void patch_usbfs_init() +{ + log_info("Initialized"); +} \ No newline at end of file diff --git a/src/main/hook/patch/usbfs.h b/src/main/hook/patch/usbfs.h new file mode 100644 index 0000000..0730b62 --- /dev/null +++ b/src/main/hook/patch/usbfs.h @@ -0,0 +1,14 @@ +/** + * The kernels used by nx2 and nxa support usbfs. Newer kernels + * don't have this module anymore. This module takes care of fixing any + * issues not having the module. + */ +#ifndef PATCH_USBFS_H +#define PATCH_USBFS_H + +/** + * Initialize the patch module + */ +void patch_usbfs_init(); + +#endif \ No newline at end of file diff --git a/src/main/hook/patch/x11-event-loop.c b/src/main/hook/patch/x11-event-loop.c new file mode 100644 index 0000000..8ac4174 --- /dev/null +++ b/src/main/hook/patch/x11-event-loop.c @@ -0,0 +1,269 @@ +#define LOG_MODULE "patch-x11-event-loop" + +#include +#include +#include +#include + +#include "capnhook/hook/lib.h" + +#include "ptapi/io/x11-input-hook.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/time.h" + +struct patch_x11_event_loop_ctx { + Display* display; + Window window; + pthread_t thread; + atomic_int run; +}; + +typedef Window (*XCreateWindow_t)(Display *display, Window parent, int x, int y, unsigned int width, + unsigned int height, unsigned int border_width, int depth, unsigned int _class, Visual *visual, + unsigned long valuemask, XSetWindowAttributes *attributes); +typedef Display* (*XOpenDisplay_t)(const char *display_name); +typedef int (*XDestroyWindow_t)(Display *display, Window w); + +static XCreateWindow_t patch_x11_event_loop_real_XCreateWindow; +static XOpenDisplay_t patch_x11_event_loop_real_XOpenDisplay; +static XDestroyWindow_t patch_x11_event_loop_real_XDestroyWindow; + +static bool patch_x11_event_loop_enabled; +static struct patch_x11_event_loop_ctx* patch_x11_event_loop_ctx; + +static pthread_mutex_t patch_x11_event_loop_input_handlers_lock; +static const struct ptapi_io_x11_input_hook_handler** patch_x11_event_loop_input_handlers; +static size_t patch_x11_event_loop_num_input_handlers; + +static bool patch_x11_event_loop_is_key_repeated(Display* display, XEvent* event) +{ + /* When a key is repeated, there will be two events: released, followed by another immediate pressed. + So check to see if another pressed is present */ + if (!XPending(display)) { + return false; + } + + XEvent e; + XPeekEvent(display, &e); + + if (e.type == KeyPress && e.xkey.keycode == event->xkey.keycode && (e.xkey.time - event->xkey.time) < 2) { + XNextEvent(display, &e); + return true; + } + + return false; +} + +static void* patch_x11_event_loop_run(void* args) +{ + log_info("Running X11 event loop thread"); + + struct patch_x11_event_loop_ctx* ctx = (struct patch_x11_event_loop_ctx*) args; + + if (XSelectInput(ctx->display, ctx->window, KeyPressMask | KeyReleaseMask) == BadWindow) { + log_error("XSelectInput failed"); + return NULL; + } + + XGrabKeyboard(ctx->display, ctx->window, 1, GrabModeAsync, GrabModeAsync, CurrentTime); + + while (atomic_load(&ctx->run) > 0) { + while (atomic_load(&ctx->run) > 0 && XPending(ctx->display) > 0) { + XEvent event; + KeySym key; + + if (XNextEvent(ctx->display, &event) != Success) { + log_error("XNextEvent"); + continue; + } + + switch (event.type) { + case KeyPress: + { + /* Mask out the modifier states X11 sets and read again */ + event.xkey.state &= ~ShiftMask; + event.xkey.state &= ~LockMask; + + XLookupString(&event.xkey, 0, 0, &key, 0); + + /* Dispatch to external input handlers */ + if (patch_x11_event_loop_num_input_handlers > 0) { + pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock); + + for (size_t i = 0; i < patch_x11_event_loop_num_input_handlers; i++) { + if (patch_x11_event_loop_input_handlers[i]->dispatch_key_press) { + patch_x11_event_loop_input_handlers[i]->dispatch_key_press(key); + } + } + + pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock); + } + + break; + } + + case KeyRelease: + { + /* Mask out the modifier states X11 sets and read again */ + event.xkey.state &= ~ShiftMask; + event.xkey.state &= ~LockMask; + + XLookupString(&event.xkey, 0, 0, &key, 0); + + /* Dispatch to external input handlers */ + if (patch_x11_event_loop_num_input_handlers > 0) { + /* Dispatch release if key is not repeated */ + if (!patch_x11_event_loop_is_key_repeated(ctx->display, &event)) { + pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock); + + for (size_t i = 0; i < patch_x11_event_loop_num_input_handlers; i++) { + if (patch_x11_event_loop_input_handlers[i]->dispatch_key_release) { + patch_x11_event_loop_input_handlers[i]->dispatch_key_release(key); + } + } + + pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock); + } + } + + break; + } + + default: + break; + } + } + + // Avoid CPU banging + util_time_sleep_ms(1); + } + + log_info("Finished X11 event loop thread"); + + return NULL; +} + +Display *XOpenDisplay(const char *display_name) +{ + if (!patch_x11_event_loop_real_XOpenDisplay) { + patch_x11_event_loop_real_XOpenDisplay = (XOpenDisplay_t) cnh_lib_get_func_addr("XOpenDisplay"); + } + + log_debug("XOpenDisplay: %s", display_name); + + // This function needs to be called before any other X11 function is called. + // Required to pump events in separate thread + if (patch_x11_event_loop_enabled && XInitThreads() != Success) { + log_error("XInitThreads failed"); + } + + Display* res = patch_x11_event_loop_real_XOpenDisplay(display_name); + + if (!res) { + log_error("XOpenDisplay returned NULL. This might indicate that your environment is not properly setup. Check " + " that you have GPU drivers installed and configured properly and that OpenGL hardware acceleration is " + " working (use the command line tool \"glxinfo\")."); + } + + return res; +} + +Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, + unsigned int border_width, int depth, unsigned int _class, Visual *visual, unsigned long valuemask, + XSetWindowAttributes *attributes) +{ + log_debug("XCreateWindow"); + + if (!patch_x11_event_loop_real_XCreateWindow) { + patch_x11_event_loop_real_XCreateWindow = (XCreateWindow_t) cnh_lib_get_func_addr("XCreateWindow"); + } + + Window w = patch_x11_event_loop_real_XCreateWindow(display, parent, x, y, width, height, border_width, depth, + _class, visual, valuemask, attributes); + + if (patch_x11_event_loop_enabled && !patch_x11_event_loop_ctx) { + patch_x11_event_loop_ctx = util_xmalloc(sizeof(struct patch_x11_event_loop_ctx)); + + patch_x11_event_loop_ctx->display = display; + patch_x11_event_loop_ctx->window = w; + patch_x11_event_loop_ctx->run = ATOMIC_VAR_INIT(1); + + pthread_create(&patch_x11_event_loop_ctx->thread, NULL, patch_x11_event_loop_run, patch_x11_event_loop_ctx); + } + + return w; +} + +int XDestroyWindow(Display *display, Window w) +{ + log_debug("XDestroyWindow"); + + if (!patch_x11_event_loop_real_XDestroyWindow) { + patch_x11_event_loop_real_XDestroyWindow = (XDestroyWindow_t) cnh_lib_get_func_addr("XDestroyWindow"); + } + + if (patch_x11_event_loop_enabled && patch_x11_event_loop_ctx) { + log_debug("Stopping X11 event loop thread..."); + + atomic_store(&patch_x11_event_loop_ctx->run, 0); + pthread_join(patch_x11_event_loop_ctx->thread, NULL); + free(patch_x11_event_loop_ctx); + patch_x11_event_loop_ctx = NULL; + + log_debug("Stopped X11 event loop thread"); + } + + return patch_x11_event_loop_real_XDestroyWindow(display, w); +} + +void patch_x11_event_loop_init() +{ + patch_x11_event_loop_enabled = true; + log_info("Initialized"); +} + +void patch_x11_event_loop_add_input_handler(const char* lib_with_handler_impl) +{ + const struct ptapi_io_x11_input_hook_handler** new_array; + size_t new_size; + void* lib_handle; + ptapi_io_x11_input_handler_hook_t input_handler_hook_func; + const struct ptapi_io_x11_input_hook_handler* input_handler_hook; + + if (!lib_with_handler_impl) { + log_die("No library path with input handler implementation specified"); + } + + log_info("Loading library with x11-input-handler api implementation %s", lib_with_handler_impl); + + lib_handle = cnh_lib_load(lib_with_handler_impl); + + input_handler_hook_func = (ptapi_io_x11_input_handler_hook_t) + cnh_lib_get_func_addr_handle(lib_handle, "ptapi_io_x11_input_handler_hook"); + + input_handler_hook = input_handler_hook_func(); + + if (!input_handler_hook) { + log_warn("Library impl %s returned NULL hook handler, skipping", lib_with_handler_impl); + return; + } + + pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock); + + new_size = patch_x11_event_loop_num_input_handlers + 1; + new_array = realloc(patch_x11_event_loop_input_handlers, new_size * sizeof(struct ptapi_io_input_hook_handler*)); + + if (new_array != NULL) { + patch_x11_event_loop_input_handlers = new_array; + + patch_x11_event_loop_input_handlers[patch_x11_event_loop_num_input_handlers++] = input_handler_hook; + } else { + log_die("Out of memory"); + } + + pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock); + + log_debug("Added input handler %p of lib %s", input_handler_hook, lib_with_handler_impl); +} \ No newline at end of file diff --git a/src/main/hook/patch/x11-event-loop.h b/src/main/hook/patch/x11-event-loop.h new file mode 100644 index 0000000..282ca17 --- /dev/null +++ b/src/main/hook/patch/x11-event-loop.h @@ -0,0 +1,18 @@ +#ifndef PROHOOK_X11_EVENT_LOOP_H +#define PROHOOK_X11_EVENT_LOOP_H + +/** + * Initialize this module which re-implements a X11 event loop processing keyboard button presses and releases. + * This is required for Pro 1/2 because the game has all X11 input handling removed. Therefore, we cannot use any + * ptapi io implementations using X11, e.g. keyboard inputs. + */ +void patch_x11_event_loop_init(); + +/** + * Register a handler (multiple possible) to receive X11 input events, e.g. key pressed, released + * + * @param lib_with_handler_impl Path to a library implementing the x11-input-handler API + */ +void patch_x11_event_loop_add_input_handler(const char* lib_with_handler_impl); + +#endif diff --git a/src/main/hook/pri/main.c b/src/main/hook/pri/main.c new file mode 100644 index 0000000..0d53da3 --- /dev/null +++ b/src/main/hook/pri/main.c @@ -0,0 +1,294 @@ +/** + * Hook library for Pump It Up: Prime + */ +#define LOG_MODULE "prihook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/amixer-block.h" +#include "hook/patch/blacklist-url.h" +#include "hook/patch/block-keyboard-grab.h" +#include "hook/patch/gfx.h" +#include "hook/patch/hasp.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/mounts.h" +#include "hook/patch/network.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/ram-wipe.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/usb-mnt.h" +#include "hook/patch/usbfs.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/net.h" +#include "util/sys-info.h" + +#include "options.h" +#include "usb-updates.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_prihook_hdd_raw_start[]; +extern const uint8_t _binary_prihook_hdd_raw_end[]; +extern const uint8_t _binary_prihook_hasp_key_start[]; +extern const uint8_t _binary_prihook_hasp_key_end[]; + +static void prihook_bootstrapping(int argc, char** argv, struct prihook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!prihook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + hook_core_piu_utils_fix_locale(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void prihook_patch_fs_init(struct prihook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void prihook_fs_redir_settings(struct prihook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void prihook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); + patch_usbfs_init(); +} + +static void prihook_fs_redirs_init(struct prihook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + prihook_fs_redir_settings(options); + + prihook_fs_redir_usb(); +} + +static void prihook_patch_fs_mounting_init() +{ + patch_mounts_init(); + + patch_usb_mnt_init(); +} + +static void prihook_patch_gfx_init(struct prihook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void prihook_patch_main_loop_init(struct prihook_options* options) +{ + log_assert(options); + + patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } + + patch_block_keyboard_grab_init(); +} + +static void prihook_patch_sound_init(struct prihook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); + patch_axmier_block_init(); +} + +static void prihook_patch_sigsegv_init(struct prihook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void prihook_patch_dongle_init() +{ + patch_hasp_init((const uint8_t*) _binary_prihook_hasp_key_start, + ((uintptr_t) &_binary_prihook_hasp_key_end - (uintptr_t) &_binary_prihook_hasp_key_start)); +} + +static void prihook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_prihook_hdd_raw_start, + ((uintptr_t) &_binary_prihook_hdd_raw_end - (uintptr_t) &_binary_prihook_hdd_raw_start)); +} + +static void prihook_patch_ram_wipe_init() +{ + patch_ram_wipe_init(); +} + +static void prihook_patch_piuio_init(struct prihook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +static void prihook_patch_net_init(struct prihook_options* options) +{ + patch_blacklist_url_init(); + /* update server */ + patch_blacklist_url_add("http://update_kr"); + /* game server */ + patch_blacklist_url_add("http://www2.piugame.com"); + + patch_network_init(); + + if (options->patch.net.server) { + char* address; + uint16_t port; + + if (!util_net_split_ipv4_str(options->patch.net.server, &address, &port)) { + log_warn("Invalid format for option network address specified, ignored"); + } else { + patch_network_redirect_server_address("115.68.108.183", address, (uint16_t) port); + free(address); + } + } else { + // Redirect to avoid phoning home if no server address is set + patch_network_redirect_server_address("115.68.108.183", "127.0.0.1", 12345); + } + + // Idk what this address is...redirect to something save for now + patch_network_redirect_server_address("45.76.222.114", "127.0.0.1", 12345); +} + +static void prihook_patch_usb_init() +{ + prihook_usb_updates_init(); +} + +void prihook_constructor(void) +{ + /* Nothing here */ +} + +void prihook_destructor(void) +{ + /* Nothing here */ +} + +void prihook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct prihook_options options; + + prihook_bootstrapping(argc, argv, &options, &game_data_path); + prihook_patch_fs_init(&options); + prihook_fs_redirs_init(&options, game_data_path); + prihook_patch_fs_mounting_init(); + prihook_patch_gfx_init(&options); + prihook_patch_main_loop_init(&options); + prihook_patch_sound_init(&options); + prihook_patch_sigsegv_init(&options); + prihook_patch_dongle_init(); + prihook_patch_hdd_check_init(); + prihook_patch_ram_wipe_init(); + prihook_patch_piuio_init(&options); + prihook_patch_net_init(&options); + prihook_patch_usb_init(); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void prihook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(prihook_constructor); +LIB_MAIN_DESTRUCTOR(prihook_destructor); +LIB_MAIN_TRAP_MAIN(prihook_trap_before_main, prihook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/pri/options.c b/src/main/hook/pri/options.c new file mode 100644 index 0000000..e78db1d --- /dev/null +++ b/src/main/hook/pri/options.c @@ -0,0 +1,183 @@ +#include "hook/pri/options.h" + +#include "util/options.h" + +#define PRIHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define PRIHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER "patch.net.server" +#define PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define PRIHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def prihook_options_def[] = { + { + .name = PRIHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (PRI) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER, + .description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)", + .param = 'n', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs prihook_options_defs = { + .usage_header = + "Pumptools prihook for Pump It Up: Prime, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./prihook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = prihook_options_def, + .ndefs = lengthof(prihook_options_def) +}; + +bool prihook_options_init(int argc, char** argv, struct prihook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&prihook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.settings = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.net.server = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER); + options->patch.piuio.api_lib = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/pri/options.h b/src/main/hook/pri/options.h new file mode 100644 index 0000000..e4ba4ed --- /dev/null +++ b/src/main/hook/pri/options.h @@ -0,0 +1,58 @@ +#ifndef PRIHOOK_OPTIONS_H +#define PRIHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct prihook_options { + struct game { + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct net { + const char* server; + } net; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool prihook_options_init(int argc, char** argv, struct prihook_options* options); + +#endif diff --git a/src/main/hook/pri/prihook.hasp.key b/src/main/hook/pri/prihook.hasp.key new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/pri/prihook.hasp.key @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/pri/prihook.hdd.raw b/src/main/hook/pri/prihook.hdd.raw new file mode 100644 index 0000000..77b1c43 --- /dev/null +++ b/src/main/hook/pri/prihook.hdd.raw @@ -0,0 +1 @@ +DUMMY NOT RELEASED YET \ No newline at end of file diff --git a/src/main/hook/pri/usb-updates.c b/src/main/hook/pri/usb-updates.c new file mode 100644 index 0000000..876a7da --- /dev/null +++ b/src/main/hook/pri/usb-updates.c @@ -0,0 +1,27 @@ +#define LOG_MODULE "prihook-usb-updates" + +#include + +#include "capnhook/hook/filehook.h" + +#include "util/log.h" + +static enum cnh_result prihook_usb_updates_filehook(struct cnh_filehook_irp *irp) +{ + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN) { + return cnh_filehook_invoke_next(irp); + } + + if (!strcmp(irp->open_filename, "/mnt/0/prime_") || !strcmp(irp->open_filename, "/mnt/1/prime_")) { + log_info("Blocking usb update %s", irp->open_filename); + + return CNH_RESULT_NO_SUCH_FILE_OR_DIR; + } + + return cnh_filehook_invoke_next(irp); +} + +void prihook_usb_updates_init(void) +{ + cnh_filehook_push_handler(prihook_usb_updates_filehook); +} \ No newline at end of file diff --git a/src/main/hook/pri/usb-updates.h b/src/main/hook/pri/usb-updates.h new file mode 100644 index 0000000..817a467 --- /dev/null +++ b/src/main/hook/pri/usb-updates.h @@ -0,0 +1,12 @@ +/** + * Block updates from usb flash drives on Prime + */ +#ifndef PRIHOOK_USB_UPDATES_H +#define PATCH_USB_UPDATES_H + +/** + * Initialize patch module + */ +void prihook_usb_updates_init(void); + +#endif \ No newline at end of file diff --git a/src/main/hook/pro/main.c b/src/main/hook/pro/main.c new file mode 100644 index 0000000..aed7037 --- /dev/null +++ b/src/main/hook/pro/main.c @@ -0,0 +1,218 @@ +/** + * Hook library for Pump It Up: Pro + */ +#define LOG_MODULE "prohook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/hook-mon.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/x11-event-loop.h" + +#include "hook/propatch/usb-fix.h" + +#include "hook/patch/piubtn.h" +#include "hook/patch/piuio.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/log.h" +#include "util/sys-info.h" + +#include "options.h" + +static void prohook_bootstrapping(int argc, char** argv, struct prohook_options* options) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!prohook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing"); +} + +static void prohook_patch_fs_init(struct prohook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void prohook_fs_redir_settings(struct prohook_options* options) +{ + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/data", abs_path); + free(abs_path); + } else { + log_warn("No settings (data) path specified"); + } +} + +static void prohook_fs_redir_data(struct prohook_options* options) +{ + if (options->game.data) { + char* abs_path = util_fs_get_abs_path(options->game.data); + + cnh_redir_add("/game", abs_path); + free(abs_path); + } else { + log_warn("No data (game) path specified"); + } +} + +static void prohook_fs_redirs_init(struct prohook_options* options) +{ + log_assert(options); + + prohook_fs_redir_settings(options); + prohook_fs_redir_data(options); +} + +static void prohook_patch_sigsegv_init(struct prohook_options* options) +{ + log_assert(options); + + /* seems like pump pro doesn't like it when injecting our own signal + handler. game crashes instantly when adding it. */ + /* + patch_sigsegv_init(); + */ +} + +static void prohook_patch_x11_event_loop_init(struct prohook_options* options) +{ + patch_x11_event_loop_init(); + + // Register up to two X11 input handlers for piuio and piubtn + + if (options->patch.x11_event_loop.api_lib) { + char* abs_path_lib = util_fs_get_abs_path(options->patch.x11_event_loop.api_lib); + + patch_x11_event_loop_add_input_handler(abs_path_lib); + free(abs_path_lib); + } + + if (options->patch.x11_event_loop.api_lib2) { + char* abs_path_lib = util_fs_get_abs_path(options->patch.x11_event_loop.api_lib2); + + patch_x11_event_loop_add_input_handler(abs_path_lib); + free(abs_path_lib); + } +} + +static void prohook_patch_usbprofiles(struct prohook_options* options) +{ + propatch_usb_fix_init( + options->patch.usb_profile.device_nodes, + options->patch.usb_profile.p1_bus_port, + options->patch.usb_profile.p2_bus_port); +} + +static void prohook_patch_piuio_init(struct prohook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +static void prohook_patch_piubtn_init(struct prohook_options* options) +{ + if (options->patch.piubtn.api_lib) { + char* abs_path_btnlib = util_fs_get_abs_path(options->patch.piubtn.api_lib); + + patch_piubtn_init(abs_path_btnlib); + free(abs_path_btnlib); + } +} + +void prohook_constructor(void) +{ + /* Nothing here */ +} + +void prohook_destructor(void) +{ + /* Nothing here */ +} + +void prohook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + struct prohook_options options; + + prohook_bootstrapping(argc, argv, &options); + prohook_patch_fs_init(&options); + prohook_fs_redirs_init(&options); + prohook_patch_sigsegv_init(&options); + prohook_patch_x11_event_loop_init(&options); + prohook_patch_usbprofiles(&options); + prohook_patch_piuio_init(&options); + prohook_patch_piubtn_init(&options); + + log_info("Hooking finished"); +} + +void prohook_trap_after_main(void) +{ + propatch_usb_fix_shutdown(); + patch_piubtn_shutdown(); + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(prohook_constructor); +LIB_MAIN_DESTRUCTOR(prohook_destructor); +LIB_MAIN_TRAP_MAIN(prohook_trap_before_main, prohook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/pro/options.c b/src/main/hook/pro/options.c new file mode 100644 index 0000000..9aadcc5 --- /dev/null +++ b/src/main/hook/pro/options.c @@ -0,0 +1,197 @@ +#include "hook/pro/options.h" + +#include "util/options.h" + +#define PROHOOK_OPTIONS_STR_GAME_DATA "game.data" +#define PROHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB "patch.piubtn.emu_lib" +#define PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT "patch.usb_profile.p1.bus_port" +#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT "patch.usb_profile.p2.bus_port" +#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES "patch.usb_profile.dev_nodes" +#define PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER "patch_x11_event_loop.input_handler_lib" +#define PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2 "patch_x11_event_loop.input_handler_lib2" +#define PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +static const struct util_options_def prohook_options_def[] = { + { + .name = PROHOOK_OPTIONS_STR_GAME_DATA, + .description = "Path to game data (game) folder", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./game", + }, + { + .name = PROHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (data) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB, + .description = "Path to library implementing the piubtn api for piubtn emulation", + .param = 'b', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT, + .description = "Bus and port (format: X-X, e.g. 1-2) of the USB slot to assign to Player 1 when a USB thumb " + "drive is plugged in", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT, + .description = "Bus and port (format: X-X, e.g. 1-2) of the USB slot to assign to Player 2 when a USB thumb " + "drive is plugged in", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES, + .description = "Device nodes of plugged in USB thumb drives to consider for mounting for usb profiles, format: " + "sdX,sdY e.g. sde,sdf", + .param = 't', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2, + .description = "Path to a second library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'r', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +static const struct util_options_defs prohook_options_defs = { + .usage_header = + "Pumptools prohook for Pump It Up: Pro, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./prohook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = prohook_options_def, + .ndefs = lengthof(prohook_options_def) +}; + +bool prohook_options_init(int argc, char** argv, struct prohook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&prohook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.data = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_GAME_DATA); + options->game.settings = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.hook_mon.file = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.piubtn.api_lib = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB); + options->patch.piuio.api_lib = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.usb_profile.device_nodes = + util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES); + options->patch.usb_profile.p1_bus_port = + util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT); + options->patch.usb_profile.p2_bus_port = + util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT); + options->patch.x11_event_loop.api_lib = + util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER); + options->patch.x11_event_loop.api_lib2 = + util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2); + options->log.file = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/pro/options.h b/src/main/hook/pro/options.h new file mode 100644 index 0000000..8cd6010 --- /dev/null +++ b/src/main/hook/pro/options.h @@ -0,0 +1,53 @@ +#ifndef PROHOOK_OPTIONS_H +#define PROHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct prohook_options { + struct game { + const char* data; + const char* settings; + } game; + + struct patch { + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct piubtn { + const char* api_lib; + } piubtn; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct usb_profile { + const char* device_nodes; + const char* p1_bus_port; + const char* p2_bus_port; + } usb_profile; + + struct x11_event_loop { + const char* api_lib; + const char* api_lib2; + } x11_event_loop; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool prohook_options_init(int argc, char** argv, struct prohook_options* options); + +#endif diff --git a/src/main/hook/pro2/main.c b/src/main/hook/pro2/main.c new file mode 100644 index 0000000..ba6af5b --- /dev/null +++ b/src/main/hook/pro2/main.c @@ -0,0 +1,230 @@ +/** + * Hook library for Pump It Up: Pro 2 + */ +#define LOG_MODULE "pro2hook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/hook-mon.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" +#include "hook/patch/x11-event-loop.h" + +#include "hook/patch/piubtn.h" +#include "hook/patch/piuio.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/log.h" +#include "util/patch.h" +#include "util/sys-info.h" + +#include "options.h" + +/** + * Copy/paste from binary: + * int PatchOriginalDlopen() + * { + * int result; // eax@1 + * + * result = mprotect((void *)((unsigned int)dlopen & 0xFFFFF000), 0x2000u, 7) + 1; + * if ( !result ) + * { + * sub_836EF70("../../src/pump/SecureBinary.cpp", 127, (int)"Assertion 'ret != -1' failed"); + * sub_821B1B0("Assertion 'ret != -1' failed"); + * } + * if ( *(_BYTE *)dlopen != -1 ) + * { + * sub_836EF70("../../src/pump/SecureBinary.cpp", 130, (int)"Assertion 'pDlopen[0] == 0xFF' failed"); + * sub_821B1B0("Assertion 'pDlopen[0] == 0xFF' failed"); + * } + * *((_BYTE *)dlopen + 5) = 0x90u; + * *(_BYTE *)dlopen = 0xE9u; + * dword_865C03C = *(_DWORD *)dlopen; + * word_865C040 = *((_WORD *)dlopen + 2); + * *(_DWORD *)((char *)dlopen + 1) = (char *)sub_8383C90 + 0xF7FB232B; + * return result; + * } + */ +static void pro2hook_patch_secure_binary_dlopen_switcheroo() +{ + uint8_t buffer[4] = {0xC3, 0x90, 0x90, 0x90}; + + log_info("Patching dlopen switcheroo"); + + /* This address will only work with the latest revision executable (iirc + that was R5?) */ + util_patch_write_memory(0x8383BC0, buffer, 4); +} + +static void pro2hook_bootstrapping(int argc, char** argv, struct pro2hook_options* options) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!pro2hook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing"); +} + +static void pro2hook_patch_fs_init(struct pro2hook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void pro2hook_fs_redir_data(struct pro2hook_options* options) +{ + log_assert(options); + + if (options->game.data) { + char* abs_path = util_fs_get_abs_path(options->game.data); + + cnh_redir_add("/pro2", abs_path); + free(abs_path); + } else { + log_warn("No data (game) path specified"); + } +} + +static void pro2hook_fs_redirs_init(struct pro2hook_options* options) +{ + log_assert(options); + + pro2hook_fs_redir_data(options); +} + +static void pro2hook_patch_sigsegv_init(struct pro2hook_options* options) +{ + log_assert(options); + + /* seems like pump pro doesn't like it when injecting our own signal + handler. game crashes instantly when adding it. */ + /* + patch_sigsegv_init(); + */ +} + +static void pro2hook_patch_x11_event_loop_init(struct pro2hook_options* options) +{ + patch_x11_event_loop_init(); + + // Register up to two X11 input handlers for piuio and piubtn + + if (options->patch.x11_event_loop.api_lib) { + char* abs_path_lib = util_fs_get_abs_path(options->patch.x11_event_loop.api_lib); + + patch_x11_event_loop_add_input_handler(abs_path_lib); + free(abs_path_lib); + } + + if (options->patch.x11_event_loop.api_lib2) { + char* abs_path_lib = util_fs_get_abs_path(options->patch.x11_event_loop.api_lib2); + + patch_x11_event_loop_add_input_handler(abs_path_lib); + free(abs_path_lib); + } +} + +static void pro2hook_patch_piuio_init(struct pro2hook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +static void pro2hook_patch_piubtn_init(struct pro2hook_options* options) +{ + if (options->patch.piubtn.api_lib) { + char* abs_path_btnlib = util_fs_get_abs_path(options->patch.piubtn.api_lib); + + patch_piubtn_init(abs_path_btnlib); + free(abs_path_btnlib); + } +} + +static void pro2hook_patch_secure_binary() +{ + pro2hook_patch_secure_binary_dlopen_switcheroo(); +} + +void pro2hook_constructor(void) +{ + /* Nothing here */ +} + +void pro2hook_destructor(void) +{ + /* Nothing here */ +} + +void pro2hook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + struct pro2hook_options options; + + pro2hook_bootstrapping(argc, argv, &options); + pro2hook_patch_fs_init(&options); + pro2hook_fs_redirs_init(&options); + pro2hook_patch_sigsegv_init(&options); + pro2hook_patch_x11_event_loop_init(&options); + pro2hook_patch_piuio_init(&options); + pro2hook_patch_piubtn_init(&options); + pro2hook_patch_secure_binary(); + + log_info("Hooking finished"); +} + +void pro2hook_trap_after_main(void) +{ + patch_piubtn_shutdown(); + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(pro2hook_constructor); +LIB_MAIN_DESTRUCTOR(pro2hook_destructor); +LIB_MAIN_TRAP_MAIN(pro2hook_trap_before_main, pro2hook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/pro2/options.c b/src/main/hook/pro2/options.c new file mode 100644 index 0000000..1dac0c9 --- /dev/null +++ b/src/main/hook/pro2/options.c @@ -0,0 +1,155 @@ +#include "hook/pro2/options.h" + +#include "util/options.h" + +#define PRO2HOOK_OPTIONS_STR_GAME_DATA "game.data" +#define PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define PRO2HOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB "patch.piubtn.emu_lib" +#define PRO2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define PRO2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define PRO2HOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER "patch_x11_event_loop.input_handler_lib" +#define PRO2HOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2 "patch_x11_event_loop.input_handler_lib2" +#define PRO2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define PRO2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +const struct util_options_def pro2hook_options_def[] = { + { + .name = PRO2HOOK_OPTIONS_STR_GAME_DATA, + .description = "Path to game data (game) folder", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./game", + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB, + .description = "Path to library implementing the piubtn api for piubtn emulation", + .param = 'b', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2, + .description = "Path to a second library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'r', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = PRO2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +const struct util_options_defs pro2hook_options_defs = { + .usage_header = + "Pumptools prohook for Pump It Up: Pro 2, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./prohook2.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = pro2hook_options_def, + .ndefs = lengthof(pro2hook_options_def) +}; + +bool pro2hook_options_init(int argc, char** argv, struct pro2hook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&pro2hook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.data = util_options_get_str(options_opt, PRO2HOOK_OPTIONS_STR_GAME_DATA); + options->patch.hook_mon.file = util_options_get_bool(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.piubtn.api_lib = util_options_get_str(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB); + options->patch.piuio.api_lib = util_options_get_str(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.x11_event_loop.api_lib = + util_options_get_str(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER); + options->patch.x11_event_loop.api_lib2 = + util_options_get_str(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2); + options->log.file = util_options_get_str(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, PRO2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/pro2/options.h b/src/main/hook/pro2/options.h new file mode 100644 index 0000000..19600df --- /dev/null +++ b/src/main/hook/pro2/options.h @@ -0,0 +1,46 @@ +#ifndef PRO2HOOK_OPTIONS_H +#define PRO2HOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct pro2hook_options { + struct game { + const char* data; + } game; + + struct patch { + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct piubtn { + const char* api_lib; + } piubtn; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct x11_event_loop { + const char* api_lib; + const char* api_lib2; + } x11_event_loop; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool pro2hook_options_init(int argc, char** argv, struct pro2hook_options* options); + +#endif diff --git a/src/main/hook/propatch/usb-fix.c b/src/main/hook/propatch/usb-fix.c new file mode 100644 index 0000000..bd3021a --- /dev/null +++ b/src/main/hook/propatch/usb-fix.c @@ -0,0 +1,177 @@ +#define LOG_MODULE "usb-fix" + +#include + +#include "capnhook/hook/lib.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +typedef ssize_t (*readlink_t) (const char * path, char * buf, size_t len); +static readlink_t pro_usb_fix_real_readlink; + +static const int16_t propatch_usb_fix_usb_static_ini_usb_bus[2] = {1, 1}; +static const int16_t propatch_usb_fix_usb_static_ini_usb_port[2] = {2, 1}; + +static char propatch_usb_fix_device_thumb_drive_p1[128]; +static char propatch_usb_fix_device_thumb_drive_p2[128]; + +static int propatch_usb_fix_usb_bus[2]; +static int propatch_usb_fix_usb_port[2]; + +static bool propatch_usb_fix_enabled; + +// Non static for testing +ssize_t propatch_usb_fix_readlink(const char* path, char* buf, size_t len) +{ + if (!pro_usb_fix_real_readlink) { + pro_usb_fix_real_readlink = (readlink_t) cnh_lib_get_func_addr("readlink"); + } + + // pro is scanning the /sys/block directory where all usb thumb drives show up once connected + // The game iterates the directory and resolves the /sys/block/sdX/device symlink + // On current kernels, e.g. 5.6.14, it might look like this + // ../devices/pci0000:00/0000:00:14.0/usb2/2-2/2-2:1.0/host7/target7:0:0/7:0:0:0/block/sdd + // However, when pro was developed, the symlink looked entirely different. + // In order to allow the game to detect and mount usb thumb drives on newer kernels, the path + // needs to be altered to match what the game is expecting which might be similar to this: + // ../devices/pci0000:00/0000:00:14.0/usb2/2-2/2-2:1.0 + // The game tokenizes this path by / and picks the second to last item, which is '2-2' here. + // This item gets further split into bus (2) and port (2). If that is successful, the game treats the + // detected device as valid allowing it to mount if the bus and port match what has been configured in + // the Static.ini file + if (propatch_usb_fix_enabled && util_str_starts_with(path, "/sys/block/") && util_str_ends_with(path, "/device")) { + log_debug("Trap %s", path); + + // Remove the trailing "/device" part which is no longer valid on current kernels + // /sys/block/sdc/device -> /sys/block/sdc + char* tmp = util_str_dup(path); + size_t len_tmp = strlen(tmp); + tmp[len_tmp - 7] = '\0'; + + memset(buf, 0, len); + + ssize_t res = pro_usb_fix_real_readlink(tmp, buf, len); + + util_xfree((void**) &tmp); + + if (strstr(buf, propatch_usb_fix_device_thumb_drive_p1) || strstr(buf, propatch_usb_fix_device_thumb_drive_p2)) { + log_debug("Detected assigned flash drive plugged in"); + + size_t count; + char** toks; + + toks = util_str_split(buf, "/", &count); + + // some sanity checks to ensure the format isn't different + if ( count != 12 || + strcmp(toks[0], "..") != 0 || + strcmp(toks[1], "devices") != 0 || + strcmp(toks[10], "block") != 0) { + log_error( + "/sys/block device readlink format changed, usb thumb drive profiles will likely not work!: %s", + buf); + util_str_free_split(toks, count); + return 0; + } + + int bus; + int port; + const char* device = toks[11]; + + if (sscanf(toks[5], "%d-%d", &bus, &port) != 2) { + log_error("Parsing bus-port of %s failed", buf); + util_str_free_split(toks, count); + return 0; + } + + log_debug("Detected flash drive on bus %d, port %d, device %s", bus, port, device); + + for (int i = 0; i < 2; i++) { + if (propatch_usb_fix_usb_bus[i] == bus && propatch_usb_fix_usb_port[i] == port) { + // The usb manager only cares about reading the second to last token in the correct format + // Copy-paste everything else + sprintf( + buf, + "%s/%s/%s/%s/%s/%d-%d/%d-%d:1.0", + toks[0], + toks[1], + toks[2], + toks[3], + toks[4], + propatch_usb_fix_usb_static_ini_usb_bus[i], + propatch_usb_fix_usb_static_ini_usb_port[i], + propatch_usb_fix_usb_static_ini_usb_bus[i], + propatch_usb_fix_usb_static_ini_usb_port[i]); + + log_debug("Player %d usb thumb drive at path %s", i, buf); + + util_str_free_split(toks, count); + + return strlen(buf); + } + } + + util_str_free_split(toks, count); + } + + return res; + } + + return pro_usb_fix_real_readlink(path, buf, len); +} + +ssize_t readlink(const char* path, char* buf, size_t len) +{ + return propatch_usb_fix_readlink(path, buf, len); +} + +void propatch_usb_fix_init(const char* device_nodes, const char* p1_bus_port, const char* p2_bus_port) +{ + size_t count; + char** toks; + + if (!device_nodes || !p1_bus_port || !p2_bus_port) { + log_warn("Disabled, missing one or multiple option properties"); + return; + } + + toks = util_str_split(device_nodes, ",", &count); + + if (count != 2) { + log_error("Invalid format for device nodes: %s", device_nodes); + util_str_free_split(toks, count); + return; + } + + strcpy(propatch_usb_fix_device_thumb_drive_p1, toks[0]); + strcpy(propatch_usb_fix_device_thumb_drive_p2, toks[1]); + + util_str_free_split(toks, count); + + if (sscanf(p1_bus_port, "%d-%d", &propatch_usb_fix_usb_bus[0], &propatch_usb_fix_usb_port[0]) != 2) { + log_error("Invalid format for p1 bus-port: %s", p1_bus_port); + return; + } + + if (sscanf(p2_bus_port, "%d-%d", &propatch_usb_fix_usb_bus[1], &propatch_usb_fix_usb_port[1]) != 2) { + log_error("Invalid format for p2 bus-port: %s", p2_bus_port); + return; + } + + log_info("Initialized: device nodes %s,%s, p1 %d-%d, p2 %d-%d", + propatch_usb_fix_device_thumb_drive_p1, + propatch_usb_fix_device_thumb_drive_p2, + propatch_usb_fix_usb_bus[0], + propatch_usb_fix_usb_port[0], + propatch_usb_fix_usb_bus[1], + propatch_usb_fix_usb_port[1]); + + propatch_usb_fix_enabled = true; +} + +void propatch_usb_fix_shutdown() +{ + +} \ No newline at end of file diff --git a/src/main/hook/propatch/usb-fix.h b/src/main/hook/propatch/usb-fix.h new file mode 100644 index 0000000..0246d83 --- /dev/null +++ b/src/main/hook/propatch/usb-fix.h @@ -0,0 +1,5 @@ +#pragma once + +void propatch_usb_fix_init(const char* device_nodes, const char* p1_bus_port, const char* p2_bus_port); + +void propatch_usb_fix_shutdown(); \ No newline at end of file diff --git a/src/main/hook/x2/main.c b/src/main/hook/x2/main.c new file mode 100644 index 0000000..00b4e3f --- /dev/null +++ b/src/main/hook/x2/main.c @@ -0,0 +1,250 @@ +/** + * Hook library for Pump It Up: Exceed 2 + */ +#define LOG_MODULE "x2hook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/gfx.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog34.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/patch.h" +#include "util/str.h" +#include "util/sys-info.h" + +#include "options.h" +#include "unlock.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_x2hook_dog_key_start[]; +extern const uint8_t _binary_x2hook_dog_key_end[]; + +static void x2hook_bootstrapping(int argc, char** argv, struct x2hook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!x2hook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void x2hook_patch_fs_init(struct x2hook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void x2hook_fs_redir_settings(struct x2hook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void x2hook_fs_redir_script(struct x2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + path_tmp = util_str_merge(game_data_path, "/SCRIPT"); + cnh_redir_add("/SCRIPT", path_tmp); + free(path_tmp); +} + +static void x2hook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); +} + +static void x2hook_fs_redirs_init(struct x2hook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + /* Expecting all assets in the piu game (asset) folder. redirects for files + that are not in there by default for reasons */ + x2hook_fs_redir_settings(options); + x2hook_fs_redir_script(options, game_data_path); + + x2hook_fs_redir_usb(); +} + +static void x2hook_patch_gfx_init(struct x2hook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void x2hook_patch_game_init(struct x2hook_options* options) +{ + log_assert(options); + + if (options->game.force_unlock) { + hook_x2_unlock_init(); + } + + /* return from StopAllEffects to avoid killing the sound thread */ + log_warn("Applying memory patch only valid for version 102"); + util_patch_write_memory_byte(0x08074CE0, 0xC3); +} + +static void x2hook_patch_main_loop_init(struct x2hook_options* options) +{ + log_assert(options); + + patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void x2hook_patch_sound_init(struct x2hook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); +} + +static void x2hook_patch_sigsegv_init(struct x2hook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void x2hook_patch_dongle_init() +{ + patch_microdog34_init((const uint8_t*) _binary_x2hook_dog_key_start, + ((uintptr_t) &_binary_x2hook_dog_key_end - (uintptr_t) &_binary_x2hook_dog_key_start)); +} + +static void x2hook_patch_piuio_init(struct x2hook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +void x2hook_constructor(void) +{ + /* Nothing here */ +} + +void x2hook_destructor(void) +{ + /* Nothing here */ +} + +void x2hook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct x2hook_options options; + + x2hook_bootstrapping(argc, argv, &options, &game_data_path); + x2hook_patch_fs_init(&options); + x2hook_fs_redirs_init(&options, game_data_path); + x2hook_patch_gfx_init(&options); + x2hook_patch_game_init(&options); + x2hook_patch_main_loop_init(&options); + x2hook_patch_sound_init(&options); + x2hook_patch_sigsegv_init(&options); + x2hook_patch_dongle_init(); + x2hook_patch_piuio_init(&options); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void x2hook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(x2hook_constructor); +LIB_MAIN_DESTRUCTOR(x2hook_destructor); +LIB_MAIN_TRAP_MAIN(x2hook_trap_before_main, x2hook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/x2/ogl-fix.c b/src/main/hook/x2/ogl-fix.c new file mode 100644 index 0000000..067909e --- /dev/null +++ b/src/main/hook/x2/ogl-fix.c @@ -0,0 +1,38 @@ +/** + * Module to fix weird OpenGL error that only appeared on Exceed 2 thus far. + * + * If OpenGL is not forced into single threaded mode, the backend will run in + * multi-threaded mode for some reason and crash in __glDispatchCheckMultithreaded + * when the game calls glXChooseVisual in its GFX init function. + * + * The fix is quite simple (luckily) as this seems that Exceed 2 is not the only + * game that requires the environment variable __GL_SINGLETHREADED to be set. + */ + +#include +#include + +#include "capnhook/hook/lib.h" + +typedef char* (*getenv_t) (const char* name); + +static getenv_t _x2hook_ogl_fix_real_getenv; + +char* getenv(const char* name) +{ + if (!_x2hook_ogl_fix_real_getenv) { + _x2hook_ogl_fix_real_getenv = (getenv_t) cnh_lib_get_func_addr("getenv"); + } + + char* ret = _x2hook_ogl_fix_real_getenv(name); + + if (!strcmp(name, "__GL_SINGLETHREADED")) { + if (ret == NULL || strcmp(name, "1") != 0) { + printf("!!! x2hook: __GL_SINGLETHREADED not set or enabled, force patching OpenGL to single threaded to " + "avoid crash !!!\n"); + return "1"; + } + } + + return ret; +} \ No newline at end of file diff --git a/src/main/hook/x2/options.c b/src/main/hook/x2/options.c new file mode 100644 index 0000000..3816488 --- /dev/null +++ b/src/main/hook/x2/options.c @@ -0,0 +1,183 @@ +#include "hook/x2/options.h" + +#include "util/options.h" + +#define X2HOOK_OPTIONS_STR_GAME_FORCE_UNLOCK "game.force_unlock" +#define X2HOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define X2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define X2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define X2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define X2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define X2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define X2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define X2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define X2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +static const struct util_options_def x2hook_options_def[] = { + { + .name = X2HOOK_OPTIONS_STR_GAME_FORCE_UNLOCK, + .description = "Force unlock the game. Modifies the current and any new PIUEXCEED.INI settings file permanently", + .param = 'z', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = X2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +static const struct util_options_defs x2hook_options_defs = { + .usage_header = + "Pumptools x2hook for Pump It Up: Exceed 2, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./x2hook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = x2hook_options_def, + .ndefs = lengthof(x2hook_options_def) +}; + +bool x2hook_options_init(int argc, char** argv, struct x2hook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&x2hook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.force_unlock = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_GAME_FORCE_UNLOCK); + options->game.settings = util_options_get_str(options_opt, X2HOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + X2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, X2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.piuio.api_lib = util_options_get_str(options_opt, X2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, X2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, X2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, X2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, X2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/x2/options.h b/src/main/hook/x2/options.h new file mode 100644 index 0000000..21f963d --- /dev/null +++ b/src/main/hook/x2/options.h @@ -0,0 +1,55 @@ +#ifndef X2HOOK_OPTIONS_H +#define X2HOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct x2hook_options { + struct game { + bool force_unlock; + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool x2hook_options_init(int argc, char** argv, struct x2hook_options* options); + +#endif diff --git a/src/main/hook/x2/unlock.c b/src/main/hook/x2/unlock.c new file mode 100644 index 0000000..459cf44 --- /dev/null +++ b/src/main/hook/x2/unlock.c @@ -0,0 +1,81 @@ +#define LOG_MODULE "hook-x2-unlock" + +#include +#include + +#include "asset/x2/lib/settings.h" + +#include "capnhook/hook/filehook.h" + +#include "util/log.h" +#include "util/str.h" + +static FILE* _hook_x2_unlock_settings_file = NULL; + +static enum cnh_result _hook_x2_unlock_filehook(struct cnh_filehook_irp *irp); + +void hook_x2_unlock_init(void) +{ + cnh_filehook_push_handler(_hook_x2_unlock_filehook); + + log_info("Initialized"); +} + +static enum cnh_result _hook_x2_unlock_filehook(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + assert(irp); + + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != _hook_x2_unlock_settings_file) { + return cnh_filehook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_FILEHOOK_IRP_OP_OPEN: + { + /* Let it open the real file */ + result = cnh_filehook_invoke_next(irp); + + if (util_str_ends_with(irp->open_filename, ASSET_X2_SETTINGS_FILE_NAME)) { + if (result == CNH_RESULT_SUCCESS) { + log_debug("Intercepting settings file open"); + _hook_x2_unlock_settings_file = irp->file; + } + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_READ: + { + /* Let it read the real file */ + result = cnh_filehook_invoke_next(irp); + + if (result == CNH_RESULT_SUCCESS) { + struct asset_x2_settings* settings = (struct asset_x2_settings*) irp->read.bytes; + + asset_x2_settings_unlock_all(settings); + + log_debug("Applied unlock patch to loaded settings (buffer size %d)", irp->read.pos); + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_CLOSE: + { + _hook_x2_unlock_settings_file = NULL; + + result = cnh_filehook_invoke_next(irp); + + break; + } + + default: + result = cnh_filehook_invoke_next(irp); + break; + } + + return result; +} \ No newline at end of file diff --git a/src/main/hook/x2/unlock.h b/src/main/hook/x2/unlock.h new file mode 100644 index 0000000..4105a0a --- /dev/null +++ b/src/main/hook/x2/unlock.h @@ -0,0 +1,12 @@ +/** + * Patch module to force unlock all permanently unlockable songs and additional difficulties in the game. + */ +#ifndef HOOK_X2_UNLOCK_H +#define HOOK_X2_UNLOCK_H + +/** + * Initialize the patch module force unlocking all locked game content. + */ +void hook_x2_unlock_init(void); + +#endif diff --git a/src/main/hook/x2/x2hook.dog.key b/src/main/hook/x2/x2hook.dog.key new file mode 100755 index 0000000000000000000000000000000000000000..25344183a99a8a01ec1a0c51d5972838ff1182e5 GIT binary patch literal 64444 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 literal 0 HcmV?d00001 diff --git a/src/main/hook/zero/main.c b/src/main/hook/zero/main.c new file mode 100644 index 0000000..3ecbc00 --- /dev/null +++ b/src/main/hook/zero/main.c @@ -0,0 +1,255 @@ +/** + * Hook library for Pump It Up: Zero + */ +#define LOG_MODULE "zerohook" + +#include + +#include "capnhook/hook/lib-main.h" +#include "capnhook/hooklib/redir.h" + +#include "hook/core/piu-utils.h" + +#include "hook/patch/gfx.h" +#include "hook/patch/hdd-check.h" +#include "hook/patch/hook-mon.h" +#include "hook/patch/main-loop.h" +#include "hook/patch/microdog34.h" +#include "hook/patch/piuio.h" +#include "hook/patch/piuio-exit.h" +#include "hook/patch/redir.h" +#include "hook/patch/sigsegv.h" +#include "hook/patch/sound.h" +#include "hook/patch/usb-emu.h" +#include "hook/patch/usb-init-fix.h" + +#include "util/fs.h" +#include "util/glibc.h" +#include "util/str.h" +#include "util/sys-info.h" + +#include "options.h" +#include "unlock.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_zerohook_hdd_raw_start[]; +extern const uint8_t _binary_zerohook_hdd_raw_end[]; +extern const uint8_t _binary_zerohook_dog_key_start[]; +extern const uint8_t _binary_zerohook_dog_key_end[]; + +static void zerohook_bootstrapping(int argc, char** argv, struct zerohook_options* options, char** game_data_path) +{ + log_assert(argc >= 0); + log_assert(argv); + log_assert(options); + log_assert(game_data_path); + + if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) { + return; + } + + hook_core_piu_log_init(argc, argv); + + if (!zerohook_options_init(argc, argv, options)) { + exit(0); + } + + hook_core_piu_log_info(argc, argv); + + *game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv); + + hook_core_piu_utils_verify_root_user(); + + log_info("Initializing, piu game data path: %s", *game_data_path); +} + +static void zerohook_patch_fs_init(struct zerohook_options* options) +{ + log_assert(options); + + patch_hook_mon_init( + options->patch.hook_mon.io, + options->patch.hook_mon.file, + options->patch.hook_mon.fs, + options->patch.hook_mon.usb, + options->patch.hook_mon.open); + + patch_redir_init(); +} + +static void zerohook_fs_redir_settings(struct zerohook_options* options) +{ + log_assert(options); + + if (options->game.settings) { + if (!util_fs_path_exists(options->game.settings)) { + log_info("Settings path %s does not exist, creating", options->game.settings); + + if (!util_fs_mkdir(options->game.settings)) { + log_error("Creating directory %s failed", options->game.settings); + } + } + + char* abs_path = util_fs_get_abs_path(options->game.settings); + + cnh_redir_add("/SETTINGS", abs_path); + free(abs_path); + } else { + log_warn("No settings path specified"); + } +} + +static void zerohook_fs_redir_script(struct zerohook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + char* path_tmp; + + path_tmp = util_str_merge(game_data_path, "/SCRIPT"); + cnh_redir_add("/SCRIPT", path_tmp); + free(path_tmp); +} + +static void zerohook_fs_redir_usb() +{ + /* Needed on newer kernels */ + cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices"); +} + +static void zerohook_fs_redirs_init(struct zerohook_options* options, const char* game_data_path) +{ + log_assert(options); + log_assert(game_data_path); + + /* Expecting all assets in the piu game (asset) folder. redirects for files + that are not in there by default for reasons */ + zerohook_fs_redir_settings(options); + zerohook_fs_redir_script(options, game_data_path); + + zerohook_fs_redir_usb(); +} + +static void zerohook_patch_gfx_init(struct zerohook_options* options) +{ + log_assert(options); + + patch_gfx_init(); + + if (options->patch.gfx.windowed) { + patch_gfx_force_window_mode(); + } +} + +static void zerohook_patch_game_init(struct zerohook_options* options) +{ + log_assert(options); + + if (options->game.force_unlock) { + hook_zero_unlock_init(); + } +} + +static void zerohook_patch_main_loop_init(struct zerohook_options* options) +{ + log_assert(options); + + patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false); + + if (options->patch.main_loop.x11_input_handler_api_lib) { + char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib); + + patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib); + free(abs_path_x11_input_hook_lib); + } +} + +static void zerohook_patch_sound_init(struct zerohook_options* options) +{ + log_assert(options); + + patch_sound_init(options->patch.sound.device); +} + +static void zerohook_patch_sigsegv_init(struct zerohook_options* options) +{ + log_assert(options); + + patch_sigsegv_init(options->patch.sigsegv.halt_on_segv); +} + +static void zerohook_patch_dongle_init() +{ + patch_microdog34_init((const uint8_t*) _binary_zerohook_dog_key_start, + ((uintptr_t) &_binary_zerohook_dog_key_end - (uintptr_t) &_binary_zerohook_dog_key_start)); +} + +static void zerohook_patch_hdd_check_init() +{ + patch_hdd_check_init((const uint8_t*) _binary_zerohook_hdd_raw_start, + ((uintptr_t) &_binary_zerohook_hdd_raw_end - (uintptr_t) &_binary_zerohook_hdd_raw_start)); +} + +static void zerohook_patch_piuio_init(struct zerohook_options* options) +{ + log_assert(options); + + /* Hook before IO emulation */ + if (options->patch.piuio.exit_test_serv) { + patch_piuio_exit_init(); + } + + patch_usb_init_fix_init(); + patch_usb_emu_init(); + + if (options->patch.piuio.api_lib) { + char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib); + + patch_piuio_init(abs_path_iolib); + free(abs_path_iolib); + } +} + +void zerohook_constructor(void) +{ + /* Nothing here */ +} + +void zerohook_destructor(void) +{ + /* Nothing here */ +} + +void zerohook_trap_before_main(int argc, char** argv) +{ + log_assert(argc >= 0); + log_assert(argv); + + char* game_data_path; + struct zerohook_options options; + + zerohook_bootstrapping(argc, argv, &options, &game_data_path); + zerohook_patch_fs_init(&options); + zerohook_fs_redirs_init(&options, game_data_path); + zerohook_patch_gfx_init(&options); + zerohook_patch_game_init(&options); + zerohook_patch_main_loop_init(&options); + zerohook_patch_sound_init(&options); + zerohook_patch_sigsegv_init(&options); + zerohook_patch_dongle_init(); + zerohook_patch_hdd_check_init(); + zerohook_patch_piuio_init(&options); + + free(game_data_path); + + log_info("Hooking finished"); +} + +void zerohook_trap_after_main(void) +{ + patch_piuio_shutdown(); +} + +LIB_MAIN_CONSTRUCTOR(zerohook_constructor); +LIB_MAIN_DESTRUCTOR(zerohook_destructor); +LIB_MAIN_TRAP_MAIN(zerohook_trap_before_main, zerohook_trap_after_main); \ No newline at end of file diff --git a/src/main/hook/zero/options.c b/src/main/hook/zero/options.c new file mode 100644 index 0000000..74166bc --- /dev/null +++ b/src/main/hook/zero/options.c @@ -0,0 +1,183 @@ +#include "hook/zero/options.h" + +#include "util/options.h" + +#define ZEROHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK "game.force_unlock" +#define ZEROHOOK_OPTIONS_STR_GAME_SETTINGS "game.settings" +#define ZEROHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED "patch.gfx.windowed" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE "patch.hook_mon.file" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS "patch.hook_mon.fs" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs" +#define ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler" +#define ZEROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib" +#define ZEROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv" +#define ZEROHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device" +#define ZEROHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv" +#define ZEROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file" +#define ZEROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level" + +static const struct util_options_def zerohook_options_def[] = { + { + .name = ZEROHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK, + .description = "Force unlock the game. Modifies the current and any new PIUZERO.INI settings file permanently", + .param = 'z', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_GAME_SETTINGS, + .description = "Path to game settings (SETTINGS) folder", + .param = 's', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "./save", + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED, + .description = "Force game into window mode", + .param = 'w', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE, + .description = "Enable file call monitoring", + .param = 'f', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS, + .description = "Enable file system related call monitoring", + .param = 'g', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO, + .description = "Enable IO syscall monitoring", + .param = 'i', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN, + .description = "Enable any file/IO open call monitoring", + .param = 'j', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB, + .description = "Enable libusb call monitoring", + .param = 'u', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS, + .description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)", + .param = 'k', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER, + .description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs", + .param = 'q', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB, + .description = "Path to library implementing the piuio api for piuio emulation", + .param = 'p', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = NULL, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV, + .description = "Enable game exit on Test + Service", + .param = 'e', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.b = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE, + .description = "Select the sound device to open on snd_pcm_open", + .param = 'a', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "dmix", + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV, + .description = "Halt on sigsegv to attach a debugger to the process", + .param = 'd', + .type = UTIL_OPTIONS_TYPE_BOOL, + .default_value.str = false, + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE, + .description = "Print the log output to the specified file", + .param = 'o', + .type = UTIL_OPTIONS_TYPE_STR, + .default_value.str = "pumptools.log", + }, + { + .name = ZEROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL, + .description = "Set the log level (0-4)", + .param = 'l', + .type = UTIL_OPTIONS_TYPE_INT, + .default_value.i = LOG_LEVEL_DEBUG, + }, +}; + +static const struct util_options_defs zerohook_options_defs = { + .usage_header = + "Pumptools zerohook for Pump It Up: Zero, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n" + "Usage: LD_PRELOAD=./zerohook.so [game exec] [game data path] ", + .usage_param = 'h', + .defs = zerohook_options_def, + .ndefs = lengthof(zerohook_options_def) +}; + +bool zerohook_options_init(int argc, char** argv, struct zerohook_options* options) +{ + log_assert(argv); + log_assert(options); + + struct util_options_opts* options_opt; + + util_options_init(argc, argv); + options_opt = util_options_get(&zerohook_options_defs); + + if (!options_opt) { + return false; + } + + options->game.force_unlock = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK); + options->game.settings = util_options_get_str(options_opt, ZEROHOOK_OPTIONS_STR_GAME_SETTINGS); + options->patch.gfx.windowed = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED); + options->patch.hook_mon.file = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE); + options->patch.hook_mon.fs = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS); + options->patch.hook_mon.io = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO); + options->patch.hook_mon.open = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN); + options->patch.hook_mon.usb = util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB); + options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt, + ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS); + options->patch.main_loop.x11_input_handler_api_lib = + util_options_get_str(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER); + options->patch.piuio.api_lib = util_options_get_str(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB); + options->patch.piuio.exit_test_serv = + util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV); + options->patch.sound.device = util_options_get_str(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE); + options->patch.sigsegv.halt_on_segv = + util_options_get_bool(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV); + options->log.file = util_options_get_str(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE); + options->log.level = + (enum util_log_level) util_options_get_int(options_opt, ZEROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL); + + return true; +} \ No newline at end of file diff --git a/src/main/hook/zero/options.h b/src/main/hook/zero/options.h new file mode 100644 index 0000000..a5e4f00 --- /dev/null +++ b/src/main/hook/zero/options.h @@ -0,0 +1,55 @@ +#ifndef ZEROHOOK_OPTIONS_H +#define ZEROHOOK_OPTIONS_H + +#include +#include + +#include "util/log.h" + +struct zerohook_options { + struct game { + bool force_unlock; + const char* settings; + } game; + + struct patch { + struct gfx { + bool windowed; + } gfx; + + struct hook_mon { + bool file; + bool fs; + bool io; + bool open; + bool usb; + } hook_mon; + + struct main_loop { + bool disable_built_in_inputs; + const char* x11_input_handler_api_lib; + } main_loop; + + struct piuio { + const char* api_lib; + bool exit_test_serv; + } piuio; + + struct sound { + const char* device; + } sound; + + struct sigsegv { + bool halt_on_segv; + } sigsegv; + } patch; + + struct log { + const char* file; + enum util_log_level level; + } log; +}; + +bool zerohook_options_init(int argc, char** argv, struct zerohook_options* options); + +#endif diff --git a/src/main/hook/zero/unlock.c b/src/main/hook/zero/unlock.c new file mode 100644 index 0000000..bb088c7 --- /dev/null +++ b/src/main/hook/zero/unlock.c @@ -0,0 +1,81 @@ +#define LOG_MODULE "hook-zero-unlock" + +#include +#include + +#include "asset/zero/lib/settings.h" + +#include "capnhook/hook/filehook.h" + +#include "util/log.h" +#include "util/str.h" + +static FILE* _hook_zerounlock_settings_file = NULL; + +static enum cnh_result _hook_zerounlock_filehook(struct cnh_filehook_irp *irp); + +void hook_zero_unlock_init(void) +{ + cnh_filehook_push_handler(_hook_zerounlock_filehook); + + log_info("Initialized"); +} + +static enum cnh_result _hook_zerounlock_filehook(struct cnh_filehook_irp *irp) +{ + enum cnh_result result; + + assert(irp); + + if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != _hook_zerounlock_settings_file) { + return cnh_filehook_invoke_next(irp); + } + + switch (irp->op) { + case CNH_FILEHOOK_IRP_OP_OPEN: + { + /* Let it open the real file */ + result = cnh_filehook_invoke_next(irp); + + if (util_str_ends_with(irp->open_filename, ASSET_ZERO_SETTINGS_FILE_NAME)) { + if (result == CNH_RESULT_SUCCESS) { + log_debug("Intercepting settings file open"); + _hook_zerounlock_settings_file = irp->file; + } + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_READ: + { + /* Let it read the real file */ + result = cnh_filehook_invoke_next(irp); + + if (result == CNH_RESULT_SUCCESS) { + struct asset_zero_settings* settings = (struct asset_zero_settings*) irp->read.bytes; + + asset_zero_settings_unlock_all(settings); + + log_debug("Applied unlock patch to loaded settings (buffer size %d)", irp->read.pos); + } + + break; + } + + case CNH_FILEHOOK_IRP_OP_CLOSE: + { + _hook_zerounlock_settings_file = NULL; + + result = cnh_filehook_invoke_next(irp); + + break; + } + + default: + result = cnh_filehook_invoke_next(irp); + break; + } + + return result; +} \ No newline at end of file diff --git a/src/main/hook/zero/unlock.h b/src/main/hook/zero/unlock.h new file mode 100644 index 0000000..a41c593 --- /dev/null +++ b/src/main/hook/zero/unlock.h @@ -0,0 +1,12 @@ +/** + * Patch module to force unlock all songs and missions of the game. + */ +#ifndef HOOK_ZERO_UNLOCK_H +#define HOOK_ZERO_UNLOCK_H + +/** + * Initialize the patch module force unlocking all locked game content. + */ +void hook_zero_unlock_init(void); + +#endif diff --git a/src/main/hook/zero/zerohook.dog.key b/src/main/hook/zero/zerohook.dog.key new file mode 100755 index 0000000000000000000000000000000000000000..42eb75f934c137e717afd0aa3fb0b2e7a79e2d16 GIT binary patch literal 92792 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
    ud76qjGxs;;Rf|8HB>HpF@hO3D8Fl zzxDvcb%Q|bTJex5jw$|cx+n)`*z*prC@)dKDs#i&T300w4E;cA6smqI2HEQbbbVGE zQ2%8eYky4Od0(84$wvw zuD*Py72YY%E86A-i370vLcaF1e1NrZ`0P8g8izX+7HM8J%yAyb#shRim##tM)vf`v zZ!ELCpYCVNrr&w#3p^%&MTI>JIFGCjy$J*U^}kuAZ#2t zvtlT%s}EC8OOag!3go}f9MQ`MZLGBwHEj4?u+)t)&bdiLWQaWFf6Bh*!{@hI+eyog zg}ldZ)ZxvTFBh<0ZUiQkSlFs~S=f683}I!>q+esk?$Q^^Hs#dZ?;Ij#ru-l-J9d)S zA$h75%$tw(i6@v-_w(7W-tFjGBw*=aP!Y{+&a^*Od&Otf>9@I`&wlmF{2H5pHDk77 zt7dxE?U6Mpiu>td*!wYW{FHsO%_7@6S$By2AT6f)EBp3J4_fy{#R+uHzyXyd#r@*g zU9S|?2d$OU;3$5W&$J2+HVQS4ZJ~#~$IaBv2HH!eu(FwZMr1y361U4TW1#@{y*e4& z!2+&VGe?fHCR(42JsM;A4QeWu-EBZrz7Rkn2UzkoqokO#U260v*3pUjZfPL$-EB9? z5-0^MW~mfRdw<8t-zypSvYw@;@75wJGe?z$1J-+@TX&A|GzNd=ou3)%q=EgcMep}$ z2dvx;Cd+#P<=ayR%_=)X2}E)1wlg-ImISOLV_I6hd@OIKC{r0k?&3S|)*>pCGZI1l zDyCH{X~GlH>Fx{O`bmsS$%uS++ZpJ@twCIG2%ablr8?UG=6WZ3X+?>0w-!-3fT2|l zu(*ErD`cA!pR2bQ!jaFig`MMTS*?cl`dsQwY*TtbZ=l9Lp00uW!46RzyX^sdqRt>L zc~{ECpBN@3xm^cWV)q-;5JN`=iII9?PGz`Qb%;vy@^}0;_>r;@^}x(AtT2a%n+T47agv*!TyEna)7CtnnmqXuMj$n|33_ zU2cV{LhwoQ2PtTdi7fL9T3HFWC+3nzs;-MrQr^5^_GJJI4R)@>d_!>sup-;66)(tM zd}5(OERcxh5s7R(K&R283|)IaES4E7+{=L|$5nn1%Rdqa8f3o-P95z9ajlXBhbhrs zk)-FTdlBi(ABQXh=;lQhx1NqAy63klL|-Xn5^>0gAqR$5DUpTqvg;QjkeJNp-1eibHsvWsdKBu>`mbx$Sbia&CT6kdCN!W8_ z>M#9qpp7pbP%g0~)jTQsWGN8&SP*ue>Cv+~Zoo=GFZi{Y$TC!6H2CfQ2x0qQ4M3tG z`sphrV2!cbJP|*0ZBu4bDqH?*n>7;de@U?K7YhLv>#)^NtQWFJc&^f=vn@ZJ{Y!{M zA-6r$0dup)5FkJ$cqbg7bK>bah4RU!3j2H&K0x?YNk?j-Q`C{Nk;v zu=FvEur&dK*>)@2!RDJWiodzLR4IH2STDs_hW2?bo71V3Z+rgxc}j|60NTiPSyQWw z7o9P4(P=e`zgXa3^}#g{PV3liv$h{#=^NNms9Mu)YJ;@;n=^7JOm2}^g{NY?xK`rH z@GVWh;laTu6st|LKW)U{(yi#Yjr3e8KE6EjYw4K?1?(|XhR)*=&_+>rRn+DvmEa6V zm5NreV%Y1*Y*I~s+PEE8H`>BRnIluQrU~)1*QNvPF_Ze??@J)AM(W|7jq4%|D=Xzz z6Vuo}2rkb*=D^6BcYr0&=kI^w35GWPI^}nk4HVe(?bK=2b-)@{X=QsT#7?{v`$Ok; zU~la|Cq_`wE_D;ydzVCW_qN8|nOARw@AOg!6MshF`j6R#pAX72U5=OW!x6>mS>W&&-Tzhh2Rr7pY zCo{YL*6klLf{Lc&O@DI8+xOSu2s;BOQ5xYR?!5xD+i9wB)q0pcopa>_U^ zkSM2z6w9zBs zgu=wMwsiX2^t%XL|1q-}`dkLAat6}tT>n|L3X&UNpg#KJr{9Vg zft&figH6T09cOkx;QEjG9Bvdlh^yPFr-38q&HA0wFFbzs3yuFHMo^(F({UfL4BKxV zE1?~{5%*MRuHNc5D+1Sl%vAhx(7HlMz0i~4cX%Q$k&mvt)m(V{j~GG4cP(aUp7w#} zgr9`4_u)6spNwq!_F^G${m1N9d5Z+J@k5fM0@km__|E3z&HBH;!hSwlnHfTD)LC9S zQFdA0QAyLT@@ZoI;6EouP$BCtFbd)l<~&zcLK(&46WE3RT87~@0@r`cO6A|7`S#gi zN@dH@BPhm?Wbr;UGCVks~4T0-F=99Bq`M0g{ z#CBgu&B5F2lUd<06V3f*^1}S~&>Gfdh9N7d(xcXnem_9S0U@OPo)8 z9~u|R7z7dCJcB;*f-Z78A}a7STvoGy71U4A#Xg*>W%W%&GpC}wgwxUqmsJTvp`oiZ6gg7mn6jFo%Ldr9|7s6;475mxUVjS{kqvhQp8a zQF~uK#K4g1(;31Amo-Ok5A}uNrYPUEbIi|*#Hq$bRmU#FWrbl;V1T%sn#==Np6l4M z=^yKoF1_gjmsLz`K?PVtOnTh%1F8=#Rz7s|+?Y0l%aX78=mc2ZJQf3W+*gF9+pgj! zw;FiCWj*61hkiqkTI~<(Twu2-i~jC!Yp09kj;Nh8UVmIe3gRLr@Uu(~Nqg`<_rEc9xkg^?rds9x5Xd?_ptFT)W9nS2ApGWxJ{3P0mtLH&Iw*ZC`-GIBMrSeo4YH=KBPqDSs1 zEYm*`#3g0sEYk9-fb8sjqHI9iC3nTbylW24{3tvjtaS> zuJsi)5Z4zzX>T?{D(Od=DD|V<-mvd4B2VT9z#>@dDrDlV!yP$0b~-@4^?5Mic zQI7)FRfesde3^Ho+}7jdl*w~o$8|1-2)gzegaXGo`^lNE5F1%{GZ4bwONM<+5$Y$< zQ*$U6PWH>hCU;G_(qr20M33CjeB?58?MvovpPd=Ifp@BPK}OAi6%RSWj!KNeP8?h> z>8B^KzF(>=JM_j@&Q$5jr5zP=M-QtX{{pPZlHOin2Q89Id7d^OzOKRkJqCXhG65{| zDE(@2PS*|om)E6T9m%DTi)Kf4zLjnRuq4|(bMuCp=4o{BMoqNxV9(R8)R1)p)&q>X zyXraJmoRTr4B(d+Z0wv7xueVZoltJO>&>L+v0Jx1^*IdUqD@^B zSW7B9wbnk}I8kc$&t61C(Y@j4Sp}@jXI?+B^0-578VG(=^<7m%iHwR36Cn^6}51Q)GX1#WnB>zhw{;V{SB&X z?Z;`Ry|S*=()z&8PdI9@c!Ic=Rxe7%F>8!}be6Scd(lr1H?FH!le_>cg&Ng_-ac0X zJNe^pV=g(^d$#B}gL?ogm*|kT8sm7iE3TqMk+C)G-=p2i%%6R=lv@o7GYhWc??^fu z;_{}_wex9p{?Hi4vZ%4yh%9?HGLziW^h9VchS_*5RS~*Z>7gGMXcnwKu-AS^@RXWC z8{?8siU#4Btv$c*GvZ|bH5Bf(&onW>1*}s`wR2L5erEn{nzZaFwXoN%7ASdA0PB^S z%eObA-zUy@8z#R)d*cl^F6}VCmw=V>-Fm4n&+fLXG>y2%X?NIbP0J(3(7KgtjLoFf z@4M%oet26dv4OS%H!haJoxRq&EW$2VA_PduqBa@~GY3iFvZPPbXoEJsEKW};K1s5C zyU|xcj!dTlE~}dO@O8k#?aDQ@$8KRTVE*hb7ip6Kmqj4$hzeNQx#lE`&r{r9y->(& zwQ+d@mlb=D_%~o}2A$y1Isg5IzOxkFi*K#4$0k2cxZ`cJwi7`CfyA2e#&DzA(Z>^W zLHi3e5;~4G8#vQj9^tp*tDjidQ6YB}npgVg+HVhPCZ78c6p4A~iY8Q;ur)McxMyUp zl6|`Ki)PFvnV!H_pDH1)rvH5NyLc?>K!PjlF}GZ0lWdE~d9nW+5sey>{MrAtooDhJ zZY@_9crD<>NHKS;)*JS{+9)ajwK3t#vw?u4*)hG{uRdwfi@is#Wjm@1P7KgKK0Df} zV<+N6+Vl0&9BHs6MRruk9i?{p#DIIEqJIq4-28#F<4{VC?iCH#&yEvXW6*uyGTl>@ zx$tAjl_o9}->yd!xoCD&lm7Uhpt$bYaa}|kvFC2qvsn6m?B0$Fxug1e9B7TA)m?AI zXIWiU@J+RLIw5g9a)ce#J>i_j?YOolczo=Elgr{ohH2@yECkpjw8dX4VvBG)sho%@ z^IgDsZ%v7>O=MB&toKfU&MiiPX-eyn$)Sg&TulA{;lA}2xPdm7cT?Sw3+r>oBn|Bx zcPe`>II`jZNMtpF6~9dvC}hI?-ml zYU%}Y(d?+W35di%8%fp$lyAlxmBuIHumqo%huucY;^(!1HSmVfHWoW!-HWYM>g%CZi}-A@=7fBkZsw;=#0!BR-r zd=Ylu_pI4h*X_8rUn*Q>=`K~NrR!2Tx2fNakL{*Kya=>0)oD=+-ApY{0YNCEr#Xl~&Q z&4-HCgd`jK@|V6yP=4TRay+|pM&yo8p}Gfx>$ORJgQ?tNgg4X4_%+cc9qcs<%-guC zfOYJbl>eB+N$vV>mSb8EBo84M&5r8ueRt@$P0!Mn7WFMN*?3@v~qYI)nC7_K8;}61~nIwM}#27KVeo5vsa)ccf)qNZ& zU&!X-J$2HDKdw=POpa2L+jB>S+|dIGb0{DETXa)}oPsYddX|QV=Xh5+a)cdKY?_e= zXrq(tMy-ZXb_X^;W(IM{(9n(wxug6a8OH(Zg+p52~q!TRu(GvonQvDatpmYYQqx6Uv+-+$K&`~FH9^Z9ds zZ7;-i2sLU=Cm!m(!E_Z?JV0DYq7Uus$T|F}4o~t1qh!T1<(PY7)IfvmcWOxYA<)LN z6f3e>m5JFIX@Tc0^3!4GkQw}*K>y#@URR4fuU31F%-5li_)6F!vhe_&$~Y~QH&N-n zFEz>Bu6^bD#C&8bHVx1q`z>va4vkGPw7ly=LPIxM#0AiFaRy-Td$hOgtKYs}r?yT` zFZKO6;YXF%UuER4&t83B-;;Z(QU1tz-ixcbn;Ocua6Pzw9~h#MpD`P__RC{#qd5=b zDFckm(FyIdV6RaWVXQ%G6y2PmBAln@`w}f5aF8{cJvuOmJ&cvscNIZgdPg)gxU~cY zb)WI^%wj*V-$Q<2mHSVWt*iCF_3h$ketx2CuNeA6WT;{vT_`!waS!8UOa{a%4XAeO zrmXDYVYtnDD0oV95BY&rjFz{&L0ncv1!BA-$7h9EMdi#&d|;26LVaT>0qd(zmk@<& zNKvig@BBOGvwj>H#2&`)C@#=C%r83MGu9MuQrTQlyd&>e+U+4fuuA76DF=vaB%~+N zJp1Ms_g1E}qq&{B2RiOyG#4L*`W!zk+=iOZCkCnSYM+0NX)eEq{J^TTkr$mHuEJ*) zHCLpDqDut0g?~trXCCOdhcRzc3(Ct$i%ZFKkvu$I?nS2;s~HY^Zbfpq7TTvU^#OlP z^P2_Xi>$nL3iK)1IT-%IXz2eIG?5jc#kf&#h~TLIlEGzx9hbg^4YaotyX)e*%2zVn z%O|nd%vPddkL5ag4iRo&d$O%-d81akx6ay>0msnmET?<@s`eee#oBj+8 z7qh_MQJvz!-RN^X4n|Rd-6rv&b$dD-P$?^P99l;Xe&mKVn7#4xWWCA#3{Ub;2e|EN z!n#6y6~v{-nTdA}zwI5lg%*8JiG=o^4hK~744^~vj>CK{Tv0X2-n&adcpS?d^@HqDfU5@V{U%j?8jnF6gEZq5BSK9_&z~tgOLsxqf6tR2 zQ2DW61=^#VxQ^b7%BNPIeIdH~MIaIE{wv0w3tFRy_9qp1v#^%Ow{c60Q>o?U0U_*Z z+Gv~-1#MI=vp60bLI3C!L8lrPRUzzsL)Y7@puQ0I#N{K#ty83Ki}s;Uc?7!mJoy2Y zd~c$NKwPH?JdS(d=-#w7nk999?hAXKmV)Vs4OpjDHFSkk>bVveH_+Yl3w|CD!k(rD zKU?S>sf%c+@=OAEFJ#}8Vm#JM)4Hd_0hI$Z>Cj$`m#C?l^g_%=fgy3_ZE2++oUw*sugB)|1-lnc?G$_?i1>2N^haTdLKz~T@_)5OkMZ(T^0)yrTwT77`q zo~G0p(?5OTcCN#!*pcGlCzF%X>`yCEZ(HBl)8T+hW_)2Q5LX3-@NB@Oo6X6QFDCPk zKcgPtwx_A!9O0jLDYxeeNTaDzY_7noefbOyX|TUv|4~w)`Xrf;YKm-P|B92(kxxD zTZ^d7;>`i=y~Ax$CvVedxO~z$wAxVo2LU4A-FD3Q9!n6{5o|%_Xi^N@lc(jiF1gFX z{{LS&B6Zn-W%2m=CtMW!l5W~zhvQT~`FEceQTgzCmSlHN-|e{8d!Op?tR%QTZ`xUj<;jwHkQXAlh6^?AdA7@qH9_ zuGVBWloPOy3%An6Ssj*Kx+>}LJmE6zb%iH)D4{;Oa4w_B)_!Odd(7A9>zepOL~Yt_ zzh6mv7{sMa$R*9wPNgPdH#vFQX`zM_6X-n&0E%tpZkB;&X_VbZ1 zKD8Re^_|~BfzCs6z{eRK>mrp~9-=sQ+YR~1p!;5WLh*WW8yl^d#(AMv)Yo9oMF&z8 z%s^Z@8&CCZ;|ch(PYD;vaoJ(+J};uO-OCPWEcfVBh%L_B-sHBHc6+JkIo}ca?zT5J z<3ZQ{28OsDTR`M|B@^*XyK>ft-C9KDs#7@lpp7E9N9G4ZGJ;)1*P1fy^*j*y?zZ2) zyH*ESc3=4(``JD|PmNDl%q(jjvRjL&Ou|_Ntx21F>?wZg8upIx{kYBLM+UI-0Ka;( zOhH@$kqO~E*{YF)IK|pa9v5Nf$;EmezXB|_s}G7l;~R1`j!ZMRO8WL7YSV6eZgMOd zV37zbDwn2-UF1LdGN|7I6Lya8!eZ;6HHz&qK#us?@@G}cU6OjvB-F~!w;#W-J{hu^ zD-@Ec%|*uh08${WAI_aIMVkEA0FJ>W>62 zz*6+c#T{}`srpfRSw1JUJpyiAp?=d)8+~i1eJ|V%6*?0$?OWJek^z?$I6)Z=;wnlZ zzclJz-qyOh*nH0~u` z*8^8>4P1+{tcUiXjgyk>xq=E*1e5YlX0_MuZ~zUm-1n&9Q6gX zF_}ARppN#m8+K=p=Fb{}a>SARt#AtdkO5dcV{{s^Y)77qI38=_;~D@<&3`)_Q1Wp) z@eQy-r0PF(sF}t)TjJg7V_5olfZLv?r6YnZfW=(&D}?G&jL)~>+(*S-hiUh8IH2;V zBf)3DN=N^0;?GHe_e}1yjxSaQ?0dC=atzx4#VvPx@a|V5(Y)ubF3+eOo*fXvo+gb9 z+F20S;nZPrp?L$}*)un!^(qo!-xC;a&;IPi*q;2reyMX;be9J$nL%7esdNN)5=cjB zS8r?2e(7c3B}G`AsU)BSta}^Re2%=8`sMw#F>ru{ANIVXDixIiu&{VvT|9A5t3E+{ za@I7g6n2g;o1zgK160`chFd>MYoZ-UFKn%ofqmcKi_rH0aRrVpj^kf?is=}e;$}KJ z4*NMo?|Cu|u!t+xf5jC=bqPhyN_SD$!tU>XEz(2xSC3MT2=gsWhs9=xkwzOjUW9+R zT>{aX*6$#$jrLb=dRF%uo)2%Nv#bmZ?vf%bwx!oXIfb>fC-+7_#6Ee%L+EE^c@y^7 zH&*>AwAWf$si`5ywfD3r%5U0R_+sY}2C_@waF}Ndw2_IW#wOPA;SFUscisBOqXE05 z2#d6|Hc3$fjk}L;6Cw;` zm*9SLsRd}G%>0Aumpqk)-svV^{Flq3cS#Wz*LeirZL_wM;&-kan^tS26iBVab)5ON z@XOb(p*$=cJ?43RaD9&$l~PN|f>X8#F_)$P-amVNqJBFN7f-9QTgd3zt&8K@7%#L- zUm*-+mw-n+eG0IQgGy-G?$?oAesP|twTMV>mlR=fC4BQw8@I8*Qj&=>+vgV_SMtb4dFMG zd~{|8tr0r!65wtgy$M)lKN9;Vuj^=Hx}tu+JIj2Gi(PdBGHYJ?RZe?PAKE-Aty-W7H>z)B!Vx@*WH zj(S#p?AGF^U~+`cy9Dar(lr6=Z65x#uYwfkhE(O3?E0#=yQBz<;^)pldCWzY3unVg z1edb|N)IzVxGRa!d6%HbB@%iL;j{fNS>&c4q>{eD@sb|}_S%Vj`*(EE#@rlM{*2#U zqk>1n(Z>b8TkSe6!eaVmYYD(AG5o}xbR$6ZVweAk&CD#=@BBE1ocak^SLg|vJw$|- z_$F05ZWiS`A`E1gK>xXm;x>zatG-EtYDnFWB21qmPn5$h^+77Tc@%!F=b`0M93I_l zR~>baO?KA?-8>>3>>7#(&JMFC*$Xx1Ojia)UjLapS(6`!oS4gtA3^B6OW-xM3eC3-=Ex`?iKVW&#)o*( zos>gjR{S??ITcSF#FZUj(y5Te!zQ+g@Bdn?z~OHt;!=QY$Di^2i7n|mC2}>U7mdl3N?IkZ^ua%$hdjO*00*ZUPlgR=Q4rf8j$N2`=p}rlL|LHRc;aXIt=fZIBdX5^u9RLuXC$};H#yF zH}hc@=t3ZQ@Ra<-B4D9BY`Nk>^i`+tIQ9g^EeqIlg=yt^Xv`FxQ(;Zx%sMl8mCizb z4Zi`&a3GmE2O~9z%U;`T?#&HJmugLW1xa<8LIw6t= z#yKCMzhfUgWf(`5Pu6egJLl$HhhdL>mu=iPL0p+xAJYski9c194V5lm=V(JR97y(d z`8^I`@y3^qX1TiGf3V1SC~YoH0umv45c5v7Xq&aY7{uX#_9g51RgTfpJ|w;WmTd}C zD}lI%zuXNx5}-*lFT%g*`zY$m-%7-#&D@~dfb~f0j6Mnf7d^LmQt6NA>4u2C|5o^E z4?$~9{Hqe&9-N-@XNf9Sxhwn>|5hR{nRGEh^V*Bd3u#_LE$DOKFLQnNJEDWw`)>u0 z%GzbnM)ksHdK~Ua=9h8l7Ez=w!rq5WB!mgAmA?_n{(Y)Q1x-sw=UZ~grPF_(6>;e& zRTDHOH=V_aTU-~Lvdk?Y&K|CUJtoJQxxok8_?mErTY8< zEBuRB{l@aV$UFVKSyu94*!S0!WD{u4hZ00H{Qiu`T`hGT@8PQr0*J5B--k%Y352j;?+13Emg#}j-dC4a_poLi^RKbeb5ePMZkLIj6#_&WXF?!+SQ5iS;A zY@=77Vt=Wvs&QtRVJIKPr7>&!wMuu%V0u^f`y6xBFArN?I0;nE0~Ln($n37=B` zZUN#F?}oDzVErt<8I*Rm(DT{wuaD-JU%*SiY@LeEKc^6|mQvX6DIE7o`uu32*)wJn z_87CYGKO%QMYqMZaY9u|`zY}KP3ee?5i0(Ss&jBkzP&w$uvad^u0u zKDZ#oU}()y%&tnyt?MO5YjEGAu=&rh_XCJB>3#%%M{Zgv$0xSAVm7#&Zl1YSu=fp} zCX9FiSm)z>bo6v3I61PijZJN6V8<15@2DJL9pz&b?l?R4ax*!%N_hbr_B+=p7wXvo zYc0TyS2ot_j(pIUi)^2HVb76q!0ZVz! z9eq&zR_0s5ku}ZVA7MY!G_cMQ)_F4mRr zlfFS$h8e8uf0E<3!d~A-eb;#$uy8)EwI6v=P@wYT65b#t{Qo)Va+(`@r=OWXWyN$e zMpEC2lo@Z+f4i%N^{>wUXtHjWdQfz4WaK z_L%&vPz*G_ca{&w^}0)vYY-~mHZ^3K2kXLbiSOb>K=;IQw){%Cg<)?t%gv?3=IF5Z z)lP_eK>ht3j@6Qt29ZnS^B0p(zMH^aGsLVjRRDiSb&vCU#2QQPJ*c5-7AJaP_g{EX z(injCF=$5O+i-`9Z_B*fI~A%*xYx^XoD}M#!#{ka;mEU}ClR?bQhxGrAY9hVmOy+E zSLn}PGlZ-7TW& z<`0<${sF9D79;D6<#1V3*Q5W;-M4d(T^_gH-_9PN`#nW>gn!6j1}@9!_|E@mJpA-p zqFLVcHPfEz3#>sOVfXjqwJ6ZDqwa3Gn3xo)sGSn8ys)z??B`I>_*w|K_MyJMC~v=# z#2G&>n3WvFI0d(j9PwXl0LwBl7k^PkADw35Lg@%Q&vUpe{Dkg5>yO)W1(LHmtJ*`k z4AagYuO7ruIEUvHiO03#Mv!Sl85)TDy)R%b8rwKIu;P7{nj(OC@-6nRU8&{YVyi%0 z>G78yayhHw4P<6!tBC(tf*aRcm#=pKtK6DoB#SNhRe7^t@SwH?5nL7rx6sHoi*3u% z|7zBNPHgt)FI1-yOyhD%xgm08G15>lSX2G@>5aY$7SDYVJiN+ zfORyMr7&uIny!VRdZGwh&3j*`eGJXdnxVa&xcJr#v(1kkUYSwqZhDSW?BlX;HI7!~ z9Ej__R$xcacXi6vQ!4eB+Vf#Qw`mBM|LmXG?xXLX`q0_n#_7N%YN^7PyBV?CZ3T z;c|te4`7wuY&fsbF|Cp`M27bTI}hPn+-_uzqv0{Y(ya99O-1S8$FkUPI)7WDbhj2! zSvtw;1z_2S;~edfA1#QVuoadgz1D%qcelM@h8tSb8L(ky?!ppmb=5s9*g4n@d%kV| zNnIYqMXFqiIc59hP(-=R!^9vl*kj+{M8WicH6UKX=396Q^?XKMdlN>`h23pHRDL7I z5C~Y^r1a}7dUj^TS0V**l)PvV`R=xpwWu!vmbqH*jpdCXU%fc8-va$Q^1HQ&%1LXs z+JMF1Lr=&T@vX05&2Lz!tM4Tu-`(~lyY+FvGWld^C)F68<>&v6#JaLoc()c&d5X;+ z+Mm9*fW6LVQB(}& zzjUX9M0`aBDZ=A$wN{wYkL^A$qOyrV|DX9I$(FFmsYPDjcu7`?&ik2?<(CGLQI)XS z--rl1_9m~^KYI(fx2hCo^1EfwT<&l(PT+NGU^wyd1-&EWR#$bjx&DTt*g8YV-%--J zTypgR=|DrJh{fUSM;GyW{+owx6Jw}wc)|5zTO;AlJeP;*z@zi(>1Sow&st7TDd;zJ zw2)viFFUj5;m|n84PH6eIniJm%1sa#Ioh!%Rnib{hX$)3s+6BicCG|+N8Wvw3xHM5 zJ#{@^fMx;B)-#)0E=LPF!j6iP1MNLv)iJHA6sV=Xj_;|Scg^ov-%%lVWJ<;HCr`fp zOsfb|3Xj?}bc^l@62a>4d50WfMCWxew^V2{Z?7)7Bq9b#Hcm0CP!_vYt^72T8~{?D%ixd;zG zih%ZGR`h5L4(iL8i*4LKaj0V^3^~G%O1aWU7PQg%u1`3=sBy&Y^avrY9}ckhVu%I{ z{pr89H^{qxjv@3EOJ3mhBoeNw`(2%KEbu5ww4of1n5g-bXs24_@%g6;xyvj+aEyIB z^Ck$3`{`WR>|LO1LAc-xjmcl1_{Ja;(~wr~tzY~4m$Lp&^vE5(@_qVeuCRT7arl|3 zJ6?J1%RDSObVJTS8#%&`N-JOl%A1VOuwQnVUCTU~d?mB7(Fyi*o5}=-4qSVk$ulT* zsPZ>baIFm4ZZTKyoDsPrRc1YC?ruIc!HXhUGVvnrf?n(+_i5w^JF1HlYJcX)+tvfmz^33ScRI`d9b@beme3sE#}C#DP!aaJF0kwZfNZ!tU6xuirU5W&*B8W zT>S!pJ1XRk$}zEvx8uUzl3yVayZ`){bemfba=yD&HL|RfppE_0vL{kZFP*XsHR;a5 zdEv8Li>R!Ft~3T%cb^9)A2E?J#4ac|=2+jTK;*mI{w33E9k3Y36N{%(+>2-f`JH8& z{9)g#9l9@uw^`c{u-fMvnec$%sYZ>VE~U6cais&EOzH$KU6K{;55 z$bEiLcy}8RmEVXbdH@#g$KboOisB0FZj0U54N4^t`R=xJh24bm(RgL@$2a0eN!VYU zHb6aYy|7!0sEm3YuMEWH@>%+li9&xsVUN~IEopQ#BH!J10sniNfQ2e^G&sJ`R)8{n0~S8&Zp1G3=Jcfcl+&C ze&EJ=9mKUJSf^pB#J|~AoxJ!;>^SUo_ZfK{XukdG*mA3XY9Spa5$j;}z0a_FF=avA z1P~WRJ)d^49W`NLiF*u_8`<@}+Hp`_l4(7ZQy67YcjV@}|NS%Z2^SKzGq5+h4f@$Y z?^~&S@0bY2_Cia|$1tR`^oGsCCE&LPZIrgF_l==_Oe~%an}bd zvOcAz<13p4jgJ%3I{2>I@1;MeuI9}e^h^s0T3kR?i^uhFmi%?bBNujV=)|?DyzRKC zwoW)Vgi^_@Bs+*>AUK&G*?0+~Z0VF7ZtNtSSSaUy^o*?)`e&kf--%7+K5q8u+V>$jUX*1DPfiMCWo<%v-E9RG!`D@C2Qgf4zC$mzVqb`pT zyUH@#FQRB`M0s$}TKph@m})b8E_g)laM-f&Q8N8sCQ*r=OKSF%d`d zw*q5!0NN8cewCsv^kx@-ZSeTv=IFAnzmh7E9QTzm+aKY-nO-mwt(#9ro4AU$!t#X2Mck-JQU&oz$KHamnadIx{>9;Kgkm8Ff{E zDD`&>5SNlWm;S^>xh2inJoQjZjc6ubq(G2fGlZ+_!=%Z;oQ%>sSG58%52e8i4AR?i zZO1!JuoPjhEPrlQ_d{pet4r*sUs4K_)W{*y4E5p-C5)tloby_j z?U082Cu~vC!vieLuKR0KaU6L}O@!np8U}LUvP@gpptXQwx$GPn^VZK>H0Nlh3Z=GR zk%9F&VwMi=^*P2sLVE2t$MGb=E>WD@sj%BP{p$(z97;1W;njMu-o*aKh{kjFZYQju zw#36n2B7}yFxe#IO==FcOdGMISfZ}5*E_1yP7Z-<-ywgOBO~vnZ2lWp88s?r47hQr zYdn<$Ea8U{iqV%h7;YAgw>fXFZ+DNdKDd->u7G9Q?2=^db-dMqxGTLak`VUV@4F0J zC%}^CPmr`zNj7;`#LTcpiBS(Ls4cPX+$l!D(!cY8^fKj`=(=Ub`@SIcCb+CrLwe|4 z-Fy-}=i_fT#DxwY^}95~y8Uy9^=b8Ug65*fezd!Elkp$A%)MS}pBe^xY!aYv;R4!7 zOd9assqsDkm#m>v@)l_6u!7nWvwyo_1X$KCm9Edl%BN$QC;6fRM_{k%Ji*6?`iTnJ zV2gks*$kezX%*_tld#_l&`0q)1>*9&RB`y}kP}IZPOp8Si=Q*xHeR{$loqh)b6+;N zJ^Zk7H2b%%4mURJ@ja37f=e(3)=a3(Yc0+51n+soaa_={sQMW=T zMSaZr9&Q`6Pf$YZqRl5C6zOG*-$o6+N}_T6yf|D|x_3t$xc27JlFz*jYqFW#yPk0z z$=hB&hxO4g;)LeNk{K&GQ(o?!w|EM@IMZ=Z^wnT<>fo)*vnk=|0+B0 zK(4<3k0X@qy(2q&W`*oscJ@pWGLxNwi@)RB5+0a|qBSLpp2qh(N8ZCBJz0lN6&WNu#f(VJf0t<1R3Q^W_AWvd!! z0I+)O?-T9@M$=pq^2p^(>UaW`)l$y=dtV3aeH2H!UOQVJZ-bT7ND}yyjxBKF>>*|b4$;am~_;pSQzgubb!io3i-4MuvRp%@3ewB|&AeTJ-7xF%F=e_7u{YEj8{Rsmobj`2Uqa_=&!GMVn%7Mg%YR#YJISeqY`}d&u|goqlBSvx?Bo%x#xtkl@H- z^Wl{>-+8FI(x?`|@qH1KeF4Kb`>7X&Zi1&|f+4S!2V^R-1O4T@DfuS73}smit*uxh zY;Y2)E+YbjIe;~ys_-Gm->-5ZLumro|Jy!;2${TU(m zJu|970l;cJ9rNqdZ~&HS5#BS}qO~xny2@`-V*#vFqKxQ#ER;eO)pvAB{X8K5?uy)( z*Wfc!J`sr+H}|;vpAM@$meJ3FeBa(qF8KoJD#RYjT(L|L9erhbFDz9@3Tli!ZI^%N zkYU$VY~~WwZT7JB{(jc@5;4iAP+8-j6Tp2|M%$sos(0+2m!9DYf14|^gUXt&51xd@ z$guCI&aD`MjE}AH>Qjs2#H+w8?Ap7zgLKS9@|&L1O;mA$%rm2Kua*M zg5wGIm0pGS{aH^+kZ`-PbPx?7V1Anx^cDPG=YzeEfn(8`{DA!60;z1FwqA+NFW+?VDASP0aO=;Q<4Pd%QlE{68_LmvB<`J06REVcy9 z70v|4@G%A2dOBe(HK;KT-o6FS-PgmlFKvC}AI^A~`iV8`sUuX@$Awl2K$n|o^hTeA zZq`aJo!_jL66Afg{jmzN01G+BYdknac-xc47;h2T{^4+{!kXedYk`I31Q7tBxdjScwZ)}Rz0QOgjqQ3W~-7vKw z4x+@6A~MM99aF7^^nk7lQc*P*6*$pwOI63o>3txNeS4kc!T{D|KLKO(_tA}?vo&^S zvy70S#>nm+{5uE3vG3@#y^J4GwutCEl9Zn7-mWPi6@k?5X@f%C|8Tm6BDE*E<*peZhI{dvb*sQ?oZ5I=1JS z=iKlik5^4TIfLIve8)|5-Al-tj}t#*RX$xS{dcb%T{=t>2wo=|o`{)rUfD#8Suzns z?UjUlPh-M-298&YB-!ati+FUDR(F0_U+01{Ecq?gp#O~rtnXpp$0fgDA2t(h4yNKo z9-7szj*ZDL^Exfwueiyvl5PdI=e}Jcb5nbB&(e19vDr7*!>JIww6h<8_mPNCly-J4 zmn`n~H}79*YLM3-=TPUsd97y)%Sz0uW1B8R>^;mv1Er&T`QJ6>Y6;tbt_aCUGRo`N z!sPcV<7MttLjK&l^KOHC0x2|JkVqq&GLt6-QK+Mf$p5?bqf2|{6v6!fqmhqv*Uv{M z_4T)C|L8|Pe6c$k^Sg$^>M=N;kd7|bPw%)kDAON$OA<2!_SQmroh`tK1Nsa1Q_B0v z3u&?j?!}rdZ*Lmi?McMPzMY=5oJpN*0!?lZwzG&pUh~`tt$SF9BVL$sQ#4Q%LLV4*G16 z^MzjGdG&ieqSx>3-YqtiJg7GVA0kQym!Pq6P~d*RDMm~Al;SLx5DB*TXUPw3bkdKSPz(un!W<8*XO^ZSXJN(Dt)$`)yuU$bE5M>gUbcq z0oDxxj;*S|)XE3fM&x7=jUdnY+OLXd0<3K8n0De}dfO{Ayn6+ctiA`EJ?Z?NKM9yG z{7j2wWxiG^7noY(kQYfkagy)B`iw0B3_utC`Ay*fl9jJrwhd~|EKi#c+MaYi(fDu= zUZW zoot(lii-YpiR=X>-DBLLcP9!tV8HfV2YhA`A%=T9{ewV%@Jf6IU1eX+0n-ytjp7#c zff!@di&}UU!f2f;cjrkd(B)2aK41`u^&Y(5( zy1;yM0*4Tl{@k-0=&22m_aF_8Yoh@yx6OgXIao0 z`5p03vDprBTh$?p6N5TnfZR2-46y9@mvjs>BpVna*8QCkT2Ky{o_M-`nb{Ly3418Z zyYOM(%ei^utH6yM$e&e|hyXCZ>Q!x-(b?23@m{Lr$+mUM#}kDdFetl#{T9$QiPUgi zJw?|&&YjW~ca>-Efa!^+m{l>O088QiY?C({-X+r#8+#W06t5GV4;ak&6u$ykm|j-> zyg3RwK5h&5q(5AIbHMb()7EfqaIKs#eNNBX#vM~^AXmG&Ib$%7M+y=UH+Kw zjkGXYw`^1s-m?4rxO%|!#8cnbuD|a?u*r|4W36wAW}is)KtX?(Y!Q|G+4bJH{S{WV zG#`alhNdb9wde@b!cLR*9zm6(dJR6?eA6uMrJE_A)K}`oM}uE+s*Z3uvN+~Z0wNG& zXu+7XF>1VsIo-O5Q7{tZ{KU{=_E=SDT$)7CWfvJa!sW|LpbdK3CEF6M^uE%S+N4T zvK2mDBc8XrHg=DmK*JanHVuUIazpT>23T8L76`jHwh?hyR$XdDIw0?97WMK0*F`;4 z-0xNkqn-aXH>#5BmOKSX)V^_gmm0Vxy^ATfn#_jFDmazUOq3a83YBG(=>T3=`Ekl_ z*PS(c^KeM?(d}=_4NzIgZ%x4bmyWJ0T^-g2ai6e`hXO|<+P?w`IRf{z~AAhpMaYb6g7WJ~~jgD1MVm8AV(c_QdBlhn$zYhxi;EV-ouHwp~Vv zAVm5S$y%grJpfhLlcXVgKo@U-a1b`B_G+sliY0%yDC9YxlDtlvLR0+qFDnVAFV%EIBt(!_8=tTAFHpmWFh z29-ri#Iyylib{RFTv!M0eBEG)jMbKJfXd<|Is@i&I?ZXB!tRo72x<~MBtU#r43$+D zs$~l3Dh+#h8*Q>F;^R5J3+L39A&=#f$8gsJhBc`oVjxBddC{xkPBq7Up~284tP)sI2CEMqeOCzQK!Y zbl%JEYtM!Aqp%Jbh)@vV}-*IyKJ7NV* z89`+kzqtVJE%;U+mu+-o?Uio@sl}`3r{tlszF|!e0WnHapAJ%yo4Qy(Fl}Atun2k1 z7m-W~UMB=dYlL>5wFwT@)PJF0cy&aqyyWu zlaR-&mIWl>eiO;$Q-%vezp@j}`f!F^^dZlY&-wFA!(yb}k5L>swn@nnFVM$MMxE0O z?}~B95l2bfv8nh|T(${b4HZM}0xjPqE>e^fr> zQj!2ZUw$lhQ{PcK4Ok!fu;J0`KpwBE7|(&Z+MHVRA3V38-N7CWv2mN}hkX6I)gzD& z=)%{u3RGYi`218}Ywhc|QONsE;@c3w^+$d0n)}|q+0@UsRe3{gIm!RgCC3&y_+E|% zbTwWVy0vom^85Qm91pmID1(l5{6}SGeZ($|MF*=(<&Nv^UFgz5<+oz#@I6hkC4py%S48}hgA2YpAl99cXdEpQFc)wrBdqL|$<68MdC54+cd;z*|>DzNo5 zJ_0NkLpPh^#yje@$*4M2^?34-K_;zsG^J_v7(R)hB_gNVJQcBzxAVwXG1%15B4zawYADt7DzaN#-I6~F_ z?`n+bJO^0UR0c>dSGs0I>jF0a%3?V?dll7;x4$sQlnpft5H^z+Y^^@@<^v6 zD!yyK2KRq`nwx*x!gX1cpK9p7n{(~WBV3Lw9>uw92kUFY%^rZ`zXZAz!0SujPWdAu=^Co(2q&1UfaHM!!vU$YUlRf_LEOz9qcJ zj7+-OgYNoL#uj(a^&{V~BP!}$Hn4&II`yMOx;}&1d`Feb{FmRw)+1bwEPk0o3$96b zoYyFOMCwObIooCDo}CFfKaue~=Qf}#Z^7-#hHH*(Pxw?UNmT&kJxI9p>Qew~h zK4;p1;+hj0EQJW{|B6-HwP;C!2@_y>M* z9of_q%Gc@Cfiw4ya5=J=RLo}&=&wyto5!Pb&qA$aYW9Q^UO?WLR^6El?g!YG!JcP- zSQb%LhfnBHRth<%z*))iJI}py^!!?*`3sUHRC$p< zq8?r|<|A%#VjHYI!&7H*NoaS8LCyK^fTd@O)qxme3xk|)^=rB6ON1wNB{e|ar%>*5 z1)L)f3x0CO5>mkKeK3vIqR}1wcbo7W?^-i-!gO8SHK`lkj&Sy0FkQ&|=G`?lHSl@;+lqmh2Ap^Ff9jRLhjghdK*4L&#WJw{ z-yTPox>p2%IrpBZ^-LBGy~5%P-`A0rlVDRyNU!#p#w1vbeEVMg;@8@ASlws+Lja|L#l`79k{2`^NFNl4}80-^ZTuZMv@|7xPvKHYU$P9v3bH*^1XU+=l5+qX3+oBT+3CRvo3 zq$4X#?cHp#CxVZ_!m_^AHIn?s3Z6!sN`^l~iuK?1~x zc<=ULI$p5k4P@C^62Y@JkU;y!)0OyOUasiUX{oWmx6})rl$R^$h&-UORI0ms0A09( z8;vruD7+>UFNUqQQ7oadq(9#;0$AwIACx|ckS?x?OaBs-qWcb&b^X(eSb)`=d@DW4 z{;3>8ULKcwb-Wf-)^PCUD*$V9*F?Fbt{)}P3y*e<6#8%Rd~2HO23S?$X8ILPzNkZd zy}BCdoMBLPHJCRU!B`CYj#?I7h|i7pj8|)$+NUa-WG_tl8Dg%RBo2Sw?v-rt#+4+tXeX#AapAGuafWK;RpKUMz zG1{^5w|1sJjVv;i!NOX94tZYNSN19rV2uZO;OS!tTyPnz5oqd3hCF66w$#G~Se=+V z)vv!GU?8A9Cv3Sf2KoEAmmB*XU~zN^6R=q~-Zfd-^QY!Qm;I|N;5yV~Od$hUq;%@2 ziQez9xu-3KN!j`#=lGtMC1eAv%Tt)h71)dycyNCPoW>Y)fJ@9@Mv7m|z!={SD4w;B zNlg@K7 z&59;fni*W3^q0}@K)x-&Y6=#(O3vx1MJnvI=#1-G@|PK0heIa(V16QM{gXaIL`q6I z!)o~TA6Fm21^CP8<%e!?PYn%|gDugEhS&B_TwW&LGKaix+lzcT3W!l=uD(jt`}x?; zTF45IuyD#>O~Q3J)6DpLoCBLIKI@j`d9sbv2d9Xmy30eMVbvFHhY?iWjzZ$y6k@_3-B z&W|I{9{xp>|L*}uuF*cAzv^`cX+OxdIDW^n_!gob3;8p#OHywRuv)#fr<{Aj*vTGU z`A}(i3-Wbh7x6(0z{0AVu8ww;(Jr?4zH;7_@tCJV{{6P5;|-I-SOWXiipn~iY=+|I zd+!a#E##T_o#~n>COg%*A7N)u*?hyB6!Oinz+ey2DI$p$a30~$(Pkluvo#tkdvbHz46Uf*7k{Nw|$WHAT3CJ=x&M?MU& z&~au=<`YTcIIrF2Y|V^+4zvgFUukRBuK>$c{8!x>L95cLmpb)wtjmy}t@%}4sRgiz z(|%2ON%#0>elG}~GyWkCuO7gTQH&!VVEwrHxc0-hysEp-r+7Mi@lpUAc>hW#+kxZ4 z`;%OxdYa^eA3tYLtTM>Y!pi{c9;aJ?>q8ygO|d(w=hveXZmk%I=6(Zg;Qf0q{yn$` zhTJM$z@XphF*(g1|7}3i3SI_a7ap370`!;oP>D#~DO8NjtR>?9Yw{?74ZMHRzrObd zSVp5`L`7PjhWWH-Y0Nky-oncO?EDOI!21v%Pe6?C_!h==;*ATL>M=8b4ZMG~`$NA0 zx<2}hPcO>%dXSzsdF`gP@f2PLU^m8%P!F&S1Pys&8$9-q zz$#c7No}~QgdY2D&$}l}A|GA`V8^{M3+@TjGU@6+JDnI4YROqLT3I^}*ueXj?a^6q zy;is>PFa+stoPdag`it^?IGvVKD?k`1Y$hfo|LvdTV#AbGLg~tlmp~@ZAAII*Dw}r z4x^eOMvER2tts^5Rr~xIwI50WbZ=MAcsfWHBEc1At6Mabdzs%q|6yuQsKdV_<1Pc@QB_p4N<^G(= zc?bFbS72Jl5Ci(2M?hdNv>>JO?SO|yMp8}$Tw?w*N?b_vfU!9C%bMACaYRdcpL0a% z%y?6{`fL!?-X%iRuDksDMg(P`(|fUplEWyY9UApPu8suHTmGW_?=Vr6857VogT=O~ z9FrI8rZ)LO&adpR%;_Pwe-_Y4)Ps9{>Pz$#EqNYCeY(QK-z;Y<`A>&q3c0&JM*zCw zg7mw;CE_z?*sdm1rZ=b@W_JUi zD>7pQDLPS(_|XJ#t10e>v6}p{j-XbZwSl-WR++VBGQ#%P@Rtdv1snl{ZEHu3hVlC zQee8s_HD8k!{73`gp<~NXSt(!`@B~LF4L&HZbxTC-!Xu{ss@=T<6hA)P+$N1ynBmA)viaBKmutHq#S=itTZq?|bzr^jxft-Wkjmrg}QQx7K zI6uCnOUF+OvrD=)xw3GJIp1Vy)-$;q1XiQ>jpb>IKj*08V!_}!it_{3I$*DA%8 z=;Biup$d7g4~aEu0?=Qh8q0z76noZ>Dl<)`FJ&yl7ug>xbny-*x)9RK#X^1uU^P!nY<||T#C?z1 z8Th%2`~oDqrXVxZy8;v(^?BQ(eQof9j5)hiZ5Hi$Q0=#^*PeDssC@( zqx;h*K$lB`Bv!yy6&=+a20`DQ$0Sg7&28C(*PID4MfUUNPPE(^Da?%uKeC~+nr*TW z09}tq-GZr_va2)M3vfz_cBG-QiakuW09N>=G!+6YF|U{P4w|%Rx{!13GD@=H0PDr` zEmnJ3MT3`Ef@pD!LdH;aAy7zh1FUZ>w5CawyNTmBYdL469zxEEhPuXq;|V;CZp{I% zpR;mVu2TyabALkB#W;Wg?&I5imB^3YW;`cU;-XG5UQh^?74XVq42V&Y%1(SqOemvu zxp2yMZEP4SD}v}|Gr)>BcTqHS@YuX=oqIj_%p&A`4g;4ixHk%|{1h?4=!$H;^&nHa z1!E~xT{nHQ!F*xHTm0+2I)2vHc%Z-QQfMee@n+@cEwV(cDu?AIwE7Fj! zUyKrc;C{I{N2Ltohh?gB;mRzfH}$Qd##sGW?)SPo?56&aR6&tHp66lAIka;)3Fwfo z(JCu{=8tvZ**0$*3DrK83Db>wW;a9CHN9sf4}2!n9<=7$-VVdM?o*Z@BD<{(m6bd8 zf*)WxP_RE|5O6eF&fLg*>9ec^mGxsH0NfAYLh`mJJo3&e88#5H)gZN08suwq?#D0SzDLc>t#kLxr3Z`VYAWMaQiLIi+BXg;>G=-y zS1?+}ge@(`kSeMS44KP@oY1NyL0TxZ1j8}eazS-`iq#j9= zI^-BNgZ06@NjtfG?YUAUL;T?A%mm6OP6t9b@f5oQ4SbG*DPVm1nmsCxWO~nVDTOlR zdxyBU_b3qK8w1{9S^OQ8AT6yo^CCSoCki=W@GLI}92c(6oZbpij%UAf3Dpx#VhNUd zg7l)Hjs>3s)9stEX1!n1Lc-WqIsfA;eo>=w3mp|S?)U3vl5 ztxnWD18w8(>{MACK0ZonsI2o|%_aaV{Mp$6?sRImVIOL1o$h9R9tp19snz zvn@AZp8ff)Q^NLK+S?W*sH}mznxTL$1tbS~cfQV24*xDJAtfXXsH}@JY)=3dt6_7W zQglfnsqtixYr#egRF*=n9~Ho&GbuxFlNslXQw<`sm3D+YS6E>EWd^V$G05mhewzA5 zAtO13{2V8Qs*9+c2^`;RKZt90)PF;r;_`_y(A*qy&Wh+=C%6}uJW%k0x2xFe>TKhb zPdRpwud6XceH=iH6YrhLE6P`GLNIcTYah)+?yrfnnBY3!Pw9)sBe{#CZ@an^DiO*d z?=1+)j4cFoC8>4bj@-}FaSdZoO_Kh&0JZNciXZ%*Bf~!T$XJ^ZF8R*a(r1Qvc@S?g zKxJt*g@9|UGfe#JiEAPs+%BCNwhCEmg34;UyG8@V7{{%7k(uv`_mu06o_p6{_CRIL zp3VjHh07az4+#`$v1z;CmfXJ(4LQbfibxwk7h4RQmBiK+1u8xRV$^}kaHzW2Y^W{) zECK9ymODnO19Ux+^$nt>5>QzmHM@WB2Y|hg7WDRxwkF6lH%e+$7zT78@Bea8*eU^Z zg>GIne;*ncD*ZA!A~*0MNaHUd z^HMH+=@#UB2W$2Mc(1kN&Qj>Ae5mE>L1i3QfuIRhm%Q%e5)dQ8d5YGr7yaL{Jv1tJ zWXgs-o+w+Z_6Jxf52%ZJ1c(QmxYLnpx%3dB>Pn9L2415_F(ShkkTMF&Z(bim`x5E} zm9@5O;0NfE{?dGvo@NX|=BD0k<)3Ef=bdYB}fK2{H~dBQB}c3 z3_EMcPrOjHwGAx}c^)np7H>Zb^gZ?tW^=U2c_EEfV?mP!4ahMjA@G8qRfb?6>KSTp zI&y@JoNcY$-oq^)UxFK3*aPSawDwu*!(%maN_uimhIf(sc+bPNNOj2c0L!a$w;Nw& zK#(HHVTk!{801{qaCeU}z#=MpSWmF7`>W5TlQ>TOe8SUb50YtLYb)&MM~y$7C)@0Xiu zs~moq+CG{-Y<+wQBb_oWz$&>DDbS=snEm3jLTvb}P?= ztb@ahALKFh9kxEcL~a(L2+)CtB6~HR}(fOUcWEklR zZT5W|ZfBF@RUEE;L%gI4uU&a` zwagK?hdM}fyyxNCrG);MfUavCDPeB%XRUf#ZC9lYz6~C>KE7n9y8ygDQs}WrcetjO z=y_)4M%IKwe(twHfV~mWRTkwF7(bUWWA){>oP02S{_!df*OJa;t^usV&z?24rRo{T zB&9^+3sbF!t&cAeSRw}Z=(eSMyveQFcvMV*E(?fp70Q3IJbATluKAGd_s9=BdD^3N@I~>S)xsG>6;Ad6SE9BxWT8_c< zruVjM+rGkv1(05rUazfTx_I`z0uk!Ozt0aRU|qY%jb@UERvc_${6I_fLIv3RZt$HHtYdW@_|7puoe=H1$F<#lLxMty_A}g8&Y0$V9#49ig><#i;p%wpwF|?tdDEP^kW^5t+m{us_Kdl9Pa-yN$Eia z*SEbm`^~tcy(AS4apwG7i@g712*=5;UJ1CC>EAl7%ZXI&q#BZ#<^6Ro5f1nNm=J6= zfou33P8gQ>5+i<^h$@C|P0e)wF@)p9&|?xD7v?^qmhr@);ls6Cuq3IF--5&aKPE%L z?%+JFsv##e%F>{EuF-?Z>+wyFW5fzQ`x@~y>@8&3;6r1VOZRSKivaQ}}gT*FpILRYo#=lI z;W!Zt&pGd_TeOvtg(O&l(ze~$I+!^ zd!EaHuIjG-d{H<3>|v%&!n1yEkk@`Aa{b3)EVBLPCbPo|LumI_85CxXD-9Bxw9W94 zW^lwPw!a*$>%6V0W9Jfj>$8pdFIfu znW%0Ev)24=2hXv&3pKdk#EJNkg6uBJ7-w9_Gkg!zdU*W*wowbQ0`HG_G+jkl-OT0V zb2nq^&qYGMPOKK&-v(lQTU$L*!-a5LMtU-biE(b=?>6B%{y4mP2VfD)l}%-zYrONW?&~cg`H-FWPn|6@%Cg;9Tx3_?g&0yC{VXz>p&Mk_y zT-j-4>Z8T|YC|TguZtjK`tJq2P!08VSd8fVtXy$zTiGFZ7d)iwzng>m_!rG4c>N+I zXrjNNUQo!17R4upI}bUh;8JD;K1V^6#kAUmG?`%-ns>wB-E>WZ;y2lt2|Vb(G~PBh5W zqF6jFe-Q=p_+DAg#0k(Pl$l$r7VGp533WVTx6lCceEUslJ2=LiE%3UEQ1H=S4qK*B z#C#lbf3Zhu|IUfR2B)Z0WWGh&yxNHFDOo9(ny%I?P5VTdjlAbwTZjnr99Kb%ciyoxhdbV=8nY3-*)gEkNIG70W5;z zGuA8#n_Xq{S4Z#TCy2r0|F=z@_R=$ewW1S)`C)i`kq7Vo1MV*+kgqubg~s4GC*Gs# z0fw3H>=aEUztzpe7k{@2&vDQrBw|2U8U^}Ls5GgXbJuzrMy(3uxhN*t(hR^FWi7%@ zOpTgeavg2w;L~%2N6X(fsi@W9Z){XsYWs=T{LqvMp{6EkseAsn9X!XBgL~|NuGa-} zbbP0a-VAu$NAw@G_Jzm)Z<}EZ$25TTg~zkpwSUElIQvBbCav8uzi#t4;m`3oUM27| z!8!Jlglg6TGqz1ix_PSr@_3qQEe%|Ef4dxrDkO)4>+o@>PS1Z)_)m-Q9oiM1zXBPTzxU>{I;sdOlAcKn30zwNRoaE)3He{&qsrh5o6MuOFV7XVU zJ|tw{cB?aBn<-*q!TMtb-;o}zX&#Ivv~QjoIj%HW(;j`T$FFgWEBBcN2R(l0RldG& zpDU*Y2C^n8`X}r0!?>zTW&Fa3tKDYYl0fryGbc z)Ul^R{=JULxF0uxzHe}D=+@SB-e#ap!VcDCg1l!dsa~)gU=dYfs!VxUIwLfrL~xv4 z%l)Gsz9Ym977u_W^0;+v!JKmTx^l*Vd>bm{XNbo?;Qj(wmhyZr0=>`R%F#9|l#a|$ z!>8ttRWY6l_-wP>oV}9F%$ple_^FqM1@R%TH8tGX#s+kiT@9fYFzn^^VJam^ntXcc zPmAy!jni{n09etMlMD2=U3ZqqP_>3;nB(9h{IN3n!UygfTEcJg))i%G6MMGw=B~Wy z(?3@59X%ky0N143tEWRFuO{=Uq2;AVuCsZ-NBCnkfR~7NomVNVmqiQCSWYsLa!fs6jk$ha_AaK<7t{z z@q0K9;)m>yE8t@J1?HKyJB9Au5W=tb4ZY68Uil>bIKO|@1+P^K0x@oE(iBU8!Xk~0cuGe^0rNO^OAg1q0vtA0lh(DgIQb@hpC)MYVr zPZApA2FUA=ENBlM02XazmxyJ8{;TWMsbyJSS{BE}^RGIF)YRYaBhr2)zU#j%;4izB zt*-^>3Z9xtHmkeI+7)$5*L%kr^7YFzlST(%iTp}&)z?c3lQ*`hC18GC0KcODS+-vl ztpivyqhs_4tlmYgJmOt~%0in`#f7n8V*nEYYn|EK<(qxZ*FPnrkrny66?m7* z+sziQmEGIL4}ZLx^oesd)Q74*XETaA1-?g|v|;(nGW?!@4-W!t_l@>huw<8I zP(2R!%X*&p(iQ&YY&TRw9#Ob!7XNd+(Z3h2q{Fr~!p4Nf+!rrKfwJ2*DMn+rq MiLs78$aCcX10=T(NB{r; literal 0 HcmV?d00001 diff --git a/src/main/hook/zero/zerohook.hdd.raw b/src/main/hook/zero/zerohook.hdd.raw new file mode 100755 index 0000000000000000000000000000000000000000..718572705b0c145b1c7dfd85ff356f1712b5a24d GIT binary patch literal 5120 zcmZQz7zHCa1OiHP3lySKi}J|~1jZo_6et8_2HT*~<{aee!p6wJzyftqPH=YRpmE%& zLq}t^a8f(xZlshQMeDjE2By2#kin H;0XZ$r_mA9 literal 0 HcmV?d00001 diff --git a/src/main/io/piubtn/defs.h b/src/main/io/piubtn/defs.h new file mode 100644 index 0000000..73bd7c8 --- /dev/null +++ b/src/main/io/piubtn/defs.h @@ -0,0 +1,17 @@ +#ifndef PIUBTN_DRV_DEFS_H +#define PIUBTN_DRV_DEFS_H + +#define PIUBTN_DRV_VID 0x0D2F +#define PIUBTN_DRV_PID 0x1010 + +#define PIUBTN_DRV_CONFIG 0x01 +#define PIUBTN_DRV_IFACE 0x00 + +#define PIUBTN_DRV_USB_CTRL_TYPE_IN 0xC0 +#define PIUBTN_DRV_USB_CTRL_TYPE_OUT 0x40 +#define PIUBTN_DRV_USB_CTRL_REQUEST 0xAE +#define PIUBTN_DRV_USB_REQ_TIMEOUT 10000 + +#define PIUBTN_DRV_BUFFER_SIZE 8 + +#endif \ No newline at end of file diff --git a/src/main/io/piubtn/device.c b/src/main/io/piubtn/device.c new file mode 100644 index 0000000..e0c8e95 --- /dev/null +++ b/src/main/io/piubtn/device.c @@ -0,0 +1,84 @@ +#define LOG_MODULE "piubtn-drv-device" + +#include "io/util/usb_.h" + +#include "util/log.h" + +#include "defs.h" +#include "device.h" + +static void* piubtn_drv_device_handle; + +bool piubtn_drv_device_open(void) +{ + if (piubtn_drv_device_handle) { + log_warn("Device already opened"); + return true; + } + + piubtn_drv_device_handle = io_usb_open(PIUBTN_DRV_VID, PIUBTN_DRV_PID, + PIUBTN_DRV_CONFIG, PIUBTN_DRV_IFACE); + + return piubtn_drv_device_handle; +} + +bool piubtn_drv_device_read(uint8_t* buffer, uint8_t len) +{ + int32_t res; + + if (!piubtn_drv_device_handle) { + log_error("Device not opened"); + return false; + } + + if (len < PIUBTN_DRV_BUFFER_SIZE) { + log_error("Read failed, buffer (%d) too small", len); + return false; + } + + res = io_usb_control_transfer(piubtn_drv_device_handle, + PIUBTN_DRV_USB_CTRL_TYPE_IN, PIUBTN_DRV_USB_CTRL_REQUEST, 0, 0, buffer, + PIUBTN_DRV_BUFFER_SIZE, PIUBTN_DRV_USB_REQ_TIMEOUT); + + if (res != PIUBTN_DRV_BUFFER_SIZE) { + log_error("Read failed: %d", res); + return false; + } + + return true; +} + +bool piubtn_drv_device_write(uint8_t* buffer, uint8_t len) +{ + int32_t res; + + if (!piubtn_drv_device_handle) { + log_error("Device not opened"); + return false; + } + + if (len < PIUBTN_DRV_BUFFER_SIZE) { + log_error("Write failed, buffer (%d) too small", len); + return false; + } + + res = io_usb_control_transfer(piubtn_drv_device_handle, + PIUBTN_DRV_USB_CTRL_TYPE_OUT, PIUBTN_DRV_USB_CTRL_REQUEST, 0, 0, buffer, + PIUBTN_DRV_BUFFER_SIZE, PIUBTN_DRV_USB_REQ_TIMEOUT); + + if (res != PIUBTN_DRV_BUFFER_SIZE) { + log_error("Write failed: %d", res); + return false; + } + + return true; +} + +void piubtn_drv_device_close(void) +{ + if (!piubtn_drv_device_handle) { + log_error("Device not opened"); + } + + io_usb_close(piubtn_drv_device_handle); +} \ No newline at end of file diff --git a/src/main/io/piubtn/device.h b/src/main/io/piubtn/device.h new file mode 100644 index 0000000..e2bc097 --- /dev/null +++ b/src/main/io/piubtn/device.h @@ -0,0 +1,41 @@ +/** + * This module serves as a low level device implementation for a usb piubtn + * io. It uses libusb-1.0 to communicate with the usb device. + */ +#ifndef PIUBTN_DRV_DEVICE_H +#define PIUBTN_DRV_DEVICE_H + +#include +#include + +/** + * Open a connected usb piubtn device + * + * @return True if opening a piubtn device was successful, false on failure + */ +bool piubtn_drv_device_open(void); + +/** + * Read raw data from the piubtn device + * + * @param buffer Allocated buffer to read data from the device into + * @param len Number of bytes to read + * @return True if reading data to device was successful, false otherwise + */ +bool piubtn_drv_device_read(uint8_t* buffer, uint8_t len); + +/** + * Write raw data to the piubtn device + * + * @param buffer Buffer with data to write + * @param len Number of bytes to write + * @return True if writing data to device was successful, false otherwise + */ +bool piubtn_drv_device_write(uint8_t* buffer, uint8_t len); + +/** + * Close the opened piubtn device + */ +void piubtn_drv_device_close(void); + +#endif \ No newline at end of file diff --git a/src/main/io/piuio/defs.h b/src/main/io/piuio/defs.h new file mode 100644 index 0000000..dd3641a --- /dev/null +++ b/src/main/io/piuio/defs.h @@ -0,0 +1,17 @@ +#ifndef PIUIO_DRV_DEFS_H +#define PIUIO_DRV_DEFS_H + +#define PIUIO_DRV_VID 0x0547 +#define PIUIO_DRV_PID 0x1002 + +#define PIUIO_DRV_CONFIG 0x01 +#define PIUIO_DRV_IFACE 0x00 + +#define PIUIO_DRV_USB_CTRL_TYPE_IN 0xC0 +#define PIUIO_DRV_USB_CTRL_TYPE_OUT 0x40 +#define PIUIO_DRV_USB_CTRL_REQUEST 0xAE +#define PIUIO_DRV_USB_REQ_TIMEOUT 10000 + +#define PIUIO_DRV_BUFFER_SIZE 8 + +#endif \ No newline at end of file diff --git a/src/main/io/piuio/device.c b/src/main/io/piuio/device.c new file mode 100644 index 0000000..b1db8b5 --- /dev/null +++ b/src/main/io/piuio/device.c @@ -0,0 +1,84 @@ +#define LOG_MODULE "piuio-drv-device" + +#include "io/util/usb_.h" + +#include "util/log.h" + +#include "defs.h" +#include "device.h" + +static void* piuio_drv_device_handle; + +bool piuio_drv_device_open(void) +{ + if (piuio_drv_device_handle) { + log_warn("Device already opened"); + return true; + } + + piuio_drv_device_handle = io_usb_open(PIUIO_DRV_VID, PIUIO_DRV_PID, + PIUIO_DRV_CONFIG, PIUIO_DRV_IFACE); + + return piuio_drv_device_handle; +} + +bool piuio_drv_device_read(uint8_t* buffer, uint8_t len) +{ + int32_t res; + + if (!piuio_drv_device_handle) { + log_error("Device not opened"); + return false; + } + + if (len < PIUIO_DRV_BUFFER_SIZE) { + log_error("Read failed, buffer (%d) too small", len); + return false; + } + + res = io_usb_control_transfer(piuio_drv_device_handle, + PIUIO_DRV_USB_CTRL_TYPE_IN, PIUIO_DRV_USB_CTRL_REQUEST, 0, 0, buffer, + PIUIO_DRV_BUFFER_SIZE, PIUIO_DRV_USB_REQ_TIMEOUT); + + if (res != PIUIO_DRV_BUFFER_SIZE) { + log_error("Read failed: %d", res); + return false; + } + + return true; +} + +bool piuio_drv_device_write(uint8_t* buffer, uint8_t len) +{ + int32_t res; + + if (!piuio_drv_device_handle) { + log_error("Device not opened"); + return false; + } + + if (len < PIUIO_DRV_BUFFER_SIZE) { + log_error("Write failed, buffer (%d) too small", len); + return false; + } + + res = io_usb_control_transfer(piuio_drv_device_handle, + PIUIO_DRV_USB_CTRL_TYPE_OUT, PIUIO_DRV_USB_CTRL_REQUEST, 0, 0, buffer, + PIUIO_DRV_BUFFER_SIZE, PIUIO_DRV_USB_REQ_TIMEOUT); + + if (res != PIUIO_DRV_BUFFER_SIZE) { + log_error("Write failed: %d", res); + return false; + } + + return true; +} + +void piuio_drv_device_close(void) +{ + if (!piuio_drv_device_handle) { + log_error("Device not opened"); + } + + io_usb_close(piuio_drv_device_handle); +} \ No newline at end of file diff --git a/src/main/io/piuio/device.h b/src/main/io/piuio/device.h new file mode 100644 index 0000000..82d7400 --- /dev/null +++ b/src/main/io/piuio/device.h @@ -0,0 +1,41 @@ +/** + * This module serves as a low level device implementation for a usb piuio + * card. It uses libusb-1.0 to communicate with the usb device. + */ +#ifndef PIUIO_DRV_DEVICE_H +#define PIUIO_DRV_DEVICE_H + +#include +#include + +/** + * Open a connected usb piuio device + * + * @return True if opening a piuio device was successful, false on failure + */ +bool piuio_drv_device_open(void); + +/** + * Read raw data from the piuio device + * + * @param buffer Allocated buffer to read data from the device into + * @param len Number of bytes to read + * @return True if reading data to device was successful, false otherwise + */ +bool piuio_drv_device_read(uint8_t* buffer, uint8_t len); + +/** + * Write raw data to the piuio device + * + * @param buffer Buffer with data to write + * @param len Number of bytes to write + * @return True if writing data to device was successful, false otherwise + */ +bool piuio_drv_device_write(uint8_t* buffer, uint8_t len); + +/** + * Close the opened piuio device + */ +void piuio_drv_device_close(void); + +#endif \ No newline at end of file diff --git a/src/main/io/util/joystick-util.c b/src/main/io/util/joystick-util.c new file mode 100644 index 0000000..74be37b --- /dev/null +++ b/src/main/io/util/joystick-util.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#include +#include + +#include "io/util/joystick-util.h" + +#include "util/fs.h" +#include "util/log.h" + +size_t io_util_joystick_util_scan(struct io_util_joystick_util_device_info* devices, size_t len) +{ + log_assert(devices); + + char dev_path[PATH_MAX]; + int handle; + size_t num_joysticks; + + num_joysticks = 0; + + for (size_t i = 0; i < len; i++) { + sprintf(dev_path, "/dev/input/js%d", i); + + memset(&devices[num_joysticks], 0, sizeof(struct io_util_joystick_util_device_info)); + + if (util_fs_path_exists(dev_path)) { + // temporarily have to open the device + handle = open(dev_path, O_RDONLY | O_NONBLOCK); + + if (handle == -1) { + log_error("Opening joystick device %s failed: %s", dev_path, strerror(errno)); + continue; + } + + strcpy(devices[num_joysticks].dev_path, dev_path); + + ioctl(handle, JSIOCGAXES, &(devices[num_joysticks].num_axes)); + ioctl(handle, JSIOCGBUTTONS, &(devices[num_joysticks].num_buttons)); + ioctl(handle, JSIOCGNAME(JOYSTICK_NAME_LEN), devices[num_joysticks].name); + + close(handle); + + num_joysticks++; + } + } + + return num_joysticks; +} \ No newline at end of file diff --git a/src/main/io/util/joystick-util.h b/src/main/io/util/joystick-util.h new file mode 100644 index 0000000..f9becfd --- /dev/null +++ b/src/main/io/util/joystick-util.h @@ -0,0 +1,20 @@ +#ifndef IO_UTIL_JOYSTICK_UTIL_H +#define IO_UTIL_JOYSTICK_UTIL_H + +#include +#include +#include +#include + +#define JOYSTICK_NAME_LEN 128 + +struct io_util_joystick_util_device_info { + char dev_path[PATH_MAX]; + uint16_t num_buttons; + uint16_t num_axes; + char name[JOYSTICK_NAME_LEN]; +}; + +size_t io_util_joystick_util_scan(struct io_util_joystick_util_device_info* devices, size_t len); + +#endif diff --git a/src/main/io/util/joystick.c b/src/main/io/util/joystick.c new file mode 100644 index 0000000..3dee804 --- /dev/null +++ b/src/main/io/util/joystick.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include +#include + +#include "io/util/joystick.h" + +#include "util/log.h" +#include "util/mem.h" + +#define MAX_NUM_EVENTS 64 + +bool io_util_joystick_open(const char* dev_path, struct io_util_joystick** ctx) +{ + log_assert(dev_path); + log_assert(ctx); + + int handle; + + handle = open(dev_path, O_RDONLY | O_NONBLOCK); + + if (handle == -1) { + log_error("Opening joystick device %s failed: %s", dev_path, strerror(errno)); + return false; + } + + *ctx = util_xmalloc(sizeof(struct io_util_joystick)); + + strcpy((*ctx)->dev_path, dev_path); + (*ctx)->handle = handle; + + // Init values to avoid having ioctl return garbage + (*ctx)->num_buttons = 0; + (*ctx)->num_axes = 0; + memset((*ctx)->name, 0, sizeof(char) * JOYSTICK_NAME_LEN); + + // grab data + ioctl(handle, JSIOCGAXES, &((*ctx)->num_axes)); + ioctl(handle, JSIOCGBUTTONS, &((*ctx)->num_buttons)); + ioctl(handle, JSIOCGNAME(JOYSTICK_NAME_LEN), (*ctx)->name); + + (*ctx)->button_state = util_xmalloc(sizeof(uint8_t) * (*ctx)->num_buttons); + + log_debug("Opened joystick device %s, handle %p, num buttons %d, num axes %d, name %s", (*ctx)->dev_path, + (*ctx)->handle, (*ctx)->num_buttons, (*ctx)->num_axes, (*ctx)->name); + + return true; +} + +bool io_util_joystick_close(struct io_util_joystick* ctx) +{ + log_assert(ctx); + + bool res; + + log_debug("Closing joystick device %s, handle %p", ctx->dev_path, ctx->handle); + + if (close(ctx->handle) != 0) { + log_error("Closing joystick device %s failed: %s", ctx->dev_path, strerror(errno)); + res = false; + } else { + res = true; + } + + free(ctx->button_state); + free(ctx); + + return res; +} + +bool io_util_joystick_update(struct io_util_joystick* ctx) +{ + log_assert(ctx); + + struct js_event jse[MAX_NUM_EVENTS]; + + int bytes = read(ctx->handle, jse, sizeof(struct js_event) * MAX_NUM_EVENTS); + + if (bytes < 0) { + switch (errno) { + // try again on next poll + case EAGAIN: + return true; + default: + log_error("Reading from joystick device failed: %s", ctx->dev_path, strerror(errno)); + return false; + } + } + + // determine how many whole events we read + bytes /= sizeof(struct js_event); + + // now iterate all events + for (int i = 0; i < bytes; i++) { + switch (jse[i].type & ~JS_EVENT_INIT) { + case JS_EVENT_BUTTON: + ctx->button_state[jse[i].number] = (bool) jse[i].value; + break; + + default: + break; + } + } + + + return true; +} + +bool io_util_joystick_is_button_pressed(struct io_util_joystick* ctx, uint16_t button) +{ + log_assert(ctx); + + if (button >= ctx->num_buttons) { + return false; + } + + return ctx->button_state[button]; +} \ No newline at end of file diff --git a/src/main/io/util/joystick.h b/src/main/io/util/joystick.h new file mode 100644 index 0000000..88e3c3d --- /dev/null +++ b/src/main/io/util/joystick.h @@ -0,0 +1,27 @@ +#ifndef IO_UTIL_JOYSTICK_H +#define IO_UTIL_JOYSTICK_H + +#include +#include +#include + +#define JOYSTICK_NAME_LEN 128 + +struct io_util_joystick { + char dev_path[PATH_MAX]; + int handle; + uint16_t num_buttons; + uint16_t num_axes; + char name[JOYSTICK_NAME_LEN]; + bool* button_state; +}; + +bool io_util_joystick_open(const char* dev_path, struct io_util_joystick** ctx); + +bool io_util_joystick_close(struct io_util_joystick* ctx); + +bool io_util_joystick_update(struct io_util_joystick* ctx); + +bool io_util_joystick_is_button_pressed(struct io_util_joystick* ctx, uint16_t button); + +#endif diff --git a/src/main/io/util/usb.c b/src/main/io/util/usb.c new file mode 100644 index 0000000..3acf0fc --- /dev/null +++ b/src/main/io/util/usb.c @@ -0,0 +1,171 @@ +#define LOG_MODULE "io-usb" + +#include +#include + +#include "util/log.h" +#include "util/mem.h" + +struct usb_io_ctx { + struct libusb_context* ctx; + struct libusb_device_handle* dev; +}; + +static struct libusb_device_handle* io_usb_get_device_handle( + struct libusb_context* ctx, uint16_t vid, uint16_t pid) +{ + int ret; + struct libusb_device** dev_list; + struct libusb_device* device; + struct libusb_device_handle* handle; + + dev_list = NULL; + device = NULL; + + ssize_t num_dev = libusb_get_device_list(ctx, &dev_list); + + /* find device */ + for (ssize_t i = 0; i < num_dev; i++) { + struct libusb_device_descriptor dev_desc_tmp; + struct libusb_device* dev_tmp; + + dev_tmp = dev_list[i]; + + libusb_get_device_descriptor(dev_tmp, &dev_desc_tmp); + + /* for handling multiple devices with the same pid and vid */ + /* + device_id_tmp = ((libusb_get_bus_number(dev_tmp) << 8) | + libusb_get_port_number(dev_tmp)); + */ + + if (dev_desc_tmp.idVendor == vid && dev_desc_tmp.idProduct == pid) { + device = dev_tmp; + break; + } + } + + /* not found */ + if (device == NULL) { + libusb_free_device_list(dev_list, 1); + log_error("Could not find device %04X:%04X", vid, pid); + return NULL; + } + + ret = libusb_open(device, &handle); + if (ret != LIBUSB_SUCCESS) { + libusb_free_device_list(dev_list, 1); + + log_error("Could not open device %04X:%04X: %s", vid, pid, + libusb_error_name(ret)); + return NULL; + } + + libusb_free_device_list(dev_list, 1); + + return handle; +} + +void* io_usb_open(uint16_t vid, uint16_t pid, uint16_t config, uint16_t iface) +{ + int ret; + struct libusb_context* ctx; + struct libusb_device_handle* dev; + struct usb_io_ctx* handle; + + log_debug("Opening %04X:%04X, config %d, iface %d", vid, pid, config, + iface); + + ret = libusb_init(&ctx); + + if (ret != LIBUSB_SUCCESS) { + log_error("(%04X:%04X) Initializing libusb context failed: %s", + vid, pid, libusb_error_name(ret)); + return NULL; + } + + /* dont print any error messages to stderr, change this for debugging */ + // libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE); + + dev = io_usb_get_device_handle(ctx, vid, pid); + + if (!dev) { + libusb_exit(ctx); + return NULL; + } + + ret = libusb_set_configuration(dev, config); + + if (ret != LIBUSB_SUCCESS) { + libusb_close(dev); + libusb_exit(ctx); + + log_error("(%04X:%04X) Setting configuration failed", vid, pid, + libusb_error_name(ret)); + return NULL; + } + + /* check if the device is attached to the kernel, detach it first then */ + if (libusb_kernel_driver_active(dev, iface) == 1) { + ret = libusb_detach_kernel_driver(dev, iface); + if (ret != LIBUSB_SUCCESS) { + libusb_close(dev); + libusb_exit(ctx); + + log_error( + "(%04X:%04X) Detaching interface %d from kernel failed: %s", + vid, pid, iface, libusb_error_name(ret)); + return NULL; + } + } + + ret = libusb_claim_interface(dev, iface); + + if (ret != LIBUSB_SUCCESS) { + libusb_close(dev); + libusb_exit(ctx); + + log_error("(%04X:%04X) Claiming interface %d failed: %s", vid, pid, + iface, libusb_error_name(ret)); + return NULL; + } + + handle = (struct usb_io_ctx*) util_xmalloc(sizeof(struct usb_io_ctx)); + + handle->ctx = ctx; + handle->dev = dev; + + log_debug("Opened %04X:%04X, handle %p", vid, pid, handle); + + return handle; +} + +int32_t io_usb_control_transfer(void* handle, uint8_t request_type, + uint8_t request, uint16_t value, uint16_t index, uint8_t* data, + uint16_t len, uint32_t timeout) +{ + struct usb_io_ctx* dev = (struct usb_io_ctx*) handle; + int32_t ret; + + ret = libusb_control_transfer(dev->dev, request_type, request, value, + index, data, len, timeout); + + if (ret != len) { + log_error("Control transfer, handle %p failed: %s", handle, + libusb_error_name(ret)); + } + + return ret; +} + +void io_usb_close(void* handle) +{ + struct usb_io_ctx* dev = (struct usb_io_ctx*) handle; + + log_debug("Closing handle %p", handle); + + libusb_close(dev->dev); + libusb_exit(dev->ctx); + + free(dev); +} diff --git a/src/main/io/util/usb_.h b/src/main/io/util/usb_.h new file mode 100644 index 0000000..ab032cf --- /dev/null +++ b/src/main/io/util/usb_.h @@ -0,0 +1,46 @@ +/** + * Wrapper module for libusb-1.0 to make it a little more convenient to use + * usb devices + */ +#ifndef IO_USB_H +#define IO_USB_H + +#include + +/** + * Open a usb device + * + * @param vid Vendor ID of the device + * @param pid Product ID of the device + * @param config Configuration to set + * @param iface Interface to claim + * @return On success, a handle to the opened device, NULL on failure + */ +void* io_usb_open(uint16_t vid, uint16_t pid, uint16_t config, uint16_t iface); + +/** + * Execute a control transfer + * + * @param handle Handle of an opened usb device + * @param request_type Request type + * @param request Request + * @param value Value + * @param index Index + * @param data Pointer to an allocated buffer (depending on the vendor + * specific request type, this can be a read or write buffer) + * @param len Length of the data to write/read + * @param timeout Timeout for the operation in ms + * @return Number of bytes read/written or -1 on error + */ +int32_t io_usb_control_transfer(void* handle, uint8_t request_type, + uint8_t request, uint16_t value, uint16_t index, uint8_t* data, + uint16_t len, uint32_t timeout); + +/** + * Close a opened usb device + * + * @param handle Handle of the opened device + */ +void io_usb_close(void* handle); + +#endif \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/joystick-conf/main.c b/src/main/ptapi/io/piubtn/joystick-conf/main.c new file mode 100644 index 0000000..0e381c3 --- /dev/null +++ b/src/main/ptapi/io/piubtn/joystick-conf/main.c @@ -0,0 +1,255 @@ +#include +#include + +#include "io/util/joystick.h" +#include "io/util/joystick-util.h" + +#include "ptapi/io/piubtn/joystick-util/joystick-conf.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/time.h" + +#define MAX_JOYSTICKS 16 +#define CONFIG_FILENAME "piubtn-joystick-conf.bin" +#define SKIP_INPUT 0xFFFF + +int kbhit() +{ + struct timeval tv = { 0L, 0L }; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); + + return select(1, &fds, NULL, NULL, &tv); +} + +int getch() +{ + int r; + unsigned char c; + + if ((r = read(0, &c, sizeof(c))) < 0) { + return r; + } else { + return c; + } +} + +static uint16_t joystick_get_next_input(struct io_util_joystick* joystick) +{ + bool pressed; + uint16_t button; + + pressed = false; + button = 0; + + while (true) { + if (!io_util_joystick_update(joystick)) { + printf("Error updating joystick failed.\n"); + exit(-1); + } + + // Allow skip-able input assignment via enter key on keyboard + if (kbhit() > 0) { + if (getch() == '\n') { + return SKIP_INPUT; + } + } + + if (!pressed) { + for (uint16_t j = 0; j < joystick->num_buttons; j++) { + if (io_util_joystick_is_button_pressed(joystick, j)) { + button = j; + pressed = true; + break; + } + } + } else { + // Wait for release of pressed input -> debouncing + if (!io_util_joystick_is_button_pressed(joystick, button)) { + break; + } + } + + util_time_sleep_ms(10); + } + + return button; +} + +static void menu_joystick_test() +{ + struct io_util_joystick_util_device_info dev_info[MAX_JOYSTICKS]; + size_t connected_joysticks; + + connected_joysticks = io_util_joystick_util_scan(dev_info, MAX_JOYSTICKS); + + printf("Connected joysticks: %d\n", connected_joysticks); + + for (size_t i = 0; i < connected_joysticks; i++) { + printf("%d: %s -> %s, buttons %d, axes %d\n", + i, dev_info[i].name, dev_info[i].dev_path, dev_info[i].num_buttons, dev_info[i].num_axes); + } + + size_t selected_device_idx; + + printf("Select device: "); + scanf("%d", &selected_device_idx); + + if (selected_device_idx > connected_joysticks) { + printf("Invalid device id %d, out of range\n", selected_device_idx); + return; + } + + struct io_util_joystick* joystick; + + if (!io_util_joystick_open(dev_info[selected_device_idx].dev_path, &joystick)) { + printf("Error opening device %s -> %s", dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path); + return; + } + + printf("Pressed + released inputs:\n"); + + while (true) { + printf("%d\n", joystick_get_next_input(joystick)); + } + + io_util_joystick_close(joystick); +} + +static void menu_joystick_map() +{ + struct ptapi_io_piubtn_joystick_util_conf* config; + struct ptapi_io_piubtn_joystick_util_conf_entry config_entry; + + struct io_util_joystick_util_device_info dev_info[MAX_JOYSTICKS]; + size_t connected_joysticks; + struct io_util_joystick* joystick; + + connected_joysticks = io_util_joystick_util_scan(dev_info, MAX_JOYSTICKS); + + printf("Connected joysticks: %d\n", connected_joysticks); + + for (size_t i = 0; i < connected_joysticks; i++) { + printf("%d: %s -> %s, buttons %d, axes %d\n", + i, dev_info[i].name, dev_info[i].dev_path, dev_info[i].num_buttons, dev_info[i].num_axes); + } + + size_t selected_device_idx; + + printf("Select device: "); + scanf("%d", &selected_device_idx); + + if (selected_device_idx > connected_joysticks) { + printf("Invalid device id %d, out of range\n", selected_device_idx); + return; + } + + if (!ptapi_io_piubtn_joystick_util_conf_read_from_file(&config, CONFIG_FILENAME)) { + printf("Reading existing config file failed, creating new\n"); + + ptapi_io_piubtn_joystick_util_conf_new(&config); + + memset(&config_entry, 0, sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry)); + + strcpy(config_entry.dev_path, dev_info[selected_device_idx].dev_path); + strcpy(config_entry.name, dev_info[selected_device_idx].name); + } else { + if (!ptapi_io_piubtn_joystick_util_conf_find_entry(config, dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path, &config_entry)) { + printf("Could not find existing mapping entry in config for joystick, creating new one\n"); + + memset(&config_entry, 0, sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry)); + + strcpy(config_entry.dev_path, dev_info[selected_device_idx].dev_path); + strcpy(config_entry.name, dev_info[selected_device_idx].name); + } else { + printf("Found existing mapping entry in config for joystick, overwriting\n"); + } + } + + printf("Configuring device %s -> %s\n", dev_info[selected_device_idx].name, dev_info[selected_device_idx].dev_path); + + if (!io_util_joystick_open(dev_info[selected_device_idx].dev_path, &joystick)) { + printf("Error opening device %s -> %s", dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path); + return; + } + + for (uint32_t i = PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_LEFT; + i < PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_COUNT; + i++) { + printf("Press button to assign to \"%s\" or Enter/Return to skip: ", ptapi_io_piubtn_joystick_util_conf_input_str[i]); + fflush(stdout); + + config_entry.button_map[i] = joystick_get_next_input(joystick); + + if (config_entry.button_map[i] == SKIP_INPUT) { + printf("SKIP\n"); + } else { + printf("%d\n", config_entry.button_map[i]); + } + } + + io_util_joystick_close(joystick); + + printf("Configuration of device %s -> %s done\n", dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path); + + if (!ptapi_io_piubtn_joystick_util_conf_set_entry(config, &config_entry)) { + ptapi_io_piubtn_joystick_util_conf_append_entry(&config, &config_entry); + } + + ptapi_io_piubtn_joystick_util_conf_write_to_file(config, CONFIG_FILENAME); + + free(config); + + printf("Configuration file saved: %s\n", CONFIG_FILENAME); +} + +int main(int argc, char** argv) +{ + bool main_loop; + + util_log_set_file("joystick-conf.log", false); + util_log_set_level(LOG_LEVEL_ERROR); + + printf("ptapi PIUBTN joystick button mapping config tool\n"); + + main_loop = true; + + while (main_loop) { + uint32_t item; + + printf("Main menu, please select:\n"); + printf("1 > Joystick input test\n"); + printf("2 > Configure joystick mappings\n"); + printf("3 > Exit\n"); + printf("Select number: "); + + scanf("%d", &item); + + switch (item) { + case 1: + menu_joystick_test(); + break; + + case 2: + menu_joystick_map(); + break; + + case 3: + main_loop = false; + break; + + default: + printf("Invalid item chosen: %d\n", item); + break; + } + } + + return 0; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/joystick-util/joystick-conf.c b/src/main/ptapi/io/piubtn/joystick-util/joystick-conf.c new file mode 100644 index 0000000..4242c8a --- /dev/null +++ b/src/main/ptapi/io/piubtn/joystick-util/joystick-conf.c @@ -0,0 +1,99 @@ +#include "ptapi/io/piubtn/joystick-util/joystick-conf.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" + +const char* ptapi_io_piubtn_joystick_util_conf_input_str[PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_COUNT] = { + "invalid", + "P1 Left", + "P1 Right", + "P1 Start", + "P1 Back", + "P2 Left", + "P2 Right", + "P2 Start", + "P2 Back", +}; + +void ptapi_io_piubtn_joystick_util_conf_new(struct ptapi_io_piubtn_joystick_util_conf** conf) +{ + log_assert(conf); + + *conf = util_xmalloc(sizeof(struct ptapi_io_piubtn_joystick_util_conf)); + (*conf)->num_entries = 0; +} + +bool ptapi_io_piubtn_joystick_util_conf_read_from_file(struct ptapi_io_piubtn_joystick_util_conf** conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + void* buffer; + size_t size; + + if (!util_file_load(path, &buffer, &size, false)) { + return false; + } + + *conf = (struct ptapi_io_piubtn_joystick_util_conf*) buffer; + + return true; +} + +bool ptapi_io_piubtn_joystick_util_conf_write_to_file(struct ptapi_io_piubtn_joystick_util_conf* conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + return util_file_save(path, conf, sizeof(struct ptapi_io_piubtn_joystick_util_conf) + + sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry) * conf->num_entries); +} + +bool ptapi_io_piubtn_joystick_util_conf_set_entry(struct ptapi_io_piubtn_joystick_util_conf* conf, + struct ptapi_io_piubtn_joystick_util_conf_entry* entry) +{ + log_assert(conf); + log_assert(entry); + + for (size_t i = 0; i < conf->num_entries; i++) { + if (!strcmp(conf->entries[i].name, entry->name) && !strcmp(conf->entries[i].dev_path, entry->dev_path)) { + memcpy(&conf->entries[i], entry, sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry)); + return true; + } + } + + return false; +} + +void ptapi_io_piubtn_joystick_util_conf_append_entry(struct ptapi_io_piubtn_joystick_util_conf** conf, + struct ptapi_io_piubtn_joystick_util_conf_entry* entry) +{ + log_assert(conf); + log_assert(entry); + + (*conf)->num_entries++; + + *conf = util_xrealloc(*conf, sizeof(struct ptapi_io_piubtn_joystick_util_conf*) + + sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry) * (*conf)->num_entries); + + memcpy(&(*conf)->entries[(*conf)->num_entries - 1], entry, sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry)); +}; + +bool ptapi_io_piubtn_joystick_util_conf_find_entry(struct ptapi_io_piubtn_joystick_util_conf* conf, const char* name, + const char* dev_path, struct ptapi_io_piubtn_joystick_util_conf_entry* entry) +{ + log_assert(name); + log_assert(dev_path); + log_assert(entry); + + for (size_t i = 0; i < conf->num_entries; i++) { + if (!strcmp(conf->entries[i].name, name) && !strcmp(conf->entries[i].dev_path, dev_path)) { + memcpy(entry, &conf->entries[i], sizeof(struct ptapi_io_piubtn_joystick_util_conf_entry)); + + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/joystick-util/joystick-conf.h b/src/main/ptapi/io/piubtn/joystick-util/joystick-conf.h new file mode 100644 index 0000000..d27dbc7 --- /dev/null +++ b/src/main/ptapi/io/piubtn/joystick-util/joystick-conf.h @@ -0,0 +1,50 @@ +#ifndef PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_H +#define PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_H + +#include + +#include "io/util/joystick.h" + +enum PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT { + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_INVALID = 0, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_LEFT = 1, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_RIGHT = 2, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_START = 3, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_BACK = 4, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_LEFT = 5, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_RIGHT = 6, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_START = 7, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_BACK = 8, + PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_COUNT = 9, +}; + +extern const char* ptapi_io_piubtn_joystick_util_conf_input_str[PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_COUNT]; + +struct ptapi_io_piubtn_joystick_util_conf_entry { + char name[JOYSTICK_NAME_LEN]; + char dev_path[PATH_MAX]; + + uint16_t button_map[PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_COUNT]; +}; + +struct ptapi_io_piubtn_joystick_util_conf { + size_t num_entries; + struct ptapi_io_piubtn_joystick_util_conf_entry entries[]; +}; + +void ptapi_io_piubtn_joystick_util_conf_new(struct ptapi_io_piubtn_joystick_util_conf** conf); + +bool ptapi_io_piubtn_joystick_util_conf_read_from_file(struct ptapi_io_piubtn_joystick_util_conf** conf, const char* path); + +bool ptapi_io_piubtn_joystick_util_conf_write_to_file(struct ptapi_io_piubtn_joystick_util_conf* conf, const char* path); + +bool ptapi_io_piubtn_joystick_util_conf_set_entry(struct ptapi_io_piubtn_joystick_util_conf* conf, + struct ptapi_io_piubtn_joystick_util_conf_entry* entry); + +void ptapi_io_piubtn_joystick_util_conf_append_entry(struct ptapi_io_piubtn_joystick_util_conf** conf, + struct ptapi_io_piubtn_joystick_util_conf_entry* entry); + +bool ptapi_io_piubtn_joystick_util_conf_find_entry(struct ptapi_io_piubtn_joystick_util_conf* conf, const char* name, + const char* dev_path, struct ptapi_io_piubtn_joystick_util_conf_entry* entry); + +#endif diff --git a/src/main/ptapi/io/piubtn/joystick/joystick.c b/src/main/ptapi/io/piubtn/joystick/joystick.c new file mode 100644 index 0000000..12d09d3 --- /dev/null +++ b/src/main/ptapi/io/piubtn/joystick/joystick.c @@ -0,0 +1,174 @@ +/** + * Implementation of the piubtn API to use the game with joysticks/gamepads. + */ +#define LOG_MODULE "ptapi-io-piubtn-joystick" + +#include "io/util/joystick.h" +#include "io/util/joystick-util.h" + +#include "ptapi/io/piubtn.h" + +#include "ptapi/io/piubtn/joystick-util/joystick-conf.h" + +#include "util/log.h" +#include "util/proc.h" +#include "util/str.h" + +#define MAX_NUM_JOYSTICKS 16 +#define CONFIG_FILENAME "/piubtn-joystick-conf.bin" + +struct ptapi_io_piubtn_joystick_with_conf { + struct ptapi_io_piubtn_joystick_util_conf_entry* conf; + struct io_util_joystick* joystick; +}; + +static struct ptapi_io_piubtn_joystick_util_conf* ptapi_io_piubtn_joystick_util_conf; +static struct ptapi_io_piubtn_joystick_with_conf ptapi_io_piubtn_joysticks_with_conf[MAX_NUM_JOYSTICKS]; +static size_t ptapi_io_piubtn_num_active_joysticks; + +static bool ptapi_io_piubtn_merge_inputs(enum PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT input) +{ + bool pressed; + + pressed = false; + + for (size_t i = 0; i < ptapi_io_piubtn_num_active_joysticks; i++) { + if (ptapi_io_piubtn_joysticks_with_conf[i].joystick) { + pressed = pressed || + io_util_joystick_is_button_pressed( + ptapi_io_piubtn_joysticks_with_conf[i].joystick, + ptapi_io_piubtn_joysticks_with_conf[i].conf->button_map[input]); + } + } + + return pressed; +} + +const char* ptapi_io_piubtn_ident(void) +{ + return "joystick"; +} + +bool ptapi_io_piubtn_open() +{ + char path[PATH_MAX]; + char* config_path; + struct io_util_joystick_util_device_info device_info[MAX_NUM_JOYSTICKS]; + size_t devices_connected; + + // The game changes the working directory to the 'game' sub-folder. Therefore, ./my-config does not work here. + if (!util_proc_get_folder_path_executable_no_ld_linux(path, sizeof(path))) { + log_error("Getting executable folder path failed."); + return false; + } + + config_path = util_str_merge(path, CONFIG_FILENAME); + + if (!ptapi_io_piubtn_joystick_util_conf_read_from_file(&ptapi_io_piubtn_joystick_util_conf, config_path)) { + log_error("Loading joystick config file %s failed.", CONFIG_FILENAME); + free(config_path); + return false; + } + + free(config_path); + + devices_connected = io_util_joystick_util_scan(device_info, MAX_NUM_JOYSTICKS); + + log_debug("Found connected joysticks: %d", devices_connected); + + ptapi_io_piubtn_num_active_joysticks = 0; + + memset(ptapi_io_piubtn_joysticks_with_conf, 0, sizeof(struct ptapi_io_piubtn_joystick_with_conf) * MAX_NUM_JOYSTICKS); + + for (size_t i = 0; i < devices_connected; i++) { + log_debug("%d: %s -> %s, buttons %d, axes %d\n", + i, device_info[i].name, device_info[i].dev_path, device_info[i].num_buttons, device_info[i].num_axes); + + // Find a matching configuration + for (size_t j = 0; j < ptapi_io_piubtn_joystick_util_conf->num_entries; j++) { + + if (!strcmp(ptapi_io_piubtn_joystick_util_conf->entries[j].name, device_info[i].name) && + !strcmp(ptapi_io_piubtn_joystick_util_conf->entries[j].dev_path, device_info[i].dev_path)) { + log_debug("Found matching configuration for %s -> %s", device_info[i].name, device_info[i].dev_path); + + ptapi_io_piubtn_joysticks_with_conf[ptapi_io_piubtn_num_active_joysticks].conf = + &ptapi_io_piubtn_joystick_util_conf->entries[j]; + ptapi_io_piubtn_num_active_joysticks++; + } + } + } + + // Open all joysticks with a matching configuration + + log_debug("Opening %d joysticks...", ptapi_io_piubtn_num_active_joysticks); + + for (size_t i = 0; i < ptapi_io_piubtn_num_active_joysticks; i++) { + + if (!io_util_joystick_open(ptapi_io_piubtn_joysticks_with_conf[i].conf->dev_path, + &ptapi_io_piubtn_joysticks_with_conf[i].joystick)) { + log_warn("Could not open joystick %s -> %s, ignoring", ptapi_io_piubtn_joysticks_with_conf[i].conf->name, + ptapi_io_piubtn_joysticks_with_conf[i].conf->dev_path); + } else { + log_info("Opened joystick %s -> %s", ptapi_io_piubtn_joysticks_with_conf[i].conf->name, + ptapi_io_piubtn_joysticks_with_conf[i].conf->dev_path); + } + } + + return true; +} + +void ptapi_io_piubtn_close(void) +{ + free(ptapi_io_piubtn_joystick_util_conf); + + for (size_t i = 0; i < ptapi_io_piubtn_num_active_joysticks; i++) { + if (ptapi_io_piubtn_joysticks_with_conf[i].joystick) { + io_util_joystick_close(ptapi_io_piubtn_joysticks_with_conf[i].joystick); + } + } +} + +bool ptapi_io_piubtn_recv(void) +{ + bool success; + + success = true; + + for (size_t i = 0; i < ptapi_io_piubtn_num_active_joysticks; i++) { + if (ptapi_io_piubtn_joysticks_with_conf[i].joystick) { + success = io_util_joystick_update(ptapi_io_piubtn_joysticks_with_conf[i].joystick); + + if (!success) { + log_error("Updating joystick %s -> %s failed", ptapi_io_piubtn_joysticks_with_conf[i].conf->name, + ptapi_io_piubtn_joysticks_with_conf[i].conf->dev_path); + } + } + } + + return success; +} + +bool ptapi_io_piubtn_send(void) +{ + return true; +} + +void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* inputs) +{ + if (player == 0) { + inputs->start = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_START); + inputs->back = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_BACK); + inputs->left = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_LEFT); + inputs->right = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P1_RIGHT); + } else { + inputs->start = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_START); + inputs->back = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_BACK); + inputs->left = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_LEFT); + inputs->right = ptapi_io_piubtn_merge_inputs(PTAPI_IO_PIUBTN_JOYSTICK_UTIL_CONF_INPUT_P2_RIGHT); + } +} + +void ptapi_io_piubtn_set_output(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs) +{ + /* Not supported */ +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/keyboard-conf/main.c b/src/main/ptapi/io/piubtn/keyboard-conf/main.c new file mode 100644 index 0000000..5daeb98 --- /dev/null +++ b/src/main/ptapi/io/piubtn/keyboard-conf/main.c @@ -0,0 +1,142 @@ +#include + +#include +#include + +#include "ptapi/io/piubtn/keyboard-util/keyboard-conf.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/time.h" + +#define CONFIG_FILENAME "piubtn-keyboard-conf.bin" + +static Display* display; +static Window window; + +static uint32_t keyboard_get_next_input() +{ + XEvent event; + KeySym key; + + key = 0; + + while (true) { + XNextEvent(display, &event); + + if (event.type == KeyPress) { + XLookupString(&event.xkey, 0, 0, &key, 0); + } else if (event.type == KeyRelease) { + break; + } + } + + return key; +} + +static void menu_keyboard_test() +{ + printf("Pressed + released inputs:\n"); + + while (true) { + printf("%d\n", keyboard_get_next_input()); + } +} + +static void menu_keyboard_map() +{ + struct ptapi_io_piubtn_keyboard_util_conf* config; + + if (!ptapi_io_piubtn_keyboard_util_conf_read_from_file(&config, CONFIG_FILENAME)) { + printf("Reading existing config file failed, creating new\n"); + + ptapi_io_piubtn_keyboard_util_conf_new(&config); + } else { + printf("Found existing mapping entry in config for keyboard, overwriting\n"); + } + + printf("A new window with no contents/white background is opened. Ensure to have the application focus on that " + "window to allow input capturing. Otherwise, the tool cannot capture any keyboard inputs!\n"); + + // Delay a moment to avoid picking up any previous keyboard inputs + util_time_sleep_ms(500); + + for (uint32_t i = PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_LEFT; + i < PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_COUNT; + i++) { + printf("Press button to assign to \"%s\": ", ptapi_io_piubtn_keyboard_util_conf_input_str[i]); + fflush(stdout); + + config->button_map[i] = keyboard_get_next_input(); + + printf("%d\n", config->button_map[i]); + } + + ptapi_io_piubtn_keyboard_util_conf_write_to_file(config, CONFIG_FILENAME); + + free(config); + + printf("Configuration file saved: %s\n", CONFIG_FILENAME); +} + +int main(int argc, char** argv) +{ + bool main_loop; + int screen; + + util_log_set_file("keyboard-conf.log", false); + util_log_set_level(LOG_LEVEL_ERROR); + + display = XOpenDisplay(NULL); + + if (!display) { + printf("Opening display failed\n"); + return -1; + } + + screen = DefaultScreen(display); + + window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 200, 200, 1, + BlackPixel(display, screen), WhitePixel(display, screen)); + + XSelectInput(display, window, KeyPressMask | KeyReleaseMask); + XMapWindow(display, window); + + printf("ptapi PIUBTN keyboard button mapping config tool\n"); + + main_loop = true; + + while (main_loop) { + uint32_t item; + + printf("Main menu, please select:\n"); + printf("1 > Keyboard input test\n"); + printf("2 > Configure keyboard mappings\n"); + printf("3 > Exit\n"); + printf("Select number: "); + + scanf("%d", &item); + + switch (item) { + case 1: + menu_keyboard_test(); + break; + + case 2: + menu_keyboard_map(); + break; + + case 3: + main_loop = false; + break; + + default: + printf("Invalid item chosen: %d\n", item); + break; + } + } + + XCloseDisplay(display); + + return 0; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.c b/src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.c new file mode 100644 index 0000000..a67bcf5 --- /dev/null +++ b/src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.c @@ -0,0 +1,50 @@ +#include "ptapi/io/piubtn/keyboard-util/keyboard-conf.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" + +const char* ptapi_io_piubtn_keyboard_util_conf_input_str[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_COUNT] = { + "invalid", + "P1 Left", + "P1 Right", + "P1 Start", + "P1 Back", + "P2 Left", + "P2 Right", + "P2 Start", + "P2 Back", +}; + +void ptapi_io_piubtn_keyboard_util_conf_new(struct ptapi_io_piubtn_keyboard_util_conf** conf) +{ + log_assert(conf); + + *conf = util_xmalloc(sizeof(struct ptapi_io_piubtn_keyboard_util_conf)); + memset(*conf, 0, sizeof(struct ptapi_io_piubtn_keyboard_util_conf)); +} + +bool ptapi_io_piubtn_keyboard_util_conf_read_from_file(struct ptapi_io_piubtn_keyboard_util_conf** conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + void* buffer; + size_t size; + + if (!util_file_load(path, &buffer, &size, false)) { + return false; + } + + *conf = (struct ptapi_io_piubtn_keyboard_util_conf*) buffer; + + return true; +} + +bool ptapi_io_piubtn_keyboard_util_conf_write_to_file(struct ptapi_io_piubtn_keyboard_util_conf* conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + return util_file_save(path, conf, sizeof(struct ptapi_io_piubtn_keyboard_util_conf)); +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.h b/src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.h new file mode 100644 index 0000000..65ab31c --- /dev/null +++ b/src/main/ptapi/io/piubtn/keyboard-util/keyboard-conf.h @@ -0,0 +1,33 @@ +#ifndef PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_H +#define PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_H + +#include + +#include "io/util/joystick.h" + +enum PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT { + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_INVALID = 0, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_LEFT = 1, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_RIGHT = 2, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_START = 3, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_BACK = 4, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_LEFT = 5, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_RIGHT = 6, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_START = 7, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_BACK = 8, + PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_COUNT = 9, +}; + +extern const char* ptapi_io_piubtn_keyboard_util_conf_input_str[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_COUNT]; + +struct ptapi_io_piubtn_keyboard_util_conf { + uint32_t button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_COUNT]; +}; + +void ptapi_io_piubtn_keyboard_util_conf_new(struct ptapi_io_piubtn_keyboard_util_conf** conf); + +bool ptapi_io_piubtn_keyboard_util_conf_read_from_file(struct ptapi_io_piubtn_keyboard_util_conf** conf, const char* path); + +bool ptapi_io_piubtn_keyboard_util_conf_write_to_file(struct ptapi_io_piubtn_keyboard_util_conf* conf, const char* path); + +#endif diff --git a/src/main/ptapi/io/piubtn/keyboard/keyboard.c b/src/main/ptapi/io/piubtn/keyboard/keyboard.c new file mode 100644 index 0000000..5a6a4c4 --- /dev/null +++ b/src/main/ptapi/io/piubtn/keyboard/keyboard.c @@ -0,0 +1,126 @@ +/** + * Implementation of the piubtn API. This implements keyboard wrapper to play + * (actually mainly test) any piu games supporting the piubtn IO + */ +#define LOG_MODULE "ptapi-io-piubtn-keyboard" + +#include +#include + +#include "ptapi/io/piubtn.h" +#include "ptapi/io/x11-input-hook.h" + +#include "ptapi/io/piubtn/keyboard-util/keyboard-conf.h" + +#include "util/log.h" +#include "util/proc.h" +#include "util/str.h" + +#define CONFIG_FILENAME "/piubtn-keyboard-conf.bin" +#define KEY_MAP_SIZE 0xFFFF + +struct ptapi_io_piubtn_keyboard_util_conf* ptapi_io_piubtn_keyboard_conf; + +static bool ptapi_io_piubtn_keyboard_buffer[KEY_MAP_SIZE]; + +static void _piubtn_emu_keyboard_dispatch_key_press(KeySym key); +static void _piubtn_emu_keyboard_dispatch_key_release(KeySym key); + +static const struct ptapi_io_x11_input_hook_handler _piubtn_emu_keyboard_input_hook_handler = { + .dispatch_key_press = _piubtn_emu_keyboard_dispatch_key_press, + .dispatch_key_release = _piubtn_emu_keyboard_dispatch_key_release, +}; + +const char* ptapi_io_piubtn_ident(void) +{ + return "keyboard"; +} + +const struct ptapi_io_x11_input_hook_handler* ptapi_io_x11_input_handler_hook(void) +{ + return &_piubtn_emu_keyboard_input_hook_handler; +} + +bool ptapi_io_piubtn_open() +{ + char path[PATH_MAX]; + char* config_path; + + // The game changes the working directory to the 'game' sub-folder. Therefore, ./my-config does not work here. + if (!util_proc_get_folder_path_executable_no_ld_linux(path, sizeof(path))) { + log_error("Getting executable folder path failed."); + return false; + } + + config_path = util_str_merge(path, CONFIG_FILENAME); + + if (!ptapi_io_piubtn_keyboard_util_conf_read_from_file(&ptapi_io_piubtn_keyboard_conf, config_path)) { + log_error("Loading keyboard config file %s failed.", config_path); + free(config_path); + return false; + } + + free(config_path); + + memset(ptapi_io_piubtn_keyboard_buffer, 0, sizeof(bool) * KEY_MAP_SIZE); + + return true; +} + +void ptapi_io_piubtn_close(void) +{ + free(ptapi_io_piubtn_keyboard_conf); +} + +bool ptapi_io_piubtn_recv(void) +{ + /* Nothing to poll */ + return true; +} + +bool ptapi_io_piubtn_send(void) +{ + return true; +} + +void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* inputs) +{ + if (player == 0) { + inputs->left = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_LEFT]]; + inputs->right = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_RIGHT]]; + inputs->start = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_START]]; + inputs->back = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P1_BACK]]; + } else { + inputs->left = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_LEFT]]; + inputs->right = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_RIGHT]]; + inputs->start = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_START]]; + inputs->back = ptapi_io_piubtn_keyboard_buffer[ + ptapi_io_piubtn_keyboard_conf->button_map[PTAPI_IO_PIUBTN_KEYBOARD_UTIL_CONF_INPUT_P2_BACK]]; + } +} + +void ptapi_io_piubtn_set_output(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs) +{ + /* Not supported */ +} + +static void _piubtn_emu_keyboard_dispatch_key_press(KeySym key) +{ + if (key > 0 && key < KEY_MAP_SIZE) { + ptapi_io_piubtn_keyboard_buffer[key] = true; + } +} + +static void _piubtn_emu_keyboard_dispatch_key_release(KeySym key) +{ + if (key > 0 && key < KEY_MAP_SIZE) { + ptapi_io_piubtn_keyboard_buffer[key] = false; + } +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/null/null.c b/src/main/ptapi/io/piubtn/null/null.c new file mode 100644 index 0000000..b0f6e37 --- /dev/null +++ b/src/main/ptapi/io/piubtn/null/null.c @@ -0,0 +1,42 @@ +/** + * Implementation of the piubtn API. Null driver for testing and starting piu without a real io + */ +#define LOG_MODULE "ptapi-io-piubtn-null" + +#include "ptapi/io/piubtn.h" + +const char* ptapi_io_piubtn_ident(void) +{ + return "null"; +} + +bool ptapi_io_piubtn_open(void) +{ + return true; +} + + +void ptapi_io_piubtn_close(void) +{ + +} + +bool ptapi_io_piubtn_recv(void) +{ + return true; +} + +bool ptapi_io_piubtn_send(void) +{ + return true; +} + +void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* inputs) +{ + +} + +void ptapi_io_piubtn_set_output(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs) +{ + +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/real/piubtn.c b/src/main/ptapi/io/piubtn/real/piubtn.c new file mode 100644 index 0000000..56afe59 --- /dev/null +++ b/src/main/ptapi/io/piubtn/real/piubtn.c @@ -0,0 +1,135 @@ +/** + * Implementation of the piubtn API. This implements a piubtn usb driver to + * communicate with real piubtn hardware and also shares a common interface with + * other "piubtn devices" (e.g. keyboard, custom IOs) + */ +#define LOG_MODULE "ptapi-io-piubtn-real" + +#include +#include + +#include "io/piubtn/defs.h" +#include "io/piubtn/device.h" + +#include "ptapi/io/piubtn.h" + +static uint8_t piubtn_drv_piubtn_in_buffer[PIUBTN_DRV_BUFFER_SIZE]; +static uint8_t piubtn_drv_piubtn_out_buffer[PIUBTN_DRV_BUFFER_SIZE]; + +static struct ptapi_io_piubtn_inputs piubtn_drv_piubtn_in[2]; +static struct ptapi_io_piubtn_outputs piubtn_drv_piubtn_out[2]; + +static void piubtn_drv_piubtn_copy_outputs() +{ + memset(piubtn_drv_piubtn_out_buffer, 0, + sizeof(piubtn_drv_piubtn_out_buffer)); + + /* Player 1 */ + + if (piubtn_drv_piubtn_out[0].start) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 0); + } + + if (piubtn_drv_piubtn_out[0].right) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 1); + } + + if (piubtn_drv_piubtn_out[0].left) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 2); + } + + if (piubtn_drv_piubtn_out[0].back) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 3); + } + + /* Player 2 */ + + if (piubtn_drv_piubtn_out[1].start) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 4); + } + + if (piubtn_drv_piubtn_out[1].right) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 5); + } + + if (piubtn_drv_piubtn_out[1].left) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 6); + } + + if (piubtn_drv_piubtn_out[1].back) { + piubtn_drv_piubtn_out_buffer[0] |= (1 << 7); + } +} + +static void piubtn_drv_piubtn_copy_inputs() +{ + /* Player 1 */ + piubtn_drv_piubtn_in[0].back = piubtn_drv_piubtn_in_buffer[0] & (1 << 0); + piubtn_drv_piubtn_in[0].left = piubtn_drv_piubtn_in_buffer[0] & (1 << 1); + piubtn_drv_piubtn_in[0].right = piubtn_drv_piubtn_in_buffer[0] & (1 << 2); + piubtn_drv_piubtn_in[0].start = piubtn_drv_piubtn_in_buffer[0] & (1 << 3); + + /* Player 2 */ + piubtn_drv_piubtn_in[1].back = piubtn_drv_piubtn_in_buffer[0] & (1 << 4); + piubtn_drv_piubtn_in[1].left = piubtn_drv_piubtn_in_buffer[0] & (1 << 5); + piubtn_drv_piubtn_in[1].right = piubtn_drv_piubtn_in_buffer[0] & (1 << 6); + piubtn_drv_piubtn_in[1].start = piubtn_drv_piubtn_in_buffer[0] & (1 << 7); +} + +const char* ptapi_io_piubtn_ident(void) +{ + return "piubtn"; +} + +bool ptapi_io_piubtn_open(void) +{ + return piubtn_drv_device_open(); +} + +void ptapi_io_piubtn_close(void) +{ + piubtn_drv_device_close(); +} + +bool ptapi_io_piubtn_recv(void) +{ + if (!piubtn_drv_device_read(piubtn_drv_piubtn_in_buffer, + sizeof(piubtn_drv_piubtn_in_buffer))) { + return false; + } + + /* Invert pull ups */ + for (uint8_t j = 0; j < 4; j++) { + piubtn_drv_piubtn_in_buffer[j] ^= 0xFF; + } + + piubtn_drv_piubtn_copy_inputs(); + + return true; +} + +bool ptapi_io_piubtn_send(void) +{ + piubtn_drv_piubtn_copy_outputs(); + + if (!piubtn_drv_device_write(piubtn_drv_piubtn_out_buffer, + sizeof(piubtn_drv_piubtn_out_buffer))) { + return false; + } + + return true; +} + +void ptapi_io_piubtn_get_input(uint8_t player, + struct ptapi_io_piubtn_inputs* inputs) +{ + memcpy(inputs, &piubtn_drv_piubtn_in[player], + sizeof(struct ptapi_io_piubtn_inputs)); +} + +void ptapi_io_piubtn_set_output(uint8_t player, + const struct ptapi_io_piubtn_outputs* outputs) +{ + memcpy(&piubtn_drv_piubtn_out[player], outputs, + sizeof(struct ptapi_io_piubtn_outputs)); +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/test/main.c b/src/main/ptapi/io/piubtn/test/main.c new file mode 100644 index 0000000..d3fe9f0 --- /dev/null +++ b/src/main/ptapi/io/piubtn/test/main.c @@ -0,0 +1,103 @@ +/** + * Tool to test implementations of the piubtn API + */ +#include +#include +#include +#include + +#include "ptapi/io/piubtn.h" +#include "ptapi/io/piubtn/util/lib.h" + +#include "util/log.h" + +static struct ptapi_io_piubtn_api api; + +int main(int argc, char** argv) +{ + struct ptapi_io_piubtn_inputs inputs[2]; + struct ptapi_io_piubtn_outputs outputs[2]; + + util_log_set_file("piubtn-test.log", false); + util_log_set_level(LOG_LEVEL_ERROR); + + if (argc < 2) { + printf( + "Usage: %s [debug]\n", + argv[0]); + return -1; + } + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], "debug")) { + util_log_set_level(LOG_LEVEL_DEBUG); + break; + } + } + + if (!ptapi_io_piubtn_util_lib_load(argv[1], &api)) { + printf("Loading piubtn lib %s failed\n", argv[1]); + return -2; + } + + if (!api.open()) { + return -3; + } + + for (uint8_t i = 0; i < 2; i++) { + memset(&inputs, 0, sizeof(inputs)); + memset(&outputs, 0, sizeof(outputs)); + } + + printf("Enter main loop by pressing any key (on the keyboard)\n"); + getchar(); + + while (true) { + if (!api.recv()) { + return -4; + } + + for (uint8_t i = 0; i < 2; i++) { + api.get_input(i, &inputs[i]); + } + + if (inputs[0].start && inputs[1].start) { + break; + } + + system("clear"); + + printf("Press p1 start + p2 start to exit\n"); + printf( + "|-------------------|\n" + "| %d %d |\n" + "|%d %d %d %d|\n" + "| %d %d |\n" + "|-------------------|\n", + inputs[0].back, inputs[1].back, + inputs[0].left, inputs[0].right, inputs[1].left, inputs[1].right, + inputs[0].start, inputs[1].start); + + for (int i = 0; i < 2; i++) { + memset(&outputs[i], 0, sizeof(outputs[i])); + + inputs[i].start = outputs[i].start; + inputs[i].back = outputs[i].back; + inputs[i].left = outputs[i].left; + inputs[i].right = outputs[i].right; + + api.set_output(i, &outputs[i]); + } + + if (!api.send()) { + return -5; + } + + /* Avoid hardware banging */ + usleep(1000); + } + + api.close(); + + return 0; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/util/lib.c b/src/main/ptapi/io/piubtn/util/lib.c new file mode 100644 index 0000000..94934a3 --- /dev/null +++ b/src/main/ptapi/io/piubtn/util/lib.c @@ -0,0 +1,34 @@ +#include + +#include "capnhook/hook/lib.h" + +#include "ptapi/io/piubtn/util/lib.h" + +bool ptapi_io_piubtn_util_lib_load(const char* path, struct ptapi_io_piubtn_api* api) +{ + void* handle; + + handle = cnh_lib_load(path); + + if (handle == NULL) { + return false; + } + + api->ident = (ptapi_io_piubtn_ident_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piubtn_ident"); + + api->open = (ptapi_io_piubtn_open_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piubtn_open"); + api->close = (ptapi_io_piubtn_close_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piubtn_close"); + api->recv = (ptapi_io_piubtn_recv_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piubtn_recv"); + api->send = (ptapi_io_piubtn_send_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piubtn_send"); + api->get_input = (ptapi_io_piubtn_get_input_t) + cnh_lib_get_func_addr_handle(handle, "ptapi_io_piubtn_get_input"); + api->set_output = (ptapi_io_piubtn_set_output_t) + cnh_lib_get_func_addr_handle(handle, "ptapi_io_piubtn_set_output"); + + return true; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piubtn/util/lib.h b/src/main/ptapi/io/piubtn/util/lib.h new file mode 100644 index 0000000..c8adcbc --- /dev/null +++ b/src/main/ptapi/io/piubtn/util/lib.h @@ -0,0 +1,8 @@ +#ifndef PTAPI_IO_PIUBTN_UTIL_LIB_H +#define PTAPI_IO_PIUBTN_UTIL_LIB_H + +#include "ptapi/io/piubtn.h" + +bool ptapi_io_piubtn_util_lib_load(const char* path, struct ptapi_io_piubtn_api* api); + +#endif diff --git a/src/main/ptapi/io/piuio/joystick-conf/main.c b/src/main/ptapi/io/piuio/joystick-conf/main.c new file mode 100644 index 0000000..6e3dc66 --- /dev/null +++ b/src/main/ptapi/io/piuio/joystick-conf/main.c @@ -0,0 +1,254 @@ +#include +#include + +#include "io/util/joystick.h" +#include "io/util/joystick-util.h" + +#include "ptapi/io/piuio/joystick-util/joystick-conf.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/time.h" + +#define MAX_JOYSTICKS 16 +#define CONFIG_FILENAME "piuio-joystick-conf.bin" +#define SKIP_INPUT 0xFFFF + +int kbhit() +{ + struct timeval tv = { 0L, 0L }; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); + + return select(1, &fds, NULL, NULL, &tv); +} + +int getch() +{ + int r; + unsigned char c; + + if ((r = read(0, &c, sizeof(c))) < 0) { + return r; + } else { + return c; + } +} + +static uint16_t joystick_get_next_input(struct io_util_joystick* joystick) +{ + bool pressed; + uint16_t button; + + pressed = false; + button = 0; + + while (true) { + if (!io_util_joystick_update(joystick)) { + printf("Error updating joystick failed.\n"); + exit(-1); + } + + // Allow skip-able input assignment via enter key on keyboard + if (kbhit() > 0) { + if (getch() == '\n') { + return SKIP_INPUT; + } + } + + if (!pressed) { + for (uint16_t j = 0; j < joystick->num_buttons; j++) { + if (io_util_joystick_is_button_pressed(joystick, j)) { + button = j; + pressed = true; + break; + } + } + } else { + // Wait for release of pressed input -> debouncing + if (!io_util_joystick_is_button_pressed(joystick, button)) { + break; + } + } + + util_time_sleep_ms(10); + } + + return button; +} + +static void menu_joystick_test() +{ + struct io_util_joystick_util_device_info dev_info[MAX_JOYSTICKS]; + size_t connected_joysticks; + + connected_joysticks = io_util_joystick_util_scan(dev_info, MAX_JOYSTICKS); + + printf("Connected joysticks: %d\n", connected_joysticks); + + for (size_t i = 0; i < connected_joysticks; i++) { + printf("%d: %s -> %s, buttons %d, axes %d\n", + i, dev_info[i].name, dev_info[i].dev_path, dev_info[i].num_buttons, dev_info[i].num_axes); + } + + size_t selected_device_idx; + + printf("Select device: "); + scanf("%d", &selected_device_idx); + + if (selected_device_idx > connected_joysticks) { + printf("Invalid device id %d, out of range\n", selected_device_idx); + return; + } + + struct io_util_joystick* joystick; + + if (!io_util_joystick_open(dev_info[selected_device_idx].dev_path, &joystick)) { + printf("Error opening device %s -> %s", dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path); + return; + } + + printf("Pressed + released inputs:\n"); + + while (true) { + printf("%d\n", joystick_get_next_input(joystick)); + } + + io_util_joystick_close(joystick); +} + +static void menu_joystick_map() +{ + struct ptapi_io_piuio_joystick_util_conf* config; + struct ptapi_io_piuio_joystick_util_conf_entry config_entry; + + struct io_util_joystick_util_device_info dev_info[MAX_JOYSTICKS]; + size_t connected_joysticks; + struct io_util_joystick* joystick; + + connected_joysticks = io_util_joystick_util_scan(dev_info, MAX_JOYSTICKS); + + printf("Connected joysticks: %d\n", connected_joysticks); + + for (size_t i = 0; i < connected_joysticks; i++) { + printf("%d: %s -> %s, buttons %d, axes %d\n", + i, dev_info[i].name, dev_info[i].dev_path, dev_info[i].num_buttons, dev_info[i].num_axes); + } + + size_t selected_device_idx; + + printf("Select device: "); + scanf("%d", &selected_device_idx); + + if (selected_device_idx > connected_joysticks) { + printf("Invalid device id %d, out of range\n", selected_device_idx); + return; + } + + if (!ptapi_io_piuio_joystick_util_conf_read_from_file(&config, CONFIG_FILENAME)) { + printf("Reading existing config file failed, creating new\n"); + + ptapi_io_piuio_joystick_util_conf_new(&config); + + memset(&config_entry, 0, sizeof(struct ptapi_io_piuio_joystick_util_conf_entry)); + + strcpy(config_entry.dev_path, dev_info[selected_device_idx].dev_path); + strcpy(config_entry.name, dev_info[selected_device_idx].name); + } else { + if (!ptapi_io_piuio_joystick_util_conf_find_entry(config, dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path, &config_entry)) { + printf("Could not find existing mapping entry in config for joystick, creating new one\n"); + + memset(&config_entry, 0, sizeof(struct ptapi_io_piuio_joystick_util_conf_entry)); + + strcpy(config_entry.dev_path, dev_info[selected_device_idx].dev_path); + strcpy(config_entry.name, dev_info[selected_device_idx].name); + } else { + printf("Found existing mapping entry in config for joystick, overwriting\n"); + } + } + + printf("Configuring device %s -> %s\n", dev_info[selected_device_idx].name, dev_info[selected_device_idx].dev_path); + + if (!io_util_joystick_open(dev_info[selected_device_idx].dev_path, &joystick)) { + printf("Error opening device %s -> %s", dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path); + return; + } + + for (uint32_t i = PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_LU; i < PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COUNT; + i++) { + printf("Press button to assign to \"%s\" or Enter/Return to skip: ", ptapi_io_piuio_joystick_util_conf_input_str[i]); + fflush(stdout); + + config_entry.button_map[i] = joystick_get_next_input(joystick); + + if (config_entry.button_map[i] == SKIP_INPUT) { + printf("SKIP\n"); + } else { + printf("%d\n", config_entry.button_map[i]); + } + } + + io_util_joystick_close(joystick); + + printf("Configuration of device %s -> %s done\n", dev_info[selected_device_idx].name, + dev_info[selected_device_idx].dev_path); + + if (!ptapi_io_piuio_joystick_util_conf_set_entry(config, &config_entry)) { + ptapi_io_piuio_joystick_util_conf_append_entry(&config, &config_entry); + } + + ptapi_io_piuio_joystick_util_conf_write_to_file(config, CONFIG_FILENAME); + + free(config); + + printf("Configuration file saved: %s\n", CONFIG_FILENAME); +} + +int main(int argc, char** argv) +{ + bool main_loop; + + util_log_set_file("joystick-conf.log", false); + util_log_set_level(LOG_LEVEL_ERROR); + + printf("ptapi PIUIO joystick button mapping config tool\n"); + + main_loop = true; + + while (main_loop) { + uint32_t item; + + printf("Main menu, please select:\n"); + printf("1 > Joystick input test\n"); + printf("2 > Configure joystick mappings\n"); + printf("3 > Exit\n"); + printf("Select number: "); + + scanf("%d", &item); + + switch (item) { + case 1: + menu_joystick_test(); + break; + + case 2: + menu_joystick_map(); + break; + + case 3: + main_loop = false; + break; + + default: + printf("Invalid item chosen: %d\n", item); + break; + } + } + + return 0; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/joystick-util/joystick-conf.c b/src/main/ptapi/io/piuio/joystick-util/joystick-conf.c new file mode 100644 index 0000000..9216923 --- /dev/null +++ b/src/main/ptapi/io/piuio/joystick-util/joystick-conf.c @@ -0,0 +1,106 @@ +#include "ptapi/io/piuio/joystick-util/joystick-conf.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" + +const char* ptapi_io_piuio_joystick_util_conf_input_str[PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COUNT] = { + "invalid", + "P1 Left Up", + "P1 Right Up", + "P1 Center", + "P1 Left Down", + "P1 Right Down", + "P2 Left Up", + "P2 Right Up", + "P2 Center", + "P2 Left Down", + "P2 Right Down", + "Service", + "Test", + "Coin Clear", + "Coin", + "Coin 2" +}; + +void ptapi_io_piuio_joystick_util_conf_new(struct ptapi_io_piuio_joystick_util_conf** conf) +{ + log_assert(conf); + + *conf = util_xmalloc(sizeof(struct ptapi_io_piuio_joystick_util_conf)); + (*conf)->num_entries = 0; +} + +bool ptapi_io_piuio_joystick_util_conf_read_from_file(struct ptapi_io_piuio_joystick_util_conf** conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + void* buffer; + size_t size; + + if (!util_file_load(path, &buffer, &size, false)) { + return false; + } + + *conf = (struct ptapi_io_piuio_joystick_util_conf*) buffer; + + return true; +} + +bool ptapi_io_piuio_joystick_util_conf_write_to_file(struct ptapi_io_piuio_joystick_util_conf* conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + return util_file_save(path, conf, sizeof(struct ptapi_io_piuio_joystick_util_conf) + + sizeof(struct ptapi_io_piuio_joystick_util_conf_entry) * conf->num_entries); +} + +bool ptapi_io_piuio_joystick_util_conf_set_entry(struct ptapi_io_piuio_joystick_util_conf* conf, + struct ptapi_io_piuio_joystick_util_conf_entry* entry) +{ + log_assert(conf); + log_assert(entry); + + for (size_t i = 0; i < conf->num_entries; i++) { + if (!strcmp(conf->entries[i].name, entry->name) && !strcmp(conf->entries[i].dev_path, entry->dev_path)) { + memcpy(&conf->entries[i], entry, sizeof(struct ptapi_io_piuio_joystick_util_conf_entry)); + return true; + } + } + + return false; +} + +void ptapi_io_piuio_joystick_util_conf_append_entry(struct ptapi_io_piuio_joystick_util_conf** conf, + struct ptapi_io_piuio_joystick_util_conf_entry* entry) +{ + log_assert(conf); + log_assert(entry); + + (*conf)->num_entries++; + + *conf = util_xrealloc(*conf, sizeof(struct ptapi_io_piuio_joystick_util_conf*) + + sizeof(struct ptapi_io_piuio_joystick_util_conf_entry) * (*conf)->num_entries); + + memcpy(&(*conf)->entries[(*conf)->num_entries - 1], entry, sizeof(struct ptapi_io_piuio_joystick_util_conf_entry)); +}; + +bool ptapi_io_piuio_joystick_util_conf_find_entry(struct ptapi_io_piuio_joystick_util_conf* conf, const char* name, + const char* dev_path, struct ptapi_io_piuio_joystick_util_conf_entry* entry) +{ + log_assert(name); + log_assert(dev_path); + log_assert(entry); + + for (size_t i = 0; i < conf->num_entries; i++) { + if (!strcmp(conf->entries[i].name, name) && !strcmp(conf->entries[i].dev_path, dev_path)) { + memcpy(entry, &conf->entries[i], sizeof(struct ptapi_io_piuio_joystick_util_conf_entry)); + + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/joystick-util/joystick-conf.h b/src/main/ptapi/io/piuio/joystick-util/joystick-conf.h new file mode 100644 index 0000000..094d768 --- /dev/null +++ b/src/main/ptapi/io/piuio/joystick-util/joystick-conf.h @@ -0,0 +1,57 @@ +#ifndef PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_H +#define PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_H + +#include + +#include "io/util/joystick.h" + +enum PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT { + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_INVALID = 0, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_LU = 1, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_RU = 2, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_CN = 3, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_LD = 4, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_RD = 5, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_LU = 6, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_RU = 7, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_CN = 8, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_LD = 9, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_RD = 10, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_SERVICE = 11, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_TEST = 12, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_CLEAR = 13, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COIN = 14, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COIN2 = 15, + PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COUNT = 16, +}; + +extern const char* ptapi_io_piuio_joystick_util_conf_input_str[PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COUNT]; + +struct ptapi_io_piuio_joystick_util_conf_entry { + char name[JOYSTICK_NAME_LEN]; + char dev_path[PATH_MAX]; + + uint16_t button_map[PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COUNT]; +}; + +struct ptapi_io_piuio_joystick_util_conf { + size_t num_entries; + struct ptapi_io_piuio_joystick_util_conf_entry entries[]; +}; + +void ptapi_io_piuio_joystick_util_conf_new(struct ptapi_io_piuio_joystick_util_conf** conf); + +bool ptapi_io_piuio_joystick_util_conf_read_from_file(struct ptapi_io_piuio_joystick_util_conf** conf, const char* path); + +bool ptapi_io_piuio_joystick_util_conf_write_to_file(struct ptapi_io_piuio_joystick_util_conf* conf, const char* path); + +bool ptapi_io_piuio_joystick_util_conf_set_entry(struct ptapi_io_piuio_joystick_util_conf* conf, + struct ptapi_io_piuio_joystick_util_conf_entry* entry); + +void ptapi_io_piuio_joystick_util_conf_append_entry(struct ptapi_io_piuio_joystick_util_conf** conf, + struct ptapi_io_piuio_joystick_util_conf_entry* entry); + +bool ptapi_io_piuio_joystick_util_conf_find_entry(struct ptapi_io_piuio_joystick_util_conf* conf, const char* name, + const char* dev_path, struct ptapi_io_piuio_joystick_util_conf_entry* entry); + +#endif diff --git a/src/main/ptapi/io/piuio/joystick/joystick.c b/src/main/ptapi/io/piuio/joystick/joystick.c new file mode 100644 index 0000000..5ad3663 --- /dev/null +++ b/src/main/ptapi/io/piuio/joystick/joystick.c @@ -0,0 +1,195 @@ +/** + * Implementation of the piuio API to use the game with joysticks/gamepads. + */ +#define LOG_MODULE "ptapi-io-piuio-joystick" + +#include "io/util/joystick.h" +#include "io/util/joystick-util.h" + +#include "ptapi/io/piuio.h" + +#include "ptapi/io/piuio/joystick-util/joystick-conf.h" + +#include "util/log.h" +#include "util/proc.h" +#include "util/str.h" + +#define MAX_NUM_JOYSTICKS 16 +#define CONFIG_FILENAME "/piuio-joystick-conf.bin" + +struct ptapi_io_piuio_joystick_with_conf { + struct ptapi_io_piuio_joystick_util_conf_entry* conf; + struct io_util_joystick* joystick; +}; + +static struct ptapi_io_piuio_joystick_util_conf* ptapi_io_piuio_joystick_util_conf; +static struct ptapi_io_piuio_joystick_with_conf ptapi_io_piuio_joysticks_with_conf[MAX_NUM_JOYSTICKS]; +static size_t ptapi_io_piuio_num_active_joysticks; + +static bool ptapi_io_piuio_merge_inputs(enum PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT input) +{ + bool pressed; + + pressed = false; + + for (size_t i = 0; i < ptapi_io_piuio_num_active_joysticks; i++) { + if (ptapi_io_piuio_joysticks_with_conf[i].joystick) { + pressed = pressed || + io_util_joystick_is_button_pressed( + ptapi_io_piuio_joysticks_with_conf[i].joystick, + ptapi_io_piuio_joysticks_with_conf[i].conf->button_map[input]); + } + } + + return pressed; +} + +const char* ptapi_io_piuio_ident(void) +{ + return "joystick"; +} + +bool ptapi_io_piuio_open() +{ + char path[PATH_MAX]; + char* config_path; + struct io_util_joystick_util_device_info device_info[MAX_NUM_JOYSTICKS]; + size_t devices_connected; + + // The game changes the working directory to the 'game' sub-folder. Therefore, ./my-config does not work here. + if (!util_proc_get_folder_path_executable_no_ld_linux(path, sizeof(path))) { + log_error("Getting executable folder path failed."); + return false; + } + + config_path = util_str_merge(path, CONFIG_FILENAME); + + log_info("Loading configuration: ", config_path); + + if (!ptapi_io_piuio_joystick_util_conf_read_from_file(&ptapi_io_piuio_joystick_util_conf, config_path)) { + log_error("Loading joystick config file %s failed.", CONFIG_FILENAME); + free(config_path); + return false; + } + + free(config_path); + + devices_connected = io_util_joystick_util_scan(device_info, MAX_NUM_JOYSTICKS); + + log_debug("Found connected joysticks: %d", devices_connected); + + ptapi_io_piuio_num_active_joysticks = 0; + + memset(ptapi_io_piuio_joysticks_with_conf, 0, sizeof(struct ptapi_io_piuio_joystick_with_conf) * MAX_NUM_JOYSTICKS); + + for (size_t i = 0; i < devices_connected; i++) { + log_debug("%d: %s -> %s, buttons %d, axes %d\n", + i, device_info[i].name, device_info[i].dev_path, device_info[i].num_buttons, device_info[i].num_axes); + + // Find a matching configuration + for (size_t j = 0; j < ptapi_io_piuio_joystick_util_conf->num_entries; j++) { + + if (!strcmp(ptapi_io_piuio_joystick_util_conf->entries[j].name, device_info[i].name) && + !strcmp(ptapi_io_piuio_joystick_util_conf->entries[j].dev_path, device_info[i].dev_path)) { + log_debug("Found matching configuration for %s -> %s", device_info[i].name, device_info[i].dev_path); + + ptapi_io_piuio_joysticks_with_conf[ptapi_io_piuio_num_active_joysticks].conf = + &ptapi_io_piuio_joystick_util_conf->entries[j]; + ptapi_io_piuio_num_active_joysticks++; + } + } + } + + // Open all joysticks with a matching configuration + + log_debug("Opening %d joysticks...", ptapi_io_piuio_num_active_joysticks); + + for (size_t i = 0; i < ptapi_io_piuio_num_active_joysticks; i++) { + + if (!io_util_joystick_open(ptapi_io_piuio_joysticks_with_conf[i].conf->dev_path, + &ptapi_io_piuio_joysticks_with_conf[i].joystick)) { + log_warn("Could not open joystick %s -> %s, ignoring", ptapi_io_piuio_joysticks_with_conf[i].conf->name, + ptapi_io_piuio_joysticks_with_conf[i].conf->dev_path); + } else { + log_info("Opened joystick %s -> %s", ptapi_io_piuio_joysticks_with_conf[i].conf->name, + ptapi_io_piuio_joysticks_with_conf[i].conf->dev_path); + } + } + + return true; +} + +void ptapi_io_piuio_close(void) +{ + free(ptapi_io_piuio_joystick_util_conf); + + for (size_t i = 0; i < ptapi_io_piuio_num_active_joysticks; i++) { + if (ptapi_io_piuio_joysticks_with_conf[i].joystick) { + io_util_joystick_close(ptapi_io_piuio_joysticks_with_conf[i].joystick); + } + } +} + +bool ptapi_io_piuio_recv(void) +{ + bool success; + + success = true; + + for (size_t i = 0; i < ptapi_io_piuio_num_active_joysticks; i++) { + if (ptapi_io_piuio_joysticks_with_conf[i].joystick) { + success = io_util_joystick_update(ptapi_io_piuio_joysticks_with_conf[i].joystick); + + if (!success) { + log_error("Updating joystick %s -> %s failed", ptapi_io_piuio_joysticks_with_conf[i].conf->name, + ptapi_io_piuio_joysticks_with_conf[i].conf->dev_path); + } + } + } + + return success; +} + +bool ptapi_io_piuio_send(void) +{ + /* Not supported */ + + return true; +} + +void ptapi_io_piuio_get_input_pad(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs) +{ + if (player == 0) { + inputs->lu = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_LU); + inputs->ru = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_RU); + inputs->cn = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_CN); + inputs->ld = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_LD); + inputs->rd = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P1_RD); + } else { + inputs->lu = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_LU); + inputs->ru = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_RU); + inputs->cn = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_CN); + inputs->ld = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_LD); + inputs->rd = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_P2_RD); + } +} + +void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs) +{ + inputs->test = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_TEST); + inputs->service = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_SERVICE); + inputs->clear = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_CLEAR); + inputs->coin = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COIN); + inputs->coin2 = ptapi_io_piuio_merge_inputs(PTAPI_IO_PIUIO_JOYSTICK_UTIL_CONF_INPUT_COIN2); +} + +void ptapi_io_piuio_set_output_pad(uint8_t player, const struct ptapi_io_piuio_pad_outputs* outputs) +{ + /* Not supported */ +} + +void ptapi_io_piuio_set_output_cab(const struct ptapi_io_piuio_cab_outputs* outputs) +{ + /* Not supported */ +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/keyboard-conf/main.c b/src/main/ptapi/io/piuio/keyboard-conf/main.c new file mode 100644 index 0000000..34169df --- /dev/null +++ b/src/main/ptapi/io/piuio/keyboard-conf/main.c @@ -0,0 +1,147 @@ +#include + +#include +#include + +#include "ptapi/io/piuio/keyboard-util/keyboard-conf.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/time.h" + +#define CONFIG_FILENAME "piuio-keyboard-conf.bin" + +static Display* display; +static Window window; + +static uint32_t keyboard_get_next_input() +{ + XEvent event; + KeySym key; + + key = 0; + + while (true) { + XNextEvent(display, &event); + + if (event.type == KeyPress) { + XLookupString(&event.xkey, 0, 0, &key, 0); + } else if (event.type == KeyRelease) { + break; + } + } + + return key; +} + +static void menu_keyboard_test() +{ + printf("Pressed + released inputs:\n"); + + while (true) { + printf("%d\n", keyboard_get_next_input()); + } +} + +static void menu_keyboard_map() +{ + struct ptapi_io_piuio_keyboard_util_conf* config; + + if (!ptapi_io_piuio_keyboard_util_conf_read_from_file(&config, CONFIG_FILENAME)) { + printf("Reading existing config file failed, creating new\n"); + + ptapi_io_piuio_keyboard_util_conf_new(&config); + } else { + printf("Found existing mapping entry in config for keyboard, overwriting\n"); + } + + printf("A new window with no contents/white background is opened. Ensure to have the application focus on that " + "window to allow input capturing. Otherwise, the tool cannot capture any keyboard inputs!\n"); + + // Delay a moment to avoid picking up any previous keyboard inputs + util_time_sleep_ms(500); + + for (uint32_t i = PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_LU; i < PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COUNT; + i++) { + printf("Press button to assign to \"%s\" or 'Enter/Return' to skip: ", + ptapi_io_piuio_keyboard_util_conf_input_str[i]); + fflush(stdout); + + config->button_map[i] = keyboard_get_next_input(); + + if (config->button_map[i] == XK_Return) { + config->button_map[i] = 0; + printf("SKIP\n"); + } else { + printf("%d\n", config->button_map[i]); + } + } + + ptapi_io_piuio_keyboard_util_conf_write_to_file(config, CONFIG_FILENAME); + + free(config); + + printf("Configuration file saved: %s\n", CONFIG_FILENAME); +} + +int main(int argc, char** argv) +{ + bool main_loop; + int screen; + + util_log_set_file("keyboard-conf.log", false); + util_log_set_level(LOG_LEVEL_ERROR); + + display = XOpenDisplay(NULL); + + if (!display) { + printf("Opening display failed\n"); + return -1; + } + + screen = DefaultScreen(display); + + window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 200, 200, 1, + BlackPixel(display, screen), WhitePixel(display, screen)); + + XSelectInput(display, window, KeyPressMask | KeyReleaseMask); + XMapWindow(display, window); + + printf("ptapi PIUIO keyboard button mapping config tool\n"); + + main_loop = true; + + while (main_loop) { + uint32_t item; + + printf("Main menu, please select:\n"); + printf("1 > Keyboard input test\n"); + printf("2 > Configure keyboard mappings\n"); + printf("3 > Exit\n"); + printf("Select number: "); + + scanf("%d", &item); + + switch (item) { + case 1: + menu_keyboard_test(); + break; + + case 2: + menu_keyboard_map(); + break; + + case 3: + main_loop = false; + break; + + default: + printf("Invalid item chosen: %d\n", item); + break; + } + } + + XCloseDisplay(display); + + return 0; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.c b/src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.c new file mode 100644 index 0000000..604936e --- /dev/null +++ b/src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.c @@ -0,0 +1,57 @@ +#include "ptapi/io/piuio/keyboard-util/keyboard-conf.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" + +const char* ptapi_io_piuio_keyboard_util_conf_input_str[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COUNT] = { + "invalid", + "P1 Left Up", + "P1 Right Up", + "P1 Center", + "P1 Left Down", + "P1 Right Down", + "P2 Left Up", + "P2 Right Up", + "P2 Center", + "P2 Left Down", + "P2 Right Down", + "Service", + "Test", + "Coin Clear", + "Coin", + "Coin 2" +}; + +void ptapi_io_piuio_keyboard_util_conf_new(struct ptapi_io_piuio_keyboard_util_conf** conf) +{ + log_assert(conf); + + *conf = util_xmalloc(sizeof(struct ptapi_io_piuio_keyboard_util_conf)); + memset(*conf, 0, sizeof(struct ptapi_io_piuio_keyboard_util_conf)); +} + +bool ptapi_io_piuio_keyboard_util_conf_read_from_file(struct ptapi_io_piuio_keyboard_util_conf** conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + void* buffer; + size_t size; + + if (!util_file_load(path, &buffer, &size, false)) { + return false; + } + + *conf = (struct ptapi_io_piuio_keyboard_util_conf*) buffer; + + return true; +} + +bool ptapi_io_piuio_keyboard_util_conf_write_to_file(struct ptapi_io_piuio_keyboard_util_conf* conf, const char* path) +{ + log_assert(path); + log_assert(conf); + + return util_file_save(path, conf, sizeof(struct ptapi_io_piuio_keyboard_util_conf)); +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.h b/src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.h new file mode 100644 index 0000000..79f63fb --- /dev/null +++ b/src/main/ptapi/io/piuio/keyboard-util/keyboard-conf.h @@ -0,0 +1,40 @@ +#ifndef PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_H +#define PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_H + +#include + +#include "io/util/joystick.h" + +enum PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT { + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_INVALID = 0, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_LU = 1, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_RU = 2, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_CN = 3, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_LD = 4, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_RD = 5, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_LU = 6, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_RU = 7, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_CN = 8, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_LD = 9, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_RD = 10, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_SERVICE = 11, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_TEST = 12, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_CLEAR = 13, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COIN = 14, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COIN2 = 15, + PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COUNT = 16, +}; + +extern const char* ptapi_io_piuio_keyboard_util_conf_input_str[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COUNT]; + +struct ptapi_io_piuio_keyboard_util_conf { + uint32_t button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COUNT]; +}; + +void ptapi_io_piuio_keyboard_util_conf_new(struct ptapi_io_piuio_keyboard_util_conf** conf); + +bool ptapi_io_piuio_keyboard_util_conf_read_from_file(struct ptapi_io_piuio_keyboard_util_conf** conf, const char* path); + +bool ptapi_io_piuio_keyboard_util_conf_write_to_file(struct ptapi_io_piuio_keyboard_util_conf* conf, const char* path); + +#endif diff --git a/src/main/ptapi/io/piuio/keyboard/keyboard.c b/src/main/ptapi/io/piuio/keyboard/keyboard.c new file mode 100644 index 0000000..0adf510 --- /dev/null +++ b/src/main/ptapi/io/piuio/keyboard/keyboard.c @@ -0,0 +1,151 @@ +/** + * Implementation of the piuio API. This implements keyboard wrapper to play + * (actually mainly test) any piu games supporting a (mk6) usb piuio + */ +#define LOG_MODULE "ptapi-io-piuio-keyboard" + +#include + +#include "ptapi/io/piuio.h" +#include "ptapi/io/x11-input-hook.h" + +#include "ptapi/io/piuio/keyboard-util/keyboard-conf.h" + +#include "util/log.h" +#include "util/proc.h" +#include "util/str.h" + +#define CONFIG_FILENAME "/piuio-keyboard-conf.bin" +#define KEY_MAP_SIZE 0xFFFF + +struct ptapi_io_piuio_keyboard_util_conf* ptapi_io_piuio_keyboard_conf; + +static bool ptapi_io_piuio_keyboard_buffer[KEY_MAP_SIZE]; + +static void _piuio_emu_keyboard_dispatch_key_press(KeySym key); +static void _piuio_emu_keyboard_dispatch_key_release(KeySym key); + +static const struct ptapi_io_x11_input_hook_handler _piuio_emu_keyboard_input_hook_handler = { + .dispatch_key_press = _piuio_emu_keyboard_dispatch_key_press, + .dispatch_key_release = _piuio_emu_keyboard_dispatch_key_release, +}; + +const char* ptapi_io_piuio_ident(void) +{ + return "keyboard"; +} + +const struct ptapi_io_x11_input_hook_handler* ptapi_io_x11_input_handler_hook(void) +{ + return &_piuio_emu_keyboard_input_hook_handler; +} + +bool ptapi_io_piuio_open() +{ + char path[PATH_MAX]; + char* config_path; + + // The game changes the working directory to the 'game' sub-folder. Therefore, ./my-config does not work here. + if (!util_proc_get_folder_path_executable_no_ld_linux(path, sizeof(path))) { + log_error("Getting executable folder path failed."); + return false; + } + + config_path = util_str_merge(path, CONFIG_FILENAME); + + log_info("Loading configuration: ", config_path); + + if (!ptapi_io_piuio_keyboard_util_conf_read_from_file(&ptapi_io_piuio_keyboard_conf, config_path)) { + log_error("Loading keyboard config file %s failed.", config_path); + free(config_path); + return false; + } + + free(config_path); + + memset(ptapi_io_piuio_keyboard_buffer, 0, sizeof(bool) * KEY_MAP_SIZE); + + return true; +} + +void ptapi_io_piuio_close(void) +{ + free(ptapi_io_piuio_keyboard_conf); +} + +bool ptapi_io_piuio_recv(void) +{ + /* Nothing to poll */ + return true; +} + +bool ptapi_io_piuio_send(void) +{ + return true; +} + +void ptapi_io_piuio_get_input_pad(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs) +{ + if (player == 0) { + inputs->lu = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_LU]]; + inputs->ru = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_RU]]; + inputs->cn = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_CN]]; + inputs->ld = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_LD]]; + inputs->rd = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P1_RD]]; + } else { + inputs->lu = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_LU]]; + inputs->ru = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_RU]]; + inputs->cn = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_CN]]; + inputs->ld = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_LD]]; + inputs->rd = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_P2_RD]]; + } +} + +void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs) +{ + inputs->test = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_TEST]]; + inputs->service = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_SERVICE]]; + inputs->clear = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_CLEAR]]; + inputs->coin = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COIN]]; + inputs->coin2 = ptapi_io_piuio_keyboard_buffer[ + ptapi_io_piuio_keyboard_conf->button_map[PTAPI_IO_PIUIO_KEYBOARD_UTIL_CONF_INPUT_COIN2]]; +} + +void ptapi_io_piuio_set_output_pad(uint8_t player, const struct ptapi_io_piuio_pad_outputs* outputs) +{ + /* Not supported */ +} + +void ptapi_io_piuio_set_output_cab(const struct ptapi_io_piuio_cab_outputs* outputs) +{ + /* Not supported */ +} + +static void _piuio_emu_keyboard_dispatch_key_press(KeySym key) +{ + if (key > 0 && key < KEY_MAP_SIZE) { + ptapi_io_piuio_keyboard_buffer[key] = true; + } +} + +static void _piuio_emu_keyboard_dispatch_key_release(KeySym key) +{ + if (key > 0 && key < KEY_MAP_SIZE) { + ptapi_io_piuio_keyboard_buffer[key] = false; + } +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/null/null.c b/src/main/ptapi/io/piuio/null/null.c new file mode 100644 index 0000000..7669052 --- /dev/null +++ b/src/main/ptapi/io/piuio/null/null.c @@ -0,0 +1,55 @@ +/** + * Implementation of the piuio API. Null driver for testing and starting piu without a real io + */ +#define LOG_MODULE "ptapi-io-piuio-null" + +#include "ptapi/io/piuio.h" + +const char* ptapi_io_piuio_ident(void) +{ + return "null"; +} + +bool ptapi_io_piuio_open(void) +{ + return true; +} + +void ptapi_io_piuio_close(void) +{ + +} + +bool ptapi_io_piuio_recv(void) +{ + return true; +} + +bool ptapi_io_piuio_send(void) +{ + return true; +} + +void ptapi_io_piuio_get_input_pad(uint8_t player, + enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs) +{ + +} + +void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs) +{ + +} + +void ptapi_io_piuio_set_output_pad(uint8_t player, + const struct ptapi_io_piuio_pad_outputs* outputs) +{ + +} + +void ptapi_io_piuio_set_output_cab( + const struct ptapi_io_piuio_cab_outputs* outputs) +{ + /* Not supported */ +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/real/piuio.c b/src/main/ptapi/io/piuio/real/piuio.c new file mode 100644 index 0000000..d3ed607 --- /dev/null +++ b/src/main/ptapi/io/piuio/real/piuio.c @@ -0,0 +1,187 @@ +/** + * Implementation of the piuio API. This implements a piuio usb driver to + * communicate with real piuio hardware and also shares a common interface with + * other "piuio devices" (e.g. keyboard, custom IOs) + */ +#define LOG_MODULE "ptapi-io-piuio-null" + +#include +#include + +#include "io/piuio/defs.h" +#include "io/piuio/device.h" + +#include "ptapi/io/piuio.h" + +static uint8_t piuio_drv_piuio_in_buffer[PIUIO_DRV_BUFFER_SIZE]; +static uint8_t piuio_drv_piuio_out_buffer[PIUIO_DRV_BUFFER_SIZE]; + +static struct ptapi_io_piuio_pad_inputs + piuio_drv_piuio_pad_in[2][PTAPI_IO_PIUIO_SENSOR_GROUP_NUM]; +static struct ptapi_io_piuio_sys_inputs piuio_drv_piuio_sys; +static struct ptapi_io_piuio_pad_outputs piuio_drv_piuio_pad_out[2]; +static struct ptapi_io_piuio_cab_outputs piuio_drv_piuio_cab_out; + +static void piuio_drv_piuio_copy_outputs(uint8_t sensor_group) +{ + memset(piuio_drv_piuio_out_buffer, 0, sizeof(piuio_drv_piuio_out_buffer)); + + /* 00 = sensor 1 (right), 01 = sensor 2 (left), 10 = sensor 3 (down), + 11 = sensor 4 (up) */ + /* Pad 1 sensor group selector */ + piuio_drv_piuio_out_buffer[0] |= sensor_group; + /* Pad 2 sensor group selector */ + piuio_drv_piuio_out_buffer[2] |= sensor_group; + + /* Set pad lights */ + for (uint8_t i = 0; i < 2; i++) { + if (piuio_drv_piuio_pad_out[i].lu) { + piuio_drv_piuio_out_buffer[i * 2] |= (1 << 2); + } + + if (piuio_drv_piuio_pad_out[i].ru) { + piuio_drv_piuio_out_buffer[i * 2] |= (1 << 3); + } + + if (piuio_drv_piuio_pad_out[i].cn) { + piuio_drv_piuio_out_buffer[i * 2] |= (1 << 4); + } + + if (piuio_drv_piuio_pad_out[i].ld) { + piuio_drv_piuio_out_buffer[i * 2] |= (1 << 5); + } + + if (piuio_drv_piuio_pad_out[i].rd) { + piuio_drv_piuio_out_buffer[i * 2] |= (1 << 6); + } + } + + /* Neons/Bass */ + if (piuio_drv_piuio_cab_out.bass) { + piuio_drv_piuio_out_buffer[1] |= (1 << 2); + } + + /* Halogens */ + if (piuio_drv_piuio_cab_out.halo_r2) { + piuio_drv_piuio_out_buffer[2] |= (1 << 7); + } + + if (piuio_drv_piuio_cab_out.halo_r1) { + piuio_drv_piuio_out_buffer[3] |= (1 << 0); + } + + if (piuio_drv_piuio_cab_out.halo_l2) { + piuio_drv_piuio_out_buffer[3] |= (1 << 1); + } + + if (piuio_drv_piuio_cab_out.halo_l1) { + piuio_drv_piuio_out_buffer[3] |= (1 << 2); + } + + // // set coin counter 1 + // piuio_drv_piuio_out_buffer[3] |= ((m_outputStates->m_counter & 0x01) << 4); + + // // set coin counter 2 (front usb enable) + // piuio_drv_piuio_out_buffer[1] |= ((m_outputStates->m_counter & 0x02) << 3); +} + +static void piuio_drv_piuio_copy_inputs(uint8_t sensor_group) +{ + /* Pad */ + for (uint8_t i = 0; i < 2; i++) { + piuio_drv_piuio_pad_in[i][sensor_group].lu = + piuio_drv_piuio_in_buffer[i * 2] & (1 << 0); + piuio_drv_piuio_pad_in[i][sensor_group].ru = + piuio_drv_piuio_in_buffer[i * 2] & (1 << 1); + piuio_drv_piuio_pad_in[i][sensor_group].cn = + piuio_drv_piuio_in_buffer[i * 2] & (1 << 2); + piuio_drv_piuio_pad_in[i][sensor_group].ld = + piuio_drv_piuio_in_buffer[i * 2] & (1 << 3); + piuio_drv_piuio_pad_in[i][sensor_group].rd = + piuio_drv_piuio_in_buffer[i * 2] & (1 << 4); + } + + /* Sys */ + piuio_drv_piuio_sys.test = piuio_drv_piuio_in_buffer[1] & (1 << 1); + piuio_drv_piuio_sys.service = piuio_drv_piuio_in_buffer[1] & (1 << 6); + piuio_drv_piuio_sys.clear = piuio_drv_piuio_in_buffer[1] & (1 << 7); + piuio_drv_piuio_sys.coin = piuio_drv_piuio_in_buffer[1] & (1 << 2); + + memset(piuio_drv_piuio_in_buffer, 0, sizeof(piuio_drv_piuio_in_buffer)); +} + +const char* ptapi_io_piuio_ident(void) +{ + return "piuio"; +} + +bool ptapi_io_piuio_open(void) +{ + return piuio_drv_device_open(); +} + +void ptapi_io_piuio_close(void) +{ + piuio_drv_device_close(); +} + +bool ptapi_io_piuio_recv(void) +{ + /* cycle all four sensor groups */ + for (uint8_t i = 0; i < PTAPI_IO_PIUIO_SENSOR_GROUP_NUM; i++) { + piuio_drv_piuio_copy_outputs(i); + + if (!piuio_drv_device_write(piuio_drv_piuio_out_buffer, + sizeof(piuio_drv_piuio_out_buffer))) { + return false; + } + + if (!piuio_drv_device_read(piuio_drv_piuio_in_buffer, + sizeof(piuio_drv_piuio_in_buffer))) { + return false; + } + + /* Invert pull ups */ + for (uint8_t j = 0; j < 4; j++) { + piuio_drv_piuio_in_buffer[j] ^= 0xFF; + } + + piuio_drv_piuio_copy_inputs(i); + } + + return true; +} + +bool ptapi_io_piuio_send(void) +{ + /* Already done in recv */ + return true; +} + +void ptapi_io_piuio_get_input_pad(uint8_t player, + enum ptapi_io_piuio_sensor_group sensor_group, + struct ptapi_io_piuio_pad_inputs* inputs) +{ + memcpy(inputs, &piuio_drv_piuio_pad_in[player][sensor_group], + sizeof(struct ptapi_io_piuio_pad_inputs)); +} + +void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs) +{ + memcpy(inputs, &piuio_drv_piuio_sys, + sizeof(struct ptapi_io_piuio_sys_inputs)); +} + +void ptapi_io_piuio_set_output_pad(uint8_t player, + const struct ptapi_io_piuio_pad_outputs* outputs) +{ + memcpy(&piuio_drv_piuio_pad_out[player], outputs, + sizeof(struct ptapi_io_piuio_pad_outputs)); +} + +void ptapi_io_piuio_set_output_cab( + const struct ptapi_io_piuio_cab_outputs* outputs) +{ + memcpy(&piuio_drv_piuio_cab_out, outputs, + sizeof(struct ptapi_io_piuio_cab_outputs)); +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/test/main.c b/src/main/ptapi/io/piuio/test/main.c new file mode 100644 index 0000000..437d681 --- /dev/null +++ b/src/main/ptapi/io/piuio/test/main.c @@ -0,0 +1,181 @@ +/** + * Tool to test implementations of the piuio API + */ +#include +#include +#include +#include + +#include "ptapi/io/piuio.h" +#include "ptapi/io/piuio/util/lib.h" + +#include "util/log.h" + +static struct ptapi_io_piuio_api api; + +int main(int argc, char** argv) +{ + struct ptapi_io_piuio_pad_inputs + pad_in[2][PTAPI_IO_PIUIO_SENSOR_GROUP_NUM]; + struct ptapi_io_piuio_sys_inputs sys_in; + struct ptapi_io_piuio_pad_outputs pad_out[2]; + struct ptapi_io_piuio_cab_outputs cab_out; + + util_log_set_file("piuio-test.log", false); + util_log_set_level(LOG_LEVEL_ERROR); + + if (argc < 2) { + printf( + "Usage: %s [debug]\n", + argv[0]); + return -1; + } + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], "debug")) { + util_log_set_level(LOG_LEVEL_DEBUG); + break; + } + } + + if (!ptapi_io_piuio_util_lib_load(argv[1], &api)) { + printf("Loading piuio lib %s failed\n", argv[1]); + return -2; + } + + if (!api.open()) { + return -3; + } + + memset(&pad_in, 0, sizeof(pad_in)); + memset(&sys_in, 0, sizeof(sys_in)); + memset(&pad_out, 0, sizeof(pad_out)); + memset(&cab_out, 0, sizeof(cab_out)); + + printf("Enter main loop by pressing any key (on the keyboard)\n"); + getchar(); + + while (true) { + if (!api.recv()) { + return -4; + } + + for (uint8_t i = 0; i < 2; i++) { + for (uint8_t j = 0; j < PTAPI_IO_PIUIO_SENSOR_GROUP_NUM; j++) { + api.get_input_pad(i, j, &pad_in[i][j]); + } + } + + api.get_input_sys(&sys_in); + + if (sys_in.test && sys_in.service) { + break; + } + + system("clear"); + + printf("Press test + service to exit\n"); + printf( + "| Test %d Service %d Clear %d Coin %d |\n" + "|-------------------||-------------------|\n" + "| %d %d || %d %d |\n" + "|%d %d %d %d||%d %d %d %d|\n" + "| %d %d || %d %d |\n" + "| %d || %d |\n" + "| %d %d || %d %d |\n" + "| %d || %d |\n" + "| %d %d || %d %d |\n" + "|%d %d %d %d||%d %d %d %d|\n" + "| %d %d || %d %d |\n" + "|-------------------||-------------------|\n", + sys_in.test, sys_in.service, sys_in.clear, sys_in.coin, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].lu, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].ru, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].lu, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].ru, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].lu, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].lu, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].ru, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].ru, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].lu, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].lu, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].ru, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].ru, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].lu, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].ru, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].lu, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].ru, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].cn, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].cn, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].cn, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].cn, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].cn, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].cn, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].cn, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].cn, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].ld, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].rd, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].ld, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_UP].rd, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].ld, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].ld, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].rd, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].rd, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].ld, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].ld, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT].rd, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT].rd, + + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].ld, + pad_in[0][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].rd, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].ld, + pad_in[1][PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN].rd); + + memset(&pad_out, 0, sizeof(pad_out)); + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < PTAPI_IO_PIUIO_SENSOR_GROUP_NUM; j++) { + if (pad_in[i][j].lu) { + pad_out[i].lu = true; + } + + if (pad_in[i][j].ru) { + pad_out[i].ru = true; + } + + if (pad_in[i][j].cn) { + pad_out[i].cn = true; + } + + if (pad_in[i][j].ld) { + pad_out[i].ld = true; + } + + if (pad_in[i][j].rd) { + pad_out[i].rd = true; + } + } + + api.set_output_pad(i, &pad_out[i]); + } + + if (!api.send()) { + return -5; + } + + /* Avoid hardware banging */ + usleep(1000); + } + + api.close(); + + return 0; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/util/lib.c b/src/main/ptapi/io/piuio/util/lib.c new file mode 100644 index 0000000..7d15d7b --- /dev/null +++ b/src/main/ptapi/io/piuio/util/lib.c @@ -0,0 +1,38 @@ +#include + +#include "capnhook/hook/lib.h" + +#include "ptapi/io/piuio/util/lib.h" + +bool ptapi_io_piuio_util_lib_load(const char* path, struct ptapi_io_piuio_api* api) +{ + void* handle; + + handle = cnh_lib_load(path); + + if (handle == NULL) { + return false; + } + + api->ident = (ptapi_io_piuio_ident_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piuio_ident"); + + api->open = (ptapi_io_piuio_open_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piuio_open"); + api->close = (ptapi_io_piuio_close_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piuio_close"); + api->recv = (ptapi_io_piuio_recv_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piuio_recv"); + api->send = (ptapi_io_piuio_send_t) cnh_lib_get_func_addr_handle( + handle, "ptapi_io_piuio_send"); + api->get_input_pad = (ptapi_io_piuio_get_input_pad_t) + cnh_lib_get_func_addr_handle(handle, "ptapi_io_piuio_get_input_pad"); + api->get_input_sys = (ptapi_io_piuio_get_input_sys_t) + cnh_lib_get_func_addr_handle(handle, "ptapi_io_piuio_get_input_sys"); + api->set_output_pad = (ptapi_io_piuio_set_output_pad_t) + cnh_lib_get_func_addr_handle(handle, "ptapi_io_piuio_set_output_pad"); + api->set_output_cab = (ptapi_io_piuio_set_output_cab_t) + cnh_lib_get_func_addr_handle(handle, "ptapi_io_piuio_set_output_cab"); + + return true; +} \ No newline at end of file diff --git a/src/main/ptapi/io/piuio/util/lib.h b/src/main/ptapi/io/piuio/util/lib.h new file mode 100644 index 0000000..e564b1a --- /dev/null +++ b/src/main/ptapi/io/piuio/util/lib.h @@ -0,0 +1,8 @@ +#ifndef PTAPI_IO_PIUIO_UTIL_LIB_H +#define PTAPI_IO_PIUIO_UTIL_LIB_H + +#include "ptapi/io/piuio.h" + +bool ptapi_io_piuio_util_lib_load(const char* path, struct ptapi_io_piuio_api* api); + +#endif diff --git a/src/main/pumpnet/client/main.c b/src/main/pumpnet/client/main.c new file mode 100644 index 0000000..143fe6d --- /dev/null +++ b/src/main/pumpnet/client/main.c @@ -0,0 +1,115 @@ +#define LOG_MODULE "pumpnet-client" + +#include +#include + +#include "asset/nx2/lib/usb-rank.h" +#include "asset/nx2/lib/usb-save.h" + +#include "pumpnet/lib/pumpnet.h" + +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" + +static void _print_usage_and_exit(const char* program_name) +{ + log_info("Usage: %s " + "", program_name); + exit(EXIT_FAILURE); +} + +static size_t _get_size_save_file(enum asset_game_version game_version) +{ + switch (game_version) { + case ASSET_GAME_VERSION_NX2: + return ASSET_NX2_USB_SAVE_SIZE; + + default: + log_die_illegal_state(); + return 0; + } +} + +static size_t _get_size_rank_file(enum asset_game_version game_version) +{ + switch (game_version) { + case ASSET_GAME_VERSION_NX2: + return ASSET_NX2_USB_RANK_SIZE; + + default: + log_die_illegal_state(); + return 0; + } +} + +static size_t _get_size_usb_file(enum asset_game_version game_version, enum pumpnet_lib_file_type file_type) +{ + switch (file_type) { + case PUMPNET_LIB_FILE_TYPE_SAVE: + return _get_size_save_file(game_version); + + case PUMPNET_LIB_FILE_TYPE_RANK: + return _get_size_rank_file(game_version); + + default: + log_die_illegal_state(); + return 0; + } +} + +int main(int argc, char** argv) +{ + util_log_set_level(LOG_LEVEL_DEBUG); + + if (argc < 8) { + _print_usage_and_exit(argv[0]); + } + + const char* server_addr = argv[1]; + const char* cmd = argv[2]; + enum asset_game_version game_version = strtol(argv[3], NULL, 10); + enum pumpnet_lib_file_type file_type = strtol(argv[4], NULL, 10); + uint64_t machine_id = strtol(argv[5], NULL, 16); + uint64_t player_ref_id = strtol(argv[6], NULL, 16); + const char* file_path = argv[7]; + + bool success; + + pumpnet_lib_init(game_version, server_addr, machine_id, NULL, true); + + if (!strcmp(cmd, "put")) { + size_t size; + void* buffer; + + if (!util_file_load(file_path, &buffer, &size, false)) { + log_error("Loading data from %s failed", file_path); + success = false; + } else { + success = pumpnet_lib_put(file_type, player_ref_id, buffer, sizeof(buffer)); + } + } else if (!strcmp(cmd, "get")) { + size_t buffer_size = _get_size_usb_file(game_version, file_type); + uint8_t* buffer = malloc(buffer_size); + + success = pumpnet_lib_get(file_type, player_ref_id, buffer, sizeof(buffer)); + + if (success) { + if (!util_file_save(file_path, buffer, buffer_size)) { + log_error("Saving data to %s, size %d failed", file_path, buffer_size); + success = false; + } + } + } else { + log_error("Invalid command %s", cmd); + success = false; + } + + pumpnet_lib_shutdown(); + + if (success) { + exit(EXIT_SUCCESS); + } else { + exit(EXIT_FAILURE); + } +} \ No newline at end of file diff --git a/src/main/pumpnet/lib/http.c b/src/main/pumpnet/lib/http.c new file mode 100644 index 0000000..91a4df5 --- /dev/null +++ b/src/main/pumpnet/lib/http.c @@ -0,0 +1,297 @@ +#define LOG_MODULE "http" + +#include +#include + +#include "util/base64.h" +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +#define MEDIA_TYPE "text/plain" +#define RECV_BUFFER_SIZE 1024 * 512 +#define CLIENT_CRT "/client-crt.pem" +#define CLIENT_KEY "/client-key.pem" +#define CA_BUNDLE_CRT "/ca-bundle-crt.pem" + +struct pumpnet_lib_http_buffer { + void* data; + size_t size; + size_t pos; +}; + +static size_t _pumpnet_lib_http_curl_cb_write_data(void* ptr, size_t size, size_t nmemb, void* ctx) +{ + struct pumpnet_lib_http_buffer* buffer; + + buffer = (struct pumpnet_lib_http_buffer*) ctx; + + if (buffer->pos == buffer->size) { + return 0; + } + + if (buffer->pos + size * nmemb >= buffer->size) { + log_error("Buffer overflow, pos %d, size %d | size %d, nmemb %d", + buffer->pos, + buffer->size, + size, + nmemb); + return 0; + } + + memcpy(buffer->data + buffer->pos, ptr, size * nmemb); + buffer->pos += size * nmemb; + + return size * nmemb; +} + +static size_t _pumpnet_lib_http_curl_cb_read_data(void* ptr, size_t size, size_t nmemb, void* ctx) +{ + struct pumpnet_lib_http_buffer* buffer; + size_t max_size; + size_t read; + + max_size = size * nmemb; + + buffer = (struct pumpnet_lib_http_buffer*) ctx; + + if (buffer->size == buffer->pos) { + return 0; + } + + if (buffer->size - buffer->pos < max_size) { + read = buffer->size - buffer->pos; + } else { + read = max_size; + } + + memcpy(ptr, buffer->data + buffer->pos, read); + + buffer->pos += read; + + return read; +} + +int _pumpnet_libcurl_debug_callback( + CURL *handle, + curl_infotype type, + char *data, + size_t size, + void *userptr) +{ + char* null_term_buffer; + + switch (type) { + case CURLINFO_TEXT: + log_debug("[CURL]: %s", data); + break; + + case CURLINFO_HEADER_IN: + case CURLINFO_HEADER_OUT: + null_term_buffer = util_xmalloc(size + 1); + memcpy(null_term_buffer, data, size); + null_term_buffer[size] = '\0'; + + log_debug("[CURL]: %d (%p), len %ld:\n%s", type, handle, size, data); + + free(null_term_buffer); + break; + case CURLINFO_DATA_IN: + case CURLINFO_DATA_OUT: + case CURLINFO_SSL_DATA_OUT: + case CURLINFO_SSL_DATA_IN: + log_debug("[CURL]: %d (%p), len %ld", type, handle, size); + break; + default: + log_die_illegal_state(); + } + + return 0; +} + +static char* pumpnet_lib_http_client_crt_path; +static char* pumpnet_lib_http_client_key_path; +static char* pumpnet_lib_http_ca_bundle_crt_path; +static bool pumpnet_lib_http_verbose_debug_log; + +void pumpnet_lib_http_init(const char* cert_dir_path, bool verbose_debug_log) +{ + if (cert_dir_path) { + char* absolute_path = util_fs_get_abs_path(cert_dir_path); + + pumpnet_lib_http_client_crt_path = util_str_merge(absolute_path, CLIENT_CRT); + pumpnet_lib_http_client_key_path = util_str_merge(absolute_path, CLIENT_KEY); + pumpnet_lib_http_ca_bundle_crt_path = util_str_merge(absolute_path, CA_BUNDLE_CRT); + + free(absolute_path); + } + + pumpnet_lib_http_verbose_debug_log = verbose_debug_log; + + log_info("Initialized, client crt %s, client key %s, ca bundle crt %s, verbose debug log %d", + pumpnet_lib_http_client_crt_path, + pumpnet_lib_http_client_key_path, + pumpnet_lib_http_ca_bundle_crt_path, + verbose_debug_log); +} + +void pumpnet_lib_http_shutdown() +{ + if (pumpnet_lib_http_client_crt_path) { + free(pumpnet_lib_http_client_crt_path); + } + + if (pumpnet_lib_http_client_key_path) { + free(pumpnet_lib_http_client_key_path); + } + + if (pumpnet_lib_http_ca_bundle_crt_path) { + free(pumpnet_lib_http_ca_bundle_crt_path); + } +} + +bool pumpnet_lib_http_get_put( + uint64_t trace_id, + const char* address, + void* send_data, + size_t send_size, + void* recv_data, + size_t recv_size, + uint32_t* http_code, + bool is_post) +{ + log_assert(address); + log_assert(send_data); + log_assert(recv_data); + log_assert(http_code); + + CURL* curl_handle; + CURLcode res; + struct pumpnet_lib_http_buffer send_buffer; + struct pumpnet_lib_http_buffer recv_buffer; + struct curl_slist* host = NULL; + + *http_code = 0; + + curl_handle = curl_easy_init(); + + if (!curl_handle) { + log_error("[%llX] Initializing curl backend failed", trace_id); + return false; + } + + send_buffer.data = util_base64_encode(send_data, send_size, &send_buffer.size); + send_buffer.pos = 0; + + recv_buffer.data = util_xmalloc(RECV_BUFFER_SIZE); + recv_buffer.size = RECV_BUFFER_SIZE; + recv_buffer.pos = 0; + + if (is_post) { + curl_easy_setopt(curl_handle, CURLOPT_POST, 1L); + } else { + curl_easy_setopt(curl_handle, CURLOPT_POST, 1L); + curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "GET"); + } + + if (pumpnet_lib_http_verbose_debug_log) { + curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curl_handle, CURLOPT_DEBUGFUNCTION, _pumpnet_libcurl_debug_callback); + } + + if (pumpnet_lib_http_client_crt_path) { + host = curl_slist_append(NULL, "pumpnet:443:185.41.243.94"); + curl_easy_setopt(curl_handle, CURLOPT_RESOLVE, host); + curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, pumpnet_lib_http_client_crt_path); + curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, pumpnet_lib_http_client_key_path); + curl_easy_setopt(curl_handle, CURLOPT_SSLKEYTYPE, "PEM"); + curl_easy_setopt(curl_handle, CURLOPT_CAINFO, pumpnet_lib_http_ca_bundle_crt_path); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1); + } + + // It seems like some libcurl revisions cut off the content after processing it using the provided + // CURLOPT_READFUNCTION if the size is not force set like this + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, send_buffer.size); + + curl_easy_setopt(curl_handle, CURLOPT_URL, address); + curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, _pumpnet_lib_http_curl_cb_read_data); + curl_easy_setopt(curl_handle, CURLOPT_READDATA, &send_buffer); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, _pumpnet_lib_http_curl_cb_write_data); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &recv_buffer); + + struct curl_slist *hs=NULL; + hs = curl_slist_append(hs, "Content-Type: " MEDIA_TYPE); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, hs); + + log_debug("[%llX][%s] %s %d %d", trace_id, address, is_post ? "POST" : "GET", send_size, recv_size); + + res = curl_easy_perform(curl_handle); + + curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, http_code); + + log_debug("[%llX][%s] %s: %d (%d %d)", + trace_id, + address, + is_post ? "POST" : "GET", + *http_code, + recv_buffer.pos, + send_buffer.pos); + + if (host) { + curl_slist_free_all(host); + } + + curl_slist_free_all(hs); + + curl_easy_cleanup(curl_handle); + + if (res != CURLE_OK) { + log_error("[%llX][%s][%d] Performing curl request failed: %s", + trace_id, + address, + is_post, + curl_easy_strerror(res)); + + free(send_buffer.data); + free(recv_buffer.data); + return false; + } + + if (send_buffer.pos != send_buffer.size) { + log_error("[%llX][%s][%d] Invalid send data size: %d != %d", + trace_id, + address, + is_post, + send_buffer.pos, + send_buffer.size); + + free(send_buffer.data); + free(recv_buffer.data); + return false; + } + + free(send_buffer.data); + + size_t recv_size_decoded; + uint8_t* tmp_recv_decoded = util_base64_decode(recv_buffer.data, recv_buffer.pos, &recv_size_decoded); + + free(recv_buffer.data); + + if (recv_size_decoded != recv_size) { + log_error("[%llX][%s][%d] Invalid recv data size: %d != %d", + trace_id, + address, + is_post, + recv_size_decoded, + recv_size); + + free(tmp_recv_decoded); + return false; + } + + memcpy(recv_data, tmp_recv_decoded, recv_size); + free(tmp_recv_decoded); + + return true; +} \ No newline at end of file diff --git a/src/main/pumpnet/lib/http.h b/src/main/pumpnet/lib/http.h new file mode 100644 index 0000000..312fb8e --- /dev/null +++ b/src/main/pumpnet/lib/http.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#define HTTP_CODE_OK 200 +#define HTTP_CODE_PRECONDITION_FAILED 412 + +void pumpnet_lib_http_init(const char* cert_dir_path, bool verbose_debug_log); + +void pumpnet_lib_http_shutdown(); + +bool pumpnet_lib_http_get_put( + uint64_t trace_id, + const char* address, + void* send_data, + size_t send_size, + void* recv_data, + size_t recv_size, + uint32_t* http_code, + bool is_post); \ No newline at end of file diff --git a/src/main/pumpnet/lib/profile-token.c b/src/main/pumpnet/lib/profile-token.c new file mode 100644 index 0000000..5ac22a9 --- /dev/null +++ b/src/main/pumpnet/lib/profile-token.c @@ -0,0 +1,44 @@ +#define LOG_MODULE "pumpnet-lib-profile-token" + +#include +#include +#include + +#include "pumpnet/lib/profile-token.h" + +#include "util/log.h" + +bool pumpnet_lib_profile_token_load(const char* path, uint64_t* profile_id) +{ + FILE* file = fopen(path, "rb"); + ssize_t size; + + if (!file) { + *profile_id = PUMPNET_LIB_PROFILE_TOKEN_INVALID; + return false; + } + + // TODO file needs to be encrypted + + fseek(file, 0, SEEK_END); + size = ftell(file); + + if (size != 8) { + fclose(file); + *profile_id = PUMPNET_LIB_PROFILE_TOKEN_INVALID; + log_error("Invalid file size (%d) for pumpnet profile %s", size, path); + return false; + } + + fseek(file, 0, SEEK_SET); + + if (fread(profile_id, 8, 1, file) != 1) { + fclose(file); + *profile_id = PUMPNET_LIB_PROFILE_TOKEN_INVALID; + log_error("Reading pumpnet profile %s failed: %s", path, strerror(errno)); + return false; + } + + fclose(file); + return true; +} \ No newline at end of file diff --git a/src/main/pumpnet/lib/profile-token.h b/src/main/pumpnet/lib/profile-token.h new file mode 100644 index 0000000..6776d19 --- /dev/null +++ b/src/main/pumpnet/lib/profile-token.h @@ -0,0 +1,15 @@ +// +// Created by on 9/16/18. +// + +#ifndef PUMPNET_LIB_PROFILE_TOKEN_H +#define PUMPNET_LIB_PROFILE_TOKEN_H + +#include +#include + +#define PUMPNET_LIB_PROFILE_TOKEN_INVALID 0xFFFFFFFFFFFFFFFF + +bool pumpnet_lib_profile_token_load(const char* path, uint64_t* profile_id); + +#endif diff --git a/src/main/pumpnet/lib/protocol.h b/src/main/pumpnet/lib/protocol.h new file mode 100644 index 0000000..a3743ca --- /dev/null +++ b/src/main/pumpnet/lib/protocol.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include "pumpnet/lib/pumpnet.h" + +#define USBPROFILE_ENDPOINT "/usbprofile/v1" + +struct pumpnet_lib_get_save_req { + uint64_t trace_id; + uint64_t machine_id; + uint64_t player_ref_id; +} __attribute__((__packed__)); + +struct pumpnet_lib_get_save_resp { + size_t size; + uint8_t data[]; +} __attribute__((__packed__)); + +struct pumpnet_lib_get_rank_req { + uint64_t trace_id; + uint64_t machine_id; + uint64_t player_ref_id; +} __attribute__((__packed__)); + +struct pumpnet_lib_get_rank_resp { + size_t size; + uint8_t data[]; +} __attribute__((__packed__)); + +struct pumpnet_lib_put_save_req { + uint64_t trace_id; + uint64_t machine_id; + uint64_t player_ref_id; + size_t size; + uint8_t data[]; +} __attribute__((__packed__)); + +struct pumpnet_lib_put_save_resp { + +} __attribute__((__packed__)); + +struct pumpnet_lib_put_rank_req { + uint64_t trace_id; + uint64_t machine_id; + uint64_t player_ref_id; + size_t size; + uint8_t data[]; +} __attribute__((__packed__)); + +struct pumpnet_lib_put_rank_resp { + +} __attribute__((__packed__)); \ No newline at end of file diff --git a/src/main/pumpnet/lib/pumpnet.c b/src/main/pumpnet/lib/pumpnet.c new file mode 100644 index 0000000..3ec46f7 --- /dev/null +++ b/src/main/pumpnet/lib/pumpnet.c @@ -0,0 +1,343 @@ +#define LOG_MODULE "pumpnet" + +#include + +#include "pumpnet/lib/http.h" +#include "pumpnet/lib/protocol.h" +#include "pumpnet/lib/pumpnet.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/rand.h" +#include "util/str.h" +#include "util/time.h" + +#define RETRY_COUNT_ON_ERROR 10 +#define RETRY_TIME_BACKOFF_MS 2000 + +static enum asset_game_version pumpnet_lib_game; +static char* pumpnet_lib_server_addr; +static uint64_t pumpnet_lib_machine_id; + +static char* pumpnet_lib_server_endpoint_save; +static char* pumpnet_lib_server_endpoint_rank; + +static char* _pumpnet_lib_get_endpoint_save(enum asset_game_version game, const char* server_addr) +{ + switch (game) { + case ASSET_GAME_VERSION_NX2: + return util_str_merge(server_addr, USBPROFILE_ENDPOINT "/nx2/save"); + + default: + log_die("Unsupported game version %d", game); + return NULL; + } +} + +static char* _pumpnet_lib_get_endpoint_rank(enum asset_game_version game, const char* server_addr) +{ + switch (game) { + case ASSET_GAME_VERSION_NX2: + return util_str_merge(server_addr, USBPROFILE_ENDPOINT "/nx2/rank"); + + default: + log_die("Unsupported game version %d", game); + return NULL; + } +} + +static uint64_t _pumpnet_lib_generate_tracing_id() +{ + return util_rand_gen_64(); +} + +static bool _pumpnet_lib_get_put( + uint64_t trace_id, + const char* endpoint, + void* req_buffer, + size_t req_size, + void* resp_buffer, + size_t resp_size, + bool is_post) +{ + uint32_t http_code; + bool success; + + http_code = 0; + success = false; + + for (int i = 0; i < RETRY_COUNT_ON_ERROR; i++) { + success = pumpnet_lib_http_get_put( + trace_id, + endpoint, + req_buffer, + req_size, + resp_buffer, + resp_size, + &http_code, + is_post); + + if (http_code == 0 || http_code == HTTP_CODE_PRECONDITION_FAILED) { + log_warn("[%llX][%s][%s] Failed, http code %d, retrying (%d)...", + trace_id, + is_post ? "post" : "get", + endpoint, + http_code, + i); + + util_time_sleep_ms(RETRY_TIME_BACKOFF_MS); + } else { + break; + } + } + + if (!success) { + log_error("[%llX][%s][%s] Failed", trace_id, is_post ? "post" : "get", endpoint); + + return false; + } else if (http_code != 200) { + log_error("[%llX][%s][%s] Get non successful: %d", trace_id, is_post ? "post" : "get", endpoint, http_code); + return false; + } + + return true; +} + +static bool _pumpnet_lib_get_rank(uint64_t player_ref_id, void* buffer, size_t size) +{ + log_assert(buffer); + + struct pumpnet_lib_get_rank_req req; + struct pumpnet_lib_get_rank_resp* resp; + size_t resp_size; + uint64_t trace_id; + + trace_id = _pumpnet_lib_generate_tracing_id(); + + req.trace_id = trace_id; + req.machine_id = pumpnet_lib_machine_id; + req.player_ref_id = player_ref_id; + + resp_size = sizeof(struct pumpnet_lib_get_rank_resp) + size; + resp = util_xmalloc(resp_size); + + log_info("[%llX][%llX] Get rank", trace_id, player_ref_id); + + if (!_pumpnet_lib_get_put( + trace_id, + pumpnet_lib_server_endpoint_rank, + &req, + sizeof(req), + resp, + resp_size, + false)) { + free(resp); + return false; + } + + if (resp->size > size) { + log_error("[%llX] Rank resp size greater than buffer size: %d > %d", + trace_id, + resp->size, + size); + free(resp); + return false; + } + + memcpy(buffer, resp->data, resp->size); + + free(resp); + + return true; +} + +static bool _pumpnet_lib_get_save(uint64_t player_ref_id, void* buffer, size_t size) +{ + log_assert(buffer); + + struct pumpnet_lib_get_save_req req; + struct pumpnet_lib_get_save_resp* resp; + size_t resp_size; + uint64_t trace_id; + + trace_id = _pumpnet_lib_generate_tracing_id(); + + req.trace_id = trace_id; + req.machine_id = pumpnet_lib_machine_id; + req.player_ref_id = player_ref_id; + + resp_size = sizeof(struct pumpnet_lib_get_save_resp) + size; + resp = util_xmalloc(resp_size); + + log_info("[%llX][%llX] Get save", trace_id, player_ref_id); + + if (!_pumpnet_lib_get_put( + trace_id, + pumpnet_lib_server_endpoint_save, + &req, + sizeof(req), + resp, + resp_size, + false)) { + free(resp); + return false; + } + + if (resp->size > size) { + log_error("[%llX] Save resp size greater than buffer size: %d > %d", + trace_id, + resp->size, + size); + free(resp); + return false; + } + + memcpy(buffer, resp->data, resp->size); + + free(resp); + + return true; +} + +static bool _pumpnet_lib_put_rank(uint64_t player_ref_id, const void* buffer, size_t size) +{ + log_assert(buffer); + + struct pumpnet_lib_put_rank_req* req; + struct pumpnet_lib_put_rank_resp resp; + size_t req_size; + uint64_t trace_id; + + trace_id = _pumpnet_lib_generate_tracing_id(); + + req_size = sizeof(struct pumpnet_lib_put_rank_req) + size; + req = util_xmalloc(req_size); + + req->trace_id = trace_id; + req->machine_id = pumpnet_lib_machine_id; + req->player_ref_id = player_ref_id; + req->size = size; + memcpy(req->data, buffer, size); + + log_info("[%llX][%llX] Put rank", trace_id, player_ref_id); + + if (!_pumpnet_lib_get_put( + trace_id, + pumpnet_lib_server_endpoint_rank, + req, + req_size, + &resp, + sizeof(resp), + true)) { + free(req); + return false; + } + + free(req); + + return true; +} + +static bool _pumpnet_lib_put_save(uint64_t player_ref_id, const void* buffer, size_t size) +{ + log_assert(buffer); + + struct pumpnet_lib_put_save_req* req; + struct pumpnet_lib_put_save_resp resp; + size_t req_size; + uint64_t trace_id; + + trace_id = _pumpnet_lib_generate_tracing_id(); + + req_size = sizeof(struct pumpnet_lib_put_save_req) + size; + req = util_xmalloc(req_size); + + req->trace_id = trace_id; + req->machine_id = pumpnet_lib_machine_id; + req->player_ref_id = player_ref_id; + req->size = size; + memcpy(req->data, buffer, size); + + log_info("[%llX][%llX] Put save", trace_id, player_ref_id); + + if (!_pumpnet_lib_get_put( + trace_id, + pumpnet_lib_server_endpoint_save, + req, + req_size, + &resp, + sizeof(resp), + true)) { + free(req); + return false; + } + + free(req); + + return true; +} + +void pumpnet_lib_init( + enum asset_game_version game, + const char* server_addr, + uint64_t machine_id, + const char* cert_dir_path, + bool verbose_debug_log) +{ + pumpnet_lib_http_init(cert_dir_path, verbose_debug_log); + + pumpnet_lib_game = game; + pumpnet_lib_server_addr = util_str_dup(server_addr); + pumpnet_lib_machine_id = machine_id; + + pumpnet_lib_server_endpoint_save = _pumpnet_lib_get_endpoint_save(game, server_addr); + pumpnet_lib_server_endpoint_rank = _pumpnet_lib_get_endpoint_rank(game, server_addr); + + log_info("Initialized pumpnet for game %d, serveraddr %s, main endpoint version %s", + pumpnet_lib_game, + pumpnet_lib_server_addr, + USBPROFILE_ENDPOINT); +} + +void pumpnet_lib_shutdown() +{ + free(pumpnet_lib_server_endpoint_save); + free(pumpnet_lib_server_endpoint_rank); + + pumpnet_lib_http_shutdown(); + + log_info("Shut down"); +} + +bool pumpnet_lib_get(enum pumpnet_lib_file_type file_type, uint64_t player_ref_id, void* buffer, size_t size) +{ + switch (file_type) { + case PUMPNET_LIB_FILE_TYPE_SAVE: + return _pumpnet_lib_get_save(player_ref_id, buffer, size); + + case PUMPNET_LIB_FILE_TYPE_RANK: + return _pumpnet_lib_get_rank(player_ref_id, buffer, size); + + case PUMPNET_LIB_FILE_TYPE_COUNT: + default: + log_die_illegal_state(); + return false; + } +} + +bool pumpnet_lib_put(enum pumpnet_lib_file_type file_type, uint64_t player_ref_id, const void* buffer, size_t size) +{ + switch (file_type) { + case PUMPNET_LIB_FILE_TYPE_SAVE: + return _pumpnet_lib_put_save(player_ref_id, buffer, size); + + case PUMPNET_LIB_FILE_TYPE_RANK: + return _pumpnet_lib_put_rank(player_ref_id, buffer, size); + + case PUMPNET_LIB_FILE_TYPE_COUNT: + default: + log_die_illegal_state(); + return false; + } +} + diff --git a/src/main/pumpnet/lib/pumpnet.h b/src/main/pumpnet/lib/pumpnet.h new file mode 100644 index 0000000..1494e21 --- /dev/null +++ b/src/main/pumpnet/lib/pumpnet.h @@ -0,0 +1,33 @@ +// +// Created by on 9/16/18. +// + +#ifndef PUMPNET_LIB_PUMPNET_H +#define PUMPNET_LIB_PUMPNET_H + +#include +#include +#include + +#include "asset/game-version.h" + +enum pumpnet_lib_file_type { + PUMPNET_LIB_FILE_TYPE_SAVE = 0, + PUMPNET_LIB_FILE_TYPE_RANK = 1, + PUMPNET_LIB_FILE_TYPE_COUNT = 2, +}; + +void pumpnet_lib_init( + enum asset_game_version game, + const char* server_addr, + uint64_t machine_id, + const char* cert_dir_path, + bool verbose_debug_log); + +void pumpnet_lib_shutdown(); + +bool pumpnet_lib_get(enum pumpnet_lib_file_type file_type, uint64_t player_ref_id, void* buffer, size_t size); + +bool pumpnet_lib_put(enum pumpnet_lib_file_type file_type, uint64_t player_ref_id, const void* buffer, size_t size); + +#endif diff --git a/src/main/sec/hasp/lib/asn1.c b/src/main/sec/hasp/lib/asn1.c new file mode 100644 index 0000000..8d0f4f5 --- /dev/null +++ b/src/main/sec/hasp/lib/asn1.c @@ -0,0 +1,518 @@ +#include +#include + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +#include "asn1.h" + +static uint32_t sec_hasp_asn1_decode_int(const uint8_t* buffer, size_t* offset, uint32_t blen); +static uint8_t* sec_hasp_asn1_decode_data(const uint8_t* buffer, size_t* offset, uint32_t blen); +static char* sec_hasp_asn1_decode_str(const uint8_t* buffer, size_t* offset, uint32_t blen); +static uint32_t sec_hasp_asn1_decode_length(const uint8_t* buffer, size_t* offset); +static uint16_t sec_hasp_asn1_decode_tag(const uint8_t* buffer, size_t* offset); +static void sec_hasp_asn1_encode_int(uint32_t val, uint8_t* buffer, size_t* offset); +static void sec_hasp_asn1_encode_data(const uint8_t* data, size_t len, uint8_t* buffer, size_t* offset); +static void sec_hasp_asn1_encode_str(const char* str, uint8_t* buffer, size_t* offset); +static void sec_hasp_asn1_encode_length(uint32_t len, uint8_t* buffer, size_t* offset); +static void sec_hasp_asn1_encode_tag(uint16_t tag, uint8_t* buffer, size_t* offset); + +struct sec_hasp_asn1_store* sec_hasp_asn1_object_store_alloc(uint16_t oid, uint32_t size) +{ + struct sec_hasp_asn1_store* tmp = malloc(sizeof(struct sec_hasp_asn1_store)); + + tmp->objects = malloc(sizeof(struct sec_hasp_asn1_object) * size); + tmp->capacity = size; + tmp->oid = oid; + tmp->pos = 0; + + memset(tmp->objects, 0, sizeof(struct sec_hasp_asn1_object) * size); + + return tmp; +} + +void sec_hasp_asn1_store_free(struct sec_hasp_asn1_store* store) +{ + for (size_t i = 0; i < store->pos; i++) { + if (store->objects[i].type == SEC_HASP_ASN1_VT_STR) { + free(store->objects[i].str); + } else if (store->objects[i].type == SEC_HASP_ASN1_VT_DATA) { + free(store->objects[i].data); + } + } + + free(store); +} + +void sec_hasp_asn1_object_add_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t value) +{ + if (store->pos == store->capacity) { + return; + } + + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_INT; + + /* Determine length, considers padding for encoding later as well */ + // TODO not sure if this is correct, ask mario + if (value <= 0xFF) { + store->objects[store->pos].blen = 1; + } else if (value <= 0xFFFF) { + store->objects[store->pos].blen = 2; + } else if (value <= 0xFFFFFF) { + store->objects[store->pos].blen = 3; + } else if (value <= 0x7FFFFFFF) { + store->objects[store->pos].blen = 4; + } else { + store->objects[store->pos].blen = 5; + } + + store->objects[store->pos].int_val = value; + store->pos++; +} + +void sec_hasp_asn1_object_add_str(struct sec_hasp_asn1_store* store, uint16_t tag, const char* str) +{ + if (store->pos == store->capacity) { + return; + } + + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_STR; + + /* Store len + null terminator */ + store->objects[store->pos].blen = strlen(str) + 1; + store->objects[store->pos].str = util_str_dup(str); + store->pos++; +} + +void sec_hasp_asn1_object_add_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t time) +{ + if (store->pos == store->capacity) { + return; + } + + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_TIME; + + store->objects[store->pos].blen = 5; + store->objects[store->pos].time = time; + store->pos++; +} + +void sec_hasp_asn1_object_add_data(struct sec_hasp_asn1_store* store, uint16_t tag, const uint8_t* data, + size_t len) +{ + if (store->pos == store->capacity) { + return; + } + + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_DATA; + + /* Store len + null terminator */ + store->objects[store->pos].blen = len; + store->objects[store->pos].data = util_xmalloc(len); + memcpy(store->objects[store->pos].data, data, len); + + store->pos++; +} + +void sec_hasp_asn1_object_set_int(struct sec_hasp_asn1_store* store, uint16_t tag) +{ + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_INT; + store->pos++; +} + +void sec_hasp_asn1_object_set_str(struct sec_hasp_asn1_store* store, uint16_t tag) +{ + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_STR; + store->pos++; +} + +void sec_hasp_asn1_object_set_time(struct sec_hasp_asn1_store* store, uint16_t tag) +{ + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_TIME; + store->pos++; +} + +void sec_hasp_asn1_object_set_data(struct sec_hasp_asn1_store* store, uint16_t tag) +{ + store->objects[store->pos].tag = tag; + store->objects[store->pos].type = SEC_HASP_ASN1_VT_DATA; + store->pos++; +} + +bool sec_hasp_asn1_object_get_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value) +{ + for (size_t i = 0; i < store->pos; i++) { + if (store->objects[i].tag == tag) { + if (store->objects[i].type != SEC_HASP_ASN1_VT_INT) { + log_error("Type of tag %X is not int", tag); + return false; + } else { + *ret_value = store->objects[i].int_val; + return true; + } + } + } + + return false; +} + +bool sec_hasp_asn1_object_get_str(struct sec_hasp_asn1_store* store, uint16_t tag, char** ret_value) +{ + for (size_t i = 0; i < store->pos; i++) { + if (store->objects[i].tag == tag) { + if (store->objects[i].type != SEC_HASP_ASN1_VT_STR) { + log_error("Type of tag %X is not str", tag); + return false; + } else { + *ret_value = util_str_dup(store->objects[i].str); + return true; + } + } + } + + return false; +} + +bool sec_hasp_asn1_object_get_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value) +{ + for (size_t i = 0; i < store->pos; i++) { + if (store->objects[i].tag == tag) { + if (store->objects[i].type != SEC_HASP_ASN1_VT_TIME) { + log_error("Type of tag %X is not time", tag); + return false; + } else { + *ret_value = store->objects[i].int_val; + return true; + } + } + } + + return false; +} + +bool sec_hasp_asn1_object_get_data(struct sec_hasp_asn1_store* store, uint16_t tag, uint8_t** ret_data, + size_t* ret_len) +{ + for (size_t i = 0; i < store->pos; i++) { + if (store->objects[i].tag == tag) { + if (store->objects[i].type != SEC_HASP_ASN1_VT_DATA) { + log_error("Type of tag %X is not str", tag); + return false; + } else { + *ret_len = store->objects[i].blen; + *ret_data = util_xmalloc(*ret_len); + memcpy(*ret_data, store->objects[i].data, *ret_len); + return true; + } + } + } + + return false; +} + + +size_t sec_hasp_asn1_encode(struct sec_hasp_asn1_store* store, uint8_t* buffer, size_t len) +{ + uint8_t buffer_tmp[32768]; + size_t offset = 0; + + /* we need to know the size of the payload to encode the first length field, encode all objects first */ + for (size_t i = 0; i < store->pos; i++) { + sec_hasp_asn1_encode_tag(store->objects[i].tag, buffer_tmp, &offset); + sec_hasp_asn1_encode_length(store->objects[i].blen, buffer_tmp, &offset); + + switch(store->objects[i].type) { + case SEC_HASP_ASN1_VT_INVALID: + log_error("Invalid object type"); + break; + + case SEC_HASP_ASN1_VT_TIME: + buffer_tmp[offset++] = 0x00; + sec_hasp_asn1_encode_int(store->objects[i].time, buffer_tmp, &offset); + break; + + case SEC_HASP_ASN1_VT_INT: + sec_hasp_asn1_encode_int(store->objects[i].time, buffer_tmp, &offset); + break; + + case SEC_HASP_ASN1_VT_STR: + sec_hasp_asn1_encode_str(store->objects[i].str, buffer_tmp, &offset); + break; + + case SEC_HASP_ASN1_VT_DATA: + sec_hasp_asn1_encode_data(store->objects[i].data, store->objects[i].blen, buffer_tmp, &offset); + break; + + default: + log_error("Unknown object type %d", store->objects[i].type); + break; + } + } + + size_t offset_out = 0; + + sec_hasp_asn1_encode_tag(store->oid, buffer, &offset_out); + sec_hasp_asn1_encode_length(offset, buffer, &offset_out); + + if (offset > len) { + log_error("Target buffer too small: %d < %d", len, offset + offset_out); + } else { + memcpy(&buffer[offset_out], buffer_tmp, offset); + } + + return offset + offset_out; +} + +void sec_hasp_asn1_decode(struct sec_hasp_asn1_store* store, const uint8_t* buffer, size_t len) +{ + size_t offset = 0; + + store->oid = sec_hasp_asn1_decode_tag(buffer, &offset); + sec_hasp_asn1_decode_length(buffer, &offset); + + while (offset < len) { + uint16_t tag = sec_hasp_asn1_decode_tag(buffer, &offset); + uint32_t obj_len = sec_hasp_asn1_decode_length(buffer, &offset); + + if (tag <= 0x7F || tag >= 0x9F) { + log_error("Found invalid object tag: %X", tag); + return; + } + + struct sec_hasp_asn1_object* obj = NULL; + + /* find object that matches the tag and type */ + for (size_t i = 0; i < store->pos; i++) { + if (store->objects[i].tag == tag) { + obj = &store->objects[i]; + break; + } + } + + if (!obj) { + log_error("No object in store that matches tag %X", tag); + return; + } + + obj->blen = obj_len; + + switch (obj->type) { + case SEC_HASP_ASN1_VT_INVALID: + log_error("Invalid object type specified for tag %X", obj->tag); + break; + + case SEC_HASP_ASN1_VT_TIME: + case SEC_HASP_ASN1_VT_INT: + obj->int_val = sec_hasp_asn1_decode_int(buffer, &offset, obj->blen); + break; + + case SEC_HASP_ASN1_VT_STR: + obj->str = sec_hasp_asn1_decode_str(buffer, &offset, obj->blen); + break; + + case SEC_HASP_ASN1_VT_DATA: + obj->data = sec_hasp_asn1_decode_data(buffer, &offset, obj->blen); + break; + + default: + log_error("Unknown object type for tag %X", obj->tag); + break; + } + } +} + +static uint32_t sec_hasp_asn1_decode_int(const uint8_t* buffer, size_t* offset, uint32_t blen) +{ + uint32_t data = 0; + + switch (blen) { + case 1: + data = buffer[(*offset)++]; + break; + + case 2: + data |= buffer[(*offset)++] << 8; + data |= buffer[(*offset)++]; + break; + + case 3: + data |= buffer[(*offset)++] << 16; + data |= buffer[(*offset)++] << 8; + data |= buffer[(*offset)++]; + break; + + case 4: + data |= buffer[(*offset)++] << 24; + data |= buffer[(*offset)++] << 16; + data |= buffer[(*offset)++] << 8; + data |= buffer[(*offset)++]; + break; + + case 5: + /* skip first byte? */ + (*offset)++; + data |= buffer[(*offset)++] << 24; + data |= buffer[(*offset)++] << 16; + data |= buffer[(*offset)++] << 8; + data |= buffer[(*offset)++]; + break; + + default: + // TODO invalid len? + break; + } + + return data; +} + +static uint8_t* sec_hasp_asn1_decode_data(const uint8_t* buffer, size_t* offset, uint32_t blen) +{ + uint8_t* data = util_xmalloc(sizeof(uint8_t) * blen); + + memcpy(data, buffer + *offset, blen); + (*offset) += blen; + + return data; +} + +static char* sec_hasp_asn1_decode_str(const uint8_t* buffer, size_t* offset, uint32_t blen) +{ + /* len already includes null terminator */ + char* str = util_xmalloc(sizeof(char) * blen); + + memcpy(str, buffer + *offset, blen); + (*offset) += blen; + + return str; +} + +static uint32_t sec_hasp_asn1_decode_length(const uint8_t* buffer, size_t* offset) +{ + uint32_t len; + + len = buffer[(*offset)++]; + + if (len == 0x81) { + len = buffer[(*offset)++]; + } else if (len == 0x82) { + /* Big endian */ + len = buffer[(*offset)++] << 8; + len |= buffer[(*offset)++]; + } + + return len; +} + +static uint16_t sec_hasp_asn1_decode_tag(const uint8_t* buffer, size_t* offset) +{ + uint16_t tag; + + tag = buffer[(*offset)++]; + + if (tag == 0x7F) { + /* Big endian */ + tag = tag << 8; + tag |= buffer[(*offset)++]; + } + + return tag; +} + +static void sec_hasp_asn1_encode_int(uint32_t val, uint8_t* buffer, size_t* offset) +{ + uint8_t tmp[8]; + size_t tmp_pos = 0; + + if (val <= 0xFF) { + tmp[tmp_pos++] = (uint8_t) val; + } else if (val <= 0xFFFF) { + /* Big endian */ + tmp[tmp_pos++] = (uint8_t) (val >> 8); + tmp[tmp_pos++] = (uint8_t) val; + } else if (val <= 0xFFFFFF) { + /* Big endian */ + tmp[tmp_pos++] = (uint8_t) (val >> 16); + tmp[tmp_pos++] = (uint8_t) (val >> 8); + tmp[tmp_pos++] = (uint8_t) val; + } else if (val <= 0xFFFFFFFF) { + /* Big endian */ + tmp[tmp_pos++] = (uint8_t) (val >> 24); + tmp[tmp_pos++] = (uint8_t) (val >> 16); + tmp[tmp_pos++] = (uint8_t) (val >> 8); + tmp[tmp_pos++] = (uint8_t) val; + } else if (val <= 0xFFFFFFFFFFFFFFFF) { + // TODO quad words not supported in decode? + } + + /* Deal with padding */ + if (tmp[0] > 0x7F) { + buffer[(*offset)++] = 0x00; + } + + memcpy(buffer + *offset, tmp, tmp_pos); + (*offset) += tmp_pos; +} + +static void sec_hasp_asn1_encode_data(const uint8_t* data, size_t len, uint8_t* buffer, size_t* offset) +{ + memcpy(buffer + *offset, data, len); + (*offset) += len; +} + +static void sec_hasp_asn1_encode_str(const char* str, uint8_t* buffer, size_t* offset) +{ + size_t len = strlen(str); + + memcpy(buffer + *offset, str, len); + (*offset) += len; + + /* Add null terminator */ + buffer[(*offset)++] = 0x00; +} + +static void sec_hasp_asn1_encode_length(uint32_t len, uint8_t* buffer, size_t* offset) +{ + if (len <= 0xF7) { + buffer[(*offset)++] = (uint8_t) len; + } else if (len <= 0xFF) { + buffer[(*offset)++] = 0x81; + buffer[(*offset)++] = (uint8_t) len; + } else if (len <= 0xFFFF) { + buffer[(*offset)++] = 0x82; + /* Big endian */ + buffer[(*offset)++] = (uint8_t) (len >> 8); + buffer[(*offset)++] = (uint8_t) len; + } else if (len <= 0xFFFF) { + buffer[(*offset)++] = 0x82; + /* Big endian */ + buffer[(*offset)++] = (uint8_t) (len >> 16); + buffer[(*offset)++] = (uint8_t) (len >> 8); + buffer[(*offset)++] = (uint8_t) len; + } else if (len <= 0xFFFFFFFF) { + buffer[(*offset)++] = 0x84; + /* Big endian */ + buffer[(*offset)++] = (uint8_t) (len >> 24); + buffer[(*offset)++] = (uint8_t) (len >> 16); + buffer[(*offset)++] = (uint8_t) (len >> 8); + buffer[(*offset)++] = (uint8_t) len; + } +} + +static void sec_hasp_asn1_encode_tag(uint16_t tag, uint8_t* buffer, size_t* offset) +{ + if (tag > 0xFF) { + /* Big endian */ + buffer[(*offset)++] = (uint8_t) (tag >> 8); + buffer[(*offset)++] = (uint8_t) (tag); + } else { + buffer[(*offset)++] = (uint8_t) (tag); + } +} \ No newline at end of file diff --git a/src/main/sec/hasp/lib/asn1.h b/src/main/sec/hasp/lib/asn1.h new file mode 100644 index 0000000..19120b8 --- /dev/null +++ b/src/main/sec/hasp/lib/asn1.h @@ -0,0 +1,71 @@ +#ifndef SEC_HASP_ASN1_H +#define SEC_HASP_ASN1_H + +#include +#include + +#include "util/list.h" + +enum sec_hasp_asn1_value_type { + SEC_HASP_ASN1_VT_INVALID = 0, + SEC_HASP_ASN1_VT_INT = 1, + SEC_HASP_ASN1_VT_STR = 2, + SEC_HASP_ASN1_VT_TIME = 3, + SEC_HASP_ASN1_VT_DATA = 4, +}; + +struct sec_hasp_asn1_object { + uint16_t tag; + uint32_t blen; + enum sec_hasp_asn1_value_type type; + + union { + uint32_t time; + uint32_t int_val; + uint8_t* data; + char* str; + }; +}; + +struct sec_hasp_asn1_store { + uint16_t oid; + size_t capacity; + size_t pos; + struct sec_hasp_asn1_object* objects; +}; + +struct sec_hasp_asn1_store* sec_hasp_asn1_object_store_alloc(uint16_t oid, uint32_t size); + +void sec_hasp_asn1_store_free(struct sec_hasp_asn1_store* store); + +void sec_hasp_asn1_object_add_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t value); + +void sec_hasp_asn1_object_add_str(struct sec_hasp_asn1_store* store, uint16_t tag, const char* str); + +void sec_hasp_asn1_object_add_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t time); + +void sec_hasp_asn1_object_add_data(struct sec_hasp_asn1_store* store, uint16_t tag, const uint8_t* data, + size_t len); + +void sec_hasp_asn1_object_set_int(struct sec_hasp_asn1_store* store, uint16_t tag); + +void sec_hasp_asn1_object_set_str(struct sec_hasp_asn1_store* store, uint16_t tag); + +void sec_hasp_asn1_object_set_time(struct sec_hasp_asn1_store* store, uint16_t tag); + +void sec_hasp_asn1_object_set_data(struct sec_hasp_asn1_store* store, uint16_t tag); + +bool sec_hasp_asn1_object_get_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value); + +bool sec_hasp_asn1_object_get_str(struct sec_hasp_asn1_store* store, uint16_t tag, char** ret_value); + +bool sec_hasp_asn1_object_get_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value); + +bool sec_hasp_asn1_object_get_data(struct sec_hasp_asn1_store* store, uint16_t tag, uint8_t** ret_data, + size_t* ret_len); + +size_t sec_hasp_asn1_encode(struct sec_hasp_asn1_store* store, uint8_t* buffer, size_t len); + +void sec_hasp_asn1_decode(struct sec_hasp_asn1_store* store, const uint8_t* buffer, size_t len); + +#endif diff --git a/src/main/sec/hasp/lib/const.h b/src/main/sec/hasp/lib/const.h new file mode 100644 index 0000000..8949476 --- /dev/null +++ b/src/main/sec/hasp/lib/const.h @@ -0,0 +1,80 @@ +#ifndef SEC_HASP_CONST_H +#define SEC_HASP_CONST_H + +#define SEC_HAS_CONST_HEADER_SZ 24 + +#define SEC_HAS_CONST_FILEID_RW = 0xfff4 +#define SEC_HAS_CONST_FILEID_RO = 0xfff5 + +#define SEC_HAS_CONST_SCOPE_LM "" +#define SEC_HAS_CONST_SCOPE_HANDLE "" + +#define SEC_HAS_CONST_FORMAT_GETID "" +#define SEC_HAS_CONST_FORMAT_GETSESSION "" +#define SEC_HAS_CONST_FORMAT_GETKEYINFO "" + +#define SEC_HAS_CONST_SPEC_FEATURE_ID "" + +enum sec_hasp_const_status { + SEC_HASP_CONST_STATUS_OK = 0, + SEC_HASP_CONST_STATUS_MEM_RANGE = 1, + SEC_HASP_CONST_STATUS_INV_FILEID = 10, + SEC_HASP_CONST_STATUS_NO_TIME = 12, + SEC_HASP_CONST_STATUS_INV_VCODE = 22, + SEC_HASP_CONST_STATUS_INV_HND = 9, + SEC_HASP_CONST_STATUS_TOO_SHORT = 8, + SEC_HASP_CONST_STATUS_DEVICE_ERR = 43, + SEC_HASP_CONST_STATUS_SCHAN_ERR = 46, + SEC_HASP_CONST_STATUS_BROKEN_SESSION = 0x7F000027 +}; + +enum sec_hasp_const_operation_id { + /* Not Used - Admin or Get LMS Version? */ + SEC_HASP_CONST_OP_ID_ADMIN = 0, + /* Not Used */ + SEC_HASP_CONST_OP_ID_ECHO = 1, + SEC_HASP_CONST_OP_ID_LOGIN = 0x2711, + SEC_HASP_CONST_OP_ID_LOGOUT = 0x2712, + SEC_HASP_CONST_OP_ID_LOGINSCOPE = 0x2713, + SEC_HASP_CONST_OP_ID_GETINFO = 0x2714, + SEC_HASP_CONST_OP_ID_PARSE_SCOPE = 0x2715, + SEC_HASP_CONST_OP_ID_SETUPSCHANNEL = 0x2716, + SEC_HASP_CONST_OP_ID_ENCRYPT = 0x2724, + SEC_HASP_CONST_OP_ID_DECRYPT = 0x2725, + SEC_HASP_CONST_OP_ID_READ = 0x271A, + SEC_HASP_CONST_OP_ID_WRITE = 0x271B, + SEC_HASP_CONST_OP_ID_GETSIZE = 0x271C, + SEC_HASP_CONST_OP_ID_GETRTC = 0x271D, + SEC_HASP_CONST_OP_ID_GETAPIUID = 0x2774, + /* Not Used */ + SEC_HASP_CONST_OP_ID_UPDATE = 0x2775, + /* Not Used */ + SEC_HASP_CONST_OP_ID_DETACH = 0x2779, +}; + +enum sec_hasp_const_operational_object_id { + SEC_HASP_CONST_OID_CLIENTID_REQ = 0x7F34, + SEC_HASP_CONST_OID_CLIENTID_RESP =0x7F35, + SEC_HASP_CONST_OID_LOGIN_REQ = 0x61, + SEC_HASP_CONST_OID_LOGIN_REP = 0x62, + SEC_HASP_CONST_OID_LOGINSCOPE_REQ = 0x63, + SEC_HASP_CONST_OID_LOGINSCOPE_REP = 0x64, + SEC_HASP_CONST_OID_LOGOUT_REQ = 0x65, + SEC_HASP_CONST_OID_LOGOUT_REP = 0x66, + SEC_HASP_CONST_OID_INFO_REQ = 0x67, + SEC_HASP_CONST_OID_INFO_REP = 0x68, + SEC_HASP_CONST_OID_READ_REQ = 0x6A, + SEC_HASP_CONST_OID_READ_REP = 0x6B, + SEC_HASP_CONST_OID_WRITE_REQ = 0x6C, + SEC_HASP_CONST_OID_WRITE_REP = 0x6D, + SEC_HASP_CONST_OID_GETSIZE_REQ = 0x6E, + SEC_HASP_CONST_OID_GETSIZE_REP = 0x6F, + SEC_HASP_CONST_OID_GETRTC_REQ = 0x70, + SEC_HASP_CONST_OID_GETRTC_REP = 0x71, + SEC_HASP_CONST_OID_SCHANNEL_REQ = 0x72, + SEC_HASP_CONST_OID_SCHANNEL_REP = 0x73, + SEC_HASP_CONST_OID_CRYPT_REQ = 0x77, + SEC_HASP_CONST_OID_CRYPT_REP = 0x78, +}; + +#endif diff --git a/src/main/sec/hasp/lib/handler.c b/src/main/sec/hasp/lib/handler.c new file mode 100644 index 0000000..9c471ac --- /dev/null +++ b/src/main/sec/hasp/lib/handler.c @@ -0,0 +1,118 @@ +#define LOG_MODULE "sec-hasp-handler" + +#include + +#include "handler.h" + +#include "util/log.h" + +enum sec_hasp_handler_packet_type { + SEC_HASP_HANDLER_PT_APIUID = 0x2774, + SEC_HASP_HANDLER_PT_LOGIN = 0x2711, + SEC_HASP_HANDLER_PT_LOGOUT = 0x2712, + SEC_HASP_HANDLER_PT_GETINFO = 0x2714, + SEC_HASP_HANDLER_PT_SCHANNEL = 0x2716, + SEC_HASP_HANDLER_PT_ENCRYPT = 0x2724, + SEC_HASP_HANDLER_PT_DECRYPT = 0x2725, + SEC_HASP_HANDLER_PT_READ = 0x271A, + SEC_HASP_HANDLER_PT_WRITE = 0x271B, +}; + +void sec_hasp_handler_init(const uint8_t* key_data, size_t len) +{ + +} + +struct sec_hasp_handler_transaction* sec_hasp_handler_alloc_transaction(size_t max_payload_size) +{ + struct sec_hasp_handler_transaction* trans; + + trans = malloc(sizeof(struct sec_hasp_handler_transaction)); + trans->req_resp_max_size = sizeof(struct sec_hasp_handler_header) + max_payload_size; + trans->req = malloc(trans->req_resp_max_size); + trans->resp = malloc(trans->req_resp_max_size); + + return trans; +} + +void sec_hasp_handler_free_transaction(struct sec_hasp_handler_transaction* transaction) +{ + free(transaction->req); + free(transaction->resp); + free(transaction); +} + +void sec_hasp_handler_do_transaction(struct sec_hasp_handler_transaction* transaction) +{ + log_debug("Req: packet_size %d, head_value 0x%X, transaction_num %d, session_id 0x%X, packet_type 0x%X, " + "unknown 0x%X, tail_value 0x%X", transaction->req->header.packet_size, transaction->req->header.head_value, + transaction->req->header.transaction_num, transaction->req->header.session_id, + transaction->req->header.packet_type, transaction->req->header.tail_value); + + switch (transaction->req->header.packet_type) { + case SEC_HASP_HANDLER_PT_APIUID: + log_debug("SEC_HASP_HANDLER_PT_APIUID"); + break; + + case SEC_HASP_HANDLER_PT_LOGIN: + log_debug("SEC_HASP_HANDLER_PT_LOGIN"); + break; + + case SEC_HASP_HANDLER_PT_LOGOUT: + log_debug("SEC_HASP_HANDLER_PT_LOGOUT"); + break; + + case SEC_HASP_HANDLER_PT_GETINFO: + log_debug("SEC_HASP_HANDLER_PT_GETINFO"); + break; + + case SEC_HASP_HANDLER_PT_SCHANNEL: + log_debug("SEC_HASP_HANDLER_PT_SCHANNEL"); + break; + + case SEC_HASP_HANDLER_PT_ENCRYPT: + log_debug("SEC_HASP_HANDLER_PT_ENCRYPT"); + break; + + case SEC_HASP_HANDLER_PT_DECRYPT: + log_debug("SEC_HASP_HANDLER_PT_DECRYPT"); + break; + + case SEC_HASP_HANDLER_PT_READ: + log_debug("SEC_HASP_HANDLER_PT_READ"); + break; + + case SEC_HASP_HANDLER_PT_WRITE: + log_debug("SEC_HASP_HANDLER_PT_WRITE"); + break; + + default: + log_error("Invalid packet type: %X", transaction->req->header.packet_type); + memset(&transaction->req->header, 0, sizeof(struct sec_hasp_handler_header)); + break; + } +} + +//static void sec_hasp_handler_get_client_id(struct sec_hasp_handler_transaction* transaction) +//{ +// transaction->resp->header.packet_size +// transaction->resp->header.head_value +// transaction->resp->header.transaction_num +// transaction->resp->header.session_id +// transaction->resp->header.packet_type +// transaction->resp->header.tail_value +// +// rp = request_packet.payload_object +// +// client_id = HaspUtils.make_fake_handle_value() +// client_id_response = HaspObject.HO_Client_ID_Response() +// client_id_response.populate(HaspConst.HASP_STATUS_OK,client_id) +// +// self.client_db[client_id] = { +// "hasp_serial":0, +// "sessions":{} +// } +// +// return client_id_response +//} + diff --git a/src/main/sec/hasp/lib/handler.h b/src/main/sec/hasp/lib/handler.h new file mode 100644 index 0000000..27b27fe --- /dev/null +++ b/src/main/sec/hasp/lib/handler.h @@ -0,0 +1,41 @@ +#ifndef SEC_HASP_HANDLER_H +#define SEC_HASP_HANDLER_H + +#include +#include + +struct sec_hasp_handler_header { + uint32_t packet_size; + uint16_t head_value; + uint32_t transaction_num; + uint32_t session_id; + uint16_t unknown; + uint16_t packet_type; + uint32_t tail_value; +} __attribute((__packed__)); + +struct sec_hasp_handler_req { + struct sec_hasp_handler_header header; + uint8_t payload[]; +}; + +struct sec_hasp_handler_resp { + struct sec_hasp_handler_header header; + uint8_t payload[]; +}; + +struct sec_hasp_handler_transaction { + size_t req_resp_max_size; + struct sec_hasp_handler_req* req; + struct sec_hasp_handler_resp* resp; +}; + +void sec_hasp_handler_init(const uint8_t* key_data, size_t len); + +struct sec_hasp_handler_transaction* sec_hasp_handler_alloc_transaction(size_t max_payload_size); + +void sec_hasp_handler_free_transaction(struct sec_hasp_handler_transaction* transaction); + +void sec_hasp_handler_do_transaction(struct sec_hasp_handler_transaction* transaction); + +#endif diff --git a/src/main/sec/hasp/lib/object.c b/src/main/sec/hasp/lib/object.c new file mode 100644 index 0000000..8a175c6 --- /dev/null +++ b/src/main/sec/hasp/lib/object.c @@ -0,0 +1,4 @@ +// +// Created by on 6/2/18. +// + diff --git a/src/main/sec/hasp/lib/object.h b/src/main/sec/hasp/lib/object.h new file mode 100644 index 0000000..9985258 --- /dev/null +++ b/src/main/sec/hasp/lib/object.h @@ -0,0 +1,6 @@ +#ifndef SEC_HASP_OBJECT_H +#define SEC_HASP_OBJECT_H + + + +#endif diff --git a/src/main/sec/hasp/lib/object/client-id-req.c b/src/main/sec/hasp/lib/object/client-id-req.c new file mode 100644 index 0000000..5c731f6 --- /dev/null +++ b/src/main/sec/hasp/lib/object/client-id-req.c @@ -0,0 +1,61 @@ +#include + +#include "sec/hasp/lib/asn1.h" +#include "sec/hasp/lib/const.h" + +#include "util/mem.h" + +#include "client-id-req.h" + +struct sec_hasp_object_client_id_req* sec_hasp_object_client_id_req_alloc() +{ + struct sec_hasp_object_client_id_req* obj = util_xmalloc(sizeof(struct sec_hasp_object_client_id_req)); + + obj->oid = SEC_HASP_CONST_OID_CLIENTID_REQ; + obj->val_80 = 0; + obj->api_version_major = 0; + obj->api_version_minor = 0; + obj->timestamp = 0; + + return obj; +} + +void sec_hasp_object_client_id_req_free(struct sec_hasp_object_client_id_req* obj) +{ + free(obj); +} + +size_t sec_hasp_object_client_id_req_encode(struct sec_hasp_object_client_id_req* obj, uint8_t* buffer, + size_t len) +{ + struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 4); + + /* populate right before encoding */ + obj->timestamp = (uint32_t) time(NULL); + + sec_hasp_asn1_object_add_int(store, 0x80, obj->val_80); + sec_hasp_asn1_object_add_int(store, 0x81, obj->api_version_major); + sec_hasp_asn1_object_add_int(store, 0x82, obj->api_version_minor); + sec_hasp_asn1_object_add_time(store, 0x84, obj->timestamp); + + return sec_hasp_asn1_encode(store, buffer, len); +} + +void sec_hasp_object_client_id_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_req* obj) +{ + struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 4); + + sec_hasp_asn1_object_set_int(store, 0x80); + sec_hasp_asn1_object_set_int(store, 0x81); + sec_hasp_asn1_object_set_int(store, 0x82); + sec_hasp_asn1_object_set_time(store, 0x84); + + sec_hasp_asn1_decode(store, buffer, len); + + obj->oid = store->oid; + + sec_hasp_asn1_object_get_int(store, 0x80, &obj->val_80); + sec_hasp_asn1_object_get_int(store, 0x81, &obj->api_version_major); + sec_hasp_asn1_object_get_int(store, 0x82, &obj->api_version_minor); + sec_hasp_asn1_object_get_time(store, 0x84, &obj->timestamp); +} \ No newline at end of file diff --git a/src/main/sec/hasp/lib/object/client-id-req.h b/src/main/sec/hasp/lib/object/client-id-req.h new file mode 100644 index 0000000..11081cb --- /dev/null +++ b/src/main/sec/hasp/lib/object/client-id-req.h @@ -0,0 +1,24 @@ +#ifndef SEC_HASP_OBJECT_CLIENT_ID_REQ_H +#define SEC_HASP_OBJECT_CLIENT_ID_REQ_H + +#include +#include + +struct sec_hasp_object_client_id_req { + uint16_t oid; + uint32_t val_80; + uint32_t api_version_major; + uint32_t api_version_minor; + uint32_t timestamp; +}; + +struct sec_hasp_object_client_id_req* sec_hasp_object_client_id_req_alloc(); + +void sec_hasp_object_client_id_req_free(struct sec_hasp_object_client_id_req* obj); + +size_t sec_hasp_object_client_id_req_encode(struct sec_hasp_object_client_id_req* obj, uint8_t* buffer, + size_t len); + +void sec_hasp_object_client_id_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_req* obj); + +#endif diff --git a/src/main/sec/hasp/lib/object/client-id-resp.c b/src/main/sec/hasp/lib/object/client-id-resp.c new file mode 100644 index 0000000..a8df9de --- /dev/null +++ b/src/main/sec/hasp/lib/object/client-id-resp.c @@ -0,0 +1,48 @@ +#include "sec/hasp/lib/asn1.h" +#include "sec/hasp/lib/const.h" + +#include "util/mem.h" + +#include "client-id-resp.h" + +struct sec_hasp_object_client_id_resp* sec_hasp_object_client_id_resp_alloc() +{ + struct sec_hasp_object_client_id_resp* obj = util_xmalloc(sizeof(struct sec_hasp_object_client_id_resp)); + + obj->oid = SEC_HASP_CONST_OID_CLIENTID_RESP; + obj->status = 0; + obj->client_id = 0; + + return obj; +} + +void sec_hasp_object_client_id_resp_free(struct sec_hasp_object_client_id_resp* obj) +{ + free(obj); +} + +size_t sec_hasp_object_client_id_resp_encode(struct sec_hasp_object_client_id_resp* obj, uint8_t* buffer, + size_t len) +{ + struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 4); + + sec_hasp_asn1_object_add_int(store, 0x80, obj->status); + sec_hasp_asn1_object_add_int(store, 0x81, obj->client_id); + + return sec_hasp_asn1_encode(store, buffer, len); +} + +void sec_hasp_object_client_id_resp_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_resp* obj) +{ + struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 2); + + sec_hasp_asn1_object_set_int(store, 0x80); + sec_hasp_asn1_object_set_int(store, 0x81); + + sec_hasp_asn1_decode(store, buffer, len); + + obj->oid = store->oid; + + sec_hasp_asn1_object_get_int(store, 0x80, &obj->status); + sec_hasp_asn1_object_get_int(store, 0x81, &obj->client_id); +} \ No newline at end of file diff --git a/src/main/sec/hasp/lib/object/client-id-resp.h b/src/main/sec/hasp/lib/object/client-id-resp.h new file mode 100644 index 0000000..e4d51a7 --- /dev/null +++ b/src/main/sec/hasp/lib/object/client-id-resp.h @@ -0,0 +1,22 @@ +#ifndef SEC_HASP_OBJECT_CLIENT_ID_RESP_H +#define SEC_HASP_OBJECT_CLIENT_ID_RESP_H + +#include +#include + +struct sec_hasp_object_client_id_resp { + uint16_t oid; + uint32_t status; + uint32_t client_id; +}; + +struct sec_hasp_object_client_id_resp* sec_hasp_object_client_id_resp_alloc(); + +void sec_hasp_object_client_id_resp_free(struct sec_hasp_object_client_id_resp* obj); + +size_t sec_hasp_object_client_id_resp_encode(struct sec_hasp_object_client_id_resp* obj, uint8_t* buffer, + size_t len); + +void sec_hasp_object_client_id_resp_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_resp* obj); + +#endif diff --git a/src/main/sec/hasp/lib/object/login-req.c b/src/main/sec/hasp/lib/object/login-req.c new file mode 100644 index 0000000..1f928f3 --- /dev/null +++ b/src/main/sec/hasp/lib/object/login-req.c @@ -0,0 +1,139 @@ +#include + +#include "sec/hasp/main.h" +#include "sec/hasp/const.h" + +#include "util/mem.h" + +#include "login-req.h" + +struct sec_hasp_object_login_req* sec_hasp_object_login_req_init() +{ + struct sec_hasp_object_login_req* obj = util_xmalloc(sizeof(struct sec_hasp_object_login_req)); + + obj->oid = SEC_HASP_CONST_OID_LOGIN_REQ; + obj->pid = 0; + obj->tid = 0; + obj->hasp_uid = 0; + obj->vendor_id = 0; + obj->feature_id = 0; + obj->username = NULL; + obj->machine_name = NULL; + obj->login_type = NULL; + obj->api_version_major = 0; + obj->api_version_minor = 0; + obj->timestamp = 0; + obj->val_8b = 0; + obj->val_8c = 0; + obj->val_8d = 0; + obj->val_8e = 0; + obj->volume_serial = 0; + obj->val_90 = 0; + obj->hasp_handle = 0; + + return obj; +} + +void sec_hasp_object_login_req_free(struct sec_hasp_object_login_req* obj) +{ + if (obj->username) { + free(obj->username); + } + + if (obj->machine_name) { + free(obj->machine_name); + } + + if (obj->login_type) { + free(obj->login_type); + } +} + +size_t sec_hasp_object_login_req_encode(struct sec_hasp_object_login_req* obj, uint8_t* buffer, + size_t len) +{ + struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 18); + + /* populate right before encoding */ + obj->timestamp = (uint32_t) time(NULL); + + sec_hasp_asn1_object_add_int(store, 0x80, obj->pid); + sec_hasp_asn1_object_add_int(store, 0x81, obj->tid); + sec_hasp_asn1_object_add_int(store, 0x82, obj->hasp_uid); + sec_hasp_asn1_object_add_int(store, 0x83, obj->vendor_id); + sec_hasp_asn1_object_add_int(store, 0x84, obj->feature_id); + + sec_hasp_asn1_object_add_str(store, 0x85, obj->username); + sec_hasp_asn1_object_add_str(store, 0x86, obj->machine_name); + sec_hasp_asn1_object_add_str(store, 0x87, obj->login_type); + + sec_hasp_asn1_object_add_int(store, 0x88, obj->api_version_major); + sec_hasp_asn1_object_add_int(store, 0x89, obj->api_version_minor); + + sec_hasp_asn1_object_add_time(store, 0x8A, obj->timestamp); + + sec_hasp_asn1_object_add_int(store, 0x8B, obj->val_8b); + sec_hasp_asn1_object_add_int(store, 0x8C, obj->val_8c); + sec_hasp_asn1_object_add_int(store, 0x8D, obj->val_8d); + sec_hasp_asn1_object_add_int(store, 0x8E, obj->val_8e); + sec_hasp_asn1_object_add_int(store, 0x8F, obj->volume_serial); + sec_hasp_asn1_object_add_int(store, 0x90, obj->val_90); + sec_hasp_asn1_object_add_int(store, 0x91, obj->hasp_handle); + + return sec_hasp_asn1_encode(store, buffer, len); +} + +void sec_hasp_object_login_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_login_req* obj) +{ + struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 18); + + sec_hasp_asn1_object_set_int(store, 0x80); + sec_hasp_asn1_object_set_int(store, 0x81); + sec_hasp_asn1_object_set_int(store, 0x82); + sec_hasp_asn1_object_set_int(store, 0x83); + sec_hasp_asn1_object_set_int(store, 0x84); + + sec_hasp_asn1_object_set_str(store, 0x85); + sec_hasp_asn1_object_set_str(store, 0x86); + sec_hasp_asn1_object_set_str(store, 0x87); + + sec_hasp_asn1_object_set_int(store, 0x88); + sec_hasp_asn1_object_set_int(store, 0x89); + + sec_hasp_asn1_object_set_time(store, 0x8A); + + sec_hasp_asn1_object_set_int(store, 0x8B); + sec_hasp_asn1_object_set_int(store, 0x8C); + sec_hasp_asn1_object_set_int(store, 0x8D); + sec_hasp_asn1_object_set_int(store, 0x8E); + sec_hasp_asn1_object_set_int(store, 0x8F); + sec_hasp_asn1_object_set_int(store, 0x90); + sec_hasp_asn1_object_set_int(store, 0x91); + + sec_hasp_asn1_decode(store, buffer, len); + + obj->oid = store->oid; + + sec_hasp_asn1_object_get_int(store, 0x80, &obj->pid); + sec_hasp_asn1_object_get_int(store, 0x81, &obj->tid); + sec_hasp_asn1_object_get_int(store, 0x82, &obj->hasp_uid); + sec_hasp_asn1_object_get_int(store, 0x83, &obj->vendor_id); + sec_hasp_asn1_object_get_int(store, 0x84, &obj->feature_id); + + sec_hasp_asn1_object_get_str(store, 0x85, &obj->username); + sec_hasp_asn1_object_get_str(store, 0x86, &obj->machine_name); + sec_hasp_asn1_object_get_str(store, 0x87, &obj->login_type); + + sec_hasp_asn1_object_get_int(store, 0x88, &obj->api_version_major); + sec_hasp_asn1_object_get_int(store, 0x89, &obj->api_version_minor); + + sec_hasp_asn1_object_get_time(store, 0x8A, &obj->timestamp); + + sec_hasp_asn1_object_get_int(store, 0x8B, &obj->val_8b); + sec_hasp_asn1_object_get_int(store, 0x8C, &obj->val_8c); + sec_hasp_asn1_object_get_int(store, 0x8D, &obj->val_8d); + sec_hasp_asn1_object_get_int(store, 0x8E, &obj->val_8e); + sec_hasp_asn1_object_get_int(store, 0x8F, &obj->volume_serial); + sec_hasp_asn1_object_get_int(store, 0x90, &obj->val_90); + sec_hasp_asn1_object_get_int(store, 0x91, &obj->hasp_handle); +} \ No newline at end of file diff --git a/src/main/sec/hasp/lib/object/login-req.h b/src/main/sec/hasp/lib/object/login-req.h new file mode 100644 index 0000000..f9d0cf9 --- /dev/null +++ b/src/main/sec/hasp/lib/object/login-req.h @@ -0,0 +1,38 @@ +#ifndef SEC_HASP_OBJECT_LOGIN_REQ_H +#define SEC_HASP_OBJECT_LOGIN_REQ_H + +#include +#include + +struct sec_hasp_object_login_req { + uint16_t oid; + uint32_t pid; + uint32_t tid; + uint32_t hasp_uid; + uint32_t vendor_id; + uint32_t feature_id; + char* username; + char* machine_name; + char* login_type; + uint32_t api_version_major; + uint32_t api_version_minor; + uint32_t timestamp; + uint32_t val_8b; + uint32_t val_8c; + uint32_t val_8d; + uint32_t val_8e; + uint32_t volume_serial; + uint32_t val_90; + uint32_t hasp_handle; +}; + +struct sec_hasp_object_login_req* sec_hasp_object_login_req_init(); + +void sec_hasp_object_login_req_free(struct sec_hasp_object_login_req* obj); + +size_t sec_hasp_object_login_req_encode(struct sec_hasp_object_login_req* obj, uint8_t* buffer, + size_t len); + +void sec_hasp_object_login_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_login_req* obj); + +#endif diff --git a/src/main/sec/hasp/lib/server.c b/src/main/sec/hasp/lib/server.c new file mode 100644 index 0000000..3834571 --- /dev/null +++ b/src/main/sec/hasp/lib/server.c @@ -0,0 +1,162 @@ +#define LOG_MODULE "sec-hasp-server" + +#include +#include +#include +#include +#include +#include + +#include "sec/hasp/lib/handler.h" + +#include "util/log.h" + +#include "server.h" + +#define HASP_PORT 1947 +#define HASP_MAX_BUFFER 16384 + +static bool sec_hasp_server_run_s; +static bool sec_hasp_server_is_running_s; + +void sec_hasp_server_init(const uint8_t* key_data, size_t len) +{ + sec_hasp_handler_init(key_data, len); + sec_hasp_server_run_s = true; + sec_hasp_server_is_running_s = false; +} + +void sec_hasp_server_run() +{ + int fd = -1; + struct sockaddr_in addr; + struct sockaddr_in addr_remote; + socklen_t addr_len_remote; + int fd_remote = -1; + int retval; + struct sec_hasp_handler_transaction* transaction; + ssize_t recv_len; + + log_info("Setting up socket for server"); + + sec_hasp_server_is_running_s = true; + + transaction = sec_hasp_handler_alloc_transaction(HASP_MAX_BUFFER); + + fd = socket(AF_INET, SOCK_STREAM, 0); + + if (fd == -1) { + log_error("Opening socket failed: %s", strerror(errno)); + goto return_cleanup; + } + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + /* bind to localhost which limits accepting connections to localhost, only */ + addr.sin_addr.s_addr = htonl(0x7F000001); + addr.sin_port = htons(HASP_PORT); + + retval = bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)); + + if (retval == -1) { + log_error("Binding socket failed: %s", strerror(errno)); + goto return_cleanup; + } + + log_info("Running server..."); + + while (sec_hasp_server_run_s) { + /* a single connection is fine here */ + retval = listen(fd, 1); + + if (retval == -1) { + log_error("Listening for incoming connections failed: %s", strerror(errno)); + goto return_cleanup; + } + + /* got a connection */ + addr_len_remote = sizeof(addr_remote); + fd_remote = accept(fd, &addr_remote, &addr_len_remote); + + if (fd_remote == -1) { + log_error("Accepting incoming connection failed: %s", strerror(errno)); + goto return_cleanup; + } + + log_debug("Remote %X connected", addr_remote.sin_addr.s_addr); + + /* put the socket to the remote into non blocking mode */ + if (fcntl(fd_remote, F_SETFL, fcntl(fd_remote, F_GETFL) | O_NONBLOCK) < 0) { + log_error("Setting socket to non blocking failed: %s", strerror(errno)); + goto return_cleanup; + } + + while (sec_hasp_server_run_s) { + recv_len = recv(fd_remote, transaction->req, transaction->req_resp_max_size, 0); + + if (recv_len == -1) { + /* no data available, sleep to reduce cpu load and retry */ + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* 10 ms */ + usleep(1000 * 10); + continue; + } else if (errno == ECONNRESET) { + log_debug("Remote %X disconnected", addr_remote.sin_addr.s_addr); + close(fd_remote); + break; + } else { + log_error("Reading from connection failed: %s", strerror(errno)); + goto return_cleanup; + } + } + + if (recv_len == 0) { + /* remote disconnected */ + log_debug("Remote %X disconnected", addr_remote.sin_addr.s_addr); + close(fd_remote); + break; + } + + log_debug("Received data: %d bytes", recv_len); + + sec_hasp_handler_do_transaction(transaction); + + /* send reply */ + recv_len = send(fd_remote, transaction->resp, transaction->resp->header.packet_size, 0); + + if (recv_len == -1) { + if (errno == ECONNRESET) { + log_debug("Remote %X disconnected", addr_remote.sin_addr.s_addr); + close(fd_remote); + break; + } else { + log_error("Writing to connection failed: %s", strerror(errno)); + goto return_cleanup; + } + } + } + } + +return_cleanup: + if (fd_remote != -1) { + close(fd); + } + + if (fd != -1) { + close(fd); + } + + sec_hasp_handler_free_transaction(transaction); + + sec_hasp_server_is_running_s = false; +} + +bool sec_hasp_server_is_running(void) +{ + return sec_hasp_server_is_running_s; +} + +void sec_hasp_server_shutdown(void) +{ + sec_hasp_server_run_s = false; +} \ No newline at end of file diff --git a/src/main/sec/hasp/lib/server.h b/src/main/sec/hasp/lib/server.h new file mode 100644 index 0000000..f7e9eae --- /dev/null +++ b/src/main/sec/hasp/lib/server.h @@ -0,0 +1,33 @@ +#ifndef SEC_HASP_SERVER_H +#define SEC_HASP_SERVER_H + +#include +#include +#include + +/** + * Initialize the hasp server module. This just initializes the hasp + * dongle emulator module + * + * @param key_data Pointer to loaded key data (attributes, key table) + * @param len Length of the buffer + */ +void sec_hasp_server_init(const uint8_t* key_data, size_t len); + +/** + * Run the server. This call blocks until the server is shut down. + * Recommended to run this in a separate thread. + */ +void sec_hasp_server_run(void); + +/** + * Check if the server is running + */ +bool sec_hasp_server_is_running(void); + +/** + * Signal a shut down to the server + */ +void sec_hasp_server_shutdown(void); + +#endif diff --git a/src/main/sec/hasp/lib/util.c b/src/main/sec/hasp/lib/util.c new file mode 100644 index 0000000..5f5941b --- /dev/null +++ b/src/main/sec/hasp/lib/util.c @@ -0,0 +1,15 @@ +#include + +#include "util/rand.h" + +#include "util.h" + +uint32_t sec_hasp_util_make_fake_handle_value() +{ + return util_rand_gen_32(); +} + +uint32_t sec_hasp_util_get_timestamp() +{ + return (uint32_t) time(NULL); +} \ No newline at end of file diff --git a/src/main/sec/hasp/lib/util.h b/src/main/sec/hasp/lib/util.h new file mode 100644 index 0000000..c01c4ad --- /dev/null +++ b/src/main/sec/hasp/lib/util.h @@ -0,0 +1,10 @@ +#ifndef SEC_HASP_UTIL_H +#define SEC_HASP_UTIL_H + +#include + +uint32_t sec_hasp_util_make_fake_handle_value(); + +uint32_t sec_hasp_util_get_timestamp(); + +#endif diff --git a/src/main/sec/hasp/old/hasp.c b/src/main/sec/hasp/old/hasp.c new file mode 100644 index 0000000..b365255 --- /dev/null +++ b/src/main/sec/hasp/old/hasp.c @@ -0,0 +1,87 @@ +#define LOG_MODULE "sec-hasp" + +#include + +#include "sec/hasp/old/hasp.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +struct sec_hasp_key_table { + uint32_t nkeys; + struct sec_hasp_key* keys; +}; + +/* index 0 (type): 1 = dev, 2 = retail + index 1 (language): 3001 = english */ +/* static const uint32_t sec_hasp_features[] = {2, 3001}; */ +static const uint32_t sec_hasp_key_id = 0xDEADBEEF; +static struct sec_hasp_key_table sec_hasp_keys; + +void sec_hasp_init(const uint8_t* key_data, size_t len) +{ + sec_hasp_keys.nkeys = len / sizeof(struct sec_hasp_key); + sec_hasp_keys.keys = + util_xmalloc(sizeof(struct sec_hasp_key) * sec_hasp_keys.nkeys); + + memcpy(sec_hasp_keys.keys, key_data, + sec_hasp_keys.nkeys * sizeof(struct sec_hasp_key)); + + log_info("Loaded %d keys", sec_hasp_keys.nkeys); +} + +int sec_hasp_api_login(int feature, int vendor_code, int* handle) +{ + *handle = (int) &sec_hasp_key_id; + + log_debug("login, feature %d, vendor_code %d, ret handle 0x%X", feature, + vendor_code, *handle); + + return 0; +} + +int sec_hasp_api_logout(int handle) +{ + if (handle != (int) &sec_hasp_key_id) { + log_error("Logout of unknown handle 0x%X", handle); + } else { + log_debug("Logout: 0x%X", handle); + } + + return 0; +} + +unsigned int sec_hasp_api_getid(void) +{ + return sec_hasp_key_id; +} + +int sec_hasp_api_decrypt(int handle, void* buffer, size_t length) +{ + char* buf; + + if (handle != (int) &sec_hasp_key_id) { + log_error("Unknown handle 0x%X sending decrypt request, ignored"); + return -1; + } + + for (uint32_t i = 0; i < sec_hasp_keys.nkeys; i++) { + if (!memcmp(buffer, sec_hasp_keys.keys[i].req, + sizeof(sec_hasp_keys.keys[i].req))) { + log_debug("Decrypt %u -> %u", + *((uint64_t*) sec_hasp_keys.keys[i].req), + *((uint64_t*) sec_hasp_keys.keys[i].resp)); + memcpy(buffer, sec_hasp_keys.keys[i].resp, + sizeof(sec_hasp_keys.keys[i].resp)); + return 0; + } + } + + buf = util_str_buffer(buffer, length); + + log_warn("Missing key for request %s", buf); + free(buf); + + return 0; +} \ No newline at end of file diff --git a/src/main/sec/hasp/old/hasp.h b/src/main/sec/hasp/old/hasp.h new file mode 100644 index 0000000..582ae0c --- /dev/null +++ b/src/main/sec/hasp/old/hasp.h @@ -0,0 +1,35 @@ +/** + * Hasp emulator (Fiesta 2 and up) + */ +#ifndef SEC_HASP_H +#define SEC_HASP_H + +#include +#include + +/** + * A single entry in the key table + */ +struct sec_hasp_key { + uint8_t req[64]; + uint8_t resp[64]; +} __attribute__((packed)); + +/** + * Initialize the hasp emulation module. The dongle for this + * was used on Prime and up + * + * @param key_data Pointer to loaded key data (key table) + * @param len Length of the buffer + */ +void sec_hasp_init(const uint8_t* key_data, size_t len); + +int sec_hasp_api_login(int feature, int vendor_code, int* handle); + +int sec_hasp_api_logout(int handle); + +unsigned int sec_hasp_api_getid(void); + +int sec_hasp_api_decrypt(int handle, void* buffer, size_t length); + +#endif \ No newline at end of file diff --git a/src/main/sec/hasp/server/main.c b/src/main/sec/hasp/server/main.c new file mode 100644 index 0000000..7e1ddb8 --- /dev/null +++ b/src/main/sec/hasp/server/main.c @@ -0,0 +1,7 @@ +#include "sec/hasp/lib/server.h" + +int main(int argc, char** argv) +{ + sec_hasp_server_init(NULL, 0); + sec_hasp_server_run(); +} \ No newline at end of file diff --git a/src/main/sec/lockchip/lockchip-defs.h b/src/main/sec/lockchip/lockchip-defs.h new file mode 100644 index 0000000..438537f --- /dev/null +++ b/src/main/sec/lockchip/lockchip-defs.h @@ -0,0 +1,64 @@ +#ifndef SEC_LOCKCHIP_DEFS_H +#define SEC_LOCKCHIP_DEFS_H + +#include + +/* List of games using the old type mk3 lockchip board */ +enum sec_lockchip_defs_games { + SEC_LOCK_CHIP_DEFS_GAME_3RD_SE = 0, + SEC_LOCK_CHIP_DEFS_GAME_COLLECTION = 1, + SEC_LOCK_CHIP_DEFS_GAME_PERFECT_COLLECTION = 2, + SEC_LOCK_CHIP_DEFS_GAME_EXTRA_PROTO = 3, + SEC_LOCK_CHIP_DEFS_GAME_PREMIERE = 4, + SEC_LOCK_CHIP_DEFS_GAME_PREX = 5, + SEC_LOCK_CHIP_DEFS_GAME_REBIRTH = 6, + SEC_LOCK_CHIP_DEFS_GAME_PREMIERE_2 = 7, + /* Extra Plus */ + SEC_LOCK_CHIP_DEFS_GAME_PREX_2_BETA = 8, + SEC_LOCK_CHIP_DEFS_GAME_PREX_2 = 9, + SEC_LOCK_CHIP_DEFS_GAME_PREMIERE_3 = 10, + SEC_LOCK_CHIP_DEFS_GAME_PREX_3 = 11, + SEC_LOCK_CHIP_DEFS_GAME_EXTRA = 12, + /* NXA for mk3, funbox... */ + SEC_LOCK_CHIP_DEFS_GAME_BOOTLEGS = 13, + SEC_LOCK_CHIP_DEFS_GAME_EXCEED = 14, + SEC_LOCK_CHIP_DEFS_GAME_COUNT = 15, +}; + +/** List of lockchip transforms of all pump games that used it. + */ +static const uint8_t sec_lockchip_defs_transforms + [SEC_LOCK_CHIP_DEFS_GAME_COUNT][8] = { + /* 3rd SE */ + {0xF0, 0x1C, 0xFE, 0x03, 0x81, 0x40, 0x38, 0xF8}, + /* Collection */ + {0xF0, 0x1C, 0xFE, 0x03, 0x81, 0x40, 0x38, 0xF8}, + /* Perfect Collection */ + {0xF0, 0x1C, 0xFE, 0x03, 0x81, 0x40, 0x38, 0xF8}, + /* Extra Proto */ + {0xF8, 0x82, 0x70, 0x0C, 0xFD, 0xC1, 0x20, 0xE0}, + /* Premiere */ + {0xE0, 0x78, 0x7C, 0xFD, 0xF1, 0xF2, 0xC2, 0xC0}, + /* Prex */ + {0xE0, 0x78, 0x7C, 0xFD, 0xF1, 0xF2, 0xC2, 0xC0}, + /* Rebirth */ + {0xFC, 0xF9, 0x08, 0x10, 0xE2, 0xC2, 0x40, 0x80}, + /* Premiere 2 */ + {0xFC, 0x03, 0xE1, 0x20, 0x38, 0x78, 0x70, 0xF0}, + /* Prex 2 Beta */ + {0xE0, 0x38, 0x78, 0x81, 0x03, 0xFE, 0x0C, 0xF0}, + /* Prex 2 */ + {0xE0, 0x38, 0x78, 0x81, 0x03, 0xFE, 0x0C, 0xF0}, + /* Premiere 3 */ + {0x02, 0xC1, 0xF9, 0x78, 0x7C, 0x1C, 0x10, 0xF0}, + /* Prex 3 */ + {0xF0, 0xE1, 0xF9, 0x78, 0x7C, 0xFE, 0xC2, 0xC0}, + /* Extra */ + {0xF8, 0x82, 0x70, 0x0C, 0xFD, 0xC1, 0x20, 0xE0}, + /* Bootlegs */ + {0x02, 0xC1, 0xF9, 0x78, 0x7C, 0x1C, 0x10, 0xF0}, + /* Exceed */ + {0xF0, 0x78, 0xF9, 0xFD, 0x1C, 0x20, 0xC2, 0x02}, +}; + +#endif \ No newline at end of file diff --git a/src/main/sec/lockchip/lockchip.c b/src/main/sec/lockchip/lockchip.c new file mode 100644 index 0000000..cf8e7f6 --- /dev/null +++ b/src/main/sec/lockchip/lockchip.c @@ -0,0 +1,87 @@ +#define LOG_MODULE "sec-lockchip" + +#include "sec/lockchip/lockchip.h" + +static const uint8_t sec_lockchip_initial_sbox[8] = { + 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x7f +}; + +static const uint8_t* sec_lockchip_transform; +static uint8_t sec_lockchip_state; + +static void sec_lockchip_apply_initial_sbox(void) +{ + uint8_t r = 0; + + for (uint8_t i = 0; i < 8; i++) { + + if (sec_lockchip_state & (1 << i)) { + r ^= sec_lockchip_initial_sbox[i]; + } + } + + sec_lockchip_state = r; +} + +static uint8_t sec_lockchip_comp_sbox_ceof(uint8_t sel, uint8_t bit) +{ + uint8_t r ; + + if (!sel) { + return sec_lockchip_transform[bit]; + } + + r = sec_lockchip_comp_sbox_ceof((sel - 1) & 7, (bit - 1) & 7); + r = (r << 1) | (((r >> 7) ^ (r >> 6)) & 1); + + if (bit != 7) { + return r; + } + + return r ^ sec_lockchip_comp_sbox_ceof(sel, 0); +} + +static void sec_lockchip_apply_bit_sbox(uint8_t bit) +{ + uint8_t r = 0; + + for (uint8_t i = 0; i < 8; i++) { + + if (sec_lockchip_state & (1 << i)) { + r ^= sec_lockchip_comp_sbox_ceof(bit, i); + } + } + + sec_lockchip_state = r; +} + +void sec_lockchip_init(const uint8_t* transform) +{ + sec_lockchip_transform = transform; + sec_lockchip_state = 0; +} + +void sec_lockchip_start(void) +{ + sec_lockchip_state = 0xFC; +} + +uint8_t sec_lockchip_step(uint8_t data) +{ + uint8_t result = 0; + + for (uint8_t bit = 0; bit < 8; bit++) { + + if (bit == 0) { + sec_lockchip_apply_initial_sbox(); + } + + result ^= (((sec_lockchip_state >> bit) & 1) << bit); + + if (((data >> bit) & 1) == 0) { + sec_lockchip_apply_bit_sbox(bit); + } + } + + return result; +} \ No newline at end of file diff --git a/src/main/sec/lockchip/lockchip.h b/src/main/sec/lockchip/lockchip.h new file mode 100644 index 0000000..9034763 --- /dev/null +++ b/src/main/sec/lockchip/lockchip.h @@ -0,0 +1,31 @@ +/** + * Lockchip (MK3 games) emulator + * + * Credits to TheSchaf for the emulation code and transform data + */ +#ifndef SEC_LOCKCHIP_H +#define SEC_LOCKCHIP_H + +#include + +/** + * Initialize (or reset) the lockchip emulation module + * + * @param transform Pointer to a transform to use for the step calls + */ +void sec_lockchip_init(const uint8_t* transform); + +/** + * Start lockchip emulation and set the initial state before calling step + */ +void sec_lockchip_start(void); + +/** + * Execute a step on some data + * + * @param data Input data to transform + * @return Transformed output + */ +uint8_t sec_lockchip_step(uint8_t data); + +#endif \ No newline at end of file diff --git a/src/main/sec/microdog34/microdog34.c b/src/main/sec/microdog34/microdog34.c new file mode 100644 index 0000000..a9902aa --- /dev/null +++ b/src/main/sec/microdog34/microdog34.c @@ -0,0 +1,399 @@ +#define LOG_MODULE "sec-microdog34" + +#include +#include + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +#define IOCTL_REQUEST_MD_XACT 0x6B00 +#define GOLD_SALT 0x646C6F47 +#define MAGIC 0x484D + +enum sec_microdog34_req_opcode { + SEC_MICRODOG34_OP_DOG_CHECK = 0x01, + SEC_MICRODOG34_OP_READ_DOG = 0x02, + SEC_MICRODOG34_OP_WRITE_DOG = 0x03, + SEC_MICRODOG34_OP_CONVERT = 0x04, + SEC_MICRODOG34_OP_SET_PASS = 0x07, + SEC_MICRODOG34_OP_SET_SHARE = 0x08, + SEC_MICRODOG34_OP_GET_LOCK_NO = 0x0B, + SEC_MICRODOG34_OP_LOGIN = 0x14, + SEC_MICRODOG34_OP_DOG_CASCADE = 0x15, + SEC_MICRODOG34_OP_RAINBOW_TABLE_ADD = 0x539, + SEC_MICRODOG34_OP_DOG_SERIAL = 0x53A, + SEC_MICRODOG34_OP_SET_MFG_SERIAL = 0x53B, + SEC_MICRODOG34_OP_SET_VID = 0x53C, + SEC_MICRODOG34_OP_RELOAD_RAINBOW_TABLE = 0x53D +}; + +struct sec_microdog34_req { + uint16_t magic; + uint16_t opcode; + uint32_t dog_serial; + uint32_t mask_key; + uint16_t dog_addr; + uint16_t dog_bytes; + uint8_t dog_data[256]; + uint32_t dog_password; + uint8_t host_id; +} __attribute__((__packed__)); + +enum sec_microdog34_resp_code { + SEC_MICRODOG34_RESP_NO_ERR = 0, + SEC_MICRODOG34_RESP_ERR_PASS = 0x2745 +}; + +struct sec_microdog34_resp { + uint32_t dog_serial; + uint32_t return_code; + uint8_t dog_data[200]; +} __attribute__((__packed__)); + +struct sec_microdog34_header { + uint32_t serial; + uint32_t password; + uint8_t vendor_id[8]; + uint32_t mfg_serial; + uint8_t flash_memory[200]; + uint32_t num_keys; +}; + +struct sec_microdog34_key { + uint32_t response; + uint32_t algorithm; + uint32_t req_len; + uint8_t request[64]; +}; + +static void sec_microdog34_dispatch(struct sec_microdog34_req* req, + struct sec_microdog34_resp* resp); +static void sec_microdog34_crypt_req(struct sec_microdog34_req* req); +static void sec_microdog34_crypt_resp(struct sec_microdog34_req* req, + struct sec_microdog34_resp* resp); +static void sec_microdog34_dump_req(struct sec_microdog34_req* req); +static void sec_microdog34_dump_resq(struct sec_microdog34_resp* resp); +static uint32_t sec_microdog34_convert_req(const uint8_t* req_data, + uint16_t req_len); + +static struct sec_microdog34_header sec_microdog34_header; +static struct sec_microdog34_key* sec_microdog34_key_table; + +static uint8_t sec_microdog34_share; + +void sec_microdog34_init(const uint8_t* key_data, size_t len) +{ + memcpy(&sec_microdog34_header, key_data, + sizeof(struct sec_microdog34_header)); + + if (len - sizeof(struct sec_microdog34_header) < + sec_microdog34_header.num_keys * + sizeof(struct sec_microdog34_key)) { + log_error("Loading key table failed, incomplete key table " + "(num_keys entry: %d, num_keys size: %d", + sec_microdog34_header.num_keys, + (len - sizeof(struct sec_microdog34_header)) / + sizeof(struct sec_microdog34_key)); + return; + } + + sec_microdog34_key_table = util_xmalloc(sec_microdog34_header.num_keys * + sizeof(struct sec_microdog34_key)); + + memcpy(sec_microdog34_key_table, + key_data + sizeof(struct sec_microdog34_header), + sec_microdog34_header.num_keys * sizeof(struct sec_microdog34_key)); + + log_info("Loaded %d keys, serial 0x%X, password 0x%X", + sec_microdog34_header.num_keys, sec_microdog34_header.serial, + sec_microdog34_header.password); + + sec_microdog34_share = 0; +} + +int sec_microdog34_process(int request, void* data) +{ + if (request == IOCTL_REQUEST_MD_XACT) { + struct sec_microdog34_req req; + struct sec_microdog34_resp resp; + + memset(&resp, 0, sizeof(struct sec_microdog34_resp)); + + // where to get the data? weird stuff, but that's how it's done + // it really has to be like that, otherwise we get trash from data + uint32_t req_data_offset = *(unsigned int*) data; + memcpy(&req, (void*) req_data_offset, + sizeof(struct sec_microdog34_req)); + + sec_microdog34_crypt_req(&req); + sec_microdog34_dispatch(&req, &resp); + sec_microdog34_crypt_resp(&req, &resp); + + // again, same as req data + // it really has to be like that, otherwise we get trash from data + uint32_t resp_data_offset = *(unsigned int*) data - 272; + memcpy((void*) resp_data_offset, &resp, + sizeof(struct sec_microdog34_resp)); + + return 0; + } + + return -1; +} + +static void sec_microdog34_dispatch(struct sec_microdog34_req* req, + struct sec_microdog34_resp* resp) +{ + struct sec_microdog34_key* key; + + resp->dog_serial = req->dog_serial; + + if (req->magic != MAGIC) { + log_error("Bad magic 0x%X for request", req->magic); + } + + sec_microdog34_dump_req(req); + + switch (req->opcode) { + case SEC_MICRODOG34_OP_DOG_CHECK: + log_debug("SEC_MICRODOG34_OP_DOG_CHECK"); + break; + + case SEC_MICRODOG34_OP_READ_DOG: + log_debug("SEC_MICRODOG34_OP_READ_DOG"); + + if (req->dog_password == sec_microdog34_header.password) { + memcpy(resp->dog_data, + sec_microdog34_header.flash_memory + req->dog_addr, + req->dog_bytes); + } else { + resp->return_code = SEC_MICRODOG34_RESP_ERR_PASS; + } + + break; + + case SEC_MICRODOG34_OP_WRITE_DOG: + log_debug("SEC_MICRODOG34_OP_WRITE_DOG"); + + if (req->dog_password == sec_microdog34_header.password) { + memcpy(sec_microdog34_header.flash_memory + req->dog_addr, + req->dog_data, req->dog_bytes); + } else { + resp->return_code = SEC_MICRODOG34_RESP_ERR_PASS; + } + + break; + + case SEC_MICRODOG34_OP_CONVERT: + log_debug("SEC_MICRODOG34_OP_CONVERT"); + + uint32_t resp_data = sec_microdog34_convert_req(req->dog_data, + req->dog_bytes); + memcpy(resp->dog_data, &resp_data, sizeof(uint32_t)); + + break; + + case SEC_MICRODOG34_OP_SET_PASS: + log_debug("SEC_MICRODOG34_OP_SET_PASS: 0x%08X", + *((uint32_t*) req->dog_data)); + + if (req->dog_password == sec_microdog34_header.password) { + sec_microdog34_header.password = *((uint32_t*) req->dog_data); + } + else + resp->return_code = SEC_MICRODOG34_RESP_ERR_PASS; + + break; + + case SEC_MICRODOG34_OP_SET_SHARE: + log_debug("SEC_MICRODOG34_OP_SET_SHARE"); + + sec_microdog34_share = req->dog_data[0]; + resp->dog_data[0] = sec_microdog34_share; + + break; + + case SEC_MICRODOG34_OP_GET_LOCK_NO: + log_debug("SEC_MICRODOG34_OP_GET_LOCK_NO: 0x%08X", + sec_microdog34_header.mfg_serial); + + memcpy(resp->dog_data, &sec_microdog34_header.mfg_serial, 4); + + break; + + case SEC_MICRODOG34_OP_LOGIN: + log_debug("SEC_MICRODOG34_OP_LOGIN"); + + memcpy(resp->dog_data, sec_microdog34_header.vendor_id, + sizeof(sec_microdog34_header.vendor_id)); + + break; + + case SEC_MICRODOG34_OP_DOG_CASCADE: + log_debug("SEC_MICRODOG34_OP_DOG_CASCADE"); + + resp->dog_data[0] = req->dog_data[0]; + + break; + + case SEC_MICRODOG34_OP_RAINBOW_TABLE_ADD: + log_debug("SEC_MICRODOG34_OP_RAINBOW_TABLE_ADD"); + + /* expand table */ + sec_microdog34_key_table = util_xrealloc(sec_microdog34_key_table, + (sec_microdog34_header.num_keys + 1) * + sizeof(struct sec_microdog34_key)); + + key = &sec_microdog34_key_table[sec_microdog34_header.num_keys]; + key->response = req->dog_password; + /* algorithm(last 4 bytes of flash memory) */ + key->algorithm = + *((uint32_t*) (sec_microdog34_header.flash_memory + 196)); + key->req_len = req->dog_bytes; + memcpy(key->request, req->dog_data, sizeof(key->request)); + + sec_microdog34_header.num_keys++; + + break; + + case SEC_MICRODOG34_OP_DOG_SERIAL: + log_debug("SEC_MICRODOG34_OP_DOG_SERIAL: 0x%08X", + *((uint32_t*) req->dog_data)); + + sec_microdog34_header.serial = *((uint32_t*) req->dog_data); + + break; + + case SEC_MICRODOG34_OP_SET_MFG_SERIAL: + log_debug("SEC_MICRODOG34_OP_SET_MFG_SERIAL: 0x%08X ", + *((uint32_t*) req->dog_data)); + + sec_microdog34_header.mfg_serial = *((uint32_t*) req->dog_data); + + break; + + case SEC_MICRODOG34_OP_SET_VID: + log_debug("SEC_MICRODOG34_OP_SET_VID"); + + memcpy(sec_microdog34_header.vendor_id, req->dog_data, + sizeof(sec_microdog34_header.vendor_id)); + + break; + + case SEC_MICRODOG34_OP_RELOAD_RAINBOW_TABLE: + log_debug("SEC_MICRODOG34_OP_RELOAD_RAINBOW_TABLE"); + + /* nothing to load here */ + break; + + default: + log_warn("Unsupported opcode: %04X", req->opcode); + break; + } + + sec_microdog34_dump_resq(resp); +} + +static void sec_microdog34_crypt_req(struct sec_microdog34_req* req) +{ + uint32_t tmp_mask = (req->mask_key + GOLD_SALT) & 0xFFFFFFFF; + uint8_t tmb_mask[4] = {0, 0, 0, 0}; + memcpy(tmb_mask, &tmp_mask, 4); + + req->dog_addr ^= (tmp_mask & 0xFFFF); + req->dog_bytes ^= (tmp_mask & 0xFFFF); + req->dog_password ^= tmp_mask; + req->host_id ^= (tmp_mask & 0xFF); + + for (int i = 0 ; i < sizeof(req->dog_data); i++) { + req->dog_data[i] ^= tmb_mask[i % 4]; + } +} + +static void sec_microdog34_crypt_resp(struct sec_microdog34_req* req, + struct sec_microdog34_resp* resp) +{ + uint32_t tmp_mask = (req->mask_key + GOLD_SALT) & 0xFFFFFFFF; + uint8_t tmb_mask[4] = {0, 0, 0, 0}; + memcpy(tmb_mask, &tmp_mask, 4); + + for (int i = 0 ; i < sizeof(resp->dog_data); i++) { + resp->dog_data[i] ^= tmb_mask[i % 4]; + } +} + +static void sec_microdog34_dump_req(struct sec_microdog34_req* req) +{ + char* data_tmp = util_str_buffer(req->dog_data, sizeof(req->dog_data)); + + log_debug( + "Dog request:\n" + "magic: 0x%X\n" + "opcode: 0x%X\n" + "dog_serial: 0x%X\n" + "mask_key: 0x%X\n" + "dog_addr: 0x%X\n" + "dog_bytes: 0x%X\n" + "dog_data: %s\n" + "dog_pass: 0x%X\n" + "host_id: 0x%X", + req->magic, + req->opcode, + req->dog_serial, + req->mask_key, + req->dog_addr, + req->dog_bytes, + data_tmp, + req->dog_password, + req->host_id); + + free(data_tmp); +} + +static void sec_microdog34_dump_resq(struct sec_microdog34_resp* resp) +{ + char* data_tmp = util_str_buffer(resp->dog_data, sizeof(resp->dog_data)); + + log_debug( + "Dog response:\n" + "dog_serial: 0x%X\n" + "return_code: 0x%X\n" + "dog_data: %s\n", + resp->dog_serial, + resp->return_code, + data_tmp); + + free(data_tmp); +} + +static uint32_t sec_microdog34_convert_req(const uint8_t* req_data, + uint16_t req_len) +{ + uint32_t cur_algo; + + cur_algo = 0; + memcpy(&cur_algo, sec_microdog34_header.flash_memory + 196, 4); + + for (uint32_t i = 0; i < sec_microdog34_header.num_keys; i++) { + struct sec_microdog34_key* key = &sec_microdog34_key_table[i]; + + if (key->algorithm == cur_algo) { + + if (key->req_len == req_len) { + + if (!memcmp(key->request, req_data, req_len)) { + char* tmp = util_str_buffer(req_data, req_len); + log_debug("Converting: %s ==> %X", tmp, key->response); + free(tmp); + return key->response; + } + } + } + } + + char* tmp = util_str_buffer(req_data, req_len); + log_warn("Converting request %s failed, no matching response found", tmp); + free(tmp); + return 0; +} \ No newline at end of file diff --git a/src/main/sec/microdog34/microdog34.h b/src/main/sec/microdog34/microdog34.h new file mode 100644 index 0000000..04d75d8 --- /dev/null +++ b/src/main/sec/microdog34/microdog34.h @@ -0,0 +1,51 @@ +/** + * Microdog 3.4 emulator + * + * Credits to batteryshark for the emulation code and key files + */ +#ifndef SEC_MICRODOG34_H +#define SEC_MICRODOG34_H + +/** + * Header of a key file containing attributes of the dongle. This is followed + * by an arbitrary number of keys + */ +struct sec_microdog34_header { + uint32_t serial; + uint32_t password; + uint8_t vendor_id[8]; + uint32_t mfg_serial; + uint8_t flash_memory[200]; + uint32_t num_keys; +}; + +/** + * A single entry in the key table (comes after the header) + */ +struct sec_microdog34_key { + uint32_t response; + uint32_t algorithm; + uint32_t req_len; + uint8_t request[64]; +}; + +/** + * Initialize the microdog (3.4) emulation module. The dongle for this + * was used on Exceed2, Zero and NX + * + * @param key_data Pointer to loaded key data (dog attributes, key table) + * @param len Length of the buffer + */ +void sec_microdog34_init(const uint8_t* key_data, size_t len); + +/** + * Process an incoming request to the dongle + * + * @param request IOCTL request for the dongle + * @param data Pointer to a buffer with request data. Response is returned + * to the same buffer (request overwritten) + * @return 0 and success, -1 on failure + */ +int sec_microdog34_process(int request, void* data); + +#endif \ No newline at end of file diff --git a/src/main/sec/microdog40/microdog40.c b/src/main/sec/microdog40/microdog40.c new file mode 100644 index 0000000..18eb43d --- /dev/null +++ b/src/main/sec/microdog40/microdog40.c @@ -0,0 +1,427 @@ +#define LOG_MODULE "sec-microdog40" + +#include + +#include "crypt/aes.h" +#include "crypt/md5.h" + +#include "sec/microdog40/microdog40.h" + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +#define REQHEAD_SIZE 0x120 +#define REQTAIL_SIZE 0x10 +#define PROTOCOL_VERSION 0x11 + +enum sec_microdog40_req_opcode { + SEC_MICRODOG40_REQ_OPCODE_SET_SHARE = 0x08, + SEC_MICRODOG40_REQ_OPCODE_GET_LOCK_NO = 0x0B, + SEC_MICRODOG40_REQ_OPCODE_GET_ID = 0x14, + SEC_MICRODOG40_REQ_OPCODE_CONVERT = 0x40, + SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_1 = 0x65, + SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_2 = 0x67, + SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_3 = 0x66 +}; + +struct sec_microdog40_month_key_hash_input { + uint8_t ssk_prefix[25]; + uint16_t year; + uint8_t const45; + uint16_t month; +} __attribute((__packed__)); + +static const uint8_t sec_microdog40_shared_secret[30] = { + 0x2A, 0x2F, 0xED, 0x5E, 0x49, + 0x26, 0x40, 0x19, 0x40, 0x40, + 0xE2, 0x51, 0xAA, 0xFA, 0xDB, + 0xCB, 0x67, 0x21, 0x4C, 0xA4, + 0x10, 0x7E, 0x51, 0x22, 0x25, + 0x11, 0x2B, 0x3C, 0x46, 0x5E +}; + +static const uint16_t sec_microdog40_magic = 0x484D; + +static struct sec_microdog40_header sec_microdog40_header; +static struct sec_microdog40_key* sec_microdog40_key_table; + +static uint8_t sec_microdog40_share; + +static void sec_microdog40_log_req(const struct sec_microdog40_req* req) +{ + char* data_tmp = util_str_buffer(req->payload, sizeof(req->payload)); + + log_debug( + "Processing request:\n" + "magic: 0x%X\n" + "req_type: 0x%X\n" + "mask_key1: 0x%X\n" + "dog_cascade: 0x%X\n" + "mfg_serial: 0x%X\n" + "mask_key2: 0x%X\n" + "dog_addr: 0x%X\n" + "payload_size: %d\n" + "mask_key3: 0x%X\n" + "payload: %s\n" + "dog_password: 0x%X\n" + "host_id: 0x%X\n" + "mask_key4: 0x%X\n" + "timestamp.year: %d\n" + "timestamp.month: %d\n" + "timestamp.day: %d\n" + "timestamp.hour: %d\n" + "timestamp.minute: %d\n" + "timestamp.second: %d", + req->magic, + req->req_type, + req->mask_key1, + req->dog_cascade, + req->mfg_serial, + req->mask_key2, + req->dog_addr, + req->payload_size, + req->mask_key3, + data_tmp, + req->dog_password, + req->host_id, + req->mask_key4, + req->timestamp.year, + req->timestamp.month, + req->timestamp.day, + req->timestamp.hour, + req->timestamp.minute, + req->timestamp.second); + + free(data_tmp); +} + +static void sec_microdog40_get_month_key(uint8_t* month_key, + const struct sec_microdog40_timestamp* timestamp) +{ + struct sec_microdog40_month_key_hash_input hash_in; + + memcpy(hash_in.ssk_prefix, sec_microdog40_shared_secret, + sizeof(hash_in.ssk_prefix)); + hash_in.year = timestamp->year; + hash_in.month = timestamp->month; + hash_in.const45 = 45; + + crypt_md5_hash(month_key, (const uint8_t*) &hash_in, + sizeof(struct sec_microdog40_month_key_hash_input)); +} + +static void sec_microdog40_dec_req(const struct sec_microdog40_req* enc_req, + struct sec_microdog40_req* dec_req) +{ + uint8_t key[16]; + + crypt_md5_hash(key, sec_microdog40_shared_secret, + sizeof(sec_microdog40_shared_secret)); + crypt_aes_dec(key, CRYPT_AES_KEY_LENGTH_16_BYTES, ((uint8_t *) dec_req) + + REQHEAD_SIZE, ((uint8_t*) enc_req) + REQHEAD_SIZE, REQTAIL_SIZE); + + sec_microdog40_get_month_key(key, &dec_req->timestamp); + crypt_aes_dec(key, CRYPT_AES_KEY_LENGTH_16_BYTES, ((uint8_t *) dec_req), + ((uint8_t*) enc_req), REQHEAD_SIZE); + + dec_req->magic ^= dec_req->mask_key4; + dec_req->req_type ^= dec_req->mask_key4; + dec_req->mask_key1 ^= dec_req->mask_key4; + dec_req->dog_cascade ^= dec_req->mask_key4; + dec_req->mfg_serial ^= dec_req->mask_key4; + dec_req->mask_key2 ^= dec_req->mask_key4; + dec_req->dog_addr ^= dec_req->mask_key4; + dec_req->payload_size ^= dec_req->mask_key4; + dec_req->mask_key3 ^= dec_req->mask_key4; + dec_req->dog_password ^= dec_req->mask_key4; + dec_req->host_id ^= dec_req->mask_key4; + + for (int i = 0 ; i < 64 ; i++) { + ((uint32_t *) dec_req->payload)[i] ^= dec_req->mask_key4; + } + + dec_req->magic ^= dec_req->mask_key3; + dec_req->req_type ^= dec_req->mask_key3; + dec_req->mask_key1 ^= dec_req->mask_key3; + dec_req->dog_cascade ^= dec_req->mask_key3; + dec_req->mfg_serial ^= dec_req->mask_key3; + dec_req->mask_key2 ^= dec_req->mask_key3; + dec_req->dog_addr ^= dec_req->mask_key3; + dec_req->payload_size ^= dec_req->mask_key3; + + dec_req->magic ^= dec_req->mask_key2; + dec_req->req_type ^= dec_req->mask_key2; + dec_req->mask_key1 ^= dec_req->mask_key2; + dec_req->dog_cascade ^= dec_req->mask_key2; + dec_req->mfg_serial ^= dec_req->mask_key2; + + dec_req->magic ^= dec_req->mask_key1; + dec_req->req_type ^= dec_req->mask_key1; +} + +/* unused */ +/* +static void sec_microdog40_dec_resp(const struct sec_microdog40_resp* enc_resp, + struct sec_microdog40_resp* dec_resp, + const struct sec_microdog40_timestamp* timestamp) +{ + uint8_t key[16]; + + sec_microdog40_get_month_key(key, timestamp); + crypt_aes_dec(key, CRYPT_AES_KEY_LENGTH_16_BYTES, (uint8_t*) dec_resp, + (uint8_t*) enc_resp, sizeof(struct sec_microdog40_resp)); + + for (int i = 0 ; i < 64 ; i++) { + ((uint32_t *) dec_resp->payload)[i] ^= dec_resp->mask_key4; + } + + dec_resp->mask_key3 ^= dec_resp->mask_key4; + dec_resp->krnl_retval ^= dec_resp->mask_key4; + dec_resp->mask_key2 ^= dec_resp->mask_key4; + dec_resp->req_type ^= dec_resp->mask_key4; + dec_resp->mask_key1 ^= dec_resp->mask_key4; + dec_resp->magic ^= dec_resp->mask_key4; + + dec_resp->krnl_retval ^= dec_resp->mask_key3; + dec_resp->mask_key2 ^= dec_resp->mask_key3; + dec_resp->req_type ^= dec_resp->mask_key3; + dec_resp->mask_key1 ^= dec_resp->mask_key3; + dec_resp->magic ^= dec_resp->mask_key3; + + dec_resp->req_type ^= dec_resp->mask_key2; + dec_resp->mask_key1 ^= dec_resp->mask_key2; + dec_resp->magic ^= dec_resp->mask_key2; + + dec_resp->magic ^= dec_resp->mask_key1; +} +*/ + +/* unused */ +/* +static void sec_microdog40_enc_req(const struct sec_microdog40_req* dec_req, + struct sec_microdog40_req* enc_req) +{ + uint8_t key[16]; + + // Mask keying not necessary + + sec_microdog40_get_month_key(key, &dec_req->timestamp); + crypt_aes_enc(key, CRYPT_AES_KEY_LENGTH_16_BYTES, (uint8_t*) enc_req, + (uint8_t*) dec_req, sizeof(struct sec_microdog40_req)); + + crypt_md5_hash(key, sec_microdog40_shared_secret, + sizeof(sec_microdog40_shared_secret)); + crypt_aes_enc(key, CRYPT_AES_KEY_LENGTH_16_BYTES, ((uint8_t*) enc_req) + + REQHEAD_SIZE, ((uint8_t*) &dec_req) + REQHEAD_SIZE, REQTAIL_SIZE); +} +*/ + +static void sec_microdog40_encrypt_resp( + const struct sec_microdog40_resp* dec_resp, + struct sec_microdog40_resp* enc_resp, + const struct sec_microdog40_timestamp* timestamp) +{ + uint8_t key[16]; + + sec_microdog40_get_month_key(key, timestamp); + crypt_aes_enc(key, CRYPT_AES_KEY_LENGTH_16_BYTES, (uint8_t*) enc_resp, + (uint8_t*) dec_resp, sizeof(struct sec_microdog40_resp)); +} + +static uint32_t sec_microdog40_convert_req(const uint8_t* req_data, + uint16_t req_len) +{ + uint32_t cur_algo; + + cur_algo = 0; + memcpy(&cur_algo, sec_microdog40_header.flash_memory + 196, 4); + + for (uint32_t i = 0; i < sec_microdog40_header.num_keys; i++) { + struct sec_microdog40_key* key = &sec_microdog40_key_table[i]; + + if (key->algorithm == cur_algo) { + + if (key->req_len == req_len) { + + if (!memcmp(key->request, req_data, req_len)) { + char* tmp = util_str_buffer(req_data, req_len); + log_debug("Converting: %s ==> %X", tmp, key->response); + free(tmp); + return key->response; + } + } + } + } + + char* tmp = util_str_buffer(req_data, req_len); + log_warn("Converting request %s failed, no matching response found", tmp); + free(tmp); + return 0; +} + +static void sec_microdog40_dispatch(const struct sec_microdog40_req* req, + struct sec_microdog40_resp* resp) +{ + // prepare response + resp->magic = sec_microdog40_magic; + resp->req_type = req->req_type; + + if (req->magic != sec_microdog40_magic) { + log_warn("Bad magic for request: %X", req->magic); + } + + sec_microdog40_log_req(req); + + switch (req->req_type) + { + case SEC_MICRODOG40_REQ_OPCODE_SET_SHARE: + { + log_debug("SEC_MICRODOG40_REQ_OPCODE_SET_SHARE"); + + sec_microdog40_share = req->payload[0]; + break; + } + + case SEC_MICRODOG40_REQ_OPCODE_GET_LOCK_NO: + { + log_debug("SEC_MICRODOG40_REQ_OPCODE_GET_LOCK_NO 0x%08X", + sec_microdog40_header.mfg_serial); + + memcpy(resp->payload, &sec_microdog40_header.mfg_serial, 4); + break; + } + + case SEC_MICRODOG40_REQ_OPCODE_GET_ID: + { + log_debug("SEC_MICRODOG40_REQ_OPCODE_GET_ID 0x%02X 0x%02X 0x%02X " + "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", + sec_microdog40_header.vendor_id[0], + sec_microdog40_header.vendor_id[1], + sec_microdog40_header.vendor_id[2], + sec_microdog40_header.vendor_id[3], + sec_microdog40_header.vendor_id[4], + sec_microdog40_header.vendor_id[5], + sec_microdog40_header.vendor_id[6], + sec_microdog40_header.vendor_id[7]); + + memcpy(resp->payload, sec_microdog40_header.vendor_id, + sizeof(sec_microdog40_header.vendor_id)); + + break; + } + + case SEC_MICRODOG40_REQ_OPCODE_CONVERT: + { + uint32_t resp_data; + + log_debug("SEC_MICRODOG40_REQ_OPCODE_CONVERT"); + + resp_data = sec_microdog40_convert_req(req->payload, + req->payload_size); + memcpy(resp->payload, &resp_data, sizeof(uint32_t)); + + break; + } + + case SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_1: + { + log_debug("SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_1"); + /* no-op */ + break; + } + + case SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_2: + { + log_debug("SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_2"); + /* no-op */ + break; + } + + case SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_3: + { + uint8_t month_key[16]; + + log_debug("SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_3"); + + sec_microdog40_get_month_key(month_key, &req->timestamp); + + crypt_aes_enc(month_key, CRYPT_AES_KEY_LENGTH_16_BYTES, + resp->payload, req->payload, 16); + + break; + } + + default: + { + log_warn("Unsupported Opcode: %04X", req->req_type); + resp->magic = 0; // mark to indicate error + break; + } + } +} + +void sec_microdog40_init(const uint8_t* key_data, size_t len) +{ + if (len < sizeof(struct sec_microdog40_header)) { + log_error("Loading key table failed, incomplete header"); + return; + } + + memcpy(&sec_microdog40_header, key_data, + sizeof(struct sec_microdog40_header)); + + if (len - sizeof(struct sec_microdog40_header) < + sec_microdog40_header.num_keys * + sizeof(struct sec_microdog40_key)) { + log_error("Loading key table failed, incomplete key table"); + return; + } + + sec_microdog40_key_table = util_xmalloc(sec_microdog40_header.num_keys * + sizeof(struct sec_microdog40_key)); + + memcpy(sec_microdog40_key_table, + key_data + sizeof(struct sec_microdog40_header), + sec_microdog40_header.num_keys * sizeof(struct sec_microdog40_key)); + + log_info("Loaded %d keys, serial 0x%X, password 0x%X", + sec_microdog40_header.num_keys, sec_microdog40_header.serial, + sec_microdog40_header.password); + + sec_microdog40_share = 0; +} + +bool sec_microdog40_do_transaction( + struct sec_microdog40_transaction* transaction) +{ + struct sec_microdog40_req dec_req; + struct sec_microdog40_resp dec_resp; + + if (transaction->header != PROTOCOL_VERSION) { + log_error("Wrong protocol version of transaction %X.", + transaction->header); + return false; + } + + log_debug("Decrypting request..."); + sec_microdog40_dec_req(&transaction->request, &dec_req); + + sec_microdog40_dispatch(&dec_req, &dec_resp); + + /* no error */ + if (dec_resp.magic != 0) { + transaction->header = 0; + + log_debug("Encrypting response..."); + sec_microdog40_encrypt_resp(&dec_resp, &transaction->response, + &dec_req.timestamp); + } else { + transaction->header = 20023; + log_error("Transaction failed."); + } + + log_debug("Transaction successful"); + + return true; +} \ No newline at end of file diff --git a/src/main/sec/microdog40/microdog40.h b/src/main/sec/microdog40/microdog40.h new file mode 100644 index 0000000..c356ad1 --- /dev/null +++ b/src/main/sec/microdog40/microdog40.h @@ -0,0 +1,111 @@ +/** + * Microdog 4.0 emulator + * + * Credits to batteryshark for the emulation code and key files + */ +#ifndef SEC_MICRODOG40_H +#define SEC_MICRODOG40_H + +#include +#include + +/** + * Header of a key file containing attributes of the dongle. This is followed + * by an arbitrary number of keys + */ +struct sec_microdog40_header { + uint32_t serial; + uint32_t password; + uint8_t vendor_id[8]; + uint32_t mfg_serial; + uint8_t flash_memory[200]; + uint32_t num_keys; +}; + +/** + * A single entry in the key table (comes after the header) + */ +struct sec_microdog40_key { + uint32_t response; + uint32_t algorithm; + uint32_t req_len; + uint8_t request[64]; +}; + +/** + * Timestamp for a dongle request + */ +struct sec_microdog40_timestamp { + uint16_t year; + uint16_t month; + uint16_t day; + uint16_t hour; + uint16_t minute; + uint16_t second; + uint8_t padding[3]; +} __attribute((__packed__)); + +/** + * Request to the dongle as part of a transaction + */ +struct sec_microdog40_req { + uint16_t magic; + uint8_t req_type; + uint32_t mask_key1; + uint8_t dog_cascade; + uint32_t mfg_serial; + uint32_t mask_key2; + uint16_t dog_addr; + uint16_t payload_size; + uint32_t mask_key3; + uint8_t payload[256]; + uint32_t dog_password; + uint8_t host_id; + uint32_t mask_key4; + struct sec_microdog40_timestamp timestamp; +} __attribute((__packed__)); + +/** + * Dongle response as part of a transaction + */ +struct sec_microdog40_resp { + uint16_t magic; + uint32_t mask_key1; + uint8_t req_type; + uint32_t mask_key2; + uint32_t krnl_retval; + uint32_t mask_key3; + uint8_t payload[256]; + uint32_t mask_key4; + uint8_t padding[9]; +} __attribute((__packed__)); + +/** + * Dongle emulator transaction data + */ +struct sec_microdog40_transaction { + uint32_t header; + struct sec_microdog40_req request; + struct sec_microdog40_resp response; +} __attribute((__packed__)); + +/** + * Initialize the microdog (4.0) emulation module. The dongle for this + * was used on NX2, NXA, Fiesta and FiestaEX + * + * @param key_data Pointer to loaded key data (dog attributes, key table) + * @param len Length of the buffer + */ +void sec_microdog40_init(const uint8_t* key_data, size_t len); + +/** + * Execute a transaction on the dongle + * + * @param transaction Transaction containing the request. The response is + * written to it after successfully processing the request + * @return True if the request was successfully processed and a response was + * written, false on failure + */ +bool sec_microdog40_do_transaction(struct sec_microdog40_transaction* transaction); + +#endif \ No newline at end of file diff --git a/src/main/sec/microdog40/microdog40d.c b/src/main/sec/microdog40/microdog40d.c new file mode 100644 index 0000000..1754896 --- /dev/null +++ b/src/main/sec/microdog40/microdog40d.c @@ -0,0 +1,109 @@ +#define LOG_MODULE "sec-microdog40d" + +#include +#include +#include +#include +#include +#include + +#include "sec/microdog40/microdog40.h" + +#include "util/log.h" + +static const char* sec_microdog40d_sock_path = "/var/run/microdog/u.daemon"; + +static bool sec_microdog40d_run_d; +static bool sec_microdog40d_is_running_d; + +void sec_microdog40d_init(const uint8_t* key_data, size_t len) +{ + sec_microdog40_init(key_data, len); + sec_microdog40d_run_d = true; + sec_microdog40d_is_running_d = false; +} + +void sec_microdog40d_run(void) +{ + int fd; + struct sec_microdog40_transaction transaction; + struct sockaddr_un peer_addr; + socklen_t peer_addr_len; + int retval; + + sec_microdog40d_is_running_d = true; + + fd = -1; + peer_addr_len = sizeof(peer_addr); + retval = 0; + + unlink(sec_microdog40d_sock_path); + + /* make sure /var/run/microdog folder exists */ + mkdir("/var/run/microdog", 0700); + + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd == -1) { + log_error("Opening socket failed: %s", strerror(errno)); + sec_microdog40d_is_running_d = false; + return; + } + + memset(&peer_addr, 0, sizeof(struct sockaddr_un)); + peer_addr.sun_family = AF_UNIX; + strcpy(peer_addr.sun_path, sec_microdog40d_sock_path); + + retval = bind(fd, (struct sockaddr *) &peer_addr, + sizeof(struct sockaddr_un)); + + if (retval == -1) { + log_error("Binding socket failed: %s", strerror(errno)); + sec_microdog40d_is_running_d = false; + return; + } + + while (sec_microdog40d_run_d) { + peer_addr_len = sizeof(peer_addr); + retval = recvfrom(fd, &transaction, + sizeof(struct sec_microdog40_transaction), 0, + (struct sockaddr *) &peer_addr, &peer_addr_len); + + if (retval == -1) { + + if (errno == EBADF) { + break; + } else { + log_error("Receiving data failed: %s", strerror(errno)); + sec_microdog40d_is_running_d = false; + return; + } + } else if (retval != sizeof(struct sec_microdog40_transaction)) { + log_warn("Package too short, expected %d bytes, got %d bytes", + sizeof(struct sec_microdog40_transaction), retval); + } else { + if (sec_microdog40_do_transaction(&transaction)) { + sendto(fd, &transaction, + sizeof(struct sec_microdog40_transaction), 0, + (struct sockaddr *) &peer_addr, peer_addr_len); + } else { + log_error("Transaction failed."); + } + } + } + + // cleanup + close(fd); + unlink(sec_microdog40d_sock_path); + + sec_microdog40d_is_running_d = false; +} + +bool sec_microdog40d_is_running(void) +{ + return sec_microdog40d_is_running_d; +} + +void sec_microdog40d_shutdown(void) +{ + sec_microdog40d_run_d = false; +} \ No newline at end of file diff --git a/src/main/sec/microdog40/microdog40d.h b/src/main/sec/microdog40/microdog40d.h new file mode 100644 index 0000000..e429cbd --- /dev/null +++ b/src/main/sec/microdog40/microdog40d.h @@ -0,0 +1,35 @@ +/** + * Microdog 4.0 daemon module + */ +#ifndef SEC_MICRODOG40D_H +#define SEC_MICRODOG40D_H + +#include +#include + +/** + * Initialize the microdog (4.0) daemon module. This just initializes the + * dongle emulator module + * + * @param key_data Pointer to loaded key data (dog attributes, key table) + * @param len Length of the buffer + */ +void sec_microdog40d_init(const uint8_t* key_data, size_t len); + +/** + * Run the daemon. This call blocks until the daemon is shut down. + * Recommended to run this in a separate thread. + */ +void sec_microdog40d_run(void); + +/** + * Check if the daemon is running + */ +bool sec_microdog40d_is_running(void); + +/** + * Signal a shut down to the daemon + */ +void sec_microdog40d_shutdown(void); + +#endif \ No newline at end of file diff --git a/src/main/util/adler32.c b/src/main/util/adler32.c new file mode 100644 index 0000000..8d05078 --- /dev/null +++ b/src/main/util/adler32.c @@ -0,0 +1,17 @@ +#include "util/adler32.h" + +#define BASE 65521 + +uint32_t util_adler32_calc(uint32_t initval, const uint8_t* input, size_t length) +{ + unsigned int s1 = initval & 0xffff; + unsigned int s2 = (initval >> 16) & 0xffff; + unsigned int n; + + for (n = 0; n < length; n++) { + s1 = (s1 + input[n]) % BASE; + s2 = (s2 + s1) % BASE; + } + + return (s2 << 16) + s1; +} \ No newline at end of file diff --git a/src/main/util/adler32.h b/src/main/util/adler32.h new file mode 100644 index 0000000..1f74a50 --- /dev/null +++ b/src/main/util/adler32.h @@ -0,0 +1,17 @@ +#ifndef UTIL_ADLER32_H +#define UTIL_ADLER32_H + +#include +#include + +/** + * Calculate the adler32 checksum + * + * @param initval Initial value for calculation + * @param input Input buffer to checksum + * @param length Length of the input buffer + * @return Adler32 value of input buffer + */ +uint32_t util_adler32_calc(uint32_t initval, const uint8_t* input, size_t length); + +#endif \ No newline at end of file diff --git a/src/main/util/array.c b/src/main/util/array.c new file mode 100644 index 0000000..e9f61f3 --- /dev/null +++ b/src/main/util/array.c @@ -0,0 +1,55 @@ +#include +#include +#include + +#include "util/array.h" +#include "util/log.h" +#include "util/mem.h" + +void util_array_init(struct util_array* array) +{ + memset(array, 0, sizeof(*array)); +} + +void util_array_remove_(size_t itemsz, struct util_array* array, size_t i) +{ + array->nitems--; + + memmove(((uint8_t *) array->items) + i * itemsz, + ((uint8_t *) array->items) + (i + 1) * itemsz, + (array->nitems - i) * itemsz); +} + +void* util_array_reserve_(size_t itemsz, struct util_array* array, size_t nitems) +{ + size_t new_nalloced; + size_t new_nitems; + void* result; + + new_nitems = array->nitems + nitems; + + if (new_nitems > array->nalloced) { + new_nalloced = array->nalloced; + + if (new_nalloced == 0) { + new_nalloced = 1; + } + + while (new_nalloced < new_nitems) { + new_nalloced *= 2; + } + + array->items = util_xrealloc(array->items, new_nalloced * itemsz); + array->nalloced = new_nalloced; + } + + result = ((uint8_t *) array->items) + array->nitems * itemsz; + array->nitems = new_nitems; + + return result; +} + +void util_array_fini(struct util_array* array) +{ + free(array->items); +} diff --git a/src/main/util/array.h b/src/main/util/array.h new file mode 100644 index 0000000..8a541ce --- /dev/null +++ b/src/main/util/array.h @@ -0,0 +1,60 @@ +#ifndef UTIL_ARRAY_H +#define UTIL_ARRAY_H + +#include + +/** + * Array with a fixed number of items + */ +struct util_array { + void* items; + size_t nitems; + size_t nalloced; +}; + +#define util_array_item(type, array, i) \ + (&(((type*) (array)->items)[i])) + +#define util_array_reserve(type, array, nitems) \ + ((type*) util_array_reserve_(sizeof(type), array, nitems)) + +#define util_array_remove(type, array, i) \ + util_array_remove_(sizeof(type), array, i) + +#define util_array_append(type, array) \ + util_array_reserve(type, array, 1) + +/** + * Initialize the array after allocation + * + * @param array Pointer to allocated array to initialize + */ +void util_array_init(struct util_array* array); + +/** + * Reserve/allocate space for the specified number of items in the array + * + * @param itemsz Size of a single item + * @param array Array to use + * @param Number of items with itemsz each to reserve + * @return Pointer to first index of reserved slots in array + */ +void* util_array_reserve_(size_t itemsz, struct util_array* array, size_t nitems); + +/** + * Remove an item from the array. The array will be shrunken to current_size - 1 + * + * @param itemsz Size of a single item + * @param array Array to remove the item from + * @param i Index of the item to remove + */ +void util_array_remove_(size_t itemsz, struct util_array* array, size_t i); + +/** + * Free/Deallocate an allocated array + * + * @param array Allocated array to free + */ +void util_array_fini(struct util_array* array); + +#endif diff --git a/src/main/util/base64.c b/src/main/util/base64.c new file mode 100644 index 0000000..0ab955a --- /dev/null +++ b/src/main/util/base64.c @@ -0,0 +1,170 @@ +#include + +#include "util/base64.h" +#include "util/mem.h" + +// Copy-pasted with minor tweaks from: https://github.com/littlstar/b64.c + +static const char b64_table[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +uint8_t* util_base64_encode(const uint8_t* src, size_t len, size_t* out_len) +{ + int i = 0; + int j = 0; + unsigned char *enc = NULL; + size_t size = 0; + unsigned char buf[4]; + unsigned char tmp[3]; + + enc = (unsigned char *) util_xmalloc(0); + + while (len--) { + tmp[i++] = *(src++); + + if (3 == i) { + buf[0] = (tmp[0] & 0xfc) >> 2; + buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); + buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); + buf[3] = tmp[2] & 0x3f; + + enc = (unsigned char *) util_xrealloc(enc, size + 4); + + for (i = 0; i < 4; ++i) { + enc[size++] = b64_table[buf[i]]; + } + + i = 0; + } + } + + if (i > 0) { + for (j = i; j < 3; ++j) { + tmp[j] = '\0'; + } + + buf[0] = (tmp[0] & 0xfc) >> 2; + buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); + buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); + buf[3] = tmp[2] & 0x3f; + + for (j = 0; (j < i + 1); ++j) { + enc = (unsigned char *) util_xrealloc(enc, size + 1); + enc[size++] = b64_table[buf[j]]; + } + + while ((i++ < 3)) { + enc = (unsigned char *) util_xrealloc(enc, size + 1); + enc[size++] = '='; + } + } + + enc = (unsigned char *) util_xrealloc(enc, size + 1); + enc[size] = '\0'; + + *out_len = size; + + return enc; +} + +uint8_t* util_base64_decode(const uint8_t* src, size_t len, size_t* out_len) +{ + int i = 0; + int j = 0; + int l = 0; + size_t size = 0; + unsigned char *dec = NULL; + unsigned char buf[3]; + unsigned char tmp[4]; + + dec = (unsigned char *) util_xmalloc(0); + + while (len--) { + if ('=' == src[j]) { + break; + } + if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { + break; + } + + tmp[i++] = src[j++]; + + if (4 == i) { + for (i = 0; i < 4; ++i) { + for (l = 0; l < 64; ++l) { + if (tmp[i] == b64_table[l]) { + tmp[i] = l; + break; + } + } + } + + buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4); + buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2); + buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3]; + + dec = (unsigned char *) util_xrealloc(dec, size + 3); + + if (dec != NULL){ + for (i = 0; i < 3; ++i) { + dec[size++] = buf[i]; + } + } else { + return NULL; + } + + i = 0; + } + } + + if (i > 0) { + for (j = i; j < 4; ++j) { + tmp[j] = '\0'; + } + + for (j = 0; j < 4; ++j) { + for (l = 0; l < 64; ++l) { + if (tmp[j] == b64_table[l]) { + tmp[j] = l; + break; + } + } + } + + buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4); + buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2); + buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3]; + + dec = (unsigned char *)util_xrealloc(dec, size + (i - 1)); + + if (dec != NULL){ + for (j = 0; (j < i - 1); ++j) { + dec[size++] = buf[j]; + } + } else { + return NULL; + } + } + + dec = (unsigned char *)util_xrealloc(dec, size + 1); + + if (dec != NULL){ + dec[size] = '\0'; + } else { + return NULL; + } + + if (out_len != NULL) { + *out_len = size; + } + + return dec; +} \ No newline at end of file diff --git a/src/main/util/base64.h b/src/main/util/base64.h new file mode 100644 index 0000000..e3fdcf2 --- /dev/null +++ b/src/main/util/base64.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +uint8_t* util_base64_encode(const uint8_t* src, size_t len, size_t* out_len); + +uint8_t* util_base64_decode(const uint8_t* src, size_t len, size_t* out_len); \ No newline at end of file diff --git a/src/main/util/defs.h b/src/main/util/defs.h new file mode 100644 index 0000000..c90240d --- /dev/null +++ b/src/main/util/defs.h @@ -0,0 +1,18 @@ +#ifndef UTIL_DEFS_H +#define UTIL_DEFS_H + +#include +#include + +#define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#define STRINGIFY_(x) #x +#define STRINGIFY(x) STRINGIFY_(x) +#define XSTRINGIFY(arg) STRINGIFY(arg) + +#define lengthof(x) (sizeof(x) / sizeof(x[0])) + +#define containerof(ptr, outer_t, member) \ + ((void *) (((uint8_t *) ptr) - offsetof(outer_t, member))) + +#endif diff --git a/src/main/util/fs.c b/src/main/util/fs.c new file mode 100644 index 0000000..2b5d773 --- /dev/null +++ b/src/main/util/fs.c @@ -0,0 +1,222 @@ +#define LOG_MODULE "util-fs" + +#include +#include +#include +#include +#include +#include +#include + +#include "util/defs.h" +#include "util/fs.h" +#include "util/log.h" +#include "util/mem.h" + +bool util_file_load(const char* filename, void** out_bytes, size_t *out_nbytes, + bool text_mode) +{ + FILE *f; + void *bytes; + size_t nbytes; + int result; + + log_assert(out_bytes != NULL); + *out_bytes = NULL; + + f = fopen(filename, "rb"); + + if (f == NULL) { + log_warn("%s: Error opening file: %s", filename, strerror(errno)); + + goto open_fail; + } + + fseek(f, 0, SEEK_END); + nbytes = ftell(f); + fseek(f, 0, SEEK_SET); + + /* Add for null terminator */ + if (text_mode) { + nbytes++; + } + + bytes = malloc(nbytes); + + if (bytes == NULL) { + log_warn("%s: malloc(%u) failed", filename, (unsigned int) nbytes); + + goto malloc_fail; + } + + if (text_mode) { + result = fread(bytes, nbytes - 1, 1, f); + } else { + result = fread(bytes, nbytes, 1, f); + } + + if (result != 1) { + log_warn("%s: Error reading file: %s", filename, strerror(errno)); + + goto read_fail; + } + + *out_bytes = bytes; + + if (out_nbytes != NULL) { + *out_nbytes = nbytes; + } + + fclose(f); + + /* Add null terminator */ + if (text_mode) { + ((char*) bytes)[nbytes - 1] = '\0'; + } + + log_debug("File loaded %s, size %d", filename, *out_nbytes); + + return true; + +read_fail: + free(bytes); + +malloc_fail: + fclose(f); + +open_fail: + return false; +} + +bool util_file_save(const char* filename, const void* bytes, size_t nbytes) +{ + FILE *f; + int result; + + f = fopen(filename, "wb"); + + if (f == NULL) { + log_warn("%s: Error creating file: %s", filename, strerror(errno)); + + goto open_fail; + } + + result = fwrite(bytes, nbytes, 1, f); + + if (result != 1) { + log_warn("%s: Error writing file: %s", filename, strerror(errno)); + + goto write_fail; + } + + fclose(f); + + log_debug("File saved %s, size %d", filename, nbytes); + + return true; + +write_fail: + fclose(f); + +open_fail: + return false; +} + +bool util_fs_path_exists(const char* path) +{ + // Don't use stat here because that doesn't work on mounts, e.g. sqashfs/appimage + + bool exists; + FILE* file = fopen(path, "r"); + + exists = file != NULL; + + if (file != NULL) { + fclose(file); + } + + return exists; +} + +bool util_fs_mkdir(const char* path) +{ + return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0; +} + +bool util_fs_mkfile(const char* path) +{ + FILE* file; + bool res; + + file = fopen(path, "a"); + + res = file != NULL; + + if (file) { + fclose(file); + } + + return res; +} + +char* util_fs_get_path_to_file(const char* path) +{ + size_t len; + char* res; + + len = strlen(path); + + for (ssize_t i = len - 1; i >= 0; i--) { + if (path[i] == '/') { + len--; + break; + } + + len--; + } + + res = (char*) util_xmalloc(sizeof(char) * (len + 1)); + strncpy(res, path, len); + res[len] = '\0'; + + return res; +} + +char* util_fs_get_filename(const char* path) +{ + size_t path_len; + size_t len; + char* res; + + len = strlen(path); + path_len = len; + + for (ssize_t i = len - 1; i >= 0; i--) { + if (path[i] == '/') { + len++; + break; + } + + len--; + } + + res = (char*) util_xmalloc(sizeof(char) * ((path_len - len) + 1)); + strncpy(res, path + len, path_len - len); + res[path_len - len] = '\0'; + + return res; +} + +char* util_fs_get_abs_path(const char* path) +{ + char* real_path; + + real_path = realpath(path, NULL); + + if (!real_path) { + log_error("Resolving path '%s' to absolute path failed: %s", path, + strerror(errno)); + } + + return real_path; +} \ No newline at end of file diff --git a/src/main/util/fs.h b/src/main/util/fs.h new file mode 100644 index 0000000..31f92af --- /dev/null +++ b/src/main/util/fs.h @@ -0,0 +1,81 @@ +#ifndef UTIL_FS_H +#define UTIL_FS_H + +#include +#include +#include +#include + +/** + * Load a file fully into memory + * + * @param filename Path of the file to load + * @param bytes Pointer to a pointer to return an allocated location with the + * loaded data to + * @param nbytes Pointer to a variable to return the read size of the file to + * @param text_mode True to read the file in text mode (add terminating \0), + * false for binary mode + * @return True on success, false on error + */ +bool util_file_load(const char* filename, void** bytes, size_t* nbytes, bool text_mode); + +/** + * Save a buffer to a file (overwrite any existing files with the same name) + * + * @param filename Path to save the data to + * @param bytes Pointer to buffer with contents to save + * @param nbytes Number of bytes to write to the file + * @return True on success, false on error + */ +bool util_file_save(const char* filename, const void* bytes, size_t nbytes); + +/** + * Check if a normal file, folder, symlink, ... exists + * + * @return True if exists, false otherwise + */ +bool util_fs_path_exists(const char* path); + +/** + * Create a new directory + * + * @param path Path to directory + * @return True if successful, false on failure + */ +bool util_fs_mkdir(const char* path); + +/** + * Create a new empty file + * + * @param path Path to the file to create + * @return True if successful, false on failure + */ +bool util_fs_mkfile(const char* path); + +/** + * Get the path pointing to the file (without the filename) + * + * @param path Full path to file + * @return Newly allocated string (caller has to free) containing the path, only + */ +char* util_fs_get_path_to_file(const char* path); + +/** + * Get the start position of the filename in the path + * + * @param path Full path to file + * @return Newly allocated string (caller has to free) containing the filename, + * only + */ +char* util_fs_get_filename(const char* path); + +/** + * Get the absolute path of the give (relative) path + * + * @param path (Relative) path + * @return Allocated string (caller has to free) containing the full absolute + * path for the given (relative) path + */ +char* util_fs_get_abs_path(const char* path); + +#endif diff --git a/src/main/util/glibc.c b/src/main/util/glibc.c new file mode 100644 index 0000000..bc0b506 --- /dev/null +++ b/src/main/util/glibc.c @@ -0,0 +1,10 @@ +#define LOG_MODULE "util-glibc" + +#include + +#include "util/log.h" + +void util_glibc_info_log() +{ + log_info("glibc release '%s', version '%s'", gnu_get_libc_release(), gnu_get_libc_version()); +} \ No newline at end of file diff --git a/src/main/util/glibc.h b/src/main/util/glibc.h new file mode 100644 index 0000000..35640aa --- /dev/null +++ b/src/main/util/glibc.h @@ -0,0 +1,6 @@ +#ifndef PUMPTOOLS_UTIL_GLIBC_H +#define PUMPTOOLS_UTIL_GLIBC_H + +void util_glibc_info_log(); + +#endif diff --git a/src/main/util/hex.c b/src/main/util/hex.c new file mode 100644 index 0000000..bcfd471 --- /dev/null +++ b/src/main/util/hex.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "util/hex.h" +#include "util/log.h" + +static bool util_hex_decode_nibble(char c, uint8_t *nibble) +{ + if (c >= '0' && c <= '9') { + *nibble = c - '0'; + } else if (c >= 'A' && c <= 'F') { + *nibble = c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + *nibble = c - 'a' + 10; + } else { + return false; + } + + return true; +} + +bool util_hex_decode(void *ptr, size_t nbytes, const char *chars, size_t nchars) +{ + uint8_t *bytes = ptr; + + uint32_t i; + uint8_t hi; + uint8_t lo; + + log_assert(nchars >= 2 * nbytes); + + for (i = 0 ; i < nbytes ; i++) { + if ( !util_hex_decode_nibble(chars[2 * i + 0], &hi) || + !util_hex_decode_nibble(chars[2 * i + 1], &lo)) { + return false; + } + + bytes[i] = (hi << 4) | lo; + } + + return true; +} + +static void util_hex_encode(const void *ptr, size_t nbytes, char *chars, + size_t nchars, const char *digits) +{ + const uint8_t *bytes = ptr; + + size_t i; + + log_assert(nchars >= 2 * nbytes + 1); + + for (i = 0 ; i < nbytes ; i++) { + chars[i * 2 + 0] = digits[bytes[i] >> 4]; + chars[i * 2 + 1] = digits[bytes[i] & 15]; + } + + chars[nbytes * 2] = '\0'; +} + +void util_hex_encode_lc(const void *bytes, size_t nbytes, char *chars, + size_t nchars) +{ + util_hex_encode(bytes, nbytes, chars, nchars, "0123456789abcdef"); +} + +void util_hex_encode_uc(const void *bytes, size_t nbytes, char *chars, + size_t nchars) +{ + util_hex_encode(bytes, nbytes, chars, nchars, "0123456789ABCDEF"); +} + diff --git a/src/main/util/hex.h b/src/main/util/hex.h new file mode 100644 index 0000000..96486cb --- /dev/null +++ b/src/main/util/hex.h @@ -0,0 +1,14 @@ +#ifndef UTIL_HEX_H +#define UTIL_HEX_H + +#include +#include + +bool util_hex_decode(void *bytes, size_t nbytes, const char *chars, + size_t nchars); +void util_hex_encode_uc(const void *bytes, size_t nbytes, char *chars, + size_t nchars); +void util_hex_encode_lc(const void *bytes, size_t nbytes, char *chars, + size_t nchars); + +#endif diff --git a/src/main/util/iobuf.c b/src/main/util/iobuf.c new file mode 100644 index 0000000..b8bd76e --- /dev/null +++ b/src/main/util/iobuf.c @@ -0,0 +1,22 @@ +#include "util/iobuf.h" + +#include + +size_t util_iobuf_move(struct util_iobuf* dest, struct util_const_iobuf* src) +{ + size_t dest_avail; + size_t src_avail; + size_t chunksz; + + dest_avail = dest->nbytes - dest->pos; + src_avail = src->nbytes - src->pos; + chunksz = dest_avail < src_avail ? dest_avail : src_avail; + + memcpy(&dest->bytes[dest->pos], &src->bytes[src->pos], chunksz); + + dest->pos += chunksz; + src->pos += chunksz; + + return chunksz; +} + diff --git a/src/main/util/iobuf.h b/src/main/util/iobuf.h new file mode 100644 index 0000000..4086482 --- /dev/null +++ b/src/main/util/iobuf.h @@ -0,0 +1,35 @@ +#ifndef UTIL_IOBUF_H +#define UTIL_IOBUF_H + +#include +#include + +/** + * Iobuffer struct holding data, size and position + */ +struct util_iobuf { + uint8_t* bytes; + size_t nbytes; + size_t pos; +}; + +/** + * Const variant of iobuffer struct holding data, size and position + */ +struct util_const_iobuf { + const uint8_t* bytes; + size_t nbytes; + size_t pos; +}; + +/** + * Move the contents of one iobuffer to another one (data, size and pos) + * + * @param dest Destination to move to + * @param src Source to move from + * @return Number of bytes moved (this can be less than the source's size + * e.g. if destination size < src size) + */ +size_t util_iobuf_move(struct util_iobuf* dest, struct util_const_iobuf* src); + +#endif diff --git a/src/main/util/list.c b/src/main/util/list.c new file mode 100644 index 0000000..b88d2c1 --- /dev/null +++ b/src/main/util/list.c @@ -0,0 +1,91 @@ +#include "util/list.h" + +#include +#include + +void util_list_init(struct util_list* list) +{ + memset(list, 0, sizeof(*list)); +} + +void util_list_append(struct util_list* list, struct util_list_node* node) +{ + node->next = NULL; + + if (list->tail != NULL) { + list->tail->next = node; + } else { + list->head = node; + } + + list->tail = node; +} + +bool util_list_contains(struct util_list* list, struct util_list_node* node) +{ + struct util_list_node* pos; + + for (pos = list->head ; pos != NULL ; pos = pos->next) { + if (pos == node) { + return true; + } + } + + return false; +} + +struct util_list_node* util_list_pop_head(struct util_list* list) +{ + struct util_list_node* node; + + if (list->head == NULL) { + return NULL; + } + + node = list->head; + list->head = node->next; + + if (node->next == NULL) { + list->tail = NULL; + } + + node->next = NULL; + + return node; +} + +void util_list_remove(struct util_list* list, struct util_list_node* node) +{ + struct util_list_node* pos; + struct util_list_node* prev; + + for (prev = NULL, pos = list->head + ; pos != NULL + ; prev = pos, pos = pos->next) { + if (pos == node) { + if (prev != NULL) { + prev->next = node->next; + } else { + list->head = node->next; + } + + if (node->next == NULL) { + list->tail = prev; + } + + node->next = NULL; + + return; + } + } +} + +bool util_list_empty(struct util_list* list) +{ + return list->head == NULL; +} + +inline struct util_list_node* util_list_peek_head(struct util_list* list) +{ + return list->head; +} diff --git a/src/main/util/list.h b/src/main/util/list.h new file mode 100644 index 0000000..7ab8aeb --- /dev/null +++ b/src/main/util/list.h @@ -0,0 +1,79 @@ +#ifndef UTIL_LIST_H +#define UTIL_LIST_H + +#include +#include + +/** + * (Doubly linked) list object + */ +struct util_list { + struct util_list_node* head; + struct util_list_node* tail; +}; + +/** + * List element/node + */ +struct util_list_node { + struct util_list_node* next; +}; + +/** + * Initialize an allocated list + * + * @param list Pointer to a list to initialize + */ +void util_list_init(struct util_list* list); + +/** + * Append an element to a list + * + * @param list List to append to + * @param node Node to append to the list + */ +void util_list_append(struct util_list* list, struct util_list_node* node); + +/** + * Check if the list contains the specified element + * + * @param list List to check + * @param node Node to look for in the list + * @return True if list contains the specified node, false otherwise + */ +bool util_list_contains(struct util_list* list, struct util_list_node* node); + +/** + * Peak (get but do not remove) the head of the list + * + * @param list List to peak + * @return Head element of the list (or null if empty) + */ +struct util_list_node* util_list_peek_head(struct util_list* list); + +/** + * Pop (get and remove) the head of the list + * + * @param list List to pop + * @return Removed head element of the list (or null if empty) + */ +struct util_list_node* util_list_pop_head(struct util_list* list); + +/** + * Remove a specific element of the list. If the element is not part of the, + * the list is not modified. + * + * @param list List to remove an element from + * @param node Element to remove from the list + */ +void util_list_remove(struct util_list* list, struct util_list_node* node); + +/** + * Check if a list is empty + * + * @param list List to check + * @return True if empty, false otherwise + */ +bool util_list_empty(struct util_list* list); + +#endif diff --git a/src/main/util/log.c b/src/main/util/log.c new file mode 100644 index 0000000..cee3fc6 --- /dev/null +++ b/src/main/util/log.c @@ -0,0 +1,149 @@ +#define LOG_MODULE "util-log" + +#include +#include +#include + +#include "util/defs.h" +#include "util/log.h" +#include "util/str.h" +#include "util/time.h" + +#define COLORIZING_CONTROL_SEQ "\033[%d;%dm%s\033[0m" + +static void util_log_format(enum util_log_level level, const char* module, + const char* trace_file, size_t trace_line, const char* fmt, va_list ap); +static void util_log_writer_console(void* ctx, enum util_log_level level, const char* module, const char* trace_file, + size_t trace_line, const char* msg); +static void util_log_writer_file(void* ctx, enum util_log_level level, const char* module, const char* trace_file, + size_t trace_line, const char* msg); + +static const char util_log_level_chars[] = "DEWIM"; + +static enum util_log_level util_log_level = LOG_LEVEL_DEBUG; +static FILE* util_log_file; + +void util_log_set_file(const char* path, bool append) +{ + const char* mode = append ? "a+" : "w+"; + + if (path) { + util_log_file = fopen(path, mode); + log_info("Open log file: %s", path); + } +} + +void util_log_set_level(enum util_log_level new_level) +{ + util_log_level = new_level; +} + +FILE* util_log_get_file_handle(void) +{ + return util_log_file; +} + +void util_log(enum util_log_level level, const char* module, const char* trace_file, size_t trace_line, + const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + util_log_format(level, module, trace_file, trace_line, fmt, ap); + va_end(ap); +} + +static void util_log_colorize_text(enum util_log_level level, const char* text, char* buffer) +{ + switch (level) { + case LOG_LEVEL_DEBUG: + sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 37, text); + break; + + case LOG_LEVEL_INFO: + sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 34, text); + break; + + case LOG_LEVEL_WARN: + sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 33, text); + break; + + case LOG_LEVEL_ERROR: + sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 31, text); + break; + + case LOG_LEVEL_DIE: + sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 31, text); + break; + + default: + log_die_illegal_state(); + break; + } +} + +static void util_log_format(enum util_log_level level, const char* module, + const char* trace_file, size_t trace_line, const char* fmt, va_list ap) +{ + char msg[8192]; + + if (level <= util_log_level) { + util_str_vformat(msg, sizeof(msg), fmt, ap); + + util_log_writer_console(NULL, level, module, trace_file, trace_line, msg); + + if (util_log_file != NULL) { + util_log_writer_file(util_log_file, level, module, trace_file, trace_line, msg); + } + } + + if (level == LOG_LEVEL_DIE) { + abort(); + } +} + +static void util_log_writer_console(void* ctx, enum util_log_level level, const char* module, const char* trace_file, + size_t trace_line, const char* msg) +{ + char text_level[128]; + char text_level_color[128]; + + util_str_format(text_level, sizeof(text_level), "[%c]", util_log_level_chars[level]); + util_log_colorize_text(level, text_level, text_level_color); + + // --------------------------- + + struct util_time_timestamp timestamp; + + util_time_get_current_time(×tamp); + + // --------------------------- + + char line[8192]; + + util_str_format(line, sizeof(line), "%s[%d/%d/%d-%d:%d:%d:%d][%s][%s:%d] %s\n", text_level_color, timestamp.year, + timestamp.month, timestamp.day, timestamp.hour, timestamp.min, timestamp.sec, timestamp.millisec, + module, trace_file, trace_line, msg); + + printf("%s", line); +} + +static void util_log_writer_file(void* ctx, enum util_log_level level, const char* module, const char* trace_file, + size_t trace_line, const char* msg) +{ + struct util_time_timestamp timestamp; + + util_time_get_current_time(×tamp); + + // --------------------------- + + char line[8192]; + size_t line_len; + + line_len = util_str_format(line, sizeof(line), "[%c][%d/%d/%d-%d:%d:%d:%d][%s][%s:%d] %s\n", + util_log_level_chars[level], timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.min, + timestamp.sec, timestamp.millisec, module, trace_file, trace_line, msg); + + fwrite(line, 1, line_len, (FILE*) ctx); + fflush((FILE*) ctx); +} \ No newline at end of file diff --git a/src/main/util/log.h b/src/main/util/log.h new file mode 100644 index 0000000..708a0fb --- /dev/null +++ b/src/main/util/log.h @@ -0,0 +1,97 @@ +#ifndef UTIL_LOG_H +#define UTIL_LOG_H + +#include +#include +#include + +#include "util/defs.h" + +#ifndef LOG_MODULE +#define LOG_MODULE FILENAME +#endif + +#ifndef LOG_SUPPRESS + +/* Don't expose source file names and absolute paths on public releases */ +#ifdef PT_PUBLIC_RELEASE +#undef FILENAME +#define FILENAME "" +#define SOURCE_LINE 0 +#else +#define SOURCE_LINE __LINE__ +#endif + +#define log_debug(...) util_log(LOG_LEVEL_DEBUG, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__) +#define log_info(...) util_log(LOG_LEVEL_INFO, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__) +#define log_warn(...) util_log(LOG_LEVEL_WARN, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__) +#define log_error(...) util_log(LOG_LEVEL_ERROR, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__) +#define log_die(...) util_log(LOG_LEVEL_DIE, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__) +#define log_die_illegal_state() util_log(LOG_LEVEL_DIE, LOG_MODULE, FILENAME, SOURCE_LINE, "Illegal state") + +#else + +#define log_debug(...) +#define log_info(...) +#define log_warn(...) +#define log_error(...) +#define log_die(...) + +#endif + +#define log_assert(x) \ + do { \ + if (!(x)) { \ + log_die(FILENAME, __LINE__, __FUNCTION__); \ + } \ + } while (0) + +/** + * Different log levels for logging + */ +enum util_log_level { + LOG_LEVEL_DIE = 0, + LOG_LEVEL_ERROR = 1, + LOG_LEVEL_WARN = 2, + LOG_LEVEL_INFO = 3, + LOG_LEVEL_DEBUG = 4 +}; + +/** + * Open a log file to write log output to in addition to stdout + * + * @param path Path of the log file (existing files are overwritten of append argument false) + * @param append True to append to an existing file, false to create a new file with the specified name + */ +void util_log_set_file(const char* path, bool append); + +/** + * Set the log level for logging + * + * @param new_level New log level + */ +void util_log_set_level(enum util_log_level new_level); + +/** + * Get the log file handle (required for hooking to filter it on fwrite calls on the filehook monitor) + * + * @return FILE handle of log file or NULL if logging to file disabled + */ +FILE* util_log_get_file_handle(void); + +/** + * Log a message + * + * Don't use this call to log something, use the macros instead + * + * @param level Log level of the message + * @param module Name of the module where this function is called + * @param trace_file Additional trace information, file name + * @param trace_line Additional trace information, line number + * @param fmt Format string of log message + * @param ... Arguments for format string + */ +void util_log(enum util_log_level level, const char* module, const char* trace_file, size_t trace_line, + const char* fmt, ...); + +#endif \ No newline at end of file diff --git a/src/main/util/mem.c b/src/main/util/mem.c new file mode 100644 index 0000000..b6923c7 --- /dev/null +++ b/src/main/util/mem.c @@ -0,0 +1,108 @@ +#define LOG_MODULE "util-mem" + +#include +#include +#include + +#include "util/log.h" +#include "util/mem.h" + +static bool _util_mem_debug_output; + +static void* _util_xmalloc(size_t nbytes); +static void* _util_xrealloc(void* mem, size_t nbytes); +static void _util_xfree(void** mem); + +static const struct util_mem_interface _util_mem_interface_default = { + .xmalloc = _util_xmalloc, + .xrealloc = _util_xrealloc, + .xfree = _util_xfree, +}; + +static const struct util_mem_interface* _util_mem_interface = &_util_mem_interface_default; + +static void* _util_xmalloc(size_t nbytes) +{ + void* mem; + + mem = malloc(nbytes); + + if (_util_mem_debug_output) { + log_debug("xmalloc(%d): %p", nbytes, mem); + } + + if (mem == NULL) { + log_die("xmalloc(%u) failed", (uint32_t) nbytes); + return NULL; + } + + return mem; +} + +static void* _util_xrealloc(void* mem, size_t nbytes) +{ + void* newmem; + + newmem = realloc(mem, nbytes); + + if (_util_mem_debug_output) { + log_debug("xrealloc(%p %d): %p", mem, nbytes, newmem); + } + + if (newmem == NULL) { + log_die("xrealloc(%p, %u) failed", mem, (uint32_t) nbytes); + return NULL; + } + + return newmem; +} + +static void _util_xfree(void** mem) +{ + log_assert(mem); + + if (*mem != NULL) { + if (_util_mem_debug_output) { + log_debug("xfree(%p %p)", mem, *mem); + } + + free(*mem); + *mem = NULL; + } else { + if (_util_mem_debug_output) { + log_warn("xfree(%p NULL)", mem); + } + } +} + +void util_mem_init(const struct util_mem_interface* interface) +{ + log_assert(interface); + + _util_mem_interface = interface; +} + +void util_mem_init_default() +{ + _util_mem_interface = &_util_mem_interface_default; +} + +void util_mem_enable_debug_output() +{ + _util_mem_debug_output = true; +} + +void* util_xmalloc(size_t nbytes) +{ + return _util_mem_interface->xmalloc(nbytes); +} + +void* util_xrealloc(void* mem, size_t nbytes) +{ + return _util_mem_interface->xrealloc(mem, nbytes); +} + +void util_xfree(void** mem) +{ + _util_mem_interface->xfree(mem); +} \ No newline at end of file diff --git a/src/main/util/mem.h b/src/main/util/mem.h new file mode 100644 index 0000000..5eaedb1 --- /dev/null +++ b/src/main/util/mem.h @@ -0,0 +1,57 @@ +#ifndef UTIL_MEM_H +#define UTIL_MEM_H + +#include +#include + +typedef void* (*util_xmalloc_t)(size_t nbytes); +typedef void* (*util_xrealloc_t)(void* mem, size_t nbytes); +typedef void (*util_free_t)(void** mem); + +struct util_mem_interface { + util_xmalloc_t xmalloc; + util_xrealloc_t xrealloc; + util_free_t xfree; +}; + +/** + * Install a different memory interfacee, e.g. to use a different allocator or hooks for unit-testing. + */ +void util_mem_init(const struct util_mem_interface* interface); + +/** + * Optional, initialize the default memory interface. This needs to be called only if you want to switch back from + * a non-default interface that got installed using util_mem_init. + */ +void util_mem_init_default(); + +/** + * Enable debug output of all allocations and de-allocations that go through the default interface of this module. + */ +void util_mem_enable_debug_output(); + +/** + * Allocate memory on the heap (malloc wrapper) + * + * @param nbytes Number of bytes to allocate + * @return Pointer to allocated memory + */ +void* util_xmalloc(size_t nbytes); + +/** + * Realloc memory (realloc wrapper) + * + * @param mem Pointer to allocated memory to realloc/expand + * @param nbytes New size of memory region + * @return Pointer to reallocated memory region + */ +void* util_xrealloc(void* mem, size_t nbytes); + +/** + * Free allocated memory. + * + * @param mem Pointer to the pointer with allocated memory to free. The pointer to the memory will be set to NULL. + */ +void util_xfree(void** mem); + +#endif diff --git a/src/main/util/net.c b/src/main/util/net.c new file mode 100644 index 0000000..c65fd65 --- /dev/null +++ b/src/main/util/net.c @@ -0,0 +1,41 @@ +#include +#include + +#include "util/net.h" +#include "util/str.h" + +bool util_net_split_ipv4_str(const char* str, char** address, uint16_t* port) +{ + char* tmp = util_str_dup(str); + char* pch = strtok(tmp, ":"); + int counter = 0; + + *address = NULL; + *port = 0xFFFF; + + while (pch != NULL) { + switch (counter) { + case 0: + *address = util_str_dup(pch); + break; + + case 1: + *port = (uint16_t) strtol(pch, NULL, 10); + break; + + default: + if (*address) { + free(*address); + } + + free(tmp); + return false; + } + + pch = strtok (NULL, ":"); + counter++; + } + + free(tmp); + return true; +} \ No newline at end of file diff --git a/src/main/util/net.h b/src/main/util/net.h new file mode 100644 index 0000000..1aac758 --- /dev/null +++ b/src/main/util/net.h @@ -0,0 +1,17 @@ +#ifndef UTIL_NET_H +#define UTIL_NET_H + +#include +#include + +/** + * Split an ipv4 string (e.g. 127.0.0.1:22 or just 127.0.0.1) into address and port + * + * @param str String to split + * @param address Address part (must be free'd by caller) + * @param port Port part (or -1 if it doesn't exist) + * @return True if successful, false on format error + */ +bool util_net_split_ipv4_str(const char* str, char** address, uint16_t* port); + +#endif diff --git a/src/main/util/options.c b/src/main/util/options.c new file mode 100644 index 0000000..b086b22 --- /dev/null +++ b/src/main/util/options.c @@ -0,0 +1,758 @@ +#define LOG_MODULE "util-options" + +#include +#include +#include + +#include "util/defs.h" +#include "util/fs.h" +#include "util/hex.h" +#include "util/log.h" +#include "util/mem.h" +#include "util/options.h" +#include "util/str.h" + +static struct util_options_opts* util_options_get2(int argc, char** argv, + const struct util_options_defs* option_defs); +static bool util_options_init_from_args(struct util_options_opts* options, + const struct util_options_defs* option_defs, int argc, char** argv); +static bool util_options_init_from_file(struct util_options_opts* options, + const struct util_options_defs* option_defs, char* file_path); +static bool util_options_write_default_options_file( + const struct util_options_defs* option_defs, char* file_path); + +static int util_options_argc; +static char** util_options_argv; + +void util_options_init(int argc, char** argv) +{ + util_options_argc = argc; + util_options_argv = argv; +} + +struct util_options_opts* util_options_get( + const struct util_options_defs* option_defs) +{ + struct util_options_opts* options; + + options = util_options_get2(util_options_argc, util_options_argv, + option_defs); + + if (!options) { + exit(0); + } + + return options; +} + +int util_options_get_int(const struct util_options_opts* opts, + const char* name) +{ + for (uint32_t i = 0; i < opts->entries; i++) { + + if (!strcmp(opts->defs->defs[i].name, name)) { + + if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_INT) { + log_warn("Option %s is not of type int", name); + return 0; + } + + if (opts->values[i].avail) { + return opts->values[i].value.i; + } else { + return opts->defs->defs[i].default_value.i; + } + } + } + + log_warn("Could not find int option %s", name); + return 0; +} + +double util_options_get_double(const struct util_options_opts* opts, const char* name) +{ + for (uint32_t i = 0; i < opts->entries; i++) { + + if (!strcmp(opts->defs->defs[i].name, name)) { + + if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_DOUBLE) { + log_warn("Option %s is not of type double", name); + return 0; + } + + if (opts->values[i].avail) { + return opts->values[i].value.d; + } else { + return opts->defs->defs[i].default_value.d; + } + } + } + + log_warn("Could not find double option %s", name); + return 0; +} + +const char* util_options_get_str(const struct util_options_opts* opts, + const char* name) +{ + for (uint32_t i = 0; i < opts->entries; i++) { + + if (!strcmp(opts->defs->defs[i].name, name)) { + + if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_STR) { + log_warn("Option %s is not of type str", name); + return 0; + } + + if (opts->values[i].avail) { + return opts->values[i].value.str; + } else { + return opts->defs->defs[i].default_value.str; + } + } + } + + log_warn("Could not find str option %s", name); + return NULL; +} + +bool util_options_get_bool(const struct util_options_opts* opts, + const char* name) +{ + for (uint32_t i = 0; i < opts->entries; i++) { + + if (!strcmp(opts->defs->defs[i].name, name)) { + + if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_BOOL) { + log_warn("Option %s is not of type bool", name); + return false; + } + + if (opts->values[i].avail) { + return opts->values[i].value.b; + } else { + return opts->defs->defs[i].default_value.b; + } + } + } + + log_warn("Could not find bool option %s", name); + return false; +} + +const uint8_t* util_options_get_bin(const struct util_options_opts* opts, + const char* name, size_t* length) +{ + for (uint32_t i = 0; i < opts->entries; i++) { + + if (!strcmp(opts->defs->defs[i].name, name)) { + + if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_BIN) { + log_warn("Option %s is not of type bin", name); + return 0; + } + + if (opts->values[i].avail) { + if (length) { + *length = opts->values[i].value.bin.len; + } + + return opts->values[i].value.bin.data; + } else { + if (length) { + *length = opts->defs->defs[i].default_value.bin.len; + } + + return opts->defs->defs[i].default_value.bin.data; + } + } + } + + log_warn("Could not find bin option %s", name); + return NULL; +} + +void util_options_print_usage(const struct util_options_defs* option_defs) +{ + printf( + "%s\nSpecify options as arguments or use --options [path file] to " + "specify a config file containing key=value per line entries\n", + option_defs->usage_header); + + for (uint32_t i = 0; i < option_defs->ndefs; i++) { + + switch (option_defs->defs[i].type) { + case UTIL_OPTIONS_TYPE_INT: + { + printf( + " -%c [int] %s: %s\n" + " default: %d\n", + option_defs->defs[i].param, option_defs->defs[i].name, + option_defs->defs[i].description, + option_defs->defs[i].default_value.i); + + break; + } + + case UTIL_OPTIONS_TYPE_DOUBLE: + { + printf( + " -%c [double] %s: %s\n" + " default: %f\n", + option_defs->defs[i].param, option_defs->defs[i].name, + option_defs->defs[i].description, + option_defs->defs[i].default_value.d); + + break; + } + + case UTIL_OPTIONS_TYPE_STR: + { + printf( + " -%c [str] %s: %s\n" + " default: %s\n", + option_defs->defs[i].param, option_defs->defs[i].name, + option_defs->defs[i].description, + option_defs->defs[i].default_value.str); + + break; + } + + case UTIL_OPTIONS_TYPE_BOOL: + { + printf( + " -%c [bool] %s: %s\n" + " default: %d\n", + option_defs->defs[i].param, option_defs->defs[i].name, + option_defs->defs[i].description, + option_defs->defs[i].default_value.b); + + break; + } + + case UTIL_OPTIONS_TYPE_BIN: + { + size_t len = option_defs->defs[i].default_value.bin.len * 2 + 1; + char* buf = util_xmalloc(len); + + util_hex_encode_uc(option_defs->defs[i].default_value.bin.data, + option_defs->defs[i].default_value.bin.len, buf, len); + + printf( + " -%c [bin] %s: %s\n" + " default (len %Iu): %s\n", + option_defs->defs[i].param, option_defs->defs[i].name, + option_defs->defs[i].description, + option_defs->defs[i].default_value.bin.len, + buf); + + free(buf); + + break; + } + + default: + { + printf( + " -%c [unkn] %s: %s\n" + " default: -invalid-\n", + option_defs->defs[i].param, option_defs->defs[i].name, + option_defs->defs[i].description); + + break; + } + } + } +} + +void util_options_free(struct util_options_opts* opts) +{ + for (uint32_t i = 0; i < opts->entries; i++) { + + switch (opts->defs->defs[i].type) { + case UTIL_OPTIONS_TYPE_STR: + { + if (opts->values[i].value.str) { + free(opts->values[i].value.str); + } + + break; + } + + case UTIL_OPTIONS_TYPE_BIN: + { + if (opts->values[i].value.bin.data) { + free(opts->values[i].value.bin.data); + } + + break; + } + + default: + break; + } + } + + free(opts->values); + free(opts); +} + +// if NULL, usage is printed +static struct util_options_opts* util_options_get2( + int argc, char** argv, const struct util_options_defs* option_defs) +{ + bool success; + char* options_file = NULL; + struct util_options_opts* options = + (struct util_options_opts*) + util_xmalloc(sizeof(struct util_options_opts)); + + if (option_defs == NULL) { + options->defs = NULL; + options->values = NULL; + options->entries = 0; + + return options; + } + + options->defs = option_defs; + options->entries = option_defs->ndefs; + + options->values = (struct util_options_value*) util_xmalloc( + sizeof(struct util_options_value) * options->entries); + + memset(options->values, 0, + sizeof(struct util_options_value) * options->entries); + + /* detect if we read options from a file */ + for (int i = 0; i < argc; i++) { + + if (!strcmp(argv[i], "--options")) { + + if (i + 1 >= argc) { + log_warn("Missing argument for --options\n"); + + util_options_print_usage(option_defs); + util_options_free(options); + return NULL; + } + + options_file = argv[i + 1]; + break; + } + } + + if (options_file) { + log_debug("Processing options file %s", options_file); + success = util_options_init_from_file(options, option_defs, + options_file); + + if (!success) { + exit(0); + } + } + + log_debug("Processing cmd args"); + success = util_options_init_from_args(options, option_defs, argc, argv); + + if (!success) { + util_options_print_usage(option_defs); + util_options_free(options); + return NULL; + } else { + return options; + } +} + +static bool util_options_init_from_args(struct util_options_opts* options, + const struct util_options_defs* option_defs, int argc, char** argv) +{ + for (int i = 0; i < argc; i++) { + + if (argv[i][0] != '-') { + continue; + } + + for (uint32_t j = 0; j < options->entries; j++) { + /* prints usage */ + if (argv[i][1] == option_defs->usage_param) { + return false; + } + + if (options->defs->defs[j].param == argv[i][1]) { + + switch (options->defs->defs[j].type) { + case UTIL_OPTIONS_TYPE_INT: + { + if (i + 1 >= argc) { + break; + } + + ++i; + + options->values[j].value.i = atoi(argv[i]); + + break; + } + + case UTIL_OPTIONS_TYPE_DOUBLE: + { + if (i + 1 >= argc) { + break; + } + + ++i; + + options->values[j].value.d = atof(argv[i]); + + break; + } + + case UTIL_OPTIONS_TYPE_STR: + { + if (i + 1 >= argc) { + break; + } + + ++i; + + /* FIXME memory leak if overriding string from options + file */ + + if (strlen(argv[i]) > 0) { + options->values[j].value.str = util_str_dup(argv[i]); + } else { + options->values[j].value.str = NULL; + } + + break; + } + + case UTIL_OPTIONS_TYPE_BOOL: + { + options->values[j].value.b = true; + + break; + } + + case UTIL_OPTIONS_TYPE_BIN: + { + if (i + 1 >= argc) { + break; + } + + ++i; + + /* FIXME memory leak if overriding bin data from options + file */ + + if (strlen(argv[i]) > 0) { + size_t len = strlen(argv[i]); + len = len / 2 + len % 2; + + options->values[j].value.bin.len = len; + options->values[j].value.bin.data = util_xmalloc(len); + + if (!util_hex_decode(options->values[j].value.bin.data, + options->values[j].value.bin.len, argv[i], + strlen(argv[i]))) { + log_warn("Decoding binary data for key %s " + "failed", options->defs->defs[j].name); + options->values[j].value.bin.len = 0; + options->values[j].value.bin.data = NULL; + } + } else { + options->values[j].value.bin.len = 0; + options->values[j].value.bin.data = NULL; + } + + break; + } + + default: + continue; + } + + log_debug("Cmd arg: -%c %s (type %d): %s", + options->defs->defs[j].param, options->defs->defs[j].name, + options->defs->defs[j].type, argv[i]); + + options->values[j].avail = true; + break; + } + } + } + + return true; +} + + + +static bool util_options_init_from_file(struct util_options_opts* options, + const struct util_options_defs* option_defs, char* file_path) +{ + char* pos_lines; + char* pos_key_val; + char* ctx_lines; + char* ctx_key_val; + char* data; + size_t len; + + if (!util_file_load(file_path, (void**) &data, &len, true)) { + /* If file does not exist, create one with default configuration + values */ + if (util_fs_path_exists(file_path)) { + log_warn("Loading options file %s failed, faulty or corrupted " + "configuration", file_path); + } else { + /* Create a default config file if the usage param is set. This + indicates that we are currently not on the inject process + but already on the inject library. We want all config params + of the inject lib */ + if (option_defs->usage_param) { + log_info("Options file %s does not exist, creating default...", + file_path); + + if (!util_options_write_default_options_file(option_defs, + file_path)) { + log_warn("Creating default options file %s failed", + file_path); + } else { + log_info("Options file %s created. Tweak it to your needs and restart the game.", + file_path); + } + } + } + + return false; + } + + pos_lines = strtok_r(data, "\n", &ctx_lines); + + while (pos_lines != NULL) { + char* pos_line_dup; + char* key = NULL; + char* val = NULL; + + /* ignore comments and empty lines */ + if (strlen(pos_lines) > 0 && pos_lines[0] != '#') { + pos_line_dup = util_str_dup(pos_lines); + pos_key_val = strtok_r(pos_line_dup, "=", &ctx_key_val); + + log_debug("Line: %s", pos_lines); + + if (pos_key_val != NULL) { + key = pos_key_val; + val = &pos_key_val[strlen(key) + 1]; + } else { + log_warn("Invalid options line %s in options file %s", pos_lines, file_path); + free(pos_line_dup); + free(data); + return false; + } + + log_debug("Key: %s, Value: %s", key, val); + + /* search for key */ + for (uint32_t j = 0; j < options->entries; j++) { + + if (!strcmp(options->defs->defs[j].name, key)) { + + switch (options->defs->defs[j].type) { + case UTIL_OPTIONS_TYPE_INT: + { + if (val) { + options->values[j].value.i = atoi(val); + } else { + options->values[j].value.i = 0; + } + + break; + } + + case UTIL_OPTIONS_TYPE_DOUBLE: + { + if (val) { + options->values[j].value.d = atof(val); + } else { + options->values[j].value.d = 0.0; + } + + break; + } + + case UTIL_OPTIONS_TYPE_STR: + { + if (val && strlen(val) > 0) { + options->values[j].value.str = + util_str_dup(val); + } else { + options->values[j].value.str = NULL; + } + + break; + } + + case UTIL_OPTIONS_TYPE_BOOL: + { + if (val) { + if (atoi(val) <= 0) { + options->values[j].value.b = false; + } else { + options->values[j].value.b = true; + } + } else { + options->values[j].value.b = false; + } + + + break; + } + + case UTIL_OPTIONS_TYPE_BIN: + { + if (val && strlen(val) > 0) { + size_t lenBin = strlen(val); + lenBin = lenBin / 2 + lenBin % 2; + + options->values[j].value.bin.len = lenBin; + options->values[j].value.bin.data = + util_xmalloc(lenBin); + + if (!util_hex_decode( + options->values[j].value.bin.data, + options->values[j].value.bin.len, val, + strlen(val))) { + log_warn("Decoding binary data for key " + "%s failed", + options->defs->defs[j].name); + options->values[j].value.bin.len = 0; + options->values[j].value.bin.data = NULL; + } + } else { + options->values[j].value.bin.len = 0; + options->values[j].value.bin.data = NULL; + } + + break; + } + + default: + continue; + } + + log_debug("Options file param: -%c %s (type %d): %s", + options->defs->defs[j].param, + options->defs->defs[j].name, + options->defs->defs[j].type, val ? val : "NULL"); + + options->values[j].avail = true; + break; + } + } + + free(pos_line_dup); + } + + pos_lines = strtok_r(NULL, "\n", &ctx_lines); + } + + free(data); + + return true; +} + +static bool util_options_write_default_options_file( + const struct util_options_defs* option_defs, char* file_path) +{ + FILE* file; + + file = fopen(file_path, "wb"); + + if (file == NULL) { + return false; + } + + for (uint32_t i = 0; i < option_defs->ndefs; i++) { + + switch (option_defs->defs[i].type) { + case UTIL_OPTIONS_TYPE_INT: + { + fprintf(file, "# [int]: %s\n", + option_defs->defs[i].description); + fprintf(file, "%s=%d\n\n", option_defs->defs[i].name, + option_defs->defs[i].default_value.i); + + break; + } + + case UTIL_OPTIONS_TYPE_DOUBLE: + { + fprintf(file, "# [double]: %s\n", + option_defs->defs[i].description); + fprintf(file, "%s=%f\n\n", option_defs->defs[i].name, + option_defs->defs[i].default_value.d); + + break; + } + + case UTIL_OPTIONS_TYPE_STR: + { + fprintf(file, "# [str]: %s\n", + option_defs->defs[i].description); + + if (option_defs->defs[i].default_value.str) { + fprintf(file, "%s=%s\n\n", option_defs->defs[i].name, + option_defs->defs[i].default_value.str); + } else { + fprintf(file, "%s=\n\n", option_defs->defs[i].name); + } + + break; + } + + case UTIL_OPTIONS_TYPE_BOOL: + { + fprintf(file, "# [bool (0/1)]: %s\n", + option_defs->defs[i].description); + fprintf(file, "%s=%d\n\n", option_defs->defs[i].name, + option_defs->defs[i].default_value.b); + + break; + } + + case UTIL_OPTIONS_TYPE_BIN: + { + fprintf(file, "# [bin]: %s\n", + option_defs->defs[i].description); + + if (option_defs->defs[i].default_value.bin.data) { + size_t len = + option_defs->defs[i].default_value.bin.len * 2 + 1; + char* buf = util_xmalloc(len); + + util_hex_encode_uc( + option_defs->defs[i].default_value.bin.data, + option_defs->defs[i].default_value.bin.len, buf, len); + + + fprintf(file, "%s=%s\n\n", option_defs->defs[i].name, buf); + + free(buf); + } + + break; + } + + default: + { + log_warn("Invalid value type %d found", + option_defs->defs[i].type); + break; + } + } + } + + fclose(file); + return true; +} \ No newline at end of file diff --git a/src/main/util/options.h b/src/main/util/options.h new file mode 100644 index 0000000..6a871c6 --- /dev/null +++ b/src/main/util/options.h @@ -0,0 +1,170 @@ +#ifndef UTIL_OPTIONS_H +#define UTIL_OPTIONS_H + +#include +#include +#include + +/** + * Value types support by option values + */ +enum util_options_type { + UTIL_OPTIONS_TYPE_INT, + UTIL_OPTIONS_TYPE_DOUBLE, + UTIL_OPTIONS_TYPE_STR, + UTIL_OPTIONS_TYPE_BOOL, + UTIL_OPTIONS_TYPE_BIN, +}; + +/** + * Single option definition element. Use this to define possible option + * key-value tuples to parse from an argument list + */ +struct util_options_def { + const char* name; + const char* description; + const char param; + enum util_options_type type; + union { + int i; + double d; + const char* str; + bool b; + struct { + const uint8_t* data; + size_t len; + } bin; + } default_value; +}; + +/** + * Option definitions. A list of key-value elements defining option values + * as well as usage information for the application + */ +struct util_options_defs { + const char* usage_header; + char usage_param; + const struct util_options_def* defs; + uint32_t ndefs; +}; + +/** + * A single option value as part of the key-value tuple + */ +struct util_options_value { + bool avail; + union { + int i; + double d; + char* str; + bool b; + struct { + uint8_t* data; + size_t len; + } bin; + } value; +}; + +/** + * Parsed option values based on an options definition + */ +struct util_options_opts { + const struct util_options_defs* defs; + struct util_options_value* values; + uint32_t entries; +}; + +/** + * Initialize the options module by passing the arguments from main on + * + * Make sure to call this as early as possible when entering main and before + * any other calls of this module are invoked + * + * @param argc Argc from main + * @param argv Argv from main + */ +void util_options_init(int argc, char** argv); + +/** + * Get options from the initial argument list + * + * @param option_defs A list of option definitions. The arguments are parsed + * using this list. If NULL, usage information with the definition + * is printed and this call also returns NULL. + * @return A list of parsed options based on the specified definitions or + * NULL if usage information was printed. + */ +struct util_options_opts* util_options_get( + const struct util_options_defs* option_defs); + +/** + * Get an integer value from an options list + * + * @param opts Parsed options list received from util_options_get + * @param name Name of the options key + * @return Value of the options key converted to an integer value. If the type + * of the options key is not matching, 0 is returned + */ +int util_options_get_int(const struct util_options_opts* opts, + const char* name); + +/** + * Get a double value from an options list + * + * @param opts Parsed options list received from util_options_get + * @param name Name of the options key + * @return Value of the options key converted to a double value. If the type + * of the options key is not matching, 0 is returned + */ +double util_options_get_double(const struct util_options_opts* opts, const char* name); + +/** + * Get a string from an options list + * + * @param opts Parsed options list received from util_options_get + * @param name Name of the options key + * @return Value of the options key converted to a string. If the type + * of the options key is not matching, NULL is returned + */ +const char* util_options_get_str(const struct util_options_opts* opts, + const char* name); + +/** + * Get a bool value from an options list + * + * @param opts Parsed options list received from util_options_get + * @param name Name of the options key + * @return Value of the options key converted to a bool value. If the type + * of the options key is not matching, false is returned + */ +bool util_options_get_bool(const struct util_options_opts* opts, + const char* name); + +/** + * Get binary data from an options list + * + * @param opts Parsed options list received from util_options_get + * @param name Name of the options key + * @param length Pointer to return the length of the binary data to + * (set to NULL if not required) + * @return Value of the options key converted to a binary array. If the type + * of the options key is not matching, NULL is returned + */ +const uint8_t* util_options_get_bin(const struct util_options_opts* opts, + const char* name, size_t* length); + +/** + * Print usage information + * + * @param option_defs A list of option definitions. + */ +void util_options_print_usage(const struct util_options_defs* opts); + +/** + * Free an options list + * + * @param opts Options list to free + */ +void util_options_free(struct util_options_opts* opts); + +#endif diff --git a/src/main/util/patch.c b/src/main/util/patch.c new file mode 100644 index 0000000..61bcb52 --- /dev/null +++ b/src/main/util/patch.c @@ -0,0 +1,59 @@ +#define LOG_MODULE "util-patch" + +#include + +#include "util/log.h" +#include "util/patch.h" + +/* addr needs to be a multiple of page size */ +#define UNPROTECT(addr,len) mprotect((void*)(addr-(addr%4096)),(addr%4096) + \ + len,PROT_READ|PROT_WRITE|PROT_EXEC) + +void util_patch_write_memory(uintptr_t mem, const void* data, size_t len) +{ + if (UNPROTECT(mem, len) != 0) { + log_die("Unprotecting memory %p, len %d failed", mem, len); + } + + memcpy((void*) mem, data, len); +} + +void util_patch_write_memory_byte(uintptr_t mem, uint8_t data) +{ + util_patch_write_memory(mem, (const void*) &data, sizeof(uint8_t)); +} + +void util_patch_function(uintptr_t func_addr, void* detour_func) +{ + /* uintptr_t is said to be portable (32/64-bit) */ + uint8_t offset = 5; + + /* 64-bit binary */ + if (sizeof(uintptr_t) == 8) { + offset += 4; + } + + uintptr_t call = + (uintptr_t) (((uintptr_t) detour_func) - func_addr - offset); + + if (UNPROTECT(func_addr, 4096) != 0) { + log_die("Unprotecting memory %p, len %d failed", func_addr); + } + + *((uint8_t*) (func_addr)) = 0xE9; + *((uintptr_t*) (func_addr + 1)) = call; +} + +void* util_patch_find_signiture(const uint8_t* sig, uint32_t sig_len, + int32_t sig_offset, void* start_addr, void* end_addr, int32_t alignment) +{ + size_t pos; + + for (pos = (size_t) start_addr; pos < (size_t) end_addr; pos += alignment) { + if (!memcmp((void*) pos, sig, sig_len)) { + return (void*) (pos + sig_offset); + } + } + + return NULL; +} \ No newline at end of file diff --git a/src/main/util/patch.h b/src/main/util/patch.h new file mode 100644 index 0000000..1bd5249 --- /dev/null +++ b/src/main/util/patch.h @@ -0,0 +1,52 @@ +#ifndef UTIL_PATCH_H +#define UTIL_PATCH_H + +#include +#include +#include + +/** + * Write data to an arbitrary memory location + * + * @param mem Memory location to write to + * @param data Pointer to buffer with data to write + * @param len Length of data to write + */ +void util_patch_write_memory(uintptr_t mem, const void* data, size_t len); + +/** + * Write a single byte to an arbitrary memory location + * + * @param mem Memory location to write to + * @param data Byte to write + */ +void util_patch_write_memory_byte(uintptr_t mem, uint8_t data); + +/** + * Write a function ptr/function call to a memory location + * + * Use this to patch existing call instructions and detour to your own code + * + * @param func_addr Address of the function/call instruction to replace + * @param detour_func Address of your function to detour to + */ +void util_patch_function(uintptr_t func_addr, void* detour_func); + +/** + * Scan a memory area limited by a start and end address for a signiture. + * + * @param sig Buffer with signiture to search for + * @param sig_len Length of signiture + * @param sig_offset Offset that gets added to the address where the signiture + * starts (if found) + * @param start_addr Pointer to the address to start searching at + * @param end_addr Pointer to the address to stop searching at + * @param alignment Aligns the search signiture, i.e. search in steps of + * X bytes + * @return If found, pointer to memory where the signiture was found (first + * occurance) with the signiture offset added, NULL otherwise + */ +void* util_patch_find_signiture(const uint8_t* sig, uint32_t sig_len, + int32_t sig_offset, void* start_addr, void* end_addr, int32_t alignment); + +#endif \ No newline at end of file diff --git a/src/main/util/proc.c b/src/main/util/proc.c new file mode 100644 index 0000000..e78ee6e --- /dev/null +++ b/src/main/util/proc.c @@ -0,0 +1,218 @@ +#define LOG_MODULE "util-proc" + +#include +#include +#include +#include + +#include "util/log.h" +#include "util/proc.h" +#include "util/str.h" + +static char* util_sys_read_entries_from_proc_file(const char* path, int* count_out) +{ + const char* sep = "\n"; + char* str = util_str_dup(""); + char* tmp; + + FILE* cmdline = fopen(path, "rb"); + + if (!cmdline) { + log_error("Opening %s failed: %s", path, strerror(errno)); + return str; + } + + char* arg = 0; + size_t size = 0; + int count = 0; + + while (getdelim(&arg, &size, 0, cmdline) != -1) { + if (strlen(str) > 0) { + tmp = util_str_merge(str, sep); + free(str); + str = tmp; + } + + tmp = util_str_merge(str, arg); + free(str); + str = tmp; + count++; + } + + free(arg); + fclose(cmdline); + + if (count_out) { + *count_out = count; + } + + return str; +} + +static void util_proc_log_current_working_dir() +{ + char tmp[PATH_MAX]; + + if (!getcwd(tmp, sizeof(tmp))) { + log_error("Getting current working directory failed"); + } else { + log_info("Current working directory: %s", tmp); + } +} + +static void util_proc_log_current_process() +{ + log_info("PID: %d", getpid()); +} + +static void util_sys_info_log_path_executable() +{ + char buffer[PATH_MAX]; + + if (!util_proc_get_path_executable(buffer, sizeof(buffer))) { + log_error("Getting path of executable failed"); + } else { + log_info("Executable: %s", buffer); + } +} + +static void util_sys_info_log_user() +{ + log_info("User: %d", getuid()); +} + +static void util_sys_info_log_running_as_root() +{ + log_info("Running as root: %d", util_proc_is_running_as_root()); +} + +static void util_sys_info_log_cmd_line_args() +{ + int count; + char* str = util_sys_read_entries_from_proc_file("/proc/self/cmdline", &count); + + log_info("Cmd arguments (%d):\n%s", count, str); + + free(str); +} + +static void util_sys_info_log_env_vars() +{ + int count; + char* str = util_sys_read_entries_from_proc_file("/proc/self/environ", &count); + + log_info("Environment variables (%d):\n%s", count, str); + + free(str); +} + +bool util_proc_is_running_as_root() +{ + return getuid() == 0; +} + +bool util_proc_get_path_executable(char* buffer, size_t size) +{ + // readlink does not null terminate + memset(buffer, 0, size); + + return readlink("/proc/self/exe", buffer, size) != -1; +} + +bool util_proc_get_folder_path_executable(char* buffer, size_t size) +{ + if (!util_proc_get_path_executable(buffer, size)) { + return false; + } + + size_t pos = strlen(buffer) - 1; + + // If executable in the root folder, keep the single / + while (pos > 0 && buffer[pos] != '/') { + buffer[pos] = '\0'; + pos--; + } + + // delete / + if (pos > 0) { + buffer[pos] = '\0'; + } + + return true; +} + +bool util_proc_get_folder_path_executable_no_ld_linux(char* buffer, size_t size) +{ + if (!util_proc_get_path_executable(buffer, size)) { + log_error("Getting executable path failed"); + return false; + } + + if (util_str_ends_with(buffer, "ld-linux.so.2")) { + int argc; + char* args = util_sys_read_entries_from_proc_file("/proc/self/cmdline", &argc); + + char* tok = strtok(args, "\n"); + bool awaiting_value = false; + + // Skip first token, ld-linux binary + tok = strtok(NULL, "\n"); + + while (tok != NULL) { + // Check if the next arg is declaring an option key for ld-linux + if (util_str_starts_with(tok, "--")) { + awaiting_value = 1; + } else if (awaiting_value) { + // Just hit the awaited value for the previously skipped option key + awaiting_value = false; + } else { + // Got executable arg passed to ld-linux + if (strlen(tok) > size) { + free(args); + return false; + } + + strcpy(buffer, tok); + + // Remove executable name + // If executable in the root folder, keep the single / + size_t pos = strlen(buffer) - 1; + while (pos > 0 && buffer[pos] != '/') { + buffer[pos] = '\0'; + pos--; + } + + // delete / + if (pos > 0) { + buffer[pos] = '\0'; + } + + free(args); + return true; + } + + tok = strtok(NULL, "\n"); + } + + free(args); + return false; + } else { + return util_proc_get_folder_path_executable(buffer, size); + } +} + + +void util_proc_log_info() +{ + log_info("================================ Current process information ================================"); + + util_proc_log_current_process(); + util_sys_info_log_path_executable(); + util_proc_log_current_working_dir(); + util_sys_info_log_user(); + util_sys_info_log_running_as_root(); + util_sys_info_log_cmd_line_args(); + util_sys_info_log_env_vars(); + + log_info("================================================================================================"); +} \ No newline at end of file diff --git a/src/main/util/proc.h b/src/main/util/proc.h new file mode 100644 index 0000000..601a0b8 --- /dev/null +++ b/src/main/util/proc.h @@ -0,0 +1,47 @@ +#ifndef UTIL_PROC_H +#define UTIL_PROC_H + +#include +#include + +/** + * Check if the current process is running as a root user. + * + * @return True if running as root, false otherwise. + */ +bool util_proc_is_running_as_root(); + +/** + * Get the full path of the executable of the current process (including the executable name). + * + * @param buffer Buffer to read the path into. + * @param size Size of the buffer + * @return True on success, false on failure, e.g. buffer too small. + */ +bool util_proc_get_path_executable(char* buffer, size_t size); + +/** + * Get the full path of the folder the executable of the current process is located in. + * + * @param buffer Buffer to read the path into. + * @param size Size of the buffer + * @return True on success, false on failure, e.g. buffer too small. + */ +bool util_proc_get_folder_path_executable(char* buffer, size_t size); + +/** + * Special version of util_proc_get_folder_path_executable that considers when the process is run explicitly with a + * ld-linux binary. Returns the path of the application's executable and not ld-linux in that case. + * + * @param buffer Buffer to read the path into. + * @param size Size of the buffer + * @return True on success, false on failure, e.g. buffer too small. + */ +bool util_proc_get_folder_path_executable_no_ld_linux(char* buffer, size_t size); + +/** + * Log information about the current process to the console. + */ +void util_proc_log_info(); + +#endif diff --git a/src/main/util/rand.c b/src/main/util/rand.c new file mode 100644 index 0000000..cbd365d --- /dev/null +++ b/src/main/util/rand.c @@ -0,0 +1,34 @@ +#include +#include + +#include "rand.h" + +static int _util_rand_init = 0; + +static void _util_rand_initialize() +{ + if (!_util_rand_init) { + _util_rand_init = 1; + srand((unsigned int) time(NULL)); + } +} + +uint32_t util_rand_gen_32() +{ + _util_rand_initialize(); + + return (uint32_t) rand(); +} + +uint64_t util_rand_gen_64() +{ + uint64_t value; + + _util_rand_initialize(); + + value = 0; + value |= (((uint64_t) rand()) << 32); + value |= ((uint64_t) rand()); + + return value; +} \ No newline at end of file diff --git a/src/main/util/rand.h b/src/main/util/rand.h new file mode 100644 index 0000000..cc79f0b --- /dev/null +++ b/src/main/util/rand.h @@ -0,0 +1,10 @@ +#ifndef UTIL_RAND_H +#define UTIL_RAND_H + +#include + +uint32_t util_rand_gen_32(); + +uint64_t util_rand_gen_64(); + +#endif diff --git a/src/main/util/sock-tcp.c b/src/main/util/sock-tcp.c new file mode 100644 index 0000000..655146e --- /dev/null +++ b/src/main/util/sock-tcp.c @@ -0,0 +1,185 @@ +#define LOG_MODULE "sock-tcp" + +#include +#include +#include +#include +#include + +#include "util/net.h" +#include "util/log.h" +#include "util/sock-tcp.h" + +bool util_sock_tcp_is_connectable(const char* ipv4, uint32_t timeout_ms) +{ + char* address; + uint16_t port; + + util_net_split_ipv4_str(ipv4, &address, &port); + + bool res = util_sock_tcp_is_connectable2(address, port, timeout_ms); + + free(address); + return res; +} + +bool util_sock_tcp_is_connectable2(const char* ipv4, uint16_t port, uint32_t timeout_ms) +{ + struct sockaddr_in sa; + + // store this IP address in sa: + inet_pton(AF_INET, ipv4, &(sa.sin_addr)); + + return util_sock_tcp_is_connectable3(htonl(sa.sin_addr.s_addr), port, timeout_ms); +} + +bool util_sock_tcp_is_connectable3(uint32_t ipv4, uint16_t port, uint32_t timeout_ms) +{ + int handle; + struct sockaddr_in addr; + fd_set fdset; + struct timeval tv; + bool res; + + handle = socket(AF_INET, SOCK_STREAM, 0); + + if (handle == -1) { + log_error("Creating socket (%X, %d) failed: %s", ipv4, port, strerror(errno)); + return false; + } + + fcntl(handle, F_SETFL, O_NONBLOCK); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(ipv4); + + connect(handle, (const struct sockaddr*) &addr, sizeof(addr)); + + FD_ZERO(&fdset); + FD_SET(handle, &fdset); + tv.tv_sec = (__time_t) (timeout_ms / 1000); + tv.tv_usec = (__suseconds_t) ((timeout_ms % 1000) * 1000); + + if (select(handle + 1, NULL, &fdset, NULL, &tv) == 1) { + int so_error; + socklen_t len = sizeof(so_error); + + getsockopt(handle, SOL_SOCKET, SO_ERROR, &so_error, &len); + + if (so_error == 0) { + res = true; + } else { + res = false; + } + } else { + res = false; + } + + close(handle); + + return res; +} + +int util_sock_tcp_connect(const char* ipv4) +{ + char* address; + uint16_t port; + + util_net_split_ipv4_str(ipv4, &address, &port); + + int res = util_sock_tcp_connect2(address, port); + + free(address); + return res; +} + +int util_sock_tcp_connect2(const char* ipv4, uint16_t port) +{ + struct sockaddr_in sa; + + // store this IP address in sa: + inet_pton(AF_INET, ipv4, &(sa.sin_addr)); + + return util_sock_tcp_connect3(htonl(sa.sin_addr.s_addr), port); +} + +int util_sock_tcp_connect3(uint32_t ipv4, uint16_t port) +{ + int handle; + struct sockaddr_in addr; + + handle = socket(AF_INET, SOCK_STREAM, 0); + + if (handle == -1) { + log_error("Creating socket (%X, %d) failed: %s", ipv4, port, strerror(errno)); + return -1; + } + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(ipv4); + + if (connect(handle, (const struct sockaddr*) &addr, sizeof(addr)) == -1) { + close(handle); + log_error("Connecting to %X, %d failed: %s", ipv4, port, strerror(errno)); + return -1; + } + + log_debug("Connected to %X on port %d", ipv4, port); + + return handle; +} + +ssize_t util_sock_tcp_send(int handle, void* buffer, size_t size, uint32_t timeout_ms) +{ + struct timeval tv; + tv.tv_sec = (__time_t) (timeout_ms / 1000); + tv.tv_usec = (__suseconds_t) ((timeout_ms % 1000) * 1000); + + setsockopt(handle, SOL_SOCKET, SO_SNDTIMEO, (const char*) &tv, sizeof(tv)); + + ssize_t length = send(handle, buffer, size, 0); + + if (length < 0) { + // same as EWOULDBLOCK + if (errno == EAGAIN) { + // no data for non blocking + return 0; + } + + return -1; + } + + return length; +} + +ssize_t util_sock_tcp_recv(int handle, void* buffer, size_t size, uint32_t timeout_ms) +{ + struct timeval tv; + tv.tv_sec = (__time_t) (timeout_ms / 1000); + tv.tv_usec = (__suseconds_t) ((timeout_ms % 1000) * 1000); + + setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(tv)); + + ssize_t length = recv(handle, buffer, size, 0); + + if (length < 0) { + // same as EWOULDBLOCK + if (errno == EAGAIN) { + // no data for non blocking + return 0; + } + + return -1; + } + + return length; +} + +void util_sock_tcp_close(int handle) +{ + close(handle); +} \ No newline at end of file diff --git a/src/main/util/sock-tcp.h b/src/main/util/sock-tcp.h new file mode 100644 index 0000000..67134de --- /dev/null +++ b/src/main/util/sock-tcp.h @@ -0,0 +1,30 @@ +// +// Created by on 9/16/18. +// + +#ifndef UTIL_SOCK_TCP_H +#define UTIL_SOCK_TCP_H + +#include +#include +#include + +bool util_sock_tcp_is_connectable(const char* ipv4, uint32_t timeout_ms); + +bool util_sock_tcp_is_connectable2(const char* ipv4, uint16_t port, uint32_t timeout_ms); + +bool util_sock_tcp_is_connectable3(uint32_t ipv4, uint16_t port, uint32_t timeout_ms); + +int util_sock_tcp_connect(const char* ipv4); + +int util_sock_tcp_connect2(const char* ipv4, uint16_t port); + +int util_sock_tcp_connect3(uint32_t ipv4, uint16_t port); + +ssize_t util_sock_tcp_send(int handle, void* buffer, size_t size, uint32_t timeout_ms); + +ssize_t util_sock_tcp_recv(int handle, void* buffer, size_t size, uint32_t timeout_ms); + +void util_sock_tcp_close(int handle); + +#endif diff --git a/src/main/util/str.c b/src/main/util/str.c new file mode 100644 index 0000000..6e2c1ce --- /dev/null +++ b/src/main/util/str.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include + +#include "util/log.h" +#include "util/mem.h" +#include "util/str.h" + +bool util_str_starts_with(const char* haystack, const char* needle) +{ + size_t haystack_len; + size_t needle_len; + + haystack_len = strlen(haystack); + needle_len = strlen(needle); + + if (needle_len > haystack_len) { + return false; + } + + return !memcmp(haystack, needle, needle_len); +} + +bool util_str_ends_with(const char* haystack, const char* needle) +{ + size_t haystack_len; + size_t needle_len; + + haystack_len = strlen(haystack); + needle_len = strlen(needle); + + if (needle_len > haystack_len) { + return false; + } + + return !memcmp(&haystack[haystack_len - needle_len], needle, needle_len); +} + +size_t util_str_format(char* buf, size_t nchars, const char* fmt, ...) +{ + va_list ap; + size_t result; + + va_start(ap, fmt); + result = util_str_vformat(buf, nchars, fmt, ap); + va_end(ap); + + return result; +} + +size_t util_str_vformat(char* buf, size_t nchars, const char* fmt, va_list ap) +{ + int result; + + result = vsnprintf(buf, nchars, fmt, ap); + + if (result >= (int) nchars || result < 0) { + abort(); + } + + return (size_t) result; +} + +void util_str_cat(char* dest, size_t dnchars, const char* src) +{ + size_t dlen; + size_t slen; + + dlen = strlen(dest); + slen = strlen(src); + + if (dlen + slen >= dnchars) { + abort(); + } + + memcpy(dest + dlen, src, (slen + 1) * sizeof(char)); +} + +void util_str_cpy(char* dest, size_t dnchars, const char* src) +{ + size_t slen; + + slen = strlen(src); + + if (slen >= dnchars) { + abort(); + } + + memcpy(dest, src, (slen + 1) * sizeof(char)); +} + +char* util_str_merge(const char* str1, const char* str2) +{ + char* out; + size_t str1_len; + size_t str2_len; + size_t total; + + str1_len = strlen(str1); + str2_len = strlen(str2); + total = str1_len + str2_len + 1; + + out = util_xmalloc(total); + memcpy(out, str1, str1_len); + memcpy(out + str1_len, str2, str2_len); + out[total - 1] = '\0'; + + return out; +} + +char* util_str_dup(const char* str) +{ + char *dest; + size_t nbytes; + + log_assert(str); + + nbytes = strlen(str) + 1; + dest = util_xmalloc(nbytes); + memcpy(dest, str, nbytes); + + return dest; +} + +void util_str_trim(char* str) +{ + char *pos; + + for (pos = str + strlen(str) - 1 ; pos > str ; pos--) { + if (!isspace(*pos)) { + return; + } + + *pos = '\0'; + } +} + +char* util_str_buffer(const uint8_t* buf, size_t len) +{ + char* ret; + size_t pos; + + pos = 0; + ret = util_xmalloc(len * 3 + 1); + + for (size_t i = 0; i < len; i++) { + uint8_t tmp = buf[i]; + + pos += sprintf(ret + pos, "%02X ", tmp); + } + + ret[len * 3] = '\0'; + + return ret; +} + +char** util_str_split(const char* str, const char* delim, size_t* count) +{ + char** toks; + char* copy; + char* cur; + size_t counter; + + log_assert(str); + log_assert(delim); + log_assert(count); + + *count = 0; + + copy = util_str_dup(str); + cur = strtok(copy, delim); + + // First iteration, just count items + while (cur != NULL) { + (*count)++; + cur = strtok(NULL, delim); + } + + util_xfree((void**) ©); + + toks = util_xmalloc(sizeof(char*) * (*count)); + + copy = util_str_dup(str); + cur = strtok(copy, delim); + + counter = 0; + + // Second iteration, grab tokens + while (cur != NULL) { + toks[counter] = util_str_dup(cur); + counter++; + + cur = strtok(NULL, delim); + } + + util_xfree((void**) ©); + + return toks; +} + +void util_str_free_split(char** split, size_t count) +{ + log_assert(split); + + for (int i = 0; i < count; i++) { + util_xfree((void**) &split[i]); + } + + util_xfree((void**) &split); +} \ No newline at end of file diff --git a/src/main/util/str.h b/src/main/util/str.h new file mode 100644 index 0000000..7720d5a --- /dev/null +++ b/src/main/util/str.h @@ -0,0 +1,107 @@ +#ifndef UTIL_STR_H +#define UTIL_STR_H + +#include +#include +#include +#include + +/** + * Check if a string starts with a specific (sub-) string + * + * @param haystack String to check + * @param needle String to compare with start of haystack + * @return True if haystack ends with needle, false otherwise + */ +bool util_str_starts_with(const char* haystack, const char* needle); + +/** + * Check if a string ends with a specific (sub-) string + * + * @param haystack String to check + * @param needle String to compare with end of haystack + * @return True if haystack ends with needle, false otherwise + */ +bool util_str_ends_with(const char* haystack, const char* needle); + +/** + * Print a formated string to a buffer + * + * @param buf Allocated buffer to print to + * @param nchars Size of allocated buffer + * @param fmt Format of the string to print + * @param ... Arguments for the format string + * @return Size of the string printed to the buffer + */ +size_t util_str_format(char* buf, size_t nchars, const char* fmt, ...); + +/** + * Print a formated string to a buffer + * + * @param buf Allocated buffer to print to + * @param nchars Size of allocated buffer + * @param fmt Format of the string to print + * @param ap Argument list for format + * @return Size of the string printed to the buffer + */ +size_t util_str_vformat(char* buf, size_t nchars, const char* fmt, va_list ap); + +/** + * Concat a string to another one + * + * @param dest Destination to append to + * @param dnchars Size of dest buffer + * @param src Source string to concat to dest + */ +void util_str_cat(char* dest, size_t dnchars, const char* src); + +/** + * Copy a string + * + * @param dest Destination to copy to + * @param dnchars Size of destination + * @param src Source string to copy from (to dest) + */ +void util_str_cpy(char* dest, size_t dnchars, const char* src); + +/** + * Merge to strings (str1 + str2) + * + * @param str1 String 1 to merge + * @param str2 String 2 to merge + * @return Newly allocated merged string: str1 + str2. Caller has to manage + * memory returned + */ +char* util_str_merge(const char* str1, const char* str2); + +/** + * Duplicate a string + * + * @param src String to duplicate + * @return Duplicated string (newly allocated memory). Caller has to manage + * memory returned + */ +char* util_str_dup(const char* src); + +/** + * Remove trailing spaces of a string + * + * @param str String to trim + */ +void util_str_trim(char* str); + +/** + * Print a buffer as hex digits to a string + * + * @param buf Buffer to print + * @param len Length of the buffer + * @return String representation of the buffer. Caller has to manage returned + * memory + */ +char* util_str_buffer(const uint8_t* buf, size_t len); + +char** util_str_split(const char* str, const char* delim, size_t* count); + +void util_str_free_split(char** split, size_t count); + +#endif diff --git a/src/main/util/sys-info.c b/src/main/util/sys-info.c new file mode 100644 index 0000000..32715c1 --- /dev/null +++ b/src/main/util/sys-info.c @@ -0,0 +1,22 @@ +#define LOG_MODULE "util-sys-info" + +#include + +#include "util/log.h" + +static void util_sys_info_log_kernel() +{ + struct utsname buf; + + if (uname(&buf)) { + log_error("Reading kernel version failed"); + return; + } + + log_info("%s|%s|%s|%s|%s", buf.sysname, buf.nodename, buf.release, buf.version, buf.machine); +} + +void util_sys_info_log() +{ + util_sys_info_log_kernel(); +} diff --git a/src/main/util/sys-info.h b/src/main/util/sys-info.h new file mode 100644 index 0000000..f51b2ae --- /dev/null +++ b/src/main/util/sys-info.h @@ -0,0 +1,9 @@ +#ifndef UTILSYS_INFO_H +#define UTIL_SYS_INFO_H + +/** + * Print system information to the log (kernel, cpu, ram etc) + */ +void util_sys_info_log(); + +#endif diff --git a/src/main/util/test.c b/src/main/util/test.c new file mode 100644 index 0000000..abfb6c1 --- /dev/null +++ b/src/main/util/test.c @@ -0,0 +1,159 @@ +#define LOG_MODULE "util-test" + +#include + +#include "list.h" +#include "log.h" +#include "mem.h" +#include "test.h" +#include "str.h" + +struct util_test_case { + struct util_list_node head; + char* name; + util_test_func_t func; +}; + +static size_t util_test_count; +static struct util_list util_test_list; + +void util_test_init() +{ + util_test_count = 0; + util_list_init(&util_test_list); + + log_info("Initialized"); +} + +void util_test_add(const char* name, util_test_func_t func) +{ + struct util_test_case* test; + + test = util_xmalloc(sizeof(struct util_test_case)); + + test->name = util_str_dup(name); + test->func = func; + + util_list_append(&util_test_list, &test->head); + util_test_count++; + + log_info("Added %s, func %p", name, func); +} + +void util_test_exec() +{ + log_info("Exec %d tests", util_test_count); + + struct util_list_node* pos; + struct util_test_case* test; + size_t counter = 1; + + for (pos = util_test_list.head; pos != NULL; pos = pos->next) { + test = containerof(pos, struct util_test_case, head); + + log_debug("%d/%d Executing %s...", counter++, util_test_count, test->name); + + if (!test->func()) { + log_error("%s failed", test->name); + return; + } + } + + log_info("All tests passed"); +} + +void util_test_shutdown() +{ + log_info("Shutdown"); + + struct util_list_node* pos; + struct util_test_case* test; + + // TODO list elems cleanup? + + for (pos = util_test_list.head; pos != NULL; pos = pos->next) { + test = containerof(pos, struct util_test_case, head); + + free(test->name); + } +} + +bool util_test_assert_exp(bool exp, const char* exp_str, const char* file, size_t line_num) +{ + if (!exp) { + log_error("Assert failed [%s:%d]: Expression %s failed", file, line_num, exp_str); + return false; + } else { + log_debug("Assert successful [%s:%d]: Expression %s", file, line_num, exp_str); + return true; + } +} + +bool util_test_assert_uint(size_t val_exp, size_t val_actual, const char* exp, const char* actual, const char* file, + size_t line_num) +{ + if (val_exp != val_actual) { + log_error("Assert failed [%s:%d]: %d != %d of expected %s and actual %s", file, line_num, val_exp, val_actual, + exp, actual); + return false; + } else { + log_debug("Assert successful [%s:%d]: %d == %d of expected %s and actual %s", file, line_num, val_exp, + val_actual, exp, actual); + return true; + } +} + +bool util_test_assert_str(const char* val_exp, const char* val_actual, const char* exp, const char* actual, + const char* file, size_t line_num) +{ + if (strcmp(val_exp, val_actual) != 0) { + log_error("Assert failed [%s:%d]: %s != %s of expected %s and actual %s", file, line_num, val_exp, val_actual, + exp, actual); + return false; + } else { + log_debug("Assert successful [%s:%d]: %s == %s of expected %s and actual %s", file, line_num, val_exp, + val_actual, exp, actual); + return true; + } +} + +bool util_test_assert_data(const void* data_exp, const void* data_actual, size_t len, const char* exp, + const char* actual, const char* file, size_t line_num) +{ + bool ret; + char* data_exp_str = util_str_buffer(data_exp, len); + char* data_actual_str = util_str_buffer(data_actual, len); + + if (memcmp(data_exp, data_actual, len) != 0) { + log_error("Assert failed [%s:%d]: %s != %s of expected %s and actual %s", file, line_num, data_exp_str, + data_actual_str, exp, actual); + + uint32_t cnt = 0; + + for (size_t i = 0; i < len; i++) { + /* print the first 5 diffs, only */ + if (((const uint8_t*) data_exp)[i] != ((const uint8_t*) data_actual)[i]) { + if (cnt < 5) { + log_error("pos %d: %x != %x", i, ((const uint8_t*) data_exp)[i], ((const uint8_t*) data_actual)[i]); + } + + cnt++; + } + } + + if (cnt > 5) { + log_error("...and more different bytes, total diffs %d", cnt); + } + + ret = false; + } else { + log_debug("Assert successful [%s:%d]: %s == %s of expected %s and actual %s", file, line_num, data_exp_str, + data_actual_str, exp, actual); + ret = true; + } + + free(data_exp_str); + free(data_actual_str); + + return ret; +} \ No newline at end of file diff --git a/src/main/util/test.h b/src/main/util/test.h new file mode 100644 index 0000000..c41eabe --- /dev/null +++ b/src/main/util/test.h @@ -0,0 +1,81 @@ +#ifndef UTIL_TEST_H +#define UTIL_TEST_H + +#include +#include + +#include "defs.h" +#include "log.h" + +#define UTIL_TEST_MAIN_START \ + int main() \ + { \ + log_info("Unit test %s", FILENAME); \ + util_test_init(); \ + +#define UTIL_TEST_MAIN_END \ + util_test_exec(); \ + util_test_shutdown(); \ + return 0; \ + } \ + +#define UTIL_TEST_FUNC_START(name) \ + bool name() \ +{ \ + +#define UTIL_TEST_FUNC_END \ + return true; \ +} \ + +#define UTIL_TEST_ADD(func) util_test_add(STRINGIFY(func), func); + +#define UTIL_TEST_ASSERT(exp) \ + do { \ + if (!util_test_assert_exp(exp, STRINGIFY(exp), FILENAME, __LINE__)) { \ + return false; \ + } \ + } while (0); \ + +#define UTIL_TEST_ASSERT_UINT(exp, actual) \ + do { \ + if (!util_test_assert_uint(exp, actual, STRINGIFY(exp), STRINGIFY(actual), FILENAME, __LINE__)) { \ + return false; \ + } \ + } while (0); \ + +#define UTIL_TEST_ASSERT_STR(exp, actual) \ + do { \ + if (!util_test_assert_str(exp, actual, STRINGIFY(exp), STRINGIFY(actual), FILENAME, __LINE__)) { \ + return false; \ + } \ + } while (0); \ + +#define UTIL_TEST_ASSERT_DATA(exp, actual, len) \ + do { \ + if (!util_test_assert_data(exp, actual, len, STRINGIFY(exp), STRINGIFY(actual), FILENAME, __LINE__)) { \ + return false; \ + } \ + } while (0); \ + +typedef bool (*util_test_func_t)(); + +void util_test_init(); + +void util_test_add(const char* name, util_test_func_t func); + +void util_test_exec(); + +void util_test_shutdown(); + +bool util_test_assert_exp(bool exp, const char* exp_str, const char* file, size_t line_num); + +bool util_test_assert_uint(size_t val_exp, size_t val_actual, const char* exp, const char* actual, const char* file, + size_t line_num); + +bool util_test_assert_str(const char* val_exp, const char* val_actual, const char* exp, const char* actual, + const char* file, size_t line_num); + +bool util_test_assert_data(const void* data_exp, const void* data_actual, size_t len, const char* exp, + const char* actual, const char* file, size_t line_num); + +#endif diff --git a/src/main/util/time.c b/src/main/util/time.c new file mode 100644 index 0000000..acee0f5 --- /dev/null +++ b/src/main/util/time.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include "util/time.h" + +#define SEC_PER_DAY 86400 +#define SEC_PER_HOUR 3600 +#define SEC_PER_MIN 60 + +void util_time_sleep_ns(uint64_t time_ns) +{ + struct timespec t; + t.tv_sec = (__time_t) (time_ns / (1000 * 1000 * 1000)); + t.tv_nsec = (__syscall_slong_t) time_ns % (1000 * 1000 * 1000); + + nanosleep(&t, NULL); +} + +void util_time_sleep_us(uint64_t time_us) +{ + struct timespec t; + t.tv_sec = (__time_t) (time_us / (1000 * 1000)); + t.tv_nsec = (__syscall_slong_t) (time_us % (1000 * 1000)) * 1000; + + nanosleep(&t, NULL); +} + +void util_time_sleep_ms(uint64_t time_ms) +{ + struct timespec t; + t.tv_sec = (__time_t) (time_ms / 1000); + t.tv_nsec = (__syscall_slong_t) (time_ms % 1000) * 1000 * 1000; + + nanosleep(&t, NULL); +} + +void util_time_sleep_sec(uint64_t time_sec) +{ + struct timespec t; + t.tv_sec = (__time_t) time_sec; + t.tv_nsec = 0; + + nanosleep(&t, NULL); +} + +void util_time_get_current_time(struct util_time_timestamp* timestamp) +{ + if (!timestamp) { + return; + } + + time_t t = time(NULL); + struct tm* tm = localtime(&t); + + struct timeval tv; + gettimeofday(&tv, NULL); + + timestamp->millisec = tv.tv_usec / 1000; + timestamp->sec = tm->tm_sec; + timestamp->min = tm->tm_min; + timestamp->hour = tm->tm_hour; + timestamp->day = tm->tm_mday; + // Months since January [0, 11] + timestamp->month = tm->tm_mon + 1; + // Years since 1900 + timestamp->year = tm->tm_year + 1900; +} \ No newline at end of file diff --git a/src/main/util/time.h b/src/main/util/time.h new file mode 100644 index 0000000..80f106b --- /dev/null +++ b/src/main/util/time.h @@ -0,0 +1,26 @@ +#ifndef UTIL_TIME_H +#define UTIL_TIME_H + +#include + +struct util_time_timestamp { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint8_t sec; + uint16_t millisec; +}; + +void util_time_sleep_ns(uint64_t time_ns); + +void util_time_sleep_us(uint64_t time_us); + +void util_time_sleep_ms(uint64_t time_ms); + +void util_time_sleep_sec(uint64_t time_sec); + +void util_time_get_current_time(struct util_time_timestamp* timestamp); + +#endif //UTIL_TIME_H diff --git a/src/test/capnhook/hook/lib/main.c b/src/test/capnhook/hook/lib/main.c new file mode 100644 index 0000000..f13cf59 --- /dev/null +++ b/src/test/capnhook/hook/lib/main.c @@ -0,0 +1,73 @@ +#include + +#include "capnhook/hook/lib.h" + +#include "util/mem.h" + +typedef int (*test_mock_function_t)(int a); + +static int test_mock_function(int a) +{ + return a * 2; +} + +static void test_cnh_lib_mock_init_unit_test(void** state) +{ + struct cnh_lib_unit_test_func_mocks* mocks; + size_t mocks_cnt; + void* ptr; + + mocks_cnt = 1; + mocks = cnh_lib_allocate_func_mocks(mocks_cnt); + + mocks[0].name = "test_mock_function"; + mocks[0].func = test_mock_function; + + cnh_lib_init_unit_test(mocks, mocks_cnt); + + ptr = cnh_lib_load("asdf"); + assert_ptr_not_equal(ptr, NULL); + + ptr = cnh_lib_get_func_addr_handle(ptr, "test_mock_function"); + assert_ptr_equal(ptr, test_mock_function); + + assert_int_equal(((test_mock_function_t) ptr)(2), 4); + + ptr = cnh_lib_get_func_addr_handle(ptr, "asdf"); + assert_ptr_equal(ptr, NULL); + + cnh_lib_unload(ptr); + // Nothing happens here + + ptr = cnh_lib_get_func_addr( "test_mock_function"); + assert_ptr_equal(ptr, test_mock_function); + + cnh_lib_shutdown_unit_test(); +} + +static void test_cnh_lib_real(void** state) +{ + void* ptr; + + cnh_lib_init(); + + ptr = cnh_lib_load("libc.so.6"); + + assert_ptr_not_equal(ptr, NULL); + assert_ptr_equal(cnh_lib_load("asdfasdas"), NULL); + + assert_ptr_not_equal(cnh_lib_get_func_addr_handle(ptr, "printf"), NULL); + assert_ptr_not_equal(cnh_lib_get_func_addr("printf"), NULL); + + assert_ptr_equal(cnh_lib_get_func_addr("asdasdas"), NULL); +} + +int main(int argc, char* argv[]) +{ + const struct CMUnitTest tests[] ={ + cmocka_unit_test(test_cnh_lib_mock_init_unit_test), + cmocka_unit_test(test_cnh_lib_real) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/src/test/hook/propatch/usb-fix/main.c b/src/test/hook/propatch/usb-fix/main.c new file mode 100644 index 0000000..01de203 --- /dev/null +++ b/src/test/hook/propatch/usb-fix/main.c @@ -0,0 +1,145 @@ +#include + +#include + +#include "capnhook/hook/lib.h" + +#include "hook/propatch/usb-fix.h" + +#include "test-util/mem.h" + +#include "util/log.h" +#include "util/mem.h" + +static const char* readlink_return_value = "../devices/pci0000:00/0000:00:14.0/usb2/2-2/2-2:1.0/host7/target7:0:0/7:0:0:0/block/sde"; +static const char* player1_match_buf = "../devices/pci0000:00/0000:00:14.0/usb2/1-1/1-1:1.0"; +static const char* player2_match_buf = "../devices/pci0000:00/0000:00:14.0/usb2/1-2/1-2:1.0"; + +extern ssize_t propatch_usb_fix_readlink(const char* path, char* buf, size_t len); + +static uint32_t readlink_call_count = 0; + +ssize_t readlink_mock(const char* path, char* buf, size_t len) +{ + ssize_t len_return; + + readlink_call_count++; + + len_return = strlen(readlink_return_value); + + assert_true(len >= len_return); + + strcpy(buf, readlink_return_value); + + return len_return; +} + +static int setup(void** state) +{ + struct cnh_lib_unit_test_func_mocks* func_mocks; + size_t func_mocks_cnt; + + test_util_mem_install_mem_interface(); + + func_mocks_cnt = 1; + func_mocks = cnh_lib_allocate_func_mocks(func_mocks_cnt); + + func_mocks[0].name = "readlink"; + func_mocks[0].func = readlink_mock; + + cnh_lib_init_unit_test(func_mocks, func_mocks_cnt); + + readlink_call_count = 0; + + return 0; +} + +static int teardown(void** state) +{ + propatch_usb_fix_shutdown(); + + cnh_lib_shutdown_unit_test(); + + return 0; +} + +static void test_usb_fix_disabled(void** state) +{ + ssize_t res; + char buffer[256]; + + res = propatch_usb_fix_readlink( + "/sys/block/sde/device", + buffer, + sizeof(buffer)); + + assert_int_equal(res, strlen(readlink_return_value)); + assert_string_equal(buffer, readlink_return_value); + + assert_int_equal(readlink_call_count, 1); +} + +static void test_no_match_usb_fix(void** state) +{ + ssize_t res; + char buffer[256]; + + propatch_usb_fix_init("sdd,sdf", "2-1", "2-2"); + + res = propatch_usb_fix_readlink( + "/sys/block/sde/device", + buffer, + sizeof(buffer)); + + assert_int_equal(res, strlen(readlink_return_value)); + + assert_int_equal(readlink_call_count, 1); +} + +static void test_match_player1_usb_fix(void** state) +{ + ssize_t res; + char buffer[256]; + + propatch_usb_fix_init("sde,sdf", "2-1", "2-2"); + + res = propatch_usb_fix_readlink( + "/sys/block/sde/device", + buffer, + sizeof(buffer)); + + assert_int_equal(res, strlen(player1_match_buf)); + assert_string_equal(buffer, player1_match_buf); + + assert_int_equal(readlink_call_count, 1); +} + +static void test_match_player2_usb_fix(void** state) +{ + ssize_t res; + char buffer[256]; + + propatch_usb_fix_init("sde,sdf", "2-2", "2-1"); + + res = propatch_usb_fix_readlink( + "/sys/block/sde/device", + buffer, + sizeof(buffer)); + + assert_int_equal(res, strlen(player2_match_buf)); + assert_string_equal(buffer, player2_match_buf); + + assert_int_equal(readlink_call_count, 1); +} + +int main(int argc, char* argv[]) +{ + const struct CMUnitTest tests[] ={ + cmocka_unit_test_setup_teardown(test_usb_fix_disabled, setup, teardown), + cmocka_unit_test_setup_teardown(test_no_match_usb_fix, setup, teardown), + cmocka_unit_test_setup_teardown(test_match_player1_usb_fix, setup, teardown), + cmocka_unit_test_setup_teardown(test_match_player2_usb_fix, setup, teardown) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/src/test/test-util/mem.c b/src/test/test-util/mem.c new file mode 100644 index 0000000..3a96046 --- /dev/null +++ b/src/test/test-util/mem.c @@ -0,0 +1,52 @@ +#define LOG_MODULE "test-util-mem" + +#include + +#include "test-util/mem.h" + +#include "util/log.h" +#include "util/mem.h" + +static void* _test_util_mem_xmalloc(size_t nbytes) +{ + void* ptr; + + ptr = test_malloc(nbytes); + + log_debug("malloc(%d): %p", nbytes, ptr); + + return ptr; +} + +static void* _test_util_mem_xrealloc(void* mem, size_t nbytes) +{ + void* ptr; + + ptr = test_realloc(mem, nbytes); + + log_debug("realloc(%p %d): %p", mem, nbytes, ptr); + + return ptr; +} + +static void _test_util_mem_xfree(void** mem) +{ + if (*mem != NULL) { + log_debug("free(%p %p)", mem, *mem); + test_free(*mem); + *mem = NULL; + } else { + log_warn("free(%p NULL)", mem); + } +} + +static const struct util_mem_interface _test_util_mem_interface_test = { + .xmalloc = _test_util_mem_xmalloc, + .xrealloc = _test_util_mem_xrealloc, + .xfree = _test_util_mem_xfree, +}; + +void test_util_mem_install_mem_interface() +{ + util_mem_init(&_test_util_mem_interface_test); +} \ No newline at end of file diff --git a/src/test/test-util/mem.h b/src/test/test-util/mem.h new file mode 100644 index 0000000..8e5d797 --- /dev/null +++ b/src/test/test-util/mem.h @@ -0,0 +1,6 @@ +#pragma once + +/** + * Install the memory test interface which is backed by cmocka for leak and error detection on unit tests. + */ +void test_util_mem_install_mem_interface(); \ No newline at end of file diff --git a/src/test/util/mem/main.c b/src/test/util/mem/main.c new file mode 100644 index 0000000..4f8551e --- /dev/null +++ b/src/test/util/mem/main.c @@ -0,0 +1,50 @@ +#include + +#include "test-util/mem.h" + +#include "util/mem.h" + +static void test_util_mem_mock_interface(void** state) +{ + void* ptr; + + test_util_mem_install_mem_interface(); + + ptr = util_xmalloc(100); + assert_ptr_not_equal(ptr, NULL); + + ptr = util_xrealloc(ptr, 200); + assert_ptr_not_equal(ptr, NULL); + + util_xfree(&ptr); + assert_ptr_equal(ptr, NULL); +} + +static void test_util_mem_real(void** state) +{ + void* ptr; + + util_mem_init_default(); + + ptr = util_xmalloc(100); + assert_ptr_not_equal(ptr, NULL); + + ptr = util_xrealloc(ptr, 200); + assert_ptr_not_equal(ptr, NULL); + + util_xfree(&ptr); + assert_ptr_equal(ptr, NULL); + + // Should not crash + util_xfree(&ptr); +} + +int main(int argc, char* argv[]) +{ + const struct CMUnitTest tests[] ={ + cmocka_unit_test(test_util_mem_mock_interface), + cmocka_unit_test(test_util_mem_real) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/src/test/util/str/main.c b/src/test/util/str/main.c new file mode 100644 index 0000000..743bcdd --- /dev/null +++ b/src/test/util/str/main.c @@ -0,0 +1,101 @@ +#include + +#include "test-util/mem.h" + +#include "util/mem.h" +#include "util/str.h" + +static int setup(void** state) +{ + test_util_mem_install_mem_interface(); + + return 0; +} + +static void test_str_dup(void** state) +{ + char* str; + + str = util_str_dup("aasdf"); + assert_string_equal(str, "aasdf"); + + util_xfree((void**) &str); +} + +static void test_str_dup_empty(void** state) +{ + char* str; + + str = util_str_dup(""); + assert_string_equal(str, ""); + + util_xfree((void**) &str); +} + +static void test_str_split0(void** state) +{ + size_t count; + char** toks; + + toks = util_str_split("", ",", &count); + + assert_int_equal(count, 0); + + util_str_free_split(toks, count); +} + +static void test_str_split1(void** state) +{ + size_t count; + char** toks; + + toks = util_str_split("asd", ",", &count); + + assert_int_equal(count, 1); + assert_string_equal(toks[0], "asd"); + + util_str_free_split(toks, count); +} + +static void test_str_split2(void** state) +{ + size_t count; + char** toks; + + toks = util_str_split("asd,123", ",", &count); + + assert_int_equal(count, 2); + assert_string_equal(toks[0], "asd"); + assert_string_equal(toks[1], "123"); + + util_str_free_split(toks, count); +} + +static void test_str_split3(void** state) +{ + size_t count; + char** toks; + + toks = util_str_split("/asd/123/ddd/", "/", &count); + + assert_int_equal(count, 3); + assert_string_equal(toks[0], "asd"); + assert_string_equal(toks[1], "123"); + assert_string_equal(toks[2], "ddd"); + + util_str_free_split(toks, count); +} + +int main(int argc, char* argv[]) +{ + const struct CMUnitTest tests[] ={ + cmocka_unit_test_setup(test_str_dup, setup), + cmocka_unit_test_setup(test_str_dup_empty, setup), + cmocka_unit_test_setup(test_str_split0, setup), + cmocka_unit_test_setup(test_str_split1, setup), + cmocka_unit_test_setup(test_str_split2, setup), + cmocka_unit_test_setup(test_str_split3, setup) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/utils/files-lowercase.sh b/utils/files-lowercase.sh new file mode 100755 index 0000000..1d2986b --- /dev/null +++ b/utils/files-lowercase.sh @@ -0,0 +1,15 @@ +#!/bin/env bash + +if [ ! "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +for SRC in `find $1 -depth` +do + DST=`dirname "${SRC}"`/`basename "${SRC}" | tr '[A-Z]' '[a-z]'` + if [ "${SRC}" != "${DST}" ] + then + [ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed" + fi +done diff --git a/utils/grab_deps.sh b/utils/grab_deps.sh new file mode 100755 index 0000000..2b890a0 --- /dev/null +++ b/utils/grab_deps.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Author : Hemanth.HM +# Email : hemanth[dot]hm[at]gmail[dot]com +# License : GNU GPLv3 +# + +function useage() +{ + cat << EOU +Useage: bash $0 +EOU +exit 1 +} + +#Validate the inputs +[[ $# < 2 ]] && useage + +#Check if the paths are vaild +[[ ! -e $1 ]] && echo "Not a vaild input $1" && exit 1 +[[ -d $2 ]] || echo "No such directory $2 creating..."&& mkdir -p "$2" + +#Get the library dependencies +echo "Collecting the shared library dependencies for $1..." +deps=$(ldd $1 | awk 'BEGIN{ORS=" "}$1~/^\//{print $1}$3~/^\//{print $3}' | sed 's/,$/\n/') +echo "Copying the dependencies to $2" + +#Copy the deps +for dep in $deps +do + echo "Copying $dep to $2" + cp "$dep" "$2" +done + +echo "Done!" +