From 88c27e2cc011873f1ae726b5b1507c29a4270faa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 21 Sep 2016 21:57:24 +0200 Subject: [PATCH] - 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. --- src/g_game.cpp | 25 ++- src/g_game.h | 4 +- src/g_level.cpp | 4 +- src/json.cpp | 30 --- src/m_png.cpp | 20 +- src/m_png.h | 4 +- src/menu/loadsavemenu.cpp | 321 ++++++++++++++++------------- src/resourcefiles/resourcefile.cpp | 22 +- src/resourcefiles/resourcefile.h | 3 +- src/serializer.cpp | 265 ++++++++++++++++-------- src/serializer.h | 6 +- src/textures/pngtexture.cpp | 11 +- 12 files changed, 423 insertions(+), 292 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 7ed832e0a..aee960345 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -117,6 +117,7 @@ void STAT_Serialize(FSerializer &file); bool WriteZip(const char *filename, TArray &filenames, TArray &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; diff --git a/src/g_game.h b/src/g_game.h index bf4099854..0b0d094f5 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -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 { diff --git a/src/g_level.cpp b/src/g_level.cpp index 2acb1335c..e795f4a34 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -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); diff --git a/src/json.cpp b/src/json.cpp index 982d9fb79..1bdc5d90e 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -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); - */ -} diff --git a/src/m_png.cpp b/src/m_png.cpp index 35cd8587e..b122212a5 100644 --- a/src/m_png.cpp +++ b/src/m_png.cpp @@ -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 diff --git a/src/m_png.h b/src/m_png.h index ef25d70d4..9fb9eeeff 100644 --- a/src/m_png.h +++ b/src/m_png.h @@ -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 diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 6333ab3bf..91492e88d 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -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 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; } } diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index c66430a66..2daf4aee1 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -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; +} //========================================================================== // diff --git a/src/resourcefiles/resourcefile.h b/src/resourcefiles/resourcefile.h index b96075f5d..b79c2cc59 100644 --- a/src/resourcefiles/resourcefile.h +++ b/src/resourcefiles/resourcefile.h @@ -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 diff --git a/src/serializer.cpp b/src/serializer.cpp index ea18a3a58..33b90524f 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -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 > Writer; -#else - typedef rapidjson::PrettyWriter > Writer; -#endif + typedef rapidjson::PrettyWriter > PrettyWriter; - Writer mWriter; + Writer *mWriter1; + PrettyWriter *mWriter2; TArray mInObject; rapidjson::StringBuffer mOutString; TArray mDObjects; TMap 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 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(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; } } diff --git a/src/serializer.h b/src/serializer.h index 312d53393..a5a7fda52 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -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(); diff --git a/src/textures/pngtexture.cpp b/src/textures/pngtexture.cpp index e47fa62c0..d34b00607 100644 --- a/src/textures/pngtexture.cpp +++ b/src/textures/pngtexture.cpp @@ -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) {