Skip to content

Commit

Permalink
* Rewrite path mapper to simplify code and support UTF16 path names.
Browse files Browse the repository at this point in the history
* Rewrite Ebr file apis to use new path mapper.
* Remove dead code.
* fixed unit tests to build after refactor.

Fixes microsoft#1875
  • Loading branch information
Raj Seshasankaran committed Feb 1, 2017
1 parent 1725e10 commit e238a98
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 408 deletions.
282 changes: 37 additions & 245 deletions Frameworks/Starboard/AssetFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,226 +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

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, "");
}
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 @@ -257,29 +70,19 @@ 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));
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 @@ -300,75 +103,64 @@ 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) {
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));
}

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

0 comments on commit e238a98

Please sign in to comment.