|
1 /**************************************************************************** |
|
2 ** |
|
3 ** |
|
4 ** Implementation of QBuffer class |
|
5 ** |
|
6 ** Created : 930812 |
|
7 ** |
|
8 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. |
|
9 ** |
|
10 ** This file is part of the tools module of the Qt GUI Toolkit. |
|
11 ** |
|
12 ** This file may be distributed under the terms of the Q Public License |
|
13 ** as defined by Trolltech AS of Norway and appearing in the file |
|
14 ** LICENSE.QPL included in the packaging of this file. |
|
15 ** |
|
16 ** This file may be distributed and/or modified under the terms of the |
|
17 ** GNU General Public License version 2 as published by the Free Software |
|
18 ** Foundation and appearing in the file LICENSE.GPL included in the |
|
19 ** packaging of this file. |
|
20 ** |
|
21 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition |
|
22 ** licenses may use this file in accordance with the Qt Commercial License |
|
23 ** Agreement provided with the Software. |
|
24 ** |
|
25 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
|
26 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
|
27 ** |
|
28 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for |
|
29 ** information about Qt Commercial License Agreements. |
|
30 ** See http://www.trolltech.com/qpl/ for QPL licensing information. |
|
31 ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
|
32 ** |
|
33 ** Contact info@trolltech.com if any conditions of this licensing are |
|
34 ** not clear to you. |
|
35 ** |
|
36 **********************************************************************/ |
|
37 |
|
38 #include "qbuffer.h" |
|
39 #include <stdlib.h> |
|
40 |
|
41 // REVISED: paul |
|
42 /*! |
|
43 \class QBuffer qbuffer.h |
|
44 \brief The QBuffer class is an I/O device that operates on a QByteArray |
|
45 |
|
46 \ingroup io |
|
47 |
|
48 QBuffer allows reading and writing a memory buffer. It is normally |
|
49 used together with a QTextStream or a QDataStream. QBuffer has an |
|
50 associated QByteArray which holds the buffer data. The size() of the |
|
51 buffer is automatically adjusted as data is written. |
|
52 |
|
53 The constructor \c QBuffer(QByteArray) creates a QBuffer with an |
|
54 existing byte array. The byte array can also be set with setBuffer(). |
|
55 Writing to the QBuffer will modify the original byte array, since |
|
56 QByteArray is \link shclass.html explicitly shared.\endlink |
|
57 |
|
58 Use open() to open the buffer before use, and to set the mode |
|
59 (read-only,write-only, etc.). close() closes the buffer. The buffer |
|
60 must be closed before reopening or calling setBuffer(). |
|
61 |
|
62 The common way to use QBuffer is through \l QDataStream or \l QTextStream |
|
63 which have constructors that take a QBuffer parameter. For |
|
64 convenience, there are also QDataStream and QTextStream constructors |
|
65 that take a QByteArray parameter. These constructors create and open |
|
66 an internal QBuffer. |
|
67 |
|
68 Note that QTextStream can also operate on a QString (a Unicode |
|
69 string); a QBuffer cannot. |
|
70 |
|
71 You can also use QBuffer directly through the standard QIODevice |
|
72 functions readBlock(), writeBlock() readLine(), at(), getch(), putch() and |
|
73 ungetch(). |
|
74 |
|
75 \sa QFile, QDataStream, QTextStream, QByteArray, \link shclass.html Shared Classes\endlink |
|
76 */ |
|
77 |
|
78 |
|
79 /*! |
|
80 Constructs an empty buffer. |
|
81 */ |
|
82 |
|
83 QBuffer::QBuffer() |
|
84 { |
|
85 setFlags( IO_Direct ); |
|
86 a_inc = 16; // initial increment |
|
87 a_len = 0; |
|
88 ioIndex = 0; |
|
89 } |
|
90 |
|
91 |
|
92 /*! |
|
93 Constructs a buffer that operates on \a buf. |
|
94 If you open the buffer in write mode (\c IO_WriteOnly or |
|
95 \c IO_ReadWrite) and write something into the buffer, \a buf |
|
96 will be modified. |
|
97 |
|
98 |
|
99 Example: |
|
100 \code |
|
101 QCString str = "abc"; |
|
102 QBuffer b( str ); |
|
103 b.open( IO_WriteOnly ); |
|
104 b.at( 3 ); // position at \0 |
|
105 b.writeBlock( "def", 4 ); // write including \0 |
|
106 b.close(); |
|
107 // Now, str == "abcdef" |
|
108 \endcode |
|
109 |
|
110 |
|
111 \sa setBuffer() |
|
112 */ |
|
113 |
|
114 QBuffer::QBuffer( QByteArray buf ) : a(buf) |
|
115 { |
|
116 setFlags( IO_Direct ); |
|
117 a_len = a.size(); |
|
118 a_inc = (a_len > 512) ? 512 : a_len; // initial increment |
|
119 if ( a_inc < 16 ) |
|
120 a_inc = 16; |
|
121 ioIndex = 0; |
|
122 } |
|
123 |
|
124 /*! |
|
125 Destructs the buffer. |
|
126 */ |
|
127 |
|
128 QBuffer::~QBuffer() |
|
129 { |
|
130 } |
|
131 |
|
132 |
|
133 /*! |
|
134 Replaces the buffer's contents with \a buf. |
|
135 |
|
136 This may not be done when isOpen() is TRUE. |
|
137 |
|
138 Note that if you open the buffer in write mode (\c IO_WriteOnly or |
|
139 IO_ReadWrite) and write something into the buffer, \a buf is also |
|
140 modified because QByteArray is an explicitly shared class. |
|
141 |
|
142 \sa buffer(), open(), close() |
|
143 */ |
|
144 |
|
145 bool QBuffer::setBuffer( QByteArray buf ) |
|
146 { |
|
147 if ( isOpen() ) { |
|
148 #if defined(CHECK_STATE) |
|
149 qWarning( "QBuffer::setBuffer: Buffer is open"); |
|
150 #endif |
|
151 return FALSE; |
|
152 } |
|
153 a = buf; |
|
154 a_len = a.size(); |
|
155 a_inc = (a_len > 512) ? 512 : a_len; // initial increment |
|
156 if ( a_inc < 16 ) |
|
157 a_inc = 16; |
|
158 ioIndex = 0; |
|
159 return TRUE; |
|
160 } |
|
161 |
|
162 /*! |
|
163 \fn QByteArray QBuffer::buffer() const |
|
164 |
|
165 Returns this buffer's byte array. |
|
166 |
|
167 \sa setBuffer() |
|
168 */ |
|
169 |
|
170 /*! |
|
171 \reimp |
|
172 Opens the buffer in the mode \a m. Returns TRUE if successful, |
|
173 otherwise FALSE. The buffer must be opened before use. |
|
174 |
|
175 The mode parameter \a m must be a combination of the following flags. |
|
176 <ul> |
|
177 <li>\c IO_ReadOnly opens a buffer in read-only mode. |
|
178 <li>\c IO_WriteOnly opens a buffer in write-only mode. |
|
179 <li>\c IO_ReadWrite opens a buffer in read/write mode. |
|
180 <li>\c IO_Append sets the buffer index to the end of the buffer. |
|
181 <li>\c IO_Truncate truncates the buffer. |
|
182 </ul> |
|
183 |
|
184 \sa close(), isOpen() |
|
185 */ |
|
186 |
|
187 bool QBuffer::open( int m ) |
|
188 { |
|
189 if ( isOpen() ) { // buffer already open |
|
190 #if defined(CHECK_STATE) |
|
191 qWarning( "QBuffer::open: Buffer already open" ); |
|
192 #endif |
|
193 return FALSE; |
|
194 } |
|
195 setMode( m ); |
|
196 if ( m & IO_Truncate ) { // truncate buffer |
|
197 a.resize( 0 ); |
|
198 a_len = 0; |
|
199 } |
|
200 if ( m & IO_Append ) { // append to end of buffer |
|
201 ioIndex = a.size(); |
|
202 } else { |
|
203 ioIndex = 0; |
|
204 } |
|
205 a_inc = 16; |
|
206 setState( IO_Open ); |
|
207 setStatus( 0 ); |
|
208 return TRUE; |
|
209 } |
|
210 |
|
211 /*! |
|
212 \reimp |
|
213 Closes an open buffer. |
|
214 \sa open() |
|
215 */ |
|
216 |
|
217 void QBuffer::close() |
|
218 { |
|
219 if ( isOpen() ) { |
|
220 setFlags( IO_Direct ); |
|
221 ioIndex = 0; |
|
222 a_inc = 16; |
|
223 } |
|
224 } |
|
225 |
|
226 /*! |
|
227 \reimp |
|
228 The flush function does nothing for a QBuffer. |
|
229 */ |
|
230 |
|
231 void QBuffer::flush() |
|
232 { |
|
233 return; |
|
234 } |
|
235 |
|
236 |
|
237 /*! |
|
238 \fn int QBuffer::at() const |
|
239 \reimp |
|
240 */ |
|
241 |
|
242 /*! |
|
243 \fn uint QBuffer::size() const |
|
244 \reimp |
|
245 */ |
|
246 |
|
247 /*! |
|
248 \reimp |
|
249 */ |
|
250 |
|
251 bool QBuffer::at( int pos ) |
|
252 { |
|
253 #if defined(CHECK_STATE) |
|
254 if ( !isOpen() ) { |
|
255 qWarning( "QBuffer::at: Buffer is not open" ); |
|
256 return FALSE; |
|
257 } |
|
258 #endif |
|
259 if ( (uint)pos > a_len ) { |
|
260 #if defined(CHECK_RANGE) |
|
261 qWarning( "QBuffer::at: Index %d out of range", pos ); |
|
262 #endif |
|
263 return FALSE; |
|
264 } |
|
265 ioIndex = pos; |
|
266 return TRUE; |
|
267 } |
|
268 |
|
269 |
|
270 /*! |
|
271 \reimp |
|
272 */ |
|
273 |
|
274 int QBuffer::readBlock( char *p, uint len ) |
|
275 { |
|
276 #if defined(CHECK_STATE) |
|
277 CHECK_PTR( p ); |
|
278 if ( !isOpen() ) { // buffer not open |
|
279 qWarning( "QBuffer::readBlock: Buffer not open" ); |
|
280 return -1; |
|
281 } |
|
282 if ( !isReadable() ) { // reading not permitted |
|
283 qWarning( "QBuffer::readBlock: Read operation not permitted" ); |
|
284 return -1; |
|
285 } |
|
286 #endif |
|
287 if ( (uint)ioIndex + len > a.size() ) { // overflow |
|
288 if ( (uint)ioIndex >= a.size() ) { |
|
289 setStatus( IO_ReadError ); |
|
290 return -1; |
|
291 } else { |
|
292 len = a.size() - (uint)ioIndex; |
|
293 } |
|
294 } |
|
295 memcpy( p, a.data()+ioIndex, len ); |
|
296 ioIndex += len; |
|
297 return len; |
|
298 } |
|
299 |
|
300 /*! |
|
301 \reimp |
|
302 |
|
303 Writes \a len bytes from \a p into the buffer at the current index, |
|
304 overwriting any characters there and extending the buffer if necessary. |
|
305 Returns the number of bytes actually written. |
|
306 |
|
307 Returns -1 if a serious error occurred. |
|
308 |
|
309 \sa readBlock() |
|
310 */ |
|
311 |
|
312 int QBuffer::writeBlock( const char *p, uint len ) |
|
313 { |
|
314 #if defined(CHECK_NULL) |
|
315 if ( p == 0 && len != 0 ) |
|
316 qWarning( "QBuffer::writeBlock: Null pointer error" ); |
|
317 #endif |
|
318 #if defined(CHECK_STATE) |
|
319 if ( !isOpen() ) { // buffer not open |
|
320 qWarning( "QBuffer::writeBlock: Buffer not open" ); |
|
321 return -1; |
|
322 } |
|
323 if ( !isWritable() ) { // writing not permitted |
|
324 qWarning( "QBuffer::writeBlock: Write operation not permitted" ); |
|
325 return -1; |
|
326 } |
|
327 #endif |
|
328 if ( (uint)ioIndex + len >= a_len ) { // overflow |
|
329 uint new_len = a_len + a_inc*(((uint)ioIndex+len-a_len)/a_inc+1); |
|
330 if ( !a.resize( new_len ) ) { // could not resize |
|
331 #if defined(CHECK_NULL) |
|
332 qWarning( "QBuffer::writeBlock: Memory allocation error" ); |
|
333 #endif |
|
334 setStatus( IO_ResourceError ); |
|
335 return -1; |
|
336 } |
|
337 a_inc *= 2; // double increment |
|
338 a_len = new_len; |
|
339 a.shd->len = (uint)ioIndex + len; |
|
340 } |
|
341 memcpy( a.data()+ioIndex, p, len ); |
|
342 ioIndex += len; |
|
343 if ( a.shd->len < (uint)ioIndex ) |
|
344 a.shd->len = (uint)ioIndex; // fake (not alloc'd) length |
|
345 return len; |
|
346 } |
|
347 |
|
348 |
|
349 /*! |
|
350 \reimp |
|
351 */ |
|
352 |
|
353 int QBuffer::readLine( char *p, uint maxlen ) |
|
354 { |
|
355 #if defined(CHECK_STATE) |
|
356 CHECK_PTR( p ); |
|
357 if ( !isOpen() ) { // buffer not open |
|
358 qWarning( "QBuffer::readLine: Buffer not open" ); |
|
359 return -1; |
|
360 } |
|
361 if ( !isReadable() ) { // reading not permitted |
|
362 qWarning( "QBuffer::readLine: Read operation not permitted" ); |
|
363 return -1; |
|
364 } |
|
365 #endif |
|
366 if ( maxlen == 0 ) |
|
367 return 0; |
|
368 uint start = (uint)ioIndex; |
|
369 char *d = a.data() + ioIndex; |
|
370 maxlen--; // make room for 0-terminator |
|
371 if ( a.size() - (uint)ioIndex < maxlen ) |
|
372 maxlen = a.size() - (uint)ioIndex; |
|
373 while ( maxlen-- ) { |
|
374 if ( (*p++ = *d++) == '\n' ) |
|
375 break; |
|
376 } |
|
377 *p = '\0'; |
|
378 ioIndex = d - a.data(); |
|
379 return (uint)ioIndex - start; |
|
380 } |
|
381 |
|
382 |
|
383 /*! |
|
384 \reimp |
|
385 */ |
|
386 |
|
387 int QBuffer::getch() |
|
388 { |
|
389 #if defined(CHECK_STATE) |
|
390 if ( !isOpen() ) { // buffer not open |
|
391 qWarning( "QBuffer::getch: Buffer not open" ); |
|
392 return -1; |
|
393 } |
|
394 if ( !isReadable() ) { // reading not permitted |
|
395 qWarning( "QBuffer::getch: Read operation not permitted" ); |
|
396 return -1; |
|
397 } |
|
398 #endif |
|
399 if ( (uint)ioIndex+1 > a.size() ) { // overflow |
|
400 setStatus( IO_ReadError ); |
|
401 return -1; |
|
402 } |
|
403 return uchar(*(a.data()+ioIndex++)); |
|
404 } |
|
405 |
|
406 /*! |
|
407 \reimp |
|
408 Writes the character \a ch into the buffer, overwriting |
|
409 the character at the current index, extending the buffer |
|
410 if necessary. |
|
411 |
|
412 Returns \a ch, or -1 if some error occurred. |
|
413 |
|
414 \sa getch(), ungetch() |
|
415 */ |
|
416 |
|
417 int QBuffer::putch( int ch ) |
|
418 { |
|
419 #if defined(CHECK_STATE) |
|
420 if ( !isOpen() ) { // buffer not open |
|
421 qWarning( "QBuffer::putch: Buffer not open" ); |
|
422 return -1; |
|
423 } |
|
424 if ( !isWritable() ) { // writing not permitted |
|
425 qWarning( "QBuffer::putch: Write operation not permitted" ); |
|
426 return -1; |
|
427 } |
|
428 #endif |
|
429 if ( (uint)ioIndex + 1 >= a_len ) { // overflow |
|
430 char buf[1]; |
|
431 buf[0] = (char)ch; |
|
432 if ( writeBlock(buf,1) != 1 ) |
|
433 return -1; // write error |
|
434 } else { |
|
435 *(a.data() + ioIndex++) = (char)ch; |
|
436 if ( a.shd->len < (uint)ioIndex ) |
|
437 a.shd->len = (uint)ioIndex; |
|
438 } |
|
439 return ch; |
|
440 } |
|
441 |
|
442 /*! |
|
443 \reimp |
|
444 */ |
|
445 |
|
446 int QBuffer::ungetch( int ch ) |
|
447 { |
|
448 #if defined(CHECK_STATE) |
|
449 if ( !isOpen() ) { // buffer not open |
|
450 qWarning( "QBuffer::ungetch: Buffer not open" ); |
|
451 return -1; |
|
452 } |
|
453 if ( !isReadable() ) { // reading not permitted |
|
454 qWarning( "QBuffer::ungetch: Read operation not permitted" ); |
|
455 return -1; |
|
456 } |
|
457 #endif |
|
458 if ( ch != -1 ) { |
|
459 if ( ioIndex ) |
|
460 ioIndex--; |
|
461 else |
|
462 ch = -1; |
|
463 } |
|
464 return ch; |
|
465 } |