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: |
68 | QByteDataBuffer() : bufferCompleteSize(0), firstPos(0) |
69 | { |
70 | } |
71 | |
72 | ~QByteDataBuffer() |
73 | { |
74 | clear(); |
75 | } |
76 | |
77 | static inline void popFront(QByteArray &ba, qint64 n) |
78 | { |
79 | ba = QByteArray(ba.constData() + n, ba.size() - n); |
80 | } |
81 | |
82 | inline void squeezeFirst() |
83 | { |
84 | if (!buffers.isEmpty() && firstPos > 0) { |
85 | popFront(ba&: buffers.first(), n: firstPos); |
86 | firstPos = 0; |
87 | } |
88 | } |
89 | |
90 | inline void append(const QByteDataBuffer& other) |
91 | { |
92 | if (other.isEmpty()) |
93 | return; |
94 | |
95 | buffers.append(t: other.buffers); |
96 | bufferCompleteSize += other.byteAmount(); |
97 | |
98 | if (other.firstPos > 0) |
99 | popFront(ba&: buffers[bufferCount() - other.bufferCount()], n: other.firstPos); |
100 | } |
101 | |
102 | |
103 | inline void append(const QByteArray& bd) |
104 | { |
105 | if (bd.isEmpty()) |
106 | return; |
107 | |
108 | buffers.append(t: bd); |
109 | bufferCompleteSize += bd.size(); |
110 | } |
111 | |
112 | inline void prepend(const QByteArray& bd) |
113 | { |
114 | if (bd.isEmpty()) |
115 | return; |
116 | |
117 | squeezeFirst(); |
118 | |
119 | buffers.prepend(t: 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. |
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. |
134 | inline QByteArray readAll() |
135 | { |
136 | return read(amount: 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. |
141 | inline QByteArray read(qint64 amount) |
142 | { |
143 | amount = qMin(a: byteAmount(), b: amount); |
144 | QByteArray byteData; |
145 | byteData.resize(size: amount); |
146 | read(dst: byteData.data(), amount: 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. |
152 | qint64 read(char* dst, qint64 amount) |
153 | { |
154 | amount = qMin(a: amount, b: 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(dest: writeDst, src: first.constData() + firstPos, n: 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(dest: writeDst, src: first.constData() + firstPos, n: amount); |
173 | firstPos += amount; |
174 | amount = 0; |
175 | } |
176 | } |
177 | |
178 | return originalAmount; |
179 | } |
180 | |
181 | inline char getChar() |
182 | { |
183 | char c; |
184 | read(dst: &c, amount: 1); |
185 | return c; |
186 | } |
187 | |
188 | inline void clear() |
189 | { |
190 | buffers.clear(); |
191 | bufferCompleteSize = 0; |
192 | firstPos = 0; |
193 | } |
194 | |
195 | // The byte count of all QByteArrays |
196 | inline qint64 byteAmount() const |
197 | { |
198 | return bufferCompleteSize; |
199 | } |
200 | |
201 | // the number of QByteArrays |
202 | inline int bufferCount() const |
203 | { |
204 | return buffers.length(); |
205 | } |
206 | |
207 | inline bool isEmpty() const |
208 | { |
209 | return byteAmount() == 0; |
210 | } |
211 | |
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 | |
228 | inline bool canReadLine() const { |
229 | int i = 0; |
230 | if (i < buffers.length()) { |
231 | if (buffers.at(i).indexOf(c: '\n', from: firstPos) != -1) |
232 | return true; |
233 | ++i; |
234 | |
235 | for (; i < buffers.length(); i++) |
236 | if (buffers.at(i).contains(c: '\n')) |
237 | return true; |
238 | } |
239 | return false; |
240 | } |
241 | }; |
242 | |
243 | QT_END_NAMESPACE |
244 | |
245 | #endif // QBYTEDATA_P_H |
246 | |