diff --git a/src/emu/fileio.c b/src/emu/fileio.c index abfbdc5509e..6e6e5e748c8 100644 --- a/src/emu/fileio.c +++ b/src/emu/fileio.c @@ -384,6 +384,17 @@ void mame_fclose(mame_file *file) } +/*------------------------------------------------- + mame_fcompress - enable/disable streaming file + compression via zlib +-------------------------------------------------*/ + +file_error mame_fcompress(mame_file *file, int compress) +{ + return core_fcompress(file->file, compress); +} + + /*************************************************************************** FILE POSITIONING @@ -604,7 +615,6 @@ int CLIB_DECL mame_fprintf(mame_file *file, const char *fmt, ...) FILE ENUMERATION ***************************************************************************/ - /*------------------------------------------------- mame_openpath - open a search path (multiple directories) for iteration diff --git a/src/emu/fileio.h b/src/emu/fileio.h index 8a25ac8a75c..2bd0c48e800 100644 --- a/src/emu/fileio.h +++ b/src/emu/fileio.h @@ -98,6 +98,9 @@ file_error mame_fopen_ram(const void *data, UINT32 length, UINT32 openflags, mam /* close an open file */ void mame_fclose(mame_file *file); +/* enable/disable streaming file compression via zlib */ +file_error mame_fcompress(mame_file *file, int compress); + /* ----- file positioning ----- */ @@ -170,4 +173,5 @@ const char *mame_file_full_name(mame_file *file); const char *mame_fhash(mame_file *file, UINT32 functions); + #endif /* __FILEIO_H__ */ diff --git a/src/emu/inptport.c b/src/emu/inptport.c index 5bd1491f7da..fff9bca81da 100644 --- a/src/emu/inptport.c +++ b/src/emu/inptport.c @@ -3973,6 +3973,9 @@ static time_t playback_init(running_machine *machine) if (memcmp(machine->gamedrv->name, header + 0x14, strlen(machine->gamedrv->name) + 1) != 0) fatalerror("Input file is for " GAMENOUN " '%s', not for current " GAMENOUN " '%s'\n", header + 0x14, machine->gamedrv->name); + /* enable compression */ + mame_fcompress(portdata->playback_file, TRUE); + return basetime; } @@ -4044,7 +4047,8 @@ static void playback_port(const input_port_config *port) { analog_field_state *analog; - /* read the digital value */ + /* read the default value and the digital state */ + port->state->defvalue = playback_read_uint32(port->machine); port->state->digital = playback_read_uint32(port->machine); /* loop over analog ports and save their data */ @@ -4168,6 +4172,9 @@ static void record_init(running_machine *machine) /* write it */ mame_fwrite(portdata->record_file, header, sizeof(header)); + + /* enable compression */ + mame_fcompress(portdata->record_file, TRUE); } @@ -4228,7 +4235,8 @@ static void record_port(const input_port_config *port) { analog_field_state *analog; - /* store the digital value */ + /* store the default value and digital state */ + record_write_uint32(port->machine, port->state->defvalue); record_write_uint32(port->machine, port->state->digital); /* loop over analog ports and save their data */ diff --git a/src/emu/inptport.h b/src/emu/inptport.h index 3701687f158..86ccb51756b 100644 --- a/src/emu/inptport.h +++ b/src/emu/inptport.h @@ -46,7 +46,7 @@ /* INP file information */ #define INP_HEADER_SIZE 64 -#define INP_HEADER_MAJVERSION 2 +#define INP_HEADER_MAJVERSION 3 #define INP_HEADER_MINVERSION 0 diff --git a/src/lib/util/corefile.c b/src/lib/util/corefile.c index 3d9303ef32f..157ee455991 100644 --- a/src/lib/util/corefile.c +++ b/src/lib/util/corefile.c @@ -11,6 +11,7 @@ #include "corefile.h" #include "unicode.h" +#include "zlib.h" #include #include @@ -53,10 +54,21 @@ enum _text_file_type typedef enum _text_file_type text_file_type; +typedef struct _zlib_data zlib_data; +struct _zlib_data +{ + z_stream stream; + UINT8 buffer[1024]; + UINT64 realoffset; + UINT64 nextoffset; +}; + + /* typedef struct _core_file core_file -- declared in corefile.h */ struct _core_file { osd_file * file; /* OSD file handle */ + zlib_data * zdata; /* compression data */ UINT32 openflags; /* flags we were opened with */ UINT8 data_allocated; /* was the data allocated by us? */ UINT8 * data; /* file data, if RAM-based */ @@ -79,6 +91,8 @@ struct _core_file /* misc helpers */ static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sourcelen, void *dest, UINT32 destoffs, UINT32 destlen); +static file_error osd_or_zlib_read(core_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual); +static file_error osd_or_zlib_write(core_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual); @@ -198,6 +212,8 @@ file_error core_fopen_ram_copy(const void *data, size_t length, UINT32 openflags void core_fclose(core_file *file) { /* close files and free memory */ + if (file->zdata != NULL) + core_fcompress(file, FALSE); if (file->file != NULL) osd_close(file->file); if (file->data != NULL && file->data_allocated) @@ -206,6 +222,102 @@ void core_fclose(core_file *file) } +/*------------------------------------------------- + core_fcompress - enable/disable streaming file + compression via zlib +-------------------------------------------------*/ + +file_error core_fcompress(core_file *file, int compress) +{ + file_error result = FILERR_NONE; + + /* can only do this for read-only and write-only cases */ + if ((file->openflags & OPEN_FLAG_WRITE) != 0 && (file->openflags & OPEN_FLAG_READ) != 0) + return FILERR_INVALID_ACCESS; + + /* if we have been compressing, flush and free the data */ + if (file->zdata != NULL && !compress) + { + int zerr = Z_OK; + + /* flush any remaining data if we are writing */ + while ((file->openflags & OPEN_FLAG_WRITE) != 0 && zerr != Z_STREAM_END) + { + UINT32 actualdata; + file_error filerr; + + /* deflate some more */ + zerr = deflate(&file->zdata->stream, Z_FINISH); + if (zerr != Z_STREAM_END && zerr != Z_OK) + { + result = FILERR_INVALID_DATA; + break; + } + + /* write the data */ + if (file->zdata->stream.avail_out != sizeof(file->zdata->buffer)) + { + filerr = osd_write(file->file, file->zdata->buffer, file->zdata->realoffset, sizeof(file->zdata->buffer) - file->zdata->stream.avail_out, &actualdata); + if (filerr != FILERR_NONE) + break; + file->zdata->realoffset += actualdata; + file->zdata->stream.next_out = file->zdata->buffer; + file->zdata->stream.avail_out = sizeof(file->zdata->buffer); + } + } + + /* end the appropriate operation */ + if ((file->openflags & OPEN_FLAG_WRITE) != 0) + deflateEnd(&file->zdata->stream); + else + inflateEnd(&file->zdata->stream); + + /* free memory */ + free(file->zdata); + file->zdata = NULL; + } + + /* if we are just starting to compress, allocate a new buffer */ + if (file->zdata == NULL && compress) + { + int zerr; + + /* allocate memory */ + file->zdata = malloc(sizeof(*file->zdata)); + if (file->zdata == NULL) + return FILERR_OUT_OF_MEMORY; + memset(file->zdata, 0, sizeof(file->zdata)); + + /* initialize the stream and compressor */ + if ((file->openflags & OPEN_FLAG_WRITE) != 0) + { + file->zdata->stream.next_out = file->zdata->buffer; + file->zdata->stream.avail_out = sizeof(file->zdata->buffer); + zerr = deflateInit(&file->zdata->stream, Z_BEST_COMPRESSION); + } + else + zerr = inflateInit(&file->zdata->stream); + + /* on error, return an error */ + if (zerr != Z_OK) + { + free(file->zdata); + file->zdata = NULL; + return FILERR_OUT_OF_MEMORY; + } + + /* flush buffers */ + file->bufferbytes = 0; + + /* set the initial offset */ + file->zdata->realoffset = file->offset; + file->zdata->nextoffset = file->offset; + } + + return result; +} + + /*************************************************************************** FILE POSITIONING @@ -218,6 +330,10 @@ void core_fclose(core_file *file) int core_fseek(core_file *file, INT64 offset, int whence) { int err = 0; + + /* error if compressing */ + if (file->zdata != NULL) + return 1; /* flush any buffered char */ file->back_char_head = 0; @@ -312,7 +428,7 @@ UINT32 core_fread(core_file *file, void *buffer, UINT32 length) /* read as much as makes sense into the buffer */ file->bufferbase = file->offset + bytes_read; file->bufferbytes = 0; - filerr = osd_read(file->file, file->buffer, file->bufferbase, sizeof(file->buffer), &file->bufferbytes); + filerr = osd_or_zlib_read(file, file->buffer, file->bufferbase, sizeof(file->buffer), &file->bufferbytes); /* do a bounded copy from the buffer to the destination */ bytes_read += safe_buffer_copy(file->buffer, 0, file->bufferbytes, buffer, bytes_read, length); @@ -322,7 +438,7 @@ UINT32 core_fread(core_file *file, void *buffer, UINT32 length) else { UINT32 new_bytes_read = 0; - filerr = osd_read(file->file, (UINT8 *)buffer + bytes_read, file->offset + bytes_read, length - bytes_read, &new_bytes_read); + filerr = osd_or_zlib_read(file, (UINT8 *)buffer + bytes_read, file->offset + bytes_read, length - bytes_read, &new_bytes_read); bytes_read += new_bytes_read; } } @@ -555,7 +671,7 @@ const void *core_fbuffer(core_file *file) file->data_allocated = TRUE; /* read the file */ - filerr = osd_read(file->file, file->data, 0, file->length, &read_length); + filerr = osd_or_zlib_read(file, file->data, 0, file->length, &read_length); if (filerr != FILERR_NONE || read_length != file->length) { free(file->data); @@ -596,7 +712,7 @@ UINT32 core_fwrite(core_file *file, const void *buffer, UINT32 length) file->bufferbytes = 0; /* do the write */ - filerr = osd_write(file->file, buffer, file->offset, length, &bytes_written); + filerr = osd_or_zlib_write(file, buffer, file->offset, length, &bytes_written); /* return the number of bytes read */ file->offset += bytes_written; @@ -755,3 +871,110 @@ static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sou memcpy((UINT8 *)dest + destoffs, (const UINT8 *)source + sourceoffs, bytes_to_copy); return bytes_to_copy; } + + +/*------------------------------------------------- + osd_or_zlib_read - wrapper for osd_read that + handles zlib-compressed data +-------------------------------------------------*/ + +static file_error osd_or_zlib_read(core_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual) +{ + /* if no compression, just pass through */ + if (file->zdata == NULL) + return osd_read(file->file, buffer, offset, length, actual); + + /* if the offset doesn't match the next offset, fail */ + if (offset != file->zdata->nextoffset) + return FILERR_INVALID_ACCESS; + + /* set up the destination */ + file->zdata->stream.next_out = buffer; + file->zdata->stream.avail_out = length; + while (file->zdata->stream.avail_out != 0) + { + file_error filerr; + UINT32 actualdata; + int zerr = Z_OK; + + /* if we didn't make progress, report an error or the end */ + if (file->zdata->stream.avail_in != 0) + zerr = inflate(&file->zdata->stream, Z_SYNC_FLUSH); + if (zerr != Z_OK) + { + *actual = length - file->zdata->stream.avail_out; + file->zdata->nextoffset += *actual; + return (zerr == Z_STREAM_END) ? FILERR_NONE : FILERR_INVALID_DATA; + } + + /* fetch more data if needed */ + if (file->zdata->stream.avail_in == 0) + { + filerr = osd_read(file->file, file->zdata->buffer, file->zdata->realoffset, sizeof(file->zdata->buffer), &actualdata); + if (filerr != FILERR_NONE) + return filerr; + file->zdata->realoffset += actualdata; + file->zdata->stream.next_in = file->zdata->buffer; + file->zdata->stream.avail_in = sizeof(file->zdata->buffer); + } + } + + /* we read everything */ + *actual = length; + file->zdata->nextoffset += *actual; + return FILERR_NONE; +} + + +/*------------------------------------------------- + osd_or_zlib_write - wrapper for osd_write that + handles zlib-compressed data +-------------------------------------------------*/ + +static file_error osd_or_zlib_write(core_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual) +{ + /* if no compression, just pass through */ + if (file->zdata == NULL) + return osd_write(file->file, buffer, offset, length, actual); + + /* if the offset doesn't match the next offset, fail */ + if (offset != file->zdata->nextoffset) + return FILERR_INVALID_ACCESS; + + /* set up the source */ + file->zdata->stream.next_in = (void *)buffer; + file->zdata->stream.avail_in = length; + while (file->zdata->stream.avail_in != 0) + { + file_error filerr; + UINT32 actualdata; + int zerr; + + /* if we didn't make progress, report an error or the end */ + zerr = deflate(&file->zdata->stream, Z_NO_FLUSH); + if (zerr != Z_OK) + { + *actual = length - file->zdata->stream.avail_in; + file->zdata->nextoffset += *actual; + return FILERR_INVALID_DATA; + } + + /* write more data if we are full up */ + if (file->zdata->stream.avail_out == 0) + { + filerr = osd_write(file->file, file->zdata->buffer, file->zdata->realoffset, sizeof(file->zdata->buffer), &actualdata); + if (filerr != FILERR_NONE) + return filerr; + file->zdata->realoffset += actualdata; + file->zdata->stream.next_out = file->zdata->buffer; + file->zdata->stream.avail_out = sizeof(file->zdata->buffer); + } + } + + /* we read everything */ + *actual = length; + file->zdata->nextoffset += *actual; + return FILERR_NONE; +} + + diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h index cf9571cb9be..944ad19e97a 100644 --- a/src/lib/util/corefile.h +++ b/src/lib/util/corefile.h @@ -55,6 +55,9 @@ file_error core_fopen_ram_copy(const void *data, size_t length, UINT32 openflags /* close an open file */ void core_fclose(core_file *file); +/* enable/disable streaming file compression via zlib */ +file_error core_fcompress(core_file *file, int compress); + /* ----- file positioning ----- */ diff --git a/src/lib/util/png.c b/src/lib/util/png.c index 5917ebbdca5..2346419c2df 100644 --- a/src/lib/util/png.c +++ b/src/lib/util/png.c @@ -809,7 +809,7 @@ static png_error write_deflated_chunk(core_file *fp, UINT8 *data, UINT32 type, U memset(&stream, 0, sizeof(stream)); stream.next_in = data; stream.avail_in = length; - zerr = deflateInit(&stream, Z_DEFAULT_COMPRESSION); + zerr = deflateInit(&stream, Z_BEST_COMPRESSION); if (zerr != Z_OK) return PNGERR_COMPRESS_ERROR;