summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/fileio.c')
-rw-r--r--src/emu/fileio.c177
1 files changed, 167 insertions, 10 deletions
diff --git a/src/emu/fileio.c b/src/emu/fileio.c
index 3a644cf7639..d5fbf122043 100644
--- a/src/emu/fileio.c
+++ b/src/emu/fileio.c
@@ -37,8 +37,12 @@
***************************************************************************/
+
+
+
#include "emu.h"
#include "unzip.h"
+#include "un7z.h"
#include "fileio.h"
@@ -174,6 +178,9 @@ emu_file::emu_file(UINT32 openflags)
m_zipfile(NULL),
m_zipdata(NULL),
m_ziplength(0),
+ m__7zfile(NULL),
+ m__7zdata(NULL),
+ m__7zlength(0),
m_remove_on_close(false)
{
// sanity check the open flags
@@ -189,6 +196,9 @@ emu_file::emu_file(const char *searchpath, UINT32 openflags)
m_zipfile(NULL),
m_zipdata(NULL),
m_ziplength(0),
+ m__7zfile(NULL),
+ m__7zdata(NULL),
+ m__7zlength(0),
m_remove_on_close(false)
{
// sanity check the open flags
@@ -216,7 +226,7 @@ emu_file::~emu_file()
emu_file::operator core_file *()
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return NULL;
// return the core file
@@ -226,7 +236,7 @@ emu_file::operator core_file *()
emu_file::operator core_file &()
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
throw emu_fatalerror("operator core_file & used on invalid file");
// return the core file
@@ -251,12 +261,18 @@ hash_collection &emu_file::hashes(const char *types)
return m_hashes;
// load the ZIP file if needed
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ 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 != NULL)
+ {
+ m_hashes.compute(m__7zdata, m__7zlength, needed);
+ return m_hashes;
+ }
+
if (m_zipdata != NULL)
{
m_hashes.compute(m_zipdata, m_ziplength, needed);
@@ -368,9 +384,19 @@ file_error emu_file::open_next()
// if we're opening for read-only we have other options
if ((m_openflags & (OPEN_FLAG_READ | OPEN_FLAG_WRITE)) == OPEN_FLAG_READ)
{
+ astring tempfullpath = m_fullpath;
+
+ filerr = attempt__7zped();
+ if (filerr == FILERR_NONE)
+ break;
+
+ m_fullpath = tempfullpath;
+
filerr = attempt_zipped();
if (filerr == FILERR_NONE)
break;
+
+
}
}
return filerr;
@@ -401,6 +427,10 @@ file_error emu_file::open_ram(const void *data, UINT32 length)
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;
@@ -409,6 +439,10 @@ void emu_file::close()
core_fclose(m_file);
m_file = NULL;
+ if (m__7zdata != NULL)
+ global_free(m__7zdata);
+ m__7zdata = NULL;
+
if (m_zipdata != NULL)
global_free(m_zipdata);
m_zipdata = NULL;
@@ -436,13 +470,30 @@ file_error emu_file::compress(int 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 (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return 1;
// seek if we can
@@ -460,7 +511,7 @@ int emu_file::seek(INT64 offset, int whence)
UINT64 emu_file::tell()
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return 0;
// tell if we can
@@ -478,7 +529,7 @@ UINT64 emu_file::tell()
bool emu_file::eof()
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return 0;
// return EOF if we can
@@ -496,6 +547,9 @@ bool emu_file::eof()
UINT64 emu_file::size()
{
// use the ZIP length if present
+ if (m__7zfile != NULL)
+ return m__7zlength;
+
if (m_zipfile != NULL)
return m_ziplength;
@@ -514,7 +568,7 @@ UINT64 emu_file::size()
UINT32 emu_file::read(void *buffer, UINT32 length)
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return 0;
// read the data if we can
@@ -532,7 +586,7 @@ UINT32 emu_file::read(void *buffer, UINT32 length)
int emu_file::getc()
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return EOF;
// read the data if we can
@@ -550,7 +604,7 @@ int emu_file::getc()
int emu_file::ungetc(int c)
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return 1;
// read the data if we can
@@ -568,7 +622,7 @@ int emu_file::ungetc(int c)
char *emu_file::gets(char *s, int n)
{
// load the ZIP file now if we haven't yet
- if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
+ if (compressed_file_ready())
return NULL;
// read the data if we can
@@ -766,3 +820,106 @@ 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()
+{
+ astring filename;
+
+ // loop over directory parts up to the start of filename
+ while (1)
+ {
+ // find the final path separator
+ int dirsep = m_fullpath.rchr(0, PATH_SEPARATOR[0]);
+ if (dirsep == -1)
+ return FILERR_NOT_FOUND;
+
+ // insert the part from the right of the separator into the head of the filename
+ if (filename.len() > 0)
+ filename.ins(0, "/");
+ filename.inssubstr(0, m_fullpath, dirsep + 1, -1);
+
+ // remove this part of the filename and append a .7z extension
+ m_fullpath.substr(0, dirsep).cat(".7z");
+
+ // attempt to open the _7Z file
+ _7z_file *_7z;
+ _7z_error _7zerr = _7z_file_open(m_fullpath, &_7z);
+
+ // chop the ._7z back off the filename before continuing
+ 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.cstr(), filename.len(), 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.cstr(), filename.len(), 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.cstr(), filename.len(), 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 == NULL);
+ assert(m__7zfile != NULL);
+
+ // allocate some memory
+ m__7zdata = global_alloc_array(UINT8, m__7zlength);
+
+ // read the data into our buffer and return
+ _7z_error _7zerr = _7z_file_decompress(m__7zfile, m__7zdata, m__7zlength);
+ if (_7zerr != _7ZERR_NONE)
+ {
+ global_free(m__7zdata);
+ m__7zdata = NULL;
+ return FILERR_FAILURE;
+ }
+
+ // convert to RAM file
+ file_error filerr = core_fopen_ram(m__7zdata, m__7zlength, m_openflags, &m_file);
+ if (filerr != FILERR_NONE)
+ {
+ global_free(m__7zdata);
+ m__7zdata = NULL;
+ return FILERR_FAILURE;
+ }
+
+ // close out the _7Z file
+ _7z_file_close(m__7zfile);
+ m__7zfile = NULL;
+ return FILERR_NONE;
+}