├── waf ├── VERSION ├── .dir-locals.el ├── COPYING.THIRD_PARTY ├── src ├── endian.cpp ├── programs │ ├── icon.ico │ ├── icon.png │ ├── launcher.rc │ ├── stcm-editor.rc │ └── launcher.c ├── windows_server │ ├── server.def │ ├── server.rc │ ├── hook.hpp │ ├── hook.cpp │ └── cpk.hpp ├── vita_plugin │ ├── plugin.yml │ ├── cpk.hpp │ ├── taihen_cpp.hpp │ └── plugin.cpp ├── version.hpp.in ├── format │ ├── eof_item.cpp │ ├── eof_item.hpp │ ├── eof_item.binding.hpp │ ├── stcm │ │ ├── string_data.hpp │ │ ├── file.binding.hpp │ │ ├── file.hpp │ │ ├── gbnl.cpp │ │ ├── string_data.binding.hpp │ │ ├── data.hpp │ │ ├── expansion.hpp │ │ ├── gbnl.binding.hpp │ │ ├── file.cpp │ │ ├── data.binding.hpp │ │ ├── header.hpp │ │ ├── gbnl.hpp │ │ ├── data.cpp │ │ ├── string_data.cpp │ │ ├── expansion.cpp │ │ ├── exports.hpp │ │ ├── expansion.binding.hpp │ │ ├── exports.cpp │ │ ├── header.binding.hpp │ │ ├── header.cpp │ │ ├── collection_link.hpp │ │ ├── collection_link.binding.hpp │ │ ├── exports.binding.hpp │ │ └── collection_link.cpp │ ├── primitive_item.cpp │ ├── cstring_item.hpp │ ├── cstring_item.cpp │ ├── stsc │ │ ├── file.hpp │ │ ├── file.binding.hpp │ │ ├── header.hpp │ │ ├── file.cpp │ │ ├── header.cpp │ │ └── header.binding.hpp │ ├── raw_item.binding.hpp │ ├── cstring_item.binding.hpp │ ├── raw_item.cpp │ ├── primitive_item.hpp │ ├── context.binding.hpp │ ├── context.hpp │ ├── builder.lua │ ├── gbnl_lua.hpp │ ├── raw_item.hpp │ ├── item_base.hpp │ ├── primitive_item.binding.hpp │ ├── gbnl.hpp │ └── context.cpp ├── txt_serializable.cpp ├── factory.hpp ├── endian.binding.hpp ├── open.cpp ├── pattern.hpp ├── utils.hpp ├── open.binding.hpp ├── txt_serializable.binding.hpp ├── txt_serializable.hpp ├── open.hpp ├── utils.cpp ├── dumpable.binding.hpp ├── endian.hpp ├── dumpable.hpp ├── pattern.cpp ├── dumpable.cpp ├── sink.binding.hpp ├── sink.hpp └── pattern_parse.hpp ├── .gitmodules ├── test └── pattern_fail.cpp ├── .gitignore ├── tools ├── ci_conf.gcc.sh ├── ci_conf_wincommon.sh ├── qemu_vdso_fix_linux_amd64.c ├── ci_conf.clang-msvc64.sh ├── ci_conf.clang-msvc.sh ├── ci_conf_linuxcommon.sh ├── ci_conf.default.sh ├── valgrind.supp ├── ci_conf.clang.sh ├── ci.sh ├── vmrun.sh ├── README.md ├── qmp └── qemu.patch ├── COPYING ├── gen_binding.sh ├── .clang-tidy ├── doc └── formats │ ├── gbin.md │ └── cl3.md └── wscript /waf: -------------------------------------------------------------------------------- 1 | libshit/waf -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.4.0-pre 2 | -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | libshit/.dir-locals.el -------------------------------------------------------------------------------- /COPYING.THIRD_PARTY: -------------------------------------------------------------------------------- 1 | libshit/COPYING.THIRD_PARTY -------------------------------------------------------------------------------- /src/endian.cpp: -------------------------------------------------------------------------------- 1 | #include "endian.hpp" 2 | #include "endian.binding.hpp" 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libshit"] 2 | path = libshit 3 | url = ../libshit.git 4 | -------------------------------------------------------------------------------- /src/programs/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/u3shit/neptools/HEAD/src/programs/icon.ico -------------------------------------------------------------------------------- /src/programs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/u3shit/neptools/HEAD/src/programs/icon.png -------------------------------------------------------------------------------- /src/windows_server/server.def: -------------------------------------------------------------------------------- 1 | LIBRARY neptools-server 2 | EXPORTS 3 | DirectInput8Create=_DirectInput8Create@20 4 | -------------------------------------------------------------------------------- /test/pattern_fail.cpp: -------------------------------------------------------------------------------- 1 | #include "pattern_parse.hpp" 2 | 3 | using namespace Neptools; 4 | auto x = NEPTOOLS_PATTERN(TEST_PATTERN); 5 | -------------------------------------------------------------------------------- /src/vita_plugin/plugin.yml: -------------------------------------------------------------------------------- 1 | neptools: 2 | attributes: 0 3 | version: 4 | major: 0 5 | minor: 0 6 | main: 7 | start: module_start 8 | #stop: module_stop 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#*# 3 | .#* 4 | 5 | build 6 | .lock-waf_* 7 | .waf* 8 | 9 | compile_commands.json 10 | .clang_complete 11 | wscript_user.py 12 | 13 | pkg/ 14 | 15 | tools/*.so 16 | 17 | *.pyc 18 | -------------------------------------------------------------------------------- /src/version.hpp.in: -------------------------------------------------------------------------------- 1 | #ifndef UUID_9B678665_38D4_4683_8E87_6EA045BA7585 2 | #define UUID_9B678665_38D4_4683_8E87_6EA045BA7585 3 | #pragma once 4 | 5 | #define NEPTOOLS_VERSION "@VERSION@" 6 | #define NEPTOOLS_RC_VERSION @RC_VERSION@ 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/format/eof_item.cpp: -------------------------------------------------------------------------------- 1 | #include "eof_item.hpp" 2 | #include "context.hpp" 3 | 4 | namespace Neptools 5 | { 6 | 7 | void EofItem::Inspect_(std::ostream& os, unsigned indent) const 8 | { 9 | Item::Inspect_(os, indent); 10 | os << "eof()"; 11 | } 12 | 13 | } 14 | 15 | #include "eof_item.binding.hpp" 16 | -------------------------------------------------------------------------------- /src/vita_plugin/cpk.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_ACERBLY_PYROBORIC_HUSS_SMOFS_2629 2 | #define GUARD_ACERBLY_PYROBORIC_HUSS_SMOFS_2629 3 | #pragma once 4 | 5 | #include 6 | 7 | namespace Neptools::VitaPlugin 8 | { 9 | 10 | void Init(std::string data_path_in, std::string cache_path_in); 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /tools/ci_conf.gcc.sh: -------------------------------------------------------------------------------- 1 | source tools/ci_conf_linuxcommon.sh 2 | 3 | opt="-march=x86-64 -mtune=generic" 4 | 5 | run export CC="$(cd /usr/bin; ls gcc-*.*.* | tail -n1)" 6 | run export CXX="$(cd /usr/bin; ls g++-*.*.* | tail -n1)" 7 | run export AR=gcc-ar 8 | run export CFLAGS="$opt" 9 | run export CXXFLAGS="$opt" 10 | run export LINKFLAGS="$opt -static-libstdc++" 11 | 12 | run $CC --version 13 | -------------------------------------------------------------------------------- /src/txt_serializable.cpp: -------------------------------------------------------------------------------- 1 | #include "txt_serializable.hpp" 2 | 3 | #include 4 | 5 | namespace Neptools 6 | { 7 | 8 | LIBSHIT_LUAGEN() 9 | static std::string WriteTxt(TxtSerializable& ser) 10 | { 11 | std::stringstream ss; 12 | ser.WriteTxt(ss); 13 | return ss.str(); 14 | } 15 | 16 | LIBSHIT_LUAGEN() 17 | static void ReadTxt(TxtSerializable& ser, const std::string& str) 18 | { 19 | std::stringstream ss{str}; 20 | ser.ReadTxt(ss); 21 | } 22 | 23 | } 24 | 25 | #include "txt_serializable.binding.hpp" 26 | -------------------------------------------------------------------------------- /tools/ci_conf_wincommon.sh: -------------------------------------------------------------------------------- 1 | run clang --version 2 | 3 | run export HOST_CC=gcc 4 | run export HOST_CXX=g++ 5 | run export HOST_CFLAGS= 6 | run export HOST_CXXFLAGS= 7 | run export HOST_LINKFLAGS= 8 | run export AR=llvm-ar 9 | run export CC=clang 10 | run export CXX=clang++ 11 | config_opts=(--lua-dll) 12 | 13 | tests=( 14 | 'wine build/stcm-editor.exe --ansi-colors --xml-output=test-wine.xml --test -fc --reporters=libshit-junit,console' 15 | 'tools/vmrun.sh /opt/win7-vm/vm.opts test-win7.xml build/stcm-editor.exe build/lua53.dll' 16 | ) 17 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /src/factory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_F3B9AB07_80DA_4DCF_AA4F_F6E225EFA110 2 | #define UUID_F3B9AB07_80DA_4DCF_AA4F_F6E225EFA110 3 | #pragma once 4 | 5 | #include 6 | 7 | namespace Neptools 8 | { 9 | 10 | template 11 | class BaseFactory 12 | { 13 | public: 14 | using Fun = FunT; 15 | BaseFactory(Fun f) { GetStore().push_back(f); } 16 | 17 | protected: 18 | using Store = std::vector; 19 | static Store& GetStore() 20 | { 21 | static Store store; 22 | return store; 23 | } 24 | }; 25 | 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /src/format/eof_item.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_2E2EE447_59EF_4611_B8B5_40180CC6FBCC 2 | #define UUID_2E2EE447_59EF_4611_B8B5_40180CC6FBCC 3 | #pragma once 4 | 5 | #include "item.hpp" 6 | 7 | namespace Neptools 8 | { 9 | 10 | class EofItem final : public Item 11 | { 12 | LIBSHIT_DYNAMIC_OBJECT; 13 | public: 14 | EofItem(Key k, Context& ctx) : Item{k, ctx} {} 15 | 16 | void Dump_(Sink&) const override {} 17 | void Inspect_(std::ostream& os, unsigned indent) const override; 18 | FilePosition GetSize() const noexcept override { return 0; } 19 | }; 20 | 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /tools/qemu_vdso_fix_linux_amd64.c: -------------------------------------------------------------------------------- 1 | /* Workaround qemu-x86_64 not supporting either of vdso/vsyscall and old glibc 2 | * versions unconditionally using vsyscall when vdso is not available (no 3 | * syscall fallback). */ 4 | 5 | /* Compile: 6 | * clang -O2 -shared -o tools/qemu_vdso_fix_linux_amd64.so tools/qemu_vdso_fix_linux_amd64.c 7 | */ 8 | 9 | #ifndef _GNU_SOURCE 10 | #define _GNU_SOURCE 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | int gettimeofday(struct timeval* tv, struct timezone* tz) 18 | { 19 | return syscall(SYS_gettimeofday, tv, tz); 20 | } 21 | -------------------------------------------------------------------------------- /src/endian.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | const char ::Libshit::Lua::TypeName<::Neptools::Endian>::TYPE_NAME[] = 6 | "neptools.endian"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.endian 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Endian>::Register(TypeBuilder& bld) 14 | { 15 | 16 | bld.Add("BIG", ::Neptools::Endian::BIG); 17 | bld.Add("LITTLE", ::Neptools::Endian::LITTLE); 18 | 19 | } 20 | static TypeRegister::StateRegister<::Neptools::Endian> reg_neptools_endian; 21 | 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /gen_binding.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cd "$(dirname "${BASH_SOURCE[0]}")" 4 | 5 | src=(src/dumpable src/endian src/open src/sink src/source src/txt_serializable 6 | src/format/cl3 src/format/context src/format/cstring_item 7 | src/format/eof_item src/format/gbnl src/format/item 8 | src/format/primitive_item src/format/raw_item 9 | src/format/stcm/collection_link src/format/stcm/data 10 | src/format/stcm/exports src/format/stcm/file src/format/stcm/gbnl 11 | src/format/stcm/header src/format/stcm/instruction 12 | src/format/stcm/string_data 13 | src/format/stsc/file src/format/stsc/header src/format/stsc/instruction) 14 | 15 | . libshit/gen_binding.sh 16 | -------------------------------------------------------------------------------- /src/open.cpp: -------------------------------------------------------------------------------- 1 | #include "open.hpp" 2 | 3 | #include 4 | 5 | namespace Neptools 6 | { 7 | 8 | auto OpenFactory::Open(Source src) -> Libshit::NotNull 9 | { 10 | for (auto& x : GetStore()) 11 | { 12 | auto ret = x(src); 13 | if (ret) return MakeNotNull(ret); 14 | } 15 | LIBSHIT_THROW(Libshit::DecodeError, "Unknown input file"); 16 | } 17 | 18 | auto OpenFactory::Open(const boost::filesystem::path& fname) 19 | -> Libshit::NotNull 20 | { 21 | LIBSHIT_ADD_INFOS( 22 | return Open(Source::FromFile(fname.native())), 23 | "File name", fname.string()); 24 | } 25 | 26 | } 27 | 28 | #include "open.binding.hpp" 29 | -------------------------------------------------------------------------------- /tools/ci_conf.clang-msvc64.sh: -------------------------------------------------------------------------------- 1 | source tools/ci_conf_wincommon.sh 2 | 3 | run export CFLAGS="-target x86_64-pc-windows-msvc18 -march=x86-64 \ 4 | -fms-compatibility-version=18 \ 5 | -Xclang -internal-isystem -Xclang /mnt/msvc/vc12/include 6 | -Xclang -internal-isystem -Xclang /mnt/msvc/vc12/win_sdk/include/um 7 | -Xclang -internal-isystem -Xclang /mnt/msvc/vc12/win_sdk/include/shared" 8 | run export CXXFLAGS="$CFLAGS -DDOCTEST_CONFIG_COLORS_ANSI" 9 | run export LINKFLAGS="-target x86_64-pc-windows-msvc18 -march=x86-64 \ 10 | -fuse-ld=lld \ 11 | -L/mnt/msvc/vc12/lib/amd64 \ 12 | -L/mnt/msvc/vc12/win_sdk/lib/winv6.3/um/x64" 13 | run export WINRC=x86_64-w64-mingw32-windres 14 | -------------------------------------------------------------------------------- /src/pattern.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_741BE2A9_1F86_4DD5_A032_0D7D5CCBA762 2 | #define UUID_741BE2A9_1F86_4DD5_A032_0D7D5CCBA762 3 | #pragma once 4 | 5 | #include "utils.hpp" 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace Neptools 12 | { 13 | 14 | struct Pattern 15 | { 16 | const Byte* pattern; 17 | const Byte* mask; 18 | size_t size; 19 | 20 | const Byte* MaybeFind(std::string_view data) const noexcept; 21 | 22 | const Byte* Find(std::string_view data) const 23 | { 24 | auto ret = MaybeFind(data); 25 | if (!ret) LIBSHIT_THROW(std::runtime_error, "Couldn't find pattern"); 26 | return ret; 27 | } 28 | }; 29 | 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /tools/ci_conf.clang-msvc.sh: -------------------------------------------------------------------------------- 1 | source tools/ci_conf_wincommon.sh 2 | 3 | run export CFLAGS="-target i386-pc-windows-msvc18-m32 -march=x86-64 \ 4 | -fms-compatibility-version=18 \ 5 | -Xclang -internal-isystem -Xclang /mnt/msvc/vc12/include \ 6 | -Xclang -internal-isystem -Xclang /mnt/msvc/vc12/win_sdk/include/um \ 7 | -Xclang -internal-isystem -Xclang /mnt/msvc/vc12/win_sdk/include/shared" 8 | run export CXXFLAGS="$CFLAGS -DDOCTEST_CONFIG_COLORS_ANSI" 9 | run export LINKFLAGS="-target i386-pc-windows-msvc18-m32 -march=x86-64\ 10 | -fuse-ld=lld \ 11 | -L/mnt/msvc/vc12/lib \ 12 | -L/mnt/msvc/vc12/win_sdk/lib/winv6.3/um/x86" 13 | run export WINRC=x86_64-w64-mingw32-windres 14 | run export WINRCFLAGS='-F pe-i386' 15 | -------------------------------------------------------------------------------- /src/windows_server/server.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "version.hpp" 3 | 4 | 1 VERSIONINFO 5 | FILEVERSION NEPTOOLS_RC_VERSION 6 | PRODUCTVERSION NEPTOOLS_RC_VERSION 7 | FILEOS VOS_NT_WINDOWS32 8 | FILETYPE VFT_DLL 9 | { 10 | BLOCK "StringFileInfo" 11 | { 12 | BLOCK "040904E4" 13 | { 14 | VALUE "ProductName", "neptools server" 15 | VALUE "ProductVersion", NEPTOOLS_VERSION 16 | VALUE "FileDescription", "NepTools server" 17 | VALUE "FileVersion", NEPTOOLS_VERSION 18 | VALUE "InternalName", "neptools-server" 19 | VALUE "OriginalFileName", "neptools-server.dll" 20 | } 21 | } 22 | BLOCK "VarFileInfo" 23 | { 24 | VALUE "Translation", 0x409, 1200 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/format/eof_item.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::EofItem::TYPE_NAME[] = "neptools.eof_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.eof_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::EofItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::EofItem, ::Neptools::Item>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::EofItem>::Make, LuaGetRef<::Neptools::Context &>> 19 | >("new"); 20 | 21 | } 22 | static TypeRegister::StateRegister<::Neptools::EofItem> reg_neptools_eof_item; 23 | 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /tools/ci_conf_linuxcommon.sh: -------------------------------------------------------------------------------- 1 | function do_strip() 2 | { 3 | local f="$1" 4 | run objcopy --only-keep-debug "$f" "$f.debug" 5 | run chmod -x "$f.debug" 6 | run strip --strip-unneeded -R .comment -R .GCC.command.line -R .gnu_debuglink "$f" 7 | run objcopy --add-gnu-debuglink="$f.debug" "$f" 8 | } 9 | 10 | function after_build() 11 | { 12 | for f in stcm-editor libshit/ext/luajit-ljx; do 13 | [[ -f "build/$f" ]] && do_strip "build/$f" 14 | done 15 | } 16 | 17 | function join() 18 | { 19 | local IFS=$1 20 | shift 21 | echo "$*" 22 | } 23 | 24 | valgrind="valgrind --suppressions=tools/valgrind.supp --leak-check=full \ 25 | --track-origins=yes --show-leak-kinds=all --xml=yes \ 26 | --xml-file=valgrind.xml build/stcm-editor --test" 27 | 28 | tests=( 29 | "${tests[@]}" 30 | "$valgrind" 31 | ) 32 | -------------------------------------------------------------------------------- /src/format/stcm/string_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_5AE4EF4E_E8EB_4A3D_90A7_58FA73AF7B71 2 | #define UUID_5AE4EF4E_E8EB_4A3D_90A7_58FA73AF7B71 3 | #pragma once 4 | 5 | #include "../item.hpp" 6 | 7 | namespace Neptools::Stcm 8 | { 9 | class DataItem; 10 | 11 | class StringDataItem final : public Item 12 | { 13 | LIBSHIT_DYNAMIC_OBJECT; 14 | public: 15 | StringDataItem(Key k, Context& ctx, std::string str) 16 | : Item{k, ctx}, string{std::move(str)} {} 17 | 18 | static Libshit::RefCountedPtr 19 | MaybeCreateAndReplace(DataItem& it); 20 | 21 | FilePosition GetSize() const noexcept override; 22 | 23 | std::string string; 24 | 25 | private: 26 | void Dump_(Sink& sink) const override; 27 | void Inspect_(std::ostream& os, unsigned indent) const override; 28 | }; 29 | 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_9AE0723F_DD0B_434B_8880_D7981FAF1F20 2 | #define UUID_9AE0723F_DD0B_434B_8880_D7981FAF1F20 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace Neptools 12 | { 13 | class Source; // fwd 14 | 15 | using Byte = unsigned char; 16 | 17 | using FilePosition = std::uint64_t; 18 | using FileMemSize = std::size_t; 19 | 20 | static constexpr const std::size_t MEM_CHUNK = 8*1024; // 8KiB 21 | static constexpr const std::size_t MMAP_CHUNK = 128*1024; // 128KiB 22 | static constexpr const std::size_t MMAP_LIMIT = 1*1024*1024; // 1MiB 23 | 24 | std::ofstream OpenOut(const boost::filesystem::path& pth); 25 | std::ifstream OpenIn(const boost::filesystem::path& pth); 26 | 27 | void DumpBytes(std::ostream& os, Source data); 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /src/open.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::OpenFactory::TYPE_NAME[] = "neptools.open_factory"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.open_factory 12 | template<> 13 | void TypeRegisterTraits<::Neptools::OpenFactory>::Register(TypeBuilder& bld) 14 | { 15 | 16 | bld.AddFunction< 17 | static_cast<::Libshit::NotNull<::Neptools::OpenFactory::Ret> (*)(::Neptools::Source)>(::Neptools::OpenFactory::Open), 18 | static_cast<::Libshit::NotNull<::Neptools::OpenFactory::Ret> (*)(const ::boost::filesystem::path &)>(::Neptools::OpenFactory::Open) 19 | >("open"); 20 | 21 | } 22 | static TypeRegister::StateRegister<::Neptools::OpenFactory> reg_neptools_open_factory; 23 | 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /src/txt_serializable.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::TxtSerializable::TYPE_NAME[] = "neptools.txt_serializable"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.txt_serializable 12 | template<> 13 | void TypeRegisterTraits<::Neptools::TxtSerializable>::Register(TypeBuilder& bld) 14 | { 15 | 16 | bld.AddFunction< 17 | static_cast(&Neptools::WriteTxt) 18 | >("write_txt"); 19 | bld.AddFunction< 20 | static_cast(&Neptools::ReadTxt) 21 | >("read_txt"); 22 | 23 | } 24 | static TypeRegister::StateRegister<::Neptools::TxtSerializable> reg_neptools_txt_serializable; 25 | 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /src/txt_serializable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_E17CE799_6569_40E4_A8FE_39F088AE30AB 2 | #define UUID_E17CE799_6569_40E4_A8FE_39F088AE30AB 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace Neptools 13 | { 14 | 15 | class TxtSerializable : public Libshit::Lua::DynamicObject 16 | { 17 | LIBSHIT_LUA_CLASS; 18 | public: 19 | LIBSHIT_NOLUA void WriteTxt(std::ostream& os) const { WriteTxt_(os); } 20 | LIBSHIT_NOLUA void WriteTxt(std::ostream&& os) const { WriteTxt_(os); } 21 | LIBSHIT_NOLUA void ReadTxt(std::istream& is) { ReadTxt_(is); } 22 | LIBSHIT_NOLUA void ReadTxt(std::istream&& is) { ReadTxt_(is); } 23 | 24 | private: 25 | virtual void WriteTxt_(std::ostream& os) const = 0; 26 | virtual void ReadTxt_(std::istream& is) = 0; 27 | }; 28 | 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /src/format/primitive_item.cpp: -------------------------------------------------------------------------------- 1 | #include "primitive_item.hpp" 2 | #include "context.hpp" 3 | 4 | // factory 5 | #include "stcm/data.hpp" 6 | 7 | #include "primitive_item.binding.hpp" 8 | 9 | namespace Neptools 10 | { 11 | #define NEPTOOLS_GEN(cname, lname, ...) template class __VA_ARGS__ 12 | NEPTOOLS_PRIMITIVE_ITEMS(NEPTOOLS_GEN); 13 | #undef NEPTOOLS_GEN 14 | 15 | template 16 | static bool CheckFun(Stcm::DataItem& it) 17 | { 18 | if (it.type != TypeId || it.offset_unit != 1 || it.field_8 != 1) 19 | return false; 20 | auto child = dynamic_cast(&it.GetChildren().front()); 21 | if (child && child->GetSize() == sizeof(typename Item::Type)) 22 | { 23 | Item::CreateAndInsert({child, 0}); 24 | return true; 25 | } 26 | return false; 27 | } 28 | 29 | static Stcm::DataFactory reg_int32{CheckFun}; 30 | static Stcm::DataFactory reg_float{CheckFun}; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/format/cstring_item.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_94EB7F8A_BDE7_47F7_9B17_BF00A9A3EEBB 2 | #define UUID_94EB7F8A_BDE7_47F7_9B17_BF00A9A3EEBB 3 | #pragma once 4 | 5 | #include "item.hpp" 6 | #include "../source.hpp" 7 | 8 | namespace Neptools 9 | { 10 | 11 | class CStringItem final : public Item 12 | { 13 | LIBSHIT_DYNAMIC_OBJECT; 14 | public: 15 | CStringItem(Key k, Context& ctx, std::string string) 16 | : Item{k, ctx}, string{std::move(string)} {} 17 | CStringItem(Key k, Context& ctx, const Source& src); 18 | static CStringItem& CreateAndInsert(ItemPointer ptr); 19 | FilePosition GetSize() const noexcept override { return string.size() + 1; } 20 | 21 | static std::string GetLabelName(std::string string); 22 | std::string GetLabelName() const { return GetLabelName(string); } 23 | 24 | std::string string; 25 | 26 | private: 27 | void Dump_(Sink& sink) const override; 28 | void Inspect_(std::ostream& os, unsigned indent) const override; 29 | }; 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /tools/ci_conf.default.sh: -------------------------------------------------------------------------------- 1 | function before_build() 2 | { 3 | run ln -nsf /opt/boost libshit/ext/boost 4 | 5 | run rm -f test*.xml 6 | # should remove exactly the same items jenkins put into artifacts to prevent 7 | # stale files ending up in archives 8 | run rm -f build/stcm-editor build/*.{debug,exe,dll,pdb} \ 9 | build/libshit/ext/luajit-ljx{,.exe,.debug,.pdb} \ 10 | build/libshit/ext/jit/* 11 | } 12 | build_opts=(-j2) 13 | 14 | if [[ $mode = rel ]]; then 15 | mode_arg=(--release) 16 | elif [[ $mode = rel-test ]]; then 17 | mode_arg=(--release --with-tests) 18 | else 19 | mode_arg=(--optimize-ext --with-tests) 20 | fi 21 | 22 | function build() 23 | { 24 | [[ $WAF_DISTCLEAN == true ]] && run ./waf distclean 25 | run ./waf --color=yes configure "${config_opts[@]}" "${mode_arg[@]}" --all-bundle 26 | run ./waf --color=yes build "${build_opts[@]}" 27 | } 28 | 29 | tests=( 30 | 'build/stcm-editor --xml-output=test.xml --test -fc --reporters=libshit-junit,console' 31 | ) 32 | -------------------------------------------------------------------------------- /src/open.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_93BCB6F7_0156_4793_BAD5_76A9E9ABE263 2 | #define UUID_93BCB6F7_0156_4793_BAD5_76A9E9ABE263 3 | #pragma once 4 | 5 | #include "dumpable.hpp" 6 | #include "factory.hpp" 7 | #include "source.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace Neptools 17 | { 18 | 19 | inline Libshit::OptionGroup& GetFlavorOptions() 20 | { 21 | static Libshit::OptionGroup grp{ 22 | Libshit::OptionParser::GetGlobal(), "Game specific options"}; 23 | return grp; 24 | } 25 | 26 | class OpenFactory 27 | : public BaseFactory (*)(const Source&)>, 28 | public Libshit::Lua::StaticClass 29 | { 30 | LIBSHIT_LUA_CLASS; 31 | public: 32 | using Ret = Libshit::SmartPtr; 33 | LIBSHIT_NOLUA OpenFactory(BaseFactory::Fun f) : BaseFactory{f} {} 34 | 35 | static Libshit::NotNull Open(Source src); 36 | static Libshit::NotNull Open(const boost::filesystem::path& fname); 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/format/stcm/file.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::File::TYPE_NAME[] = "neptools.stcm.file"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.stcm.file 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Stcm::File>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::Stcm::File, ::Neptools::Context, ::Neptools::TxtSerializable>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::File>::Make<>, 19 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::File>::Make> 20 | >("new"); 21 | bld.AddFunction< 22 | static_cast<::Neptools::Stcm::GbnlItem * (::Neptools::Stcm::File::*)() const noexcept>(&::Neptools::Stcm::File::GetGbnl) 23 | >("get_gbnl"); 24 | bld.AddFunction< 25 | static_cast(&::Neptools::Stcm::File::Gc) 26 | >("gc"); 27 | 28 | } 29 | static TypeRegister::StateRegister<::Neptools::Stcm::File> reg_neptools_stcm_file; 30 | 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /src/vita_plugin/taihen_cpp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_CRANIALLY_GENEVESE_DISOMY_DISCLOUTS_4156 2 | #define GUARD_CRANIALLY_GENEVESE_DISOMY_DISCLOUTS_4156 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace Neptools::VitaPlugin 11 | { 12 | 13 | // replacement for tai_hook_ref_t and TAI_CONTINUE that works in c++ 14 | template class TaiHook; 15 | template 16 | class TaiHook 17 | { 18 | public: 19 | Res operator()(Args... args) 20 | { 21 | return (n->next ? n->next->func : n->old)(std::forward(args)...); 22 | }; 23 | 24 | operator uintptr_t*() { return reinterpret_cast(&n); } 25 | operator uintptr_t() { return reinterpret_cast(n); } 26 | 27 | private: 28 | using FuncPtr = Res(*)(Args...); 29 | struct Node 30 | { 31 | Node* next; 32 | FuncPtr func, old; 33 | }; 34 | Node* n; 35 | }; 36 | 37 | inline static const char* TAI_MAIN_MOD_STR = 38 | reinterpret_cast(TAI_MAIN_MODULE); 39 | 40 | LIBSHIT_GEN_EXCEPTION_TYPE(TaiError, std::runtime_error); 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/format/stcm/file.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_61A5519F_6624_43C0_8451_0BCA60B5D69A 2 | #define UUID_61A5519F_6624_43C0_8451_0BCA60B5D69A 3 | #pragma once 4 | 5 | #include "../../source.hpp" 6 | #include "../../txt_serializable.hpp" 7 | #include "../context.hpp" 8 | 9 | namespace Neptools::Stcm 10 | { 11 | class GbnlItem; 12 | 13 | class File final : public Context, public TxtSerializable 14 | { 15 | LIBSHIT_DYNAMIC_OBJECT; 16 | 17 | template 18 | using GbnlVectG = std::vector>>; 19 | 20 | GbnlItem* first_gbnl = nullptr; 21 | 22 | public: 23 | File() = default; 24 | File(Source src); 25 | 26 | LIBSHIT_NOLUA void SetGbnl(GbnlItem& gbnl) noexcept; 27 | LIBSHIT_NOLUA void UnsetGbnl(GbnlItem& gbnl) noexcept 28 | { if (first_gbnl == &gbnl) first_gbnl = nullptr; } 29 | GbnlItem* GetGbnl() const noexcept { return first_gbnl; }; 30 | 31 | void Gc() noexcept; 32 | 33 | protected: 34 | void Inspect_(std::ostream& os, unsigned indent) const override; 35 | 36 | private: 37 | void Parse_(Source& src); 38 | 39 | void WriteTxt_(std::ostream& os) const override; 40 | void ReadTxt_(std::istream& is) override; 41 | }; 42 | 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /src/programs/launcher.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "version.hpp" 3 | 4 | 0 ICON "icon.ico" 5 | 6 | 1 VERSIONINFO 7 | FILEVERSION NEPTOOLS_RC_VERSION 8 | PRODUCTVERSION NEPTOOLS_RC_VERSION 9 | FILEOS VOS_NT_WINDOWS32 10 | FILETYPE VFT_APP 11 | { 12 | BLOCK "StringFileInfo" 13 | { 14 | BLOCK "040904E4" 15 | { 16 | VALUE "ProductName", "neptools launcher" 17 | VALUE "ProductVersion", NEPTOOLS_VERSION 18 | VALUE "FileDescription", "NepTools launcher" 19 | VALUE "FileVersion", NEPTOOLS_VERSION 20 | VALUE "InternalName", "launcher" 21 | VALUE "OriginalFileName", "launcher.exe" 22 | } 23 | } 24 | BLOCK "VarFileInfo" 25 | { 26 | VALUE "Translation", 0x409, 1200 27 | } 28 | } 29 | 30 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST 31 | { 32 | "" 33 | "" 34 | "" 35 | "" 36 | "" 37 | "" 38 | "" 39 | "" 40 | "" 41 | "" 42 | } 43 | -------------------------------------------------------------------------------- /src/programs/stcm-editor.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "version.hpp" 3 | 4 | 0 ICON "icon.ico" 5 | 6 | 1 VERSIONINFO 7 | FILEVERSION NEPTOOLS_RC_VERSION 8 | PRODUCTVERSION NEPTOOLS_RC_VERSION 9 | FILEOS VOS_NT_WINDOWS32 10 | FILETYPE VFT_APP 11 | { 12 | BLOCK "StringFileInfo" 13 | { 14 | BLOCK "040904E4" 15 | { 16 | VALUE "ProductName", "stcm-editor" 17 | VALUE "ProductVersion", NEPTOOLS_VERSION 18 | VALUE "FileDescription", "NepTools stcm-editor" 19 | VALUE "FileVersion", NEPTOOLS_VERSION 20 | VALUE "InternalName", "stcm-editor" 21 | VALUE "OriginalFileName", "stcm-editor.exe" 22 | } 23 | } 24 | BLOCK "VarFileInfo" 25 | { 26 | VALUE "Translation", 0x409, 1200 27 | } 28 | } 29 | 30 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST 31 | { 32 | "" 33 | "" 34 | "" 35 | "" 36 | "" 37 | "" 38 | "" 39 | "" 40 | "" 41 | "" 42 | } 43 | -------------------------------------------------------------------------------- /src/format/stcm/gbnl.cpp: -------------------------------------------------------------------------------- 1 | #include "gbnl.hpp" 2 | #include "data.hpp" 3 | #include "../context.hpp" 4 | #include "../gbnl_lua.hpp" 5 | #include "../raw_item.hpp" 6 | 7 | #include 8 | 9 | namespace Neptools::Stcm 10 | { 11 | 12 | void GbnlItem::Dispose() noexcept 13 | { 14 | if (auto ctx = GetContextMaybe()) 15 | if (auto file = ctx.DynamicPointerCast()) 16 | file->UnsetGbnl(*this); 17 | Item::Dispose(); 18 | } 19 | 20 | GbnlItem& GbnlItem::CreateAndInsert(ItemPointer ptr) 21 | { 22 | auto x = RawItem::GetSource(ptr, -1); 23 | return x.ritem.SplitCreate(ptr.offset, x.src); 24 | } 25 | 26 | static DataFactory factory{[](DataItem& it) 27 | { 28 | auto child = dynamic_cast(&it.GetChildren().front()); 29 | if (child && child->GetSize() > sizeof(Gbnl::Header)) 30 | { 31 | char buf[4]; 32 | child->GetSource().Pread(child->GetSize() - sizeof(Gbnl::Header), buf, 4); 33 | if (memcmp(buf, "GBNL", 4) == 0) 34 | { 35 | GbnlItem::CreateAndInsert({child, 0}); 36 | return true; 37 | } 38 | } 39 | return false; 40 | }}; 41 | 42 | } 43 | 44 | LIBSHIT_STD_VECTOR_FWD(gbnl_struct, Neptools::Gbnl::StructPtr); 45 | #include "gbnl.binding.hpp" 46 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | #include 3 | 4 | #include "source.hpp" 5 | #include 6 | #include 7 | 8 | // workaround incompatibilities between clang+msvc libs, mingw ofstream (no wide 9 | // char open) and linux... 10 | #ifndef BOOST_FILESYSTEM_C_STR 11 | # define BOOST_FILESYSTEM_C_STR c_str() 12 | #endif 13 | 14 | namespace Neptools 15 | { 16 | 17 | std::ofstream OpenOut(const boost::filesystem::path& pth) 18 | { 19 | std::ofstream os; 20 | os.exceptions(std::ios_base::failbit | std::ios_base::badbit); 21 | os.open(pth.BOOST_FILESYSTEM_C_STR, std::ios_base::out | std::ios_base::binary); 22 | return os; 23 | } 24 | 25 | std::ifstream OpenIn(const boost::filesystem::path& pth) 26 | { 27 | std::ifstream is; 28 | is.exceptions(std::ios_base::failbit | std::ios_base::badbit); 29 | is.open(pth.BOOST_FILESYSTEM_C_STR, std::ios_base::in | std::ios_base::binary); 30 | return is; 31 | } 32 | 33 | void DumpBytes(std::ostream& os, Source data) 34 | { 35 | os << '"'; 36 | 37 | bool hex = false; 38 | for (FilePosition offs = 0, size = data.GetSize(); offs < size; ) 39 | { 40 | auto chunk = data.GetChunk(offs); 41 | for (char c : chunk) 42 | hex = Libshit::DumpByte(os, c, hex); 43 | offs += chunk.length(); 44 | } 45 | os << '"'; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/dumpable.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Dumpable::TYPE_NAME[] = "neptools.dumpable"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.dumpable 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Dumpable>::Register(TypeBuilder& bld) 14 | { 15 | 16 | bld.AddFunction< 17 | static_cast(&::Neptools::Dumpable::Fixup) 18 | >("fixup"); 19 | bld.AddFunction< 20 | static_cast<::Neptools::FilePosition (::Neptools::Dumpable::*)() const>(&::Neptools::Dumpable::GetSize) 21 | >("get_size"); 22 | bld.AddFunction< 23 | static_cast(&::Neptools::Dumpable::Dump), 24 | static_cast(&::Neptools::Dumpable::Dump) 25 | >("dump"); 26 | bld.AddFunction< 27 | static_cast(&::Neptools::Dumpable::Inspect), 28 | static_cast(&::Neptools::Dumpable::Inspect) 29 | >("inspect"); 30 | 31 | } 32 | static TypeRegister::StateRegister<::Neptools::Dumpable> reg_neptools_dumpable; 33 | 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /src/windows_server/hook.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_310CE7F9_73D3_4140_BA43_9DA7CB4136D1 2 | #define UUID_310CE7F9_73D3_4140_BA43_9DA7CB4136D1 3 | #pragma once 4 | 5 | #include 6 | #include "../pattern.hpp" 7 | 8 | namespace Neptools 9 | { 10 | 11 | extern Byte* image_base; 12 | size_t GetImageSize() noexcept; 13 | Byte* GetEntryPoint() noexcept; 14 | 15 | inline Byte* MaybeFindImage(const Pattern& pat) noexcept 16 | { return const_cast(pat.MaybeFind({image_base, GetImageSize()})); } 17 | inline Byte* FindImage(const Pattern& pat) 18 | { return const_cast(pat.Find({image_base, GetImageSize()})); } 19 | 20 | void* Hook(void* hook, void* dst, size_t copy); 21 | 22 | template 23 | inline T Hook(void* hook, T dst, size_t copy) 24 | { 25 | static_assert(sizeof(T) == 4); 26 | union 27 | { 28 | T t; 29 | void* vd; 30 | } u; 31 | u.t = dst; 32 | u.vd = Hook(hook, u.vd, copy); 33 | return u.t; 34 | } 35 | 36 | template 37 | T& As(void* ptr) { return *static_cast(ptr); } 38 | 39 | class Unprotect 40 | { 41 | public: 42 | Unprotect(void* ptr, size_t len); 43 | ~Unprotect(); 44 | Unprotect(const Unprotect&) = delete; 45 | void operator=(const Unprotect&) = delete; 46 | 47 | private: 48 | void* ptr; 49 | size_t len; 50 | unsigned long orig_prot; 51 | }; 52 | 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /tools/valgrind.supp: -------------------------------------------------------------------------------- 1 | { 2 | libstdc++ leaking iostream 3 | Memcheck:Leak 4 | match-leak-kinds: reachable 5 | fun:_Znam 6 | ... 7 | fun:_ZNSt8ios_base15sync_with_stdioEb 8 | } 9 | 10 | { 11 | libc++ 7.0.1 exception leak with sysroot 12 | Memcheck:Leak 13 | match-leak-kinds: reachable 14 | fun:calloc 15 | fun:_ZN10__cxxabiv122__calloc_with_fallbackEmm 16 | fun:__cxa_get_globals 17 | } 18 | 19 | { 20 | libc++ exit 21 | Memcheck:Free 22 | fun:free 23 | fun:free_key_mem 24 | fun:__dlerror_main_freeres 25 | fun:__libc_freeres 26 | fun:_vgnU_freeres 27 | fun:__run_exit_handlers 28 | fun:exit 29 | } 30 | 31 | { 32 | libunwind wtf? 33 | Memcheck:Cond 34 | obj:/usr/lib64/libunwind.so.8.0.1 35 | } 36 | { 37 | libunwind wtf? 38 | Memcheck:Addr8 39 | obj:/usr/lib64/libunwind.so.8.0.1 40 | } 41 | { 42 | libunwind wtf? 43 | Memcheck:Param 44 | rt_sigprocmask(set) 45 | obj:/usr/lib64/libunwind.so.8.0.1 46 | } 47 | 48 | 49 | { 50 | luajit fastcmp in gsub/debug 51 | Memcheck:Cond 52 | fun:str_fastcmp 53 | fun:lj_str_new 54 | fun:lua_pushlstring 55 | fun:emptybuffer 56 | fun:luaL_pushresult 57 | fun:lj_cf_string_gsub 58 | fun:lj_BC_FUNCC 59 | } 60 | { 61 | luajit fastcmp in gsub/opt 62 | Memcheck:Cond 63 | fun:lj_str_new 64 | fun:lua_pushlstring 65 | fun:lj_cf_string_gsub 66 | fun:lj_BC_FUNCC 67 | } 68 | -------------------------------------------------------------------------------- /src/format/cstring_item.cpp: -------------------------------------------------------------------------------- 1 | #include "cstring_item.hpp" 2 | #include "raw_item.hpp" 3 | #include "../sink.hpp" 4 | 5 | #include 6 | 7 | namespace Neptools 8 | { 9 | 10 | CStringItem::CStringItem(Key k, Context& ctx, const Source& src) 11 | : Item{k, ctx}, string{src.PreadCString(0)} 12 | {} 13 | 14 | CStringItem& CStringItem::CreateAndInsert(ItemPointer ptr) 15 | { 16 | auto x = RawItem::GetSource(ptr, -1); 17 | return x.ritem.SplitCreate(ptr.offset, x.src); 18 | } 19 | 20 | void CStringItem::Dump_(Sink& sink) const 21 | { 22 | sink.WriteCString(string); 23 | } 24 | 25 | void CStringItem::Inspect_(std::ostream& os, unsigned indent) const 26 | { 27 | Item::Inspect_(os, indent); 28 | os << "c_string(" << Libshit::Quoted(string) << ')'; 29 | } 30 | 31 | std::string CStringItem::GetLabelName(std::string string) 32 | { 33 | size_t iptr = 0, optr = 0; 34 | bool last_valid = false; 35 | for (size_t len = string.length(); iptr < len && optr < 16; ++iptr) 36 | if (isalnum(string[iptr])) 37 | { 38 | string[optr++] = string[iptr]; 39 | last_valid = true; 40 | } 41 | else if (last_valid) 42 | { 43 | string[optr++] = '_'; 44 | last_valid = false; 45 | } 46 | string.resize(optr); 47 | return "str_" + string; 48 | } 49 | 50 | } 51 | 52 | #include "cstring_item.binding.hpp" 53 | -------------------------------------------------------------------------------- /tools/ci_conf.clang.sh: -------------------------------------------------------------------------------- 1 | source tools/ci_conf_linuxcommon.sh 2 | 3 | opt="-march=x86-64 -mtune=generic" 4 | libcxx="-stdlib=libc++" 5 | 6 | # sysroot only supported with clang ATM 7 | sysroot=/opt/sysroot_amd64 8 | qsysroot="$(quot "$sysroot")" 9 | 10 | run clang --version 11 | run export AR=llvm-ar 12 | run export CC=clang 13 | run export CXX=clang++ 14 | run export CFLAGS="--sysroot $qsysroot $opt" 15 | # define: old glibc doesn't know about clang 16 | run export CXXFLAGS="--sysroot $qsysroot $opt $libcxx \ 17 | -D__extern_always_inline='extern __always_inline __attribute__((__gnu_inline__))'" 18 | # -lrt only needed with glibc < 2.17 19 | run export LINKFLAGS="--sysroot $qsysroot $libcxx -fuse-ld=lld \ 20 | -static-libstdc++ -Wl,--as-needed -lpthread -lrt -Wl,--no-as-needed" 21 | 22 | run export PKG_CONFIG_PATH="$(join : "$sysroot"/usr/lib/{,*/}pkgconfig)" 23 | run export PKG_CONFIG_SYSROOT_DIR="$sysroot" 24 | 25 | 26 | te='build/stcm-editor --xml-output=test' 27 | ts='--test -fc --reporters=libshit-junit,console' 28 | ld="LD_LIBRARY_PATH=$(quot "$(join : "$sysroot"/{,usr/}lib/{,*-linux-gnu})") \ 29 | $(quot "$sysroot"/lib/*/ld-linux*.so*) $te" 30 | qemu="\$CC -O2 -shared -o tools/qemu_vdso_fix_linux_amd64.so \ 31 | tools/qemu_vdso_fix_linux_amd64.c && \ 32 | qemu-x86_64 -E LD_PRELOAD=$(quot "$(pwd)/tools/qemu_vdso_fix_linux_amd64.so") \ 33 | -E $ld-qemu.xml $ts" 34 | 35 | tests=( 36 | "$te-native.xml $ts" 37 | "$ld-ld.xml $ts" 38 | "$qemu" 39 | "$valgrind" 40 | ) 41 | -------------------------------------------------------------------------------- /src/format/stcm/string_data.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::StringDataItem::TYPE_NAME[] = "neptools.stcm.string_data_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.stcm.string_data_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Stcm::StringDataItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::Stcm::StringDataItem, ::Neptools::Item>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::StringDataItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef> 19 | >("new"); 20 | bld.AddFunction< 21 | static_cast (*)(::Neptools::Stcm::DataItem &)>(::Neptools::Stcm::StringDataItem::MaybeCreateAndReplace) 22 | >("maybe_create_and_replace"); 23 | bld.AddFunction< 24 | &::Libshit::Lua::GetMember<::Neptools::Stcm::StringDataItem, std::string, &::Neptools::Stcm::StringDataItem::string> 25 | >("get_string"); 26 | bld.AddFunction< 27 | &::Libshit::Lua::SetMember<::Neptools::Stcm::StringDataItem, std::string, &::Neptools::Stcm::StringDataItem::string> 28 | >("set_string"); 29 | 30 | } 31 | static TypeRegister::StateRegister<::Neptools::Stcm::StringDataItem> reg_neptools_stcm_string_data_item; 32 | 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /src/format/stcm/data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_CB40AD6D_5157_4C96_A9A9_371A9F215955 2 | #define UUID_CB40AD6D_5157_4C96_A9A9_371A9F215955 3 | #pragma once 4 | 5 | #include "../item.hpp" 6 | #include "../../factory.hpp" 7 | #include 8 | 9 | namespace Neptools::Stcm 10 | { 11 | 12 | class DataItem final : public ItemWithChildren 13 | { 14 | LIBSHIT_DYNAMIC_OBJECT; 15 | public: 16 | struct Header 17 | { 18 | boost::endian::little_uint32_t type; 19 | boost::endian::little_uint32_t offset_unit; 20 | boost::endian::little_uint32_t field_8; 21 | boost::endian::little_uint32_t length; 22 | 23 | void Validate(FilePosition chunk_size) const; 24 | }; 25 | static_assert(sizeof(Header) == 0x10); 26 | 27 | DataItem(Key k, Context& ctx, uint32_t type, uint32_t offset_unit, 28 | uint32_t field_8) 29 | : ItemWithChildren{k, ctx}, type{type}, offset_unit{offset_unit}, 30 | field_8{field_8} {} 31 | LIBSHIT_NOLUA 32 | DataItem(Key k, Context& ctx, const Header& hdr, size_t chunk_size); 33 | static DataItem& CreateAndInsert(ItemPointer ptr); 34 | 35 | FilePosition GetSize() const noexcept override; 36 | void Fixup() override; 37 | 38 | uint32_t type, offset_unit, field_8; 39 | 40 | private: 41 | void Dump_(Sink& sink) const override; 42 | void Inspect_(std::ostream& os, unsigned indent) const override; 43 | }; 44 | 45 | struct DataFactory : BaseFactory 46 | { 47 | using BaseFactory::BaseFactory; 48 | static void Check(DataItem& it); 49 | }; 50 | 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /src/format/stsc/file.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_CACA9E02_5122_4C09_9463_73AD33BA5802 2 | #define UUID_CACA9E02_5122_4C09_9463_73AD33BA5802 3 | #pragma once 4 | 5 | #include "../context.hpp" 6 | #include "../../source.hpp" 7 | #include "../../txt_serializable.hpp" 8 | 9 | namespace Neptools::Stsc 10 | { 11 | 12 | enum class LIBSHIT_LUAGEN() Flavor 13 | { 14 | #define NEPTOOLS_GEN_STSC_FLAVOR(x, ...) \ 15 | x(NOIRE, __VA_ARGS__) \ 16 | x(POTBB, __VA_ARGS__) 17 | #define NEPTOOLS_GEN_ENUM(x,y) x, 18 | NEPTOOLS_GEN_STSC_FLAVOR(NEPTOOLS_GEN_ENUM,) 19 | #undef NEPTOOLS_GEN_ENUM 20 | }; 21 | 22 | // not constexpr because it only 5 years to implement c++14 in gcc and broken 23 | // in &2 8 | } 9 | 10 | function ewarn() 11 | { 12 | echo -e " \033[33m*\033[0m $@" >&2 13 | } 14 | 15 | function eerror() 16 | { 17 | echo -e " \033[31m*\033[0m $@" >&2 18 | } 19 | 20 | trap "exit 1" ERR 21 | 22 | if [[ $# != 2 ]]; then 23 | eerror "Usage: $0 compiler mode" 24 | exit 1 25 | fi 26 | compiler="$1" 27 | mode="$2" 28 | 29 | if [[ $mode != rel && $mode != rel-test && $mode != debug ]]; then 30 | eerror "Invalid mode $mode" 31 | exit 1 32 | fi 33 | 34 | cd "$(dirname "${BASH_SOURCE[0]}")/.." 35 | 36 | function before_build() { :; } 37 | function after_build() { :; } 38 | function after() { :; } 39 | 40 | function load() 41 | { 42 | if [[ -f ~/.neptools_ci_conf."$1".sh ]]; then 43 | source ~/.neptools_ci_conf."$1".sh 44 | else 45 | source tools/ci_conf."$1".sh 46 | fi 47 | } 48 | 49 | # env printf: bypass bash's printf as gnu printf uses 'foo bar' instead of 50 | # foo\ bar. provided we have gnu printf... 51 | if env printf '%q' >/dev/null 2>/dev/null; then 52 | quot_printf='env printf' 53 | else 54 | quot_printf=printf 55 | fi 56 | 57 | function quot() 58 | { 59 | $quot_printf '%q' "$1" 60 | } 61 | 62 | function run() 63 | { 64 | einfo "$($quot_printf '%q ' "$@")" 65 | "$@" || exit 1 66 | } 67 | 68 | load default 69 | load "$compiler" 70 | 71 | before_build 72 | build 73 | after_build 74 | 75 | ret=0 76 | if [[ $mode != rel ]]; then 77 | for t in "${tests[@]}"; do 78 | einfo "$t" 79 | time eval "$t" || ret=1 80 | done 81 | fi 82 | after 83 | exit $ret 84 | -------------------------------------------------------------------------------- /src/format/raw_item.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::RawItem::TYPE_NAME[] = "neptools.raw_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.raw_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::RawItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::RawItem, ::Neptools::Item>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::RawItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Neptools::Source>>, 19 | &::Libshit::Lua::TypeTraits<::Neptools::RawItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef> 20 | >("new"); 21 | bld.AddFunction< 22 | static_cast(&::Neptools::RawItem::GetSource), 23 | static_cast<::Neptools::RawItem::GetSourceRet (*)(::Neptools::ItemPointer, ::Neptools::FilePosition)>(::Neptools::RawItem::GetSource) 24 | >("get_source"); 25 | bld.AddFunction< 26 | static_cast<::Neptools::Item & (::Neptools::RawItem::*)(::Neptools::FilePosition, ::Libshit::NotNull<::Libshit::RefCountedPtr<::Neptools::Item> >)>(&::Neptools::RawItem::Split<::Neptools::Item>), 27 | static_cast<::Neptools::RawItem & (::Neptools::RawItem::*)(::Neptools::FilePosition, ::Neptools::FilePosition)>(&::Neptools::RawItem::Split) 28 | >("split"); 29 | 30 | } 31 | static TypeRegister::StateRegister<::Neptools::RawItem> reg_neptools_raw_item; 32 | 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /src/format/stcm/expansion.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_KNOBBILY_BROGUED_NET_REGISTER_TON_BESOTS_7814 2 | #define GUARD_KNOBBILY_BROGUED_NET_REGISTER_TON_BESOTS_7814 3 | #pragma once 4 | 5 | #include "../item.hpp" 6 | #include 7 | 8 | namespace Neptools::Stcm 9 | { 10 | 11 | class ExpansionItem final : public Item 12 | { 13 | LIBSHIT_DYNAMIC_OBJECT; 14 | public: 15 | struct Header 16 | { 17 | boost::endian::little_uint32_t index; 18 | boost::endian::little_uint32_t name; 19 | boost::endian::little_uint64_t ptr; // used by game engine 20 | boost::endian::little_uint32_t pad[16]; 21 | 22 | void Validate(FilePosition file_size) const; 23 | }; 24 | static_assert(sizeof(Header) == 0x50); 25 | 26 | ExpansionItem(Key k, Context& ctx, uint32_t index, LabelPtr name) 27 | : Item{k, ctx}, index{index}, name{name} {} 28 | LIBSHIT_NOLUA 29 | ExpansionItem(Key k, Context& ctx, const Header& hdr); 30 | static ExpansionItem& CreateAndInsert(ItemPointer ptr); 31 | 32 | FilePosition GetSize() const noexcept override { return sizeof(Header); } 33 | 34 | uint32_t index; 35 | Libshit::NotNull name; 36 | 37 | private: 38 | void Dump_(Sink& sink) const override; 39 | void Inspect_(std::ostream& os, unsigned indent) const override; 40 | }; 41 | 42 | class ExpansionsItem final : public ItemWithChildren 43 | { 44 | LIBSHIT_DYNAMIC_OBJECT; 45 | public: 46 | ExpansionsItem(Key k, Context& ctx) : ItemWithChildren{k, ctx} {} 47 | static ExpansionsItem& CreateAndInsert(ItemPointer ptr, uint32_t count); 48 | 49 | private: 50 | void Inspect_(std::ostream& os, unsigned indent) const override; 51 | }; 52 | 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /src/format/stcm/gbnl.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::GbnlItem::TYPE_NAME[] = "neptools.stcm.gbnl_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.stcm.gbnl_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Stcm::GbnlItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::Stcm::GbnlItem, ::Neptools::Item, ::Neptools::Gbnl>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::GbnlItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Neptools::Source>>, 19 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::GbnlItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Neptools::Endian>, LuaGetRef, LuaGetRef<::uint32_t>, LuaGetRef<::uint32_t>, LuaGetRef<::uint32_t>, LuaGetRef>>, 20 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::GbnlItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Libshit::Lua::StateRef>, LuaGetRef<::Neptools::Endian>, LuaGetRef, LuaGetRef<::uint32_t>, LuaGetRef<::uint32_t>, LuaGetRef<::uint32_t>, LuaGetRef>, LuaGetRef<::Libshit::Lua::RawTable>> 21 | >("new"); 22 | bld.AddFunction< 23 | static_cast<::Neptools::Stcm::GbnlItem & (*)(::Neptools::ItemPointer)>(::Neptools::Stcm::GbnlItem::CreateAndInsert) 24 | >("create_and_insert"); 25 | 26 | } 27 | static TypeRegister::StateRegister<::Neptools::Stcm::GbnlItem> reg_neptools_stcm_gbnl_item; 28 | 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /src/format/cstring_item.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::CStringItem::TYPE_NAME[] = "neptools.c_string_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.c_string_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::CStringItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::CStringItem, ::Neptools::Item>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::CStringItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef>, 19 | &::Libshit::Lua::TypeTraits<::Neptools::CStringItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef> 20 | >("new"); 21 | bld.AddFunction< 22 | static_cast<::Neptools::CStringItem & (*)(::Neptools::ItemPointer)>(::Neptools::CStringItem::CreateAndInsert) 23 | >("create_and_insert"); 24 | bld.AddFunction< 25 | static_cast(::Neptools::CStringItem::GetLabelName), 26 | static_cast(&::Neptools::CStringItem::GetLabelName) 27 | >("get_label_name"); 28 | bld.AddFunction< 29 | &::Libshit::Lua::GetMember<::Neptools::CStringItem, std::string, &::Neptools::CStringItem::string> 30 | >("get_string"); 31 | bld.AddFunction< 32 | &::Libshit::Lua::SetMember<::Neptools::CStringItem, std::string, &::Neptools::CStringItem::string> 33 | >("set_string"); 34 | 35 | } 36 | static TypeRegister::StateRegister<::Neptools::CStringItem> reg_neptools_c_string_item; 37 | 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /src/format/stsc/file.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | const char ::Libshit::Lua::TypeName<::Neptools::Stsc::Flavor>::TYPE_NAME[] = 6 | "neptools.stsc.flavor"; 7 | 8 | const char ::Neptools::Stsc::File::TYPE_NAME[] = "neptools.stsc.file"; 9 | 10 | namespace Libshit::Lua 11 | { 12 | 13 | // class neptools.stsc.flavor 14 | template<> 15 | void TypeRegisterTraits<::Neptools::Stsc::Flavor>::Register(TypeBuilder& bld) 16 | { 17 | 18 | bld.Add("NOIRE", ::Neptools::Stsc::Flavor::NOIRE); 19 | bld.Add("POTBB", ::Neptools::Stsc::Flavor::POTBB); 20 | 21 | } 22 | static TypeRegister::StateRegister<::Neptools::Stsc::Flavor> reg_neptools_stsc_flavor; 23 | 24 | // class neptools.stsc.file 25 | template<> 26 | void TypeRegisterTraits<::Neptools::Stsc::File>::Register(TypeBuilder& bld) 27 | { 28 | bld.Inherit<::Neptools::Stsc::File, ::Neptools::Context, ::Neptools::TxtSerializable>(); 29 | 30 | bld.AddFunction< 31 | &::Libshit::Lua::TypeTraits<::Neptools::Stsc::File>::Make>, 32 | &::Libshit::Lua::TypeTraits<::Neptools::Stsc::File>::Make, LuaGetRef<::Neptools::Stsc::Flavor>> 33 | >("new"); 34 | bld.AddFunction< 35 | &::Libshit::Lua::GetMember<::Neptools::Stsc::File, ::Neptools::Stsc::Flavor, &::Neptools::Stsc::File::flavor> 36 | >("get_flavor"); 37 | bld.AddFunction< 38 | &::Libshit::Lua::SetMember<::Neptools::Stsc::File, ::Neptools::Stsc::Flavor, &::Neptools::Stsc::File::flavor> 39 | >("set_flavor"); 40 | 41 | } 42 | static TypeRegister::StateRegister<::Neptools::Stsc::File> reg_neptools_stsc_file; 43 | 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /src/format/stcm/file.cpp: -------------------------------------------------------------------------------- 1 | #include "file.hpp" 2 | #include "gbnl.hpp" 3 | #include "header.hpp" 4 | #include "../eof_item.hpp" 5 | #include "../item.hpp" 6 | #include "../../open.hpp" 7 | 8 | namespace Neptools::Stcm 9 | { 10 | 11 | File::File(Source src) 12 | { 13 | ADD_SOURCE(Parse_(src), src); 14 | } 15 | 16 | void File::Parse_(Source& src) 17 | { 18 | auto root = Create(src); 19 | SetupParseFrom(*root); 20 | root->Split(root->GetSize(), Create()); 21 | HeaderItem::CreateAndInsert({root.get(), 0}); 22 | } 23 | 24 | void File::Inspect_(std::ostream& os, unsigned indent) const 25 | { 26 | LIBSHIT_ASSERT(GetLabels().empty()); 27 | os << "neptools.stcm.file()"; 28 | InspectChildren(os, indent); 29 | } 30 | 31 | void File::SetGbnl(GbnlItem& gbnl) noexcept 32 | { 33 | LIBSHIT_ASSERT(&gbnl.GetUnsafeContext() == this); 34 | if (!first_gbnl) first_gbnl = &gbnl; 35 | } 36 | 37 | void File::Gc() noexcept 38 | { 39 | for (auto it = GetChildren().begin(); it != GetChildren().end(); ) 40 | if (dynamic_cast(&*it) && it->GetLabels().empty()) 41 | it = GetChildren().erase(it); 42 | else 43 | ++it; 44 | } 45 | 46 | void File::WriteTxt_(std::ostream& os) const 47 | { if (first_gbnl) first_gbnl->WriteTxt(os); } 48 | 49 | void File::ReadTxt_(std::istream& is) 50 | { if (first_gbnl) first_gbnl->ReadTxt(is); } 51 | 52 | static OpenFactory stcm_open{[](const Source& src) -> Libshit::SmartPtr 53 | { 54 | if (src.GetSize() < sizeof(HeaderItem::Header)) return nullptr; 55 | char buf[4]; 56 | src.PreadGen(0, buf); 57 | if (memcmp(buf, "STCM", 4) == 0) 58 | return Libshit::MakeSmart(src); 59 | else 60 | return nullptr; 61 | }}; 62 | 63 | } 64 | 65 | #include 66 | #include "file.binding.hpp" 67 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # -*- yaml -*- 2 | # -cert-err*-cpp,-misc-throw-by-value-catch-by-reference: fails with boost exceptions 3 | # -misc-definitions-in-headers: doesn't work with templates 4 | # -misc-macro-parentheses: this is not lisp 5 | # -modernize-use-override: I won't type override next to each dtor retards 6 | # -modernize-raw-string-literal "\\r" is better than R"(\r)" IMHO 7 | # -readability-braces-around-statements,-readability-named-parameter, 8 | # -readability-else-after-return,-readability-implicit-bool-cast: bullshit 9 | # -readability-redundant-declaration: only false positives 10 | # -readability-inconsistent-declaration-parameter-name: it's the main reason c++ 11 | # doesn't have named arguments like python 12 | # -modernize-avoid-bind: no idea why it even exists 13 | # -misc-suspicious-semicolon: warn on every constexpr if 14 | # -misc-move-const-arg: defeats future-proofing code 15 | Checks: 'clang-diagnostic-*,clang-analyzer-*,boost*,cert*,clang-analyzer*,misc*,modernize*,performance*,readability*,-cert-err09-cpp,-cert-err58-cpp,-cert-err60-cpp,-cert-err61-cpp,-misc-definitions-in-headers,-misc-macro-parentheses,-misc-throw-by-value-catch-by-reference,-modernize-use-override,-modernize-raw-string-literal,-readability-braces-around-statements,-readability-named-parameter,-readability-else-after-return,-readability-implicit-bool-cast,-readability-redundant-declaration,-readability-inconsistent-declaration-parameter-name,-modernize-avoid-bind,-misc-suspicious-semicolon,-misc-move-const-arg' 16 | HeaderFilterRegex: '(^|[^x]|[^j]x|[^l]jx|[^/]ljx)/src/' 17 | 18 | CheckOptions: 19 | - key: misc-assert-side-effect.AssertMacros 20 | value: NEPTOOLS_ASSERT 21 | - key: misc-dangling-handle.HandleClasses 22 | value: 'std::basic_string_view;std::experimental::basic_string_view;Neptools::BasicNonowningString' 23 | - key: misc-suspicious-string-compare.WarnOnImplicitComparison 24 | value: 0 25 | -------------------------------------------------------------------------------- /src/endian.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_A2E491BD_BA3E_4C92_B931_72017B89C33C 2 | #define UUID_A2E491BD_BA3E_4C92_B931_72017B89C33C 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace Neptools 12 | { 13 | enum class LIBSHIT_LUAGEN() Endian 14 | { 15 | BIG, LITTLE, 16 | }; 17 | 18 | // not constexpr because gcc is retarded 19 | inline boost::endian::order ToBoost(Endian e) noexcept 20 | { 21 | switch (e) 22 | { 23 | case Endian::BIG: return boost::endian::order::big; 24 | case Endian::LITTLE: return boost::endian::order::little; 25 | } 26 | LIBSHIT_UNREACHABLE("Invalid Endian value"); 27 | } 28 | 29 | inline const char* ToString(Endian e) noexcept 30 | { 31 | switch (e) 32 | { 33 | case Endian::BIG: return "BIG"; 34 | case Endian::LITTLE: return "LITTLE"; 35 | } 36 | LIBSHIT_UNREACHABLE("Invalid Endian value"); 37 | } 38 | 39 | template 40 | [[nodiscard]] inline T ToNativeCopy(T t, Endian e) noexcept 41 | { 42 | return boost::endian::conditional_reverse( 43 | std::move(t), ToBoost(e), boost::endian::order::native); 44 | } 45 | 46 | template 47 | [[nodiscard]] inline T FromNativeCopy(T t, Endian e) noexcept 48 | { 49 | return boost::endian::conditional_reverse( 50 | std::move(t), ToBoost(e), boost::endian::order::native); 51 | } 52 | 53 | template 54 | inline void ToNative(T& t, Endian e) noexcept 55 | { 56 | boost::endian::conditional_reverse_inplace( 57 | t, ToBoost(e), boost::endian::order::native); 58 | } 59 | 60 | template 61 | inline void FromNative(T& t, Endian e) noexcept 62 | { 63 | boost::endian::conditional_reverse_inplace( 64 | t, ToBoost(e), boost::endian::order::native); 65 | } 66 | 67 | } 68 | 69 | LIBSHIT_ENUM(Neptools::Endian); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/format/raw_item.cpp: -------------------------------------------------------------------------------- 1 | #include "raw_item.hpp" 2 | #include "context.hpp" 3 | #include 4 | 5 | namespace Neptools 6 | { 7 | 8 | void RawItem::Dump_(Sink& sink) const 9 | { 10 | src.Dump(sink); 11 | } 12 | 13 | void RawItem::Inspect_(std::ostream& os, unsigned indent) const 14 | { 15 | Item::Inspect_(os, indent); 16 | os << "raw(" << Quoted(src) << ")"; 17 | } 18 | 19 | Libshit::NotNull> RawItem::InternalSlice( 20 | FilePosition spos, FilePosition slen) 21 | { 22 | LIBSHIT_ASSERT(spos+slen <= GetSize()); 23 | auto ctx = GetContext(); 24 | return ctx->Create(Source{src, spos, slen}, position+spos); 25 | } 26 | 27 | // split into 3 parts: 0...pos, pos...pos+nitem size, pos+nitem size...this size 28 | void RawItem::Split2( 29 | FilePosition pos, Libshit::NotNull> nitem) 30 | { 31 | auto len = nitem->GetSize(); 32 | LIBSHIT_ASSERT(pos <= GetSize() && pos+len <= GetSize()); 33 | auto rem_len = GetSize() - len - pos; 34 | 35 | if (pos == 0 && rem_len == 0) 36 | { 37 | Replace(std::move(nitem)); 38 | return; 39 | } 40 | 41 | SliceSeq seq; 42 | if (pos != 0) seq.emplace_back(MakeNotNull(this), pos); 43 | seq.emplace_back(std::move(nitem), pos+len); 44 | if (rem_len > 0) 45 | if (pos == 0) 46 | seq.emplace_back(MakeNotNull(this), GetSize()); 47 | else 48 | seq.emplace_back(InternalSlice(pos+len, rem_len), GetSize()); 49 | 50 | Item::Slice(std::move(seq)); 51 | if (pos == 0) 52 | { 53 | LIBSHIT_ASSERT(rem_len > 0); 54 | src.Slice(len, rem_len); 55 | } 56 | else 57 | src.Slice(0, pos); 58 | } 59 | 60 | RawItem& RawItem::Split(FilePosition offset, FilePosition size) 61 | { 62 | auto it = InternalSlice(offset, size); 63 | auto& ret = *it; 64 | Split2(offset, std::move(it)); 65 | return ret; 66 | } 67 | 68 | } 69 | 70 | #include "raw_item.binding.hpp" 71 | -------------------------------------------------------------------------------- /src/dumpable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_C9446864_0020_4D2F_8E96_CBC6ADCCA3BE 2 | #define UUID_C9446864_0020_4D2F_8E96_CBC6ADCCA3BE 3 | #pragma once 4 | 5 | #include "utils.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | namespace Neptools 15 | { 16 | 17 | class TxtSerializable; 18 | class Sink; 19 | 20 | class Dumpable : public Libshit::Lua::DynamicObject 21 | { 22 | LIBSHIT_LUA_CLASS; 23 | public: 24 | Dumpable() = default; 25 | Dumpable(const Dumpable&) = delete; 26 | void operator=(const Dumpable&) = delete; 27 | virtual ~Dumpable() = default; 28 | 29 | virtual void Fixup() {}; 30 | virtual FilePosition GetSize() const = 0; 31 | 32 | LIBSHIT_NOLUA 33 | virtual Libshit::NotNullSharedPtr 34 | GetDefaultTxtSerializable(const Libshit::NotNullSharedPtr& thiz); 35 | 36 | void Dump(Sink& os) const { return Dump_(os); } 37 | LIBSHIT_NOLUA 38 | void Dump(Sink&& os) const { return Dump_(os); } 39 | void Dump(const boost::filesystem::path& path) const; 40 | 41 | LIBSHIT_NOLUA 42 | void Inspect(std::ostream& os, unsigned indent = 0) const 43 | { return Inspect_(os, indent); } 44 | LIBSHIT_NOLUA 45 | void Inspect(std::ostream&& os, unsigned indent = 0) const 46 | { return Inspect_(os, indent); } 47 | void Inspect(const boost::filesystem::path& path) const; 48 | std::string Inspect() const; 49 | 50 | protected: 51 | static std::ostream& Indent(std::ostream& os, unsigned indent); 52 | 53 | private: 54 | virtual void Dump_(Sink& sink) const = 0; 55 | virtual void Inspect_(std::ostream& os, unsigned indent) const = 0; 56 | }; 57 | 58 | std::ostream& operator<<(std::ostream& os, const Dumpable& dmp); 59 | 60 | inline Libshit::Lua::DynamicObject& GetDynamicObject(Dumpable& d) { return d; } 61 | 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /tools/vmrun.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if [[ $# -lt 3 ]]; then 4 | echo "Usage: $0 vm.opts test.xml files" >&2 5 | exit 1 6 | fi 7 | 8 | dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 9 | 10 | temp_img=img.img 11 | fifo=fifo 12 | # should set: 13 | # username: ssh login user 14 | # tmp_dir: temp dir inside vm 15 | # src_img: image that will be copied to $temp_img to use 16 | # qemu_opts: additional qemu options (bash array) 17 | # should probably contain: -enable-kvm -nodefaults -m -cpu -smp -rtc 18 | # -drive (with file=$temp_img), -netdev user, -loadvm 19 | # you have to modify this script if you don't want to use user networking 20 | source "$1" 21 | shift 22 | 23 | test_dest="$1" 24 | shift 25 | 26 | set -eEx 27 | function cleanup() { 28 | "$dir/qmp" --path=qemu.sock quit 29 | exit 1 30 | } 31 | trap cleanup ERR SIGTERM SIGINT 32 | 33 | cp --reflink=auto "$src_img" "$temp_img" 34 | 35 | qemu-system-x86_64 \ 36 | "${qemu_opts[@]}" \ 37 | -display none -monitor none \ 38 | -daemonize -qmp unix:qemu.sock,server,nowait 39 | 40 | for i in $(seq 0 4); do 41 | port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') 42 | fwd="$("$dir/qmp" --path=qemu.sock human-monitor-command \ 43 | --command-line="hostfwd_add tcp:127.0.0.1:$port-:22")" 44 | if [[ -z $fwd ]]; then break; fi 45 | done 46 | 47 | scp -o StrictHostKeyChecking=no -P $port "$@" "$username@localhost:$tmp_dir/" 48 | 49 | # the braindead windows server closes connection on EOF, so fake something 50 | rm -f "$fifo" && mkfifo "$fifo" 51 | sleep 60 > "$fifo" & 52 | ssh -o StrictHostKeyChecking=no -p $port $username@localhost \ 53 | "cd $tmp_dir && stcm-editor --ansi-colors --xml-output=test.xml --test -fc --reporters=libshit-junit,console" \ 54 | < "$fifo" 55 | kill %1 56 | 57 | scp -o StrictHostKeyChecking=no -P $port \ 58 | "$username@localhost:$tmp_dir/test.xml" "$test_dest" 59 | 60 | "$dir/qmp" --path=qemu.sock quit 61 | 62 | rm "$temp_img" "$fifo" 63 | -------------------------------------------------------------------------------- /src/format/stcm/data.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::DataItem::TYPE_NAME[] = "neptools.stcm.data_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.stcm.data_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Stcm::DataItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::Stcm::DataItem, ::Neptools::ItemWithChildren>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::DataItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::uint32_t>, LuaGetRef<::uint32_t>, LuaGetRef<::uint32_t>> 19 | >("new"); 20 | bld.AddFunction< 21 | static_cast<::Neptools::Stcm::DataItem & (*)(::Neptools::ItemPointer)>(::Neptools::Stcm::DataItem::CreateAndInsert) 22 | >("create_and_insert"); 23 | bld.AddFunction< 24 | &::Libshit::Lua::GetMember<::Neptools::Stcm::DataItem, ::uint32_t, &::Neptools::Stcm::DataItem::type> 25 | >("get_type"); 26 | bld.AddFunction< 27 | &::Libshit::Lua::SetMember<::Neptools::Stcm::DataItem, ::uint32_t, &::Neptools::Stcm::DataItem::type> 28 | >("set_type"); 29 | bld.AddFunction< 30 | &::Libshit::Lua::GetMember<::Neptools::Stcm::DataItem, ::uint32_t, &::Neptools::Stcm::DataItem::offset_unit> 31 | >("get_offset_unit"); 32 | bld.AddFunction< 33 | &::Libshit::Lua::SetMember<::Neptools::Stcm::DataItem, ::uint32_t, &::Neptools::Stcm::DataItem::offset_unit> 34 | >("set_offset_unit"); 35 | bld.AddFunction< 36 | &::Libshit::Lua::GetMember<::Neptools::Stcm::DataItem, ::uint32_t, &::Neptools::Stcm::DataItem::field_8> 37 | >("get_field_8"); 38 | bld.AddFunction< 39 | &::Libshit::Lua::SetMember<::Neptools::Stcm::DataItem, ::uint32_t, &::Neptools::Stcm::DataItem::field_8> 40 | >("set_field_8"); 41 | 42 | } 43 | static TypeRegister::StateRegister<::Neptools::Stcm::DataItem> reg_neptools_stcm_data_item; 44 | 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /src/format/stcm/header.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_B9D3C4DA_158C_4858_903C_9EBDD92C2CBC 2 | #define UUID_B9D3C4DA_158C_4858_903C_9EBDD92C2CBC 3 | #pragma once 4 | 5 | #include "../raw_item.hpp" 6 | #include 7 | #include 8 | 9 | namespace Neptools::Stcm 10 | { 11 | 12 | class HeaderItem final : public Item 13 | { 14 | LIBSHIT_DYNAMIC_OBJECT; 15 | public: 16 | using MsgType = Libshit::FixedString<0x20-5-1>; 17 | struct Header 18 | { 19 | char magic[5]; 20 | char endian; 21 | MsgType msg; 22 | 23 | boost::endian::little_uint32_t export_offset; 24 | boost::endian::little_uint32_t export_count; 25 | boost::endian::little_uint32_t field_28; 26 | boost::endian::little_uint32_t collection_link_offset; 27 | boost::endian::little_uint32_t field_30; 28 | boost::endian::little_uint32_t expansion_offset; 29 | boost::endian::little_uint32_t expansion_count; 30 | 31 | void Validate(FilePosition file_size) const; 32 | }; 33 | static_assert(sizeof(Header) == 0x3c); 34 | 35 | HeaderItem( 36 | Key k, Context& ctx, const MsgType& msg, 37 | Libshit::NotNull export_sec, 38 | Libshit::NotNull collection_link, uint32_t field_28, 39 | LabelPtr expansion) 40 | : Item{k, ctx}, msg{msg}, export_sec{Libshit::Move(export_sec)}, 41 | collection_link{Libshit::Move(collection_link)}, 42 | expansion{Libshit::Move(expansion)},field_28{field_28} {} 43 | LIBSHIT_NOLUA 44 | HeaderItem(Key k, Context& ctx, const Header& hdr); 45 | static HeaderItem& CreateAndInsert(ItemPointer ptr); 46 | 47 | FilePosition GetSize() const noexcept override { return sizeof(Header); } 48 | 49 | MsgType msg; 50 | Libshit::NotNull export_sec; 51 | Libshit::NotNull collection_link; 52 | LabelPtr expansion; 53 | uint32_t field_28; 54 | 55 | private: 56 | void Dump_(Sink& sink) const override; 57 | void Inspect_(std::ostream& os, unsigned indent) const override; 58 | }; 59 | 60 | } 61 | #endif 62 | -------------------------------------------------------------------------------- /src/format/stcm/gbnl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_C8313FD1_2CD9_4882_BDAD_E751A14AA2DF 2 | #define UUID_C8313FD1_2CD9_4882_BDAD_E751A14AA2DF 3 | #pragma once 4 | 5 | #include "../item.hpp" 6 | #include "../gbnl.hpp" 7 | #include "file.hpp" 8 | 9 | namespace Neptools { class RawItem; } 10 | 11 | namespace Neptools::Stcm 12 | { 13 | 14 | class GbnlItem final : public Item, public Gbnl 15 | { 16 | LIBSHIT_DYNAMIC_OBJECT; 17 | public: 18 | GbnlItem(Key k, Context& ctx, Source src) 19 | : Item{k, ctx}, Gbnl{std::move(src)} 20 | { PostCtor(ctx); } 21 | GbnlItem(Key k, Context& ctx, Endian endian, bool is_gstl, uint32_t flags, 22 | uint32_t field_28, uint32_t field_30, 23 | Libshit::AT type) 24 | : Item{k, ctx}, 25 | Gbnl{endian, is_gstl, flags, field_28, field_30, std::move(type)} 26 | { PostCtor(ctx); } 27 | #if LIBSHIT_WITH_LUA 28 | GbnlItem( 29 | Key k, Context& ctx, Libshit::Lua::StateRef vm, Endian endian, 30 | bool is_gstl, uint32_t flags, uint32_t field_28, uint32_t field_30, 31 | Libshit::AT type, 32 | Libshit::Lua::RawTable messages) 33 | : Item{k, ctx}, 34 | Gbnl{vm, endian, is_gstl, flags, field_28, field_30, std::move(type), 35 | messages} 36 | { PostCtor(ctx); } 37 | #endif 38 | 39 | void Dispose() noexcept override; 40 | 41 | static GbnlItem& CreateAndInsert(ItemPointer ptr); 42 | 43 | void Fixup() override { Gbnl::Fixup(); } 44 | FilePosition GetSize() const noexcept override { return Gbnl::GetSize(); } 45 | 46 | private: 47 | void PostCtor(Context& ctx) noexcept 48 | { 49 | if (auto file = dynamic_cast(&ctx)) 50 | file->SetGbnl(*this); 51 | } 52 | 53 | void Dump_(Sink& sink) const override { Gbnl::Dump_(sink); } 54 | void Inspect_(std::ostream& os, unsigned indent) const override 55 | { Item::Inspect_(os, indent); Gbnl::InspectGbnl(os, indent); } 56 | }; 57 | 58 | inline Libshit::Lua::DynamicObject& GetDynamicObject(GbnlItem& item) 59 | { return static_cast(item); } 60 | 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /src/format/stcm/data.cpp: -------------------------------------------------------------------------------- 1 | #include "data.hpp" 2 | #include "../context.hpp" 3 | #include "../raw_item.hpp" 4 | #include "../../sink.hpp" 5 | #include 6 | 7 | namespace Neptools::Stcm 8 | { 9 | 10 | void DataItem::Header::Validate(FilePosition chunk_size) const 11 | { 12 | #define VALIDATE(x) LIBSHIT_VALIDATE_FIELD("Stcm::DataItem::Header", x) 13 | VALIDATE(type < 0xff); 14 | VALIDATE(length <= chunk_size); 15 | #undef VALIDATE 16 | } 17 | 18 | DataItem::DataItem(Key k, Context& ctx, const Header& raw, size_t chunk_size) 19 | : ItemWithChildren{k, ctx} 20 | { 21 | raw.Validate(chunk_size); 22 | 23 | type = raw.type; 24 | offset_unit = raw.offset_unit; 25 | field_8 = raw.field_8; 26 | } 27 | 28 | DataItem& DataItem::CreateAndInsert(ItemPointer ptr) 29 | { 30 | auto x = RawItem::Get
(ptr); 31 | 32 | auto& ret = x.ritem.SplitCreate( 33 | ptr.offset, x.t, x.ritem.GetSize() - ptr.offset - sizeof(Header)); 34 | if (x.t.length > 0) 35 | ret.MoveNextToChild(x.t.length); 36 | 37 | LIBSHIT_ASSERT(ret.GetSize() == sizeof(Header) + x.t.length); 38 | 39 | // check heuristics 40 | if (!ret.GetChildren().empty()) 41 | DataFactory::Check(ret); 42 | 43 | return ret; 44 | } 45 | 46 | void DataItem::Dump_(Sink& sink) const 47 | { 48 | Header hdr; 49 | hdr.type = type; 50 | hdr.offset_unit = offset_unit; 51 | hdr.field_8 = field_8; 52 | hdr.length = GetSize() - sizeof(Header); 53 | sink.WriteGen(hdr); 54 | 55 | ItemWithChildren::Dump_(sink); 56 | } 57 | 58 | void DataItem::Inspect_(std::ostream& os, unsigned indent) const 59 | { 60 | Item::Inspect_(os, indent); 61 | os << "data(" << type << ", " << offset_unit << ", " << field_8 << ')'; 62 | InspectChildren(os, indent); 63 | } 64 | 65 | FilePosition DataItem::GetSize() const noexcept 66 | { 67 | return ItemWithChildren::GetSize() + sizeof(Header); 68 | } 69 | 70 | void DataItem::Fixup() 71 | { 72 | ItemWithChildren::Fixup_(sizeof(Header)); 73 | } 74 | 75 | void DataFactory::Check(DataItem& it) 76 | { 77 | for (auto f : GetStore()) 78 | if (f(it)) return; 79 | } 80 | 81 | } 82 | 83 | #include "data.binding.hpp" 84 | -------------------------------------------------------------------------------- /src/format/primitive_item.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_2223739B_EEF5_4E62_B610_F34A86369503 2 | #define UUID_2223739B_EEF5_4E62_B610_F34A86369503 3 | #pragma once 4 | 5 | #include "item.hpp" 6 | #include "raw_item.hpp" 7 | #include "sink.hpp" 8 | 9 | namespace Neptools 10 | { 11 | 12 | template 13 | class PrimitiveItem final : public Item 14 | { 15 | static_assert(sizeof(T) == sizeof(DumpT)); 16 | static_assert(sizeof(T) == sizeof(Endian)); 17 | LIBSHIT_DYNAMIC_OBJECT; 18 | public: 19 | using Type = T; 20 | 21 | PrimitiveItem(Key k, Context& ctx, T val) 22 | : Item{k, ctx}, value{val} {} 23 | PrimitiveItem(Key k, Context& ctx, Source src) 24 | : Item{k, ctx} 25 | { 26 | Union u; 27 | src.PreadGen(0, u.dump); 28 | value = u.native; 29 | } 30 | static PrimitiveItem& CreateAndInsert(ItemPointer ptr) 31 | { 32 | auto x = RawItem::GetSource(ptr, -1); 33 | return x.ritem.SplitCreate(ptr.offset, x.src); 34 | } 35 | 36 | FilePosition GetSize() const noexcept override { return sizeof(T); } 37 | 38 | T value; 39 | 40 | private: 41 | union Union 42 | { 43 | T native; 44 | DumpT dump; 45 | }; 46 | 47 | void Dump_(Sink& sink) const override 48 | { 49 | Union u{value}; 50 | sink.WriteGen(Endian{u.dump}); 51 | } 52 | void Inspect_(std::ostream& os, unsigned indent) const override 53 | { 54 | Item::Inspect_(os, indent); 55 | static constexpr const char name[] = { Name..., 0 }; 56 | os << name << '(' << value << ')'; 57 | } 58 | }; 59 | 60 | #define NEPTOOLS_PRIMITIVE_ITEMS(x) \ 61 | x(Int32Item, int32, PrimitiveItem< \ 62 | int32_t, int32_t, boost::endian::little_int32_t, 'i','n','t','3','2'>); \ 63 | x(FloatItem, float, PrimitiveItem< \ 64 | float, int32_t, boost::endian::little_int32_t, 'f','l','o','a','t'>) 65 | #define NEPTOOLS_GEN(cname, lname, ...) \ 66 | using cname LIBSHIT_LUAGEN(fullname="neptools."..#lname.."_item") = __VA_ARGS__ 67 | NEPTOOLS_PRIMITIVE_ITEMS(NEPTOOLS_GEN); 68 | #undef NEPTOOLS_GEN 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/format/stcm/string_data.cpp: -------------------------------------------------------------------------------- 1 | #include "string_data.hpp" 2 | 3 | #include "data.hpp" 4 | #include "../raw_item.hpp" 5 | #include "../../sink.hpp" 6 | 7 | #include 8 | 9 | namespace Neptools::Stcm 10 | { 11 | 12 | Libshit::RefCountedPtr 13 | StringDataItem::MaybeCreateAndReplace(DataItem& it) 14 | { 15 | // string: data(0, x, 1), where x = size/4, size is strlen+1 rounded to 4 bytes 16 | // ignore x == 1: it's probably an int32 17 | if (it.type != 0 || it.offset_unit <= 1 || it.field_8 != 1 || 18 | it.GetChildren().empty() || // only one child 19 | &it.GetChildren().front() != &it.GetChildren().back()) return nullptr; 20 | auto child = dynamic_cast(&it.GetChildren().front()); 21 | if (!child || child->GetSize() != it.offset_unit * 4) return nullptr; 22 | 23 | auto src = child->GetSource(); 24 | auto s = src.ReadCString(); 25 | auto padlen = it.offset_unit * 4 - s.size() - 1; 26 | if (padlen > 4) return nullptr; 27 | char pad[4]; 28 | src.Read(pad, padlen); 29 | // check padding all zero. I don't think it's required, but in the game 30 | // files they're zero filled, + dump will generate zeros, so do not lose 31 | // information by discarding a non-null padding... 32 | for (size_t i = 0; i < padlen; ++i) 33 | if (pad[i] != 0) return nullptr; 34 | 35 | auto sit = it.GetContext()->Create(Libshit::Move(s)); 36 | it.Replace(sit); 37 | return Libshit::Move(sit); 38 | } 39 | 40 | FilePosition StringDataItem::GetSize() const noexcept 41 | { 42 | return sizeof(DataItem::Header) + (string.length() + 1 + 3) / 4 * 4; 43 | } 44 | 45 | void StringDataItem::Dump_(Sink& sink) const 46 | { 47 | auto len = (string.length() + 1 + 3) / 4 * 4; 48 | sink.WriteGen(DataItem::Header{0, len/4, 1, len}); 49 | sink.Write(string); 50 | sink.Pad(len - string.length()); 51 | } 52 | 53 | void StringDataItem::Inspect_(std::ostream& os, unsigned indent) const 54 | { 55 | Item::Inspect_(os, indent); 56 | os << "string_data(" << Libshit::Quoted(string) << ')'; 57 | } 58 | 59 | static Stcm::DataFactory reg{[](DataItem& it) { 60 | return !!StringDataItem::MaybeCreateAndReplace(it); }}; 61 | 62 | } 63 | 64 | #include "string_data.binding.hpp" 65 | -------------------------------------------------------------------------------- /src/format/stcm/expansion.cpp: -------------------------------------------------------------------------------- 1 | #include "expansion.hpp" 2 | #include "../context.hpp" 3 | #include "../raw_item.hpp" 4 | #include "../cstring_item.hpp" 5 | #include "../../sink.hpp" 6 | 7 | namespace Neptools::Stcm 8 | { 9 | 10 | void ExpansionItem::Header::Validate(FilePosition file_size) const 11 | { 12 | #define VALIDATE(x) LIBSHIT_VALIDATE_FIELD("Stcm::ExpansionItemItem::Header", x) 13 | VALIDATE(name < file_size); 14 | VALIDATE(ptr == 0); 15 | for (const auto& p : pad) VALIDATE(p == 0); 16 | #undef VALIDATE 17 | } 18 | 19 | ExpansionItem::ExpansionItem(Key k, Context& ctx, const Header& hdr) 20 | : Item{k, ctx}, name{Libshit::EmptyNotNull{}} 21 | { 22 | hdr.Validate(ctx.GetSize()); 23 | 24 | index = hdr.index; 25 | name = ctx.GetLabelTo(hdr.name); 26 | } 27 | 28 | ExpansionItem& ExpansionItem::CreateAndInsert(ItemPointer ptr) 29 | { 30 | auto x = RawItem::Get
(ptr); 31 | auto& ret = x.ritem.SplitCreate(ptr.offset, x.t); 32 | 33 | MaybeCreate(ret.name->GetPtr()); 34 | 35 | return ret; 36 | } 37 | 38 | void ExpansionItem::Dump_(Sink& sink) const 39 | { 40 | Header hdr{}; 41 | hdr.index = index; 42 | hdr.name = ToFilePos(name->GetPtr()); 43 | sink.WriteGen(hdr); 44 | } 45 | 46 | void ExpansionItem::Inspect_(std::ostream& os, unsigned indent) const 47 | { 48 | Item::Inspect_(os, indent); 49 | os << "expansion(" << index << ", " << PrintLabel(name) << ")"; 50 | } 51 | 52 | 53 | ExpansionsItem& ExpansionsItem::CreateAndInsert( 54 | ItemPointer ptr, uint32_t count) 55 | { 56 | auto& ret = ptr.AsChecked().SplitCreate( 57 | ptr.offset); 58 | ret.MoveNextToChild(count * sizeof(ExpansionItem::Header)); 59 | auto it = ret.GetChildren().begin(); 60 | 61 | for (uint32_t i = 0; i < count; ++i) 62 | { 63 | auto lbl = ret.GetContext()->CreateLabelFallback("expansion", *it); 64 | auto& exp = ExpansionItem::CreateAndInsert(lbl->GetPtr()); 65 | it = std::next(exp.Iterator()); 66 | } 67 | return ret; 68 | } 69 | 70 | void ExpansionsItem::Inspect_(std::ostream& os, unsigned indent) const 71 | { 72 | Item::Inspect_(os, indent); 73 | os << "expansions()"; 74 | InspectChildren(os, indent); 75 | } 76 | 77 | } 78 | 79 | #include "expansion.binding.hpp" 80 | -------------------------------------------------------------------------------- /src/format/stcm/exports.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_3260390C_7569_4E66_B6BA_CC5CC7E58F9A 2 | #define UUID_3260390C_7569_4E66_B6BA_CC5CC7E58F9A 3 | #pragma once 4 | 5 | #include "../item.hpp" 6 | #include "../../source.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Neptools::Stcm 13 | { 14 | 15 | class HeaderItem; 16 | class ExportsItem final : public Item 17 | { 18 | LIBSHIT_DYNAMIC_OBJECT; 19 | public: 20 | enum LIBSHIT_LUAGEN() Type : uint32_t 21 | { 22 | CODE = 0, 23 | DATA = 1, 24 | }; 25 | 26 | struct Entry 27 | { 28 | boost::endian::little_uint32_t type; 29 | Libshit::FixedString<0x20> name; 30 | boost::endian::little_uint32_t offset; 31 | 32 | void Validate(FilePosition file_size) const; 33 | }; 34 | static_assert(sizeof(Entry) == 0x28); 35 | 36 | struct EntryType : public RefCounted, public Libshit::Lua::DynamicObject 37 | { 38 | Type type; 39 | Libshit::FixedString<0x20> name; 40 | Libshit::NotNull lbl; 41 | 42 | EntryType(Type type, const Libshit::FixedString<0x20>& name, 43 | Libshit::NotNull lbl) 44 | : type{type}, name{std::move(name)}, lbl{std::move(lbl)} {} 45 | 46 | LIBSHIT_DYNAMIC_OBJECT; 47 | }; 48 | using VectorEntry = Libshit::NotNull>; 49 | 50 | ExportsItem(Key k, Context& ctx) : Item{k, ctx} {} 51 | ExportsItem(Key k, Context& ctx, Source src, uint32_t export_count); 52 | ExportsItem(Key k, Context& ctx, Libshit::AT> entries) 53 | : Item{k, ctx}, entries{std::move(entries.Get())} {} 54 | static ExportsItem& CreateAndInsert(ItemPointer ptr, uint32_t export_count); 55 | 56 | FilePosition GetSize() const noexcept override 57 | { return sizeof(Entry) * entries.size(); } 58 | 59 | LIBSHIT_LUAGEN(get="::Libshit::Lua::GetSmartOwnedMember") 60 | std::vector entries; 61 | 62 | void Dispose() noexcept override; 63 | 64 | private: 65 | void Dump_(Sink& sink) const override; 66 | void Inspect_(std::ostream& os, unsigned indent) const override; 67 | void Parse_(Context& ctx, Source& src, uint32_t export_count); 68 | }; 69 | 70 | } 71 | 72 | LIBSHIT_ENUM(Neptools::Stcm::ExportsItem::ExportsItem::Type); 73 | #endif 74 | -------------------------------------------------------------------------------- /src/pattern.cpp: -------------------------------------------------------------------------------- 1 | #include "pattern.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #define LIBSHIT_LOG_NAME "pattern" 8 | #include 9 | 10 | namespace Neptools 11 | { 12 | 13 | static bool CheckPattern( 14 | const Byte* ptr, const Byte* pattern, const Byte* mask, size_t len) 15 | { 16 | while (len--) 17 | if ((*ptr++ & *mask++) != *pattern++) 18 | return false; 19 | return true; 20 | } 21 | 22 | const Byte* Pattern::MaybeFind(std::string_view data) const noexcept 23 | { 24 | size_t max_len = 0, max_i = 0; 25 | size_t start_i = 0; 26 | for (size_t i = 0; i < size; ++i) 27 | if (mask[i] == 0xff) 28 | { 29 | if (i - start_i + 1 > max_len) 30 | { 31 | max_len = i - start_i + 1; 32 | max_i = start_i; 33 | } 34 | } 35 | else 36 | start_i = i+1; 37 | 38 | LIBSHIT_ASSERT(max_i + max_len <= size); 39 | boost::algorithm::boyer_moore bm{ 40 | pattern + max_i, pattern + max_i + max_len}; 41 | 42 | auto ptr = reinterpret_cast(data.data()) + max_i; 43 | auto ptr_end = reinterpret_cast(data.data()) + data.length() - 44 | (size - max_len - max_i); 45 | const Byte* res = nullptr; 46 | 47 | while (true) 48 | { 49 | DBG(4) << "finding " << static_cast(ptr) << "..." 50 | << static_cast(ptr_end) << std::endl; 51 | auto match = bm(ptr, ptr_end) 52 | #if BOOST_VERSION >= 106200 53 | // I hope you die a horrible death 54 | // https://github.com/boostorg/algorithm/commit/205f5ff4bbb00ece289892089a6c94c975e97ca2 55 | .first 56 | #endif 57 | ; 58 | DBG(4) << "match @" << static_cast(match) << std::endl; 59 | if (match == ptr_end) break; 60 | 61 | if (CheckPattern(match - max_i, pattern, mask, size)) 62 | if (res) 63 | { 64 | // todo? 65 | WARN << "Multiple matches for pattern " 66 | << static_cast(res) << " and " 67 | << static_cast(match - max_i) << std::endl; 68 | return nullptr; 69 | } 70 | else 71 | res = match - max_i; 72 | ptr = match + 1; 73 | } 74 | DBG(3) << "Found pattern @" << static_cast(res) << std::endl; 75 | return res; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/dumpable.cpp: -------------------------------------------------------------------------------- 1 | #include "dumpable.hpp" 2 | 3 | #include "sink.hpp" 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #if LIBSHIT_OS_IS_WINDOWS 11 | # include 12 | # define WIN32_LEAN_AND_MEAN 13 | # define NOMINMAX 14 | #include 15 | 16 | namespace 17 | { 18 | struct DeleteOnExitHelper 19 | { 20 | ~DeleteOnExitHelper() 21 | { 22 | for (auto& p : pths) 23 | DeleteFileW(p.c_str()); 24 | } 25 | 26 | std::vector pths; 27 | }; 28 | void DeleteOnExit(boost::filesystem::path pth) 29 | { 30 | static DeleteOnExitHelper hlp; 31 | hlp.pths.push_back(std::move(pth)); 32 | } 33 | } 34 | #endif 35 | 36 | namespace Neptools 37 | { 38 | 39 | Libshit::NotNullSharedPtr 40 | Dumpable::GetDefaultTxtSerializable( 41 | const Libshit::NotNullSharedPtr& thiz) 42 | { LIBSHIT_THROW(Libshit::DecodeError, "Not txt-serializable file"); } 43 | 44 | void Dumpable::Dump(const boost::filesystem::path& path) const 45 | { 46 | #if LIBSHIT_OS_IS_VITA 47 | // no unique_path on vita 48 | Dump(*Sink::ToFile(path, GetSize())); 49 | #else 50 | auto path2 = path; 51 | { 52 | auto sink = Sink::ToFile(path2+=boost::filesystem::unique_path(), GetSize()); 53 | Dump(*sink); 54 | } 55 | 56 | #if LIBSHIT_OS_IS_WINDOWS 57 | if (LIBSHIT_OS_IS_WINDOWS && boost::filesystem::is_regular_file(path)) 58 | { 59 | auto path3 = path; 60 | boost::filesystem::rename(path, path3+=boost::filesystem::unique_path()); 61 | if (!DeleteFileW(path3.c_str()) && GetLastError() == ERROR_ACCESS_DENIED) 62 | DeleteOnExit(std::move(path3)); 63 | } 64 | #endif 65 | boost::filesystem::rename(path2, path); 66 | #endif 67 | } 68 | 69 | void Dumpable::Inspect(const boost::filesystem::path& path) const 70 | { 71 | return Inspect(OpenOut(path)); 72 | } 73 | 74 | std::ostream& Dumpable::Indent(std::ostream& os, unsigned indent) 75 | { 76 | std::ostreambuf_iterator it{os}; 77 | for (size_t i = 0; i < 2*indent; ++i) *it = ' '; 78 | return os; 79 | } 80 | 81 | 82 | std::ostream& operator<<(std::ostream& os, const Dumpable& dmp) 83 | { 84 | dmp.Inspect(os); 85 | return os; 86 | } 87 | 88 | std::string Dumpable::Inspect() const 89 | { 90 | std::stringstream ss; 91 | Inspect(ss); 92 | return ss.str(); 93 | } 94 | 95 | } 96 | 97 | #include "dumpable.binding.hpp" 98 | -------------------------------------------------------------------------------- /src/format/context.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Context::TYPE_NAME[] = "neptools.context"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.context 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Context>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::Context, ::Neptools::ItemWithChildren>(); 16 | 17 | bld.AddFunction< 18 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(const std::string &) const>(&::Neptools::Context::GetLabel) 19 | >("get_label"); 20 | bld.AddFunction< 21 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(std::string, ::Neptools::ItemPointer)>(&::Neptools::Context::CreateLabel) 22 | >("create_label"); 23 | bld.AddFunction< 24 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(const std::string &, ::Neptools::ItemPointer)>(&::Neptools::Context::CreateLabelFallback), 25 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(const std::string &, ::Neptools::FilePosition)>(&::Neptools::Context::CreateLabelFallback) 26 | >("create_label_fallback"); 27 | bld.AddFunction< 28 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(std::string, ::Neptools::ItemPointer)>(&::Neptools::Context::CreateOrSetLabel) 29 | >("create_or_set_label"); 30 | bld.AddFunction< 31 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(std::string)>(&::Neptools::Context::GetOrCreateDummyLabel) 32 | >("get_or_create_dummy_label"); 33 | bld.AddFunction< 34 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(::Neptools::ItemPointer)>(&::Neptools::Context::GetLabelTo), 35 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(::Neptools::FilePosition)>(&::Neptools::Context::GetLabelTo), 36 | static_cast<::Libshit::NotNull<::Neptools::LabelPtr> (::Neptools::Context::*)(::Neptools::FilePosition, const std::string &)>(&::Neptools::Context::GetLabelTo) 37 | >("get_label_to"); 38 | bld.AddFunction< 39 | static_cast<::Neptools::ItemPointer (::Neptools::Context::*)(::Neptools::FilePosition) const noexcept>(&::Neptools::Context::GetPointer) 40 | >("get_pointer"); 41 | 42 | } 43 | static TypeRegister::StateRegister<::Neptools::Context> reg_neptools_context; 44 | 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /src/format/context.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_C2DF26B7_DE7D_47B8_BAEE_9F6EEBB12891 2 | #define UUID_C2DF26B7_DE7D_47B8_BAEE_9F6EEBB12891 3 | #pragma once 4 | 5 | #include "item.hpp" 6 | #include "../dumpable.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Neptools 13 | { 14 | 15 | class Context : public ItemWithChildren 16 | { 17 | LIBSHIT_LUA_CLASS; 18 | public: 19 | Context(); 20 | ~Context() override; 21 | 22 | void Fixup() override; 23 | 24 | template 25 | LIBSHIT_NOLUA Libshit::NotNull> Create(Args&&... args) 26 | { 27 | return Libshit::MakeSmart( 28 | Item::Key{}, *this, std::forward(args)...); 29 | } 30 | 31 | Libshit::NotNull GetLabel(const std::string& name) const; 32 | Libshit::NotNull CreateLabel(std::string name, ItemPointer ptr); 33 | Libshit::NotNull CreateLabelFallback( 34 | const std::string& name, ItemPointer ptr); 35 | Libshit::NotNull CreateLabelFallback( 36 | const std::string& name, FilePosition pos) 37 | { return CreateLabelFallback(name, GetPointer(pos)); } 38 | 39 | Libshit::NotNull CreateOrSetLabel(std::string name, ItemPointer ptr); 40 | Libshit::NotNull GetOrCreateDummyLabel(std::string name); 41 | 42 | Libshit::NotNull GetLabelTo(ItemPointer ptr); 43 | Libshit::NotNull GetLabelTo(FilePosition pos) 44 | { return GetLabelTo(GetPointer(pos)); } 45 | 46 | Libshit::NotNull GetLabelTo( 47 | FilePosition pos, const std::string& name); 48 | 49 | ItemPointer GetPointer(FilePosition pos) const noexcept; 50 | 51 | void Dispose() noexcept override; 52 | 53 | protected: 54 | void SetupParseFrom(Item& item); 55 | 56 | private: 57 | friend class Item; 58 | 59 | // properties needed: stable pointers 60 | using LabelsMap = boost::intrusive::set< 61 | Label, 62 | boost::intrusive::base_hook, 63 | boost::intrusive::constant_time_size, 64 | boost::intrusive::key_of_value>; 65 | LabelsMap labels; 66 | 67 | // properties needed: sorted 68 | using PointerMap = std::map; 69 | PointerMap pmap; 70 | }; 71 | 72 | struct PrintLabelStruct { const Label* label; }; 73 | std::ostream& operator<<(std::ostream& os, PrintLabelStruct label); 74 | inline PrintLabelStruct PrintLabel(const LabelPtr& label) 75 | { return {label.get()}; } 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/windows_server/hook.cpp: -------------------------------------------------------------------------------- 1 | #include "hook.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | #define LIBSHIT_LOG_NAME "hook" 7 | #include 8 | 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | 12 | namespace Neptools 13 | { 14 | 15 | Byte* image_base; 16 | static HANDLE heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); 17 | 18 | static constexpr size_t JMP_SIZE = 5; 19 | 20 | size_t GetImageSize() noexcept 21 | { 22 | auto dos_hdr = reinterpret_cast(image_base); 23 | auto hdr = reinterpret_cast(image_base + dos_hdr->e_lfanew); 24 | DBG(1) << "Image size: " << hdr->OptionalHeader.SizeOfImage << std::endl; 25 | return hdr->OptionalHeader.SizeOfImage; 26 | } 27 | 28 | Byte* GetEntryPoint() noexcept 29 | { 30 | auto dos_hdr = reinterpret_cast(image_base); 31 | auto hdr = reinterpret_cast(image_base + dos_hdr->e_lfanew); 32 | auto ret = image_base + hdr->OptionalHeader.AddressOfEntryPoint; 33 | DBG(1) << "OEP: " << ret << std::endl; 34 | return ret; 35 | } 36 | 37 | void* Hook(void* fun, void* dst, size_t copy) 38 | { 39 | DBG(2) << "Hooking " << fun << " to " << dst << " (" << copy << " bytes)" 40 | << std::endl; 41 | 42 | char* addr = reinterpret_cast(fun); 43 | 44 | char* ret = nullptr; 45 | if (copy) 46 | { 47 | ret = static_cast(HeapAlloc(heap, 0, copy + JMP_SIZE)); 48 | if (!ret) LIBSHIT_THROW(std::bad_alloc, std::make_tuple()); 49 | memcpy(ret, addr, copy); 50 | ret[copy] = 0xe9; // jmp 51 | auto base = ret + copy + JMP_SIZE; 52 | auto tgt = addr + copy; 53 | As(ret+copy+1) = tgt - base; 54 | } 55 | 56 | try 57 | { 58 | Unprotect up{addr, 5}; 59 | addr[0] = 0xe9; // jmp 60 | As(addr+1) = reinterpret_cast(dst) - addr - JMP_SIZE; 61 | } 62 | catch (...) 63 | { 64 | if (ret) HeapFree(heap, 0, ret); 65 | throw; 66 | } 67 | 68 | DBG(4) << "done" << std::endl; 69 | return ret; 70 | } 71 | 72 | Unprotect::Unprotect(void* ptr, size_t len) : ptr{ptr}, len{len} 73 | { 74 | if (!VirtualProtect(ptr, len, PAGE_EXECUTE_READWRITE, &orig_prot)) 75 | LIBSHIT_THROW(std::runtime_error, "Unprotect: VirtualProtect"); 76 | } 77 | 78 | Unprotect::~Unprotect() 79 | { 80 | if (!VirtualProtect(ptr, len, orig_prot, &orig_prot)) 81 | MessageBoxA(nullptr, "Failed to unprotect memory", "Neptools", 82 | MB_OK | MB_ICONERROR); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/format/builder.lua: -------------------------------------------------------------------------------- 1 | local setfenv, setmetatable, typename, match, gsub, format, ipairs, error = 2 | setfenv, setmetatable, typename, string.match, string.gsub, string.format, ipairs, error 3 | assert(setfenv, "no setfenv") -- will fail on plain lua 5.2+ 4 | 5 | local get_ctx = neptools.item.get_context 6 | local get_children = neptools.item_with_children.get_children 7 | 8 | local helpers = {} 9 | -- lazy load table 10 | -- When this script runs, only items and item_with_children is registered. 11 | -- We would need to run this script at the very end of registration phase, but 12 | -- that would fuck up inheritance... 13 | local function gen_helpers(tbl, ns) 14 | for k,v in pairs(ns) do 15 | if match(k, "_item$") then 16 | tbl[gsub(k, "_item$", "")] = v.new 17 | end 18 | end 19 | end 20 | 21 | local function get_helpers(typename) 22 | local tbl = helpers[typename] 23 | if tbl then return tbl end 24 | 25 | tbl = {} 26 | gen_helpers(tbl, neptools) 27 | if typename == "neptools.stcm.file" then 28 | gen_helpers(tbl, neptools.stcm) 29 | tbl.call = tbl.instruction -- alias 30 | elseif typename == "neptools.stsc.file" then 31 | gen_helpers(tbl, neptools.stsc) 32 | function tbl.instruction(ctx, opcode, ...) 33 | return neptools.stsc.instruction_item[ctx.flavor][opcode]. 34 | new(ctx, opcode, ...) 35 | end 36 | else 37 | error("unknown type "..typename) 38 | end 39 | 40 | helpers[typename] = tbl 41 | return tbl 42 | end 43 | 44 | local function build(item, fun) 45 | local get_label = neptools.context.get_or_create_dummy_label 46 | local create_label = neptools.context.create_or_set_label 47 | 48 | local ctx = get_ctx(item) 49 | local children = get_children(item) 50 | local labels = {} 51 | local function defer_label(name, offs) 52 | labels[#labels+1] = { name, offs or 0 } 53 | end 54 | 55 | local function add(item) 56 | children:push_back(item) 57 | for i,v in ipairs(labels) do 58 | create_label(ctx, v[1], item, v[2]) 59 | labels[i] = nil 60 | end 61 | return item 62 | end 63 | 64 | local tbl = { 65 | label = defer_label, 66 | l = function(n) return get_label(ctx, n) end, 67 | add = add, 68 | __index = _G, 69 | __newindex = error, 70 | } 71 | 72 | -- helpers 73 | for k,v in pairs(get_helpers(typename(ctx))) do 74 | tbl[k] = function(...) return add(v(ctx, ...)) end 75 | end 76 | 77 | setfenv(fun, setmetatable(tbl, tbl)) 78 | fun() 79 | if labels[1] then 80 | error(format("label %q after last item", labels[1][1])) 81 | end 82 | if ctx == item then ctx:fixup() end -- todo 83 | return ctx 84 | end 85 | 86 | return build 87 | -------------------------------------------------------------------------------- /src/format/stcm/expansion.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::ExpansionItem::TYPE_NAME[] = "neptools.stcm.expansion_item"; 7 | 8 | const char ::Neptools::Stcm::ExpansionsItem::TYPE_NAME[] = "neptools.stcm.expansions_item"; 9 | 10 | namespace Libshit::Lua 11 | { 12 | 13 | // class neptools.stcm.expansion_item 14 | template<> 15 | void TypeRegisterTraits<::Neptools::Stcm::ExpansionItem>::Register(TypeBuilder& bld) 16 | { 17 | bld.Inherit<::Neptools::Stcm::ExpansionItem, ::Neptools::Item>(); 18 | 19 | bld.AddFunction< 20 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::ExpansionItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::uint32_t>, LuaGetRef<::Neptools::LabelPtr>> 21 | >("new"); 22 | bld.AddFunction< 23 | static_cast<::Neptools::Stcm::ExpansionItem & (*)(::Neptools::ItemPointer)>(::Neptools::Stcm::ExpansionItem::CreateAndInsert) 24 | >("create_and_insert"); 25 | bld.AddFunction< 26 | &::Libshit::Lua::GetMember<::Neptools::Stcm::ExpansionItem, ::uint32_t, &::Neptools::Stcm::ExpansionItem::index> 27 | >("get_index"); 28 | bld.AddFunction< 29 | &::Libshit::Lua::SetMember<::Neptools::Stcm::ExpansionItem, ::uint32_t, &::Neptools::Stcm::ExpansionItem::index> 30 | >("set_index"); 31 | bld.AddFunction< 32 | &::Libshit::Lua::GetMember<::Neptools::Stcm::ExpansionItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::ExpansionItem::name> 33 | >("get_name"); 34 | bld.AddFunction< 35 | &::Libshit::Lua::SetMember<::Neptools::Stcm::ExpansionItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::ExpansionItem::name> 36 | >("set_name"); 37 | 38 | } 39 | static TypeRegister::StateRegister<::Neptools::Stcm::ExpansionItem> reg_neptools_stcm_expansion_item; 40 | 41 | // class neptools.stcm.expansions_item 42 | template<> 43 | void TypeRegisterTraits<::Neptools::Stcm::ExpansionsItem>::Register(TypeBuilder& bld) 44 | { 45 | bld.Inherit<::Neptools::Stcm::ExpansionsItem, ::Neptools::ItemWithChildren>(); 46 | 47 | bld.AddFunction< 48 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::ExpansionsItem>::Make, LuaGetRef<::Neptools::Context &>> 49 | >("new"); 50 | bld.AddFunction< 51 | static_cast<::Neptools::Stcm::ExpansionsItem & (*)(::Neptools::ItemPointer, ::uint32_t)>(::Neptools::Stcm::ExpansionsItem::CreateAndInsert) 52 | >("create_and_insert"); 53 | 54 | } 55 | static TypeRegister::StateRegister<::Neptools::Stcm::ExpansionsItem> reg_neptools_stcm_expansions_item; 56 | 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | The scripts in this folder are used by a jenkins slave to build and test 2 | neptools. To use it you'll need an amd64 sysroot, a qemu image of win 7 (or 3 | later) with ssh, wine, msvc includes+libs, patched clang, gcc, and probably 4 | else. Documetation is mostly non-existing. 5 | 6 | Sysroot creation 7 | ================ 8 | 9 | You need docker to run this script, it will place the base sysroot in your 10 | working directory. Readline and its deps (ncurses, tinfo) are only required by 11 | the ljx executble, they're not linked into stcm-editor. 12 | 13 | ```sh 14 | docker run --rm jimbly/steamrt-amd64-gcc bash -c 'apt-get update >&2 && apt-get -y install libreadline6-dev >&2 && dpkg-query -L libc6 libc6-dev linux-libc-dev libgcc1 gcc-4.6 libreadline6-dev libncurses5-dev libtinfo-dev | grep -E "^(/usr/include/|/usr/lib/|/lib/)" | xargs tar cvh --no-recursion' | tar x 15 | rm usr/lib/x86_64-linux-gnu/lib{readline,ncurses,tinfo}.so 16 | mv usr/lib/x86_64-linux-gnu/lib{*_nonshared,readline,ncurses,tinfo}.a ./ 17 | rm usr/lib/x86_64-linux-gnu/*.a 18 | rm -r usr/lib/x86_64-linux-gnu/{gconv,libc} 19 | rm usr/lib/gcc/x86_64-linux-gnu/*/{lto1,lto-wrapper} 20 | mv lib{*_nonshared,readline,ncurses,tinfo}.a usr/lib/x86_64-linux-gnu/ 21 | ``` 22 | 23 | To compile libc++, you'll need an [llvm git clone][llvm-git] at `release/8.x` or 24 | manually downloading and unpacking a libc++ and libc++abi tarball to a 25 | directory. 26 | 27 | ```sh 28 | LLVM="/path/to/llvm/clone" 29 | SYSROOT="/path/to/sysroot" 30 | mkdir tmp 31 | cd tmp 32 | rm *.o 33 | clang++ --sysroot "$SYSROOT" -g -DNDEBUG -D_GNU_SOURCE -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fPIC -fvisibility-inlines-hidden -std=c++11 -ffunction-sections -fdata-sections -O3 -flto=thin -DLIBCXX_BUILDING_LIBCXXABI -nostdinc++ -I "$LLVM"/libcxxabi/include -I "$LLVM"/libcxx/lib -I "$LLVM"/libcxx/include -c "$LLVM"/libcxx/src/*.cpp 34 | clang++ --sysroot "$SYSROOT" -g -D_GNU_SOURCE -D_LIBCPP_DISABLE_EXTERN_TEMPLATE -D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS -D_LIBCXXABI_BUILDING_LIBRARY -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fPIC -fvisibility-inlines-hidden -std=c++11 -ffunction-sections -fdata-sections -O3 -flto=thin -nostdinc++ -fstrict-aliasing -funwind-tables -D_DEBUG -I "$LLVM"/libcxxabi/src -I "$LLVM"/libcxxabi/include -I "$LLVM"/libcxx/include -c "$LLVM"/libcxxabi/src/*.cpp 35 | llvm-ar rs libc++.a *.o 36 | mv libc++.a "$SYSROOT"/usr/lib 37 | mkdir -p "$SYSROOT"/usr/include/c++/v1 38 | cp -R "$LLVM"/libcxx{,abi}/include/* "$SYSROOT"/usr/include/c++/v1 39 | rm "$SYSROOT"/usr/include/c++/v1/{CMakeLists.txt,__config_site.in} 40 | ``` 41 | 42 | [llvm-git]: https://github.com/llvm/llvm-project 43 | -------------------------------------------------------------------------------- /src/format/stsc/header.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_F87DF453_742A_4C38_8660_ABC81ACB04B8 2 | #define UUID_F87DF453_742A_4C38_8660_ABC81ACB04B8 3 | #pragma once 4 | 5 | #include "file.hpp" 6 | #include "../../source.hpp" 7 | #include "../item.hpp" 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace Neptools::Stsc 14 | { 15 | 16 | class HeaderItem final : public Item 17 | { 18 | LIBSHIT_DYNAMIC_OBJECT; 19 | public: 20 | struct Header 21 | { 22 | char magic[4]; 23 | boost::endian::little_uint32_t entry_point; 24 | boost::endian::little_uint32_t flags; 25 | 26 | void Validate(FilePosition size) const; 27 | }; 28 | static_assert(sizeof(Header) == 12); 29 | 30 | struct ExtraHeader2Ser 31 | { 32 | boost::endian::little_uint16_t field_0; 33 | boost::endian::little_uint16_t field_2; 34 | boost::endian::little_uint16_t field_4; 35 | boost::endian::little_uint16_t field_6; 36 | boost::endian::little_uint16_t field_8; 37 | boost::endian::little_uint16_t field_a; 38 | boost::endian::little_uint16_t field_c; 39 | }; 40 | static_assert(sizeof(ExtraHeader2Ser) == 14); 41 | 42 | class LIBSHIT_LUAGEN(name="extra_headers_2") ExtraHeaders2 43 | : public Libshit::Lua::ValueObject 44 | { 45 | LIBSHIT_LUA_CLASS; 46 | 47 | public: 48 | std::uint16_t field_0; 49 | std::uint16_t field_2; 50 | std::uint16_t field_4; 51 | std::uint16_t field_6; 52 | std::uint16_t field_8; 53 | std::uint16_t field_a; 54 | std::uint16_t field_c; 55 | 56 | ExtraHeaders2( 57 | std::uint16_t field_0, std::uint16_t field_2, std::uint16_t field_4, 58 | std::uint16_t field_6, std::uint16_t field_8, std::uint16_t field_a, 59 | std::uint16_t field_c) noexcept 60 | : field_0{field_0}, field_2{field_2}, field_4{field_4}, 61 | field_6{field_6}, field_8{field_8}, field_a{field_a}, 62 | field_c{field_c} {} 63 | }; 64 | 65 | HeaderItem(Key k, Context& ctx, Source src); 66 | HeaderItem( 67 | Key k, Context& ctx, Libshit::NotNull entry_point, 68 | std::optional extra_headers_1, 69 | std::optional extra_headers_2, 70 | std::optional extra_headers_4); 71 | static HeaderItem& CreateAndInsert(ItemPointer ptr, Flavor flavor); 72 | 73 | FilePosition GetSize() const noexcept override; 74 | 75 | Libshit::NotNull entry_point; 76 | 77 | std::optional> extra_headers_1; 78 | std::optional extra_headers_2; 79 | std::optional extra_headers_4; 80 | 81 | private: 82 | void Parse_(Context& ctx, Source& src); 83 | void Dump_(Sink& sink) const override; 84 | void Inspect_(std::ostream& os, unsigned indent) const override; 85 | }; 86 | 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/windows_server/cpk.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_6D829400_DD15_49CC_B55F_6F2565105828 2 | #define UUID_6D829400_DD15_49CC_B55F_6F2565105828 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "../source.hpp" 11 | 12 | #define WIN32_LEAN_AND_MEAN 13 | #define NOMINMAX 14 | #include 15 | 16 | namespace Neptools 17 | { 18 | 19 | #define GEN_FWD(name, fld) \ 20 | template inline auto name(Args&&... args) \ 21 | { return (this->*fld)(std::forward(args)...); } 22 | 23 | struct PakEntry 24 | { 25 | unsigned field_000; 26 | unsigned file_index; 27 | char file_name[260]; 28 | unsigned field_10c; 29 | size_t compressed_size; 30 | size_t uncompressed_size; 31 | unsigned is_compressed; 32 | unsigned field_11c; 33 | }; 34 | static_assert(sizeof(PakEntry) == 0x120); 35 | 36 | struct CpkHandlerFileInfo 37 | { 38 | unsigned index; 39 | HANDLE handle; 40 | bool is_valid; 41 | PakEntry entry; 42 | unsigned data_start; 43 | unsigned read_pos; 44 | void* huffmann_hdr; 45 | void* block; 46 | int decoded_block_index; 47 | }; 48 | static_assert(sizeof(CpkHandlerFileInfo) == 0x140); 49 | 50 | struct CpkHandler 51 | { 52 | unsigned vect0_begin, vect0_end, vect0_capacity; 53 | using FileInfo = CpkHandlerFileInfo; 54 | std::vector entry_vect; 55 | unsigned vect2_begin, vect2_end, vect2_capacity; 56 | char* data; 57 | char* hash_entries; 58 | char* names; 59 | char* basename; 60 | unsigned last_error; 61 | CRITICAL_SECTION crit_sec; 62 | 63 | char __thiscall OpenFile(const char* fname, size_t* out); 64 | char __thiscall CloseFile(unsigned index); 65 | char __thiscall Read(unsigned index, char* dst, size_t dst_size, 66 | size_t* out_size_read); 67 | 68 | using OpenFilePtr = decltype(&CpkHandler::OpenFile); 69 | using CloseFilePtr = decltype(&CpkHandler::CloseFile); 70 | using ReadPtr = decltype(&CpkHandler::Read); 71 | 72 | static CpkHandler::OpenFilePtr orig_open_file; 73 | static CpkHandler::CloseFilePtr orig_close_file; 74 | static CpkHandler::ReadPtr orig_read; 75 | 76 | GEN_FWD(OrigOpenFile, orig_open_file); 77 | GEN_FWD(OrigCloseFile, orig_close_file); 78 | GEN_FWD(OrigRead, orig_read); 79 | 80 | static void Init(); 81 | 82 | Source GetSource(const char* fname); 83 | 84 | private: 85 | FileInfo& GetEntryVect(size_t* out); 86 | bool OpenFsFile( 87 | const char* fname, const boost::filesystem::path& pth, size_t* out); 88 | bool OpenTxtFile( 89 | const char* fname, const boost::filesystem::path& pth, size_t* out); 90 | }; 91 | static_assert(sizeof(CpkHandler) == 0x50); 92 | 93 | LIBSHIT_GEN_EXCEPTION_TYPE(CpkError, std::runtime_error); 94 | 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /src/format/stcm/exports.cpp: -------------------------------------------------------------------------------- 1 | #include "exports.hpp" 2 | #include "data.hpp" 3 | #include "header.hpp" 4 | #include "instruction.hpp" 5 | #include "../context.hpp" 6 | #include "../../sink.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Neptools::Stcm 13 | { 14 | 15 | void ExportsItem::Entry::Validate(FilePosition file_size) const 16 | { 17 | #define VALIDATE(x) LIBSHIT_VALIDATE_FIELD("Stcm::ExportsItem::Entry", x) 18 | VALIDATE(type == Type::CODE || type == Type::DATA); 19 | VALIDATE(name.is_valid()); 20 | VALIDATE(offset < file_size); 21 | #undef VALIDATE 22 | } 23 | 24 | ExportsItem::ExportsItem(Key k, Context& ctx, Source src, uint32_t export_count) 25 | : Item{k, ctx} 26 | { 27 | ADD_SOURCE(Parse_(ctx, src, export_count), src); 28 | } 29 | 30 | void ExportsItem::Parse_(Context& ctx, Source& src, uint32_t export_count) 31 | { 32 | entries.reserve(export_count); 33 | auto size = ctx.GetSize(); 34 | for (uint32_t i = 0; i < export_count; ++i) 35 | { 36 | auto e = src.ReadGen(); 37 | e.Validate(size); 38 | entries.push_back( 39 | Libshit::MakeSmart( 40 | static_cast(static_cast(e.type)), 41 | e.name, 42 | ctx.CreateLabelFallback(e.name.c_str(), e.offset))); 43 | } 44 | } 45 | 46 | ExportsItem& ExportsItem::CreateAndInsert( 47 | ItemPointer ptr, uint32_t export_count) 48 | { 49 | auto x = RawItem::GetSource(ptr, export_count*sizeof(Entry)); 50 | 51 | auto& ret = x.ritem.SplitCreate( 52 | ptr.offset, x.src, export_count); 53 | 54 | for (const auto& e : ret.entries) 55 | switch (e->type) 56 | { 57 | case Type::CODE: 58 | MaybeCreate(e->lbl->GetPtr()); 59 | break; 60 | case Type::DATA: 61 | MaybeCreate(e->lbl->GetPtr()); 62 | break; 63 | } 64 | return ret; 65 | } 66 | 67 | void ExportsItem::Dispose() noexcept 68 | { 69 | entries.clear(); 70 | Item::Dispose(); 71 | } 72 | 73 | void ExportsItem::Dump_(Sink& sink) const 74 | { 75 | Entry ee; 76 | 77 | for (auto& e : entries) 78 | { 79 | ee.type = e->type; 80 | ee.name = e->name; 81 | ee.offset = ToFilePos(e->lbl->GetPtr()); 82 | sink.WriteGen(ee); 83 | } 84 | } 85 | 86 | void ExportsItem::Inspect_(std::ostream& os, unsigned indent) const 87 | { 88 | Item::Inspect_(os, indent); 89 | 90 | os << "exports{\n"; 91 | for (auto& e : entries) 92 | { 93 | Indent(os, indent+1) 94 | << '{' << e->type << ", " << Libshit::Quoted(e->name.c_str()) << ", " 95 | << PrintLabel(e->lbl) << "},\n"; 96 | } 97 | Indent(os, indent) << '}'; 98 | } 99 | 100 | } 101 | 102 | LIBSHIT_STD_VECTOR_LUAGEN( 103 | stcm_exports_item_entry_type, Libshit::NotNull>); 105 | #include "exports.binding.hpp" 106 | -------------------------------------------------------------------------------- /src/format/stcm/header.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::HeaderItem::TYPE_NAME[] = "neptools.stcm.header_item"; 7 | 8 | namespace Libshit::Lua 9 | { 10 | 11 | // class neptools.stcm.header_item 12 | template<> 13 | void TypeRegisterTraits<::Neptools::Stcm::HeaderItem>::Register(TypeBuilder& bld) 14 | { 15 | bld.Inherit<::Neptools::Stcm::HeaderItem, ::Neptools::Item>(); 16 | 17 | bld.AddFunction< 18 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::HeaderItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef, LuaGetRef<::Libshit::NotNull<::Neptools::LabelPtr>>, LuaGetRef<::Libshit::NotNull<::Neptools::LabelPtr>>, LuaGetRef<::uint32_t>, LuaGetRef<::Neptools::LabelPtr>> 19 | >("new"); 20 | bld.AddFunction< 21 | static_cast<::Neptools::Stcm::HeaderItem & (*)(::Neptools::ItemPointer)>(::Neptools::Stcm::HeaderItem::CreateAndInsert) 22 | >("create_and_insert"); 23 | bld.AddFunction< 24 | &::Libshit::Lua::GetMember<::Neptools::Stcm::HeaderItem, ::Neptools::Stcm::HeaderItem::MsgType, &::Neptools::Stcm::HeaderItem::msg> 25 | >("get_msg"); 26 | bld.AddFunction< 27 | &::Libshit::Lua::SetMember<::Neptools::Stcm::HeaderItem, ::Neptools::Stcm::HeaderItem::MsgType, &::Neptools::Stcm::HeaderItem::msg> 28 | >("set_msg"); 29 | bld.AddFunction< 30 | &::Libshit::Lua::GetMember<::Neptools::Stcm::HeaderItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::HeaderItem::export_sec> 31 | >("get_export_sec"); 32 | bld.AddFunction< 33 | &::Libshit::Lua::SetMember<::Neptools::Stcm::HeaderItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::HeaderItem::export_sec> 34 | >("set_export_sec"); 35 | bld.AddFunction< 36 | &::Libshit::Lua::GetMember<::Neptools::Stcm::HeaderItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::HeaderItem::collection_link> 37 | >("get_collection_link"); 38 | bld.AddFunction< 39 | &::Libshit::Lua::SetMember<::Neptools::Stcm::HeaderItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::HeaderItem::collection_link> 40 | >("set_collection_link"); 41 | bld.AddFunction< 42 | &::Libshit::Lua::GetMember<::Neptools::Stcm::HeaderItem, ::Neptools::LabelPtr, &::Neptools::Stcm::HeaderItem::expansion> 43 | >("get_expansion"); 44 | bld.AddFunction< 45 | &::Libshit::Lua::SetMember<::Neptools::Stcm::HeaderItem, ::Neptools::LabelPtr, &::Neptools::Stcm::HeaderItem::expansion> 46 | >("set_expansion"); 47 | bld.AddFunction< 48 | &::Libshit::Lua::GetMember<::Neptools::Stcm::HeaderItem, ::uint32_t, &::Neptools::Stcm::HeaderItem::field_28> 49 | >("get_field_28"); 50 | bld.AddFunction< 51 | &::Libshit::Lua::SetMember<::Neptools::Stcm::HeaderItem, ::uint32_t, &::Neptools::Stcm::HeaderItem::field_28> 52 | >("set_field_28"); 53 | 54 | } 55 | static TypeRegister::StateRegister<::Neptools::Stcm::HeaderItem> reg_neptools_stcm_header_item; 56 | 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /src/format/stcm/header.cpp: -------------------------------------------------------------------------------- 1 | #include "header.hpp" 2 | #include "collection_link.hpp" 3 | #include "expansion.hpp" 4 | #include "exports.hpp" 5 | #include "../context.hpp" 6 | #include "../../sink.hpp" 7 | #include "../../utils.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Neptools::Stcm 14 | { 15 | 16 | void HeaderItem::Header::Validate(FilePosition file_size) const 17 | { 18 | #define VALIDATE(x) LIBSHIT_VALIDATE_FIELD("Stcm::HeaderItem::Header", x) 19 | VALIDATE(memcmp(magic, "STCM2", 5) == 0); 20 | VALIDATE(endian == 'L'); 21 | VALIDATE(msg.is_valid()); 22 | VALIDATE(export_offset < file_size - 0x28*export_count); 23 | VALIDATE(collection_link_offset < file_size); 24 | VALIDATE(field_30 == 0); 25 | VALIDATE(expansion_count == 0 || expansion_offset != 0); 26 | VALIDATE(expansion_offset < file_size - 0x50*expansion_count); 27 | #undef VALIDATE 28 | } 29 | 30 | HeaderItem::HeaderItem(Key k, Context& ctx, const Header& hdr) 31 | : Item{k, ctx}, export_sec{Libshit::EmptyNotNull{}}, 32 | collection_link{Libshit::EmptyNotNull{}} 33 | { 34 | hdr.Validate(ctx.GetSize()); 35 | 36 | msg = hdr.msg; 37 | export_sec = ctx.CreateLabelFallback("exports", hdr.export_offset); 38 | collection_link = ctx.CreateLabelFallback( 39 | "collection_link_hdr", hdr.collection_link_offset);; 40 | if (hdr.expansion_offset != 0) 41 | expansion = ctx.CreateLabelFallback("expansion", hdr.expansion_offset); 42 | field_28 = hdr.field_28; 43 | } 44 | 45 | HeaderItem& HeaderItem::CreateAndInsert(ItemPointer ptr) 46 | { 47 | auto x = RawItem::Get
(ptr); 48 | 49 | auto& ret = x.ritem.SplitCreate(ptr.offset, x.t); 50 | CollectionLinkHeaderItem::CreateAndInsert(ret.collection_link->GetPtr()); 51 | if (ret.expansion) 52 | ExpansionsItem::CreateAndInsert(ret.expansion->GetPtr(), 53 | x.t.expansion_count); 54 | ExportsItem::CreateAndInsert(ret.export_sec->GetPtr(), x.t.export_count); 55 | return ret; 56 | } 57 | 58 | void HeaderItem::Dump_(Sink& sink) const 59 | { 60 | Header hdr{}; 61 | memcpy(hdr.magic, "STCM2", 5); 62 | hdr.endian = 'L'; 63 | hdr.msg = msg; 64 | hdr.export_offset = ToFilePos(export_sec->GetPtr()); 65 | hdr.export_count = export_sec->GetPtr().As0().entries.size(); 66 | hdr.field_28 = field_28; 67 | hdr.collection_link_offset = ToFilePos(collection_link->GetPtr()); 68 | if (expansion) 69 | { 70 | hdr.expansion_offset = ToFilePos(expansion->GetPtr()); 71 | hdr.expansion_count = expansion->GetPtr().As0(). 72 | GetChildren().size(); 73 | } 74 | 75 | sink.WriteGen(hdr); 76 | } 77 | 78 | void HeaderItem::Inspect_(std::ostream& os, unsigned indent) const 79 | { 80 | Item::Inspect_(os, indent); 81 | 82 | os << "header(" << Libshit::Quoted(msg.c_str()) << ", " 83 | << PrintLabel(export_sec) << ", " << PrintLabel(collection_link) << ", " 84 | << field_28 << ", " << PrintLabel(expansion) << ")"; 85 | } 86 | 87 | } 88 | 89 | #include "header.binding.hpp" 90 | -------------------------------------------------------------------------------- /src/format/gbnl_lua.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_907F2DFB_AA53_4295_B41F_9AAA950AEEB4 2 | #define UUID_907F2DFB_AA53_4295_B41F_9AAA950AEEB4 3 | #pragma once 4 | 5 | #include "gbnl.hpp" 6 | #include "../dynamic_struct.lua.hpp" 7 | 8 | #include 9 | 10 | #if LIBSHIT_WITH_LUA 11 | 12 | namespace Neptools 13 | { 14 | 15 | template <> 16 | struct DynamicStructTypeTraits 17 | { 18 | static void Push(Libshit::Lua::StateRef vm, const void* ptr, size_t size) 19 | { 20 | LIBSHIT_ASSERT(size == sizeof(Gbnl::OffsetString)); (void) size; 21 | auto ofs = static_cast(ptr); 22 | if (ofs->offset == static_cast(-1)) 23 | lua_pushnil(vm); 24 | else 25 | vm.Push(ofs->str); 26 | } 27 | 28 | static void Get(Libshit::Lua::StateRef vm, int idx, void* ptr, size_t size) 29 | { 30 | LIBSHIT_ASSERT(size == sizeof(Gbnl::OffsetString)); (void) size; 31 | auto ofs = static_cast(ptr); 32 | 33 | if (Libshit::Lua::IsNoneOrNil(lua_type(vm, idx))) 34 | { 35 | ofs->offset = static_cast(-1); 36 | ofs->str.clear(); 37 | } 38 | else 39 | { 40 | ofs->str = vm.Check(idx); 41 | ofs->offset = 0; // no longer null 42 | } 43 | } 44 | 45 | static constexpr bool SIZABLE = false; 46 | static constexpr const char* NAME = "string"; 47 | }; 48 | 49 | // FixString is zero terminated, Padding is not 50 | template <> 51 | struct DynamicStructTypeTraits 52 | { 53 | static void Push(Libshit::Lua::StateRef vm, const void* ptr, size_t size) 54 | { 55 | auto str = static_cast(ptr); 56 | lua_pushlstring(vm, str, strnlen(str, size)); 57 | } 58 | 59 | static void Get(Libshit::Lua::StateRef vm, int idx, void* ptr, size_t size) 60 | { 61 | auto str = vm.Check(idx); 62 | auto dst = static_cast(ptr); 63 | 64 | auto n = std::min(size-1, str.length()); 65 | memcpy(dst, str.data(), n); 66 | memset(dst+n, 0, size-n); 67 | } 68 | 69 | static constexpr bool SIZABLE = true; 70 | static constexpr const char* NAME = "fix_string"; 71 | }; 72 | 73 | template<> 74 | struct DynamicStructTypeTraits 75 | { 76 | static void Push(Libshit::Lua::StateRef vm, const void* ptr, size_t size) 77 | { 78 | auto str = static_cast(ptr); 79 | lua_pushlstring(vm, str, size); 80 | } 81 | 82 | static void Get(Libshit::Lua::StateRef vm, int idx, void* ptr, size_t size) 83 | { 84 | auto str = vm.Check(idx); 85 | auto dst = static_cast(ptr); 86 | 87 | auto n = std::min(size, str.length()); 88 | memcpy(dst, str.data(), n); 89 | memset(dst+n, 0, size-n); 90 | } 91 | 92 | static constexpr bool SIZABLE = true; 93 | static constexpr const char* NAME = "padding"; 94 | }; 95 | 96 | } 97 | 98 | NEPTOOLS_DYNAMIC_STRUCT_TABLECTOR( 99 | int8_t, int16_t, int32_t, int64_t, float, 100 | ::Neptools::Gbnl::OffsetString, ::Neptools::Gbnl::FixStringTag, 101 | ::Neptools::Gbnl::PaddingTag); 102 | 103 | #endif 104 | #endif 105 | -------------------------------------------------------------------------------- /src/sink.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Sink::TYPE_NAME[] = "neptools.sink"; 7 | 8 | const char ::Neptools::MemorySink::TYPE_NAME[] = "neptools.memory_sink"; 9 | 10 | namespace Libshit::Lua 11 | { 12 | 13 | // class neptools.sink 14 | template<> 15 | void TypeRegisterTraits<::Neptools::Sink>::Register(TypeBuilder& bld) 16 | { 17 | 18 | bld.AddFunction< 19 | static_cast<::Libshit::NotNull > (*)(::boost::filesystem::path, ::Neptools::FilePosition, bool)>(::Neptools::Sink::ToFile) 20 | >("to_file"); 21 | bld.AddFunction< 22 | static_cast<::Libshit::NotNull > (*)()>(::Neptools::Sink::ToStdOut) 23 | >("to_std_out"); 24 | bld.AddFunction< 25 | static_cast<::Neptools::FilePosition (::Neptools::Sink::*)() const noexcept>(&::Neptools::Sink::Tell) 26 | >("tell"); 27 | bld.AddFunction< 28 | static_cast(&::Neptools::Sink::Write) 29 | >("write"); 30 | bld.AddFunction< 31 | static_cast(&::Neptools::Sink::Pad) 32 | >("pad"); 33 | bld.AddFunction< 34 | static_cast(&::Neptools::Sink::Flush) 35 | >("flush"); 36 | bld.AddFunction< 37 | static_cast(&::Neptools::Sink::WriteLittleUint8) 38 | >("write_little_uint8"); 39 | bld.AddFunction< 40 | static_cast(&::Neptools::Sink::WriteLittleUint16) 41 | >("write_little_uint16"); 42 | bld.AddFunction< 43 | static_cast(&::Neptools::Sink::WriteLittleUint32) 44 | >("write_little_uint32"); 45 | bld.AddFunction< 46 | static_cast(&::Neptools::Sink::WriteLittleUint64) 47 | >("write_little_uint64"); 48 | bld.AddFunction< 49 | static_cast(&::Neptools::Sink::WriteCString) 50 | >("write_cstring"); 51 | lua_getfield(bld, -2, "__gc"); bld.SetField("close"); 52 | } 53 | static TypeRegister::StateRegister<::Neptools::Sink> reg_neptools_sink; 54 | 55 | // class neptools.memory_sink 56 | template<> 57 | void TypeRegisterTraits<::Neptools::MemorySink>::Register(TypeBuilder& bld) 58 | { 59 | bld.Inherit<::Neptools::MemorySink, ::Neptools::Sink>(); 60 | 61 | bld.AddFunction< 62 | &::Libshit::Lua::TypeTraits<::Neptools::MemorySink>::Make>, 63 | static_cast<::Libshit::NotNull > (*)(std::string_view)>(&Neptools::MemorySinkFromLua) 64 | >("new"); 65 | bld.AddFunction< 66 | static_cast(&::Neptools::MemorySink::GetStringView) 67 | >("to_string"); 68 | 69 | } 70 | static TypeRegister::StateRegister<::Neptools::MemorySink> reg_neptools_memory_sink; 71 | 72 | } 73 | #endif 74 | -------------------------------------------------------------------------------- /src/format/stsc/file.cpp: -------------------------------------------------------------------------------- 1 | #include "file.hpp" 2 | #include "header.hpp" 3 | #include "../cstring_item.hpp" 4 | #include "../eof_item.hpp" 5 | #include "../raw_item.hpp" 6 | #include "../../open.hpp" 7 | 8 | #include 9 | 10 | namespace Neptools::Stsc 11 | { 12 | 13 | File::File(Source src, Flavor flavor) : flavor{flavor} 14 | { 15 | ADD_SOURCE(Parse_(src), src); 16 | } 17 | 18 | void File::Parse_(Source& src) 19 | { 20 | auto root = Create(src); 21 | SetupParseFrom(*root); 22 | root->Split(root->GetSize(), Create()); 23 | HeaderItem::CreateAndInsert({&*root, 0}, flavor); 24 | } 25 | 26 | void File::Inspect_(std::ostream& os, unsigned indent) const 27 | { 28 | LIBSHIT_ASSERT(GetLabels().empty()); 29 | os << "neptools.stsc.file(neptools.stsc.flavor." << ToString(flavor) << ")"; 30 | InspectChildren(os, indent); 31 | } 32 | 33 | static const char SEP_DASH[] = { 34 | #define REP_MACRO(x,y,z) '-', 35 | BOOST_PP_REPEAT(40, REP_MACRO, ) 36 | '\r', 0, 37 | }; 38 | 39 | void File::WriteTxt_(std::ostream& os) const 40 | { 41 | for (auto& it : GetChildren()) 42 | { 43 | auto str = dynamic_cast(&it); 44 | if (str) 45 | { 46 | os << boost::replace_all_copy(str->string, "\\n", "\r\n") 47 | << "\r\n" << SEP_DASH << '\n'; 48 | } 49 | } 50 | } 51 | 52 | void File::ReadTxt_(std::istream& is) 53 | { 54 | std::string line, msg; 55 | auto it = GetChildren().begin(); 56 | auto end = GetChildren().end(); 57 | while (it != end && !dynamic_cast(&*it)) ++it; 58 | 59 | is.exceptions(std::ios_base::badbit); 60 | while (!std::getline(is, line).fail()) 61 | { 62 | if (line == SEP_DASH) 63 | { 64 | if (it == end) 65 | LIBSHIT_THROW(Libshit::DecodeError, "StscTxt: too many strings"); 66 | 67 | LIBSHIT_ASSERT(msg.empty() || msg.substr(msg.length()-2) == "\\n"); 68 | if (!msg.empty()) { msg.pop_back(); msg.pop_back(); } 69 | static_cast(*it).string = std::move(msg); 70 | 71 | ++it; 72 | while (it != end && !dynamic_cast(&*it)) ++it; 73 | 74 | msg.clear(); 75 | } 76 | else 77 | { 78 | if (!line.empty() && line.back() == '\r') line.pop_back(); 79 | msg.append(line).append("\\n"); 80 | } 81 | } 82 | 83 | if (it != end) 84 | LIBSHIT_THROW(Libshit::DecodeError, "StscTxt: not enough strings"); 85 | } 86 | 87 | static Flavor glob_flavor = Flavor::NOIRE; 88 | static Libshit::Option flavor_opt{ 89 | GetFlavorOptions(), "stsc-flavor", 1, "FLAVOR", 90 | #define GEN_HELP(x,y) "\t\t" #x "\n" 91 | "Set STSC flavor:\n" NEPTOOLS_GEN_STSC_FLAVOR(GEN_HELP,), 92 | #undef GEN_HELP 93 | [](auto&& args) 94 | { 95 | if (false); // NOLINT 96 | #define GEN_IFS(x, y) \ 97 | else if (strcmp(args.front(), #x) == 0) \ 98 | glob_flavor = Flavor::x; 99 | 100 | NEPTOOLS_GEN_STSC_FLAVOR(GEN_IFS,) 101 | #undef GEN_IFS 102 | else throw Libshit::InvalidParam{"invalid argument"}; 103 | }}; 104 | 105 | static OpenFactory stsc_open{[](const Source& src) -> Libshit::SmartPtr 106 | { 107 | if (src.GetSize() < sizeof(HeaderItem::Header)) return nullptr; 108 | char buf[4]; 109 | src.PreadGen(0, buf); 110 | if (memcmp(buf, "STSC", 4) == 0) 111 | return Libshit::MakeSmart(src, glob_flavor); 112 | else 113 | return nullptr; 114 | }}; 115 | 116 | } 117 | 118 | #include "file.binding.hpp" 119 | -------------------------------------------------------------------------------- /tools/qmp: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python2 2 | # 3 | # QMP command line tool 4 | # 5 | # Copyright IBM, Corp. 2011 6 | # 7 | # Authors: 8 | # Anthony Liguori 9 | # 10 | # This work is licensed under the terms of the GNU GPLv2 or later. 11 | # See the COPYING file in the top-level directory. 12 | 13 | import sys, os 14 | from qmp import QEMUMonitorProtocol 15 | 16 | def print_response(rsp, prefix=[]): 17 | if type(rsp) == list: 18 | i = 0 19 | for item in rsp: 20 | if prefix == []: 21 | prefix = ['item'] 22 | print_response(item, prefix[:-1] + ['%s[%d]' % (prefix[-1], i)]) 23 | i += 1 24 | elif type(rsp) == dict: 25 | for key in rsp.keys(): 26 | print_response(rsp[key], prefix + [key]) 27 | else: 28 | if len(prefix): 29 | print '%s: %s' % ('.'.join(prefix), rsp) 30 | else: 31 | print '%s' % (rsp) 32 | 33 | def main(args): 34 | path = None 35 | 36 | # Use QMP_PATH if it's set 37 | if os.environ.has_key('QMP_PATH'): 38 | path = os.environ['QMP_PATH'] 39 | 40 | while len(args): 41 | arg = args[0] 42 | 43 | if arg.startswith('--'): 44 | arg = arg[2:] 45 | if arg.find('=') == -1: 46 | value = True 47 | else: 48 | arg, value = arg.split('=', 1) 49 | 50 | if arg in ['path']: 51 | if type(value) == str: 52 | path = value 53 | elif arg in ['help']: 54 | os.execlp('man', 'man', 'qmp') 55 | else: 56 | print 'Unknown argument "%s"' % arg 57 | 58 | args = args[1:] 59 | else: 60 | break 61 | 62 | if not path: 63 | print "QMP path isn't set, use --path=qmp-monitor-address or set QMP_PATH" 64 | return 1 65 | 66 | if len(args): 67 | command, args = args[0], args[1:] 68 | else: 69 | print 'No command found' 70 | print 'Usage: "qmp [--path=qmp-monitor-address] qmp-cmd arguments"' 71 | return 1 72 | 73 | if command in ['help']: 74 | os.execlp('man', 'man', 'qmp') 75 | 76 | srv = QEMUMonitorProtocol(path) 77 | srv.connect() 78 | 79 | def do_command(srv, cmd, **kwds): 80 | rsp = srv.cmd(cmd, kwds) 81 | if rsp.has_key('error'): 82 | raise Exception(rsp['error']['desc']) 83 | return rsp['return'] 84 | 85 | commands = map(lambda x: x['name'], do_command(srv, 'query-commands')) 86 | 87 | srv.close() 88 | 89 | if command not in commands: 90 | fullcmd = 'qmp-%s' % command 91 | try: 92 | os.environ['QMP_PATH'] = path 93 | os.execvp(fullcmd, [fullcmd] + args) 94 | except OSError as exc: 95 | if exc.errno == 2: 96 | print 'Command "%s" not found.' % (fullcmd) 97 | return 1 98 | raise 99 | return 0 100 | 101 | srv = QEMUMonitorProtocol(path) 102 | srv.connect() 103 | 104 | arguments = {} 105 | for arg in args: 106 | if not arg.startswith('--'): 107 | print 'Unknown argument "%s"' % arg 108 | return 1 109 | 110 | arg = arg[2:] 111 | if arg.find('=') == -1: 112 | value = True 113 | else: 114 | arg, value = arg.split('=', 1) 115 | 116 | if arg in ['help']: 117 | os.execlp('man', 'man', 'qmp-%s' % command) 118 | return 1 119 | 120 | arguments[arg] = value 121 | 122 | rsp = do_command(srv, command, **arguments) 123 | print_response(rsp) 124 | 125 | if __name__ == '__main__': 126 | sys.exit(main(sys.argv[1:])) 127 | -------------------------------------------------------------------------------- /src/format/stcm/collection_link.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_51AA015D_E824_48D3_8BB4_37BC559302DA 2 | #define UUID_51AA015D_E824_48D3_8BB4_37BC559302DA 3 | #pragma once 4 | 5 | #include "../item.hpp" 6 | #include "../../source.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Neptools::Stcm 13 | { 14 | 15 | class CollectionLinkHeaderItem final : public Item 16 | { 17 | LIBSHIT_DYNAMIC_OBJECT; 18 | public: 19 | struct Header 20 | { 21 | boost::endian::little_uint32_t field_00; 22 | boost::endian::little_uint32_t offset; 23 | boost::endian::little_uint32_t count; 24 | boost::endian::little_uint32_t field_0c; 25 | boost::endian::little_uint32_t field_10; 26 | boost::endian::little_uint32_t field_14; 27 | boost::endian::little_uint32_t field_18; 28 | boost::endian::little_uint32_t field_1c; 29 | boost::endian::little_uint32_t field_20; 30 | boost::endian::little_uint32_t field_24; 31 | boost::endian::little_uint32_t field_28; 32 | boost::endian::little_uint32_t field_2c; 33 | boost::endian::little_uint32_t field_30; 34 | boost::endian::little_uint32_t field_34; 35 | boost::endian::little_uint32_t field_38; 36 | boost::endian::little_uint32_t field_3c; 37 | 38 | void Validate(FilePosition file_size) const; 39 | }; 40 | static_assert(sizeof(Header) == 0x40); 41 | 42 | CollectionLinkHeaderItem( 43 | Key k, Context& ctx, Libshit::NotNull data) 44 | : Item{k, ctx}, data{std::move(data)} {} 45 | 46 | LIBSHIT_NOLUA 47 | CollectionLinkHeaderItem(Key k, Context& ctx, const Header& s); 48 | static CollectionLinkHeaderItem& CreateAndInsert(ItemPointer ptr); 49 | 50 | FilePosition GetSize() const noexcept override 51 | { return sizeof(Header); } 52 | 53 | Libshit::NotNull data; 54 | 55 | private: 56 | void Dump_(Sink& sink) const override; 57 | void Inspect_(std::ostream& os, unsigned indent) const override; 58 | }; 59 | 60 | class CollectionLinkItem final : public Item 61 | { 62 | LIBSHIT_DYNAMIC_OBJECT; 63 | public: 64 | struct Entry 65 | { 66 | boost::endian::little_uint32_t name_0; 67 | boost::endian::little_uint32_t name_1; 68 | boost::endian::little_uint32_t ptr; // filled by engine 69 | boost::endian::little_uint32_t field_0c; 70 | boost::endian::little_uint32_t field_10; 71 | boost::endian::little_uint32_t field_14; 72 | boost::endian::little_uint32_t field_18; 73 | boost::endian::little_uint32_t field_1c; 74 | 75 | void Validate(FilePosition file_size) const; 76 | }; 77 | static_assert(sizeof(Entry) == 0x20); 78 | 79 | struct LinkEntry; 80 | CollectionLinkItem(Key k, Context& ctx) : Item{k, ctx} {} 81 | CollectionLinkItem(Key k, Context& ctx, Source src, uint32_t count); 82 | CollectionLinkItem( 83 | Key k, Context& ctx, Libshit::AT> entries) 84 | : Item{k, ctx}, entries{std::move(entries.Get())} {} 85 | 86 | FilePosition GetSize() const noexcept override 87 | { return entries.size() * sizeof(Entry); } 88 | 89 | struct LinkEntry : public Libshit::Lua::ValueObject 90 | { 91 | LabelPtr name_0; 92 | LabelPtr name_1; 93 | 94 | LinkEntry(LabelPtr name_0, LabelPtr name_1) 95 | : name_0{std::move(name_0)}, name_1{std::move(name_1)} {} 96 | LIBSHIT_LUA_CLASS; 97 | }; 98 | LIBSHIT_LUAGEN(get="::Libshit::Lua::GetSmartOwnedMember") 99 | std::vector entries; 100 | 101 | void Dispose() noexcept override; 102 | 103 | private: 104 | void Dump_(Sink& sink) const override; 105 | void Inspect_(std::ostream& os, unsigned indent) const override; 106 | void Parse_(Context& ctx, Source& src, uint32_t count); 107 | }; 108 | 109 | } 110 | #endif 111 | -------------------------------------------------------------------------------- /src/format/raw_item.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_49BE292D_0E45_47B1_8901_97A22C0190F6 2 | #define UUID_49BE292D_0E45_47B1_8901_97A22C0190F6 3 | #pragma once 4 | 5 | #include "context.hpp" 6 | #include "../source.hpp" 7 | 8 | #include 9 | 10 | namespace Neptools 11 | { 12 | 13 | class RawItem final : public Item 14 | { 15 | LIBSHIT_DYNAMIC_OBJECT; 16 | public: 17 | RawItem(Key k, Context& ctx, Source src) noexcept 18 | : Item{k, ctx}, src{std::move(src)} {} 19 | RawItem(Key k, Context& ctx, std::string src) 20 | : Item{k, ctx}, src{Source::FromMemory(std::move(src))} {} 21 | LIBSHIT_NOLUA 22 | RawItem(Key k, Context& ctx, Source src, FilePosition pos) noexcept 23 | : Item{k, ctx, pos}, src{std::move(src)} {} 24 | 25 | const Source& GetSource() const noexcept { return src; } 26 | FilePosition GetSize() const noexcept override { return src.GetSize(); } 27 | 28 | template 29 | LIBSHIT_LUAGEN(template_params={"::Neptools::Item"}) 30 | T& Split(FilePosition pos, Libshit::NotNull> nitem) 31 | { 32 | T& ret = *nitem; 33 | Split2(pos, std::move(nitem)); 34 | return ret; 35 | } 36 | 37 | template 38 | LIBSHIT_NOLUA T& SplitCreate(FilePosition pos, Args&&... args) 39 | { 40 | auto ctx = GetContext(); 41 | return Split(pos, ctx->Create(std::forward(args)...)); 42 | } 43 | 44 | RawItem& Split(FilePosition offset, FilePosition size); 45 | 46 | template 47 | LIBSHIT_NOLUA static auto Get(ItemPointer ptr) 48 | { 49 | auto& ritem = ptr.AsChecked(); 50 | LIBSHIT_ASSERT_MSG(ptr.offset <= ritem.GetSize(), "invalid offset"); 51 | if (ptr.offset + sizeof(T) > ritem.GetSize()) 52 | LIBSHIT_THROW(Libshit::DecodeError, "Premature end of data"); 53 | 54 | struct Ret { RawItem& ritem; T t; }; 55 | return Ret{ 56 | std::ref(ritem), 57 | ritem.src.PreadGen(ptr.offset)}; 58 | } 59 | 60 | struct GetSourceRet { RawItem& ritem; Source src; }; 61 | static GetSourceRet GetSource(ItemPointer ptr, FilePosition len) 62 | { 63 | auto& ritem = ptr.AsChecked(); 64 | LIBSHIT_ASSERT_MSG(ptr.offset <= ritem.GetSize(), "invalid offset"); 65 | if (len == FilePosition(-1)) len = ritem.GetSize() - ptr.offset; 66 | 67 | if (ptr.offset + len > ritem.GetSize()) 68 | LIBSHIT_THROW(Libshit::DecodeError, "Premature end of data"); 69 | return {std::ref(ritem), {ritem.src, ptr.offset, len}}; 70 | } 71 | 72 | private: 73 | Libshit::NotNull> InternalSlice( 74 | FilePosition offset, FilePosition size); 75 | void Split2( 76 | FilePosition pos, Libshit::NotNull> nitem); 77 | 78 | void Dump_(Sink& sink) const override; 79 | void Inspect_(std::ostream& os, unsigned indent) const override; 80 | 81 | Source src; 82 | }; 83 | 84 | template 85 | inline auto& MaybeCreate(ItemPointer ptr, Args&&... args) 86 | { 87 | auto item = ptr.Maybe(); 88 | if (item) 89 | return T::CreateAndInsert(ptr, std::forward(args)...); 90 | else 91 | return ptr.AsChecked0(); // check it 92 | } 93 | 94 | template 95 | inline void MaybeCreateUnchecked(ItemPointer ptr, Args&&... args) 96 | { 97 | if (ptr.Maybe()) 98 | T::CreateAndInsert(ptr, std::forward(args)...); 99 | } 100 | 101 | } 102 | 103 | template<> struct Libshit::Lua::TupleLike 104 | { 105 | template 106 | static auto& Get(const Neptools::RawItem::GetSourceRet& ret) noexcept 107 | { 108 | if constexpr (I == 0) return ret.ritem; 109 | else if constexpr (I == 1) return ret.src; 110 | } 111 | static constexpr size_t SIZE = 2; 112 | }; 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /doc/formats/gbin.md: -------------------------------------------------------------------------------- 1 | GBIN and GSTR 2 | ============= 3 | 4 | GBIN (stored inside `.gbin` files in SYSTEM/database, and inside `.cl3`s) and 5 | GSTR (stored in `.gstr` files in SYSTEM/database) are quite similar. All 6 | integers are little-endian. 7 | 8 | The sections described below (Header/Footer, Type descriptor, Struct and String 9 | table) are aligned to 16 bytes in GBIN, but unaligned in GSTR... 10 | 11 | Header/Footer 12 | ------------- 13 | 14 | ```c++ 15 | struct HeaderFooter 16 | { 17 | char magic[3]; 18 | char endian; 19 | uint16_t field_04; // always 1 20 | uint16_t field_06; // always 0 21 | uint32_t field_08; // always 16 22 | uint32_t field_0c; // always 4 23 | uint32_t flags; 24 | uint32_t struct_offset; 25 | uint32_t struct_count; 26 | uint32_t struct_size; 27 | uint32_t types_count; 28 | uint32_t types_offset; 29 | uint32_t field_28; // ?? 30 | uint32_t string_offset; 31 | uint32_t field_30; // 0 or 4 32 | uint32_t padding[3]; // always 0 33 | }; 34 | sizeof(HeaderFooter) == 0x40 35 | ``` 36 | 37 | In GSTR the above struct is a header, at the beginning of the file, magic string 38 | is `GST`. In GBIN it's a footer (so it starts at `EOF-sizeof(HeaderFooter)`), 39 | and the magic is `GBN`... Endian is denoted by `endian`, if `L` means 40 | little-endian and `B` means big-endian. 41 | 42 | `flags` is 1 if there's any string stored in the file (see Type descriptor 43 | below), 0 otherwise. `struct_offset` is 0 in GBIN and 0x40 in GSTR files (but 44 | other values should work too). Offsets are relative to the beginning of the 45 | file. 46 | 47 | Type descriptor 48 | --------------- 49 | 50 | This file contains a list of some structure. However the structure is actually 51 | defined inside the file, so you can figure out the types of each fields. 52 | 53 | ```c++ 54 | struct TypeDescriptor 55 | { 56 | uint16_t type; 57 | uint16_t offset; 58 | }; 59 | sizeof(TypeDescriptor) == 4; 60 | ``` 61 | 62 | They start at `header.types_offset`, and there's `header.types_count` of them. 63 | They're sorted into ascending order by `offset`. Each entry describes a field 64 | inside the struct, `offset` is an offset from the beginning of the struct. The 65 | valid values for `type` are: 66 | 67 | ```c++ 68 | enum Type 69 | { 70 | UINT32 = 0, 71 | UINT8 = 1, 72 | UINT16 = 2, 73 | FLOAT = 3, 74 | STRING = 5, 75 | }; 76 | ``` 77 | 78 | `UINT16`, and `UINT32` are standard 16 bit and 32 bit integers (not sure if 79 | they're signed or unsigned though, probably the format makes no difference 80 | between them), `FLOAT` is a standard 32 bit float (as used by x86 CPUs). 81 | 82 | `UINT8` is a bit special: it's normally a single byte, but can also mean a fixed 83 | length zero terminated string. They both end up as `type=1`. This editor 84 | currently uses a heuristic: if the offset of the next entry is this entry's 85 | offset + 1 (taking aligning into account), it's probably a single byte, 86 | otherwise a fixed length string. 87 | 88 | `STRING` is a 32 bit integer, an offset into the string table. Sometimes it'll 89 | be -1 (0xffffffff), that's an invalid string (maybe NULL pointer originally?). 90 | 91 | The fields are aligned: `UINT32`, `FLOAT` and `STRING` are aligned to 4 bytes 92 | and `UINT16` to 2 bytes. 93 | 94 | Struct 95 | ------ 96 | 97 | The structs start at `header.struct_offset` and there are `header.struct_count` 98 | of them. Every struct is `header.struct_size` bytes length, the fields are 99 | described by the type descriptor. 100 | 101 | 102 | String table 103 | ------------ 104 | 105 | This is optional, it only exists if `header.flags == 1`. It starts at 106 | `header.string_offset`. Each contains a bunch of zero terminated strings 107 | sequentially, and referenced inside `STRING` type fields. 108 | 109 | There's an optimization in the original files: if the same string appears 110 | multiple times, it's only stored once in the table, the identical `STRING` 111 | fields will get the same offset. 112 | -------------------------------------------------------------------------------- /src/programs/launcher.c: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include 4 | 5 | 6 | #define MSVC_URL "https://www.microsoft.com/en-us/download/details.aspx?id=40784" 7 | 8 | // set shit that's possible here 9 | #pragma comment(linker, "/merge:.text=.data") 10 | #pragma comment(linker, "/merge:.rdata=.data") 11 | 12 | static void strwcpy(wchar_t* dst, const wchar_t* src) 13 | { 14 | while (*dst++ = *src++); 15 | } 16 | 17 | void* memset(void* dst, int c, size_t len) 18 | { 19 | for (size_t i = 0; i < len; ++i) 20 | ((char *) dst)[i] = c; 21 | return dst; 22 | } 23 | 24 | static size_t strwlen(const wchar_t* ptr) 25 | { 26 | const wchar_t* p = ptr; 27 | while (*p++); 28 | return p - ptr; 29 | } 30 | 31 | static int inject_dll(HANDLE proc, wchar_t* fname) 32 | { 33 | size_t bytes = sizeof(wchar_t) * (strwlen(fname)+1); 34 | void* ptr = VirtualAllocEx(proc, NULL, bytes, MEM_COMMIT, PAGE_READWRITE); 35 | if (!ptr) return 0; 36 | 37 | if (!WriteProcessMemory(proc, ptr, fname, bytes, NULL)) return 0; 38 | 39 | HANDLE th = CreateRemoteThread( 40 | proc, NULL, 0, (LPTHREAD_START_ROUTINE) &LoadLibraryW, ptr, 0, NULL); 41 | if (!th) return 0; 42 | 43 | WaitForSingleObject(th, INFINITE); 44 | DWORD ret; 45 | if (!GetExitCodeThread(th, &ret) || ret == 0) return 0; 46 | CloseHandle(th); 47 | 48 | if (!VirtualFreeEx(proc, ptr, 0, MEM_RELEASE)) return 0; 49 | 50 | return 1; 51 | } 52 | 53 | static int mymain(void) 54 | { 55 | HANDLE h = LoadLibraryExA("msvcp120.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); 56 | if (h == NULL) 57 | { 58 | int ret = MessageBoxA( 59 | NULL, "Please install MSVC 2013 runtime\n\nOpen download page?", 60 | NULL, MB_YESNO | MB_ICONERROR); 61 | if (ret == IDYES) 62 | ShellExecuteA(NULL, NULL, MSVC_URL, NULL, NULL, SW_SHOWNORMAL); 63 | return 1; 64 | } 65 | CloseHandle(h); 66 | 67 | #define BUF_SIZE 4096 68 | wchar_t buf[BUF_SIZE]; 69 | GetModuleFileNameW(NULL, buf, BUF_SIZE); 70 | buf[BUF_SIZE-1] = 0; // maybe xp 71 | 72 | wchar_t* last_slash = buf; 73 | for (wchar_t* ptr = buf; *ptr; ++ptr) 74 | if (*ptr == L'\\') 75 | last_slash = ptr; 76 | 77 | if (*last_slash != L'\\' || last_slash - buf > BUF_SIZE - 22) 78 | { 79 | MessageBoxA(NULL, "Wrong module path", NULL, MB_OK | MB_ICONERROR); 80 | return 2; 81 | } 82 | strwcpy(last_slash + 1, L"NeptuniaReBirth3.exe"); 83 | 84 | for (int i = '3';; --i) 85 | { 86 | last_slash[16] = i; 87 | unsigned attrib = GetFileAttributesW(buf); 88 | if (attrib != INVALID_FILE_ATTRIBUTES && 89 | !(attrib & FILE_ATTRIBUTE_ENCRYPTED)) 90 | break; 91 | 92 | if (i == '1') 93 | { 94 | strwcpy(&last_slash[9], L"VII.exe"); 95 | unsigned attrib = GetFileAttributesW(buf); 96 | if (attrib != INVALID_FILE_ATTRIBUTES && 97 | !(attrib & FILE_ATTRIBUTE_ENCRYPTED)) 98 | break; 99 | 100 | MessageBoxA(NULL, "Couldn't find Neptunia", 101 | NULL, MB_OK | MB_ICONERROR); 102 | return 2; 103 | } 104 | } 105 | 106 | STARTUPINFOW si; 107 | PROCESS_INFORMATION pi; 108 | memset(&si, 0, sizeof(si)); 109 | memset(&pi, 0, sizeof(pi)); 110 | si.cb = sizeof(STARTUPINFO); 111 | if (CreateProcessW(buf, GetCommandLineW(), NULL, NULL, FALSE, 112 | CREATE_SUSPENDED, NULL, NULL, &si, &pi) == 0) 113 | { 114 | MessageBoxA(NULL, "Failed to start game", NULL, MB_OK | MB_ICONERROR); 115 | return 2; 116 | } 117 | 118 | strwcpy(last_slash + 1, L"neptools-server.dll"); 119 | if (!inject_dll(pi.hProcess, buf)) 120 | { 121 | TerminateProcess(pi.hProcess, 0); 122 | MessageBoxA(NULL, "DLL injection failed", NULL, MB_OK | MB_ICONERROR); 123 | return 3; 124 | } 125 | 126 | ResumeThread(pi.hThread); 127 | CloseHandle(pi.hProcess); 128 | CloseHandle(pi.hThread); 129 | return 0; 130 | } 131 | 132 | void __cdecl start(void); 133 | void __cdecl start(void) 134 | { 135 | ExitProcess(mymain()); 136 | } 137 | -------------------------------------------------------------------------------- /src/format/stcm/collection_link.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::CollectionLinkHeaderItem::TYPE_NAME[] = "neptools.stcm.collection_link_header_item"; 7 | 8 | const char ::Neptools::Stcm::CollectionLinkItem::TYPE_NAME[] = "neptools.stcm.collection_link_item"; 9 | 10 | const char ::Neptools::Stcm::CollectionLinkItem::LinkEntry::TYPE_NAME[] = "neptools.stcm.collection_link_item.link_entry"; 11 | 12 | namespace Libshit::Lua 13 | { 14 | 15 | // class neptools.stcm.collection_link_header_item 16 | template<> 17 | void TypeRegisterTraits<::Neptools::Stcm::CollectionLinkHeaderItem>::Register(TypeBuilder& bld) 18 | { 19 | bld.Inherit<::Neptools::Stcm::CollectionLinkHeaderItem, ::Neptools::Item>(); 20 | 21 | bld.AddFunction< 22 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::CollectionLinkHeaderItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Libshit::NotNull<::Neptools::LabelPtr>>> 23 | >("new"); 24 | bld.AddFunction< 25 | static_cast<::Neptools::Stcm::CollectionLinkHeaderItem & (*)(::Neptools::ItemPointer)>(::Neptools::Stcm::CollectionLinkHeaderItem::CreateAndInsert) 26 | >("create_and_insert"); 27 | bld.AddFunction< 28 | &::Libshit::Lua::GetMember<::Neptools::Stcm::CollectionLinkHeaderItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::CollectionLinkHeaderItem::data> 29 | >("get_data"); 30 | bld.AddFunction< 31 | &::Libshit::Lua::SetMember<::Neptools::Stcm::CollectionLinkHeaderItem, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::CollectionLinkHeaderItem::data> 32 | >("set_data"); 33 | 34 | } 35 | static TypeRegister::StateRegister<::Neptools::Stcm::CollectionLinkHeaderItem> reg_neptools_stcm_collection_link_header_item; 36 | 37 | // class neptools.stcm.collection_link_item 38 | template<> 39 | void TypeRegisterTraits<::Neptools::Stcm::CollectionLinkItem>::Register(TypeBuilder& bld) 40 | { 41 | bld.Inherit<::Neptools::Stcm::CollectionLinkItem, ::Neptools::Item>(); 42 | 43 | bld.AddFunction< 44 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::CollectionLinkItem>::Make, LuaGetRef<::Neptools::Context &>>, 45 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::CollectionLinkItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Neptools::Source>, LuaGetRef<::uint32_t>>, 46 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::CollectionLinkItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef >>> 47 | >("new"); 48 | bld.AddFunction< 49 | &::Libshit::Lua::GetSmartOwnedMember<::Neptools::Stcm::CollectionLinkItem, std::vector<::Neptools::Stcm::CollectionLinkItem::LinkEntry>, &::Neptools::Stcm::CollectionLinkItem::entries> 50 | >("get_entries"); 51 | 52 | } 53 | static TypeRegister::StateRegister<::Neptools::Stcm::CollectionLinkItem> reg_neptools_stcm_collection_link_item; 54 | 55 | // class neptools.stcm.collection_link_item.link_entry 56 | template<> 57 | void TypeRegisterTraits<::Neptools::Stcm::CollectionLinkItem::LinkEntry>::Register(TypeBuilder& bld) 58 | { 59 | 60 | bld.AddFunction< 61 | &::Libshit::Lua::GetMember<::Neptools::Stcm::CollectionLinkItem::LinkEntry, ::Neptools::LabelPtr, &::Neptools::Stcm::CollectionLinkItem::LinkEntry::name_0> 62 | >("get_name_0"); 63 | bld.AddFunction< 64 | &::Libshit::Lua::GetMember<::Neptools::Stcm::CollectionLinkItem::LinkEntry, ::Neptools::LabelPtr, &::Neptools::Stcm::CollectionLinkItem::LinkEntry::name_1> 65 | >("get_name_1"); 66 | bld.AddFunction< 67 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::CollectionLinkItem::LinkEntry>::Make, LuaGetRef<::Neptools::LabelPtr>> 68 | >("new"); 69 | 70 | } 71 | static TypeRegister::StateRegister<::Neptools::Stcm::CollectionLinkItem::LinkEntry> reg_neptools_stcm_collection_link_item_link_entry; 72 | 73 | } 74 | #endif 75 | -------------------------------------------------------------------------------- /src/format/stcm/exports.binding.hpp: -------------------------------------------------------------------------------- 1 | // Auto generated code, do not edit. See gen_binding in project root. 2 | #if LIBSHIT_WITH_LUA 3 | #include 4 | 5 | 6 | const char ::Neptools::Stcm::ExportsItem::TYPE_NAME[] = "neptools.stcm.exports_item"; 7 | const char ::Libshit::Lua::TypeName<::Neptools::Stcm::ExportsItem::Type>::TYPE_NAME[] = 8 | "neptools.stcm.exports_item.type"; 9 | 10 | const char ::Neptools::Stcm::ExportsItem::EntryType::TYPE_NAME[] = "neptools.stcm.exports_item.entry_type"; 11 | 12 | namespace Libshit::Lua 13 | { 14 | 15 | // class neptools.stcm.exports_item 16 | template<> 17 | void TypeRegisterTraits<::Neptools::Stcm::ExportsItem>::Register(TypeBuilder& bld) 18 | { 19 | bld.Inherit<::Neptools::Stcm::ExportsItem, ::Neptools::Item>(); 20 | 21 | bld.AddFunction< 22 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::ExportsItem>::Make, LuaGetRef<::Neptools::Context &>>, 23 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::ExportsItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef<::Neptools::Source>, LuaGetRef<::uint32_t>>, 24 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::ExportsItem>::Make, LuaGetRef<::Neptools::Context &>, LuaGetRef >>> 25 | >("new"); 26 | bld.AddFunction< 27 | static_cast<::Neptools::Stcm::ExportsItem & (*)(::Neptools::ItemPointer, ::uint32_t)>(::Neptools::Stcm::ExportsItem::CreateAndInsert) 28 | >("create_and_insert"); 29 | bld.AddFunction< 30 | &::Libshit::Lua::GetSmartOwnedMember<::Neptools::Stcm::ExportsItem, std::vector<::Neptools::Stcm::ExportsItem::VectorEntry>, &::Neptools::Stcm::ExportsItem::entries> 31 | >("get_entries"); 32 | 33 | } 34 | static TypeRegister::StateRegister<::Neptools::Stcm::ExportsItem> reg_neptools_stcm_exports_item; 35 | 36 | // class neptools.stcm.exports_item.type 37 | template<> 38 | void TypeRegisterTraits<::Neptools::Stcm::ExportsItem::Type>::Register(TypeBuilder& bld) 39 | { 40 | 41 | bld.Add("CODE", ::Neptools::Stcm::ExportsItem::Type::CODE); 42 | bld.Add("DATA", ::Neptools::Stcm::ExportsItem::Type::DATA); 43 | 44 | } 45 | static TypeRegister::StateRegister<::Neptools::Stcm::ExportsItem::Type> reg_neptools_stcm_exports_item_type; 46 | 47 | // class neptools.stcm.exports_item.entry_type 48 | template<> 49 | void TypeRegisterTraits<::Neptools::Stcm::ExportsItem::EntryType>::Register(TypeBuilder& bld) 50 | { 51 | 52 | bld.AddFunction< 53 | &::Libshit::Lua::GetMember<::Neptools::Stcm::ExportsItem::EntryType, ::Neptools::Stcm::ExportsItem::Type, &::Neptools::Stcm::ExportsItem::EntryType::type> 54 | >("get_type"); 55 | bld.AddFunction< 56 | &::Libshit::Lua::SetMember<::Neptools::Stcm::ExportsItem::EntryType, ::Neptools::Stcm::ExportsItem::Type, &::Neptools::Stcm::ExportsItem::EntryType::type> 57 | >("set_type"); 58 | bld.AddFunction< 59 | &::Libshit::Lua::GetMember<::Neptools::Stcm::ExportsItem::EntryType, ::Libshit::FixedString<32>, &::Neptools::Stcm::ExportsItem::EntryType::name> 60 | >("get_name"); 61 | bld.AddFunction< 62 | &::Libshit::Lua::SetMember<::Neptools::Stcm::ExportsItem::EntryType, ::Libshit::FixedString<32>, &::Neptools::Stcm::ExportsItem::EntryType::name> 63 | >("set_name"); 64 | bld.AddFunction< 65 | &::Libshit::Lua::GetMember<::Neptools::Stcm::ExportsItem::EntryType, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::ExportsItem::EntryType::lbl> 66 | >("get_lbl"); 67 | bld.AddFunction< 68 | &::Libshit::Lua::SetMember<::Neptools::Stcm::ExportsItem::EntryType, ::Libshit::NotNull<::Neptools::LabelPtr>, &::Neptools::Stcm::ExportsItem::EntryType::lbl> 69 | >("set_lbl"); 70 | bld.AddFunction< 71 | &::Libshit::Lua::TypeTraits<::Neptools::Stcm::ExportsItem::EntryType>::Make, LuaGetRef &>, LuaGetRef<::Libshit::NotNull<::Neptools::LabelPtr>>> 72 | >("new"); 73 | 74 | } 75 | static TypeRegister::StateRegister<::Neptools::Stcm::ExportsItem::EntryType> reg_neptools_stcm_exports_item_entry_type; 76 | 77 | } 78 | #endif 79 | -------------------------------------------------------------------------------- /src/format/item_base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UUID_02043882_EC07_4CCA_BD13_1BB9F5C7DB9F 2 | #define UUID_02043882_EC07_4CCA_BD13_1BB9F5C7DB9F 3 | #pragma once 4 | 5 | #include "../utils.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace Neptools LIBSHIT_META("alias_file src/format/item.hpp") 21 | { 22 | 23 | class Item; 24 | class Context; 25 | 26 | struct ItemPointer 27 | { 28 | Item* item; 29 | FilePosition offset; 30 | 31 | ItemPointer(Item* item, FilePosition offset = 0) 32 | : item{item}, offset{offset} {} 33 | ItemPointer(Item& item, FilePosition offset = 0) 34 | : item{&item}, offset{offset} {} 35 | 36 | bool operator==(const ItemPointer& o) const 37 | { return item == o.item && offset == o.offset; } 38 | bool operator!=(const ItemPointer& o) const 39 | { return item != o.item || offset != o.offset; } 40 | 41 | Item& operator*() const { return *item; } 42 | Item* operator->() const { return &*item; } 43 | 44 | template 45 | T& As() const { return *Libshit::asserted_cast(item); } 46 | 47 | template 48 | T& AsChecked() const { return dynamic_cast(*item); } 49 | 50 | template 51 | T* Maybe() const { return dynamic_cast(item); } 52 | 53 | template 54 | T& As0() const 55 | { 56 | LIBSHIT_ASSERT(offset == 0); 57 | return *Libshit::asserted_cast(item); 58 | } 59 | 60 | template 61 | T& AsChecked0() const 62 | { 63 | LIBSHIT_ASSERT(offset == 0); 64 | return dynamic_cast(*item); 65 | } 66 | 67 | template 68 | T* Maybe0() const 69 | { 70 | LIBSHIT_ASSERT(offset == 0); 71 | return dynamic_cast(item); 72 | } 73 | }; 74 | 75 | using LabelNameHook = boost::intrusive::set_base_hook< 76 | boost::intrusive::tag, 77 | boost::intrusive::optimize_size, Libshit::LinkMode>; 78 | using LabelOffsetHook = boost::intrusive::set_base_hook< 79 | boost::intrusive::tag, 80 | boost::intrusive::optimize_size, Libshit::LinkMode>; 81 | 82 | class Label final : 83 | public Libshit::RefCounted, public Libshit::Lua::DynamicObject, 84 | public LabelNameHook, public LabelOffsetHook 85 | { 86 | LIBSHIT_DYNAMIC_OBJECT; 87 | public: 88 | 89 | Label(std::string name, ItemPointer ptr) 90 | : name{std::move(name)}, ptr{ptr} {} 91 | 92 | const std::string& GetName() const { return name; } 93 | const ItemPointer& GetPtr() const { return ptr; } 94 | 95 | friend class Context; 96 | friend class Item; 97 | private: 98 | std::string name; 99 | ItemPointer ptr; 100 | }; 101 | 102 | using LabelPtr = Libshit::RefCountedPtr