all repos — mgba @ 918caf87c476a60685dffab94c3b6f615991c231

mGBA Game Boy Advance Emulator

src/platform/windows/vfs-w32.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba-util/vfs.h>
  7
  8#include <mgba-util/string.h>
  9#include <strsafe.h>
 10
 11static bool _vdwClose(struct VDir* vd);
 12static void _vdwRewind(struct VDir* vd);
 13static struct VDirEntry* _vdwListNext(struct VDir* vd);
 14static struct VFile* _vdwOpenFile(struct VDir* vd, const char* path, int mode);
 15static struct VDir* _vdwOpenDir(struct VDir* vd, const char* path);
 16static bool _vdwDeleteFile(struct VDir* vd, const char* path);
 17
 18static const char* _vdweName(struct VDirEntry* vde);
 19static enum VFSType _vdweType(struct VDirEntry* vde);
 20
 21struct VDirW32;
 22struct VDirEntryW32 {
 23	struct VDirEntry d;
 24	WIN32_FIND_DATAW ffData;
 25	char* utf8Name;
 26};
 27
 28struct VDirW32 {
 29	struct VDir d;
 30	HANDLE handle;
 31	struct VDirEntryW32 vde;
 32	char* path;
 33};
 34
 35struct VDir* VDirOpen(const char* path) {
 36	if (!path || !path[0]) {
 37		return 0;
 38	}
 39	wchar_t name[MAX_PATH + 1];
 40	MultiByteToWideChar(CP_UTF8, 0, path, -1, name, MAX_PATH);
 41	StringCchCatNW(name, MAX_PATH, L"\\*", 2);
 42	WIN32_FIND_DATAW ffData;
 43	HANDLE handle = FindFirstFileW(name, &ffData);
 44	if (handle == INVALID_HANDLE_VALUE) {
 45		return 0;
 46	}
 47
 48	struct VDirW32* vd = malloc(sizeof(struct VDirW32));
 49	if (!vd) {
 50		FindClose(handle);
 51		return 0;
 52	}
 53
 54	vd->d.close = _vdwClose;
 55	vd->d.rewind = _vdwRewind;
 56	vd->d.listNext = _vdwListNext;
 57	vd->d.openFile = _vdwOpenFile;
 58	vd->d.openDir = _vdwOpenDir;
 59	vd->d.deleteFile = _vdwDeleteFile;
 60	vd->handle = handle;
 61	vd->path = _strdup(path);
 62
 63	vd->vde.d.name = _vdweName;
 64	vd->vde.d.type = _vdweType;
 65	vd->vde.ffData = ffData;
 66	vd->vde.utf8Name = NULL;
 67
 68	return &vd->d;
 69}
 70
 71bool _vdwClose(struct VDir* vd) {
 72	struct VDirW32* vdw = (struct VDirW32*) vd;
 73	FindClose(vdw->handle);
 74	free(vdw->path);
 75	if (vdw->vde.utf8Name) {
 76		free(vdw->vde.utf8Name);
 77		vdw->vde.utf8Name = NULL;
 78	}
 79	free(vdw);
 80	return true;
 81}
 82
 83void _vdwRewind(struct VDir* vd) {
 84	struct VDirW32* vdw = (struct VDirW32*) vd;
 85	FindClose(vdw->handle);
 86	wchar_t name[MAX_PATH + 1];
 87	MultiByteToWideChar(CP_UTF8, 0, vdw->path, -1, name, MAX_PATH);
 88	StringCchCatNW(name, MAX_PATH, L"\\*", 2);
 89	if (vdw->vde.utf8Name) {
 90		free(vdw->vde.utf8Name);
 91		vdw->vde.utf8Name = NULL;
 92	}
 93	vdw->handle = FindFirstFileW(name, &vdw->vde.ffData);
 94}
 95
 96struct VDirEntry* _vdwListNext(struct VDir* vd) {
 97	struct VDirW32* vdw = (struct VDirW32*) vd;
 98	if (FindNextFileW(vdw->handle, &vdw->vde.ffData)) {
 99		if (vdw->vde.utf8Name) {
100			free(vdw->vde.utf8Name);
101			vdw->vde.utf8Name = NULL;
102		}
103		return &vdw->vde.d;
104	}
105
106	return 0;
107}
108
109struct VFile* _vdwOpenFile(struct VDir* vd, const char* path, int mode) {
110	struct VDirW32* vdw = (struct VDirW32*) vd;
111	if (!path) {
112		return 0;
113	}
114	const char* dir = vdw->path;
115	size_t size = sizeof(char) * (strlen(path) + strlen(dir) + 2);
116	char* combined = malloc(size);
117	StringCbPrintfA(combined, size, "%s\\%s", dir, path);
118
119	struct VFile* file = VFileOpen(combined, mode);
120	free(combined);
121	return file;
122}
123
124struct VDir* _vdwOpenDir(struct VDir* vd, const char* path) {
125	struct VDirW32* vdw = (struct VDirW32*) vd;
126	if (!path) {
127		return 0;
128	}
129	const char* dir = vdw->path;
130	size_t size = sizeof(char) * (strlen(path) + strlen(dir) + 2);
131	char* combined = malloc(size);
132	StringCbPrintfA(combined, size, "%s\\%s", dir, path);
133
134	struct VDir* vd2 = VDirOpen(combined);
135	if (!vd2) {
136		vd2 = VDirOpenArchive(combined);
137	}
138	free(combined);
139	return vd2;
140}
141
142bool _vdwDeleteFile(struct VDir* vd, const char* path) {
143	struct VDirW32* vdw = (struct VDirW32*) vd;
144	if (!path) {
145		return 0;
146	}
147	wchar_t dir[MAX_PATH + 1];
148	wchar_t pathw[MAX_PATH + 1];
149	wchar_t combined[MAX_PATH + 1];
150	MultiByteToWideChar(CP_UTF8, 0, vdw->path, -1, dir, MAX_PATH);
151	MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw, MAX_PATH);
152	StringCchPrintfW(combined, MAX_PATH, L"%ws\\%ws", dir, pathw);
153
154	return DeleteFileW(combined);
155}
156
157const char* _vdweName(struct VDirEntry* vde) {
158	struct VDirEntryW32* vdwe = (struct VDirEntryW32*) vde;
159	if (vdwe->utf8Name) {
160		return vdwe->utf8Name;
161	}
162	size_t len = 4 * wcslen(vdwe->ffData.cFileName);
163	vdwe->utf8Name = malloc(len);
164	WideCharToMultiByte(CP_UTF8, 0, vdwe->ffData.cFileName, -1, vdwe->utf8Name, len - 1, NULL, NULL);
165	return vdwe->utf8Name;
166}
167
168static enum VFSType _vdweType(struct VDirEntry* vde) {
169	struct VDirEntryW32* vdwe = (struct VDirEntryW32*) vde;
170	if (vdwe->ffData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
171		return VFS_DIRECTORY;
172	}
173	return VFS_FILE;
174}
175
176bool VDirCreate(const char* path) {
177	wchar_t wpath[MAX_PATH];
178	MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH);
179	if (CreateDirectoryW(wpath, NULL)) {
180		return true;
181	}
182	if (GetLastError() == ERROR_ALREADY_EXISTS) {
183		return true;
184	}
185	return false;
186}