Skip to content

Commit

Permalink
[tz::core] added tz::big_endian<T> and tz::little_endian<T> aswell as…
Browse files Browse the repository at this point in the history
… a documentation pass over the new endian code
  • Loading branch information
harrand committed Sep 23, 2023
1 parent 1589b1e commit ab006a3
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 30 deletions.
73 changes: 73 additions & 0 deletions src/tz/core/endian.hpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,90 @@
#ifndef TOPAZ_CORE_ENDIAN_HPP
#define TOPAZ_CORE_ENDIAN_HPP
#include <concepts>

namespace tz
{
/**
* @ingroup tz_core
* Indicates the endianness of scalar types.
**/
enum class endian
{
/// Little Endian
little,
/// Big Endian
big
};

/**
* @ingroup tz_core
* Query the endianness of the running machine.
* @return `endian::little` if machine is little-endian, or `endian::big` otherwise.
**/
endian get_local_machine_endianness();
/**
* @ingroup tz_core
* Query as to whether the current system is big-endian.
* @note Equivalent to `tz::get_local_machine_endianness() == endian::big`
**/
bool is_big_endian();
/**
* @ingroup tz_core
* Query as to whether the current system is littel-endian.
* @note Equivalent to `tz::get_local_machine_endianness() == endian::little`
**/
bool is_little_endian();

/**
* @ingroup tz_core
* Given an integral type, make a copy of the value, swap its bytes, and then return it.
* If the value for example is little-endian, then the result will be its big-endian variant.
* @param value Value to byte swap.
* @return Copy of value, with endianness swapped.
**/
template<std::integral T>
T endian_byte_swap(T value)
{
char* bytes = reinterpret_cast<char*>(&value);
std::size_t sz = sizeof(T);
for(std::size_t i = 0; i < sz / 2; i++)
{
std::swap(bytes[i], bytes[sz - i - 1]);
}
return value;
}

/**
* @ingroup tz_core
* Retrieve a scalar value in big-endian form. If the system is detected to be big-endian, the value is unchanged.
* @param value The value to ensure is big-endian.
* @return Byte-swap of the value if the system is little-endian, otherwise the same value.
**/
template<std::integral T>
T big_endian(T value)
{
if(is_big_endian())
{
return value;
}
return endian_byte_swap(value);
}

/**
* @ingroup tz_core
* Retrieve a scalar value in little-endian form. If the system is detected to be little-endian, the value is unchanged.
* @param value The value to ensure is little-endian.
* @return Byte-swap of the value if the system is big-endian, otherwise the same value.
**/
template<std::integral T>
T little_endian(T value)
{
if(is_little_endian())
{
return value;
}
return endian_byte_swap(value);
}
}

#endif // TOPAZ_CORE_ENDIAN_HPP
39 changes: 9 additions & 30 deletions src/tz/io/ttf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,18 @@ namespace tz::io
this->parse_table_info(ttf_minus_header, ttf_data);
}

std::uint32_t big_endian(std::uint32_t value) {
if(tz::is_big_endian())
{
return value;
}
return ((value >> 24) & 0x000000FF) | // Move the first byte to the last position
((value >> 8) & 0x0000FF00) | // Move the second byte to the second position
((value << 8) & 0x00FF0000) | // Move the third byte to the third position
((value << 24) & 0xFF000000); // Move the last byte to the first position
}

std::uint16_t big_endian(std::uint16_t value)
{
if(tz::is_big_endian())
{
return value;
}
return ((value >> 8) & 0x00FF) | // Swap the high byte and low byte
((value << 8) & 0xFF00);
}

std::string_view ttf::parse_header(std::string_view str)
{
const char* ptr = str.data();
this->header.scalar_type = big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
this->header.scalar_type = tz::big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
ptr += sizeof(std::uint32_t);
this->header.num_tables = big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
this->header.num_tables = tz::big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
ptr += sizeof(std::uint16_t);
this->header.search_range = big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
this->header.search_range = tz::big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
ptr += sizeof(std::uint16_t);
this->header.entry_selector = big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
this->header.entry_selector = tz::big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
ptr += sizeof(std::uint16_t);
this->header.range_shift = big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
this->header.range_shift = tz::big_endian(*reinterpret_cast<const std::uint16_t*>(ptr));
ptr += sizeof(std::uint16_t);

auto byte_diff = std::distance(str.data(), ptr);
Expand All @@ -80,11 +59,11 @@ namespace tz::io
ttf_table& tbl = this->tables.emplace_back();
std::memcpy(tbl.tag, ptr, 4);
ptr += 4;
tbl.checksum = big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
tbl.checksum = tz::big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
ptr += sizeof(std::uint32_t);
tbl.offset = big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
tbl.offset = tz::big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
ptr += sizeof(std::uint32_t);
tbl.length = big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
tbl.length = tz::big_endian(*reinterpret_cast<const std::uint32_t*>(ptr));
ptr += sizeof(std::uint32_t);

if(tbl.tag[0] != 'h' || tbl.tag[1] != 'e' || tbl.tag[2] != 'a' || tbl.tag[3] != 'd')
Expand All @@ -100,7 +79,7 @@ namespace tz::io
std::uint32_t sum = 0u;
for(std::size_t i = 0; i < length; i += sizeof(std::uint32_t))
{
sum += big_endian(*reinterpret_cast<const std::uint32_t*>(data.data() + offset + i));
sum += tz::big_endian(*reinterpret_cast<const std::uint32_t*>(data.data() + offset + i));
}
return sum;
}
Expand Down

0 comments on commit ab006a3

Please sign in to comment.