15 (CreateDirectoryA((path), NULL) || GetLastError() == ERROR_ALREADY_EXISTS)
25 message =
"unknown error";
34 const char *err = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
37 err =
"unknown PhysicsFS error";
49 if (!suffix || suffix[0] !=
';' || !suffix[1]) {
53 for (
const char *ch = suffix + 1; *ch; ch++) {
54 if (*ch <
'0' || *ch >
'9') {
64 for (
size_t i = segment_len; i > 1; i--) {
76 sdsrange(path, 0, -2);
84 for (
size_t i = 0; i < segment_len; i++) {
97 const char *cache_root,
98 const char *iso_relative_path,
102 if (!cache_root || !cache_root[0] || !iso_relative_path || !iso_relative_path[0]
103 || !out_path || out_path_size == 0) {
107 sds path = sdsnew(cache_root);
117 bool wrote_segment =
false;
121 const char *segment = p;
135 wrote_segment =
true;
161 if (!PHYSFS_init(
"dttr")) {
186 if (!iso || !iso_path || !iso_path[0] || strlen(iso_path) >=
sizeof(iso->
iso_path)) {
191 memset(iso, 0,
sizeof(*iso));
197 if (!PHYSFS_mount(iso_path,
NULL, 1)) {
215 const size_t name_len = strlen(name);
216 return (name_len == segment_len
229 char **entries = PHYSFS_enumerateFiles(parent && parent[0] ? parent :
"");
237 for (
char **entry = entries; *entry; entry++) {
250 PHYSFS_freeList(entries);
256 const char *requested,
260 if (!requested || !requested[0] || !out_path || out_path_size == 0) {
264 sds path = sdsempty();
272 bool wrote_segment =
false;
276 const char *segment = p;
286 if (!
find_case_match(path, segment, segment_len, match,
sizeof(match))) {
296 wrote_segment =
true;
311 const size_t len = strlen(path);
313 if (len >=
sizeof(tmp)) {
317 memcpy(tmp, path, len + 1);
319 for (
size_t i = 1; tmp[i]; i++) {
324 if (i == 2 && tmp[1] ==
':') {
344 PHYSFS_File *physfs_file,
347 FILE *file = fopen(path,
"rb");
353 bool matches =
false;
354 if (fseek(file, 0, SEEK_END) != 0) {
358 const long existing = ftell(file);
359 if (existing < 0 || (
size_t)existing !=
size || fseek(file, 0, SEEK_SET) != 0) {
363 if (!PHYSFS_seek(physfs_file, 0)) {
369 size_t remaining =
size;
371 while (remaining > 0) {
372 const size_t chunk = remaining <
sizeof(disk_buffer) ? remaining
373 :
sizeof(disk_buffer);
374 if (fread(disk_buffer, 1, chunk, file) != chunk
375 || PHYSFS_readBytes(physfs_file, iso_buffer, chunk) != (PHYSFS_sint64)chunk
376 || memcmp(disk_buffer, iso_buffer, chunk) != 0) {
386 if (!PHYSFS_seek(physfs_file, 0)) {
396 sds child = sdsnew(parent);
413 const char *iso_relative_path,
414 const char *cache_root,
418 if (!iso || !iso->
open) {
440 PHYSFS_File *in = PHYSFS_openRead(physfs_path);
447 const PHYSFS_sint64 length = PHYSFS_fileLength(in);
455 if ((uint64_t)length > (uint64_t)SIZE_MAX) {
456 set_error(
"ISO file is too large to cache");
466 if (!PHYSFS_seek(in, 0)) {
473 set_error(
"could not create cache directories");
478 FILE *out = fopen(out_path,
"wb");
481 set_error(
"could not open cache output file");
487 PHYSFS_sint64 remaining = length;
489 while (remaining > 0) {
490 const PHYSFS_uint64 chunk = remaining < (PHYSFS_sint64)
sizeof(buffer)
491 ? (PHYSFS_uint64)remaining
492 : (PHYSFS_uint64)
sizeof(buffer);
493 const PHYSFS_sint64 got = PHYSFS_readBytes(in, buffer, chunk);
495 if (got != (PHYSFS_sint64)chunk
496 || fwrite(buffer, 1, (
size_t)chunk, out) != chunk) {
506 const bool output_closed = fclose(out) == 0;
507 const bool input_closed = PHYSFS_close(in) != 0;
508 if (!output_closed || !input_closed) {
509 set_error(
"could not finish ISO extraction");
519 const char *physfs_path,
520 const char *cache_root
522 char **entries = PHYSFS_enumerateFiles(physfs_path);
531 for (
char **entry = entries; ok && *entry; entry++) {
535 set_error(
"could not build ISO tree path");
542 if (!PHYSFS_stat(child, &stat)) {
545 }
else if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
547 }
else if (stat.filetype == PHYSFS_FILETYPE_REGULAR) {
555 PHYSFS_freeList(entries);
562 const char *iso_relative_path,
563 const char *cache_root
565 if (!iso || !iso->
open) {
579 if (!PHYSFS_stat(physfs_path, &stat)) {
584 if (stat.filetype != PHYSFS_FILETYPE_DIRECTORY) {
585 set_error(
"ISO path is not a directory");
594 if (!iso || !iso->
open) {
600 memset(iso, 0,
sizeof(*iso));
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
#define DTTR_ISO_MAX_PATH
bool DTTR_Path_AsciiIeqN(const char *lhs, const char *rhs, size_t n)
bool DTTR_Path_IsSeparator(char ch)
const char * DTTR_Path_SkipSeparators(const char *path)
bool DTTR_Path_IsRelativeSegment(const char *segment, size_t segment_len)
bool DTTR_Path_CopyString(char *out, size_t out_size, const char *value)
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
bool DTTR_Path_AppendChar(sds *path, char ch)
bool DTTR_Path_AppendSeparator(sds *path, char separator)
bool DTTR_Path_AppendSegment(sds *path, const char *segment, char separator)
char DTTR_Path_AsciiLower(char ch)
size_t DTTR_Path_SegmentLen(const char *path)
static bool physfs_init()
static size_t strip_iso_version_suffix_len(const char *segment, size_t segment_len)
static void set_error(const char *message)
static void trim_trailing_separators(sds path)
bool DTTR_ISO_CachePathForFile(const char *cache_root, const char *iso_relative_path, char *out_path, size_t out_path_size)
static bool is_iso_version_suffix(const char *suffix)
static bool extract_tree_path(DTTR_IsoImage *iso, const char *physfs_path, const char *cache_root)
static bool resolve_iso_path_case(const char *requested, char *out_path, size_t out_path_size)
bool DTTR_ISO_ExtractFile(DTTR_IsoImage *iso, const char *iso_relative_path, const char *cache_root, char *out_path, size_t out_path_size)
void DTTR_ISO_Close(DTTR_IsoImage *iso)
static sds child_iso_path(const char *parent, const char *entry)
static void physfs_deinit()
static bool sdscat_lower_segment(sds *out, const char *segment, size_t segment_len)
bool DTTR_ISO_Open(DTTR_IsoImage *iso, const char *iso_path)
static int physfs_refcount
static bool file_matches_physfs_file(const char *path, PHYSFS_File *physfs_file, size_t size)
static bool find_case_match(const char *parent, const char *segment, size_t segment_len, char *out_name, size_t out_name_size)
bool DTTR_ISO_ExtractTree(DTTR_IsoImage *iso, const char *iso_relative_path, const char *cache_root)
static bool name_matches_segment(const char *name, const char *segment, size_t segment_len)
static void set_physfs_error(const char *context)
const char * DTTR_ISO_LastError()
static bool create_parent_dirs(const char *path)
static char last_error[256]
char iso_path[DTTR_ISO_MAX_PATH]