diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 5ed3380ce..40c657509 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -7,6 +7,8 @@ add_executable(relinker ${CMAKE_CURRENT_SOURCE_DIR}/elfpatcher/src/general/ProgramHeaderLayoutBuilder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elfpatcher/src/general/SectionHeaderTableBuilder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/src/ByteWriter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/io/src/ByteReader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/io/src/BufferUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileWriter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/Amd64OnlyConverter.cpp diff --git a/core/elfpatcher/src/windows/WindowsPeFormat.hpp b/core/elfpatcher/src/windows/WindowsPeFormat.hpp index d1728f541..bbea05be0 100644 --- a/core/elfpatcher/src/windows/WindowsPeFormat.hpp +++ b/core/elfpatcher/src/windows/WindowsPeFormat.hpp @@ -21,6 +21,11 @@ constexpr std::uint32_t kRelTypeAbsolute = 0; constexpr std::uint32_t kRelocBlockHeaderSize = 8; constexpr std::uint32_t kRelocEntrySize = 2; +constexpr std::uint32_t kSecExec = 0x60000020; +constexpr std::uint32_t kSecRW = 0xC0000040; +constexpr std::uint32_t kSecRO = 0x40000040; +constexpr std::uint32_t kSecDiscard = 0x02000000; + struct MzHeader { std::uint8_t data[0x40]; }; diff --git a/core/elfpatcher/src/windows/WindowsPePatcher.cpp b/core/elfpatcher/src/windows/WindowsPePatcher.cpp index e80f3a440..54954b1ab 100644 --- a/core/elfpatcher/src/windows/WindowsPePatcher.cpp +++ b/core/elfpatcher/src/windows/WindowsPePatcher.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,7 +9,6 @@ #include #include #include "WindowsPeFormat.hpp" -#include "io/ByteWriter.hpp" namespace Elfpatcher::Windows { @@ -24,15 +24,15 @@ MzHeader buildMzStub(std::uint32_t peOffset) { void writeSectionHeader(std::vector& buf, std::size_t off, const PeSection& sec) { std::memcpy(buf.data() + off, sec.name, 8); - WriteU32(buf, off + 8, sec.virtualSize); - WriteU32(buf, off + 12, sec.virtualAddress); - WriteU32(buf, off + 16, sec.rawSize); - WriteU32(buf, off + 20, sec.rawOffset); - WriteU32(buf, off + 24, 0); - WriteU32(buf, off + 28, 0); - WriteU16(buf, off + 32, 0); - WriteU16(buf, off + 34, 0); - WriteU32(buf, off + 36, sec.characteristics); + Io::WriteU32(buf, off + 8, sec.virtualSize); + Io::WriteU32(buf, off + 12, sec.virtualAddress); + Io::WriteU32(buf, off + 16, sec.rawSize); + Io::WriteU32(buf, off + 20, sec.rawOffset); + Io::WriteU32(buf, off + 24, 0); + Io::WriteU32(buf, off + 28, 0); + Io::WriteU16(buf, off + 32, 0); + Io::WriteU16(buf, off + 34, 0); + Io::WriteU32(buf, off + 36, sec.characteristics); } std::vector buildRelocSection( @@ -83,11 +83,11 @@ std::vector buildRelocSection( entryCount++; } const std::uint32_t blockSize = kRelocBlockHeaderSize + entryCount * kRelocEntrySize; - appendU32(buf, page); - appendU32(buf, blockSize); + Io::AppendU32(buf, page); + Io::AppendU32(buf, blockSize); for (const std::uint32_t off : offsets) { const auto entry = static_cast((kRelTypeDir64 << 12) | (off & 0xFFF)); - appendU16(buf, entry); + Io::AppendU16(buf, entry); } } return buf; @@ -111,43 +111,43 @@ std::vector buildImportSection( for (const auto& dll : dlls) { const std::uint32_t dllNameRva = dataBase + static_cast(dataBuf.size()); - appendStr(dataBuf, dll.dllName); - alignBuf(dataBuf, 2); + Io::AppendString(dataBuf, dll.dllName); + Io::AlignBuffer(dataBuf, 2); const std::uint32_t iltRva = dataBase + static_cast(dataBuf.size()); for (const auto& thunk : dll.thunks) { const std::uint32_t hintNameRva = dataBase + static_cast(dataBuf.size()) + static_cast((dll.thunks.size() + 1) * 8); - appendU64(dataBuf, hintNameRva); + Io::AppendU64(dataBuf, hintNameRva); } - appendU64(dataBuf, 0); + Io::AppendU64(dataBuf, 0); for (const auto& thunk : dll.thunks) { - appendU16(dataBuf, 0); - appendStr(dataBuf, thunk.symbolName); - alignBuf(dataBuf, 2); + Io::AppendU16(dataBuf, 0); + Io::AppendString(dataBuf, thunk.symbolName); + Io::AlignBuffer(dataBuf, 2); } const std::uint32_t iatRva = dataBase + static_cast(dataBuf.size()); for (std::size_t i = 0; i < dll.thunks.size(); ++i) { const std::uint32_t iatEntryRva = iatRva + static_cast(i * 8); outGotPatches.emplace_back(dll.thunks[i].gotRva, iatEntryRva); - appendU64(dataBuf, 0); + Io::AppendU64(dataBuf, 0); } - appendU64(dataBuf, 0); + Io::AppendU64(dataBuf, 0); - appendU32(descriptorBuf, iltRva); - appendU32(descriptorBuf, 0); - appendU32(descriptorBuf, 0); - appendU32(descriptorBuf, dllNameRva); - appendU32(descriptorBuf, iatRva); + Io::AppendU32(descriptorBuf, iltRva); + Io::AppendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, dllNameRva); + Io::AppendU32(descriptorBuf, iatRva); } - appendU32(descriptorBuf, 0); - appendU32(descriptorBuf, 0); - appendU32(descriptorBuf, 0); - appendU32(descriptorBuf, 0); - appendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, 0); + Io::AppendU32(descriptorBuf, 0); std::vector result; result.insert(result.end(), descriptorBuf.begin(), descriptorBuf.end()); @@ -237,7 +237,7 @@ std::vector WindowsPePatcher::Patch( seg.flags = ph.Flags; loadSegs.push_back(seg); if (seg.vaddr < imageBase) imageBase = seg.vaddr; - const std::uint64_t top = alignUp64(seg.vaddr + seg.memSize, kSectionAlignment); + const std::uint64_t top = Io::AlignUp64(seg.vaddr + seg.memSize, kSectionAlignment); if (top > imageTop) imageTop = top; } @@ -390,10 +390,10 @@ std::vector WindowsPePatcher::Patch( } const auto loadImageSize = static_cast(imageBuf.size()); - const std::uint32_t importSectionRva = alignUp(loadImageRva + loadImageSize, kSectionAlignment); + const std::uint32_t importSectionRva = Io::AlignUp(loadImageRva + loadImageSize, kSectionAlignment); std::vector importSectionData = buildImportSection(importDlls, importSectionRva, gotPatches); - alignBuf(importSectionData, kFileAlignment); + Io::AlignBuffer(importSectionData, kFileAlignment); for (const auto& [gotRva_, iatRva] : gotPatches) { const auto destInImage = static_cast(gotRva_); @@ -403,14 +403,14 @@ std::vector WindowsPePatcher::Patch( std::memcpy(imageBuf.data() + destInImage, &iatVa, 8); } - const std::uint32_t relocSectionRva = alignUp(importSectionRva + static_cast(importSectionData.size()), kSectionAlignment); + const std::uint32_t relocSectionRva = Io::AlignUp(importSectionRva + static_cast(importSectionData.size()), kSectionAlignment); std::vector relocSectionData = buildRelocSection(dynamicSection.RelaData, imageBase); - alignBuf(relocSectionData, kFileAlignment); + Io::AlignBuffer(relocSectionData, kFileAlignment); - const std::uint32_t stubSectionRva = alignUp(relocSectionRva + static_cast(relocSectionData.size()), kSectionAlignment); + const std::uint32_t stubSectionRva = Io::AlignUp(relocSectionRva + static_cast(relocSectionData.size()), kSectionAlignment); const std::uint64_t stubVaddr = adjustedBase + stubSectionRva; std::vector stubData = buildEntryStub(elfEntryVaddr, stubVaddr); - alignBuf(stubData, kFileAlignment); + Io::AlignBuffer(stubData, kFileAlignment); const std::uint32_t entryPointRva = stubSectionRva; @@ -419,75 +419,75 @@ std::vector WindowsPePatcher::Patch( if (!relocSectionData.empty()) numSections++; numSections++; - const std::uint32_t sizeOfHeaders = alignUp( + const std::uint32_t sizeOfHeaders = Io::AlignUp( 0x40 + 4 + 20 + 240 + static_cast(numSections) * 40, kFileAlignment); if (sizeOfHeaders > kSizeOfPeHeaders) throw Domain::RelinkerException("PE headers exceed reserved header block size"); - const std::uint32_t sizeOfImage = alignUp(stubSectionRva + static_cast(stubData.size()), kSectionAlignment); + const std::uint32_t sizeOfImage = Io::AlignUp(stubSectionRva + static_cast(stubData.size()), kSectionAlignment); const std::uint32_t mzPeOffset = 0x40; std::vector result(kSizeOfPeHeaders, 0); - WriteU16(result, 0, kMzMagic); - WriteU32(result, 0x3c, mzPeOffset); + Io::WriteU16(result, 0, kMzMagic); + Io::WriteU32(result, 0x3c, mzPeOffset); std::size_t off = mzPeOffset; - WriteU32(result, off, kPeSignature); off += 4; + Io::WriteU32(result, off, kPeSignature); off += 4; - WriteU16(result, off, kMachinAmd64); off += 2; - WriteU16(result, off, numSections); off += 2; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, 0); off += 4; - WriteU16(result, off, 240); off += 2; - WriteU16(result, off, kCharsExe | kCharsLargeAddressAware); off += 2; + Io::WriteU16(result, off, kMachinAmd64); off += 2; + Io::WriteU16(result, off, numSections); off += 2; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU16(result, off, 240); off += 2; + Io::WriteU16(result, off, kCharsExe | kCharsLargeAddressAware); off += 2; - WriteU16(result, off, kOptMagicPe32Plus); off += 2; - writeU8(result, off, 0); off += 1; - writeU8(result, off, 0); off += 1; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, entryPointRva); off += 4; - WriteU32(result, off, loadImageRva); off += 4; + Io::WriteU16(result, off, kOptMagicPe32Plus); off += 2; + Io::WriteU8(result, off, 0); off += 1; + Io::WriteU8(result, off, 0); off += 1; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, entryPointRva); off += 4; + Io::WriteU32(result, off, loadImageRva); off += 4; - writeU64(result, off, adjustedBase); off += 8; - WriteU32(result, off, kSectionAlignment); off += 4; - WriteU32(result, off, kFileAlignment); off += 4; - WriteU16(result, off, static_cast(kOsVersion)); off += 2; - WriteU16(result, off, static_cast(kOsVersionMinor)); off += 2; - WriteU16(result, off, 0); off += 2; - WriteU16(result, off, 0); off += 2; - WriteU16(result, off, static_cast(kOsVersion)); off += 2; - WriteU16(result, off, static_cast(kOsVersionMinor)); off += 2; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, sizeOfImage); off += 4; - WriteU32(result, off, kSizeOfPeHeaders); off += 4; - WriteU32(result, off, 0); off += 4; - WriteU16(result, off, static_cast(kSubsystemConsole)); off += 2; - WriteU16(result, off, 0); off += 2; - writeU64(result, off, 0); off += 8; - writeU64(result, off, 0); off += 8; - writeU64(result, off, 0); off += 8; - writeU64(result, off, 0); off += 8; - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, kNumberOfRvaAndSizes); off += 4; + Io::WriteU64(result, off, adjustedBase); off += 8; + Io::WriteU32(result, off, kSectionAlignment); off += 4; + Io::WriteU32(result, off, kFileAlignment); off += 4; + Io::WriteU16(result, off, static_cast(kOsVersion)); off += 2; + Io::WriteU16(result, off, static_cast(kOsVersionMinor)); off += 2; + Io::WriteU16(result, off, 0); off += 2; + Io::WriteU16(result, off, 0); off += 2; + Io::WriteU16(result, off, static_cast(kOsVersion)); off += 2; + Io::WriteU16(result, off, static_cast(kOsVersionMinor)); off += 2; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, sizeOfImage); off += 4; + Io::WriteU32(result, off, kSizeOfPeHeaders); off += 4; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU16(result, off, static_cast(kSubsystemConsole)); off += 2; + Io::WriteU16(result, off, 0); off += 2; + Io::WriteU64(result, off, 0); off += 8; + Io::WriteU64(result, off, 0); off += 8; + Io::WriteU64(result, off, 0); off += 8; + Io::WriteU64(result, off, 0); off += 8; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, kNumberOfRvaAndSizes); off += 4; for (std::uint32_t i = 0; i < kNumberOfRvaAndSizes; ++i) { - WriteU32(result, off, 0); off += 4; - WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, 0); off += 4; + Io::WriteU32(result, off, 0); off += 4; } if (!importSectionData.empty()) { - WriteU32(result, mzPeOffset + 4 + 20 + 104, importSectionRva); - WriteU32(result, mzPeOffset + 4 + 20 + 108, static_cast(importDlls.size() * 20)); + Io::WriteU32(result, mzPeOffset + 4 + 20 + 104, importSectionRva); + Io::WriteU32(result, mzPeOffset + 4 + 20 + 108, static_cast(importDlls.size() * 20)); } if (!relocSectionData.empty()) { - WriteU32(result, mzPeOffset + 4 + 20 + 168, relocSectionRva); - WriteU32(result, mzPeOffset + 4 + 20 + 172, static_cast(relocSectionData.size())); + Io::WriteU32(result, mzPeOffset + 4 + 20 + 168, relocSectionRva); + Io::WriteU32(result, mzPeOffset + 4 + 20 + 172, static_cast(relocSectionData.size())); } std::size_t shdrsOff = mzPeOffset + 4 + 20 + 240; @@ -496,24 +496,19 @@ std::vector WindowsPePatcher::Patch( char n[8]{}; std::memcpy(n, name, std::min(std::strlen(name), std::size_t(8))); std::memcpy(result.data() + shdrsOff, n, 8); - WriteU32(result, shdrsOff + 8, virtualSize); - WriteU32(result, shdrsOff + 12, rva); - WriteU32(result, shdrsOff + 16, rawSize); - WriteU32(result, shdrsOff + 20, rawOff); - WriteU32(result, shdrsOff + 24, 0); - WriteU32(result, shdrsOff + 28, 0); - WriteU16(result, shdrsOff + 32, 0); - WriteU16(result, shdrsOff + 34, 0); - WriteU32(result, shdrsOff + 36, chars); + Io::WriteU32(result, shdrsOff + 8, virtualSize); + Io::WriteU32(result, shdrsOff + 12, rva); + Io::WriteU32(result, shdrsOff + 16, rawSize); + Io::WriteU32(result, shdrsOff + 20, rawOff); + Io::WriteU32(result, shdrsOff + 24, 0); + Io::WriteU32(result, shdrsOff + 28, 0); + Io::WriteU16(result, shdrsOff + 32, 0); + Io::WriteU16(result, shdrsOff + 34, 0); + Io::WriteU32(result, shdrsOff + 36, chars); shdrsOff += 40; }; - constexpr std::uint32_t kSecExec = 0x60000020; - constexpr std::uint32_t kSecRW = 0xC0000040; - constexpr std::uint32_t kSecRO = 0x40000040; - constexpr std::uint32_t kSecDiscard = 0x02000000; - - const std::uint32_t loadRawSize = alignUp(loadImageSize, kFileAlignment); + const std::uint32_t loadRawSize = Io::AlignUp(loadImageSize, kFileAlignment); std::uint32_t curRawOff = kSizeOfPeHeaders; writeSec(".load", loadImageSize, loadImageRva, loadRawSize, curRawOff, kSecExec | kSecRW); @@ -539,7 +534,7 @@ std::vector WindowsPePatcher::Patch( writeSec(".entry", static_cast(stubData.size()), stubSectionRva, static_cast(stubData.size()), stubRawOff, kSecExec); - alignBuf(result, kFileAlignment); + Io::AlignBuffer(result, kFileAlignment); { std::vector loadRaw(imageBuf.begin(), imageBuf.end()); diff --git a/core/io/include/io/BufferUtils.hpp b/core/io/include/io/BufferUtils.hpp new file mode 100644 index 000000000..365a50847 --- /dev/null +++ b/core/io/include/io/BufferUtils.hpp @@ -0,0 +1,37 @@ +#ifndef IO_BUFFERUTILS_HPP +#define IO_BUFFERUTILS_HPP + +#include +#include +#include + +namespace Io { + +void WriteU8(std::vector& buf, std::size_t offset, std::uint8_t v); +void WriteU16(std::vector& buf, std::size_t offset, std::uint16_t v); +void WriteU32(std::vector& buf, std::size_t offset, std::uint32_t v); +void WriteU64(std::vector& buf, std::size_t offset, std::uint64_t v); + +void AppendU8(std::vector& buf, std::uint8_t v); +void AppendU16(std::vector& buf, std::uint16_t v); +void AppendU32(std::vector& buf, std::uint32_t v); +void AppendU64(std::vector& buf, std::uint64_t v); +void AppendI64(std::vector& buf, std::int64_t v); + +void AppendString(std::vector& buf, const std::string& str); +void AlignBuffer(std::vector& buf, std::size_t alignment); + +std::uint16_t ReadU16(const std::vector& buf, std::size_t offset); +std::uint32_t ReadU32(const std::vector& buf, std::size_t offset); +std::uint64_t ReadU64(const std::vector& buf, std::size_t offset); + +template +constexpr T AlignUp(T value, T alignment) { + return (value + alignment - 1) / alignment * alignment; +} + +std::uint64_t AlignUp64(std::uint64_t value, std::uint64_t alignment); + +} + +#endif diff --git a/core/io/include/io/ByteReader.hpp b/core/io/include/io/ByteReader.hpp new file mode 100644 index 000000000..27c14fe0c --- /dev/null +++ b/core/io/include/io/ByteReader.hpp @@ -0,0 +1,17 @@ +#ifndef IO_BYTEREADER_HPP +#define IO_BYTEREADER_HPP + +#include + +namespace Io { + +class ByteReader : public IByteReader { +public: + std::uint16_t ReadU16(const std::vector& buf, std::size_t offset) const override; + std::uint32_t ReadU32(const std::vector& buf, std::size_t offset) const override; + std::uint64_t ReadU64(const std::vector& buf, std::size_t offset) const override; +}; + +} + +#endif diff --git a/core/io/include/io/ByteWriter.hpp b/core/io/include/io/ByteWriter.hpp index df485e5c0..4fc51c7db 100644 --- a/core/io/include/io/ByteWriter.hpp +++ b/core/io/include/io/ByteWriter.hpp @@ -7,9 +7,13 @@ namespace Io { class ByteWriter : public IByteWriter { public: + void WriteU8(std::vector& buf, std::size_t offset, std::uint8_t v) const override; void WriteU16(std::vector& buf, std::size_t offset, std::uint16_t v) const override; void WriteU32(std::vector& buf, std::size_t offset, std::uint32_t v) const override; void WriteU64(std::vector& buf, std::size_t offset, std::uint64_t v) const override; + void AppendU8(std::vector& buf, std::uint8_t v) const override; + void AppendU16(std::vector& buf, std::uint16_t v) const override; + void AppendU32(std::vector& buf, std::uint32_t v) const override; void AppendU64(std::vector& buf, std::uint64_t v) const override; void AppendI64(std::vector& buf, std::int64_t v) const override; }; diff --git a/core/io/include/io/IByteReader.hpp b/core/io/include/io/IByteReader.hpp new file mode 100644 index 000000000..d9c820afa --- /dev/null +++ b/core/io/include/io/IByteReader.hpp @@ -0,0 +1,21 @@ +#ifndef IO_IBYTEREADER_HPP +#define IO_IBYTEREADER_HPP + +#include +#include + +namespace Io { + +class IByteReader { +public: + virtual ~IByteReader() = default; + + virtual std::uint16_t ReadU16(const std::vector& buf, std::size_t offset) const = 0; + virtual std::uint32_t ReadU32(const std::vector& buf, std::size_t offset) const = 0; + virtual std::uint64_t ReadU64(const std::vector& buf, std::size_t offset) const = 0; +}; + +} + +#endif + diff --git a/core/io/include/io/IByteWriter.hpp b/core/io/include/io/IByteWriter.hpp index c53c06d95..5f5a641e8 100644 --- a/core/io/include/io/IByteWriter.hpp +++ b/core/io/include/io/IByteWriter.hpp @@ -10,9 +10,13 @@ class IByteWriter { public: virtual ~IByteWriter() = default; + virtual void WriteU8(std::vector& buf, std::size_t offset, std::uint8_t v) const = 0; virtual void WriteU16(std::vector& buf, std::size_t offset, std::uint16_t v) const = 0; virtual void WriteU32(std::vector& buf, std::size_t offset, std::uint32_t v) const = 0; virtual void WriteU64(std::vector& buf, std::size_t offset, std::uint64_t v) const = 0; + virtual void AppendU8(std::vector& buf, std::uint8_t v) const = 0; + virtual void AppendU16(std::vector& buf, std::uint16_t v) const = 0; + virtual void AppendU32(std::vector& buf, std::uint32_t v) const = 0; virtual void AppendU64(std::vector& buf, std::uint64_t v) const = 0; virtual void AppendI64(std::vector& buf, std::int64_t v) const = 0; }; diff --git a/core/io/src/BufferUtils.cpp b/core/io/src/BufferUtils.cpp new file mode 100644 index 000000000..b938851a1 --- /dev/null +++ b/core/io/src/BufferUtils.cpp @@ -0,0 +1,98 @@ +#include +#include +#include + +namespace Io { + +void WriteU8(std::vector& buf, std::size_t offset, std::uint8_t v) { + if (offset >= buf.size()) + throw std::out_of_range("WriteU8 out of bounds"); + buf[offset] = v; +} + +void WriteU16(std::vector& buf, std::size_t offset, std::uint16_t v) { + if (offset + 2 > buf.size()) + throw std::out_of_range("WriteU16 out of bounds"); + std::memcpy(buf.data() + offset, &v, 2); +} + +void WriteU32(std::vector& buf, std::size_t offset, std::uint32_t v) { + if (offset + 4 > buf.size()) + throw std::out_of_range("WriteU32 out of bounds"); + std::memcpy(buf.data() + offset, &v, 4); +} + +void WriteU64(std::vector& buf, std::size_t offset, std::uint64_t v) { + if (offset + 8 > buf.size()) + throw std::out_of_range("WriteU64 out of bounds"); + std::memcpy(buf.data() + offset, &v, 8); +} + +void AppendU8(std::vector& buf, std::uint8_t v) { + buf.push_back(v); +} + +void AppendU16(std::vector& buf, std::uint16_t v) { + const std::size_t pos = buf.size(); + buf.resize(pos + 2); + std::memcpy(buf.data() + pos, &v, 2); +} + +void AppendU32(std::vector& buf, std::uint32_t v) { + const std::size_t pos = buf.size(); + buf.resize(pos + 4); + std::memcpy(buf.data() + pos, &v, 4); +} + +void AppendU64(std::vector& buf, std::uint64_t v) { + const std::size_t pos = buf.size(); + buf.resize(pos + 8); + std::memcpy(buf.data() + pos, &v, 8); +} + +void AppendI64(std::vector& buf, std::int64_t v) { + AppendU64(buf, static_cast(v)); +} + +void AppendString(std::vector& buf, const std::string& str) { + buf.insert(buf.end(), str.begin(), str.end()); + buf.push_back(0); +} + +void AlignBuffer(std::vector& buf, std::size_t alignment) { + const std::size_t remainder = buf.size() % alignment; + if (remainder != 0) { + const std::size_t padding = alignment - remainder; + buf.resize(buf.size() + padding, 0); + } +} + +std::uint64_t AlignUp64(std::uint64_t value, std::uint64_t alignment) { + return AlignUp(value, alignment); +} + +std::uint16_t ReadU16(const std::vector& buf, std::size_t offset) { + if (offset + 2 > buf.size()) + throw std::out_of_range("ReadU16 out of bounds"); + std::uint16_t v; + std::memcpy(&v, buf.data() + offset, 2); + return v; +} + +std::uint32_t ReadU32(const std::vector& buf, std::size_t offset) { + if (offset + 4 > buf.size()) + throw std::out_of_range("ReadU32 out of bounds"); + std::uint32_t v; + std::memcpy(&v, buf.data() + offset, 4); + return v; +} + +std::uint64_t ReadU64(const std::vector& buf, std::size_t offset) { + if (offset + 8 > buf.size()) + throw std::out_of_range("ReadU64 out of bounds"); + std::uint64_t v; + std::memcpy(&v, buf.data() + offset, 8); + return v; +} + +} diff --git a/core/io/src/ByteReader.cpp b/core/io/src/ByteReader.cpp new file mode 100644 index 000000000..81953041e --- /dev/null +++ b/core/io/src/ByteReader.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +namespace Io { + +std::uint16_t ByteReader::ReadU16(const std::vector& buf, std::size_t offset) const { + if (offset + 2 > buf.size()) + throw std::out_of_range("ByteReader::ReadU16 out of bounds"); + std::uint16_t v; + std::memcpy(&v, buf.data() + offset, 2); + return v; +} + +std::uint32_t ByteReader::ReadU32(const std::vector& buf, std::size_t offset) const { + if (offset + 4 > buf.size()) + throw std::out_of_range("ByteReader::ReadU32 out of bounds"); + std::uint32_t v; + std::memcpy(&v, buf.data() + offset, 4); + return v; +} + +std::uint64_t ByteReader::ReadU64(const std::vector& buf, std::size_t offset) const { + if (offset + 8 > buf.size()) + throw std::out_of_range("ByteReader::ReadU64 out of bounds"); + std::uint64_t v; + std::memcpy(&v, buf.data() + offset, 8); + return v; +} + +} diff --git a/core/io/src/ByteWriter.cpp b/core/io/src/ByteWriter.cpp index f242f70ca..080fd5f0b 100644 --- a/core/io/src/ByteWriter.cpp +++ b/core/io/src/ByteWriter.cpp @@ -3,6 +3,10 @@ namespace Io { +void ByteWriter::WriteU8(std::vector& buf, std::size_t offset, std::uint8_t v) const { + buf[offset] = v; +} + void ByteWriter::WriteU16(std::vector& buf, std::size_t offset, std::uint16_t v) const { std::memcpy(buf.data() + offset, &v, 2); } @@ -15,6 +19,22 @@ void ByteWriter::WriteU64(std::vector& buf, std::size_t offset, st std::memcpy(buf.data() + offset, &v, 8); } +void ByteWriter::AppendU8(std::vector& buf, std::uint8_t v) const { + buf.push_back(v); +} + +void ByteWriter::AppendU16(std::vector& buf, std::uint16_t v) const { + const std::size_t pos = buf.size(); + buf.resize(pos + 2); + std::memcpy(buf.data() + pos, &v, 2); +} + +void ByteWriter::AppendU32(std::vector& buf, std::uint32_t v) const { + const std::size_t pos = buf.size(); + buf.resize(pos + 4); + std::memcpy(buf.data() + pos, &v, 4); +} + void ByteWriter::AppendU64(std::vector& buf, std::uint64_t v) const { const std::size_t pos = buf.size(); buf.resize(pos + 8);