TurtleBrains  0.3.5
High quality, portable, C++ framework for rapid 2D game development.
tb_file_utilities.hpp
1 
9 #ifndef TurtleBrains_FileUtilities_hpp
10 #define TurtleBrains_FileUtilities_hpp
11 
12 #include <turtle_brains/core/tb_defines.hpp>
13 #include <turtle_brains/core/tb_types.hpp>
14 #include <turtle_brains/core/tb_string.hpp>
15 
16 #include <fstream>
17 #include <vector>
18 #include <type_traits>
19 
20 namespace TurtleBrains::Core
21 {
22  class DynamicStructure;
23 };
24 
25 namespace TurtleBrains::Core::FileUtilities
26 {
27  //Expects the data to be written in Little-Endian Byte Order.
28  void WriteVariableLengthEncoding(uint64 length, OutputFile& outputFile);
29 
30  //Expects the data to be read in Little-Endian Byte Order.
31  tbCore::uint64 ReadVariableLengthEncoding(InputFile& inputFile);
32 
33  template<typename Type> Type ReadVariableLength(std::istream& inputFile)
34  {
35  return tbCore::RangedCast<Type, tbCore::uint64>(ReadVariableLengthEncoding(inputFile));
36  }
37 
38  // Note: For all Binary functions below it is assumed that the file stream was opened in Binary mode. Calling these
39  // on files opened in text mode, which is default, will be likely to cause issues and headaches! You've been warned.
40 
41  // Note: This is working directly with input/output streams and it might be wise to wrap them with our own
42  // calls to Open() and Close() because this will ensure the file is opened in binary mode and not
43  // accidentally left in text mode. It could also allow TurtleBrains to save a format version itself that
44  // could remove the extra null terminator on the strings now that we have the length saved. Though ideally
45  // this wouldn't add extra information to a file/memory buffer as a developer might feel a little odd with
46  // bytes they didn't put in themselves.
47 
48  template<typename Type> void WriteBinary(const Type& object, OutputFile& outputFile)
49  { //Until we get a template specialization that ReadBinary(DynamicStructure, inputFile) works as expected,
50  // this will at least point out the errors that would otherwise cause hours of headaches. Either the
51  // DynamicStructure needs to know about FileUtilities or vice-versa, only then can create the specialization.
52  // 2025-11-09: This should be pretty impossible to get at this point since we refactored the WriteBinary() and
53  // there is a template specialization for the DynamicStructure. IF we got here, it means someone, somehow,
54  // used a DynamicStructure without properly including tb_dynamic_structure.hpp. That seems impossible.
55  tb_static_error_if((std::is_same<Type, DynamicStructure>::value), "This is the wrong WriteBinary, use tbCore::WriteBinary(object, file);");
56  outputFile.write(reinterpret_cast<const char*>(&object), sizeof(Type));
57  }
58 
62  template<> void WriteBinary<String>(const String& object, OutputFile& outputFile);
63 
67  inline void WriteBinary(const void* object, size_t size, OutputFile& outputFile)
68  {
69  outputFile.write(reinterpret_cast<const char*>(object), size);
70  }
71 
81  template<typename Type> void ReadBinary(Type& object, InputFile& inputFile)
82  {
83  //Until we get a template specialization that ReadBinary(DynamicStructure, inputFile) works as expected,
84  // this will at least point out the errors that would otherwise cause hours of headaches. Either the
85  // DynamicStructure needs to know about FileUtilities or vice-versa, only then can create the specialization.
86  // 2025-11-09: This should be pretty impossible to get at this point since we refactored the ReadBinary() and
87  // there is a template specialization for the DynamicStructure. IF we got here, it means someone, somehow,
88  // used a DynamicStructure without properly including tb_dynamic_structure.hpp. That seems impossible.
89  tb_static_error_if((std::is_same<Type, DynamicStructure>::value), "This is the wrong ReadBinary, use object = tbCore::ReadBinary(file);");
90  inputFile.read(reinterpret_cast<char*>(&object), sizeof(Type));
91  }
92 
103  template<> void ReadBinary<String>(String& object, InputFile& inputFile);
104 
115  template<typename Type> Type ReadBinary(InputFile& inputFile)
116  {
117  Type object;
118  ReadBinary(object, inputFile);
119  return object;
120  }
121 
129  inline void ReadBinary(void* object, size_t size, InputFile& inputFile)
130  {
131  inputFile.read(reinterpret_cast<char*>(object), size);
132  }
133 
134  std::vector<tbCore::byte> LoadBinaryFileContents(const String& filePath);
135 
136  String LoadFileContentsToString(const String& filePath, bool trimTrailingWhitespace = false);
137  bool SaveStringContentsToFile(const String& filePath, const String& stringContents);
138 
139  tbCore::uint32 ComputeCRC32(const String& filePath, tbCore::uint32 crc32 = 0);
140 
141  tbCore::uint32 ComputeCRC32(const std::vector<tbCore::byte>& data, tbCore::uint32 crc32 = 0);
142 
143 }; /* namespace TurtleBrains::Core::FileUtilities */
144 
145 namespace tbCore = TurtleBrains::Core;
146 
147 #endif /* TurtleBrains_FileUtilities_hpp */
#define tb_static_error_if(errorTest, message)
Definition: tb_error.hpp:51
Contains core functionality for each component of the API.
Definition: tb_debug_logger.hpp:125
std::string String
Definition: tb_string.hpp:302
std::uint32_t uint32
Unsigned integer with a size of 32 bits. Supports values from 0 to 4294967295, (2^32 - 1).
Definition: tb_types.hpp:27
std::uint64_t uint64
Unsigned integer with a size of 64 bits, Supports values from 0 to (2^64 - 1).
Definition: tb_types.hpp:29