diff --git a/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp b/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp index 2d88de1aa93..374a44e7f08 100644 --- a/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp @@ -1374,8 +1374,16 @@ void ScriptDialog::OnLoad() file.registerParser( "WaypointsList", AsciiString::TheEmptyString, ParseWaypointDataChunk ); file.registerParser( "ScriptTeams", AsciiString::TheEmptyString, ParseTeamsDataChunk ); file.registerParser( "ScriptsPlayers", AsciiString::TheEmptyString, ParsePlayersDataChunk ); - if (!file.parse(this)) { - throw(ERROR_CORRUPT_FILE_FORMAT); + // TheSuperHackers @bugfix OmarAglan Restore sides and teams when script parsing fails. + SidesList sidesBeforeImport; + sidesBeforeImport = m_sides; + try { + if (!file.parse(this)) { + throw(ERROR_CORRUPT_FILE_FORMAT); + } + } catch(...) { + m_sides = sidesBeforeImport; + throw; } pDoc->setNextWaypointID(m_maxWaypoint); @@ -1409,9 +1417,10 @@ void ScriptDialog::OnLoad() curSide = m_curSelection.m_playerIndex; } else { Int j; + // TheSuperHackers @bugfix OmarAglan Match each imported player to the current map side by name. for (j=0; jgetDict()->getAsciiString(TheKey_playerName); - if (name == m_readPlayerNames[j]) { + AsciiString name = m_sides.getSideInfo(j)->getDict()->getAsciiString(TheKey_playerName); + if (name == m_readPlayerNames[i]) { curSide = j; break; } @@ -1463,7 +1472,7 @@ void ScriptDialog::OnLoad() } } catch(...) { - DEBUG_CRASH(("threw exception in ScriptDialog::OnLoad")); + ::AfxMessageBox("Unable to import scripts. The file contains invalid data or exceeds the player limit.", MB_OK); } } @@ -1633,13 +1642,15 @@ Bool ScriptDialog::ParsePlayersDataChunk(DataChunkInput &file, DataChunkInfo *in { ScriptDialog *pThis = (ScriptDialog *)userData; Int numNames = file.readInt(); + // TheSuperHackers @bugfix OmarAglan Reject player counts that cannot fit in the import array. + if (numNames < 0 || numNames > MAX_PLAYER_COUNT) { + return false; + } Int i; for (i=0; i=MAX_PLAYER_COUNT) break; pThis->m_readPlayerNames[i] = file.readAsciiString(); } - DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over.")); - return true; + return file.atEndOfChunk(); } /** diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp index 13715f4a395..170944e41c7 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp @@ -1541,8 +1541,16 @@ void ScriptDialog::OnLoad() file.registerParser( "WaypointsList", AsciiString::TheEmptyString, ParseWaypointDataChunk ); file.registerParser( "ScriptTeams", AsciiString::TheEmptyString, ParseTeamsDataChunk ); file.registerParser( "ScriptsPlayers", AsciiString::TheEmptyString, ParsePlayersDataChunk ); - if (!file.parse(this)) { - throw(ERROR_CORRUPT_FILE_FORMAT); + // TheSuperHackers @bugfix OmarAglan Restore sides and teams when script parsing fails. + SidesList sidesBeforeImport; + sidesBeforeImport = m_sides; + try { + if (!file.parse(this)) { + throw(ERROR_CORRUPT_FILE_FORMAT); + } + } catch(...) { + m_sides = sidesBeforeImport; + throw; } pDoc->setNextWaypointID(m_maxWaypoint); @@ -1552,6 +1560,11 @@ void ScriptDialog::OnLoad() REF_PTR_RELEASE(pUndo); // belongs to pDoc now. m_sides = *TheSidesList; + // TheSuperHackers @bugfix OmarAglan Add imported players at their map indices after parsing succeeds. + for (Int sideIndex = sidesBeforeImport.getNumSides(); sideIndex < m_sides.getNumSides(); sideIndex++) { + addPlayer(sideIndex); + } + if (m_firstReadObject) { AddObjectUndoable *pUndo = new AddObjectUndoable(pDoc, m_firstReadObject); pDoc->AddAndDoUndoable(pUndo); @@ -1576,10 +1589,10 @@ void ScriptDialog::OnLoad() curSide = m_curSelection.m_playerIndex; } else { Int j; + // TheSuperHackers @bugfix OmarAglan Match each imported player to the current map side by name. for (j=0; jgetDict()->getAsciiString(TheKey_playerName); - if (name == m_readPlayerNames[j]) { + AsciiString name = m_sides.getSideInfo(j)->getDict()->getAsciiString(TheKey_playerName); + if (name == m_readPlayerNames[i]) { curSide = j; break; } @@ -1639,7 +1652,7 @@ void ScriptDialog::OnLoad() } catch(...) { - DEBUG_CRASH(("threw exception in ScriptDialog::OnLoad")); + ::AfxMessageBox("Unable to import scripts. The file contains invalid data or exceeds the player limit.", MB_OK); } } @@ -1817,12 +1830,21 @@ Bool ScriptDialog::ParsePlayersDataChunk(DataChunkInput &file, DataChunkInfo *in readDicts = file.readInt(); } Int numNames = file.readInt(); + // TheSuperHackers @bugfix OmarAglan Reject player counts that cannot fit in the import array. + if (numNames < 0 || numNames > MAX_PLAYER_COUNT) { + return false; + } Int i; for (i=0; i=MAX_PLAYER_COUNT) break; pThis->m_readPlayerNames[i] = file.readAsciiString(); if (readDicts) { Dict sideDict = file.readDict(); + // TheSuperHackers @bugfix OmarAglan Validate the dictionary identity before adding a player. + Bool hasPlayerName; + AsciiString playerName = sideDict.getAsciiString(TheKey_playerName, &hasPlayerName); + if (!hasPlayerName || playerName != pThis->m_readPlayerNames[i]) { + return false; + } bool nameFound = false; for (Int j=0; j < pThis->m_sides.getNumSides(); j++) { AsciiString name = pThis->m_sides.getSideInfo(j)->getDict()->getAsciiString(TheKey_playerName); @@ -1834,19 +1856,23 @@ Bool ScriptDialog::ParsePlayersDataChunk(DataChunkInput &file, DataChunkInfo *in } } if (nameFound == false) { + // TheSuperHackers @bugfix OmarAglan Check capacity before adding a side and using its script list. + if (pThis->m_sides.getNumSides() >= MAX_PLAYER_COUNT) { + return false; + } // This side doesn't currently exist, so add it. pThis->m_sides.addSide(&sideDict); + SidesInfo* sides = pThis->m_sides.findSideInfo(playerName); + if (sides == nullptr) { + return false; + } ScriptList* pList = newInstance(ScriptList); - SidesInfo* sides = pThis->m_sides.findSideInfo(pThis->m_readPlayerNames[i]); // A script list must be created. sides->setScriptList(pList); - // Update the dialog. - pThis->addPlayer(i); } } } - DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over.")); - return true; + return file.atEndOfChunk(); } /**