mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 22:11:43 +00:00
- implemented saving of new format savegames as zips. The code for that was adapted from zipdir.c.
This commit is contained in:
parent
810ef8f775
commit
ac3c00883d
15 changed files with 253 additions and 104 deletions
|
@ -2580,7 +2580,7 @@ void D_DoomMain (void)
|
||||||
{
|
{
|
||||||
FString file(v);
|
FString file(v);
|
||||||
FixPathSeperator (file);
|
FixPathSeperator (file);
|
||||||
DefaultExtension (file, ".zds" SAVEGAME_EXT);
|
DefaultExtension (file, "." SAVEGAME_EXT);
|
||||||
G_LoadGame (file);
|
G_LoadGame (file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -962,32 +962,6 @@ PClass *FArchive::ReadStoredClass (const PClass *wanttype)
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FArchive::UserWriteClass (PClass *type)
|
|
||||||
{
|
|
||||||
BYTE id;
|
|
||||||
|
|
||||||
if (type == NULL)
|
|
||||||
{
|
|
||||||
id = 2;
|
|
||||||
Write (&id, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DWORD *arcid;
|
|
||||||
if (NULL == (arcid = ClassToArchive.CheckKey(type)))
|
|
||||||
{
|
|
||||||
id = 1;
|
|
||||||
Write (&id, 1);
|
|
||||||
WriteClass (type);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
id = 0;
|
|
||||||
Write (&id, 1);
|
|
||||||
WriteCount (*arcid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FArchive::UserReadClass (PClass *&type)
|
void FArchive::UserReadClass (PClass *&type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,7 +152,6 @@ virtual void Read (void *mem, unsigned int len);
|
||||||
void WriteCount (DWORD count);
|
void WriteCount (DWORD count);
|
||||||
DWORD ReadCount ();
|
DWORD ReadCount ();
|
||||||
|
|
||||||
void UserWriteClass (PClass *info);
|
|
||||||
void UserReadClass (PClass *&info);
|
void UserReadClass (PClass *&info);
|
||||||
template<typename T> void UserReadClass(T *&info)
|
template<typename T> void UserReadClass(T *&info)
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,6 +85,8 @@
|
||||||
#include "p_spec.h"
|
#include "p_spec.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
#include "w_zip.h"
|
||||||
|
#include "resourcefiles/resourcefile.h"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
@ -112,6 +114,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
void G_DoAutoSave ();
|
void G_DoAutoSave ();
|
||||||
|
|
||||||
void STAT_Serialize(FSerializer &file);
|
void STAT_Serialize(FSerializer &file);
|
||||||
|
bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompressedBuffer> &content);
|
||||||
|
|
||||||
FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH);
|
FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH);
|
||||||
CVAR (Int, deathmatch, 0, CVAR_SERVERINFO|CVAR_LATCH);
|
CVAR (Int, deathmatch, 0, CVAR_SERVERINFO|CVAR_LATCH);
|
||||||
|
@ -1886,7 +1889,7 @@ void G_DoLoadGame ()
|
||||||
|
|
||||||
SaveVersion = 0;
|
SaveVersion = 0;
|
||||||
if (!M_GetPNGText (png, "ZDoom Save Version", sigcheck, 20) ||
|
if (!M_GetPNGText (png, "ZDoom Save Version", sigcheck, 20) ||
|
||||||
0 != strncmp (sigcheck, SAVESIG, 9) || // ZDOOMSAVE is the first 9 chars
|
0 != strncmp (sigcheck, "SAVEVER", 9) || // ZDOOMSAVE is the first 9 chars
|
||||||
(SaveVersion = atoi (sigcheck+9)) < MINSAVEVER)
|
(SaveVersion = atoi (sigcheck+9)) < MINSAVEVER)
|
||||||
{
|
{
|
||||||
delete png;
|
delete png;
|
||||||
|
@ -2045,7 +2048,7 @@ FString G_BuildSaveName (const char *prefix, int slot)
|
||||||
name << prefix;
|
name << prefix;
|
||||||
if (slot >= 0)
|
if (slot >= 0)
|
||||||
{
|
{
|
||||||
name.AppendFormat("%d.zds" SAVEGAME_EXT, slot);
|
name.AppendFormat("%d." SAVEGAME_EXT, slot);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -2166,6 +2169,7 @@ static void PutSavePic (FileWriter *file, int width, int height)
|
||||||
void G_DoSaveGame (bool okForQuicksave, FString filename, const char *description)
|
void G_DoSaveGame (bool okForQuicksave, FString filename, const char *description)
|
||||||
{
|
{
|
||||||
TArray<FCompressedBuffer> savegame_content;
|
TArray<FCompressedBuffer> savegame_content;
|
||||||
|
TArray<FString> savegame_filenames;
|
||||||
|
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
|
||||||
|
@ -2203,9 +2207,10 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
M_AppendPNGText(&savepic, "Current Map", level.MapName);
|
M_AppendPNGText(&savepic, "Current Map", level.MapName);
|
||||||
M_FinishPNG(&savepic);
|
M_FinishPNG(&savepic);
|
||||||
|
|
||||||
|
int ver = SAVEVER;
|
||||||
savegameinfo.AddString("Software", buf)
|
savegameinfo.AddString("Software", buf)
|
||||||
.AddString("Engine", GAMESIG)
|
.AddString("Engine", GAMESIG)
|
||||||
.AddString("Save Version", SAVESIG)
|
("Save Version", ver)
|
||||||
.AddString("Title", description)
|
.AddString("Title", description)
|
||||||
.AddString("Current Map", level.MapName);
|
.AddString("Current Map", level.MapName);
|
||||||
|
|
||||||
|
@ -2232,17 +2237,36 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
FRandom::StaticWriteRNGState(savegameglobals);
|
FRandom::StaticWriteRNGState(savegameglobals);
|
||||||
P_WriteACSDefereds(savegameglobals);
|
P_WriteACSDefereds(savegameglobals);
|
||||||
P_WriteACSVars(savegameglobals);
|
P_WriteACSVars(savegameglobals);
|
||||||
|
G_WriteVisited(savegameglobals);
|
||||||
|
|
||||||
|
|
||||||
if (NextSkill != -1)
|
if (NextSkill != -1)
|
||||||
{
|
{
|
||||||
savegameglobals("nextskill", NextSkill);
|
savegameglobals("nextskill", NextSkill);
|
||||||
}
|
}
|
||||||
|
|
||||||
//G_WriteSnapshots (stdfile);
|
auto picdata = savepic.GetBuffer();
|
||||||
|
FCompressedBuffer bufpng = { picdata->Size(), picdata->Size(), METHOD_STORED, 0, crc32(0, &(*picdata)[0], picdata->Size()), (char*)&(*picdata)[0] };
|
||||||
|
|
||||||
|
savegame_content.Push(bufpng);
|
||||||
|
savegame_filenames.Push("savepic.png");
|
||||||
|
savegame_content.Push(savegameinfo.GetCompressedOutput());
|
||||||
|
savegame_filenames.Push("info.json");
|
||||||
|
savegame_content.Push(savegameglobals.GetCompressedOutput());
|
||||||
|
savegame_filenames.Push("globals.json");
|
||||||
|
|
||||||
|
G_WriteSnapshots (savegame_filenames, savegame_content);
|
||||||
|
|
||||||
|
|
||||||
|
WriteZip(filename, savegame_filenames, savegame_content);
|
||||||
|
|
||||||
M_NotifyNewSave (filename.GetChars(), description, okForQuicksave);
|
M_NotifyNewSave (filename.GetChars(), description, okForQuicksave);
|
||||||
|
|
||||||
|
// delete the JSON buffers we created just above. Everything else will
|
||||||
|
// either still be needed or taken care of automatically.
|
||||||
|
delete[] savegame_content[1].mBuffer;
|
||||||
|
delete[] savegame_content[2].mBuffer;
|
||||||
|
|
||||||
// Check whether the file is ok. (todo when new format is ready)
|
// Check whether the file is ok. (todo when new format is ready)
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (success)
|
if (success)
|
||||||
|
@ -2252,6 +2276,8 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
}
|
}
|
||||||
else Printf(PRINT_HIGH, "Save failed\n");
|
else Printf(PRINT_HIGH, "Save failed\n");
|
||||||
|
|
||||||
|
FResourceFile *test = FResourceFile::OpenResourceFile(filename, nullptr);
|
||||||
|
|
||||||
BackupSaveName = filename;
|
BackupSaveName = filename;
|
||||||
|
|
||||||
// We don't need the snapshot any longer.
|
// We don't need the snapshot any longer.
|
||||||
|
|
|
@ -1487,8 +1487,6 @@ void G_SnapshotLevel ()
|
||||||
|
|
||||||
if (level.info->isValid())
|
if (level.info->isValid())
|
||||||
{
|
{
|
||||||
level.info->snapshotVer = SAVEVER;
|
|
||||||
|
|
||||||
FSerializer arc;
|
FSerializer arc;
|
||||||
|
|
||||||
if (arc.OpenWriter())
|
if (arc.OpenWriter())
|
||||||
|
@ -1514,7 +1512,6 @@ void G_UnSnapshotLevel (bool hubLoad)
|
||||||
|
|
||||||
if (level.info->isValid())
|
if (level.info->isValid())
|
||||||
{
|
{
|
||||||
SaveVersion = level.info->snapshotVer;
|
|
||||||
FSerializer arc;
|
FSerializer arc;
|
||||||
if (!arc.OpenReader(&level.info->Snapshot)) return;
|
if (!arc.OpenReader(&level.info->Snapshot)) return;
|
||||||
|
|
||||||
|
@ -1563,83 +1560,68 @@ void G_UnSnapshotLevel (bool hubLoad)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static void writeSnapShot (FArchive &arc, level_info_t *i)
|
void G_WriteSnapshots(TArray<FString> &filenames, TArray<FCompressedBuffer> &buffers)
|
||||||
{
|
|
||||||
arc << i->snapshotVer << i->MapName;
|
|
||||||
//i->snapshot->Serialize (arc);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void G_WriteSnapshots (FILE *file)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
FString filename;
|
||||||
|
|
||||||
#if 0
|
|
||||||
for (i = 0; i < wadlevelinfos.Size(); i++)
|
for (i = 0; i < wadlevelinfos.Size(); i++)
|
||||||
{
|
{
|
||||||
if (wadlevelinfos[i].snapshot)
|
if (wadlevelinfos[i].Snapshot.mCompressedSize > 0)
|
||||||
{
|
{
|
||||||
FPNGChunkArchive arc (file, SNAP_ID);
|
filename << wadlevelinfos[i].MapName << ".json";
|
||||||
writeSnapShot (arc, (level_info_t *)&wadlevelinfos[i]);
|
filename.ToLower();
|
||||||
|
filenames.Push(filename);
|
||||||
|
buffers.Push(wadlevelinfos[i].Snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (TheDefaultLevelInfo.snapshot != NULL)
|
if (TheDefaultLevelInfo.Snapshot.mCompressedSize > 0)
|
||||||
{
|
{
|
||||||
FPNGChunkArchive arc (file, DSNP_ID);
|
filename << TheDefaultLevelInfo.MapName << ".json";
|
||||||
writeSnapShot(arc, &TheDefaultLevelInfo);
|
filename.ToLower();
|
||||||
|
filenames.Push(filename);
|
||||||
|
buffers.Push(TheDefaultLevelInfo.Snapshot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
FPNGChunkArchive *arc = NULL;
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void G_WriteVisited(FSerializer &arc)
|
||||||
|
{
|
||||||
|
if (arc.BeginArray("visited"))
|
||||||
|
{
|
||||||
// Write out which levels have been visited
|
// Write out which levels have been visited
|
||||||
for (i = 0; i < wadlevelinfos.Size(); ++i)
|
for (auto & wi : wadlevelinfos)
|
||||||
{
|
{
|
||||||
if (wadlevelinfos[i].flags & LEVEL_VISITED)
|
if (wi.flags & LEVEL_VISITED)
|
||||||
{
|
{
|
||||||
if (arc == NULL)
|
arc.AddString(nullptr, wi.MapName);
|
||||||
{
|
|
||||||
arc = new FPNGChunkArchive (file, VIST_ID);
|
|
||||||
}
|
|
||||||
(*arc) << wadlevelinfos[i].MapName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
arc.EndArray();
|
||||||
if (arc != NULL)
|
|
||||||
{
|
|
||||||
FString empty = "";
|
|
||||||
(*arc) << empty;
|
|
||||||
delete arc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store player classes to be used when spawning a random class
|
// Store player classes to be used when spawning a random class
|
||||||
if (multiplayer)
|
if (multiplayer)
|
||||||
{
|
{
|
||||||
FPNGChunkArchive arc2 (file, RCLS_ID);
|
arc.Array("randomclasses", SinglePlayerClass, MAXPLAYERS);
|
||||||
for (i = 0; i < MAXPLAYERS; ++i)
|
|
||||||
{
|
|
||||||
SBYTE cnum = SinglePlayerClass[i];
|
|
||||||
arc2 << cnum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store player classes that are currently in use
|
if (arc.BeginObject("playerclasses"))
|
||||||
FPNGChunkArchive arc3 (file, PCLS_ID);
|
{
|
||||||
for (i = 0; i < MAXPLAYERS; ++i)
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||||
{
|
{
|
||||||
BYTE pnum;
|
|
||||||
if (playeringame[i])
|
if (playeringame[i])
|
||||||
{
|
{
|
||||||
pnum = i;
|
FString key;
|
||||||
arc3 << pnum;
|
key.Format("%d", i);
|
||||||
arc3.UserWriteClass (players[i].cls);
|
arc(key, players[i].cls);
|
||||||
}
|
}
|
||||||
pnum = 255;
|
}
|
||||||
arc3 << pnum;
|
arc.EndObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,7 +1647,6 @@ void G_ReadSnapshots (PNGHandle *png)
|
||||||
arc << snapver;
|
arc << snapver;
|
||||||
arc << MapName;
|
arc << MapName;
|
||||||
i = FindLevelInfo (MapName);
|
i = FindLevelInfo (MapName);
|
||||||
i->snapshotVer = snapver;
|
|
||||||
#if 0
|
#if 0
|
||||||
i->snapshot = new FCompressedMemFile;
|
i->snapshot = new FCompressedMemFile;
|
||||||
i->snapshot->Serialize (arc);
|
i->snapshot->Serialize (arc);
|
||||||
|
@ -1681,7 +1662,6 @@ void G_ReadSnapshots (PNGHandle *png)
|
||||||
|
|
||||||
arc << snapver;
|
arc << snapver;
|
||||||
arc << MapName;
|
arc << MapName;
|
||||||
TheDefaultLevelInfo.snapshotVer = snapver;
|
|
||||||
#if 0
|
#if 0
|
||||||
TheDefaultLevelInfo.snapshot = new FCompressedMemFile;
|
TheDefaultLevelInfo.snapshot = new FCompressedMemFile;
|
||||||
TheDefaultLevelInfo.snapshot->Serialize (arc);
|
TheDefaultLevelInfo.snapshot->Serialize (arc);
|
||||||
|
|
|
@ -295,7 +295,6 @@ struct level_info_t
|
||||||
SBYTE WallVertLight, WallHorizLight;
|
SBYTE WallVertLight, WallHorizLight;
|
||||||
int musicorder;
|
int musicorder;
|
||||||
FCompressedBuffer Snapshot;
|
FCompressedBuffer Snapshot;
|
||||||
DWORD snapshotVer;
|
|
||||||
TArray<acsdefered_t> deferred;
|
TArray<acsdefered_t> deferred;
|
||||||
float skyspeed1;
|
float skyspeed1;
|
||||||
float skyspeed2;
|
float skyspeed2;
|
||||||
|
@ -535,7 +534,8 @@ void G_SnapshotLevel (void);
|
||||||
void G_UnSnapshotLevel (bool keepPlayers);
|
void G_UnSnapshotLevel (bool keepPlayers);
|
||||||
struct PNGHandle;
|
struct PNGHandle;
|
||||||
void G_ReadSnapshots (PNGHandle *png);
|
void G_ReadSnapshots (PNGHandle *png);
|
||||||
void G_WriteSnapshots (FILE *file);
|
void G_WriteSnapshots (TArray<FString> &, TArray<FCompressedBuffer> &);
|
||||||
|
void G_WriteVisited(FSerializer &arc);
|
||||||
void G_ClearHubInfo();
|
void G_ClearHubInfo();
|
||||||
|
|
||||||
enum ESkillProperty
|
enum ESkillProperty
|
||||||
|
|
|
@ -248,8 +248,7 @@ void level_info_t::Reset()
|
||||||
WallVertLight = +8;
|
WallVertLight = +8;
|
||||||
F1Pic = "";
|
F1Pic = "";
|
||||||
musicorder = 0;
|
musicorder = 0;
|
||||||
Snapshot = { 0,0,0,0,nullptr };
|
Snapshot = { 0,0,0,0,0,nullptr };
|
||||||
snapshotVer = 0;
|
|
||||||
deferred.Clear();
|
deferred.Clear();
|
||||||
skyspeed1 = skyspeed2 = 0.f;
|
skyspeed1 = skyspeed2 = 0.f;
|
||||||
fadeto = 0;
|
fadeto = 0;
|
||||||
|
|
|
@ -241,7 +241,7 @@ void DLoadSaveMenu::ReadSaveStrings ()
|
||||||
|
|
||||||
title[SAVESTRINGSIZE] = 0;
|
title[SAVESTRINGSIZE] = 0;
|
||||||
|
|
||||||
if (NULL != (png = M_VerifyPNG (file)))
|
if (false)//NULL != (png = M_VerifyPNG (file)))
|
||||||
{
|
{
|
||||||
char *ver = M_GetPNGText (png, "ZDoom Save Version");
|
char *ver = M_GetPNGText (png, "ZDoom Save Version");
|
||||||
char *engine = M_GetPNGText (png, "Engine");
|
char *engine = M_GetPNGText (png, "Engine");
|
||||||
|
@ -251,7 +251,7 @@ void DLoadSaveMenu::ReadSaveStrings ()
|
||||||
{
|
{
|
||||||
strncpy (title, I_FindName(&c_file), SAVESTRINGSIZE);
|
strncpy (title, I_FindName(&c_file), SAVESTRINGSIZE);
|
||||||
}
|
}
|
||||||
if (strncmp (ver, SAVESIG, 9) == 0 &&
|
if (strncmp (ver, "SAVESIG", 9) == 0 &&
|
||||||
atoi (ver+9) >= MINSAVEVER &&
|
atoi (ver+9) >= MINSAVEVER &&
|
||||||
engine != NULL)
|
engine != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -898,6 +898,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload)
|
||||||
I_Error("Savegame is from a different level");
|
I_Error("Savegame is from a different level");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
arc("saveversion", SaveVersion);
|
||||||
|
|
||||||
Renderer->StartSerialize(arc);
|
Renderer->StartSerialize(arc);
|
||||||
if (arc.isReading())
|
if (arc.isReading())
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
#include "file_zip.h"
|
#include "file_zip.h"
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
|
@ -265,6 +266,7 @@ bool FZipFile::Open(bool quiet)
|
||||||
lump_p->Flags = LUMPF_ZIPFILE | LUMPFZIP_NEEDFILESTART;
|
lump_p->Flags = LUMPF_ZIPFILE | LUMPFZIP_NEEDFILESTART;
|
||||||
lump_p->Method = BYTE(zip_fh->Method);
|
lump_p->Method = BYTE(zip_fh->Method);
|
||||||
lump_p->GPFlags = zip_fh->Flags;
|
lump_p->GPFlags = zip_fh->Flags;
|
||||||
|
lump_p->CRC32 = zip_fh->CRC32;
|
||||||
lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize);
|
lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize);
|
||||||
lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset);
|
lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset);
|
||||||
lump_p->CheckEmbedded();
|
lump_p->CheckEmbedded();
|
||||||
|
@ -308,10 +310,11 @@ FCompressedBuffer FZipFile::GetRawLump(int lumpnum)
|
||||||
{
|
{
|
||||||
if ((unsigned)lumpnum >= NumLumps)
|
if ((unsigned)lumpnum >= NumLumps)
|
||||||
{
|
{
|
||||||
return{ 0,0,0,0,nullptr };
|
return{ 0,0,0,0,0,nullptr };
|
||||||
}
|
}
|
||||||
FZipLump *lmp = &Lumps[lumpnum];
|
FZipLump *lmp = &Lumps[lumpnum];
|
||||||
FCompressedBuffer cbuf = { (unsigned)lmp->LumpSize, (unsigned)lmp->CompressedSize, lmp->Method, lmp->GPFlags, new char[lmp->CompressedSize] };
|
|
||||||
|
FCompressedBuffer cbuf = { (unsigned)lmp->LumpSize, (unsigned)lmp->CompressedSize, lmp->Method, lmp->GPFlags, lmp->CRC32, new char[lmp->CompressedSize] };
|
||||||
Reader->Seek(lmp->Position, SEEK_SET);
|
Reader->Seek(lmp->Position, SEEK_SET);
|
||||||
Reader->Read(cbuf.mBuffer, lmp->CompressedSize);
|
Reader->Read(cbuf.mBuffer, lmp->CompressedSize);
|
||||||
return cbuf;
|
return cbuf;
|
||||||
|
@ -426,3 +429,169 @@ FResourceFile *CheckZip(const char *filename, FileReader *file, bool quiet)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// time_to_dos
|
||||||
|
//
|
||||||
|
// Converts time from struct tm to the DOS format used by zip files.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void time_to_dos(struct tm *time, unsigned short *dosdate, unsigned short *dostime)
|
||||||
|
{
|
||||||
|
if (time == NULL || time->tm_year < 80)
|
||||||
|
{
|
||||||
|
*dosdate = *dostime = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dosdate = LittleShort((time->tm_year - 80) * 512 + (time->tm_mon + 1) * 32 + time->tm_mday);
|
||||||
|
*dostime = LittleShort(time->tm_hour * 2048 + time->tm_min * 32 + time->tm_sec / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// append_to_zip
|
||||||
|
//
|
||||||
|
// Write a given file to the zipFile.
|
||||||
|
//
|
||||||
|
// zipfile: zip object to be written to
|
||||||
|
//
|
||||||
|
// returns: position = success, -1 = error
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time)
|
||||||
|
{
|
||||||
|
FZipLocalFileHeader local;
|
||||||
|
int position;
|
||||||
|
|
||||||
|
local.Magic = ZIP_LOCALFILE;
|
||||||
|
local.VersionToExtract[0] = 20;
|
||||||
|
local.VersionToExtract[1] = 0;
|
||||||
|
local.Flags = content.mMethod == METHOD_DEFLATE ? LittleShort(2) : LittleShort((uint16_t)content.mZipFlags);
|
||||||
|
local.Method = LittleShort(content.mMethod);
|
||||||
|
local.ModDate = date;
|
||||||
|
local.ModTime = time;
|
||||||
|
local.CRC32 = content.mCRC32;
|
||||||
|
local.UncompressedSize = LittleLong(content.mSize);
|
||||||
|
local.CompressedSize = LittleLong(content.mCompressedSize);
|
||||||
|
local.NameLength = LittleShort((unsigned short)strlen(filename));
|
||||||
|
local.ExtraLength = 0;
|
||||||
|
|
||||||
|
// Fill in local directory header.
|
||||||
|
|
||||||
|
position = (int)ftell(zip_file);
|
||||||
|
|
||||||
|
// Write out the header, file name, and file data.
|
||||||
|
if (fwrite(&local, sizeof(local), 1, zip_file) != 1 ||
|
||||||
|
fwrite(filename, strlen(filename), 1, zip_file) != 1 ||
|
||||||
|
fwrite(content.mBuffer, 1, content.mCompressedSize, zip_file) != content.mCompressedSize)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// write_central_dir
|
||||||
|
//
|
||||||
|
// Writes the central directory entry for a file.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
int AppendCentralDirectory(FILE *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time, int position)
|
||||||
|
{
|
||||||
|
FZipCentralDirectoryInfo dir;
|
||||||
|
|
||||||
|
dir.Magic = ZIP_CENTRALFILE;
|
||||||
|
dir.VersionMadeBy[0] = 20;
|
||||||
|
dir.VersionMadeBy[1] = 0;
|
||||||
|
dir.VersionToExtract[0] = 20;
|
||||||
|
dir.VersionToExtract[1] = 0;
|
||||||
|
dir.Flags = content.mMethod == METHOD_DEFLATE ? LittleShort(2) : LittleShort((uint16_t)content.mZipFlags);
|
||||||
|
dir.Method = LittleShort(content.mMethod);
|
||||||
|
dir.ModTime = time;
|
||||||
|
dir.ModDate = date;
|
||||||
|
dir.CRC32 = content.mCRC32;
|
||||||
|
dir.CompressedSize = LittleLong(content.mCompressedSize);
|
||||||
|
dir.UncompressedSize = LittleLong(content.mSize);
|
||||||
|
dir.NameLength = LittleShort((unsigned short)strlen(filename));
|
||||||
|
dir.ExtraLength = 0;
|
||||||
|
dir.CommentLength = 0;
|
||||||
|
dir.StartingDiskNumber = 0;
|
||||||
|
dir.InternalAttributes = 0;
|
||||||
|
dir.ExternalAttributes = 0;
|
||||||
|
dir.LocalHeaderOffset = LittleLong(position);
|
||||||
|
|
||||||
|
if (fwrite(&dir, sizeof(dir), 1, zip_file) != 1 ||
|
||||||
|
fwrite(filename, strlen(filename), 1, zip_file) != 1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompressedBuffer> &content)
|
||||||
|
{
|
||||||
|
// try to determine local time
|
||||||
|
struct tm *ltime;
|
||||||
|
time_t ttime;
|
||||||
|
uint16_t mydate, mytime;
|
||||||
|
ttime = time(nullptr);
|
||||||
|
ltime = localtime(&ttime);
|
||||||
|
time_to_dos(ltime, &mydate, &mytime);
|
||||||
|
|
||||||
|
TArray<int> positions;
|
||||||
|
|
||||||
|
if (filenames.Size() != content.Size()) return false;
|
||||||
|
|
||||||
|
FILE *f = fopen(filename, "wb");
|
||||||
|
if (f != nullptr)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < filenames.Size(); i++)
|
||||||
|
{
|
||||||
|
int pos = AppendToZip(f, filenames[i], content[i], mydate, mytime);
|
||||||
|
if (pos == -1)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
positions.Push(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dirofs = (int)ftell(f);
|
||||||
|
for (unsigned i = 0; i < filenames.Size(); i++)
|
||||||
|
{
|
||||||
|
if (AppendCentralDirectory(f, filenames[i], content[i], mydate, mytime, positions[i]) < 0)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the directory terminator.
|
||||||
|
FZipEndOfCentralDirectory dirend;
|
||||||
|
dirend.Magic = ZIP_ENDOFDIR;
|
||||||
|
dirend.DiskNumber = 0;
|
||||||
|
dirend.FirstDisk = 0;
|
||||||
|
dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort(filenames.Size());
|
||||||
|
dirend.DirectoryOffset = dirofs;
|
||||||
|
dirend.DirectorySize = LittleLong(ftell(f) - dirofs);
|
||||||
|
dirend.ZipCommentLength = 0;
|
||||||
|
if (fwrite(&dirend, sizeof(dirend), 1, f) != 1)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ struct FCompressedBuffer
|
||||||
unsigned mCompressedSize;
|
unsigned mCompressedSize;
|
||||||
int mMethod;
|
int mMethod;
|
||||||
int mZipFlags;
|
int mZipFlags;
|
||||||
|
unsigned mCRC32;
|
||||||
char *mBuffer;
|
char *mBuffer;
|
||||||
|
|
||||||
bool Decompress(char *destbuffer);
|
bool Decompress(char *destbuffer);
|
||||||
|
@ -41,6 +42,7 @@ struct FZipLump : public FResourceLump
|
||||||
BYTE Method;
|
BYTE Method;
|
||||||
int CompressedSize;
|
int CompressedSize;
|
||||||
int Position;
|
int Position;
|
||||||
|
unsigned CRC32;
|
||||||
|
|
||||||
virtual FileReader *GetReader();
|
virtual FileReader *GetReader();
|
||||||
virtual int FillCache();
|
virtual int FillCache();
|
||||||
|
|
|
@ -690,11 +690,12 @@ const char *FSerializer::GetOutput(unsigned *len)
|
||||||
|
|
||||||
FCompressedBuffer FSerializer::GetCompressedOutput()
|
FCompressedBuffer FSerializer::GetCompressedOutput()
|
||||||
{
|
{
|
||||||
if (isReading()) return{ 0,0,0,0,nullptr };
|
if (isReading()) return{ 0,0,0,0,0,nullptr };
|
||||||
FCompressedBuffer buff;
|
FCompressedBuffer buff;
|
||||||
EndObject();
|
EndObject();
|
||||||
buff.mSize = (unsigned)w->mOutString.GetSize();
|
buff.mSize = (unsigned)w->mOutString.GetSize();
|
||||||
buff.mZipFlags = 0;
|
buff.mZipFlags = 0;
|
||||||
|
buff.mCRC32 = crc32(0, (const Bytef*)w->mOutString.GetString(), buff.mSize);
|
||||||
|
|
||||||
uint8_t *compressbuf = new uint8_t[buff.mSize+1];
|
uint8_t *compressbuf = new uint8_t[buff.mSize+1];
|
||||||
|
|
||||||
|
@ -731,6 +732,7 @@ FCompressedBuffer FSerializer::GetCompressedOutput()
|
||||||
buff.mMethod = METHOD_DEFLATE;
|
buff.mMethod = METHOD_DEFLATE;
|
||||||
memcpy(buff.mBuffer, compressbuf, buff.mCompressedSize);
|
memcpy(buff.mBuffer, compressbuf, buff.mCompressedSize);
|
||||||
delete[] compressbuf;
|
delete[] compressbuf;
|
||||||
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
bool OpenWriter();
|
bool OpenWriter(bool randomaccess = true);
|
||||||
bool OpenReader(const char *buffer, size_t length);
|
bool OpenReader(const char *buffer, size_t length);
|
||||||
bool OpenReader(FCompressedBuffer *input);
|
bool OpenReader(FCompressedBuffer *input);
|
||||||
void Close();
|
void Close();
|
||||||
|
|
|
@ -527,6 +527,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, OneLevel &l, OneLevel
|
||||||
("levelname", l.Levelname)
|
("levelname", l.Levelname)
|
||||||
.EndObject();
|
.EndObject();
|
||||||
}
|
}
|
||||||
|
return arc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void STAT_Serialize(FSerializer &arc)
|
void STAT_Serialize(FSerializer &arc)
|
||||||
|
|
|
@ -81,10 +81,6 @@ const char *GetVersionString();
|
||||||
// SVN revision ever got.
|
// SVN revision ever got.
|
||||||
#define SAVEVER 4550
|
#define SAVEVER 4550
|
||||||
|
|
||||||
#define SAVEVERSTRINGIFY2(x) #x
|
|
||||||
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
|
||||||
#define SAVESIG "ZDOOMSAVE" SAVEVERSTRINGIFY(SAVEVER)
|
|
||||||
|
|
||||||
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
||||||
#define GAMESIG "ZDOOM"
|
#define GAMESIG "ZDOOM"
|
||||||
#define BASEWAD "zdoom.pk3"
|
#define BASEWAD "zdoom.pk3"
|
||||||
|
|
Loading…
Reference in a new issue