/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtKnx module. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qknxbytearray.h" #include QT_BEGIN_NAMESPACE /*! \class QKnxByteArray \inmodule QtKnx \ingroup qtknx-general-classes \brief The QKnxByteArray class provides an array of unsigned bytes. A KNX byte array can be used to store both raw bytes (including the string \c {\0} and any characters that might come after it) and traditional 8-bit \c {\0}-terminated strings. Using QKnxByteArray is much more convenient than using \c{const quint8 *}. Behind the scenes, it always ensures that the data is followed by a null-terminator (\c {\0}). QKnxByteArray makes a deep copy of the data given, so you can modify it later without experiencing side effects. Another approach is to set the size of the array using resize() and to initialize the data byte per byte. QKnxByteArray uses 0-based indexes, just like C++ arrays. To access the byte at a particular index position, you can use at(), set(), value() and setValue(). To extract several bytes at a time, use left(), right(), or mid(). A KNX byte array can embed \c {\0} bytes. The size() function always returns the size of the whole array, including the embedded \c {\0} bytes, but excluding the null-terminator added by QKnxByteArray. After a call to resize(), newly allocated bytes have undefined values. To set all the bytes to a particular value, call fill(). To obtain a pointer to the actual character data, call data() or constData(). These functions return a pointer to the beginning of the data. The pointer is guaranteed to remain valid until a non-const function is called on the byte array. */ /*! \fn QKnxByteArray::QKnxByteArray() Constructs an empty byte array. */ /*! \fn QKnxByteArray::~QKnxByteArray() Destroys the byte array. */ /*! Constructs a byte array of the size \a size with every byte set to the character \a ch. */ QKnxByteArray::QKnxByteArray(int size, quint8 ch) : m_bytes(size, char(ch)) {} /*! \internal Constructs a byte array of the size \a size with uninitialized contents. */ QKnxByteArray::QKnxByteArray(int size, Qt::Initialization) : m_bytes(size, Qt::Uninitialized) {} /*! Constructs a byte array from \a data containing the number of bytes specified by \a size starting from the beginning of the data. If \a data is 0, a null byte array is constructed. If \a size is negative, \a data is assumed to point to a null-terminated string and its length is determined dynamically. The terminating null-character is not considered part of the byte array. QKnxByteArray makes a deep copy of the string data. */ QKnxByteArray::QKnxByteArray(const char *data, int size) : m_bytes(data, size) {} /*! \overload QKnxByteArray() */ QKnxByteArray::QKnxByteArray(const quint8 *data, int size) : m_bytes(reinterpret_cast (data), size) {} /*! Constructs a byte array from the \c {std::initializer_list} specified by \a args. */ QKnxByteArray::QKnxByteArray(std::initializer_list args) { if (args.size() > 0) { auto d = new (std::nothrow) quint8[args.size()]; if (!d) return; memcpy(d, args.begin(), (args.end() - args.begin()) * sizeof(quint8)); m_bytes = QByteArray(reinterpret_cast (d), int(args.size())); delete []d; } } /*! \fn QKnxByteArray::QKnxByteArray(const QKnxByteArray &other) Constructs a copy of \a other. */ /*! Assigns \a other to this KNX byte array and returns a reference. */ QKnxByteArray &QKnxByteArray::operator=(const QKnxByteArray &other) Q_DECL_NOTHROW { m_bytes.operator=(other.m_bytes); return *this; } /*! \fn QKnxByteArray::QKnxByteArray(QKnxByteArray &&other) Move-constructs a QKnxByteArray instance, making it point to the same object that \a other was pointing to. */ /*! \fn QKnxByteArray &QKnxByteArray::operator=(QKnxByteArray &&other) Move-assigns \a other to this QKnxByteArray instance. */ /*! \fn void QKnxByteArray::swap(QKnxByteArray &other) Swaps the byte array \a other with this byte array. This operation is very fast and never fails. */ /*! Returns a copy of this byte array as \l QByteArray. */ const QByteArray &QKnxByteArray::toByteArray() const { return m_bytes; } /*! Returns a byte array constructed from \a byteArray . */ QKnxByteArray QKnxByteArray::fromByteArray(const QByteArray &byteArray) { QKnxByteArray ba(0, Qt::Uninitialized); ba.m_bytes = byteArray; return ba; } /*! Returns \c true if this byte array is null; otherwise returns \c false. */ bool QKnxByteArray::isNull() const { return m_bytes.isNull(); } /*! \fn bool QKnxByteArray::isEmpty() const Returns \c true if the byte array has the size 0; otherwise returns \c false. */ /*! \fn int QKnxByteArray::size() const Returns the number of bytes in this byte array. The last byte in the byte array is at the position returned by this function minus 1. */ /*! Clears the contents of the byte array and makes it null. */ void QKnxByteArray::clear() { m_bytes.clear(); } /*! Sets the size of the byte array to the number of bytes specified by \a size. If \a size is greater than the current size, the byte array is extended to \a size bytes by adding \l {default-constructed value} {default-constructed values} to the end of the array. If \a size is less than the current size, bytes are removed from the end of the array. */ void QKnxByteArray::resize(int size) { if (size > m_bytes.size()) m_bytes.append(size - m_bytes.size(), 0x00); else m_bytes.resize(size); } /*! \fn quint8 QKnxByteArray::at(int i) const Returns the character at the index position \a i in the byte array. \a i must be a valid index position in the byte array (that is, between 0 and the value returned by size()). */ /*! \fn void QKnxByteArray::set(int i, quint8 val) Sets the character at the index position \a i in the byte array to \a val. \a i must be a valid index position in the byte array (that is, between 0 and the value returned by size()). */ /*! \fn void QKnxByteArray::setValue(int i, quint8 val) Sets the value at the index position \a i in the byte array to \a val. If the index \a i is out of bounds, the function does nothing. If you are certain that \a i is within bounds, you can use set() instead, which is slightly faster. */ /*! \fn quint8 QKnxByteArray::value(int i, quint8 defaultValue = {}) const Returns the value at the index position \a i in the byte array. If the index \a i is out of bounds, the function returns \a defaultValue, which may be a \l{default-constructed value}. If you are certain that \a i is within bounds, you can use at() instead, which is slightly faster. */ /*! Returns a copy of this byte array repeated the specified number of \a times. If \a times is less than 1, an empty byte array is returned. */ QKnxByteArray QKnxByteArray::repeated(int times) const { QKnxByteArray ba(0, Qt::Uninitialized); ba.m_bytes = m_bytes.repeated(times); return ba; } /*! Sets every byte in the byte array to the character \a ch and returns a reference to this byte array. If \a size is different from -1, the byte array is resized to \a size beforehand. */ QKnxByteArray &QKnxByteArray::fill(quint8 ch, int size) { m_bytes.fill(ch, size); return *this; } /*! Returns a byte array that contains the number of leftmost bytes in the byte array specified by \a len. The entire byte array is returned if \a len is greater than the value returned by size(). */ QKnxByteArray QKnxByteArray::left(int len) const { if (len >= size()) return *this; if (len < 0) len = 0; return QKnxByteArray(constData(), len); } /*! Returns a byte array that contains the number of rightmost bytes in the byte array specified by \a len. The entire byte array is returned if \a len is greater than the value returned by size(). */ QKnxByteArray QKnxByteArray::right(int len) const { if (len >= size()) return *this; if (len < 0) len = 0; return QKnxByteArray(constData() + size() - len, len); } /*! Returns a byte array containing the number of bytes in the byte array specified by \a len, starting at the position \a pos. If \a len is -1 (the default), or \a pos added to \a len is equal to or larger than the value returned by size(), returns a byte array containing all bytes starting from the position \a pos to the end of the byte array. */ QKnxByteArray QKnxByteArray::mid(int pos, int len) const { const auto m = m_bytes.mid(pos, len); if (m.isEmpty()) return {}; return QKnxByteArray(m.constData(), m.size()); } /*! \fn QKnxByteArray::chop(int len) const Returns a byte array that contains the number of leftmost bytes in this byte array calculated by subtracting the amount of bytes specified by \a len from the amount of bytes of returned by size(). \note The behavior is undefined if \a len is negative. */ /*! \overload prepend() Prepends the character \a ch to this byte array. */ QKnxByteArray &QKnxByteArray::prepend(quint8 ch) { m_bytes.prepend(char(ch)); return *this; } /*! Prepends the byte array \a ba to this byte array and returns a reference to this byte array. */ QKnxByteArray &QKnxByteArray::prepend(const QKnxByteArray &ba) { m_bytes.prepend(reinterpret_cast (ba.constData()), ba.size()); return *this; } /*! \overload prepend() \fn QKnxByteArray &QKnxByteArray::prepend(int count, quint8 ch) Prepends the number of copies of the character \a ch specified by \a count to this byte array. */ /*! \overload insert() Inserts the character \a ch at the index position \a i in the byte array. If \a i is greater than the number of bytes returned by size(), the array is first extended using resize(). */ QKnxByteArray &QKnxByteArray::insert(int i, quint8 ch) { m_bytes.insert(i, char(ch)); return *this; } /*! \overload insert() Inserts the number of copies of the character \a ch specified by \a count at the index position \a i in the byte array. If \a i is greater than the value returned by size(), the array is first extended using resize(). */ QKnxByteArray &QKnxByteArray::insert(int i, int count, quint8 ch) { m_bytes.insert(i, count, char(ch)); return *this; } /*! Inserts the byte array \a ba at the index position \a i and returns a reference to this byte array. */ QKnxByteArray &QKnxByteArray::insert(int i, const QKnxByteArray &ba) { m_bytes.insert(i, reinterpret_cast (ba.constData()), ba.size()); return *this; } /*! \overload append() Appends the character \a ch to this byte array. */ QKnxByteArray& QKnxByteArray::append(quint8 ch) { m_bytes.append(char(ch)); return *this; } /*! Appends the byte array \a ba to the end of this byte array. */ QKnxByteArray &QKnxByteArray::append(const QKnxByteArray &ba) { m_bytes.append(reinterpret_cast (ba.constData()), ba.size()); return *this; } /*! \overload append() \fn QKnxByteArray &QKnxByteArray::append(int count, quint8 ch) Appends the number of copies of the character \a ch specified by \a count to this byte array and returns a reference to this byte array. If \a count is negative or zero, nothing is appended to the byte array. */ /*! Replaces the number of bytes specified by \a len beginning at the index position \a index with the byte array \a after, and returns a reference to this byte array. */ QKnxByteArray &QKnxByteArray::replace(int index, int len, const QKnxByteArray &after) { m_bytes.replace(index, len, reinterpret_cast (after.constData()), after.size()); return *this; } /*! \overload replace() Replaces every occurrence of the character \a before with the byte array \a after. */ QKnxByteArray &QKnxByteArray::replace(quint8 before, const QKnxByteArray &after) { m_bytes.replace(char(before), after.toByteArray()); return *this; } /*! \overload replace() Replaces every occurrence of the byte array \a before with the byte array \a after. */ QKnxByteArray &QKnxByteArray::replace(const QKnxByteArray &before, const QKnxByteArray &after) { m_bytes.replace(before.toByteArray(), after.toByteArray()); return *this; } /*! \overload replace() Replaces every occurrence of the character \a before with the character \a after. */ QKnxByteArray &QKnxByteArray::replace(quint8 before, quint8 after) { m_bytes.replace(char(before), char(after)); return *this; } /*! Removes the number of bytes specified by \a len from the array, starting at the index position \a pos, and returns a reference to the array. If \a pos is out of range, nothing happens. If \a pos is valid, but \a pos added to \a len is larger than the size of the array, the array is truncated at the position \a pos. */ QKnxByteArray &QKnxByteArray::remove(int pos, int len) { m_bytes.remove(pos, len); return *this; } /*! \fn quint8 *QKnxByteArray::data() Returns a pointer to the data stored in the byte array. The pointer can be used to access and modify the bytes that compose the array. The data is null-terminated, which means that the number of bytes in the returned character string is the value returned by size() plus 1 for the null-terminator. The pointer remains valid until the byte array is reallocated or destroyed. */ /*! \overload data() \fn const quint8 *QKnxByteArray::data() const */ /*! \fn const quint8 *QKnxByteArray::constData() const Returns a pointer to the data stored in the byte array. The pointer can be used to access the bytes that compose the array. The data is null-terminated. The pointer remains valid until the byte array is reallocated or destroyed. */ /*! \overload indexOf() Returns the index position of the first occurrence of the character \a ch in the byte array, searching forward from the index position \a from. Returns -1 if \a ch could not be found. */ int QKnxByteArray::indexOf(quint8 ch, int from) const { return m_bytes.indexOf(char(ch), from); } /*! Returns the index position of the first occurrence of the byte array \a ba in this byte array, searching forward from the index position \a from. Returns -1 if \a ba could not be found. */ int QKnxByteArray::indexOf(const QKnxByteArray &ba, int from) const { return m_bytes.indexOf(ba.toByteArray(), from); } /*! \overload lastIndexOf() Returns the index position of the last occurrence of the character \a ch in the byte array, searching backward from the index position \a from. If \a from is -1 (the default), the search starts at the last byte (that is, the value returned by size() minus 1). Returns -1 if \a ch cannot be found. */ int QKnxByteArray::lastIndexOf(quint8 ch, int from) const { return m_bytes.lastIndexOf(char(ch), from); } /*! Returns the index position of the last occurrence of the byte array \a ba in this byte array, searching backward from the index position \a from. If \a from is -1 (the default), the search starts at the last byte. Returns -1 if \a ba could not be found. */ int QKnxByteArray::lastIndexOf(const QKnxByteArray &ba, int from) const { return m_bytes.lastIndexOf(ba.toByteArray(), from); } /*! \overload contains() \fn bool QKnxByteArray::contains(quint8 ch) const Returns \c true if the byte array contains the character \a ch; otherwise returns \c false. */ /*! \fn bool QKnxByteArray::contains(const QKnxByteArray &ba) const Returns \c true if the byte array contains an occurrence of the byte array \a ba; otherwise returns \c false. */ /*! \overload startsWith() Returns \c true if this byte array starts with the character \a ch; otherwise returns \c false. */ bool QKnxByteArray::startsWith(quint8 ch) const { return m_bytes.startsWith(char(ch)); } /*! Returns \c true if this byte array starts with the byte array \a ba; otherwise returns \c false. */ bool QKnxByteArray::startsWith(const QKnxByteArray &ba) const { return m_bytes.startsWith(ba.toByteArray()); } /*! \overload endsWith() Returns \c true if this byte array ends with the character \a ch; otherwise returns \c false. */ bool QKnxByteArray::endsWith(quint8 ch) const { return m_bytes.endsWith(char(ch)); } /*! Returns \c true if this byte array ends with the byte array \a ba; otherwise returns \c false. */ bool QKnxByteArray::endsWith(const QKnxByteArray &ba) const { return m_bytes.endsWith(ba.toByteArray()); } /*! Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and the letters a-f. If \a separator is not \c{\0}, the separator character is inserted between the hex bytes. Example: \code auto macAddress = QKnxByteArray::fromHex("123456abcdef"); macAddress.toHex(':'); // returns "12:34:56:ab:cd:ef" macAddress.toHex(0); // returns "123456abcdef" \endcode */ QKnxByteArray QKnxByteArray::toHex(quint8 separator) const { if (!size()) return {}; QKnxByteArray hex(0, Qt::Uninitialized); hex.m_bytes = m_bytes.toHex(separator); return hex; } /*! \overload fromHex() */ QKnxByteArray QKnxByteArray::fromHex(const QByteArray &hexEncoded) { QKnxByteArray hex(0, Qt::Uninitialized); hex.m_bytes = QByteArray::fromHex(hexEncoded); return hex; } /*! Returns a decoded copy of the hex encoded array \a hexEncoded. Input is not checked for validity; invalid characters in the input are skipped, enabling the decoding process to continue with subsequent characters. */ QKnxByteArray QKnxByteArray::fromHex(const QKnxByteArray &hexEncoded) { return QKnxByteArray::fromHex(hexEncoded.m_bytes); } /*! \typedef QKnxByteArray::iterator This typedef provides an STL-style non-const iterator for QKnxByteArray. */ /*! \typedef QKnxByteArray::const_iterator This typedef provides an STL-style const iterator for QKnxByteArray. */ /*! \internal \typedef QKnxByteArray::Iterator */ /*! \internal \typedef QKnxByteArray::ConstIterator */ /*! \typedef QKnxByteArray::reverse_iterator This typedef provides an STL-style non-const reverse iterator for QKnxByteArray. */ /*! \typedef QKnxByteArray::const_reverse_iterator This typedef provides an STL-style const reverse iterator for QKnxByteArray. */ /*! \fn QKnxByteArray::iterator QKnxByteArray::begin() Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in the byte array. */ /*! \overload begin() \fn QKnxByteArray::const_iterator QKnxByteArray::begin() const */ /*! \fn QKnxByteArray::const_iterator QKnxByteArray::cbegin() const Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the byte array. */ /*! \fn QKnxByteArray::const_iterator QKnxByteArray::constBegin() const Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the byte array. */ /*! \fn QKnxByteArray::iterator QKnxByteArray::end() Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character after the last character in the byte array. */ /*! \overload end() \fn QKnxByteArray::const_iterator QKnxByteArray::end() const */ /*! \fn QKnxByteArray::const_iterator QKnxByteArray::cend() const Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character after the last character in the list. */ /*! \fn QKnxByteArray::const_iterator QKnxByteArray::constEnd() const Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character after the last character in the list. */ /*! \fn QKnxByteArray::reverse_iterator QKnxByteArray::rbegin() Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first character in the byte array, in reverse order. */ /*! \fn QKnxByteArray::reverse_iterator QKnxByteArray::rend() Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past the last character in the byte array, in reverse order. */ /*! \overload rbegin() \fn QKnxByteArray::const_reverse_iterator QKnxByteArray::rbegin() const */ /*! \overload rend() \fn QKnxByteArray::const_reverse_iterator QKnxByteArray::rend() const */ /*! \fn QKnxByteArray::const_reverse_iterator QKnxByteArray::crbegin() const Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first character in the byte array, in reverse order. */ /*! \fn QKnxByteArray::const_reverse_iterator QKnxByteArray::crend() const Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one past the last character in the byte array, in reverse order. */ /*! \typedef QKnxByteArray::size_type \internal */ /*! \typedef QKnxByteArray::difference_type \internal */ /*! \typedef QKnxByteArray::const_reference \internal */ /*! \typedef QKnxByteArray::const_pointer \internal */ /*! \typedef QKnxByteArray::reference \internal */ /*! \typedef QKnxByteArray::pointer \internal */ /*! \typedef QKnxByteArray::value_type \internal */ /*! \overload operator+=() \fn QKnxByteArray &QKnxByteArray::operator+=(quint8 ch) Appends the character \a ch onto the end of this byte array and returns a reference to this byte array. */ /*! \fn QKnxByteArray &QKnxByteArray::operator+=(const QKnxByteArray &ba) Appends the byte array \a ba onto the end of this byte array and returns a reference to this byte array. */ /*! \relates QKnxByteArray \fn bool operator==(const QKnxByteArray &a1, const QKnxByteArray &a2) Returns \c true if the byte array \a a1 is equal to the byte array \a a2; otherwise returns \c false. */ /*! \relates QKnxByteArray \fn bool operator!=(const QKnxByteArray &a1, const QKnxByteArray &a2) Returns \c true if the byte array \a a1 is not equal to the byte array \a a2; otherwise returns \c false. */ /*! \relates QKnxByteArray \fn const QKnxByteArray operator+(const QKnxByteArray &a1, const QKnxByteArray &a2) Returns a byte array that is the result of concatenating the byte array \a a1 and byte array \a a2. */ /*! \overload operator+() \relates QKnxByteArray \fn const QKnxByteArray operator+(const QKnxByteArray &ba, quint8 ch) Returns a byte array that is the result of concatenating the byte array \a ba and character \a ch. */ /*! \overload operator+() \relates QKnxByteArray \fn const QKnxByteArray operator+(quint8 ch, const QKnxByteArray &ba) Returns a byte array that is the result of concatenating the character \a ch and byte array \a ba. */ /*! \relates QKnxByteArray Writes the byte array \a byteArray to the \a debug stream. */ QDebug operator<<(QDebug debug, const QKnxByteArray &byteArray) { debug << byteArray.toByteArray(); return debug; } /*! \relates QKnxByteArray \fn uint qHash(const QKnxByteArray &key, uint seed = 0) Returns the hash value for the \a key, using \a seed to seed the calculation. */ uint qHash(const QKnxByteArray &ba, uint seed) Q_DECL_NOTHROW { return qHash(ba.toByteArray(), seed); } QT_END_NAMESPACE