summaryrefslogtreecommitdiffstats
path: root/lib/kaitai
diff options
context:
space:
mode:
authorEvan Dekker <ehendrikd@gmail.com>2019-05-24 21:36:57 +1000
committerEvan Dekker <ehendrikd@gmail.com>2019-05-24 21:38:15 +1000
commit83e1b45e5cfbdef5f66ecc117a2a782bc43686c9 (patch)
tree36fea735b224ec05795ca1e59e2be78b211600f5 /lib/kaitai
parentf5d7e7de5b2c26424b2477fdcb2e096ba13420ff (diff)
Rekordbox library feature that reads tracks, playlists and folders from removable devices
Diffstat (limited to 'lib/kaitai')
-rw-r--r--lib/kaitai/LICENSE7
-rwxr-xr-xlib/kaitai/custom_decoder.h16
-rwxr-xr-xlib/kaitai/kaitaistream.cpp631
-rwxr-xr-xlib/kaitai/kaitaistream.h250
-rwxr-xr-xlib/kaitai/kaitaistruct.h20
5 files changed, 924 insertions, 0 deletions
diff --git a/lib/kaitai/LICENSE b/lib/kaitai/LICENSE
new file mode 100644
index 0000000000..a1867624b1
--- /dev/null
+++ b/lib/kaitai/LICENSE
@@ -0,0 +1,7 @@
+Copyright 2016-2019 Kaitai Project: MIT license
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/lib/kaitai/custom_decoder.h b/lib/kaitai/custom_decoder.h
new file mode 100755
index 0000000000..6da7f5fd23
--- /dev/null
+++ b/lib/kaitai/custom_decoder.h
@@ -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
diff --git a/lib/kaitai/kaitaistream.cpp b/lib/kaitai/kaitaistream.cpp
new file mode 100755
index 0000000000..2a9f082e95
--- /dev/null
+++ b/lib/kaitai/kaitaistream.cpp
@@ -0,0 +1,631 @@
+#include <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(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;
+}
+
+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;
+}
+
+// ========================================================================
+// 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
diff --git a/lib/kaitai/kaitaistream.h b/lib/kaitai/kaitaistream.h
new file mode 100755
index 0000000000..9592771db0
--- /dev/null
+++ b/lib/kaitai/kaitaistream.h
@@ -0,0 +1,250 @@
+#ifndef KAITAI_STREAM_H
+#define KAITAI_STREAM_H
+
+// Kaitai Struct runtime API version: x.y.z = 'xxxyyyzzz' decimal
+#define KAITAI_STRUCT_VERSION 7000L
+
+#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://github.com/kaitai-io/kaitai_struct/wiki/Kaitai-Struct-stream-API">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(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);
+
+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
diff --git a/lib/kaitai/kaitaistruct.h b/lib/kaitai/kaitaistruct.h
new file mode 100755
index 0000000000..f8b848fdd1
--- /dev/null
+++ b/lib/kaitai/kaitaistruct.h
@@ -0,0 +1,20 @@
+#ifndef KAITAI_STRUCT_H
+#define KAITAI_STRUCT_H
+
+#include <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