24#ifndef PADS_BINARY_UTILS_H_
25#define PADS_BINARY_UTILS_H_
53inline uint8_t
getU8(
const std::vector<uint8_t>& aData,
size_t aOffset )
55 return aData[aOffset];
59inline uint16_t
getU16LE(
const std::vector<uint8_t>& aData,
size_t aOffset )
61 return static_cast<uint16_t
>( aData[aOffset] )
62 | (
static_cast<uint16_t
>( aData[aOffset + 1] ) << 8 );
66inline uint32_t
getU32LE(
const std::vector<uint8_t>& aData,
size_t aOffset )
68 return static_cast<uint32_t
>( aData[aOffset] )
69 | (
static_cast<uint32_t
>( aData[aOffset + 1] ) << 8 )
70 | (
static_cast<uint32_t
>( aData[aOffset + 2] ) << 16 )
71 | (
static_cast<uint32_t
>( aData[aOffset + 3] ) << 24 );
75inline double getF64LE(
const std::vector<uint8_t>& aData,
size_t aOffset )
79 for(
int i = 0; i < 8; ++i )
80 bits |=
static_cast<uint64_t
>( aData[aOffset + i] ) << ( 8 * i );
83 std::memcpy( &value, &bits,
sizeof( value ) );
89inline float getF32LE(
const std::vector<uint8_t>& aData,
size_t aOffset )
91 uint32_t bits =
getU32LE( aData, aOffset );
93 std::memcpy( &value, &bits,
sizeof( value ) );
104inline bool ReadFileHeader(
const wxString& aFileName, std::vector<uint8_t>& aOut,
size_t aCount )
106 std::ifstream file( aFileName.fn_str(), std::ios::binary );
108 if( !file.is_open() )
111 aOut.resize( aCount );
112 file.read(
reinterpret_cast<char*
>( aOut.data() ),
static_cast<std::streamsize
>( aCount ) );
113 aOut.resize(
static_cast<size_t>( file.gcount() ) );
124 std::ifstream file( aFileName.fn_str(), std::ios::binary | std::ios::ate );
126 if( !file.is_open() )
129 std::streamoff len = file.tellg();
130 file.seekg( 0, std::ios::beg );
135 aOut.resize(
static_cast<size_t>( len ) );
136 file.read(
reinterpret_cast<char*
>( aOut.data() ), len );
138 return file.gcount() == len;
152 if( aOffset >= aData.size() )
155 size_t available = std::min( aMaxLen, aData.size() - aOffset );
156 const uint8_t* start = &aData[aOffset];
158 const uint8_t* null_pos = std::find( start, start + available, 0 );
159 size_t len =
static_cast<size_t>( null_pos - start );
161 for(
size_t i = 0; i < len; ++i )
163 if( start[i] < 0x20 || start[i] == 0x7F )
167 return std::string(
reinterpret_cast<const char*
>( start ), len );
174inline std::string
readFixedString(
const std::vector<uint8_t>& aData,
size_t aOffset,
size_t aMaxLen )
180 while( !raw.empty() && raw.back() ==
' ' )
192inline bool HasSdbMagic(
const std::vector<uint8_t>& aData, uint8_t aMagic1 )
194 return aData.size() >= 2 && aData[0] == 0x00 && aData[1] == aMagic1;
215std::optional<SDB_FOOTER_ERROR>
CheckSdbFooter(
const std::vector<uint8_t>& aData,
size_t aFooterStart,
216 const char* aGuid,
size_t aGuidLen );
223void ValidateSdbFooter(
const std::vector<uint8_t>& aData,
size_t aFooterStart,
const char* aGuid,
244 bool InBounds(
size_t aOffset,
size_t aCount )
const
246 return aOffset <=
m_data.size() && aCount <=
m_data.size() - aOffset;
249 uint8_t
U8At(
size_t aOffset )
const
255 uint16_t
U16At(
size_t aOffset )
const
261 uint32_t
U32At(
size_t aOffset )
const
267 int32_t
I32At(
size_t aOffset )
const {
return static_cast<int32_t
>(
U32At( aOffset ) ); }
269 double F64At(
size_t aOffset )
const
284 std::string
StringAt(
size_t aOffset,
size_t aMaxLen )
const
290 void check(
size_t aOffset,
size_t aCount )
const
294 THROW_IO_ERROR( wxString::Format(
"PADS binary read out of bounds at offset %zu (file size %zu)",
295 aOffset,
m_data.size() ) );
324 std::string
Str(
size_t aOffset,
size_t aMaxLen )
const
Bounds-checked little-endian read cursor over a PADS binary buffer.
std::string StringAt(size_t aOffset, size_t aMaxLen) const
int32_t I32At(size_t aOffset) const
float F32At(size_t aOffset) const
BINARY_CURSOR(const std::vector< uint8_t > &aData)
uint8_t U8At(size_t aOffset) const
const std::vector< uint8_t > & m_data
double F64At(size_t aOffset) const
uint16_t U16At(size_t aOffset) const
bool InBounds(size_t aOffset, size_t aCount) const
void check(size_t aOffset, size_t aCount) const
uint32_t U32At(size_t aOffset) const
uint32_t U32(size_t aOffset) const
uint8_t U8(size_t aOffset) const
uint16_t U16(size_t aOffset) const
const BINARY_CURSOR & m_cursor
int32_t I32(size_t aOffset) const
double F64(size_t aOffset) const
SDB_RECORD(const BINARY_CURSOR &aCursor, size_t aBase)
std::string Str(size_t aOffset, size_t aMaxLen) const
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
bool ReadFileHeader(const wxString &aFileName, std::vector< uint8_t > &aOut, size_t aCount)
Read at most aCount leading bytes of aFileName into aOut, which is sized to what was actually read.
bool HasSdbMagic(const std::vector< uint8_t > &aData, uint8_t aMagic1)
Check the PADS SDB container magic, a leading 0x00 followed by a format-specific second byte.
constexpr uint16_t SDB_RECORD_SENTINEL
constexpr double SDB_BASIC_PER_MIL
uint8_t getU8(const std::vector< uint8_t > &aData, size_t aOffset)
Little-endian byte assembly with no bounds checking.
std::optional< SDB_FOOTER_ERROR > CheckSdbFooter(const std::vector< uint8_t > &aData, size_t aFooterStart, const char *aGuid, size_t aGuidLen)
Check a PADS SDB footer at aFooterStart: the ASCII GUID followed by an absolute back-pointer to the s...
float getF32LE(const std::vector< uint8_t > &aData, size_t aOffset)
uint32_t getU32LE(const std::vector< uint8_t > &aData, size_t aOffset)
bool ReadFileToBuffer(const wxString &aFileName, std::vector< uint8_t > &aOut)
Read an entire file into aOut.
void ValidateSdbFooter(const std::vector< uint8_t > &aData, size_t aFooterStart, const char *aGuid, size_t aGuidLen)
As CheckSdbFooter, throwing a bare IO_ERROR on failure.
uint16_t getU16LE(const std::vector< uint8_t > &aData, size_t aOffset)
std::string readFixedStringRaw(const std::vector< uint8_t > &aData, size_t aOffset, size_t aMaxLen)
Read a NUL-terminated fixed-width field starting at aOffset, scanning at most aMaxLen bytes,...
std::string readFixedString(const std::vector< uint8_t > &aData, size_t aOffset, size_t aMaxLen)
As readFixedStringRaw, then trim trailing spaces.
double getF64LE(const std::vector< uint8_t > &aData, size_t aOffset)