genesis-3d_engine/Engine/foundation/io/win360/win360fswrapper.cc
zhongdaohuan 6e8fbca745 genesis-3d engine version 1.3.
match the genesis editor version 1.3.0.653.
2014-05-05 14:50:33 +08:00

801 lines
24 KiB
C++

/****************************************************************************
Copyright (c) 2007, Radon Labs GmbH
Copyright (c) 2011-2013,WebJet Business Division,CYOU
http://www.genesis-3d.com.cn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#if WIN32
// - only need this headers
#include <Windows.h>
#include <shlobj.h>
#include <assert.h>
#include <intrin.h> // for _InterlockedIncrement
#include <new.h>
#include <math.h> // for sinf, cosf,etc
//#include "stdneb.h" // - #define NOCTLMGR in precompiled.h make a conflict with shlobj.h, so comment it
#include "io/win360/win360fswrapper.h"
//#include "core/sysfunc.h" // - do not need so much headers include in this file
#if __WIN32__
#include "util/win32/win32stringconverter.h"
#endif
namespace Win360
{
using namespace Util;
using namespace Core;
using namespace IO;
//------------------------------------------------------------------------------
/**
Open a file using the Xbox360 function CreateFile(). Returns a handle
to the file which must be passed to the other Win360FSWrapper file methods.
If opening the file fails, the function will return 0. The filename
must be a native Xbox360 path (no assigns, etc...).
*/
Win360FSWrapper::Handle
Win360FSWrapper::OpenFile(const String& path, Stream::AccessMode accessMode, Stream::AccessPattern accessPattern, DWORD flagsAndAttributes)
{
#if __XBOX360__
String xbox360Path = path;
xbox360Path.SubstituteChar('/', '\\');
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
#endif
DWORD access = 0;
DWORD disposition = 0;
DWORD shareMode = 0;
switch (accessMode)
{
case Stream::ReadAccess:
access = GENERIC_READ;
disposition = OPEN_EXISTING;
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
case Stream::WriteAccess:
access = GENERIC_WRITE;
disposition = CREATE_ALWAYS;
shareMode = FILE_SHARE_READ;
break;
case Stream::ReadWriteAccess:
case Stream::AppendAccess:
access = GENERIC_READ | GENERIC_WRITE;
disposition = OPEN_ALWAYS;
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
}
switch (accessPattern)
{
case Stream::Random:
flagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
break;
case Stream::Sequential:
flagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
break;
}
// open/create the file
#if __XBOX360__
Handle handle = CreateFile(xbox360Path.AsCharPtr(), // lpFileName
access, // dwDesiredAccess
shareMode, // dwShareMode
0, // lpSecurityAttributes
disposition, // dwCreationDisposition,
flagsAndAttributes, // dwFlagsAndAttributes
NULL); // hTemplateFile
#else
Handle handle = CreateFileW((LPCWSTR)widePath, // lpFileName
access, // dwDesiredAccess
shareMode, // dwShareMode
0, // lpSecurityAttributes
disposition, // dwCreationDisposition,
flagsAndAttributes, // dwFlagsAndAttributes
NULL); // hTemplateFile
#endif
if (handle != INVALID_HANDLE_VALUE)
{
// in append mode, we need to seek to the end of the file
if (Stream::AppendAccess == accessMode)
{
SetFilePointer(handle, 0, NULL, FILE_END);
}
return handle;
}
else
{
return 0;
}
}
//------------------------------------------------------------------------------
/**
Closes a file opened by Win360FSWrapper::OpenFile().
*/
void
Win360FSWrapper::CloseFile(Handle handle)
{
n_assert(0 != handle);
CloseHandle(handle);
}
//------------------------------------------------------------------------------
/**
Write data to a file.
*/
void
Win360FSWrapper::Write(Handle handle, const void* buf, Stream::Size numBytes)
{
n_assert(0 != handle);
n_assert(buf != 0);
n_assert(numBytes > 0);
DWORD bytesWritten;
BOOL result = WriteFile(handle, buf, numBytes, &bytesWritten, NULL);
if ((0 == result) || ((DWORD)numBytes != bytesWritten))
{
DWORD error = ::GetLastError();
n_error("Win360FSWrapper: WriteFile() failed! %d", error);
}
}
//------------------------------------------------------------------------------
/**
Read data from a file, returns number of bytes read.
*/
Stream::Size
Win360FSWrapper::Read(Handle handle, void* buf, Stream::Size numBytes)
{
n_assert(0 != handle);
n_assert(buf != 0);
n_assert(numBytes > 0);
DWORD bytesRead;
BOOL result = ReadFile(handle, buf, numBytes, &bytesRead, NULL);
if (0 == result)
{
n_error("Win360FSWrapper: ReadFile() failed!");
}
return bytesRead;
}
//------------------------------------------------------------------------------
/**
Seek in a file.
*/
void
Win360FSWrapper::Seek(Handle handle, Stream::Offset offset, Stream::SeekOrigin orig)
{
n_assert(0 != handle);
DWORD moveMethod;
switch (orig)
{
case Stream::Begin:
moveMethod = FILE_BEGIN;
break;
case Stream::Current:
moveMethod = FILE_CURRENT;
break;
case Stream::End:
moveMethod = FILE_END;
break;
default:
// can't happen
moveMethod = FILE_BEGIN;
break;
}
SetFilePointer(handle, offset, NULL, moveMethod);
}
//------------------------------------------------------------------------------
/**
Get current position in file.
*/
Stream::Position
Win360FSWrapper::Tell(Handle handle)
{
n_assert(0 != handle);
return SetFilePointer(handle, 0, NULL, FILE_CURRENT);
}
//------------------------------------------------------------------------------
/**
Flush unwritten data to file.
*/
void
Win360FSWrapper::Flush(Handle handle)
{
n_assert(0 != handle);
FlushFileBuffers(handle);
}
//------------------------------------------------------------------------------
/**
Returns true if current position is at end of file.
*/
bool
Win360FSWrapper::Eof(Handle handle)
{
n_assert(0 != handle);
DWORD fpos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
DWORD size = ::GetFileSize(handle, NULL);
// NOTE: THE '>=' IS NOT A BUG!!!
return fpos >= size;
}
//------------------------------------------------------------------------------
/**
Returns the size of a file in bytes.
*/
Stream::Size
Win360FSWrapper::GetFileSize(Handle handle)
{
n_assert(0 != handle);
return ::GetFileSize(handle, NULL);
}
//------------------------------------------------------------------------------
/**
Set the read-only status of a file. This method does nothing on the
Xbox360.
*/
void
Win360FSWrapper::SetReadOnly(const String& path, bool readOnly)
{
#if __WIN32__
n_assert(path.IsValid());
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
DWORD fileAttrs = GetFileAttributesW((LPCWSTR)widePath);
if (readOnly)
{
fileAttrs |= FILE_ATTRIBUTE_READONLY;
}
else
{
fileAttrs &= ~FILE_ATTRIBUTE_READONLY;
}
SetFileAttributes(path.AsCharPtr(), fileAttrs);
#else
// NOT AVAILABLE ON XBOX360
#endif
}
//------------------------------------------------------------------------------
/**
Get the read-only status of a file. This method always returns true
on the Xbox360.
*/
bool
Win360FSWrapper::IsReadOnly(const String& path)
{
#if __WIN32__
n_assert(path.IsValid());
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
DWORD fileAttrs = GetFileAttributesW((LPCWSTR)widePath);
return (fileAttrs & FILE_ATTRIBUTE_READONLY);
#else
// always read-only on the 360
return true;
#endif
}
//------------------------------------------------------------------------------
/**
Deletes a file. Returns true if the operation was successful. The delete
will fail if the fail doesn't exist or the file is read-only.
*/
bool
Win360FSWrapper::DeleteFile(const String& path)
{
n_assert(path.IsValid());
#if __XBOX360__
String nativePath = path;
nativePath.SubstituteChar('/', '\\');
return (0 != ::DeleteFileA(nativePath.AsCharPtr()));
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
return (0 != ::DeleteFileW((LPCWSTR)widePath));
#endif
}
//------------------------------------------------------------------------------
/**
Delete an empty directory. Returns true if the operation was successful.
*/
bool
Win360FSWrapper::DeleteDirectory(const String& path)
{
n_assert(path.IsValid());
#if __XBOX360__
String nativePath = path;
nativePath.SubstituteChar('/', '\\');
return (0 != ::RemoveDirectoryA(nativePath.AsCharPtr()));
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
return (0 != ::RemoveDirectoryW((LPCWSTR)widePath));
#endif
}
//------------------------------------------------------------------------------
/**
Return true if a file exists.
*/
bool
Win360FSWrapper::FileExists(const String& path)
{
n_assert(path.IsValid());
#if __XBOX360__
String nativePath = path;
nativePath.SubstituteChar('/', '\\');
DWORD fileAttrs = GetFileAttributesA(nativePath.AsCharPtr());
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
DWORD fileAttrs = GetFileAttributesW((LPCWSTR)widePath);
#endif
if ((-1 != fileAttrs) && (0 == (FILE_ATTRIBUTE_DIRECTORY & fileAttrs)))
{
return true;
}
else
{
return false;
}
}
//------------------------------------------------------------------------------
/**
Return true if a directory exists.
*/
bool
Win360FSWrapper::DirectoryExists(const String& path)
{
n_assert(path.IsValid());
#if __XBOX360__
String nativePath = path;
nativePath.SubstituteChar('/', '\\');
DWORD fileAttrs = GetFileAttributesA(nativePath.AsCharPtr());
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
DWORD fileAttrs = GetFileAttributesW((LPCWSTR)widePath);
#endif
if ((-1 != fileAttrs) && (0 != (FILE_ATTRIBUTE_DIRECTORY & fileAttrs)))
{
return true;
}
else
{
return false;
}
}
//------------------------------------------------------------------------------
/**
Set the write-access time stamp of a file.
*/
void
Win360FSWrapper::SetFileWriteTime(const String& path, FileTime fileTime)
{
n_assert(path.IsValid());
Handle h = Win360FSWrapper::OpenFile(path, Stream::ReadWriteAccess, Stream::Sequential);
if (0 != h)
{
SetFileTime(h, NULL, NULL, &fileTime.time);
Win360FSWrapper::CloseFile(h);
}
else
{
n_error("Win360FSWrapper::SetFileWriteTime(): failed to open file '%s'!", path.AsCharPtr());
}
}
//------------------------------------------------------------------------------
/**
Return the last write-access time to a file.
*/
FileTime
Win360FSWrapper::GetFileWriteTime(const String& path)
{
n_assert(path.IsValid());
FileTime fileTime;
Handle h = Win360FSWrapper::OpenFile(path, Stream::ReadAccess, Stream::Sequential);
if (0 != h)
{
GetFileTime(h, NULL, NULL, &fileTime.time);
Win360FSWrapper::CloseFile(h);
}
else
{
// do not fail hard if file does not exist
// n_printf("Win360FSWrapper::GetFileWriteTime(): failed to open file '%s'!", path.AsCharPtr());
}
return fileTime;
}
//------------------------------------------------------------------------------
/**
Creates a new directory.
*/
bool
Win360FSWrapper::CreateDirectory(const String& path)
{
n_assert(path.IsValid());
#if __XBOX360__
String nativePath = path;
nativePath.SubstituteChar('/', '\\');
return (0 != ::CreateDirectoryA(nativePath.AsCharPtr(), NULL));
#else
const String& nativePath = path;
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(path, widePath, sizeof(widePath));
return (0 != ::CreateDirectoryW((LPCWSTR)widePath, NULL));
#endif
}
//------------------------------------------------------------------------------
/**
Lists all files in a directory, filtered by a pattern.
*/
Array<String>
Win360FSWrapper::ListFiles(const String& dirPath, const String& pattern)
{
n_assert(dirPath.IsValid());
n_assert(pattern.IsValid());
String pathWithPattern = dirPath + "/" + pattern;
#if __XBOX360__
pathWithPattern.SubstituteChar('/', '\\');
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(pathWithPattern, widePath, sizeof(widePath));
#endif
Array<String> result;
HANDLE hFind;
#if __XBOX360__
WIN32_FIND_DATA findFileData;
hFind = FindFirstFileA(pathWithPattern.AsCharPtr(), &findFileData);
if (INVALID_HANDLE_VALUE != hFind)
{
do
{
if (0 == (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
result.Append(findFileData.cFileName);
}
}
while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
}
#else
WIN32_FIND_DATAW findFileData;
hFind = FindFirstFileW((LPCWSTR)widePath, &findFileData);
if (INVALID_HANDLE_VALUE != hFind)
{
do
{
if (0 == (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
result.Append(Win32::Win32StringConverter::WideToUTF8((ushort*)findFileData.cFileName));
}
}
while (FindNextFileW(hFind, &findFileData) != 0);
FindClose(hFind);
}
#endif
return result;
}
//------------------------------------------------------------------------------
/**
Lists all subdirectories in a directory, filtered by a pattern. This will
not return the special directories ".." and ".".
*/
Array<String>
Win360FSWrapper::ListDirectories(const String& dirPath, const String& pattern)
{
n_assert(dirPath.IsValid());
n_assert(pattern.IsValid());
String pathWithPattern = dirPath + "/" + pattern;
#if __XBOX360__
pathWithPattern.SubstituteChar('/', '\\');
#else
ushort widePath[1024];
Win32::Win32StringConverter::UTF8ToWide(pathWithPattern, widePath, sizeof(widePath));
#endif
Array<String> result;
HANDLE hFind;
#if __XBOX360__
WIN32_FIND_DATA findFileData;
hFind = FindFirstFile(pathWithPattern.AsCharPtr(), &findFileData);
if (INVALID_HANDLE_VALUE != hFind)
{
do
{
String fileName = findFileData.cFileName;
if ((0 != (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) &&
(fileName != "..") && (fileName != "."))
{
result.Append(findFileData.cFileName);
}
}
while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
}
#else
WIN32_FIND_DATAW findFileData;
hFind = FindFirstFileW((LPCWSTR)widePath, &findFileData);
if (INVALID_HANDLE_VALUE != hFind)
{
do
{
String fileName = Win32::Win32StringConverter::WideToUTF8((ushort*)findFileData.cFileName);
if ((0 != (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) &&
(fileName != "..") && (fileName != "."))
{
result.Append(fileName);
}
}
while (FindNextFileW(hFind, &findFileData) != 0);
FindClose(hFind);
}
#endif
return result;
}
//------------------------------------------------------------------------------
/**
NOTE: The user: standard assign is not supported on the 360.
*/
String
Win360FSWrapper::GetUserDirectory()
{
#if __WIN32__
ushort wideBuffer[NEBULA3_MAXPATH] = { 0 };
HRESULT hr = SHGetFolderPathW(NULL,
CSIDL_PERSONAL | CSIDL_FLAG_CREATE,
NULL,
0,
(LPWSTR)wideBuffer);
n_assert(SUCCEEDED(hr));
String result = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
result.ConvertBackslashes();
return String("file:///") + result;
#else
// there is no user: assign on the 360
return "";
#endif
}
//------------------------------------------------------------------------------
/**
NOTE: The appdata: standard assign is not supported on the 360.
*/
String
Win360FSWrapper::GetAppDataDirectory()
{
#if __WIN32__
ushort wideBuffer[NEBULA3_MAXPATH] = { 0 };
HRESULT hr = SHGetFolderPathW(NULL,
CSIDL_APPDATA | CSIDL_FLAG_CREATE,
NULL,
0,
(LPWSTR)wideBuffer);
n_assert(SUCCEEDED(hr));
String result = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
result.ConvertBackslashes();
return String("file:///") + result;
#else
// there is no user: assign on the 360
return "";
#endif
}
//------------------------------------------------------------------------------
/**
NOTE: The programs: standard assign is not supported on the 360.
*/
String
Win360FSWrapper::GetProgramsDirectory()
{
#if __WIN32__
ushort wideBuffer[NEBULA3_MAXPATH] = { 0 };
HRESULT hr = SHGetFolderPathW(NULL,
CSIDL_PROGRAM_FILES,
NULL,
0,
(LPWSTR)wideBuffer);
n_assert(SUCCEEDED(hr));
String result = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
result.ConvertBackslashes();
return String("file:///") + result;
#else
// there is no programs: assign on the 360
return "";
#endif
}
//------------------------------------------------------------------------------
/**
NOTE: The temp standard assign is not supported on the 360 (only on
Devkits!)
*/
String
Win360FSWrapper::GetTempDirectory()
{
#if __WIN32__
ushort wideBuffer[NEBULA3_MAXPATH] = { 0 };
GetTempPathW(sizeof(wideBuffer) / 2, (LPWSTR)wideBuffer);
String result = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
result.ConvertBackslashes();
result.TrimRight("/");
return String("file:///") + result;
#else
// @todo: CAREFUL, THIS ONLY EXISTS ON A XBOX360 DEVKIT!
return "file:///DEVKIT:";
#endif
}
//------------------------------------------------------------------------------
/**
This method sould return the directory where the application executable
is located.
*/
String
Win360FSWrapper::GetBinDirectory()
{
#if __WIN32__
ushort wideBuffer[NEBULA3_MAXPATH];
DWORD res = GetModuleFileNameW(NULL, (LPWSTR)wideBuffer, sizeof(wideBuffer) / 2);
n_assert(0 != res);
String result = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
result.ConvertBackslashes();
result = result.ExtractDirName();
result.TrimRight("/");
return String("file:///") + result;
#else
return "file:///GAME:/";
#endif
}
//------------------------------------------------------------------------------
/**
This method should return the installation directory of the
application.
*/
String
Win360FSWrapper::GetHomeDirectory()
{
#if __WIN32__
ushort wideBuffer[NEBULA3_MAXPATH];
DWORD res = GetModuleFileNameW(NULL, (LPWSTR)wideBuffer, sizeof(wideBuffer) / 2);
n_assert(0 != res);
String pathToExe = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
pathToExe.ConvertBackslashes();
// check if executable resides in a win32 directory
String pathToDir = pathToExe.ExtractLastDirName();
if (n_stricmp(pathToDir.AsCharPtr(), "win32") == 0)
{
// normal home:bin/win32 directory structure
// strip bin/win32
String homePath = pathToExe.ExtractDirName();
homePath = homePath.ExtractDirName();
homePath = homePath.ExtractDirName();
homePath.TrimRight("/");
return String("file:///") + homePath;
}
else
{
// not in normal home:bin/win32 directory structure,
// use the exe's directory as home path
String homePath = pathToExe.ExtractDirName();
return String("file:///") + homePath;
}
#else
// Xbox360 case is a bit simpler...
return "file:///GAME:/";
#endif
}
//------------------------------------------------------------------------------
/**
Return true if the provided string is a device name.
*/
bool
Win360FSWrapper::IsDeviceName(const Util::String& str)
{
#if __WIN32__
if (str.Length() == 1)
{
uchar c = str[0];
if (((c >= 'A') && (c <= 'Z')) ||
((c >= 'a') && (c <= 'z')))
{
return true;
}
}
return false;
#else
// on Xbox360:
if (str == "GAME") return true;
else if (str == "DEVKIT") return true;
else return false;
#endif
}
//------------------------------------------------------------------------------
/**
This method should return the path of the editor asset directory.
*/
String
Win360FSWrapper::GetEditorAssetDirectory()
{
#if __WIN32__ && __GENESIS_EDITOR__
ushort wideBuffer[NEBULA3_MAXPATH];
DWORD res = GetModuleFileNameW(NULL, (LPWSTR)wideBuffer, sizeof(wideBuffer) / 2);
n_assert(0 != res);
String result = Win32::Win32StringConverter::WideToUTF8(wideBuffer);
result.ConvertBackslashes();
result = result.ExtractDirName();
String editorPath = result.ExtractDirName();
editorPath += "editorasset/";
if (DirectoryExists(editorPath))
{
editorPath.TrimRight("/");
result = editorPath;
}
else
{
n_error("Editor asset folder not found!");
}
return String("file:///") + result;
#else
return "file:///GAME:/";
#endif
}
} // namespace IO
#endif