/** * dump_to_file_desperate: * @data : pointer to data buffer. * @size : size of @data. * @type : type of file to be saved. * * Attempt to save valuable RAM data somewhere. **/ static bool dump_to_file_desperate(const void *data, size_t size, unsigned type) { time_t time_; char timebuf[256]; char path[PATH_MAX_LENGTH]; #if defined(_WIN32) && !defined(_XBOX) const char *base = getenv("APPDATA"); #elif defined(__CELLOS_LV2__) || defined(_XBOX) const char *base = NULL; #else const char *base = getenv("HOME"); #endif if (!base) return false; snprintf(path, sizeof(path), "%s/RetroArch-recovery-%u", base, type); time(&time_); strftime(timebuf, sizeof(timebuf), "%Y-%m-%d-%H-%M-%S", localtime(&time_)); strlcat(path, timebuf, sizeof(path)); if (!filestream_write_file(path, data, size)) return false; RARCH_WARN("Succeeded in saving RAM data to \"%s\".\n", path); return true; }
/** * save_ram_file: * @path : path of RAM state that shall be written to. * @type : type of memory * * Save a RAM state from memory to disk. * */ static bool save_ram_file(ram_type_t *ram) { retro_ctx_memory_info_t mem_info; mem_info.id = ram->type; core_ctl(CORE_CTL_RETRO_GET_MEMORY, &mem_info); if (!mem_info.data || mem_info.size == 0) return false; if (!filestream_write_file(ram->path, mem_info.data, mem_info.size)) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_SAVE_SRAM)); RARCH_WARN("Attempting to recover ...\n"); /* In case the file could not be written to, * the fallback function 'dump_to_file_desperate' * will be called. */ if (!dump_to_file_desperate(mem_info.data, mem_info.size, ram->type)) { RARCH_WARN("Failed ... Cannot recover save file.\n"); } return false; } RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_SAVED_SUCCESSFULLY_TO), ram->path); return true; }
/** * dump_to_file_desperate: * @data : pointer to data buffer. * @size : size of @data. * @type : type of file to be saved. * * Attempt to save valuable RAM data somewhere. **/ bool dump_to_file_desperate(const void *data, size_t size, unsigned type) { time_t time_; char timebuf[256]; char application_data[PATH_MAX_LENGTH]; char path[PATH_MAX_LENGTH]; if (!fill_pathname_application_data(application_data, sizeof(application_data))) return false; snprintf(path, sizeof(path), "%s/RetroArch-recovery-%u", application_data, type); time(&time_); strftime(timebuf, sizeof(timebuf), "%Y-%m-%d-%H-%M-%S", localtime(&time_)); strlcat(path, timebuf, sizeof(path)); if (!filestream_write_file(path, data, size)) return false; RARCH_WARN("Succeeded in saving RAM data to \"%s\".\n", path); return true; }
static int zip_file_decompressed( const char *name, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t crc32, struct archive_extract_userdata *userdata) { /* Ignore directories. */ if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\') return 1; if (strstr(name, userdata->decomp_state.needle)) { bool goto_error = false; file_archive_file_handle_t handle = {0}; userdata->decomp_state.found = true; if (zip_file_decompressed_handle(&handle, cdata, csize, size, crc32)) { if (userdata->decomp_state.opt_file != 0) { /* Called in case core has need_fullpath enabled. */ char *buf = (char*)malloc(size); if (buf) { memcpy(buf, handle.data, size); if (!filestream_write_file(userdata->decomp_state.opt_file, buf, size)) goto_error = true; } free(buf); userdata->decomp_state.size = 0; } else { /* Called in case core has need_fullpath disabled. * Will copy decompressed content directly into * RetroArch's ROM buffer. */ *userdata->decomp_state.buf = malloc(size); memcpy(*userdata->decomp_state.buf, handle.data, size); userdata->decomp_state.size = size; } } if (handle.data) free(handle.data); if (goto_error) return 0; } return 1; }
bool file_archive_perform_mode(const char *path, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t crc32, struct archive_extract_userdata *userdata) { switch (cmode) { case ARCHIVE_MODE_UNCOMPRESSED: if (!filestream_write_file(path, cdata, size)) goto error; break; case ARCHIVE_MODE_COMPRESSED: { int ret = 0; file_archive_file_handle_t handle; handle.stream = userdata->context; handle.data = NULL; handle.real_checksum = 0; handle.backend = file_archive_get_file_backend(userdata->archive_path); if (!handle.backend) goto error; if (!handle.backend->stream_decompress_data_to_file_init(&handle, cdata, csize, size)) goto error; do { ret = handle.backend->stream_decompress_data_to_file_iterate( handle.stream); }while(ret == 0); if (!file_archive_decompress_data_to_file(&handle, ret, path, valid_exts, cdata, csize, size, crc32)) goto error; } break; default: goto error; } return true; error: return false; }
/** * file_archive_decompress_data_to_file: * @path : filename path of archive. * @valid_exts : Valid extensions of archive to be parsed. * If NULL, allow all. * @cdata : input data. * @csize : size of input data. * @size : output file size * @checksum : CRC32 checksum from input data. * * Decompress data to file. * * Returns: true (1) on success, otherwise false (0). **/ static int file_archive_decompress_data_to_file( file_archive_file_handle_t *handle, int ret, const char *path, const char *valid_exts, const uint8_t *cdata, uint32_t csize, uint32_t size, uint32_t checksum) { if (!handle || ret == -1) { ret = 0; goto end; } #if 0 handle->real_checksum = handle->backend->stream_crc_calculate( 0, handle->data, size); if (handle->real_checksum != checksum) { /* File CRC difers from archive CRC. */ printf("File CRC differs from archive CRC. File: 0x%x, Archive: 0x%x.\n", (unsigned)handle->real_checksum, (unsigned)checksum); } #endif if (!filestream_write_file(path, handle->data, size)) { ret = false; goto end; } end: if (handle) { if (handle->backend) { if (handle->backend->stream_free) handle->backend->stream_free(handle->stream); } if (handle->data) free(handle->data); } return ret; }
/** * save_state: * @path : path of saved state that shall be written to. * * Save a state from memory to disk. * * Returns: true if successful, false otherwise. **/ static bool content_save_state(const char *path) { retro_ctx_serialize_info_t serial_info; retro_ctx_size_info_t info; bool ret = false; void *data = NULL; core_ctl(CORE_CTL_RETRO_SERIALIZE_SIZE, &info); RARCH_LOG("%s: \"%s\".\n", msg_hash_to_str(MSG_SAVING_STATE), path); if (info.size == 0) return false; data = malloc(info.size); if (!data) return false; RARCH_LOG("%s: %d %s.\n", msg_hash_to_str(MSG_STATE_SIZE), (int)info.size, msg_hash_to_str(MSG_BYTES)); serial_info.data = data; serial_info.size = info.size; ret = core_ctl(CORE_CTL_RETRO_SERIALIZE, &serial_info); if (ret) ret = filestream_write_file(path, data, info.size); else { RARCH_ERR("%s \"%s\".\n", msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), path); } free(data); return ret; }
bool file_archive_perform_mode(const char *path, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t crc32, void *userdata) { switch (cmode) { case ZLIB_MODE_UNCOMPRESSED: if (!filestream_write_file(path, cdata, size)) goto error; break; case ZLIB_MODE_DEFLATE: { int ret = 0; file_archive_file_handle_t handle = {0}; handle.backend = file_archive_get_default_file_backend(); if (!handle.backend->stream_decompress_data_to_file_init(&handle, cdata, csize, size)) goto error; do { ret = handle.backend->stream_decompress_data_to_file_iterate( handle.stream); } while(ret == 0); if (!file_archive_decompress_data_to_file(&handle, ret, path, valid_exts, cdata, csize, size, crc32)) goto error; } break; default: goto error; } return true; error: return false; }
static int content_zip_file_decompressed( const char *name, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t crc32, void *userdata) { struct decomp_state *st = (struct decomp_state*)userdata; /* Ignore directories. */ if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\') return 1; RARCH_LOG("[deflate] Path: %s, CRC32: 0x%x\n", name, crc32); if (strstr(name, st->needle)) { bool goto_error = false; file_archive_file_handle_t handle = {0}; st->found = true; if (content_zip_file_decompressed_handle(&handle, cdata, csize, size, crc32)) { if (st->opt_file != 0) { /* Called in case core has need_fullpath enabled. */ char *buf = (char*)malloc(size); if (buf) { RARCH_LOG("Extracting file : %s\n", st->opt_file); memcpy(buf, handle.data, size); if (!filestream_write_file(st->opt_file, buf, size)) goto_error = true; } free(buf); st->size = 0; } else { /* Called in case core has need_fullpath disabled. * Will copy decompressed content directly into * RetroArch's ROM buffer. */ *st->buf = malloc(size); memcpy(*st->buf, handle.data, size); st->size = size; } } if (handle.data) free(handle.data); if (goto_error) return 0; } return 1; }
/* Extract the relative path (needle) from a 7z archive * (path) and allocate a buf for it to write it in. * If optional_outfile is set, extract to that instead * and don't allocate buffer. */ static int content_7zip_file_read( const char *path, const char *needle, void **buf, const char *optional_outfile) { CFileInStream archiveStream; CLookToRead lookStream; CSzArEx db; ISzAlloc allocImp; ISzAlloc allocTempImp; uint8_t *output = 0; long outsize = -1; /*These are the allocation routines. * Currently using the non-standard 7zip choices. */ allocImp.Alloc = SzAlloc; allocImp.Free = SzFree; allocTempImp.Alloc = SzAllocTemp; allocTempImp.Free = SzFreeTemp; if (InFile_Open(&archiveStream.file, path)) { RARCH_ERR("Could not open %s as 7z archive\n.", path); return -1; } FileInStream_CreateVTable(&archiveStream); LookToRead_CreateVTable(&lookStream, False); lookStream.realStream = &archiveStream.s; LookToRead_Init(&lookStream); CrcGenerateTable(); SzArEx_Init(&db); if (SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) == SZ_OK) { uint32_t i; bool file_found = false; uint16_t *temp = NULL; size_t temp_size = 0; uint32_t block_index = 0xFFFFFFFF; SRes res = SZ_OK; for (i = 0; i < db.db.NumFiles; i++) { size_t len; char infile[PATH_MAX_LENGTH]; size_t offset = 0; size_t outSizeProcessed = 0; const CSzFileItem *f = db.db.Files + i; /* We skip over everything which is not a directory. * FIXME: Why continue then if f->IsDir is true?*/ if (f->IsDir) continue; len = SzArEx_GetFileNameUtf16(&db, i, NULL); if (len > temp_size) { free(temp); temp_size = len; temp = (uint16_t *)malloc(temp_size * sizeof(temp[0])); if (temp == 0) { res = SZ_ERROR_MEM; break; } } SzArEx_GetFileNameUtf16(&db, i, temp); res = utf16_to_char_string(temp, infile, sizeof(infile)) ? SZ_OK : SZ_ERROR_FAIL; if (string_is_equal(infile, needle)) { size_t output_size = 0; RARCH_LOG_OUTPUT("Opened archive %s. Now trying to extract %s\n", path, needle); /* C LZMA SDK does not support chunked extraction - see here: * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/ * */ file_found = true; res = SzArEx_Extract(&db, &lookStream.s, i, &block_index, &output, &output_size, &offset, &outSizeProcessed, &allocImp, &allocTempImp); if (res != SZ_OK) break; /* This goes to the error section. */ outsize = outSizeProcessed; if (optional_outfile != NULL) { const void *ptr = (const void*)(output + offset); if (!filestream_write_file(optional_outfile, ptr, outsize)) { RARCH_ERR("Could not open outfilepath %s.\n", optional_outfile); res = SZ_OK; file_found = true; outsize = -1; } } else { /*We could either use the 7Zip allocated buffer, * or create our own and use it. * We would however need to realloc anyways, because RetroArch * expects a \0 at the end, therefore we allocate new, * copy and free the old one. */ *buf = malloc(outsize + 1); ((char*)(*buf))[outsize] = '\0'; memcpy(*buf,output + offset,outsize); } break; } } free(temp); IAlloc_Free(&allocImp, output); if (!(file_found && res == SZ_OK)) { /* Error handling */ if (!file_found) RARCH_ERR("File %s not found in %s\n", needle, path); RARCH_ERR("Failed to open compressed file inside 7zip archive.\n"); outsize = -1; } } SzArEx_Free(&db, &allocImp); File_Close(&archiveStream.file); return outsize; }