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) {