Skip to content

Commit

Permalink
Update binaryread, binarywrite to depend on celcompat/bit.h
Browse files Browse the repository at this point in the history
- Add fromMemory* methods for buffered read support
- Use new fromMemory* methods in stardb.cpp
  • Loading branch information
ajtribick committed Jun 2, 2024
1 parent 1b33de3 commit f6e6098
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 209 deletions.
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,6 @@ else()
message(WARNING "C++ charconv is unusable!\nWill use own implementation.")
endif()

include(TestBigEndian)
test_big_endian(WORDS_BIGENDIAN)

configure_file("config.h.in" "config.h")
configure_file("celestia.cfg.in" "celestia.cfg")

Expand Down
1 change: 0 additions & 1 deletion config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#cmakedefine HAVE_SINCOS
#cmakedefine HAVE_APPLE_SINCOS
#cmakedefine HAVE_CONSTEXPR_EMPTY_ARRAY
#cmakedefine WORDS_BIGENDIAN

#ifdef HAVE_CONSTEXPR_CMATH
#define CELESTIA_CMATH_CONSTEXPR constexpr
Expand Down
64 changes: 12 additions & 52 deletions src/celengine/stardb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <fmt/format.h>

#include <celcompat/bit.h>
#include <celcompat/charconv.h>
#include <celcompat/numbers.h>
#include <celutil/binaryread.h>
#include <celutil/fsutils.h>
#include <celutil/gettext.h>
#include <celutil/logger.h>
Expand Down Expand Up @@ -106,46 +106,6 @@ constexpr inline AstroCatalog::IndexNumber TYC3_MAX = 3u; // from TYC2
constexpr inline AstroCatalog::IndexNumber TDSC_TYC3_MAX = 4u;
constexpr inline AstroCatalog::IndexNumber TDSC_TYC3_MAX_RANGE_TYC1 = 2907u;


template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
T
readIntLE(const char* src)
{
using celestia::compat::byteswap;
using celestia::compat::endian;

T result;
std::memcpy(&result, src, sizeof(T));
if constexpr (endian::native == endian::little)
return result;
else
return celestia::compat::byteswap(result);
}


float
readFloatLE(const char* src)
{
using celestia::compat::byteswap;
using celestia::compat::endian;
float result;
if constexpr (endian::native == endian::little)
{
std::memcpy(&result, src, sizeof(float));
}
else
{
static_assert(sizeof(std::uint32_t) == sizeof(float));
std::uint32_t temp;
std::memcpy(&temp, src, sizeof(float));
temp = byteswap(temp);
std::memcpy(&result, &temp, sizeof(float));
}

return result;
}


#pragma pack(push, 1)
// stars.dat header structure
struct StarsDatHeader
Expand Down Expand Up @@ -716,14 +676,14 @@ StarDatabaseBuilder::loadBinary(std::istream& in)

// Verify the version

if (auto version = readIntLE<std::uint16_t>(header.data() + offsetof(StarsDatHeader, version));
if (auto version = util::fromMemoryLE<std::uint16_t>(header.data() + offsetof(StarsDatHeader, version));
version != StarDBVersion)
{
return false;
}

// Read the star count
nStarsInFile = readIntLE<std::uint32_t>(header.data() + offsetof(StarsDatHeader, counter));
nStarsInFile = util::fromMemoryLE<std::uint32_t>(header.data() + offsetof(StarsDatHeader, counter));
}

constexpr std::uint32_t BUFFER_RECORDS = UINT32_C(4096) / sizeof(StarsDatRecord);
Expand All @@ -738,12 +698,12 @@ StarDatabaseBuilder::loadBinary(std::istream& in)
const char* ptr = buffer.data();
for (std::uint32_t i = 0; i < recordsToRead; ++i)
{
auto catNo = readIntLE<AstroCatalog::IndexNumber>(ptr + offsetof(StarsDatRecord, catNo));
float x = readFloatLE(ptr + offsetof(StarsDatRecord, x));
float y = readFloatLE(ptr + offsetof(StarsDatRecord, y));
float z = readFloatLE(ptr + offsetof(StarsDatRecord, z));
auto absMag = readIntLE<std::int16_t>(ptr + offsetof(StarsDatRecord, absMag));
auto spectralType = readIntLE<std::uint16_t>(ptr + offsetof(StarsDatRecord, spectralType));
auto catNo = util::fromMemoryLE<AstroCatalog::IndexNumber>(ptr + offsetof(StarsDatRecord, catNo));
auto x = util::fromMemoryLE<float>(ptr + offsetof(StarsDatRecord, x));
auto y = util::fromMemoryLE<float>(ptr + offsetof(StarsDatRecord, y));
auto z = util::fromMemoryLE<float>(ptr + offsetof(StarsDatRecord, z));
auto absMag = util::fromMemoryLE<std::int16_t>(ptr + offsetof(StarsDatRecord, absMag));
auto spectralType = util::fromMemoryLE<std::uint16_t>(ptr + offsetof(StarsDatRecord, spectralType));

Star star;
star.setPosition(x, y, z);
Expand Down Expand Up @@ -1070,7 +1030,7 @@ StarDatabaseBuilder::loadCrossIndex(StarCatalog catalog, std::istream& in)
}

// Verify the version
auto version = readIntLE<std::uint16_t>(header.data() + offsetof(CrossIndexHeader, version));
auto version = util::fromMemoryLE<std::uint16_t>(header.data() + offsetof(CrossIndexHeader, version));
if (version != CrossIndexVersion)
{
GetLogger()->error(_("Bad version for cross index\n"));
Expand Down Expand Up @@ -1115,8 +1075,8 @@ StarDatabaseBuilder::loadCrossIndex(StarCatalog catalog, std::istream& in)
while (remainingRecords-- > 0)
{
StarDatabase::CrossIndexEntry& ent = xindex.emplace_back();
ent.catalogNumber = readIntLE<AstroCatalog::IndexNumber>(ptr + offsetof(CrossIndexRecord, catalogNumber));
ent.celCatalogNumber = readIntLE<AstroCatalog::IndexNumber>(ptr + offsetof(CrossIndexRecord, celCatalogNumber));
ent.catalogNumber = util::fromMemoryLE<AstroCatalog::IndexNumber>(ptr + offsetof(CrossIndexRecord, catalogNumber));
ent.celCatalogNumber = util::fromMemoryLE<AstroCatalog::IndexNumber>(ptr + offsetof(CrossIndexRecord, celCatalogNumber));
ptr += sizeof(CrossIndexRecord);
}
}
Expand Down
156 changes: 81 additions & 75 deletions src/celutil/binaryread.h
Original file line number Diff line number Diff line change
@@ -1,122 +1,128 @@
#pragma once

#include <array>
#include <cstddef>
#include <cstring>
#include <istream>
#include <type_traits>
#include <utility>

#include <config.h>

#include <celcompat/bit.h>

namespace celestia::util
{

/*! Read a value stored in machine-native byte order from an input stream.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool readNative(std::istream& in, T& value)
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline bool
readNative(std::istream& in, T& value)
{
char data[sizeof(T)];
if (!in.read(data, sizeof(T)).good()) { return false; }
std::memcpy(&value, data, sizeof(T));
return true;
return in.read(reinterpret_cast<char*>(&value), sizeof(T)).good(); /* Flawfinder: ignore */ //NOSONAR
}

template<>
inline bool readNative<char>(std::istream& in, char& value)
/*! Read a value stored in machine-native byte order from memory.
*/
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline T
fromMemoryNative(const void* src) //NOSONAR
{
return in.get(value).good();
T value;
std::memcpy(&value, src, sizeof(T));
return value;
}

template<>
inline bool readNative<signed char>(std::istream& in, signed char& value)
/*! Read a value stored opposite to machine-native byte order from an input stream.
*/
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline bool
readReversed(std::istream& in, T& value)
{
char c;
if (!in.get(c).good()) { return false; }
value = static_cast<signed char>(c);
return true;
}
if constexpr (sizeof(T) == 1)
return readNative(in, value);

template<>
inline bool readNative<unsigned char>(std::istream& in, unsigned char& value)
{
char c;
if (!in.get(c).good()) { return false; }
value = static_cast<unsigned char>(c);
return true;
}
std::array<char, sizeof(T)> temp;
if (!in.read(temp.data(), sizeof(T)).good()) /* Flawfinder: ignore */
return false;

constexpr auto halfSize = sizeof(T) / 2;
for (std::size_t i = 0; i < halfSize; ++i)
std::swap(temp[i], temp[sizeof(T) - i - 1]);

/*! Read a value stored opposite to machine-native byte order from an input stream
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool readReversed(std::istream& in, T& value)
{
char data[sizeof(T)];
if (!in.read(data, sizeof(T)).good()) { return false; }
for (std::size_t i = 0; i < sizeof(T) / 2; ++i)
{
std::swap(data[i], data[sizeof(T) - i - 1]);
}

std::memcpy(&value, data, sizeof(T));
std::memcpy(&value, temp.data(), sizeof(T));
return true;
}

template<>
inline bool readReversed<char>(std::istream& in, char& value)
{
return readNative(in, value);
}

template<>
inline bool readReversed<signed char>(std::istream& in, signed char& value)
{
return readNative(in, value);
}

template<>
inline bool readReversed<unsigned char>(std::istream& in, unsigned char& value)
/*! Read a value stored opposite to machine-native byte order from memory.
*/
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline T
fromMemoryReversed(const void* src) //NOSONAR
{
return readNative(in, value);
if constexpr (sizeof(T) == 1)
return fromMemoryNative<T>(src);

std::array<std::byte, sizeof(T)> temp;
std::memcpy(temp.data(), src, sizeof(T));
constexpr auto halfSize = sizeof(T) / 2;
for (std::size_t i = 0; i < halfSize; ++i)
std::swap(temp[i], temp[sizeof(T) - i - 1]);

T value;
std::memcpy(&value, temp.data(), sizeof(T));
return value;
}

#ifdef WORDS_BIGENDIAN

/*! Read a value stored in little-endian byte order from an input stream.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool readLE(std::istream& in, T& value)
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline bool
readLE(std::istream& in, T& value)
{
return readReversed(in, value);
using celestia::compat::endian;
if constexpr (endian::native == endian::little)
return readNative(in, value);
else
return readReversed(in, value);
}

/*! Read a value stored in big-endian byte order from an input stream.
/*! Read a value stored in little-endian byte order from memory.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool readBE(std::istream& in, T& value)
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline T
fromMemoryLE(const void* src) //NOSONAR
{
return readNative(in, value);
using celestia::compat::endian;
if constexpr (endian::native == endian::little)
return fromMemoryNative<T>(src);
else
return fromMemoryReversed<T>(src);
}

#else

/*! Read a value stored in little-endian byte order from an input stream.
/*! Read a value stored in big-endian byte order from an input stream.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool readLE(std::istream& in, T& value)
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline bool
readBE(std::istream& in, T& value)
{
return readNative(in, value);
using celestia::compat::endian;
if constexpr (endian::native == endian::little)
return readReversed(in, value);
else
return readNative(in, value);
}

/*! Read a value stored in big-endian byte order from an input stream.
/*! Read a value stored in big-endian byte order from memory.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool readBE(std::istream& in, T& value)
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
inline T
fromMemoryBE(const void* src) //NOSONAR
{
return readReversed(in, value);
using celestia::compat::endian;
if constexpr (endian::native == endian::little)
return fromMemoryReversed<T>(src);
else
return fromMemoryNative<T>(src);
}

#endif

} // end namespace celestia::util
Loading

0 comments on commit f6e6098

Please sign in to comment.