summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/fileio.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/emu/fileio.cpp
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/emu/fileio.cpp')
-rw-r--r--src/emu/fileio.cpp910
1 files changed, 910 insertions, 0 deletions
diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp
new file mode 100644
index 00000000000..68efdb021a3
--- /dev/null
+++ b/src/emu/fileio.cpp
@@ -0,0 +1,910 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ fileio.c
+
+ File access functions.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "unzip.h"
+#include "un7z.h"
+#include "fileio.h"
+
+
+const UINT32 OPEN_FLAG_HAS_CRC = 0x10000;
+
+
+
+//**************************************************************************
+// PATH ITERATOR
+//**************************************************************************
+
+//-------------------------------------------------
+// path_iterator - constructor
+//-------------------------------------------------
+
+path_iterator::path_iterator(const char *rawsearchpath)
+ : m_base(rawsearchpath),
+ m_current(m_base),
+ m_index(0)
+{
+}
+
+
+//-------------------------------------------------
+// path_iterator_get_next - get the next entry
+// in a multipath sequence
+//-------------------------------------------------
+
+bool path_iterator::next(std::string &buffer, const char *name)
+{
+ // if none left, return FALSE to indicate we are done
+ if (m_index != 0 && *m_current == 0)
+ return false;
+
+ // copy up to the next semicolon
+ const char *semi = strchr(m_current, ';');
+ if (semi == NULL)
+ semi = m_current + strlen(m_current);
+ buffer.assign(m_current, semi - m_current);
+ m_current = (*semi == 0) ? semi : semi + 1;
+
+ // append the name if we have one
+ if (name != NULL)
+ {
+ // compute the full pathname
+ if (buffer.length() > 0)
+ buffer.append(PATH_SEPARATOR);
+ buffer.append(name);
+ }
+
+ // bump the index and return TRUE
+ m_index++;
+ return true;
+}
+
+
+
+//**************************************************************************
+// FILE ENUMERATOR
+//**************************************************************************
+
+//-------------------------------------------------
+// file_enumerator - constructor
+//-------------------------------------------------
+
+file_enumerator::file_enumerator(const char *searchpath)
+ : m_iterator(searchpath),
+ m_curdir(NULL)/*,
+ m_buflen(0)*/
+{
+}
+
+
+//-------------------------------------------------
+// ~file_enumerator - destructor
+//-------------------------------------------------
+
+file_enumerator::~file_enumerator()
+{
+ // close anything open
+ if (m_curdir != NULL)
+ osd_closedir(m_curdir);
+}
+
+
+//-------------------------------------------------
+// next - return information about the next file
+// in the search path
+//-------------------------------------------------
+
+const osd_directory_entry *file_enumerator::next()
+{
+ // loop over potentially empty directories
+ while (1)
+ {
+ // if no open directory, get the next path
+ while (m_curdir == NULL)
+ {
+ // if we fail to get anything more, we're done
+ if (!m_iterator.next(m_pathbuffer))
+ return NULL;
+
+ // open the path
+ m_curdir = osd_opendir(m_pathbuffer.c_str());
+ }
+
+ // get the next entry from the current directory
+ const osd_directory_entry *result = osd_readdir(m_curdir);
+ if (result != NULL)
+ return result;
+
+ // we're done; close this directory
+ osd_closedir(m_curdir);
+ m_curdir = NULL;
+ }
+}
+
+
+
+//**************************************************************************
+// EMU FILE
+//**************************************************************************
+
+//-------------------------------------------------
+// emu_file - constructor
+//-------------------------------------------------
+
+emu_file::emu_file(UINT32 openflags)
+ : m_file(NULL),
+ m_iterator(""),
+ m_mediapaths(""),
+ m_crc(0),
+ m_openflags(openflags),
+ m_zipfile(NULL),
+ m_ziplength(0),
+ m__7zfile(NULL),
+ m__7zlength(0),
+ m_remove_on_close(false),
+ m_restrict_to_mediapath(false)
+{
+ // sanity check the open flags
+ if ((m_openflags & OPEN_FLAG_HAS_CRC) && (m_openflags & OPEN_FLAG_WRITE))
+ throw emu_fatalerror("Attempted to open a file for write with OPEN_FLAG_HAS_CRC");
+}
+
+emu_file::emu_file(const char *searchpath, UINT32 openflags)
+ : m_file(NULL),
+ m_iterator(searchpath),
+ m_mediapaths(searchpath),
+ m_crc(0),
+ m_openflags(openflags),
+ m_zipfile(NULL),
+ m_ziplength(0),
+ m__7zfile(NULL),
+ m__7zlength(0),
+ m_remove_on_close(false),
+ m_restrict_to_mediapath(false)
+{
+ // sanity check the open flags
+ if ((m_openflags & OPEN_FLAG_HAS_CRC) && (m_openflags & OPEN_FLAG_WRITE))
+ throw emu_fatalerror("Attempted to open a file for write with OPEN_FLAG_HAS_CRC");
+}
+
+
+//-------------------------------------------------
+// ~emu_file - destructor
+//-------------------------------------------------
+
+emu_file::~emu_file()
+{
+ // close in the standard way
+ close();
+}
+
+
+//-------------------------------------------------
+// operator core_file - automatically convert
+// ourselves to a core_file pointer
+//-------------------------------------------------
+
+emu_file::operator core_file *()
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return NULL;
+
+ // return the core file
+ return m_file;
+}
+
+emu_file::operator core_file &()
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ throw emu_fatalerror("operator core_file & used on invalid file");
+
+ // return the core file
+ return *m_file;
+}
+
+
+//-------------------------------------------------
+// hash - returns the hash for a file
+//-------------------------------------------------
+
+hash_collection &emu_file::hashes(const char *types)
+{
+ // determine the hashes we already have
+ std::string already_have;
+ m_hashes.hash_types(already_have);
+
+ // determine which hashes we need
+ std::string needed;
+ for (const char *scan = types; *scan != 0; scan++)
+ if (already_have.find_first_of(*scan) == -1)
+ needed.push_back(*scan);
+
+ // if we need nothing, skip it
+ if (needed.empty())
+ return m_hashes;
+
+ // load the ZIP file if needed
+ if (compressed_file_ready())
+ return m_hashes;
+ if (m_file == NULL)
+ return m_hashes;
+
+ // if we have ZIP data, just hash that directly
+ if (!m__7zdata.empty())
+ {
+ m_hashes.compute(&m__7zdata[0], m__7zdata.size(), needed.c_str());
+ return m_hashes;
+ }
+
+ if (!m_zipdata.empty())
+ {
+ m_hashes.compute(&m_zipdata[0], m_zipdata.size(), needed.c_str());
+ return m_hashes;
+ }
+
+ // read the data if we can
+ const UINT8 *filedata = (const UINT8 *)core_fbuffer(m_file);
+ if (filedata == NULL)
+ return m_hashes;
+
+ // compute the hash
+ m_hashes.compute(filedata, core_fsize(m_file), needed.c_str());
+ return m_hashes;
+}
+
+
+//-------------------------------------------------
+// open - open a file by searching paths
+//-------------------------------------------------
+
+file_error emu_file::open(const char *name)
+{
+ // remember the filename and CRC info
+ m_filename = name;
+ m_crc = 0;
+ m_openflags &= ~OPEN_FLAG_HAS_CRC;
+
+ // reset the iterator and open_next
+ m_iterator.reset();
+ return open_next();
+}
+
+file_error emu_file::open(const char *name1, const char *name2)
+{
+ // concatenate the strings and do a standard open
+ std::string name = std::string(name1).append(name2);
+ return open(name.c_str());
+}
+
+file_error emu_file::open(const char *name1, const char *name2, const char *name3)
+{
+ // concatenate the strings and do a standard open
+ std::string name = std::string(name1).append(name2).append(name3);
+ return open(name.c_str());
+}
+
+file_error emu_file::open(const char *name1, const char *name2, const char *name3, const char *name4)
+{
+ // concatenate the strings and do a standard open
+ std::string name = std::string(name1).append(name2).append(name3).append(name4);
+ return open(name.c_str());
+}
+
+file_error emu_file::open(const char *name, UINT32 crc)
+{
+ // remember the filename and CRC info
+ m_filename = name;
+ m_crc = crc;
+ m_openflags |= OPEN_FLAG_HAS_CRC;
+
+ // reset the iterator and open_next
+ m_iterator.reset();
+ return open_next();
+}
+
+file_error emu_file::open(const char *name1, const char *name2, UINT32 crc)
+{
+ // concatenate the strings and do a standard open
+ std::string name = std::string(name1).append(name2);
+ return open(name.c_str(), crc);
+}
+
+file_error emu_file::open(const char *name1, const char *name2, const char *name3, UINT32 crc)
+{
+ // concatenate the strings and do a standard open
+ std::string name = std::string(name1).append(name2).append(name3);
+ return open(name.c_str(), crc);
+}
+
+file_error emu_file::open(const char *name1, const char *name2, const char *name3, const char *name4, UINT32 crc)
+{
+ // concatenate the strings and do a standard open
+ std::string name = std::string(name1).append(name2).append(name3).append(name4);
+ return open(name.c_str(), crc);
+}
+
+
+//-------------------------------------------------
+// open_next - open the next file that matches
+// the filename by iterating over paths
+//-------------------------------------------------
+
+file_error emu_file::open_next()
+{
+ // if we're open from a previous attempt, close up now
+ if (m_file != NULL)
+ close();
+
+ // loop over paths
+ file_error filerr = FILERR_NOT_FOUND;
+ while (m_iterator.next(m_fullpath, m_filename.c_str()))
+ {
+ // attempt to open the file directly
+ filerr = core_fopen(m_fullpath.c_str(), m_openflags, &m_file);
+ if (filerr == FILERR_NONE)
+ break;
+
+ // if we're opening for read-only we have other options
+ if ((m_openflags & (OPEN_FLAG_READ | OPEN_FLAG_WRITE)) == OPEN_FLAG_READ)
+ {
+ std::string tempfullpath = m_fullpath;
+
+ filerr = attempt_zipped();
+ if (filerr == FILERR_NONE)
+ break;
+
+ m_fullpath = tempfullpath;
+
+ filerr = attempt__7zped();
+ if (filerr == FILERR_NONE)
+ break;
+ }
+ }
+ return filerr;
+}
+
+
+//-------------------------------------------------
+// open_ram - open a "file" which is actually
+// just an array of data in RAM
+//-------------------------------------------------
+
+file_error emu_file::open_ram(const void *data, UINT32 length)
+{
+ // set a fake filename and CRC
+ m_filename = "RAM";
+ m_crc = 0;
+
+ // use the core_file's built-in RAM support
+ return core_fopen_ram(data, length, m_openflags, &m_file);
+}
+
+
+//-------------------------------------------------
+// close - close a file and free all data; also
+// remove the file if requested
+//-------------------------------------------------
+
+void emu_file::close()
+{
+ // close files and free memory
+ if (m__7zfile != NULL)
+ _7z_file_close(m__7zfile);
+ m__7zfile = NULL;
+
+ if (m_zipfile != NULL)
+ zip_file_close(m_zipfile);
+ m_zipfile = NULL;
+
+ if (m_file != NULL)
+ core_fclose(m_file);
+ m_file = NULL;
+
+ m__7zdata.clear();
+ m_zipdata.clear();
+
+ if (m_remove_on_close)
+ osd_rmfile(m_fullpath.c_str());
+ m_remove_on_close = false;
+
+ // reset our hashes and path as well
+ m_hashes.reset();
+ m_fullpath.clear();
+}
+
+
+//-------------------------------------------------
+// compress - enable/disable streaming file
+// compression via zlib; level is 0 to disable
+// compression, or up to 9 for max compression
+//-------------------------------------------------
+
+file_error emu_file::compress(int level)
+{
+ return core_fcompress(m_file, level);
+}
+
+
+//-------------------------------------------------
+// compressed_file_ready - ensure our zip is ready
+// loading if needed
+//-------------------------------------------------
+
+bool emu_file::compressed_file_ready(void)
+{
+ // load the ZIP file now if we haven't yet
+ if (m__7zfile != NULL && load__7zped_file() != FILERR_NONE)
+ return true;
+
+ if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ return true;
+
+ return false;
+}
+
+//-------------------------------------------------
+// seek - seek within a file
+//-------------------------------------------------
+
+int emu_file::seek(INT64 offset, int whence)
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return 1;
+
+ // seek if we can
+ if (m_file != NULL)
+ return core_fseek(m_file, offset, whence);
+
+ return 1;
+}
+
+
+//-------------------------------------------------
+// tell - return the current file position
+//-------------------------------------------------
+
+UINT64 emu_file::tell()
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return 0;
+
+ // tell if we can
+ if (m_file != NULL)
+ return core_ftell(m_file);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// eof - return true if we're at the end of file
+//-------------------------------------------------
+
+bool emu_file::eof()
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return 0;
+
+ // return EOF if we can
+ if (m_file != NULL)
+ return core_feof(m_file);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// size - returns the size of a file
+//-------------------------------------------------
+
+UINT64 emu_file::size()
+{
+ // use the ZIP length if present
+ if (m__7zfile != NULL)
+ return m__7zlength;
+
+ if (m_zipfile != NULL)
+ return m_ziplength;
+
+ // return length if we can
+ if (m_file != NULL)
+ return core_fsize(m_file);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// read - read from a file
+//-------------------------------------------------
+
+UINT32 emu_file::read(void *buffer, UINT32 length)
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return 0;
+
+ // read the data if we can
+ if (m_file != NULL)
+ return core_fread(m_file, buffer, length);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// getc - read a character from a file
+//-------------------------------------------------
+
+int emu_file::getc()
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return EOF;
+
+ // read the data if we can
+ if (m_file != NULL)
+ return core_fgetc(m_file);
+
+ return EOF;
+}
+
+
+//-------------------------------------------------
+// ungetc - put back a character read from a file
+//-------------------------------------------------
+
+int emu_file::ungetc(int c)
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return 1;
+
+ // read the data if we can
+ if (m_file != NULL)
+ return core_ungetc(c, m_file);
+
+ return 1;
+}
+
+
+//-------------------------------------------------
+// gets - read a line from a text file
+//-------------------------------------------------
+
+char *emu_file::gets(char *s, int n)
+{
+ // load the ZIP file now if we haven't yet
+ if (compressed_file_ready())
+ return NULL;
+
+ // read the data if we can
+ if (m_file != NULL)
+ return core_fgets(s, n, m_file);
+
+ return NULL;
+}
+
+
+//-------------------------------------------------
+// write - write to a file
+//-------------------------------------------------
+
+UINT32 emu_file::write(const void *buffer, UINT32 length)
+{
+ // write the data if we can
+ if (m_file != NULL)
+ return core_fwrite(m_file, buffer, length);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// puts - write a line to a text file
+//-------------------------------------------------
+
+int emu_file::puts(const char *s)
+{
+ // write the data if we can
+ if (m_file != NULL)
+ return core_fputs(m_file, s);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// printf - vfprintf to a text file
+//-------------------------------------------------
+
+int CLIB_DECL emu_file::printf(const char *fmt, ...)
+{
+ int rc;
+ va_list va;
+ va_start(va, fmt);
+ rc = vprintf(fmt, va);
+ va_end(va);
+ return rc;
+}
+
+
+//-------------------------------------------------
+// mame_vfprintf - vfprintf to a text file
+//-------------------------------------------------
+
+int emu_file::vprintf(const char *fmt, va_list va)
+{
+ // write the data if we can
+ return (m_file != NULL) ? core_vfprintf(m_file, fmt, va) : 0;
+}
+
+
+//-------------------------------------------------
+// part_of_mediapath - checks if 'path' is part of
+// any media path
+//-------------------------------------------------
+
+bool emu_file::part_of_mediapath(std::string path)
+{
+ bool result = false;
+ std::string mediapath;
+ m_mediapaths.reset();
+ while (m_mediapaths.next(mediapath, NULL) && !result) {
+ if (path.compare(mediapath.substr(0, mediapath.length())))
+ result = true;
+ }
+ return result;
+}
+
+//-------------------------------------------------
+// attempt_zipped - attempt to open a ZIPped file
+//-------------------------------------------------
+
+file_error emu_file::attempt_zipped()
+{
+ std::string filename;
+
+ // loop over directory parts up to the start of filename
+ while (1)
+ {
+ // find the final path separator
+ int dirsep = m_fullpath.find_last_of(PATH_SEPARATOR[0]);
+ if (dirsep == -1)
+ return FILERR_NOT_FOUND;
+
+ if (restrict_to_mediapath())
+ if ( !part_of_mediapath(m_fullpath) )
+ return FILERR_NOT_FOUND;
+
+ // insert the part from the right of the separator into the head of the filename
+ if (filename.length() > 0)
+ filename.insert(0, "/");
+ filename.insert(0, m_fullpath.substr(dirsep + 1, -1));
+
+ // remove this part of the filename and append a .zip extension
+ m_fullpath = m_fullpath.substr(0, dirsep).append(".zip");
+
+ // attempt to open the ZIP file
+ zip_file *zip;
+ zip_error ziperr = zip_file_open(m_fullpath.c_str(), &zip);
+
+ // chop the .zip back off the filename before continuing
+ m_fullpath = m_fullpath.substr(0, dirsep);
+
+ // if we failed to open this file, continue scanning
+ if (ziperr != ZIPERR_NONE)
+ continue;
+
+ // see if we can find a file with the right name and (if available) crc
+ const zip_file_header *header;
+ for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
+ if (zip_filename_match(*header, filename) && (!(m_openflags & OPEN_FLAG_HAS_CRC) || header->crc == m_crc))
+ break;
+
+ // if that failed, look for a file with the right crc, but the wrong filename
+ if (header == NULL && (m_openflags & OPEN_FLAG_HAS_CRC))
+ for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
+ if (header->crc == m_crc && !zip_header_is_path(*header))
+ break;
+
+ // if that failed, look for a file with the right name; reporting a bad checksum
+ // is more helpful and less confusing than reporting "rom not found"
+ if (header == NULL)
+ for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
+ if (zip_filename_match(*header, filename))
+ break;
+
+ // if we got it, read the data
+ if (header != NULL)
+ {
+ m_zipfile = zip;
+ m_ziplength = header->uncompressed_length;
+
+ // build a hash with just the CRC
+ m_hashes.reset();
+ m_hashes.add_crc(header->crc);
+ return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? FILERR_NONE : load_zipped_file();
+ }
+
+ // close up the ZIP file and try the next level
+ zip_file_close(zip);
+ }
+}
+
+
+//-------------------------------------------------
+// load_zipped_file - load a ZIPped file
+//-------------------------------------------------
+
+file_error emu_file::load_zipped_file()
+{
+ assert(m_file == NULL);
+ assert(m_zipdata.empty());
+ assert(m_zipfile != NULL);
+
+ // allocate some memory
+ m_zipdata.resize(m_ziplength);
+
+ // read the data into our buffer and return
+ zip_error ziperr = zip_file_decompress(m_zipfile, &m_zipdata[0], m_zipdata.size());
+ if (ziperr != ZIPERR_NONE)
+ {
+ m_zipdata.clear();
+ return FILERR_FAILURE;
+ }
+
+ // convert to RAM file
+ file_error filerr = core_fopen_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, &m_file);
+ if (filerr != FILERR_NONE)
+ {
+ m_zipdata.clear();
+ return FILERR_FAILURE;
+ }
+
+ // close out the ZIP file
+ zip_file_close(m_zipfile);
+ m_zipfile = NULL;
+ return FILERR_NONE;
+}
+
+
+//-------------------------------------------------
+// zip_filename_match - compare zip filename
+// to expected filename, ignoring any directory
+//-------------------------------------------------
+
+bool emu_file::zip_filename_match(const zip_file_header &header, const std::string &filename)
+{
+ const char *zipfile = header.filename + header.filename_length - filename.length();
+ return (zipfile >= header.filename && core_stricmp(filename.c_str(),zipfile) == 0 && (zipfile == header.filename || zipfile[-1] == '/'));
+}
+
+
+//-------------------------------------------------
+// zip_header_is_path - check whether filename
+// in header is a path
+//-------------------------------------------------
+
+bool emu_file::zip_header_is_path(const zip_file_header &header)
+{
+ const char *zipfile = header.filename + header.filename_length - 1;
+ return (zipfile >= header.filename && zipfile[0] == '/');
+}
+
+//-------------------------------------------------
+// attempt__7zped - attempt to open a .7z file
+//-------------------------------------------------
+
+file_error emu_file::attempt__7zped()
+{
+ std::string filename;
+
+ // loop over directory parts up to the start of filename
+ while (1)
+ {
+ // find the final path separator
+ int dirsep = m_fullpath.find_last_of(PATH_SEPARATOR[0]);
+ if (dirsep == -1)
+ return FILERR_NOT_FOUND;
+
+ if (restrict_to_mediapath())
+ if ( !part_of_mediapath(m_fullpath) )
+ return FILERR_NOT_FOUND;
+
+ // insert the part from the right of the separator into the head of the filename
+ if (filename.length() > 0)
+ filename.insert(0, "/");
+ filename.insert(0, m_fullpath.substr(dirsep + 1, -1));
+
+ // remove this part of the filename and append a .7z extension
+ m_fullpath = m_fullpath.substr(0, dirsep).append(".7z");
+
+ // attempt to open the _7Z file
+ _7z_file *_7z;
+ _7z_error _7zerr = _7z_file_open(m_fullpath.c_str(), &_7z);
+
+ // chop the ._7z back off the filename before continuing
+ m_fullpath = m_fullpath.substr(0, dirsep);
+
+ // if we failed to open this file, continue scanning
+ if (_7zerr != _7ZERR_NONE)
+ continue;
+
+ int fileno = -1;
+
+ // see if we can find a file with the right name and (if available) crc
+ if (m_openflags & OPEN_FLAG_HAS_CRC) fileno = _7z_search_crc_match(_7z, m_crc, filename.c_str(), filename.length(), true, true);
+
+ // if that failed, look for a file with the right crc, but the wrong filename
+ if (fileno==-1)
+ if (m_openflags & OPEN_FLAG_HAS_CRC) fileno = _7z_search_crc_match(_7z, m_crc, filename.c_str(), filename.length(), true, false);
+
+ // if that failed, look for a file with the right name; reporting a bad checksum
+ // is more helpful and less confusing than reporting "rom not found"
+ if (fileno==-1)
+ fileno = _7z_search_crc_match(_7z, m_crc, filename.c_str(), filename.length(), false, true);
+
+ if (fileno != -1)
+ {
+ m__7zfile = _7z;
+ m__7zlength = _7z->uncompressed_length;
+
+ // build a hash with just the CRC
+ m_hashes.reset();
+ m_hashes.add_crc(_7z->crc);
+ return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? FILERR_NONE : load__7zped_file();
+ }
+
+ // close up the _7Z file and try the next level
+ _7z_file_close(_7z);
+ }
+}
+
+
+//-------------------------------------------------
+// load__7zped_file - load a _7Zped file
+//-------------------------------------------------
+
+file_error emu_file::load__7zped_file()
+{
+ assert(m_file == NULL);
+ assert(m__7zdata.empty());
+ assert(m__7zfile != NULL);
+
+ // allocate some memory
+ m__7zdata.resize(m__7zlength);
+
+ // read the data into our buffer and return
+ _7z_error _7zerr = _7z_file_decompress(m__7zfile, &m__7zdata[0], m__7zdata.size());
+ if (_7zerr != _7ZERR_NONE)
+ {
+ m__7zdata.clear();
+ return FILERR_FAILURE;
+ }
+
+ // convert to RAM file
+ file_error filerr = core_fopen_ram(&m__7zdata[0], m__7zdata.size(), m_openflags, &m_file);
+ if (filerr != FILERR_NONE)
+ {
+ m__7zdata.clear();
+ return FILERR_FAILURE;
+ }
+
+ // close out the _7Z file
+ _7z_file_close(m__7zfile);
+ m__7zfile = NULL;
+ return FILERR_NONE;
+}