#include "stdafx.h"
#include "hwinio.h"
#include "hwinexception.h"
#include "hwincomobject.h"
namespace harlinn
{
namespace windows
{
namespace io
{
namespace
{
wchar_t TrimEndChars[] = { 0x9, 0xA, 0xB, 0xC, 0xD, 0x20, 0x85, 0xA0};
wchar_t RealInvalidPathChars[] = { '\"', '<', '>', '|', '\0', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
wchar_t InvalidFileNameChars[] = { '\"', '<', '>', '|', '\0', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ':', '*', '?', '\\', '/' };
inline void CheckInvalidPathChars(const String& path)
{
if(path.IndexOf([] (wchar_t c) -> bool
{
return (c == '\"' || c == '<' || c == '>' || c == '|' || c < 32);
}) != String::npos)
{
throw ArgumentException("Invalid path character");
}
}
}
// ----------------------------------------------------------------------
// StreamBase
// ----------------------------------------------------------------------
HWIN_EXPORT ComObject* StreamBase::CreateComObject() const
{
ComStream* result = new ComStream(std::const_pointer_cast<StreamBase,const StreamBase>( As<StreamBase>() ));
return result;
}
HWIN_EXPORT StreamBase& StreamBase::Initialize()
{
Base::Initialize();
return *this;
}
HWIN_EXPORT long long StreamBase::Position() const
{
return const_cast<StreamBase*>(this)->Seek(0,SeekOrigin::CurrentPosition);
}
HWIN_EXPORT StreamBase& StreamBase::SetPosition(long long thePosition)
{
this->Seek(thePosition,SeekOrigin::StartOfFile);
return *this;
}
HWIN_EXPORT long long StreamBase::Size() const
{
long long currentPosition = this->Position();
long long result = const_cast<StreamBase*>(this)->Seek(0,SeekOrigin::EndOfFile);
const_cast<StreamBase*>(this)->Seek(currentPosition,SeekOrigin::StartOfFile);
return result;
}
HWIN_EXPORT StreamBase& StreamBase::SetSize(long long theSize)
{
// this is intentionally a nop
return *this;
}
HWIN_EXPORT StreamBase& StreamBase::Flush()
{
// this is intentionally a nop
return *this;
}
// -----------------------------------------------------------------
// FileSystemEntry
// -----------------------------------------------------------------
HWIN_EXPORT FileSystemEntry::FileSystemEntry(const String& theParentDirectory, const String& theName, FileAttributes theAttributes,
const DateTime& theCreationTime, const DateTime& theLastAccessTime, const DateTime& theLastWriteTime)
: parentDirectory(theParentDirectory), name(theName), attributes(theAttributes),
creationTime(theCreationTime),lastAccessTime(theLastAccessTime), lastWriteTime(theLastWriteTime)
{}
// -----------------------------------------------------------------
// FileInfo
// -----------------------------------------------------------------
HWIN_EXPORT FileInfo::FileInfo(const String& theParentDirectory, const String& theName, FileAttributes theAttributes,
const DateTime& theCreationTime, const DateTime& theLastAccessTime, const DateTime& lastWriteTime,
long long theFileSize)
: Base(theParentDirectory, theName, theAttributes, theCreationTime, theLastAccessTime, lastWriteTime),
fileSize(theFileSize)
{}
// -----------------------------------------------------------------
// DirectoryInfo
// -----------------------------------------------------------------
HWIN_EXPORT DirectoryInfo::DirectoryInfo(const String& theParentDirectory, const String& theName, FileAttributes theAttributes,
const DateTime& theCreationTime, const DateTime& theLastAccessTime, const DateTime& lastWriteTime)
: Base(theParentDirectory, theName, theAttributes, theCreationTime, theLastAccessTime, lastWriteTime)
{}
// -----------------------------------------------------------------
// FileSystemEntriesBase
// -----------------------------------------------------------------
HWIN_EXPORT FileSystemEntriesBase::FileSystemEntriesBase(const String& thePath, const String& theSearchPattern )
: path(thePath),searchPattern(theSearchPattern),searchHandle(INVALID_HANDLE_VALUE)
{
path.TrimRight(L"\\/",2);
path = Path::GetFullPathName(path);
}
HWIN_EXPORT FileSystemEntriesBase::FileSystemEntriesBase(const String& theSearchPattern )
: searchPattern(theSearchPattern),
searchHandle(INVALID_HANDLE_VALUE)
{
path = Directory::GetCurrentDirectory();
}
HWIN_EXPORT FileSystemEntriesBase::~FileSystemEntriesBase()
{
if(searchHandle != INVALID_HANDLE_VALUE)
{
FindClose(searchHandle);
}
}
HWIN_EXPORT bool FileSystemEntriesBase::Read()
{
current.reset();
memset(&data,0,sizeof(WIN32_FIND_DATA));
if(searchHandle == INVALID_HANDLE_VALUE)
{
String s = path;
s += L'\\';
s += searchPattern;
searchHandle = FindFirstFileExW(s.c_str(),FindExInfoBasic,&data,FindExSearchNameMatch,nullptr,0);
if(searchHandle == INVALID_HANDLE_VALUE)
{
if(GetLastError() != ERROR_FILE_NOT_FOUND)
{
ThrowLastOSError();
}
else
{
return false;
}
}
return true;
}
else
{
if(FindNextFileW(searchHandle,&data) == 0)
{
if(GetLastError() != ERROR_FILE_NOT_FOUND)
{
ThrowLastOSError();
}
else
{
return false;
}
}
return true;
}
}
HWIN_EXPORT String FileSystemEntriesBase::Name() const
{
return data.cFileName;
}
HWIN_EXPORT String FileSystemEntriesBase::FullPath() const
{
String result = path;
result += '\\';
result += data.cFileName;
return result;
}
// -----------------------------------------------------------------
// Path
// -----------------------------------------------------------------
HWIN_EXPORT String Path::ChangeExtension(const String& path, const String& newExtension)
{
if (!path.IsEmpty())
{
CheckInvalidPathChars(path);
wchar_t stopCharacters[] = {'.', DirectorySeparatorChar , AltDirectorySeparatorChar, VolumeSeparatorChar,'\x00'};
String::size_type index = path.LastIndexOfAnyOf(stopCharacters);
String result = path;
if(index != String::npos)
{
if(path[index] == '.')
{
result = path.SubString(0, index);
}
}
if(!newExtension.IsEmpty())
{
if(newExtension[0] != '.')
{
result += '.';
}
result += newExtension;
}
return result;
}
return String();
}
HWIN_EXPORT String Path::GetLongPathName(const String& path)
{
if(!path.IsEmpty())
{
wchar_t buffer[MAX_PATH+1] = {0,};
auto length = ::GetLongPathNameW(path.c_str(),buffer,sizeof(buffer)/sizeof(wchar_t));
if(length == 0)
{
ThrowLastOSError();
}
if(length > (sizeof(buffer)/sizeof(wchar_t)))
{
String result;
result.SetLength(length-1);
length = ::GetLongPathNameW(path.c_str(),result.c_str(),length);
if(length == 0)
{
ThrowLastOSError();
}
return result;
}
else
{
String result(buffer,length);
return result;
}
}
return String();
}
HWIN_EXPORT String Path::GetFullPathName(const String& path)
{
if(!path.IsEmpty())
{
LPWSTR filePart;
wchar_t buffer[MAX_PATH+1] = {0,};
auto length = ::GetFullPathNameW(path.c_str(),sizeof(buffer)/sizeof(wchar_t),buffer,&filePart);
if(length == 0)
{
ThrowLastOSError();
}
if(length >= (sizeof(buffer)/sizeof(wchar_t)))
{
String result;
result.SetLength(length-1);
length = ::GetFullPathNameW(path.c_str(),length,result.c_str(),&filePart);
if(length == 0)
{
ThrowLastOSError();
}
return result;
}
else
{
String result(buffer,length);
return result;
}
}
return String();
}
HWIN_EXPORT String Path::GetFullPathName(const String& path,String::size_type& indexOfFileName)
{
if(!path.IsEmpty())
{
LPWSTR filePart;
wchar_t buffer[MAX_PATH+1] = {0,};
auto length = ::GetFullPathNameW(path.c_str(),sizeof(buffer)/sizeof(wchar_t),buffer,&filePart);
if(length == 0)
{
ThrowLastOSError();
}
if(length >= (sizeof(buffer)/sizeof(wchar_t)))
{
String result;
result.SetLength(length-1);
length = ::GetFullPathNameW(path.c_str(),length,result.c_str(),&filePart);
if(length == 0)
{
ThrowLastOSError();
}
indexOfFileName = filePart - result.c_str();
return result;
}
else
{
indexOfFileName = filePart - buffer;
String result(buffer,length);
return result;
}
}
indexOfFileName = String::npos;
return String();
}
// -----------------------------------------------------------------
// File
// -----------------------------------------------------------------
namespace
{
bool ExistsLockedOrShared(const wchar_t* path)
{
WIN32_FIND_DATAW FindData;
HANDLE hFind;
bool result = false;
// Either the file is locked/share_exclusive or we got an access denied
hFind = FindFirstFileW(path,&FindData );
if( hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
result = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
}
return result;
}
}
HWIN_EXPORT bool File::Exist(const String& path)
{
if(!path.IsEmpty())
{
auto attrs = GetFileAttributesW(path.c_str());
if(attrs != INVALID_FILE_ATTRIBUTES)
{
if((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
return true;
}
}
else
{
auto lastError = GetLastError();
if((lastError != ERROR_FILE_NOT_FOUND)&&
(lastError != ERROR_PATH_NOT_FOUND)&&
(lastError != ERROR_INVALID_NAME))
{
return ExistsLockedOrShared(path.c_str());
}
}
}
return false;
}
HWIN_EXPORT bool File::Exist(const wchar_t* path)
{
if(path && path[0])
{
auto attrs = GetFileAttributesW(path);
if(attrs != INVALID_FILE_ATTRIBUTES)
{
if((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
return true;
}
}
else
{
auto lastError = GetLastError();
if((lastError != ERROR_FILE_NOT_FOUND)&&
(lastError != ERROR_PATH_NOT_FOUND)&&
(lastError != ERROR_INVALID_NAME))
{
return ExistsLockedOrShared(path);
}
}
}
return false;
}
// -----------------------------------------------------------------
// Directory
// -----------------------------------------------------------------
HWIN_EXPORT String Directory::GetCurrentDirectory()
{
wchar_t buffer[MAX_PATH+1] = {0,};
auto length = ::GetCurrentDirectory(sizeof(buffer)/sizeof(wchar_t),buffer);
if(length == 0)
{
ThrowLastOSError();
}
if(length > (sizeof(buffer)/sizeof(wchar_t)))
{
String result;
result.SetLength(length-1);
length = ::GetCurrentDirectory(length,result.c_str());
if(length == 0)
{
ThrowLastOSError();
}
return result;
}
else
{
String result(buffer,length);
return result;
}
}
HWIN_EXPORT bool Directory::Exist(const String& path)
{
if(!path.IsEmpty())
{
auto attrs = GetFileAttributesW(path.c_str());
if(attrs != INVALID_FILE_ATTRIBUTES)
{
if((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
return true;
}
}
}
return false;
}
HWIN_EXPORT bool Directory::Exist(const wchar_t* path)
{
if(path)
{
auto attrs = GetFileAttributesW(path);
if(attrs != INVALID_FILE_ATTRIBUTES)
{
if((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
return true;
}
}
}
return false;
}
// -----------------------------------------------------------------
// StreamCore
// -----------------------------------------------------------------
HWIN_EXPORT StreamCore::StreamCore(HANDLE theFileHandle)
: hFile(theFileHandle)
{}
HWIN_EXPORT StreamCore::~StreamCore()
{
if(hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
}
HWIN_EXPORT StreamBase& StreamCore::SetPosition(long long thePosition)
{
Seek(thePosition,SeekOrigin::StartOfFile);
return *this;
}
HWIN_EXPORT long long StreamCore::Size() const
{
LARGE_INTEGER llFileSize;
llFileSize.QuadPart = 0;
if(GetFileSizeEx(hFile,&llFileSize) == 0)
{
ThrowLastOSError();
}
return llFileSize.QuadPart;
}
HWIN_EXPORT StreamBase& StreamCore::SetSize(long long theSize)
{
long long currentPosition = this->Position();
long long newPosition = Seek(theSize,SeekOrigin::StartOfFile);
SetEndOfFile(hFile);
if(currentPosition < newPosition)
{
Seek(currentPosition,SeekOrigin::StartOfFile);
}
return *this;
}
HWIN_EXPORT StreamBase& StreamCore::Flush()
{
if(FlushFileBuffers(hFile) == 0)
{
ThrowLastOSError();
}
return *this;
}
HWIN_EXPORT long long StreamCore::Read(void* buffer, size_t numberOfBytesToRead )
{
DWORD numberOfBytesRead = 0;
if(ReadFile(hFile,buffer,DWORD(numberOfBytesToRead),&numberOfBytesRead,nullptr) == 0)
{
ThrowLastOSError();
}
return numberOfBytesRead;
}
HWIN_EXPORT long long StreamCore::Write(const void* buffer, size_t numberOfBytesToWrite )
{
DWORD numberOfBytesWritten = 0;
if(WriteFile(hFile,buffer,DWORD(numberOfBytesToWrite),&numberOfBytesWritten,nullptr) == 0)
{
ThrowLastOSError();
}
return numberOfBytesWritten;
}
HWIN_EXPORT long long StreamCore::Seek(long long offset, SeekOrigin seekOrigin)
{
LARGE_INTEGER llOffset;
llOffset.QuadPart = offset;
LARGE_INTEGER llNewPosition;
llNewPosition.QuadPart = 0;
if(SetFilePointerEx(hFile,llOffset,&llNewPosition,DWORD(seekOrigin)) == 0)
{
ThrowLastOSError();
}
return llNewPosition.QuadPart;
}
HWIN_EXPORT std::shared_ptr<StreamBase> StreamCore::Clone() const
{
HANDLE newHandle = 0;
if(::DuplicateHandle(GetCurrentProcess(),hFile,GetCurrentProcess(),&newHandle,0,FALSE,DUPLICATE_SAME_ACCESS) == 0)
{
ThrowLastOSError();
}
auto result = std::make_shared<StreamCore>(newHandle);
return result;
}
// -----------------------------------------------------------------
// FileStream
// -----------------------------------------------------------------
HWIN_EXPORT HANDLE FileStream::Create(LPCWSTR lpFileName, FileAccess fileAccess, FileShare fileShare, LPSECURITY_ATTRIBUTES lpSecurityAttributes,FileMode fileMode,FileAttributes attributes,FileOptions fileOptions)
{
DWORD creationDisposition = 0;
if(fileMode != FileMode::Append)
{
creationDisposition = DWORD(fileMode);
}
else
{
creationDisposition = DWORD(FileMode::OpenOrCreate);
}
DWORD flagsAndAttributes = DWORD(attributes) | DWORD(fileOptions);
HANDLE result = ::CreateFile(lpFileName,DWORD(fileAccess),DWORD(fileShare),lpSecurityAttributes,creationDisposition,flagsAndAttributes,nullptr);
if(result == INVALID_HANDLE_VALUE)
{
ThrowLastOSError();
}
if(fileMode == FileMode::Append)
{
LARGE_INTEGER liDistanceToMove;
liDistanceToMove.QuadPart = 0;
if(SetFilePointerEx(result,liDistanceToMove,nullptr,FILE_END) == 0)
{
CloseHandle(result);
ThrowLastOSError();
}
}
return result;
}
HWIN_EXPORT FileStream::FileStream(const String& fileName, FileAccess fileAccess, FileShare fileShare, LPSECURITY_ATTRIBUTES lpSecurityAttributes,FileMode fileMode,FileAttributes attributes,FileOptions fileOptions)
: Base(Create(fileName.c_str(), fileAccess, fileShare, lpSecurityAttributes,fileMode,attributes,fileOptions))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName, FileAccess fileAccess, FileShare fileShare, LPSECURITY_ATTRIBUTES lpSecurityAttributes,FileMode fileMode,FileAttributes attributes,FileOptions fileOptions)
: Base(Create(fileName, fileAccess, fileShare, lpSecurityAttributes,fileMode,attributes,fileOptions))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName)
: Base(Create(fileName.c_str(), FileAccess::Default, FileShare::Default, nullptr,FileMode::Default,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName)
: Base(Create(fileName, FileAccess::Default, FileShare::Default, nullptr,FileMode::Default,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName,FileAccess fileAccess)
: Base(Create(fileName.c_str(), fileAccess, FileShare::Default, nullptr,FileMode::Default,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName,FileAccess fileAccess)
: Base(Create(fileName, fileAccess, FileShare::Default, nullptr,FileMode::Default,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName,FileAccess fileAccess,FileShare fileShare)
: Base(Create(fileName.c_str(), fileAccess, fileShare, nullptr,FileMode::Default,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName,FileAccess fileAccess,FileShare fileShare)
: Base(Create(fileName, fileAccess, fileShare, nullptr,FileMode::Default,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName,FileAccess fileAccess,FileMode fileMode)
: Base(Create(fileName.c_str(), fileAccess, FileShare::Default, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName,FileAccess fileAccess,FileMode fileMode)
: Base(Create(fileName, fileAccess, FileShare::Default, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName,FileAccess fileAccess,FileShare fileShare,FileMode fileMode)
: Base(Create(fileName.c_str(), fileAccess, fileShare, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName,FileAccess fileAccess,FileShare fileShare,FileMode fileMode)
: Base(Create(fileName, fileAccess, fileShare, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName,FileShare fileShare,FileMode fileMode)
: Base(Create(fileName.c_str(), FileAccess::Default, fileShare, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName,FileShare fileShare,FileMode fileMode)
: Base(Create(fileName, FileAccess::Default, fileShare, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName,FileMode fileMode)
: Base(Create(fileName.c_str(), FileAccess::Default, FileShare::Default, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName,FileMode fileMode)
: Base(Create(fileName, FileAccess::Default, FileShare::Default, nullptr,fileMode,FileAttributes::Normal,FileOptions::Default))
{}
HWIN_EXPORT FileStream::FileStream(const String& fileName, FileAccess fileAccess, FileShare fileShare, FileMode fileMode,FileAttributes attributes,FileOptions fileOptions)
: Base(Create(fileName.c_str(), fileAccess, fileShare, nullptr,fileMode,attributes,fileOptions))
{}
HWIN_EXPORT FileStream::FileStream(LPCWSTR fileName, FileAccess fileAccess, FileShare fileShare, FileMode fileMode,FileAttributes attributes,FileOptions fileOptions)
: Base(Create(fileName, fileAccess, fileShare, nullptr,fileMode,attributes,fileOptions))
{}
};
};
};