You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
686 lines
17 KiB
686 lines
17 KiB
//////////////////////////////////////////////////////////////////// |
|
// File.h |
|
// |
|
// Copyright 2007 cDc@seacave |
|
// Distributed under the Boost Software License, Version 1.0 |
|
// (See http://www.boost.org/LICENSE_1_0.txt) |
|
|
|
#ifndef __SEACAVE_FILE_H__ |
|
#define __SEACAVE_FILE_H__ |
|
|
|
|
|
// I N C L U D E S ///////////////////////////////////////////////// |
|
|
|
#include "Streams.h" |
|
|
|
// Under both Windows and Unix, the stat function is used for classification |
|
|
|
// Under Gnu/Linux, the following classifications are defined |
|
// source: Gnu/Linux man page for stat(2) http://linux.die.net/man/2/stat |
|
// S_IFMT 0170000 bitmask for the file type bitfields |
|
// S_IFSOCK 0140000 socket (Note this overlaps with S_IFDIR) |
|
// S_IFLNK 0120000 symbolic link |
|
// S_IFREG 0100000 regular file |
|
// S_IFBLK 0060000 block device |
|
// S_IFDIR 0040000 directory |
|
// S_IFCHR 0020000 character device |
|
// S_IFIFO 0010000 FIFO |
|
// There are also some Posix-standard macros: |
|
// S_ISREG(m) is it a regular file? |
|
// S_ISDIR(m) directory? |
|
// S_ISCHR(m) character device? |
|
// S_ISBLK(m) block device? |
|
// S_ISFIFO(m) FIFO (named pipe)? |
|
// S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) |
|
// S_ISSOCK(m) socket? (Not in POSIX.1-1996.) |
|
// Under Windows, the following are defined: |
|
// source: Header file sys/stat.h distributed with Visual Studio 10 |
|
// _S_IFMT (S_IFMT) 0xF000 file type mask |
|
// _S_IFREG (S_IFREG) 0x8000 regular |
|
// _S_IFDIR (S_IFDIR) 0x4000 directory |
|
// _S_IFCHR (S_IFCHR) 0x2000 character special |
|
// _S_IFIFO 0x1000 pipe |
|
|
|
#ifdef _MSC_VER |
|
#include <io.h> |
|
// file type tests are not defined for some reason on Windows despite them providing the stat() function! |
|
#define F_OK 0 |
|
#define X_OK 1 |
|
#define W_OK 2 |
|
#define R_OK 4 |
|
// Posix-style macros for Windows |
|
#ifndef S_ISREG |
|
#define S_ISREG(mode) ((mode & _S_IFMT) == _S_IFREG) |
|
#endif |
|
#ifndef S_ISDIR |
|
#define S_ISDIR(mode) ((mode & _S_IFMT) == _S_IFDIR) |
|
#endif |
|
#ifndef S_ISCHR |
|
#define S_ISCHR(mode) ((mode & _S_IFMT) == _S_IFCHR) |
|
#endif |
|
#ifndef S_ISBLK |
|
#define S_ISBLK(mode) (false) |
|
#endif |
|
#ifndef S_ISFIFO |
|
#define S_ISFIFO(mode) ((mode & _S_IFMT) == _S_IFIFO) |
|
#endif |
|
#ifndef S_ISLNK |
|
#define S_ISLNK(mode) (false) |
|
#endif |
|
#ifndef S_ISSOCK |
|
#define S_ISSOCK(mode) (false) |
|
#endif |
|
#else |
|
#include <unistd.h> |
|
#include <dirent.h> |
|
#define _taccess access |
|
#endif |
|
#ifdef __APPLE__ |
|
#define fdatasync fsync |
|
#endif |
|
|
|
|
|
// D E F I N E S /////////////////////////////////////////////////// |
|
|
|
// size of the stored file size variable |
|
#ifdef LARGEFILESIZE |
|
#define FILESIZE size_f_t |
|
#else |
|
#define FILESIZE size_t |
|
#endif |
|
|
|
// invalid file handle |
|
#ifdef _MSC_VER |
|
#define FILE_INVALID_HANDLE INVALID_HANDLE_VALUE |
|
#else |
|
#define FILE_INVALID_HANDLE int(-1) |
|
#endif |
|
|
|
|
|
namespace SEACAVE { |
|
|
|
// S T R U C T S /////////////////////////////////////////////////// |
|
|
|
class GENERAL_API File : public IOStream { |
|
public: |
|
typedef struct FILEINFO_TYPE { |
|
String path; |
|
FILESIZE size; |
|
DWORD attrib; |
|
} FILEINFO; |
|
typedef cList<FILEINFO> FileInfoArr; |
|
|
|
typedef enum FMCREATE_TYPE { |
|
OPEN = 0x01, |
|
CREATE = 0x02, |
|
TRUNCATE = 0x04 |
|
} FMCREATE; |
|
|
|
typedef enum FMFLAGS_TYPE { |
|
SYNC = 0x01, |
|
NOBUFFER = 0x02, |
|
RANDOM = 0x04, |
|
SEQUENTIAL = 0x08 |
|
} FMFLAGS; |
|
|
|
inline File() : h(FILE_INVALID_HANDLE) { |
|
#ifndef _RELEASE |
|
breakRead = -1; |
|
breakWrite = -1; |
|
#endif |
|
} |
|
inline File(LPCTSTR aFileName, int access, int mode, int flags=0) : h(FILE_INVALID_HANDLE) { |
|
#ifndef _RELEASE |
|
breakRead = -1; |
|
breakWrite = -1; |
|
#endif |
|
File::open(aFileName, access, mode, flags); |
|
} |
|
|
|
virtual ~File() { |
|
File::close(); |
|
} |
|
|
|
#ifdef _SUPPORT_CPP11 |
|
inline File(File&& rhs) : h(rhs.h) { |
|
#ifndef _RELEASE |
|
breakRead = rhs.breakRead; |
|
breakWrite = rhs.breakWrite; |
|
#endif |
|
rhs.h = FILE_INVALID_HANDLE; |
|
} |
|
|
|
inline File& operator=(File&& rhs) { |
|
h = rhs.h; |
|
#ifndef _RELEASE |
|
breakRead = rhs.breakRead; |
|
breakWrite = rhs.breakWrite; |
|
#endif |
|
rhs.h = FILE_INVALID_HANDLE; |
|
return *this; |
|
} |
|
#endif |
|
|
|
bool isOpen() const { |
|
return h != FILE_INVALID_HANDLE; |
|
} |
|
|
|
#ifdef _MSC_VER |
|
typedef enum FMACCESS_TYPE { |
|
READ = GENERIC_READ, |
|
WRITE = GENERIC_WRITE, |
|
RW = READ | WRITE |
|
} FMACCESS; |
|
|
|
typedef enum FMCHECKACCESS_TYPE { |
|
CA_EXIST = F_OK, // existence |
|
CA_WRITE = W_OK, // write |
|
CA_READ = R_OK, // read |
|
CA_RW = R_OK | W_OK, |
|
} FMCHECKACCESS; |
|
|
|
/** |
|
* Open the file specified. |
|
* If there are errors, h is set to FILE_INVALID_HANDLE. |
|
* Use isOpen() to check. |
|
*/ |
|
virtual void open(LPCTSTR aFileName, int access, int mode, int flags=0) { |
|
ASSERT(access == WRITE || access == READ || access == (READ | WRITE)); |
|
|
|
close(); |
|
|
|
DWORD m = 0; |
|
if (mode & OPEN) { |
|
if (mode & CREATE) { |
|
m = (mode & TRUNCATE) ? CREATE_ALWAYS : OPEN_ALWAYS; |
|
} else { |
|
m = (mode & TRUNCATE) ? TRUNCATE_EXISTING : OPEN_EXISTING; |
|
} |
|
} else { |
|
ASSERT(mode & CREATE); |
|
m = (mode & TRUNCATE) ? CREATE_ALWAYS : CREATE_NEW; |
|
} |
|
|
|
DWORD f = 0; |
|
if (flags & SYNC) |
|
f |= FILE_FLAG_WRITE_THROUGH; |
|
if (flags & NOBUFFER) |
|
f |= FILE_FLAG_NO_BUFFERING; |
|
if (flags & RANDOM) |
|
f |= FILE_FLAG_RANDOM_ACCESS; |
|
if (flags & SEQUENTIAL) |
|
f |= FILE_FLAG_SEQUENTIAL_SCAN; |
|
|
|
h = ::CreateFile(aFileName, access, FILE_SHARE_READ, NULL, m, f, NULL); |
|
} |
|
|
|
virtual void close() { |
|
if (isOpen()) { |
|
FlushFileBuffers(h); |
|
CloseHandle(h); |
|
h = FILE_INVALID_HANDLE; |
|
} |
|
} |
|
|
|
uint32_t getLastModified() { |
|
ASSERT(isOpen()); |
|
FILETIME f = {0}; |
|
::GetFileTime(h, NULL, NULL, &f); |
|
return convertTime(&f); |
|
} |
|
|
|
static uint32_t convertTime(FILETIME* f) { |
|
SYSTEMTIME s = { 1970, 1, 0, 1, 0, 0, 0, 0 }; |
|
FILETIME f2 = {0}; |
|
if (::SystemTimeToFileTime(&s, &f2)) { |
|
uint64_t* a = (uint64_t*)f; |
|
uint64_t* b = (uint64_t*)&f2; |
|
*a -= *b; |
|
*a /= (1000LL*1000LL*1000LL/100LL); // 100ns > s |
|
return (uint32_t)*a; |
|
} |
|
return 0; |
|
} |
|
|
|
size_f_t getSize() const override { |
|
ASSERT(isOpen()); |
|
DWORD x; |
|
DWORD l = ::GetFileSize(h, &x); |
|
if ((l == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR)) |
|
return SIZE_NA; |
|
return (size_f_t)l | ((size_f_t)x)<<32; |
|
} |
|
|
|
virtual bool setSize(size_f_t newSize) { |
|
const size_f_t pos = getPos(); |
|
if (pos == SIZE_NA) |
|
return false; |
|
if (!setPos(newSize)) |
|
return false; |
|
if (!setEOF()) |
|
return false; |
|
if (!setPos(pos)) |
|
return false; |
|
return true; |
|
} |
|
|
|
size_f_t getPos() const override { |
|
ASSERT(isOpen()); |
|
LONG x = 0; |
|
const DWORD l = ::SetFilePointer(h, 0, &x, FILE_CURRENT); |
|
if (l == INVALID_SET_FILE_POINTER) |
|
return SIZE_NA; |
|
return (size_f_t)l | ((size_f_t)x)<<32; |
|
} |
|
|
|
bool setPos(size_f_t pos) override { |
|
ASSERT(isOpen()); |
|
LONG x = (LONG) (pos>>32); |
|
return (::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_BEGIN) != INVALID_SET_FILE_POINTER); |
|
} |
|
|
|
virtual bool setEndPos(size_f_t pos) { |
|
ASSERT(isOpen()); |
|
LONG x = (LONG) (pos>>32); |
|
return (::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_END) != INVALID_SET_FILE_POINTER); |
|
} |
|
|
|
virtual bool movePos(size_f_t pos) { |
|
ASSERT(isOpen()); |
|
LONG x = (LONG) (pos>>32); |
|
return (::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_CURRENT) != INVALID_SET_FILE_POINTER); |
|
} |
|
|
|
size_t read(void* buf, size_t len) override { |
|
ASSERT(isOpen()); |
|
#ifndef _RELEASE |
|
if (breakRead != (size_t)(-1)) { |
|
if (breakRead <= len) { |
|
ASSERT("FILE::read() break" == NULL); |
|
breakRead = -1; |
|
} else { |
|
breakRead -= len; |
|
} |
|
} |
|
#endif |
|
DWORD x; |
|
if (!::ReadFile(h, buf, (DWORD)len, &x, NULL)) |
|
return STREAM_ERROR; |
|
return x; |
|
} |
|
|
|
size_t write(const void* buf, size_t len) override { |
|
ASSERT(isOpen()); |
|
#ifndef _RELEASE |
|
if (breakWrite != (size_t)(-1)) { |
|
if (breakWrite <= len) { |
|
ASSERT("FILE::write() break" == NULL); |
|
breakWrite = -1; |
|
} else { |
|
breakWrite -= len; |
|
} |
|
} |
|
#endif |
|
DWORD x; |
|
if (!::WriteFile(h, buf, (DWORD)len, &x, NULL)) |
|
return STREAM_ERROR; |
|
ASSERT(x == len); |
|
return x; |
|
} |
|
virtual bool setEOF() { |
|
ASSERT(isOpen()); |
|
return (SetEndOfFile(h) != FALSE); |
|
} |
|
|
|
size_t flush() override { |
|
ASSERT(isOpen()); |
|
return (FlushFileBuffers(h) ? 0 : STREAM_ERROR); |
|
} |
|
|
|
virtual bool getInfo(BY_HANDLE_FILE_INFORMATION* fileInfo) { |
|
ASSERT(isOpen()); |
|
return (GetFileInformationByHandle(h, fileInfo) != FALSE); |
|
} |
|
|
|
static uint32_t getAttrib(LPCTSTR aFileName) { |
|
return GetFileAttributes(aFileName); |
|
} |
|
|
|
static bool setAttrib(LPCTSTR aFileName, uint32_t attribs) { |
|
return (SetFileAttributes(aFileName, attribs) != FALSE); |
|
} |
|
|
|
static void deleteFile(LPCTSTR aFileName) { ::DeleteFile(aFileName); } |
|
static bool renameFile(LPCTSTR source, LPCTSTR target) { |
|
if (!::MoveFile(source, target)) { |
|
// Can't move, try copy/delete... |
|
if (!::CopyFile(source, target, FALSE)) |
|
return false; |
|
deleteFile(source); |
|
} |
|
return true; |
|
} |
|
static bool copyFile(LPCTSTR source, LPCTSTR target) { return ::CopyFile(source, target, FALSE) == TRUE; } |
|
|
|
static size_f_t getSize(LPCTSTR aFileName) { |
|
const HANDLE fh = ::CreateFile(aFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); |
|
if (fh == FILE_INVALID_HANDLE) |
|
return SIZE_NA; |
|
DWORD x; |
|
DWORD l = ::GetFileSize(fh, &x); |
|
CloseHandle(fh); |
|
if ((l == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR)) |
|
return SIZE_NA; |
|
return (((size_f_t)l) | (((size_f_t)x)<<32)); |
|
} |
|
|
|
|
|
static size_f_t findFiles(const String& _strPath, const String& strMask, bool bProcessSubdir, FileInfoArr& arrFiles) { |
|
// List all the files. |
|
WIN32_FIND_DATA fd; |
|
HANDLE hFind; |
|
size_f_t totalSize = 0; |
|
String strPath(_strPath); |
|
Util::ensureFolderSlash(strPath); |
|
//Find all the files in this folder. |
|
hFind = FindFirstFile((strPath + strMask).c_str(), &fd); |
|
if (hFind != FILE_INVALID_HANDLE) { |
|
do { |
|
// this is a file that can be used |
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
|
continue; |
|
// Store the file name. |
|
FILEINFO& fileInfo = arrFiles.AddEmpty(); |
|
fileInfo.path = strPath + fd.cFileName; |
|
#ifdef LARGEFILESIZE |
|
fileInfo.size = (((size_f_t)fd.nFileSizeLow) | (((size_f_t)fd.nFileSizeHigh)<<32)); |
|
#else |
|
fileInfo.size = fd.nFileSizeLow; |
|
#endif |
|
fileInfo.attrib = fd.dwFileAttributes; |
|
totalSize += fileInfo.size; |
|
} while (FindNextFile(hFind, &fd)); |
|
FindClose(hFind); |
|
} |
|
//Process the subfolders also... |
|
if (!bProcessSubdir) |
|
return totalSize; |
|
hFind = FindFirstFile((strPath + '*').c_str(), &fd); |
|
if (hFind != FILE_INVALID_HANDLE) { |
|
do { |
|
// if SUBDIR then process that too |
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) |
|
continue; |
|
if (!_tcscmp(fd.cFileName, _T("."))) |
|
continue; |
|
if (!_tcscmp(fd.cFileName, _T(".."))) |
|
continue; |
|
// Process all subfolders recursively |
|
totalSize += findFiles(strPath + fd.cFileName + PATH_SEPARATOR, strMask, true, arrFiles); |
|
} while (FindNextFile(hFind, &fd)); |
|
FindClose(hFind); |
|
} |
|
return totalSize; |
|
} |
|
|
|
#else // _MSC_VER |
|
|
|
typedef enum FMACCESS_TYPE { |
|
READ = 0x01, |
|
WRITE = 0x02, |
|
RW = READ | WRITE, |
|
} FMACCESS; |
|
|
|
typedef enum FMCHECKACCESS_TYPE { |
|
CA_EXIST = F_OK, // existence |
|
CA_WRITE = W_OK, // write |
|
CA_READ = R_OK, // read |
|
CA_RW = R_OK | W_OK, |
|
CA_EXEC = X_OK, // execute |
|
} FMCHECKACCESS; |
|
|
|
/** |
|
* Open the file specified. |
|
* If there are errors, h is set to FILE_INVALID_HANDLE. |
|
* Use isOpen() to check. |
|
*/ |
|
virtual void open(LPCTSTR aFileName, int access, int mode, int flags=0) { |
|
ASSERT(access == WRITE || access == READ || access == (READ | WRITE)); |
|
|
|
close(); |
|
|
|
int m = 0; |
|
if (access == READ) |
|
m |= O_RDONLY; |
|
else if (access == WRITE) |
|
m |= O_WRONLY; |
|
else |
|
m |= O_RDWR; |
|
|
|
if (mode & CREATE) |
|
m |= O_CREAT; |
|
if (mode & TRUNCATE) |
|
m |= O_TRUNC; |
|
|
|
if (flags & SYNC) |
|
m |= O_DSYNC; |
|
#ifndef __APPLE__ |
|
if (flags & NOBUFFER) |
|
m |= O_DIRECT; |
|
#endif |
|
h = ::open(aFileName, m, S_IRUSR | S_IWUSR); |
|
} |
|
|
|
virtual void close() { |
|
if (h != FILE_INVALID_HANDLE) { |
|
::close(h); |
|
h = FILE_INVALID_HANDLE; |
|
} |
|
} |
|
|
|
uint32_t getLastModified() { |
|
ASSERT(isOpen()); |
|
struct stat s; |
|
if (::fstat(h, &s) == -1) |
|
return 0; |
|
return (uint32_t)s.st_mtime; |
|
} |
|
|
|
size_f_t getSize() const override { |
|
ASSERT(isOpen()); |
|
struct stat s; |
|
if (::fstat(h, &s) == -1) |
|
return SIZE_NA; |
|
return (size_f_t)s.st_size; |
|
} |
|
|
|
size_f_t getPos() const override { |
|
ASSERT(isOpen()); |
|
return (size_f_t)lseek(h, 0, SEEK_CUR); |
|
} |
|
|
|
bool setPos(size_f_t pos) override { ASSERT(isOpen()); return lseek(h, (off_t)pos, SEEK_SET) != (off_t)-1; } |
|
virtual bool setEndPos(size_f_t pos) { ASSERT(isOpen()); return lseek(h, (off_t)pos, SEEK_END) != (off_t)-1; } |
|
virtual bool movePos(size_f_t pos) { ASSERT(isOpen()); return lseek(h, (off_t)pos, SEEK_CUR) != (off_t)-1; } |
|
|
|
size_t read(void* buf, size_t len) override { |
|
ASSERT(isOpen()); |
|
#ifndef _RELEASE |
|
if (breakRead != (size_t)(-1)) { |
|
if (breakRead <= len) { |
|
ASSERT("FILE::read() break" == NULL); |
|
breakRead = -1; |
|
} else { |
|
breakRead -= len; |
|
} |
|
} |
|
#endif |
|
ssize_t x = ::read(h, buf, len); |
|
if (x == -1) |
|
return STREAM_ERROR; |
|
return (size_t)x; |
|
} |
|
|
|
size_t write(const void* buf, size_t len) override { |
|
ASSERT(isOpen()); |
|
#ifndef _RELEASE |
|
if (breakWrite != (size_t)(-1)) { |
|
if (breakWrite <= len) { |
|
ASSERT("FILE::write() break" == NULL); |
|
breakWrite = -1; |
|
} else { |
|
breakWrite -= len; |
|
} |
|
} |
|
#endif |
|
ssize_t x = ::write(h, buf, len); |
|
if (x == -1) |
|
return STREAM_ERROR; |
|
if (x < (ssize_t)len) |
|
return STREAM_ERROR; |
|
return x; |
|
} |
|
|
|
virtual bool setEOF() { |
|
ASSERT(isOpen()); |
|
return (ftruncate(h, (off_t)getPos()) != -1); |
|
} |
|
virtual bool setSize(size_f_t newSize) { |
|
ASSERT(isOpen()); |
|
return (ftruncate(h, (off_t)newSize) != -1); |
|
} |
|
|
|
size_t flush() override { |
|
ASSERT(isOpen()); |
|
return fdatasync(h); |
|
} |
|
|
|
static void deleteFile(LPCTSTR aFileName) { ::remove(aFileName); } |
|
static bool renameFile(LPCTSTR source, LPCTSTR target) { return ::rename(source, target) == 0; } |
|
static bool copyFile(LPCTSTR source, LPCTSTR target) { |
|
std::ifstream src(source, std::ios::binary); |
|
if (!src.is_open()) |
|
return false; |
|
std::ofstream dst(target, std::ios::binary); |
|
if (!dst.is_open()) |
|
return false; |
|
dst << src.rdbuf(); |
|
return true; |
|
} |
|
|
|
static size_f_t getSize(LPCTSTR aFileName) { |
|
struct stat buf; |
|
if (stat(aFileName, &buf) != 0) |
|
return SIZE_NA; |
|
return buf.st_size; |
|
} |
|
|
|
#endif // _MSC_VER |
|
|
|
// test for whether there's something (i.e. folder or file) with this name |
|
// and what access mode is supported |
|
static bool isPresent(LPCTSTR path) { |
|
struct stat buf; |
|
return stat(path, &buf) == 0; |
|
} |
|
static bool access(LPCTSTR path, int mode=CA_EXIST) { |
|
return ::_taccess(path, mode) == 0; |
|
} |
|
// test for whether there's something present and its a folder |
|
static bool isFolder(LPCTSTR path) { |
|
struct stat buf; |
|
if (!(stat(path, &buf) == 0)) |
|
return false; |
|
// If the object is present, see if it is a directory |
|
// this is the Posix-approved way of testing |
|
return S_ISDIR(buf.st_mode); |
|
} |
|
// test for whether there's something present and its a file |
|
// a file can be a regular file, a symbolic link, a FIFO or a socket, but not a device |
|
static bool isFile(LPCTSTR path) { |
|
struct stat buf; |
|
if (!(stat(path, &buf) == 0)) |
|
return false; |
|
// If the object is present, see if it is a file or file-like object |
|
// Note that devices are neither folders nor files |
|
// this is the Posix-approved way of testing |
|
return S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode) || S_ISSOCK(buf.st_mode) || S_ISFIFO(buf.st_mode); |
|
} |
|
|
|
// time the file was originally created |
|
static time_t getCreated(LPCTSTR path) { |
|
struct stat buf; |
|
if (stat(path, &buf) != 0) return 0; |
|
return buf.st_ctime; |
|
} |
|
// time the file was last modified |
|
static time_t getModified(LPCTSTR path) { |
|
struct stat buf; |
|
if (stat(path, &buf) != 0) return 0; |
|
return buf.st_mtime; |
|
} |
|
// time the file was accessed |
|
static time_t getAccessed(LPCTSTR path) { |
|
struct stat buf; |
|
if (stat(path, &buf) != 0) return 0; |
|
return buf.st_atime; |
|
} |
|
|
|
// set the current folder |
|
static bool setCurrentFolder(LPCTSTR path) { |
|
if (!isFolder(path)) |
|
return false; |
|
#ifdef _MSC_VER |
|
// Windows implementation - this returns non-zero for success |
|
return (SetCurrentDirectory(path) != 0); |
|
#else |
|
// Unix implementation - this returns zero for success |
|
return (chdir(path) == 0); |
|
#endif |
|
} |
|
|
|
template <class VECTOR> |
|
inline size_t write(const VECTOR& arr) { |
|
const typename VECTOR::IDX nSize(arr.GetSize()); |
|
size_t nBytes(write(&nSize, sizeof(typename VECTOR::IDX))); |
|
nBytes += write(arr.GetData(), arr.GetDataSize()); |
|
return nBytes; |
|
} |
|
|
|
template <class VECTOR> |
|
inline size_t read(VECTOR& arr) { |
|
typename VECTOR::IDX nSize; |
|
size_t nBytes(read(&nSize, sizeof(typename VECTOR::IDX))); |
|
arr.Resize(nSize); |
|
nBytes += read(arr.GetData(), arr.GetDataSize()); |
|
return nBytes; |
|
} |
|
|
|
enum { LAYER_ID_IN=3 }; |
|
InputStream* getInputStream(int typ=InputStream::LAYER_ID_IN) override { return (typ == LAYER_ID_IN ? static_cast<InputStream*>(this) : IOStream::getInputStream(typ)); } |
|
enum { LAYER_ID_OUT=3 }; |
|
OutputStream* getOutputStream(int typ=OutputStream::LAYER_ID_OUT) override { return (typ == LAYER_ID_OUT ? static_cast<OutputStream*>(this) : IOStream::getOutputStream(typ)); } |
|
|
|
protected: |
|
#ifdef _MSC_VER |
|
HANDLE h; |
|
#else |
|
int h; |
|
#endif |
|
|
|
public: |
|
#ifndef _RELEASE |
|
size_t breakRead; |
|
size_t breakWrite; |
|
#endif |
|
|
|
private: |
|
File(const File&); |
|
File& operator=(const File&); |
|
}; |
|
typedef File* LPFILE; |
|
/*----------------------------------------------------------------*/ |
|
|
|
} // namespace SEACAVE |
|
|
|
#endif // __SEACAVE_FILE_H__
|
|
|