-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathMemFile.h
219 lines (183 loc) · 6.84 KB
/
MemFile.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//----------------------------------------------------------------------------------------------------------------------
// File I/O like routines for memory loaded files
// Copyright (c) 2024 Samuel Gomes
//----------------------------------------------------------------------------------------------------------------------
#pragma once
#include "Debug.h"
#include "Types.h"
#include <cstdint>
#include <algorithm>
#include <vector>
/// @brief A pointer to an object of this struct is returned by MemFile_Create()
struct MemFile
{
std::vector<uint8_t> buffer; // a std::vector of bytes
size_t cursor; // the current read / write position in the vector
};
/// @brief Creates a new MemFile object using an existing memory buffer
/// @param data A valid data buffer or nullptr
/// @param size The correct size of the data if data is not nullptr
/// @return A pointer to a new MemFile or nullptr on failure
uintptr_t MemFile_Create(uintptr_t data, size_t size)
{
auto memFile = new MemFile;
if (memFile)
{
memFile->buffer.assign(reinterpret_cast<const uint8_t *>(data), reinterpret_cast<const uint8_t *>(data) + size);
memFile->cursor = 0;
}
return reinterpret_cast<uintptr_t>(memFile);
}
/// @brief Deletes a MemFile object created using MemFile_Create()
/// @param p A valid pointer to a MemFile object
void MemFile_Destroy(uintptr_t p)
{
if (p)
delete reinterpret_cast<MemFile *>(p);
else
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
}
/// @brief Returns QB_TRUE if the cursor moved past the end of the buffer
/// @param p A valid pointer to a MemFile object
/// @return QB_TRUE if EOF, QB_FALSE otherwise
qb_bool MemFile_IsEOF(uintptr_t p)
{
auto memFile = reinterpret_cast<const MemFile *>(p);
if (memFile)
return TO_QB_BOOL(memFile->cursor >= memFile->buffer.size());
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
return QB_FALSE;
}
/// @brief Returns the size of the buffer in bytes
/// @param p A valid pointer to a MemFile object
/// @return The size of the buffer in bytes
size_t MemFile_GetSize(uintptr_t p)
{
auto memFile = reinterpret_cast<const MemFile *>(p);
if (memFile)
return memFile->buffer.size();
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
return 0;
}
/// @brief Returns the cursor position
/// @param p A valid pointer to a MemFile object
/// @return The position from the origin
size_t MemFile_GetPosition(uintptr_t p)
{
auto memFile = reinterpret_cast<const MemFile *>(p);
if (memFile)
return memFile->cursor;
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
return 0;
}
/// @brief Position the read / write cursor inside the data buffer
/// @param p A valid pointer to a MemFile object
/// @param position A value that is less than or equal to the size of the buffer
void MemFile_Seek(uintptr_t p, size_t position)
{
auto memFile = reinterpret_cast<MemFile *>(p);
if (memFile && position <= memFile->buffer.size())
memFile->cursor = position;
else
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
}
/// @brief Resizes the buffer of a MemFile object
/// @param p A valid pointer to a MemFile object
/// @param newSize The new size of the buffer
void MemFile_Resize(uintptr_t p, size_t newSize)
{
auto memFile = reinterpret_cast<MemFile *>(p);
if (memFile)
{
memFile->buffer.resize(newSize);
if (memFile->cursor > newSize)
memFile->cursor = newSize;
}
else
{
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
}
}
/// @brief Reads a chunk of data from the buffer at the cursor position
/// @param p A valid pointer to a MemFile object
/// @param data Pointer to the buffer the data needs to be written to
/// @param size The size of the chuck that needs to be read
/// @return The actual number of bytes read. This can be less than `size`
size_t MemFile_Read(uintptr_t p, uintptr_t data, size_t size)
{
auto memFile = reinterpret_cast<MemFile *>(p);
if (memFile && data)
{
auto bytesToRead = std::min(size, memFile->buffer.size() - memFile->cursor);
if (bytesToRead > 0)
{
std::copy(memFile->buffer.begin() + memFile->cursor, memFile->buffer.begin() + memFile->cursor + bytesToRead, (uint8_t *)data);
memFile->cursor += bytesToRead;
}
return bytesToRead;
}
else
{
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
}
return 0;
}
/// @brief Writes a chunk of data to the buffer at the cursor position (optionally growing the buffer size)
/// @param p A valid pointer to a MemFile object
/// @param data Pointer to the buffer the data needs to be read from
/// @param size The size of the chunk that needs to be written
/// @return The number of bytes written
size_t MemFile_Write(uintptr_t p, uintptr_t data, size_t size)
{
auto memFile = reinterpret_cast<MemFile *>(p);
if (memFile && data)
{
// Resize the buffer if needed
if (memFile->cursor + size > memFile->buffer.size())
memFile->buffer.resize(memFile->cursor + size);
// Copy the data to the buffer
std::copy((uint8_t *)data, (uint8_t *)data + size, memFile->buffer.begin() + memFile->cursor);
// Move the cursor
memFile->cursor += size;
return size;
}
else
{
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
}
return 0;
}
/// @brief Reads a value of type T from the buffer at the cursor position
/// @tparam T A valid C+ type
/// @param p A valid pointer to a MemFile object
/// @return The T value read
template <typename T>
inline T MemFile_Read(uintptr_t p)
{
T value = T();
if (MemFile_Read(p, reinterpret_cast<uintptr_t>(&value), sizeof(T)) != sizeof(T))
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
return value;
}
/// @brief Writes a value of type T to the buffer at the cursor position
/// @tparam T A valid C+ type
/// @param p A valid pointer to a MemFile object
/// @param value The T value to write
template <typename T>
inline void MemFile_Write(uintptr_t p, T value)
{
if (MemFile_Write(p, reinterpret_cast<uintptr_t>(&value), sizeof(T)) != sizeof(T))
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
}
#define MemFile_ReadByte(p) MemFile_Read<uint8_t>(p)
#define MemFile_WriteByte(p, byte) MemFile_Write<uint8_t>((p), (byte))
#define MemFile_ReadInteger(p) MemFile_Read<uint16_t>(p)
#define MemFile_WriteInteger(p, word) MemFile_Write<uint16_t>((p), (word))
#define MemFile_ReadLong(p) MemFile_Read<uint32_t>(p)
#define MemFile_WriteLong(p, dword) MemFile_Write<uint32_t>((p), (dword))
#define MemFile_ReadSingle(p) MemFile_Read<float>(p)
#define MemFile_WriteSingle(p, fp32) MemFile_Write<float>((p), (fp32))
#define MemFile_ReadInteger64(p) MemFile_Read<uint64_t>(p)
#define MemFile_WriteInteger64(p, qword) MemFile_Write<uint64_t>((p), (qword))
#define MemFile_ReadDouble(p) MemFile_Read<double>(p)
#define MemFile_WriteDouble(p, fp64) MemFile_Write<double>((p), (fp64))