summaryrefslogtreecommitdiffstats
path: root/src/tools/qfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/qfile.cpp')
-rw-r--r--src/tools/qfile.cpp747
1 files changed, 747 insertions, 0 deletions
diff --git a/src/tools/qfile.cpp b/src/tools/qfile.cpp
new file mode 100644
index 0000000..11e21d1
--- /dev/null
+++ b/src/tools/qfile.cpp
@@ -0,0 +1,747 @@
+/****************************************************************************
+**
+** Implementation of QFile class
+**
+** Created : 930812
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the tools module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at [email protected].
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qplatformdefs.h"
+
+// POSIX Large File Support redefines open -> open64
+#if defined(open)
+# undef open
+#endif
+
+// POSIX Large File Support redefines truncate -> truncate64
+#if defined(truncate)
+# undef truncate
+#endif
+
+#include "qfile.h"
+#ifndef NO_ERRNO_H
+#include <errno.h>
+#endif
+
+
+// Duplicated from qobject.h, but we cannot include qobject.h here since
+// it causes qmake to not build on irix g++
+#define QT_TRANSLATE_NOOP(scope,x) (x)
+
+const char* qt_fileerr_unknown = QT_TRANSLATE_NOOP( "QFile", "Unknown error" );
+const char* qt_fileerr_read = QT_TRANSLATE_NOOP( "QFile", "Could not read from the file" );
+const char* qt_fileerr_write = QT_TRANSLATE_NOOP( "QFile", "Could not write to the file" );
+
+#define QFILEERR_EACCES QT_TRANSLATE_NOOP( "QFile", "Permission denied" )
+#define QFILEERR_EMFILE QT_TRANSLATE_NOOP( "QFile", "Too many open files" )
+#define QFILEERR_ENOENT QT_TRANSLATE_NOOP( "QFile", "No such file or directory" )
+#define QFILEERR_ENOSPC QT_TRANSLATE_NOOP( "QFile", "No space left on device" )
+
+class QFilePrivate
+{
+public:
+ QString errorString;
+};
+
+extern bool qt_file_access( const QString& fn, int t );
+
+/*!
+ \class QFile qfile.h
+ \reentrant
+ \brief The QFile class is an I/O device that operates on files.
+
+ \ingroup io
+ \mainclass
+
+ QFile is an I/O device for reading and writing binary and text
+ files. A QFile may be used by itself or more conveniently with a
+ QDataStream or QTextStream.
+
+ The file name is usually passed in the constructor but can be
+ changed with setName(). You can check for a file's existence with
+ exists() and remove a file with remove().
+
+ The file is opened with open(), closed with close() and flushed
+ with flush(). Data is usually read and written using QDataStream
+ or QTextStream, but you can read with readBlock() and readLine()
+ and write with writeBlock(). QFile also supports getch(),
+ ungetch() and putch().
+
+ The size of the file is returned by size(). You can get the
+ current file position or move to a new file position using the
+ at() functions. If you've reached the end of the file, atEnd()
+ returns TRUE. The file handle is returned by handle().
+
+ Here is a code fragment that uses QTextStream to read a text file
+ line by line. It prints each line with a line number.
+ \code
+ QStringList lines;
+ QFile file( "file.txt" );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ int i = 1;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine(); // line of text excluding '\n'
+ printf( "%3d: %s\n", i++, line.latin1() );
+ lines += line;
+ }
+ file.close();
+ }
+ \endcode
+
+ Writing text is just as easy. The following example shows how to
+ write the data we read into the string list from the previous
+ example:
+ \code
+ QFile file( "file.txt" );
+ if ( file.open( IO_WriteOnly ) ) {
+ QTextStream stream( &file );
+ for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
+ stream << *it << "\n";
+ file.close();
+ }
+ \endcode
+
+ The QFileInfo class holds detailed information about a file, such
+ as access permissions, file dates and file types.
+
+ The QDir class manages directories and lists of file names.
+
+ Qt uses Unicode file names. If you want to do your own I/O on Unix
+ systems you may want to use encodeName() (and decodeName()) to
+ convert the file name into the local encoding.
+
+ \important readAll() at()
+
+ \sa QDataStream, QTextStream
+*/
+
+/*!
+ \fn Q_LONG QFile::writeBlock( const QByteArray& data )
+
+ \overload
+*/
+
+
+/*!
+ Constructs a QFile with no name.
+*/
+
+QFile::QFile()
+: d(0)
+{
+ init();
+}
+
+/*!
+ Constructs a QFile with a file name \a name.
+
+ \sa setName()
+*/
+
+QFile::QFile( const QString &name )
+ : fn(name), d(0)
+{
+ init();
+}
+
+
+/*!
+ Destroys a QFile. Calls close().
+*/
+
+QFile::~QFile()
+{
+ close();
+ delete d;
+}
+
+
+/*!
+ \internal
+ Initialize internal data.
+*/
+
+void QFile::init()
+{
+ delete d;
+ d = new QFilePrivate;
+ setFlags( IO_Direct );
+ setStatus( IO_Ok );
+ setErrorString( qt_fileerr_unknown );
+ fh = 0;
+ fd = 0;
+ length = 0;
+ ioIndex = 0;
+ ext_f = FALSE; // not an external file handle
+}
+
+
+/*!
+ \fn QString QFile::name() const
+
+ Returns the name set by setName().
+
+ \sa setName(), QFileInfo::fileName()
+*/
+
+/*!
+ Sets the name of the file to \a name. The name can have no path, a
+ relative path or an absolute absolute path.
+
+ Do not call this function if the file has already been opened.
+
+ If the file name has no path or a relative path, the path used
+ will be whatever the application's current directory path is
+ \e{at the time of the open()} call.
+
+ Example:
+ \code
+ QFile file;
+ QDir::setCurrent( "/tmp" );
+ file.setName( "readme.txt" );
+ QDir::setCurrent( "/home" );
+ file.open( IO_ReadOnly ); // opens "/home/readme.txt" under Unix
+ \endcode
+
+ Note that the directory separator "/" works for all operating
+ systems supported by Qt.
+
+ \sa name(), QFileInfo, QDir
+*/
+
+void QFile::setName( const QString &name )
+{
+ if ( isOpen() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QFile::setName: File is open" );
+#endif
+ close();
+ }
+ fn = name;
+}
+
+/*!
+ \overload
+
+ Returns TRUE if this file exists; otherwise returns FALSE.
+
+ \sa name()
+*/
+
+bool QFile::exists() const
+{
+ return qt_file_access( fn, F_OK );
+}
+
+/*!
+ Returns TRUE if the file given by \a fileName exists; otherwise
+ returns FALSE.
+*/
+
+bool QFile::exists( const QString &fileName )
+{
+ return qt_file_access( fileName, F_OK );
+}
+
+
+/*!
+ Removes the file specified by the file name currently set. Returns
+ TRUE if successful; otherwise returns FALSE.
+
+ The file is closed before it is removed.
+*/
+
+bool QFile::remove()
+{
+ close();
+ return remove( fn );
+}
+
+#if defined(Q_OS_MAC) || defined(Q_OS_MSDOS) || defined(Q_OS_WIN32) || defined(Q_OS_OS2)
+# define HAS_TEXT_FILEMODE // has translate/text filemode
+#endif
+#if defined(O_NONBLOCK)
+# define HAS_ASYNC_FILEMODE
+# define OPEN_ASYNC O_NONBLOCK
+#elif defined(O_NDELAY)
+# define HAS_ASYNC_FILEMODE
+# define OPEN_ASYNC O_NDELAY
+#endif
+
+/*!
+ Flushes the file buffer to the disk.
+
+ close() also flushes the file buffer.
+*/
+
+void QFile::flush()
+{
+ if ( isOpen() && fh ) { // can only flush open/buffered file
+ if ( fflush( fh ) ) { // write error
+ if ( errno == ENOSPC ) // disk is full
+ setStatus( IO_ResourceError );
+ else
+ setStatus( IO_WriteError );
+ setErrorStringErrno( errno );
+ }
+ }
+}
+
+/*! \reimp
+ \fn QIODevice::Offset QFile::at() const
+*/
+
+/*!
+ Returns TRUE if the end of file has been reached; otherwise returns FALSE.
+ If QFile has not been open()'d, then the behavior is undefined.
+
+ \sa size()
+*/
+
+bool QFile::atEnd() const
+{
+ if ( !isOpen() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QFile::atEnd: File is not open" );
+#endif
+ return FALSE;
+ }
+ if ( isDirectAccess() && !isTranslated() ) {
+ if ( at() < size() )
+ return FALSE;
+ }
+ const QString errorString = d->errorString;
+ const bool ret = QIODevice::atEnd();
+ if (errorString != d->errorString)
+ d->errorString = errorString;
+ return ret;
+}
+
+/*!
+ Reads a line of text.
+
+ Reads bytes from the file into the char* \a p, until end-of-line
+ or \a maxlen bytes have been read, whichever occurs first. Returns
+ the number of bytes read, or -1 if there was an error. Any
+ terminating newline is not stripped.
+
+ This function is only efficient for buffered files. Avoid
+ readLine() for files that have been opened with the \c IO_Raw
+ flag.
+
+ \sa readBlock(), QTextStream::readLine()
+*/
+
+Q_LONG QFile::readLine( char *p, Q_ULONG maxlen )
+{
+ if ( maxlen == 0 ) // application bug?
+ return 0;
+#if defined(QT_CHECK_STATE)
+ Q_CHECK_PTR( p );
+ if ( !isOpen() ) { // file not open
+ qWarning( "QFile::readLine: File not open" );
+ return -1;
+ }
+ if ( !isReadable() ) { // reading not permitted
+ qWarning( "QFile::readLine: Read operation not permitted" );
+ return -1;
+ }
+#endif
+ Q_LONG nread; // number of bytes read
+ if ( isRaw() ) { // raw file
+ nread = QIODevice::readLine( p, maxlen );
+ } else { // buffered file
+ p = fgets( p, maxlen, fh );
+ if ( p ) {
+ nread = qstrlen( p );
+ if ( !isSequentialAccess() )
+ ioIndex += nread;
+ } else {
+ nread = -1;
+ setStatus(IO_ReadError);
+ setErrorString( qt_fileerr_read );
+ }
+ }
+ return nread;
+}
+
+
+/*!
+ \overload
+
+ Reads a line of text.
+
+ Reads bytes from the file into string \a s, until end-of-line or
+ \a maxlen bytes have been read, whichever occurs first. Returns
+ the number of bytes read, or -1 if there was an error, e.g. end of
+ file. Any terminating newline is not stripped.
+
+ This function is only efficient for buffered files. Avoid using
+ readLine() for files that have been opened with the \c IO_Raw
+ flag.
+
+ Note that the string is read as plain Latin1 bytes, not Unicode.
+
+ \sa readBlock(), QTextStream::readLine()
+*/
+
+Q_LONG QFile::readLine( QString& s, Q_ULONG maxlen )
+{
+ QByteArray ba(maxlen);
+ Q_LONG l = readLine(ba.data(),maxlen);
+ if ( l >= 0 ) {
+ ba.truncate(l);
+ s = QString(ba);
+ }
+ return l;
+}
+
+
+/*!
+ Reads a single byte/character from the file.
+
+ Returns the byte/character read, or -1 if the end of the file has
+ been reached.
+
+ \sa putch(), ungetch()
+*/
+
+int QFile::getch()
+{
+#if defined(QT_CHECK_STATE)
+ if ( !isOpen() ) { // file not open
+ qWarning( "QFile::getch: File not open" );
+ return EOF;
+ }
+ if ( !isReadable() ) { // reading not permitted
+ qWarning( "QFile::getch: Read operation not permitted" );
+ return EOF;
+ }
+#endif
+
+ int ch;
+
+ if ( !ungetchBuffer.isEmpty() ) {
+ int len = ungetchBuffer.length();
+ ch = ungetchBuffer[ len-1 ];
+ ungetchBuffer.truncate( len - 1 );
+ return ch;
+ }
+
+ if ( isRaw() ) { // raw file (inefficient)
+ char buf[1];
+ ch = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
+ } else { // buffered file
+ if ( (ch = getc( fh )) != EOF ) {
+ if ( !isSequentialAccess() )
+ ioIndex++;
+ } else {
+ setStatus(IO_ReadError);
+ setErrorString( qt_fileerr_read );
+ }
+ }
+ return ch;
+}
+
+/*!
+ Writes the character \a ch to the file.
+
+ Returns \a ch, or -1 if some error occurred.
+
+ \sa getch(), ungetch()
+*/
+
+int QFile::putch( int ch )
+{
+#if defined(QT_CHECK_STATE)
+ if ( !isOpen() ) { // file not open
+ qWarning( "QFile::putch: File not open" );
+ return EOF;
+ }
+ if ( !isWritable() ) { // writing not permitted
+ qWarning( "QFile::putch: Write operation not permitted" );
+ return EOF;
+ }
+#endif
+ if ( isRaw() ) { // raw file (inefficient)
+ char buf[1];
+ buf[0] = ch;
+ ch = writeBlock( buf, 1 ) == 1 ? ch : EOF;
+ } else { // buffered file
+ if ( (ch = putc( ch, fh )) != EOF ) {
+ if ( !isSequentialAccess() )
+ ioIndex++;
+ if ( ioIndex > length ) // update file length
+ length = ioIndex;
+ } else {
+ setStatus(IO_WriteError);
+ setErrorString( qt_fileerr_write );
+ }
+ }
+ return ch;
+}
+
+/*!
+ Puts the character \a ch back into the file and decrements the
+ index if it is not zero.
+
+ This function is normally called to "undo" a getch() operation.
+
+ Returns \a ch, or -1 if an error occurred.
+
+ \sa getch(), putch()
+*/
+
+int QFile::ungetch( int ch )
+{
+#if defined(QT_CHECK_STATE)
+ if ( !isOpen() ) { // file not open
+ qWarning( "QFile::ungetch: File not open" );
+ return EOF;
+ }
+ if ( !isReadable() ) { // reading not permitted
+ qWarning( "QFile::ungetch: Read operation not permitted" );
+ return EOF;
+ }
+#endif
+ if ( ch == EOF ) // cannot unget EOF
+ return ch;
+
+ if ( isSequentialAccess() && !fh) {
+ // pipe or similar => we cannot ungetch, so do it manually
+ ungetchBuffer += QChar(ch);
+ return ch;
+ }
+
+ if ( isRaw() ) { // raw file (very inefficient)
+ char buf[1];
+ at( ioIndex-1 );
+ buf[0] = ch;
+ if ( writeBlock(buf, 1) == 1 )
+ at ( ioIndex-1 );
+ else
+ ch = EOF;
+ } else { // buffered file
+ if ( (ch = ungetc(ch, fh)) != EOF ) {
+ if ( !isSequentialAccess() )
+ ioIndex--;
+ } else {
+ setStatus( IO_ReadError );
+ setErrorString( qt_fileerr_read );
+ }
+ }
+ return ch;
+}
+
+
+static QCString locale_encoder( const QString &fileName )
+{
+ return fileName.local8Bit();
+}
+
+
+static QFile::EncoderFn encoder = locale_encoder;
+
+/*!
+ When you use QFile, QFileInfo, and QDir to access the file system
+ with Qt, you can use Unicode file names. On Unix, these file names
+ are converted to an 8-bit encoding. If you want to do your own
+ file I/O on Unix, you should convert the file name using this
+ function. On Windows NT/2000, Unicode file names are supported
+ directly in the file system and this function should be avoided.
+ On Windows 95, non-Latin1 locales are not supported.
+
+ By default, this function converts \a fileName to the local 8-bit
+ encoding determined by the user's locale. This is sufficient for
+ file names that the user chooses. File names hard-coded into the
+ application should only use 7-bit ASCII filename characters.
+
+ The conversion scheme can be changed using setEncodingFunction().
+ This might be useful if you wish to give the user an option to
+ store file names in UTF-8, etc., but be aware that such file names
+ would probably then be unrecognizable when seen by other programs.
+
+ \sa decodeName()
+*/
+
+QCString QFile::encodeName( const QString &fileName )
+{
+ return (*encoder)(fileName);
+}
+
+/*!
+ \enum QFile::EncoderFn
+
+ This is used by QFile::setEncodingFunction().
+*/
+
+/*!
+ \nonreentrant
+
+ Sets the function for encoding Unicode file names to \a f. The
+ default encodes in the locale-specific 8-bit encoding.
+
+ \sa encodeName()
+*/
+void QFile::setEncodingFunction( EncoderFn f )
+{
+ encoder = f;
+}
+
+static
+QString locale_decoder( const QCString &localFileName )
+{
+#ifndef Q_WS_MAC
+ return QString::fromLocal8Bit(localFileName);
+#else
+ extern QString qt_mac_precomposeFileName(const QString &); // qglobal.cpp
+ return qt_mac_precomposeFileName(QString::fromLocal8Bit(localFileName));
+#endif
+}
+
+static QFile::DecoderFn decoder = locale_decoder;
+
+/*!
+ This does the reverse of QFile::encodeName() using \a localFileName.
+
+ \sa setDecodingFunction()
+*/
+QString QFile::decodeName( const QCString &localFileName )
+{
+ return (*decoder)(localFileName);
+}
+
+/*!
+ \enum QFile::DecoderFn
+
+ This is used by QFile::setDecodingFunction().
+*/
+
+/*!
+ \nonreentrant
+
+ Sets the function for decoding 8-bit file names to \a f. The
+ default uses the locale-specific 8-bit encoding.
+
+ \sa encodeName(), decodeName()
+*/
+
+void QFile::setDecodingFunction( DecoderFn f )
+{
+ decoder = f;
+}
+
+/*!
+ Returns a human-readable description of the reason of an error that occurred
+ on the device. The error described by the string corresponds to changes of
+ QIODevice::status(). If the status is reset, the error string is also reset.
+
+ The returned strings are not translated with the QObject::tr() or
+ QApplication::translate() functions. They are marked as translatable
+ strings in the "QFile" context. Before you show the string to the user you
+ should translate it first, for example:
+
+ \code
+ QFile f( "address.dat" );
+ if ( !f.open( IO_ReadOnly ) {
+ QMessageBox::critical(
+ this,
+ tr("Open failed"),
+ tr("Could not open file for reading: %1").arg( qApp->translate("QFile",f.errorString()) )
+ );
+ return;
+ }
+ \endcode
+
+ \sa QIODevice::status(), QIODevice::resetStatus(), setErrorString()
+*/
+
+QString QFile::errorString() const
+{
+ if ( status() == IO_Ok )
+ return qt_fileerr_unknown;
+ return d->errorString;
+}
+
+/*!
+ \nonreentrant
+
+ Sets the error string returned by the errorString() function to \a str.
+
+ \sa errorString(), QIODevice::status()
+*/
+
+void QFile::setErrorString( const QString& str )
+{
+ d->errorString = str;
+}
+
+void QFile::setErrorStringErrno( int errnum )
+{
+ switch ( errnum ) {
+ case EACCES:
+ d->errorString = QFILEERR_EACCES;
+ break;
+ case EMFILE:
+ d->errorString = QFILEERR_EMFILE;
+ break;
+ case ENOENT:
+ d->errorString = QFILEERR_ENOENT;
+ break;
+ case ENOSPC:
+ d->errorString = QFILEERR_ENOSPC;
+ break;
+ default:
+#ifndef Q_OS_TEMP
+ d->errorString = QString::fromLocal8Bit( strerror( errnum ) );
+#else
+ {
+ unsigned short *string;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ errnum,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&string,
+ 0,
+ NULL );
+ d->errorString = QString::fromUcs2( string );
+ LocalFree( (HLOCAL)string );
+ }
+#endif
+ break;
+ }
+}