├── .gitconfig ├── .github ├── FUNDING.yml └── workflows │ ├── build-docs.yml │ ├── build-linux.yml │ ├── build-macos.yml │ └── build-windows.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── deps ├── .gitignore ├── pybind11.wrap └── zlib.wrap ├── examples └── meson.build ├── meson.build ├── meson_options.txt ├── src ├── bindings │ ├── meson.build │ └── python │ │ ├── libalfheim.cc │ │ └── meson.build ├── libalfheim │ ├── aout.cc │ ├── aout.hh │ ├── aout │ │ ├── meson.build │ │ └── types.hh │ ├── coff.cc │ ├── coff.hh │ ├── coff │ │ ├── meson.build │ │ └── types.hh │ ├── config.hh.in │ ├── ecoff.cc │ ├── ecoff.hh │ ├── ecoff │ │ ├── meson.build │ │ └── types.hh │ ├── elf.cc │ ├── elf.hh │ ├── elf │ │ ├── meson.build │ │ └── types.hh │ ├── internal │ │ ├── bits.hh │ │ ├── defs.hh │ │ ├── enum.hh │ │ ├── fd.hh │ │ ├── meson.build │ │ ├── mmap.hh │ │ ├── utility.hh │ │ └── zlib.hh │ ├── macho.cc │ ├── macho.hh │ ├── macho │ │ ├── meson.build │ │ └── types.hh │ ├── meson.build │ ├── os360.cc │ ├── os360.hh │ ├── os360 │ │ ├── meson.build │ │ └── types.hh │ ├── pe32.cc │ ├── pe32.hh │ ├── pe32 │ │ ├── meson.build │ │ └── types.hh │ ├── xcoff.cc │ ├── xcoff.hh │ └── xcoff │ │ ├── meson.build │ │ └── types.hh └── meson.build └── tests └── meson.build /.gitconfig: -------------------------------------------------------------------------------- 1 | [pull] 2 | rebase = merges 3 | [rebase] 4 | autoStash = true 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: lethalbit 2 | patreon: lethalbit 3 | ko_fi: lethalbit 4 | -------------------------------------------------------------------------------- /.github/workflows/build-docs.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lethalbit/libalfheim/eb64e3126902301066036242de0d37be1723ff71/.github/workflows/build-docs.yml -------------------------------------------------------------------------------- /.github/workflows/build-linux.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lethalbit/libalfheim/eb64e3126902301066036242de0d37be1723ff71/.github/workflows/build-linux.yml -------------------------------------------------------------------------------- /.github/workflows/build-macos.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lethalbit/libalfheim/eb64e3126902301066036242de0d37be1723ff71/.github/workflows/build-macos.yml -------------------------------------------------------------------------------- /.github/workflows/build-windows.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lethalbit/libalfheim/eb64e3126902301066036242de0d37be1723ff71/.github/workflows/build-windows.yml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022, All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of ORGANIZATION nor the names of 14 | its contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libalfheim 2 | 3 | libalfheim is a C++ library designed to facilitate with the parsing and generation of various object files formats. 4 | 5 | The sister library for parsing and generating debug info formats can be found at [lethalbit/libfortress](https://github.com/lethalbit/libfortress). 6 | 7 | ## Configuring and Building 8 | 9 | The following steps describe how to build libalfheim, it should be consistent for both Linux and Windows, but Windows remains untested. 10 | 11 | ### Prerequisites 12 | 13 | To build libalfheim, ensure you have the following build time dependencies: 14 | * git 15 | * meson 16 | * ninja 17 | * zlib >=1.2.12 18 | * g++ >= 11 or clang++ >= 11 19 | 20 | Optionally, when also building with binding support (which is the default) you also need: 21 | * python >= 3.9 22 | * pybind11 >= 2.7.0 23 | 24 | 25 | ### Configuring 26 | 27 | You can build libalfheim with the default options, all of which can be found in [`meson_options.txt`](meson_options.txt). You can change these by specifying `-D=` at initial meson invocation time, or with `meson configure` in the build directory post initial configure. 28 | 29 | To change the install prefix, which is `/usr/local` by default ensure to pass `--prefix ` when running meson for the first time. 30 | 31 | In either case, simply running `meson build` from the root of the repository will be sufficient and place all of the build files in the `build` subdirectory. 32 | 33 | ### Building 34 | 35 | Once you have configured libalfheim appropriately, to simply build and install simply run the following: 36 | 37 | ``` 38 | $ ninja -C build 39 | $ ninja -C build install 40 | ``` 41 | 42 | This will build and install libalfheim into the default prefix which is `/usr/local`, to change that see the configuration steps above. 43 | 44 | ### Notes to Package Maintainers 45 | 46 | If you are building libalfheim for inclusion in a distributions package system then ensure to set `DESTDIR` prior to running meson install. 47 | 48 | There is also a `bugreport_url` configuration option that is set to this repositories issues tracker by default, it is recommended to change it to your distributions bug tracking page. 49 | 50 | ## License 51 | 52 | libalfheim is licensed under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html) and can be found in [LICENSE](https://github.com/lethalbit/libalfheim/tree/main/LICENSE). 53 | -------------------------------------------------------------------------------- /deps/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !zlib.wrap 4 | !pybind11.wrap 5 | -------------------------------------------------------------------------------- /deps/pybind11.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = pybind11-2.9.0 3 | source_url = https://github.com/pybind/pybind11/archive/refs/tags/v2.9.0.tar.gz 4 | source_filename = pybind11-2.9.0.tar.gz 5 | source_hash = 057fb68dafd972bc13afb855f3b0d8cf0fa1a78ef053e815d9af79be7ff567cb 6 | patch_filename = pybind11_2.9.0-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/pybind11_2.9.0-1/get_patch 8 | patch_hash = a96220bde795f16c23d45148acc3798ec763b84542b651b3c4b9b977bc5712ba 9 | 10 | [provide] 11 | pybind11 = pybind11_dep 12 | -------------------------------------------------------------------------------- /deps/zlib.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = zlib-1.2.12 3 | source_url = http://zlib.net/fossils/zlib-1.2.12.tar.gz 4 | source_filename = zlib-1.2.12.tar.gz 5 | source_hash = 91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9 6 | patch_filename = zlib_1.2.12-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.2.12-1/get_patch 8 | patch_hash = 8ec8344f3fe7b06ad4be768fd416694bc56cb4545ce78b0f1c18b3e72b3ec936 9 | 10 | [provide] 11 | zlib = zlib_dep 12 | 13 | -------------------------------------------------------------------------------- /examples/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | message('Building examples') 4 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | project( 3 | 'libalfheim', 4 | 'cpp', 5 | default_options: [ 6 | 'cpp_std=c++17', 7 | 'warning_level=3', 8 | 'build.cpp_std=c++17', 9 | 'buildtype=debugoptimized', 10 | 'strip=true', 11 | 'b_ndebug=if-release', 12 | 'b_lto=true' 13 | ], 14 | subproject_dir: 'deps', 15 | version: '0.0.1', 16 | license: [ 17 | 'BSD-3-Clause', 18 | ], 19 | meson_version: '>=0.59.0', 20 | ) 21 | 22 | cxx = meson.get_compiler('cpp') 23 | 24 | if get_option('cpp_std') not in ['c++17', 'c++20', 'c++23', 'gnu++17', 'gnu++20', 'gnu++23'] 25 | error('Unsupported C++ Version @0@, must be c++17/gnu++17 or newer'.format(get_option('cpp_std'))) 26 | endif 27 | 28 | extended_warnings = [ 29 | '-Wdouble-promotion', 30 | '-Wformat=2', 31 | '-Wformat-overflow=2', 32 | '-Wformat-signedness', 33 | '-Wformat-truncation', 34 | '-Wnull-dereference', 35 | '-Wmissing-attributes', 36 | '-Wmissing-braces', 37 | '-Wsequence-point', 38 | '-Wreturn-type', 39 | '-Wunused', 40 | '-Wunused-local-typedefs', 41 | '-Wunused-const-variable=2', 42 | '-Wmaybe-uninitialized', 43 | '-Wunknown-pragmas', 44 | '-Wstrict-aliasing', 45 | '-Wstrict-overflow=3', 46 | '-Wstring-compare', 47 | '-Wstringop-overflow', 48 | '-Warith-conversion', 49 | '-Wvla-parameter', 50 | '-Wduplicated-branches', 51 | '-Wshadow=local', 52 | '-Wunsafe-loop-optimizations', 53 | '-Wbad-function-cast', 54 | '-Wcast-qual', 55 | '-Wcast-align=strict', 56 | '-Wcast-function-type', 57 | '-Wconversion', 58 | '-Wdangling-else', 59 | '-Wsign-conversion', 60 | '-Wfloat-conversion', 61 | '-Wpacked', 62 | '-Wpadded', 63 | '-Wredundant-decls', 64 | '-Winline', 65 | '-Wvla', 66 | '-Wstack-protector', 67 | '-Wunsuffixed-float-constant', 68 | '-Wimplicit-fallthrough', 69 | ] 70 | 71 | add_project_arguments( 72 | cxx.get_supported_arguments(extended_warnings), 73 | language: 'cpp' 74 | ) 75 | 76 | zlib = dependency('zlib', required: false, version: '>=1.2.12') 77 | 78 | if not zlib.found() 79 | message('Did not find local zlib install, bundling') 80 | zlib_wrap = subproject('zlib', default_options: []) 81 | zlib = zlib_wrap.get_variable('zlib_dep') 82 | endif 83 | 84 | 85 | subdir('src') 86 | 87 | if get_option('build_tests') 88 | subdir('tests') 89 | endif 90 | 91 | if get_option('build_examples') 92 | subdir('examples') 93 | endif 94 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'bugreport_url', 3 | type: 'string', 4 | value: 'https://github.com/lethalbit/libalfheim/issues', 5 | description: 'URL for bug report submissions' 6 | ) 7 | 8 | option( 9 | 'build_bindings', 10 | type: 'boolean', 11 | value: true, 12 | description: 'Build the library with bindings' 13 | ) 14 | 15 | option( 16 | 'build_tests', 17 | type: 'boolean', 18 | value: true, 19 | description: 'Build the library with tests' 20 | ) 21 | 22 | option( 23 | 'build_fuzzers', 24 | type: 'boolean', 25 | value: true, 26 | description: 'Build the library fuzzers for aditional testing' 27 | ) 28 | 29 | option( 30 | 'build_examples', 31 | type: 'boolean', 32 | value: true, 33 | description: 'Build the library with examples' 34 | ) 35 | 36 | option( 37 | 'bindings_python', 38 | type: 'boolean', 39 | value: true, 40 | description: 'Build the python bindings (only if build_bindings is enabled)' 41 | ) 42 | -------------------------------------------------------------------------------- /src/bindings/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | message('Building bindings') 4 | 5 | if get_option('bindings_python') 6 | subdir('python') 7 | endif 8 | -------------------------------------------------------------------------------- /src/bindings/python/libalfheim.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace py = pybind11; 8 | 9 | PYBIND11_MODULE(libalfheim, m) { 10 | 11 | m.doc() = "A library for parsing and generating various object file formats."; 12 | m.attr("__version__") = Alfheim::Config::version; 13 | 14 | [[maybe_unused]] 15 | auto aout = m.def_submodule("aout", "Alfheim module for parsing and generating a.out binaries"); 16 | [[maybe_unused]] 17 | auto coff = m.def_submodule("coff", "Alfheim module for parsing and generating COFF binaries"); 18 | [[maybe_unused]] 19 | auto ecoff = m.def_submodule("ecoff", "Alfheim module for parsing and generating ECOFF binaries"); 20 | [[maybe_unused]] 21 | auto elf = m.def_submodule("elf", "Alfheim module for parsing and generating ELF32/ELF64 binaries"); 22 | [[maybe_unused]] 23 | auto macho = m.def_submodule("macho", "Alfheim module for parsing and generating Mach-O binaries"); 24 | [[maybe_unused]] 25 | auto os360 = m.def_submodule("os360", "Alfheim module for parsing and generating os360 binaries"); 26 | [[maybe_unused]] 27 | auto pe32 = m.def_submodule("pe32", "Alfheim module for parsing and generating PE32/PE32+ binaries"); 28 | [[maybe_unused]] 29 | auto xcoff = m.def_submodule("xcoff", "Alfheim module for parsing and generating XCOFF binaries"); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/bindings/python/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | message('Building bindings: Python') 4 | 5 | py = import('python') 6 | py = py.find_installation( 7 | 'python3', 8 | required: false, 9 | modules: [] 10 | ) 11 | 12 | pybind11 = dependency('pybind11', required: false, version: '>=2.7.0') 13 | if not pybind11.found() 14 | message('Did not find local pybind11 install, bundling') 15 | pybind11_wrap = subproject('pybind11', default_options: []) 16 | pybind11 = pybind11_wrap.get_variable('pybind11_dep') 17 | endif 18 | 19 | libalfheim_py = py.extension_module( 20 | 'libalfheim', 21 | files([ 22 | 'libalfheim.cc' 23 | ]), 24 | 25 | include_directories: [ 26 | library_inc, 27 | ], 28 | 29 | dependencies: [ 30 | pybind11 31 | ], 32 | 33 | link_with: [ 34 | libalfheim, 35 | ], 36 | 37 | cpp_args: [ 38 | '-DLIBALFHEIM_BINDINGS_PYTHON' 39 | ], 40 | 41 | install: (not meson.is_subproject()) 42 | ) 43 | -------------------------------------------------------------------------------- /src/libalfheim/aout.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* aout.cc - a.out support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/aout.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* aout.hh - a.out support */ 3 | #pragma once 4 | #if !defined(libalfheim_aout_hh) 5 | #define libalfheim_aout_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::aout { 10 | 11 | } 12 | 13 | #endif /* libalfheim_aout_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/aout/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_aout = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_aout, 14 | subdir: 'libalfheim' / 'aout' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/aout/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* aout/types.hh - a.out types */ 3 | #pragma once 4 | #if !defined(libalfheim_aout_types_hh) 5 | #define libalfheim_aout_types_hh 6 | 7 | namespace Alfheim::aout::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_aout_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/coff.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* coff.cc - COFF support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/coff.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* coff.hh - COFF support */ 3 | #pragma once 4 | #if !defined(libalfheim_coff_hh) 5 | #define libalfheim_coff_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::COFF { 10 | 11 | } 12 | 13 | #endif /* libalfheim_coff_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/coff/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_coff = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_coff, 14 | subdir: 'libalfheim' / 'coff' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/coff/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* coff/types.hh - COFF types */ 3 | #pragma once 4 | #if !defined(libalfheim_coff_types_hh) 5 | #define libalfheim_coff_types_hh 6 | 7 | namespace Alfheim::COFF::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_coff_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/config.hh.in: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* config.hh - Build-time configuration */ 3 | @AUTOGEN_HEADER@ 4 | #pragma once 5 | #if !defined(libalfheim_config_hh) 6 | #define libalfheim_config_hh 7 | 8 | #include 9 | #include 10 | using namespace std::literals::string_view_literals; 11 | 12 | namespace Alfheim::Config { 13 | enum class endian_t : std::uint8_t { 14 | little = 0x0U, 15 | big = 0x1U, 16 | }; 17 | 18 | /* Version Information */ 19 | [[maybe_unused]] 20 | constexpr static auto version{"@VERSION_NUMBER@"sv}; 21 | [[maybe_unused]] 22 | constexpr static auto git_hash{"@GIT_HASH@"sv}; 23 | [[maybe_unused]] 24 | constexpr static auto compiler_name{"@COMPILER_NAME@"sv}; 25 | [[maybe_unused]] 26 | constexpr static auto compiler_version{"@COMPILER_VERSION@"sv}; 27 | 28 | /* Platform Information */ 29 | [[maybe_unused]] 30 | constexpr static auto target_system{"@TARGET_SYS@"sv}; 31 | [[maybe_unused]] 32 | constexpr static auto target_arch{"@TARGET_ARCH@"sv}; 33 | [[maybe_unused]] 34 | constexpr static auto target_endian{@TARGET_ENDIAN@}; 35 | [[maybe_unused]] 36 | constexpr static auto target_width{@TARGET_WIDTH@}; 37 | 38 | [[maybe_unused]] 39 | constexpr static auto build_system{"@BUILD_SYS@"sv}; 40 | [[maybe_unused]] 41 | constexpr static auto build_arch{"@BUILD_ARCH@"sv}; 42 | [[maybe_unused]] 43 | constexpr static auto build_endian{@BUILD_ENDIAN@}; 44 | [[maybe_unused]] 45 | constexpr static auto build_width{@BUILD_WIDTH@}; 46 | 47 | /* Misc */ 48 | [[maybe_unused]] 49 | constexpr static auto bugreport_url{"@BUGREPORT_URL@"sv}; 50 | } 51 | 52 | #endif /* libalfheim_config_hh */ 53 | -------------------------------------------------------------------------------- /src/libalfheim/ecoff.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* ecoff.cc - ECOFF support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/ecoff.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* ecoff.hh - ECOFF support */ 3 | #pragma once 4 | #if !defined(libalfheim_ecoff_hh) 5 | #define libalfheim_ecoff_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::ECOFF { 10 | 11 | } 12 | 13 | #endif /* libalfheim_ecoff_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/ecoff/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_ecoff = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_ecoff, 14 | subdir: 'libalfheim' / 'ecoff' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/ecoff/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* ecoff/types.hh - COFF types */ 3 | #pragma once 4 | #if !defined(libalfheim_ecoff_types_hh) 5 | #define libalfheim_ecoff_types_hh 6 | 7 | namespace Alfheim::ECOFF::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_ecoff_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/elf.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* elf.cc - ELF/ELF64 support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/elf.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* elf.hh - ELF/ELF64 support */ 3 | #pragma once 4 | #if !defined(libalfheim_elf_hh) 5 | #define libalfheim_elf_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::ELF { 10 | 11 | } 12 | 13 | #endif /* libalfheim_elf_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/elf/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_elf = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_elf, 14 | subdir: 'libalfheim' / 'elf' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/elf/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* elf/types.hh - ELF types */ 3 | #pragma once 4 | #if !defined(libalfheim_elf_types_hh) 5 | #define libalfheim_elf_types_hh 6 | 7 | namespace Alfheim::ELF::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_elf_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/internal/bits.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | #pragma once 3 | #if !defined(libalfheim_internal_bits_hh) 4 | #define libalfheim_internal_bits_hh 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Alfheim::Internal { 14 | /* LEB128 encoding and decoding */ 15 | template 16 | [[nodiscard]] 17 | std::enable_if_t && std::is_signed_v, std::vector> 18 | leb128_encode(T num) { 19 | using U = typename std::make_unsigned::type; 20 | using V = promoted_type_t; 21 | std::vector enc{}; 22 | bool more{true}; 23 | while (more) { 24 | auto byte{std::uint8_t(static_cast(num) & 0x7FU)}; 25 | num >>= 7U; 26 | 27 | if ((!num && !(byte & 0x40U)) || (num == -1 && (byte & 0x40U))) 28 | more = false; 29 | else 30 | byte |= 0x80U; 31 | enc.emplace_back(byte); 32 | } 33 | return enc; 34 | } 35 | 36 | template 37 | [[nodiscard]] 38 | std::enable_if_t && std::is_signed_v, T> 39 | leb128_decode(const std::vector &vec) { 40 | using U = typename std::make_unsigned::type; 41 | using V = promoted_type_t; 42 | V enc{}; 43 | std::size_t shift{}; 44 | for (const auto &byte : vec) { 45 | enc |= V{byte & 0x7FU} << shift; 46 | shift += 7U; 47 | } 48 | if (shift && shift < sizeof(T) * 8U) { 49 | --shift; 50 | for (std::size_t i{1U}; i < (sizeof(T) * 8U) - shift; ++i) 51 | enc |= (enc & (V{1U} << shift)) << i; 52 | } 53 | return static_cast(enc); 54 | } 55 | 56 | template 57 | [[nodiscard]] 58 | std::enable_if_t && std::is_unsigned_v, std::vector> 59 | leb128_encode(const T value) { 60 | using U = typename std::make_unsigned::type; 61 | using V = promoted_type_t; 62 | auto num{static_cast(value)}; 63 | std::vector enc{}; 64 | do{ 65 | std::uint8_t byte = num & 0x7FU; 66 | num >>= 7U; 67 | if (num != 0U) 68 | byte |= 0x80U; 69 | enc.emplace_back(byte); 70 | } 71 | while (num != 0U); 72 | return enc; 73 | } 74 | 75 | template 76 | [[nodiscard]] 77 | std::enable_if_t && std::is_unsigned_v, T> 78 | leb128_decode(const std::vector &vec) { 79 | using U = typename std::make_unsigned::type; 80 | using V = promoted_type_t; 81 | V enc{}; 82 | std::size_t shift{}; 83 | for (const auto &byte : vec) { 84 | enc |= V{byte & 0x7FU} << shift; 85 | shift += 7U; 86 | } 87 | return static_cast(enc); 88 | } 89 | 90 | /* endian swapping facilities */ 91 | [[nodiscard]] 92 | inline constexpr std::uint16_t swap16(const std::uint16_t x) noexcept { 93 | return std::uint16_t( 94 | ((x & 0x00FFU) << 8U) | 95 | ((x & 0xFF00U) >> 8U) 96 | ); 97 | } 98 | 99 | [[nodiscard]] 100 | inline constexpr std::uint32_t swap32(const std::uint32_t x) noexcept { 101 | return std::uint32_t( 102 | ((x & 0x000000FFU) << 24U) | 103 | ((x & 0x0000FF00U) << 8U ) | 104 | ((x & 0x00FF0000U) >> 8U ) | 105 | ((x & 0xFF000000U) >> 24U) 106 | ); 107 | } 108 | 109 | [[nodiscard]] 110 | inline constexpr std::uint64_t swap64(const std::uint64_t x) noexcept{ 111 | return std::uint64_t( 112 | ((x & 0x00000000000000FFUL) << 56U) | 113 | ((x & 0x000000000000FF00UL) << 40U) | 114 | ((x & 0x0000000000FF0000UL) << 24U) | 115 | ((x & 0x00000000FF000000UL) << 8U ) | 116 | ((x & 0x000000FF00000000UL) >> 8U ) | 117 | ((x & 0x0000FF0000000000UL) >> 24U) | 118 | ((x & 0x00FF000000000000UL) >> 40U) | 119 | ((x & 0xFF00000000000000UL) >> 56U) 120 | ); 121 | } 122 | 123 | 124 | template 125 | [[nodiscard]] 126 | inline constexpr typename std::enable_if_t && std::is_unsigned_v, T> 127 | rotl(T x, const std::size_t k) noexcept { 128 | constexpr auto bits = std::numeric_limits::digits; 129 | return (x << k) | (x >> (bits - k)); 130 | } 131 | 132 | template 133 | [[nodiscard]] 134 | inline constexpr typename std::enable_if_t && std::is_unsigned_v, T> 135 | rotr(T x, const std::size_t k) noexcept { 136 | constexpr auto bits = std::numeric_limits::digits; 137 | return (x >> k) | (x << (bits - k)); 138 | } 139 | 140 | 141 | template 142 | struct bitspan_t final { 143 | static constexpr std::size_t size = (_msb - _lsb) + 1; 144 | static_assert(_lsb <= _msb, "bitspan LSB must be smaller than or equal to the MSB"); 145 | 146 | template 147 | struct field final { 148 | using value_type = T; 149 | using vu_type = typename std::make_unsigned_t; 150 | 151 | static constexpr auto msb = _msb_; 152 | static constexpr auto lsb = _lsb_; 153 | static constexpr std::size_t width = std::numeric_limits::digits; 154 | static_assert(msb <= width, "MSB must be less than or equal to the width of the bitspan type"); 155 | static constexpr vu_type computed_mask = (((vu_type(1) << (vu_type(msb) + vu_type(1)) - vu_type(lsb)) - vu_type(1)) << vu_type(lsb)); 156 | 157 | 158 | /* Get the value of this field in the given register */ 159 | template 160 | [[nodiscard]] 161 | static inline constexpr std::enable_if_t::value, V> get(const V v) noexcept { 162 | return (vu_type((v) & computed_mask) >> lsb); 163 | } 164 | 165 | template 166 | [[nodiscard]] 167 | static inline constexpr std::enable_if_t::value, V> get(const V v) noexcept { 168 | return static_cast( 169 | vu_type((v) & computed_mask) >> lsb 170 | ); 171 | } 172 | 173 | /* Set the value of this field in the given register */ 174 | template 175 | [[nodiscard]] 176 | static inline constexpr std::enable_if_t> set(V& f, const V v) noexcept { 177 | using Vp = promoted_type_t; 178 | f = V(Vp(((f) & ~computed_mask) | ((vu_type(v) << lsb) & computed_mask))); 179 | } 180 | 181 | template 182 | [[nodiscard]] 183 | static inline constexpr std::enable_if_t> set(V& f, const V v) noexcept { 184 | using Vt = typename std::underlying_type_t; 185 | using Vp = promoted_type_t; 186 | 187 | f = Vp(((f) & ~computed_mask) | ((vu_type(v) << lsb) & computed_mask)); 188 | } 189 | }; 190 | }; 191 | 192 | template 193 | using bit_t = bitspan_t; 194 | 195 | namespace { 196 | template 197 | struct type_at_index_t; 198 | 199 | template 200 | struct type_at_index_t { 201 | using type = typename type_at_index_t::type; 202 | }; 203 | 204 | template 205 | struct type_at_index_t<0, T, U...> { 206 | using type = T; 207 | }; 208 | } 209 | 210 | template 211 | struct bitfield_t final { 212 | using value_type = T; 213 | using vu_type = typename std::make_unsigned_t; 214 | 215 | static constexpr auto width = std::numeric_limits::digits; 216 | static constexpr auto size = width; 217 | static constexpr std::size_t field_count = sizeof... (U); 218 | 219 | /* Returns the field requested by index */ 220 | template 221 | using field = typename type_at_index_t::type::template field; 222 | 223 | /* This is functionally equivalent to ::fields::get() */ 224 | template 225 | [[nodiscard]] 226 | static inline constexpr auto get(const V v) noexcept { 227 | static_assert(idx < field_count, "field index out of range"); 228 | return field::template get(v); 229 | } 230 | 231 | /* This is functionally equivalent to ::fields::set(v) */ 232 | template 233 | static inline constexpr void set(V& f, const V v) noexcept { 234 | static_assert(idx < field_count, "field index out of range"); 235 | field::set(f, v); 236 | } 237 | 238 | }; 239 | } 240 | 241 | #endif /* libalfheim_internal_bits_hh */ 242 | -------------------------------------------------------------------------------- /src/libalfheim/internal/defs.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | #pragma once 3 | #if !defined(libalfheim_internal_defs_hh) 4 | #define libalfheim_internal_defs_hh 5 | 6 | #if defined(_MSC_VER) && !defined(_WINDOWS) 7 | # define _WINDOWS 1 8 | #endif 9 | 10 | #ifdef _WINDOWS 11 | # ifdef LIBALFHEIM_BUILD_INTERNAL 12 | // NOLINTNEXTLINE 13 | # define LIBALFHEIM_CLS_API __declspec(dllexport) 14 | # else 15 | // NOLINTNEXTLINE 16 | # define LIBALFHEIM_CLS_API __declspec(dllimport) 17 | # endif 18 | // NOLINTNEXTLINE 19 | # define LIBALFHEIM_API extern LIBALFHEIM_CLS_API 20 | // NOLINTNEXTLINE 21 | # define LIBALFHEIM_CLS_MAYBE_API 22 | #else 23 | // NOLINTNEXTLINE 24 | # define LIBALFHEIM_CLS_API __attribute__ ((visibility("default"))) 25 | // NOLINTNEXTLINE 26 | # define LIBALFHEIM_CLS_MAYBE_API LIBALFHEIM_CLS_API 27 | // NOLINTNEXTLINE 28 | # define LIBALFHEIM_API extern LIBALFHEIM_CLS_API 29 | #endif 30 | 31 | #endif /* libalfheim_internal_defs_hh */ 32 | -------------------------------------------------------------------------------- /src/libalfheim/internal/enum.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* internal/enum.hh - C++ Enum utilities */ 3 | #pragma once 4 | #if !defined(libalfheim_internal_enum_hh) 5 | #define libalfheim_internal_enum_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::Internal { 10 | 11 | template 12 | [[nodiscard]] 13 | constexpr typename std::enable_if_t, T> 14 | operator|(T l, T r) noexcept { 15 | using U = typename std::underlying_type_t; 16 | return static_cast( 17 | static_cast(l) | static_cast(r) 18 | ); 19 | } 20 | 21 | template 22 | [[nodiscard]] 23 | constexpr typename std::enable_if_t, T> 24 | operator|=(T& l, T r) noexcept { 25 | using U = typename std::underlying_type_t; 26 | return l = static_cast( 27 | static_cast(l) | static_cast(r) 28 | ); 29 | } 30 | 31 | template 32 | [[nodiscard]] 33 | constexpr typename std::enable_if_t, T> 34 | operator&(T l, T r) noexcept { 35 | using U = typename std::underlying_type_t; 36 | return static_cast( 37 | static_cast(l) & static_cast(r) 38 | ); 39 | } 40 | 41 | template 42 | [[nodiscard]] 43 | constexpr typename std::enable_if_t, T> 44 | operator&=(T& l, T r) noexcept { 45 | using U = typename std::underlying_type_t; 46 | return l = static_cast( 47 | static_cast(l) & static_cast(r) 48 | ); 49 | } 50 | 51 | template 52 | [[nodiscard]] 53 | constexpr typename std::enable_if_t, T> 54 | operator^(T l, T r) noexcept { 55 | using U = typename std::underlying_type_t; 56 | return static_cast( 57 | static_cast(l) ^ static_cast(r) 58 | ); 59 | } 60 | 61 | template 62 | [[nodiscard]] 63 | constexpr typename std::enable_if_t, T> 64 | operator^=(T& l, T r) noexcept { 65 | using U = typename std::underlying_type_t; 66 | return l = static_cast( 67 | static_cast(l) ^ static_cast(r) 68 | ); 69 | } 70 | 71 | template 72 | [[nodiscard]] 73 | constexpr typename std::enable_if_t, T> 74 | operator~(T l) noexcept { 75 | using U = typename std::underlying_type_t; 76 | return l = static_cast( 77 | ~static_cast(l) 78 | ); 79 | } 80 | 81 | template 82 | [[nodiscard]] 83 | constexpr typename std::enable_if_t && std::is_integral_v, T> 84 | operator|(T l, V r) noexcept { 85 | using U = typename std::underlying_type_t; 86 | return static_cast( 87 | static_cast(l) | r 88 | ); 89 | } 90 | 91 | template 92 | [[nodiscard]] 93 | constexpr typename std::enable_if_t && std::is_integral_v, T> 94 | operator|=(T& l, T r) noexcept { 95 | using U = typename std::underlying_type_t; 96 | return l = static_cast( 97 | static_cast(l) | r 98 | ); 99 | } 100 | 101 | template 102 | [[nodiscard]] 103 | constexpr typename std::enable_if_t && std::is_integral_v, T> 104 | operator&(T l, T r) noexcept { 105 | using U = typename std::underlying_type_t; 106 | return static_cast( 107 | static_cast(l) & r 108 | ); 109 | } 110 | 111 | template 112 | [[nodiscard]] 113 | constexpr typename std::enable_if_t && std::is_integral_v, T> 114 | operator&=(T& l, T r) noexcept { 115 | using U = typename std::underlying_type_t; 116 | return l = static_cast( 117 | static_cast(l) & r 118 | ); 119 | } 120 | 121 | template 122 | [[nodiscard]] 123 | constexpr typename std::enable_if_t && std::is_integral_v, T> 124 | operator^(T l, T r) noexcept { 125 | using U = typename std::underlying_type_t; 126 | return static_cast( 127 | static_cast(l) ^ r 128 | ); 129 | } 130 | 131 | template 132 | [[nodiscard]] 133 | constexpr typename std::enable_if_t && std::is_integral_v, T> 134 | operator^=(T& l, T r) noexcept { 135 | using U = typename std::underlying_type_t; 136 | return l = static_cast( 137 | static_cast(l) ^ r 138 | ); 139 | } 140 | 141 | template 142 | [[nodiscard]] 143 | constexpr typename std::enable_if_t && std::is_enum_v, T> 144 | operator|(T l, V r) noexcept { 145 | using U = typename std::underlying_type_t; 146 | return static_cast( 147 | l | static_cast(r) 148 | ); 149 | } 150 | 151 | template 152 | [[nodiscard]] 153 | constexpr typename std::enable_if_t && std::is_enum_v, T> 154 | operator|=(T& l, T r) noexcept { 155 | using U = typename std::underlying_type_t; 156 | return l = static_cast( 157 | l | static_cast(r) 158 | ); 159 | } 160 | 161 | template 162 | [[nodiscard]] 163 | constexpr typename std::enable_if_t && std::is_enum_v, T> 164 | operator&(T l, T r) noexcept { 165 | using U = typename std::underlying_type_t; 166 | return static_cast( 167 | l & static_cast(r) 168 | ); 169 | } 170 | 171 | template 172 | [[nodiscard]] 173 | constexpr typename std::enable_if_t && std::is_enum_v, T> 174 | operator&=(T& l, T r) noexcept { 175 | using U = typename std::underlying_type_t; 176 | return l = static_cast( 177 | l & static_cast(r) 178 | ); 179 | } 180 | 181 | template 182 | [[nodiscard]] 183 | constexpr typename std::enable_if_t && std::is_enum_v, T> 184 | operator^(T l, T r) noexcept { 185 | using U = typename std::underlying_type_t; 186 | return static_cast( 187 | l ^ static_cast(r) 188 | ); 189 | } 190 | 191 | template 192 | [[nodiscard]] 193 | constexpr typename std::enable_if_t && std::is_enum_v, T> 194 | operator^=(T& l, T r) noexcept { 195 | using U = typename std::underlying_type_t; 196 | return l = static_cast( 197 | l ^ static_cast(r) 198 | ); 199 | } 200 | 201 | } 202 | 203 | #endif /* libalfheim_internal_enum_hh */ 204 | -------------------------------------------------------------------------------- /src/libalfheim/internal/fd.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* internal/fd.hh - RAII File wrapper */ 3 | #pragma once 4 | #if !defined(libalfheim_internal_fd_hh) 5 | #define libalfheim_internal_fd_hh 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if !defined(_MSC_VER) 19 | # include 20 | #else 21 | # include 22 | #endif 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace Alfheim::Internal { 32 | namespace fs = std::filesystem; 33 | 34 | namespace { 35 | #if defined(_WINDOWS) 36 | [[nodiscard]] 37 | inline Types::ssize_t fdread(const std::int32_t fd, void* const buff, const std::size_t, len) noexcept { 38 | return read(fd, buff, std::uint32_t(len)); 39 | } 40 | 41 | [[nodiscard]] 42 | inline Types::ssize_t fdwrite(const std::int32_t fd, const void* const buff, const std::size_t len) noexcept { 43 | return write(fd, buff, std::uint32_t(len)); 44 | } 45 | 46 | [[nodiscard]] 47 | inline int fstat(const std::int32_t fd, Types::stat_t* stat) noexcept { 48 | return _fstat64(fd, stat); 49 | } 50 | 51 | [[nodiscard]] 52 | inline Types::off_t fdseek(const std::int32_t fd, const Types::off_t offset, const std::int32_t whence) noexcept { 53 | return _lseeki64(fd, offset, whence); 54 | } 55 | 56 | [[nodiscard]] 57 | inline Types::off_t fdtell(const std::int32_t fd) noexcept { 58 | return _telli64(fd); 59 | } 60 | 61 | [[nodiscard]] 62 | inline std::int32_t fdtruncate(const std::int32_t fd, const Types::off_t size) noexcept { 63 | return _chsize_s(fd, size); 64 | } 65 | #else 66 | using ::fstat; 67 | 68 | [[nodiscard]] 69 | inline Types::ssize_t fdread(const std::int32_t fd, void* const buff, const std::size_t len) noexcept { 70 | return ::read(fd, buff, len); 71 | } 72 | 73 | [[nodiscard]] 74 | inline Types::ssize_t fdwrite(const std::int32_t fd, const void* const buff, const std::size_t len) noexcept { 75 | return ::write(fd, buff, len); 76 | } 77 | 78 | [[nodiscard]] 79 | inline Types::off_t fdseek(const std::int32_t fd, const Types::off_t offset, const std::int32_t whence) noexcept { 80 | return ::lseek(fd, offset, whence); 81 | } 82 | 83 | [[nodiscard]] 84 | inline Types::off_t fdtell(const std::int32_t fd) noexcept { 85 | return ::lseek(fd, 0, SEEK_CUR); 86 | } 87 | 88 | [[nodiscard]] 89 | inline std::int32_t fdtruncate(const std::int32_t fd, const Types::off_t size) noexcept { 90 | return ::ftruncate(fd, size); 91 | } 92 | #endif 93 | } 94 | 95 | struct fd_t final { 96 | private: 97 | std::int32_t _fd{-1}; 98 | bool _eof{false}; 99 | Types::off_t _len{-1}; 100 | public: 101 | constexpr fd_t() noexcept = default; 102 | constexpr fd_t(const std::int32_t fd) noexcept : _fd{fd} { /* NOP */ } 103 | 104 | fd_t(const char* const file, const int flags, const Types::mode_t mode = 0) noexcept : 105 | _fd{::open(file, flags, mode)} { /* NOP */ } 106 | 107 | fd_t(const std::string& file, const int flags, const Types::mode_t mode = 0) noexcept : 108 | _fd{::open(file.c_str(), flags, mode)} { /* NOP */ } 109 | 110 | fd_t(const fs::path& file, const int flags, const Types::mode_t mode = 0) noexcept : 111 | _fd{::open(file.c_str(), flags, mode)} { /* NOP */ } 112 | 113 | fd_t(fd_t&& fd) noexcept : fd_t{} { swap(fd); } 114 | fd_t(const fd_t&) = delete; 115 | fd_t& operator=(const fd_t&) = delete; 116 | 117 | 118 | ~fd_t() noexcept { 119 | if (_fd != -1) 120 | ::close(_fd); 121 | } 122 | 123 | void operator=(fd_t&& fd) noexcept { swap(fd); } 124 | [[nodiscard]] 125 | operator std::int32_t() const noexcept { return _fd; } 126 | [[nodiscard]] 127 | bool operator==(const std::int32_t desc) const noexcept { return _fd == desc; } 128 | [[nodiscard]] 129 | bool valid() const noexcept { return _fd != -1; } 130 | [[nodiscard]] 131 | bool is_eof() const noexcept { return _eof; } 132 | void invalidate() noexcept { _fd = -1; } 133 | 134 | void swap(fd_t& desc) { 135 | std::swap(_fd, desc._fd); 136 | std::swap(_len, desc._len); 137 | std::swap(_eof, desc._eof); 138 | } 139 | 140 | [[nodiscard]] 141 | Types::off_t seek(const Types::off_t offset, const std::int32_t whence) noexcept { 142 | const auto res = fdseek(_fd, offset, whence); 143 | _eof = (res == length()); 144 | return res; 145 | } 146 | 147 | [[nodiscard]] 148 | bool seek_rel(const Types::off_t offset) noexcept { 149 | const auto pos = tell(); 150 | if (pos == -1 || pos + offset < 0) 151 | return false; 152 | return seek(offset, SEEK_CUR) == (pos + offset); 153 | } 154 | 155 | [[nodiscard]] 156 | Types::off_t tell() const noexcept { return fdtell(_fd); } 157 | 158 | [[nodiscard]] 159 | bool head() noexcept { return seek(0, SEEK_SET) == 0; } 160 | 161 | [[nodiscard]] 162 | fd_t dup() const noexcept { return ::dup(_fd); } 163 | 164 | [[nodiscard]] 165 | bool tail() noexcept { 166 | const auto off = length(); 167 | if (off < 0) 168 | return false; 169 | return seek(off, SEEK_SET) == off; 170 | } 171 | 172 | [[nodiscard]] 173 | Types::stat_t stat() const noexcept { 174 | Types::stat_t fd_stat{}; 175 | if (!fstat(_fd, &fd_stat)) 176 | return fd_stat; 177 | return {}; 178 | } 179 | 180 | [[nodiscard]] 181 | Types::off_t length() noexcept { 182 | if (_len != -1) 183 | return _len; 184 | 185 | Types::stat_t fd_stat{}; 186 | const auto res = fstat(_fd, &fd_stat); 187 | _len = res ? -1 : fd_stat.st_size; 188 | return _len; 189 | } 190 | 191 | [[nodiscard]] 192 | bool resize(const Types::off_t size) const noexcept { 193 | return fdtruncate(_fd, size) == 0; 194 | } 195 | 196 | [[nodiscard]] 197 | Types::ssize_t read(void* const buff, const std::size_t len, std::nullptr_t) noexcept { 198 | const auto res = fdread(_fd, buff, len); 199 | 200 | if (!res && len) 201 | _eof = true; 202 | 203 | return res; 204 | } 205 | 206 | [[nodiscard]] 207 | Types::ssize_t write(const void* const buff, const std::size_t len, std::nullptr_t) const noexcept { 208 | return fdwrite(_fd, buff, len); 209 | } 210 | 211 | [[nodiscard]] 212 | bool read(void* const val, const std::size_t len, std::size_t& res_len) noexcept { 213 | const auto res = read(val, len, nullptr); 214 | if (res < 0) 215 | return false; 216 | return (res_len = std::size_t(res)) == len; 217 | } 218 | 219 | [[nodiscard]] 220 | bool read(void* const val, const std::size_t len) noexcept { 221 | std::size_t res_len{0}; 222 | return read(val, len, res_len); 223 | } 224 | 225 | [[nodiscard]] 226 | bool write(const void* const val, const std::size_t len) const noexcept { 227 | const auto res = write(val, len, nullptr); 228 | if (res < 0) 229 | return false; 230 | return std::size_t(res) == len; 231 | } 232 | 233 | template 234 | [[nodiscard]] 235 | bool read(T& val) noexcept { 236 | return read(&val, sizeof(T)); 237 | } 238 | 239 | template 240 | [[nodiscard]] 241 | bool write(const T& val) const noexcept { 242 | return write(&val, sizeof(T)); 243 | } 244 | 245 | template 246 | [[nodiscard]] 247 | bool read(std::unique_ptr& val) noexcept { 248 | return read(val.get(), sizeof(T)); 249 | } 250 | 251 | template 252 | [[nodiscard]] 253 | bool read(const std::unique_ptr& val) noexcept { 254 | return read(val.get(), sizeof(T)); 255 | } 256 | 257 | template 258 | [[nodiscard]] 259 | bool write(const std::unique_ptr& val) const noexcept { 260 | return write(val.get(), sizeof(T)); 261 | } 262 | 263 | template 264 | [[nodiscard]] 265 | bool read(const std::unique_ptr& val, const std::size_t len) noexcept { 266 | return read(val.get(), sizeof(T) * len); 267 | } 268 | 269 | template 270 | [[nodiscard]] 271 | bool write(const std::unique_ptr& val, const std::size_t len) const noexcept { 272 | return write(val.get(), sizeof(T) * len); 273 | } 274 | 275 | template 276 | [[nodiscard]] 277 | bool read(std::array& val) noexcept { 278 | return read(val.data(), sizeof(T) * N); 279 | } 280 | 281 | template 282 | [[nodiscard]] 283 | bool write(const std::array& val) noexcept { 284 | return write(val.data(), sizeof(T) * N); 285 | } 286 | 287 | [[nodiscard]] 288 | bool write(const std::string& val) const noexcept { 289 | return write(val.data(), val.size()); 290 | } 291 | 292 | [[nodiscard]] 293 | bool write(const std::string_view& val) const noexcept { 294 | return write(val.data(), val.size()); 295 | } 296 | 297 | [[nodiscard]] 298 | bool read_le(std::uint16_t& val) noexcept { 299 | if constexpr (Alfheim::Internal::is_le()) { 300 | return read(val); 301 | } else { 302 | std::uint16_t _value{}; 303 | const auto res = read(_value); 304 | val = Alfheim::Internal::swap16(_value); 305 | return res; 306 | } 307 | } 308 | 309 | [[nodiscard]] 310 | bool write_le(const std::uint16_t val) const noexcept { 311 | if constexpr (Alfheim::Internal::is_le()) { 312 | return write(val); 313 | } else { 314 | return write(Alfheim::Internal::swap16(val)); 315 | } 316 | } 317 | 318 | [[nodiscard]] 319 | bool read_le(std::uint32_t& val) noexcept { 320 | if constexpr (Alfheim::Internal::is_le()) { 321 | return read(val); 322 | } else { 323 | std::uint32_t _value{}; 324 | const auto res = read(_value); 325 | val = Alfheim::Internal::swap32(_value); 326 | return res; 327 | } 328 | } 329 | 330 | [[nodiscard]] 331 | bool write_le(const std::uint32_t val) const noexcept { 332 | if constexpr (Alfheim::Internal::is_le()) { 333 | return write(val); 334 | } else { 335 | return write(Alfheim::Internal::swap32(val)); 336 | } 337 | } 338 | 339 | [[nodiscard]] 340 | bool read_le(std::uint64_t& val) noexcept { 341 | if constexpr (Alfheim::Internal::is_le()) { 342 | return read(val); 343 | } else { 344 | std::uint64_t _value{}; 345 | const auto res = read(_value); 346 | val = Alfheim::Internal::swap64(_value); 347 | return res; 348 | } 349 | } 350 | 351 | [[nodiscard]] 352 | bool write_le(const std::uint64_t val) const noexcept { 353 | if constexpr (Alfheim::Internal::is_le()) { 354 | return write(val); 355 | } else { 356 | return write(Alfheim::Internal::swap64(val)); 357 | } 358 | } 359 | 360 | template< 361 | typename T, 362 | typename = typename std::enable_if_t< 363 | std::is_integral_v && std::is_same_v && 364 | std::is_signed_v && sizeof(T) >= 2 365 | > 366 | > 367 | [[nodiscard]] 368 | bool read_le(T& val) noexcept { 369 | typename std::make_unsigned_t data{}; 370 | const auto res = read_le(data); 371 | val = static_cast(data); 372 | return res; 373 | } 374 | 375 | template< 376 | typename T, 377 | typename = typename std::enable_if_t< 378 | std::is_integral_v && std::is_same_v && 379 | std::is_signed_v && sizeof(T) >= 2 380 | > 381 | > 382 | [[nodiscard]] 383 | bool write_le(T& val) noexcept { 384 | return write_le( 385 | static_cast>( 386 | val 387 | ) 388 | ); 389 | } 390 | 391 | [[nodiscard]] 392 | bool read_be(std::uint16_t& val) noexcept { 393 | if constexpr (Alfheim::Internal::is_be()) { 394 | return read(val); 395 | } else { 396 | std::uint16_t _value{}; 397 | const auto res = read(_value); 398 | val = Alfheim::Internal::swap16(_value); 399 | return res; 400 | } 401 | } 402 | 403 | [[nodiscard]] 404 | bool write_be(const std::uint16_t val) const noexcept { 405 | if constexpr (Alfheim::Internal::is_be()) { 406 | return write(val); 407 | } else { 408 | return write(Alfheim::Internal::swap16(val)); 409 | } 410 | } 411 | 412 | [[nodiscard]] 413 | bool read_be(std::uint32_t& val) noexcept { 414 | if constexpr (Alfheim::Internal::is_be()) { 415 | return read(val); 416 | } else { 417 | std::uint32_t _value{}; 418 | const auto res = read(_value); 419 | val = Alfheim::Internal::swap32(_value); 420 | return res; 421 | } 422 | } 423 | 424 | [[nodiscard]] 425 | bool write_be(const std::uint32_t val) const noexcept { 426 | if constexpr (Alfheim::Internal::is_be()) { 427 | return write(val); 428 | } else { 429 | return write(Alfheim::Internal::swap32(val)); 430 | } 431 | } 432 | 433 | [[nodiscard]] 434 | bool read_be(std::uint64_t& val) noexcept { 435 | if constexpr (Alfheim::Internal::is_be()) { 436 | return read(val); 437 | } else { 438 | std::uint64_t _value{}; 439 | const auto res = read(_value); 440 | val = Alfheim::Internal::swap64(_value); 441 | return res; 442 | } 443 | } 444 | 445 | [[nodiscard]] 446 | bool write_be(const std::uint64_t val) const noexcept { 447 | if constexpr (Alfheim::Internal::is_be()) { 448 | return write(val); 449 | } else { 450 | return write(Alfheim::Internal::swap64(val)); 451 | } 452 | } 453 | 454 | template< 455 | typename T, 456 | typename = typename std::enable_if_t< 457 | std::is_integral_v && std::is_same_v && 458 | std::is_signed_v && sizeof(T) >= 2 459 | > 460 | > 461 | [[nodiscard]] 462 | bool read_be(T& val) noexcept { 463 | typename std::make_unsigned_t data{}; 464 | const auto res = read_be(data); 465 | val = static_cast(data); 466 | return res; 467 | } 468 | 469 | template< 470 | typename T, 471 | typename = typename std::enable_if_t< 472 | std::is_integral_v && std::is_same_v && 473 | std::is_signed_v && sizeof(T) >= 2 474 | > 475 | > 476 | [[nodiscard]] 477 | bool write_be(T& val) noexcept { 478 | return write_be( 479 | static_cast>( 480 | val 481 | ) 482 | ); 483 | } 484 | 485 | [[nodiscard]] 486 | mmap_t map(const std::int32_t prot, const int flags) noexcept { 487 | const auto len{length()}; 488 | if (len <= 0) 489 | return {}; 490 | return map(prot, static_cast(len), flags); 491 | } 492 | 493 | [[nodiscard]] 494 | mmap_t map(const std::int32_t prot, const std::size_t len, const int flags, void* const addr = nullptr) noexcept { 495 | if (!valid()) 496 | return {}; 497 | const std::int32_t file = _fd; 498 | invalidate(); 499 | return {file, len, prot, flags, addr}; 500 | } 501 | }; 502 | 503 | 504 | inline void swap(fd_t& fd_a, fd_t& fd_b) noexcept { fd_a.swap(fd_b); } 505 | } 506 | 507 | 508 | #endif /* libalfheim_internal_fd_hh */ 509 | -------------------------------------------------------------------------------- /src/libalfheim/internal/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_internal = files([ 4 | 'bits.hh', 5 | 'defs.hh', 6 | 'enum.hh', 7 | 'fd.hh', 8 | 'mmap.hh', 9 | 'utility.hh', 10 | 'zlib.hh', 11 | ]) 12 | 13 | library_srcs += files([ 14 | 15 | ]) 16 | 17 | if not meson.is_subproject() 18 | install_headers( 19 | library_hdrs_internal, 20 | subdir: 'libalfheim' / 'internal' 21 | ) 22 | endif 23 | -------------------------------------------------------------------------------- /src/libalfheim/internal/mmap.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* internal/mmap.hh - RAII mmap wrapper */ 3 | #pragma once 4 | #if !defined(libalfheim_internal_mmap_hh) 5 | #define libalfheim_internal_mmap_hh 6 | 7 | #include 8 | 9 | #if !defined(_WINDOWS) 10 | # include 11 | # include 12 | #else 13 | # include 14 | # include 15 | # define WIN32_LEAN_AND_MEAN 16 | # include 17 | # undef WIN32_LEAN_AND_MEAN 18 | # undef min 19 | # undef max 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | 38 | 39 | namespace Alfheim::Internal { 40 | #if defined(_WINDOWS) 41 | constexpr DWORD PROT_READ{PAGE_READONLY}; 42 | constexpr DWORD PROT_WRITE{PAGE_READWRITE}; 43 | constexpr auto MADV_SEQUENTIAL{0}; 44 | constexpr auto MADV_WILLNEED{0}; 45 | constexpr auto MADV_DONTDUMP{0}; 46 | #endif 47 | struct mmap_t final { 48 | private: 49 | std::size_t _len{0}; 50 | #if defined(_WINDOWS) 51 | HANDLE _mapping{INVALID_HANDLE_VALUE}; 52 | #endif 53 | void* _addr{nullptr}; 54 | std::int32_t _fd{-1}; 55 | #if !defined(_WINDOWS) 56 | [[nodiscard]] 57 | mmap_t(const mmap_t& map, const std::size_t len, const std::int32_t prot, 58 | const std::int32_t flags = MAP_SHARED, void* const addr = nullptr 59 | ) noexcept : _len{len}, _addr{[&]() noexcept -> void* { 60 | const auto ptr{::mmap(addr, len, prot, flags, map._fd, 0)}; 61 | return (ptr == MAP_FAILED) ? nullptr : ptr; 62 | }()}, _fd{-1} { /* NOP */ } 63 | #endif 64 | 65 | template 66 | [[nodiscard]] 67 | std::enable_if_t< 68 | std::is_pod_v && !has_nullable_ctor_v && !std::is_same_v, 69 | T*> 70 | index(const std::size_t idx) const { 71 | if (idx < _len) { 72 | const auto addr = reinterpret_cast(_addr); 73 | return new (reinterpret_cast(addr + (idx * sizeof(T)))) T{}; 74 | } 75 | throw std::out_of_range("mmap_t index out of range"); 76 | } 77 | 78 | template 79 | [[nodiscard]] 80 | std::enable_if_t< 81 | has_nullable_ctor_v && !std::is_same_v, 82 | T*> 83 | index(const std::size_t idx) const { 84 | if (idx < _len) { 85 | const auto addr = reinterpret_cast(_addr); 86 | return new (reinterpret_cast(addr + (idx * sizeof(T)))) T{nullptr}; 87 | } 88 | throw std::out_of_range("mmap_t index out of range"); 89 | } 90 | 91 | template 92 | [[nodiscard]] 93 | std::enable_if_t, void*> 94 | index(const std::size_t idx) const { 95 | if (idx < _len) { 96 | const auto addr = reinterpret_cast(_addr); 97 | return reinterpret_cast(addr + idx ); 98 | } 99 | throw std::out_of_range("mmap_t index out of range"); 100 | } 101 | 102 | #if defined(_WINDOWS) 103 | constexpr static DWORD clear_prot(const DWORD prot) noexcept { 104 | if (prot & PAGE_READWRITE) 105 | return prot & ~PAGE_READONLY; 106 | return prot; 107 | } 108 | 109 | constexpr static DWORD prot_to_access(const DWORD prot) noexcept { 110 | if (prot & PAGE_READWRITE) 111 | return FILE_MAP_WRITE; 112 | else if (prot & PAGE_READONLY) 113 | return FILE_MAP_READ; 114 | else if (prot & PAGE_WRITECOPY) 115 | return FILE_MAP_WRITE; 116 | return {}; 117 | } 118 | #endif 119 | 120 | public: 121 | [[nodiscard]] 122 | constexpr mmap_t() noexcept = default; 123 | 124 | mmap_t(const mmap_t&) = delete; 125 | mmap_t& operator=(const mmap_t&) = delete; 126 | 127 | [[nodiscard]] 128 | bool operator==(const mmap_t& b) const noexcept { 129 | return _fd == b._fd && _addr == b._addr && _len == b._len; 130 | } 131 | [[nodiscard]] 132 | bool operator!=(const mmap_t& b) const noexcept { return !(*this == b); } 133 | 134 | #if !defined(_WINDOWS) 135 | [[nodiscard]] 136 | mmap_t(const std::int32_t fd, const std::size_t len, const std::int32_t prot, 137 | const std::int32_t flags = MAP_SHARED, void* const addr = nullptr 138 | ) noexcept : _len{len}, _addr{[&]() noexcept -> void* { 139 | const auto ptr{::mmap(addr, len, prot, flags, fd, 0)}; 140 | return (ptr == MAP_FAILED) ? nullptr : ptr; 141 | }()}, _fd{fd} { /* NOP */ } 142 | 143 | [[nodiscard]] 144 | mmap_t(mmap_t&& map) noexcept : mmap_t{} { swap(map); } 145 | void operator=(mmap_t&& map) noexcept { swap(map); } 146 | ~mmap_t() noexcept { 147 | if (_addr) 148 | ::munmap(_addr, _len); 149 | if (_fd != -1) 150 | ::close(_fd); 151 | } 152 | 153 | [[nodiscard]] 154 | constexpr bool valid() const noexcept { return _addr; } 155 | #endif 156 | 157 | void swap(mmap_t& map) noexcept { 158 | std::swap(_fd, map._fd); 159 | std::swap(_addr, map._addr); 160 | std::swap(_len, map._len); 161 | #if defined(_WINDOWS) 162 | std::swap(_mapping, map._mapping); 163 | #endif 164 | } 165 | 166 | [[nodiscard]] 167 | std::size_t length() const noexcept { return _len; } 168 | 169 | [[nodiscard]] 170 | mmap_t dup(const std::int32_t prot, const std::size_t len, const std::int32_t flags, void* const addr) const noexcept { 171 | if (!valid()) 172 | return {}; 173 | return {*this, len, prot, flags, addr}; 174 | } 175 | 176 | [[nodiscard]] 177 | bool chperm(const std::int32_t prot) const noexcept { 178 | return ::mprotect(_addr, _len, prot) == 0; 179 | } 180 | 181 | template 182 | [[nodiscard]] 183 | T* address() noexcept { return static_cast(_addr); } 184 | 185 | template 186 | [[nodiscard]] 187 | const T* address() const noexcept { return static_cast(_addr); } 188 | 189 | void* address(const std::size_t offset) noexcept { return index(offset); } 190 | const void* address(const std::size_t offset) const noexcept { return index(offset); } 191 | 192 | template 193 | [[nodiscard]] 194 | T* operator[](const std::size_t idx) { return index(idx); } 195 | template 196 | [[nodiscard]] 197 | const T* operator[](const std::size_t idx) const { return index(idx); } 198 | 199 | template 200 | [[nodiscard]] 201 | T* at(const std::size_t idx) { return index(idx); } 202 | template 203 | [[nodiscard]] 204 | const T* at(const std::size_t idx) const { return index(idx); } 205 | 206 | [[nodiscard]] 207 | std::uintptr_t numeric_address() const noexcept { 208 | return reinterpret_cast(_addr); 209 | } 210 | 211 | [[nodiscard]] 212 | bool lock() const noexcept { 213 | return lock(_len); 214 | } 215 | 216 | [[nodiscard]] 217 | bool lock(const std::size_t len) const noexcept { 218 | return ::mlock(_addr, len) == 0; 219 | } 220 | 221 | [[nodiscard]] 222 | bool lock_at(const std::size_t idx, const std::size_t len) const noexcept { 223 | const auto addr = reinterpret_cast(_addr); 224 | return ::mlock(reinterpret_cast(addr + idx), len) == 0; 225 | } 226 | 227 | [[nodiscard]] 228 | bool unlock() const noexcept { 229 | return unlock(_len); 230 | } 231 | 232 | [[nodiscard]] 233 | bool unlock(const std::size_t len) const noexcept { 234 | return ::munlock(_addr, len) == 0; 235 | } 236 | 237 | [[nodiscard]] 238 | bool unlock_at(const std::size_t idx, const std::size_t len) const noexcept { 239 | const auto addr = reinterpret_cast(_addr); 240 | return ::munlock(reinterpret_cast(addr + idx), len) == 0; 241 | } 242 | 243 | [[nodiscard]] 244 | bool remap(const std::int32_t flags, const std::size_t len) noexcept { 245 | const auto old_len = _len; 246 | _len = len; 247 | return (_addr = ::mremap(_addr, old_len, _len, flags)) != MAP_FAILED; 248 | } 249 | 250 | [[nodiscard]] 251 | bool remap(const std::int32_t flags, const std::size_t len, const std::uintptr_t addr) noexcept { 252 | const auto old_len = _len; 253 | _len = len; 254 | const void* wanted_addr = reinterpret_cast(addr); 255 | return (_addr = ::mremap(_addr, old_len, _len, flags, wanted_addr)) != MAP_FAILED; 256 | } 257 | 258 | #if !defined(_WINDOWS) 259 | [[nodiscard]] 260 | bool sync(const std::int32_t flags = MS_SYNC | MS_INVALIDATE) const noexcept { 261 | return sync(flags, _len); 262 | } 263 | 264 | [[nodiscard]] 265 | bool sync(const std::int32_t flags, const std::size_t len) const noexcept { 266 | return ::msync(_addr, len, flags) == 0; 267 | } 268 | 269 | [[nodiscard]] 270 | bool advise(const std::int32_t advice) const noexcept { 271 | return advise(advice, _len); 272 | } 273 | 274 | [[nodiscard]] 275 | bool advise(const std::int32_t advice, const std::size_t len) const noexcept { 276 | return ::madvise(_addr, len, advice) == 0; 277 | } 278 | 279 | [[nodiscard]] 280 | bool advise_at(const std::int32_t advice, const std::size_t len, const std::size_t idx) const noexcept { 281 | const auto addr = reinterpret_cast(_addr); 282 | return ::madvise(reinterpret_cast(addr + idx), len, advice) == 0; 283 | } 284 | 285 | #endif 286 | }; 287 | 288 | inline void swap(mmap_t& a, mmap_t& b) noexcept { a.swap(b); } 289 | } 290 | 291 | #endif /* libalfheim_internal_mmap_hh */ 292 | -------------------------------------------------------------------------------- /src/libalfheim/internal/utility.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* internal/utility.hh - Various helpers and such */ 3 | #pragma once 4 | #if !defined(libalfheim_internal_utility_hh) 5 | #define libalfheim_internal_utility_hh 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #if !defined(_MSC_VER) 18 | # include 19 | #else 20 | # include 21 | #endif 22 | 23 | namespace Alfheim::Internal { namespace Units { 24 | /* IEC Units*/ 25 | constexpr std::uint64_t operator ""_KiB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1024; } 26 | constexpr std::uint64_t operator ""_MiB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1048576; } 27 | constexpr std::uint64_t operator ""_GiB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1073741824; } 28 | constexpr std::uint64_t operator ""_TiB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1099511627776; } 29 | constexpr std::uint64_t operator ""_PiB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1125899906842624; } 30 | 31 | /* SI Units */ 32 | constexpr std::uint64_t operator ""_KB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1000; } 33 | constexpr std::uint64_t operator ""_MB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1000000; } 34 | constexpr std::uint64_t operator ""_GB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1000000000; } 35 | constexpr std::uint64_t operator ""_TB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1000000000000; } 36 | constexpr std::uint64_t operator ""_PB(const unsigned long long value) noexcept { return std::uint64_t(value) * 1000000000000000; } 37 | } 38 | 39 | namespace Types { 40 | #if defined(_WINDOWS) 41 | using mode_t = std::int32_t; 42 | using stat_t = struct ::_stat64; 43 | # if defined(_WIN64) 44 | using ssize_t = __int64; 45 | using off_t = std::int64_t; 46 | # else 47 | using ssize_t = int; 48 | using off_t = std::int32_t; 49 | # endif 50 | #else 51 | using stat_t = struct ::stat; 52 | using mode_t = std::int32_t; 53 | using ssize_t = typename std::make_signed::type; 54 | using off_t = std::int64_t; 55 | #endif 56 | } 57 | 58 | template 59 | struct has_nullable_ctor final { 60 | template 61 | static std::true_type _ctor(decltype(U(std::nullptr_t()))*); 62 | template 63 | static std::false_type _ctor(...); 64 | 65 | static const bool value = std::is_same(nullptr)), std::true_type>::value; 66 | }; 67 | 68 | template 69 | constexpr bool has_nullable_ctor_v = has_nullable_ctor::value; 70 | 71 | template 72 | struct is_vector : std::false_type {}; 73 | 74 | template 75 | struct is_vector> : std::true_type {}; 76 | 77 | template 78 | struct is_array : std::false_type {}; 79 | 80 | template 81 | struct is_array> : std::true_type {}; 82 | 83 | template 84 | constexpr inline bool is_vector_v = is_vector::value; 85 | 86 | template 87 | constexpr inline bool is_array_v = is_array::value; 88 | 89 | template 90 | using value_t = typename T::value_type; 91 | 92 | 93 | template> 94 | struct promoted_type; 95 | 96 | template 97 | struct promoted_type { using type = std::uint32_t; }; 98 | 99 | template 100 | struct promoted_type { using type = std::int32_t; }; 101 | 102 | template<> 103 | struct promoted_type { using type = std::uint64_t; }; 104 | 105 | template<> 106 | struct promoted_type { using type = std::int64_t; }; 107 | 108 | template<> 109 | struct promoted_type> { using type = std::size_t; }; 110 | 111 | template<> 112 | struct promoted_type> { using type = Types::ssize_t; }; 113 | 114 | template 115 | using promoted_type_t = typename promoted_type::type; 116 | 117 | /* Helper methods */ 118 | [[nodiscard]] 119 | inline constexpr bool is_be() noexcept { 120 | return Alfheim::Config::target_endian == Alfheim::Config::endian_t::big; 121 | } 122 | 123 | [[nodiscard]] 124 | inline constexpr bool is_le() noexcept { 125 | return Alfheim::Config::target_endian == Alfheim::Config::endian_t::little; 126 | } 127 | } 128 | 129 | #endif /* libalfheim_internal_utility_hh */ 130 | -------------------------------------------------------------------------------- /src/libalfheim/internal/zlib.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* internal/zlib.hh - zlib RAII wrapper */ 3 | #pragma once 4 | #if !defined(libalfheim_internal_zlib_hh) 5 | #define libalfheim_internal_zlib_hh 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | extern "C" { 24 | #define ZLIB_CONST 25 | #include 26 | #include 27 | #undef ZLIB_CONST 28 | } 29 | 30 | namespace Alfheim::Internal { 31 | using namespace Alfheim::Internal::Units; 32 | 33 | struct zlib_t final { 34 | private: 35 | enum struct zmode_t : std::uint8_t { 36 | inflate = 0x00U, 37 | deflate = 0x01U 38 | }; 39 | 40 | template 41 | struct zctx_t final { 42 | private: 43 | zlib_t::zmode_t _mode; 44 | z_stream _stream; 45 | std::array _buffer; 46 | bool _eos; 47 | public: 48 | [[nodiscard]] 49 | zctx_t(zlib_t::zmode_t mode) noexcept : 50 | _mode{mode}, _stream{}, _buffer{}, _eos{} { 51 | if (_mode == zlib_t::zmode_t::inflate) { 52 | _eos = (::inflateInit(&_stream) != Z_OK); 53 | } else { 54 | _eos = (::deflateInit(&_stream, Z_DEFAULT_COMPRESSION) != Z_OK); 55 | } 56 | } 57 | 58 | ~zctx_t() noexcept { 59 | if (_mode == zlib_t::zmode_t::inflate) { 60 | _eos = (::inflateEnd(&_stream) != Z_OK); 61 | } else { 62 | _eos = (::deflateEnd(&_stream) != Z_OK); 63 | } 64 | } 65 | 66 | [[nodiscard]] 67 | bool valid() const noexcept { return !_eos; } 68 | 69 | [[nodiscard]] 70 | std::optional> process(const std::uint8_t* data, const std::size_t len) noexcept { 71 | using processor_t = bool(zctx_t&, std::vector&,const std::uint8_t*,const std::size_t); 72 | 73 | const auto n_chunks = (len + chunk_size - 1) / chunk_size; 74 | const std::function processor{(_mode == zlib_t::zmode_t::inflate) ? &zctx_t::inflate : &zctx_t::deflate}; 75 | 76 | std::vector _output{}; 77 | 78 | for(std::size_t idx{}; idx < n_chunks && !_eos; ++idx) { 79 | const auto *const buffer = data + (chunk_size * idx); 80 | const auto buffer_len = (idx == n_chunks - 1) ? len - ((n_chunks - 1) * chunk_size) : chunk_size; 81 | 82 | if (!processor(*this, _output, buffer, buffer_len)) { 83 | return std::nullopt; 84 | } 85 | } 86 | // TODO: lonk input buffers don't like this 87 | [[maybe_unused]] 88 | const auto _ = reset(); 89 | return std::make_optional(_output); 90 | } 91 | 92 | [[nodiscard]] 93 | std::optional> process(const std::vector& data) noexcept { 94 | return process(data.data(), data.size()); 95 | } 96 | 97 | template 98 | [[nodiscard]] 99 | std::optional> process(const std::array& data) noexcept { 100 | return process(data.data(), len); 101 | } 102 | 103 | private: 104 | [[nodiscard]] 105 | bool inflate(std::vector& out, const std::uint8_t* buff, const std::size_t buff_size) noexcept { 106 | _stream.next_in = buff; 107 | _stream.avail_in = buff_size; 108 | _stream.avail_out = 0; 109 | 110 | while (_stream.avail_in && (_stream.avail_out == 0) && !_eos) { 111 | _stream.next_out = _buffer.data(); 112 | _stream.avail_out = _buffer.size(); 113 | 114 | const auto ret = ::inflate(&_stream, Z_NO_FLUSH); 115 | 116 | if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR) 117 | return false; 118 | else if (ret == Z_STREAM_END) 119 | _eos = true; 120 | 121 | const auto copy_len = _buffer.size() - _stream.avail_out; 122 | const auto offset = out.size(); 123 | out.resize(out.size() + copy_len); 124 | std::memcpy(out.data() + offset, _buffer.data(), copy_len); 125 | 126 | } 127 | return true; 128 | } 129 | 130 | [[nodiscard]] 131 | bool deflate(std::vector& out, const std::uint8_t* buff, const std::size_t buff_size) noexcept { 132 | _stream.next_in = buff; 133 | _stream.avail_in = buff_size; 134 | _stream.avail_out = 0; 135 | 136 | while (_stream.avail_in && (_stream.avail_out == 0) && !_eos) { 137 | _stream.next_out = _buffer.data(); 138 | _stream.avail_out = _buffer.size(); 139 | 140 | const auto ret = ::deflate(&_stream, (buff_size < chunk_size) ? Z_FINISH : Z_NO_FLUSH); 141 | 142 | if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR) 143 | return false; 144 | else if (ret == Z_STREAM_END) 145 | _eos = true; 146 | 147 | const auto copy_len = _buffer.size() - _stream.avail_out; 148 | const auto offset = out.size(); 149 | out.resize(out.size() + copy_len); 150 | std::memcpy(out.data() + offset, _buffer.data(), copy_len); 151 | 152 | } 153 | return true; 154 | } 155 | 156 | [[nodiscard]] 157 | bool reset() noexcept { 158 | _eos = false; 159 | if (_mode == zlib_t::zmode_t::inflate) 160 | return inflateReset(&_stream) == Z_OK; 161 | else 162 | return deflateReset(&_stream) == Z_OK; 163 | 164 | } 165 | }; 166 | 167 | zctx_t<> _inflate; 168 | zctx_t<> _deflate; 169 | 170 | public: 171 | [[nodiscard]] 172 | zlib_t() noexcept : 173 | _inflate{zlib_t::zmode_t::inflate}, 174 | _deflate{zlib_t::zmode_t::deflate} 175 | { /* NOP */ } 176 | 177 | [[nodiscard]] 178 | bool valid() const noexcept { return _inflate.valid() && _deflate.valid(); } 179 | 180 | template 181 | [[nodiscard]] 182 | std::enable_if_t && !is_array_v && !is_vector_v, std::optional> 183 | inflate(const std::array& data) noexcept { 184 | return inflate(data.data(), len); 185 | } 186 | 187 | template 188 | [[nodiscard]] 189 | std::enable_if_t && !is_array_v && !is_vector_v, std::optional> 190 | inflate(const std::vector& data) noexcept { 191 | return inflate(data.data(), data.size()); 192 | } 193 | 194 | template 195 | [[nodiscard]] 196 | std::enable_if_t && !is_array_v && !is_vector_v, std::optional> 197 | inflate(const std::uint8_t* data, const std::size_t len) noexcept { 198 | T _tmp{}; 199 | 200 | if(auto res = _inflate.process(data, len)) { 201 | if (res->size() > sizeof(T)) 202 | return std::nullopt; 203 | std::memcpy(&_tmp, res->data(), res->size()); 204 | return std::make_optional(_tmp); 205 | } else { 206 | return std::nullopt; 207 | } 208 | } 209 | 210 | template 211 | [[nodiscard]] 212 | std::enable_if_t> && is_vector_v && !is_array_v, std::optional> 213 | inflate(const std::vector& data) noexcept { 214 | return inflate(data.data(), data.size()); 215 | } 216 | 217 | template 218 | [[nodiscard]] 219 | std::enable_if_t> && is_vector_v && !is_array_v, std::optional> 220 | inflate(const std::uint8_t* data, const std::size_t len) noexcept { 221 | T objs{}; 222 | if (auto res = _inflate.process(data, len)) { 223 | const auto obj_count = (res->size() + sizeof(value_t) - 1) / sizeof(value_t); 224 | objs.resize(obj_count); 225 | 226 | std::memcpy(objs.data(), res->data(), res->size()); 227 | return std::make_optional(objs); 228 | } else { 229 | return std::nullopt; 230 | } 231 | } 232 | 233 | template 234 | [[nodiscard]] 235 | std::enable_if_t> && is_array_v && !is_vector_v, std::optional> 236 | inflate(const std::vector& data) noexcept { 237 | return inflate(data.data(), data.size()); 238 | } 239 | 240 | template 241 | [[nodiscard]] 242 | std::enable_if_t> && is_array_v && !is_vector_v, std::optional> 243 | inflate(const std::uint8_t* data, const std::size_t data_len) noexcept { 244 | T objs{}; 245 | 246 | if (auto res = _inflate.process(data, data_len)) { 247 | if (res->size() > sizeof(value_t) * objs.size()) 248 | return std::nullopt; 249 | std::memcpy(objs.data(), res->data(), res->size()); 250 | return std::make_optional(objs); 251 | } else { 252 | return std::nullopt; 253 | } 254 | } 255 | 256 | template 257 | [[nodiscard]] 258 | std::optional> 259 | inflate(const std::array& data) noexcept { 260 | return _inflate.process(data); 261 | } 262 | 263 | [[nodiscard]] 264 | std::optional> 265 | inflate(const std::vector& data) noexcept { 266 | return _inflate.process(data); 267 | } 268 | 269 | [[nodiscard]] 270 | std::optional> 271 | inflate(const std::uint8_t* data, const std::size_t len) noexcept { 272 | return _inflate.process(data, len); 273 | } 274 | 275 | template 276 | [[nodiscard]] 277 | std::enable_if_t, std::optional>> 278 | deflate(T& obj) noexcept { 279 | std::array buff{}; 280 | std::memcpy(buff.data(), &obj, sizeof(T)); 281 | return _deflate.process(buff); 282 | } 283 | 284 | template 285 | [[nodiscard]] 286 | std::enable_if_t, std::optional>> 287 | deflate(const std::array& objs) noexcept { 288 | std::array buff{}; 289 | std::memcpy(buff.data(), objs.data(), len); 290 | return _deflate.process(buff); 291 | } 292 | 293 | template 294 | [[nodiscard]] 295 | std::enable_if_t, std::optional>> 296 | deflate(const std::vector& objs) noexcept { 297 | std::vector buff{sizeof(T) * objs.size()}; 298 | std::memcpy(buff.data(), objs.data(), sizeof(T) * objs.size()); 299 | return _deflate.process(buff); 300 | } 301 | 302 | [[nodiscard]] 303 | std::optional> 304 | deflate(const std::vector& data) noexcept { 305 | return _deflate.process(data); 306 | } 307 | 308 | template 309 | [[nodiscard]] 310 | std::optional> 311 | deflate(const std::array& data) noexcept { 312 | return _deflate.process(data); 313 | } 314 | }; 315 | } 316 | 317 | #endif /* libalfheim_internal_zlib_hh */ 318 | -------------------------------------------------------------------------------- /src/libalfheim/macho.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* macho.cc - Mach-O support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/macho.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* macho.hh - Mach-O support */ 3 | #pragma once 4 | #if !defined(libalfheim_macho_hh) 5 | #define libalfheim_macho_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::MachO { 10 | 11 | } 12 | 13 | #endif /* libalfheim_macho_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/macho/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_macho = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_macho, 14 | subdir: 'libalfheim' / 'macho' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/macho/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* macho/types.hh - macho types */ 3 | #pragma once 4 | #if !defined(libalfheim_macho_types_hh) 5 | #define libalfheim_macho_types_hh 6 | 7 | namespace Alfheim::MachO::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_macho_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | # Configuration data for the `xylene_config.hh` header 4 | config = configuration_data() 5 | config.set('AUTOGEN_HEADER', '/* THIS FILE IS AUTOGENERATED, DO NOT EDIT */') 6 | ## Version Information 7 | config.set('COMPILER_NAME', cxx.get_id()) 8 | config.set('COMPILER_VERSION', cxx.version()) 9 | ## Platform information 10 | config.set('TARGET_SYS', target_machine.system()) 11 | config.set('TARGET_ARCH', target_machine.cpu()) 12 | config.set('TARGET_ENDIAN', 'endian_t::@0@'.format(target_machine.endian())) 13 | config.set('TARGET_WIDTH', meson.get_compiler('cpp', native: false).sizeof('void*')) 14 | 15 | config.set('BUILD_SYS', build_machine.system()) 16 | config.set('BUILD_ARCH', build_machine.cpu()) 17 | config.set('BUILD_ENDIAN', 'endian_t::@0@'.format(build_machine.endian())) 18 | config.set('BUILD_WIDTH', meson.get_compiler('cpp', native: true).sizeof('void*')) 19 | 20 | ## Misc 21 | config.set('BUGREPORT_URL', get_option('bugreport_url')) 22 | 23 | git = find_program('git', required: false, native: true) 24 | if git.found() 25 | git_hash = run_command(git, 'rev-parse', '--short', 'HEAD').stdout().strip() 26 | if run_command(git, 'diff', '--quiet').returncode() != 0 27 | git_hash += '-dirty' 28 | endif 29 | config.set('GIT_HASH', git_hash) 30 | describe = run_command(git, 'describe', '--tag') 31 | if describe.returncode() == 0 32 | config.set('VERSION_NUMBER', describe.stdout().strip()) 33 | else 34 | config.set('VERSION_NUMBER', '@0@-@1@'.format(meson.project_version(), git_hash)) 35 | endif 36 | else 37 | config.set('VERSION_NUMBER', meson.project_version()) 38 | endif 39 | 40 | config_header = configure_file( 41 | configuration: config, 42 | input: 'config.hh.in', 43 | output: 'config.hh' 44 | ) 45 | 46 | library_deps = [ 47 | zlib, 48 | ] 49 | 50 | library_hdrs = files([ 51 | 'aout.hh', 52 | 'coff.hh', 53 | 'ecoff.hh', 54 | 'elf.hh', 55 | 'macho.hh', 56 | 'os360.hh', 57 | 'pe32.hh', 58 | 'xcoff.hh', 59 | ]) 60 | 61 | library_srcs = files([ 62 | 'aout.cc', 63 | 'coff.cc', 64 | 'ecoff.cc', 65 | 'elf.cc', 66 | 'macho.cc', 67 | 'os360.cc', 68 | 'pe32.cc', 69 | 'xcoff.cc', 70 | ]) 71 | 72 | subdir('internal') 73 | 74 | subdir('aout') 75 | subdir('coff') 76 | subdir('ecoff') 77 | subdir('elf') 78 | subdir('macho') 79 | subdir('os360') 80 | subdir('pe32') 81 | subdir('xcoff') 82 | 83 | 84 | libalfheim = library( 85 | 'libalfheim', 86 | library_srcs, 87 | 88 | include_directories: [ 89 | library_inc, 90 | ], 91 | dependencies: [ 92 | library_deps, 93 | ], 94 | 95 | name_prefix: '', 96 | pic: true, 97 | gnu_symbol_visibility: 'inlineshidden', 98 | implicit_include_directories: false, 99 | 100 | cpp_args: [ 101 | '-DLIBALFHEIM_BUILD_INTERNAL' 102 | ], 103 | install: (not meson.is_subproject()) 104 | ) 105 | 106 | libalfheim_dep = declare_dependency( 107 | include_directories: [ 108 | library_inc, 109 | ], 110 | dependencies: [ 111 | library_deps, 112 | ], 113 | link_with: libalfheim, 114 | version: meson.project_version(), 115 | ) 116 | 117 | if not meson.is_subproject() 118 | install_headers( 119 | library_hdrs + [ config_header ], 120 | subdir: 'libalfheim' 121 | ) 122 | 123 | pkgconfig = import('pkgconfig') 124 | pkgconfig.generate( 125 | subdirs: '.', 126 | name: 'libalfheim', 127 | filebase: 'libalfheim', 128 | libraries: [ libalfheim ], 129 | version: meson.project_version(), 130 | description: 'A C++17 library for parsing and generating various object file formats.' 131 | ) 132 | endif 133 | -------------------------------------------------------------------------------- /src/libalfheim/os360.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* os360.cc - os360 support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/os360.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* os360.hh - os360 support */ 3 | #pragma once 4 | #if !defined(libalfheim_os360_hh) 5 | #define libalfheim_os360_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::os360 { 10 | 11 | } 12 | 13 | #endif /* libalfheim_os360_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/os360/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_os360 = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_os360, 14 | subdir: 'libalfheim' / 'os360' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/os360/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* os360/types.hh - os360 types */ 3 | #pragma once 4 | #if !defined(libalfheim_os360_types_hh) 5 | #define libalfheim_os360_types_hh 6 | 7 | namespace Alfheim::os360::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_os360_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/pe32.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* pe32.cc - PE32/PE32+ support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/pe32.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* pe32.hh - PE32/PE32+ support */ 3 | #pragma once 4 | #if !defined(libalfheim_pe32_hh) 5 | #define libalfheim_pe32_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::PE32 { 10 | 11 | } 12 | 13 | #endif /* libalfheim_pe32_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/pe32/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_pe32 = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_pe32, 14 | subdir: 'libalfheim' / 'pe32' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/pe32/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* pe32/types.hh - PE32 types */ 3 | #pragma once 4 | #if !defined(libalfheim_pe32_types_hh) 5 | #define libalfheim_pe32_types_hh 6 | 7 | namespace Alfheim::PE32::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_pe32_types_hh */ 12 | -------------------------------------------------------------------------------- /src/libalfheim/xcoff.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* xcoff.cc - XCOFF support */ 3 | 4 | #include 5 | -------------------------------------------------------------------------------- /src/libalfheim/xcoff.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* xcoff.hh - XCOFF support */ 3 | #pragma once 4 | #if !defined(libalfheim_xcoff_hh) 5 | #define libalfheim_xcoff_hh 6 | 7 | #include 8 | 9 | namespace Alfheim::XCOFF { 10 | 11 | } 12 | 13 | #endif /* libalfheim_xcoff_hh */ 14 | -------------------------------------------------------------------------------- /src/libalfheim/xcoff/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_hdrs_xcoff = files([ 4 | 'types.hh', 5 | ]) 6 | 7 | library_srcs += files([ 8 | 9 | ]) 10 | 11 | if not meson.is_subproject() 12 | install_headers( 13 | library_hdrs_xcoff, 14 | subdir: 'libalfheim' / 'xcoff' 15 | ) 16 | endif 17 | -------------------------------------------------------------------------------- /src/libalfheim/xcoff/types.hh: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* xcoff/types.hh - XCOFF types */ 3 | #pragma once 4 | #if !defined(libalfheim_xcoff_types_hh) 5 | #define libalfheim_xcoff_types_hh 6 | 7 | namespace Alfheim::XCOFF::Types { 8 | 9 | } 10 | 11 | #endif /* libalfheim_xcoff_types_hh */ 12 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | library_inc = include_directories('.') 4 | 5 | subdir('libalfheim') 6 | 7 | if get_option('build_bindings') 8 | subdir('bindings') 9 | endif 10 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | message('Building tests') 4 | --------------------------------------------------------------------------------