2010-09-03 05:41:20 +08:00
|
|
|
/*
|
|
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
Copyright (c) 2007-2012 by Wenzel Jakob and others.
|
2010-09-03 05:41:20 +08:00
|
|
|
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License Version 3
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
Mitsuba is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2011-04-14 21:15:59 +08:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2010-09-03 05:41:20 +08:00
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
#include <mitsuba/core/fstream.h>
|
|
|
|
#include <cerrno>
|
|
|
|
|
|
|
|
#if !defined(WIN32)
|
2012-09-28 00:43:51 +08:00
|
|
|
# include <unistd.h>
|
|
|
|
#else
|
|
|
|
# include <windows.h>
|
2012-10-09 14:02:27 +08:00
|
|
|
# include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
|
2010-08-10 01:38:37 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
struct FileStream::FileStreamPrivate
|
|
|
|
{
|
|
|
|
#if defined(WIN32)
|
|
|
|
HANDLE file;
|
|
|
|
#else
|
|
|
|
FILE* file;
|
|
|
|
#endif
|
|
|
|
bool write;
|
|
|
|
bool read;
|
|
|
|
FileStream::EFileMode mode;
|
|
|
|
fs::path path;
|
|
|
|
|
|
|
|
FileStreamPrivate() : file(NULL) {}
|
|
|
|
};
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
FileStream::FileStream()
|
2012-09-28 00:43:51 +08:00
|
|
|
: d(new FileStreamPrivate) {
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
2010-09-10 09:14:48 +08:00
|
|
|
FileStream::FileStream(const fs::path &path, EFileMode mode)
|
2012-09-28 00:43:51 +08:00
|
|
|
: d(new FileStreamPrivate) {
|
2010-09-10 09:14:48 +08:00
|
|
|
open(path, mode);
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
2010-09-10 09:14:48 +08:00
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
FileStream::~FileStream() {
|
2012-09-28 00:43:51 +08:00
|
|
|
if (d->file != 0)
|
2010-08-10 01:38:37 +08:00
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
const fs::path& FileStream::getPath() const {
|
|
|
|
return d->path;
|
|
|
|
}
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
std::string FileStream::toString() const {
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << "FileStream[" << Stream::toString()
|
2012-09-28 00:43:51 +08:00
|
|
|
<< ", path=\"" << d->path.string()
|
|
|
|
<< "\", mode=" << d->mode << "]";
|
2010-08-10 01:38:37 +08:00
|
|
|
return oss.str();
|
|
|
|
}
|
|
|
|
|
2010-09-10 09:14:48 +08:00
|
|
|
void FileStream::open(const fs::path &path, EFileMode mode) {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file == 0, "A file has already been opened using this stream");
|
2010-08-10 01:38:37 +08:00
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
Log(ETrace, "Opening \"%s\"", path.string().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path = path;
|
|
|
|
d->mode = mode;
|
|
|
|
d->write = true;
|
|
|
|
d->read = true;
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD dwDesiredAccess = GENERIC_READ;
|
|
|
|
DWORD dwCreationDisposition = OPEN_EXISTING;
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
switch (d->mode) {
|
2010-08-10 01:38:37 +08:00
|
|
|
case EReadOnly:
|
2012-09-28 00:43:51 +08:00
|
|
|
d->write = false;
|
2010-08-10 01:38:37 +08:00
|
|
|
break;
|
|
|
|
case EReadWrite:
|
|
|
|
dwDesiredAccess |= GENERIC_WRITE;
|
|
|
|
break;
|
|
|
|
case ETruncWrite:
|
2012-09-28 00:43:51 +08:00
|
|
|
d->read = false;
|
2010-08-10 01:38:37 +08:00
|
|
|
dwDesiredAccess = GENERIC_WRITE;
|
|
|
|
dwCreationDisposition = CREATE_ALWAYS;
|
|
|
|
break;
|
|
|
|
case ETruncReadWrite:
|
|
|
|
dwDesiredAccess |= GENERIC_WRITE;
|
|
|
|
dwCreationDisposition = CREATE_ALWAYS;
|
|
|
|
break;
|
|
|
|
case EAppendWrite:
|
2012-09-28 00:43:51 +08:00
|
|
|
d->read = false;
|
2010-08-10 01:38:37 +08:00
|
|
|
dwDesiredAccess = GENERIC_WRITE;
|
|
|
|
break;
|
|
|
|
case EAppendReadWrite:
|
|
|
|
dwDesiredAccess |= GENERIC_WRITE;
|
|
|
|
break;
|
2012-10-21 02:04:13 +08:00
|
|
|
default:
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Unknown file mode");
|
|
|
|
break;
|
|
|
|
}
|
2010-08-31 03:40:32 +08:00
|
|
|
|
2012-10-21 02:04:13 +08:00
|
|
|
d->file = CreateFileW(path.c_str(), dwDesiredAccess,
|
|
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
|
2010-08-10 01:38:37 +08:00
|
|
|
dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
if (d->file == INVALID_HANDLE_VALUE)
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while trying to open file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2012-10-21 02:04:13 +08:00
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
if (d->mode == EAppendWrite || d->mode == EAppendReadWrite)
|
|
|
|
seek(getSize());
|
2010-08-10 01:38:37 +08:00
|
|
|
#else
|
|
|
|
const char *modeString = NULL;
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
switch (d->mode) {
|
2010-08-10 01:38:37 +08:00
|
|
|
case EReadOnly:
|
|
|
|
modeString = "rb";
|
2012-09-28 00:43:51 +08:00
|
|
|
d->write = false;
|
2010-08-10 01:38:37 +08:00
|
|
|
break;
|
|
|
|
case EReadWrite:
|
|
|
|
modeString = "rb+";
|
|
|
|
break;
|
|
|
|
case ETruncWrite:
|
|
|
|
modeString = "wb";
|
2012-09-28 00:43:51 +08:00
|
|
|
d->read = false;
|
2010-08-10 01:38:37 +08:00
|
|
|
break;
|
|
|
|
case ETruncReadWrite:
|
|
|
|
modeString = "wb+";
|
|
|
|
break;
|
|
|
|
case EAppendWrite:
|
|
|
|
modeString = "ab";
|
2012-09-28 00:43:51 +08:00
|
|
|
d->read = false;
|
2010-08-10 01:38:37 +08:00
|
|
|
break;
|
|
|
|
case EAppendReadWrite:
|
|
|
|
modeString = "ab+";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log(EError, "Unknown file mode");
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
d->file = fopen(d->path.string().c_str(), modeString);
|
2010-08-10 01:38:37 +08:00
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
if (d->file == NULL) {
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while trying to open file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::close() {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
Log(ETrace, "Closing \"%s\"", d->path.string().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2012-09-28 00:43:51 +08:00
|
|
|
if (!CloseHandle(d->file)) {
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while trying to close file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#else
|
2012-09-28 00:43:51 +08:00
|
|
|
if (fclose(d->file)) {
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while trying to close file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
2012-09-28 00:43:51 +08:00
|
|
|
d->file = 0;
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FileStream::remove() {
|
|
|
|
close();
|
2012-09-28 00:43:51 +08:00
|
|
|
Log(EDebug, "Removing \"%s\"", d->path.string().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
fs::remove(d->path);
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
void FileStream::seek(size_t pos) {
|
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
2012-10-21 02:04:13 +08:00
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
#ifdef WIN32
|
|
|
|
LARGE_INTEGER fpos;
|
|
|
|
fpos.QuadPart = pos;
|
2012-09-28 00:43:51 +08:00
|
|
|
if (SetFilePointerEx(d->file, fpos, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while trying to seek to position %i in file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
pos, d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#else
|
2012-09-28 00:43:51 +08:00
|
|
|
if (fseek(d->file, pos, SEEK_SET)) {
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while trying to seek to position %i in file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
pos, d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t FileStream::getPos() const {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
2010-08-10 01:38:37 +08:00
|
|
|
#ifdef WIN32
|
2012-09-28 00:43:51 +08:00
|
|
|
DWORD pos = SetFilePointer(d->file, 0, 0, FILE_CURRENT);
|
2010-08-10 01:38:37 +08:00
|
|
|
if (pos == INVALID_SET_FILE_POINTER) {
|
|
|
|
Log(EError, "Error while looking up the position in file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
return (size_t) pos;
|
|
|
|
#else
|
|
|
|
long pos;
|
2012-09-28 00:43:51 +08:00
|
|
|
pos = ftell(d->file);
|
2010-08-10 01:38:37 +08:00
|
|
|
if (pos == -1) {
|
2012-10-21 02:04:13 +08:00
|
|
|
Log(EError, "Error while looking up the position in file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
return (size_t) pos;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t FileStream::getSize() const {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
LARGE_INTEGER result;
|
2012-09-28 00:43:51 +08:00
|
|
|
if (GetFileSizeEx(d->file, &result) == 0) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while getting the file size of \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
return (size_t) result.QuadPart;
|
|
|
|
#else
|
|
|
|
size_t size, tmp;
|
2012-10-21 02:04:13 +08:00
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
tmp = getPos();
|
2012-09-28 00:43:51 +08:00
|
|
|
if (fseek(d->file, 0, SEEK_END)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while seeking within \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
size = getPos();
|
2012-09-28 00:43:51 +08:00
|
|
|
if (fseek(d->file, tmp, SEEK_SET)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while seeking within \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
return size;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::truncate(size_t size) {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
AssertEx(d->write, "File is not open with write access");
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
size_t pos = getPos();
|
2012-10-21 02:04:13 +08:00
|
|
|
if (pos > size)
|
2010-08-10 01:38:37 +08:00
|
|
|
pos = size;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2012-09-28 00:43:51 +08:00
|
|
|
seek(size);
|
|
|
|
if (!SetEndOfFile(d->file)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while truncating file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#else
|
2012-09-28 00:43:51 +08:00
|
|
|
seek(pos);
|
2010-08-10 01:38:37 +08:00
|
|
|
flush();
|
|
|
|
|
2012-09-28 00:43:51 +08:00
|
|
|
if (ftruncate(fileno(d->file), size)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while truncating file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
2012-09-28 00:43:51 +08:00
|
|
|
seek(pos);
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::flush() {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
AssertEx(d->write, "File is not open with write access");
|
2010-08-10 01:38:37 +08:00
|
|
|
#ifdef WIN32
|
2012-09-28 00:43:51 +08:00
|
|
|
if (!FlushFileBuffers(d->file)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while flusing the buffers of \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#else
|
2012-09-28 00:43:51 +08:00
|
|
|
if (fflush(d->file) != 0) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while flusing the buffers of \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::read(void *pPtr, size_t size) {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
AssertEx(d->read, "File is not open with read access");
|
2012-10-21 02:04:13 +08:00
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
if (size == 0)
|
|
|
|
return;
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD lpNumberOfBytesRead;
|
2012-09-28 00:43:51 +08:00
|
|
|
if (!ReadFile(d->file, pPtr, (DWORD) size, &lpNumberOfBytesRead, 0)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while reading from file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
2012-10-21 02:04:13 +08:00
|
|
|
if (lpNumberOfBytesRead != (DWORD) size)
|
2011-04-24 18:44:18 +08:00
|
|
|
throw EOFException(formatString("Read less data than expected (%i bytes required) "
|
2012-09-28 00:43:51 +08:00
|
|
|
"from file \"%s\"", size, d->path.string().c_str()), (size_t) lpNumberOfBytesRead);
|
2010-08-10 01:38:37 +08:00
|
|
|
#else
|
2011-04-24 18:44:18 +08:00
|
|
|
size_t bytesRead;
|
2012-09-28 00:43:51 +08:00
|
|
|
if ((bytesRead = fread(pPtr, 1, size, d->file)) != size) {
|
|
|
|
if (ferror(d->file) != 0) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while reading from file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
2011-04-24 18:44:18 +08:00
|
|
|
throw EOFException(formatString("Read less data than expected (%i bytes required) "
|
2012-09-28 00:43:51 +08:00
|
|
|
"from file \"%s\"", size, d->path.string().c_str()), bytesRead);
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::write(const void *pPtr, size_t size) {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
AssertEx(d->write, "File is not open with write access");
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD lpNumberOfBytesWritten;
|
2012-09-28 00:43:51 +08:00
|
|
|
if (!WriteFile(d->file, pPtr, (DWORD) size, &lpNumberOfBytesWritten, 0)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while writing to file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
2012-10-21 02:04:13 +08:00
|
|
|
if (lpNumberOfBytesWritten != (DWORD) size)
|
2011-04-24 18:44:18 +08:00
|
|
|
throw EOFException(formatString("Wrote less data than expected (%i bytes required) "
|
2012-09-28 00:43:51 +08:00
|
|
|
"to file \"%s\"", size, d->path.string().c_str()), (size_t) lpNumberOfBytesWritten);
|
2010-08-10 01:38:37 +08:00
|
|
|
#else
|
2011-04-24 18:44:18 +08:00
|
|
|
size_t bytesWritten;
|
2012-09-28 00:43:51 +08:00
|
|
|
if ((bytesWritten = fwrite(pPtr, 1, size, d->file)) != size) {
|
|
|
|
if (ferror(d->file))
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EError, "Error while writing to file \"%s\": %s",
|
2012-09-28 00:43:51 +08:00
|
|
|
d->path.string().c_str(), strerror(errno));
|
2011-04-24 18:44:18 +08:00
|
|
|
throw EOFException(formatString("Wrote less data than expected (%i bytes required) "
|
2012-09-28 00:43:51 +08:00
|
|
|
"to file \"%s\"", size, d->path.string().c_str()), bytesWritten);
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStream::canRead() const {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
return d->read;
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStream::canWrite() const {
|
2012-09-28 00:43:51 +08:00
|
|
|
AssertEx(d->file != 0, "No file is currently open");
|
|
|
|
return d->write;
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
|
2012-10-09 14:02:27 +08:00
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
static boost::filesystem::detail::utf8_codecvt_facet *__facet = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void FileStream::staticInitialization() {
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
/* On Linux + MacOS, strings are assumed to be in UTF-8. On
|
|
|
|
Windows, they still are, but fs::path is UTF-16. So we need
|
|
|
|
a codecvt_facet to take care of the necessary conversions */
|
2012-10-21 02:04:13 +08:00
|
|
|
std::locale global_loc = std::locale();
|
2012-10-09 14:02:27 +08:00
|
|
|
__facet = new boost::filesystem::detail::utf8_codecvt_facet();
|
|
|
|
std::locale locale(global_loc, __facet);
|
2012-10-21 02:04:13 +08:00
|
|
|
boost::filesystem::path::imbue(locale);
|
2012-10-09 14:02:27 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::staticShutdown() {
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
boost::filesystem::path::imbue(std::locale());
|
|
|
|
/* Can't delete __facet unfortunately, or we risk a crash .. oh well.. */
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
MTS_IMPLEMENT_CLASS(FileStream, false, Stream)
|
|
|
|
MTS_NAMESPACE_END
|