I figure I should include a patch for my code as well to save anyone needing this some effort. I've also tested this in Windows (ANSI & UNICODE) and Linux.
http://maragnus.com/upload/irr-io-ifile ... ions.patch
-- /EDIT --
In the spirit of sharing, here are a couple extensions to Irrlicht that I've put into my projects. Also included is the hard to find method of getting the path to the Saved Games folder in Windows Vista and 7 with backwards compatibility with XP.
CFileSystem::existDirectory
This function tests if the provided path is an existing directory. The path must exist and it must be a directory to return true. Should work on all OSes.
You must include this for Windows.
Code: Select all
#if defined(_MSC_VER)
#include <sys/stat.h>
#endif
//! Returns true if filename points to an existing directory
bool CFileSystem::existDirectory(const io::path& filename)
{
#if defined(_MSC_VER)
#if defined(_IRR_WCHAR_FILESYSTEM)
struct _stat stat;
if (_wstat(filename.c_str(), &stat) != 0)
return false;
return (stat.st_mode & _S_IFDIR) != 0;
#else
struct _stat stat;
if (_stat(filename.c_str(), &stat) != 0)
return false;
return (stat.st_mode & _S_IFDIR) != 0;
#endif
#else
struct stat stat;
if (stat(filename.c_str(), &stat) != 0)
return false;
return (stat.st_mode & S_IFDIR) != 0;
#endif
}
This function creates the directories for the provided filename. If the entire filename is the path, suffix it with a slash.
IE #1: createDirectories("saves/world1/scene.xml") will make sure that the path leading up to scene.xml exists.
IE #2: createDirectories("saves/world1/") will do the same thing without the filename.
Code: Select all
//! Creates the directory structure for a file recursively.
bool CFileSystem::createDirectories(const io::path& filename)
{
io::path path = getAbsolutePath(filename);
path += "/";
#if defined(_IRR_WINDOWS_API_) && defined(_IRR_WCHAR_FILESYSTEM)
for (int pos = path.findNext(L'/', 1); pos > 0; pos = path.findNext(L'/', pos+1))
#else
for (int pos = path.findNext('/', 1); pos > 0; pos = path.findNext('/', pos+1))
#endif
{
#if defined(_IRR_WINDOWS_API_) && !defined(_IRR_WINDOWS_CE_PLATFORM_)
if (pos > 1 && path[pos-1] == L':')
continue;
#endif
io::path cur = path.subString(0, pos);
if (existDirectory(cur))
continue;
#if defined(_IRR_WINDOWS_API_)
#if defined(_IRR_WCHAR_FILESYSTEM)
if (_wmkdir(cur.c_str()) != 0)
return false;
#else
if (_mkdir(cur.c_str()) != 0)
return false;
#endif
#else
if (mkdir(cur.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
return false;
#endif
}
return true;
}
Lastly, for Windows Vista and 7, I wanted to utilize the Saved Games folder. Windows XP doesn't even have the function that requests the folder, so I needed to get fancy and load the function dynamically. Windows XP defaults to My Documents\My Games
Obviously, this is Windows-only code and requires at least Windows 2000 or Windows XP. Haven't tested on anything earlier. You'll want to do a recursive mkdir on the returned value. I coded this with UNICODE defined, without it, you'll have to MultiByteToWideChar() the result from SHGetKnownFolderPath as there is no ASCII version.
Code: Select all
#include <shlobj.h>
#define PRODUCT_TITLE TEXT("Your Game Name")
typedef HRESULT (WINAPI *PSHGetKnownFolderPath)(const GUID &rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); // free *ppszPath with CoTaskMemFree
irr::io::path getSavePath()
{
// Get Save Path
irr::io::path savepath;
DWORD winver = GetVersion();
if ((DWORD)(LOBYTE(LOWORD(winver))) >= 6)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
PWSTR svgmpath = NULL;
HMODULE shell = GetModuleHandle(TEXT("shell32.dll"));
PSHGetKnownFolderPath GetKnownFolderPath = (PSHGetKnownFolderPath)GetProcAddress(shell, "SHGetKnownFolderPath");
const GUID FOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}};
GetKnownFolderPath(FOLDERID_SavedGames, KF_FLAG_CREATE | KF_FLAG_NO_ALIAS, NULL, &svgmpath);
savepath = svgmpath;
CoTaskMemFree(svgmpath);
CoUninitialize();
}
else if ((DWORD)(LOBYTE(LOWORD(winver))) == 5)
{
WCHAR svgmpath[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, svgmpath);
wcscat_s(svgmpath, MAX_PATH, TEXT("\\My Games"));
savepath = svgmpath;
}
else
{
MessageBox(NULL, TEXT("Windows XP or later is required."), PRODUCT_TITLE, MB_ICONERROR);
ExitProcess(1);
return 0;
}
savepath += TEXT("\\") PRODUCT_TITLE TEXT("\\");
return savepath;
}