- allow the compact and pretty writers for JSON to coexist by wrapping the whole stuff into another class that calls the proper one as needed. Due to the implementation it is not possible to decide at run time how this should behave so there have to be two different objects for either mode.

- savegame code handles new format.
This commit is contained in:
Christoph Oelckers 2016-09-21 21:57:24 +02:00
parent ac3c00883d
commit 88c27e2cc0
12 changed files with 423 additions and 292 deletions

View file

@ -117,6 +117,7 @@ void STAT_Serialize(FSerializer &file);
bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompressedBuffer> &content);
FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH);
CVAR(Bool, save_formatted, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // use formatted JSON for saves (more readable but a larger files and a bit slower.
CVAR (Int, deathmatch, 0, CVAR_SERVERINFO|CVAR_LATCH);
CVAR (Bool, chasedemo, false, 0);
CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
@ -1778,7 +1779,7 @@ void G_LoadGame (const char* name, bool hidecon)
}
}
static bool CheckSingleWad (char *name, bool &printRequires, bool printwarn)
static bool CheckSingleWad (const char *name, bool &printRequires, bool printwarn)
{
if (name == NULL)
{
@ -1798,22 +1799,20 @@ static bool CheckSingleWad (char *name, bool &printRequires, bool printwarn)
}
}
printRequires = true;
delete[] name;
return false;
}
delete[] name;
return true;
}
// Return false if not all the needed wads have been loaded.
bool G_CheckSaveGameWads (PNGHandle *png, bool printwarn)
bool G_CheckSaveGameWads (FSerializer &arc, bool printwarn)
{
char *text;
bool printRequires = false;
FString text;
text = M_GetPNGText (png, "Game WAD");
arc("Game WAD", text);
CheckSingleWad (text, printRequires, printwarn);
text = M_GetPNGText (png, "Map WAD");
arc("Map WAD", text);
CheckSingleWad (text, printRequires, printwarn);
if (printRequires)
@ -2195,8 +2194,8 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
FSerializer savegameinfo; // this is for displayable info about the savegame
FSerializer savegameglobals; // and this for non-level related info that must be saved.
savegameinfo.OpenWriter();
savegameglobals.OpenWriter();
savegameinfo.OpenWriter(true);
savegameglobals.OpenWriter(save_formatted);
SaveVersion = SAVEVER;
PutSavePic(&savepic, SAVEPICWIDTH, SAVEPICHEIGHT);
@ -2267,16 +2266,16 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
delete[] savegame_content[1].mBuffer;
delete[] savegame_content[2].mBuffer;
// Check whether the file is ok. (todo when new format is ready)
bool success = true;
if (success)
// Check whether the file is ok by trying to open it.
FResourceFile *test = FResourceFile::OpenResourceFile(filename, nullptr, true);
if (test != nullptr)
{
delete test;
if (longsavemessages) Printf ("%s (%s)\n", GStrings("GGSAVED"), filename.GetChars());
else Printf ("%s\n", GStrings("GGSAVED"));
}
else Printf(PRINT_HIGH, "Save failed\n");
FResourceFile *test = FResourceFile::OpenResourceFile(filename, nullptr);
BackupSaveName = filename;

View file

@ -68,8 +68,8 @@ void G_ScreenShot (char *filename);
FString G_BuildSaveName (const char *prefix, int slot);
struct PNGHandle;
bool G_CheckSaveGameWads (PNGHandle *png, bool printwarn);
class FSerializer;
bool G_CheckSaveGameWads (FSerializer &arc, bool printwarn);
enum EFinishLevelType
{

View file

@ -94,7 +94,7 @@
void STAT_StartNewGame(const char *lev);
void STAT_ChangeLevel(const char *newl);
EXTERN_CVAR(Bool, save_formatted)
EXTERN_CVAR (Float, sv_gravity)
EXTERN_CVAR (Float, sv_aircontrol)
EXTERN_CVAR (Int, disableautosave)
@ -1489,7 +1489,7 @@ void G_SnapshotLevel ()
{
FSerializer arc;
if (arc.OpenWriter())
if (arc.OpenWriter(save_formatted))
{
SaveVersion = SAVEVER;
G_SerializeLevel(arc, false);

View file

@ -37,33 +37,3 @@ void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad)
{
}
}
void G_SerializeLevel(FSerializer &arc, bool);
CCMD(writejson)
{
DWORD t = I_MSTime();
FSerializer arc;
arc.OpenWriter();
G_SerializeLevel(arc, false);
arc.WriteObjects();
DWORD tt = I_MSTime();
Printf("JSON generation took %d ms\n", tt - t);
FILE *f = fopen("out.json", "wb");
unsigned siz;
const char *str = arc.GetOutput(&siz);
fwrite(str, 1, siz, f);
fclose(f);
/*
DWORD ttt = I_MSTime();
Printf("JSON save took %d ms\n", ttt - tt);
FDocument doc(arc.w->mOutString.GetString(), arc.w->mOutString.GetSize());
DWORD tttt = I_MSTime();
Printf("JSON parse took %d ms\n", tttt - ttt);
*/
}

View file

@ -80,7 +80,7 @@ PNGHandle::PNGHandle (FILE *file) : File(0), bDeleteFilePtr(true), ChunkPt(0)
File = new FileReader(file);
}
PNGHandle::PNGHandle (FileReader *file) : File(file), bDeleteFilePtr(false), ChunkPt(0) {}
PNGHandle::PNGHandle (FileReader *file, bool takereader) : File(file), bDeleteFilePtr(takereader), ChunkPt(0) {}
PNGHandle::~PNGHandle ()
{
for (unsigned int i = 0; i < TextChunks.Size(); ++i)
@ -374,15 +374,14 @@ bool M_GetPNGText (PNGHandle *png, const char *keyword, char *buffer, size_t buf
//
//==========================================================================
PNGHandle *M_VerifyPNG (FILE *file)
PNGHandle *M_VerifyPNG (FileReader *filer, bool takereader)
{
PNGHandle::Chunk chunk;
FileReader *filer;
PNGHandle *png;
DWORD data[2];
bool sawIDAT = false;
if (fread (&data, 1, 8, file) != 8)
if (filer->Read(&data, 8) != 8)
{
return NULL;
}
@ -390,7 +389,7 @@ PNGHandle *M_VerifyPNG (FILE *file)
{ // Does not have PNG signature
return NULL;
}
if (fread (&data, 1, 8, file) != 8)
if (filer->Read (&data, 8) != 8)
{
return NULL;
}
@ -400,8 +399,7 @@ PNGHandle *M_VerifyPNG (FILE *file)
}
// It looks like a PNG so far, so start creating a PNGHandle for it
png = new PNGHandle (file);
filer = png->File;
png = new PNGHandle (filer, takereader);
chunk.ID = data[1];
chunk.Offset = 16;
chunk.Size = BigLong((unsigned int)data[0]);
@ -430,7 +428,7 @@ PNGHandle *M_VerifyPNG (FILE *file)
sawIDAT = true;
}
chunk.ID = data[1];
chunk.Offset = ftell (file);
chunk.Offset = filer->Tell();
chunk.Size = BigLong((unsigned int)data[0]);
png->Chunks.Push (chunk);
@ -454,6 +452,12 @@ PNGHandle *M_VerifyPNG (FILE *file)
return NULL;
}
PNGHandle *M_VerifyPNG(FILE *file)
{
FileReader *fr = new FileReader(file);
return M_VerifyPNG(fr, true);
}
//==========================================================================
//
// M_FreePNG

View file

@ -80,7 +80,7 @@ struct PNGHandle
unsigned int ChunkPt;
PNGHandle(FILE *file);
PNGHandle(FileReader *file);
PNGHandle(FileReader *file, bool takereader = false);
~PNGHandle();
};
@ -88,7 +88,7 @@ struct PNGHandle
// the signature, but also checking for the IEND chunk. CRC checking of
// each chunk is not done. If it is valid, you get a PNGHandle to pass to
// the following functions.
PNGHandle *M_VerifyPNG (FileReader *file);
PNGHandle *M_VerifyPNG (FileReader *file, bool takereader = false);
PNGHandle *M_VerifyPNG (FILE *file);
// Finds a chunk in a PNG file. The file pointer will be positioned at the

View file

@ -46,6 +46,8 @@
#include "doomstat.h"
#include "gi.h"
#include "d_gui.h"
#include "serializer.h"
#include "resourcefiles/resourcefile.h"
@ -86,6 +88,10 @@ protected:
int commentRight;
int commentBottom;
// this needs to be kept in memory so that the texture can access it when it needs to.
FileReader *currentSavePic;
TArray<char> SavePicData;
static int InsertSaveNode (FSaveGameNode *node);
static void ReadSaveStrings ();
@ -221,103 +227,135 @@ void DLoadSaveMenu::ReadSaveStrings ()
{
// I_FindName only returns the file's name and not its full path
FString filepath = G_BuildSaveName (I_FindName(&c_file), -1);
FILE *file = fopen (filepath, "rb");
if (file != NULL)
FResourceFile *savegame = FResourceFile::OpenResourceFile(filepath, nullptr, true, true);
if (savegame != nullptr)
{
PNGHandle *png;
char sig[16];
char title[SAVESTRINGSIZE+1];
bool oldVer = true;
bool addIt = false;
bool oldVer = false;
bool missing = false;
// ZDoom 1.23 betas 21-33 have the savesig first.
// Earlier versions have the savesig second.
// Later versions have the savegame encapsulated inside a PNG.
//
// Old savegame versions are always added to the menu so
// the user can easily delete them if desired.
title[SAVESTRINGSIZE] = 0;
if (false)//NULL != (png = M_VerifyPNG (file)))
FResourceLump *info = savegame->FindLump("info.json");
if (info == nullptr)
{
char *ver = M_GetPNGText (png, "ZDoom Save Version");
char *engine = M_GetPNGText (png, "Engine");
if (ver != NULL)
{
if (!M_GetPNGText (png, "Title", title, SAVESTRINGSIZE))
{
strncpy (title, I_FindName(&c_file), SAVESTRINGSIZE);
}
if (strncmp (ver, "SAVESIG", 9) == 0 &&
atoi (ver+9) >= MINSAVEVER &&
engine != NULL)
{
// Was saved with a compatible ZDoom version,
// so check if it's for the current game.
// If it is, add it. Otherwise, ignore it.
char *iwad = M_GetPNGText (png, "Game WAD");
if (iwad != NULL)
{
if (stricmp (iwad, Wads.GetWadName (FWadCollection::IWAD_FILENUM)) == 0)
{
addIt = true;
oldVer = false;
missing = !G_CheckSaveGameWads (png, false);
}
delete[] iwad;
}
}
else
{ // An old version
addIt = true;
}
delete[] ver;
}
if (engine != NULL)
{
delete[] engine;
}
delete png;
// savegame info not found. This is not a savegame so leave it alone.
delete savegame;
continue;
}
else
void *data = info->CacheLump();
FSerializer arc;
if (arc.OpenReader((const char *)data, info->LumpSize, true))
{
fseek (file, 0, SEEK_SET);
if (fread (sig, 1, 16, file) == 16)
int savever = 0;
FString engine;
FString iwad;
FString title;
arc("Save Version", savever);
arc("Engine", engine);
arc("Game WAD", iwad);
arc("Title", title);
if (engine.Compare(GAMESIG) != 0 || savever > SAVEVER)
{
if (strncmp (sig, "ZDOOMSAVE", 9) == 0)
{
if (fread (title, 1, SAVESTRINGSIZE, file) == SAVESTRINGSIZE)
{
addIt = true;
}
}
else
{
memcpy (title, sig, 16);
if (fread (title + 16, 1, SAVESTRINGSIZE-16, file) == SAVESTRINGSIZE-16 &&
fread (sig, 1, 16, file) == 16 &&
strncmp (sig, "ZDOOMSAVE", 9) == 0)
{
addIt = true;
}
}
// different engine or newer version:
// not our business. Leave it alone.
delete savegame;
continue;
}
if (savever < MINSAVEVER)
{
// old, incompatible savegame. List as not usable.
oldVer = true;
}
else if (iwad.CompareNoCase(Wads.GetWadName(FWadCollection::IWAD_FILENUM)) == 0)
{
missing = !G_CheckSaveGameWads(arc, false);
}
}
if (addIt)
{
FSaveGameNode *node = new FSaveGameNode;
node->Filename = filepath;
node->bOldVersion = oldVer;
node->bMissingWads = missing;
memcpy (node->Title, title, SAVESTRINGSIZE);
InsertSaveNode (node);
strncpy(node->Title, title.GetChars(), SAVESTRINGSIZE);
InsertSaveNode(node);
delete savegame;
}
}
else // check for old formats.
{
FILE *file = fopen (filepath, "rb");
if (file != NULL)
{
PNGHandle *png;
char sig[16];
char title[SAVESTRINGSIZE+1];
bool oldVer = true;
bool addIt = false;
bool missing = false;
// ZDoom 1.23 betas 21-33 have the savesig first.
// Earlier versions have the savesig second.
// Later versions have the savegame encapsulated inside a PNG.
//
// Old savegame versions are always added to the menu so
// the user can easily delete them if desired.
title[SAVESTRINGSIZE] = 0;
if (NULL != (png = M_VerifyPNG (file)))
{
char *ver = M_GetPNGText (png, "ZDoom Save Version");
if (ver != NULL)
{
// An old version
if (!M_GetPNGText(png, "Title", title, SAVESTRINGSIZE))
{
strncpy(title, I_FindName(&c_file), SAVESTRINGSIZE);
}
addIt = true;
delete[] ver;
}
delete png;
}
else
{
fseek (file, 0, SEEK_SET);
if (fread (sig, 1, 16, file) == 16)
{
if (strncmp (sig, "ZDOOMSAVE", 9) == 0)
{
if (fread (title, 1, SAVESTRINGSIZE, file) == SAVESTRINGSIZE)
{
addIt = true;
}
}
else
{
memcpy (title, sig, 16);
if (fread (title + 16, 1, SAVESTRINGSIZE-16, file) == SAVESTRINGSIZE-16 &&
fread (sig, 1, 16, file) == 16 &&
strncmp (sig, "ZDOOMSAVE", 9) == 0)
{
addIt = true;
}
}
}
}
if (addIt)
{
FSaveGameNode *node = new FSaveGameNode;
node->Filename = filepath;
node->bOldVersion = true;
node->bMissingWads = false;
memcpy (node->Title, title, SAVESTRINGSIZE);
InsertSaveNode (node);
}
fclose (file);
}
fclose (file);
}
} while (I_FindNext (filefirst, &c_file) == 0);
I_FindClose (filefirst);
@ -407,6 +445,7 @@ DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, FListMenuDescriptor *desc)
listboxHeight = listboxRows * rowHeight + 1;
listboxRight = listboxLeft + listboxWidth;
listboxBottom = listboxTop + listboxHeight;
currentSavePic = nullptr;
commentLeft = savepicLeft;
commentTop = savepicTop + savepicHeight + 16;
@ -418,6 +457,8 @@ DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, FListMenuDescriptor *desc)
void DLoadSaveMenu::Destroy()
{
if (currentSavePic != nullptr) delete currentSavePic;
currentSavePic = nullptr;
ClearSaveStuff ();
}
@ -429,17 +470,23 @@ void DLoadSaveMenu::Destroy()
void DLoadSaveMenu::UnloadSaveData ()
{
if (SavePic != NULL)
if (SavePic != nullptr)
{
delete SavePic;
}
if (SaveComment != NULL)
if (SaveComment != nullptr)
{
V_FreeBrokenLines (SaveComment);
}
if (currentSavePic != nullptr)
{
delete currentSavePic;
}
SavePic = NULL;
SaveComment = NULL;
SavePic = nullptr;
SaveComment = nullptr;
currentSavePic = nullptr;
SavePicData.Clear();
}
//=============================================================================
@ -465,8 +512,7 @@ void DLoadSaveMenu::ClearSaveStuff ()
void DLoadSaveMenu::ExtractSaveData (int index)
{
FILE *file;
PNGHandle *png;
FResourceFile *resf;
FSaveGameNode *node;
UnloadSaveData ();
@ -475,66 +521,61 @@ void DLoadSaveMenu::ExtractSaveData (int index)
(node = SaveGames[index]) &&
!node->Filename.IsEmpty() &&
!node->bOldVersion &&
(file = fopen (node->Filename.GetChars(), "rb")) != NULL)
(resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), nullptr, true)) != nullptr)
{
if (NULL != (png = M_VerifyPNG (file)))
FResourceLump *info = resf->FindLump("info.json");
if (info == nullptr)
{
char *time, *pcomment, *comment;
size_t commentlen, totallen, timelen;
// this should not happen because the file has already been verified.
return;
}
void *data = info->CacheLump();
FSerializer arc;
if (arc.OpenReader((const char *)data, info->LumpSize, true))
{
FString time, pcomment, comment;
// Extract comment
time = M_GetPNGText (png, "Creation Time");
pcomment = M_GetPNGText (png, "Comment");
if (pcomment != NULL)
{
commentlen = strlen (pcomment);
}
else
{
commentlen = 0;
}
if (time != NULL)
{
timelen = strlen (time);
totallen = timelen + commentlen + 3;
}
else
{
timelen = 0;
totallen = commentlen + 1;
}
if (totallen != 0)
{
comment = new char[totallen];
arc("Creation Time", time);
arc("Comment", pcomment);
if (timelen)
{
memcpy (comment, time, timelen);
comment[timelen] = '\n';
comment[timelen+1] = '\n';
timelen += 2;
}
if (commentlen)
{
memcpy (comment + timelen, pcomment, commentlen);
}
comment[timelen+commentlen] = 0;
SaveComment = V_BreakLines (SmallFont, 216*screen->GetWidth()/640/CleanXfac, comment);
delete[] comment;
delete[] time;
delete[] pcomment;
}
comment = time;
if (time.Len() > 0) comment += "\n\n";
comment += pcomment;
SaveComment = V_BreakLines (SmallFont, 216*screen->GetWidth()/640/CleanXfac, comment.GetChars());
// Extract pic
SavePic = PNGTexture_CreateFromFile(png, node->Filename);
delete png;
if (SavePic->GetWidth() == 1 && SavePic->GetHeight() == 1)
FResourceLump *pic = resf->FindLump("savepic.png");
if (pic != nullptr)
{
delete SavePic;
SavePic = NULL;
FileReader *reader = pic->NewReader();
if (reader != nullptr)
{
// copy to a memory buffer which gets accessed through a memory reader and PNGHandle.
// We cannot use the actual lump as backing for the texture because that requires keeping the
// savegame file open.
SavePicData.Resize(pic->LumpSize);
reader->Read(&SavePicData[0], pic->LumpSize);
reader = new MemoryReader(&SavePicData[0], SavePicData.Size());
PNGHandle *png = M_VerifyPNG(reader);
if (png != nullptr)
{
SavePic = PNGTexture_CreateFromFile(png, node->Filename);
currentSavePic = reader; // must be kept so that the texture can read from it.
delete png;
if (SavePic->GetWidth() == 1 && SavePic->GetHeight() == 1)
{
delete SavePic;
SavePic = nullptr;
delete currentSavePic;
currentSavePic = nullptr;
SavePicData.Clear();
}
}
}
}
}
fclose (file);
delete resf;
}
}

View file

@ -270,7 +270,7 @@ FResourceFile *CheckDir(const char *filename, FileReader *file, bool quiet);
static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckLump };
FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader *file, bool quiet)
FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader *file, bool quiet, bool containeronly)
{
if (file == NULL)
{
@ -283,7 +283,7 @@ FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader
return NULL;
}
}
for(size_t i = 0; i < countof(funcs); i++)
for(size_t i = 0; i < countof(funcs) - containeronly; i++)
{
FResourceFile *resfile = funcs[i](filename, file, quiet);
if (resfile != NULL) return resfile;
@ -560,6 +560,24 @@ void FResourceFile::FindStrifeTeaserVoices ()
{
}
//==========================================================================
//
// Finds a lump by a given name. Used for savegames
//
//==========================================================================
FResourceLump *FResourceFile::FindLump(const char *name)
{
for (unsigned i = 0; i < NumLumps; i++)
{
FResourceLump *lump = GetLump(i);
if (!stricmp(name, lump->FullName))
{
return lump;
}
}
return nullptr;
}
//==========================================================================
//

View file

@ -77,7 +77,7 @@ private:
void JunkLeftoverFilters(void *lumps, size_t lumpsize, DWORD max);
public:
static FResourceFile *OpenResourceFile(const char *filename, FileReader *file, bool quiet = false);
static FResourceFile *OpenResourceFile(const char *filename, FileReader *file, bool quiet = false, bool containeronly = false);
static FResourceFile *OpenDirectory(const char *filename, bool quiet = false);
virtual ~FResourceFile();
FileReader *GetReader() const { return Reader; }
@ -88,6 +88,7 @@ public:
virtual void FindStrifeTeaserVoices ();
virtual bool Open(bool quiet) = 0;
virtual FResourceLump *GetLump(int no) = 0;
FResourceLump *FindLump(const char *name);
};
struct FUncompressedLump : public FResourceLump

View file

@ -3,10 +3,6 @@
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag
#ifdef _DEBUG
#define PRETTY
#endif
#include "rapidjson/rapidjson.h"
#include "rapidjson/writer.h"
#include "rapidjson/prettywriter.h"
@ -69,26 +65,126 @@ struct FJSONObject
struct FWriter
{
// Since this is done by template parameters, we'd have to template the entire serializer to allow this switch at run time. Argh!
#ifndef PRETTY
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::ASCII<> > Writer;
#else
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::ASCII<> > Writer;
#endif
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::ASCII<> > PrettyWriter;
Writer mWriter;
Writer *mWriter1;
PrettyWriter *mWriter2;
TArray<bool> mInObject;
rapidjson::StringBuffer mOutString;
TArray<DObject *> mDObjects;
TMap<DObject *, int> mObjectMap;
FWriter() : mWriter(mOutString)
{}
FWriter(bool pretty)
{
if (!pretty)
{
mWriter1 = new Writer(mOutString);
mWriter2 = nullptr;
}
else
{
mWriter1 = nullptr;
mWriter2 = new PrettyWriter(mOutString);
}
}
~FWriter()
{
if (mWriter1) delete mWriter1;
if (mWriter2) delete mWriter2;
}
bool inObject() const
{
return mInObject.Size() > 0 && mInObject.Last();
}
void StartObject()
{
if (mWriter1) mWriter1->StartObject();
else if (mWriter2) mWriter2->StartObject();
}
void EndObject()
{
if (mWriter1) mWriter1->EndObject();
else if (mWriter2) mWriter2->EndObject();
}
void StartArray()
{
if (mWriter1) mWriter1->StartArray();
else if (mWriter2) mWriter2->StartArray();
}
void EndArray()
{
if (mWriter1) mWriter1->EndArray();
else if (mWriter2) mWriter2->EndArray();
}
void Key(const char *k)
{
if (mWriter1) mWriter1->Key(k);
else if (mWriter2) mWriter2->Key(k);
}
void Null()
{
if (mWriter1) mWriter1->Null();
else if (mWriter2) mWriter2->Null();
}
void String(const char *k)
{
if (mWriter1) mWriter1->String(k);
else if (mWriter2) mWriter2->String(k);
}
void String(const char *k, int size)
{
if (mWriter1) mWriter1->String(k, size);
else if (mWriter2) mWriter2->String(k, size);
}
void Bool(bool k)
{
if (mWriter1) mWriter1->Bool(k);
else if (mWriter2) mWriter2->Bool(k);
}
void Int(int32_t k)
{
if (mWriter1) mWriter1->Int(k);
else if (mWriter2) mWriter2->Int(k);
}
void Int64(int64_t k)
{
if (mWriter1) mWriter1->Int64(k);
else if (mWriter2) mWriter2->Int64(k);
}
void Uint(uint32_t k)
{
if (mWriter1) mWriter1->Uint(k);
else if (mWriter2) mWriter2->Uint(k);
}
void Uint64(int64_t k)
{
if (mWriter1) mWriter1->Uint64(k);
else if (mWriter2) mWriter2->Uint64(k);
}
void Double(double k)
{
if (mWriter1) mWriter1->Double(k);
else if (mWriter2) mWriter2->Double(k);
}
};
//==========================================================================
@ -100,14 +196,13 @@ struct FWriter
struct FReader
{
TArray<FJSONObject> mObjects;
rapidjson::Value mDocObj; // just because RapidJSON is stupid and does not allow direct access to what's in the document.
rapidjson::Document mDoc;
FReader(const char *buffer, size_t length)
FReader(const char *buffer, size_t length, bool randomaccess)
{
rapidjson::Document doc;
doc.Parse(buffer, length);
mDocObj = doc.GetObject();
mObjects.Push(FJSONObject(&mDocObj)); // Todo: Decide if this should be made random access...
mDoc.Parse(buffer, length);
mObjects.Push(FJSONObject(&mDoc, randomaccess));
}
rapidjson::Value *FindKey(const char *key)
@ -149,12 +244,12 @@ struct FReader
//
//==========================================================================
bool FSerializer::OpenWriter(bool randomaccess)
bool FSerializer::OpenWriter(bool pretty)
{
if (w != nullptr || r != nullptr) return false;
w = new FWriter;
w = new FWriter(pretty);
BeginObject(nullptr, randomaccess);
BeginObject(nullptr);
return true;
}
@ -164,10 +259,10 @@ bool FSerializer::OpenWriter(bool randomaccess)
//
//==========================================================================
bool FSerializer::OpenReader(const char *buffer, size_t length)
bool FSerializer::OpenReader(const char *buffer, size_t length, bool randomaccess)
{
if (w != nullptr || r != nullptr) return false;
r = new FReader(buffer, length);
r = new FReader(buffer, length, randomaccess);
return true;
}
@ -177,21 +272,21 @@ bool FSerializer::OpenReader(const char *buffer, size_t length)
//
//==========================================================================
bool FSerializer::OpenReader(FCompressedBuffer *input)
bool FSerializer::OpenReader(FCompressedBuffer *input, bool randomaccess)
{
if (input->mSize <= 0 || input->mBuffer == nullptr) return false;
if (w != nullptr || r != nullptr) return false;
if (input->mMethod == METHOD_STORED)
{
r = new FReader((char*)input->mBuffer, input->mSize);
r = new FReader((char*)input->mBuffer, input->mSize, randomaccess);
return true;
}
else
{
char *unpacked = new char[input->mSize];
input->Decompress(unpacked);
r = new FReader(unpacked, input->mSize);
r = new FReader(unpacked, input->mSize, randomaccess);
return true;
}
}
@ -260,7 +355,7 @@ void FSerializer::WriteKey(const char *key)
{
I_Error("missing element name");
}
w->mWriter.Key(key);
w->Key(key);
}
}
@ -275,7 +370,7 @@ bool FSerializer::BeginObject(const char *name, bool randomaccess)
if (isWriting())
{
WriteKey(name);
w->mWriter.StartObject();
w->StartObject();
w->mInObject.Push(true);
}
else
@ -312,7 +407,7 @@ void FSerializer::EndObject()
{
if (w->inObject())
{
w->mWriter.EndObject();
w->EndObject();
w->mInObject.Pop();
}
else
@ -337,7 +432,7 @@ bool FSerializer::BeginArray(const char *name)
if (isWriting())
{
WriteKey(name);
w->mWriter.StartArray();
w->StartArray();
w->mInObject.Push(false);
}
else
@ -374,7 +469,7 @@ void FSerializer::EndArray()
{
if (!w->inObject())
{
w->mWriter.EndArray();
w->EndArray();
w->mInObject.Pop();
}
else
@ -404,19 +499,19 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe
}
WriteKey(key);
w->mWriter.StartArray();
w->StartArray();
for (int i = 0; i < 5; i++)
{
if (i == 0 && args[i] < 0 && P_IsACSSpecial(special))
{
w->mWriter.String(FName(ENamedName(-args[i])).GetChars());
w->String(FName(ENamedName(-args[i])).GetChars());
}
else
{
w->mWriter.Int(args[i]);
w->Int(args[i]);
}
}
w->mWriter.EndArray();
w->EndArray();
}
else
{
@ -465,11 +560,11 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num)
WriteKey(key);
if (num < 0)
{
w->mWriter.String(FName(ENamedName(-num)).GetChars());
w->String(FName(ENamedName(-num)).GetChars());
}
else
{
w->mWriter.Int(num);
w->Int(num);
}
}
else
@ -527,7 +622,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d
{
if (w->inObject() && def != nullptr && *def == spritenum) return *this;
WriteKey(key);
w->mWriter.String(sprites[spritenum].name, 4);
w->String(sprites[spritenum].name, 4);
}
else
{
@ -562,7 +657,7 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr)
if (isWriting())
{
WriteKey(key);
w->mWriter.String(charptr);
w->String(charptr);
}
else
{
@ -593,7 +688,7 @@ FSerializer &FSerializer::AddString(const char *key, const char *charptr)
if (isWriting())
{
WriteKey(key);
w->mWriter.String(charptr);
w->String(charptr);
}
return *this;
}
@ -608,7 +703,7 @@ unsigned FSerializer::GetSize(const char *group)
{
if (isWriting()) return -1; // we do not know this when writing.
const rapidjson::Value &val = r->mDocObj[group];
const rapidjson::Value &val = r->mDoc[group];
if (!val.IsArray()) return -1;
return val.Size();
}
@ -645,15 +740,15 @@ void FSerializer::WriteObjects()
player_t *player;
BeginObject(nullptr);
w->mWriter.Key("classtype");
w->mWriter.String(obj->GetClass()->TypeName.GetChars());
w->Key("classtype");
w->String(obj->GetClass()->TypeName.GetChars());
if (obj->IsKindOf(RUNTIME_CLASS(AActor)) &&
(player = static_cast<AActor *>(obj)->player) &&
player->mo == obj)
{
w->mWriter.Key("playerindex");
w->mWriter.Int(int(player - players));
w->Key("playerindex");
w->Int(int(player - players));
}
obj->SerializeUserVars(*this);
@ -755,7 +850,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *def
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.Bool(value);
arc.w->Bool(value);
}
}
else
@ -789,7 +884,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.Int64(value);
arc.w->Int64(value);
}
}
else
@ -823,7 +918,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint6
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.Uint64(value);
arc.w->Uint64(value);
}
}
else
@ -858,7 +953,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.Int(value);
arc.w->Int(value);
}
}
else
@ -892,7 +987,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint3
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.Uint(value);
arc.w->Uint(value);
}
}
else
@ -968,7 +1063,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.Double(value);
arc.w->Double(value);
}
}
else
@ -1077,14 +1172,14 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
if (!value.Exists())
{
arc.WriteKey(key);
arc.w->mWriter.Null();
arc.w->Null();
return arc;
}
if (value.isNull())
{
// save 'no texture' in a more space saving way
arc.WriteKey(key);
arc.w->mWriter.Int(0);
arc.w->Int(0);
return arc;
}
FTextureID chk = value;
@ -1101,10 +1196,10 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
name = pic->Name;
}
arc.WriteKey(key);
arc.w->mWriter.StartArray();
arc.w->mWriter.String(name);
arc.w->mWriter.Int(pic->UseType);
arc.w->mWriter.EndArray();
arc.w->StartArray();
arc.w->String(name);
arc.w->Int(pic->UseType);
arc.w->EndArray();
}
}
else
@ -1215,7 +1310,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
arc.w->mWriter.String(value.GetChars());
arc.w->String(value.GetChars());
}
}
else
@ -1252,11 +1347,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicCol
}
arc.WriteKey(key);
arc.w->mWriter.StartArray();
arc.w->mWriter.Uint(cm->Color);
arc.w->mWriter.Uint(cm->Fade);
arc.w->mWriter.Uint(cm->Desaturate);
arc.w->mWriter.EndArray();
arc.w->StartArray();
arc.w->Uint(cm->Color);
arc.w->Uint(cm->Fade);
arc.w->Uint(cm->Desaturate);
arc.w->EndArray();
}
else
{
@ -1300,8 +1395,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
{
arc.WriteKey(key);
const char *sn = (const char*)sid;
if (sn != nullptr) arc.w->mWriter.String(sn);
else arc.w->mWriter.Null();
if (sn != nullptr) arc.w->String(sn);
else arc.w->Null();
}
}
else
@ -1342,11 +1437,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor
arc.WriteKey(key);
if (clst == nullptr)
{
arc.w->mWriter.Null();
arc.w->Null();
}
else
{
arc.w->mWriter.String(clst->TypeName.GetChars());
arc.w->String(clst->TypeName.GetChars());
}
}
}
@ -1388,11 +1483,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl
arc.WriteKey(key);
if (clst == nullptr)
{
arc.w->mWriter.Null();
arc.w->Null();
}
else
{
arc.w->mWriter.String(clst->TypeName.GetChars());
arc.w->String(clst->TypeName.GetChars());
}
}
}
@ -1436,7 +1531,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
arc.WriteKey(key);
if (state == nullptr)
{
arc.w->mWriter.Null();
arc.w->Null();
}
else
{
@ -1444,14 +1539,14 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
if (info != NULL)
{
arc.w->mWriter.StartArray();
arc.w->mWriter.String(info->TypeName.GetChars());
arc.w->mWriter.Uint((uint32_t)(state - info->OwnedStates));
arc.w->mWriter.EndArray();
arc.w->StartArray();
arc.w->String(info->TypeName.GetChars());
arc.w->Uint((uint32_t)(state - info->OwnedStates));
arc.w->EndArray();
}
else
{
arc.w->mWriter.Null();
arc.w->Null();
}
}
}
@ -1507,11 +1602,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDial
arc.WriteKey(key);
if (node == nullptr)
{
arc.w->mWriter.Null();
arc.w->Null();
}
else
{
arc.w->mWriter.Uint(node->ThisNodeNum);
arc.w->Uint(node->ThisNodeNum);
}
}
}
@ -1560,11 +1655,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p
arc.WriteKey(key);
if (pstr == nullptr)
{
arc.w->mWriter.Null();
arc.w->Null();
}
else
{
arc.w->mWriter.String(pstr->GetChars());
arc.w->String(pstr->GetChars());
}
}
}
@ -1604,7 +1699,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString
if (!arc.w->inObject() || def == nullptr || pstr.Compare(*def) != 0)
{
arc.WriteKey(key);
arc.w->mWriter.String(pstr.GetChars());
arc.w->String(pstr.GetChars());
}
}
else
@ -1645,11 +1740,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr
arc.WriteKey(key);
if (pstr == nullptr)
{
arc.w->mWriter.Null();
arc.w->Null();
}
else
{
arc.w->mWriter.String(pstr);
arc.w->String(pstr);
}
}
}
@ -1719,16 +1814,16 @@ FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &value, N
switch (value.type)
{
case NumericValue::NM_signed:
arc.w->mWriter.Int64(value.signedval);
arc.w->Int64(value.signedval);
break;
case NumericValue::NM_unsigned:
arc.w->mWriter.Uint64(value.unsignedval);
arc.w->Uint64(value.unsignedval);
break;
case NumericValue::NM_float:
arc.w->mWriter.Double(value.floatval);
arc.w->Double(value.floatval);
break;
default:
arc.w->mWriter.Null();
arc.w->Null();
break;
}
}

View file

@ -58,9 +58,9 @@ public:
{
Close();
}
bool OpenWriter(bool randomaccess = true);
bool OpenReader(const char *buffer, size_t length);
bool OpenReader(FCompressedBuffer *input);
bool OpenWriter(bool pretty = true);
bool OpenReader(const char *buffer, size_t length, bool randomaccess = false);
bool OpenReader(FCompressedBuffer *input, bool randomaccess = false);
void Close();
bool BeginObject(const char *name, bool randomaccess = false);
void EndObject();

View file

@ -66,6 +66,7 @@ protected:
FString SourceFile;
BYTE *Pixels;
Span **Spans;
FileReader *fr;
BYTE BitDepth;
BYTE ColorType;
@ -209,6 +210,8 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename
DWORD len, id;
int i;
if (lumpnum == -1) fr = &lump;
UseType = TEX_MiscPatch;
LeftOffset = 0;
TopOffset = 0;
@ -462,7 +465,7 @@ void FPNGTexture::MakeTexture ()
}
else
{
lump = new FileReader(SourceFile.GetChars());
lump = fr;// new FileReader(SourceFile.GetChars());
}
Pixels = new BYTE[Width*Height];
@ -599,7 +602,7 @@ void FPNGTexture::MakeTexture ()
delete[] tempix;
}
}
delete lump;
if (lump != fr) delete lump;
}
//===========================================================================
@ -624,7 +627,7 @@ int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo
}
else
{
lump = new FileReader(SourceFile.GetChars());
lump = fr;// new FileReader(SourceFile.GetChars());
}
lump->Seek(33, SEEK_SET);
@ -683,7 +686,7 @@ int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo
lump->Read(&len, 4);
lump->Read(&id, 4);
M_ReadIDAT (lump, Pixels, Width, Height, pixwidth, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
delete lump;
if (lump != fr) delete lump;
switch (ColorType)
{