mirror of
https://github.com/cuberite/cuberite.git
synced 2025-01-05 10:27:10 +08:00
Overhaul endian handling in ByteBuffer and FastNBT (#5543)
* Overhaul endian handling in ByteBuffer and FastNBT Rather than juggling "swapped" and "unswapped" versions of integers, different library functions, #defines, etc., simply always read everything byte-by-byte. This works regardless of host CPU endian, got optimised down to either a normal load or a byteswap on every compiler I tested - only 1 instruction on most CPU architectures. This commit introduces a "Bytes" array type to keep endian-sensitive data seperate from host data, alongside the needed C++ template machinery for it to work seamlessly. This approach is a little bit safer as well since you get length- and type-checking for most callsites. * Remove remaining references to old-style endianness conversion, remove functions themselves. --------- Co-authored-by: Alexander Harkness <me@bearbin.net>
This commit is contained in:
parent
b31cfb4c36
commit
d82a6afd9e
@ -9,6 +9,7 @@ as provided in the LICENSE file.
|
||||
9caihezi
|
||||
AirOne01
|
||||
Altenius
|
||||
ashquarky
|
||||
BasedDoge (Donated AlchemistVillage prefabs)
|
||||
bearbin (Alexander Harkness)
|
||||
beeduck
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/StringCompression.h"
|
||||
#include "src/WorldStorage/FastNBT.h"
|
||||
#include "src/IniFile.h"
|
||||
#include "src/Endianness.h"
|
||||
|
||||
|
||||
|
||||
@ -143,7 +144,7 @@ public:
|
||||
|
||||
// Get the real data size:
|
||||
const char * chunkData = m_FileData.data() + chunkOffset * 4096;
|
||||
UInt32 chunkSize = GetBEInt(chunkData);
|
||||
UInt32 chunkSize = NetworkBufToHost(chunkData);
|
||||
if ((chunkSize < 2) || (chunkSize / 4096 > numChunkSectors))
|
||||
{
|
||||
// Bad data, bail out
|
||||
@ -181,7 +182,7 @@ protected:
|
||||
const char * hdr = m_FileData.data();
|
||||
for (size_t i = 0; i < ARRAYCOUNT(m_Header); i++)
|
||||
{
|
||||
m_Header[i] = GetBEInt(hdr + 4 * i);
|
||||
m_Header[i] = NetworkBufToHost(hdr + 4 * i);
|
||||
}
|
||||
m_IsValid = true;
|
||||
}
|
||||
@ -241,7 +242,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk
|
||||
const char * beBiomes = nbt.GetData(mcsBiomes);
|
||||
for (size_t i = 0; i < ARRAYCOUNT(biomeMap); i++)
|
||||
{
|
||||
biomeMap[i] = (EMCSBiome)GetBEInt(beBiomes + 4 * i);
|
||||
biomeMap[i] = (EMCSBiome)NetworkBufToHost<Int32>(beBiomes + 4 * i);
|
||||
}
|
||||
a_DestChunk.setBiomes(biomeMap);
|
||||
return;
|
||||
|
@ -285,10 +285,9 @@ bool cByteBuffer::ReadBEInt16(Int16 & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(2);
|
||||
UInt16 val;
|
||||
ReadBuf(&val, 2);
|
||||
val = ntohs(val);
|
||||
memcpy(&a_Value, &val, 2);
|
||||
Bytes<Int16> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<Int16>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -301,8 +300,9 @@ bool cByteBuffer::ReadBEUInt16(UInt16 & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(2);
|
||||
ReadBuf(&a_Value, 2);
|
||||
a_Value = ntohs(a_Value);
|
||||
Bytes<UInt16> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<UInt16>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -315,10 +315,9 @@ bool cByteBuffer::ReadBEInt32(Int32 & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(4);
|
||||
UInt32 val;
|
||||
ReadBuf(&val, 4);
|
||||
val = ntohl(val);
|
||||
memcpy(&a_Value, &val, 4);
|
||||
Bytes<Int32> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<Int32>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -331,8 +330,9 @@ bool cByteBuffer::ReadBEUInt32(UInt32 & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(4);
|
||||
ReadBuf(&a_Value, 4);
|
||||
a_Value = ntohl(a_Value);
|
||||
Bytes<UInt32> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<UInt32>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -345,8 +345,9 @@ bool cByteBuffer::ReadBEInt64(Int64 & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(8);
|
||||
ReadBuf(&a_Value, 8);
|
||||
a_Value = NetworkToHostLong8(&a_Value);
|
||||
Bytes<Int64> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<Int64>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -359,8 +360,9 @@ bool cByteBuffer::ReadBEUInt64(UInt64 & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(8);
|
||||
ReadBuf(&a_Value, 8);
|
||||
a_Value = NetworkToHostULong8(&a_Value);
|
||||
Bytes<UInt64> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<UInt64>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -373,8 +375,9 @@ bool cByteBuffer::ReadBEFloat(float & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(4);
|
||||
ReadBuf(&a_Value, 4);
|
||||
a_Value = NetworkToHostFloat4(&a_Value);
|
||||
Bytes<float> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<float>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -387,8 +390,9 @@ bool cByteBuffer::ReadBEDouble(double & a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
NEEDBYTES(8);
|
||||
ReadBuf(&a_Value, 8);
|
||||
a_Value = NetworkToHostDouble8(&a_Value);
|
||||
Bytes<double> bytes;
|
||||
ReadBuf(bytes.data(), bytes.size());
|
||||
a_Value = NetworkToHost<double>(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -629,10 +633,8 @@ bool cByteBuffer::WriteBEInt16(Int16 a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(2);
|
||||
UInt16 val;
|
||||
memcpy(&val, &a_Value, 2);
|
||||
val = htons(val);
|
||||
return WriteBuf(&val, 2);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -644,8 +646,8 @@ bool cByteBuffer::WriteBEUInt16(UInt16 a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(2);
|
||||
a_Value = htons(a_Value);
|
||||
return WriteBuf(&a_Value, 2);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -657,8 +659,8 @@ bool cByteBuffer::WriteBEInt32(Int32 a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(4);
|
||||
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||
return WriteBuf(&Converted, 4);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -670,8 +672,8 @@ bool cByteBuffer::WriteBEUInt32(UInt32 a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(4);
|
||||
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||
return WriteBuf(&Converted, 4);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -683,8 +685,8 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(8);
|
||||
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||
return WriteBuf(&Converted, 8);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -696,8 +698,8 @@ bool cByteBuffer::WriteBEUInt64(UInt64 a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(8);
|
||||
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||
return WriteBuf(&Converted, 8);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -709,8 +711,8 @@ bool cByteBuffer::WriteBEFloat(float a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(4);
|
||||
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||
return WriteBuf(&Converted, 4);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
@ -722,8 +724,8 @@ bool cByteBuffer::WriteBEDouble(double a_Value)
|
||||
CHECK_THREAD
|
||||
CheckValid();
|
||||
PUTBYTES(8);
|
||||
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||
return WriteBuf(&Converted, 8);
|
||||
auto Converted = HostToNetwork(a_Value);
|
||||
return WriteBuf(Converted.data(), Converted.size());
|
||||
}
|
||||
|
||||
|
||||
|
183
src/Endianness.h
183
src/Endianness.h
@ -1,86 +1,143 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#undef ntohll
|
||||
#define ntohll(x) (((static_cast<UInt64>(ntohl(static_cast<UInt32>(x)))) << 32) + ntohl(x >> 32))
|
||||
#include <array>
|
||||
template <typename T>
|
||||
using Bytes = std::array<std::byte, sizeof(T)>;
|
||||
|
||||
// bit_cast used for going between ulong, float, etc. It's a new C++20 feature
|
||||
#ifdef __cpp_lib_bit_cast
|
||||
#include <bit>
|
||||
using std::bit_cast;
|
||||
|
||||
|
||||
|
||||
|
||||
// Changes endianness
|
||||
inline UInt64 HostToNetwork8(const void * a_Value)
|
||||
// Fallback in case we're using C++17
|
||||
#else
|
||||
// bit-for-bit convert one type to another. In C++ the only non-UB way to do this is *memcpy*. Nearly every other
|
||||
// option is a strict aliasing violation.
|
||||
template<class To, class From>
|
||||
std::enable_if_t<
|
||||
sizeof(To) == sizeof(From),
|
||||
To>
|
||||
bit_cast(const From &src) noexcept
|
||||
{
|
||||
UInt64 buf;
|
||||
memcpy( &buf, a_Value, sizeof( buf));
|
||||
buf = (( ( static_cast<UInt64>(htonl(static_cast<UInt32>(buf)))) << 32) + htonl(buf >> 32));
|
||||
return buf;
|
||||
To dst;
|
||||
std::memcpy(&dst, &src, sizeof(To));
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** Converts a 16-bit host integer or float value to bytes in big-endian (Network) order.
|
||||
@tparam Value The host 16-bit type (Int16, UInt16). Usually inferred.
|
||||
@param a_Value The input integer or float value.
|
||||
@return The resulting bytes. */
|
||||
template<typename Value, std::enable_if_t<sizeof(Value) == 2, bool> = true>
|
||||
inline Bytes<Value> HostToNetwork(Value a_Value)
|
||||
{
|
||||
UInt16 Bits = bit_cast<UInt16>(a_Value);
|
||||
return
|
||||
{
|
||||
std::byte(Bits >> 8),
|
||||
std::byte(Bits)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline UInt32 HostToNetwork4(const void * a_Value)
|
||||
/** Converts a 32-bit host integer or float value to bytes in big-endian (Network) order.
|
||||
@tparam Value The host 32-bit type (Int32, UInt32, float). Usually inferred.
|
||||
@param a_Value The input integer or float value.
|
||||
@return The resulting bytes. */
|
||||
template<typename Value, std::enable_if_t<sizeof(Value) == 4, bool> = true>
|
||||
inline Bytes<Value> HostToNetwork(Value a_Value)
|
||||
{
|
||||
UInt32 buf;
|
||||
memcpy( &buf, a_Value, sizeof( buf));
|
||||
buf = ntohl( buf);
|
||||
return buf;
|
||||
UInt32 Bits = bit_cast<UInt32>(a_Value);
|
||||
return
|
||||
{
|
||||
std::byte(Bits >> 24),
|
||||
std::byte(Bits >> 16),
|
||||
std::byte(Bits >> 8),
|
||||
std::byte(Bits)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline double NetworkToHostDouble8(const void * a_Value)
|
||||
/** Converts a 64-bit host integer or float value to bytes in big-endian (Network) order.
|
||||
@tparam Value The host 64-bit type (Int64, UInt64, double). Usually inferred.
|
||||
@param a_Value The input integer or float value.
|
||||
@return The resulting bytes. */
|
||||
template<typename Value, std::enable_if_t<sizeof(Value) == 8, bool> = true>
|
||||
inline Bytes<Value> HostToNetwork(Value a_Value)
|
||||
{
|
||||
UInt64 buf = 0;
|
||||
memcpy(&buf, a_Value, 8);
|
||||
buf = ntohll(buf);
|
||||
double x;
|
||||
memcpy(&x, &buf, sizeof(double));
|
||||
return x;
|
||||
UInt64 Bits = bit_cast<UInt64>(a_Value);
|
||||
return
|
||||
{
|
||||
std::byte(Bits >> 56),
|
||||
std::byte(Bits >> 48),
|
||||
std::byte(Bits >> 40),
|
||||
std::byte(Bits >> 32),
|
||||
std::byte(Bits >> 24),
|
||||
std::byte(Bits >> 16),
|
||||
std::byte(Bits >> 8),
|
||||
std::byte(Bits)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline Int64 NetworkToHostLong8(const void * a_Value)
|
||||
/** Reads a 16-bit integer or float value from big-endian (Network) bytes.
|
||||
@tparam Value The desired 16-bit type (Int16, UInt16)
|
||||
@param a_Value The input bytes.
|
||||
@return The resulting integer or float value. */
|
||||
template<typename Value, std::enable_if_t<sizeof(Value) == 2, bool> = true>
|
||||
inline Value NetworkToHost(Bytes<Value> a_Value)
|
||||
{
|
||||
UInt64 buf;
|
||||
memcpy(&buf, a_Value, 8);
|
||||
buf = ntohll(buf);
|
||||
return *reinterpret_cast<Int64 *>(&buf);
|
||||
UInt16 val = UInt16(
|
||||
UInt16(a_Value[0]) << 8 |
|
||||
UInt16(a_Value[1]));
|
||||
return bit_cast<Value>(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline UInt64 NetworkToHostULong8(const void * a_Value)
|
||||
/** Reads a 32-bit integer or float value from big-endian (Network) bytes.
|
||||
@tparam Value The desired 32-bit type (Int32, UInt32, float)
|
||||
@param a_Value The input bytes.
|
||||
@return The resulting integer or float value. */
|
||||
template<typename Value, std::enable_if_t<sizeof(Value) == 4, bool> = true>
|
||||
inline Value NetworkToHost(Bytes<Value> a_Value)
|
||||
{
|
||||
UInt64 buf;
|
||||
memcpy(&buf, a_Value, 8);
|
||||
buf = ntohll(buf);
|
||||
return buf;
|
||||
UInt32 val = UInt32(
|
||||
UInt32(a_Value[0]) << 24 |
|
||||
UInt32(a_Value[1]) << 16 |
|
||||
UInt32(a_Value[2]) << 8 |
|
||||
UInt32(a_Value[3]));
|
||||
return bit_cast<Value>(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline float NetworkToHostFloat4(const void * a_Value)
|
||||
/** Reads a 64-bit integer or float value from big-endian (Network) bytes.
|
||||
@tparam Value The desired 64-bit type (Int64, UInt64, double)
|
||||
@param a_Value The input bytes.
|
||||
@return The resulting integer or float value. */
|
||||
template<typename Value, std::enable_if_t<sizeof(Value) == 8, bool> = true>
|
||||
inline Value NetworkToHost(Bytes<Value> a_Value)
|
||||
{
|
||||
UInt32 buf;
|
||||
float x;
|
||||
memcpy(&buf, a_Value, 4);
|
||||
buf = ntohl(buf);
|
||||
memcpy(&x, &buf, sizeof(float));
|
||||
return x;
|
||||
UInt64 val = UInt64(
|
||||
UInt64(a_Value[0]) << 56 |
|
||||
UInt64(a_Value[1]) << 48 |
|
||||
UInt64(a_Value[2]) << 40 |
|
||||
UInt64(a_Value[3]) << 32 |
|
||||
UInt64(a_Value[4]) << 24 |
|
||||
UInt64(a_Value[5]) << 16 |
|
||||
UInt64(a_Value[6]) << 8 |
|
||||
UInt64(a_Value[7]));
|
||||
return bit_cast<Value>(val);
|
||||
}
|
||||
|
||||
/** Reads an integer or float type from its big-endian (Network) bytes.
|
||||
@tparam Value The desired result type (Int16 / 32 / 64, UInt16 / 32 / 64, float, double).
|
||||
@param a_Mem A pointer to the first input byte. Length is inferred from the result type.
|
||||
@return The resulting integer or float value.
|
||||
|
||||
|
||||
|
||||
Consider using NetworkToHost when the data is owned since it provides additional type safety (length is known). */
|
||||
template<typename Value>
|
||||
inline Value NetworkBufToHost(const std::byte* a_Mem)
|
||||
{
|
||||
// Copy unfortunately needed to add the length information required by the rest of the API.
|
||||
// Gets completely optimised out in my testing.
|
||||
Bytes<Value> bytes;
|
||||
std::copy(a_Mem, a_Mem + sizeof(Value), bytes.begin());
|
||||
return NetworkToHost<Value>(bytes);
|
||||
}
|
||||
|
@ -5,13 +5,9 @@
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include "Endianness.h"
|
||||
#include "fmt/printf.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Under MSVC, link to WinSock2 (needed by RawBEToUTF8's byteswapping)
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@ -339,13 +335,14 @@ void ReplaceURL(AString & iHayStack, const AString & iNeedle, const AString & iR
|
||||
|
||||
|
||||
|
||||
AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8)
|
||||
AString & RawBEUTF16ToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8)
|
||||
{
|
||||
a_UTF8.clear();
|
||||
a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size
|
||||
for (size_t i = 0; i < a_NumShorts; i++)
|
||||
{
|
||||
a_UTF8.append(UnicodeCharToUtf8(GetBEUShort(&a_RawData[i * 2])));
|
||||
auto UTF16 = NetworkBufToHost<UInt16>(reinterpret_cast<const std::byte *>(&a_RawData[i * 2]));
|
||||
a_UTF8.append(UnicodeCharToUtf8(UTF16));
|
||||
}
|
||||
return a_UTF8;
|
||||
}
|
||||
@ -946,54 +943,6 @@ AString Base64Encode(const AString & a_Input)
|
||||
|
||||
|
||||
|
||||
short GetBEShort(const std::byte * const a_Mem)
|
||||
{
|
||||
return static_cast<short>(
|
||||
(static_cast<short>(a_Mem[0]) << 8) |
|
||||
static_cast<short>(a_Mem[1])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned short GetBEUShort(const char * a_Mem)
|
||||
{
|
||||
const Byte * Bytes = reinterpret_cast<const Byte *>(a_Mem);
|
||||
return static_cast<unsigned short>((Bytes[0] << 8) | Bytes[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int GetBEInt(const std::byte * const a_Mem)
|
||||
{
|
||||
return
|
||||
(static_cast<int>(a_Mem[0]) << 24) |
|
||||
(static_cast<int>(a_Mem[1]) << 16) |
|
||||
(static_cast<int>(a_Mem[2]) << 8) |
|
||||
static_cast<int>(a_Mem[3])
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SetBEInt(std::byte * a_Mem, Int32 a_Value)
|
||||
{
|
||||
a_Mem[0] = std::byte(a_Value >> 24);
|
||||
a_Mem[1] = std::byte((a_Value >> 16) & 0xff);
|
||||
a_Mem[2] = std::byte((a_Value >> 8) & 0xff);
|
||||
a_Mem[3] = std::byte(a_Value & 0xff);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output)
|
||||
{
|
||||
a_Output.clear();
|
||||
|
@ -67,7 +67,7 @@ extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AS
|
||||
extern void ReplaceURL(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith);
|
||||
|
||||
/** Converts a stream of BE shorts into UTF-8 string; returns a_UTF8. */
|
||||
extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8);
|
||||
extern AString & RawBEUTF16ToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8);
|
||||
|
||||
/** Converts a unicode character to its UTF8 representation. */
|
||||
extern AString UnicodeCharToUtf8(unsigned a_UnicodeChar);
|
||||
@ -101,18 +101,6 @@ extern AString Base64Decode(const AString & a_Base64String); // Exported manual
|
||||
/** Encodes a string into Base64 */
|
||||
extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter
|
||||
|
||||
/** Reads two bytes from the specified memory location and interprets them as BigEndian short */
|
||||
extern short GetBEShort(const std::byte * a_Mem);
|
||||
|
||||
/** Reads two bytes from the specified memory location and interprets them as BigEndian unsigned short */
|
||||
extern unsigned short GetBEUShort(const char * a_Mem);
|
||||
|
||||
/** Reads four bytes from the specified memory location and interprets them as BigEndian int */
|
||||
extern int GetBEInt(const std::byte * a_Mem);
|
||||
|
||||
/** Writes four bytes to the specified memory location so that they interpret as BigEndian int */
|
||||
extern void SetBEInt(std::byte * a_Mem, Int32 a_Value);
|
||||
|
||||
/** Splits a string that has embedded \0 characters, on those characters.
|
||||
a_Output is first cleared and then each separate string is pushed back into a_Output.
|
||||
Returns true if there are at least two strings in a_Output (there was at least one \0 separator). */
|
||||
|
@ -189,7 +189,7 @@ eNBTParseError cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringL
|
||||
{
|
||||
NEEDBYTES(2, eNBTParseError::npStringMissingLength);
|
||||
a_StringStart = m_Pos + 2;
|
||||
a_StringLen = static_cast<size_t>(GetBEShort(m_Data.data() + m_Pos));
|
||||
a_StringLen = static_cast<size_t>(NetworkBufToHost<UInt16>(m_Data.data() + m_Pos));
|
||||
NEEDBYTES(2 + a_StringLen, eNBTParseError::npStringInvalidLength);
|
||||
m_Pos += 2 + a_StringLen;
|
||||
return eNBTParseError::npSuccess;
|
||||
@ -247,7 +247,7 @@ eNBTParseError cParsedNBT::ReadList(eTagType a_ChildrenType)
|
||||
|
||||
// Read the count:
|
||||
NEEDBYTES(4, eNBTParseError::npListMissingLength);
|
||||
int Count = GetBEInt(m_Data.data() + m_Pos);
|
||||
int Count = NetworkBufToHost<int>(m_Data.data() + m_Pos);
|
||||
m_Pos += 4;
|
||||
auto MinChildSize = GetMinTagSize(a_ChildrenType);
|
||||
if ((Count < 0) || (Count > static_cast<int>((m_Data.size() - m_Pos) / MinChildSize)))
|
||||
@ -311,7 +311,7 @@ eNBTParseError cParsedNBT::ReadTag(void)
|
||||
case TAG_ByteArray:
|
||||
{
|
||||
NEEDBYTES(4, eNBTParseError::npArrayMissingLength);
|
||||
int len = GetBEInt(m_Data.data() + m_Pos);
|
||||
int len = NetworkBufToHost<int>(m_Data.data() + m_Pos);
|
||||
m_Pos += 4;
|
||||
if (len < 0)
|
||||
{
|
||||
@ -343,7 +343,7 @@ eNBTParseError cParsedNBT::ReadTag(void)
|
||||
case TAG_IntArray:
|
||||
{
|
||||
NEEDBYTES(4, eNBTParseError::npArrayMissingLength);
|
||||
int len = GetBEInt(m_Data.data() + m_Pos);
|
||||
int len = NetworkBufToHost<int>(m_Data.data() + m_Pos);
|
||||
m_Pos += 4;
|
||||
if (len < 0)
|
||||
{
|
||||
@ -539,7 +539,8 @@ void cFastNBTWriter::EndList(void)
|
||||
ASSERT(m_Stack[m_CurrentStack].m_Type == TAG_List);
|
||||
|
||||
// Update the list count:
|
||||
SetBEInt(m_Result.data() + m_Stack[m_CurrentStack].m_Pos, m_Stack[m_CurrentStack].m_Count);
|
||||
auto Value = HostToNetwork(m_Stack[m_CurrentStack].m_Count);
|
||||
std::copy(Value.begin(), Value.end(), m_Result.data() + m_Stack[m_CurrentStack].m_Pos);
|
||||
|
||||
--m_CurrentStack;
|
||||
}
|
||||
@ -561,8 +562,8 @@ void cFastNBTWriter::AddByte(const AString & a_Name, unsigned char a_Value)
|
||||
void cFastNBTWriter::AddShort(const AString & a_Name, Int16 a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_Short);
|
||||
UInt16 Value = htons(static_cast<UInt16>(a_Value));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Value), 2);
|
||||
auto Value = HostToNetwork(a_Value);
|
||||
m_Result.append(Value.begin(), Value.end());
|
||||
}
|
||||
|
||||
|
||||
@ -572,8 +573,8 @@ void cFastNBTWriter::AddShort(const AString & a_Name, Int16 a_Value)
|
||||
void cFastNBTWriter::AddInt(const AString & a_Name, Int32 a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_Int);
|
||||
UInt32 Value = htonl(static_cast<UInt32>(a_Value));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Value), 4);
|
||||
auto Value = HostToNetwork(a_Value);
|
||||
m_Result.append(Value.begin(), Value.end());
|
||||
}
|
||||
|
||||
|
||||
@ -583,8 +584,8 @@ void cFastNBTWriter::AddInt(const AString & a_Name, Int32 a_Value)
|
||||
void cFastNBTWriter::AddLong(const AString & a_Name, Int64 a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_Long);
|
||||
UInt64 Value = HostToNetwork8(&a_Value);
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Value), 8);
|
||||
auto Value = HostToNetwork(a_Value);
|
||||
m_Result.append(Value.begin(), Value.end());
|
||||
}
|
||||
|
||||
|
||||
@ -594,8 +595,8 @@ void cFastNBTWriter::AddLong(const AString & a_Name, Int64 a_Value)
|
||||
void cFastNBTWriter::AddFloat(const AString & a_Name, float a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_Float);
|
||||
UInt32 Value = HostToNetwork4(&a_Value);
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Value), 4);
|
||||
auto Value = HostToNetwork(a_Value);
|
||||
m_Result.append(Value.begin(), Value.end());
|
||||
}
|
||||
|
||||
|
||||
@ -605,8 +606,8 @@ void cFastNBTWriter::AddFloat(const AString & a_Name, float a_Value)
|
||||
void cFastNBTWriter::AddDouble(const AString & a_Name, double a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_Double);
|
||||
UInt64 Value = HostToNetwork8(&a_Value);
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Value), 8);
|
||||
auto Value = HostToNetwork(a_Value);
|
||||
m_Result.append(Value.begin(), Value.end());
|
||||
}
|
||||
|
||||
|
||||
@ -616,8 +617,8 @@ void cFastNBTWriter::AddDouble(const AString & a_Name, double a_Value)
|
||||
void cFastNBTWriter::AddString(const AString & a_Name, const std::string_view a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_String);
|
||||
const UInt16 Length = htons(static_cast<UInt16>(a_Value.size()));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Length), sizeof(Length));
|
||||
auto Length = HostToNetwork(static_cast<UInt16>(a_Value.size()));
|
||||
m_Result.append(Length.begin(), Length.end());
|
||||
m_Result.append({ reinterpret_cast<const std::byte *>(a_Value.data()), a_Value.size() });
|
||||
}
|
||||
|
||||
@ -628,8 +629,8 @@ void cFastNBTWriter::AddString(const AString & a_Name, const std::string_view a_
|
||||
void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements)
|
||||
{
|
||||
TagCommon(a_Name, TAG_ByteArray);
|
||||
UInt32 len = htonl(static_cast<UInt32>(a_NumElements));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&len), 4);
|
||||
auto Length = HostToNetwork(static_cast<UInt32>(a_NumElements));
|
||||
m_Result.append(Length.begin(), Length.end());
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(a_Value), a_NumElements);
|
||||
}
|
||||
|
||||
@ -640,8 +641,8 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value,
|
||||
void cFastNBTWriter::AddByteArray(const AString & a_Name, size_t a_NumElements, unsigned char a_Value)
|
||||
{
|
||||
TagCommon(a_Name, TAG_ByteArray);
|
||||
UInt32 len = htonl(static_cast<UInt32>(a_NumElements));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&len), 4);
|
||||
auto Length = HostToNetwork(static_cast<UInt32>(a_NumElements));
|
||||
m_Result.append(Length.begin(), Length.end());
|
||||
m_Result.append(a_NumElements, std::byte(a_Value));
|
||||
}
|
||||
|
||||
@ -652,18 +653,18 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, size_t a_NumElements,
|
||||
void cFastNBTWriter::AddIntArray(const AString & a_Name, const Int32 * a_Value, size_t a_NumElements)
|
||||
{
|
||||
TagCommon(a_Name, TAG_IntArray);
|
||||
UInt32 len = htonl(static_cast<UInt32>(a_NumElements));
|
||||
auto Length = HostToNetwork(static_cast<UInt32>(a_NumElements));
|
||||
size_t cap = m_Result.capacity();
|
||||
size_t size = m_Result.length();
|
||||
if ((cap - size) < (4 + a_NumElements * 4))
|
||||
{
|
||||
m_Result.reserve(size + 4 + (a_NumElements * 4));
|
||||
}
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&len), sizeof(len));
|
||||
m_Result.append(Length.begin(), Length.end());
|
||||
for (size_t i = 0; i < a_NumElements; i++)
|
||||
{
|
||||
UInt32 Element = htonl(static_cast<UInt32>(a_Value[i]));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Element), sizeof(Element));
|
||||
auto Element = HostToNetwork(a_Value[i]);
|
||||
m_Result.append(Element.begin(), Element.end());
|
||||
}
|
||||
}
|
||||
|
||||
@ -684,7 +685,7 @@ void cFastNBTWriter::Finish(void)
|
||||
void cFastNBTWriter::WriteString(const std::string_view a_Data)
|
||||
{
|
||||
// TODO check size <= short max
|
||||
UInt16 Len = htons(static_cast<unsigned short>(a_Data.size()));
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(&Len), sizeof(Len));
|
||||
auto Length = HostToNetwork(static_cast<UInt16>(a_Data.size()));
|
||||
m_Result.append(Length.begin(), Length.end());
|
||||
m_Result.append(reinterpret_cast<const std::byte *>(a_Data.data()), a_Data.size());
|
||||
}
|
||||
|
@ -227,21 +227,21 @@ public:
|
||||
inline Int16 GetShort(int a_Tag) const
|
||||
{
|
||||
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Short);
|
||||
return GetBEShort(GetData(a_Tag));
|
||||
return NetworkBufToHost<Int16>(GetData(a_Tag));
|
||||
}
|
||||
|
||||
/** Returns the value stored in an Int tag. Not valid for any other tag type. */
|
||||
inline Int32 GetInt(int a_Tag) const
|
||||
{
|
||||
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Int);
|
||||
return GetBEInt(GetData(a_Tag));
|
||||
return NetworkBufToHost<Int32>(GetData(a_Tag));
|
||||
}
|
||||
|
||||
/** Returns the value stored in a Long tag. Not valid for any other tag type. */
|
||||
inline Int64 GetLong(int a_Tag) const
|
||||
{
|
||||
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Long);
|
||||
return NetworkToHostLong8(GetData(a_Tag));
|
||||
return NetworkBufToHost<Int64>(GetData(a_Tag));
|
||||
}
|
||||
|
||||
/** Returns the value stored in a Float tag. Not valid for any other tag type. */
|
||||
@ -256,10 +256,7 @@ public:
|
||||
UNUSED_VAR(Check1);
|
||||
UNUSED_VAR(Check2);
|
||||
|
||||
Int32 i = GetBEInt(GetData(a_Tag));
|
||||
float f;
|
||||
memcpy(&f, &i, sizeof(f));
|
||||
return f;
|
||||
return NetworkBufToHost<float>(GetData(a_Tag));
|
||||
}
|
||||
|
||||
/** Returns the value stored in a Double tag. Not valid for any other tag type. */
|
||||
@ -273,7 +270,7 @@ public:
|
||||
UNUSED_VAR(Check2);
|
||||
|
||||
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Double);
|
||||
return NetworkToHostDouble8(GetData(a_Tag));
|
||||
return NetworkBufToHost<double>(GetData(a_Tag));
|
||||
}
|
||||
|
||||
/** Returns the value stored in a String tag. Not valid for any other tag type. */
|
||||
|
@ -108,7 +108,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
|
||||
const auto * ColourData = (a_NBT.GetData(explosiontag));
|
||||
for (size_t i = 0; i < DataLength; i += 4)
|
||||
{
|
||||
a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
|
||||
a_FireworkItem.m_Colours.push_back(NetworkBufToHost<Int32>(ColourData + i));
|
||||
}
|
||||
}
|
||||
else if (ExplosionName == "FadeColors")
|
||||
@ -124,7 +124,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB
|
||||
const auto * FadeColourData = (a_NBT.GetData(explosiontag));
|
||||
for (size_t i = 0; i < DataLength; i += 4)
|
||||
{
|
||||
a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
|
||||
a_FireworkItem.m_FadeColours.push_back(NetworkBufToHost<Int32>(FadeColourData + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -510,7 +510,7 @@ bool cWSSAnvil::LoadHeightMapFromNBT(cChunkDef::HeightMap & a_HeightMap, const c
|
||||
for (int RelX = 0; RelX < cChunkDef::Width; RelX++)
|
||||
{
|
||||
const int Index = 4 * (RelX + RelZ * cChunkDef::Width);
|
||||
const int Height = GetBEInt(HeightData + Index);
|
||||
const int Height = NetworkBufToHost<Int32>(HeightData + Index);
|
||||
|
||||
if (Height > std::numeric_limits<HEIGHTTYPE>::max())
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user