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