openpilot v0.9.6 release
date: 2024-01-12T10:13:37 master commit: ba792d576a49a0899b88a753fa1c52956bedf9e6
This commit is contained in:
16
third_party/kaitai/custom_decoder.h
vendored
Normal file
16
third_party/kaitai/custom_decoder.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef KAITAI_CUSTOM_DECODER_H
|
||||
#define KAITAI_CUSTOM_DECODER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace kaitai {
|
||||
|
||||
class custom_decoder {
|
||||
public:
|
||||
virtual ~custom_decoder() {};
|
||||
virtual std::string decode(std::string src) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
189
third_party/kaitai/exceptions.h
vendored
Normal file
189
third_party/kaitai/exceptions.h
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
#ifndef KAITAI_EXCEPTIONS_H
|
||||
#define KAITAI_EXCEPTIONS_H
|
||||
|
||||
#include <kaitai/kaitaistream.h>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
// We need to use "noexcept" in virtual destructor of our exceptions
|
||||
// subclasses. Different compilers have different ideas on how to
|
||||
// achieve that: C++98 compilers prefer `throw()`, C++11 and later
|
||||
// use `noexcept`. We define KS_NOEXCEPT macro for that.
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
#define KS_NOEXCEPT noexcept
|
||||
#else
|
||||
#define KS_NOEXCEPT throw()
|
||||
#endif
|
||||
|
||||
namespace kaitai {
|
||||
|
||||
/**
|
||||
* Common ancestor for all error originating from Kaitai Struct usage.
|
||||
* Stores KSY source path, pointing to an element supposedly guilty of
|
||||
* an error.
|
||||
*/
|
||||
class kstruct_error: public std::runtime_error {
|
||||
public:
|
||||
kstruct_error(const std::string what, const std::string src_path):
|
||||
std::runtime_error(src_path + ": " + what),
|
||||
m_src_path(src_path)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~kstruct_error() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
const std::string m_src_path;
|
||||
};
|
||||
|
||||
/**
|
||||
* Error that occurs when default endianness should be decided with
|
||||
* a switch, but nothing matches (although using endianness expression
|
||||
* implies that there should be some positive result).
|
||||
*/
|
||||
class undecided_endianness_error: public kstruct_error {
|
||||
public:
|
||||
undecided_endianness_error(const std::string src_path):
|
||||
kstruct_error("unable to decide on endianness for a type", src_path)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~undecided_endianness_error() KS_NOEXCEPT {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Common ancestor for all validation failures. Stores pointer to
|
||||
* KaitaiStream IO object which was involved in an error.
|
||||
*/
|
||||
class validation_failed_error: public kstruct_error {
|
||||
public:
|
||||
validation_failed_error(const std::string what, kstream* io, const std::string src_path):
|
||||
kstruct_error("at pos " + kstream::to_string(static_cast<int>(io->pos())) + ": validation failed: " + what, src_path),
|
||||
m_io(io)
|
||||
{
|
||||
}
|
||||
|
||||
// "at pos #{io.pos}: validation failed: #{msg}"
|
||||
|
||||
virtual ~validation_failed_error() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
kstream* m_io;
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals validation failure: we required "actual" value to be equal to
|
||||
* "expected", but it turned out that it's not.
|
||||
*/
|
||||
template<typename T>
|
||||
class validation_not_equal_error: public validation_failed_error {
|
||||
public:
|
||||
validation_not_equal_error<T>(const T& expected, const T& actual, kstream* io, const std::string src_path):
|
||||
validation_failed_error("not equal", io, src_path),
|
||||
m_expected(expected),
|
||||
m_actual(actual)
|
||||
{
|
||||
}
|
||||
|
||||
// "not equal, expected #{expected.inspect}, but got #{actual.inspect}"
|
||||
|
||||
virtual ~validation_not_equal_error<T>() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
const T& m_expected;
|
||||
const T& m_actual;
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals validation failure: we required "actual" value to be greater
|
||||
* than or equal to "min", but it turned out that it's not.
|
||||
*/
|
||||
template<typename T>
|
||||
class validation_less_than_error: public validation_failed_error {
|
||||
public:
|
||||
validation_less_than_error<T>(const T& min, const T& actual, kstream* io, const std::string src_path):
|
||||
validation_failed_error("not in range", io, src_path),
|
||||
m_min(min),
|
||||
m_actual(actual)
|
||||
{
|
||||
}
|
||||
|
||||
// "not in range, min #{min.inspect}, but got #{actual.inspect}"
|
||||
|
||||
virtual ~validation_less_than_error<T>() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
const T& m_min;
|
||||
const T& m_actual;
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals validation failure: we required "actual" value to be less
|
||||
* than or equal to "max", but it turned out that it's not.
|
||||
*/
|
||||
template<typename T>
|
||||
class validation_greater_than_error: public validation_failed_error {
|
||||
public:
|
||||
validation_greater_than_error<T>(const T& max, const T& actual, kstream* io, const std::string src_path):
|
||||
validation_failed_error("not in range", io, src_path),
|
||||
m_max(max),
|
||||
m_actual(actual)
|
||||
{
|
||||
}
|
||||
|
||||
// "not in range, max #{max.inspect}, but got #{actual.inspect}"
|
||||
|
||||
virtual ~validation_greater_than_error<T>() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
const T& m_max;
|
||||
const T& m_actual;
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals validation failure: we required "actual" value to be from
|
||||
* the list, but it turned out that it's not.
|
||||
*/
|
||||
template<typename T>
|
||||
class validation_not_any_of_error: public validation_failed_error {
|
||||
public:
|
||||
validation_not_any_of_error<T>(const T& actual, kstream* io, const std::string src_path):
|
||||
validation_failed_error("not any of the list", io, src_path),
|
||||
m_actual(actual)
|
||||
{
|
||||
}
|
||||
|
||||
// "not any of the list, got #{actual.inspect}"
|
||||
|
||||
virtual ~validation_not_any_of_error<T>() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
const T& m_actual;
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals validation failure: we required "actual" value to match
|
||||
* the expression, but it turned out that it doesn't.
|
||||
*/
|
||||
template<typename T>
|
||||
class validation_expr_error: public validation_failed_error {
|
||||
public:
|
||||
validation_expr_error<T>(const T& actual, kstream* io, const std::string src_path):
|
||||
validation_failed_error("not matching the expression", io, src_path),
|
||||
m_actual(actual)
|
||||
{
|
||||
}
|
||||
|
||||
// "not matching the expression, got #{actual.inspect}"
|
||||
|
||||
virtual ~validation_expr_error<T>() KS_NOEXCEPT {};
|
||||
|
||||
protected:
|
||||
const T& m_actual;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
689
third_party/kaitai/kaitaistream.cpp
vendored
Normal file
689
third_party/kaitai/kaitaistream.cpp
vendored
Normal file
@@ -0,0 +1,689 @@
|
||||
#include <kaitai/kaitaistream.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <machine/endian.h>
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#elif defined(_MSC_VER) // !__APPLE__
|
||||
#include <stdlib.h>
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
#define __BIG_ENDIAN 4321
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#define bswap_16(x) _byteswap_ushort(x)
|
||||
#define bswap_32(x) _byteswap_ulong(x)
|
||||
#define bswap_64(x) _byteswap_uint64(x)
|
||||
#else // !__APPLE__ or !_MSC_VER
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
kaitai::kstream::kstream(std::istream* io) {
|
||||
m_io = io;
|
||||
init();
|
||||
}
|
||||
|
||||
kaitai::kstream::kstream(std::string& data): m_io_str(data) {
|
||||
m_io = &m_io_str;
|
||||
init();
|
||||
}
|
||||
|
||||
void kaitai::kstream::init() {
|
||||
exceptions_enable();
|
||||
align_to_byte();
|
||||
}
|
||||
|
||||
void kaitai::kstream::close() {
|
||||
// m_io->close();
|
||||
}
|
||||
|
||||
void kaitai::kstream::exceptions_enable() const {
|
||||
m_io->exceptions(
|
||||
std::istream::eofbit |
|
||||
std::istream::failbit |
|
||||
std::istream::badbit
|
||||
);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Stream positioning
|
||||
// ========================================================================
|
||||
|
||||
bool kaitai::kstream::is_eof() const {
|
||||
if (m_bits_left > 0) {
|
||||
return false;
|
||||
}
|
||||
char t;
|
||||
m_io->exceptions(
|
||||
std::istream::badbit
|
||||
);
|
||||
m_io->get(t);
|
||||
if (m_io->eof()) {
|
||||
m_io->clear();
|
||||
exceptions_enable();
|
||||
return true;
|
||||
} else {
|
||||
m_io->unget();
|
||||
exceptions_enable();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void kaitai::kstream::seek(uint64_t pos) {
|
||||
m_io->seekg(pos);
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::pos() {
|
||||
return m_io->tellg();
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::size() {
|
||||
std::iostream::pos_type cur_pos = m_io->tellg();
|
||||
m_io->seekg(0, std::ios::end);
|
||||
std::iostream::pos_type len = m_io->tellg();
|
||||
m_io->seekg(cur_pos);
|
||||
return len;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Integer numbers
|
||||
// ========================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Signed
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
int8_t kaitai::kstream::read_s1() {
|
||||
char t;
|
||||
m_io->get(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
// ........................................................................
|
||||
// Big-endian
|
||||
// ........................................................................
|
||||
|
||||
int16_t kaitai::kstream::read_s2be() {
|
||||
int16_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 2);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_16(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
int32_t kaitai::kstream::read_s4be() {
|
||||
int32_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 4);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_32(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
int64_t kaitai::kstream::read_s8be() {
|
||||
int64_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 8);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_64(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
// ........................................................................
|
||||
// Little-endian
|
||||
// ........................................................................
|
||||
|
||||
int16_t kaitai::kstream::read_s2le() {
|
||||
int16_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 2);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_16(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
int32_t kaitai::kstream::read_s4le() {
|
||||
int32_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 4);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_32(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
int64_t kaitai::kstream::read_s8le() {
|
||||
int64_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 8);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_64(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Unsigned
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
uint8_t kaitai::kstream::read_u1() {
|
||||
char t;
|
||||
m_io->get(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
// ........................................................................
|
||||
// Big-endian
|
||||
// ........................................................................
|
||||
|
||||
uint16_t kaitai::kstream::read_u2be() {
|
||||
uint16_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 2);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_16(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32_t kaitai::kstream::read_u4be() {
|
||||
uint32_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 4);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_32(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::read_u8be() {
|
||||
uint64_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 8);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_64(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
// ........................................................................
|
||||
// Little-endian
|
||||
// ........................................................................
|
||||
|
||||
uint16_t kaitai::kstream::read_u2le() {
|
||||
uint16_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 2);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_16(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32_t kaitai::kstream::read_u4le() {
|
||||
uint32_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 4);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_32(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::read_u8le() {
|
||||
uint64_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 8);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_64(t);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Floating point numbers
|
||||
// ========================================================================
|
||||
|
||||
// ........................................................................
|
||||
// Big-endian
|
||||
// ........................................................................
|
||||
|
||||
float kaitai::kstream::read_f4be() {
|
||||
uint32_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 4);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_32(t);
|
||||
#endif
|
||||
return reinterpret_cast<float&>(t);
|
||||
}
|
||||
|
||||
double kaitai::kstream::read_f8be() {
|
||||
uint64_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 8);
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
t = bswap_64(t);
|
||||
#endif
|
||||
return reinterpret_cast<double&>(t);
|
||||
}
|
||||
|
||||
// ........................................................................
|
||||
// Little-endian
|
||||
// ........................................................................
|
||||
|
||||
float kaitai::kstream::read_f4le() {
|
||||
uint32_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 4);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_32(t);
|
||||
#endif
|
||||
return reinterpret_cast<float&>(t);
|
||||
}
|
||||
|
||||
double kaitai::kstream::read_f8le() {
|
||||
uint64_t t;
|
||||
m_io->read(reinterpret_cast<char *>(&t), 8);
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
t = bswap_64(t);
|
||||
#endif
|
||||
return reinterpret_cast<double&>(t);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Unaligned bit values
|
||||
// ========================================================================
|
||||
|
||||
void kaitai::kstream::align_to_byte() {
|
||||
m_bits_left = 0;
|
||||
m_bits = 0;
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::read_bits_int_be(int n) {
|
||||
int bits_needed = n - m_bits_left;
|
||||
if (bits_needed > 0) {
|
||||
// 1 bit => 1 byte
|
||||
// 8 bits => 1 byte
|
||||
// 9 bits => 2 bytes
|
||||
int bytes_needed = ((bits_needed - 1) / 8) + 1;
|
||||
if (bytes_needed > 8)
|
||||
throw std::runtime_error("read_bits_int: more than 8 bytes requested");
|
||||
char buf[8];
|
||||
m_io->read(buf, bytes_needed);
|
||||
for (int i = 0; i < bytes_needed; i++) {
|
||||
uint8_t b = buf[i];
|
||||
m_bits <<= 8;
|
||||
m_bits |= b;
|
||||
m_bits_left += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// raw mask with required number of 1s, starting from lowest bit
|
||||
uint64_t mask = get_mask_ones(n);
|
||||
// shift mask to align with highest bits available in @bits
|
||||
int shift_bits = m_bits_left - n;
|
||||
mask <<= shift_bits;
|
||||
// derive reading result
|
||||
uint64_t res = (m_bits & mask) >> shift_bits;
|
||||
// clear top bits that we've just read => AND with 1s
|
||||
m_bits_left -= n;
|
||||
mask = get_mask_ones(m_bits_left);
|
||||
m_bits &= mask;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Deprecated, use read_bits_int_be() instead.
|
||||
uint64_t kaitai::kstream::read_bits_int(int n) {
|
||||
return read_bits_int_be(n);
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::read_bits_int_le(int n) {
|
||||
int bits_needed = n - m_bits_left;
|
||||
if (bits_needed > 0) {
|
||||
// 1 bit => 1 byte
|
||||
// 8 bits => 1 byte
|
||||
// 9 bits => 2 bytes
|
||||
int bytes_needed = ((bits_needed - 1) / 8) + 1;
|
||||
if (bytes_needed > 8)
|
||||
throw std::runtime_error("read_bits_int_le: more than 8 bytes requested");
|
||||
char buf[8];
|
||||
m_io->read(buf, bytes_needed);
|
||||
for (int i = 0; i < bytes_needed; i++) {
|
||||
uint8_t b = buf[i];
|
||||
m_bits |= (static_cast<uint64_t>(b) << m_bits_left);
|
||||
m_bits_left += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// raw mask with required number of 1s, starting from lowest bit
|
||||
uint64_t mask = get_mask_ones(n);
|
||||
// derive reading result
|
||||
uint64_t res = m_bits & mask;
|
||||
// remove bottom bits that we've just read by shifting
|
||||
m_bits >>= n;
|
||||
m_bits_left -= n;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint64_t kaitai::kstream::get_mask_ones(int n) {
|
||||
if (n == 64) {
|
||||
return 0xFFFFFFFFFFFFFFFF;
|
||||
} else {
|
||||
return ((uint64_t) 1 << n) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Byte arrays
|
||||
// ========================================================================
|
||||
|
||||
std::string kaitai::kstream::read_bytes(std::streamsize len) {
|
||||
std::vector<char> result(len);
|
||||
|
||||
// NOTE: streamsize type is signed, negative values are only *supposed* to not be used.
|
||||
// http://en.cppreference.com/w/cpp/io/streamsize
|
||||
if (len < 0) {
|
||||
throw std::runtime_error("read_bytes: requested a negative amount");
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
m_io->read(&result[0], len);
|
||||
}
|
||||
|
||||
return std::string(result.begin(), result.end());
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::read_bytes_full() {
|
||||
std::iostream::pos_type p1 = m_io->tellg();
|
||||
m_io->seekg(0, std::ios::end);
|
||||
std::iostream::pos_type p2 = m_io->tellg();
|
||||
size_t len = p2 - p1;
|
||||
|
||||
// Note: this requires a std::string to be backed with a
|
||||
// contiguous buffer. Officially, it's a only requirement since
|
||||
// C++11 (C++98 and C++03 didn't have this requirement), but all
|
||||
// major implementations had contiguous buffers anyway.
|
||||
std::string result(len, ' ');
|
||||
m_io->seekg(p1);
|
||||
m_io->read(&result[0], len);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::read_bytes_term(char term, bool include, bool consume, bool eos_error) {
|
||||
std::string result;
|
||||
std::getline(*m_io, result, term);
|
||||
if (m_io->eof()) {
|
||||
// encountered EOF
|
||||
if (eos_error) {
|
||||
throw std::runtime_error("read_bytes_term: encountered EOF");
|
||||
}
|
||||
} else {
|
||||
// encountered terminator
|
||||
if (include)
|
||||
result.push_back(term);
|
||||
if (!consume)
|
||||
m_io->unget();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::ensure_fixed_contents(std::string expected) {
|
||||
std::string actual = read_bytes(expected.length());
|
||||
|
||||
if (actual != expected) {
|
||||
// NOTE: I think printing it outright is not best idea, it could contain non-ascii charactes like backspace and beeps and whatnot. It would be better to print hexlified version, and also to redirect it to stderr.
|
||||
throw std::runtime_error("ensure_fixed_contents: actual data does not match expected data");
|
||||
}
|
||||
|
||||
return actual;
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::bytes_strip_right(std::string src, char pad_byte) {
|
||||
std::size_t new_len = src.length();
|
||||
|
||||
while (new_len > 0 && src[new_len - 1] == pad_byte)
|
||||
new_len--;
|
||||
|
||||
return src.substr(0, new_len);
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::bytes_terminate(std::string src, char term, bool include) {
|
||||
std::size_t new_len = 0;
|
||||
std::size_t max_len = src.length();
|
||||
|
||||
while (new_len < max_len && src[new_len] != term)
|
||||
new_len++;
|
||||
|
||||
if (include && new_len < max_len)
|
||||
new_len++;
|
||||
|
||||
return src.substr(0, new_len);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Byte array processing
|
||||
// ========================================================================
|
||||
|
||||
std::string kaitai::kstream::process_xor_one(std::string data, uint8_t key) {
|
||||
size_t len = data.length();
|
||||
std::string result(len, ' ');
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
result[i] = data[i] ^ key;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::process_xor_many(std::string data, std::string key) {
|
||||
size_t len = data.length();
|
||||
size_t kl = key.length();
|
||||
std::string result(len, ' ');
|
||||
|
||||
size_t ki = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
result[i] = data[i] ^ key[ki];
|
||||
ki++;
|
||||
if (ki >= kl)
|
||||
ki = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string kaitai::kstream::process_rotate_left(std::string data, int amount) {
|
||||
size_t len = data.length();
|
||||
std::string result(len, ' ');
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t bits = data[i];
|
||||
result[i] = (bits << amount) | (bits >> (8 - amount));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef KS_ZLIB
|
||||
#include <zlib.h>
|
||||
|
||||
std::string kaitai::kstream::process_zlib(std::string data) {
|
||||
int ret;
|
||||
|
||||
unsigned char *src_ptr = reinterpret_cast<unsigned char*>(&data[0]);
|
||||
std::stringstream dst_strm;
|
||||
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
ret = inflateInit(&strm);
|
||||
if (ret != Z_OK)
|
||||
throw std::runtime_error("process_zlib: inflateInit error");
|
||||
|
||||
strm.next_in = src_ptr;
|
||||
strm.avail_in = data.length();
|
||||
|
||||
unsigned char outbuffer[ZLIB_BUF_SIZE];
|
||||
std::string outstring;
|
||||
|
||||
// get the decompressed bytes blockwise using repeated calls to inflate
|
||||
do {
|
||||
strm.next_out = reinterpret_cast<Bytef*>(outbuffer);
|
||||
strm.avail_out = sizeof(outbuffer);
|
||||
|
||||
ret = inflate(&strm, 0);
|
||||
|
||||
if (outstring.size() < strm.total_out)
|
||||
outstring.append(reinterpret_cast<char*>(outbuffer), strm.total_out - outstring.size());
|
||||
} while (ret == Z_OK);
|
||||
|
||||
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
|
||||
std::ostringstream exc_msg;
|
||||
exc_msg << "process_zlib: error #" << ret << "): " << strm.msg;
|
||||
throw std::runtime_error(exc_msg.str());
|
||||
}
|
||||
|
||||
if (inflateEnd(&strm) != Z_OK)
|
||||
throw std::runtime_error("process_zlib: inflateEnd error");
|
||||
|
||||
return outstring;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ========================================================================
|
||||
// Misc utility methods
|
||||
// ========================================================================
|
||||
|
||||
int kaitai::kstream::mod(int a, int b) {
|
||||
if (b <= 0)
|
||||
throw std::invalid_argument("mod: divisor b <= 0");
|
||||
int r = a % b;
|
||||
if (r < 0)
|
||||
r += b;
|
||||
return r;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
std::string kaitai::kstream::to_string(int val) {
|
||||
// if int is 32 bits, "-2147483648" is the longest string representation
|
||||
// => 11 chars + zero => 12 chars
|
||||
// if int is 64 bits, "-9223372036854775808" is the longest
|
||||
// => 20 chars + zero => 21 chars
|
||||
char buf[25];
|
||||
int got_len = snprintf(buf, sizeof(buf), "%d", val);
|
||||
|
||||
// should never happen, but check nonetheless
|
||||
if (got_len > sizeof(buf))
|
||||
throw std::invalid_argument("to_string: integer is longer than string buffer");
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
std::string kaitai::kstream::reverse(std::string val) {
|
||||
std::reverse(val.begin(), val.end());
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t kaitai::kstream::byte_array_min(const std::string val) {
|
||||
uint8_t min = 0xff; // UINT8_MAX
|
||||
std::string::const_iterator end = val.end();
|
||||
for (std::string::const_iterator it = val.begin(); it != end; ++it) {
|
||||
uint8_t cur = static_cast<uint8_t>(*it);
|
||||
if (cur < min) {
|
||||
min = cur;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
uint8_t kaitai::kstream::byte_array_max(const std::string val) {
|
||||
uint8_t max = 0; // UINT8_MIN
|
||||
std::string::const_iterator end = val.end();
|
||||
for (std::string::const_iterator it = val.begin(); it != end; ++it) {
|
||||
uint8_t cur = static_cast<uint8_t>(*it);
|
||||
if (cur > max) {
|
||||
max = cur;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Other internal methods
|
||||
// ========================================================================
|
||||
|
||||
#ifndef KS_STR_DEFAULT_ENCODING
|
||||
#define KS_STR_DEFAULT_ENCODING "UTF-8"
|
||||
#endif
|
||||
|
||||
#ifdef KS_STR_ENCODING_ICONV
|
||||
|
||||
#include <iconv.h>
|
||||
#include <cerrno>
|
||||
#include <stdexcept>
|
||||
|
||||
std::string kaitai::kstream::bytes_to_str(std::string src, std::string src_enc) {
|
||||
iconv_t cd = iconv_open(KS_STR_DEFAULT_ENCODING, src_enc.c_str());
|
||||
|
||||
if (cd == (iconv_t) -1) {
|
||||
if (errno == EINVAL) {
|
||||
throw std::runtime_error("bytes_to_str: invalid encoding pair conversion requested");
|
||||
} else {
|
||||
throw std::runtime_error("bytes_to_str: error opening iconv");
|
||||
}
|
||||
}
|
||||
|
||||
size_t src_len = src.length();
|
||||
size_t src_left = src_len;
|
||||
|
||||
// Start with a buffer length of double the source length.
|
||||
size_t dst_len = src_len * 2;
|
||||
std::string dst(dst_len, ' ');
|
||||
size_t dst_left = dst_len;
|
||||
|
||||
char *src_ptr = &src[0];
|
||||
char *dst_ptr = &dst[0];
|
||||
|
||||
while (true) {
|
||||
size_t res = iconv(cd, &src_ptr, &src_left, &dst_ptr, &dst_left);
|
||||
|
||||
if (res == (size_t) -1) {
|
||||
if (errno == E2BIG) {
|
||||
// dst buffer is not enough to accomodate whole string
|
||||
// enlarge the buffer and try again
|
||||
size_t dst_used = dst_len - dst_left;
|
||||
dst_left += dst_len;
|
||||
dst_len += dst_len;
|
||||
dst.resize(dst_len);
|
||||
|
||||
// dst.resize might have allocated destination buffer in another area
|
||||
// of memory, thus our previous pointer "dst" will be invalid; re-point
|
||||
// it using "dst_used".
|
||||
dst_ptr = &dst[dst_used];
|
||||
} else {
|
||||
throw std::runtime_error("bytes_to_str: iconv error");
|
||||
}
|
||||
} else {
|
||||
// conversion successful
|
||||
dst.resize(dst_len - dst_left);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iconv_close(cd) != 0) {
|
||||
throw std::runtime_error("bytes_to_str: iconv close error");
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
#elif defined(KS_STR_ENCODING_NONE)
|
||||
std::string kaitai::kstream::bytes_to_str(std::string src, std::string src_enc) {
|
||||
return src;
|
||||
}
|
||||
#else
|
||||
#error Need to decide how to handle strings: please define one of: KS_STR_ENCODING_ICONV, KS_STR_ENCODING_NONE
|
||||
#endif
|
||||
268
third_party/kaitai/kaitaistream.h
vendored
Normal file
268
third_party/kaitai/kaitaistream.h
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
#ifndef KAITAI_STREAM_H
|
||||
#define KAITAI_STREAM_H
|
||||
|
||||
// Kaitai Struct runtime API version: x.y.z = 'xxxyyyzzz' decimal
|
||||
#define KAITAI_STRUCT_VERSION 9000L
|
||||
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace kaitai {
|
||||
|
||||
/**
|
||||
* Kaitai Stream class (kaitai::kstream) is an implementation of
|
||||
* <a href="https://doc.kaitai.io/stream_api.html">Kaitai Struct stream API</a>
|
||||
* for C++/STL. It's implemented as a wrapper over generic STL std::istream.
|
||||
*
|
||||
* It provides a wide variety of simple methods to read (parse) binary
|
||||
* representations of primitive types, such as integer and floating
|
||||
* point numbers, byte arrays and strings, and also provides stream
|
||||
* positioning / navigation methods with unified cross-language and
|
||||
* cross-toolkit semantics.
|
||||
*
|
||||
* Typically, end users won't access Kaitai Stream class manually, but would
|
||||
* describe a binary structure format using .ksy language and then would use
|
||||
* Kaitai Struct compiler to generate source code in desired target language.
|
||||
* That code, in turn, would use this class and API to do the actual parsing
|
||||
* job.
|
||||
*/
|
||||
class kstream {
|
||||
public:
|
||||
/**
|
||||
* Constructs new Kaitai Stream object, wrapping a given std::istream.
|
||||
* \param io istream object to use for this Kaitai Stream
|
||||
*/
|
||||
kstream(std::istream* io);
|
||||
|
||||
/**
|
||||
* Constructs new Kaitai Stream object, wrapping a given in-memory data
|
||||
* buffer.
|
||||
* \param data data buffer to use for this Kaitai Stream
|
||||
*/
|
||||
kstream(std::string& data);
|
||||
|
||||
void close();
|
||||
|
||||
/** @name Stream positioning */
|
||||
//@{
|
||||
/**
|
||||
* Check if stream pointer is at the end of stream. Note that the semantics
|
||||
* are different from traditional STL semantics: one does *not* need to do a
|
||||
* read (which will fail) after the actual end of the stream to trigger EOF
|
||||
* flag, which can be accessed after that read. It is sufficient to just be
|
||||
* at the end of the stream for this method to return true.
|
||||
* \return "true" if we are located at the end of the stream.
|
||||
*/
|
||||
bool is_eof() const;
|
||||
|
||||
/**
|
||||
* Set stream pointer to designated position.
|
||||
* \param pos new position (offset in bytes from the beginning of the stream)
|
||||
*/
|
||||
void seek(uint64_t pos);
|
||||
|
||||
/**
|
||||
* Get current position of a stream pointer.
|
||||
* \return pointer position, number of bytes from the beginning of the stream
|
||||
*/
|
||||
uint64_t pos();
|
||||
|
||||
/**
|
||||
* Get total size of the stream in bytes.
|
||||
* \return size of the stream in bytes
|
||||
*/
|
||||
uint64_t size();
|
||||
//@}
|
||||
|
||||
/** @name Integer numbers */
|
||||
//@{
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Signed
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
int8_t read_s1();
|
||||
|
||||
// ........................................................................
|
||||
// Big-endian
|
||||
// ........................................................................
|
||||
|
||||
int16_t read_s2be();
|
||||
int32_t read_s4be();
|
||||
int64_t read_s8be();
|
||||
|
||||
// ........................................................................
|
||||
// Little-endian
|
||||
// ........................................................................
|
||||
|
||||
int16_t read_s2le();
|
||||
int32_t read_s4le();
|
||||
int64_t read_s8le();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Unsigned
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
uint8_t read_u1();
|
||||
|
||||
// ........................................................................
|
||||
// Big-endian
|
||||
// ........................................................................
|
||||
|
||||
uint16_t read_u2be();
|
||||
uint32_t read_u4be();
|
||||
uint64_t read_u8be();
|
||||
|
||||
// ........................................................................
|
||||
// Little-endian
|
||||
// ........................................................................
|
||||
|
||||
uint16_t read_u2le();
|
||||
uint32_t read_u4le();
|
||||
uint64_t read_u8le();
|
||||
|
||||
//@}
|
||||
|
||||
/** @name Floating point numbers */
|
||||
//@{
|
||||
|
||||
// ........................................................................
|
||||
// Big-endian
|
||||
// ........................................................................
|
||||
|
||||
float read_f4be();
|
||||
double read_f8be();
|
||||
|
||||
// ........................................................................
|
||||
// Little-endian
|
||||
// ........................................................................
|
||||
|
||||
float read_f4le();
|
||||
double read_f8le();
|
||||
|
||||
//@}
|
||||
|
||||
/** @name Unaligned bit values */
|
||||
//@{
|
||||
|
||||
void align_to_byte();
|
||||
uint64_t read_bits_int_be(int n);
|
||||
uint64_t read_bits_int(int n);
|
||||
uint64_t read_bits_int_le(int n);
|
||||
|
||||
//@}
|
||||
|
||||
/** @name Byte arrays */
|
||||
//@{
|
||||
|
||||
std::string read_bytes(std::streamsize len);
|
||||
std::string read_bytes_full();
|
||||
std::string read_bytes_term(char term, bool include, bool consume, bool eos_error);
|
||||
std::string ensure_fixed_contents(std::string expected);
|
||||
|
||||
static std::string bytes_strip_right(std::string src, char pad_byte);
|
||||
static std::string bytes_terminate(std::string src, char term, bool include);
|
||||
static std::string bytes_to_str(std::string src, std::string src_enc);
|
||||
|
||||
//@}
|
||||
|
||||
/** @name Byte array processing */
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Performs a XOR processing with given data, XORing every byte of input with a single
|
||||
* given value.
|
||||
* @param data data to process
|
||||
* @param key value to XOR with
|
||||
* @return processed data
|
||||
*/
|
||||
static std::string process_xor_one(std::string data, uint8_t key);
|
||||
|
||||
/**
|
||||
* Performs a XOR processing with given data, XORing every byte of input with a key
|
||||
* array, repeating key array many times, if necessary (i.e. if data array is longer
|
||||
* than key array).
|
||||
* @param data data to process
|
||||
* @param key array of bytes to XOR with
|
||||
* @return processed data
|
||||
*/
|
||||
static std::string process_xor_many(std::string data, std::string key);
|
||||
|
||||
/**
|
||||
* Performs a circular left rotation shift for a given buffer by a given amount of bits,
|
||||
* using groups of 1 bytes each time. Right circular rotation should be performed
|
||||
* using this procedure with corrected amount.
|
||||
* @param data source data to process
|
||||
* @param amount number of bits to shift by
|
||||
* @return copy of source array with requested shift applied
|
||||
*/
|
||||
static std::string process_rotate_left(std::string data, int amount);
|
||||
|
||||
#ifdef KS_ZLIB
|
||||
/**
|
||||
* Performs an unpacking ("inflation") of zlib-compressed data with usual zlib headers.
|
||||
* @param data data to unpack
|
||||
* @return unpacked data
|
||||
* @throws IOException
|
||||
*/
|
||||
static std::string process_zlib(std::string data);
|
||||
#endif
|
||||
|
||||
//@}
|
||||
|
||||
/**
|
||||
* Performs modulo operation between two integers: dividend `a`
|
||||
* and divisor `b`. Divisor `b` is expected to be positive. The
|
||||
* result is always 0 <= x <= b - 1.
|
||||
*/
|
||||
static int mod(int a, int b);
|
||||
|
||||
/**
|
||||
* Converts given integer `val` to a decimal string representation.
|
||||
* Should be used in place of std::to_string() (which is available only
|
||||
* since C++11) in older C++ implementations.
|
||||
*/
|
||||
static std::string to_string(int val);
|
||||
|
||||
/**
|
||||
* Reverses given string `val`, so that the first character becomes the
|
||||
* last and the last one becomes the first. This should be used to avoid
|
||||
* the need of local variables at the caller.
|
||||
*/
|
||||
static std::string reverse(std::string val);
|
||||
|
||||
/**
|
||||
* Finds the minimal byte in a byte array, treating bytes as
|
||||
* unsigned values.
|
||||
* @param val byte array to scan
|
||||
* @return minimal byte in byte array as integer
|
||||
*/
|
||||
static uint8_t byte_array_min(const std::string val);
|
||||
|
||||
/**
|
||||
* Finds the maximal byte in a byte array, treating bytes as
|
||||
* unsigned values.
|
||||
* @param val byte array to scan
|
||||
* @return maximal byte in byte array as integer
|
||||
*/
|
||||
static uint8_t byte_array_max(const std::string val);
|
||||
|
||||
private:
|
||||
std::istream* m_io;
|
||||
std::istringstream m_io_str;
|
||||
int m_bits_left;
|
||||
uint64_t m_bits;
|
||||
|
||||
void init();
|
||||
void exceptions_enable() const;
|
||||
|
||||
static uint64_t get_mask_ones(int n);
|
||||
|
||||
static const int ZLIB_BUF_SIZE = 128 * 1024;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
20
third_party/kaitai/kaitaistruct.h
vendored
Normal file
20
third_party/kaitai/kaitaistruct.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef KAITAI_STRUCT_H
|
||||
#define KAITAI_STRUCT_H
|
||||
|
||||
#include <kaitai/kaitaistream.h>
|
||||
|
||||
namespace kaitai {
|
||||
|
||||
class kstruct {
|
||||
public:
|
||||
kstruct(kstream *_io) { m__io = _io; }
|
||||
virtual ~kstruct() {}
|
||||
protected:
|
||||
kstream *m__io;
|
||||
public:
|
||||
kstream *_io() { return m__io; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user