libultraship
Reimplementations of libultra (N64 SDK) functions for modern hardware
Loading...
Searching...
No Matches
BitConverter.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <limits>
5#include <vector>
6#include <cstring>
7
8#ifdef _MSC_VER
9#define BSWAP16 _byteswap_ushort
10#define BSWAP32 _byteswap_ulong
11#define BSWAP64 _byteswap_uint64
12#else
13#define BSWAP16 __builtin_bswap16
14#define BSWAP32 __builtin_bswap32
15#define BSWAP64 __builtin_bswap64
16#endif
17
24enum class Endianness {
25 Little = 0,
26 Big = 1,
27
28#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || defined(__BIG_ENDIAN__)
29 Native = Big,
30#else
31 Native = Little,
32#endif
33};
34
49class BitConverter {
50 public:
54 static inline int8_t ToInt8BE(const uint8_t* data, int32_t offset) {
55 return (uint8_t)data[offset + 0];
56 }
57
59 static inline int8_t ToInt8BE(const std::vector<uint8_t>& data, int32_t offset) {
60 return (uint8_t)data[offset + 0];
61 }
62
66 static inline uint8_t ToUInt8BE(const uint8_t* data, int32_t offset) {
67 return (uint8_t)data[offset + 0];
68 }
69
71 static inline uint8_t ToUInt8BE(const std::vector<uint8_t>& data, int32_t offset) {
72 return (uint8_t)data[offset + 0];
73 }
74
78 static inline int16_t ToInt16BE(const uint8_t* data, int32_t offset) {
79 return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
80 }
81
83 static inline int16_t ToInt16BE(const std::vector<uint8_t>& data, int32_t offset) {
84 return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
85 }
86
90 static inline uint16_t ToUInt16BE(const uint8_t* data, int32_t offset) {
91 return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
92 }
93
95 static inline uint16_t ToUInt16BE(const std::vector<uint8_t>& data, int32_t offset) {
96 return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
97 }
98
102 static inline int32_t ToInt32BE(const uint8_t* data, int32_t offset) {
103 return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
104 ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
105 }
106
108 static inline int32_t ToInt32BE(const std::vector<uint8_t>& data, int32_t offset) {
109 return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
110 ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
111 }
112
116 static inline uint32_t ToUInt32BE(const uint8_t* data, int32_t offset) {
117 return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
118 ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
119 }
120
122 static inline uint32_t ToUInt32BE(const std::vector<uint8_t>& data, int32_t offset) {
123 return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
124 ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
125 }
126
130 static inline int64_t ToInt64BE(const uint8_t* data, int32_t offset) {
131 return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
132 ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
133 ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
134 ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
135 }
136
138 static inline int64_t ToInt64BE(const std::vector<uint8_t>& data, int32_t offset) {
139 return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
140 ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
141 ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
142 ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
143 }
144
148 static inline uint64_t ToUInt64BE(const uint8_t* data, int32_t offset) {
149 return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
150 ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
151 ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
152 ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
153 }
154
156 static inline uint64_t ToUInt64BE(const std::vector<uint8_t>& data, int32_t offset) {
157 return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
158 ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
159 ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
160 ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
161 }
162
169 static inline float ToFloatBE(const uint8_t* data, int32_t offset) {
170 float value;
171 uint32_t floatData = ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
172 ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
173 static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float");
174 std::memcpy(&value, &floatData, sizeof(value));
175 return value;
176 }
177
179 static inline float ToFloatBE(const std::vector<uint8_t>& data, int32_t offset) {
180 float value;
181 uint32_t floatData = ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
182 ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
183 static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float");
184 std::memcpy(&value, &floatData, sizeof(value));
185 return value;
186 }
187
193 static inline double ToDoubleBE(const uint8_t* data, int32_t offset) {
194 double value;
195 uint64_t floatData = ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
196 ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
197 ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
198 ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
199 static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double");
200 // Checks if the float format on the platform the ZAPD binary is running on supports the
201 // same float format as the object file.
202 static_assert(std::numeric_limits<float>::is_iec559, "expected IEC559 floats on host machine");
203 std::memcpy(&value, &floatData, sizeof(value));
204 return value;
205 }
206
208 static inline double ToDoubleBE(const std::vector<uint8_t>& data, int32_t offset) {
209 double value;
210 uint64_t floatData = ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
211 ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
212 ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
213 ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
214 static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double");
215 // Checks if the float format on the platform the ZAPD binary is running on supports the
216 // same float format as the object file.
217 static_assert(std::numeric_limits<double>::is_iec559, "expected IEC559 doubles on host machine");
218 std::memcpy(&value, &floatData, sizeof(value));
219 return value;
220 }
221
233 static inline void RomToBigEndian(uint8_t* rom, size_t romSize) {
234 if (romSize <= 0) {
235 return;
236 }
237
238 // Use the first byte to determine byte order
239 uint8_t firstByte = rom[0];
240
241 switch (firstByte) {
242 case 0x37: // v64
243 for (size_t pos = 0; pos < (romSize / 2); pos++) {
244 ((uint16_t*)rom)[pos] = ToUInt16BE(rom, pos * 2);
245 }
246 break;
247 case 0x40: // n64
248 for (size_t pos = 0; pos < (romSize / 4); pos++) {
249 ((uint32_t*)rom)[pos] = ToUInt32BE(rom, pos * 4);
250 }
251 break;
252 case 0x80: // z64
253 break; // Already BE, no need to swap
254 }
255 }
256};
@ Little
Least-significant byte first.
@ Native
Platform is little-endian; Native resolves to Little.
@ Big
Most-significant byte first.