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 000000000..3a92f3470
--- /dev/null
+++ b/src/tools/qfile.cpp
@@ -0,0 +1,747 @@
+/****************************************************************************
+**
+** Implementation of TQFile class
+**
+** Created : 930812
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the tools module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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 sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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( "TQFile", "Unknown error" );
+const char* qt_fileerr_read = QT_TRANSLATE_NOOP( "TQFile", "Could not read from the file" );
+const char* qt_fileerr_write = QT_TRANSLATE_NOOP( "TQFile", "Could not write to the file" );
+
+#define TQFILEERR_EACCES QT_TRANSLATE_NOOP( "TQFile", "Permission denied" )
+#define TQFILEERR_EMFILE QT_TRANSLATE_NOOP( "TQFile", "Too many open files" )
+#define TQFILEERR_ENOENT QT_TRANSLATE_NOOP( "TQFile", "No such file or directory" )
+#define TQFILEERR_ENOSPC QT_TRANSLATE_NOOP( "TQFile", "No space left on device" )
+
+class TQFilePrivate
+{
+public:
+ TQString errorString;
+};
+
+extern bool qt_file_access( const TQString& fn, int t );
+
+/*!
+ \class TQFile qfile.h
+ \reentrant
+ \brief The TQFile class is an I/O device that operates on files.
+
+ \ingroup io
+ \mainclass
+
+ TQFile is an I/O device for reading and writing binary and text
+ files. A TQFile may be used by itself or more conveniently with a
+ TQDataStream or TQTextStream.
+
+ 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 TQDataStream
+ or TQTextStream, but you can read with readBlock() and readLine()
+ and write with writeBlock(). TQFile 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 TQTextStream to read a text file
+ line by line. It prints each line with a line number.
+ \code
+ TQStringList lines;
+ TQFile file( "file.txt" );
+ if ( file.open( IO_ReadOnly ) ) {
+ TQTextStream stream( &file );
+ TQString 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
+ TQFile file( "file.txt" );
+ if ( file.open( IO_WriteOnly ) ) {
+ TQTextStream stream( &file );
+ for ( TQStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
+ stream << *it << "\n";
+ file.close();
+ }
+ \endcode
+
+ The TQFileInfo class holds detailed information about a file, such
+ as access permissions, file dates and file types.
+
+ The TQDir class manages directories and lists of file names.
+
+ TQt 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 TQDataStream, TQTextStream
+*/
+
+/*!
+ \fn Q_LONG TQFile::writeBlock( const TQByteArray& data )
+
+ \overload
+*/
+
+
+/*!
+ Constructs a TQFile with no name.
+*/
+
+TQFile::TQFile()
+: d(0)
+{
+ init();
+}
+
+/*!
+ Constructs a TQFile with a file name \a name.
+
+ \sa setName()
+*/
+
+TQFile::TQFile( const TQString &name )
+ : fn(name), d(0)
+{
+ init();
+}
+
+
+/*!
+ Destroys a TQFile. Calls close().
+*/
+
+TQFile::~TQFile()
+{
+ close();
+ delete d;
+}
+
+
+/*!
+ \internal
+ Initialize internal data.
+*/
+
+void TQFile::init()
+{
+ delete d;
+ d = new TQFilePrivate;
+ 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 TQString TQFile::name() const
+
+ Returns the name set by setName().
+
+ \sa setName(), TQFileInfo::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
+ TQFile file;
+ TQDir::setCurrent( "/tmp" );
+ file.setName( "readme.txt" );
+ TQDir::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 TQt.
+
+ \sa name(), TQFileInfo, TQDir
+*/
+
+void TQFile::setName( const TQString &name )
+{
+ if ( isOpen() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "TQFile::setName: File is open" );
+#endif
+ close();
+ }
+ fn = name;
+}
+
+/*!
+ \overload
+
+ Returns TRUE if this file exists; otherwise returns FALSE.
+
+ \sa name()
+*/
+
+bool TQFile::exists() const
+{
+ return qt_file_access( fn, F_OK );
+}
+
+/*!
+ Returns TRUE if the file given by \a fileName exists; otherwise
+ returns FALSE.
+*/
+
+bool TQFile::exists( const TQString &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 TQFile::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 TQFile::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 TQIODevice::Offset TQFile::at() const
+*/
+
+/*!
+ Returns TRUE if the end of file has been reached; otherwise returns FALSE.
+ If TQFile has not been open()'d, then the behavior is undefined.
+
+ \sa size()
+*/
+
+bool TQFile::atEnd() const
+{
+ if ( !isOpen() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "TQFile::atEnd: File is not open" );
+#endif
+ return FALSE;
+ }
+ if ( isDirectAccess() && !isTranslated() ) {
+ if ( at() < size() )
+ return FALSE;
+ }
+ const TQString errorString = d->errorString;
+ const bool ret = TQIODevice::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(), TQTextStream::readLine()
+*/
+
+Q_LONG TQFile::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( "TQFile::readLine: File not open" );
+ return -1;
+ }
+ if ( !isReadable() ) { // reading not permitted
+ qWarning( "TQFile::readLine: Read operation not permitted" );
+ return -1;
+ }
+#endif
+ Q_LONG nread; // number of bytes read
+ if ( isRaw() ) { // raw file
+ nread = TQIODevice::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(), TQTextStream::readLine()
+*/
+
+Q_LONG TQFile::readLine( TQString& s, Q_ULONG maxlen )
+{
+ TQByteArray ba(maxlen);
+ Q_LONG l = readLine(ba.data(),maxlen);
+ if ( l >= 0 ) {
+ ba.truncate(l);
+ s = TQString(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 TQFile::getch()
+{
+#if defined(QT_CHECK_STATE)
+ if ( !isOpen() ) { // file not open
+ qWarning( "TQFile::getch: File not open" );
+ return EOF;
+ }
+ if ( !isReadable() ) { // reading not permitted
+ qWarning( "TQFile::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 TQFile::putch( int ch )
+{
+#if defined(QT_CHECK_STATE)
+ if ( !isOpen() ) { // file not open
+ qWarning( "TQFile::putch: File not open" );
+ return EOF;
+ }
+ if ( !isWritable() ) { // writing not permitted
+ qWarning( "TQFile::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 TQFile::ungetch( int ch )
+{
+#if defined(QT_CHECK_STATE)
+ if ( !isOpen() ) { // file not open
+ qWarning( "TQFile::ungetch: File not open" );
+ return EOF;
+ }
+ if ( !isReadable() ) { // reading not permitted
+ qWarning( "TQFile::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 += TQChar(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 TQCString locale_encoder( const TQString &fileName )
+{
+ return fileName.local8Bit();
+}
+
+
+static TQFile::EncoderFn encoder = locale_encoder;
+
+/*!
+ When you use TQFile, TQFileInfo, and TQDir to access the file system
+ with TQt, 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()
+*/
+
+TQCString TQFile::encodeName( const TQString &fileName )
+{
+ return (*encoder)(fileName);
+}
+
+/*!
+ \enum TQFile::EncoderFn
+
+ This is used by TQFile::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 TQFile::setEncodingFunction( EncoderFn f )
+{
+ encoder = f;
+}
+
+static
+TQString locale_decoder( const TQCString &localFileName )
+{
+#ifndef Q_WS_MAC
+ return TQString::fromLocal8Bit(localFileName);
+#else
+ extern TQString qt_mac_precomposeFileName(const TQString &); // qglobal.cpp
+ return qt_mac_precomposeFileName(TQString::fromLocal8Bit(localFileName));
+#endif
+}
+
+static TQFile::DecoderFn decoder = locale_decoder;
+
+/*!
+ This does the reverse of TQFile::encodeName() using \a localFileName.
+
+ \sa setDecodingFunction()
+*/
+TQString TQFile::decodeName( const TQCString &localFileName )
+{
+ return (*decoder)(localFileName);
+}
+
+/*!
+ \enum TQFile::DecoderFn
+
+ This is used by TQFile::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 TQFile::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
+ TQIODevice::status(). If the status is reset, the error string is also reset.
+
+ The returned strings are not translated with the TQObject::tr() or
+ TQApplication::translate() functions. They are marked as translatable
+ strings in the "TQFile" context. Before you show the string to the user you
+ should translate it first, for example:
+
+ \code
+ TQFile f( "address.dat" );
+ if ( !f.open( IO_ReadOnly ) {
+ TQMessageBox::critical(
+ this,
+ tr("Open failed"),
+ tr("Could not open file for reading: %1").arg( qApp->translate("TQFile",f.errorString()) )
+ );
+ return;
+ }
+ \endcode
+
+ \sa TQIODevice::status(), TQIODevice::resetStatus(), setErrorString()
+*/
+
+TQString TQFile::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(), TQIODevice::status()
+*/
+
+void TQFile::setErrorString( const TQString& str )
+{
+ d->errorString = str;
+}
+
+void TQFile::setErrorStringErrno( int errnum )
+{
+ switch ( errnum ) {
+ case EACCES:
+ d->errorString = TQFILEERR_EACCES;
+ break;
+ case EMFILE:
+ d->errorString = TQFILEERR_EMFILE;
+ break;
+ case ENOENT:
+ d->errorString = TQFILEERR_ENOENT;
+ break;
+ case ENOSPC:
+ d->errorString = TQFILEERR_ENOSPC;
+ break;
+ default:
+#ifndef Q_OS_TEMP
+ d->errorString = TQString::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 = TQString::fromUcs2( string );
+ LocalFree( (HLOCAL)string );
+ }
+#endif
+ break;
+ }
+}