fork download
  1. #include "ByteBuffer.h"
  2.  
  3. #include "System/Macroes/Asserts.h"
  4. #include "FileSystem/PathFormatting.h"
  5. #include "Logger/Log.h"
  6.  
  7. #include <algorithm> //For std::swap
  8. #include <cstring> //For std::memcpy
  9. #include <fstream>
  10.  
  11. ByteBuffer::ByteBuffer(size_t bytesToAllocate)
  12. {
  13. this->AllocateData(bytesToAllocate);
  14. }
  15.  
  16. ByteBuffer::ByteBuffer(ByteBuffer &&other)
  17. {
  18. std::swap(this->data, other.data);
  19. std::swap(this->bytes, other.bytes);
  20. std::swap(this->isOwner, other.isOwner);
  21. }
  22.  
  23. ByteBuffer &ByteBuffer::operator=(ByteBuffer &&other)
  24. {
  25. std::swap(this->data, other.data);
  26. std::swap(this->bytes, other.bytes);
  27. std::swap(this->isOwner, other.isOwner);
  28.  
  29. return *this;
  30. }
  31.  
  32. ByteBuffer::~ByteBuffer()
  33. {
  34. this->Clear();
  35. }
  36.  
  37. //========================================================
  38. //Named constructors, for convience:
  39. //========================================================
  40.  
  41. //Creates a ByteBuffer that owns 'data', and will delete it when destroyed.
  42. ByteBuffer ByteBuffer::MakeOwnerOf(Byte *data, size_t bytes)
  43. {
  44. ByteBuffer buffer;
  45. buffer.TakeData(data, bytes);
  46. return buffer;
  47. }
  48.  
  49. ByteBuffer ByteBuffer::MakeOwnerOf(ByteBuffer &other)
  50. {
  51. ByteBuffer buffer;
  52. buffer.TakeData(other);
  53. return buffer;
  54. }
  55.  
  56. //Creates a ByteBuffer that copies 'data'. When destroyed, this ByteBuffer will delete the copied memory but not the original.
  57. ByteBuffer ByteBuffer::MakeCopiedFrom(const Byte *data, size_t bytes)
  58. {
  59. ByteBuffer buffer;
  60. buffer.CopyData(data, bytes);
  61. return buffer;
  62. }
  63.  
  64. ByteBuffer ByteBuffer::MakeCopiedFrom(const ByteBuffer &other, size_t pos, size_t bytes)
  65. {
  66. ByteBuffer buffer;
  67. buffer.CopyData(other, pos, bytes);
  68. return buffer;
  69. }
  70.  
  71. //Creates a ByteBuffer that points to 'data', without copying it, and will not delete the memory when destroyed.
  72. ByteBuffer ByteBuffer::MakePointedAt(Byte *data, size_t bytes)
  73. {
  74. ByteBuffer buffer;
  75. buffer.PointToData(data, bytes);
  76. return buffer;
  77. }
  78.  
  79. ByteBuffer ByteBuffer::MakePointedAt(ByteBuffer &other, size_t pos, size_t bytes)
  80. {
  81. ByteBuffer buffer;
  82. buffer.PointToData(other, pos, bytes);
  83. return buffer;
  84. }
  85.  
  86. //Creates a ByteBuffer that allocates a new block of memory of size 'bytes', and that will delete the memory when destroyed.
  87. ByteBuffer ByteBuffer::MakeAllocated(size_t bytes)
  88. {
  89. ByteBuffer buffer;
  90. buffer.AllocateData(bytes);
  91.  
  92. return buffer;
  93. }
  94.  
  95. //========================================================
  96. //Access functions:
  97. //========================================================
  98.  
  99. //Returns a reference to the bytes starting at 'pos'.
  100. //Doesn't check if 'pos' is inbounds or not.
  101. Byte &ByteBuffer::operator[](size_t pos)
  102. {
  103. return this->data[pos];
  104. }
  105.  
  106. const Byte &ByteBuffer::operator[](size_t pos) const
  107. {
  108. return this->data[pos];
  109. }
  110.  
  111. //Returns a reference to the bytes starting at 'pos'.
  112. //This is the same as buffer[pos], except it _does_ check if pos is in-bounds, by asserting.
  113. Byte &ByteBuffer::At(size_t pos)
  114. {
  115. Assert(pos < this->bytes, "'pos' is out of range");
  116. return this->data[pos];
  117. }
  118.  
  119. const Byte &ByteBuffer::At(size_t pos) const
  120. {
  121. Assert(pos < this->bytes, "'pos' is out of range");
  122. return this->data[pos];
  123. }
  124.  
  125. //Returns a pointer to the first byte of the entire buffer. (The same as buffer[0])
  126. Byte *ByteBuffer::GetData()
  127. {
  128. return this->data;
  129. }
  130.  
  131. const Byte *ByteBuffer::GetData() const
  132. {
  133. return this->data;
  134. }
  135.  
  136. //Creates a non-owning ByteBuffer that points to the memory starting at 'pos', and containing the specified length of bytes.
  137. //This is similar to getting a substring of a string.
  138. //This ByteBuffer still owns and data and is responsible for freeing it. The returned buffer merely points to the data, but doesn't own it.
  139. ByteBuffer ByteBuffer::MakeDataPortion(size_t pos, size_t bytes)
  140. {
  141. return ByteBuffer::MakePointedAt(*this, pos, bytes);
  142. }
  143.  
  144. //The same as 'MakeDataPortion()', but copies the data.
  145. ByteBuffer ByteBuffer::DuplicateDataPortion(size_t pos, size_t bytes)
  146. {
  147. return ByteBuffer::MakeCopiedFrom(*this, pos, bytes);
  148. }
  149.  
  150. //========================================================
  151. //Querying functions:
  152. //========================================================
  153.  
  154. //Returns the size of the buffer, in bytes.
  155. size_t ByteBuffer::GetSize() const
  156. {
  157. return this->bytes;
  158. }
  159.  
  160. //True if this ByteBuffer owns the memory it points to.
  161. bool ByteBuffer::IsOwner() const
  162. {
  163. return this->isOwner;
  164. }
  165.  
  166. //True if this ByteBuffer points to nullptr, or is of size 0.
  167. bool ByteBuffer::IsEmpty() const
  168. {
  169. return (this->bytes == 0 || !this->data);
  170. }
  171.  
  172. //========================================================
  173. //Freeing functions: (deletes or releases the data)
  174. //========================================================
  175.  
  176. //Releases ownership of the data, returning it.
  177. //This ByteBuffer still points to the data, but will never delete it.
  178. //If 'bytes' is not Null, it will be set to the size of this buffer.
  179. Byte *ByteBuffer::ReleaseData(size_t *bytes)
  180. {
  181. //Release ownership.
  182. this->isOwner = false;
  183.  
  184. //Set the number of bytes, if asked for.
  185. if(bytes)
  186. {
  187. *bytes = this->bytes;
  188. }
  189.  
  190. //Return the pointer.
  191. return this->data;
  192. }
  193.  
  194. //Releases ownership of the data, returning it.
  195. //This ByteBuffer no longer points to the data, and will never delete it.
  196. //If 'bytes' is not Null, it will be set to the size of this buffer.
  197. //This is the same as calling ReleaseData() followed by Clear().
  198. Byte *ByteBuffer::ReleaseAndReset(size_t *bytes)
  199. {
  200. //Release owernship of the data.
  201. Byte *dataPtr = this->ReleaseData(bytes);
  202.  
  203. //Clear this buffer.
  204. this->Clear();
  205.  
  206. //Return the pointer.
  207. return dataPtr;
  208. }
  209.  
  210. //Clears this ByteBuffer, setting the data pointer to nullptr and the size to 0.
  211. //If this ByteBuffer owns the memory it points to, that memory will now get deleted.
  212. void ByteBuffer::Clear()
  213. {
  214. this->resetTo(nullptr, 0, false);
  215. }
  216.  
  217. //========================================================
  218. //Re-assignment functions
  219. //========================================================
  220.  
  221. //Takes ownership of 'data' without copying it.
  222. //When this ByteBuffer is destroyed, it will delete 'data' also.
  223. //Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
  224. void ByteBuffer::TakeData(Byte *data, size_t bytes)
  225. {
  226. Assert(bytes > 0, "Can't take zero bytes.");
  227. this->resetTo(data, bytes, true);
  228. }
  229.  
  230. //'other' is made to Release() the data.
  231. void ByteBuffer::TakeData(ByteBuffer &other)
  232. {
  233. size_t bytes;
  234. Byte *data = other.ReleaseData(&bytes);
  235. this->resetTo(data, bytes, true);
  236. }
  237.  
  238. //Copies 'data'. When this ByteBuffer is destroyed, it will delete the copied memory but not the original.
  239. //Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
  240. void ByteBuffer::CopyData(const Byte *data, size_t bytes)
  241. {
  242. Assert(bytes > 0, "Can't copy zero bytes.");
  243.  
  244. //Allocate the new memory.
  245. Byte *copiedData = new Byte[bytes];
  246.  
  247. //Copy the data over.
  248. std::memcpy(copiedData, data, bytes);
  249.  
  250. //Assign the data.
  251. this->resetTo(copiedData, bytes, true);
  252. }
  253.  
  254. void ByteBuffer::CopyData(const ByteBuffer &other, size_t pos, size_t bytes)
  255. {
  256. if(bytes == ByteBuffer::NoPos)
  257. {
  258. bytes = (other.GetSize() - pos);
  259. }
  260.  
  261. Assert((pos + bytes) <= other.GetSize(), "Trying to copy more data than exists in the buffer.");
  262. this->CopyData(&other[pos], bytes);
  263. }
  264.  
  265. //Points to 'data', without copying it, and when this ByteBuffer is destroyed, will not delete the memory.
  266. //Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
  267. void ByteBuffer::PointToData(Byte *data, size_t bytes)
  268. {
  269. Assert(bytes > 0, "Can't point to zero bytes.");
  270.  
  271. this->resetTo(data, bytes, false);
  272. }
  273.  
  274. void ByteBuffer::PointToData(ByteBuffer &other, size_t pos, size_t bytes)
  275. {
  276. if(bytes == ByteBuffer::NoPos)
  277. {
  278. bytes = (other.GetSize() - pos);
  279. }
  280.  
  281. Assert((pos + bytes) <= other.GetSize(), "Trying to point to more data than exists in the buffer.");
  282. this->PointToData(&other[pos], bytes);
  283. }
  284.  
  285. //Allocates a new block of memory of size 'bytes'.
  286. //Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
  287. void ByteBuffer::AllocateData(size_t bytes)
  288. {
  289. Assert(bytes > 0, "Can't allocate zero bytes.");
  290.  
  291. this->resetTo(new Byte[bytes], bytes, true);
  292. }
  293.  
  294. //================================================================================
  295.  
  296. //Clears the existing data (freeing it if this ByteBuffer is the owner),
  297. //and assigning 'data' as the new memory pointer and 'bytes' as the new size.
  298. void ByteBuffer::resetTo(Byte *data, size_t bytes, bool isOwner)
  299. {
  300. //If we're the owner, delete the old memory (if any - it might be null).
  301. if(this->isOwner)
  302. delete[] this->data;
  303.  
  304. //Assign the new data, if any (it might be null).
  305. this->data = data;
  306. this->bytes = bytes;
  307. this->isOwner = isOwner;
  308. }
  309.  
  310. //================================================================================
  311.  
  312. //Resizes 'byteBuffer' by allocating a new buffer of size 'newSize', and copying the old bytes to it, before deleting the original buffer.
  313. //If 'offset' is specified, offsets the position to place the the old memory in the new buffer. This allows you to grow the buffer's front as well as the back.
  314. //e.g. to grow a buffer's front and back by 4 bytes each, you can do: ResizeByteBuffer(buffer, (buffer.GetSize() + 8), 4);
  315. //This can shrink or grow the buffer.
  316. void ResizeByteBuffer(ByteBuffer &byteBuffer, size_t newSize, size_t offset)
  317. {
  318. if(newSize == ByteBuffer_SuggestedResize)
  319. {
  320. size_t currentSize = byteBuffer.GetSize();
  321.  
  322. //Grow the ByteBuffer to the new size plus 35% or at least 128 bytes.
  323. newSize = ((currentSize < 384) ? (currentSize + 128): size_t(float(currentSize) * 1.35f));
  324. }
  325.  
  326. if(newSize == byteBuffer.GetSize())
  327. return;
  328.  
  329. Assert(newSize > 0, "Can't allocate zero bytes.");
  330. Assert(newSize > offset, "Offset can't be outside the buffer size.");
  331.  
  332. //Allocate the new memory.
  333. Byte *newData = new Byte[newSize];
  334.  
  335. //Figure out how many bytes to copy.
  336. size_t bytesToCopy = std::min(byteBuffer.GetSize(), (newSize-offset));
  337.  
  338. //Copy the data over.
  339. std::memcpy(&newData[offset], byteBuffer.GetData(), bytesToCopy);
  340.  
  341. //Assign the data.
  342. byteBuffer.TakeData(newData, newSize);
  343. }
  344.  
  345. //Starting at 'pos', fills a number of bytes (bytes) in byteBuffer with 'fillValue'.
  346. void FillByteBuffer(ByteBuffer &byteBuffer, Byte fillValue, size_t pos, size_t bytes)
  347. {
  348. Assert(pos < byteBuffer.GetSize(), "Can't fill outside the buffer.");
  349.  
  350. //Make sure we stay within the buffer.
  351. if((bytes + pos) > byteBuffer.GetSize())
  352. {
  353. bytes = (byteBuffer.GetSize() - pos);
  354. }
  355.  
  356. //Set the bytes.
  357. std::memset(&byteBuffer[pos], fillValue, bytes);
  358. }
  359.  
  360. //================================================================================
  361.  
  362. //Loads a file entirely into a bytebuffer. Returns an empty ByteBuffer if the load failed or if the file was empty.
  363. ByteBuffer LoadFileAsByteBuffer(const std::string &filename)
  364. {
  365. //Open the file.
  366. std::ifstream file(filename, std::fstream::binary);
  367.  
  368. //Make sure the file was opened.
  369. if(!file)
  370. {
  371. Log::Message(MSG_SOURCE("FileFunctions", Log::Severity::Error))
  372. << "Failed to load '" << Log_HighlightCyan(GetFilenameFromPath(filename)) << "' at " << Log_DisplayPath(filename)
  373. << "\nDo I have sufficient privileges? Does the file even exist?" << Log::FlushStream;
  374.  
  375. return ByteBuffer();
  376. }
  377.  
  378. //Seek to the end of the file, to figure out its length.
  379. file.seekg(0, std::ios::end);
  380. size_t bytes = file.tellg();
  381.  
  382. //Return if the file was empty.
  383. if(bytes == 0)
  384. {
  385. return ByteBuffer();
  386. }
  387.  
  388. //Allocate the byte buffer of the apropriate size.
  389. ByteBuffer byteBuffer = ByteBuffer::MakeAllocated(bytes);
  390.  
  391. //Jump back to the beginning, and read the file into the buffer.
  392. file.seekg(0, std::ios::beg);
  393. file.read(reinterpret_cast<char*>(byteBuffer.GetData()), bytes);
  394.  
  395. //Return the buffer and (automaticly) close the file.
  396. return byteBuffer;
  397. }
  398.  
  399. bool SaveByteBufferToFile(const ByteBuffer &byteBuffer, const std::string &filename, size_t bytes)
  400. {
  401. //Open the file.
  402. std::ofstream file(filename, std::fstream::binary);
  403.  
  404. //Make sure the file was opened.
  405. if(!file)
  406. {
  407. Log::Message(MSG_SOURCE("FileFunctions", Log::Severity::Error))
  408. << "Failed to open '" << Log_HighlightCyan(GetFilenameFromPath(filename)) << "' for writing, at " << Log_DisplayPath(filename)
  409. << "\nDo I have sufficient privileges to write to this directory?" << Log::FlushStream;
  410.  
  411. return false;
  412. }
  413.  
  414. size_t amountToWrite = std::min(bytes, byteBuffer.GetSize());
  415.  
  416. //Write the data.
  417. file.write(reinterpret_cast<const char*>(byteBuffer.GetData()), amountToWrite);
  418.  
  419. //Return and (automaticly) close the file.
  420. return true;
  421. }
  422.  
  423. ByteBuffer StringToByteBuffer(const std::string &str)
  424. {
  425. return ByteBuffer::MakeCopiedFrom(reinterpret_cast<const Byte*>(str.data()), str.size());
  426. }
  427.  
  428. std::string ByteBufferToString(const ByteBuffer &byteBuffer)
  429. {
  430. return std::string(reinterpret_cast<const char*>(byteBuffer.GetData()),
  431. byteBuffer.GetSize());
  432. }
  433.  
  434. //================================================================================
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:1:24: fatal error: ByteBuffer.h: No such file or directory
 #include "ByteBuffer.h"
                        ^
compilation terminated.
stdout
Standard output is empty