Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite portions of EbrFile handling to use UTF16 #1891

Merged
merged 8 commits into from
Feb 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Frameworks/Foundation/NSPathUtilities.mm
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@
// Helper that gets the path for a folder dirName under the current app's AppData/Local... directory,
// creating the folder if necessary
NSString* _getCreateAppDataLocalDir(const char* dirName) {
auto ret = [NSString stringWithFormat:@"%hs/%hs", EbrGetWritableFolder(), dirName];
auto ret = [NSString stringWithFormat:@"%S/%hs", IwGetWritableFolder(), dirName];
_mkdir([ret cStringUsingEncoding:NSUTF8StringEncoding]);
return ret;
}

// Override for when a higher-level directory needs to be created first (eg: Foo1/Foo2/)
NSString* _getCreateAppDataLocalDir(const char* dirName1, const char* dirName2) {
_getCreateAppDataLocalDir(dirName1);
auto ret = [NSString stringWithFormat:@"%hs/%hs/%hs", EbrGetWritableFolder(), dirName1, dirName2];
auto ret = [NSString stringWithFormat:@"%S/%hs/%hs", IwGetWritableFolder(), dirName1, dirName2];
_mkdir([ret cStringUsingEncoding:NSUTF8StringEncoding]);
return ret;
}
Expand Down
292 changes: 45 additions & 247 deletions Frameworks/Starboard/AssetFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,228 +14,39 @@
//
//******************************************************************************

#include <Windows.h>
#include <objbase.h>
#include <algorithm>
#include <map>
#include "Starboard.h"
#include "ErrorHandling.h"
#include "StringHelpers.h"
#include <sys/stat.h>
#include <direct.h>
#include <io.h>

#include "Starboard.h"
#include "Platform/EbrPlatform.h"
#include "AssetFile.h"
#include "PathMapper.h"
#include "LoggingNative.h"

static const wchar_t* TAG = L"AssetFile";

#define strtok_r strtok_s

char CPathMapper::currentDir[4096];

void appendPath(char* curpath, const char* path) {
char copy[4096];

strcpy_s(copy, path);

char* save;
char* curToken = strtok_r(copy, "/\\", &save);
char* curpathEnd = curpath + strlen(curpath);
while (curToken) {
if (strlen(curToken) == 0) {
curToken = strtok_r(NULL, "/\\", &save);
}
int tokenLen = strlen(curToken);
if (strcmp(curToken, "~") == 0) {
strcpy_s(curpath, 2048, "/home");
curpathEnd = curpath + strlen(curpath);
} else {
strcat_s(curpathEnd, 2048, "/");
curpathEnd++;
strcat_s(curpathEnd, 2048, curToken);
curpathEnd += tokenLen;
}
curToken = strtok_r(NULL, "/\\", &save);
}
if (strcmp(curpath, "") == 0)
strcpy_s(curpath, 2048, "/");
}

static void EscapePath(char* dest, const char* src) {
while (*dest)
dest++;

while (*src) {
switch (*src) {
case '?':
*dest = '+';
break;

default:
*dest = *src;
}

dest++;
src++;
}

*dest = 0;
}

bool convertPath(char* filePath, const char* relativePath) {
if (!EbrGetRootMapping(NULL, filePath, 4096))
return false;
int curComponent = 0;

char copy[4096];

strcpy_s(copy, relativePath);

char* save;
char* curToken = strtok_r(copy, "/", &save);
char* filePathEnd = filePath + strlen(filePath);
while (curToken) {
if (strlen(curToken) == 0 || strcmp(curToken, ".") == 0) {
curToken = strtok_r(NULL, "/", &save);
continue;
}

if (curComponent == 0) {
if (!EbrGetRootMapping(curToken, filePath, 4096))
return false;
filePathEnd = filePath + strlen(filePath);
} else {
strcat_s(filePathEnd, 2048, "\\");
filePathEnd++;
EscapePath(filePathEnd, curToken);
filePathEnd += strlen(curToken);
}
curComponent++;

curToken = strtok_r(NULL, "/\\", &save);
}

if (strcmp(filePath, "") == 0)
return false;

return true;
}

bool fixPath(char* outPath, const char* relativePath) {
strcpy_s(outPath, 2048, "");
int curComponent = 0;

if (relativePath[0] != '/')
return false;

char copy[4096];

strcpy_s(copy, relativePath);

char* save;
char* curToken = strtok_r(copy, "/", &save);
char* outPathEnd = outPath + strlen(outPath);
while (curToken) {
if (strlen(curToken) == 0 || strcmp(curToken, ".") == 0) {
curToken = strtok_r(NULL, "/", &save);
continue;
}
if (strcmp(curToken, "..") == 0) {
if (curComponent == 0) {
return false;
}
// Move back one directory
char* curPos = outPath + strlen(outPath);
while (curPos >= outPath) {
if (*curPos == '/') {
*curPos = 0;
break;
}
curPos--;
}
// Impossible!
if (curPos < outPath) {
return false;
}
if (curPos == outPath) {
strcpy_s(outPath, 2048, "/");
}
curComponent--;
curToken = strtok_r(NULL, "/", &save);
outPathEnd = outPath + strlen(outPath);
continue;
}

strcat_s(outPathEnd, 2048, "/");
outPathEnd++;
strcat_s(outPathEnd, 2048, curToken);
outPathEnd += strlen(curToken);
curComponent++;

curToken = strtok_r(NULL, "/", &save);
}
if (strcmp(outPath, "") == 0) {
strcpy_s(outPath, 2048, "/");
}

return true;
}

char* CPathMapper::FixedPath() {
if (fixedValid)
return fixedPath;
return NULL;
}

char* CPathMapper::MappedPath() {
if (fixedValid && mappedValid)
return mappedPath;
return NULL;
}

CPathMapper::CPathMapper(const char* path) {
char relativePath[4096];
strcpy_s(relativePath, "");

if (path[0] != '/') {
appendPath(relativePath, currentDir);
}
appendPath(relativePath, path);
fixedValid = fixPath(fixedPath, relativePath);
mappedValid = convertPath(mappedPath, fixedPath);
}

void ScanAssets() {
}

struct EbrDir {
EbrDirReader* curReader;
};

class EbrFSDirReader : public EbrDirReader {
public:
char path[4096];
char startPath[4096];
std::wstring path;
std::wstring startPath;
HANDLE findHandle;
WIN32_FIND_DATAW data;
bool isFirst;

static EbrDirReader* open(const char* path);
static EbrDirReader* open(const std::wstring& path);
virtual ~EbrFSDirReader();
virtual bool readNext(EbrDir* curDir, EbrDirEnt* end);
};

EbrDirReader* EbrFSDirReader::open(const char* path) {
CPathMapper map(path);
if (!map.MappedPath())
return NULL;

EbrDirReader* EbrFSDirReader::open(const std::wstring& path) {
EbrFSDirReader* ret = new EbrFSDirReader();
sprintf_s(ret->path, "%s\\*", (const char*)CPathMapper(path));
strcpy_s(ret->startPath, path);
std::wstring widePath(ret->path, ret->path + strlen(ret->path));
ret->findHandle = FindFirstFileExW(widePath.c_str(), FindExInfoStandard, &ret->data, FindExSearchNameMatch, NULL, 0);
ret->path = path + std::wstring(L"\\*");
ret->startPath = path;

ret->findHandle = FindFirstFileExW(ret->path.c_str(), FindExInfoStandard, &ret->data, FindExSearchNameMatch, NULL, 0);
if (!ret->findHandle || ret->findHandle == INVALID_HANDLE_VALUE) {
delete ret;
return NULL;
Expand All @@ -259,29 +70,20 @@ bool EbrFSDirReader::readNext(EbrDir* curDir, EbrDirEnt* ent) {
return false;
}

// Note that we're doing wcslen here, which is number of characters. If we've got continues
// in the stream then we may truncate the buffer.
std::string conv(data.cFileName, data.cFileName + wcslen(data.cFileName));
strcpy_s(ent->fileName, conv.c_str());
char tmpPath[4096];
strcpy_s(tmpPath, startPath);
strcat_s(tmpPath, "//");
strcat_s(tmpPath, conv.c_str());
const std::string filename = Strings::WideToNarrow(std::wstring(data.cFileName));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is WideToNarrow a Multibyte conversion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, using UTF8.

strcpy_s(ent->fileName, filename.c_str());
ent->isDir = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
return true;
}

EbrDir* EbrOpenDir(const char* path) {
CPathMapper map(path);
char* fixedName = map.FixedPath();
if (!fixedName) {
return NULL;
}

if (!map.MappedPath())
if (!map) {
return NULL;
}

EbrDirReader* fsReader = EbrFSDirReader::open(fixedName);
EbrDirReader* fsReader = EbrFSDirReader::open(map.MappedPath());
if (!fsReader) {
return NULL;
}
Expand All @@ -302,75 +104,71 @@ void EbrCloseDir(EbrDir* pDir) {
delete pDir;
}

bool EbrIsDir(const char* path) {
CPathMapper map(path);
char* fixedName = map.FixedPath();
if (!fixedName) {
return NULL;
}

std::wstring unicodePath(map.MappedPath(), map.MappedPath() + strlen(map.MappedPath()));
static bool _EbrIsDir(const wchar_t* path) {
WIN32_FILE_ATTRIBUTE_DATA fileAttribData;
if (GetFileAttributesExW(unicodePath.c_str(), GetFileExInfoStandard, &fileAttribData)) {
if (GetFileAttributesExW(path, GetFileExInfoStandard, &fileAttribData)) {
if ((fileAttribData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
return true;
}
return false;
}

bool EbrIsDir(const char* path) {
CPathMapper map(path);

if (!map) {
return NULL;
}

return _EbrIsDir(map);
}

int EbrStat(const char* filename, struct stat* ret) {
#ifdef _USE_32BIT_TIME_T
CPathMapper map(filename);
char* fixedName = map.FixedPath();
if (!fixedName) {
if (!map) {
TraceError(TAG, L"EbrStat failure!");
return -1;
}

if (EbrIsDir(filename)) {
if (_EbrIsDir(map)) {
memset(ret, 0, sizeof(struct stat));
ret->st_size = 0;
ret->st_mode = 0x1B6 | 0040000;
return 0;
}

if (!map.MappedPath()) {
TraceError(TAG, L"EbrStat failure!");
return -1;
}

return stat(map.MappedPath(), ret);
return _wstat32(map, reinterpret_cast<struct _stat32*>(ret));
#else
// This is from stat.h, unfortunately, it doesn't define the wstat apis for non 32-bit time_t
// essentially on our platform, EbrStat is same as EbrStat64i32.
// keeping this #ifdef just in case.
return EbrStat64i32(filename, reinterpret_cast<struct _stat64i32*>(ret));
#endif
}

int EbrStat64i32(const char* filename, struct _stat64i32* ret) {
CPathMapper map(filename);
char* fixedName = map.FixedPath();
if (!fixedName) {
if (!map) {
TraceError(TAG, L"EbrStat failure!");
return -1;
}

if (EbrIsDir(filename)) {
if (_EbrIsDir(map)) {
memset(ret, 0, sizeof(struct _stat64i32));
ret->st_size = 0;
ret->st_mode = 0x1B6 | 0040000;
return 0;
}

if (!map.MappedPath()) {
TraceError(TAG, L"EbrStat failure!");
return -1;
}

return _stat64i32(map.MappedPath(), ret);
return _wstat64i32(map, ret);
}

int EbrAccess(const char* file, int mode) {
CPathMapper map(file);
char* fixedName = map.FixedPath();
if (!fixedName) {
return -1;
}

if (!map.MappedPath())
if (!map)
return -1;

return _access(map.MappedPath(), mode);
return _waccess(map, mode);
}
Loading