2010-08-10 01:38:37 +08:00
|
|
|
#include <mitsuba/core/fstream.h>
|
|
|
|
#include <cerrno>
|
|
|
|
|
|
|
|
#if !defined(WIN32)
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
FileStream::FileStream()
|
|
|
|
: m_file(0) {
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStream::FileStream(const std::string &filename, EFileMode mode)
|
|
|
|
: m_file(0) {
|
|
|
|
open(filename, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStream::~FileStream() {
|
|
|
|
if (m_file != 0)
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FileStream::toString() const {
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << "FileStream[" << Stream::toString()
|
|
|
|
<< ", filename=\"" << m_filename
|
|
|
|
<< "\", mode=" << m_mode << "]";
|
|
|
|
return oss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStream::exists(const std::string &filename) {
|
|
|
|
#ifdef WIN32
|
|
|
|
WIN32_FIND_DATA lpFindFileData;
|
|
|
|
HANDLE hFind = FindFirstFile(filename.c_str(), &lpFindFileData);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
FindClose(hFind);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
return (access(filename.c_str(), F_OK) == 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::open(const std::string &filename, EFileMode mode) {
|
|
|
|
AssertEx(m_file == 0, "A file has already been opened using this stream");
|
|
|
|
|
|
|
|
Log(ETrace, "Opening \"%s\"", filename.c_str());
|
|
|
|
|
|
|
|
m_filename = filename;
|
|
|
|
m_mode = mode;
|
|
|
|
m_write = true;
|
|
|
|
m_read = true;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD dwDesiredAccess = GENERIC_READ;
|
|
|
|
DWORD dwCreationDisposition = OPEN_EXISTING;
|
|
|
|
|
|
|
|
switch (m_mode) {
|
|
|
|
case EReadOnly:
|
|
|
|
m_write = false;
|
|
|
|
break;
|
|
|
|
case EReadWrite:
|
|
|
|
dwDesiredAccess |= GENERIC_WRITE;
|
|
|
|
break;
|
|
|
|
case ETruncWrite:
|
|
|
|
m_read = false;
|
|
|
|
dwDesiredAccess = GENERIC_WRITE;
|
|
|
|
dwCreationDisposition = CREATE_ALWAYS;
|
|
|
|
break;
|
|
|
|
case ETruncReadWrite:
|
|
|
|
dwDesiredAccess |= GENERIC_WRITE;
|
|
|
|
dwCreationDisposition = CREATE_ALWAYS;
|
|
|
|
break;
|
|
|
|
case EAppendWrite:
|
|
|
|
m_read = false;
|
|
|
|
dwDesiredAccess = GENERIC_WRITE;
|
|
|
|
break;
|
|
|
|
case EAppendReadWrite:
|
|
|
|
dwDesiredAccess |= GENERIC_WRITE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log(EError, "Unknown file mode");
|
|
|
|
break;
|
|
|
|
}
|
2010-08-31 03:40:32 +08:00
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
m_file = CreateFile(filename.c_str(), dwDesiredAccess,
|
|
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
|
|
|
|
dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
|
|
|
|
|
if (m_file == INVALID_HANDLE_VALUE)
|
|
|
|
Log(EError, "Error while trying to open file \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
|
|
|
|
if (m_mode == EAppendWrite || m_mode == EAppendReadWrite)
|
|
|
|
setPos(getSize());
|
|
|
|
#else
|
|
|
|
const char *modeString = NULL;
|
|
|
|
|
|
|
|
switch (m_mode) {
|
|
|
|
case EReadOnly:
|
|
|
|
modeString = "rb";
|
|
|
|
m_write = false;
|
|
|
|
break;
|
|
|
|
case EReadWrite:
|
|
|
|
modeString = "rb+";
|
|
|
|
break;
|
|
|
|
case ETruncWrite:
|
|
|
|
modeString = "wb";
|
|
|
|
m_read = false;
|
|
|
|
break;
|
|
|
|
case ETruncReadWrite:
|
|
|
|
modeString = "wb+";
|
|
|
|
break;
|
|
|
|
case EAppendWrite:
|
|
|
|
modeString = "ab";
|
|
|
|
m_read = false;
|
|
|
|
break;
|
|
|
|
case EAppendReadWrite:
|
|
|
|
modeString = "ab+";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log(EError, "Unknown file mode");
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
m_file = fopen(m_filename.c_str(), modeString);
|
|
|
|
|
|
|
|
if (m_file == NULL) {
|
|
|
|
Log(EError, "Error while trying to open file \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::close() {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
Log(ETrace, "Closing \"%s\"", m_filename.c_str());
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
if (!CloseHandle(m_file)) {
|
|
|
|
Log(EError, "Error while trying to close file \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (fclose(m_file)) {
|
|
|
|
Log(EError, "Error while trying to close file \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
m_file = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FileStream::remove() {
|
|
|
|
close();
|
|
|
|
|
|
|
|
Log(EDebug, "Removing \"%s\"",
|
|
|
|
m_filename.c_str());
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
DeleteFile(m_filename.c_str());
|
|
|
|
#else
|
|
|
|
unlink(m_filename.c_str());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::setPos(size_t pos) {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
LARGE_INTEGER fpos;
|
|
|
|
fpos.QuadPart = pos;
|
|
|
|
if (SetFilePointerEx(m_file, fpos, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
|
|
|
Log(EError, "Error while trying to seek to position %i in file \"%s\": %s",
|
|
|
|
pos, m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (fseek(m_file, pos, SEEK_SET)) {
|
|
|
|
Log(EError, "Error while trying to seek to position %i in file \"%s\": %s",
|
|
|
|
pos, m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t FileStream::getPos() const {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD pos = SetFilePointer(m_file, 0, 0, FILE_CURRENT);
|
|
|
|
if (pos == INVALID_SET_FILE_POINTER) {
|
|
|
|
Log(EError, "Error while looking up the position in file \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
return (size_t) pos;
|
|
|
|
#else
|
|
|
|
long pos;
|
|
|
|
pos = ftell(m_file);
|
|
|
|
if (pos == -1) {
|
|
|
|
Log(EError, "Error while looking up the position in file \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
return (size_t) pos;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t FileStream::getSize() const {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
LARGE_INTEGER result;
|
|
|
|
if (GetFileSizeEx(m_file, &result) == 0) {
|
|
|
|
Log(EError, "Error while getting the file size of \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
return (size_t) result.QuadPart;
|
|
|
|
#else
|
|
|
|
size_t size, tmp;
|
|
|
|
|
|
|
|
tmp = getPos();
|
|
|
|
if (fseek(m_file, 0, SEEK_END)) {
|
|
|
|
Log(EError, "Error while seeking within \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
size = getPos();
|
|
|
|
if (fseek(m_file, tmp, SEEK_SET)) {
|
|
|
|
Log(EError, "Error while seeking within \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::truncate(size_t size) {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
AssertEx(m_write, "File is not open with write access");
|
|
|
|
|
|
|
|
size_t pos = getPos();
|
|
|
|
if (pos > size)
|
|
|
|
pos = size;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
setPos(size);
|
|
|
|
if (!SetEndOfFile(m_file)) {
|
|
|
|
Log(EError, "Error while truncating file \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/* File truncation support blows on posix.. */
|
|
|
|
setPos(pos);
|
|
|
|
flush();
|
|
|
|
|
|
|
|
if (ftruncate(fileno(m_file), size)) {
|
|
|
|
Log(EError, "Error while truncating file \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
setPos(pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::flush() {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
AssertEx(m_write, "File is not open with write access");
|
|
|
|
#ifdef WIN32
|
|
|
|
if (!FlushFileBuffers(m_file)) {
|
|
|
|
Log(EError, "Error while flusing the buffers of \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (fflush(m_file) != 0) {
|
|
|
|
Log(EError, "Error while flusing the buffers of \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::read(void *pPtr, size_t size) {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
AssertEx(m_read, "File is not open with read access");
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
return;
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD lpNumberOfBytesRead;
|
|
|
|
if (!ReadFile(m_file, pPtr, (DWORD) size, &lpNumberOfBytesRead, 0)) {
|
|
|
|
Log(EError, "Error while reading from file \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
if (lpNumberOfBytesRead != (DWORD) size) {
|
|
|
|
Log(EError, "Read less data than expected (%i bytes required) "
|
|
|
|
"from file \"%s\"", size, m_filename.c_str());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (fread(pPtr, size, 1, m_file) != 1) {
|
|
|
|
if (ferror(m_file) != 0) {
|
|
|
|
Log(EError, "Error while reading from file \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
Log(EError, "Read less data than expected (%i bytes required) "
|
|
|
|
"from file \"%s\"", size, m_filename.c_str());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStream::write(const void *pPtr, size_t size) {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
AssertEx(m_write, "File is not open with write access");
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
DWORD lpNumberOfBytesWritten;
|
|
|
|
if (!WriteFile(m_file, pPtr, (DWORD) size, &lpNumberOfBytesWritten, 0)) {
|
|
|
|
Log(EError, "Error while writing to file \"%s\": %s",
|
|
|
|
m_filename.c_str(), lastErrorText().c_str());
|
|
|
|
}
|
|
|
|
if (lpNumberOfBytesWritten != (DWORD) size) {
|
|
|
|
Log(EError, "Wrote less data than expected (%i bytes required) "
|
|
|
|
"to file \"%s\"", size, m_filename.c_str());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (fwrite(pPtr, size, 1, m_file) != 1) {
|
|
|
|
if (ferror(m_file)) {
|
|
|
|
Log(EError, "Error while writing to file \"%s\": %s",
|
|
|
|
m_filename.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
Log(EError, "Wrote less data than expected (%i bytes required) "
|
|
|
|
"to file \"%s\"", size, m_filename.c_str());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStream::canRead() const {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
return m_read;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStream::canWrite() const {
|
|
|
|
AssertEx(m_file != 0, "No file is currently open");
|
|
|
|
return m_write;
|
|
|
|
}
|
|
|
|
|
|
|
|
MTS_IMPLEMENT_CLASS(FileStream, false, Stream)
|
|
|
|
MTS_NAMESPACE_END
|