/****************************************************************************** * Copyright (c) 2014, Hobu Inc., hobu@hobu.co * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided * with the distribution. * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. ****************************************************************************/ #pragma once #include #include #include "pdal_util_export.hpp" #include "portable_endian.hpp" namespace pdal { /** Buffer wrapper for input of binary data from a buffer. */ class PDAL_DLL Extractor { public: /** Construct an extractor to operate on a buffer. \param buf Buffer to extract from. \param size Buffer size. */ Extractor(const char *buf, std::size_t size) : m_eback(buf), m_egptr(buf + size), m_gptr(buf) {} public: /** Determine if the buffer is good. \return Whether the buffer is good. */ operator bool () { return good(); } /** Seek to a position in the buffer. \param pos Position to seek in buffer. */ void seek(std::size_t pos) { m_gptr = m_eback + pos; } /** Advance buffer position. \param cnt Number of bytes to skip in buffer. */ void skip(std::size_t cnt) { m_gptr += cnt; } /** Return the get position of buffer. \return Get position. */ size_t position() const { return m_gptr - m_eback; } /** Determine whether the extractor is good (the get pointer is in the buffer). \return Whether the get pointer is valid. */ bool good() const { return m_gptr < m_egptr; } /** Extract a string of a particular size from the buffer. Trim trailing null bytes. \param s String to extract to. \param size Number of bytes to extract from buffer into string. */ void get(std::string& s, size_t size) { s = std::string(m_gptr, size); m_gptr += size; while (size) { size--; if (s[size] != '\0') { s.resize(size + 1); return; } } s.clear(); } /** Extract data to char vector. Vector must be sized to indicate number of bytes to extract. \param buf Vector to which bytes should be extracted. */ void get(std::vector& buf) { memcpy((char *)buf.data(), m_gptr, buf.size()); m_gptr += buf.size(); } /** Extract data to unsigned char vector. Vector must be sized to indicate number of bytes to extract. \param buf Vector to which bytes should be extracted. */ void get(std::vector& buf) { memcpy((char *)buf.data(), m_gptr, buf.size()); m_gptr += buf.size(); } /** Extract data into a provided buffer. \param buf Pointer to buffer to which bytes should be extracted. \param size Number of bytes to extract. */ void get(char *buf, size_t size) { memcpy(buf, m_gptr, size); m_gptr += size; } /** Extract data into a provided unsigned buffer. \param buf Pointer to buffer to which bytes should be extracted. \param size Number of bytes to extract. */ void get(unsigned char *buf, size_t size) { memcpy(buf, m_gptr, size); m_gptr += size; } virtual Extractor& operator >> (uint8_t& v) = 0; virtual Extractor& operator >> (int8_t& v) = 0; virtual Extractor& operator >> (uint16_t& v) = 0; virtual Extractor& operator >> (int16_t& v) = 0; virtual Extractor& operator >> (uint32_t& v) = 0; virtual Extractor& operator >> (int32_t& v) = 0; virtual Extractor& operator >> (uint64_t& v) = 0; virtual Extractor& operator >> (int64_t& v) = 0; virtual Extractor& operator >> (float& v) = 0; virtual Extractor& operator >> (double& v) = 0; protected: const char *m_eback; ///< Start of the buffer (name from std::streambuf) const char *m_egptr; ///< End of the buffer. const char *m_gptr; ///< Current get position. }; /** Wrapper extraction of little-endian data from a buffer to host ordering. */ class PDAL_DLL LeExtractor : public Extractor { public: /** Construct extractor for a buffer. \param buf Buffer from which to extract. \param size Size of buffer. */ LeExtractor(const char *buf, std::size_t size) : Extractor(buf, size) {} /** Extract an unsigned byte from a buffer. \param v Unsigned byte to extract to. \return This extractor. */ LeExtractor& operator >> (uint8_t& v) { v = *(const uint8_t *)m_gptr++; return *this; } /** Extract a byte from a buffer. \param v Byte to extract to. \return This extractor. */ LeExtractor& operator >> (int8_t& v) { v = *(const int8_t *)m_gptr++; return *this; } /** Extract an unsgined short from a buffer. \param v Short to extract to. \return This extractor. */ LeExtractor& operator >> (uint16_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = le16toh(v); m_gptr += sizeof(v); return *this; } /** Extract a short from a buffer. \param v Short to extract to. \return This extractor. */ LeExtractor& operator >> (int16_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = (int16_t)le16toh((uint16_t)v); m_gptr += sizeof(v); return *this; } /** Extract an unsigned int from a buffer. \param v Unsigned int to extract to. \return This extractor. */ LeExtractor& operator >> (uint32_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = le32toh(v); m_gptr += sizeof(v); return *this; } /** Extract an int from a buffer. \param v int to extract to. \return This extractor. */ LeExtractor& operator >> (int32_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = (int32_t)le32toh((uint32_t)v); m_gptr += sizeof(v); return *this; } /** Extract an unsigned long int from a buffer. \param v unsigned long int to extract to. \return This extractor. */ LeExtractor& operator >> (uint64_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = le64toh(v); m_gptr += sizeof(v); return *this; } /** Extract a long int from a buffer. \param v long int to extract to. \return This extractor. */ LeExtractor& operator >> (int64_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = (int64_t)le64toh((uint64_t)v); m_gptr += sizeof(v); return *this; } /** Extract a float from a buffer. \param v float to extract to. \return This extractor. */ LeExtractor& operator >> (float& v) { memcpy(&v, m_gptr, sizeof(v)); uint32_t tmp = le32toh(*(uint32_t *)(&v)); memcpy(&v, &tmp, sizeof(tmp)); m_gptr += sizeof(v); return *this; } /** Extract a double from a buffer. \param v double to extract to. \return This extractor. */ LeExtractor& operator >> (double& v) { memcpy(&v, m_gptr, sizeof(v)); uint64_t tmp = le64toh(*(uint64_t *)(&v)); memcpy(&v, &tmp, sizeof(tmp)); m_gptr += sizeof(v); return *this; } }; /** Wrapper extraction of big-endian data from a buffer to host ordering. */ class PDAL_DLL BeExtractor : public Extractor { public: /** Construct extractor for a buffer. \param buf Buffer from which to extract. \param size Size of buffer. */ BeExtractor(const char *buf, std::size_t size) : Extractor(buf, size) {} /** Extract an unsigned byte from a buffer. \param v unsigned byte to extract to. \return This extractor. */ BeExtractor& operator >> (uint8_t& v) { v = *(const uint8_t *)m_gptr++; return *this; } /** Extract a byte from a buffer. \param v byte to extract to. \return This extractor. */ BeExtractor& operator >> (int8_t& v) { v = *(const int8_t *)m_gptr++; return *this; } /** Extract an unsigned short from a buffer. \param v unsigned short to extract to. \return This extractor. */ BeExtractor& operator >> (uint16_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = be16toh(v); m_gptr += sizeof(v); return *this; } /** Extract a short from a buffer. \param v short to extract to. \return This extractor. */ BeExtractor& operator >> (int16_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = (int16_t)be16toh((uint16_t)v); m_gptr += sizeof(v); return *this; } /** Extract an unsigned int from a buffer. \param v unsigned int to extract to. \return This extractor. */ BeExtractor& operator >> (uint32_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = be32toh(v); m_gptr += sizeof(v); return *this; } /** Extract an int from a buffer. \param v int to extract to. \return This extractor. */ BeExtractor& operator >> (int32_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = (int32_t)be32toh((uint32_t)v); m_gptr += sizeof(v); return *this; } /** Extract an unsigned long int from a buffer. \param v unsigned long int to extract to. \return This extractor. */ BeExtractor& operator >> (uint64_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = be64toh(v); m_gptr += sizeof(v); return *this; } /** Extract a long int from a buffer. \param v long int to extract to. \return This extractor. */ BeExtractor& operator >> (int64_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = (int64_t)be64toh((uint64_t)v); m_gptr += sizeof(v); return *this; } /** Extract a float from a buffer. \param v float to extract to. \return This extractor. */ BeExtractor& operator >> (float& v) { memcpy(&v, m_gptr, sizeof(v)); uint32_t tmp = be32toh(*(uint32_t *)(&v)); memcpy(&v, &tmp, sizeof(tmp)); m_gptr += sizeof(v); return *this; } /** Extract a double from a buffer. \param v double to extract to. \return This extractor. */ BeExtractor& operator >> (double& v) { memcpy(&v, m_gptr, sizeof(v)); uint64_t tmp = be64toh(*(uint64_t *)(&v)); memcpy(&v, &tmp, sizeof(tmp)); m_gptr += sizeof(v); return *this; } }; /** Wrapper extraction of data from a buffer to host ordering. Endianness of buffered data can be specified at run-time. */ class PDAL_DLL SwitchableExtractor : public Extractor { public: static const bool DefaultIsLittleEndian = true; /** Construct extractor for a buffer. \param buf Buffer to extract from. \param size Buffer size. */ SwitchableExtractor(const char* buf, std::size_t size) : Extractor(buf, size) , m_isLittleEndian(DefaultIsLittleEndian) {} /** Construct extractor for a buffer. \param buf Buffer to extract from. \param size Buffer size. \param isLittleEndian \c true if the extractor converts from little endian byte order */ SwitchableExtractor(const char* buf, std::size_t size, bool isLittleEndian) : Extractor(buf, size) , m_isLittleEndian(isLittleEndian) {} /** Returns whether the extractor converts from little endian. \return \c true if the extractor converts from little endian. */ bool isLittleEndian() const { return m_isLittleEndian; } /** Set to convert from little endian. */ void switchToLittleEndian() { m_isLittleEndian = true; } /** Set to convert from big endian. */ void switchToBigEndian() { m_isLittleEndian = false; } /** Extract an unsigned byte from a buffer. \param v unsigned byte to extract to. \return This extractor. */ SwitchableExtractor& operator>>(uint8_t& v) { v = *(const uint8_t*)m_gptr++; return *this; } /** Extract a byte from a buffer. \param v byte to extract to. \return This extractor. */ SwitchableExtractor& operator>>(int8_t& v) { v = *(const int8_t*)m_gptr++; return *this; } /** Extract an unsigned short from a buffer. \param v unsigned short to extract to. \return This extractor. */ SwitchableExtractor& operator>>(uint16_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = isLittleEndian() ? le16toh(v) : be16toh(v); m_gptr += sizeof(v); return *this; } /** Extract a short from a buffer. \param v short to extract to. \return This extractor. */ SwitchableExtractor& operator>>(int16_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = isLittleEndian() ? (int16_t)le16toh((uint16_t)v) : (int16_t)be16toh((uint16_t)v); m_gptr += sizeof(v); return *this; } /** Extract an unsigned int from a buffer. \param v unsigned int to extract to. \return This extractor. */ SwitchableExtractor& operator>>(uint32_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = isLittleEndian() ? le32toh(v) : be32toh(v); m_gptr += sizeof(v); return *this; } /** Extract an int from a buffer. \param v int to extract to. \return This extractor. */ SwitchableExtractor& operator>>(int32_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = isLittleEndian() ? (int32_t)le32toh((uint32_t)v) : (int32_t)be32toh((uint32_t)v); m_gptr += sizeof(v); return *this; } /** Extract an unsigned long from a buffer. \param v unsigned long to extract to. \return This extractor. */ SwitchableExtractor& operator>>(uint64_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = isLittleEndian() ? le64toh(v) : be64toh(v); m_gptr += sizeof(v); return *this; } /** Extract a long from a buffer. \param v long to extract to. \return This extractor. */ SwitchableExtractor& operator>>(int64_t& v) { memcpy(&v, m_gptr, sizeof(v)); v = isLittleEndian() ? (int64_t)le64toh((uint64_t)v) : (int64_t)be64toh((uint64_t)v); m_gptr += sizeof(v); return *this; } /** Extract a float from a buffer. \param v float to extract to. \return This extractor. */ SwitchableExtractor& operator>>(float& v) { memcpy(&v, m_gptr, sizeof(v)); uint32_t tmp = isLittleEndian() ? le32toh(*(uint32_t*)(&v)) : be32toh(*(uint32_t*)(&v)); memcpy(&v, &tmp, sizeof(tmp)); m_gptr += sizeof(v); return *this; } /** Extract a double from a buffer. \param v double to extract to. \return This extractor. */ SwitchableExtractor& operator>>(double& v) { memcpy(&v, m_gptr, sizeof(v)); uint64_t tmp = isLittleEndian() ? le64toh(*(uint64_t*)(&v)) : be64toh(*(uint64_t*)(&v)); memcpy(&v, &tmp, sizeof(tmp)); m_gptr += sizeof(v); return *this; } private: bool m_isLittleEndian; }; } // namespace pdal