From 887d60628d02354d40283f2b1e98212c5803270e Mon Sep 17 00:00:00 2001 From: jacob1 Date: Wed, 27 Dec 2017 11:50:09 -0500 Subject: [PATCH] use c++11, use unique_ptr in GameSave::SerializeOPS --- SConscript | 5 +- src/bson/BSON.cpp | 3 +- src/client/GameSave.cpp | 278 ++++++++++++++--------------- src/client/GameSave.h | 11 ++ src/gui/game/GameController.cpp | 2 +- src/gui/save/LocalSaveActivity.cpp | 2 +- 6 files changed, 150 insertions(+), 151 deletions(-) diff --git a/SConscript b/SConscript index ca62728eb..bd64e29eb 100644 --- a/SConscript +++ b/SConscript @@ -396,10 +396,7 @@ elif not GetOption('help'): env = conf.Finish() if not msvc: - if platform == "Windows": - env.Append(CXXFLAGS=['-std=gnu++98']) - else: - env.Append(CXXFLAGS=['-std=c++98']) + env.Append(CXXFLAGS=['-std=c++11']) env.Append(CXXFLAGS=['-Wno-invalid-offsetof']) if platform == "Linux": env.Append(CXXFLAGS=['-Wno-unused-result']) diff --git a/src/bson/BSON.cpp b/src/bson/BSON.cpp index 45f689721..ec4eee7dc 100644 --- a/src/bson/BSON.cpp +++ b/src/bson/BSON.cpp @@ -664,7 +664,8 @@ int bson_finish( bson *b ) { } void bson_destroy( bson *b ) { - bson_free( b->data ); + if (b->data) + bson_free( b->data ); b->err = 0; b->data = 0; b->cur = 0; diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 4b71939d8..4b3593d55 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -262,7 +263,15 @@ std::vector GameSave::Serialise() char * GameSave::Serialise(unsigned int & dataSize) { - return serialiseOPS(dataSize); + try + { + return serialiseOPS(dataSize); + } + catch (BuildException e) + { + std::cout << e.what() << std::endl; + return NULL; + } } vector2d GameSave::Translate(vector2d translate) @@ -1935,24 +1944,12 @@ void GameSave::readPSv(char * data, int dataLength) char * GameSave::serialiseOPS(unsigned int & dataLength) { - //Particle *particles = sim->parts; - unsigned char *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *finalData = NULL, *outputData = NULL, *soapLinkData = NULL; - unsigned char *pressData = NULL, *vxData = NULL, *vyData = NULL, *ambientData = NULL; - unsigned *partsPosLink = NULL, *partsPosFirstMap = NULL, *partsPosCount = NULL, *partsPosLastMap = NULL; - unsigned partsCount = 0, *partsSaveIndex = NULL; - unsigned *elementCount = new unsigned[PT_NUM]; - unsigned int partsDataLen, partsPosDataLen, fanDataLen, wallDataLen,finalDataLen, outputDataLen, soapLinkDataLen; - unsigned int pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0; int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH; - int x, y, i, wallDataFound = 0; - int posCount, signsCount; + int x, y, i; // minimum version this save is compatible with // when building, this number may be increased depending on what elements are used // or what properties are detected int minimumMajorVersion = 90, minimumMinorVersion = 2; - bson b; - - std::fill(elementCount, elementCount+PT_NUM, 0); //Get coords in blocks blockX = 0;//orig_x0/CELL; @@ -1968,26 +1965,26 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) fullW = blockW*CELL; fullH = blockH*CELL; - //Copy fan and wall data - wallData = (unsigned char*)malloc(blockW*blockH); - wallDataLen = blockW*blockH; - fanData = (unsigned char*)malloc((blockW*blockH)*2); - fanDataLen = 0; - pressData = (unsigned char*)malloc((blockW*blockH)*2); - vxData = (unsigned char*)malloc((blockW*blockH)*2); - vyData = (unsigned char*)malloc((blockW*blockH)*2); - ambientData = (unsigned char*)malloc((blockW*blockH)*2); + // Copy fan and wall data + auto wallData = std::unique_ptr(new unsigned char[blockWidth*blockHeight]); + bool hasWallData = false; + auto fanData = std::unique_ptr(new unsigned char[blockWidth*blockHeight*2]); + auto pressData = std::unique_ptr(new unsigned char[blockWidth*blockHeight*2]); + auto vxData = std::unique_ptr(new unsigned char[blockWidth*blockHeight*2]); + auto vyData = std::unique_ptr(new unsigned char[blockWidth*blockHeight*2]); + auto ambientData = std::unique_ptr(new unsigned char[blockWidth*blockHeight*2]); + std::fill(&ambientData[0], &ambientData[blockWidth*blockHeight*2], 0); if (!wallData || !fanData || !pressData || !vxData || !vyData || !ambientData) - { - puts("Save Error, out of memory\n"); - outputData = NULL; - goto fin; - } + throw BuildException("Save error, out of memory (blockmaps)"); + unsigned int wallDataLen = blockWidth*blockHeight, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0; + for(x = blockX; x < blockX+blockW; x++) { for(y = blockY; y < blockY+blockH; y++) { wallData[(y-blockY)*blockW+(x-blockX)] = blockMap[y][x]; + if (blockMap[y][x]) + hasWallData = true; //save pressure and x/y velocity grids float pres = std::max(-255.0f,std::min(255.0f,pressure[y][x]))+256.0f; @@ -2006,8 +2003,6 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) ambientData[ambientDataLen++] = tempTemp; ambientData[ambientDataLen++] = tempTemp >> 8; - if(blockMap[y][x] && !wallDataFound) - wallDataFound = 1; if(blockMap[y][x]==WL_FAN) { i = (int)(fanVelX[y][x]*64.0f+127.5f); @@ -2021,26 +2016,23 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) } } } - if(!fanDataLen) - { - free(fanData); - fanData = NULL; - } - if(!wallDataFound) - { - free(wallData); - wallData = NULL; - } //Index positions of all particles, using linked lists //partsPosFirstMap is pmap for the first particle in each position //partsPosLastMap is pmap for the last particle in each position //partsPosCount is the number of particles in each position //partsPosLink contains, for each particle, (i<<8)|1 of the next particle in the same position - partsPosFirstMap = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned)); - partsPosLastMap = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned)); - partsPosCount = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned)); - partsPosLink = (unsigned int *)calloc(NPART, sizeof(unsigned)); + auto partsPosFirstMap = std::unique_ptr(new unsigned[fullW*fullH]); + auto partsPosLastMap = std::unique_ptr(new unsigned[fullW*fullH]); + auto partsPosCount = std::unique_ptr(new unsigned[fullW*fullH]); + auto partsPosLink = std::unique_ptr(new unsigned[NPART]); + if (!partsPosFirstMap || !partsPosLastMap || !partsPosCount || !partsPosLink) + throw BuildException("Save error, out of memory (partmaps)"); + std::fill(&partsPosFirstMap[0], &partsPosFirstMap[fullW*fullH], 0); + std::fill(&partsPosLastMap[0], &partsPosLastMap[fullW*fullH], 0); + std::fill(&partsPosCount[0], &partsPosCount[fullW*fullH], 0); + std::fill(&partsPosLink[0], &partsPosLink[NPART], 0); + unsigned int soapCount = 0; for(i = 0; i < particlesCount; i++) { if(particles[i].type) @@ -2067,13 +2059,15 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) } //Store number of particles in each position - partsPosData = (unsigned char*)malloc(fullW*fullH*3); - partsPosDataLen = 0; + auto partsPosData = std::unique_ptr(new unsigned char[fullW*fullH*3]); + unsigned int partsPosDataLen = 0; + if (!partsPosData) + throw BuildException("Save error, out of memory (partposdata)"); for (y=0;y>16; partsPosData[partsPosDataLen++] = (posCount&0x0000FF00)>>8; partsPosData[partsPosDataLen++] = (posCount&0x000000FF); @@ -2086,10 +2080,13 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) | pavg | tmp[3+4] | tmp2[2] | tmp2 | ctype[2] | vy | vx | dcololour | ctype[1] | tmp[2] | tmp[1] | life[2] | life[1] | temp dbl len| life[2] means a second byte (for a 16 bit field) if life[1] is present */ - partsData = (unsigned char *)malloc(NPART * (sizeof(Particle)+1)); - partsDataLen = 0; - partsSaveIndex = (unsigned int *)calloc(NPART, sizeof(unsigned)); - partsCount = 0; + auto partsData = std::unique_ptr(new unsigned char[NPART * (sizeof(Particle)+1)]); + unsigned int partsDataLen = 0; + auto partsSaveIndex = std::unique_ptr(new unsigned[NPART]); + unsigned int partsCount = 0; + if (!partsData || !partsSaveIndex) + throw BuildException("Save error, out of memory (partsdata)"); + std::fill(&partsSaveIndex[0], &partsSaveIndex[NPART], 0); for (y=0;y>8; + if (particles[i].type == PT_SOAP) + soapCount++; + if (particles[i].type == PT_RPEL && particles[i].ctype) { RESTRICTVERSION(91, 4); @@ -2264,52 +2263,57 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) } } - soapLinkData = (unsigned char*)malloc(3*elementCount[PT_SOAP]); - soapLinkDataLen = 0; - //Iterate through particles in the same order that they were saved - for (y=0;y(); + unsigned int soapLinkDataLen = 0; + if (soapCount) { - for (x=0;x(soapLinkData)); + + //Iterate through particles in the same order that they were saved + for (y=0;y>8; - - if (particles[i].type==PT_SOAP) + //Find the first particle in this position + i = partsPosFirstMap[y*fullW + x]; + + //Loop while there is a pmap entry + while (i) { - //Only save forward link for each particle, back links can be deduced from other forward links - //linkedIndex is index within saved particles + 1, 0 means not saved or no link - - unsigned linkedIndex = 0; - if ((particles[i].ctype&2) && particles[i].tmp>=0 && particles[i].tmp>8; + + if (particles[i].type==PT_SOAP) { - linkedIndex = partsSaveIndex[particles[i].tmp]; + //Only save forward link for each particle, back links can be deduced from other forward links + //linkedIndex is index within saved particles + 1, 0 means not saved or no link + + unsigned linkedIndex = 0; + if ((particles[i].ctype&2) && particles[i].tmp>=0 && particles[i].tmp>16; + soapLinkData[soapLinkDataLen++] = (linkedIndex&0x00FF00)>>8; + soapLinkData[soapLinkDataLen++] = (linkedIndex&0x0000FF); } - soapLinkData[soapLinkDataLen++] = (linkedIndex&0xFF0000)>>16; - soapLinkData[soapLinkDataLen++] = (linkedIndex&0x00FF00)>>8; - soapLinkData[soapLinkDataLen++] = (linkedIndex&0x0000FF); + + //Get the pmap entry for the next particle in the same position + i = partsPosLink[i]; } - - //Get the pmap entry for the next particle in the same position - i = partsPosLink[i]; } } } - if(!soapLinkDataLen) - { - free(soapLinkData); - soapLinkData = NULL; - } - if(!partsDataLen) - { - free(partsData); - partsData = NULL; - } + + bson b; + b.data = NULL; + auto bson_deleter = [](bson * b) { bson_destroy(b); }; + // Use unique_ptr with a custom deleter to ensure that bson_destroy is called even when an exception is thrown + std::unique_ptr b_ptr(&b, bson_deleter); bson_init(&b); bson_append_start_object(&b, "origin"); @@ -2340,34 +2344,38 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) //bson_append_int(&b, "leftSelectedElement", sl); //bson_append_int(&b, "rightSelectedElement", sr); //bson_append_int(&b, "activeMenu", active_menu); - if (partsData) - bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData, partsDataLen); - if (partsPosData) - bson_append_binary(&b, "partsPos", BSON_BIN_USER, (const char *)partsPosData, partsPosDataLen); - if (wallData) - bson_append_binary(&b, "wallMap", BSON_BIN_USER, (const char *)wallData, wallDataLen); - if (fanData) - bson_append_binary(&b, "fanMap", BSON_BIN_USER, (const char *)fanData, fanDataLen); - if (pressData) - bson_append_binary(&b, "pressMap", (char)BSON_BIN_USER, (const char*)pressData, pressDataLen); - if (vxData) - bson_append_binary(&b, "vxMap", (char)BSON_BIN_USER, (const char*)vxData, vxDataLen); - if (vyData) - bson_append_binary(&b, "vyMap", (char)BSON_BIN_USER, (const char*)vyData, vyDataLen); - if (ambientData && this->aheatEnable) - bson_append_binary(&b, "ambientMap", (char)BSON_BIN_USER, (const char*)ambientData, ambientDataLen); - if (soapLinkData) - bson_append_binary(&b, "soapLinks", BSON_BIN_USER, (const char *)soapLinkData, soapLinkDataLen); - if (partsData && palette.size()) + if (partsData && partsDataLen) { - bson_append_start_array(&b, "palette"); - for(std::vector::iterator iter = palette.begin(), end = palette.end(); iter != end; ++iter) + bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData.get(), partsDataLen); + + if (palette.size()) { - bson_append_int(&b, (*iter).first.c_str(), (*iter).second); + bson_append_start_array(&b, "palette"); + for(std::vector::iterator iter = palette.begin(), end = palette.end(); iter != end; ++iter) + { + bson_append_int(&b, (*iter).first.c_str(), (*iter).second); + } + bson_append_finish_array(&b); } - bson_append_finish_array(&b); + + if (partsPosData && partsPosDataLen) + bson_append_binary(&b, "partsPos", BSON_BIN_USER, (const char *)partsPosData.get(), partsPosDataLen); } - signsCount = 0; + if (wallData && hasWallData) + bson_append_binary(&b, "wallMap", BSON_BIN_USER, (const char *)wallData.get(), wallDataLen); + if (fanData && fanDataLen) + bson_append_binary(&b, "fanMap", BSON_BIN_USER, (const char *)fanData.get(), fanDataLen); + if (pressData && pressDataLen) + bson_append_binary(&b, "pressMap", (char)BSON_BIN_USER, (const char*)pressData.get(), pressDataLen); + if (vxData && vxDataLen) + bson_append_binary(&b, "vxMap", (char)BSON_BIN_USER, (const char*)vxData.get(), vxDataLen); + if (vyData && vyDataLen) + bson_append_binary(&b, "vyMap", (char)BSON_BIN_USER, (const char*)vyData.get(), vyDataLen); + if (ambientData && this->aheatEnable && ambientDataLen) + bson_append_binary(&b, "ambientMap", (char)BSON_BIN_USER, (const char*)ambientData.get(), ambientDataLen); + if (soapLinkData && soapLinkDataLen) + bson_append_binary(&b, "soapLinks", BSON_BIN_USER, (const char *)soapLinkData, soapLinkDataLen); + unsigned int signsCount = 0; for (size_t i = 0; i < signs.size(); i++) { if(signs[i].text.length() && signs[i].x>=0 && signs[i].x<=fullW && signs[i].y>=0 && signs[i].y<=fullH) @@ -2399,12 +2407,13 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) bson_append_finish_object(&b); } if (bson_finish(&b) == BSON_ERROR) - goto fin; + throw BuildException("Error building bson data"); - finalData = (unsigned char *)bson_data(&b); - finalDataLen = bson_size(&b); - outputDataLen = finalDataLen*2+12; - outputData = new unsigned char[outputDataLen]; + unsigned char *finalData = (unsigned char*)bson_data(&b); + unsigned int finalDataLen = bson_size(&b); + auto outputData = std::unique_ptr(new unsigned char[finalDataLen*2+12]); + if (!outputData) + throw BuildException("Save error, out of memory (finalData): " + format::NumberToString(finalDataLen*2+12)); outputData[0] = 'O'; outputData[1] = 'P'; @@ -2419,39 +2428,20 @@ char * GameSave::serialiseOPS(unsigned int & dataLength) outputData[10] = finalDataLen >> 16; outputData[11] = finalDataLen >> 24; - if (BZ2_bzBuffToBuffCompress((char*)(outputData+12), &outputDataLen, (char*)finalData, bson_size(&b), 9, 0, 0) != BZ_OK) + unsigned int compressedSize = finalDataLen*2, bz2ret; + if ((bz2ret = BZ2_bzBuffToBuffCompress((char*)(outputData.get()+12), &compressedSize, (char*)finalData, bson_size(&b), 9, 0, 0)) != BZ_OK) { - puts("Save Error\n"); - delete [] outputData; - dataLength = 0; - outputData = NULL; - goto fin; + throw BuildException("Save error, could not compress (ret " + format::NumberToString(bz2ret) + ")"); } #ifdef DEBUG - printf("compressed data: %d\n", outputDataLen); + printf("compressed data: %d\n", compressedSize); #endif - dataLength = outputDataLen + 12; + dataLength = compressedSize + 12; -fin: - bson_destroy(&b); - free(partsData); - free(wallData); - free(pressData); - free(vxData); - free(vyData); - free(ambientData); - free(fanData); - delete[] elementCount; - free(partsSaveIndex); - free(soapLinkData); - free(partsPosData); - free(partsPosFirstMap); - free(partsPosLastMap); - free(partsPosCount); - free(partsPosLink); - - return (char*)outputData; + char *saveData = new char[dataLength]; + std::copy(&outputData[0], &outputData[dataLength], &saveData[0]); + return saveData; } void GameSave::ConvertBsonToJson(bson_iterator *iter, Json::Value *j, int depth) diff --git a/src/client/GameSave.h b/src/client/GameSave.h index 860cd6c9e..89caaa11b 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -26,6 +26,17 @@ public: ~ParseException() throw() {} }; +struct BuildException: public std::exception { + std::string message; +public: + BuildException(std::string message_): message(message_) {} + const char * what() const throw() + { + return message.c_str(); + } + ~BuildException() throw() {} +}; + class GameSave { public: diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index 05eeb1244..356949a99 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -1241,7 +1241,7 @@ void GameController::OpenLocalSaveWindow(bool asCurrent) std::vector saveData = gameSave->Serialise(); if (saveData.size() == 0) new ErrorMessage("Error", "Unable to serialize game data."); - else if (Client::Ref().WriteFile(gameSave->Serialise(), gameModel->GetSaveFile()->GetName())) + else if (Client::Ref().WriteFile(saveData, gameModel->GetSaveFile()->GetName())) new ErrorMessage("Error", "Unable to write save file."); else gameModel->SetInfoTip("Saved Successfully"); diff --git a/src/gui/save/LocalSaveActivity.cpp b/src/gui/save/LocalSaveActivity.cpp index 153fa4851..61cdff6d6 100644 --- a/src/gui/save/LocalSaveActivity.cpp +++ b/src/gui/save/LocalSaveActivity.cpp @@ -121,7 +121,7 @@ void LocalSaveActivity::saveWrite(std::string finalFilename) std::vector saveData = gameSave->Serialise(); if (saveData.size() == 0) new ErrorMessage("Error", "Unable to serialize game data."); - else if (Client::Ref().WriteFile(gameSave->Serialise(), finalFilename)) + else if (Client::Ref().WriteFile(saveData, finalFilename)) new ErrorMessage("Error", "Unable to write save file."); else {