src/corelib/io/qtextstream.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtCore module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 //#define QTEXTSTREAM_DEBUG
00025 static const int QTEXTSTREAM_BUFFERSIZE = 16384;
00026 
00212 #include "qtextstream.h"
00213 #include "qbuffer.h"
00214 #include "qfile.h"
00215 #ifndef QT_NO_TEXTCODEC
00216 #include "qtextcodec.h"
00217 #endif
00218 #ifndef Q_OS_TEMP
00219 #include <locale.h>
00220 #endif
00221 
00222 #include <stdlib.h>
00223 
00224 #if defined QTEXTSTREAM_DEBUG
00225 #include <ctype.h>
00226 
00227 // Returns a human readable representation of the first \a len
00228 // characters in \a data.
00229 static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
00230 {
00231     if (!data) return "(null)";
00232     QByteArray out;
00233     for (int i = 0; i < len; ++i) {
00234         char c = data[i];
00235         if (isprint(c)) {
00236             out += c;
00237         } else switch (c) {
00238         case '\n': out += "\\n"; break;
00239         case '\r': out += "\\r"; break;
00240         case '\t': out += "\\t"; break;
00241         default:
00242             QString tmp;
00243             tmp.sprintf("\\x%x", (unsigned int)(unsigned char)c);
00244             out += tmp.toLatin1();
00245         }
00246     }
00247 
00248     if (len < maxSize)
00249         out += "...";
00250 
00251     return out;
00252 }
00253 #endif
00254 
00255 // A precondition macro
00256 #define Q_VOID
00257 #define CHECK_VALID_STREAM(x) do { \
00258     if (!d->string && !d->device) { \
00259         qWarning("QTextStream: No device"); \
00260         return x; \
00261     } } while (0)
00262 
00263 // Base implementations of operator>> for ints and reals
00264 #define IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(type) do { \
00265     Q_D(QTextStream); \
00266     CHECK_VALID_STREAM(*this); \
00267     qulonglong tmp; \
00268     switch (d->getNumber(&tmp)) { \
00269     case QTextStreamPrivate::npsOk: \
00270         i = (type)tmp; \
00271         break; \
00272     case QTextStreamPrivate::npsMissingDigit: \
00273     case QTextStreamPrivate::npsInvalidPrefix: \
00274         i = (type)0; \
00275         setStatus(atEnd() ? QTextStream::ReadPastEnd : QTextStream::ReadCorruptData); \
00276         break; \
00277     } \
00278     return *this; } while (0)
00279 
00280 #define IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR(type) do { \
00281     Q_D(QTextStream); \
00282     CHECK_VALID_STREAM(*this); \
00283     double tmp; \
00284     if (d->getReal(&tmp)) { \
00285         f = (type)tmp; \
00286     } else { \
00287         f = (type)0; \
00288         setStatus(atEnd() ? QTextStream::ReadPastEnd : QTextStream::ReadCorruptData); \
00289     } \
00290     return *this; } while (0)
00291 
00292 #ifndef QT_NO_QOBJECT
00293 class QDeviceClosedNotifier : public QObject
00294 {
00295     Q_OBJECT
00296 public:
00297     inline QDeviceClosedNotifier()
00298     { }
00299 
00300     inline void setupDevice(QTextStream *stream, QIODevice *device)
00301     {
00302         disconnect();
00303         if (device)
00304             connect(device, SIGNAL(aboutToClose()), this, SLOT(flushStream()));
00305         this->stream = stream;
00306     }
00307 
00308 public slots:
00309     inline void flushStream() { stream->flush(); }
00310 
00311 private:
00312     QTextStream *stream;
00313 };
00314 #endif
00315 
00316 //-------------------------------------------------------------------
00317 class QTextStreamPrivate
00318 {
00319     Q_DECLARE_PUBLIC(QTextStream)
00320 public:
00321     QTextStreamPrivate(QTextStream *q_ptr);
00322     ~QTextStreamPrivate();
00323     void reset();
00324 
00325     // device
00326     QIODevice *device;
00327 #ifndef QT_NO_QOBJECT
00328     QDeviceClosedNotifier deviceClosedNotifier;
00329 #endif
00330     bool deleteDevice;
00331 
00332     // string
00333     QString *string;
00334     int stringOffset;
00335     QIODevice::OpenMode stringOpenMode;
00336 
00337 #ifndef QT_NO_TEXTCODEC
00338     // codec
00339     QTextCodec *codec;
00340     QTextCodec::ConverterState readConverterState;
00341     QTextCodec::ConverterState writeConverterState;
00342     bool autoDetectUnicode;
00343 #endif
00344 
00345     // i/o
00346     enum TokenDelimiter {
00347         Space,
00348         NotSpace,
00349         EndOfLine,
00350         EndOfFile
00351     };
00352 
00353     bool scan(const QChar **ptr, int *tokenLength,
00354               int maxlen, TokenDelimiter delimiter);
00355     inline const QChar *readPtr() const;
00356     inline void consumeLastToken();
00357     inline void consume(int nchars);
00358     int lastTokenSize;
00359 
00360     // Return value type for getNumber()
00361     enum NumberParsingStatus {
00362         npsOk,
00363         npsMissingDigit,
00364         npsInvalidPrefix
00365     };
00366 
00367     inline bool write(const QString &data);
00368     inline bool getChar(QChar *ch);
00369     inline void ungetChar(const QChar &ch);
00370     NumberParsingStatus getNumber(qulonglong *l);
00371     bool getReal(double *f);
00372 
00373     bool putNumber(qulonglong number, bool negative);
00374     inline bool putString(const QString &ch);
00375 
00376     // buffers
00377     bool fillReadBuffer(qint64 maxBytes = -1);
00378     bool flushWriteBuffer();
00379     QString writeBuffer;
00380     QString readBuffer;
00381     int readBufferOffset;
00382     qint64 readBufferStartDevicePos;
00383     QString endOfBufferState;
00384 #ifndef QT_NO_TEXTCODEC
00385     QTextCodec::ConverterState readBufferStartReadConverterState;
00386 #endif
00387     QString readBufferStartEndOfBufferState;
00388 
00389     // streaming parameters
00390     int realNumberPrecision;
00391     int integerBase;
00392     int fieldWidth;
00393     QChar padChar;
00394     QTextStream::FieldAlignment fieldAlignment;
00395     QTextStream::RealNumberNotation realNumberNotation;
00396     QTextStream::NumberFlags numberFlags;
00397 
00398     // status
00399     QTextStream::Status status;
00400 
00401     QTextStream *q_ptr;
00402 };
00403 
00406 QTextStreamPrivate::QTextStreamPrivate(QTextStream *q_ptr)
00407 {
00408     this->q_ptr = q_ptr;
00409     reset();
00410 }
00411 
00414 QTextStreamPrivate::~QTextStreamPrivate()
00415 {
00416     if (deleteDevice)
00417         delete device;
00418 }
00419 
00420 #ifndef QT_NO_TEXTCODEC
00421 static void resetCodecConverterState(QTextCodec::ConverterState *state) {
00422     state->flags = QTextCodec::DefaultConversion;
00423     state->remainingChars = state->invalidChars =
00424            state->state_data[0] = state->state_data[1] = state->state_data[2] = 0;
00425     if (state->d) qFree(state->d);
00426     state->d = 0;
00427 }
00428 
00429 static void copyConverterState(QTextCodec::ConverterState *dest, const QTextCodec::ConverterState *src)
00430 {
00431     // ### QTextCodec::ConverterState's copy constructors and assignments are
00432     // private. This function copies the structure manually.
00433     dest->flags = src->flags;
00434     dest->invalidChars = src->invalidChars;
00435     dest->state_data[0] = src->state_data[0];
00436     dest->state_data[1] = src->state_data[1];
00437     dest->state_data[2] = src->state_data[2];
00438     dest->d = src->d; // <- ### wrong?
00439 }
00440 #endif
00441 
00444 void QTextStreamPrivate::reset()
00445 {
00446     realNumberPrecision = 6;
00447     integerBase = 0;
00448     fieldWidth = 0;
00449     padChar = QLatin1Char(' ');
00450     fieldAlignment = QTextStream::AlignRight;
00451     realNumberNotation = QTextStream::SmartNotation;
00452     numberFlags = 0;
00453 
00454     device = 0;
00455     deleteDevice = false;
00456     string = 0;
00457     stringOffset = 0;
00458     stringOpenMode = QIODevice::NotOpen;
00459 
00460     readBufferOffset = 0;
00461     readBufferStartDevicePos = 0;
00462     endOfBufferState.clear();
00463     lastTokenSize = 0;
00464 
00465 #ifndef QT_NO_TEXTCODEC
00466     codec = QTextCodec::codecForLocale();
00467     ::resetCodecConverterState(&readConverterState);
00468     ::resetCodecConverterState(&writeConverterState);
00469     ::resetCodecConverterState(&readBufferStartReadConverterState);
00470     writeConverterState.flags |= QTextCodec::IgnoreHeader;
00471     autoDetectUnicode = true;
00472 #endif
00473 }
00474 
00477 bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
00478 {
00479     // no buffer next to the QString itself; this function should only
00480     // be called internally, for devices.
00481     Q_ASSERT(!string);
00482     Q_ASSERT(device);
00483 
00484     // handle text translation and bypass the Text flag in the device.
00485     bool textModeEnabled = device->isTextModeEnabled();
00486     if (textModeEnabled)
00487         device->setTextModeEnabled(false);
00488 
00489 #ifndef QT_NO_TEXTCODEC
00490     // codec auto detection, explicitly defaults to locale encoding if
00491     // the codec has been set to 0.
00492     if (!codec || autoDetectUnicode) {
00493         autoDetectUnicode = false;
00494 
00495         char bomBuffer[2];
00496         if (device->peek(bomBuffer, 2) == 2 && (uchar(bomBuffer[0]) == 0xff && uchar(bomBuffer[1]) == 0xfe
00497                                                 || uchar(bomBuffer[0]) == 0xfe && uchar(bomBuffer[1]) == 0xff)) {
00498             codec = QTextCodec::codecForName("UTF-16");
00499         } else if (!codec) {
00500             codec = QTextCodec::codecForLocale();
00501             writeConverterState.flags |= QTextCodec::IgnoreHeader;
00502         }
00503     }
00504 #if defined (QTEXTSTREAM_DEBUG)
00505     qDebug("QTextStreamPrivate::fillReadBuffer(), using %s codec",
00506            codec->name().constData());
00507 #endif
00508 #endif
00509 
00510     // read raw data into a temporary buffer
00511     char buf[QTEXTSTREAM_BUFFERSIZE];
00512     qint64 bytesRead = 0;
00513 #if defined(Q_OS_WIN)
00514     // On Windows, there is no non-blocking stdin - so we fall back to reading
00515     // lines instead. If there is no QOBJECT, we read lines for all sequential
00516     // devices; otherwise, we read lines only for stdin.
00517     QFile *file = 0;
00518     Q_UNUSED(file);
00519     if (device->isSequential()
00520 #if !defined(QT_NO_QOBJECT)
00521         && (file = qobject_cast<QFile *>(device)) && file->handle() == 0
00522 #endif
00523         ) {
00524         if (maxBytes != -1)
00525             bytesRead = device->readLine(buf, qMin<qint64>(sizeof(buf), maxBytes));
00526         else
00527             bytesRead = device->readLine(buf, sizeof(buf));
00528     } else
00529 #endif
00530     {
00531         if (maxBytes != -1)
00532             bytesRead = device->read(buf, qMin<qint64>(sizeof(buf), maxBytes));
00533         else
00534             bytesRead = device->read(buf, sizeof(buf));
00535     }
00536 
00537 #if defined (QTEXTSTREAM_DEBUG)
00538     qDebug("QTextStreamPrivate::fillReadBuffer(), device->read(\"%s\", %d) == %d",
00539            qt_prettyDebug(buf, qMin(32,int(bytesRead)) , int(bytesRead)).constData(), sizeof(buf), int(bytesRead));
00540 #endif
00541     if (bytesRead <= 0)
00542         return false;
00543 
00544     int oldReadBufferSize = readBuffer.size();
00545     readBuffer += endOfBufferState;
00546 #ifndef QT_NO_TEXTCODEC
00547     // convert to unicode
00548     readBuffer += codec->toUnicode(buf, bytesRead, &readConverterState);
00549 #else
00550     readBuffer += QString(QByteArray(buf, bytesRead));
00551 #endif
00552 
00553     // reset the Text flag.
00554     if (textModeEnabled)
00555         device->setTextModeEnabled(true);
00556 
00557     // remove all '\r\n' in the string.
00558     if (readBuffer.size() > oldReadBufferSize && textModeEnabled) {
00559         QChar CR = QLatin1Char('\r');
00560         QChar LF = QLatin1Char('\n');
00561         QChar *writePtr = readBuffer.data();
00562         QChar *readPtr = readBuffer.data();
00563         QChar *endPtr = readBuffer.data() + readBuffer.size();
00564 
00565         int n = 0;
00566         while (readPtr < endPtr) {
00567             if (readPtr + 1 < endPtr && *readPtr == CR && *(readPtr + 1) == LF) {
00568                 *writePtr = LF;
00569                 if (n < readBufferOffset)
00570                     --readBufferOffset;
00571                 ++readPtr;
00572             } else  if (readPtr != writePtr) {
00573                 *writePtr = *readPtr;
00574             }
00575 
00576             ++n;
00577             ++writePtr;
00578             ++readPtr;
00579         }
00580         readBuffer.resize(writePtr - readBuffer.data());
00581 
00582         if (readBuffer.endsWith(QLatin1Char('\r')) && !device->atEnd()) {
00583             endOfBufferState = QLatin1String("\r");
00584             readBuffer.chop(1);
00585         } else {
00586             endOfBufferState.clear();
00587         }
00588     }
00589 
00590 #if defined (QTEXTSTREAM_DEBUG)
00591     qDebug("QTextStreamPrivate::fillReadBuffer() read %d bytes from device. readBuffer = [%s]", int(bytesRead),
00592            qt_prettyDebug(readBuffer.toLatin1(), readBuffer.size(), readBuffer.size()).data());
00593 #endif
00594     return true;
00595 }
00596 
00599 bool QTextStreamPrivate::flushWriteBuffer()
00600 {
00601     // no buffer next to the QString itself; this function should only
00602     // be called internally, for devices.
00603     if (string || !device)
00604         return false;
00605     if (writeBuffer.isEmpty())
00606         return true;
00607 
00608 #if defined (Q_OS_WIN)
00609     // handle text translation and bypass the Text flag in the device.
00610     bool textModeEnabled = device->isTextModeEnabled();
00611     if (textModeEnabled) {
00612         device->setTextModeEnabled(false);
00613         writeBuffer.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
00614     }
00615 #endif
00616 
00617 #ifndef QT_NO_TEXTCODEC
00618     if (!codec)
00619         codec = QTextCodec::codecForLocale();
00620 #if defined (QTEXTSTREAM_DEBUG)
00621     qDebug("QTextStreamPrivate::flushWriteBuffer(), using %s codec (%s generating BOM)",
00622            codec->name().constData(), writeConverterState.flags & QTextCodec::IgnoreHeader ? "not" : "");
00623 #endif
00624 
00625     // convert from unicode to raw data
00626     QByteArray data = codec->fromUnicode(writeBuffer.data(), writeBuffer.size(), &writeConverterState);
00627 #else
00628     QByteArray data = writeBuffer.toLocal8Bit();
00629 #endif
00630     writeBuffer.clear();
00631 
00632     // write raw data to the device
00633     qint64 bytesWritten = device->write(data);
00634 #if defined (QTEXTSTREAM_DEBUG)
00635     qDebug("QTextStreamPrivate::flushWriteBuffer(), device->write(\"%s\") == %d",
00636            qt_prettyDebug(data.constData(), qMin(data.size(),32), data.size()).constData(), int(bytesWritten));
00637 #endif
00638     if (bytesWritten <= 0)
00639         return false;
00640 
00641 #if defined (Q_OS_WIN)
00642     // replace the text flag
00643     if (textModeEnabled)
00644         device->setTextModeEnabled(true);
00645 #endif
00646 
00647     // flush the file
00648 #ifndef QT_NO_QOBJECT
00649     QFile *file = qobject_cast<QFile *>(device);
00650     bool flushed = file && file->flush();
00651 #else
00652     bool flushed = true;
00653 #endif
00654 
00655 #if defined (QTEXTSTREAM_DEBUG)
00656     qDebug("QTextStreamPrivate::flushWriteBuffer() wrote %d bytes",
00657            int(bytesWritten));
00658 #endif
00659     return flushed && bytesWritten == qint64(data.size());
00660 }
00661 
00668 bool QTextStreamPrivate::scan(const QChar **ptr, int *length, int maxlen, TokenDelimiter delimiter)
00669 {
00670     int totalSize = 0;
00671     int delimSize = 0;
00672     bool consumeDelimiter = false;
00673     bool foundToken = false;
00674     int startOffset = device ? readBufferOffset : stringOffset;
00675     QChar lastChar;
00676 
00677     bool canStillReadFromDevice = true;
00678     do {
00679         int endOffset;
00680         const QChar *chPtr;
00681         if (device) {
00682             chPtr = readBuffer.constData();
00683             endOffset = readBuffer.size();
00684         } else {
00685             chPtr = string->constData();
00686             endOffset = string->size();
00687         }
00688         chPtr += startOffset;
00689 
00690         for (; !foundToken && startOffset < endOffset && (!maxlen || totalSize < maxlen); ++startOffset) {
00691             const QChar ch = *chPtr++;
00692             ++totalSize;
00693 
00694             if (delimiter == Space && ch.isSpace()) {
00695                 foundToken = true;
00696                 delimSize = 1;
00697             } else if (delimiter == NotSpace && !ch.isSpace()) {
00698                 foundToken = true;
00699                 delimSize = 1;
00700             } else if (delimiter == EndOfLine && ch == QLatin1Char('\n')) {
00701                 foundToken = true;
00702                 delimSize = (lastChar == QLatin1Char('\r')) ? 2 : 1;
00703                 consumeDelimiter = true;
00704             }
00705 
00706             lastChar = ch;
00707         }
00708     } while (!foundToken
00709              && (!maxlen || totalSize < maxlen)
00710              && (device && (canStillReadFromDevice = fillReadBuffer())));
00711 
00712     // if the token was not found, but we reached the end of input,
00713     // then we accept what we got. if we are not at the end of input,
00714     // we return false.
00715     if (!foundToken && (!maxlen || totalSize < maxlen)
00716         && (totalSize == 0
00717             || (string && stringOffset + totalSize < string->size())
00718             || (device && !device->atEnd() && canStillReadFromDevice))) {
00719 #if defined (QTEXTSTREAM_DEBUG)
00720         qDebug("QTextStreamPrivate::scan() did not find the token.");
00721 #endif
00722         return false;
00723     }
00724 
00725     // if we find a '\r' at the end of the data when reading lines,
00726     // don't make it part of the line.
00727     if (totalSize > 0 && !foundToken && delimiter == EndOfLine) {
00728         if (((string && stringOffset + totalSize == string->size()) || (device && device->atEnd()))
00729             && lastChar == QLatin1Char('\r')) {
00730             consumeDelimiter = true;
00731             ++delimSize;
00732         }
00733     }
00734 
00735     // set the read offset and length of the token
00736     if (length)
00737         *length = totalSize - delimSize;
00738     if (ptr)
00739         *ptr = readPtr();
00740 
00741     // update last token size. the callee will call consumeLastToken() when
00742     // done.
00743     lastTokenSize = totalSize;
00744     if (!consumeDelimiter)
00745         lastTokenSize -= delimSize;
00746 
00747 #if defined (QTEXTSTREAM_DEBUG)
00748     qDebug("QTextStreamPrivate::scan(%p, %p, %d, %x) token length = %d, delimiter = %d",
00749            ptr, length, maxlen, (int)delimiter, totalSize - delimSize, delimSize);
00750 #endif
00751     return true;
00752 }
00753 
00756 inline const QChar *QTextStreamPrivate::readPtr() const
00757 {
00758     Q_ASSERT(readBufferOffset <= readBuffer.size());
00759     if (string)
00760         return string->constData() + stringOffset;
00761     return readBuffer.constData() + readBufferOffset;
00762 }
00763 
00766 inline void QTextStreamPrivate::consumeLastToken()
00767 {
00768     if (lastTokenSize)
00769         consume(lastTokenSize);
00770     lastTokenSize = 0;
00771 }
00772 
00775 inline void QTextStreamPrivate::consume(int size)
00776 {
00777 #if defined (QTEXTSTREAM_DEBUG)
00778     qDebug("QTextStreamPrivate::consume(%d)", size);
00779 #endif
00780     if (string) {
00781         stringOffset += size;
00782         if (stringOffset > string->size())
00783             stringOffset = string->size();
00784     } else {
00785         readBufferOffset += size;
00786         if (readBufferOffset >= readBuffer.size()) {
00787             readBufferOffset = 0;
00788             readBuffer.clear();
00789             readBufferStartDevicePos = device->pos();
00790 #ifndef QT_NO_TEXTCODEC
00791             copyConverterState(&readBufferStartReadConverterState, &readConverterState);
00792 #endif
00793             readBufferStartEndOfBufferState = endOfBufferState;
00794         }
00795     }
00796 }
00797 
00800 inline bool QTextStreamPrivate::write(const QString &data)
00801 {
00802     if (string) {
00803         // ### What about seek()??
00804         string->append(data);
00805     } else {
00806         writeBuffer += data;
00807         if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
00808             return flushWriteBuffer();
00809     }
00810     return true;
00811 }
00812 
00815 inline bool QTextStreamPrivate::getChar(QChar *ch)
00816 {
00817     if ((string && stringOffset == string->size())
00818         || (device && readBuffer.isEmpty() && !fillReadBuffer())) {
00819         if (ch)
00820             *ch = 0;
00821         return false;
00822     }
00823     if (ch)
00824         *ch = *readPtr();
00825     consume(1);
00826     return true;
00827 }
00828 
00831 inline void QTextStreamPrivate::ungetChar(const QChar &ch)
00832 {
00833     if (string) {
00834         if (stringOffset == 0)
00835             string->prepend(ch);
00836         else
00837             (*string)[--stringOffset] = ch;
00838         return;
00839     }
00840 
00841     if (readBufferOffset == 0) {
00842         readBuffer.prepend(ch);
00843         return;
00844     }
00845 
00846     readBuffer[--readBufferOffset] = ch;
00847 }
00848 
00851 inline bool QTextStreamPrivate::putString(const QString &s)
00852 {
00853     QString tmp = s;
00854 
00855     // handle padding
00856     int padSize = fieldWidth - s.size();
00857     if (padSize > 0) {
00858         QString pad(padSize > 0 ? padSize : 0, padChar);
00859         if (fieldAlignment == QTextStream::AlignLeft) {
00860             tmp.append(QString(padSize, padChar));
00861         } else if (fieldAlignment == QTextStream::AlignRight) {
00862             tmp.prepend(QString(padSize, padChar));
00863         } else if (fieldAlignment == QTextStream::AlignCenter) {
00864             tmp.prepend(QString(padSize/2, padChar));
00865             tmp.append(QString(padSize - padSize/2, padChar));
00866         }
00867     }
00868 
00869 #if defined (QTEXTSTREAM_DEBUG)
00870     QByteArray a = s.toUtf8();
00871     QByteArray b = tmp.toUtf8();
00872     qDebug("QTextStreamPrivate::putString(\"%s\") calls write(\"%s\")",
00873            qt_prettyDebug(a.constData(), a.size(), qMax(16, a.size())).constData(),
00874            qt_prettyDebug(b.constData(), b.size(), qMax(16, b.size())).constData());
00875 #endif
00876     return write(tmp);
00877 }
00878 
00885 QTextStream::QTextStream()
00886     : d_ptr(new QTextStreamPrivate(this))
00887 {
00888 #if defined (QTEXTSTREAM_DEBUG)
00889     qDebug("QTextStream::QTextStream()");
00890 #endif
00891     Q_D(QTextStream);
00892     d->status = Ok;
00893 }
00894 
00898 QTextStream::QTextStream(QIODevice *device)
00899     : d_ptr(new QTextStreamPrivate(this))
00900 {
00901 #if defined (QTEXTSTREAM_DEBUG)
00902     qDebug("QTextStream::QTextStream(QIODevice *device == *%p)",
00903            device);
00904 #endif
00905     Q_D(QTextStream);
00906     d->device = device;
00907 #ifndef QT_NO_QOBJECT
00908     d->deviceClosedNotifier.setupDevice(this, d->device);
00909 #endif
00910     d->status = Ok;
00911 }
00912 
00917 QTextStream::QTextStream(QString *string, QIODevice::OpenMode openMode)
00918     : d_ptr(new QTextStreamPrivate(this))
00919 {
00920 #if defined (QTEXTSTREAM_DEBUG)
00921     qDebug("QTextStream::QTextStream(QString *string == *%p, openMode = %d)",
00922            string, int(openMode));
00923 #endif
00924     Q_D(QTextStream);
00925     d->string = string;
00926     d->stringOpenMode = openMode;
00927     d->status = Ok;
00928 }
00929 
00935 QTextStream::QTextStream(QByteArray *array, QIODevice::OpenMode openMode)
00936     : d_ptr(new QTextStreamPrivate(this))
00937 {
00938 #if defined (QTEXTSTREAM_DEBUG)
00939     qDebug("QTextStream::QTextStream(QByteArray *array == *%p, openMode = %d)",
00940            array, int(openMode));
00941 #endif
00942     Q_D(QTextStream);
00943     d->device = new QBuffer(array);
00944     d->device->open(openMode);
00945     d->deleteDevice = true;
00946 #ifndef QT_NO_QOBJECT
00947     d->deviceClosedNotifier.setupDevice(this, d->device);
00948 #endif
00949     d->status = Ok;
00950 }
00951 
00973 QTextStream::QTextStream(const QByteArray &array, QIODevice::OpenMode openMode)
00974     : d_ptr(new QTextStreamPrivate(this))
00975 {
00976 #if defined (QTEXTSTREAM_DEBUG)
00977     qDebug("QTextStream::QTextStream(const QByteArray &array == *(%p), openMode = %d)",
00978            &array, int(openMode));
00979 #endif
00980     QBuffer *buffer = new QBuffer;
00981     buffer->setData(array);
00982     buffer->open(openMode);
00983 
00984     Q_D(QTextStream);
00985     d->device = buffer;
00986     d->deleteDevice = true;
00987 #ifndef QT_NO_QOBJECT
00988     d->deviceClosedNotifier.setupDevice(this, d->device);
00989 #endif
00990     d->status = Ok;
00991 }
00992 
01008 QTextStream::QTextStream(FILE *fileHandle, QIODevice::OpenMode openMode)
01009     : d_ptr(new QTextStreamPrivate(this))
01010 {
01011 #if defined (QTEXTSTREAM_DEBUG)
01012     qDebug("QTextStream::QTextStream(FILE *fileHandle = %p, openMode = %d)",
01013            fileHandle, int(openMode));
01014 #endif
01015     QFile *file = new QFile;
01016     file->open(fileHandle, openMode);
01017 
01018     Q_D(QTextStream);
01019     d->device = file;
01020     d->deleteDevice = true;
01021 #ifndef QT_NO_QOBJECT
01022     d->deviceClosedNotifier.setupDevice(this, d->device);
01023 #endif
01024     d->status = Ok;
01025 }
01026 
01033 QTextStream::~QTextStream()
01034 {
01035     Q_D(QTextStream);
01036 #if defined (QTEXTSTREAM_DEBUG)
01037     qDebug("QTextStream::~QTextStream()");
01038 #endif
01039     if (!d->writeBuffer.isEmpty())
01040         d->flushWriteBuffer();
01041 
01042     delete d;
01043     d_ptr = 0;
01044 }
01045 
01051 void QTextStream::reset()
01052 {
01053     Q_D(QTextStream);
01054 
01055     d->realNumberPrecision = 6;
01056     d->integerBase = 0;
01057     d->fieldWidth = 0;
01058     d->padChar = QLatin1Char(' ');
01059     d->fieldAlignment = QTextStream::AlignRight;
01060     d->realNumberNotation = QTextStream::SmartNotation;
01061     d->numberFlags = 0;
01062 }
01063 
01069 void QTextStream::flush()
01070 {
01071     Q_D(QTextStream);
01072     d->flushWriteBuffer();
01073 }
01074 
01079 bool QTextStream::seek(qint64 pos)
01080 {
01081     Q_D(QTextStream);
01082     d->lastTokenSize = 0;
01083 
01084     if (d->device) {
01085         // Empty the write buffer
01086         d->flushWriteBuffer();
01087         if (!d->device->seek(pos))
01088             return false;
01089         d->readBuffer.clear();
01090         d->readBufferOffset = 0;
01091         d->endOfBufferState.clear();
01092         d->readBufferStartDevicePos = d->device->pos();
01093         d->readBufferStartEndOfBufferState.clear();
01094 
01095 #ifndef QT_NO_TEXTCODEC
01096         // Reset the codec converter states.
01097         ::resetCodecConverterState(&d->readConverterState);
01098         ::resetCodecConverterState(&d->readBufferStartReadConverterState);
01099         ::resetCodecConverterState(&d->writeConverterState);
01100 #endif
01101         return true;
01102     }
01103 
01104     // string
01105     if (d->string && pos <= d->string->size()) {
01106         d->stringOffset = int(pos);
01107         return true;
01108     }
01109     return false;
01110 }
01111 
01125 qint64 QTextStream::pos() const
01126 {
01127     Q_D(const QTextStream);
01128     if (d->device) {
01129         // Cutoff
01130         if (d->readBuffer.isEmpty() && d->endOfBufferState.isEmpty())
01131             return d->device->pos();
01132         if (d->device->isSequential())
01133             return 0;
01134 
01135         // Seek the device
01136         if (!d->device->seek(d->readBufferStartDevicePos))
01137             return qint64(-1);
01138 
01139         // Reset the read buffer
01140         QTextStreamPrivate *thatd = const_cast<QTextStreamPrivate *>(d);
01141         thatd->readBuffer.clear();
01142 
01143         // Restore the codec converter state and end state to the read buffer
01144         // start state.
01145 #ifndef QT_NO_TEXTCODEC
01146         ::copyConverterState(&thatd->readConverterState, &d->readBufferStartReadConverterState);
01147 #endif
01148         thatd->endOfBufferState = d->readBufferStartEndOfBufferState;
01149 #ifndef QT_NO_TEXTCODEC
01150         if (d->readBufferStartDevicePos == 0)
01151             thatd->autoDetectUnicode = true;
01152 #endif
01153 
01154         // Rewind the device to get to the current position Ensure that
01155         // readBufferOffset is unaffected by fillReadBuffer()
01156         int oldReadBufferOffset = d->readBufferOffset;
01157         while (d->readBuffer.size() < oldReadBufferOffset) {
01158             if (!thatd->fillReadBuffer(1))
01159                 return qint64(-1);
01160         }
01161         thatd->readBufferOffset = oldReadBufferOffset;
01162 
01163         // Return the device position.
01164         return d->device->pos();
01165     }
01166 
01167     if (d->string)
01168         return d->stringOffset;
01169 
01170     qWarning("QTextStream::pos: no device");
01171     return qint64(-1);
01172 }
01173 
01185 void QTextStream::skipWhiteSpace()
01186 {
01187     Q_D(QTextStream);
01188     CHECK_VALID_STREAM(Q_VOID);
01189     d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
01190     d->consumeLastToken();
01191 }
01192 
01200 void QTextStream::setDevice(QIODevice *device)
01201 {
01202     Q_D(QTextStream);
01203     flush();
01204     if (d->deleteDevice) {
01205 #ifndef QT_NO_QOBJECT
01206         d->deviceClosedNotifier.disconnect();
01207 #endif
01208         delete d->device;
01209         d->deleteDevice = false;
01210     }
01211     d->device = device;
01212     d->string = 0;
01213 #ifndef QT_NO_QOBJECT
01214     d->deviceClosedNotifier.setupDevice(this, d->device);
01215 #endif
01216 }
01217 
01224 QIODevice *QTextStream::device() const
01225 {
01226     Q_D(const QTextStream);
01227     return d->device;
01228 }
01229 
01237 void QTextStream::setString(QString *string, QIODevice::OpenMode openMode)
01238 {
01239     Q_D(QTextStream);
01240     flush();
01241     if (d->deleteDevice) {
01242 #ifndef QT_NO_QOBJECT
01243         d->deviceClosedNotifier.disconnect();
01244 #endif
01245         delete d->device;
01246         d->deleteDevice = false;
01247     }
01248     d->string = string;
01249     d->device = 0;
01250     d->stringOpenMode = openMode;
01251 }
01252 
01259 QString *QTextStream::string() const
01260 {
01261     Q_D(const QTextStream);
01262     return d->string;
01263 }
01264 
01273 void QTextStream::setFieldAlignment(FieldAlignment mode)
01274 {
01275     Q_D(QTextStream);
01276     d->fieldAlignment = mode;
01277 }
01278 
01284 QTextStream::FieldAlignment QTextStream::fieldAlignment() const
01285 {
01286     Q_D(const QTextStream);
01287     return d->fieldAlignment;
01288 }
01289 
01314 void QTextStream::setPadChar(QChar ch)
01315 {
01316     Q_D(QTextStream);
01317     d->padChar = ch;
01318 }
01319 
01325 QChar QTextStream::padChar() const
01326 {
01327     Q_D(const QTextStream);
01328     return d->padChar;
01329 }
01330 
01338 void QTextStream::setFieldWidth(int width)
01339 {
01340     Q_D(QTextStream);
01341     d->fieldWidth = width;
01342 }
01343 
01349 int QTextStream::fieldWidth() const
01350 {
01351     Q_D(const QTextStream);
01352     return d->fieldWidth;
01353 }
01354 
01363 void QTextStream::setNumberFlags(NumberFlags flags)
01364 {
01365     Q_D(QTextStream);
01366     d->numberFlags = flags;
01367 }
01368 
01374 QTextStream::NumberFlags QTextStream::numberFlags() const
01375 {
01376     Q_D(const QTextStream);
01377     return d->numberFlags;
01378 }
01379 
01390 void QTextStream::setIntegerBase(int base)
01391 {
01392     Q_D(QTextStream);
01393     d->integerBase = base;
01394 }
01395 
01402 int QTextStream::integerBase() const
01403 {
01404     Q_D(const QTextStream);
01405     return d->integerBase;
01406 }
01407 
01416 void QTextStream::setRealNumberNotation(RealNumberNotation notation)
01417 {
01418     Q_D(QTextStream);
01419     d->realNumberNotation = notation;
01420 }
01421 
01427 QTextStream::RealNumberNotation QTextStream::realNumberNotation() const
01428 {
01429     Q_D(const QTextStream);
01430     return d->realNumberNotation;
01431 }
01432 
01440 void QTextStream::setRealNumberPrecision(int precision)
01441 {
01442     Q_D(QTextStream);
01443     d->realNumberPrecision = precision;
01444 }
01445 
01452 int QTextStream::realNumberPrecision() const
01453 {
01454     Q_D(const QTextStream);
01455     return d->realNumberPrecision;
01456 }
01457 
01464 QTextStream::Status QTextStream::status() const
01465 {
01466     Q_D(const QTextStream);
01467     return d->status;
01468 }
01469 
01477 void QTextStream::resetStatus()
01478 {
01479     Q_D(QTextStream);
01480     d->status = Ok;
01481 }
01482 
01490 void QTextStream::setStatus(Status status)
01491 {
01492     Q_D(QTextStream);
01493     if (d->status == Ok)
01494         d->status = status;
01495 }
01496 
01503 bool QTextStream::atEnd() const
01504 {
01505     Q_D(const QTextStream);
01506     CHECK_VALID_STREAM(true);
01507 
01508     if (d->string)
01509         return d->string->size() == d->stringOffset;
01510     return d->readBuffer.isEmpty() && d->device->atEnd();
01511 }
01512 
01523 QString QTextStream::readAll()
01524 {
01525     Q_D(QTextStream);
01526     CHECK_VALID_STREAM(QString());
01527 
01528     const QChar *readPtr;
01529     int length;
01530     if (!d->scan(&readPtr, &length, /* maxlen = */ 0, QTextStreamPrivate::EndOfFile))
01531         return QString();
01532 
01533     QString tmp = QString(readPtr, length);
01534     d->consumeLastToken();
01535     return tmp;
01536 }
01537 
01556 QString QTextStream::readLine(qint64 maxlen)
01557 {
01558     Q_D(QTextStream);
01559     CHECK_VALID_STREAM(QString());
01560 
01561     const QChar *readPtr;
01562     int length;
01563     if (!d->scan(&readPtr, &length, int(maxlen), QTextStreamPrivate::EndOfLine))
01564         return QString();
01565 
01566     QString tmp = QString(readPtr, length);
01567     d->consumeLastToken();
01568     return tmp;
01569 }
01570 
01579 QString QTextStream::read(qint64 maxlen)
01580 {
01581     Q_D(QTextStream);
01582     CHECK_VALID_STREAM(QString());
01583 
01584     if (maxlen <= 0)
01585         return QString::fromLatin1("");     // empty, not null
01586 
01587     const QChar *readPtr;
01588     int length;
01589     if (!d->scan(&readPtr, &length, int(maxlen), QTextStreamPrivate::EndOfFile))
01590         return QString();
01591 
01592     QString tmp = QString(readPtr, length);
01593     d->consumeLastToken();
01594     return tmp;
01595 }
01596 
01599 QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong *ret)
01600 {
01601     scan(0, 0, 0, NotSpace);
01602     consumeLastToken();
01603 
01604     // detect int encoding
01605     int base = integerBase;
01606     if (base == 0) {
01607         QChar ch;
01608         if (!getChar(&ch))
01609             return npsInvalidPrefix;
01610         if (ch == QLatin1Char('0')) {
01611             QChar ch2;
01612             if (!getChar(&ch2)) {
01613                 // Result is the number 0
01614                 *ret = 0;
01615                 return npsOk;
01616             }
01617             ch2 = ch2.toLower();
01618 
01619             if (ch2 == QLatin1Char('x')) {
01620                 base = 16;
01621             } else if (ch2 == QLatin1Char('b')) {
01622                 base = 2;
01623             } else if (ch2.isDigit() && ch2.digitValue() >= 0 && ch2.digitValue() <= 7) {
01624                 base = 8;
01625             } else {
01626                 base = 10;
01627             }
01628             ungetChar(ch2);
01629         } else if (ch == QLatin1Char('-') || ch == QLatin1Char('+') || ch.isDigit()) {
01630             base = 10;
01631         } else {
01632             ungetChar(ch);
01633             return npsInvalidPrefix;
01634         }
01635         ungetChar(ch);
01636         // State of the stream is now the same as on entry
01637         // (cursor is at prefix),
01638         // and local variable 'base' has been set appropriately.
01639     }
01640 
01641     qulonglong val=0;
01642     switch (base) {
01643     case 2: {
01644         QChar pf1, pf2, dig;
01645         // Parse prefix '0b'
01646         if (!getChar(&pf1) || pf1 != QLatin1Char('0'))
01647             return npsInvalidPrefix;
01648         if (!getChar(&pf2) || pf2.toLower() != QLatin1Char('b'))
01649             return npsInvalidPrefix;
01650         // Parse digits
01651         int ndigits = 0;
01652         while (getChar(&dig)) {
01653             int n = dig.toLower().unicode();
01654             if (n == '0' || n == '1') {
01655                 val <<= 1;
01656                 val += n - '0';
01657             } else {
01658                 ungetChar(dig);
01659                 break;
01660             }
01661             ndigits++;
01662         }
01663         if (ndigits == 0) {
01664             // Unwind the prefix and abort
01665             ungetChar(pf2);
01666             ungetChar(pf1);
01667             return npsMissingDigit;
01668         }
01669         break;
01670     }
01671     case 8: {
01672         QChar pf, dig;
01673         // Parse prefix '0'
01674         if (!getChar(&pf) || pf != QLatin1Char('0'))
01675             return npsInvalidPrefix;
01676         // Parse digits
01677         int ndigits = 0;
01678         while (getChar(&dig)) {
01679             int n = dig.toLower().unicode();
01680             if (n >= '0' && n <= '7') {
01681                 val *= 8;
01682                 val += n - '0';
01683             } else {
01684                 ungetChar(dig);
01685                 break;
01686             }
01687             ndigits++;
01688         }
01689         if (ndigits == 0) {
01690             // Unwind the prefix and abort
01691             ungetChar(pf);
01692             return npsMissingDigit;
01693         }
01694         break;
01695     }
01696     case 10: {
01697         // Parse sign (or first digit)
01698         QChar sign;
01699         int ndigits = 0;
01700         if (!getChar(&sign))
01701             return npsMissingDigit;
01702         if (sign != QLatin1Char('-') && sign != QLatin1Char('+')) {
01703             if (!sign.isDigit()) {
01704                 ungetChar(sign);
01705                 return npsMissingDigit;
01706             }
01707             val += sign.digitValue();
01708             ndigits++;
01709         }
01710         // Parse digits
01711         QChar ch;
01712         while (getChar(&ch)) {
01713             if (ch.isDigit()) {
01714                 val *= 10;
01715                 val += ch.digitValue();
01716             } else {
01717                 ungetChar(ch);
01718                 break;
01719             }
01720             ndigits++;
01721         }
01722         if (ndigits == 0)
01723             return npsMissingDigit;
01724         if (sign == QLatin1Char('-')) {
01725             qlonglong ival = qlonglong(val);
01726             if (ival > 0)
01727                 ival = -ival;
01728             val = qulonglong(ival);
01729         }
01730         break;
01731     }
01732     case 16: {
01733         QChar pf1, pf2, dig;
01734         // Parse prefix ' 0x'
01735         if (!getChar(&pf1) || pf1 != QLatin1Char('0'))
01736             return npsInvalidPrefix;
01737         if (!getChar(&pf2) || pf2.toLower() != QLatin1Char('x'))
01738             return npsInvalidPrefix;
01739         // Parse digits
01740         int ndigits = 0;
01741         while (getChar(&dig)) {
01742             int n = dig.toLower().unicode();
01743             if (n >= '0' && n <= '9') {
01744                 val <<= 4;
01745                 val += n - '0';
01746             } else if (n >= 'a' && n <= 'f') {
01747                 val <<= 4;
01748                 val += 10 + (n - 'a');
01749             } else {
01750                 ungetChar(dig);
01751                 break;
01752             }
01753             ndigits++;
01754         }
01755         if (ndigits == 0) {
01756             return npsMissingDigit;
01757         }
01758         break;
01759     }
01760     default:
01761         // Unsupported integerBase
01762         return npsInvalidPrefix;
01763     }
01764 
01765     if (ret)
01766         *ret = val;
01767     return npsOk;
01768 }
01769 
01773 bool QTextStreamPrivate::getReal(double *f)
01774 {
01775     // We use a table-driven FSM to parse floating point numbers
01776     // strtod() cannot be used directly since we may be reading from a
01777     // QIODevice.
01778     enum ParserState {
01779         Init = 0,
01780         Sign = 1,
01781         Mantissa = 2,
01782         Dot = 3,
01783         Abscissa = 4,
01784         ExpMark = 5,
01785         ExpSign = 6,
01786         Exponent = 7,
01787         Done = 8
01788     };
01789     enum InputToken {
01790         None = 0,
01791         InputSign = 1,
01792         InputDigit = 2,
01793         InputDot = 3,
01794         InputExp = 4
01795     };
01796 
01797     static uchar table[8][5] = {
01798         // None InputSign InputDigit InputDot InputExp
01799         { 0,    Sign,     Mantissa,  Dot,     0        }, // Init
01800         { 0,    0,        Mantissa,  Dot,     0        }, // Sign
01801         { Done, Done,     Mantissa,  Dot,     ExpMark  }, // Mantissa
01802         { 0,    0,        Abscissa,  0,       0        }, // Dot
01803         { Done, Done,     Abscissa,  Done,    ExpMark  }, // Abscissa
01804         { 0,    ExpSign,  Exponent,  0,       0        }, // ExpMark
01805         { 0,    0,        Exponent,  0,       0        }, // ExpSign
01806         { Done, Done,     Exponent,  Done,    Done     }  // Exponent
01807     };
01808 
01809     ParserState state = Init;
01810     InputToken input = None;
01811 
01812     scan(0, 0, 0, NotSpace);
01813     consumeLastToken();
01814 
01815     const int BufferSize = 128;
01816     char buf[BufferSize];
01817     int i = 0;
01818 
01819     QChar c;
01820     while (getChar(&c)) {
01821         switch (c.unicode()) {
01822         case '+':
01823         case '-':
01824             input = InputSign;
01825             break;
01826         case '0': case '1': case '2': case '3': case '4':
01827         case '5': case '6': case '7': case '8': case '9':
01828             input = InputDigit;
01829             break;
01830         case '.':
01831             input = InputDot;
01832             break;
01833         case 'e':
01834         case 'E':
01835             input = InputExp;
01836             break;
01837         default:
01838             input = None;
01839             break;
01840         }
01841 
01842         state = ParserState(table[state][input]);
01843 
01844         if  (state == Init || state == Done || i > (BufferSize - 5)) {
01845             ungetChar(c);
01846             if (i > (BufferSize - 5)) { // ignore rest of digits
01847                 while (getChar(&c)) {
01848                     if (!c.isDigit()) {
01849                         ungetChar(c);
01850                         break;
01851                     }
01852                 }
01853             }
01854             break;
01855         }
01856 
01857         buf[i++] = c.toLatin1();
01858     }
01859 
01860     if (i == 0)
01861         return false;
01862 
01863     buf[i] = '\0';
01864 
01865     if (f)
01866         *f = strtod(buf, 0);
01867     return true;
01868 }
01869 
01884 QTextStream &QTextStream::operator>>(QChar &c)
01885 {
01886     Q_D(QTextStream);
01887     CHECK_VALID_STREAM(*this);
01888     d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
01889     if (!d->getChar(&c))
01890         setStatus(ReadPastEnd);
01891     return *this;
01892 }
01893 
01903 QTextStream &QTextStream::operator>>(char &c)
01904 {
01905     QChar ch;
01906     *this >> ch;
01907     c = ch.toLatin1();
01908     return *this;
01909 }
01910 
01935 QTextStream &QTextStream::operator>>(signed short &i)
01936 {
01937     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(signed short);
01938 }
01939 
01945 QTextStream &QTextStream::operator>>(unsigned short &i)
01946 {
01947     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(unsigned short);
01948 }
01949 
01955 QTextStream &QTextStream::operator>>(signed int &i)
01956 {
01957     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(signed int);
01958 }
01959 
01965 QTextStream &QTextStream::operator>>(unsigned int &i)
01966 {
01967     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(unsigned int);
01968 }
01969 
01975 QTextStream &QTextStream::operator>>(signed long &i)
01976 {
01977     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(signed long);
01978 }
01979 
01985 QTextStream &QTextStream::operator>>(unsigned long &i)
01986 {
01987     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(unsigned long);
01988 }
01989 
01995 QTextStream &QTextStream::operator>>(qlonglong &i)
01996 {
01997     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(qlonglong);
01998 }
01999 
02005 QTextStream &QTextStream::operator>>(qulonglong &i)
02006 {
02007     IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(qulonglong);
02008 }
02009 
02018 QTextStream &QTextStream::operator>>(float &f)
02019 {
02020     IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR(float);
02021 }
02022 
02028 QTextStream &QTextStream::operator>>(double &f)
02029 {
02030     IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR(double);
02031 }
02032 
02040 QTextStream &QTextStream::operator>>(QString &str)
02041 {
02042     Q_D(QTextStream);
02043     CHECK_VALID_STREAM(*this);
02044 
02045     str.clear();
02046     d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
02047     d->consumeLastToken();
02048 
02049     const QChar *ptr;
02050     int length;
02051     if (!d->scan(&ptr, &length, 0, QTextStreamPrivate::Space)) {
02052         setStatus(ReadPastEnd);
02053         return *this;
02054     }
02055 
02056     str = QString(ptr, length);
02057     d->consumeLastToken();
02058     return *this;
02059 }
02060 
02068 QTextStream &QTextStream::operator>>(QByteArray &array)
02069 {
02070     Q_D(QTextStream);
02071     CHECK_VALID_STREAM(*this);
02072 
02073     array.clear();
02074     d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
02075     d->consumeLastToken();
02076 
02077     const QChar *ptr;
02078     int length;
02079     if (!d->scan(&ptr, &length, 0, QTextStreamPrivate::Space)) {
02080         setStatus(ReadPastEnd);
02081         return *this;
02082     }
02083 
02084     for (int i = 0; i < length; ++i)
02085         array += ptr[i].toLatin1();
02086 
02087     d->consumeLastToken();
02088     return *this;
02089 }
02090 
02104 QTextStream &QTextStream::operator>>(char *c)
02105 {
02106     Q_D(QTextStream);
02107     *c = 0;
02108     CHECK_VALID_STREAM(*this);
02109     d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
02110     d->consumeLastToken();
02111 
02112     const QChar *ptr;
02113     int length;
02114     if (!d->scan(&ptr, &length, 0, QTextStreamPrivate::Space)) {
02115         setStatus(ReadPastEnd);
02116         return *this;
02117     }
02118 
02119     for (int i = 0; i < length; ++i)
02120         *c++ = ptr[i].toLatin1();
02121     *c = '\0';
02122     d->consumeLastToken();
02123     return *this;
02124 }
02125 
02128 bool QTextStreamPrivate::putNumber(qulonglong number, bool negative)
02129 {
02130     QString tmp;
02131     if (negative)
02132         tmp = QLatin1Char('-');
02133     else if (numberFlags & QTextStream::ForceSign)
02134         tmp = QLatin1Char('+');
02135 
02136     if (numberFlags & QTextStream::ShowBase) {
02137         switch (integerBase) {
02138         case 2: tmp += QLatin1String("0b"); break;
02139         case 8: tmp += QLatin1String("0"); break;
02140         case 16: tmp += QLatin1String("0x"); break;
02141         default: break;
02142         }
02143     }
02144 
02145     tmp += QString::number(number, integerBase ? integerBase : 10);
02146     if (numberFlags & QTextStream::UppercaseBase)
02147         tmp = tmp.toUpper(); // ### in-place instead
02148 
02149     return putString(tmp);
02150 }
02151 
02156 QTextStream &QTextStream::operator<<(QBool b)
02157 {
02158     return *this << bool(b);
02159 }
02160 
02167 QTextStream &QTextStream::operator<<(QChar c)
02168 {
02169     Q_D(QTextStream);
02170     CHECK_VALID_STREAM(*this);
02171     d->putString(QString(c));
02172     return *this;
02173 }
02174 
02180 QTextStream &QTextStream::operator<<(char c)
02181 {
02182     Q_D(QTextStream);
02183     CHECK_VALID_STREAM(*this);
02184     d->putString(QString(QChar::fromAscii(c)));
02185     return *this;
02186 }
02187 
02196 QTextStream &QTextStream::operator<<(signed short i)
02197 {
02198     Q_D(QTextStream);
02199     CHECK_VALID_STREAM(*this);
02200     d->putNumber((qulonglong)qAbs(qlonglong(i)), i < 0);
02201     return *this;
02202 }
02203 
02209 QTextStream &QTextStream::operator<<(unsigned short i)
02210 {
02211     Q_D(QTextStream);
02212     CHECK_VALID_STREAM(*this);
02213     d->putNumber((qulonglong)i, false);
02214     return *this;
02215 }
02216 
02222 QTextStream &QTextStream::operator<<(signed int i)
02223 {
02224     Q_D(QTextStream);
02225     CHECK_VALID_STREAM(*this);
02226     d->putNumber((qulonglong)qAbs(qlonglong(i)), i < 0);
02227     return *this;
02228 }
02229 
02235 QTextStream &QTextStream::operator<<(unsigned int i)
02236 {
02237     Q_D(QTextStream);
02238     CHECK_VALID_STREAM(*this);
02239     d->putNumber((qulonglong)i, false);
02240     return *this;
02241 }
02242 
02248 QTextStream &QTextStream::operator<<(signed long i)
02249 {
02250     Q_D(QTextStream);
02251     CHECK_VALID_STREAM(*this);
02252     d->putNumber((qulonglong)qAbs(qlonglong(i)), i < 0);
02253     return *this;
02254 }
02255 
02261 QTextStream &QTextStream::operator<<(unsigned long i)
02262 {
02263     Q_D(QTextStream);
02264     CHECK_VALID_STREAM(*this);
02265     d->putNumber((qulonglong)i, false);
02266     return *this;
02267 }
02268 
02274 QTextStream &QTextStream::operator<<(qlonglong i)
02275 {
02276     Q_D(QTextStream);
02277     CHECK_VALID_STREAM(*this);
02278     d->putNumber((qulonglong)qAbs(i), i < 0);
02279     return *this;
02280 }
02281 
02287 QTextStream &QTextStream::operator<<(qulonglong i)
02288 {
02289     Q_D(QTextStream);
02290     CHECK_VALID_STREAM(*this);
02291     d->putNumber(i, false);
02292     return *this;
02293 }
02294 
02306 QTextStream &QTextStream::operator<<(float f)
02307 {
02308     return *this << double(f);
02309 }
02310 
02316 QTextStream &QTextStream::operator<<(double f)
02317 {
02318     Q_D(QTextStream);
02319     CHECK_VALID_STREAM(*this);
02320 
02321     char f_char;
02322     char format[16];
02323     if (d->realNumberNotation == FixedNotation)
02324         f_char = 'f';
02325     else if (d->realNumberNotation == ScientificNotation)
02326         f_char = (d->numberFlags & UppercaseBase) ? 'E' : 'e';
02327     else
02328         f_char = (d->numberFlags & UppercaseBase) ? 'G' : 'g';
02329 
02330     // generate format string
02331     register char *fs = format;
02332 
02333     // "%.<prec>l<f_char>"
02334     *fs++ = '%';
02335     if (d->numberFlags & QTextStream::ForcePoint)
02336         *fs++ = '#';
02337     *fs++ = '.';
02338     int prec = d->realNumberPrecision;
02339     if (prec > 99)
02340         prec = 99;
02341     if (prec >= 10) {
02342         *fs++ = prec / 10 + '0';
02343         *fs++ = prec % 10 + '0';
02344     } else {
02345         *fs++ = prec + '0';
02346     }
02347     *fs++ = 'l';
02348     *fs++ = f_char;
02349     *fs = '\0';
02350     QString num;
02351     num.sprintf(format, f);                        // convert to text
02352 
02353     if (f > 0.0 && (d->numberFlags & ForceSign))
02354         num.prepend(QLatin1Char('+'));
02355 
02356     d->putString(num);
02357     return *this;
02358 }
02359 
02368 QTextStream &QTextStream::operator<<(const QString &string)
02369 {
02370     Q_D(QTextStream);
02371     CHECK_VALID_STREAM(*this);
02372     d->putString(string);
02373     return *this;
02374 }
02375 
02382 QTextStream &QTextStream::operator<<(const QByteArray &array)
02383 {
02384     Q_D(QTextStream);
02385     CHECK_VALID_STREAM(*this);
02386     d->putString(QString::fromAscii(array.constData(), array.length()));
02387     return *this;
02388 }
02389 
02406 QTextStream &QTextStream::operator<<(const char *string)
02407 {
02408     Q_D(QTextStream);
02409     CHECK_VALID_STREAM(*this);
02410     d->putString(QLatin1String(string));
02411     return *this;
02412 }
02413 
02419 QTextStream &QTextStream::operator<<(const void *ptr)
02420 {
02421     Q_D(QTextStream);
02422     CHECK_VALID_STREAM(*this);
02423     int oldBase = d->integerBase;
02424     NumberFlags oldFlags = d->numberFlags;
02425     d->integerBase = 16;
02426     d->numberFlags |= ShowBase;
02427     d->putNumber(reinterpret_cast<quintptr>(ptr), false);
02428     d->integerBase = oldBase;
02429     d->numberFlags = oldFlags;
02430     return *this;
02431 }
02432 
02441 QTextStream &bin(QTextStream &stream)
02442 {
02443     stream.setIntegerBase(2);
02444     return stream;
02445 }
02446 
02455 QTextStream &oct(QTextStream &stream)
02456 {
02457     stream.setIntegerBase(8);
02458     return stream;
02459 }
02460 
02469 QTextStream &dec(QTextStream &stream)
02470 {
02471     stream.setIntegerBase(10);
02472     return stream;
02473 }
02474 
02483 QTextStream &hex(QTextStream &stream)
02484 {
02485     stream.setIntegerBase(16);
02486     return stream;
02487 }
02488 
02497 QTextStream &showbase(QTextStream &stream)
02498 {
02499     stream.setNumberFlags(stream.numberFlags() | QTextStream::ShowBase);
02500     return stream;
02501 }
02502 
02511 QTextStream &forcesign(QTextStream &stream)
02512 {
02513     stream.setNumberFlags(stream.numberFlags() | QTextStream::ForceSign);
02514     return stream;
02515 }
02516 
02525 QTextStream &forcepoint(QTextStream &stream)
02526 {
02527     stream.setNumberFlags(stream.numberFlags() | QTextStream::ForcePoint);
02528     return stream;
02529 }
02530 
02539 QTextStream &noshowbase(QTextStream &stream)
02540 {
02541     stream.setNumberFlags(stream.numberFlags() &= ~QTextStream::ShowBase);
02542     return stream;
02543 }
02544 
02553 QTextStream &noforcesign(QTextStream &stream)
02554 {
02555     stream.setNumberFlags(stream.numberFlags() &= ~QTextStream::ForceSign);
02556     return stream;
02557 }
02558 
02567 QTextStream &noforcepoint(QTextStream &stream)
02568 {
02569     stream.setNumberFlags(stream.numberFlags() &= ~QTextStream::ForcePoint);
02570     return stream;
02571 }
02572 
02581 QTextStream &uppercasebase(QTextStream &stream)
02582 {
02583     stream.setNumberFlags(stream.numberFlags() | QTextStream::UppercaseBase);
02584     return stream;
02585 }
02586 
02595 QTextStream &uppercasedigits(QTextStream &stream)
02596 {
02597     stream.setNumberFlags(stream.numberFlags() | QTextStream::UppercaseDigits);
02598     return stream;
02599 }
02600 
02609 QTextStream &lowercasebase(QTextStream &stream)
02610 {
02611     stream.setNumberFlags(stream.numberFlags() & ~QTextStream::UppercaseBase);
02612     return stream;
02613 }
02614 
02623 QTextStream &lowercasedigits(QTextStream &stream)
02624 {
02625     stream.setNumberFlags(stream.numberFlags() & ~QTextStream::UppercaseDigits);
02626     return stream;
02627 }
02628 
02637 QTextStream &fixed(QTextStream &stream)
02638 {
02639     stream.setRealNumberNotation(QTextStream::FixedNotation);
02640     return stream;
02641 }
02642 
02651 QTextStream &scientific(QTextStream &stream)
02652 {
02653     stream.setRealNumberNotation(QTextStream::ScientificNotation);
02654     return stream;
02655 }
02656 
02665 QTextStream &left(QTextStream &stream)
02666 {
02667     stream.setFieldAlignment(QTextStream::AlignLeft);
02668     return stream;
02669 }
02670 
02679 QTextStream &right(QTextStream &stream)
02680 {
02681     stream.setFieldAlignment(QTextStream::AlignRight);
02682     return stream;
02683 }
02684 
02693 QTextStream &center(QTextStream &stream)
02694 {
02695     stream.setFieldAlignment(QTextStream::AlignCenter);
02696     return stream;
02697 }
02698 
02715 QTextStream &endl(QTextStream &stream)
02716 {
02717     return stream << QLatin1Char('\n') << flush;
02718 }
02719 
02727 QTextStream &flush(QTextStream &stream)
02728 {
02729     stream.flush();
02730     return stream;
02731 }
02732 
02740 QTextStream &reset(QTextStream &stream)
02741 {
02742     stream.reset();
02743     return stream;
02744 }
02745 
02753 QTextStream &ws(QTextStream &stream)
02754 {
02755     stream.skipWhiteSpace();
02756     return stream;
02757 }
02758 
02780 #ifndef QT_NO_TEXTCODEC
02781 
02789 QTextStream &bom(QTextStream &stream)
02790 {
02791     stream.setGenerateByteOrderMark(true);
02792     return stream;
02793 }
02794 
02806 void QTextStream::setCodec(QTextCodec *codec)
02807 {
02808     Q_D(QTextStream);
02809     d->codec = codec;
02810 }
02811 
02827 void QTextStream::setCodec(const char *codecName)
02828 {
02829     Q_D(QTextStream);
02830     QTextCodec *codec = QTextCodec::codecForName(codecName);
02831     if (codec)
02832         d->codec = codec;
02833 }
02834 
02840 QTextCodec *QTextStream::codec() const
02841 {
02842     Q_D(const QTextStream);
02843     return d->codec;
02844 }
02845 
02857 void QTextStream::setAutoDetectUnicode(bool enabled)
02858 {
02859     Q_D(QTextStream);
02860     d->autoDetectUnicode = enabled;
02861 }
02862 
02869 bool QTextStream::autoDetectUnicode() const
02870 {
02871     Q_D(const QTextStream);
02872     return d->autoDetectUnicode;
02873 }
02874 
02883 void QTextStream::setGenerateByteOrderMark(bool generate)
02884 {
02885     Q_D(QTextStream);
02886     if (d->writeBuffer.isEmpty()) {
02887         if (generate)
02888             d->writeConverterState.flags &= ~QTextCodec::IgnoreHeader;
02889         else
02890             d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
02891     }
02892 }
02893 
02900 bool QTextStream::generateByteOrderMark() const
02901 {
02902     Q_D(const QTextStream);
02903     return (d->writeConverterState.flags & QTextCodec::IgnoreHeader) == 0;
02904 }
02905 
02906 #endif
02907 
02908 #ifdef QT3_SUPPORT
02909 
02967 int QTextStream::flagsInternal() const
02968 {
02969     Q_D(const QTextStream);
02970 
02971     int f = 0;
02972     switch (d->fieldAlignment) {
02973     case AlignLeft: f |= left; break;
02974     case AlignRight: f |= right; break;
02975     case AlignCenter: f |= internal; break;
02976     default:
02977         break;
02978     }
02979     switch (d->integerBase) {
02980     case 2: f |= bin; break;
02981     case 8: f |= oct; break;
02982     case 10: f |= dec; break;
02983     case 16: f |= hex; break;
02984     default:
02985         break;
02986     }
02987     switch (d->realNumberNotation) {
02988     case FixedNotation: f |= fixed; break;
02989     case ScientificNotation: f |= scientific; break;
02990     default:
02991         break;
02992     }
02993     if (d->numberFlags & ShowBase)
02994         f |= showbase;
02995     if (d->numberFlags & ForcePoint)
02996         f |= showpoint;
02997     if (d->numberFlags & ForceSign)
02998         f |= showpos;
02999     if (d->numberFlags & UppercaseBase)
03000         f |= uppercase;
03001     return f;
03002 }
03003 
03006 int QTextStream::flagsInternal(int newFlags)
03007 {
03008     int oldFlags = flagsInternal();
03009 
03010     if (newFlags & left)
03011         setFieldAlignment(AlignLeft);
03012     else if (newFlags & right)
03013         setFieldAlignment(AlignRight);
03014     else if (newFlags & internal)
03015         setFieldAlignment(AlignCenter);
03016 
03017     if (newFlags & bin)
03018         setIntegerBase(2);
03019     else if (newFlags & oct)
03020         setIntegerBase(8);
03021     else if (newFlags & dec)
03022         setIntegerBase(10);
03023     else if (newFlags & hex)
03024         setIntegerBase(16);
03025 
03026     if (newFlags & showbase)
03027         setNumberFlags(numberFlags() | ShowBase);
03028     if (newFlags & showpos)
03029         setNumberFlags(numberFlags() | ForceSign);
03030     if (newFlags & showpoint)
03031         setNumberFlags(numberFlags() | ForcePoint);
03032     if (newFlags & uppercase)
03033         setNumberFlags(numberFlags() | UppercaseBase);
03034 
03035     if (newFlags & fixed)
03036         setRealNumberNotation(FixedNotation);
03037     else if (newFlags & scientific)
03038         setRealNumberNotation(ScientificNotation);
03039 
03040     return oldFlags;
03041 }
03042 
03043 #ifndef QT_NO_TEXTCODEC
03044 
03047 void QTextStream::setEncoding(Encoding encoding)
03048 {
03049     Q_D(QTextStream);
03050     ::resetCodecConverterState(&d->readConverterState);
03051     ::resetCodecConverterState(&d->writeConverterState);
03052 
03053     switch (encoding) {
03054     case Locale:
03055         d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
03056         setCodec(QTextCodec::codecForLocale());
03057         d->autoDetectUnicode = true;
03058         break;
03059     case Latin1:
03060         d->readConverterState.flags |= QTextCodec::IgnoreHeader;
03061         d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
03062         setCodec(QTextCodec::codecForName("ISO-8859-1"));
03063         d->autoDetectUnicode = false;
03064         break;
03065     case Unicode:
03066         setCodec(QTextCodec::codecForName("UTF-16"));
03067         d->autoDetectUnicode = false;
03068         break;
03069     case RawUnicode:
03070         d->readConverterState.flags |= QTextCodec::IgnoreHeader;
03071         d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
03072         setCodec(QTextCodec::codecForName("UTF-16"));
03073         d->autoDetectUnicode = false;
03074         break;
03075     case UnicodeNetworkOrder:
03076         d->readConverterState.flags |= QTextCodec::IgnoreHeader;
03077         d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
03078         setCodec(QTextCodec::codecForName("UTF-16BE"));
03079         d->autoDetectUnicode = false;
03080         break;
03081     case UnicodeReverse:
03082         d->readConverterState.flags |= QTextCodec::IgnoreHeader;
03083         d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
03084         setCodec(QTextCodec::codecForName("UTF-16LE"));
03085         d->autoDetectUnicode = false;
03086         break;
03087     case UnicodeUTF8:
03088         d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
03089         setCodec(QTextCodec::codecForName("UTF-8"));
03090         d->autoDetectUnicode = true;
03091         break;
03092     }
03093 }
03094 #endif
03095 
03208 #endif
03209 
03210 #ifndef QT_NO_QOBJECT
03211 #include "qtextstream.moc"
03212 #endif

Generated on Thu Mar 15 11:53:21 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1