src/qt3support/text/q3textstream.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/text/q3textstream.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,2436 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3textstream.h"
+#include <qdebug.h>
+
+#ifndef QT_NO_TEXTSTREAM
+#include "qtextcodec.h"
+#include "qregexp.h"
+#include "qbuffer.h"
+#include "qfile.h"
+#include "q3cstring.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifndef Q_OS_WINCE
+#include <locale.h>
+#endif
+
+#if defined(Q_OS_WIN32)
+#include "qt_windows.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_TEXTCODEC
+static void resetCodecConverterState(QTextCodec::ConverterState *state) {
+    state->flags = QTextCodec::DefaultConversion;
+    state->remainingChars = state->invalidChars =
+           state->state_data[0] = state->state_data[1] = state->state_data[2] = 0;
+    if (state->d) qFree(state->d);
+    state->d = 0;
+}
+#endif
+
+/*!
+    \class Q3TextStream
+    \compat
+    \reentrant
+    \brief The Q3TextStream class provides basic functions for reading
+    and writing text using a QIODevice.
+
+    The text stream class has a functional interface that is very
+    similar to that of the standard C++ iostream class.
+
+    Qt provides several global functions similar to the ones in iostream:
+    \table
+    \header \i Function \i Meaning
+    \row \i bin \i sets the Q3TextStream to read/write binary numbers
+    \row \i oct \i sets the Q3TextStream to read/write octal numbers
+    \row \i dec \i sets the Q3TextStream to read/write decimal numbers
+    \row \i hex \i sets the Q3TextStream to read/write hexadecimal numbers
+    \row \i endl \i forces a line break
+    \row \i flush \i forces the QIODevice to flush any buffered data
+    \row \i ws \i eats any available whitespace (on input)
+    \row \i reset \i resets the Q3TextStream to its default mode (see reset())
+    \row \i qSetW(int) \i sets the \link width() field width \endlink
+    to the given argument
+    \row \i qSetFill(int) \i sets the \link fill() fill character
+    \endlink to the given argument
+    \row \i qSetPrecision(int) \i sets the \link precision() precision
+    \endlink to the given argument
+    \endtable
+
+    \warning By default Q3TextStream will automatically detect whether
+    integers in the stream are in decimal, octal, hexadecimal or
+    binary format when reading from the stream. In particular, a
+    leading '0' signifies octal, i.e. the sequence "0100" will be
+    interpreted as 64.
+
+    The Q3TextStream class reads and writes text; it is not appropriate
+    for dealing with binary data (but QDataStream is).
+
+    By default, output of Unicode text (i.e. QString) is done using
+    the local 8-bit encoding. This can be changed using the
+    setEncoding() method. For input, the Q3TextStream will auto-detect
+    standard Unicode "byte order marked" text files; otherwise the
+    local 8-bit encoding is used.
+
+    The QIODevice is set in the constructor, or later using
+    setDevice(). If the end of the input is reached atEnd() returns
+    TRUE. Data can be read into variables of the appropriate type
+    using the operator>>() overloads, or read in its entirety into a
+    single string using read(), or read a line at a time using
+    readLine(). Whitespace can be skipped over using skipWhiteSpace().
+    You can set flags for the stream using flags() or setf(). The
+    stream also supports width(), precision() and fill(); use reset()
+    to reset the defaults.
+
+    \sa QDataStream
+*/
+
+/*!
+    \enum Q3TextStream::Encoding
+
+    \value Locale
+    \value Latin1
+    \value Unicode
+    \value UnicodeNetworkOrder
+    \value UnicodeReverse
+    \value RawUnicode
+    \value UnicodeUTF8
+
+    See setEncoding() for an explanation of the encodings.
+*/
+
+/*
+  \class QTSManip
+  \internal
+*/
+
+#if defined(QT_CHECK_STATE)
+#undef  CHECK_STREAM_PRECOND
+#define CHECK_STREAM_PRECOND  if ( !dev ) {				\
+				qWarning( "Q3TextStream: No device" );	\
+				return *this; }
+#else
+#define CHECK_STREAM_PRECOND
+#endif
+
+
+#define I_SHORT		0x0010
+#define I_INT		0x0020
+#define I_LONG		0x0030
+#define I_TYPE_MASK	0x00f0
+
+#define I_BASE_2	Q3TextStream::bin
+#define I_BASE_8	Q3TextStream::oct
+#define I_BASE_10	Q3TextStream::dec
+#define I_BASE_16	Q3TextStream::hex
+#define I_BASE_MASK	(Q3TextStream::bin | Q3TextStream::oct | Q3TextStream::dec | Q3TextStream::hex)
+
+#define I_SIGNED	0x0100
+#define I_UNSIGNED	0x0200
+#define I_SIGN_MASK	0x0f00
+
+
+static const QChar QEOF = QChar((ushort)0xffff); //guaranteed not to be a character.
+static const uint getline_buf_size = 256; // bufsize used by ts_getline()
+
+const int Q3TextStream::basefield   = I_BASE_MASK;
+const int Q3TextStream::adjustfield = ( Q3TextStream::left |
+				       Q3TextStream::right |
+				       Q3TextStream::internal );
+const int Q3TextStream::floatfield  = ( Q3TextStream::scientific |
+				       Q3TextStream::fixed );
+
+
+class Q3TextStreamPrivate {
+public:
+#ifndef QT_NO_TEXTCODEC
+    Q3TextStreamPrivate()
+	: sourceType( NotSet ) { }
+    ~Q3TextStreamPrivate() {
+    }
+#else
+    Q3TextStreamPrivate() : sourceType( NotSet ) { }
+    ~Q3TextStreamPrivate() { }
+#endif
+    QString ungetcBuf;
+
+    enum SourceType { NotSet, IODevice, String, ByteArray, File };
+    SourceType sourceType;
+};
+
+
+// skips whitespace and returns the first non-whitespace character
+QChar Q3TextStream::eat_ws()
+{
+    QChar c;
+    do { c = ts_getc(); } while ( c != QEOF && ts_isspace(c) );
+    return c;
+}
+
+void Q3TextStream::init()
+{
+    // ### ungetcBuf = QEOF;
+    dev = 0;
+    owndev = FALSE;
+    mapper = 0;
+#ifndef QT_NO_TEXTCODEC
+    resetCodecConverterState(&mapperReadState);
+    resetCodecConverterState(&mapperWriteState);
+#endif
+    d = new Q3TextStreamPrivate;
+    doUnicodeHeader = TRUE; // autodetect
+    latin1 = TRUE; // should use locale?
+    internalOrder = QChar::networkOrdered();
+    networkOrder = TRUE;
+}
+
+/*!
+    Constructs a data stream that has no IO device.
+*/
+
+Q3TextStream::Q3TextStream()
+{
+    init();
+    setEncoding( Locale );
+    reset();
+    d->sourceType = Q3TextStreamPrivate::NotSet;
+}
+
+/*!
+    Constructs a text stream that uses the IO device \a iod.
+*/
+
+Q3TextStream::Q3TextStream( QIODevice *iod )
+{
+    init();
+    setEncoding( Locale );
+    dev = iod;
+    reset();
+    d->sourceType = Q3TextStreamPrivate::IODevice;
+}
+
+// TODO: use special-case handling of this case in Q3TextStream, and
+//	 simplify this class to only deal with QChar or QString data.
+class QStringBuffer : public QIODevice {
+public:
+    QStringBuffer( QString* str );
+    ~QStringBuffer();
+    bool  open( OpenMode m );
+    void  close();
+    qint64 size() const;
+
+protected:
+    qint64 readData( char *p, qint64 len );
+    qint64 writeData( const char *p, qint64 len );
+
+    QString* s;
+
+private:
+    QStringBuffer( const QStringBuffer & );
+    QStringBuffer &operator=( const QStringBuffer & );
+};
+
+
+QStringBuffer::QStringBuffer( QString* str )
+{
+    s = str;
+}
+
+QStringBuffer::~QStringBuffer()
+{
+}
+
+
+bool QStringBuffer::open( OpenMode m )
+{
+    if ( !s ) {
+#if defined(QT_CHECK_STATE)
+	qWarning( "QStringBuffer::open: No string" );
+#endif
+	return FALSE;
+    }
+    if ( isOpen() ) {
+#if defined(QT_CHECK_STATE)
+	qWarning( "QStringBuffer::open: Buffer already open" );
+#endif
+	return FALSE;
+    }
+    setOpenMode( m );
+    if ( m & QIODevice::Truncate )
+	s->truncate( 0 );
+
+    if ( m & QIODevice::Append ) {
+	seek(s->length()*sizeof(QChar));
+    } else {
+	seek(0);
+    }
+    return TRUE;
+}
+
+void QStringBuffer::close()
+{
+    if ( isOpen() ) {
+	seek(0);
+        QIODevice::close();
+    }
+}
+
+qint64 QStringBuffer::size() const
+{
+    return s ? s->length()*sizeof(QChar) : 0;
+}
+
+qint64 QStringBuffer::readData( char *p, qint64 len )
+{
+#if defined(QT_CHECK_STATE)
+    Q_CHECK_PTR( p );
+    if ( !isOpen() ) {
+	qWarning( "QStringBuffer::readBlock: Buffer not open" );
+	return qint64(-1);
+    }
+    if ( !isReadable() ) {
+	qWarning( "QStringBuffer::readBlock: Read operation not permitted" );
+	return qint64(-1);
+    }
+#endif
+    if ( pos() + len > qint64(s->length()*sizeof(QChar)) ) {
+	// overflow
+	if ( pos() >= qint64(s->length()*sizeof(QChar)) ) {
+	    return -1;
+	} else {
+	    len = s->length()*2 - pos();
+	}
+    }
+    memcpy( p, ((const char*)(s->unicode()))+pos(), len );
+    return len;
+}
+
+qint64 QStringBuffer::writeData( const char *p, qint64 len )
+{
+#if defined(QT_CHECK_NULL)
+    if ( p == 0 && len != 0 )
+	qWarning( "QStringBuffer::writeBlock: Null pointer error" );
+#endif
+#if defined(QT_CHECK_STATE)
+    if ( !isOpen() ) {
+	qWarning( "QStringBuffer::writeBlock: Buffer not open" );
+	return -1;
+    }
+    if ( !isWritable() ) {
+	qWarning( "QStringBuffer::writeBlock: Write operation not permitted" );
+	return -1;
+    }
+    if ( pos()&1 ) {
+	qWarning( "QStringBuffer::writeBlock: non-even index - non Unicode" );
+	return -1;
+    }
+    if ( len&1 ) {
+	qWarning( "QStringBuffer::writeBlock: non-even length - non Unicode" );
+	return -1;
+    }
+#endif
+    s->replace(pos()/2, len/2, (QChar*)p, len/2);
+    return len;
+}
+
+/*!
+    Constructs a text stream that operates on the Unicode QString, \a
+    str, through an internal device. The \a filemode argument is
+    passed to the device's open() function; see \l{QIODevice::mode()}.
+
+    If you set an encoding or codec with setEncoding() or setCodec(),
+    this setting is ignored for text streams that operate on QString.
+
+    Example:
+    \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 0
+
+    Writing data to the text stream will modify the contents of the
+    string. The string will be expanded when data is written beyond
+    the end of the string. Note that the string will not be truncated:
+    \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 1
+
+    Note that because QString is Unicode, you should not use
+    readRawBytes() or writeRawBytes() on such a stream.
+*/
+
+Q3TextStream::Q3TextStream( QString* str, int filemode )
+{
+    // TODO: optimize for this case as it becomes more common
+    //        (see QStringBuffer above)
+    init();
+    dev = new QStringBuffer( str );
+    ((QStringBuffer *)dev)->open( QIODevice::OpenMode(filemode) );
+    owndev = TRUE;
+    setEncoding(RawUnicode);
+    reset();
+    d->sourceType = Q3TextStreamPrivate::String;
+}
+
+/*! \obsolete
+
+  This constructor is equivalent to the constructor taking a QString*
+  parameter.
+*/
+
+Q3TextStream::Q3TextStream( QString& str, int filemode )
+{
+    init();
+    dev = new QStringBuffer( &str );
+    ((QStringBuffer *)dev)->open( QIODevice::OpenMode(filemode) );
+    owndev = TRUE;
+    setEncoding(RawUnicode);
+    reset();
+    d->sourceType = Q3TextStreamPrivate::String;
+}
+
+/*!
+    Constructs a text stream that operates on the byte array, \a a,
+    through an internal QBuffer device. The \a mode argument is passed
+    to the device's open() function; see \l{QIODevice::mode()}.
+
+    Example:
+    \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 2
+
+    Writing data to the text stream will modify the contents of the
+    array. The array will be expanded when data is written beyond the
+    end of the string.
+
+    Same example, using a QBuffer:
+    \snippet doc/src/snippets/code/src_qt3support_text_q3textstream.cpp 3
+*/
+
+Q3TextStream::Q3TextStream( QByteArray &a, int mode )
+{
+    init();
+    QBuffer *buffer = new QBuffer;
+    buffer->setBuffer( &a );
+    buffer->open( QIODevice::OpenMode(mode) );
+    dev = buffer;
+    owndev = TRUE;
+    setEncoding( Latin1 ); //### Locale???
+    reset();
+    d->sourceType = Q3TextStreamPrivate::ByteArray;
+}
+
+/*!
+    Constructs a text stream that operates on an existing file handle
+    \a fh through an internal QFile device. The \a mode argument is
+    passed to the device's open() function; see \l{QIODevice::mode()}.
+
+    Note that if you create a Q3TextStream \c cout or another name that
+    is also used for another variable of a different type, some
+    linkers may confuse the two variables, which will often cause
+    crashes.
+*/
+
+Q3TextStream::Q3TextStream( FILE *fh, int mode )
+{
+    init();
+    setEncoding( Locale ); //###
+    dev = new QFile;
+    ((QFile *)dev)->open( QIODevice::OpenMode(mode), fh );
+    owndev = TRUE;
+    reset();
+    d->sourceType = Q3TextStreamPrivate::File;
+}
+
+/*!
+    Destroys the text stream.
+
+    The destructor does not affect the current IO device.
+*/
+
+Q3TextStream::~Q3TextStream()
+{
+    if ( owndev )
+	delete dev;
+    delete d;
+}
+
+/*!
+    \since 4.2
+
+    Positions the read pointer at the first non-whitespace character.
+*/
+void Q3TextStream::skipWhiteSpace()
+{
+    ts_ungetc( eat_ws() );
+}
+
+
+/*!
+    Tries to read \a len characters from the stream and stores them in
+    \a buf. Returns the number of characters really read.
+
+    \warning There will no QEOF appended if the read reaches the end
+    of the file. EOF is reached when the return value does not equal
+    \a len.
+*/
+uint Q3TextStream::ts_getbuf( QChar* buf, uint len )
+{
+    if ( len < 1 )
+	return 0;
+
+    uint rnum = 0;   // the number of QChars really read
+
+    if ( d && d->ungetcBuf.length() ) {
+	while ( rnum < len && rnum < uint(d->ungetcBuf.length()) ) {
+	    *buf = d->ungetcBuf.constref( rnum );
+	    buf++;
+	    rnum++;
+	}
+	d->ungetcBuf = d->ungetcBuf.mid( rnum );
+	if ( rnum >= len )
+	    return rnum;
+    }
+
+    // we use dev->ungetch() for one of the bytes of the unicode
+    // byte-order mark, but a local unget hack for the other byte:
+    int ungetHack = EOF;
+
+    if ( doUnicodeHeader ) {
+	doUnicodeHeader = FALSE; // only at the top
+	int c1 = dev->getch();
+	if ( c1 == EOF )
+	    return rnum;
+	int c2 = dev->getch();
+	if ( c1 == 0xfe && c2 == 0xff ) {
+	    mapper = 0;
+	    latin1 = FALSE;
+	    internalOrder = QChar::networkOrdered();
+	    networkOrder = TRUE;
+	} else if ( c1 == 0xff && c2 == 0xfe ) {
+	    mapper = 0;
+	    latin1 = FALSE;
+	    internalOrder = !QChar::networkOrdered();
+	    networkOrder = FALSE;
+	} else {
+	    if ( c2 != EOF ) {
+	 	dev->ungetch( c2 );
+		ungetHack = c1;
+	    } else {
+		/*
+		  A small bug might hide here. If only the first byte
+		  of a file has made it so far, and that first byte
+		  is half of the byte-order mark, then the utfness
+		  will not be detected.
+		*/
+	 	dev->ungetch( c1 );
+	    }
+	}
+    }
+
+#ifndef QT_NO_TEXTCODEC
+    if ( mapper ) {
+	bool shortRead = FALSE;
+        while( rnum < len ) {
+	    QString s;
+	    bool readBlock = !( len == 1+rnum );
+	    for (;;) {
+		// for efficiency: normally read a whole block
+		if ( readBlock ) {
+		    // guess buffersize; this may be wrong (too small or too
+		    // big). But we can handle this (either iterate reading
+		    // or use ungetcBuf).
+		    // Note that this might cause problems for codecs where
+		    // one byte can result in >1 Unicode Characters if bytes
+		    // are written to the stream in the meantime (loss of
+		    // synchronicity).
+		    uint rlen = len - rnum;
+		    char *cbuf = new char[ rlen ];
+		    if ( ungetHack != EOF ) {
+			rlen = 1+dev->readBlock( cbuf+1, rlen-1 );
+			cbuf[0] = (char)ungetHack;
+			ungetHack = EOF;
+		    } else {
+			rlen = dev->readBlock( cbuf, rlen );
+		    }
+		    s += mapper->toUnicode( cbuf, rlen, &mapperWriteState );
+		    delete[] cbuf;
+		    // use buffered reading only for the first time, because we
+		    // have to get the stream synchronous again (this is easier
+		    // with single character reading)
+		    readBlock = FALSE;
+		}
+		// get stream (and codec) in sync
+		int c;
+		if ( ungetHack == EOF ) {
+		    c = dev->getch();
+		} else {
+		    c = ungetHack;
+		    ungetHack = EOF;
+		}
+		if ( c == EOF ) {
+		    shortRead = TRUE;
+		    break;
+		}
+		char b = c;
+		uint lengthBefore = s.length();
+		s += mapper->toUnicode( &b, 1, &mapperWriteState );
+
+		if ( uint(s.length()) > lengthBefore )
+		    break; // it seems we are in sync now
+	    }
+	    uint i = 0;
+	    uint end = QMIN( len-rnum, uint(s.length()) );
+	    while( i < end ) {
+		*buf = s.constref(i++);
+		buf++;
+	    }
+	    rnum += end;
+	    if ( uint(s.length()) > i ) {
+		// could be = but append is clearer
+		d->ungetcBuf.append( s.mid( i ) );
+	    }
+	    if ( shortRead )
+		return rnum;
+	}
+    } else
+#endif
+    if ( latin1 ) {
+	if ( len == 1+rnum ) {
+	    // use this method for one character because it is more efficient
+	    // (arnt doubts whether it makes a difference, but lets it stand)
+	    int c = (ungetHack == EOF) ? dev->getch() : ungetHack;
+	    if ( c != EOF ) {
+		*buf = QLatin1Char((char)c);
+		buf++;
+		rnum++;
+	    }
+	} else {
+	    if ( ungetHack != EOF ) {
+		*buf = QLatin1Char((char)ungetHack);
+		buf++;
+		rnum++;
+		ungetHack = EOF;
+	    }
+	    char *cbuf = new char[len - rnum];
+	    while ( !dev->atEnd() && rnum < len ) {
+		uint rlen = len - rnum;
+		rlen = dev->readBlock( cbuf, rlen );
+		char *it = cbuf;
+		char *end = cbuf + rlen;
+		while ( it < end ) {
+		    *buf = QLatin1Char(*it);
+		    buf++;
+		    it++;
+		}
+		rnum += rlen;
+	    }
+	    delete[] cbuf;
+	}
+    } else { // UCS-2 or UTF-16
+	if ( len == 1+rnum ) {
+	    int c1 = (ungetHack == EOF) ? dev->getch() : ungetHack;
+
+
+            if ( c1 == EOF )
+		return rnum;
+	    int c2 = dev->getch();
+
+
+            if ( c2 == EOF )
+		return rnum;
+
+	    if ( networkOrder ) {
+		*buf = QChar( c2, c1 );
+	    } else {
+		*buf = QChar( c1, c2 );
+	    }
+	    buf++;
+	    rnum++;
+	} else {
+	    char *cbuf = new char[ 2*( len - rnum ) ]; // for paranoids: overflow possible
+	    while ( !dev->atEnd() && rnum < len ) {
+		uint rlen = 2 * ( len-rnum );
+		if ( ungetHack != EOF ) {
+		    rlen = 1+dev->readBlock( cbuf+1, rlen-1 );
+		    cbuf[0] = (char)ungetHack;
+		    ungetHack = EOF;
+		} else {
+		    rlen = dev->readBlock( cbuf, rlen );
+		}
+		// We can't use an odd number of bytes, so put it back. But
+		// do it only if we are capable of reading more -- normally
+		// there should not be an odd number, but the file might be
+		// truncated or not in UTF-16...
+		if ( (rlen & 1) == 1 )
+		    if ( !dev->atEnd() )
+			dev->ungetch( cbuf[--rlen] );
+		uint i = 0;
+		if ( networkOrder ) {
+		    while( i < rlen ) {
+			*buf = QChar( cbuf[i+1], cbuf[i] );
+			buf++;
+			i+=2;
+		    }
+		} else {
+		    while( i < rlen ) {
+			*buf = QChar( cbuf[i], cbuf[i+1] );
+			buf++;
+			i+=2;
+		    }
+		}
+		rnum += i/2;
+	    }
+	    delete[] cbuf;
+	}
+    }
+    return rnum;
+}
+
+/*!
+    Tries to read one line, but at most len characters from the stream
+    and stores them in \a buf.
+
+    Returns the number of characters really read. Newlines are not
+    stripped.
+
+    There will be a QEOF appended if the read reaches the end of file;
+    this is different to ts_getbuf().
+
+    This function works only if a newline (as byte) is also a newline
+    (as resulting character) since it uses QIODevice::readLine(). So
+    use it only for such codecs where this is true!
+
+    This function is (almost) a no-op for UTF 16. Don't use it if
+    doUnicodeHeader is TRUE!
+*/
+uint Q3TextStream::ts_getline( QChar* buf )
+{
+    uint rnum=0;   // the number of QChars really read
+    char cbuf[ getline_buf_size+1 ];
+
+    if ( d && d->ungetcBuf.length() ) {
+	while( rnum < getline_buf_size && rnum < uint(d->ungetcBuf.length()) ) {
+	    buf[rnum] = d->ungetcBuf.constref(rnum);
+	    rnum++;
+	}
+	d->ungetcBuf = d->ungetcBuf.mid( rnum );
+	if ( rnum >= getline_buf_size )
+	    return rnum;
+    }
+
+#ifndef QT_NO_TEXTCODEC
+    if ( mapper ) {
+	QString s;
+	bool readBlock = TRUE;
+	for (;;) {
+	    // for efficiency: try to read a line
+	    if ( readBlock ) {
+		int rlen = getline_buf_size - rnum;
+		rlen = dev->readLine( cbuf, rlen+1 );
+		if ( rlen == -1 )
+		    rlen = 0;
+		s  += mapper->toUnicode( cbuf, rlen, &mapperWriteState );
+		readBlock = FALSE;
+	    }
+	    if ( dev->atEnd()
+		    || s.at( s.length()-1 ) == QLatin1Char('\n')
+		    || s.at( s.length()-1 ) == QLatin1Char('\r')
+	       ) {
+		break;
+	    } else {
+		// get stream (and codec) in sync
+		int c;
+		c = dev->getch();
+		if ( c == EOF ) {
+		    break;
+		}
+		char b = c;
+		uint lengthBefore = s.length();
+		s  += mapper->toUnicode( &b, 1, &mapperWriteState );
+		if ( uint(s.length()) > lengthBefore )
+		    break; // it seems we are in sync now
+	    }
+	}
+	uint i = 0;
+	while( rnum < getline_buf_size && i < uint(s.length()) )
+	    buf[rnum++] = s.constref(i++);
+	if ( uint(s.length()) > i )
+	    // could be = but append is clearer
+	    d->ungetcBuf.append( s.mid( i ) );
+	if ( rnum < getline_buf_size && dev->atEnd() )
+	    buf[rnum++] = QEOF;
+    } else
+#endif
+    if ( latin1 ) {
+	int rlen = getline_buf_size - rnum;
+	rlen = dev->readLine( cbuf, rlen+1 );
+	if ( rlen == -1 )
+	    rlen = 0;
+	char *end = cbuf+rlen;
+	char *it = cbuf;
+	buf +=rnum;
+	while ( it != end ) {
+	    buf->setCell( *(it++) );
+	    buf->setRow( 0 );
+	    buf++;
+	}
+	rnum += rlen;
+	if ( rnum < getline_buf_size && dev->atEnd() )
+	    buf[1] = QEOF;
+    }
+    return rnum;
+}
+
+
+/*!
+    Puts one character into the stream.
+*/
+void Q3TextStream::ts_putc( QChar c )
+{
+#ifndef QT_NO_TEXTCODEC
+    if ( mapper ) {
+	int len = 1;
+	QString s = c;
+	Q3CString block = mapper->fromUnicode( s.data(), len );//, &mapperReadState );
+	dev->writeBlock( block );
+    } else
+#endif
+    if ( latin1 ) {
+	if ( c.row() )
+	    dev->putch( '?' ); // unknown character
+	else
+	    dev->putch( c.cell() );
+    } else {
+	if ( doUnicodeHeader ) {
+	    doUnicodeHeader = FALSE;
+	    ts_putc( QChar::ByteOrderMark );
+	}
+	if ( internalOrder ) {
+	    // this case is needed by QStringBuffer
+	    dev->writeBlock( (char*)&c, sizeof(QChar) );
+	} else if ( networkOrder ) {
+	    dev->putch( c.row() );
+	    dev->putch( c.cell() );
+	} else {
+	    dev->putch( c.cell() );
+	    dev->putch( c.row() );
+	}
+    }
+}
+
+/*!
+    Puts one character into the stream.
+*/
+void Q3TextStream::ts_putc( int ch )
+{
+    ts_putc( QChar((ushort)ch) );
+}
+
+bool Q3TextStream::ts_isdigit( QChar c )
+{
+    return c.isDigit();
+}
+
+bool Q3TextStream::ts_isspace( QChar c )
+{
+    return c.isSpace();
+}
+
+void Q3TextStream::ts_ungetc( QChar c )
+{
+    if ( c.unicode() == 0xffff )
+	return;
+
+    d->ungetcBuf.prepend( c );
+}
+
+/*!
+    \since 4.2
+
+    Reads \a len bytes from the stream into \a s and returns a
+    reference to the stream.
+
+    The buffer \a s must be preallocated.
+
+    Note that no encoding is done by this function.
+
+    \warning The behavior of this function is undefined unless the
+    stream's encoding is set to Unicode or Latin1.
+
+    \sa QIODevice::readBlock()
+*/
+
+Q3TextStream &Q3TextStream::readRawBytes( char *s, uint len )
+{
+    dev->readBlock( s, len );
+    return *this;
+}
+
+/*!
+    \since 4.2
+
+    Writes the \a len bytes from \a s to the stream and returns a
+    reference to the stream.
+
+    Note that no encoding is done by this function.
+
+    \sa QIODevice::writeBlock()
+*/
+
+Q3TextStream &Q3TextStream::writeRawBytes( const char* s, uint len )
+{
+    dev->writeBlock( s, len );
+    return *this;
+}
+
+
+Q3TextStream &Q3TextStream::writeBlock( const char* p, uint len )
+{
+    if ( doUnicodeHeader ) {
+	doUnicodeHeader = FALSE;
+	if ( !mapper && !latin1 ) {
+	    ts_putc( QChar::ByteOrderMark );
+        }
+    }
+    // QCString and const char * are treated as Latin-1
+    if ( !mapper && latin1 ) {
+	dev->writeBlock( p, len );
+    } else if ( !mapper && internalOrder ) {
+	QChar *u = new QChar[len];
+	for ( uint i = 0; i < len; i++ )
+	    u[i] = QLatin1Char(p[i]);
+	dev->writeBlock( (char*)u, len * sizeof(QChar) );
+	delete [] u;
+    }
+#ifndef QT_NO_TEXTCODEC
+    else if (mapper) {
+        QString s = QString::fromLatin1(p, len);
+        int l = len;
+        Q3CString block = mapper->fromUnicode(s.data(), l );//, &mapperReadState );
+        dev->writeBlock( block );
+    }
+#endif
+    else {
+	for ( uint i = 0; i < len; i++ )
+	    ts_putc( (uchar)p[i] );
+    }
+    return *this;
+}
+
+Q3TextStream &Q3TextStream::writeBlock( const QChar* p, uint len )
+{
+#ifndef QT_NO_TEXTCODEC
+    if ( mapper ) {
+	QConstString s( p, len );
+	int l = len;
+	Q3CString block = mapper->fromUnicode( s.string().data(), l );//, &mapperReadState );
+	dev->writeBlock( block );
+    } else
+#endif
+    if ( latin1 ) {
+	dev->write(QString( p, len ).toLatin1());
+    } else if ( internalOrder ) {
+	if ( doUnicodeHeader ) {
+	    doUnicodeHeader = FALSE;
+	    ts_putc( QChar::ByteOrderMark );
+	}
+	dev->writeBlock( (char*)p, sizeof(QChar)*len );
+    } else {
+	for (uint i=0; i<len; i++)
+	    ts_putc( p[i] );
+    }
+    return *this;
+}
+
+/*!
+    \since 4.2
+
+    Resets the text stream.
+
+    \list
+    \i All flags are set to 0.
+    \i The field width is set to 0.
+    \i The fill character is set to ' ' (Space).
+    \i The precision is set to 6.
+    \endlist
+
+    \sa setf(), width(), fill(), precision()
+*/
+
+void Q3TextStream::reset()
+{
+    fflags = 0;
+    fwidth = 0;
+    fillchar = ' ';
+    fprec = 6;
+}
+
+/*!
+    \fn QIODevice *Q3TextStream::device() const
+    \since 4.2
+
+    Returns the IO device currently set.
+
+    \sa setDevice(), unsetDevice()
+*/
+
+/*!
+    \since 4.2
+
+    Sets the IO device to \a iod.
+
+    \sa device(), unsetDevice()
+*/
+
+void Q3TextStream::setDevice( QIODevice *iod )
+{
+    if ( owndev ) {
+	delete dev;
+	owndev = FALSE;
+    }
+    dev = iod;
+    d->sourceType = Q3TextStreamPrivate::IODevice;
+}
+
+/*!
+    \since 4.2
+
+    Unsets the IO device. Equivalent to setDevice( 0 ).
+
+    \sa device(), setDevice()
+*/
+
+void Q3TextStream::unsetDevice()
+{
+    setDevice( 0 );
+    d->sourceType = Q3TextStreamPrivate::NotSet;
+}
+
+/*!
+    \fn bool Q3TextStream::atEnd() const
+    \since 4.2
+
+    Returns TRUE if the IO device has reached the end position (end of
+    the stream or file) or if there is no IO device set; otherwise
+    returns FALSE.
+
+    \sa QIODevice::atEnd()
+*/
+
+/*!\fn bool Q3TextStream::eof() const
+
+  \obsolete
+
+  This function has been renamed to atEnd().
+
+  \sa QIODevice::atEnd()
+*/
+
+/*****************************************************************************
+  Q3TextStream read functions
+ *****************************************************************************/
+
+
+/*!
+    \overload
+
+    Reads a char \a c from the stream and returns a reference to the
+    stream. Note that whitespace is skipped.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( char &c )
+{
+    CHECK_STREAM_PRECOND
+    c = eat_ws().toLatin1();
+    return *this;
+}
+
+/*!
+    Reads a char \a c from the stream and returns a reference to the
+    stream. Note that whitespace is \e not skipped.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( QChar &c )
+{
+    CHECK_STREAM_PRECOND
+    c = ts_getc();
+    return *this;
+}
+
+
+ulong Q3TextStream::input_bin()
+{
+    ulong val = 0;
+    QChar ch = eat_ws();
+    int dv = ch.digitValue();
+    while (  dv == 0 || dv == 1 ) {
+	val = ( val << 1 ) + dv;
+	ch = ts_getc();
+	dv = ch.digitValue();
+    }
+    if ( ch != QEOF )
+	ts_ungetc( ch );
+    return val;
+}
+
+ulong Q3TextStream::input_oct()
+{
+    ulong val = 0;
+    QChar ch = eat_ws();
+    int dv = ch.digitValue();
+    while ( dv >= 0 && dv <= 7 ) {
+	val = ( val << 3 ) + dv;
+	ch = ts_getc();
+	dv = ch.digitValue();
+    }
+    if ( dv == 8 || dv == 9 ) {
+	while ( ts_isdigit(ch) )
+	    ch = ts_getc();
+    }
+    if ( ch != QEOF )
+	ts_ungetc( ch );
+    return val;
+}
+
+ulong Q3TextStream::input_dec()
+{
+    ulong val = 0;
+    QChar ch = eat_ws();
+    int dv = ch.digitValue();
+    while ( ts_isdigit(ch) ) {
+	val = val * 10 + dv;
+	ch = ts_getc();
+	dv = ch.digitValue();
+    }
+    if ( ch != QEOF )
+	ts_ungetc( ch );
+    return val;
+}
+
+ulong Q3TextStream::input_hex()
+{
+    ulong val = 0;
+    QChar ch = eat_ws();
+    char c = ch.toLatin1();
+    while ( isxdigit((uchar) c) ) {
+	val <<= 4;
+	if ( ts_isdigit(QLatin1Char(c)) )
+	    val += c - '0';
+	else
+	    val += 10 + tolower( (uchar) c ) - 'a';
+        ch = ts_getc();
+	c = ch.toLatin1();
+    }
+    if ( ch != QEOF )
+	ts_ungetc( ch );
+    return val;
+}
+
+long Q3TextStream::input_int()
+{
+    long val;
+    QChar ch;
+    char c;
+    switch ( flags() & basefield ) {
+    case bin:
+	val = (long)input_bin();
+	break;
+    case oct:
+	val = (long)input_oct();
+	break;
+    case dec:
+        ch = eat_ws();
+	c = ch.toLatin1();
+	if ( ch == QEOF ) {
+	    val = 0;
+	} else {
+	    if ( !(c == '-' || c == '+') )
+		ts_ungetc( ch );
+	    if ( c == '-' ) {
+		ulong v = input_dec();
+		if ( v ) {		// ensure that LONG_MIN can be read
+		    v--;
+		    val = -((long)v) - 1;
+		} else {
+		    val = 0;
+		}
+	    } else {
+		val = (long)input_dec();
+	    }
+	}
+	break;
+    case hex:
+	val = (long)input_hex();
+	break;
+    default:
+	val = 0;
+        ch = eat_ws();
+	c = ch.toLatin1();
+	if ( c == '0' ) {		// bin, oct or hex
+            ch = ts_getc();
+	    c = ch.toLatin1();
+	    if ( tolower((uchar) c) == 'x' )
+		val = (long)input_hex();
+	    else if ( tolower((uchar) c) == 'b' )
+		val = (long)input_bin();
+	    else {			// octal
+		ts_ungetc( ch );
+		if ( c >= '0' && c <= '7' ) {
+		    val = (long)input_oct();
+		} else {
+		    val = 0;
+		}
+	    }
+	} else if ( ts_isdigit(ch) ) {
+	    ts_ungetc( ch );
+	    val = (long)input_dec();
+	} else if ( c == '-' || c == '+' ) {
+	    ulong v = input_dec();
+	    if ( c == '-' ) {
+		if ( v ) {		// ensure that LONG_MIN can be read
+		    v--;
+		    val = -((long)v) - 1;
+		} else {
+		    val = 0;
+		}
+	    } else {
+		val = (long)v;
+	    }
+	}
+    }
+    return val;
+}
+
+//
+// We use a table-driven FSM to parse floating point numbers
+// strtod() cannot be used directly since we're reading from a QIODevice
+//
+
+double Q3TextStream::input_double()
+{
+    const int Init	 = 0;			// states
+    const int Sign	 = 1;
+    const int Mantissa	 = 2;
+    const int Dot	 = 3;
+    const int Abscissa	 = 4;
+    const int ExpMark	 = 5;
+    const int ExpSign	 = 6;
+    const int Exponent	 = 7;
+    const int Done	 = 8;
+
+    const int InputSign	 = 1;			// input tokens
+    const int InputDigit = 2;
+    const int InputDot	 = 3;
+    const int InputExp	 = 4;
+
+    static const uchar table[8][5] = {
+     /* None	 InputSign   InputDigit InputDot InputExp */
+	{ 0,	    Sign,     Mantissa,	 Dot,	   0,	   }, // Init
+	{ 0,	    0,	      Mantissa,	 Dot,	   0,	   }, // Sign
+	{ Done,	    Done,     Mantissa,	 Dot,	   ExpMark,}, // Mantissa
+	{ 0,	    0,	      Abscissa,	 0,	   0,	   }, // Dot
+	{ Done,	    Done,     Abscissa,	 Done,	   ExpMark,}, // Abscissa
+	{ 0,	    ExpSign,  Exponent,	 0,	   0,	   }, // ExpMark
+	{ 0,	    0,	      Exponent,	 0,	   0,	   }, // ExpSign
+	{ Done,	    Done,     Exponent,	 Done,	   Done	   }  // Exponent
+    };
+
+    int state = Init;				// parse state
+    int input;					// input token
+
+    char buf[256];
+    int i = 0;
+    QChar c = eat_ws();
+
+    for (;;) {
+
+	switch ( c.toLatin1() ) {
+	    case '+':
+	    case '-':
+		input = InputSign;
+		break;
+	    case '0': case '1': case '2': case '3': case '4':
+	    case '5': case '6': case '7': case '8': case '9':
+		input = InputDigit;
+		break;
+	    case '.':
+		input = InputDot;
+		break;
+	    case 'e':
+	    case 'E':
+		input = InputExp;
+		break;
+	    default:
+		input = 0;
+		break;
+	}
+
+	state = table[state][input];
+
+	if  ( state == 0 || state == Done || i > 250 ) {
+	    if ( i > 250 ) {			// ignore rest of digits
+		do { c = ts_getc(); } while ( c != QEOF && ts_isdigit(c) );
+	    }
+	    if ( c != QEOF )
+		ts_ungetc( c );
+	    buf[i] = '\0';
+	    char *end;
+	    return strtod( buf, &end );
+	}
+
+	buf[i++] = c.toLatin1();
+	c = ts_getc();
+    }
+
+#if !defined(Q_CC_EDG)
+    return 0.0;
+#endif
+}
+
+
+/*!
+    \overload
+
+    Reads a signed \c short integer \a i from the stream and returns a
+    reference to the stream. See flags() for an explanation of the
+    expected input format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( signed short &i )
+{
+    CHECK_STREAM_PRECOND
+    i = (signed short)input_int();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads an unsigned \c short integer \a i from the stream and
+    returns a reference to the stream. See flags() for an explanation
+    of the expected input format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( unsigned short &i )
+{
+    CHECK_STREAM_PRECOND
+    i = (unsigned short)input_int();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads a signed \c int \a i from the stream and returns a reference
+    to the stream. See flags() for an explanation of the expected
+    input format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( signed int &i )
+{
+    CHECK_STREAM_PRECOND
+    i = (signed int)input_int();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads an unsigned \c int \a i from the stream and returns a
+    reference to the stream. See flags() for an explanation of the
+    expected input format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( unsigned int &i )
+{
+    CHECK_STREAM_PRECOND
+    i = (unsigned int)input_int();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads a signed \c long int \a i from the stream and returns a
+    reference to the stream. See flags() for an explanation of the
+    expected input format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( signed long &i )
+{
+    CHECK_STREAM_PRECOND
+    i = (signed long)input_int();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads an unsigned \c long int \a i from the stream and returns a
+    reference to the stream. See flags() for an explanation of the
+    expected input format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( unsigned long &i )
+{
+    CHECK_STREAM_PRECOND
+    i = (unsigned long)input_int();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads a \c float \a f from the stream and returns a reference to
+    the stream. See flags() for an explanation of the expected input
+    format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( float &f )
+{
+    CHECK_STREAM_PRECOND
+    f = (float)input_double();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads a \c double \a f from the stream and returns a reference to
+    the stream. See flags() for an explanation of the expected input
+    format.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( double &f )
+{
+    CHECK_STREAM_PRECOND
+    f = input_double();
+    return *this;
+}
+
+
+/*!
+    \overload
+
+    Reads a "word" from the stream into \a s and returns a reference
+    to the stream.
+
+    A word consists of characters for which isspace() returns FALSE.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( char *s )
+{
+    CHECK_STREAM_PRECOND
+    int maxlen = width( 0 );
+    QChar c = eat_ws();
+    if ( !maxlen )
+	maxlen = -1;
+    while ( c != QEOF ) {
+	if ( ts_isspace(c) || maxlen-- == 0 ) {
+	    ts_ungetc( c );
+	    break;
+	}
+	*s++ = c.toLatin1();
+	c = ts_getc();
+    }
+
+    *s = '\0';
+    return *this;
+}
+
+/*!
+    \overload
+
+    Reads a "word" from the stream into \a str and returns a reference
+    to the stream.
+
+    A word consists of characters for which isspace() returns FALSE.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( QString &str )
+{
+    CHECK_STREAM_PRECOND
+    str=QString::fromLatin1("");
+    QChar	c = eat_ws();
+
+    while ( c != QEOF ) {
+	if ( ts_isspace(c) ) {
+	    ts_ungetc( c );
+	    break;
+	}
+
+	str += c;
+	c = ts_getc();
+    }
+
+    return *this;
+}
+
+/*!
+    \overload
+
+    Reads a "word" from the stream into \a str and returns a reference
+    to the stream.
+
+    A word consists of characters for which isspace() returns FALSE.
+*/
+
+Q3TextStream &Q3TextStream::operator>>( Q3CString &str )
+{
+    CHECK_STREAM_PRECOND
+    Q3CString  *dynbuf = 0;
+    const int buflen = 256;
+    char      buffer[buflen];
+    char     *s = buffer;
+    int	      i = 0;
+    QChar	      c = eat_ws();
+
+    while ( c != QEOF ) {
+	if ( ts_isspace(c) ) {
+	    ts_ungetc( c );
+	    break;
+	}
+	if ( i >= buflen-1 ) {
+	    if ( !dynbuf )  {			// create dynamic buffer
+		dynbuf = new Q3CString(buflen*2);
+		memcpy( dynbuf->data(), s, i );	// copy old data
+	    } else if ( i >= (int)dynbuf->size()-1 ) {
+		dynbuf->resize( dynbuf->size()*2 );
+	    }
+	    s = dynbuf->data();
+	}
+	s[i++] = c.toLatin1();
+	c = ts_getc();
+    }
+    str.resize( i );
+    memcpy( str.data(), s, i );
+
+    delete dynbuf;
+    return *this;
+}
+
+
+/*!
+    \since 4.2
+
+    Reads a line from the stream and returns a string containing the
+    text.
+
+    The returned string does not contain any trailing newline or
+    carriage return. Note that this is different from
+    QIODevice::readLine(), which does not strip the newline at the end
+    of the line.
+
+    On EOF you will get a QString that is null. On reading an empty
+    line the returned QString is empty but not null.
+
+    \sa QIODevice::readLine()
+*/
+
+QString Q3TextStream::readLine()
+{
+#if defined(QT_CHECK_STATE)
+    if ( !dev ) {
+	qWarning( "Q3TextStream::readLine: No device" );
+	return QString::null;
+    }
+#endif
+    bool readCharByChar = TRUE;
+    QString result;
+#if 0
+    if ( !doUnicodeHeader && (
+	    (latin1) ||
+	    (mapper != 0 && mapper->mibEnum() == 106 ) // UTF 8
+       ) ) {
+	readCharByChar = FALSE;
+	// use optimized read line
+	QChar c[getline_buf_size];
+	int pos = 0;
+	bool eof = FALSE;
+
+	for (;;) {
+	    pos = ts_getline( c );
+	    if ( pos == 0 ) {
+		// something went wrong; try fallback
+		readCharByChar = TRUE;
+		//dev->resetStatus();
+		break;
+	    }
+	    if ( c[pos-1] == QEOF || c[pos-1] == '\n' ) {
+		if ( pos>2 && c[pos-1]==QEOF && c[pos-2]=='\n' ) {
+		    result += QString( c, pos-2 );
+		} else if ( pos > 1 ) {
+		    result += QString( c, pos-1 );
+		}
+		if ( pos == 1 && c[pos-1] == QEOF )
+		    eof = TRUE;
+		break;
+	    } else {
+		result += QString( c, pos );
+	    }
+	}
+	if ( eof && result.isEmpty() )
+	    return QString::null;
+    }
+#endif
+    if ( readCharByChar ) {
+	const int buf_size = 256;
+	QChar c[buf_size];
+	int pos = 0;
+
+	c[pos] = ts_getc();
+	if ( c[pos] == QEOF )
+	    return QString::null;
+
+	while ( c[pos] != QEOF && c[pos] != QLatin1Char('\n') ) {
+	    if ( c[pos] == QLatin1Char('\r') ) { // ( handle mac and dos )
+		QChar nextc = ts_getc();
+		if ( nextc != QLatin1Char('\n') )
+		    ts_ungetc( nextc );
+		break;
+	    }
+	    pos++;
+	    if ( pos >= buf_size ) {
+		result += QString( c, pos );
+		pos = 0;
+	    }
+	    c[pos] = ts_getc();
+	}
+	result += QString( c, pos );
+    }
+
+    return result;
+}
+
+
+/*!
+    \since 4.2
+
+    Reads the entire stream from the current position, and returns a string
+    containing the text.
+
+    \sa readLine()
+*/
+
+QString Q3TextStream::read()
+{
+#if defined(QT_CHECK_STATE)
+    if ( !dev ) {
+	qWarning( "Q3TextStream::read: No device" );
+	return QString::null;
+    }
+#endif
+    QString    result;
+    const uint bufsize = 512;
+    QChar      buf[bufsize];
+    uint       i, num, start;
+    bool       skipped_cr = FALSE;
+
+    for (;;) {
+	num = ts_getbuf(buf,bufsize);
+	// convert dos (\r\n) and mac (\r) style eol to unix style (\n)
+	start = 0;
+	for ( i=0; i<num; i++ ) {
+	    if ( buf[i] == QLatin1Char('\r') ) {
+		// Only skip single cr's preceding lf's
+		if ( skipped_cr ) {
+		    result += buf[i];
+		    start++;
+		} else {
+		    result += QString( &buf[start], i-start );
+		    start = i+1;
+		    skipped_cr = TRUE;
+		}
+	    } else {
+		if ( skipped_cr ) {
+		    if ( buf[i] != QLatin1Char('\n') ) {
+			// Should not have skipped it
+			result += QLatin1Char('\n');
+		    }
+		    skipped_cr = FALSE;
+		}
+	    }
+	}
+	if ( start < num )
+	    result += QString( &buf[start], i-start );
+	if ( num != bufsize ) // if ( EOF )
+	    break;
+    }
+    return result;
+}
+
+
+
+/*****************************************************************************
+  Q3TextStream write functions
+ *****************************************************************************/
+
+/*!
+    \since 4.2
+
+    Writes character \c char to the stream and returns a reference to
+    the stream.
+
+    The character \a c is assumed to be Latin1 encoded independent of
+    the Encoding set for the Q3TextStream.
+*/
+Q3TextStream &Q3TextStream::operator<<( QChar c )
+{
+    CHECK_STREAM_PRECOND
+    ts_putc( c );
+    return *this;
+}
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes character \a c to the stream and returns a reference to the
+    stream.
+*/
+Q3TextStream &Q3TextStream::operator<<( char c )
+{
+    CHECK_STREAM_PRECOND
+    unsigned char uc = (unsigned char) c;
+    ts_putc( uc );
+    return *this;
+}
+
+Q3TextStream &Q3TextStream::output_int( int format, ulong n, bool neg )
+{
+    static const char hexdigits_lower[] = "0123456789abcdef";
+    static const char hexdigits_upper[] = "0123456789ABCDEF";
+    CHECK_STREAM_PRECOND
+    char buf[76];
+    register char *p;
+    int	  len;
+    const char *hexdigits;
+
+    switch ( flags() & I_BASE_MASK ) {
+
+	case I_BASE_2:				// output binary number
+	    switch ( format & I_TYPE_MASK ) {
+		case I_SHORT: len=16; break;
+		case I_INT:   len=sizeof(int)*8; break;
+		case I_LONG:  len=32; break;
+		default:      len = 0;
+	    }
+	    p = &buf[74];			// go reverse order
+	    *p = '\0';
+	    while ( len-- ) {
+		*--p = (char)(n&1) + '0';
+		n >>= 1;
+		if ( !n )
+		    break;
+	    }
+	    if ( flags() & showbase ) {		// show base
+		*--p = (flags() & uppercase) ? 'B' : 'b';
+		*--p = '0';
+	    }
+	    break;
+
+	case I_BASE_8:				// output octal number
+	    p = &buf[74];
+	    *p = '\0';
+	    do {
+		*--p = (char)(n&7) + '0';
+		n >>= 3;
+	    } while ( n );
+	    if ( flags() & showbase )
+		*--p = '0';
+	    break;
+
+	case I_BASE_16:				// output hexadecimal number
+	    p = &buf[74];
+	    *p = '\0';
+	    hexdigits = (flags() & uppercase) ?
+		hexdigits_upper : hexdigits_lower;
+	    do {
+		*--p = hexdigits[(int)n&0xf];
+		n >>= 4;
+	    } while ( n );
+	    if ( flags() & showbase ) {
+		*--p = (flags() & uppercase) ? 'X' : 'x';
+		*--p = '0';
+	    }
+	    break;
+
+	default:				// decimal base is default
+	    p = &buf[74];
+	    *p = '\0';
+	    if ( neg )
+		n = (ulong)(-(long)n);
+	    do {
+		*--p = ((int)(n%10)) + '0';
+		n /= 10;
+	    } while ( n );
+	    if ( neg )
+		*--p = '-';
+	    else if ( flags() & showpos )
+		*--p = '+';
+	    if ( (flags() & internal) && fwidth && !ts_isdigit(QLatin1Char(*p)) ) {
+		ts_putc( *p );			// special case for internal
+		++p;				//   padding
+		fwidth--;
+		return *this << (const char*)p;
+	    }
+    }
+    if ( fwidth ) {				// adjustment required
+	if ( !(flags() & left) ) {		// but NOT left adjustment
+	    len = qstrlen(p);
+	    int padlen = fwidth - len;
+	    if ( padlen <= 0 ) {		// no padding required
+		writeBlock( p, len );
+	    } else if ( padlen < (int)(p-buf) ) { // speeds up padding
+		memset( p-padlen, (char)fillchar, padlen );
+		writeBlock( p-padlen, padlen+len );
+	    }
+	    else				// standard padding
+		*this << (const char*)p;
+	}
+	else
+	    *this << (const char*)p;
+	fwidth = 0;				// reset field width
+    }
+    else {
+	writeBlock( p, qstrlen(p) );
+    }
+    return *this;
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes a \c short integer \a i to the stream and returns a
+    reference to the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( signed short i )
+{
+    return output_int( I_SHORT | I_SIGNED, i, i < 0 );
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes an \c unsigned \c short integer \a i to the stream and
+    returns a reference to the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( unsigned short i )
+{
+    return output_int( I_SHORT | I_UNSIGNED, i, FALSE );
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes an \c int \a i to the stream and returns a reference to the
+    stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( signed int i )
+{
+    return output_int( I_INT | I_SIGNED, i, i < 0 );
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes an \c unsigned \c int \a i to the stream and returns a
+    reference to the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( unsigned int i )
+{
+    return output_int( I_INT | I_UNSIGNED, i, FALSE );
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes a \c long \c int \a i to the stream and returns a reference
+    to the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( signed long i )
+{
+    return output_int( I_LONG | I_SIGNED, i, i < 0 );
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes an \c unsigned \c long \c int \a i to the stream and
+    returns a reference to the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( unsigned long i )
+{
+    return output_int( I_LONG | I_UNSIGNED, i, FALSE );
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes a \c float \a f to the stream and returns a reference to
+    the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( float f )
+{
+    return *this << (double)f;
+}
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes a \c double \a f to the stream and returns a reference to
+    the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( double f )
+{
+    CHECK_STREAM_PRECOND
+    char f_char;
+    char format[16];
+    if ( (flags()&floatfield) == fixed )
+	f_char = 'f';
+    else if ( (flags()&floatfield) == scientific )
+	f_char = (flags() & uppercase) ? 'E' : 'e';
+    else
+	f_char = (flags() & uppercase) ? 'G' : 'g';
+    register char *fs = format;			// generate format string
+    *fs++ = '%';				//   "%.<prec>l<f_char>"
+    *fs++ = '.';
+    int prec = precision();
+    if ( prec > 99 )
+	prec = 99;
+    if ( prec >= 10 ) {
+	*fs++ = prec / 10 + '0';
+	*fs++ = prec % 10 + '0';
+    } else {
+	*fs++ = prec + '0';
+    }
+    *fs++ = 'l';
+    *fs++ = f_char;
+    *fs = '\0';
+    QString num;
+    num.sprintf(format, f);			// convert to text
+    if ( fwidth )				// padding
+	*this << num.latin1();
+    else					// just write it
+	writeBlock(num.latin1(), num.length());
+    return *this;
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes a string to the stream and returns a reference to the
+    stream.
+
+    The string \a s is assumed to be Latin1 encoded independent of the
+    Encoding set for the Q3TextStream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( const char* s )
+{
+    CHECK_STREAM_PRECOND
+    char padbuf[48];
+    uint len = qstrlen( s );			// don't write null terminator
+    if ( fwidth ) {				// field width set
+	int padlen = fwidth - len;
+	fwidth = 0;				// reset width
+	if ( padlen > 0 ) {
+	    char *ppad;
+	    if ( padlen > 46 ) {		// create extra big fill buffer
+		ppad = new char[padlen];
+		Q_CHECK_PTR( ppad );
+	    } else {
+		ppad = padbuf;
+	    }
+	    memset( ppad, (char)fillchar, padlen );	// fill with fillchar
+	    if ( !(flags() & left) ) {
+		writeBlock( ppad, padlen );
+		padlen = 0;
+	    }
+	    writeBlock( s, len );
+	    if ( padlen )
+		writeBlock( ppad, padlen );
+	    if ( ppad != padbuf )		// delete extra big fill buf
+		delete[] ppad;
+	    return *this;
+	}
+    }
+    writeBlock( s, len );
+    return *this;
+}
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes \a s to the stream and returns a reference to the stream.
+
+    The string \a s is assumed to be Latin1 encoded independent of the
+    Encoding set for the Q3TextStream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( const Q3CString & s )
+{
+    return operator<<(s.data());
+}
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes \a s to the stream and returns a reference to the stream.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( const QString& s )
+{
+    if ( !mapper && latin1 )
+	return operator<<(s.latin1());
+    CHECK_STREAM_PRECOND
+    QString s1 = s;
+    if ( fwidth ) {				// field width set
+	if ( !(flags() & left) ) {
+	    s1 = s.rightJustify(fwidth, QLatin1Char((char)fillchar));
+	} else {
+	    s1 = s.leftJustify(fwidth, QLatin1Char((char)fillchar));
+	}
+	fwidth = 0;				// reset width
+    }
+    writeBlock( s1.unicode(), s1.length() );
+    return *this;
+}
+
+
+/*!
+    \overload
+    \since 4.2
+
+    Writes a pointer to the stream and returns a reference to the
+    stream.
+
+    The \a ptr is output as an unsigned long hexadecimal integer.
+*/
+
+Q3TextStream &Q3TextStream::operator<<( void *ptr )
+{
+    int f = flags();
+    setf( hex, basefield );
+    setf( showbase );
+    unsetf( uppercase );
+    output_int( I_LONG | I_UNSIGNED, (ulong)ptr, FALSE );
+    flags( f );
+    return *this;
+}
+
+
+/*!
+    \fn int Q3TextStream::flags() const
+    \since 4.2
+
+    Returns the current stream flags. The default value is 0.
+
+    \table
+    \header \i Flag \i Meaning
+    \row \i \c skipws \i Not currently used; whitespace always skipped
+    \row \i \c left \i Numeric fields are left-aligned
+    \row \i \c right
+	 \i Not currently used (by default, numerics are right-aligned)
+    \row \i \c internal \i Puts any padding spaces between +/- and value
+    \row \i \c bin \i Output \e and input only in binary
+    \row \i \c oct \i Output \e and input only in octal
+    \row \i \c dec \i Output \e and input only in decimal
+    \row \i \c hex \i Output \e and input only in hexadecimal
+    \row \i \c showbase
+	 \i Annotates numeric outputs with 0b, 0, or 0x if in \c bin,
+	 \c oct, or \c hex format
+    \row \i \c showpoint \i Not currently used
+    \row \i \c uppercase \i Uses 0B and 0X rather than 0b and 0x
+    \row \i \c showpos \i Shows + for positive numeric values
+    \row \i \c scientific \i Uses scientific notation for floating point values
+    \row \i \c fixed \i Uses fixed-point notation for floating point values
+    \endtable
+
+    Note that unless \c bin, \c oct, \c dec, or \c hex is set, the
+    input base is octal if the value starts with 0, hexadecimal if it
+    starts with 0x, binary if it starts with 0b, and decimal
+    otherwise.
+
+    \sa setf(), unsetf()
+*/
+
+/*!
+    \fn int Q3TextStream::flags( int f )
+
+    \overload
+
+    Sets the stream flags to \a f. Returns the previous stream flags.
+
+    \sa setf(), unsetf(), flags()
+*/
+
+/*!
+    \fn int Q3TextStream::setf( int bits )
+    \since 4.2
+
+    Sets the stream flag bits \a bits. Returns the previous stream
+    flags.
+
+    Equivalent to \c{flags( flags() | bits )}.
+
+    \sa unsetf()
+*/
+
+/*!
+    \fn int Q3TextStream::setf( int bits, int mask )
+
+    \overload
+
+    Sets the stream flag bits \a bits with a bit mask \a mask. Returns
+    the previous stream flags.
+
+    Equivalent to \c{flags( (flags() & ~mask) | (bits & mask) )}.
+
+    \sa setf(), unsetf()
+*/
+
+/*!
+    \fn int Q3TextStream::unsetf( int bits )
+    \since 4.2
+
+    Clears the stream flag bits \a bits. Returns the previous stream
+    flags.
+
+    Equivalent to \c{flags( flags() & ~mask )}.
+
+    \sa setf()
+*/
+
+/*!
+    \fn int Q3TextStream::width() const
+    \since 4.2
+
+    Returns the field width. The default value is 0.
+*/
+
+/*!
+    \fn int Q3TextStream::width( int w )
+
+    \overload
+
+    Sets the field width to \a w. Returns the previous field width.
+*/
+
+/*!
+    \fn int Q3TextStream::fill() const
+    \since 4.2
+
+    Returns the fill character. The default value is ' ' (space).
+*/
+
+/*!
+    \fn int Q3TextStream::fill( int f )
+    \overload
+
+    Sets the fill character to \a f. Returns the previous fill character.
+*/
+
+/*!
+    \fn int Q3TextStream::precision() const
+    \since 4.2
+
+    Returns the precision. The default value is 6.
+*/
+
+/*!
+    \fn int Q3TextStream::precision( int p )
+
+    \overload
+
+    Sets the precision to \a p. Returns the previous precision setting.
+*/
+
+
+Q3TextStream &bin( Q3TextStream &s )
+{
+    s.setf(Q3TextStream::bin,Q3TextStream::basefield);
+    return s;
+}
+
+Q3TextStream &oct( Q3TextStream &s )
+{
+    s.setf(Q3TextStream::oct,Q3TextStream::basefield);
+    return s;
+}
+
+Q3TextStream &dec( Q3TextStream &s )
+{
+    s.setf(Q3TextStream::dec,Q3TextStream::basefield);
+    return s;
+}
+
+Q3TextStream &hex( Q3TextStream &s )
+{
+    s.setf(Q3TextStream::hex,Q3TextStream::basefield);
+    return s;
+}
+
+Q3TextStream &endl( Q3TextStream &s )
+{
+    return s << '\n';
+}
+
+Q3TextStream &flush( Q3TextStream &s )
+{
+    return s;
+}
+
+Q3TextStream &ws( Q3TextStream &s )
+{
+    s.skipWhiteSpace();
+    return s;
+}
+
+Q3TextStream &reset( Q3TextStream &s )
+{
+    s.reset();
+    return s;
+}
+
+/*!
+  \since 4.2
+
+  Sets the encoding of this stream to \a e, where \a e is one of the
+  following values:
+  \table
+  \header \i Encoding \i Meaning
+  \row \i Locale
+       \i Uses local file format (Latin1 if locale is not set), but
+       autodetecting Unicode(utf16) on input.
+  \row \i Unicode
+       \i Uses Unicode(utf16) for input and output. Output will be
+       written in the order most efficient for the current platform
+       (i.e. the order used internally in QString).
+  \row \i UnicodeUTF8
+       \i Using Unicode(utf8) for input and output. If you use it for
+       input it will autodetect utf16 and use it instead of utf8.
+  \row \i Latin1
+       \i ISO-8859-1. Will not autodetect utf16.
+  \row \i UnicodeNetworkOrder
+       \i Uses network order Unicode(utf16) for input and output.
+       Useful when reading Unicode data that does not start with the
+       byte order marker.
+  \row \i UnicodeReverse
+       \i Uses reverse network order Unicode(utf16) for input and
+       output. Useful when reading Unicode data that does not start
+       with the byte order marker or when writing data that should be
+       read by buggy Windows applications.
+  \row \i RawUnicode
+       \i Like Unicode, but does not write the byte order marker nor
+       does it auto-detect the byte order. Useful only when writing to
+       non-persistent storage used by a single process.
+  \endtable
+
+  \c Locale and all Unicode encodings, except \c RawUnicode, will look
+  at the first two bytes in an input stream to determine the byte
+  order. The initial byte order marker will be stripped off before
+  data is read.
+
+  Note that this function should be called before any data is read to
+  or written from the stream.
+
+  \sa setCodec()
+*/
+
+void Q3TextStream::setEncoding( Encoding e )
+{
+    resetCodecConverterState(&mapperReadState);
+    resetCodecConverterState(&mapperWriteState);
+
+    if ( d->sourceType == Q3TextStreamPrivate::String )
+	return;
+
+    switch ( e ) {
+    case Unicode:
+	mapper = 0;
+	latin1 = FALSE;
+	doUnicodeHeader = TRUE;
+	internalOrder = TRUE;
+	networkOrder = QChar::networkOrdered();
+	break;
+    case UnicodeUTF8:
+#ifndef QT_NO_TEXTCODEC
+	mapper = QTextCodec::codecForMib( 106 );
+        mapperWriteState.flags |= QTextCodec::IgnoreHeader;
+	latin1 = FALSE;
+	doUnicodeHeader = TRUE;
+	internalOrder = TRUE;
+	networkOrder = QChar::networkOrdered();
+#else
+	mapper = 0;
+	latin1 = TRUE;
+	doUnicodeHeader = TRUE;
+#endif
+	break;
+    case UnicodeNetworkOrder:
+	mapper = 0;
+	latin1 = FALSE;
+	doUnicodeHeader = TRUE;
+	internalOrder = QChar::networkOrdered();
+	networkOrder = TRUE;
+	break;
+    case UnicodeReverse:
+	mapper = 0;
+	latin1 = FALSE;
+	doUnicodeHeader = TRUE;
+	internalOrder = !QChar::networkOrdered();
+	networkOrder = FALSE;
+	break;
+    case RawUnicode:
+	mapper = 0;
+	latin1 = FALSE;
+	doUnicodeHeader = FALSE;
+	internalOrder = TRUE;
+	networkOrder = QChar::networkOrdered();
+	break;
+    case Locale:
+	latin1 = TRUE; // fallback to Latin-1
+#ifndef QT_NO_TEXTCODEC
+	mapper = QTextCodec::codecForLocale();
+        mapperReadState.flags |= QTextCodec::IgnoreHeader;
+        mapperWriteState.flags |= QTextCodec::IgnoreHeader;
+	// optimized Latin-1 processing
+#if defined(Q_OS_WIN32)
+	if ( GetACP() == 1252 )
+	    mapper = 0;
+#endif
+	if ( mapper && mapper->mibEnum() == 4 )
+#endif
+	    mapper = 0;
+
+	doUnicodeHeader = TRUE; // If it reads as Unicode, accept it
+	break;
+    case Latin1:
+	mapper = 0;
+	doUnicodeHeader = FALSE;
+	latin1 = TRUE;
+	break;
+    }
+}
+
+
+#ifndef QT_NO_TEXTCODEC
+/*!
+    \since 4.2
+
+    Sets the codec for this stream to \a codec. Will not try to
+    autodetect Unicode.
+
+    Note that this function should be called before any data is read
+    to/written from the stream.
+
+    \sa setEncoding(), codec()
+*/
+
+void Q3TextStream::setCodec( QTextCodec *codec )
+{
+    if ( d->sourceType == Q3TextStreamPrivate::String )
+	return; // QString does not need any codec
+    mapper = codec;
+    latin1 = ( codec->mibEnum() == 4 );
+    if ( latin1 )
+	mapper = 0;
+    doUnicodeHeader = FALSE;
+}
+
+/*!
+  Returns the codec actually used for this stream.
+  \since 4.2
+
+  If Unicode is automatically detected in input, a codec with \link
+  QTextCodec::name() name() \endlink "ISO-10646-UCS-2" is returned.
+
+  \sa setCodec()
+*/
+
+QTextCodec *Q3TextStream::codec()
+{
+    if ( mapper ) {
+	return mapper;
+    } else {
+	// 4 is "ISO 8859-1", 1000 is "ISO-10646-UCS-2"
+	return QTextCodec::codecForMib( latin1 ? 4 : 1000 );
+    }
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_TEXTSTREAM