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}