source: trunk/src/qt3support/text/q3textstream.cpp@ 324

Last change on this file since 324 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 55.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt3Support module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "q3textstream.h"
43#include <qdebug.h>
44
45#ifndef QT_NO_TEXTSTREAM
46#include "qtextcodec.h"
47#include "qregexp.h"
48#include "qbuffer.h"
49#include "qfile.h"
50#include "q3cstring.h"
51#include <stdio.h>
52#include <ctype.h>
53#include <stdlib.h>
54#ifndef Q_OS_WINCE
55#include <locale.h>
56#endif
57
58#if defined(Q_OS_WIN32)
59#include "qt_windows.h"
60#endif
61
62QT_BEGIN_NAMESPACE
63
64#ifndef QT_NO_TEXTCODEC
65static void resetCodecConverterState(QTextCodec::ConverterState *state) {
66 state->flags = QTextCodec::DefaultConversion;
67 state->remainingChars = state->invalidChars =
68 state->state_data[0] = state->state_data[1] = state->state_data[2] = 0;
69 if (state->d) qFree(state->d);
70 state->d = 0;
71}
72#endif
73
74/*!
75 \class Q3TextStream
76 \compat
77 \reentrant
78 \brief The Q3TextStream class provides basic functions for reading
79 and writing text using a QIODevice.
80
81 The text stream class has a functional interface that is very
82 similar to that of the standard C++ iostream class.
83
84 Qt provides several global functions similar to the ones in iostream:
85 \table
86 \header \i Function \i Meaning
87 \row \i bin \i sets the Q3TextStream to read/write binary numbers
88 \row \i oct \i sets the Q3TextStream to read/write octal numbers
89 \row \i dec \i sets the Q3TextStream to read/write decimal numbers
90 \row \i hex \i sets the Q3TextStream to read/write hexadecimal numbers
91 \row \i endl \i forces a line break
92 \row \i flush \i forces the QIODevice to flush any buffered data
93 \row \i ws \i eats any available whitespace (on input)
94 \row \i reset \i resets the Q3TextStream to its default mode (see reset())
95 \row \i qSetW(int) \i sets the \link width() field width \endlink
96 to the given argument
97 \row \i qSetFill(int) \i sets the \link fill() fill character
98 \endlink to the given argument
99 \row \i qSetPrecision(int) \i sets the \link precision() precision
100 \endlink to the given argument
101 \endtable
102
103 \warning By default Q3TextStream will automatically detect whether
104 integers in the stream are in decimal, octal, hexadecimal or
105 binary format when reading from the stream. In particular, a
106 leading '0' signifies octal, i.e. the sequence "0100" will be
107 interpreted as 64.
108
109 The Q3TextStream class reads and writes text; it is not appropriate
110 for dealing with binary data (but QDataStream is).
111
112 By default, output of Unicode text (i.e. QString) is done using
113 the local 8-bit encoding. This can be changed using the
114 setEncoding() method. For input, the Q3TextStream will auto-detect
115 standard Unicode "byte order marked" text files; otherwise the
116 local 8-bit encoding is used.
117
118 The QIODevice is set in the constructor, or later using
119 setDevice(). If the end of the input is reached atEnd() returns
120 TRUE. Data can be read into variables of the appropriate type
121 using the operator>>() overloads, or read in its entirety into a
122 single string using read(), or read a line at a time using
123 readLine(). Whitespace can be skipped over using skipWhiteSpace().
124 You can set flags for the stream using flags() or setf(). The
125 stream also supports width(), precision() and fill(); use reset()
126 to reset the defaults.
127
128 \sa QDataStream
129*/
130
131/*!
132 \enum Q3TextStream::Encoding
133
134 \value Locale
135 \value Latin1
136 \value Unicode
137 \value UnicodeNetworkOrder
138 \value UnicodeReverse
139 \value RawUnicode
140 \value UnicodeUTF8
141
142 See setEncoding() for an explanation of the encodings.
143*/
144
145/*
146 \class QTSManip
147 \internal
148*/
149
150#if defined(QT_CHECK_STATE)
151#undef CHECK_STREAM_PRECOND
152#define CHECK_STREAM_PRECOND if ( !dev ) { \
153 qWarning( "Q3TextStream: No device" ); \
154 return *this; }
155#else
156#define CHECK_STREAM_PRECOND
157#endif
158
159
160#define I_SHORT 0x0010
161#define I_INT 0x0020
162#define I_LONG 0x0030
163#define I_TYPE_MASK 0x00f0
164
165#define I_BASE_2 Q3TextStream::bin
166#define I_BASE_8 Q3TextStream::oct
167#define I_BASE_10 Q3TextStream::dec
168#define I_BASE_16 Q3TextStream::hex
169#define I_BASE_MASK (Q3TextStream::bin | Q3TextStream::oct | Q3TextStream::dec | Q3TextStream::hex)
170
171#define I_SIGNED 0x0100
172#define I_UNSIGNED 0x0200
173#define I_SIGN_MASK 0x0f00
174
175
176static const QChar QEOF = QChar((ushort)0xffff); //guaranteed not to be a character.
177static const uint getline_buf_size = 256; // bufsize used by ts_getline()
178
179const int Q3TextStream::basefield = I_BASE_MASK;
180const int Q3TextStream::adjustfield = ( Q3TextStream::left |
181 Q3TextStream::right |
182 Q3TextStream::internal );
183const int Q3TextStream::floatfield = ( Q3TextStream::scientific |
184 Q3TextStream::fixed );
185
186
187class Q3TextStreamPrivate {
188public:
189#ifndef QT_NO_TEXTCODEC
190 Q3TextStreamPrivate()
191 : sourceType( NotSet ) { }
192 ~Q3TextStreamPrivate() {
193 }
194#else
195 Q3TextStreamPrivate() : sourceType( NotSet ) { }
196 ~Q3TextStreamPrivate() { }
197#endif
198 QString ungetcBuf;
199
200 enum SourceType { NotSet, IODevice, String, ByteArray, File };
201 SourceType sourceType;
202};
203
204
205// skips whitespace and returns the first non-whitespace character
206QChar Q3TextStream::eat_ws()
207{
208 QChar c;
209 do { c = ts_getc(); } while ( c != QEOF && ts_isspace(c) );
210 return c;
211}
212
213void Q3TextStream::init()
214{
215 // ### ungetcBuf = QEOF;
216 dev = 0;
217 owndev = FALSE;
218 mapper = 0;
219#ifndef QT_NO_TEXTCODEC
220 resetCodecConverterState(&mapperReadState);
221 resetCodecConverterState(&mapperWriteState);
222#endif
223 d = new Q3TextStreamPrivate;
224 doUnicodeHeader = TRUE; // autodetect
225 latin1 = TRUE; // should use locale?
226 internalOrder = QChar::networkOrdered();
227 networkOrder = TRUE;
228}
229
230/*!
231 Constructs a data stream that has no IO device.
232*/
233
234Q3TextStream::Q3TextStream()
235{
236 init();
237 setEncoding( Locale );
238 reset();
239 d->sourceType = Q3TextStreamPrivate::NotSet;
240}
241
242/*!
243 Constructs a text stream that uses the IO device \a iod.
244*/
245
246Q3TextStream::Q3TextStream( QIODevice *iod )
247{
248 init();
249 setEncoding( Locale );
250 dev = iod;
251 reset();
252 d->sourceType = Q3TextStreamPrivate::IODevice;
253}
254
255// TODO: use special-case handling of this case in Q3TextStream, and
256// simplify this class to only deal with QChar or QString data.
257class QStringBuffer : public QIODevice {
258public:
259 QStringBuffer( QString* str );
260 ~QStringBuffer();
261 bool open( OpenMode m );
262 void close();
263 qint64 size() const;
264
265protected:
266 qint64 readData( char *p, qint64 len );
267 qint64 writeData( const char *p, qint64 len );
268
269 QString* s;
270
271private:
272 QStringBuffer( const QStringBuffer & );
273 QStringBuffer &operator=( const QStringBuffer & );
274};
275
276
277QStringBuffer::QStringBuffer( QString* str )
278{
279 s = str;
280}
281
282QStringBuffer::~QStringBuffer()
283{
284}
285
286
287bool QStringBuffer::open( OpenMode m )
288{
289 if ( !s ) {
290#if defined(QT_CHECK_STATE)
291 qWarning( "QStringBuffer::open: No string" );
292#endif
293 return FALSE;
294 }
295 if ( isOpen() ) {
296#if defined(QT_CHECK_STATE)
297 qWarning( "QStringBuffer::open: Buffer already open" );
298#endif
299 return FALSE;
300 }
301 setOpenMode( m );
302 if ( m & QIODevice::Truncate )
303 s->truncate( 0 );
304
305 if ( m & QIODevice::Append ) {
306 seek(s->length()*sizeof(QChar));
307 } else {
308 seek(0);
309 }
310 return TRUE;
311}
312
313void QStringBuffer::close()
314{
315 if ( isOpen() ) {
316 seek(0);
317 QIODevice::close();
318 }
319}
320
321qint64 QStringBuffer::size() const
322{
323 return s ? s->length()*sizeof(QChar) : 0;
324}
325
326qint64 QStringBuffer::readData( char *p, qint64 len )
327{
328#if defined(QT_CHECK_STATE)
329 Q_CHECK_PTR( p );
330 if ( !isOpen() ) {
331 qWarning( "QStringBuffer::readBlock: Buffer not open" );
332 return qint64(-1);
333 }
334 if ( !isReadable() ) {
335 qWarning( "QStringBuffer::readBlock: Read operation not permitted" );
336 return qint64(-1);
337 }
338#endif
339 if ( pos() + len > qint64(s->length()*sizeof(QChar)) ) {
340 // overflow
341 if ( pos() >= qint64(s->length()*sizeof(QChar)) ) {
342 return -1;
343 } else {
344 len = s->length()*2 - pos();
345 }
346 }
347 memcpy( p, ((const char*)(s->unicode()))+pos(), len );
348 return len;
349}
350
351qint64 QStringBuffer::writeData( const char *p, qint64 len )
352{
353#if defined(QT_CHECK_NULL)
354 if ( p == 0 && len != 0 )
355 qWarning( "QStringBuffer::writeBlock: Null pointer error" );
356#endif
357#if defined(QT_CHECK_STATE)
358 if ( !isOpen() ) {
359 qWarning( "QStringBuffer::writeBlock: Buffer not open" );
360 return -1;
361 }
362 if ( !isWritable() ) {
363 qWarning( "QStringBuffer::writeBlock: Write operation not permitted" );
364 return -1;
365 }
366 if ( pos()&1 ) {
367 qWarning( "QStringBuffer::writeBlock: non-even index - non Unicode" );
368 return -1;
369 }
370 if ( len&1 ) {
371 qWarning( "QStringBuffer::writeBlock: non-even length - non Unicode" );
372 return -1;
373 }
374#endif
375 s->replace(pos()/2, len/2, (QChar*)p, len/2);
376 return len;
377}
378
379/*!
380 Constructs a text stream that operates on the Unicode QString, \a
381 str, through an internal device. The \a filemode argument is
382 passed to the device's open() function; see \l{QIODevice::mode()}.
383
384 If you set an encoding or codec with setEncoding() or setCodec(),
385 this setting is ignored for text streams that operate on QString.
386
387 Example:
388 \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 0
389
390 Writing data to the text stream will modify the contents of the
391 string. The string will be expanded when data is written beyond
392 the end of the string. Note that the string will not be truncated:
393 \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 1
394
395 Note that because QString is Unicode, you should not use
396 readRawBytes() or writeRawBytes() on such a stream.
397*/
398
399Q3TextStream::Q3TextStream( QString* str, int filemode )
400{
401 // TODO: optimize for this case as it becomes more common
402 // (see QStringBuffer above)
403 init();
404 dev = new QStringBuffer( str );
405 ((QStringBuffer *)dev)->open( QIODevice::OpenMode(filemode) );
406 owndev = TRUE;
407 setEncoding(RawUnicode);
408 reset();
409 d->sourceType = Q3TextStreamPrivate::String;
410}
411
412/*! \obsolete
413
414 This constructor is equivalent to the constructor taking a QString*
415 parameter.
416*/
417
418Q3TextStream::Q3TextStream( QString& str, int filemode )
419{
420 init();
421 dev = new QStringBuffer( &str );
422 ((QStringBuffer *)dev)->open( QIODevice::OpenMode(filemode) );
423 owndev = TRUE;
424 setEncoding(RawUnicode);
425 reset();
426 d->sourceType = Q3TextStreamPrivate::String;
427}
428
429/*!
430 Constructs a text stream that operates on the byte array, \a a,
431 through an internal QBuffer device. The \a mode argument is passed
432 to the device's open() function; see \l{QIODevice::mode()}.
433
434 Example:
435 \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 2
436
437 Writing data to the text stream will modify the contents of the
438 array. The array will be expanded when data is written beyond the
439 end of the string.
440
441 Same example, using a QBuffer:
442 \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 3
443*/
444
445Q3TextStream::Q3TextStream( QByteArray &a, int mode )
446{
447 init();
448 QBuffer *buffer = new QBuffer;
449 buffer->setBuffer( &a );
450 buffer->open( QIODevice::OpenMode(mode) );
451 dev = buffer;
452 owndev = TRUE;
453 setEncoding( Latin1 ); //### Locale???
454 reset();
455 d->sourceType = Q3TextStreamPrivate::ByteArray;
456}
457
458/*!
459 Constructs a text stream that operates on an existing file handle
460 \a fh through an internal QFile device. The \a mode argument is
461 passed to the device's open() function; see \l{QIODevice::mode()}.
462
463 Note that if you create a Q3TextStream \c cout or another name that
464 is also used for another variable of a different type, some
465 linkers may confuse the two variables, which will often cause
466 crashes.
467*/
468
469Q3TextStream::Q3TextStream( FILE *fh, int mode )
470{
471 init();
472 setEncoding( Locale ); //###
473 dev = new QFile;
474 ((QFile *)dev)->open( QIODevice::OpenMode(mode), fh );
475 owndev = TRUE;
476 reset();
477 d->sourceType = Q3TextStreamPrivate::File;
478}
479
480/*!
481 Destroys the text stream.
482
483 The destructor does not affect the current IO device.
484*/
485
486Q3TextStream::~Q3TextStream()
487{
488 if ( owndev )
489 delete dev;
490 delete d;
491}
492
493/*!
494 \since 4.2
495
496 Positions the read pointer at the first non-whitespace character.
497*/
498void Q3TextStream::skipWhiteSpace()
499{
500 ts_ungetc( eat_ws() );
501}
502
503
504/*!
505 Tries to read \a len characters from the stream and stores them in
506 \a buf. Returns the number of characters really read.
507
508 \warning There will no QEOF appended if the read reaches the end
509 of the file. EOF is reached when the return value does not equal
510 \a len.
511*/
512uint Q3TextStream::ts_getbuf( QChar* buf, uint len )
513{
514 if ( len < 1 )
515 return 0;
516
517 uint rnum = 0; // the number of QChars really read
518
519 if ( d && d->ungetcBuf.length() ) {
520 while ( rnum < len && rnum < uint(d->ungetcBuf.length()) ) {
521 *buf = d->ungetcBuf.constref( rnum );
522 buf++;
523 rnum++;
524 }
525 d->ungetcBuf = d->ungetcBuf.mid( rnum );
526 if ( rnum >= len )
527 return rnum;
528 }
529
530 // we use dev->ungetch() for one of the bytes of the unicode
531 // byte-order mark, but a local unget hack for the other byte:
532 int ungetHack = EOF;
533
534 if ( doUnicodeHeader ) {
535 doUnicodeHeader = FALSE; // only at the top
536 int c1 = dev->getch();
537 if ( c1 == EOF )
538 return rnum;
539 int c2 = dev->getch();
540 if ( c1 == 0xfe && c2 == 0xff ) {
541 mapper = 0;
542 latin1 = FALSE;
543 internalOrder = QChar::networkOrdered();
544 networkOrder = TRUE;
545 } else if ( c1 == 0xff && c2 == 0xfe ) {
546 mapper = 0;
547 latin1 = FALSE;
548 internalOrder = !QChar::networkOrdered();
549 networkOrder = FALSE;
550 } else {
551 if ( c2 != EOF ) {
552 dev->ungetch( c2 );
553 ungetHack = c1;
554 } else {
555 /*
556 A small bug might hide here. If only the first byte
557 of a file has made it so far, and that first byte
558 is half of the byte-order mark, then the utfness
559 will not be detected.
560 */
561 dev->ungetch( c1 );
562 }
563 }
564 }
565
566#ifndef QT_NO_TEXTCODEC
567 if ( mapper ) {
568 bool shortRead = FALSE;
569 while( rnum < len ) {
570 QString s;
571 bool readBlock = !( len == 1+rnum );
572 for (;;) {
573 // for efficiency: normally read a whole block
574 if ( readBlock ) {
575 // guess buffersize; this may be wrong (too small or too
576 // big). But we can handle this (either iterate reading
577 // or use ungetcBuf).
578 // Note that this might cause problems for codecs where
579 // one byte can result in >1 Unicode Characters if bytes
580 // are written to the stream in the meantime (loss of
581 // synchronicity).
582 uint rlen = len - rnum;
583 char *cbuf = new char[ rlen ];
584 if ( ungetHack != EOF ) {
585 rlen = 1+dev->readBlock( cbuf+1, rlen-1 );
586 cbuf[0] = (char)ungetHack;
587 ungetHack = EOF;
588 } else {
589 rlen = dev->readBlock( cbuf, rlen );
590 }
591 s += mapper->toUnicode( cbuf, rlen, &mapperWriteState );
592 delete[] cbuf;
593 // use buffered reading only for the first time, because we
594 // have to get the stream synchronous again (this is easier
595 // with single character reading)
596 readBlock = FALSE;
597 }
598 // get stream (and codec) in sync
599 int c;
600 if ( ungetHack == EOF ) {
601 c = dev->getch();
602 } else {
603 c = ungetHack;
604 ungetHack = EOF;
605 }
606 if ( c == EOF ) {
607 shortRead = TRUE;
608 break;
609 }
610 char b = c;
611 uint lengthBefore = s.length();
612 s += mapper->toUnicode( &b, 1, &mapperWriteState );
613
614 if ( uint(s.length()) > lengthBefore )
615 break; // it seems we are in sync now
616 }
617 uint i = 0;
618 uint end = QMIN( len-rnum, uint(s.length()) );
619 while( i < end ) {
620 *buf = s.constref(i++);
621 buf++;
622 }
623 rnum += end;
624 if ( uint(s.length()) > i ) {
625 // could be = but append is clearer
626 d->ungetcBuf.append( s.mid( i ) );
627 }
628 if ( shortRead )
629 return rnum;
630 }
631 } else
632#endif
633 if ( latin1 ) {
634 if ( len == 1+rnum ) {
635 // use this method for one character because it is more efficient
636 // (arnt doubts whether it makes a difference, but lets it stand)
637 int c = (ungetHack == EOF) ? dev->getch() : ungetHack;
638 if ( c != EOF ) {
639 *buf = QLatin1Char((char)c);
640 buf++;
641 rnum++;
642 }
643 } else {
644 if ( ungetHack != EOF ) {
645 *buf = QLatin1Char((char)ungetHack);
646 buf++;
647 rnum++;
648 ungetHack = EOF;
649 }
650 char *cbuf = new char[len - rnum];
651 while ( !dev->atEnd() && rnum < len ) {
652 uint rlen = len - rnum;
653 rlen = dev->readBlock( cbuf, rlen );
654 char *it = cbuf;
655 char *end = cbuf + rlen;
656 while ( it < end ) {
657 *buf = QLatin1Char(*it);
658 buf++;
659 it++;
660 }
661 rnum += rlen;
662 }
663 delete[] cbuf;
664 }
665 } else { // UCS-2 or UTF-16
666 if ( len == 1+rnum ) {
667 int c1 = (ungetHack == EOF) ? dev->getch() : ungetHack;
668
669
670 if ( c1 == EOF )
671 return rnum;
672 int c2 = dev->getch();
673
674
675 if ( c2 == EOF )
676 return rnum;
677
678 if ( networkOrder ) {
679 *buf = QChar( c2, c1 );
680 } else {
681 *buf = QChar( c1, c2 );
682 }
683 buf++;
684 rnum++;
685 } else {
686 char *cbuf = new char[ 2*( len - rnum ) ]; // for paranoids: overflow possible
687 while ( !dev->atEnd() && rnum < len ) {
688 uint rlen = 2 * ( len-rnum );
689 if ( ungetHack != EOF ) {
690 rlen = 1+dev->readBlock( cbuf+1, rlen-1 );
691 cbuf[0] = (char)ungetHack;
692 ungetHack = EOF;
693 } else {
694 rlen = dev->readBlock( cbuf, rlen );
695 }
696 // We can't use an odd number of bytes, so put it back. But
697 // do it only if we are capable of reading more -- normally
698 // there should not be an odd number, but the file might be
699 // truncated or not in UTF-16...
700 if ( (rlen & 1) == 1 )
701 if ( !dev->atEnd() )
702 dev->ungetch( cbuf[--rlen] );
703 uint i = 0;
704 if ( networkOrder ) {
705 while( i < rlen ) {
706 *buf = QChar( cbuf[i+1], cbuf[i] );
707 buf++;
708 i+=2;
709 }
710 } else {
711 while( i < rlen ) {
712 *buf = QChar( cbuf[i], cbuf[i+1] );
713 buf++;
714 i+=2;
715 }
716 }
717 rnum += i/2;
718 }
719 delete[] cbuf;
720 }
721 }
722 return rnum;
723}
724
725/*!
726 Tries to read one line, but at most len characters from the stream
727 and stores them in \a buf.
728
729 Returns the number of characters really read. Newlines are not
730 stripped.
731
732 There will be a QEOF appended if the read reaches the end of file;
733 this is different to ts_getbuf().
734
735 This function works only if a newline (as byte) is also a newline
736 (as resulting character) since it uses QIODevice::readLine(). So
737 use it only for such codecs where this is true!
738
739 This function is (almost) a no-op for UTF 16. Don't use it if
740 doUnicodeHeader is TRUE!
741*/
742uint Q3TextStream::ts_getline( QChar* buf )
743{
744 uint rnum=0; // the number of QChars really read
745 char cbuf[ getline_buf_size+1 ];
746
747 if ( d && d->ungetcBuf.length() ) {
748 while( rnum < getline_buf_size && rnum < uint(d->ungetcBuf.length()) ) {
749 buf[rnum] = d->ungetcBuf.constref(rnum);
750 rnum++;
751 }
752 d->ungetcBuf = d->ungetcBuf.mid( rnum );
753 if ( rnum >= getline_buf_size )
754 return rnum;
755 }
756
757#ifndef QT_NO_TEXTCODEC
758 if ( mapper ) {
759 QString s;
760 bool readBlock = TRUE;
761 for (;;) {
762 // for efficiency: try to read a line
763 if ( readBlock ) {
764 int rlen = getline_buf_size - rnum;
765 rlen = dev->readLine( cbuf, rlen+1 );
766 if ( rlen == -1 )
767 rlen = 0;
768 s += mapper->toUnicode( cbuf, rlen, &mapperWriteState );
769 readBlock = FALSE;
770 }
771 if ( dev->atEnd()
772 || s.at( s.length()-1 ) == QLatin1Char('\n')
773 || s.at( s.length()-1 ) == QLatin1Char('\r')
774 ) {
775 break;
776 } else {
777 // get stream (and codec) in sync
778 int c;
779 c = dev->getch();
780 if ( c == EOF ) {
781 break;
782 }
783 char b = c;
784 uint lengthBefore = s.length();
785 s += mapper->toUnicode( &b, 1, &mapperWriteState );
786 if ( uint(s.length()) > lengthBefore )
787 break; // it seems we are in sync now
788 }
789 }
790 uint i = 0;
791 while( rnum < getline_buf_size && i < uint(s.length()) )
792 buf[rnum++] = s.constref(i++);
793 if ( uint(s.length()) > i )
794 // could be = but append is clearer
795 d->ungetcBuf.append( s.mid( i ) );
796 if ( rnum < getline_buf_size && dev->atEnd() )
797 buf[rnum++] = QEOF;
798 } else
799#endif
800 if ( latin1 ) {
801 int rlen = getline_buf_size - rnum;
802 rlen = dev->readLine( cbuf, rlen+1 );
803 if ( rlen == -1 )
804 rlen = 0;
805 char *end = cbuf+rlen;
806 char *it = cbuf;
807 buf +=rnum;
808 while ( it != end ) {
809 buf->setCell( *(it++) );
810 buf->setRow( 0 );
811 buf++;
812 }
813 rnum += rlen;
814 if ( rnum < getline_buf_size && dev->atEnd() )
815 buf[1] = QEOF;
816 }
817 return rnum;
818}
819
820
821/*!
822 Puts one character into the stream.
823*/
824void Q3TextStream::ts_putc( QChar c )
825{
826#ifndef QT_NO_TEXTCODEC
827 if ( mapper ) {
828 int len = 1;
829 QString s = c;
830 Q3CString block = mapper->fromUnicode( s.data(), len );//, &mapperReadState );
831 dev->writeBlock( block );
832 } else
833#endif
834 if ( latin1 ) {
835 if ( c.row() )
836 dev->putch( '?' ); // unknown character
837 else
838 dev->putch( c.cell() );
839 } else {
840 if ( doUnicodeHeader ) {
841 doUnicodeHeader = FALSE;
842 ts_putc( QChar::ByteOrderMark );
843 }
844 if ( internalOrder ) {
845 // this case is needed by QStringBuffer
846 dev->writeBlock( (char*)&c, sizeof(QChar) );
847 } else if ( networkOrder ) {
848 dev->putch( c.row() );
849 dev->putch( c.cell() );
850 } else {
851 dev->putch( c.cell() );
852 dev->putch( c.row() );
853 }
854 }
855}
856
857/*!
858 Puts one character into the stream.
859*/
860void Q3TextStream::ts_putc( int ch )
861{
862 ts_putc( QChar((ushort)ch) );
863}
864
865bool Q3TextStream::ts_isdigit( QChar c )
866{
867 return c.isDigit();
868}
869
870bool Q3TextStream::ts_isspace( QChar c )
871{
872 return c.isSpace();
873}
874
875void Q3TextStream::ts_ungetc( QChar c )
876{
877 if ( c.unicode() == 0xffff )
878 return;
879
880 d->ungetcBuf.prepend( c );
881}
882
883/*!
884 \since 4.2
885
886 Reads \a len bytes from the stream into \a s and returns a
887 reference to the stream.
888
889 The buffer \a s must be preallocated.
890
891 Note that no encoding is done by this function.
892
893 \warning The behavior of this function is undefined unless the
894 stream's encoding is set to Unicode or Latin1.
895
896 \sa QIODevice::readBlock()
897*/
898
899Q3TextStream &Q3TextStream::readRawBytes( char *s, uint len )
900{
901 dev->readBlock( s, len );
902 return *this;
903}
904
905/*!
906 \since 4.2
907
908 Writes the \a len bytes from \a s to the stream and returns a
909 reference to the stream.
910
911 Note that no encoding is done by this function.
912
913 \sa QIODevice::writeBlock()
914*/
915
916Q3TextStream &Q3TextStream::writeRawBytes( const char* s, uint len )
917{
918 dev->writeBlock( s, len );
919 return *this;
920}
921
922
923Q3TextStream &Q3TextStream::writeBlock( const char* p, uint len )
924{
925 if ( doUnicodeHeader ) {
926 doUnicodeHeader = FALSE;
927 if ( !mapper && !latin1 ) {
928 ts_putc( QChar::ByteOrderMark );
929 }
930 }
931 // QCString and const char * are treated as Latin-1
932 if ( !mapper && latin1 ) {
933 dev->writeBlock( p, len );
934 } else if ( !mapper && internalOrder ) {
935 QChar *u = new QChar[len];
936 for ( uint i = 0; i < len; i++ )
937 u[i] = QLatin1Char(p[i]);
938 dev->writeBlock( (char*)u, len * sizeof(QChar) );
939 delete [] u;
940 }
941#ifndef QT_NO_TEXTCODEC
942 else if (mapper) {
943 QString s = QString::fromLatin1(p, len);
944 int l = len;
945 Q3CString block = mapper->fromUnicode(s.data(), l );//, &mapperReadState );
946 dev->writeBlock( block );
947 }
948#endif
949 else {
950 for ( uint i = 0; i < len; i++ )
951 ts_putc( (uchar)p[i] );
952 }
953 return *this;
954}
955
956Q3TextStream &Q3TextStream::writeBlock( const QChar* p, uint len )
957{
958#ifndef QT_NO_TEXTCODEC
959 if ( mapper ) {
960 QConstString s( p, len );
961 int l = len;
962 Q3CString block = mapper->fromUnicode( s.string().data(), l );//, &mapperReadState );
963 dev->writeBlock( block );
964 } else
965#endif
966 if ( latin1 ) {
967 dev->write(QString( p, len ).toLatin1());
968 } else if ( internalOrder ) {
969 if ( doUnicodeHeader ) {
970 doUnicodeHeader = FALSE;
971 ts_putc( QChar::ByteOrderMark );
972 }
973 dev->writeBlock( (char*)p, sizeof(QChar)*len );
974 } else {
975 for (uint i=0; i<len; i++)
976 ts_putc( p[i] );
977 }
978 return *this;