102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
game_data.c
Go to the documentation of this file.
1#include "sidecar_private.h"
2
3#include <dttr_iso.h>
4#include <dttr_path.h>
5#include <dttr_pcdogs.h>
6
7#include <sds.h>
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include <windows.h>
14
20
22
24 memset(&source, 0, sizeof(source));
25}
26
28 game_data_source next = {0};
30 next.cache_root,
31 sizeof(next.cache_root),
32 getenv("DTTR_ISO_CACHE_ROOT")
33 )
35 next.game_root,
36 sizeof(next.game_root),
37 getenv("DTTR_ISO_GAME_ROOT")
38 )) {
40 return;
41 }
42
43 next.is_iso = true;
44 source = next;
45}
46
48 const char *name,
49 const char *segment,
50 size_t segment_len
51) {
52 return strlen(name) == segment_len && DTTR_Path_AsciiIeqN(name, segment, segment_len);
53}
54
55static bool find_case_match(
56 const char *parent,
57 const char *segment,
58 size_t segment_len,
59 char *out_name,
60 size_t out_name_size
61) {
62 const size_t parent_len = strlen(parent);
63 const bool needs_separator = parent_len > 0
64 && !DTTR_Path_IsSeparator(parent[parent_len - 1]);
65 char pattern[DTTR_ISO_MAX_PATH];
66 const int written = snprintf(
67 pattern,
68 sizeof(pattern),
69 "%s%s*",
70 parent,
71 needs_separator ? "\\" : ""
72 );
73 if (written <= 0 || (size_t)written >= sizeof(pattern)) {
74 return false;
75 }
76
77 WIN32_FIND_DATAA data;
78 HANDLE find = FindFirstFileA(pattern, &data);
79 if (find == INVALID_HANDLE_VALUE) {
80 return false;
81 }
82
83 bool found = false;
84 do {
85 if (name_matches_segment(data.cFileName, segment, segment_len)) {
86 found = DTTR_Path_CopyString(out_name, out_name_size, data.cFileName);
87 break;
88 }
89 } while (FindNextFileA(find, &data));
90 FindClose(find);
91 return found;
92}
93
95 const char *path,
96 char *out_path,
97 size_t out_path_size
98) {
99 if (!path || !path[0] || !out_path || out_path_size == 0) {
100 return false;
101 }
102
103 const char *rest = NULL;
104 sds resolved = DTTR_Path_NativeRoot(path, &rest);
105 if (!resolved) {
106 return false;
107 }
108
109 rest = DTTR_Path_SkipSeparators(rest);
110
111 bool wrote_segment = false;
112 bool ok = true;
113 while (*rest) {
114 const char *segment = rest;
115 size_t segment_len = DTTR_Path_SegmentLen(segment);
116 if (DTTR_Path_IsRelativeSegment(segment, segment_len)) {
117 ok = false;
118 break;
119 }
120
121 char match[DTTR_ISO_MAX_PATH];
122 if (!find_case_match(resolved, segment, segment_len, match, sizeof(match))) {
123 ok = false;
124 break;
125 }
126
127 if (!DTTR_Path_AppendSegment(&resolved, match, DTTR_PATH_NATIVE_SEPARATOR)) {
128 ok = false;
129 break;
130 }
131
132 wrote_segment = true;
133
134 rest = DTTR_Path_SkipSeparators(rest + segment_len);
135 }
136
137 ok = ok && wrote_segment && DTTR_Path_ExactExists(resolved)
138 && DTTR_Path_CopySds(out_path, out_path_size, resolved);
139 sdsfree(resolved);
140
141 return ok;
142}
143
144const char *dttr_game_data_find_data_segment(const char *path) {
145 if (!path) {
146 return NULL;
147 }
148
149 for (const char *p = path; *p;) {
150 const size_t segment_len = DTTR_Path_SegmentLen(p);
151 if (segment_len == sizeof("data") - 1
152 && DTTR_Path_AsciiIeqN(p, "data", sizeof("data") - 1)) {
153 return p;
154 }
155
156 if (segment_len == sizeof("pcdogs.pkg") - 1
157 && DTTR_Path_AsciiIeqN(p, "pcdogs.pkg", sizeof("pcdogs.pkg") - 1)) {
158 return p;
159 }
160
161 p = DTTR_Path_SkipSeparators(p + segment_len);
162 }
163
164 return NULL;
165}
166
167static bool append_game_path(const char *relative, char *out, size_t out_size) {
168 if (!relative || !DTTR_Path_IsSafeRelative(relative)) {
169 return false;
170 }
171
172 relative = DTTR_Path_SkipSeparators(relative);
173 sds path = sdsnew(source.game_root);
174 if (!path || !DTTR_Path_AppendSegment(&path, relative, '/')) {
175 sdsfree(path);
176 return false;
177 }
178
179 const bool ok = DTTR_Path_CopySds(out, out_size, path);
180 sdsfree(path);
181 return ok;
182}
183
185 const char *path,
186 char *out_path,
187 size_t out_path_size
188) {
189 if (!source.is_iso || !path || !path[0] || !out_path || out_path_size == 0) {
190 return false;
191 }
192
193 const char *relative = path;
194 if (DTTR_Path_IsAnyAbsolute(path)) {
195 relative = dttr_game_data_find_data_segment(path);
196 if (!relative) {
197 return false;
198 }
199 }
200
201 char iso_path[DTTR_ISO_MAX_PATH];
202 if (!append_game_path(relative, iso_path, sizeof(iso_path))) {
203 return false;
204 }
205
206 return DTTR_ISO_CachePathForFile(source.cache_root, iso_path, out_path, out_path_size)
207 && DTTR_Path_ExactExists(out_path);
208}
209
210sds dttr_game_data_resolve_media_path(const char *relative) {
213 sds requested = sdsnew(base_path ? *base_path : NULL);
214 if (!requested || !DTTR_Path_AppendSegment(&requested, relative, '\\')) {
215 sdsfree(requested);
216 return sdsempty();
217 }
218
219 char resolved[MAX_PATH];
220 const char *out_path = NULL;
221
222 if (dttr_game_data_resolve_existing_read_path(requested, resolved, sizeof(resolved))) {
223 out_path = resolved;
224 }
225
226 char cached[MAX_PATH];
227 if (!out_path && dttr_game_data_resolve_read_path(relative, cached, sizeof(cached))) {
228 out_path = cached;
229 }
230
231 if (!out_path) {
232 return requested;
233 }
234
235 sds out = sdsnew(out_path);
236 sdsfree(requested);
237 return out;
238}
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void DTTR_Graphics_COM_DirectDrawSurface7 *self DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags DTTR_Graphics_COM_DirectDrawSurface7 void void * data
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
#define DTTR_ISO_MAX_PATH
Definition dttr_iso.h:7
bool DTTR_ISO_CachePathForFile(const char *cache_root, const char *iso_relative_path, char *out_path, size_t out_path_size)
Definition iso.c:96
bool DTTR_Path_AsciiIeqN(const char *lhs, const char *rhs, size_t n)
Definition path.c:58
sds DTTR_Path_NativeRoot(const char *path, const char **rest)
Definition path.c:247
bool DTTR_Path_IsSeparator(char ch)
Definition path.c:76
const char * DTTR_Path_SkipSeparators(const char *path)
Definition path.c:80
bool DTTR_Path_IsRelativeSegment(const char *segment, size_t segment_len)
Definition path.c:98
bool DTTR_Path_CopyString(char *out, size_t out_size, const char *value)
Definition path.c:68
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
Definition path.c:72
bool DTTR_Path_ExactExists(const char *path)
Definition path.c:187
#define DTTR_PATH_NATIVE_SEPARATOR
Definition dttr_path.h:9
bool DTTR_Path_IsAnyAbsolute(const char *path)
Definition path.c:179
bool DTTR_Path_AppendSegment(sds *path, const char *segment, char separator)
Definition path.c:276
size_t DTTR_Path_SegmentLen(const char *path)
Definition path.c:88
bool DTTR_Path_IsSafeRelative(const char *path)
Definition path.c:107
#define DTTR_PCDOGS_D_AUDIO_OPEN_STREAM_PKG_BASE_PATH_COUNT
DTTR_PCDOGS_API const struct DTTR_PCDOGS_D_Audio_OpenStream_PKGBasePath_type *const DTTR_PCDOGS_D_Audio_OpenStream_PKGBasePath
sds dttr_game_data_resolve_media_path(const char *relative)
Definition game_data.c:210
bool dttr_game_data_resolve_read_path(const char *path, char *out_path, size_t out_path_size)
Definition game_data.c:184
void dttr_game_data_cleanup()
Definition game_data.c:23
static bool append_game_path(const char *relative, char *out, size_t out_size)
Definition game_data.c:167
bool dttr_game_data_resolve_existing_read_path(const char *path, char *out_path, size_t out_path_size)
Definition game_data.c:94
static game_data_source source
Definition game_data.c:21
static bool find_case_match(const char *parent, const char *segment, size_t segment_len, char *out_name, size_t out_name_size)
Definition game_data.c:55
const char * dttr_game_data_find_data_segment(const char *path)
Definition game_data.c:144
void dttr_game_data_init()
Definition game_data.c:27
static bool name_matches_segment(const char *name, const char *segment, size_t segment_len)
Definition game_data.c:47
char game_root[DTTR_ISO_MAX_PATH]
Definition game_data.c:18
char cache_root[DTTR_ISO_MAX_PATH]
Definition game_data.c:17