diff --git a/src/dos/drive_zip.cpp b/src/dos/drive_zip.cpp index d7d35421..61be25bf 100644 --- a/src/dos/drive_zip.cpp +++ b/src/dos/drive_zip.cpp @@ -20,6 +20,7 @@ #include "dos_inc.h" #include "drives.h" #include "inout.h" +#include "pic.h" #include @@ -1134,19 +1135,21 @@ struct Zip_File : Zip_Entry Bit32u decomp_size, comp_size, crc; Bit32u refs; Bit16u ofs_past_header; - Bit8u bit_flags; - Bit8u method; + Bit8u bit_flags, method, have_pic; Bit64u data_ofs; ZIP_Unpacker* unpacker; Zip_File(Bit16u _attr, const char* filename, Bit16u _date, Bit16u _time, Bit64u _data_ofs, Bit32u _decomp_size, Bit32u _comp_size, Bit32u _crc, Bit8u _bit_flags, Bit8u _method) - : Zip_Entry(_attr, filename, _date, _time), data_ofs(_data_ofs), decomp_size(_decomp_size), comp_size(_comp_size), crc(_crc), refs(0), bit_flags(_bit_flags), method(_method), ofs_past_header(0), unpacker(NULL) {} + : Zip_Entry(_attr, filename, _date, _time), data_ofs(_data_ofs), decomp_size(_decomp_size), comp_size(_comp_size), crc(_crc), refs(0), bit_flags(_bit_flags), method(_method), have_pic(0), ofs_past_header(0), unpacker(NULL) {} ~Zip_File() { DBP_ASSERT(!refs); + if (have_pic) { PICHandler((Bitu)this); PIC_RemoveSpecificEvents(PICHandler, (Bitu)this); } delete unpacker; } + + static void PICHandler(Bitu implPtr); }; struct Zip_StoredUnpacker : ZIP_Unpacker @@ -1301,8 +1304,8 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker Bit8u read_buf[READ_BLOCK]; Bit8u write_buf[WRITE_BLOCK]; - enum { SEEK_CURSOR_MAX_DEFL = 128 + (sizeof(SeekCursor) + 9) / 10 * 11, SEEK_CACHE_CURSOR_STEPS = 20 }; - struct SeekCache { zipDrive* drv; std::string path; Bit32u cache_count; } * seek_cache; + enum { SEEK_CURSOR_MAX_DEFL = 128 + (sizeof(SeekCursor) + 9) / 10 * 11, SEEK_CACHE_CURSOR_NEED = 50, SEEK_CACHE_CURSOR_STEPS = 20 }; + struct SeekCache { zipDrive* drv; std::string path; Bit32u count; } * seek_cache; Zip_DeflateUnpacker(Zip_Archive& _archive, const Zip_File& f, zipDrive* drv, const char* path) : archive(_archive), crc_run(0), crc_ofs((Bit32u)-1), crc_failed(0), seek_cache(NULL) { @@ -1319,12 +1322,12 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker // Read seek cache file for larger files Bit8u drive_idx; - if (cursor_count > 50 && (drive_idx = DriveGetIndex(drv)) != DOS_DRIVES) + if (cursor_count > SEEK_CACHE_CURSOR_NEED && (drive_idx = DriveGetIndex(drv)) != DOS_DRIVES) { seek_cache = new SeekCache; seek_cache->drv = drv; seek_cache->path = path; - seek_cache->cache_count = 0; + seek_cache->count = 0; std::string::size_type separator = seek_cache->path.rfind('.'); int extlen = (separator == std::string::npos ? 9 : (int)(seek_cache->path.length() - separator)); if (extlen <= 4) seek_cache->path.resize(seek_cache->path.length() - extlen); @@ -1338,7 +1341,7 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker Bit8u* compbuf = new Bit8u[sizeof(SeekCursor)]; Bit16u hdrin[7], hdrtest[7] = { (Bit16u)0x5345, (Bit16u)sizeof(SeekCursor), (Bit16u)(f.comp_size>>16), (Bit16u)f.comp_size, (Bit16u)(f.data_ofs>>32), (Bit16u)(f.data_ofs>>16), (Bit16u)f.data_ofs }, sz; bool valid = (df->Read((Bit8u*)hdrin, &(sz = (Bit16u)sizeof(hdrin))) && !memcmp(hdrin, hdrtest, sizeof(hdrin))); - for (Bit16u idx_complen[2]; valid; seek_cache->cache_count++) + for (Bit16u idx_complen[2]; valid; seek_cache->count++) { if (!df->Read((Bit8u*)idx_complen, &(sz = sizeof(idx_complen))) || sz != sizeof(idx_complen) || idx_complen[0] >= cursor_count || idx_complen[1] >= sizeof(SeekCursor)) break; if (idx_complen[1]) @@ -1354,7 +1357,7 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker if (!valid) { Drives[drive_idx]->FileUnlink((char*)seek_cache->path.c_str()); - seek_cache->cache_count = 0; + seek_cache->count = 0; } } } @@ -1362,8 +1365,8 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker ~Zip_DeflateUnpacker() { - free(cursors); if (seek_cache) delete seek_cache; + free(cursors); } void Reset(const Zip_File& f) @@ -1478,58 +1481,40 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker memcpy(cursors[idx].write_buf, write_buf, sizeof(write_buf)); // Write a seek cache next to the compressed file for larger files - if (seek_cache && idx > 50 && (idx % SEEK_CACHE_CURSOR_STEPS) == 0) + if (seek_cache && idx > SEEK_CACHE_CURSOR_NEED) { - Bit32u cursor_count = (f.decomp_size + (cursor_block - 1)) / cursor_block, cursor_got = 0; - for (Bit32u ii = 0; ii < cursor_count; ii += SEEK_CACHE_CURSOR_STEPS) - if (cursors[ii].cursor_out) - cursor_got++; + Bit32u cursor_count = (Bit16u)((f.decomp_size + (cursor_block - 1)) / cursor_block), cursor_got = 0; + for (Bit32u ii = (SEEK_CACHE_CURSOR_STEPS / 2); ii < cursor_count; ii++) + { + if (!cursors[ii].cursor_out) continue; + cursor_got++; + ii = (SEEK_CACHE_CURSOR_STEPS / 2 - 1) + ((ii + (SEEK_CACHE_CURSOR_STEPS-1)) / SEEK_CACHE_CURSOR_STEPS * SEEK_CACHE_CURSOR_STEPS); + } //printf("[%s] CURSORS FOR SEEK CACHE: %d / %d\n", f.name, cursor_got, (cursor_count+(SEEK_CACHE_CURSOR_STEPS-1))/SEEK_CACHE_CURSOR_STEPS); - if (cursor_got > cursor_count / (SEEK_CACHE_CURSOR_STEPS*2) && cursor_got > seek_cache->cache_count && (cursor_got >= seek_cache->cache_count + 5 || cursor_got == (cursor_count+(SEEK_CACHE_CURSOR_STEPS-1))/SEEK_CACHE_CURSOR_STEPS) && cursor_count <= 0xFFFF) + if (cursor_got > cursor_count / (SEEK_CACHE_CURSOR_STEPS*2) && cursor_got > seek_cache->count && cursor_count <= 0xFFFF) { - DOS_File *df; - Bit8u drive_idx = DriveGetIndex(seek_cache->drv); - if (drive_idx != DOS_DRIVES && Drives[drive_idx]->FileCreate(&df, (char*)seek_cache->path.c_str(), DOS_ATTR_ARCHIVE)) - { - df->AddRef(); - sdefl* compressor = new sdefl; - Bit8u* compbuf = new Bit8u[SEEK_CURSOR_MAX_DEFL]; - Bit16u hdr[7] = { (Bit16u)0x5345, (Bit16u)sizeof(SeekCursor), (Bit16u)(f.comp_size>>16), (Bit16u)f.comp_size, (Bit16u)(f.data_ofs>>32), (Bit16u)(f.data_ofs>>16), (Bit16u)f.data_ofs }, idx_complen[2], sz; - df->Write((Bit8u*)hdr, &(sz = (Bit16u)sizeof(hdr))); - for (idx_complen[0] = 0; idx_complen[0] < cursor_count; idx_complen[0] += SEEK_CACHE_CURSOR_STEPS) - { - if (!cursors[idx_complen[0]].cursor_out) continue; - Bit32u complen = compressor->Run(compbuf, (const unsigned char*)&cursors[idx_complen[0]], sizeof(SeekCursor)); - DBP_ASSERT(complen < SEEK_CURSOR_MAX_DEFL); - idx_complen[1] = (complen < (sizeof(SeekCursor)-10) ? (Bit16u)complen : (Bit16u)0); // store compressed only when beneficial - df->Write((Bit8u*)idx_complen, &(sz = (Bit16u)sizeof(idx_complen))); - if (idx_complen[1]) df->Write((Bit8u*)compbuf, &idx_complen[1]); - else df->Write((Bit8u*)&cursors[idx_complen[0]], &(sz = (Bit16u)sizeof(SeekCursor))); - } - df->Close(); - delete df; - delete[] compbuf; - delete compressor; - } - seek_cache->cache_count = cursor_got; + seek_cache->count = cursor_got; + const_cast(f).have_pic = 1; + PIC_RemoveSpecificEvents(Zip_File::PICHandler, (Bitu)&f); + PIC_AddEvent(Zip_File::PICHandler, 5.0f, (Bitu)&f); } - } - if (last_idx != idx && seek_cache && idx > 50) - { - extern Bit32u DBP_GetTicks(); - Bit32u tick = DBP_GetTicks(); - if (last_idx == (Bit32u)-1) { slowload_num = 0; slowload_tick = tick + 77; } - else if (slowload_num++ >= SEEK_CACHE_CURSOR_STEPS*2 && (Bit32s)(tick - slowload_tick) >= 33) + if (last_idx != idx) { - slowload_tick = tick; - extern void DBP_ShowSlowLoading(); - DBP_ShowSlowLoading(); - extern bool DBP_IsShuttingDown(); - if (DBP_IsShuttingDown()) - return (Bit32u)(p_res - (Bit8u*)res_buf); + extern Bit32u DBP_GetTicks(); + Bit32u tick = DBP_GetTicks(); + if (last_idx == (Bit32u)-1) { slowload_num = 0; slowload_tick = tick + 77; } + else if (slowload_num++ >= SEEK_CACHE_CURSOR_STEPS*2 && (Bit32s)(tick - slowload_tick) >= 33 && f.have_pic) + { + slowload_tick = tick; + extern void DBP_ShowSlowLoading(); + DBP_ShowSlowLoading(); + extern bool DBP_IsShuttingDown(); + if (DBP_IsShuttingDown()) + return (Bit32u)(p_res - (Bit8u*)res_buf); // abort slow file loading if shut down was initiated + } + last_idx = idx; } - last_idx = idx; } } } @@ -1543,8 +1528,41 @@ struct Zip_DeflateUnpacker : ZIP_Unpacker crc_ofs = 0; // this enables CRC checking during decompression in Read return true; } + + void WriteSeekCache(const Zip_File& f) + { + DOS_File *df; + Bit8u drive_idx = DriveGetIndex(seek_cache->drv); + if (drive_idx == DOS_DRIVES || !Drives[drive_idx]->FileCreate(&df, (char*)seek_cache->path.c_str(), DOS_ATTR_ARCHIVE)) return; + df->AddRef(); + Bit16u hdr[7] = { (Bit16u)0x5345, (Bit16u)sizeof(SeekCursor), (Bit16u)(f.comp_size>>16), (Bit16u)f.comp_size, (Bit16u)(f.data_ofs>>32), (Bit16u)(f.data_ofs>>16), (Bit16u)f.data_ofs }, idx_complen[2], sz; + df->Write((Bit8u*)hdr, &(sz = (Bit16u)sizeof(hdr))); + struct scomp { sdefl defl; Bit8u buf[SEEK_CURSOR_MAX_DEFL]; } *comp = new scomp; + for (Bit32u ii = (SEEK_CACHE_CURSOR_STEPS / 2), cursor_count = (f.decomp_size + (cursor_block - 1)) / cursor_block; ii < cursor_count; ii++) + { + if (!cursors[ii].cursor_out) continue; + idx_complen[0] = (Bit16u)ii; + ii = (SEEK_CACHE_CURSOR_STEPS / 2 - 1) + ((ii + (SEEK_CACHE_CURSOR_STEPS-1)) / SEEK_CACHE_CURSOR_STEPS * SEEK_CACHE_CURSOR_STEPS); + Bit32u complen = comp->defl.Run(comp->buf, (const unsigned char*)&cursors[idx_complen[0]], sizeof(SeekCursor)); + DBP_ASSERT(complen < SEEK_CURSOR_MAX_DEFL); + idx_complen[1] = (complen < (sizeof(SeekCursor)-10) ? (Bit16u)complen : (Bit16u)0); // store compressed only when beneficial + df->Write((Bit8u*)idx_complen, &(sz = (Bit16u)sizeof(idx_complen))); + if (idx_complen[1]) df->Write((Bit8u*)comp->buf, &idx_complen[1]); + else df->Write((Bit8u*)&cursors[idx_complen[0]], &(sz = (Bit16u)sizeof(SeekCursor))); + } + df->Close(); + delete df; + delete comp; + } }; +void Zip_File::PICHandler(Bitu implPtr) +{ + Zip_File& f = *(Zip_File*)implPtr; + ((Zip_DeflateUnpacker*)f.unpacker)->WriteSeekCache(f); + f.have_pic = 0; +} + struct Zip_Handle : public DOS_File { Bit32u ofs; @@ -2201,3 +2219,6 @@ void zipDrive::Uncompress(const Bit8u* src, Bit32u src_len, Bit8u* trg, Bit32u t DBP_ASSERT(status == miniz::TINFL_STATUS_HAS_MORE_OUTPUT || status == miniz::TINFL_STATUS_DONE); } } + +#include +DBP_SERIALIZE_SET_POINTER_LIST(PIC_EventHandler, zipDrive, Zip_File::PICHandler); diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index bb30ea87..0d9f0f16 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -644,9 +644,10 @@ void DBPSerialize_PIC(DBPArchive& ar) DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, SBLASTER); DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, TIMER); DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, MOUSE); - DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, unionDrive); + DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, unionDrive); // not stored anymore (old saves might have it though) DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, IDEController); DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, Voodoo); + DBP_SERIALIZE_EXTERN_POINTER_LIST(PIC_EventHandler, zipDrive); // not stored float pic_indices[PIC_QUEUESIZE]; Bitu pic_values[PIC_QUEUESIZE]; @@ -660,8 +661,9 @@ void DBPSerialize_PIC(DBPArchive& ar) { for (PICEntry* it = pic_queue.next_entry; it; it = it->next) { - // skip storing state irrelevant union drive event which has a pointer in its value + // skip storing state irrelevant union and zip drive events which keep a pointer in the value if (it->pic_event == DBPSerializePIC_EventHandlerunionDrivePtrs[0]) continue; + if (it->pic_event == DBPSerializePIC_EventHandlerzipDrivePtrs[0]) continue; pic_indices[pic_count] = it->index; pic_values[pic_count] = it->value; pic_events[pic_count] = it->pic_event; @@ -684,7 +686,7 @@ void DBPSerialize_PIC(DBPArchive& ar) DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, SBLASTER), DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, TIMER), DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, MOUSE), - DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, unionDrive), + DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, unionDrive), // not really needed but needs to be kept for compatibility with old saves DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, IDEController), DBP_SERIALIZE_GET_POINTER_LIST(PIC_EventHandler, Voodoo));