1 /**************************************************************************** |
1 /**************************************************************************** |
2 ** |
2 ** |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
4 ** All rights reserved. |
4 ** All rights reserved. |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
6 ** |
6 ** |
7 ** This file is part of the QtCore module of the Qt Toolkit. |
7 ** This file is part of the QtCore module of the Qt Toolkit. |
8 ** |
8 ** |
60 |
60 |
61 static const int QFILE_WRITEBUFFER_SIZE = 16384; |
61 static const int QFILE_WRITEBUFFER_SIZE = 16384; |
62 |
62 |
63 static QByteArray locale_encode(const QString &f) |
63 static QByteArray locale_encode(const QString &f) |
64 { |
64 { |
65 #ifndef Q_OS_DARWIN |
65 #if defined(Q_OS_DARWIN) |
66 return f.toLocal8Bit(); |
|
67 #else |
|
68 // Mac always expects UTF-8... and decomposed... |
66 // Mac always expects UTF-8... and decomposed... |
69 return f.normalized(QString::NormalizationForm_D).toUtf8(); |
67 return f.normalized(QString::NormalizationForm_D).toUtf8(); |
|
68 #elif defined(Q_OS_SYMBIAN) |
|
69 return f.toUtf8(); |
|
70 #else |
|
71 return f.toLocal8Bit(); |
70 #endif |
72 #endif |
71 } |
73 } |
72 |
74 |
73 static QString locale_decode(const QByteArray &f) |
75 static QString locale_decode(const QByteArray &f) |
74 { |
76 { |
75 #ifndef Q_OS_DARWIN |
77 #if defined(Q_OS_DARWIN) |
76 return QString::fromLocal8Bit(f); |
|
77 #else |
|
78 // Mac always gives us UTF-8 and decomposed, we want that composed... |
78 // Mac always gives us UTF-8 and decomposed, we want that composed... |
79 return QString::fromUtf8(f).normalized(QString::NormalizationForm_C); |
79 return QString::fromUtf8(f).normalized(QString::NormalizationForm_C); |
|
80 #elif defined(Q_OS_SYMBIAN) |
|
81 return QString::fromUtf8(f); |
|
82 #else |
|
83 return QString::fromLocal8Bit(f); |
80 #endif |
84 #endif |
81 } |
85 } |
82 |
86 |
83 //************* QFilePrivate |
87 //************* QFilePrivate |
84 QFile::EncoderFn QFilePrivate::encoder = locale_encode; |
88 QFile::EncoderFn QFilePrivate::encoder = locale_encode; |
85 QFile::DecoderFn QFilePrivate::decoder = locale_decode; |
89 QFile::DecoderFn QFilePrivate::decoder = locale_decode; |
86 |
90 |
87 QFilePrivate::QFilePrivate() |
91 QFilePrivate::QFilePrivate() |
88 : fileEngine(0), lastWasWrite(false), |
92 : fileEngine(0), lastWasWrite(false), |
89 writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError) |
93 writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError), |
|
94 cachedSize(0) |
90 { |
95 { |
91 } |
96 } |
92 |
97 |
93 QFilePrivate::~QFilePrivate() |
98 QFilePrivate::~QFilePrivate() |
94 { |
99 { |
641 Q_D(QFile); |
646 Q_D(QFile); |
642 if (d->fileName.isEmpty()) { |
647 if (d->fileName.isEmpty()) { |
643 qWarning("QFile::remove: Empty or null file name"); |
648 qWarning("QFile::remove: Empty or null file name"); |
644 return false; |
649 return false; |
645 } |
650 } |
|
651 unsetError(); |
646 close(); |
652 close(); |
647 if(error() == QFile::NoError) { |
653 if(error() == QFile::NoError) { |
648 if(fileEngine()->remove()) { |
654 if(fileEngine()->remove()) { |
649 unsetError(); |
655 unsetError(); |
650 return true; |
656 return true; |
651 } |
657 } |
652 d->setError(QFile::RemoveError, fileEngine()->errorString()); |
658 d->setError(QFile::RemoveError, d->fileEngine->errorString()); |
653 } |
659 } |
654 return false; |
660 return false; |
655 } |
661 } |
656 |
662 |
657 /*! |
663 /*! |
701 close(); |
707 close(); |
702 if(error() == QFile::NoError) { |
708 if(error() == QFile::NoError) { |
703 if (fileEngine()->rename(newName)) { |
709 if (fileEngine()->rename(newName)) { |
704 unsetError(); |
710 unsetError(); |
705 // engine was able to handle the new name so we just reset it |
711 // engine was able to handle the new name so we just reset it |
706 fileEngine()->setFileName(newName); |
712 d->fileEngine->setFileName(newName); |
707 d->fileName = newName; |
713 d->fileName = newName; |
708 return true; |
714 return true; |
709 } |
715 } |
710 |
716 |
711 if (isSequential()) { |
717 if (isSequential()) { |
966 |
972 |
967 \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite} |
973 \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite} |
968 mode, if the relevant file does not already exist, this function |
974 mode, if the relevant file does not already exist, this function |
969 will try to create a new file before opening it. |
975 will try to create a new file before opening it. |
970 |
976 |
971 \note Because of limitations in the native API, QFile ignores the |
|
972 Unbuffered flag on Windows. |
|
973 |
|
974 \sa QIODevice::OpenMode, setFileName() |
977 \sa QIODevice::OpenMode, setFileName() |
975 */ |
978 */ |
976 bool QFile::open(OpenMode mode) |
979 bool QFile::open(OpenMode mode) |
977 { |
980 { |
978 Q_D(QFile); |
981 Q_D(QFile); |
986 unsetError(); |
989 unsetError(); |
987 if ((mode & (ReadOnly | WriteOnly)) == 0) { |
990 if ((mode & (ReadOnly | WriteOnly)) == 0) { |
988 qWarning("QIODevice::open: File access not specified"); |
991 qWarning("QIODevice::open: File access not specified"); |
989 return false; |
992 return false; |
990 } |
993 } |
991 if (fileEngine()->open(mode)) { |
994 |
|
995 // QIODevice provides the buffering, so there's no need to request it from the file engine. |
|
996 if (fileEngine()->open(mode | QIODevice::Unbuffered)) { |
992 QIODevice::open(mode); |
997 QIODevice::open(mode); |
993 if (mode & Append) |
998 if (mode & Append) |
994 seek(size()); |
999 seek(size()); |
995 return true; |
1000 return true; |
996 } |
1001 } |
997 QFile::FileError err = fileEngine()->error(); |
1002 QFile::FileError err = d->fileEngine->error(); |
998 if(err == QFile::UnspecifiedError) |
1003 if(err == QFile::UnspecifiedError) |
999 err = QFile::OpenError; |
1004 err = QFile::OpenError; |
1000 d->setError(err, fileEngine()->errorString()); |
1005 d->setError(err, d->fileEngine->errorString()); |
1001 return false; |
1006 return false; |
1002 } |
1007 } |
1003 |
1008 |
1004 /*! \fn QFile::open(OpenMode, FILE*) |
1009 /*! \fn QFile::open(OpenMode, FILE*) |
1005 |
1010 |
1187 \sa unmap(), QAbstractFileEngine::supportsExtension() |
1191 \sa unmap(), QAbstractFileEngine::supportsExtension() |
1188 */ |
1192 */ |
1189 uchar *QFile::map(qint64 offset, qint64 size, MemoryMapFlags flags) |
1193 uchar *QFile::map(qint64 offset, qint64 size, MemoryMapFlags flags) |
1190 { |
1194 { |
1191 Q_D(QFile); |
1195 Q_D(QFile); |
1192 QAbstractFileEngine *engine = fileEngine(); |
1196 if (fileEngine() |
1193 if (engine |
1197 && d->fileEngine->supportsExtension(QAbstractFileEngine::MapExtension)) { |
1194 && engine->supportsExtension(QAbstractFileEngine::MapExtension)) { |
|
1195 unsetError(); |
1198 unsetError(); |
1196 uchar *address = engine->map(offset, size, flags); |
1199 uchar *address = d->fileEngine->map(offset, size, flags); |
1197 if (address == 0) |
1200 if (address == 0) |
1198 d->setError(engine->error(), engine->errorString()); |
1201 d->setError(d->fileEngine->error(), d->fileEngine->errorString()); |
1199 return address; |
1202 return address; |
1200 } |
1203 } |
1201 return 0; |
1204 return 0; |
1202 } |
1205 } |
1203 |
1206 |
1210 \sa map(), QAbstractFileEngine::supportsExtension() |
1213 \sa map(), QAbstractFileEngine::supportsExtension() |
1211 */ |
1214 */ |
1212 bool QFile::unmap(uchar *address) |
1215 bool QFile::unmap(uchar *address) |
1213 { |
1216 { |
1214 Q_D(QFile); |
1217 Q_D(QFile); |
1215 QAbstractFileEngine *engine = fileEngine(); |
1218 if (fileEngine() |
1216 if (engine |
1219 && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) { |
1217 && engine->supportsExtension(QAbstractFileEngine::UnMapExtension)) { |
|
1218 unsetError(); |
1220 unsetError(); |
1219 bool success = engine->unmap(address); |
1221 bool success = d->fileEngine->unmap(address); |
1220 if (!success) |
1222 if (!success) |
1221 d->setError(engine->error(), engine->errorString()); |
1223 d->setError(d->fileEngine->error(), d->fileEngine->errorString()); |
1222 return success; |
1224 return success; |
1223 } |
1225 } |
1224 return false; |
1226 return false; |
1225 } |
1227 } |
1226 |
1228 |
1249 QFile::resize(qint64 sz) |
1251 QFile::resize(qint64 sz) |
1250 { |
1252 { |
1251 Q_D(QFile); |
1253 Q_D(QFile); |
1252 if (!d->ensureFlushed()) |
1254 if (!d->ensureFlushed()) |
1253 return false; |
1255 return false; |
1254 if (isOpen() && fileEngine()->pos() > sz) |
1256 fileEngine(); |
|
1257 if (isOpen() && d->fileEngine->pos() > sz) |
1255 seek(sz); |
1258 seek(sz); |
1256 if(fileEngine()->setSize(sz)) { |
1259 if(d->fileEngine->setSize(sz)) { |
1257 unsetError(); |
1260 unsetError(); |
|
1261 d->cachedSize = sz; |
1258 return true; |
1262 return true; |
1259 } |
1263 } |
1260 d->setError(QFile::ResizeError, fileEngine()->errorString()); |
1264 d->cachedSize = 0; |
|
1265 d->setError(QFile::ResizeError, d->fileEngine->errorString()); |
1261 return false; |
1266 return false; |
1262 } |
1267 } |
1263 |
1268 |
1264 /*! |
1269 /*! |
1265 \overload |
1270 \overload |
1352 |
1357 |
1353 bool |
1358 bool |
1354 QFile::flush() |
1359 QFile::flush() |
1355 { |
1360 { |
1356 Q_D(QFile); |
1361 Q_D(QFile); |
|
1362 if (!d->fileEngine) { |
|
1363 qWarning("QFile::flush: No file engine. Is IODevice open?"); |
|
1364 return false; |
|
1365 } |
|
1366 |
1357 if (!d->writeBuffer.isEmpty()) { |
1367 if (!d->writeBuffer.isEmpty()) { |
1358 qint64 size = d->writeBuffer.size(); |
1368 qint64 size = d->writeBuffer.size(); |
1359 if (_qfile_writeData(d->fileEngine ? d->fileEngine : fileEngine(), |
1369 if (_qfile_writeData(d->fileEngine, &d->writeBuffer) != size) { |
1360 &d->writeBuffer) != size) { |
1370 QFile::FileError err = d->fileEngine->error(); |
1361 QFile::FileError err = fileEngine()->error(); |
|
1362 if(err == QFile::UnspecifiedError) |
1371 if(err == QFile::UnspecifiedError) |
1363 err = QFile::WriteError; |
1372 err = QFile::WriteError; |
1364 d->setError(err, fileEngine()->errorString()); |
1373 d->setError(err, d->fileEngine->errorString()); |
1365 return false; |
1374 return false; |
1366 } |
1375 } |
1367 } |
1376 } |
1368 |
1377 |
1369 if (!fileEngine()->flush()) { |
1378 if (!d->fileEngine->flush()) { |
1370 QFile::FileError err = fileEngine()->error(); |
1379 QFile::FileError err = d->fileEngine->error(); |
1371 if(err == QFile::UnspecifiedError) |
1380 if(err == QFile::UnspecifiedError) |
1372 err = QFile::WriteError; |
1381 err = QFile::WriteError; |
1373 d->setError(err, fileEngine()->errorString()); |
1382 d->setError(err, d->fileEngine->errorString()); |
1374 return false; |
1383 return false; |
1375 } |
1384 } |
1376 return true; |
1385 return true; |
1377 } |
1386 } |
1378 |
1387 |
1385 QFile::close() |
1394 QFile::close() |
1386 { |
1395 { |
1387 Q_D(QFile); |
1396 Q_D(QFile); |
1388 if(!isOpen()) |
1397 if(!isOpen()) |
1389 return; |
1398 return; |
1390 flush(); |
1399 bool flushed = flush(); |
1391 QIODevice::close(); |
1400 QIODevice::close(); |
1392 |
1401 |
1393 unsetError(); |
1402 // reset write buffer |
1394 if(!fileEngine()->close()) |
1403 d->lastWasWrite = false; |
1395 d->setError(fileEngine()->error(), fileEngine()->errorString()); |
1404 d->writeBuffer.clear(); |
|
1405 |
|
1406 // keep earlier error from flush |
|
1407 if (d->fileEngine->close() && flushed) |
|
1408 unsetError(); |
|
1409 else if (flushed) |
|
1410 d->setError(d->fileEngine->error(), d->fileEngine->errorString()); |
1396 } |
1411 } |
1397 |
1412 |
1398 /*! |
1413 /*! |
1399 Returns the size of the file. |
1414 Returns the size of the file. |
1400 |
1415 |
1432 |
1448 |
1433 bool QFile::atEnd() const |
1449 bool QFile::atEnd() const |
1434 { |
1450 { |
1435 Q_D(const QFile); |
1451 Q_D(const QFile); |
1436 |
1452 |
|
1453 // If there's buffered data left, we're not at the end. |
|
1454 if (!d->buffer.isEmpty()) |
|
1455 return false; |
|
1456 |
1437 if (!isOpen()) |
1457 if (!isOpen()) |
1438 return true; |
1458 return true; |
1439 |
1459 |
1440 if (!d->ensureFlushed()) |
1460 if (!d->ensureFlushed()) |
1441 return false; |
1461 return false; |
1442 |
1462 |
1443 // If there's buffered data left, we're not at the end. |
|
1444 if (!d->buffer.isEmpty()) |
|
1445 return false; |
|
1446 |
|
1447 // If the file engine knows best, say what it says. |
1463 // If the file engine knows best, say what it says. |
1448 if (fileEngine()->supportsExtension(QAbstractFileEngine::AtEndExtension)) { |
1464 if (d->fileEngine->supportsExtension(QAbstractFileEngine::AtEndExtension)) { |
1449 // Check if the file engine supports AtEndExtension, and if it does, |
1465 // Check if the file engine supports AtEndExtension, and if it does, |
1450 // check if the file engine claims to be at the end. |
1466 // check if the file engine claims to be at the end. |
1451 return fileEngine()->atEnd(); |
1467 return d->fileEngine->atEnd(); |
1452 } |
1468 } |
|
1469 |
|
1470 // if it looks like we are at the end, or if size is not cached, |
|
1471 // fall through to bytesAvailable() to make sure. |
|
1472 if (pos() < d->cachedSize) |
|
1473 return false; |
1453 |
1474 |
1454 // Fall back to checking how much is available (will stat files). |
1475 // Fall back to checking how much is available (will stat files). |
1455 return bytesAvailable() == 0; |
1476 return bytesAvailable() == 0; |
1456 } |
1477 } |
1457 |
1478 |
1468 } |
1489 } |
1469 |
1490 |
1470 if (!d->ensureFlushed()) |
1491 if (!d->ensureFlushed()) |
1471 return false; |
1492 return false; |
1472 |
1493 |
1473 if (!fileEngine()->seek(off) || !QIODevice::seek(off)) { |
1494 if (!d->fileEngine->seek(off) || !QIODevice::seek(off)) { |
1474 QFile::FileError err = fileEngine()->error(); |
1495 QFile::FileError err = d->fileEngine->error(); |
1475 if(err == QFile::UnspecifiedError) |
1496 if(err == QFile::UnspecifiedError) |
1476 err = QFile::PositionError; |
1497 err = QFile::PositionError; |
1477 d->setError(err, fileEngine()->errorString()); |
1498 d->setError(err, d->fileEngine->errorString()); |
1478 return false; |
1499 return false; |
1479 } |
1500 } |
1480 unsetError(); |
1501 unsetError(); |
1481 return true; |
1502 return true; |
1482 } |
1503 } |
1488 { |
1509 { |
1489 Q_D(QFile); |
1510 Q_D(QFile); |
1490 if (!d->ensureFlushed()) |
1511 if (!d->ensureFlushed()) |
1491 return -1; |
1512 return -1; |
1492 |
1513 |
1493 if (fileEngine()->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) |
1514 qint64 read; |
1494 return fileEngine()->readLine(data, maxlen); |
1515 if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) { |
1495 |
1516 read = d->fileEngine->readLine(data, maxlen); |
1496 // Fall back to QIODevice's readLine implementation if the engine |
1517 } else { |
1497 // cannot do it faster. |
1518 // Fall back to QIODevice's readLine implementation if the engine |
1498 return QIODevice::readLineData(data, maxlen); |
1519 // cannot do it faster. |
|
1520 read = QIODevice::readLineData(data, maxlen); |
|
1521 } |
|
1522 |
|
1523 if (read < maxlen) { |
|
1524 // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked |
|
1525 d->cachedSize = 0; |
|
1526 } |
|
1527 |
|
1528 return read; |
1499 } |
1529 } |
1500 |
1530 |
1501 /*! |
1531 /*! |
1502 \reimp |
1532 \reimp |
1503 */ |
1533 */ |
1507 Q_D(QFile); |
1537 Q_D(QFile); |
1508 unsetError(); |
1538 unsetError(); |
1509 if (!d->ensureFlushed()) |
1539 if (!d->ensureFlushed()) |
1510 return -1; |
1540 return -1; |
1511 |
1541 |
1512 qint64 ret = -1; |
1542 qint64 read = d->fileEngine->read(data, len); |
1513 qint64 read = fileEngine()->read(data, len); |
1543 if(read < 0) { |
1514 if (read != -1) |
1544 QFile::FileError err = d->fileEngine->error(); |
1515 ret = read; |
|
1516 |
|
1517 if(ret < 0) { |
|
1518 QFile::FileError err = fileEngine()->error(); |
|
1519 if(err == QFile::UnspecifiedError) |
1545 if(err == QFile::UnspecifiedError) |
1520 err = QFile::ReadError; |
1546 err = QFile::ReadError; |
1521 d->setError(err, fileEngine()->errorString()); |
1547 d->setError(err, d->fileEngine->errorString()); |
1522 } |
1548 } |
1523 return ret; |
1549 |
|
1550 if (read < len) { |
|
1551 // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked |
|
1552 d->cachedSize = 0; |
|
1553 } |
|
1554 |
|
1555 return read; |
1524 } |
1556 } |
1525 |
1557 |
1526 /*! |
1558 /*! |
1527 \internal |
1559 \internal |
1528 */ |
1560 */ |
1598 } |
1630 } |
1599 |
1631 |
1600 // Write directly to the engine if the block size is larger than |
1632 // Write directly to the engine if the block size is larger than |
1601 // the write buffer size. |
1633 // the write buffer size. |
1602 if (!buffered || len > QFILE_WRITEBUFFER_SIZE) { |
1634 if (!buffered || len > QFILE_WRITEBUFFER_SIZE) { |
1603 QAbstractFileEngine *fe = d->fileEngine ? d->fileEngine : fileEngine(); |
1635 qint64 ret = d->fileEngine->write(data, len); |
1604 qint64 ret = fe->write(data, len); |
|
1605 if(ret < 0) { |
1636 if(ret < 0) { |
1606 QFile::FileError err = fileEngine()->error(); |
1637 QFile::FileError err = d->fileEngine->error(); |
1607 if(err == QFile::UnspecifiedError) |
1638 if(err == QFile::UnspecifiedError) |
1608 err = QFile::WriteError; |
1639 err = QFile::WriteError; |
1609 d->setError(err, fileEngine()->errorString()); |
1640 d->setError(err, d->fileEngine->errorString()); |
1610 } |
1641 } |
1611 return ret; |
1642 return ret; |
1612 } |
1643 } |
1613 |
1644 |
1614 // Write to the buffer. |
1645 // Write to the buffer. |