static int file_archive_parse_file_init(file_archive_transfer_t *state, const char *file) { state->backend = file_archive_get_default_file_backend(); if (!state->backend) return -1; state->handle = file_archive_open(file); if (!state->handle) return -1; state->zip_size = file_archive_size(state->handle); if (state->zip_size < 22) return -1; state->data = file_archive_data(state->handle); state->footer = state->data + state->zip_size - 22; for (;; state->footer--) { if (state->footer <= state->data + 22) return -1; if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE) { unsigned comment_len = read_le(state->footer + 20, 2); if (state->footer + 22 + comment_len == state->data + state->zip_size) break; } } state->directory = state->data + read_le(state->footer + 16, 4); return 0; }
static int zip_parse_file_init(file_archive_transfer_t *state, const char *file) { if (state->archive_size < 22) return -1; state->footer = state->data + state->archive_size - 22; for (;; state->footer--) { if (state->footer <= state->data + 22) return -1; if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE) { unsigned comment_len = read_le(state->footer + 20, 2); if (state->footer + 22 + comment_len == state->data + state->archive_size) break; } } state->directory = state->data + read_le(state->footer + 16, 4); return 0; }
static int zip_parse_file_iterate_step_internal( file_archive_transfer_t *state, char *filename, const uint8_t **cdata, unsigned *cmode, uint32_t *size, uint32_t *csize, uint32_t *checksum, unsigned *payback) { uint32_t offset; uint32_t namelength, extralength, commentlength, offsetNL, offsetEL; uint32_t signature = read_le(state->directory + 0, 4); if (signature != CENTRAL_FILE_HEADER_SIGNATURE) return 0; *cmode = read_le(state->directory + 10, 2); /* compression mode, 0 = store, 8 = deflate */ *checksum = read_le(state->directory + 16, 4); /* CRC32 */ *csize = read_le(state->directory + 20, 4); /* compressed size */ *size = read_le(state->directory + 24, 4); /* uncompressed size */ namelength = read_le(state->directory + 28, 2); /* file name length */ extralength = read_le(state->directory + 30, 2); /* extra field length */ commentlength = read_le(state->directory + 32, 2); /* file comment length */ if (namelength >= PATH_MAX_LENGTH) return -1; memcpy(filename, state->directory + 46, namelength); /* file name */ offset = read_le(state->directory + 42, 4); /* relative offset of local file header */ offsetNL = read_le(state->data + offset + 26, 2); /* file name length */ offsetEL = read_le(state->data + offset + 28, 2); /* extra field length */ *cdata = state->data + offset + 30 + offsetNL + offsetEL; *payback = 46 + namelength + extralength + commentlength; return 1; }
static int file_archive_parse_file_iterate_step_internal( file_archive_transfer_t *state, char *filename, const uint8_t **cdata, unsigned *cmode, uint32_t *size, uint32_t *csize, uint32_t *checksum, unsigned *payback) { uint32_t offset; uint32_t namelength, extralength, commentlength, offsetNL, offsetEL; uint32_t signature = read_le(state->directory + 0, 4); if (signature != CENTRAL_FILE_HEADER_SIGNATURE) return 0; *cmode = read_le(state->directory + 10, 2); *checksum = read_le(state->directory + 16, 4); *csize = read_le(state->directory + 20, 4); *size = read_le(state->directory + 24, 4); namelength = read_le(state->directory + 28, 2); extralength = read_le(state->directory + 30, 2); commentlength = read_le(state->directory + 32, 2); if (namelength >= PATH_MAX_LENGTH) return -1; memcpy(filename, state->directory + 46, namelength); offset = read_le(state->directory + 42, 4); offsetNL = read_le(state->data + offset + 26, 2); offsetEL = read_le(state->data + offset + 28, 2); *cdata = state->data + offset + 30 + offsetNL + offsetEL; *payback = 46 + namelength + extralength + commentlength; return 1; }
bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata) { const uint8_t *footer = NULL; const uint8_t *directory = NULL; bool ret = true; const uint8_t *data = NULL; const struct zlib_file_backend *backend = zlib_get_default_file_backend(); if (!backend) return NULL; ssize_t zip_size = 0; void *handle = backend->open(file); if (!handle) GOTO_END_ERROR(); zip_size = backend->size(handle); if (zip_size < 22) GOTO_END_ERROR(); data = backend->data(handle); footer = data + zip_size - 22; for (;; footer--) { if (footer <= data + 22) GOTO_END_ERROR(); if (read_le(footer, 4) == 0x06054b50) { unsigned comment_len = read_le(footer + 20, 2); if (footer + 22 + comment_len == data + zip_size) break; } } directory = data + read_le(footer + 16, 4); for (;;) { uint32_t signature = read_le(directory + 0, 4); if (signature != 0x02014b50) break; unsigned cmode = read_le(directory + 10, 2); uint32_t crc32 = read_le(directory + 16, 4); uint32_t csize = read_le(directory + 20, 4); uint32_t size = read_le(directory + 24, 4); unsigned namelength = read_le(directory + 28, 2); unsigned extralength = read_le(directory + 30, 2); unsigned commentlength = read_le(directory + 32, 2); char filename[PATH_MAX] = {0}; if (namelength >= PATH_MAX) GOTO_END_ERROR(); memcpy(filename, directory + 46, namelength); uint32_t offset = read_le(directory + 42, 4); unsigned offsetNL = read_le(data + offset + 26, 2); unsigned offsetEL = read_le(data + offset + 28, 2); const uint8_t *cdata = data + offset + 30 + offsetNL + offsetEL; //RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + offsetNL + offsetEL, csize, size); if (!file_cb(filename, cdata, cmode, csize, size, crc32, userdata)) break; directory += 46 + namelength + extralength + commentlength; } end: if (handle) backend->free(handle); return ret; }