├── BinaryTools ├── TestBin1.bin ├── TestBin3.bin ├── Binary.h ├── Binary.cpp ├── Span.h ├── BinaryReader.h ├── BinaryTools.vcxproj.filters ├── BinaryWriter.h ├── BinaryWriter.cpp ├── BinaryTools.cpp ├── BinaryReader.cpp ├── MemoryBuffer.h └── BinaryTools.vcxproj ├── License.txt ├── BinaryTools.sln ├── README.md └── .gitignore /BinaryTools/TestBin1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moneyl/BinaryTools/HEAD/BinaryTools/TestBin1.bin -------------------------------------------------------------------------------- /BinaryTools/TestBin3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moneyl/BinaryTools/HEAD/BinaryTools/TestBin3.bin -------------------------------------------------------------------------------- /BinaryTools/Binary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Span.h" 4 | 5 | Span ReadAllBytes(const std::string& filePath); -------------------------------------------------------------------------------- /BinaryTools/Binary.cpp: -------------------------------------------------------------------------------- 1 | #include "Binary.h" 2 | #include 3 | 4 | Span ReadAllBytes(const std::string& filePath) 5 | { 6 | std::ifstream file(filePath, std::ios::ate | std::ios::binary); 7 | 8 | if (!file.is_open()) 9 | { 10 | throw std::runtime_error("Failed to open file!"); //Todo: Note file name/path in error. Maybe better to just return an optional 11 | } 12 | 13 | size_t fileSize = (size_t)file.tellg(); 14 | char* buffer = new char[fileSize]; 15 | 16 | file.seekg(0); 17 | file.read(buffer, fileSize); 18 | file.close(); 19 | 20 | 21 | 22 | return Span(buffer, fileSize); 23 | } -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 moneyl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /BinaryTools.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29509.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BinaryTools", "BinaryTools\BinaryTools.vcxproj", "{DC3D45C9-4E30-4E00-9E95-76FCF3754849}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Debug|x64.ActiveCfg = Debug|x64 17 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Debug|x64.Build.0 = Debug|x64 18 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Debug|x86.ActiveCfg = Debug|Win32 19 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Debug|x86.Build.0 = Debug|Win32 20 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Release|x64.ActiveCfg = Release|x64 21 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Release|x64.Build.0 = Release|x64 22 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Release|x86.ActiveCfg = Release|Win32 23 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A5347320-02AF-4DBE-B357-2B183ABC44F7} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /BinaryTools/Span.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //Simple wrapper around a contiguous area of memory 4 | template 5 | struct Span 6 | { 7 | public: 8 | Span(T* ptr, size_t size) : ptr_(ptr), size_(size) {} 9 | 10 | T* Data() { return ptr_; } 11 | size_t Size() { return size_; } 12 | 13 | //Returns pointer to start of contiguous memory area 14 | T* begin() { return ptr_; } 15 | //Returns pointer to start of contiguous memory area 16 | const T* begin() const { return ptr_; } 17 | //Returns pointer to end of contiguous memory area (the end of the last memory). 18 | //To get the last member, use back() instead. 19 | T* end() { return ptr_ + size_; } 20 | //Returns pointer to end of contiguous memory area (the end of the last memory). 21 | //To get the last member, use back() instead. 22 | const T* end() const { return ptr_ + size_; } 23 | //Returns reference to first member of the span 24 | T& front() { return *ptr_; } 25 | //Returns reference to first member of the span 26 | const T& front() const { return *ptr_; } 27 | //Returns reference to last member of the span 28 | T& back() { return *(ptr_ + size_); } 29 | //Returns reference to last member of the span 30 | const T& back() const { return *(ptr_ + size_); } 31 | 32 | //Todo: Add optional bounds checking for debug builds 33 | //Returns reference to element at provided index. Does no bounds checking 34 | T& operator[](size_t index) { return ptr_[index]; } 35 | //Returns reference to element at provided index. Does no bounds checking 36 | const T& operator[](size_t index) const { return ptr_[index]; } 37 | 38 | private: 39 | T* ptr_ = nullptr; 40 | size_t size_ = 0; 41 | }; -------------------------------------------------------------------------------- /BinaryTools/BinaryReader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "MemoryBuffer.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct MemoryBuffer; 9 | 10 | 11 | //Class that can read binary data either from a file or from a fixed size buffer 12 | //depending on the constructor used. 13 | class BinaryReader 14 | { 15 | public: 16 | //Reads binary data from file at path 17 | BinaryReader(std::string_view inputPath); 18 | //Reads binary data from fixed size memory buffer 19 | BinaryReader(char* buffer, uint32_t sizeInBytes); 20 | //Reads binary data from fixed size memory buffer 21 | BinaryReader(std::span buffer); 22 | ~BinaryReader(); 23 | 24 | [[nodiscard]] uint8_t ReadUint8(); 25 | [[nodiscard]] uint16_t ReadUint16(); 26 | [[nodiscard]] uint32_t ReadUint32(); 27 | [[nodiscard]] uint64_t ReadUint64(); 28 | 29 | [[nodiscard]] int8_t ReadInt8(); 30 | [[nodiscard]] int16_t ReadInt16(); 31 | [[nodiscard]] int32_t ReadInt32(); 32 | [[nodiscard]] int64_t ReadInt64(); 33 | 34 | [[nodiscard]] char ReadChar(); 35 | [[nodiscard]] wchar_t ReadCharWide(); 36 | [[nodiscard]] std::string ReadNullTerminatedString(); 37 | [[nodiscard]] std::string ReadFixedLengthString(size_t length); 38 | [[nodiscard]] std::wstring ReadNullTerminatedStringWide(); 39 | [[nodiscard]] std::wstring ReadFixedLengthStringWide(size_t length); 40 | [[nodiscard]] std::vector ReadSizedStringList(size_t listSize); 41 | [[nodiscard]] char PeekChar(); 42 | [[nodiscard]] uint32_t PeekUint32(); 43 | [[nodiscard]] wchar_t PeekCharWide(); 44 | 45 | [[nodiscard]] float ReadFloat(); 46 | [[nodiscard]] double ReadDouble(); 47 | 48 | void ReadToMemory(void* destination, size_t size); 49 | 50 | void SeekBeg(size_t absoluteOffset); 51 | void SeekCur(size_t relativeOffset); 52 | void SeekReverse(size_t relativeOffset); //Move backwards from the current stream position 53 | void Skip(size_t bytesToSkip); 54 | size_t Align(size_t alignmentValue = 2048); 55 | 56 | size_t Position() const; 57 | size_t Length(); 58 | 59 | private: 60 | std::istream* stream_ = nullptr; 61 | basic_memstreambuf* buffer_ = nullptr; 62 | }; 63 | 64 | -------------------------------------------------------------------------------- /BinaryTools/BinaryTools.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {54101738-c0ef-40a7-be61-cf8ae2cbcae3} 18 | 19 | 20 | {5568f67e-fdd2-4c16-bb85-bf72217b642c} 21 | 22 | 23 | {03c417c9-055a-45f5-83d9-42357834c20e} 24 | 25 | 26 | {063757fd-06fb-4f35-8362-005b4a8261b9} 27 | 28 | 29 | 30 | 31 | src 32 | 33 | 34 | src\BinaryReader 35 | 36 | 37 | src\BinaryWriter 38 | 39 | 40 | src\helpers 41 | 42 | 43 | 44 | 45 | src\BinaryReader 46 | 47 | 48 | src\BinaryWriter 49 | 50 | 51 | src\helpers 52 | 53 | 54 | src\helpers 55 | 56 | 57 | src\helpers 58 | 59 | 60 | -------------------------------------------------------------------------------- /BinaryTools/BinaryWriter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | struct MemoryBuffer; 7 | 8 | //Class that can write binary data either from a file or from a fixed size buffer 9 | //depending on the constructor used. 10 | class BinaryWriter 11 | { 12 | public: 13 | //Writes binary data from file at path. If truncate == true any existing file contents will be cleared 14 | BinaryWriter(std::string_view inputPath, bool truncate = true); 15 | //Writes binary data from fixed size memory buffer 16 | BinaryWriter(char* buffer, uint32_t sizeInBytes); 17 | ~BinaryWriter(); 18 | 19 | void Flush(); 20 | 21 | void WriteUint8(uint8_t value); 22 | void WriteUint16(uint16_t value); 23 | void WriteUint32(uint32_t value); 24 | void WriteUint64(uint64_t value); 25 | 26 | void WriteInt8(int8_t value); 27 | void WriteInt16(int16_t value); 28 | void WriteInt32(int32_t value); 29 | void WriteInt64(int64_t value); 30 | 31 | void WriteChar(char value); 32 | //Write string to output with null terminator 33 | void WriteNullTerminatedString(const std::string& value); 34 | //Write string to output without null terminator 35 | void WriteFixedLengthString(const std::string& value); 36 | 37 | void WriteFloat(float value); 38 | void WriteDouble(double value); 39 | 40 | void WriteFromMemory(const void* data, size_t size); 41 | 42 | template 43 | void Write(const T& data) 44 | { 45 | //Don't allow T to be a pointer to avoid accidentally writing the value of a pointer instead of what it points to. 46 | static_assert(!std::is_pointer(), "BinaryWriter::Write requires T to be a non pointer type."); 47 | WriteFromMemory(&data, sizeof(T)); 48 | } 49 | 50 | template 51 | void WriteSpan(std::span data) 52 | { 53 | WriteFromMemory(data.data(), data.size_bytes()); 54 | } 55 | 56 | void SeekBeg(size_t absoluteOffset); 57 | void SeekCur(size_t relativeOffset); 58 | void Skip(size_t bytesToSkip); 59 | void WriteNullBytes(size_t bytesToWrite); 60 | //Static method for calculating alignment pad from pos and alignment. Does not change position since static 61 | static size_t CalcAlign(size_t position, size_t alignmentValue = 2048); 62 | //Aligns stream to alignment value. Returns padding byte count 63 | size_t Align(size_t alignmentValue = 2048); 64 | 65 | size_t Position() const; 66 | size_t Length(); 67 | 68 | private: 69 | std::ostream* stream_ = nullptr; 70 | MemoryBuffer* buffer_ = nullptr; 71 | }; 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BinaryTools 2 | C++ classes for reading/writing binary data and some helper functions/classes. Based on C#'s `BinaryReader` and `BinaryWriter`. 3 | 4 | ## BinaryReader & BinaryWriter 5 | Classes which can read/write binary data to/from a file or memory buffer. Both have functions for the most common primitive types. Ex: `uint32_t`, `int32_t`, `uint64_t`, `int64_t`, `float`, `double`, etc. See `BinaryReader.h` and `BinaryWriter.h` for a full list. The constructor used determines whether the class reads from a file (the constructor provides a file path), or a memory region (it provides a memory address and size). They can also read and write entire structs to or from memory using `ReadToMemory` and `WriteFromMemory`, respectively. 6 | 7 | ## Other helpers and included classes 8 | - `Span`: A very simple wrapper around a fixed sized memory region used by ReadAllBytes. You must free the memory the span points to if it's heap allocated. 9 | - `MemoryBuffer`: A simple class which inherits std::streambuf. Used by BinaryReader/Writer when interacting with a memory buffer. 10 | - `ReadAllBytes(const std::string& filePath)`: Function that reads all bytes from a file and returns them in a Span. Since it's using a span you must free the memory it returns once you're done with it. 11 | 12 | ## Example 13 | This example shows how to read/write files and in memory buffers using `BinaryReader` and `BinaryWriter`. 14 | ```c++ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | //You can specify data layouts with a struct and read/write them in one go 22 | struct ExampleHeader 23 | { 24 | uint32_t Signature = 0xF00F; 25 | uint32_t Version = 10; 26 | uint32_t Value0 = 1024; 27 | float Value1 = 45.2f; 28 | float Value2 = 800.9f; 29 | }; 30 | 31 | int main() 32 | { 33 | //Write test file to your project directory 34 | std::string testFilePath = "TestFile0.bin"; 35 | 36 | //File writing 37 | { 38 | BinaryWriter writer(testFilePath); 39 | writer.WriteUint32(100); 40 | writer.WriteFloat(512.0f); 41 | writer.WriteNullTerminatedString("Hello binary!"); 42 | //Write padding bytes to align to value. E.g. position = 13. After align(4), position = 16, the next multiple of 4. 43 | writer.Align(4); 44 | 45 | //Can also write whole structs/classes to files 46 | ExampleHeader header; 47 | writer.WriteFromMemory(&header, sizeof(ExampleHeader)); 48 | } 49 | 50 | //File reading 51 | { 52 | BinaryReader reader(testFilePath); //Assumes that the file already exists 53 | assert(reader.ReadUint32() == 100); 54 | assert(reader.ReadFloat() == 512.0f); 55 | assert(reader.ReadNullTerminatedString() == "Hello binary!"); 56 | reader.Align(4); 57 | 58 | //Can also read whole structs/classes from files 59 | ExampleHeader header; 60 | reader.ReadToMemory(&header, sizeof(ExampleHeader)); 61 | assert(header.Signature == 0xF00F); 62 | assert(header.Version == 10); 63 | assert(header.Value0 == 1024); 64 | assert(header.Value1 == 45.2f); 65 | assert(header.Value2 == 800.9f); 66 | } 67 | 68 | //Reading from memory 69 | { 70 | uint32_t someBuffer[5] = { 256, 700, 12, 895, 5784 }; 71 | BinaryReader reader2((char*)&someBuffer, 5 * sizeof(uint32_t)); 72 | assert(reader2.ReadUint32() == 256); 73 | assert(reader2.ReadUint32() == 700); 74 | assert(reader2.ReadUint32() == 12); 75 | assert(reader2.ReadUint32() == 895); 76 | assert(reader2.ReadUint32() == 5784); 77 | } 78 | } 79 | 80 | ``` 81 | -------------------------------------------------------------------------------- /BinaryTools/BinaryWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "BinaryWriter.h" 2 | #include "MemoryBuffer.h" 3 | #include 4 | #include 5 | 6 | BinaryWriter::BinaryWriter(std::string_view inputPath, bool truncate) 7 | { 8 | //Can't simply exclude the truncate flag when !truncate. More details here: https://stackoverflow.com/a/57070159 9 | int flags = 0; 10 | if (truncate) 11 | flags = std::ofstream::out | std::ofstream::binary | std::ofstream::trunc; //Clears existing contents of the file 12 | else 13 | flags = std::ofstream::in | std::ofstream::out | std::ofstream::binary; 14 | 15 | //If not truncating and the file doesn't exist, then opening will fail. So we create the file first if it doesn't exist 16 | if (!truncate && !std::filesystem::exists(inputPath)) 17 | { 18 | std::fstream f; 19 | f.open(inputPath, std::fstream::out); 20 | f.close(); 21 | } 22 | 23 | stream_ = new std::ofstream(std::string(inputPath), flags); 24 | } 25 | 26 | BinaryWriter::BinaryWriter(char* buffer, uint32_t sizeInBytes) 27 | { 28 | buffer_ = new MemoryBuffer(buffer, sizeInBytes); 29 | stream_ = new std::ostream(buffer_); 30 | } 31 | 32 | BinaryWriter::~BinaryWriter() 33 | { 34 | delete stream_; 35 | if (buffer_) 36 | delete[] buffer_; 37 | } 38 | 39 | void BinaryWriter::Flush() 40 | { 41 | stream_->flush(); 42 | } 43 | 44 | void BinaryWriter::WriteUint8(uint8_t value) 45 | { 46 | stream_->write(reinterpret_cast(&value), 1); 47 | } 48 | 49 | void BinaryWriter::WriteUint16(uint16_t value) 50 | { 51 | stream_->write(reinterpret_cast(&value), 2); 52 | } 53 | 54 | void BinaryWriter::WriteUint32(uint32_t value) 55 | { 56 | stream_->write(reinterpret_cast(&value), 4); 57 | } 58 | 59 | void BinaryWriter::WriteUint64(uint64_t value) 60 | { 61 | stream_->write(reinterpret_cast(&value), 8); 62 | } 63 | 64 | void BinaryWriter::WriteInt8(int8_t value) 65 | { 66 | stream_->write(reinterpret_cast(&value), 1); 67 | } 68 | 69 | void BinaryWriter::WriteInt16(int16_t value) 70 | { 71 | stream_->write(reinterpret_cast(&value), 2); 72 | } 73 | 74 | void BinaryWriter::WriteInt32(int32_t value) 75 | { 76 | stream_->write(reinterpret_cast(&value), 4); 77 | } 78 | 79 | void BinaryWriter::WriteInt64(int64_t value) 80 | { 81 | stream_->write(reinterpret_cast(&value), 8); 82 | } 83 | 84 | void BinaryWriter::WriteChar(char value) 85 | { 86 | stream_->write(reinterpret_cast(&value), 1); 87 | } 88 | 89 | void BinaryWriter::WriteNullTerminatedString(const std::string& value) 90 | { 91 | stream_->write(value.data(), value.size()); 92 | WriteChar('\0'); 93 | } 94 | 95 | void BinaryWriter::WriteFixedLengthString(const std::string& value) 96 | { 97 | stream_->write(value.data(), value.size()); 98 | } 99 | 100 | void BinaryWriter::WriteFloat(float value) 101 | { 102 | stream_->write(reinterpret_cast(&value), 4); 103 | } 104 | 105 | void BinaryWriter::WriteDouble(double value) 106 | { 107 | stream_->write(reinterpret_cast(&value), 8); 108 | } 109 | 110 | void BinaryWriter::WriteFromMemory(const void* data, size_t size) 111 | { 112 | stream_->write(reinterpret_cast(data), size); 113 | } 114 | 115 | void BinaryWriter::SeekBeg(size_t absoluteOffset) 116 | { 117 | stream_->seekp(absoluteOffset, std::ifstream::beg); 118 | } 119 | 120 | void BinaryWriter::SeekCur(size_t relativeOffset) 121 | { 122 | stream_->seekp(relativeOffset, std::ifstream::cur); 123 | } 124 | 125 | void BinaryWriter::Skip(size_t bytesToSkip) 126 | { 127 | size_t position = Position(); 128 | size_t length = Length(); 129 | 130 | //If we're skipped past the end of the stream then skip what's available and write null bytes for the rest 131 | if (position + bytesToSkip > length) 132 | { 133 | size_t bytesAvailable = length - position; 134 | size_t bytesNeeded = bytesToSkip - bytesAvailable; 135 | 136 | stream_->seekp(bytesAvailable, std::ifstream::cur); 137 | WriteNullBytes(bytesNeeded); 138 | } 139 | else 140 | stream_->seekp(bytesToSkip, std::ifstream::cur); 141 | } 142 | 143 | void BinaryWriter::WriteNullBytes(size_t bytesToWrite) 144 | { 145 | //Todo: See if quicker to allocate array of zeros and use WriteFromMemory 146 | for (size_t i = 0; i < bytesToWrite; i++) 147 | WriteUint8(0); 148 | } 149 | 150 | size_t BinaryWriter::CalcAlign(size_t position, size_t alignmentValue) 151 | { 152 | const size_t remainder = position % alignmentValue; 153 | size_t paddingSize = remainder > 0 ? alignmentValue - remainder : 0; 154 | return paddingSize; 155 | } 156 | 157 | size_t BinaryWriter::Align(size_t alignmentValue) 158 | { 159 | const size_t paddingSize = CalcAlign(stream_->tellp(), alignmentValue); 160 | Skip(paddingSize); 161 | return paddingSize; 162 | } 163 | 164 | size_t BinaryWriter::Position() const 165 | { 166 | return stream_->tellp(); 167 | } 168 | 169 | size_t BinaryWriter::Length() 170 | { 171 | //Save current position 172 | size_t realPosition = Position(); 173 | 174 | //Seek to end of file and get position (the length) 175 | stream_->seekp(0, std::ios::end); 176 | size_t endPosition = Position(); 177 | 178 | //Seek back to real pos and return length 179 | if (realPosition != endPosition) 180 | SeekBeg(realPosition); 181 | 182 | return endPosition; 183 | } 184 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | [Ll]og/ 22 | 23 | # Visual Studio 2015 cache/options directory 24 | .vs/ 25 | # Uncomment if you have tasks that create the project's static files in wwwroot 26 | #wwwroot/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | project.fragment.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | *.VC.db 83 | *.VC.VC.opendb 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | #*.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.jfm 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | # CodeRush 255 | .cr/ 256 | 257 | # Python Tools for Visual Studio (PTVS) 258 | __pycache__/ 259 | *.pyc 260 | CodeGraphData/ 261 | 262 | # Documentation build files and tool test output 263 | \.vscode/settings\.json 264 | Docs/_build/ 265 | \.vscode/ 266 | Tools/Player\.rst 267 | Tools/TestFile\.h 268 | Proxy DLL Loader/Appveyor/ 269 | 270 | RSL/Appveyor/ 271 | 272 | Appveyor/ 273 | 274 | TODO 275 | 276 | BinaryTools/TestBin2.bin 277 | -------------------------------------------------------------------------------- /BinaryTools/BinaryTools.cpp: -------------------------------------------------------------------------------- 1 | #include "BinaryWriter.h" 2 | #include "BinaryReader.h" 3 | #include "Binary.h" 4 | #include 5 | 6 | struct TestPod 7 | { 8 | float x; 9 | float y; 10 | float z; 11 | uint32_t cash; 12 | int32_t score; 13 | }; 14 | 15 | int main() 16 | { 17 | printf("**** Test 1 - Write + Read a few values ****\n"); 18 | //Test writing a few values and reading them back 19 | { 20 | { 21 | printf("Writing some values to file... "); 22 | BinaryWriter writer("./TestBin1.bin"); 23 | writer.WriteFloat(1232.3f); 24 | writer.WriteFloat(300.7f); 25 | writer.WriteFloat(1680.0f); 26 | writer.WriteUint32(8000); 27 | writer.WriteInt32(-2003443); 28 | printf("Done!\n"); 29 | } 30 | { 31 | printf("Reading those values back...\n"); 32 | BinaryReader reader("./TestBin1.bin"); 33 | printf("Float: %f\n", reader.ReadFloat()); 34 | printf("Float: %f\n", reader.ReadFloat()); 35 | printf("Float: %f\n", reader.ReadFloat()); 36 | printf("Uint32: %d\n", reader.ReadUint32()); 37 | printf("Int32: %d\n", reader.ReadInt32()); 38 | printf("Done!\n"); 39 | } 40 | 41 | } 42 | 43 | printf("\n\n**** Test 2 - Write + Read a POD struct directly to/from memory ****\n"); 44 | //Test writing a struct from memory, reading it back and casting the data onto it 45 | { 46 | //Write data 47 | { 48 | TestPod writeData = {}; 49 | writeData.x = 1234.44f; 50 | writeData.y = 1734.44f; 51 | writeData.z = 22334.44f; 52 | writeData.cash = 1003; 53 | writeData.score = -64230; 54 | printf("sizeof(TestPod) = %zd\n", sizeof(TestPod)); 55 | 56 | printf("Writing POD struct from memory... "); 57 | BinaryWriter writer("./TestBin2.bin"); 58 | writer.WriteFromMemory(&writeData, sizeof(TestPod)); 59 | printf("Done!\n\n"); 60 | } 61 | //Read it back 62 | { 63 | TestPod readData = {}; 64 | readData.x = 0.00000000f; 65 | readData.y = 0.00000000f; 66 | readData.z = 0.00000000f; 67 | readData.cash = 0; 68 | readData.score = 0; 69 | 70 | printf("Reading back data directly into POD struct location in memory... "); 71 | BinaryReader reader("./TestBin2.bin"); 72 | reader.ReadToMemory(&readData, sizeof(TestPod)); 73 | printf("Done!\n"); 74 | printf("Printing values...\n"); 75 | printf("Float: %f\n", readData.x); 76 | printf("Float: %f\n", readData.y); 77 | printf("Float: %f\n", readData.z); 78 | printf("Uint32: %d\n", readData.cash); 79 | printf("Int32: %d\n", readData.score); 80 | } 81 | } 82 | 83 | printf("\n\n**** Test 3 - Read a POD struct directly to/from memory from handmade binary file ****\n"); 84 | //Test reading data from handmade binary file straight into POD struct memory location 85 | { 86 | { 87 | TestPod readData = {}; 88 | readData.x = 0.00000000f; 89 | readData.y = 0.00000000f; 90 | readData.z = 0.00000000f; 91 | readData.cash = 0; 92 | readData.score = 0; 93 | 94 | printf("Reading data directly into POD struct location in memory... "); 95 | BinaryReader reader("./TestBin3.bin"); 96 | reader.ReadToMemory(&readData, sizeof(TestPod)); 97 | printf("Done!\n"); 98 | printf("Printing values...\n"); 99 | printf("Float: %f\n", readData.x); 100 | printf("Float: %f\n", readData.y); 101 | printf("Float: %f\n", readData.z); 102 | printf("Uint32: %d\n", readData.cash); 103 | printf("Int32: %d\n", readData.score); 104 | } 105 | } 106 | 107 | printf("\n\n**** Test 4 - Read a POD struct from a file to memory and read data from that memory area with BinaryReader ****\n"); 108 | //Test reading data from handmade binary file straight into POD struct memory location 109 | { 110 | { 111 | TestPod readData = {}; 112 | readData.x = 0.00000000f; 113 | readData.y = 0.00000000f; 114 | readData.z = 0.00000000f; 115 | readData.cash = 0; 116 | readData.score = 0; 117 | 118 | printf("Reading data directly into memory... "); 119 | printf("Done!\n"); 120 | auto span = ReadAllBytes("./TestBin3.bin"); 121 | printf("Reading values of memory buffer with BinaryReader... "); 122 | printf("Done!\n"); 123 | 124 | BinaryReader reader(span.Data(), (uint32_t)span.Size()); 125 | printf("Printing values...\n"); 126 | printf("Float: %f\n", reader.ReadFloat()); 127 | printf("Float: %f\n", reader.ReadFloat()); 128 | printf("Float: %f\n", reader.ReadFloat()); 129 | printf("Uint32: %d\n", reader.ReadUint32()); 130 | printf("Int32: %d\n", reader.ReadInt32()); 131 | delete span.Data(); 132 | } 133 | } 134 | 135 | struct test 136 | { 137 | int a; 138 | int b; 139 | }; 140 | 141 | std::array testArray; 142 | testArray[0] = test{ 2, 3 }; 143 | testArray[1] = test{ 4, 5 }; 144 | testArray[2] = test{ 6, 7 }; 145 | //Intentionally specifying size of 2 here to see if end() actually points to the end of last element of the span 146 | Span testSpan(testArray.data(), 2); 147 | 148 | test* begin = testSpan.begin(); 149 | test* end = testSpan.end(); 150 | auto& front = testSpan.front(); 151 | auto& back = testSpan.back(); 152 | 153 | auto& zero = testSpan[0]; 154 | auto& one = testSpan[1]; 155 | auto& two = testSpan[2]; 156 | 157 | printf("Testing use of range based for loops with Span...\n"); 158 | for (auto& val : testSpan) 159 | printf("value: {a: %d, b: %d}\n", val.a, val.b); 160 | 161 | auto a = 2; 162 | } 163 | -------------------------------------------------------------------------------- /BinaryTools/BinaryReader.cpp: -------------------------------------------------------------------------------- 1 | #include "BinaryReader.h" 2 | #include "MemoryBuffer.h" 3 | 4 | BinaryReader::BinaryReader(std::string_view inputPath) 5 | { 6 | stream_ = new std::ifstream(std::string(inputPath), std::ifstream::in | std::ifstream::binary); 7 | } 8 | 9 | BinaryReader::BinaryReader(char* buffer, uint32_t sizeInBytes) 10 | { 11 | buffer_ = new basic_memstreambuf(buffer, sizeInBytes); 12 | stream_ = new std::istream(buffer_, false); 13 | } 14 | 15 | BinaryReader::BinaryReader(std::span buffer) 16 | { 17 | buffer_ = new basic_memstreambuf((char*)buffer.data(), buffer.size_bytes()); 18 | stream_ = new std::istream(buffer_, false); 19 | } 20 | 21 | BinaryReader::~BinaryReader() 22 | { 23 | delete stream_; 24 | if (buffer_) 25 | delete buffer_; 26 | } 27 | 28 | uint8_t BinaryReader::ReadUint8() 29 | { 30 | uint8_t output; 31 | stream_->read(reinterpret_cast(&output), 1); 32 | return output; 33 | } 34 | 35 | uint16_t BinaryReader::ReadUint16() 36 | { 37 | uint16_t output; 38 | stream_->read(reinterpret_cast(&output), 2); 39 | return output; 40 | } 41 | 42 | uint32_t BinaryReader::ReadUint32() 43 | { 44 | //Todo: See if using static or class var speeds these up 45 | uint32_t output; 46 | stream_->read(reinterpret_cast(&output), 4); 47 | return output; 48 | } 49 | 50 | uint64_t BinaryReader::ReadUint64() 51 | { 52 | uint64_t output; 53 | stream_->read(reinterpret_cast(&output), 8); 54 | return output; 55 | } 56 | 57 | int8_t BinaryReader::ReadInt8() 58 | { 59 | int8_t output; 60 | stream_->read(reinterpret_cast(&output), 1); 61 | return output; 62 | } 63 | 64 | int16_t BinaryReader::ReadInt16() 65 | { 66 | int16_t output; 67 | stream_->read(reinterpret_cast(&output), 2); 68 | return output; 69 | } 70 | 71 | int32_t BinaryReader::ReadInt32() 72 | { 73 | int32_t output; 74 | stream_->read(reinterpret_cast(&output), 4); 75 | return output; 76 | } 77 | 78 | int64_t BinaryReader::ReadInt64() 79 | { 80 | int64_t output; 81 | stream_->read(reinterpret_cast(&output), 8); 82 | return output; 83 | } 84 | 85 | char BinaryReader::ReadChar() 86 | { 87 | char output; 88 | stream_->read(&output, 1); 89 | return output; 90 | } 91 | 92 | wchar_t BinaryReader::ReadCharWide() 93 | { 94 | wchar_t output; 95 | stream_->read((char*)&output, 2); 96 | return output; 97 | } 98 | 99 | std::string BinaryReader::ReadNullTerminatedString() 100 | { 101 | std::string output; 102 | char charBuffer = 0; 103 | while(PeekChar() != '\0') 104 | { 105 | stream_->read(&charBuffer, 1); 106 | output.push_back(charBuffer); 107 | } 108 | Skip(1); //Move past null terminator 109 | return output; 110 | } 111 | 112 | std::string BinaryReader::ReadFixedLengthString(size_t length) 113 | { 114 | std::string output; 115 | output.reserve(length); 116 | for (int i = 0; i < length; i++) 117 | { 118 | char charBuffer; 119 | stream_->read(&charBuffer, 1); 120 | output.push_back(charBuffer); 121 | } 122 | return output; 123 | } 124 | 125 | std::wstring BinaryReader::ReadNullTerminatedStringWide() 126 | { 127 | std::wstring output; 128 | wchar_t charBuffer = 0; 129 | while (PeekCharWide() != '\0') 130 | { 131 | stream_->read((char*)&charBuffer, 2); 132 | output.push_back(charBuffer); 133 | } 134 | Skip(2); //Move past null terminator 135 | return output; 136 | } 137 | 138 | std::wstring BinaryReader::ReadFixedLengthStringWide(size_t length) 139 | { 140 | std::wstring output; 141 | output.reserve(length); 142 | for (int i = 0; i < length; i++) 143 | { 144 | wchar_t charBuffer; 145 | stream_->read((char*)&charBuffer, 2); 146 | output.push_back(charBuffer); 147 | } 148 | return output; 149 | } 150 | 151 | std::vector BinaryReader::ReadSizedStringList(size_t listSize) 152 | { 153 | std::vector stringList = { }; 154 | if (listSize == 0) 155 | return stringList; 156 | 157 | size_t startPos = Position(); 158 | while (Position() - startPos < listSize) 159 | { 160 | stringList.push_back(ReadNullTerminatedString()); 161 | while (Position() - startPos < listSize) 162 | { 163 | //TODO: See if Align(4) would accomplish the same. This is really for RfgTools++ since many RFG formats have sized string lists 164 | //Sometimes names have extra null bytes after them for some reason. Simple way to handle this 165 | if (PeekChar() == '\0') 166 | Skip(1); 167 | else 168 | break; 169 | } 170 | } 171 | 172 | return stringList; 173 | } 174 | 175 | char BinaryReader::PeekChar() 176 | { 177 | char output = ReadChar(); 178 | SeekReverse(1); 179 | return output; 180 | } 181 | 182 | uint32_t BinaryReader::PeekUint32() 183 | { 184 | uint32_t output = ReadUint32(); 185 | SeekReverse(4); 186 | return output; 187 | } 188 | 189 | 190 | wchar_t BinaryReader::PeekCharWide() 191 | { 192 | wchar_t output = ReadCharWide(); 193 | SeekReverse(2); 194 | return output; 195 | } 196 | 197 | float BinaryReader::ReadFloat() 198 | { 199 | float output; 200 | stream_->read(reinterpret_cast(&output), 4); 201 | return output; 202 | } 203 | 204 | double BinaryReader::ReadDouble() 205 | { 206 | double output; 207 | stream_->read(reinterpret_cast(&output), 8); 208 | return output; 209 | } 210 | 211 | void BinaryReader::ReadToMemory(void* destination, size_t size) 212 | { 213 | stream_->read(static_cast(destination), size); 214 | } 215 | 216 | void BinaryReader::SeekBeg(size_t absoluteOffset) 217 | { 218 | stream_->seekg(absoluteOffset, std::ifstream::beg); 219 | } 220 | 221 | void BinaryReader::SeekCur(size_t relativeOffset) 222 | { 223 | stream_->seekg(relativeOffset, std::ifstream::cur); 224 | } 225 | 226 | void BinaryReader::SeekReverse(size_t relativeOffset) 227 | { 228 | const size_t delta = std::min(Position(), relativeOffset); //Don't allow seeking before the beginning of the stream 229 | const size_t targetOffset = Position() - delta; 230 | SeekBeg(targetOffset); 231 | } 232 | 233 | void BinaryReader::Skip(size_t bytesToSkip) 234 | { 235 | stream_->seekg(bytesToSkip, std::ifstream::cur); 236 | } 237 | 238 | size_t BinaryReader::Align(size_t alignmentValue) 239 | { 240 | //Todo: Test that this math is working as expected. Had bug here in C# version 241 | const size_t remainder = stream_->tellg() % alignmentValue; 242 | size_t paddingSize = remainder > 0 ? alignmentValue - remainder : 0; 243 | Skip(paddingSize); 244 | return paddingSize; 245 | } 246 | 247 | size_t BinaryReader::Position() const 248 | { 249 | return stream_->tellg(); 250 | } 251 | 252 | size_t BinaryReader::Length() 253 | { 254 | //Save current position 255 | size_t realPosition = Position(); 256 | 257 | //Seek to end of file and get position (the length) 258 | stream_->seekg(0, std::ios::end); 259 | size_t endPosition = Position(); 260 | 261 | //Seek back to real pos and return length 262 | if(realPosition != endPosition) 263 | SeekBeg(realPosition); 264 | 265 | return endPosition; 266 | } 267 | -------------------------------------------------------------------------------- /BinaryTools/MemoryBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //Somehow the windows min and max macros are being leaked into here regardless of where I define NOMINMAX. This works as a fix for the moment 3 | #undef min 4 | #undef max 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //Simple wrapper around std::streambuf representing a memory buffer. 11 | //Used by BinaryReader and BinaryWriter 12 | struct MemoryBuffer : std::streambuf 13 | { 14 | MemoryBuffer(char* begin, char* end) 15 | { 16 | this->setg(begin, begin, end); 17 | } 18 | MemoryBuffer(char* begin, uint32_t sizeInBytes) 19 | { 20 | this->setg(begin, begin, begin + sizeInBytes); 21 | } 22 | }; 23 | 24 | //Used by BinaryReader for reading from in memory buffers. 25 | //Source: https://gist.github.com/polyvertex/ce86fddfa28edcfb19a77f9024a5461c 26 | 27 | // A memory stream buffer class compliant with `std::basic_streambuf`. 28 | // 29 | // Usage example: 30 | // 31 | // std::vector data; 32 | // // ... fill-in *data* here ... 33 | // xx::basic_memstreambuf sbuf(&data[0], data.size()); 34 | // std::istream in(&sbuf); 35 | // // ... read data from *in* ... 36 | // 37 | // Useful references: 38 | // * Deriving from std::streambuf 39 | // https://artofcode.wordpress.com/2010/12/12/deriving-from-stdstreambuf/ 40 | // * A beginner's guide to writing a custom stream buffer (std::streambuf) 41 | // http://www.voidcn.com/article/p-vjnlygmc-gy.html 42 | // * membuf.cpp 43 | // https://gist.github.com/mlfarrell/28ea0e7b10756042956b579781ac0dd8 44 | // * Memory streambuf and stream 45 | // https://codereview.stackexchange.com/questions/138479/memory-streambuf-and-stream 46 | 47 | class basic_memstreambuf : public std::streambuf 48 | { 49 | public: 50 | using BaseT = std::streambuf; 51 | 52 | using BaseT::int_type; 53 | using BaseT::traits_type; 54 | 55 | public: 56 | basic_memstreambuf() 57 | : BaseT() 58 | { } 59 | 60 | explicit basic_memstreambuf(const basic_memstreambuf& rhs) 61 | : BaseT(rhs) 62 | { } 63 | 64 | // non-standard 65 | explicit basic_memstreambuf(const std::basic_string& s) 66 | : BaseT() 67 | { 68 | //assert(!s.empty()); 69 | setg( 70 | const_cast(&s.front()), 71 | const_cast(&s.front()), 72 | const_cast(&s.back())); 73 | } 74 | 75 | // non-standard 76 | basic_memstreambuf(const char_type* s, std::streamsize n) : BaseT() 77 | { 78 | // assert(s); 79 | //assert(n > 0); 80 | setg( 81 | const_cast(s), 82 | const_cast(s), 83 | const_cast(s + n)); 84 | } 85 | 86 | // non-standard 87 | basic_memstreambuf(const char_type* begin, const char_type* end) 88 | : BaseT() 89 | { 90 | //assert(begin); 91 | //assert(end); 92 | //assert(begin < end); 93 | 94 | // check size 95 | const std::uintmax_t count = end - begin; 96 | const std::uintmax_t maxValue = static_cast(std::numeric_limits::max()); 97 | if (count > maxValue) 98 | { 99 | throw std::invalid_argument("basic_memstreambuf too big"); 100 | } 101 | 102 | setg( 103 | const_cast(begin), 104 | const_cast(begin), 105 | const_cast(end)); 106 | } 107 | 108 | basic_memstreambuf& operator=(const basic_memstreambuf&) = delete; 109 | 110 | 111 | protected: 112 | virtual std::streamsize showmanyc() override 113 | { 114 | const auto* ptr = gptr(); 115 | const auto* end = egptr(); 116 | 117 | //assert(ptr <= end); 118 | 119 | return (ptr <= end) ? (end - ptr) : 0; 120 | } 121 | 122 | virtual int_type underflow() override 123 | { 124 | const auto* ptr = gptr(); 125 | 126 | if (ptr >= egptr()) 127 | return traits_type::eof(); 128 | 129 | return traits_type::to_int_type(*ptr); 130 | } 131 | 132 | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) override 133 | { 134 | if (count == 0) 135 | return 0; 136 | 137 | const char* ptr = gptr(); 138 | const std::streamsize to_read = std::min( 139 | count, 140 | static_cast(egptr() - ptr)); 141 | 142 | if (to_read == 0) 143 | { 144 | return traits_type::eof(); 145 | } 146 | else 147 | { 148 | std::memcpy(s, ptr, to_read); 149 | gbump((int)to_read); 150 | return to_read; 151 | } 152 | } 153 | 154 | virtual pos_type seekoff( 155 | off_type off, 156 | std::ios_base::seekdir dir, 157 | std::ios_base::openmode which = std::ios_base::in) override 158 | { 159 | if (which != std::ios_base::in) 160 | { 161 | //assert(0); 162 | throw std::invalid_argument("basic_memstreambuf::seekoff[which]"); 163 | } 164 | 165 | if (dir == std::ios_base::beg) 166 | { 167 | if (off >= 0 && off < egptr() - eback()) 168 | { 169 | setg(eback(), eback() + off, egptr()); 170 | } 171 | else 172 | { 173 | //assert(0); 174 | throw std::out_of_range("basic_memstreambuf::seekoff[beg]"); 175 | } 176 | } 177 | else if (dir == std::ios_base::cur) 178 | { 179 | if ((off >= 0 && off <= egptr() - gptr()) || 180 | (off < 0 && std::abs(off) < gptr() - eback())) 181 | { 182 | gbump((int)off); 183 | } 184 | else 185 | { 186 | //assert(0); 187 | throw std::out_of_range("basic_memstreambuf::seekoff[cur]"); 188 | } 189 | } 190 | else if (dir == std::ios_base::end) 191 | { 192 | if (off <= 0 && std::abs(off) < egptr() - eback()) 193 | { 194 | setg(eback(), egptr() + (int)off, egptr()); 195 | } 196 | else 197 | { 198 | //assert(0); 199 | throw std::out_of_range("basic_memstreambuf::seekoff[end]"); 200 | } 201 | } 202 | else 203 | { 204 | //assert(0); 205 | throw std::invalid_argument("basic_memstreambuf::seekoff[dir]"); 206 | } 207 | 208 | return gptr() - eback(); 209 | } 210 | 211 | virtual pos_type seekpos( 212 | pos_type pos, 213 | std::ios_base::openmode which = std::ios_base::in) override 214 | { 215 | if (which != std::ios_base::in) 216 | { 217 | //assert(0); 218 | throw std::invalid_argument("basic_memstreambuf::seekpos[which]"); 219 | } 220 | 221 | if (pos < egptr() - eback()) 222 | { 223 | setg(eback(), eback() + pos, egptr()); 224 | } 225 | else 226 | { 227 | ////assert(0); 228 | throw std::out_of_range("memstreambuf::seekpos"); 229 | } 230 | 231 | return pos; 232 | } 233 | 234 | #if 0 235 | virtual int_type pbackfail(int_type c = traits_type::eof()) override 236 | { 237 | const auto* begin = eback(); 238 | const auto* ptr = gptr(); 239 | const auto gc = *(ptr - 1); 240 | 241 | if (ptr == begin || (c != traits_type::eof() && c != gc)) 242 | return traits_type::eof(); 243 | 244 | gbump(-1); 245 | 246 | return traits_type::to_int_type(gc); 247 | } 248 | #endif 249 | }; -------------------------------------------------------------------------------- /BinaryTools/BinaryTools.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {DC3D45C9-4E30-4E00-9E95-76FCF3754849} 24 | Win32Proj 25 | BinaryTools 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | true 92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | stdcpplatest 95 | true 96 | 97 | 98 | Console 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | true 109 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | true 111 | stdcpplatest 112 | true 113 | 114 | 115 | Console 116 | true 117 | 118 | 119 | 120 | 121 | 122 | 123 | Level3 124 | MaxSpeed 125 | true 126 | true 127 | true 128 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 129 | true 130 | stdcpplatest 131 | true 132 | 133 | 134 | Console 135 | true 136 | true 137 | true 138 | 139 | 140 | 141 | 142 | 143 | 144 | Level3 145 | MaxSpeed 146 | true 147 | true 148 | true 149 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 150 | true 151 | stdcpplatest 152 | true 153 | 154 | 155 | Console 156 | true 157 | true 158 | true 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | --------------------------------------------------------------------------------