all repos — mgba @ 5418f25d85f756b7d8028351b17ad7c7ee50a065

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 "util/vfs.h"
  7
  8#include "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
 67	return &vd->d;
 68}
 69
 70bool _vdwClose(struct VDir* vd) {
 71	struct VDirW32* vdw = (struct VDirW32*) vd;
 72	FindClose(vdw->handle);
 73	free(vdw->path);
 74	if (vdw->vde.utf8Name) {
 75		free(vdw->vde.utf8Name);
 76		vdw->vde.utf8Name = NULL;
 77	}
 78	free(vdw);
 79	return true;
 80}
 81
 82void _vdwRewind(struct VDir* vd) {
 83	struct VDirW32* vdw = (struct VDirW32*) vd;
 84	FindClose(vdw->handle);
 85	wchar_t name[MAX_PATH + 1];
 86	MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, vdw->path, -1, name, MAX_PATH);
 87	StringCchCatNW(name, MAX_PATH, L"\\*", 2);
 88	if (vdw->vde.utf8Name) {
 89		free(vdw->vde.utf8Name);
 90		vdw->vde.utf8Name = NULL;
 91	}
 92	vdw->handle = FindFirstFileW(name, &vdw->vde.ffData);
 93}
 94
 95struct VDirEntry* _vdwListNext(struct VDir* vd) {
 96	struct VDirW32* vdw = (struct VDirW32*) vd;
 97	if (FindNextFileW(vdw->handle, &vdw->vde.ffData)) {
 98		if (vdw->vde.utf8Name) {
 99			free(vdw->vde.utf8Name);
100			vdw->vde.utf8Name = NULL;
101		}
102		return &vdw->vde.d;
103	}
104
105	return 0;
106}
107
108struct VFile* _vdwOpenFile(struct VDir* vd, const char* path, int mode) {
109	struct VDirW32* vdw = (struct VDirW32*) vd;
110	if (!path) {
111		return 0;
112	}
113	const char* dir = vdw->path;
114	size_t size = sizeof(char) * (strlen(path) + strlen(dir) + 2);
115	char* combined = malloc(size);
116	StringCbPrintf(combined, size, "%s\\%s", dir, path);
117
118	struct VFile* file = VFileOpen(combined, mode);
119	free(combined);
120	return file;
121}
122
123struct VDir* _vdwOpenDir(struct VDir* vd, const char* path) {
124	struct VDirW32* vdw = (struct VDirW32*) vd;
125	if (!path) {
126		return 0;
127	}
128	const char* dir = vdw->path;
129	size_t size = sizeof(char) * (strlen(path) + strlen(dir) + 2);
130	char* combined = malloc(size);
131	StringCbPrintf(combined, size, "%s\\%s", dir, path);
132
133	struct VDir* vd2 = VDirOpen(combined);
134	if (!vd2) {
135		vd2 = VDirOpenArchive(combined);
136	}
137	free(combined);
138	return vd2;
139}
140
141bool _vdwDeleteFile(struct VDir* vd, const char* path) {
142	struct VDirW32* vdw = (struct VDirW32*) vd;
143	if (!path) {
144		return 0;
145	}
146	const char* dir = vdw->path;
147	size_t size = sizeof(char) * (strlen(path) + strlen(dir) + 2);
148	char* combined = malloc(size);
149	StringCbPrintf(combined, size, "%s\\%s", dir, path);
150
151	bool ret = DeleteFile(combined);
152	free(combined);
153	return ret;
154}
155
156const char* _vdweName(struct VDirEntry* vde) {
157	struct VDirEntryW32* vdwe = (struct VDirEntryW32*) vde;
158	if (vdwe->utf8Name) {
159		return vdwe->utf8Name;
160	}
161	size_t len = 4 * wcslen(vdwe->ffData.cFileName);
162	vdwe->utf8Name = malloc(len);
163	WideCharToMultiByte(CP_UTF8, 0, vdwe->ffData.cFileName, -1, vdwe->utf8Name, len - 1, NULL, NULL);
164	return vdwe->utf8Name;
165}
166
167static enum VFSType _vdweType(struct VDirEntry* vde) {
168	struct VDirEntryW32* vdwe = (struct VDirEntryW32*) vde;
169	if (vdwe->ffData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
170		return VFS_DIRECTORY;
171	}
172	return VFS_FILE;
173}