├── src ├── .clang-format ├── .editorconfig ├── asm │ ├── asbin.bat │ └── m4a-gsf.s ├── saptapper │ ├── byte_pattern.cpp │ ├── cartridge.hpp │ ├── types.hpp │ ├── arm.hpp │ ├── cartridge.cpp │ ├── gsf_writer.hpp │ ├── minigsf_driver_param.hpp │ ├── byte_pattern.hpp │ ├── gsf_header.hpp │ ├── psf_writer.hpp │ ├── tabulate.hpp │ ├── saptapper.hpp │ ├── algorithm.hpp │ ├── gsf_writer.cpp │ ├── mp2k_driver_param.hpp │ ├── psf_writer.cpp │ ├── mp2k_driver.hpp │ ├── bytes.hpp │ ├── saptapper.cpp │ └── mp2k_driver.cpp ├── main.cpp └── 3rdparty │ └── include │ ├── strict_fstream.hpp │ └── zstr.hpp ├── dependencies └── zlib │ ├── lib │ ├── win32 │ │ └── zlibstat.lib │ └── x64 │ │ └── zlibstat.lib │ └── include │ ├── zutil.h │ ├── ioapi.h │ ├── zconf.h │ └── unzip.h ├── .travis.yml ├── appveyor.yml ├── README.md ├── CMakeLists.txt └── LICENSE.txt /src/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | -------------------------------------------------------------------------------- /dependencies/zlib/lib/win32/zlibstat.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveemu/saptapper/HEAD/dependencies/zlib/lib/win32/zlibstat.lib -------------------------------------------------------------------------------- /dependencies/zlib/lib/x64/zlibstat.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveemu/saptapper/HEAD/dependencies/zlib/lib/x64/zlibstat.lib -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{c,cpp,h,hpp}] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /src/asm/asbin.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @setlocal 3 | @rem devkitadv required 4 | 5 | @if "%1"=="" ( 6 | echo No input files>&2 7 | exit /b 1 8 | ) 9 | 10 | set PREFIX=arm-none-eabi- 11 | 12 | %PREFIX%gcc -c -o "%~n1.o" "%1" 13 | if errorlevel 1 exit /b 14 | %PREFIX%objcopy -O binary "%~n1.o" "%~n1.bin" 15 | if errorlevel 1 exit /b 16 | 17 | exit /b 0 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: cpp 4 | 5 | matrix: 6 | include: 7 | - os: linux 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - g++-9 14 | env: 15 | - COMPILER="g++-9" 16 | 17 | script: 18 | - CXX=${COMPILER} cmake -H. -Bbuild 19 | - CXX=${COMPILER} cmake --build build 20 | -------------------------------------------------------------------------------- /src/saptapper/byte_pattern.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include "byte_pattern.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace saptapper { 9 | 10 | bool BytePattern::Match(std::string_view data, size_type pos) const { 11 | if (data.size() < pos + size()) return false; 12 | 13 | for (size_type offset = 0; offset < size(); offset++) { 14 | if (!mask_.empty() && mask_[offset] == '?') continue; 15 | if (data[pos + offset] != data_[offset]) return false; 16 | } 17 | return true; 18 | } 19 | 20 | BytePattern::size_type BytePattern::Find(std::string_view data, 21 | size_type pos) const { 22 | for (size_type offset = pos; offset <= data.size() - size(); offset++) { 23 | if (Match(data, offset)) return offset; 24 | } 25 | return std::string::npos; 26 | } 27 | 28 | } // namespace saptapper 29 | -------------------------------------------------------------------------------- /src/saptapper/cartridge.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef CARTRIDGE_HPP_ 4 | #define CARTRIDGE_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "types.hpp" 10 | 11 | namespace saptapper { 12 | 13 | class Cartridge { 14 | public: 15 | using size_type = agbsize_t; 16 | 17 | static constexpr agbsize_t kHeaderSize = 0x100; 18 | static constexpr agbsize_t kMaximumSize = 0x2000000; 19 | 20 | Cartridge() = default; 21 | 22 | std::string& rom() { return rom_; } 23 | const std::string& rom() const { return rom_; } 24 | size_type size() const { return static_cast(rom_.size()); } 25 | std::string game_title() const { return rom_.substr(0xa0, 12); } 26 | std::string game_code() const { return rom_.substr(0xac, 4); } 27 | 28 | static Cartridge LoadFromFile(const std::filesystem::path& path); 29 | 30 | private: 31 | std::string rom_; 32 | 33 | static void ValidateSize(std::uintmax_t size); 34 | }; 35 | 36 | } // namespace saptapper 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 2.1.{build} 2 | 3 | image: Visual Studio 2017 4 | 5 | environment: 6 | matrix: 7 | - generator: "Visual Studio 15" 8 | config: Release 9 | arch: vs2017-x86 10 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 11 | 12 | - generator: "Visual Studio 15 Win64" 13 | config: Release 14 | arch: vs2017-x64 15 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 16 | 17 | init: 18 | - git config --global core.autocrlf input 19 | 20 | build_script: 21 | - cmake -G"%generator%" -H. -Bbuild 22 | #- cmake --build build --config "%config%" 23 | - msbuild build\saptapper.sln /t:build /p:Configuration="%config%" /m /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" 24 | 25 | after_build: 26 | - ps: $env:gitrev = git describe --tags 27 | - ps: $env:my_version = "$env:gitrev" 28 | - set package_name=saptapper-%my_version%-%arch% 29 | - copy "build\%config%\saptapper.exe" . 30 | - 7z a %package_name%.zip saptapper.exe README.md LICENSE.txt 31 | 32 | artifacts: 33 | - path: $(package_name).zip 34 | name: $(arch) 35 | -------------------------------------------------------------------------------- /src/saptapper/types.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_TYPES_HPP_ 4 | #define SAPTAPPER_TYPES_HPP_ 5 | 6 | #include 7 | #include 8 | 9 | namespace saptapper { 10 | 11 | using agbptr_t = std::uint32_t; 12 | 13 | using agbsize_t = std::uint32_t; 14 | 15 | static constexpr auto agbnullptr{static_cast(-1)}; 16 | 17 | static constexpr auto agbnpos{static_cast(-1)}; 18 | 19 | static constexpr bool is_romptr(agbptr_t addr) { 20 | return addr >= 0x8000000 && addr <= 0x9ffffff; 21 | } 22 | 23 | static constexpr agbsize_t to_offset(agbptr_t addr) { return addr & 0x1ffffff; } 24 | 25 | static constexpr agbptr_t to_romptr(agbsize_t offset) { 26 | return 0x8000000 | (offset & 0x1ffffff); 27 | } 28 | 29 | static std::string to_string(agbptr_t addr) { 30 | if (addr == agbnullptr) { 31 | return "null"; 32 | } else { 33 | std::stringstream sstream; 34 | sstream << std::showbase << std::hex << addr; 35 | return sstream.str(); 36 | } 37 | } 38 | 39 | } // namespace saptapper 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/saptapper/arm.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_ARM_HPP_ 4 | #define SAPTAPPER_ARM_HPP_ 5 | 6 | #include 7 | #include 8 | #include "types.hpp" 9 | 10 | namespace saptapper { 11 | 12 | using armins_t = std::uint32_t; 13 | 14 | using thumbins_t = std::uint16_t; 15 | 16 | static constexpr bool is_arm_b(const armins_t ins) { 17 | return (ins & 0xff000000) == 0xea000000; 18 | } 19 | 20 | static constexpr armins_t make_arm_b(const agbptr_t current, 21 | const agbptr_t dest) { 22 | assert(current % 4 == 0 && dest % 4 == 0); 23 | const agbsize_t offset = dest - (current + 8); 24 | return 0xea000000 | ((offset / 4) & 0xffffff); 25 | } 26 | 27 | static constexpr agbptr_t arm_b_dest(const agbptr_t current, 28 | const armins_t ins) { 29 | agbsize_t offset = ins & 0xffffff; 30 | if ((offset & 0x800000) != 0) { 31 | offset |= ~0xffffff; 32 | } 33 | offset *= 4; 34 | 35 | return current + 8 + offset; 36 | } 37 | 38 | } // namespace saptapper 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/saptapper/cartridge.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include "cartridge.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace saptapper { 12 | 13 | Cartridge Cartridge::LoadFromFile(const std::filesystem::path& path) { 14 | Cartridge cartridge; 15 | 16 | const auto size = file_size(path); 17 | ValidateSize(size); 18 | 19 | std::ifstream stream(path, std::ios::in | std::ios::binary); 20 | stream.exceptions(std::ios::badbit | std::ios::eofbit | std::ios::failbit); 21 | 22 | const auto aligned_size = (size + 3) & ~3; 23 | std::string rom(aligned_size, 0); 24 | stream.read(rom.data(), size); 25 | stream.close(); 26 | 27 | cartridge.rom_ = std::move(rom); 28 | return cartridge; 29 | } 30 | 31 | void Cartridge::ValidateSize(std::uintmax_t size) { 32 | if (size < kHeaderSize) { 33 | throw std::range_error("The input data too small."); 34 | } else if (size > kMaximumSize) { 35 | throw std::range_error("The input data too large."); 36 | } 37 | } 38 | 39 | } // namespace saptapper 40 | -------------------------------------------------------------------------------- /src/saptapper/gsf_writer.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_GSF_WRITER_HPP_ 4 | #define SAPTAPPER_GSF_WRITER_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "gsf_header.hpp" 12 | #include "minigsf_driver_param.hpp" 13 | 14 | namespace saptapper { 15 | 16 | class GsfWriter { 17 | public: 18 | static void SaveToFile(const std::filesystem::path& path, 19 | const GsfHeader& header, std::string_view rom, 20 | const std::map& tags = {}); 21 | 22 | static void SaveToStream(std::ostream& out, const GsfHeader& header, 23 | std::string_view rom, 24 | const std::map& tags = {}); 25 | 26 | static void SaveMinigsfToFile( 27 | const std::filesystem::path& path, const MinigsfDriverParam& param, 28 | std::uint32_t song, const std::map& tags = {}); 29 | 30 | static void SaveMinigsfToStream( 31 | std::ostream& out, const MinigsfDriverParam& param, std::uint32_t song, 32 | const std::map& tags = {}); 33 | 34 | private: 35 | static constexpr std::uint8_t kVersion = 0x22; 36 | }; 37 | 38 | } // namespace saptapper 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/saptapper/minigsf_driver_param.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_MINIGSF_DRIVER_PARAM_HPP_ 4 | #define SAPTAPPER_MINIGSF_DRIVER_PARAM_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "tabulate.hpp" 10 | #include "types.hpp" 11 | 12 | namespace saptapper { 13 | 14 | class MinigsfDriverParam { 15 | public: 16 | MinigsfDriverParam() = default; 17 | 18 | bool ok() const noexcept { 19 | return address_ != agbnullptr && size_ != 0; 20 | } 21 | 22 | agbptr_t address() const noexcept { return address_; } 23 | 24 | agbptr_t size() const noexcept { return size_; } 25 | 26 | void set_address(agbptr_t address) noexcept { 27 | address_ = address; 28 | } 29 | 30 | void set_size(agbptr_t size) noexcept { size_ = size; } 31 | 32 | std::ostream& WriteAsTable(std::ostream& stream) const { 33 | using row_t = std::array; 34 | const row_t header{"Name", "Address / Value"}; 35 | std::array items{ 36 | row_t{"minigsf address", to_string(this->address())}, 37 | row_t{"minigsf size", std::to_string(this->size())}, 38 | }; 39 | 40 | tabulate(stream, header, items); 41 | return stream; 42 | } 43 | 44 | private: 45 | agbptr_t address_ = agbnullptr; 46 | agbsize_t size_ = 0; 47 | }; 48 | 49 | } // namespace saptapper 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/saptapper/byte_pattern.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// Byte pattern class for flexible byte sequence search. 3 | /// 4 | /// Heavily inspired by SigScan at GameDeception.net 5 | 6 | #ifndef SAPTAPPER_BYTE_PATTERN_ 7 | #define SAPTAPPER_BYTE_PATTERN_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace saptapper { 14 | 15 | class BytePattern 16 | { 17 | public: 18 | using size_type = std::string::size_type; 19 | 20 | BytePattern(std::string_view data) : data_(data) {} 21 | 22 | BytePattern(std::string_view data, std::string_view mask) 23 | : data_(data), mask_(mask) { 24 | if (data.size() != mask.size()) { 25 | throw std::invalid_argument( 26 | "BytePattern: data and mask must be the same size"); 27 | } 28 | } 29 | 30 | size_type size() const noexcept { return data_.size(); } 31 | 32 | bool Match(std::string_view data, size_type pos = 0) const; 33 | 34 | size_type Find(std::string_view data, size_type pos = 0) const; 35 | 36 | private: 37 | /// The pattern to scan for. 38 | std::string data_; 39 | 40 | /// A mask to ignore certain bytes in the pattern such as addresses. 41 | /// 42 | /// The mask should be as long as all the bytes in the pattern. 43 | /// Use '?' to ignore a byte and 'x' to check it. 44 | /// Example: "xxx????xx" - The first 3 bytes are checked, then the next 4 are ignored, 45 | /// then the last 2 are checked 46 | std::string mask_; 47 | }; 48 | 49 | } // namespace saptapper 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/saptapper/gsf_header.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_GSF_HEADER_HPP_ 4 | #define SAPTAPPER_GSF_HEADER_HPP_ 5 | 6 | #include 7 | #include "bytes.hpp" 8 | #include "types.hpp" 9 | 10 | namespace saptapper { 11 | 12 | class GsfHeader { 13 | public: 14 | using size_type = agbsize_t; 15 | 16 | GsfHeader() : entrypoint_{0}, load_offset_{0}, load_size_{0} {}; 17 | 18 | GsfHeader(agbptr_t entrypoint, agbptr_t load_offset, agbsize_t load_size) 19 | : str_{NewHeader(entrypoint, load_offset, load_size)}, 20 | entrypoint_{entrypoint}, 21 | load_offset_{load_offset}, 22 | load_size_{load_size} {} 23 | 24 | const char* data() const noexcept { return str_.data(); } 25 | constexpr size_type size() const noexcept { return kSize; } 26 | agbptr_t entrypoint() const noexcept { return entrypoint_; } 27 | agbptr_t load_offset() const noexcept { return load_offset_; } 28 | agbptr_t load_size() const noexcept { return load_size_; } 29 | 30 | private: 31 | static constexpr size_type kSize = 12; 32 | 33 | std::string str_; 34 | agbptr_t entrypoint_; 35 | agbptr_t load_offset_; 36 | agbsize_t load_size_; 37 | 38 | static std::string NewHeader(agbptr_t entrypoint, agbptr_t load_offset, 39 | agbsize_t load_size) { 40 | std::string header(kSize, 0); 41 | WriteInt32L(&header[0], entrypoint); 42 | WriteInt32L(&header[4], load_offset); 43 | WriteInt32L(&header[8], load_size); 44 | return header; 45 | } 46 | }; 47 | 48 | } // namespace saptapper 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/saptapper/psf_writer.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_PSF_WRITER_HPP_ 4 | #define SAPTAPPER_PSF_WRITER_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "zstr.hpp" 13 | 14 | namespace saptapper { 15 | 16 | class PsfWriter { 17 | public: 18 | PsfWriter(uint8_t version, std::map tags = {}); 19 | 20 | uint8_t version() const noexcept { return version_; } 21 | std::ostream& exe() noexcept { return exe_; } 22 | std::ostream& reserved() noexcept { return reserved_; } 23 | std::map& tags() noexcept { return tags_; } 24 | 25 | void SaveToFile(const std::filesystem::path& path) { 26 | SaveToFile(path, tags_); 27 | } 28 | 29 | void SaveToFile(const std::filesystem::path& path, 30 | const std::map& tags); 31 | 32 | void SaveToStream(std::ostream& out) { SaveToStream(out, tags_); } 33 | 34 | void SaveToStream(std::ostream& out, 35 | const std::map& tags); 36 | 37 | private: 38 | uint8_t version_; 39 | std::ostringstream reserved_; 40 | std::ostringstream compressed_exe_; 41 | zstr::ostream exe_; 42 | std::map tags_; 43 | 44 | std::string NewHeader(std::string_view compressed_exe, 45 | std::string_view reserved, 46 | std::uint32_t compressed_exe_crc32) const; 47 | }; 48 | 49 | } // namespace saptapper 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/saptapper/tabulate.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_TABULATE_HPP_ 4 | #define SAPTAPPER_TABULATE_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace saptapper { 11 | 12 | template 13 | static std::ostream& tabulate( 14 | std::ostream& stream, std::array<_Ty, _NumOfColumns> header, 15 | std::array, _NumOfRows> items) { 16 | // Determine column lengths. 17 | // 18 | // Note that it doesn't calculate proper lengths for non-ASCII characters. 19 | std::array maxlength; 20 | for (size_t i = 0; i < header.size(); i++) { 21 | maxlength[i] = header[i].size(); 22 | } 23 | for (const auto& item : items) { 24 | for (size_t i = 0; i < item.size(); i++) { 25 | if (maxlength[i] < item[i].size()) maxlength[i] = item[i].size(); 26 | } 27 | } 28 | 29 | // Header 30 | stream << std::setfill(' '); 31 | for (size_t i = 0; i < header.size(); i++) { 32 | stream << "|" << std::setw(maxlength[i]) << std::left << header[i] << " "; 33 | } 34 | stream << "|" << std::endl; 35 | 36 | // Separator 37 | stream << std::setfill('-'); 38 | for (size_t i = 0; i < header.size(); i++) { 39 | stream << "|" << std::setw(maxlength[i] + 1) << ""; 40 | } 41 | stream << "|" << std::endl; 42 | stream << std::setfill(' '); 43 | 44 | // Columns 45 | for (const auto& item : items) { 46 | for (size_t i = 0; i < item.size(); i++) { 47 | stream << "|" << std::setw(maxlength[i]) << std::left << item[i] << " "; 48 | } 49 | stream << "|" << std::endl; 50 | } 51 | 52 | return stream; 53 | } 54 | 55 | } // namespace saptapper 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/saptapper/saptapper.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_SAPTAPPER_HPP_ 4 | #define SAPTAPPER_SAPTAPPER_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "cartridge.hpp" 11 | #include "minigsf_driver_param.hpp" 12 | #include "mp2k_driver_param.hpp" 13 | #include "types.hpp" 14 | 15 | namespace saptapper { 16 | 17 | class Saptapper { 18 | public: 19 | static void ConvertToGsfSet(Cartridge& cartridge, 20 | const std::filesystem::path& basename, 21 | const std::filesystem::path& outdir = "", 22 | const std::string_view& gsfby = "", 23 | bool keep_duplicated = false); 24 | 25 | static void SaveMinigsfFile( 26 | const std::filesystem::path& base_path, const MinigsfDriverParam& minigsf, 27 | int song, const std::map& tags = {}); 28 | 29 | static void Inspect(const Cartridge& cartridge, Mp2kDriverParam& param, 30 | MinigsfDriverParam& minigsf, agbptr_t& gsf_driver_addr, 31 | bool throw_if_missing = false); 32 | 33 | static void PrintParam(const Mp2kDriverParam& param, 34 | const MinigsfDriverParam& minigsf); 35 | 36 | private: 37 | static agbptr_t FindFreeSpace(std::string_view rom, agbsize_t size); 38 | static agbptr_t FindFreeSpace(std::string_view rom, agbsize_t size, 39 | char filler, bool largest); 40 | 41 | static constexpr agbsize_t GetMinigsfSize(int song_count) { 42 | if (song_count <= 0) return 0; 43 | 44 | agbsize_t size = 1; 45 | int remaining = song_count >> 8; 46 | while (size < 4 && remaining != 0) { 47 | size++; 48 | remaining >>= 8; 49 | }; 50 | return size; 51 | } 52 | }; 53 | 54 | } // namespace saptapper 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/saptapper/algorithm.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_ALGORITHM_HPP_ 4 | #define SAPTAPPER_ALGORITHM_HPP_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "types.hpp" 11 | 12 | namespace saptapper { 13 | 14 | static bool memcmp_loose(const char* buf1, const char* buf2, size_t n, 15 | unsigned int max_diff) { 16 | unsigned int diff = 0; 17 | for (size_t pos = 0; pos < n; pos++) { 18 | if (buf1[pos] != buf2[pos]) { 19 | if (++diff >= max_diff) return false; 20 | } 21 | } 22 | return true; 23 | } 24 | 25 | static agbptr_t find_loose(std::string_view rom, std::string_view pattern, 26 | unsigned int max_diff, agbsize_t pos = 0) { 27 | if (rom.size() < pattern.size()) return agbnullptr; 28 | 29 | constexpr agbsize_t align = 4; 30 | for (agbsize_t offset = pos; offset < rom.size() - pattern.size(); 31 | offset += align) { 32 | if (memcmp_loose(&rom[offset], pattern.data(), pattern.size(), max_diff)) 33 | return to_romptr(offset); 34 | } 35 | return agbnullptr; 36 | } 37 | 38 | template 39 | static agbptr_t find_backwards(std::string_view rom, 40 | std::array patterns, 41 | agbsize_t pos, agbsize_t length) { 42 | if (pos >= rom.size()) return agbnullptr; 43 | 44 | constexpr agbsize_t align = 4; 45 | assert(length % align == 0); 46 | if (length < align || rom.size() < length) return agbnullptr; 47 | 48 | const agbsize_t max_pos = pos - align; 49 | const agbsize_t min_pos = pos - length; 50 | for (agbsize_t offset = max_pos; offset >= min_pos; offset -= align) { 51 | for (const auto& pattern : patterns) { 52 | if (std::memcmp(&rom[offset], pattern.data(), pattern.size()) == 0) 53 | return to_romptr(offset); 54 | } 55 | } 56 | return agbnullptr; 57 | } 58 | 59 | } // namespace saptapper 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/saptapper/gsf_writer.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include "gsf_writer.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "gsf_header.hpp" 10 | #include "psf_writer.hpp" 11 | #include "types.hpp" 12 | 13 | namespace saptapper { 14 | 15 | void GsfWriter::SaveToFile(const std::filesystem::path& path, 16 | const GsfHeader& header, std::string_view rom, 17 | const std::map& tags) { 18 | std::ofstream file(path, std::ios::out | std::ios::binary); 19 | file.exceptions(std::ios::badbit); 20 | SaveToStream(file, header, rom, tags); 21 | file.close(); 22 | } 23 | 24 | void GsfWriter::SaveToStream(std::ostream& out, const GsfHeader& header, 25 | std::string_view rom, 26 | const std::map& tags) { 27 | PsfWriter psf{kVersion}; 28 | auto& exe = psf.exe(); 29 | exe.write(header.data(), header.size()); 30 | exe.write(rom.data(), rom.size()); 31 | psf.SaveToStream(out, tags); 32 | } 33 | 34 | void GsfWriter::SaveMinigsfToFile( 35 | const std::filesystem::path& path, const MinigsfDriverParam& param, 36 | std::uint32_t song, const std::map& tags) { 37 | std::ofstream file(path, std::ios::out | std::ios::binary); 38 | file.exceptions(std::ios::badbit); 39 | SaveMinigsfToStream(file, param, song, tags); 40 | file.close(); 41 | } 42 | 43 | void GsfWriter::SaveMinigsfToStream( 44 | std::ostream& out, const MinigsfDriverParam& param, std::uint32_t song, 45 | const std::map& tags) { 46 | const agbptr_t entrypoint = 47 | is_romptr(param.address()) ? 0x8000000 : param.address() & 0xff000000; 48 | const GsfHeader gsf_header{entrypoint, param.address(), param.size()}; 49 | 50 | char rom_data[4]; 51 | WriteInt32L(rom_data, song); 52 | const std::string_view rom{rom_data, param.size()}; 53 | 54 | SaveToStream(out, gsf_header, rom, tags); 55 | } 56 | 57 | } // namespace saptapper 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Saptapper 2 | ========= 3 | [![Travis Build Status](https://travis-ci.com/loveemu/saptapper.svg?branch=master)](https://travis-ci.com/loveemu/saptapper) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/8gdychs5ftgijyui/branch/master?svg=true)](https://ci.appveyor.com/project/loveemu/saptapper/branch/master) 4 | 5 | Automated GSF ripper tool created by Caitsith2, reimplemented by loveemu from scratch. 6 | 7 | 8 | Caitsith2's original version can be found at GSF Central 9 | 10 | 11 | Downloads 12 | --------- 13 | 14 | - [Latest release](https://github.com/loveemu/saptapper/releases/latest) 15 | 16 | Usage 17 | ----- 18 | 19 | Syntax: `saptapper {OPTIONS} romfile` 20 | 21 | ### Options 22 | 23 | |Argument |Description | 24 | |----------------------------------------|------------------------------------------------------------| 25 | |`-h`, `--help` |Show this help message and exit | 26 | |`--inspect` |Show the inspection result without saving files and quit | 27 | |`-f`, `--force` |Save all songs including duplicated ones | 28 | |`-d[directory]`, `--outdir=[directory]` |The output directory (the default is the working directory) | 29 | |`-o[basename]` |The output filename (without extension) | 30 | |`romfile` |The ROM file to be processed | 31 | 32 | Note 33 | ---- 34 | 35 | Most of the games using the sappy driver are ripped completely and automatically with 36 | this program. The only manual step left, is sorting and optimizing the set. 37 | 38 | If saptapper was unable to rip the game properly, but did find one of the sappy driver 39 | functions identifying it as being sappy compatible, an error will be written to STDERR, 40 | identifying what function it was not able to find. 41 | 42 | Before submitting a gsf set that has been ripped, with or without saptapper, please at the 43 | minimum optimize the set first. Ideally, all sfxs/voices should be removed, all 44 | music/jingles kept. 45 | -------------------------------------------------------------------------------- /src/saptapper/mp2k_driver_param.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_MP2K_DRIVER_PARAM_HPP_ 4 | #define SAPTAPPER_MP2K_DRIVER_PARAM_HPP_ 5 | 6 | #include 7 | #include 8 | #include "tabulate.hpp" 9 | #include "types.hpp" 10 | 11 | namespace saptapper { 12 | 13 | class Mp2kDriverParam { 14 | public: 15 | Mp2kDriverParam() = default; 16 | 17 | bool ok() const noexcept { 18 | return song_count_ != 0 && init_fn_ != agbnullptr && 19 | main_fn_ != agbnullptr && vsync_fn_ != agbnullptr && 20 | select_song_fn_ != agbnullptr; 21 | } 22 | 23 | int song_count() const noexcept { return song_count_; } 24 | 25 | agbptr_t song_table() const noexcept { return song_table_; } 26 | 27 | agbptr_t init_fn() const noexcept { return init_fn_; } 28 | 29 | agbptr_t main_fn() const noexcept { return main_fn_; } 30 | 31 | agbptr_t vsync_fn() const noexcept { return vsync_fn_; } 32 | 33 | agbptr_t select_song_fn() const noexcept { return select_song_fn_; } 34 | 35 | void set_song_count(int count) noexcept { song_count_ = count; } 36 | 37 | void set_song_table(agbptr_t address) noexcept { song_table_ = address; } 38 | 39 | void set_init_fn(agbptr_t address) noexcept { init_fn_ = address; } 40 | 41 | void set_main_fn(agbptr_t address) noexcept { main_fn_ = address; } 42 | 43 | void set_vsync_fn(agbptr_t address) noexcept { vsync_fn_ = address; } 44 | 45 | void set_select_song_fn(agbptr_t address) noexcept { 46 | select_song_fn_ = address; 47 | } 48 | 49 | std::ostream& WriteAsTable(std::ostream& stream) const { 50 | using row_t = std::array; 51 | const row_t header{"Name", "Address / Value"}; 52 | std::array items{ 53 | row_t{"m4aSoundVSync", to_string(this->vsync_fn())}, 54 | row_t{"m4aSoundInit", to_string(this->init_fn())}, 55 | row_t{"m4aSoundMain", to_string(this->main_fn())}, 56 | row_t{"m4aSongNumStart", to_string(this->select_song_fn())}, 57 | row_t{"song_table", to_string(this->song_table())}, 58 | row_t{"len(song_table)", std::to_string(this->song_count())}, 59 | }; 60 | 61 | tabulate(stream, header, items); 62 | return stream; 63 | } 64 | 65 | private: 66 | int song_count_ = 0; 67 | agbptr_t song_table_ = agbnullptr; 68 | agbptr_t init_fn_ = agbnullptr; 69 | agbptr_t main_fn_ = agbnullptr; 70 | agbptr_t vsync_fn_ = agbnullptr; 71 | agbptr_t select_song_fn_ = agbnullptr; 72 | }; 73 | 74 | } // namespace saptapper 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/saptapper/psf_writer.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include "psf_writer.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include "bytes.hpp" 9 | 10 | namespace saptapper { 11 | 12 | PsfWriter::PsfWriter(uint8_t version, std::map tags) 13 | : version_{version}, 14 | exe_{compressed_exe_, zstr::default_buff_size, Z_BEST_COMPRESSION, 15}, 15 | tags_(std::move(tags)) {} 16 | 17 | void PsfWriter::SaveToFile(const std::filesystem::path& path, 18 | const std::map& tags) { 19 | std::ofstream file(path, std::ios::out | std::ios::binary); 20 | file.exceptions(std::ios::badbit); 21 | SaveToStream(file, tags); 22 | file.close(); 23 | } 24 | 25 | void PsfWriter::SaveToStream(std::ostream& out, 26 | const std::map& tags) { 27 | exe_.flush(); 28 | reserved_.flush(); 29 | 30 | const std::string compressed_exe = compressed_exe_.str(); 31 | const std::string reserved = reserved_.str(); 32 | const std::uint32_t compressed_exe_crc32 = 33 | crc32(0L, reinterpret_cast(compressed_exe.data()), 34 | static_cast(compressed_exe.size())); 35 | 36 | const std::string header{ 37 | NewHeader(compressed_exe, reserved, compressed_exe_crc32)}; 38 | out.write(header.data(), header.size()); 39 | out.write(reserved.data(), reserved.size()); 40 | out.write(compressed_exe.data(), compressed_exe.size()); 41 | 42 | if (!tags.empty()) { 43 | out.write("[TAG]", 5); 44 | 45 | for (const auto& tag : tags) { 46 | const auto& key = tag.first; 47 | const auto& value = tag.second; 48 | 49 | std::istringstream value_reader{value}; 50 | std::string line; 51 | while (std::getline(value_reader, line)) 52 | out << key << '=' << value << '\n'; 53 | } 54 | } 55 | } 56 | 57 | std::string PsfWriter::NewHeader(std::string_view compressed_exe, 58 | std::string_view reserved, 59 | std::uint32_t compressed_exe_crc32) const { 60 | std::string header(16, 0); 61 | std::memcpy(header.data(), "PSF", 3); 62 | WriteInt8(&header[3], version_); 63 | WriteInt32L(&header[4], static_cast(reserved.size())); 64 | WriteInt32L(&header[8], static_cast(compressed_exe.size())); 65 | WriteInt32L(&header[12], compressed_exe_crc32); 66 | return header; 67 | } 68 | 69 | } // namespace saptapper 70 | -------------------------------------------------------------------------------- /src/asm/m4a-gsf.s: -------------------------------------------------------------------------------- 1 | 2 | .text 3 | .global main 4 | 5 | .ascii "__DRIVER_START__" 6 | 7 | .arm 8 | .align 9 | main: 10 | adr r1, main_thumb+1 @ set THUMB flag 11 | bx r1 12 | 13 | .thumb 14 | .align 2 15 | main_thumb: 16 | adr r0, a_GsfDriverMark 17 | 18 | loc_read_watermark: 19 | ldr r1, [r0] 20 | add r0, r0, #4 21 | lsr r2, r1, #24 22 | bne loc_read_watermark @ repeat until NUL 23 | b init 24 | 25 | .align 26 | a_GsfDriverMark: 27 | .asciz "Sappy Driver Ripper by CaitSith2\\Zoopd, (c) 2004, 2014 loveemu" 28 | 29 | .align 30 | init: 31 | push {lr} 32 | ldr r3, sappy_soundinit 33 | bl bx_r3 34 | ldr r0, num_3007FFC 35 | adr r1, irq_handler 36 | str r1, [r0] @ set IRQ handler address 37 | ldr r0, num_4000000 38 | mov r1, #8 39 | str r1, [r0, #0x4] @ set DISPSTAT (enable V-Blank IRQ) 40 | mov r1, #1 41 | ldr r0, num_4000200 42 | str r1, [r0, #0x0] @ set IE (request V-Blank interrupt) 43 | str r1, [r0, #0x8] @ set IME (activate interrupts) 44 | ldr r0, num_songindex 45 | ldr r3, sappy_selectsong 46 | bl bx_r3 @ call sappy_SelectSongByNum 47 | 48 | main_loop: 49 | ldr r3, sappy_soundmain 50 | bl bx_r3 51 | swi 5 @ VSyncIntrWait 52 | b main_loop 53 | 54 | .arm 55 | .align 56 | irq_handler: @ reference: gbatek, devkitadv/crtls/isr.S 57 | ldr r3, num_4000200 58 | ldr r1, [r3, #0x0] 59 | and r0, r1, r1, lsr #16 60 | 61 | stmfd sp!, {r0-r3, lr} 62 | 63 | adr r1, vsync_callback+1 64 | ands r2, r0, #0x0001 65 | bne irq_callhandler 66 | b irq_nohandler 67 | 68 | irq_callhandler: 69 | mov lr, pc 70 | bx r1 71 | 72 | irq_nohandler: 73 | ldmfd sp!, {r0-r3, lr} 74 | 75 | strh r0, [r3, #0x2] @ acknowledge Interrupt 76 | ldr r3, num_3007FFC 77 | str r0, [r3, #-4] @ set BIOS IRQ flags for (VBlank)IntrWait 78 | 79 | bx lr 80 | 81 | .thumb 82 | .align 2 83 | vsync_callback: 84 | push {lr} 85 | 86 | ldr r3, sappy_vsync 87 | bl bx_r3 88 | 89 | pop {r0} 90 | bx r0 91 | 92 | .align 2 93 | num_3007FFC: 94 | .word 0x03007FFC 95 | 96 | num_4000000: 97 | .word 0x04000000 98 | 99 | num_4000200: 100 | .word 0x04000200 101 | 102 | sappy_soundinit: 103 | .word 0 104 | 105 | sappy_selectsong: 106 | .word 0 107 | 108 | sappy_soundmain: 109 | .word 0 110 | 111 | sappy_vsync: 112 | .word 0 113 | 114 | num_songindex: 115 | .word 1 116 | 117 | .thumb 118 | .align 2 119 | bx_r3: 120 | cmp r3, #0 121 | beq locret_1 122 | bx r3 123 | locret_1: 124 | bx lr 125 | 126 | .align 127 | .ascii "___DRIVER_END___" 128 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(saptapper C CXX) 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | include_directories(src/3rdparty/include) 8 | 9 | if(MSVC) 10 | if(CMAKE_CL_64) 11 | set(MSVC_ARCHITECTURE_NAME x64) 12 | else() 13 | set(MSVC_ARCHITECTURE_NAME win32) 14 | endif() 15 | 16 | # Use bundled dependencies 17 | set(ZLIB_ROOT ${CMAKE_SOURCE_DIR}/dependencies/zlib) 18 | set(ZLIB_LIBRARY ${CMAKE_SOURCE_DIR}/dependencies/zlib/lib/${MSVC_ARCHITECTURE_NAME}/zlibstat.lib) 19 | add_definitions(-DZLIB_WINAPI) 20 | endif() 21 | 22 | find_package(ZLIB REQUIRED) 23 | 24 | if(MSVC) 25 | option(STATIC_CRT "Use static CRT libraries" ON) 26 | 27 | # Rewrite command line flags to use /MT if necessary 28 | if(STATIC_CRT) 29 | foreach(flag_var 30 | CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE 31 | CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) 32 | if(${flag_var} MATCHES "/MD") 33 | string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") 34 | endif(${flag_var} MATCHES "/MD") 35 | endforeach(flag_var) 36 | endif() 37 | 38 | # Allow for wildcards in command-line path arguments 39 | # http://msdn.microsoft.com/en-us/library/8bch7bkk.aspx 40 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} setargv.obj") 41 | 42 | # Disable MSVC specific secure error 43 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 44 | endif() 45 | 46 | #============================================================================ 47 | # saptapper 48 | #============================================================================ 49 | 50 | set(SRCS 51 | src/main.cpp 52 | src/saptapper/byte_pattern.cpp 53 | src/saptapper/cartridge.cpp 54 | src/saptapper/gsf_writer.cpp 55 | src/saptapper/mp2k_driver.cpp 56 | src/saptapper/psf_writer.cpp 57 | src/saptapper/saptapper.cpp 58 | ) 59 | 60 | set(HDRS 61 | src/3rdparty/include/args.hxx 62 | src/3rdparty/include/strict_fstream.hpp 63 | src/3rdparty/include/zstr.hpp 64 | src/saptapper/algorithm.hpp 65 | src/saptapper/arm.hpp 66 | src/saptapper/bytes.hpp 67 | src/saptapper/byte_pattern.hpp 68 | src/saptapper/cartridge.hpp 69 | src/saptapper/gsf_header.hpp 70 | src/saptapper/gsf_writer.hpp 71 | src/saptapper/minigsf_driver_param.hpp 72 | src/saptapper/mp2k_driver.hpp 73 | src/saptapper/mp2k_driver_param.hpp 74 | src/saptapper/psf_writer.hpp 75 | src/saptapper/saptapper.hpp 76 | src/saptapper/tabulate.hpp 77 | src/saptapper/types.hpp 78 | ) 79 | 80 | add_executable(saptapper ${SRCS} ${HDRS}) 81 | 82 | if(ZLIB_FOUND) 83 | include_directories(${ZLIB_INCLUDE_DIRS}) 84 | target_link_libraries(saptapper ${ZLIB_LIBRARIES}) 85 | endif(ZLIB_FOUND) 86 | -------------------------------------------------------------------------------- /src/saptapper/mp2k_driver.hpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #ifndef SAPTAPPER_MP2K_DRIVER_HPP_ 4 | #define SAPTAPPER_MP2K_DRIVER_HPP_ 5 | 6 | #include 7 | #include 8 | #include "mp2k_driver_param.hpp" 9 | #include "types.hpp" 10 | 11 | namespace saptapper { 12 | 13 | class Mp2kDriver { 14 | public: 15 | Mp2kDriver() = delete; 16 | 17 | static constexpr int kNoSong = -1; 18 | 19 | static constexpr agbsize_t gsf_driver_size() noexcept { 20 | return sizeof(gsf_driver_block); 21 | } 22 | 23 | static constexpr agbptr_t minigsf_address(agbptr_t gsf_driver_addr) noexcept { 24 | return (gsf_driver_addr != agbnullptr) 25 | ? (gsf_driver_addr + kSongNumberOffset) 26 | : agbnullptr; 27 | } 28 | 29 | static std::string name() { return "MusicPlayer2000"; } 30 | 31 | static Mp2kDriverParam Inspect(std::string_view rom); 32 | 33 | static void InstallGsfDriver(std::string& rom, agbptr_t address, 34 | const Mp2kDriverParam& param); 35 | 36 | static int FindIdenticalSong(std::string_view rom, agbptr_t song_table, 37 | int song); 38 | 39 | private: 40 | static constexpr agbsize_t kInitFnOffset = 0xd8; 41 | static constexpr agbsize_t kSelectSongFnOffset = 0xdc; 42 | static constexpr agbsize_t kMainFnOffset = 0xe0; 43 | static constexpr agbsize_t kVSyncFnOffset = 0xe4; 44 | static constexpr agbsize_t kSongNumberOffset = 0xe8; 45 | 46 | static constexpr unsigned char gsf_driver_block[244] = { 47 | 0x01, 0x10, 0x8F, 0xE2, 0x11, 0xFF, 0x2F, 0xE1, 0x02, 0xA0, 0x01, 0x68, 48 | 0x04, 0x30, 0x0A, 0x0E, 0xFB, 0xD1, 0x1F, 0xE0, 0x53, 0x61, 0x70, 0x70, 49 | 0x79, 0x20, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x20, 0x52, 0x69, 0x70, 50 | 0x70, 0x65, 0x72, 0x20, 0x62, 0x79, 0x20, 0x43, 0x61, 0x69, 0x74, 0x53, 51 | 0x69, 0x74, 0x68, 0x32, 0x5C, 0x5A, 0x6F, 0x6F, 0x70, 0x64, 0x2C, 0x20, 52 | 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x34, 0x2C, 0x20, 0x32, 0x30, 53 | 0x31, 0x34, 0x20, 0x6C, 0x6F, 0x76, 0x65, 0x65, 0x6D, 0x75, 0x00, 0x00, 54 | 0x00, 0xB5, 0x20, 0x4B, 0x00, 0xF0, 0x48, 0xF8, 0x1B, 0x48, 0x09, 0xA1, 55 | 0x01, 0x60, 0x1B, 0x48, 0x08, 0x21, 0x41, 0x60, 0x01, 0x21, 0x1A, 0x48, 56 | 0x01, 0x60, 0x81, 0x60, 0x1D, 0x48, 0x1A, 0x4B, 0x00, 0xF0, 0x3A, 0xF8, 57 | 0x19, 0x4B, 0x00, 0xF0, 0x37, 0xF8, 0x05, 0xDF, 0xFA, 0xE7, 0x00, 0x00, 58 | 0x48, 0x30, 0x9F, 0xE5, 0x00, 0x10, 0x93, 0xE5, 0x21, 0x08, 0x01, 0xE0, 59 | 0x0F, 0x40, 0x2D, 0xE9, 0x25, 0x10, 0x8F, 0xE2, 0x01, 0x20, 0x10, 0xE2, 60 | 0x00, 0x00, 0x00, 0x1A, 0x01, 0x00, 0x00, 0xEA, 0x0F, 0xE0, 0xA0, 0xE1, 61 | 0x11, 0xFF, 0x2F, 0xE1, 0x0F, 0x40, 0xBD, 0xE8, 0xB2, 0x00, 0xC3, 0xE1, 62 | 0x10, 0x30, 0x9F, 0xE5, 0x04, 0x00, 0x03, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1, 63 | 0x00, 0xB5, 0x08, 0x4B, 0x00, 0xF0, 0x12, 0xF8, 0x01, 0xBC, 0x00, 0x47, 64 | 0xFC, 0x7F, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0xD0, 67 | 0x18, 0x47, 0x70, 0x47}; 68 | 69 | static agbptr_t FindInitFn(std::string_view rom, agbptr_t main_fn); 70 | static agbptr_t FindMainFn(std::string_view rom, agbptr_t select_song_fn); 71 | static agbptr_t FindVSyncFn(std::string_view rom, agbptr_t init_fn); 72 | static agbptr_t FindSelectSongFn(std::string_view rom); 73 | static agbptr_t FindSongTable(std::string_view rom, agbptr_t select_song_fn); 74 | static int ReadSongCount(std::string_view rom, agbptr_t song_table); 75 | }; 76 | 77 | } // namespace saptapper 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include 4 | #include 5 | #include 6 | #include "args.hxx" 7 | #include "saptapper/cartridge.hpp" 8 | #include "saptapper/saptapper.hpp" 9 | 10 | using namespace saptapper; 11 | using namespace std::literals::string_literals; 12 | 13 | inline static const std::string kAppName = "Saptapper"s; 14 | inline static const std::string kAppVersion = "2.0"s; 15 | inline static const std::string kAppCredits = 16 | "Original created by Caitsith2, reimplemented by loveemu from scratch."s 17 | "\nVisit for details."s; 18 | 19 | int main(int argc, const char** argv) { 20 | try { 21 | args::ArgumentParser parser( 22 | "An automated GSF ripper for MusicPlayer2000 driver by Nintendo " 23 | "(aka. m4a or Sappy)."); 24 | args::HelpFlag help(parser, "help", "Show this help message and exit", 25 | {'h', "help"}); 26 | args::Flag inspect_arg( 27 | parser, "inspect", 28 | "Show the inspection result without saving files and quit", 29 | {"inspect"}); 30 | args::Flag force_arg(parser, "force", 31 | "Save all songs including duplicated ones", 32 | {'f', "force"}); 33 | args::ValueFlag outdir_arg( 34 | parser, "directory", 35 | "The output directory (the default is the working directory)", 36 | {'d', "outdir"}); 37 | args::ValueFlag basename_arg( 38 | parser, "basename", "The output filename (without extension)", {'o'}); 39 | args::ValueFlag gsfby_arg( 40 | parser, "name", "The creator name to be tagged to minigsfs", {"gsfby"}, 41 | args::Options::HiddenFromUsage | args::Options::HiddenFromDescription); 42 | args::Positional input_arg( 43 | parser, "romfile", "The ROM file to be processed", 44 | args::Options::Required); 45 | 46 | try { 47 | if (argc < 2) throw args::Help(help.Name()); 48 | 49 | parser.ParseCLI(argc, argv); 50 | } catch (args::Help&) { 51 | std::cout << kAppName << " " << kAppVersion << std::endl << std::endl; 52 | std::cout << kAppCredits << std::endl << std::endl; 53 | std::cout << parser; 54 | return EXIT_SUCCESS; 55 | } 56 | 57 | const auto in_path = args::get(input_arg); 58 | if (!exists(in_path)) { 59 | std::cerr << in_path.string() << ": File does not exist" << std::endl; 60 | return EXIT_FAILURE; 61 | } 62 | 63 | Cartridge cartridge = Cartridge::LoadFromFile(in_path); 64 | 65 | if (inspect_arg) { 66 | Mp2kDriverParam param; 67 | MinigsfDriverParam minigsf; 68 | agbptr_t gsf_driver_addr = agbnullptr; 69 | Saptapper::Inspect(cartridge, param, minigsf, gsf_driver_addr); 70 | Saptapper::PrintParam(param, minigsf); 71 | } else { 72 | const std::filesystem::path basename{ 73 | basename_arg ? args::get(basename_arg) : in_path.stem()}; 74 | const std::filesystem::path outdir{args::get(outdir_arg)}; 75 | 76 | std::string gsfby{args::get(gsfby_arg)}; 77 | if (gsfby != "Caitsith2") { 78 | if (gsfby.empty()) { 79 | gsfby = "Saptapper"; 80 | } else { 81 | gsfby.insert(0, "Saptapper, with help of "); 82 | } 83 | } 84 | 85 | bool keep_duplicated = force_arg; 86 | Saptapper::ConvertToGsfSet(cartridge, basename, outdir, gsfby, 87 | keep_duplicated); 88 | } 89 | } catch (std::exception& e) { 90 | std::cerr << e.what() << std::endl; 91 | return EXIT_FAILURE; 92 | } 93 | 94 | return EXIT_SUCCESS; 95 | } 96 | -------------------------------------------------------------------------------- /src/saptapper/bytes.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// Byte I/O templates. 3 | 4 | #ifndef SAPTAPPER_BYTE_IO_HPP_ 5 | #define SAPTAPPER_BYTE_IO_HPP_ 6 | 7 | #include 8 | 9 | namespace saptapper { 10 | 11 | /// Writes an 8-bit integer. 12 | /// @param out the output iterator. 13 | /// @param value the number to be written. 14 | /// @return the output iterator that points to the next element of the written 15 | /// data. 16 | /// @tparam OutputIterator an Iterator that can write to the pointed-to element. 17 | template 18 | constexpr OutputIterator WriteInt8(OutputIterator out, std::uint8_t value) { 19 | static_assert(sizeof(*out) == 1, "Element size of OutputIterator must be 1."); 20 | 21 | *out = static_cast(value); 22 | std::advance(out, 1); 23 | 24 | return out; 25 | } 26 | 27 | /// Writes a 16-bit integer in little-endian order. 28 | /// @param out the output iterator. 29 | /// @param value the number to be written. 30 | /// @return the output iterator that points to the next element of the written 31 | /// data. 32 | /// @tparam OutputIterator an Iterator that can write to the pointed-to element. 33 | template 34 | constexpr OutputIterator WriteInt16L(OutputIterator out, std::uint16_t value) { 35 | static_assert(sizeof(*out) == 1, "Element size of OutputIterator must be 1."); 36 | 37 | *out = value & 0xff; 38 | std::advance(out, 1); 39 | *out = static_cast((value >> 8) & 0xff); 40 | std::advance(out, 1); 41 | 42 | return out; 43 | } 44 | 45 | /// Writes a 32-bit integer in little-endian order. 46 | /// @param out the output iterator. 47 | /// @param value the number to be written. 48 | /// @return the output iterator that points to the next element of the written 49 | /// data. 50 | /// @tparam OutputIterator an Iterator that can write to the pointed-to element. 51 | template 52 | constexpr OutputIterator WriteInt32L(OutputIterator out, std::uint32_t value) { 53 | static_assert(sizeof(*out) == 1, "Element size of OutputIterator must be 1."); 54 | 55 | *out = static_cast(value & 0xff); 56 | std::advance(out, 1); 57 | *out = static_cast((value >> 8) & 0xff); 58 | std::advance(out, 1); 59 | *out = static_cast((value >> 16) & 0xff); 60 | std::advance(out, 1); 61 | *out = static_cast((value >> 24) & 0xff); 62 | std::advance(out, 1); 63 | 64 | return out; 65 | } 66 | 67 | /// Reads a 8-bit integer in little-endian order. 68 | /// @param in the input iterator. 69 | /// @return the number to be read. 70 | /// @tparam InputIterator an Iterator that can read from the pointed-to element. 71 | template 72 | constexpr std::uint8_t ReadInt8L(InputIterator in) { 73 | static_assert(sizeof(*in) == 1, "Element size of InputIterator must be 1."); 74 | return *in; 75 | } 76 | 77 | /// Reads a 16-bit integer in little-endian order. 78 | /// @param in the input iterator. 79 | /// @return the number to be read. 80 | /// @tparam InputIterator an Iterator that can read from the pointed-to element. 81 | template 82 | constexpr std::uint16_t ReadInt16L(InputIterator in) { 83 | static_assert(sizeof(*in) == 1, "Element size of InputIterator must be 1."); 84 | 85 | const std::uint8_t v1 = *in; 86 | std::advance(in, 1); 87 | const std::uint8_t v2 = *in; 88 | 89 | return v1 | (v2 << 8); 90 | } 91 | 92 | /// Reads a 32-bit integer in little-endian order. 93 | /// @param in the input iterator. 94 | /// @return the number to be read. 95 | /// @tparam InputIterator an Iterator that can read from the pointed-to element. 96 | template 97 | constexpr std::uint32_t ReadInt32L(InputIterator in) { 98 | static_assert(sizeof(*in) == 1, "Element size of InputIterator must be 1."); 99 | 100 | const std::uint8_t v1 = *in; 101 | std::advance(in, 1); 102 | const std::uint8_t v2 = *in; 103 | std::advance(in, 1); 104 | const std::uint8_t v3 = *in; 105 | std::advance(in, 1); 106 | const std::uint8_t v4 = *in; 107 | 108 | return v1 | (v2 << 8) | (v3 << 16) | (v4 << 24); 109 | } 110 | 111 | } // namespace saptapper 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/saptapper/saptapper.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include "saptapper.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "cartridge.hpp" 13 | #include "gsf_header.hpp" 14 | #include "gsf_writer.hpp" 15 | #include "minigsf_driver_param.hpp" 16 | #include "mp2k_driver.hpp" 17 | #include "mp2k_driver_param.hpp" 18 | 19 | namespace saptapper { 20 | 21 | void Saptapper::ConvertToGsfSet(Cartridge& cartridge, 22 | const std::filesystem::path& basename, 23 | const std::filesystem::path& outdir, 24 | const std::string_view& gsfby, 25 | bool keep_duplicated) { 26 | Mp2kDriverParam param; 27 | MinigsfDriverParam minigsf; 28 | agbptr_t gsf_driver_addr = agbnullptr; 29 | Inspect(cartridge, param, minigsf, gsf_driver_addr, true); 30 | 31 | Mp2kDriver::InstallGsfDriver(cartridge.rom(), gsf_driver_addr, param); 32 | 33 | std::filesystem::path base_path{outdir}; 34 | base_path /= basename; 35 | create_directories(base_path.parent_path()); 36 | 37 | std::filesystem::path gsflib_path{base_path}; 38 | gsflib_path += ".gsflib"; 39 | 40 | const agbptr_t entrypoint = 0x8000000; 41 | const GsfHeader gsf_header{entrypoint, entrypoint, cartridge.size()}; 42 | GsfWriter::SaveToFile(gsflib_path, gsf_header, cartridge.rom()); 43 | 44 | const std::string lib{gsflib_path.filename().string()}; 45 | std::map minigsf_tags{{"_lib", lib}}; 46 | if (!gsfby.empty()) minigsf_tags["gsfby"] = gsfby; 47 | 48 | for (int song = 0; song < param.song_count(); song++) { 49 | if (!keep_duplicated) { 50 | int origin = Mp2kDriver::FindIdenticalSong(cartridge.rom(), 51 | param.song_table(), song); 52 | if (origin != Mp2kDriver::kNoSong) continue; 53 | } 54 | 55 | SaveMinigsfFile(base_path, minigsf, song, minigsf_tags); 56 | } 57 | } 58 | 59 | void Saptapper::SaveMinigsfFile( 60 | const std::filesystem::path& base_path, const MinigsfDriverParam& minigsf, 61 | int song, const std::map& tags) { 62 | std::ostringstream songid; 63 | songid << std::setfill('0') << std::setw(4) << song; 64 | 65 | std::filesystem::path minigsf_path{base_path}; 66 | minigsf_path += "-"; 67 | minigsf_path += songid.str(); 68 | minigsf_path += ".minigsf"; 69 | 70 | GsfWriter::SaveMinigsfToFile(minigsf_path, minigsf, song, tags); 71 | } 72 | 73 | void Saptapper::Inspect(const Cartridge& cartridge, Mp2kDriverParam& param, 74 | MinigsfDriverParam& minigsf, agbptr_t& gsf_driver_addr, 75 | bool throw_if_missing) { 76 | if (gsf_driver_addr != agbnullptr && !is_romptr(gsf_driver_addr)) 77 | throw std::invalid_argument("The gsf driver address is not valid."); 78 | 79 | param = Mp2kDriver::Inspect(cartridge.rom()); 80 | if (throw_if_missing && !param.ok()) { 81 | std::ostringstream message; 82 | message << "Identification of MusicPlayer2000 driver is incomplete." 83 | << std::endl 84 | << std::endl; 85 | (void)param.WriteAsTable(message); 86 | throw std::runtime_error(message.str()); 87 | } 88 | 89 | if (gsf_driver_addr == agbnullptr) 90 | gsf_driver_addr = 91 | FindFreeSpace(cartridge.rom(), Mp2kDriver::gsf_driver_size()); 92 | 93 | if (throw_if_missing && gsf_driver_addr == agbnullptr) { 94 | std::ostringstream message; 95 | message << "Unable to find the free space for gsf driver block (" 96 | << Mp2kDriver::gsf_driver_size() << " bytes required)."; 97 | throw std::runtime_error(message.str()); 98 | } 99 | 100 | minigsf.set_address(Mp2kDriver::minigsf_address(gsf_driver_addr)); 101 | minigsf.set_size(GetMinigsfSize(param.song_count())); 102 | } 103 | 104 | void Saptapper::PrintParam(const Mp2kDriverParam& param, 105 | const MinigsfDriverParam& minigsf) { 106 | std::cout << "Status: " << (param.ok() ? "OK" : "FAILED") << std::endl 107 | << std::endl; 108 | 109 | (void)param.WriteAsTable(std::cout); 110 | std::cout << std::endl; 111 | 112 | std::cout << "minigsf information:" << std::endl << std::endl; 113 | (void)minigsf.WriteAsTable(std::cout); 114 | } 115 | 116 | agbptr_t Saptapper::FindFreeSpace(std::string_view rom, agbsize_t size, 117 | char filler, bool largest) { 118 | agbptr_t space = agbnullptr; 119 | agbsize_t space_size = 0; 120 | for (agbsize_t offset = 0; offset < rom.size(); offset += 4) { 121 | if (rom[offset] == filler) { 122 | agbsize_t end_pos = offset + 1; 123 | while (end_pos < rom.size() && rom[end_pos] == filler) end_pos++; 124 | 125 | const agbsize_t candidate_size = end_pos - offset; 126 | if (candidate_size >= size) { 127 | if (candidate_size > space_size) { 128 | space = to_romptr(offset); 129 | space_size = candidate_size; 130 | if (!largest) return space; 131 | } 132 | } 133 | 134 | offset = (end_pos + 3) & ~3; 135 | } 136 | } 137 | return space; 138 | } 139 | 140 | agbptr_t Saptapper::FindFreeSpace(std::string_view rom, agbsize_t size) { 141 | constexpr bool largest = false; 142 | agbptr_t addr = FindFreeSpace(rom, size, '\xff', largest); 143 | if (addr == agbnullptr) { 144 | addr = FindFreeSpace(rom, size, 0, largest); 145 | } 146 | return addr; 147 | } 148 | 149 | } // namespace saptapper 150 | -------------------------------------------------------------------------------- /src/3rdparty/include/strict_fstream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __STRICT_FSTREAM_HPP 2 | #define __STRICT_FSTREAM_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /** 10 | * This namespace defines wrappers for std::ifstream, std::ofstream, and 11 | * std::fstream objects. The wrappers perform the following steps: 12 | * - check the open modes make sense 13 | * - check that the call to open() is successful 14 | * - (for input streams) check that the opened file is peek-able 15 | * - turn on the badbit in the exception mask 16 | */ 17 | namespace strict_fstream 18 | { 19 | 20 | /// Overload of error-reporting function, to enable use with VS. 21 | /// Ref: http://stackoverflow.com/a/901316/717706 22 | static std::string strerror() 23 | { 24 | std::string buff(80, '\0'); 25 | #ifdef _WIN32 26 | if (strerror_s(&buff[0], buff.size(), errno) != 0) 27 | { 28 | buff = "Unknown error"; 29 | } 30 | #elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE || defined(__APPLE__) 31 | // XSI-compliant strerror_r() 32 | if (strerror_r(errno, &buff[0], buff.size()) != 0) 33 | { 34 | buff = "Unknown error"; 35 | } 36 | #else 37 | // GNU-specific strerror_r() 38 | auto p = strerror_r(errno, &buff[0], buff.size()); 39 | std::string tmp(p, std::strlen(p)); 40 | std::swap(buff, tmp); 41 | #endif 42 | buff.resize(buff.find('\0')); 43 | return buff; 44 | } 45 | 46 | /// Exception class thrown by failed operations. 47 | class Exception 48 | : public std::exception 49 | { 50 | public: 51 | Exception(const std::string& msg) : _msg(msg) {} 52 | const char * what() const noexcept { return _msg.c_str(); } 53 | private: 54 | std::string _msg; 55 | }; // class Exception 56 | 57 | namespace detail 58 | { 59 | 60 | struct static_method_holder 61 | { 62 | static std::string mode_to_string(std::ios_base::openmode mode) 63 | { 64 | static const int n_modes = 6; 65 | static const std::ios_base::openmode mode_val_v[n_modes] = 66 | { 67 | std::ios_base::in, 68 | std::ios_base::out, 69 | std::ios_base::app, 70 | std::ios_base::ate, 71 | std::ios_base::trunc, 72 | std::ios_base::binary 73 | }; 74 | 75 | static const char * mode_name_v[n_modes] = 76 | { 77 | "in", 78 | "out", 79 | "app", 80 | "ate", 81 | "trunc", 82 | "binary" 83 | }; 84 | std::string res; 85 | for (int i = 0; i < n_modes; ++i) 86 | { 87 | if (mode & mode_val_v[i]) 88 | { 89 | res += (! res.empty()? "|" : ""); 90 | res += mode_name_v[i]; 91 | } 92 | } 93 | if (res.empty()) res = "none"; 94 | return res; 95 | } 96 | static void check_mode(const std::string& filename, std::ios_base::openmode mode) 97 | { 98 | if ((mode & std::ios_base::trunc) && ! (mode & std::ios_base::out)) 99 | { 100 | throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and not out"); 101 | } 102 | else if ((mode & std::ios_base::app) && ! (mode & std::ios_base::out)) 103 | { 104 | throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: app and not out"); 105 | } 106 | else if ((mode & std::ios_base::trunc) && (mode & std::ios_base::app)) 107 | { 108 | throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and app"); 109 | } 110 | } 111 | static void check_open(std::ios * s_p, const std::string& filename, std::ios_base::openmode mode) 112 | { 113 | if (s_p->fail()) 114 | { 115 | throw Exception(std::string("strict_fstream: open('") 116 | + filename + "'," + mode_to_string(mode) + "): open failed: " 117 | + strerror()); 118 | } 119 | } 120 | static void check_peek(std::istream * is_p, const std::string& filename, std::ios_base::openmode mode) 121 | { 122 | bool peek_failed = true; 123 | try 124 | { 125 | is_p->peek(); 126 | peek_failed = is_p->fail(); 127 | } 128 | catch (const std::ios_base::failure &) {} 129 | if (peek_failed) 130 | { 131 | throw Exception(std::string("strict_fstream: open('") 132 | + filename + "'," + mode_to_string(mode) + "): peek failed: " 133 | + strerror()); 134 | } 135 | is_p->clear(); 136 | } 137 | }; // struct static_method_holder 138 | 139 | } // namespace detail 140 | 141 | class ifstream 142 | : public std::ifstream 143 | { 144 | public: 145 | ifstream() = default; 146 | ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in) 147 | { 148 | open(filename, mode); 149 | } 150 | void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in) 151 | { 152 | mode |= std::ios_base::in; 153 | exceptions(std::ios_base::badbit); 154 | detail::static_method_holder::check_mode(filename, mode); 155 | std::ifstream::open(filename, mode); 156 | detail::static_method_holder::check_open(this, filename, mode); 157 | detail::static_method_holder::check_peek(this, filename, mode); 158 | } 159 | }; // class ifstream 160 | 161 | class ofstream 162 | : public std::ofstream 163 | { 164 | public: 165 | ofstream() = default; 166 | ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out) 167 | { 168 | open(filename, mode); 169 | } 170 | void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out) 171 | { 172 | mode |= std::ios_base::out; 173 | exceptions(std::ios_base::badbit); 174 | detail::static_method_holder::check_mode(filename, mode); 175 | std::ofstream::open(filename, mode); 176 | detail::static_method_holder::check_open(this, filename, mode); 177 | } 178 | }; // class ofstream 179 | 180 | class fstream 181 | : public std::fstream 182 | { 183 | public: 184 | fstream() = default; 185 | fstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in) 186 | { 187 | open(filename, mode); 188 | } 189 | void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in) 190 | { 191 | if (! (mode & std::ios_base::out)) mode |= std::ios_base::in; 192 | exceptions(std::ios_base::badbit); 193 | detail::static_method_holder::check_mode(filename, mode); 194 | std::fstream::open(filename, mode); 195 | detail::static_method_holder::check_open(this, filename, mode); 196 | detail::static_method_holder::check_peek(this, filename, mode); 197 | } 198 | }; // class fstream 199 | 200 | } // namespace strict_fstream 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /src/saptapper/mp2k_driver.cpp: -------------------------------------------------------------------------------- 1 | // Saptapper: Automated GSF ripper for MusicPlayer2000. 2 | 3 | #include "mp2k_driver.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "algorithm.hpp" 13 | #include "arm.hpp" 14 | #include "byte_pattern.hpp" 15 | #include "bytes.hpp" 16 | #include "mp2k_driver_param.hpp" 17 | #include "types.hpp" 18 | 19 | namespace saptapper { 20 | 21 | Mp2kDriverParam Mp2kDriver::Inspect(std::string_view rom) { 22 | Mp2kDriverParam param; 23 | param.set_select_song_fn(FindSelectSongFn(rom)); 24 | param.set_song_table(FindSongTable(rom, param.select_song_fn())); 25 | param.set_main_fn(FindMainFn(rom, param.select_song_fn())); 26 | param.set_init_fn(FindInitFn(rom, param.main_fn())); 27 | param.set_vsync_fn(FindVSyncFn(rom, param.init_fn())); 28 | param.set_song_count(ReadSongCount(rom, param.song_table())); 29 | return param; 30 | } 31 | 32 | void Mp2kDriver::InstallGsfDriver(std::string& rom, agbptr_t address, 33 | const Mp2kDriverParam& param) { 34 | if (!is_romptr(address)) 35 | throw std::invalid_argument("The gsf driver address is not valid."); 36 | if (!param.ok()) { 37 | std::ostringstream message; 38 | message << "Identification of MusicPlayer2000 driver is incomplete." 39 | << std::endl << std::endl; 40 | (void)param.WriteAsTable(message); 41 | throw std::invalid_argument(message.str()); 42 | } 43 | 44 | agbsize_t offset = to_offset(address); 45 | if (offset + gsf_driver_size() > rom.size()) 46 | throw std::out_of_range("The address of gsf driver block is out of range."); 47 | 48 | std::memcpy(&rom[offset], gsf_driver_block, gsf_driver_size()); 49 | WriteInt32L(&rom[offset + kInitFnOffset], param.init_fn() | 1); 50 | WriteInt32L(&rom[offset + kSelectSongFnOffset], param.select_song_fn() | 1); 51 | WriteInt32L(&rom[offset + kMainFnOffset], param.main_fn() | 1); 52 | WriteInt32L(&rom[offset + kVSyncFnOffset], param.vsync_fn() | 1); 53 | 54 | WriteInt32L(rom.data(), make_arm_b(0x8000000, address)); 55 | } 56 | 57 | int Mp2kDriver::FindIdenticalSong(std::string_view rom, agbptr_t song_table, 58 | int song) { 59 | if (song_table == agbnullptr) return kNoSong; 60 | 61 | agbsize_t start_pos = to_offset(song_table); 62 | if (start_pos >= rom.size()) return kNoSong; 63 | 64 | agbsize_t target_pos = start_pos + (8 * song); 65 | if (target_pos + 8 >= rom.size()) return kNoSong; 66 | 67 | int current_song = 0; 68 | for (agbsize_t pos = start_pos; pos < target_pos; pos += 8, current_song++) { 69 | if (std::memcmp(&rom[pos], &rom[target_pos], 8) == 0) return current_song; 70 | } 71 | return kNoSong; 72 | } 73 | 74 | agbptr_t Mp2kDriver::FindInitFn(std::string_view rom, agbptr_t main_fn) { 75 | if (main_fn == agbnullptr) return agbnullptr; 76 | 77 | using namespace std::literals::string_view_literals; 78 | std::array patterns = { 79 | "\x70\xb5\x14\x48"sv, // push {r4-r6,lr}; ldr r0, =(SoundMainRAM+1) 80 | "\xf0\xb5\x47\x46"sv, // push {r4-r7,lr}; mov r7, r8 81 | }; 82 | return find_backwards(rom, patterns, to_offset(main_fn), 0x100); 83 | } // namespace saptapper 84 | 85 | agbptr_t Mp2kDriver::FindMainFn(std::string_view rom, agbptr_t select_song_fn) { 86 | if (select_song_fn == agbnullptr) return agbnullptr; 87 | 88 | using namespace std::literals::string_view_literals; 89 | std::array patterns{"\x00\xb5"sv}; // push lr 90 | return find_backwards(rom, patterns, to_offset(select_song_fn), 0x20); 91 | } 92 | 93 | agbptr_t Mp2kDriver::FindVSyncFn(std::string_view rom, agbptr_t init_fn) { 94 | if (init_fn == agbnullptr) return agbnullptr; 95 | 96 | using namespace std::literals::string_view_literals; 97 | // LDR R0, =dword_3007FF0 98 | // LDR R0, [R0] 99 | // LDR R2, =0x68736D53 100 | // LDR R3, [R0] 101 | // SUBS (later versions) or CMP (earlier versions, such as Momotarou Matsuri) 102 | const BytePattern pattern{"\xa6\x48\x00\x68\xa6\x4a\x03\x68"sv, "?xxx?xxx"sv}; 103 | 104 | // Pattern for Puyo Pop Fever, Precure, etc.: 105 | // 106 | // PUSH {LR} 107 | // LDR R0, =dword_3007FF0 108 | // LDR R2, [R0] 109 | // LDR R0, [R2] 110 | // LDR R1, =0x978C92AD 111 | const BytePattern pattern2{"\x00\xb5\x18\x48\x02\x68\x10\x68\x17\x49"sv, 112 | "xx?xxxxx?x"sv}; 113 | 114 | const agbsize_t init_fn_pos = to_offset(init_fn); 115 | if (init_fn_pos >= rom.size()) return agbnullptr; 116 | 117 | // The m4aSoundVSync function is far from m4aSoundInit. 118 | constexpr agbsize_t length = 119 | 0x1800; // 0x1000 might be good, but longer is safer anyway :) 120 | constexpr agbsize_t align = 4; 121 | assert(length % align == 0); 122 | if (rom.size() < length) return agbnullptr; 123 | 124 | // Regular version: 125 | // 126 | // Search backwards from m4aSoundInit function. 127 | const agbsize_t max_pos = init_fn_pos - align; 128 | const agbsize_t min_pos = init_fn_pos - std::min(length, init_fn_pos); 129 | for (agbsize_t offset = max_pos; offset >= min_pos; offset -= align) { 130 | if (pattern.Match(rom, offset)) { 131 | // Momotarou Matsuri, Puyo Pop Fever: 132 | // check "BX LR" and avoid false-positive 133 | if (offset + 0x0c + 2 <= rom.size() && 134 | ReadInt16L(&rom[offset + 0x0c]) == 0x4770) { 135 | continue; 136 | } 137 | 138 | return to_romptr(offset); 139 | } 140 | } 141 | 142 | // Alternate version (Puyo Pop Fever, Precure, etc.): 143 | // 144 | // Search forwards from m4aSoundInit function. 145 | const agbsize_t min_pos2 = init_fn_pos + align; 146 | const agbsize_t max_pos2 = std::min( 147 | init_fn_pos + length, static_cast(rom.size())); 148 | for (agbsize_t offset = min_pos2; offset < max_pos2; offset += align) { 149 | if (pattern2.Match(rom, offset)) 150 | return to_romptr(offset); 151 | } 152 | 153 | return agbnullptr; 154 | } 155 | 156 | agbptr_t Mp2kDriver::FindSelectSongFn(std::string_view rom) { 157 | using namespace std::literals::string_view_literals; 158 | const std::string_view pattern{ 159 | "\x00\xb5\x00\x04\x07\x4a\x08\x49\x40\x0b"sv 160 | "\x40\x18\x83\x88\x59\x00\xc9\x18\x89\x00"sv 161 | "\x89\x18\x0a\x68\x01\x68\x10\x1c\x00\xf0"sv}; 162 | return find_loose(rom, pattern, 8); 163 | } 164 | 165 | agbptr_t Mp2kDriver::FindSongTable(std::string_view rom, 166 | agbptr_t select_song_fn) { 167 | if (select_song_fn == agbnullptr) return agbnullptr; 168 | 169 | const agbsize_t select_song_fn_pos = to_offset(select_song_fn); 170 | if (select_song_fn_pos + 40 + 4 > rom.size()) return agbnullptr; 171 | 172 | const agbptr_t song_table = ReadInt32L(&rom[select_song_fn_pos + 40]); 173 | if (!is_romptr(song_table)) return agbnullptr; 174 | if (to_offset(song_table) >= rom.size()) return agbnullptr; 175 | 176 | return song_table; 177 | } 178 | 179 | int Mp2kDriver::ReadSongCount(std::string_view rom, agbptr_t song_table) { 180 | if (song_table == agbnullptr) return 0; 181 | 182 | const agbsize_t song_table_pos = to_offset(song_table); 183 | if (rom.size() < 8) return 0; 184 | if (song_table_pos > rom.size() - 8) return 0; 185 | 186 | int song_count = 0; 187 | for (agbsize_t offset = song_table_pos; offset <= rom.size() - 8; 188 | offset += 8) { 189 | const agbptr_t song = ReadInt32L(&rom[offset]); 190 | if (!is_romptr(song)) break; 191 | song_count++; 192 | } 193 | return song_count; 194 | } 195 | 196 | } // namespace saptapper 197 | -------------------------------------------------------------------------------- /dependencies/zlib/include/zutil.h: -------------------------------------------------------------------------------- 1 | /* zutil.h -- internal interface and configuration of the compression library 2 | * Copyright (C) 1995-2013 Jean-loup Gailly. 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | /* @(#) $Id$ */ 12 | 13 | #ifndef ZUTIL_H 14 | #define ZUTIL_H 15 | 16 | #ifdef HAVE_HIDDEN 17 | # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) 18 | #else 19 | # define ZLIB_INTERNAL 20 | #endif 21 | 22 | #include "zlib.h" 23 | 24 | #if defined(STDC) && !defined(Z_SOLO) 25 | # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) 26 | # include 27 | # endif 28 | # include 29 | # include 30 | #endif 31 | 32 | #ifdef Z_SOLO 33 | typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ 34 | #endif 35 | 36 | #ifndef local 37 | # define local static 38 | #endif 39 | /* compile with -Dlocal if your debugger can't find static symbols */ 40 | 41 | typedef unsigned char uch; 42 | typedef uch FAR uchf; 43 | typedef unsigned short ush; 44 | typedef ush FAR ushf; 45 | typedef unsigned long ulg; 46 | 47 | extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ 48 | /* (size given to avoid silly warnings with Visual C++) */ 49 | 50 | #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] 51 | 52 | #define ERR_RETURN(strm,err) \ 53 | return (strm->msg = ERR_MSG(err), (err)) 54 | /* To be used only when the state is known to be valid */ 55 | 56 | /* common constants */ 57 | 58 | #ifndef DEF_WBITS 59 | # define DEF_WBITS MAX_WBITS 60 | #endif 61 | /* default windowBits for decompression. MAX_WBITS is for compression only */ 62 | 63 | #if MAX_MEM_LEVEL >= 8 64 | # define DEF_MEM_LEVEL 8 65 | #else 66 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL 67 | #endif 68 | /* default memLevel */ 69 | 70 | #define STORED_BLOCK 0 71 | #define STATIC_TREES 1 72 | #define DYN_TREES 2 73 | /* The three kinds of block type */ 74 | 75 | #define MIN_MATCH 3 76 | #define MAX_MATCH 258 77 | /* The minimum and maximum match lengths */ 78 | 79 | #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ 80 | 81 | /* target dependencies */ 82 | 83 | #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) 84 | # define OS_CODE 0x00 85 | # ifndef Z_SOLO 86 | # if defined(__TURBOC__) || defined(__BORLANDC__) 87 | # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) 88 | /* Allow compilation with ANSI keywords only enabled */ 89 | void _Cdecl farfree( void *block ); 90 | void *_Cdecl farmalloc( unsigned long nbytes ); 91 | # else 92 | # include 93 | # endif 94 | # else /* MSC or DJGPP */ 95 | # include 96 | # endif 97 | # endif 98 | #endif 99 | 100 | #ifdef AMIGA 101 | # define OS_CODE 0x01 102 | #endif 103 | 104 | #if defined(VAXC) || defined(VMS) 105 | # define OS_CODE 0x02 106 | # define F_OPEN(name, mode) \ 107 | fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") 108 | #endif 109 | 110 | #if defined(ATARI) || defined(atarist) 111 | # define OS_CODE 0x05 112 | #endif 113 | 114 | #ifdef OS2 115 | # define OS_CODE 0x06 116 | # if defined(M_I86) && !defined(Z_SOLO) 117 | # include 118 | # endif 119 | #endif 120 | 121 | #if defined(MACOS) || defined(TARGET_OS_MAC) 122 | # define OS_CODE 0x07 123 | # ifndef Z_SOLO 124 | # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os 125 | # include /* for fdopen */ 126 | # else 127 | # ifndef fdopen 128 | # define fdopen(fd,mode) NULL /* No fdopen() */ 129 | # endif 130 | # endif 131 | # endif 132 | #endif 133 | 134 | #ifdef TOPS20 135 | # define OS_CODE 0x0a 136 | #endif 137 | 138 | #ifdef WIN32 139 | # ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ 140 | # define OS_CODE 0x0b 141 | # endif 142 | #endif 143 | 144 | #ifdef __50SERIES /* Prime/PRIMOS */ 145 | # define OS_CODE 0x0f 146 | #endif 147 | 148 | #if defined(_BEOS_) || defined(RISCOS) 149 | # define fdopen(fd,mode) NULL /* No fdopen() */ 150 | #endif 151 | 152 | #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX 153 | # if defined(_WIN32_WCE) 154 | # define fdopen(fd,mode) NULL /* No fdopen() */ 155 | # ifndef _PTRDIFF_T_DEFINED 156 | typedef int ptrdiff_t; 157 | # define _PTRDIFF_T_DEFINED 158 | # endif 159 | # else 160 | # define fdopen(fd,type) _fdopen(fd,type) 161 | # endif 162 | #endif 163 | 164 | #if defined(__BORLANDC__) && !defined(MSDOS) 165 | #pragma warn -8004 166 | #pragma warn -8008 167 | #pragma warn -8066 168 | #endif 169 | 170 | /* provide prototypes for these when building zlib without LFS */ 171 | #if !defined(_WIN32) && \ 172 | (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) 173 | ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); 174 | ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); 175 | #endif 176 | 177 | /* common defaults */ 178 | 179 | #ifndef OS_CODE 180 | # define OS_CODE 0x03 /* assume Unix */ 181 | #endif 182 | 183 | #ifndef F_OPEN 184 | # define F_OPEN(name, mode) fopen((name), (mode)) 185 | #endif 186 | 187 | /* functions */ 188 | 189 | #if defined(pyr) || defined(Z_SOLO) 190 | # define NO_MEMCPY 191 | #endif 192 | #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) 193 | /* Use our own functions for small and medium model with MSC <= 5.0. 194 | * You may have to use the same strategy for Borland C (untested). 195 | * The __SC__ check is for Symantec. 196 | */ 197 | # define NO_MEMCPY 198 | #endif 199 | #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) 200 | # define HAVE_MEMCPY 201 | #endif 202 | #ifdef HAVE_MEMCPY 203 | # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ 204 | # define zmemcpy _fmemcpy 205 | # define zmemcmp _fmemcmp 206 | # define zmemzero(dest, len) _fmemset(dest, 0, len) 207 | # else 208 | # define zmemcpy memcpy 209 | # define zmemcmp memcmp 210 | # define zmemzero(dest, len) memset(dest, 0, len) 211 | # endif 212 | #else 213 | void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); 214 | int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); 215 | void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); 216 | #endif 217 | 218 | /* Diagnostic functions */ 219 | #ifdef DEBUG 220 | # include 221 | extern int ZLIB_INTERNAL z_verbose; 222 | extern void ZLIB_INTERNAL z_error OF((char *m)); 223 | # define Assert(cond,msg) {if(!(cond)) z_error(msg);} 224 | # define Trace(x) {if (z_verbose>=0) fprintf x ;} 225 | # define Tracev(x) {if (z_verbose>0) fprintf x ;} 226 | # define Tracevv(x) {if (z_verbose>1) fprintf x ;} 227 | # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} 228 | # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} 229 | #else 230 | # define Assert(cond,msg) 231 | # define Trace(x) 232 | # define Tracev(x) 233 | # define Tracevv(x) 234 | # define Tracec(c,x) 235 | # define Tracecv(c,x) 236 | #endif 237 | 238 | #ifndef Z_SOLO 239 | voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, 240 | unsigned size)); 241 | void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); 242 | #endif 243 | 244 | #define ZALLOC(strm, items, size) \ 245 | (*((strm)->zalloc))((strm)->opaque, (items), (size)) 246 | #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) 247 | #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} 248 | 249 | /* Reverse the bytes in a 32-bit value */ 250 | #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ 251 | (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) 252 | 253 | #endif /* ZUTIL_H */ 254 | -------------------------------------------------------------------------------- /dependencies/zlib/include/ioapi.h: -------------------------------------------------------------------------------- 1 | /* ioapi.h -- IO base function header for compress/uncompress .zip 2 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 3 | 4 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 5 | 6 | Modifications for Zip64 support 7 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 8 | 9 | For more info read MiniZip_info.txt 10 | 11 | Changes 12 | 13 | Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) 14 | Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. 15 | More if/def section may be needed to support other platforms 16 | Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. 17 | (but you should use iowin32.c for windows instead) 18 | 19 | */ 20 | 21 | #ifndef _ZLIBIOAPI64_H 22 | #define _ZLIBIOAPI64_H 23 | 24 | #if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) 25 | 26 | // Linux needs this to support file operation on files larger then 4+GB 27 | // But might need better if/def to select just the platforms that needs them. 28 | 29 | #ifndef __USE_FILE_OFFSET64 30 | #define __USE_FILE_OFFSET64 31 | #endif 32 | #ifndef __USE_LARGEFILE64 33 | #define __USE_LARGEFILE64 34 | #endif 35 | #ifndef _LARGEFILE64_SOURCE 36 | #define _LARGEFILE64_SOURCE 37 | #endif 38 | #ifndef _FILE_OFFSET_BIT 39 | #define _FILE_OFFSET_BIT 64 40 | #endif 41 | 42 | #endif 43 | 44 | #include 45 | #include 46 | #include "zlib.h" 47 | 48 | #if defined(USE_FILE32API) 49 | #define fopen64 fopen 50 | #define ftello64 ftell 51 | #define fseeko64 fseek 52 | #else 53 | #ifdef __FreeBSD__ 54 | #define fopen64 fopen 55 | #define ftello64 ftello 56 | #define fseeko64 fseeko 57 | #endif 58 | #ifdef _MSC_VER 59 | #define fopen64 fopen 60 | #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) 61 | #define ftello64 _ftelli64 62 | #define fseeko64 _fseeki64 63 | #else // old MSC 64 | #define ftello64 ftell 65 | #define fseeko64 fseek 66 | #endif 67 | #endif 68 | #endif 69 | 70 | /* 71 | #ifndef ZPOS64_T 72 | #ifdef _WIN32 73 | #define ZPOS64_T fpos_t 74 | #else 75 | #include 76 | #define ZPOS64_T uint64_t 77 | #endif 78 | #endif 79 | */ 80 | 81 | #ifdef HAVE_MINIZIP64_CONF_H 82 | #include "mz64conf.h" 83 | #endif 84 | 85 | /* a type choosen by DEFINE */ 86 | #ifdef HAVE_64BIT_INT_CUSTOM 87 | typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; 88 | #else 89 | #ifdef HAS_STDINT_H 90 | #include "stdint.h" 91 | typedef uint64_t ZPOS64_T; 92 | #else 93 | 94 | /* Maximum unsigned 32-bit value used as placeholder for zip64 */ 95 | #define MAXU32 0xffffffff 96 | 97 | #if defined(_MSC_VER) || defined(__BORLANDC__) 98 | typedef unsigned __int64 ZPOS64_T; 99 | #else 100 | typedef unsigned long long int ZPOS64_T; 101 | #endif 102 | #endif 103 | #endif 104 | 105 | 106 | 107 | #ifdef __cplusplus 108 | extern "C" { 109 | #endif 110 | 111 | 112 | #define ZLIB_FILEFUNC_SEEK_CUR (1) 113 | #define ZLIB_FILEFUNC_SEEK_END (2) 114 | #define ZLIB_FILEFUNC_SEEK_SET (0) 115 | 116 | #define ZLIB_FILEFUNC_MODE_READ (1) 117 | #define ZLIB_FILEFUNC_MODE_WRITE (2) 118 | #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) 119 | 120 | #define ZLIB_FILEFUNC_MODE_EXISTING (4) 121 | #define ZLIB_FILEFUNC_MODE_CREATE (8) 122 | 123 | 124 | #ifndef ZCALLBACK 125 | #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) 126 | #define ZCALLBACK CALLBACK 127 | #else 128 | #define ZCALLBACK 129 | #endif 130 | #endif 131 | 132 | 133 | 134 | 135 | typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); 136 | typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); 137 | typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); 138 | typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); 139 | typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); 140 | 141 | typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); 142 | typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); 143 | 144 | 145 | /* here is the "old" 32 bits structure structure */ 146 | typedef struct zlib_filefunc_def_s 147 | { 148 | open_file_func zopen_file; 149 | read_file_func zread_file; 150 | write_file_func zwrite_file; 151 | tell_file_func ztell_file; 152 | seek_file_func zseek_file; 153 | close_file_func zclose_file; 154 | testerror_file_func zerror_file; 155 | voidpf opaque; 156 | } zlib_filefunc_def; 157 | 158 | typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); 159 | typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); 160 | typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); 161 | 162 | typedef struct zlib_filefunc64_def_s 163 | { 164 | open64_file_func zopen64_file; 165 | read_file_func zread_file; 166 | write_file_func zwrite_file; 167 | tell64_file_func ztell64_file; 168 | seek64_file_func zseek64_file; 169 | close_file_func zclose_file; 170 | testerror_file_func zerror_file; 171 | voidpf opaque; 172 | } zlib_filefunc64_def; 173 | 174 | void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); 175 | void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); 176 | 177 | /* now internal definition, only for zip.c and unzip.h */ 178 | typedef struct zlib_filefunc64_32_def_s 179 | { 180 | zlib_filefunc64_def zfile_func64; 181 | open_file_func zopen32_file; 182 | tell_file_func ztell32_file; 183 | seek_file_func zseek32_file; 184 | } zlib_filefunc64_32_def; 185 | 186 | 187 | #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) 188 | #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) 189 | //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) 190 | //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) 191 | #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) 192 | #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) 193 | 194 | voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); 195 | long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); 196 | ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); 197 | 198 | void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); 199 | 200 | #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) 201 | #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) 202 | #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) 203 | 204 | #ifdef __cplusplus 205 | } 206 | #endif 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /src/3rdparty/include/zstr.hpp: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------- 2 | // Copyright 2015 Ontario Institute for Cancer Research 3 | // Written by Matei David (matei@cs.toronto.edu) 4 | //--------------------------------------------------------- 5 | 6 | // Reference: 7 | // http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c 8 | 9 | #ifndef __ZSTR_HPP 10 | #define __ZSTR_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "strict_fstream.hpp" 17 | 18 | namespace zstr 19 | { 20 | 21 | static const std::size_t default_buff_size = (std::size_t)1 << 20; 22 | 23 | /// Exception class thrown by failed zlib operations. 24 | class Exception 25 | : public std::exception 26 | { 27 | public: 28 | Exception(z_stream * zstrm_p, int ret) 29 | : _msg("zlib: ") 30 | { 31 | switch (ret) 32 | { 33 | case Z_STREAM_ERROR: 34 | _msg += "Z_STREAM_ERROR: "; 35 | break; 36 | case Z_DATA_ERROR: 37 | _msg += "Z_DATA_ERROR: "; 38 | break; 39 | case Z_MEM_ERROR: 40 | _msg += "Z_MEM_ERROR: "; 41 | break; 42 | case Z_VERSION_ERROR: 43 | _msg += "Z_VERSION_ERROR: "; 44 | break; 45 | case Z_BUF_ERROR: 46 | _msg += "Z_BUF_ERROR: "; 47 | break; 48 | default: 49 | std::ostringstream oss; 50 | oss << ret; 51 | _msg += "[" + oss.str() + "]: "; 52 | break; 53 | } 54 | _msg += zstrm_p->msg; 55 | } 56 | Exception(const std::string msg) : _msg(msg) {} 57 | const char * what() const noexcept { return _msg.c_str(); } 58 | private: 59 | std::string _msg; 60 | }; // class Exception 61 | 62 | namespace detail 63 | { 64 | 65 | class z_stream_wrapper 66 | : public z_stream 67 | { 68 | public: 69 | z_stream_wrapper(bool _is_input, int _level, int _window_bits) 70 | : is_input(_is_input) 71 | { 72 | this->zalloc = Z_NULL; 73 | this->zfree = Z_NULL; 74 | this->opaque = Z_NULL; 75 | int ret; 76 | if (is_input) 77 | { 78 | this->avail_in = 0; 79 | this->next_in = Z_NULL; 80 | ret = inflateInit2(this, _window_bits ? _window_bits : 15+32); 81 | } 82 | else 83 | { 84 | ret = deflateInit2(this, _level, Z_DEFLATED, _window_bits ? _window_bits : 15+16, 8, Z_DEFAULT_STRATEGY); 85 | } 86 | if (ret != Z_OK) throw Exception(this, ret); 87 | } 88 | ~z_stream_wrapper() 89 | { 90 | if (is_input) 91 | { 92 | inflateEnd(this); 93 | } 94 | else 95 | { 96 | deflateEnd(this); 97 | } 98 | } 99 | private: 100 | bool is_input; 101 | }; // class z_stream_wrapper 102 | 103 | } // namespace detail 104 | 105 | class istreambuf 106 | : public std::streambuf 107 | { 108 | public: 109 | istreambuf(std::streambuf * _sbuf_p, 110 | std::size_t _buff_size = default_buff_size, bool _auto_detect = true, int _window_bits = 0) 111 | : sbuf_p(_sbuf_p), 112 | zstrm_p(nullptr), 113 | buff_size(_buff_size), 114 | auto_detect(_auto_detect), 115 | auto_detect_run(false), 116 | is_text(false), 117 | window_bits(_window_bits) 118 | { 119 | assert(sbuf_p); 120 | in_buff = new char [buff_size]; 121 | in_buff_start = in_buff; 122 | in_buff_end = in_buff; 123 | out_buff = new char [buff_size]; 124 | setg(out_buff, out_buff, out_buff); 125 | } 126 | 127 | istreambuf(const istreambuf &) = delete; 128 | istreambuf(istreambuf &&) = default; 129 | istreambuf & operator = (const istreambuf &) = delete; 130 | istreambuf & operator = (istreambuf &&) = default; 131 | 132 | virtual ~istreambuf() 133 | { 134 | delete [] in_buff; 135 | delete [] out_buff; 136 | if (zstrm_p) delete zstrm_p; 137 | } 138 | 139 | virtual std::streambuf::int_type underflow() 140 | { 141 | if (this->gptr() == this->egptr()) 142 | { 143 | // pointers for free region in output buffer 144 | char * out_buff_free_start = out_buff; 145 | do 146 | { 147 | // read more input if none available 148 | if (in_buff_start == in_buff_end) 149 | { 150 | // empty input buffer: refill from the start 151 | in_buff_start = in_buff; 152 | std::streamsize sz = sbuf_p->sgetn(in_buff, buff_size); 153 | in_buff_end = in_buff + sz; 154 | if (in_buff_end == in_buff_start) break; // end of input 155 | } 156 | // auto detect if the stream contains text or deflate data 157 | if (auto_detect && ! auto_detect_run) 158 | { 159 | auto_detect_run = true; 160 | unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start); 161 | unsigned char b1 = *reinterpret_cast< unsigned char * >(in_buff_start + 1); 162 | // Ref: 163 | // http://en.wikipedia.org/wiki/Gzip 164 | // http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like 165 | is_text = ! (in_buff_start + 2 <= in_buff_end 166 | && ((b0 == 0x1F && b1 == 0x8B) // gzip header 167 | || (b0 == 0x78 && (b1 == 0x01 // zlib header 168 | || b1 == 0x9C 169 | || b1 == 0xDA)))); 170 | } 171 | if (is_text) 172 | { 173 | // simply swap in_buff and out_buff, and adjust pointers 174 | assert(in_buff_start == in_buff); 175 | std::swap(in_buff, out_buff); 176 | out_buff_free_start = in_buff_end; 177 | in_buff_start = in_buff; 178 | in_buff_end = in_buff; 179 | } 180 | else 181 | { 182 | // run inflate() on input 183 | if (! zstrm_p) zstrm_p = new detail::z_stream_wrapper(true, Z_DEFAULT_COMPRESSION, window_bits); 184 | zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start); 185 | zstrm_p->avail_in = static_cast(in_buff_end - in_buff_start); 186 | zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start); 187 | zstrm_p->avail_out = static_cast((out_buff + buff_size) - out_buff_free_start); 188 | int ret = inflate(zstrm_p, Z_NO_FLUSH); 189 | // process return code 190 | if (ret != Z_OK && ret != Z_STREAM_END) throw Exception(zstrm_p, ret); 191 | // update in&out pointers following inflate() 192 | in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in); 193 | in_buff_end = in_buff_start + zstrm_p->avail_in; 194 | out_buff_free_start = reinterpret_cast< decltype(out_buff_free_start) >(zstrm_p->next_out); 195 | assert(out_buff_free_start + zstrm_p->avail_out == out_buff + buff_size); 196 | // if stream ended, deallocate inflator 197 | if (ret == Z_STREAM_END) 198 | { 199 | delete zstrm_p; 200 | zstrm_p = nullptr; 201 | } 202 | } 203 | } while (out_buff_free_start == out_buff); 204 | // 2 exit conditions: 205 | // - end of input: there might or might not be output available 206 | // - out_buff_free_start != out_buff: output available 207 | this->setg(out_buff, out_buff, out_buff_free_start); 208 | } 209 | return this->gptr() == this->egptr() 210 | ? traits_type::eof() 211 | : traits_type::to_int_type(*this->gptr()); 212 | } 213 | private: 214 | std::streambuf * sbuf_p; 215 | char * in_buff; 216 | char * in_buff_start; 217 | char * in_buff_end; 218 | char * out_buff; 219 | detail::z_stream_wrapper * zstrm_p; 220 | std::size_t buff_size; 221 | bool auto_detect; 222 | bool auto_detect_run; 223 | bool is_text; 224 | int window_bits; 225 | }; // class istreambuf 226 | 227 | class ostreambuf 228 | : public std::streambuf 229 | { 230 | public: 231 | ostreambuf(std::streambuf * _sbuf_p, 232 | std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION, int _window_bits = 0) 233 | : sbuf_p(_sbuf_p), 234 | zstrm_p(new detail::z_stream_wrapper(false, _level, _window_bits)), 235 | buff_size(_buff_size) 236 | { 237 | assert(sbuf_p); 238 | in_buff = new char [buff_size]; 239 | out_buff = new char [buff_size]; 240 | setp(in_buff, in_buff + buff_size); 241 | } 242 | 243 | ostreambuf(const ostreambuf &) = delete; 244 | ostreambuf(ostreambuf &&) = default; 245 | ostreambuf & operator = (const ostreambuf &) = delete; 246 | ostreambuf & operator = (ostreambuf &&) = default; 247 | 248 | int deflate_loop(int flush) 249 | { 250 | while (true) 251 | { 252 | zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff); 253 | zstrm_p->avail_out = static_cast(buff_size); 254 | int ret = deflate(zstrm_p, flush); 255 | if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) throw Exception(zstrm_p, ret); 256 | std::streamsize sz = sbuf_p->sputn(out_buff, reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff); 257 | if (sz != reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff) 258 | { 259 | // there was an error in the sink stream 260 | return -1; 261 | } 262 | if (ret == Z_STREAM_END || ret == Z_BUF_ERROR || sz == 0) 263 | { 264 | break; 265 | } 266 | } 267 | return 0; 268 | } 269 | 270 | virtual ~ostreambuf() 271 | { 272 | // flush the zlib stream 273 | // 274 | // NOTE: Errors here (sync() return value not 0) are ignored, because we 275 | // cannot throw in a destructor. This mirrors the behaviour of 276 | // std::basic_filebuf::~basic_filebuf(). To see an exception on error, 277 | // close the ofstream with an explicit call to close(), and do not rely 278 | // on the implicit call in the destructor. 279 | // 280 | sync(); 281 | delete [] in_buff; 282 | delete [] out_buff; 283 | delete zstrm_p; 284 | } 285 | virtual std::streambuf::int_type overflow(std::streambuf::int_type c = traits_type::eof()) 286 | { 287 | zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(pbase()); 288 | zstrm_p->avail_in = static_cast(pptr() - pbase()); 289 | while (zstrm_p->avail_in > 0) 290 | { 291 | int r = deflate_loop(Z_NO_FLUSH); 292 | if (r != 0) 293 | { 294 | setp(nullptr, nullptr); 295 | return traits_type::eof(); 296 | } 297 | } 298 | setp(in_buff, in_buff + buff_size); 299 | return traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::eof() : sputc(static_cast(c)); 300 | } 301 | virtual int sync() 302 | { 303 | // first, call overflow to clear in_buff 304 | overflow(); 305 | if (! pptr()) return -1; 306 | // then, call deflate asking to finish the zlib stream 307 | zstrm_p->next_in = nullptr; 308 | zstrm_p->avail_in = 0; 309 | if (deflate_loop(Z_FINISH) != 0) return -1; 310 | deflateReset(zstrm_p); 311 | return 0; 312 | } 313 | private: 314 | std::streambuf * sbuf_p; 315 | char * in_buff; 316 | char * out_buff; 317 | detail::z_stream_wrapper * zstrm_p; 318 | std::size_t buff_size; 319 | 320 | }; // class ostreambuf 321 | 322 | class istream 323 | : public std::istream 324 | { 325 | public: 326 | istream(std::istream & is, 327 | std::size_t _buff_size = default_buff_size, bool _auto_detect = true, int _window_bits = 0) 328 | : std::istream(new istreambuf(is.rdbuf(), _buff_size, _auto_detect, _window_bits)) 329 | { 330 | exceptions(std::ios_base::badbit); 331 | } 332 | explicit istream(std::streambuf * sbuf_p) 333 | : std::istream(new istreambuf(sbuf_p)) 334 | { 335 | exceptions(std::ios_base::badbit); 336 | } 337 | virtual ~istream() 338 | { 339 | delete rdbuf(); 340 | } 341 | }; // class istream 342 | 343 | class ostream 344 | : public std::ostream 345 | { 346 | public: 347 | ostream(std::ostream & os, 348 | std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION, int _window_bits = 0) 349 | : std::ostream(new ostreambuf(os.rdbuf(), _buff_size, _level, _window_bits)) 350 | { 351 | exceptions(std::ios_base::badbit); 352 | } 353 | explicit ostream(std::streambuf * sbuf_p) 354 | : std::ostream(new ostreambuf(sbuf_p)) 355 | { 356 | exceptions(std::ios_base::badbit); 357 | } 358 | virtual ~ostream() 359 | { 360 | delete rdbuf(); 361 | } 362 | }; // class ostream 363 | 364 | namespace detail 365 | { 366 | 367 | template < typename FStream_Type > 368 | struct strict_fstream_holder 369 | { 370 | strict_fstream_holder(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in) 371 | : _fs(filename, mode) 372 | {} 373 | FStream_Type _fs; 374 | }; // class strict_fstream_holder 375 | 376 | } // namespace detail 377 | 378 | class ifstream 379 | : private detail::strict_fstream_holder< strict_fstream::ifstream >, 380 | public std::istream 381 | { 382 | public: 383 | explicit ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in) 384 | : detail::strict_fstream_holder< strict_fstream::ifstream >(filename, mode), 385 | std::istream(new istreambuf(_fs.rdbuf())) 386 | { 387 | exceptions(std::ios_base::badbit); 388 | } 389 | virtual ~ifstream() 390 | { 391 | if (rdbuf()) delete rdbuf(); 392 | } 393 | }; // class ifstream 394 | 395 | class ofstream 396 | : private detail::strict_fstream_holder< strict_fstream::ofstream >, 397 | public std::ostream 398 | { 399 | public: 400 | explicit ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out) 401 | : detail::strict_fstream_holder< strict_fstream::ofstream >(filename, mode | std::ios_base::binary), 402 | std::ostream(new ostreambuf(_fs.rdbuf())) 403 | { 404 | exceptions(std::ios_base::badbit); 405 | } 406 | ofstream& flush() { 407 | std::ostream::flush(); 408 | _fs.flush(); 409 | return *this; 410 | } 411 | virtual ~ofstream() 412 | { 413 | if (rdbuf()) delete rdbuf(); 414 | } 415 | }; // class ofstream 416 | 417 | } // namespace zstr 418 | 419 | #endif 420 | -------------------------------------------------------------------------------- /dependencies/zlib/include/zconf.h: -------------------------------------------------------------------------------- 1 | /* zconf.h -- configuration of the zlib compression library 2 | * Copyright (C) 1995-2013 Jean-loup Gailly. 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* @(#) $Id$ */ 7 | 8 | #ifndef ZCONF_H 9 | #define ZCONF_H 10 | 11 | /* 12 | * If you *really* need a unique prefix for all types and library functions, 13 | * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. 14 | * Even better than compiling with -DZ_PREFIX would be to use configure to set 15 | * this permanently in zconf.h using "./configure --zprefix". 16 | */ 17 | #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ 18 | # define Z_PREFIX_SET 19 | 20 | /* all linked symbols */ 21 | # define _dist_code z__dist_code 22 | # define _length_code z__length_code 23 | # define _tr_align z__tr_align 24 | # define _tr_flush_bits z__tr_flush_bits 25 | # define _tr_flush_block z__tr_flush_block 26 | # define _tr_init z__tr_init 27 | # define _tr_stored_block z__tr_stored_block 28 | # define _tr_tally z__tr_tally 29 | # define adler32 z_adler32 30 | # define adler32_combine z_adler32_combine 31 | # define adler32_combine64 z_adler32_combine64 32 | # ifndef Z_SOLO 33 | # define compress z_compress 34 | # define compress2 z_compress2 35 | # define compressBound z_compressBound 36 | # endif 37 | # define crc32 z_crc32 38 | # define crc32_combine z_crc32_combine 39 | # define crc32_combine64 z_crc32_combine64 40 | # define deflate z_deflate 41 | # define deflateBound z_deflateBound 42 | # define deflateCopy z_deflateCopy 43 | # define deflateEnd z_deflateEnd 44 | # define deflateInit2_ z_deflateInit2_ 45 | # define deflateInit_ z_deflateInit_ 46 | # define deflateParams z_deflateParams 47 | # define deflatePending z_deflatePending 48 | # define deflatePrime z_deflatePrime 49 | # define deflateReset z_deflateReset 50 | # define deflateResetKeep z_deflateResetKeep 51 | # define deflateSetDictionary z_deflateSetDictionary 52 | # define deflateSetHeader z_deflateSetHeader 53 | # define deflateTune z_deflateTune 54 | # define deflate_copyright z_deflate_copyright 55 | # define get_crc_table z_get_crc_table 56 | # ifndef Z_SOLO 57 | # define gz_error z_gz_error 58 | # define gz_intmax z_gz_intmax 59 | # define gz_strwinerror z_gz_strwinerror 60 | # define gzbuffer z_gzbuffer 61 | # define gzclearerr z_gzclearerr 62 | # define gzclose z_gzclose 63 | # define gzclose_r z_gzclose_r 64 | # define gzclose_w z_gzclose_w 65 | # define gzdirect z_gzdirect 66 | # define gzdopen z_gzdopen 67 | # define gzeof z_gzeof 68 | # define gzerror z_gzerror 69 | # define gzflush z_gzflush 70 | # define gzgetc z_gzgetc 71 | # define gzgetc_ z_gzgetc_ 72 | # define gzgets z_gzgets 73 | # define gzoffset z_gzoffset 74 | # define gzoffset64 z_gzoffset64 75 | # define gzopen z_gzopen 76 | # define gzopen64 z_gzopen64 77 | # ifdef _WIN32 78 | # define gzopen_w z_gzopen_w 79 | # endif 80 | # define gzprintf z_gzprintf 81 | # define gzvprintf z_gzvprintf 82 | # define gzputc z_gzputc 83 | # define gzputs z_gzputs 84 | # define gzread z_gzread 85 | # define gzrewind z_gzrewind 86 | # define gzseek z_gzseek 87 | # define gzseek64 z_gzseek64 88 | # define gzsetparams z_gzsetparams 89 | # define gztell z_gztell 90 | # define gztell64 z_gztell64 91 | # define gzungetc z_gzungetc 92 | # define gzwrite z_gzwrite 93 | # endif 94 | # define inflate z_inflate 95 | # define inflateBack z_inflateBack 96 | # define inflateBackEnd z_inflateBackEnd 97 | # define inflateBackInit_ z_inflateBackInit_ 98 | # define inflateCopy z_inflateCopy 99 | # define inflateEnd z_inflateEnd 100 | # define inflateGetHeader z_inflateGetHeader 101 | # define inflateInit2_ z_inflateInit2_ 102 | # define inflateInit_ z_inflateInit_ 103 | # define inflateMark z_inflateMark 104 | # define inflatePrime z_inflatePrime 105 | # define inflateReset z_inflateReset 106 | # define inflateReset2 z_inflateReset2 107 | # define inflateSetDictionary z_inflateSetDictionary 108 | # define inflateGetDictionary z_inflateGetDictionary 109 | # define inflateSync z_inflateSync 110 | # define inflateSyncPoint z_inflateSyncPoint 111 | # define inflateUndermine z_inflateUndermine 112 | # define inflateResetKeep z_inflateResetKeep 113 | # define inflate_copyright z_inflate_copyright 114 | # define inflate_fast z_inflate_fast 115 | # define inflate_table z_inflate_table 116 | # ifndef Z_SOLO 117 | # define uncompress z_uncompress 118 | # endif 119 | # define zError z_zError 120 | # ifndef Z_SOLO 121 | # define zcalloc z_zcalloc 122 | # define zcfree z_zcfree 123 | # endif 124 | # define zlibCompileFlags z_zlibCompileFlags 125 | # define zlibVersion z_zlibVersion 126 | 127 | /* all zlib typedefs in zlib.h and zconf.h */ 128 | # define Byte z_Byte 129 | # define Bytef z_Bytef 130 | # define alloc_func z_alloc_func 131 | # define charf z_charf 132 | # define free_func z_free_func 133 | # ifndef Z_SOLO 134 | # define gzFile z_gzFile 135 | # endif 136 | # define gz_header z_gz_header 137 | # define gz_headerp z_gz_headerp 138 | # define in_func z_in_func 139 | # define intf z_intf 140 | # define out_func z_out_func 141 | # define uInt z_uInt 142 | # define uIntf z_uIntf 143 | # define uLong z_uLong 144 | # define uLongf z_uLongf 145 | # define voidp z_voidp 146 | # define voidpc z_voidpc 147 | # define voidpf z_voidpf 148 | 149 | /* all zlib structs in zlib.h and zconf.h */ 150 | # define gz_header_s z_gz_header_s 151 | # define internal_state z_internal_state 152 | 153 | #endif 154 | 155 | #if defined(__MSDOS__) && !defined(MSDOS) 156 | # define MSDOS 157 | #endif 158 | #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) 159 | # define OS2 160 | #endif 161 | #if defined(_WINDOWS) && !defined(WINDOWS) 162 | # define WINDOWS 163 | #endif 164 | #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) 165 | # ifndef WIN32 166 | # define WIN32 167 | # endif 168 | #endif 169 | #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) 170 | # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) 171 | # ifndef SYS16BIT 172 | # define SYS16BIT 173 | # endif 174 | # endif 175 | #endif 176 | 177 | /* 178 | * Compile with -DMAXSEG_64K if the alloc function cannot allocate more 179 | * than 64k bytes at a time (needed on systems with 16-bit int). 180 | */ 181 | #ifdef SYS16BIT 182 | # define MAXSEG_64K 183 | #endif 184 | #ifdef MSDOS 185 | # define UNALIGNED_OK 186 | #endif 187 | 188 | #ifdef __STDC_VERSION__ 189 | # ifndef STDC 190 | # define STDC 191 | # endif 192 | # if __STDC_VERSION__ >= 199901L 193 | # ifndef STDC99 194 | # define STDC99 195 | # endif 196 | # endif 197 | #endif 198 | #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) 199 | # define STDC 200 | #endif 201 | #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) 202 | # define STDC 203 | #endif 204 | #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) 205 | # define STDC 206 | #endif 207 | #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) 208 | # define STDC 209 | #endif 210 | 211 | #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ 212 | # define STDC 213 | #endif 214 | 215 | #ifndef STDC 216 | # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ 217 | # define const /* note: need a more gentle solution here */ 218 | # endif 219 | #endif 220 | 221 | #if defined(ZLIB_CONST) && !defined(z_const) 222 | # define z_const const 223 | #else 224 | # define z_const 225 | #endif 226 | 227 | /* Some Mac compilers merge all .h files incorrectly: */ 228 | #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) 229 | # define NO_DUMMY_DECL 230 | #endif 231 | 232 | /* Maximum value for memLevel in deflateInit2 */ 233 | #ifndef MAX_MEM_LEVEL 234 | # ifdef MAXSEG_64K 235 | # define MAX_MEM_LEVEL 8 236 | # else 237 | # define MAX_MEM_LEVEL 9 238 | # endif 239 | #endif 240 | 241 | /* Maximum value for windowBits in deflateInit2 and inflateInit2. 242 | * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files 243 | * created by gzip. (Files created by minigzip can still be extracted by 244 | * gzip.) 245 | */ 246 | #ifndef MAX_WBITS 247 | # define MAX_WBITS 15 /* 32K LZ77 window */ 248 | #endif 249 | 250 | /* The memory requirements for deflate are (in bytes): 251 | (1 << (windowBits+2)) + (1 << (memLevel+9)) 252 | that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) 253 | plus a few kilobytes for small objects. For example, if you want to reduce 254 | the default memory requirements from 256K to 128K, compile with 255 | make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" 256 | Of course this will generally degrade compression (there's no free lunch). 257 | 258 | The memory requirements for inflate are (in bytes) 1 << windowBits 259 | that is, 32K for windowBits=15 (default value) plus a few kilobytes 260 | for small objects. 261 | */ 262 | 263 | /* Type declarations */ 264 | 265 | #ifndef OF /* function prototypes */ 266 | # ifdef STDC 267 | # define OF(args) args 268 | # else 269 | # define OF(args) () 270 | # endif 271 | #endif 272 | 273 | #ifndef Z_ARG /* function prototypes for stdarg */ 274 | # if defined(STDC) || defined(Z_HAVE_STDARG_H) 275 | # define Z_ARG(args) args 276 | # else 277 | # define Z_ARG(args) () 278 | # endif 279 | #endif 280 | 281 | /* The following definitions for FAR are needed only for MSDOS mixed 282 | * model programming (small or medium model with some far allocations). 283 | * This was tested only with MSC; for other MSDOS compilers you may have 284 | * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, 285 | * just define FAR to be empty. 286 | */ 287 | #ifdef SYS16BIT 288 | # if defined(M_I86SM) || defined(M_I86MM) 289 | /* MSC small or medium model */ 290 | # define SMALL_MEDIUM 291 | # ifdef _MSC_VER 292 | # define FAR _far 293 | # else 294 | # define FAR far 295 | # endif 296 | # endif 297 | # if (defined(__SMALL__) || defined(__MEDIUM__)) 298 | /* Turbo C small or medium model */ 299 | # define SMALL_MEDIUM 300 | # ifdef __BORLANDC__ 301 | # define FAR _far 302 | # else 303 | # define FAR far 304 | # endif 305 | # endif 306 | #endif 307 | 308 | #if defined(WINDOWS) || defined(WIN32) 309 | /* If building or using zlib as a DLL, define ZLIB_DLL. 310 | * This is not mandatory, but it offers a little performance increase. 311 | */ 312 | # ifdef ZLIB_DLL 313 | # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) 314 | # ifdef ZLIB_INTERNAL 315 | # define ZEXTERN extern __declspec(dllexport) 316 | # else 317 | # define ZEXTERN extern __declspec(dllimport) 318 | # endif 319 | # endif 320 | # endif /* ZLIB_DLL */ 321 | /* If building or using zlib with the WINAPI/WINAPIV calling convention, 322 | * define ZLIB_WINAPI. 323 | * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. 324 | */ 325 | # ifdef ZLIB_WINAPI 326 | # ifdef FAR 327 | # undef FAR 328 | # endif 329 | # include 330 | /* No need for _export, use ZLIB.DEF instead. */ 331 | /* For complete Windows compatibility, use WINAPI, not __stdcall. */ 332 | # define ZEXPORT WINAPI 333 | # ifdef WIN32 334 | # define ZEXPORTVA WINAPIV 335 | # else 336 | # define ZEXPORTVA FAR CDECL 337 | # endif 338 | # endif 339 | #endif 340 | 341 | #if defined (__BEOS__) 342 | # ifdef ZLIB_DLL 343 | # ifdef ZLIB_INTERNAL 344 | # define ZEXPORT __declspec(dllexport) 345 | # define ZEXPORTVA __declspec(dllexport) 346 | # else 347 | # define ZEXPORT __declspec(dllimport) 348 | # define ZEXPORTVA __declspec(dllimport) 349 | # endif 350 | # endif 351 | #endif 352 | 353 | #ifndef ZEXTERN 354 | # define ZEXTERN extern 355 | #endif 356 | #ifndef ZEXPORT 357 | # define ZEXPORT 358 | #endif 359 | #ifndef ZEXPORTVA 360 | # define ZEXPORTVA 361 | #endif 362 | 363 | #ifndef FAR 364 | # define FAR 365 | #endif 366 | 367 | #if !defined(__MACTYPES__) 368 | typedef unsigned char Byte; /* 8 bits */ 369 | #endif 370 | typedef unsigned int uInt; /* 16 bits or more */ 371 | typedef unsigned long uLong; /* 32 bits or more */ 372 | 373 | #ifdef SMALL_MEDIUM 374 | /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ 375 | # define Bytef Byte FAR 376 | #else 377 | typedef Byte FAR Bytef; 378 | #endif 379 | typedef char FAR charf; 380 | typedef int FAR intf; 381 | typedef uInt FAR uIntf; 382 | typedef uLong FAR uLongf; 383 | 384 | #ifdef STDC 385 | typedef void const *voidpc; 386 | typedef void FAR *voidpf; 387 | typedef void *voidp; 388 | #else 389 | typedef Byte const *voidpc; 390 | typedef Byte FAR *voidpf; 391 | typedef Byte *voidp; 392 | #endif 393 | 394 | #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) 395 | # include 396 | # if (UINT_MAX == 0xffffffffUL) 397 | # define Z_U4 unsigned 398 | # elif (ULONG_MAX == 0xffffffffUL) 399 | # define Z_U4 unsigned long 400 | # elif (USHRT_MAX == 0xffffffffUL) 401 | # define Z_U4 unsigned short 402 | # endif 403 | #endif 404 | 405 | #ifdef Z_U4 406 | typedef Z_U4 z_crc_t; 407 | #else 408 | typedef unsigned long z_crc_t; 409 | #endif 410 | 411 | #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ 412 | # define Z_HAVE_UNISTD_H 413 | #endif 414 | 415 | #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ 416 | # define Z_HAVE_STDARG_H 417 | #endif 418 | 419 | #ifdef STDC 420 | # ifndef Z_SOLO 421 | # include /* for off_t */ 422 | # endif 423 | #endif 424 | 425 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) 426 | # ifndef Z_SOLO 427 | # include /* for va_list */ 428 | # endif 429 | #endif 430 | 431 | #ifdef _WIN32 432 | # ifndef Z_SOLO 433 | # include /* for wchar_t */ 434 | # endif 435 | #endif 436 | 437 | /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and 438 | * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even 439 | * though the former does not conform to the LFS document), but considering 440 | * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as 441 | * equivalently requesting no 64-bit operations 442 | */ 443 | #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 444 | # undef _LARGEFILE64_SOURCE 445 | #endif 446 | 447 | #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) 448 | # define Z_HAVE_UNISTD_H 449 | #endif 450 | #ifndef Z_SOLO 451 | # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) 452 | # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ 453 | # ifdef VMS 454 | # include /* for off_t */ 455 | # endif 456 | # ifndef z_off_t 457 | # define z_off_t off_t 458 | # endif 459 | # endif 460 | #endif 461 | 462 | #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 463 | # define Z_LFS64 464 | #endif 465 | 466 | #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) 467 | # define Z_LARGE64 468 | #endif 469 | 470 | #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) 471 | # define Z_WANT64 472 | #endif 473 | 474 | #if !defined(SEEK_SET) && !defined(Z_SOLO) 475 | # define SEEK_SET 0 /* Seek from beginning of file. */ 476 | # define SEEK_CUR 1 /* Seek from current position. */ 477 | # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ 478 | #endif 479 | 480 | #ifndef z_off_t 481 | # define z_off_t long 482 | #endif 483 | 484 | #if !defined(_WIN32) && defined(Z_LARGE64) 485 | # define z_off64_t off64_t 486 | #else 487 | # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) 488 | # define z_off64_t __int64 489 | # else 490 | # define z_off64_t z_off_t 491 | # endif 492 | #endif 493 | 494 | /* MVS linker does not support external names larger than 8 bytes */ 495 | #if defined(__MVS__) 496 | #pragma map(deflateInit_,"DEIN") 497 | #pragma map(deflateInit2_,"DEIN2") 498 | #pragma map(deflateEnd,"DEEND") 499 | #pragma map(deflateBound,"DEBND") 500 | #pragma map(inflateInit_,"ININ") 501 | #pragma map(inflateInit2_,"ININ2") 502 | #pragma map(inflateEnd,"INEND") 503 | #pragma map(inflateSync,"INSY") 504 | #pragma map(inflateSetDictionary,"INSEDI") 505 | #pragma map(compressBound,"CMBND") 506 | #pragma map(inflate_table,"INTABL") 507 | #pragma map(inflate_fast,"INFA") 508 | #pragma map(inflate_copyright,"INCOPY") 509 | #endif 510 | 511 | #endif /* ZCONF_H */ 512 | -------------------------------------------------------------------------------- /dependencies/zlib/include/unzip.h: -------------------------------------------------------------------------------- 1 | /* unzip.h -- IO for uncompress .zip files using zlib 2 | Version 1.1, February 14h, 2010 3 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 4 | 5 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 6 | 7 | Modifications of Unzip for Zip64 8 | Copyright (C) 2007-2008 Even Rouault 9 | 10 | Modifications for Zip64 support on both zip and unzip 11 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 12 | 13 | For more info read MiniZip_info.txt 14 | 15 | --------------------------------------------------------------------------------- 16 | 17 | Condition of use and distribution are the same than zlib : 18 | 19 | This software is provided 'as-is', without any express or implied 20 | warranty. In no event will the authors be held liable for any damages 21 | arising from the use of this software. 22 | 23 | Permission is granted to anyone to use this software for any purpose, 24 | including commercial applications, and to alter it and redistribute it 25 | freely, subject to the following restrictions: 26 | 27 | 1. The origin of this software must not be misrepresented; you must not 28 | claim that you wrote the original software. If you use this software 29 | in a product, an acknowledgment in the product documentation would be 30 | appreciated but is not required. 31 | 2. Altered source versions must be plainly marked as such, and must not be 32 | misrepresented as being the original software. 33 | 3. This notice may not be removed or altered from any source distribution. 34 | 35 | --------------------------------------------------------------------------------- 36 | 37 | Changes 38 | 39 | See header of unzip64.c 40 | 41 | */ 42 | 43 | #ifndef _unz64_H 44 | #define _unz64_H 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | #ifndef _ZLIB_H 51 | #include "zlib.h" 52 | #endif 53 | 54 | #ifndef _ZLIBIOAPI_H 55 | #include "ioapi.h" 56 | #endif 57 | 58 | #ifdef HAVE_BZIP2 59 | #include "bzlib.h" 60 | #endif 61 | 62 | #define Z_BZIP2ED 12 63 | 64 | #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) 65 | /* like the STRICT of WIN32, we define a pointer that cannot be converted 66 | from (void*) without cast */ 67 | typedef struct TagunzFile__ { int unused; } unzFile__; 68 | typedef unzFile__ *unzFile; 69 | #else 70 | typedef voidp unzFile; 71 | #endif 72 | 73 | 74 | #define UNZ_OK (0) 75 | #define UNZ_END_OF_LIST_OF_FILE (-100) 76 | #define UNZ_ERRNO (Z_ERRNO) 77 | #define UNZ_EOF (0) 78 | #define UNZ_PARAMERROR (-102) 79 | #define UNZ_BADZIPFILE (-103) 80 | #define UNZ_INTERNALERROR (-104) 81 | #define UNZ_CRCERROR (-105) 82 | 83 | /* tm_unz contain date/time info */ 84 | typedef struct tm_unz_s 85 | { 86 | uInt tm_sec; /* seconds after the minute - [0,59] */ 87 | uInt tm_min; /* minutes after the hour - [0,59] */ 88 | uInt tm_hour; /* hours since midnight - [0,23] */ 89 | uInt tm_mday; /* day of the month - [1,31] */ 90 | uInt tm_mon; /* months since January - [0,11] */ 91 | uInt tm_year; /* years - [1980..2044] */ 92 | } tm_unz; 93 | 94 | /* unz_global_info structure contain global data about the ZIPfile 95 | These data comes from the end of central dir */ 96 | typedef struct unz_global_info64_s 97 | { 98 | ZPOS64_T number_entry; /* total number of entries in 99 | the central dir on this disk */ 100 | uLong size_comment; /* size of the global comment of the zipfile */ 101 | } unz_global_info64; 102 | 103 | typedef struct unz_global_info_s 104 | { 105 | uLong number_entry; /* total number of entries in 106 | the central dir on this disk */ 107 | uLong size_comment; /* size of the global comment of the zipfile */ 108 | } unz_global_info; 109 | 110 | /* unz_file_info contain information about a file in the zipfile */ 111 | typedef struct unz_file_info64_s 112 | { 113 | uLong version; /* version made by 2 bytes */ 114 | uLong version_needed; /* version needed to extract 2 bytes */ 115 | uLong flag; /* general purpose bit flag 2 bytes */ 116 | uLong compression_method; /* compression method 2 bytes */ 117 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ 118 | uLong crc; /* crc-32 4 bytes */ 119 | ZPOS64_T compressed_size; /* compressed size 8 bytes */ 120 | ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ 121 | uLong size_filename; /* filename length 2 bytes */ 122 | uLong size_file_extra; /* extra field length 2 bytes */ 123 | uLong size_file_comment; /* file comment length 2 bytes */ 124 | 125 | uLong disk_num_start; /* disk number start 2 bytes */ 126 | uLong internal_fa; /* internal file attributes 2 bytes */ 127 | uLong external_fa; /* external file attributes 4 bytes */ 128 | 129 | tm_unz tmu_date; 130 | } unz_file_info64; 131 | 132 | typedef struct unz_file_info_s 133 | { 134 | uLong version; /* version made by 2 bytes */ 135 | uLong version_needed; /* version needed to extract 2 bytes */ 136 | uLong flag; /* general purpose bit flag 2 bytes */ 137 | uLong compression_method; /* compression method 2 bytes */ 138 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ 139 | uLong crc; /* crc-32 4 bytes */ 140 | uLong compressed_size; /* compressed size 4 bytes */ 141 | uLong uncompressed_size; /* uncompressed size 4 bytes */ 142 | uLong size_filename; /* filename length 2 bytes */ 143 | uLong size_file_extra; /* extra field length 2 bytes */ 144 | uLong size_file_comment; /* file comment length 2 bytes */ 145 | 146 | uLong disk_num_start; /* disk number start 2 bytes */ 147 | uLong internal_fa; /* internal file attributes 2 bytes */ 148 | uLong external_fa; /* external file attributes 4 bytes */ 149 | 150 | tm_unz tmu_date; 151 | } unz_file_info; 152 | 153 | extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, 154 | const char* fileName2, 155 | int iCaseSensitivity)); 156 | /* 157 | Compare two filename (fileName1,fileName2). 158 | If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) 159 | If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi 160 | or strcasecmp) 161 | If iCaseSenisivity = 0, case sensitivity is defaut of your operating system 162 | (like 1 on Unix, 2 on Windows) 163 | */ 164 | 165 | 166 | extern unzFile ZEXPORT unzOpen OF((const char *path)); 167 | extern unzFile ZEXPORT unzOpen64 OF((const void *path)); 168 | /* 169 | Open a Zip file. path contain the full pathname (by example, 170 | on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer 171 | "zlib/zlib113.zip". 172 | If the zipfile cannot be opened (file don't exist or in not valid), the 173 | return value is NULL. 174 | Else, the return value is a unzFile Handle, usable with other function 175 | of this unzip package. 176 | the "64" function take a const void* pointer, because the path is just the 177 | value passed to the open64_file_func callback. 178 | Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path 179 | is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* 180 | does not describe the reality 181 | */ 182 | 183 | 184 | extern unzFile ZEXPORT unzOpen2 OF((const char *path, 185 | zlib_filefunc_def* pzlib_filefunc_def)); 186 | /* 187 | Open a Zip file, like unzOpen, but provide a set of file low level API 188 | for read/write the zip file (see ioapi.h) 189 | */ 190 | 191 | extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, 192 | zlib_filefunc64_def* pzlib_filefunc_def)); 193 | /* 194 | Open a Zip file, like unz64Open, but provide a set of file low level API 195 | for read/write the zip file (see ioapi.h) 196 | */ 197 | 198 | extern int ZEXPORT unzClose OF((unzFile file)); 199 | /* 200 | Close a ZipFile opened with unzOpen. 201 | If there is files inside the .Zip opened with unzOpenCurrentFile (see later), 202 | these files MUST be closed with unzCloseCurrentFile before call unzClose. 203 | return UNZ_OK if there is no problem. */ 204 | 205 | extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, 206 | unz_global_info *pglobal_info)); 207 | 208 | extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, 209 | unz_global_info64 *pglobal_info)); 210 | /* 211 | Write info about the ZipFile in the *pglobal_info structure. 212 | No preparation of the structure is needed 213 | return UNZ_OK if there is no problem. */ 214 | 215 | 216 | extern int ZEXPORT unzGetGlobalComment OF((unzFile file, 217 | char *szComment, 218 | uLong uSizeBuf)); 219 | /* 220 | Get the global comment string of the ZipFile, in the szComment buffer. 221 | uSizeBuf is the size of the szComment buffer. 222 | return the number of byte copied or an error code <0 223 | */ 224 | 225 | 226 | /***************************************************************************/ 227 | /* Unzip package allow you browse the directory of the zipfile */ 228 | 229 | extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); 230 | /* 231 | Set the current file of the zipfile to the first file. 232 | return UNZ_OK if there is no problem 233 | */ 234 | 235 | extern int ZEXPORT unzGoToNextFile OF((unzFile file)); 236 | /* 237 | Set the current file of the zipfile to the next file. 238 | return UNZ_OK if there is no problem 239 | return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. 240 | */ 241 | 242 | extern int ZEXPORT unzLocateFile OF((unzFile file, 243 | const char *szFileName, 244 | int iCaseSensitivity)); 245 | /* 246 | Try locate the file szFileName in the zipfile. 247 | For the iCaseSensitivity signification, see unzStringFileNameCompare 248 | 249 | return value : 250 | UNZ_OK if the file is found. It becomes the current file. 251 | UNZ_END_OF_LIST_OF_FILE if the file is not found 252 | */ 253 | 254 | 255 | /* ****************************************** */ 256 | /* Ryan supplied functions */ 257 | /* unz_file_info contain information about a file in the zipfile */ 258 | typedef struct unz_file_pos_s 259 | { 260 | uLong pos_in_zip_directory; /* offset in zip file directory */ 261 | uLong num_of_file; /* # of file */ 262 | } unz_file_pos; 263 | 264 | extern int ZEXPORT unzGetFilePos( 265 | unzFile file, 266 | unz_file_pos* file_pos); 267 | 268 | extern int ZEXPORT unzGoToFilePos( 269 | unzFile file, 270 | unz_file_pos* file_pos); 271 | 272 | typedef struct unz64_file_pos_s 273 | { 274 | ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ 275 | ZPOS64_T num_of_file; /* # of file */ 276 | } unz64_file_pos; 277 | 278 | extern int ZEXPORT unzGetFilePos64( 279 | unzFile file, 280 | unz64_file_pos* file_pos); 281 | 282 | extern int ZEXPORT unzGoToFilePos64( 283 | unzFile file, 284 | const unz64_file_pos* file_pos); 285 | 286 | /* ****************************************** */ 287 | 288 | extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, 289 | unz_file_info64 *pfile_info, 290 | char *szFileName, 291 | uLong fileNameBufferSize, 292 | void *extraField, 293 | uLong extraFieldBufferSize, 294 | char *szComment, 295 | uLong commentBufferSize)); 296 | 297 | extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, 298 | unz_file_info *pfile_info, 299 | char *szFileName, 300 | uLong fileNameBufferSize, 301 | void *extraField, 302 | uLong extraFieldBufferSize, 303 | char *szComment, 304 | uLong commentBufferSize)); 305 | /* 306 | Get Info about the current file 307 | if pfile_info!=NULL, the *pfile_info structure will contain somes info about 308 | the current file 309 | if szFileName!=NULL, the filemane string will be copied in szFileName 310 | (fileNameBufferSize is the size of the buffer) 311 | if extraField!=NULL, the extra field information will be copied in extraField 312 | (extraFieldBufferSize is the size of the buffer). 313 | This is the Central-header version of the extra field 314 | if szComment!=NULL, the comment string of the file will be copied in szComment 315 | (commentBufferSize is the size of the buffer) 316 | */ 317 | 318 | 319 | /** Addition for GDAL : START */ 320 | 321 | extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); 322 | 323 | /** Addition for GDAL : END */ 324 | 325 | 326 | /***************************************************************************/ 327 | /* for reading the content of the current zipfile, you can open it, read data 328 | from it, and close it (you can close it before reading all the file) 329 | */ 330 | 331 | extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); 332 | /* 333 | Open for reading data the current file in the zipfile. 334 | If there is no error, the return value is UNZ_OK. 335 | */ 336 | 337 | extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, 338 | const char* password)); 339 | /* 340 | Open for reading data the current file in the zipfile. 341 | password is a crypting password 342 | If there is no error, the return value is UNZ_OK. 343 | */ 344 | 345 | extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, 346 | int* method, 347 | int* level, 348 | int raw)); 349 | /* 350 | Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) 351 | if raw==1 352 | *method will receive method of compression, *level will receive level of 353 | compression 354 | note : you can set level parameter as NULL (if you did not want known level, 355 | but you CANNOT set method parameter as NULL 356 | */ 357 | 358 | extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, 359 | int* method, 360 | int* level, 361 | int raw, 362 | const char* password)); 363 | /* 364 | Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) 365 | if raw==1 366 | *method will receive method of compression, *level will receive level of 367 | compression 368 | note : you can set level parameter as NULL (if you did not want known level, 369 | but you CANNOT set method parameter as NULL 370 | */ 371 | 372 | 373 | extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); 374 | /* 375 | Close the file in zip opened with unzOpenCurrentFile 376 | Return UNZ_CRCERROR if all the file was read but the CRC is not good 377 | */ 378 | 379 | extern int ZEXPORT unzReadCurrentFile OF((unzFile file, 380 | voidp buf, 381 | unsigned len)); 382 | /* 383 | Read bytes from the current file (opened by unzOpenCurrentFile) 384 | buf contain buffer where data must be copied 385 | len the size of buf. 386 | 387 | return the number of byte copied if somes bytes are copied 388 | return 0 if the end of file was reached 389 | return <0 with error code if there is an error 390 | (UNZ_ERRNO for IO error, or zLib error for uncompress error) 391 | */ 392 | 393 | extern z_off_t ZEXPORT unztell OF((unzFile file)); 394 | 395 | extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); 396 | /* 397 | Give the current position in uncompressed data 398 | */ 399 | 400 | extern int ZEXPORT unzeof OF((unzFile file)); 401 | /* 402 | return 1 if the end of file was reached, 0 elsewhere 403 | */ 404 | 405 | extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, 406 | voidp buf, 407 | unsigned len)); 408 | /* 409 | Read extra field from the current file (opened by unzOpenCurrentFile) 410 | This is the local-header version of the extra field (sometimes, there is 411 | more info in the local-header version than in the central-header) 412 | 413 | if buf==NULL, it return the size of the local extra field 414 | 415 | if buf!=NULL, len is the size of the buffer, the extra header is copied in 416 | buf. 417 | the return value is the number of bytes copied in buf, or (if <0) 418 | the error code 419 | */ 420 | 421 | /***************************************************************************/ 422 | 423 | /* Get the current file offset */ 424 | extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); 425 | extern uLong ZEXPORT unzGetOffset (unzFile file); 426 | 427 | /* Set the current file offset */ 428 | extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); 429 | extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); 430 | 431 | 432 | 433 | #ifdef __cplusplus 434 | } 435 | #endif 436 | 437 | #endif /* _unz64_H */ 438 | --------------------------------------------------------------------------------