dep/rcheevos: Bump to v11.5.0 + local changes
https://github.com/stenzek/rcheevos
This commit is contained in:
@@ -700,6 +700,12 @@ struct rc_hash_zip_idx
|
||||
uint8_t* data;
|
||||
};
|
||||
|
||||
struct rc_hash_ms_dos_dosz_state
|
||||
{
|
||||
const char* path;
|
||||
const struct rc_hash_ms_dos_dosz_state* child;
|
||||
};
|
||||
|
||||
static int rc_hash_zip_idx_sort(const void* a, const void* b)
|
||||
{
|
||||
struct rc_hash_zip_idx *A = (struct rc_hash_zip_idx*)a, *B = (struct rc_hash_zip_idx*)b;
|
||||
@@ -707,9 +713,12 @@ static int rc_hash_zip_idx_sort(const void* a, const void* b)
|
||||
return memcmp(A->data, B->data, len);
|
||||
}
|
||||
|
||||
static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
static int rc_hash_ms_dos_parent(md5_state_t* md5, const struct rc_hash_ms_dos_dosz_state *child, const char* parentname, uint32_t parentname_len);
|
||||
static int rc_hash_ms_dos_dosc(md5_state_t* md5, const struct rc_hash_ms_dos_dosz_state *dosz);
|
||||
|
||||
static int rc_hash_zip_file(md5_state_t* md5, void* file_handle, const struct rc_hash_ms_dos_dosz_state* dosz)
|
||||
{
|
||||
uint8_t buf[2048], *alloc_buf, *cdir_start, *cdir_max, *cdir, *hashdata, eocdirhdr_size, cdirhdr_size;
|
||||
uint8_t buf[2048], *alloc_buf, *cdir_start, *cdir_max, *cdir, *hashdata, eocdirhdr_size, cdirhdr_size, nparents;
|
||||
uint32_t cdir_entry_len;
|
||||
size_t sizeof_idx, indices_offset, alloc_size;
|
||||
int64_t i_file, archive_size, ecdh_ofs, total_files, cdir_size, cdir_ofs;
|
||||
@@ -773,7 +782,7 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
rc_file_seek(file_handle, ecdh_ofs - 20, SEEK_SET);
|
||||
if (rc_file_read(file_handle, buf, 20) == 20 && RC_ZIP_READ_LE32(buf) == 0x07064b50) /* locator signature */
|
||||
{
|
||||
/* Found the locator, now read the actual ZIP64 end of central directory header */
|
||||
/* Found the locator, now read the actual ZIP64 end of central directory header */
|
||||
int64_t ecdh64_ofs = (int64_t)RC_ZIP_READ_LE64(buf + 0x08);
|
||||
if (ecdh64_ofs <= (archive_size - 56))
|
||||
{
|
||||
@@ -821,7 +830,7 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
hashindex = hashindices;
|
||||
|
||||
/* Now process the central directory file records */
|
||||
for (i_file = 0, cdir = cdir_start; i_file < total_files && cdir >= cdir_start && cdir <= cdir_max; i_file++, cdir += cdir_entry_len)
|
||||
for (i_file = nparents = 0, cdir = cdir_start; i_file < total_files && cdir >= cdir_start && cdir <= cdir_max; i_file++, cdir += cdir_entry_len)
|
||||
{
|
||||
const uint8_t *name, *name_end;
|
||||
uint32_t signature = RC_ZIP_READ_LE32(cdir + 0x00);
|
||||
@@ -891,6 +900,27 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
return rc_hash_error("Encountered invalid entry in ZIP central directory");
|
||||
}
|
||||
|
||||
/* A DOSZ file can contain a special empty <base>.dosz.parent file in its root which means a parent dosz file is used */
|
||||
if (dosz && decomp_size == 0 && filename_len > 7 && !strncasecmp((const char*)name + filename_len - 7, ".parent", 7) && !memchr(name, '/', filename_len) && !memchr(name, '\\', filename_len))
|
||||
{
|
||||
/* A DOSZ file can only have one parent file */
|
||||
if (nparents++)
|
||||
{
|
||||
free(alloc_buf);
|
||||
return rc_hash_error("Invalid DOSZ file with multiple parents");
|
||||
}
|
||||
|
||||
/* If there is an error with the parent DOSZ, abort now */
|
||||
if (!rc_hash_ms_dos_parent(md5, dosz, (const char*)name, (filename_len - 7)))
|
||||
{
|
||||
free(alloc_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We don't hash this meta file so a user is free to rename it and the parent file */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Write the pointer and length of the data we record about this file */
|
||||
hashindex->data = hashdata;
|
||||
hashindex->length = filename_len + 1 + 4 + 8;
|
||||
@@ -935,6 +965,11 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
md5_append(md5, hashindices->data, (int)hashindices->length);
|
||||
|
||||
free(alloc_buf);
|
||||
|
||||
/* If this is a .dosz file, check if an associated .dosc file exists */
|
||||
if (dosz && !rc_hash_ms_dos_dosc(md5, dosz))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
#undef RC_ZIP_READ_LE16
|
||||
@@ -944,10 +979,86 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
#undef RC_ZIP_WRITE_LE64
|
||||
}
|
||||
|
||||
static int rc_hash_ms_dos_parent(md5_state_t* md5, const struct rc_hash_ms_dos_dosz_state *child, const char* parentname, uint32_t parentname_len)
|
||||
{
|
||||
const char *lastfslash = strrchr(child->path, '/');
|
||||
const char *lastbslash = strrchr(child->path, '\\');
|
||||
const char *lastslash = (lastbslash > lastfslash ? lastbslash : lastfslash);
|
||||
size_t dir_len = (lastslash ? (lastslash + 1 - child->path) : 0);
|
||||
char* parent_path = (char*)malloc(dir_len + parentname_len + 1);
|
||||
struct rc_hash_ms_dos_dosz_state parent;
|
||||
const struct rc_hash_ms_dos_dosz_state *check;
|
||||
void* parent_handle;
|
||||
int parent_res;
|
||||
|
||||
/* Build the path of the parent by combining the directory of the current file with the name */
|
||||
if (!parent_path)
|
||||
return rc_hash_error("Could not allocate temporary buffer");
|
||||
|
||||
memcpy(parent_path, child->path, dir_len);
|
||||
memcpy(parent_path + dir_len, parentname, parentname_len);
|
||||
parent_path[dir_len + parentname_len] = '\0';
|
||||
|
||||
/* Make sure there is no recursion where a parent DOSZ is an already seen child DOSZ */
|
||||
for (check = child->child; check; check = check->child)
|
||||
{
|
||||
if (!strcmp(check->path, parent_path))
|
||||
{
|
||||
free(parent_path);
|
||||
return rc_hash_error("Invalid DOSZ file with recursive parents");
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to open the parent DOSZ file */
|
||||
parent_handle = rc_file_open(parent_path);
|
||||
if (!parent_handle)
|
||||
{
|
||||
char message[1024];
|
||||
snprintf(message, sizeof(message), "DOSZ parent file '%s' does not exist", parent_path);
|
||||
free(parent_path);
|
||||
return rc_hash_error(message);
|
||||
}
|
||||
|
||||
/* Fully hash the parent DOSZ ahead of the child */
|
||||
parent.path = parent_path;
|
||||
parent.child = child;
|
||||
parent_res = rc_hash_zip_file(md5, parent_handle, &parent);
|
||||
rc_file_close(parent_handle);
|
||||
free(parent_path);
|
||||
return parent_res;
|
||||
}
|
||||
|
||||
static int rc_hash_ms_dos_dosc(md5_state_t* md5, const struct rc_hash_ms_dos_dosz_state *dosz)
|
||||
{
|
||||
size_t path_len = strlen(dosz->path);
|
||||
if (dosz->path[path_len-1] == 'z' || dosz->path[path_len-1] == 'Z')
|
||||
{
|
||||
void* file_handle;
|
||||
char *dosc_path = strdup(dosz->path);
|
||||
if (!dosc_path)
|
||||
return rc_hash_error("Could not allocate temporary buffer");
|
||||
|
||||
/* Swap the z to c and use the same capitalization, hash the file if it exists */
|
||||
dosc_path[path_len-1] = (dosz->path[path_len-1] == 'z' ? 'c' : 'C');
|
||||
file_handle = rc_file_open(dosc_path);
|
||||
free(dosc_path);
|
||||
|
||||
if (file_handle)
|
||||
{
|
||||
/* Hash the DOSC as a plain zip file (pass NULL as dosz state) */
|
||||
int res = rc_hash_zip_file(md5, file_handle, NULL);
|
||||
rc_file_close(file_handle);
|
||||
if (!res)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rc_hash_ms_dos(char hash[33], const char* path)
|
||||
{
|
||||
struct rc_hash_ms_dos_dosz_state dosz;
|
||||
md5_state_t md5;
|
||||
size_t path_len;
|
||||
int res;
|
||||
|
||||
void* file_handle = rc_file_open(path);
|
||||
@@ -956,34 +1067,14 @@ static int rc_hash_ms_dos(char hash[33], const char* path)
|
||||
|
||||
/* hash the main content zip file first */
|
||||
md5_init(&md5);
|
||||
res = rc_hash_zip_file(&md5, file_handle);
|
||||
dosz.path = path;
|
||||
dosz.child = NULL;
|
||||
res = rc_hash_zip_file(&md5, file_handle, &dosz);
|
||||
rc_file_close(file_handle);
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
/* if this is a .dosz file, check if an associated .dosc file exists */
|
||||
path_len = strlen(path);
|
||||
if (path[path_len-1] == 'z' || path[path_len-1] == 'Z')
|
||||
{
|
||||
char *dosc_path = strdup(path);
|
||||
if (!dosc_path)
|
||||
return rc_hash_error("Could not allocate temporary buffer");
|
||||
|
||||
/* swap the z to c and use the same capitalization, hash the file if it exists*/
|
||||
dosc_path[path_len-1] = (path[path_len-1] == 'z' ? 'c' : 'C');
|
||||
file_handle = rc_file_open(dosc_path);
|
||||
free((void*)dosc_path);
|
||||
if (file_handle)
|
||||
{
|
||||
res = rc_hash_zip_file(&md5, file_handle);
|
||||
rc_file_close(file_handle);
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc_hash_finalize(&md5, hash);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user