1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtCore module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 40 #ifndef QBYTEDATA_P_H 41 #define QBYTEDATA_P_H 42 43 // 44 // W A R N I N G 45 // ------------- 46 // 47 // This file is not part of the Qt API. It exists purely as an 48 // implementation detail. This header file may change from version to 49 // version without notice, or even be removed. 50 // 51 // We mean it. 52 // 53 54 #include <QtCore/private/qglobal_p.h> 55 #include <qbytearray.h> 56 57 QT_BEGIN_NAMESPACE 58 59 // this class handles a list of QByteArrays. It is a variant of QRingBuffer 60 // that avoid malloc/realloc/memcpy. 61 class QByteDataBuffer 62 { 63 private: 64 QList<QByteArray> buffers; 65 qint64 bufferCompleteSize; 66 qint64 firstPos; 67 public: QByteDataBuffer()68 QByteDataBuffer() : bufferCompleteSize(0), firstPos(0) 69 { 70 } 71 ~QByteDataBuffer()72 ~QByteDataBuffer() 73 { 74 clear(); 75 } 76 popFront(QByteArray & ba,qint64 n)77 static inline void popFront(QByteArray &ba, qint64 n) 78 { 79 ba = QByteArray(ba.constData() + n, ba.size() - n); 80 } 81 squeezeFirst()82 inline void squeezeFirst() 83 { 84 if (!buffers.isEmpty() && firstPos > 0) { 85 popFront(buffers.first(), firstPos); 86 firstPos = 0; 87 } 88 } 89 append(const QByteDataBuffer & other)90 inline void append(const QByteDataBuffer& other) 91 { 92 if (other.isEmpty()) 93 return; 94 95 buffers.append(other.buffers); 96 bufferCompleteSize += other.byteAmount(); 97 98 if (other.firstPos > 0) 99 popFront(buffers[bufferCount() - other.bufferCount()], other.firstPos); 100 } 101 102 append(const QByteArray & bd)103 inline void append(const QByteArray& bd) 104 { 105 if (bd.isEmpty()) 106 return; 107 108 buffers.append(bd); 109 bufferCompleteSize += bd.size(); 110 } 111 prepend(const QByteArray & bd)112 inline void prepend(const QByteArray& bd) 113 { 114 if (bd.isEmpty()) 115 return; 116 117 squeezeFirst(); 118 119 buffers.prepend(bd); 120 bufferCompleteSize += bd.size(); 121 } 122 123 // return the first QByteData. User of this function has to free() its .data! 124 // preferably use this function to read data. read()125 inline QByteArray read() 126 { 127 squeezeFirst(); 128 bufferCompleteSize -= buffers.first().size(); 129 return buffers.takeFirst(); 130 } 131 132 // return everything. User of this function has to free() its .data! 133 // avoid to use this, it might malloc and memcpy. readAll()134 inline QByteArray readAll() 135 { 136 return read(byteAmount()); 137 } 138 139 // return amount. User of this function has to free() its .data! 140 // avoid to use this, it might malloc and memcpy. read(qint64 amount)141 inline QByteArray read(qint64 amount) 142 { 143 amount = qMin(byteAmount(), amount); 144 QByteArray byteData; 145 byteData.resize(amount); 146 read(byteData.data(), byteData.size()); 147 return byteData; 148 } 149 150 // return amount bytes. User of this function has to free() its .data! 151 // avoid to use this, it will memcpy. read(char * dst,qint64 amount)152 qint64 read(char* dst, qint64 amount) 153 { 154 amount = qMin(amount, byteAmount()); 155 qint64 originalAmount = amount; 156 char *writeDst = dst; 157 158 while (amount > 0) { 159 const QByteArray &first = buffers.first(); 160 qint64 firstSize = first.size() - firstPos; 161 if (amount >= firstSize) { 162 // take it completely 163 bufferCompleteSize -= firstSize; 164 amount -= firstSize; 165 memcpy(writeDst, first.constData() + firstPos, firstSize); 166 writeDst += firstSize; 167 firstPos = 0; 168 buffers.takeFirst(); 169 } else { 170 // take a part of it & it is the last one to take 171 bufferCompleteSize -= amount; 172 memcpy(writeDst, first.constData() + firstPos, amount); 173 firstPos += amount; 174 amount = 0; 175 } 176 } 177 178 return originalAmount; 179 } 180 getChar()181 inline char getChar() 182 { 183 char c; 184 read(&c, 1); 185 return c; 186 } 187 clear()188 inline void clear() 189 { 190 buffers.clear(); 191 bufferCompleteSize = 0; 192 firstPos = 0; 193 } 194 195 // The byte count of all QByteArrays byteAmount()196 inline qint64 byteAmount() const 197 { 198 return bufferCompleteSize; 199 } 200 201 // the number of QByteArrays bufferCount()202 inline int bufferCount() const 203 { 204 return buffers.length(); 205 } 206 isEmpty()207 inline bool isEmpty() const 208 { 209 return byteAmount() == 0; 210 } 211 sizeNextBlock()212 inline qint64 sizeNextBlock() const 213 { 214 if(buffers.isEmpty()) 215 return 0; 216 else 217 return buffers.first().size() - firstPos; 218 } 219 220 inline QByteArray& operator[](int i) 221 { 222 if (i == 0) 223 squeezeFirst(); 224 225 return buffers[i]; 226 } 227 canReadLine()228 inline bool canReadLine() const { 229 int i = 0; 230 if (i < buffers.length()) { 231 if (buffers.at(i).indexOf('\n', firstPos) != -1) 232 return true; 233 ++i; 234 235 for (; i < buffers.length(); i++) 236 if (buffers.at(i).contains('\n')) 237 return true; 238 } 239 return false; 240 } 241 }; 242 243 QT_END_NAMESPACE 244 245 #endif // QBYTEDATA_P_H 246