bool C4Network2Res::OptimizeStandalone(bool fSilent)
{
	CStdLock FileLock(&FileCSec);
	// for now: player files only
	if (Core.getType() == NRT_Player)
	{
		// log - this may take a few seconds
		if (!fSilent) LogF(LoadResStr("IDS_PRC_NETPREPARING"), GetFilename(szFile));
		// copy to temp file, if needed
		if (!fTempFile && SEqual(szFile, szStandalone))
		{
			char szNewStandalone[_MAX_PATH + 1];
			if (!pParent->FindTempResFileName(szStandalone, szNewStandalone))
				{ if (!fSilent) Log("OptimizeStandalone: could not find free name for temporary file!"); return false; }
			if (!C4Group_CopyItem(szStandalone, szNewStandalone))
				{ if (!fSilent) Log("OptimizeStandalone: could not copy to temporary file!"); return false; } /* TODO: Test failure */
			SCopy(szNewStandalone, szStandalone, sizeof(szStandalone) - 1);
		}
		// open as group
		C4Group Grp;
		if (!Grp.Open(szStandalone))
			{ if (!fSilent) Log("OptimizeStandalone: could not open player file!"); return false; }
		// remove bigicon, if the file size is too large
		size_t iBigIconSize=0;
		if (Grp.FindEntry(C4CFN_BigIcon, NULL, &iBigIconSize))
			if (iBigIconSize > C4NetResMaxBigicon*1024)
				Grp.Delete(C4CFN_BigIcon);
		Grp.Close();
	}
	return true;
}
Esempio n. 2
0
bool C4PlayerList::Save(C4Group &hGroup, bool fStoreTiny, const C4PlayerInfoList &rStoreList)
{
	StdStrBuf sTempFilename;
	bool fSuccess = true;
	// Save to external player files and add to group
	for (C4Player *pPlr=First; pPlr; pPlr=pPlr->Next)
	{
		// save only those in the list, and only those with a filename
		C4PlayerInfo *pNfo = rStoreList.GetPlayerInfoByID(pPlr->ID);
		if (!pNfo) continue;
		if (!pNfo->GetFilename() || !*pNfo->GetFilename()) continue;;
		// save over original file?
		bool fStoreOnOriginal = (!fStoreTiny && pNfo->GetType() == C4PT_User);
		// Create temporary file
		sTempFilename.Copy(Config.AtTempPath(pNfo->GetFilename()));
		if (fStoreOnOriginal)
			if (!C4Group_CopyItem(pPlr->Filename, sTempFilename.getData()))
				return false;
		// Open group
		C4Group PlrGroup;
		if (!PlrGroup.Open(sTempFilename.getData(), !fStoreOnOriginal))
			return false;
		// Save player
		if (!pPlr->Save(PlrGroup, true, fStoreOnOriginal)) return false;
		PlrGroup.Close();
		// Add temp file to group
		if (!hGroup.Move(sTempFilename.getData(), pNfo->GetFilename())) return false;
	}
	return fSuccess;
}
void C4Network2ResDlg::ListItem::LocalSaveResource(bool fDoOverwrite)
{
	// get associated resource
	C4Network2Res::Ref pRes = GetRefRes();
	if (!pRes) return;
	const char *szResFile = pRes->getFile();
	StdCopyStrBuf strErrCopyFile(LoadResStr("IDS_NET_ERR_COPYFILE"));
	if (!pRes->isTempFile())
	{
		GetScreen()->ShowMessage(LoadResStr("IDS_NET_ERR_COPYFILE_LOCAL"), strErrCopyFile.getData(), C4GUI::Ico_Error);
		return;
	}
	const char *szFilename = GetFilename(pRes->getCore().getFileName());
	/*  const char *szSpecialPath = "";
	  if (WildcardMatch(C4CFN_PlayerFiles, szFilename))
	    // write players to player path
	    szSpecialPath = Config.General.PlayerPath;
	*/
	const char *szTarget = Config.AtUserDataPath(szFilename);
	if (!fDoOverwrite && ItemExists(szTarget))
	{
		// show a confirmation dlg, asking whether the resource should be overwritten
		GetScreen()->ShowRemoveDlg(new C4GUI::ConfirmationDialog(
		                             FormatString(LoadResStr("IDS_NET_RES_SAVE_OVERWRITE"), GetFilename(szTarget)).getData(), LoadResStr("IDS_NET_RES_SAVE"),
		                             new C4GUI::CallbackHandler<C4Network2ResDlg::ListItem>(this, &C4Network2ResDlg::ListItem::OnButtonSaveConfirm), C4GUI::MessageDialog::btnYesNo));
		return;
	}
	if (!C4Group_CopyItem(szResFile, szTarget))
		GetScreen()->ShowMessage(strErrCopyFile.getData(), strErrCopyFile.getData(), C4GUI::Ico_Error);
	else
	{
		GetScreen()->ShowMessage(FormatString(LoadResStr("IDS_NET_RES_SAVED_DESC"), GetFilename(szTarget)).getData(),
		                         LoadResStr("IDS_NET_RES_SAVED"), C4GUI::Ico_Save);
	}
}
Esempio n. 4
0
bool C4MusicFile::ExtractFile()
{
	// safety
	if (SongExtracted) return true;
	// extract entry
	if (!C4Group_CopyItem(FileName, Config.AtTempPath(C4CFN_TempMusic2))) return false;
	// ok
	SongExtracted = true;
	return true;
}
Esempio n. 5
0
BOOL C4MusicFile::ExtractFile()
	{
	// safety
	if(SongExtracted) return TRUE;
	// extract entry
	if(!C4Group_CopyItem(FileName, Config.AtTempPath(C4CFN_TempMusic2))) return FALSE;
	// ok
	SongExtracted = TRUE;
	return TRUE;
	}
C4Network2Res::Ref C4Network2Res::Derive()
{
	// Called before the file is changed. Rescues all files and creates a
	// new resource for the file. This resource is flagged as "anonymous", as it
	// has no official core (no res ID, to be exact).
	// The resource gets its final core when FinishDerive() is called.

	// For security: This doesn't make much sense if the resource is currently being
	// loaded. So better assume the caller doesn't know what he's doing and check.
	if (isLoading()) return NULL;

	CStdLock FileLock(&FileCSec);
	// Save back original file name
	char szOrgFile[_MAX_PATH+1];
	SCopy(szFile, szOrgFile, _MAX_PATH);
	bool fOrgTempFile = fTempFile;

	// Create a copy of the file, if neccessary
	if (!*szStandalone || SEqual(szStandalone, szFile))
	{
		if (!pParent->FindTempResFileName(szOrgFile, szFile))
			{ Log("Derive: could not find free name for temporary file!"); return NULL; }
		if (!C4Group_CopyItem(szOrgFile, szFile))
			{ Log("Derive: could not copy to temporary file!"); return NULL; }
		// set standalone
		if (*szStandalone)
			SCopy(szFile, szStandalone, _MAX_PATH);
		fTempFile = true;
	}
	else
	{
		// Standlone exists: Just set szFile to point on the standlone. It's
		// assumed that the original file isn't of intrest after this point anyway.
		SCopy(szStandalone, szFile, _MAX_PATH);
		fTempFile = true;
	}

	Application.InteractiveThread.ThreadLogS("Network: Resource: deriving from %d:%s, original at %s", getResID(), Core.getFileName(), szFile);

	// (note: should remove temp file if something fails after this point)

	// create new resource
	C4Network2Res::Ref pDRes = new C4Network2Res(pParent);
	if (!pDRes) return NULL;

	// initialize
	if (!pDRes->SetDerived(Core.getFileName(), szOrgFile, fOrgTempFile, getType(), getResID()))
		return NULL;

	// add to list
	pParent->Add(pDRes);

	// return new resource
	return pDRes;
}
Esempio n. 7
0
bool C4GameSave::SaveCreateGroup(const char *szFilename, C4Group &hUseGroup)
{
	// erase any previous item (2do: work in C4Groups?)
	EraseItem(szFilename);
	// copy from previous group?
	if (GetCopyScenario())
		if (!ItemIdentical(Game.ScenarioFilename, szFilename))
			if (!C4Group_CopyItem(Game.ScenarioFilename, szFilename))
				{ LogF(LoadResStr("IDS_CNS_SAVEASERROR"), szFilename); return false; }
	// open it
	if (!hUseGroup.Open(szFilename, !GetCopyScenario()))
	{
		EraseItem(szFilename);
		LogF(LoadResStr("IDS_CNS_SAVEASERROR"), szFilename);
		return false;
	}
	// done, success
	return true;
}
Esempio n. 8
0
bool C4MessageInput::ProcessCommand(const char *szCommand) {
  C4GameLobby::MainDlg *pLobby = Game.Network.GetLobby();
  // command
  char szCmdName[C4MaxName + 1];
  SCopyUntil(szCommand + 1, szCmdName, ' ', C4MaxName);
  // parameter
  const char *pCmdPar = SSearch(szCommand, " ");
  if (!pCmdPar) pCmdPar = "";

  // dev-scripts
  if (SEqual(szCmdName, "help")) {
    LogF(LoadResStr("IDS_TEXT_COMMANDSAVAILABLEDURINGGA"));
    LogF("/private [player] [message] - %s",
         LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOTHES"));
    LogF("/team [message] - %s",
         LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOYOUR"));
    LogF("/me [action] - %s", LoadResStr("IDS_TEXT_PERFORMANACTIONINYOURNAME"));
    LogF("/sound [sound] - %s",
         LoadResStr("IDS_TEXT_PLAYASOUNDFROMTHEGLOBALSO"));
    LogF("/kick [client] - %s", LoadResStr("IDS_TEXT_KICKTHESPECIFIEDCLIENT"));
    LogF("/observer [client] - %s",
         LoadResStr("IDS_TEXT_SETTHESPECIFIEDCLIENTTOOB"));
    LogF("/fast [x] - %s", LoadResStr("IDS_TEXT_SETTOFASTMODESKIPPINGXFRA"));
    LogF("/slow - %s", LoadResStr("IDS_TEXT_SETTONORMALSPEEDMODE"));
    LogF("/chart - %s", LoadResStr("IDS_TEXT_DISPLAYNETWORKSTATISTICS"));
    LogF("/nodebug - %s", LoadResStr("IDS_TEXT_PREVENTDEBUGMODEINTHISROU"));
    LogF("/set comment [comment] - %s",
         LoadResStr("IDS_TEXT_SETANEWNETWORKCOMMENT"));
    LogF("/set password [password] - %s",
         LoadResStr("IDS_TEXT_SETANEWNETWORKPASSWORD"));
    LogF("/set faircrew [on/off] - %s",
         LoadResStr("IDS_TEXT_ENABLEORDISABLEFAIRCREW"));
    LogF("/set maxplayer [4] - %s",
         LoadResStr("IDS_TEXT_SETANEWMAXIMUMNUMBEROFPLA"));
    LogF("/script [script] - %s", LoadResStr("IDS_TEXT_EXECUTEASCRIPTCOMMAND"));
    LogF("/clear - %s", LoadResStr("IDS_MSG_CLEARTHEMESSAGEBOARD"));
    return TRUE;
  }
  // dev-scripts
  if (SEqual(szCmdName, "script")) {
    if (!Game.IsRunning) return FALSE;
    if (!Game.DebugMode) return FALSE;
    if (!Game.Network.isEnabled() &&
        !SEqual(Game.ScenarioFile.GetMaker(), Config.General.Name) &&
        Game.ScenarioFile.GetStatus() != GRPF_Folder)
      return FALSE;
    if (Game.Network.isEnabled() && !Game.Network.isHost()) return FALSE;

    Game.Control.DoInput(
        CID_Script,
        new C4ControlScript(pCmdPar, C4ControlScript::SCOPE_Console, false),
        CDT_Decide);
    return TRUE;
  }
  // set runtimte properties
  if (SEqual(szCmdName, "set")) {
    if (SEqual2(pCmdPar, "maxplayer ")) {
      if (Game.Control.isCtrlHost()) {
        if (atoi(pCmdPar + 10) == 0 && !SEqual(pCmdPar + 10, "0")) {
          Log("Syntax: /set maxplayer count");
          return FALSE;
        }
        Game.Control.DoInput(
            CID_Set, new C4ControlSet(C4CVT_MaxPlayer, atoi(pCmdPar + 10)),
            CDT_Decide);
        return TRUE;
      }
    }
    if (SEqual2(pCmdPar, "comment ") || SEqual(pCmdPar, "comment")) {
      if (!Game.Network.isEnabled() || !Game.Network.isHost()) return FALSE;
      // Set in configuration, update reference
      Config.Network.Comment.CopyValidated(pCmdPar[7] ? (pCmdPar + 8) : "");
      Game.Network.InvalidateReference();
      Log(LoadResStr("IDS_NET_COMMENTCHANGED"));
      return TRUE;
    }
    if (SEqual2(pCmdPar, "password ") || SEqual(pCmdPar, "password")) {
      if (!Game.Network.isEnabled() || !Game.Network.isHost()) return FALSE;
      Game.Network.SetPassword(pCmdPar[8] ? (pCmdPar + 9) : NULL);
      if (pLobby) pLobby->UpdatePassword();
      return TRUE;
    }
    if (SEqual2(pCmdPar, "faircrew ")) {
      if (!Game.Control.isCtrlHost() || Game.Parameters.isLeague())
        return FALSE;
      C4ControlSet *pSet = NULL;
      if (SEqual(pCmdPar + 9, "on"))
        pSet =
            new C4ControlSet(C4CVT_FairCrew, Config.General.FairCrewStrength);
      else if (SEqual(pCmdPar + 9, "off"))
        pSet = new C4ControlSet(C4CVT_FairCrew, -1);
      else if (isdigit((unsigned char)pCmdPar[9]))
        pSet = new C4ControlSet(C4CVT_FairCrew, atoi(pCmdPar + 9));
      else
        return FALSE;
      Game.Control.DoInput(CID_Set, pSet, CDT_Decide);
      return TRUE;
    }
    // unknown property
    return FALSE;
  }
  // get szen from network folder - not in lobby; use res tab there
  if (SEqual(szCmdName, "netgetscen")) {
    if (Game.Network.isEnabled() && !Game.Network.isHost() && !pLobby) {
      const C4Network2ResCore *pResCoreScen =
          Game.Parameters.Scenario.getResCore();
      if (pResCoreScen) {
        C4Network2Res::Ref pScenario =
            Game.Network.ResList.getRefRes(pResCoreScen->getID());
        if (pScenario)
          if (C4Group_CopyItem(
                  pScenario->getFile(),
                  Config.AtExePath(GetFilename(Game.ScenarioFilename)))) {
            LogF(LoadResStr("IDS_MSG_CMD_NETGETSCEN_SAVED"),
                 Config.AtExePath(GetFilename(Game.ScenarioFilename)));
            return TRUE;
          }
      }
    }
    return FALSE;
  }
  // clear message board
  if (SEqual(szCmdName, "clear")) {
    // lobby
    if (pLobby) {
      pLobby->ClearLog();
    }
    // fullscreen
    else if (Game.GraphicsSystem.MessageBoard.Active)
      Game.GraphicsSystem.MessageBoard.ClearLog();
    else {
      // EM mode
      Console.ClearLog();
    }
    return TRUE;
  }
  // kick client
  if (SEqual(szCmdName, "kick")) {
    if (Game.Network.isEnabled() && Game.Network.isHost()) {
      // find client
      C4Client *pClient = Game.Clients.getClientByName(pCmdPar);
      if (!pClient) {
        LogF(LoadResStr("IDS_MSG_CMD_NOCLIENT"), pCmdPar);
        return FALSE;
      }
      // league: Kick needs voting
      if (Game.Parameters.isLeague() &&
          Game.Players.GetAtClient(pClient->getID()))
        Game.Network.Vote(VT_Kick, true, pClient->getID());
      else
        // add control
        Game.Clients.CtrlRemove(pClient,
                                LoadResStr("IDS_MSG_KICKFROMMSGBOARD"));
    }
    return TRUE;
  }
  // set fast mode
  if (SEqual(szCmdName, "fast")) {
    if (!Game.IsRunning) return FALSE;
    if (Game.Parameters.isLeague()) {
      Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
      return FALSE;
    }
    int32_t iFS;
    if ((iFS = atoi(pCmdPar)) == 0) return FALSE;
    // set frameskip and fullspeed flag
    Game.FrameSkip = BoundBy<int32_t>(iFS, 1, 500);
    Game.FullSpeed = TRUE;
    // start calculation immediatly
    Application.NextTick(false);
    return TRUE;
  }
  // reset fast mode
  if (SEqual(szCmdName, "slow")) {
    if (!Game.IsRunning) return FALSE;
    Game.FullSpeed = FALSE;
    Game.FrameSkip = 1;
    return TRUE;
  }

  if (SEqual(szCmdName, "nodebug")) {
    if (!Game.IsRunning) return FALSE;
    Game.Control.DoInput(CID_Set, new C4ControlSet(C4CVT_AllowDebug, false),
                         CDT_Decide);
    return TRUE;
  }

  if (SEqual(szCmdName, "msgboard")) {
    if (!Game.IsRunning) return FALSE;
    // get line cnt
    int32_t iLineCnt = BoundBy(atoi(pCmdPar), 0, 20);
    if (iLineCnt == 0)
      Game.GraphicsSystem.MessageBoard.ChangeMode(2);
    else if (iLineCnt == 1)
      Game.GraphicsSystem.MessageBoard.ChangeMode(0);
    else {
      Game.GraphicsSystem.MessageBoard.iLines = iLineCnt;
      Game.GraphicsSystem.MessageBoard.ChangeMode(1);
    }
    return TRUE;
  }

  // kick/activate/deactivate/observer
  if (SEqual(szCmdName, "activate") || SEqual(szCmdName, "deactivate") ||
      SEqual(szCmdName, "observer")) {
    if (!Game.Network.isEnabled() || !Game.Network.isHost()) {
      Log(LoadResStr("IDS_MSG_CMD_HOSTONLY"));
      return FALSE;
    }
    // search for client
    C4Client *pClient = Game.Clients.getClientByName(pCmdPar);
    if (!pClient) {
      LogF(LoadResStr("IDS_MSG_CMD_NOCLIENT"), pCmdPar);
      return FALSE;
    }
    // what to do?
    C4ControlClientUpdate *pCtrl = NULL;
    if (szCmdName[0] == 'a')  // activate
      pCtrl = new C4ControlClientUpdate(pClient->getID(), CUT_Activate, true);
    else if (szCmdName[0] == 'd' && !Game.Parameters.isLeague())  // deactivate
      pCtrl = new C4ControlClientUpdate(pClient->getID(), CUT_Activate, false);
    else if (szCmdName[0] == 'o' && !Game.Parameters.isLeague())  // observer
      pCtrl = new C4ControlClientUpdate(pClient->getID(), CUT_SetObserver);
    // perform it
    if (pCtrl)
      Game.Control.DoInput(CID_ClientUpdate, pCtrl, CDT_Sync);
    else
      Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
    return TRUE;
  }

  // control mode
  if (SEqual(szCmdName, "centralctrl") || SEqual(szCmdName, "decentralctrl") ||
      SEqual(szCmdName, "asyncctrl")) {
    if (!Game.Network.isEnabled() || !Game.Network.isHost()) {
      Log(LoadResStr("IDS_MSG_CMD_HOSTONLY"));
      return FALSE;
    }
    if (Game.Parameters.isLeague() && *szCmdName == 'a') {
      Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
      return FALSE;
    }
    Game.Network.SetCtrlMode(
        *szCmdName == 'c' ? CNM_Central : *szCmdName == 'd' ? CNM_Decentral
                                                            : CNM_Async);
    return TRUE;
  }

  // show chart
  if (Game.IsRunning)
    if (SEqual(szCmdName, "chart")) return Game.ToggleChart();

  // custom command
  C4MessageBoardCommand *pCmd;
  if (Game.IsRunning)
    if (pCmd = GetCommand(szCmdName)) {
      StdStrBuf Script, CmdScript;
      // replace %player% by calling player number
      if (SSearch(pCmd->Script, "%player%")) {
        int32_t iLocalPlr = NO_OWNER;
        C4Player *pLocalPlr = Game.Players.GetLocalByIndex(0);
        if (pLocalPlr) iLocalPlr = pLocalPlr->Number;
        StdStrBuf sLocalPlr;
        sLocalPlr.Format("%d", iLocalPlr);
        CmdScript.Copy(pCmd->Script);
        CmdScript.Replace("%player%", sLocalPlr.getData());
      } else {
        CmdScript.Ref(pCmd->Script);
      }
      // insert parameters
      if (SSearch(CmdScript.getData(), "%d")) {
        // make sure it's a number by converting
        Script.Format(CmdScript.getData(), (int)atoi(pCmdPar));
      } else if (SSearch(CmdScript.getData(), "%s")) {
        // Unrestricted parameters?
        // That's kind of a security risk as it will allow anyone to execute
        // code
        switch (pCmd->eRestriction) {
          case C4MessageBoardCommand::C4MSGCMDR_Escaped: {
            // escape strings
            StdStrBuf Par;
            Par.Copy(pCmdPar);
            Par.EscapeString();
            // compose script
            Script.Format(CmdScript.getData(), Par.getData());
          } break;

          case C4MessageBoardCommand::C4MSGCMDR_Plain:
            // unescaped
            Script.Format(CmdScript.getData(), pCmdPar);
            break;

          case C4MessageBoardCommand::C4MSGCMDR_Identifier: {
            // only allow identifier-characters
            StdStrBuf Par;
            while (IsIdentifier(*pCmdPar) || isspace((unsigned char)*pCmdPar))
              Par.AppendChar(*pCmdPar++);
            // compose script
            Script.Format(CmdScript.getData(), Par.getData());
          } break;
        }
      } else
        Script = CmdScript.getData();
      // add script
      Game.Control.DoInput(CID_Script, new C4ControlScript(Script.getData()),
                           CDT_Decide);
      // ok
      return TRUE;
    }

  // unknown command
  StdStrBuf sErr;
  sErr.Format(LoadResStr("IDS_ERR_UNKNOWNCMD"), szCmdName);
  if (pLobby)
    pLobby->OnError(sErr.getData());
  else
    Log(sErr.getData());
  return FALSE;
}
Esempio n. 9
0
bool C4Playback::StreamToRecord(const char *szStream, StdStrBuf *pRecordFile) {
  // Load data
  StdBuf CompressedData;
  Log("Reading stream...");
  if (!CompressedData.LoadFromFile(szStream)) return false;

  // Decompress
  unsigned long iStreamSize = CompressedData.getSize() * 5;
  StdBuf StreamData;
  StreamData.New(iStreamSize);
  while (true) {
    // Initialize stream
    z_stream strm;
    ZeroMem(&strm, sizeof strm);
    strm.next_in = getMBufPtr<BYTE>(CompressedData);
    strm.avail_in = CompressedData.getSize();
    strm.next_out = getMBufPtr<BYTE>(StreamData);
    strm.avail_out = StreamData.getSize();

    // Decompress
    if (inflateInit(&strm) != Z_OK) return false;
    int ret = inflate(&strm, Z_FINISH);
    if (ret == Z_STREAM_END) {
      inflateEnd(&strm);
      break;
    }
    if (ret != Z_BUF_ERROR) return false;

    // All input consumed?
    iStreamSize = strm.total_out;
    if (strm.avail_in == 0) {
      Log("Stream data incomplete, using as much data as possible");
      break;
    }

    // Larger buffer needed
    StreamData.Grow(CompressedData.getSize());
    iStreamSize = StreamData.getSize();
  }
  StreamData.SetSize(iStreamSize);

  // Parse
  C4Playback Playback;
  Playback.ReadBinary(StreamData);
  LogF("Got %d chunks from stream", Playback.chunks.size());

  // Get first chunk, which must contain the initial
  chunks_t::iterator chunkIter = Playback.chunks.begin();
  if (chunkIter == Playback.chunks.end() || chunkIter->Type != RCT_File)
    return false;

  // Get initial chunk, go over file name
  StdBuf InitialData = *chunkIter->pFileData;
  const char *szInitialFilename = chunkIter->Filename.getData();

  // Put to temporary file and unpack
  char szInitial[_MAX_PATH + 1] = "~initial.tmp";
  MakeTempFilename(szInitial);
  if (!InitialData.SaveToFile(szInitial) || !C4Group_UnpackDirectory(szInitial))
    return false;

  // Load Scenario.txt from Initial
  C4Group Grp;
  C4Scenario Initial;
  if (!Grp.Open(szInitial) || !Initial.Load(Grp) || !Grp.Close()) return false;

  // Copy original scenario
  const char *szOrigin = Initial.Head.Origin.getData();
  char szRecord[_MAX_PATH + 1];
  SCopy(szStream, szRecord, _MAX_PATH);
  if (GetExtension(szRecord)) *(GetExtension(szRecord) - 1) = 0;
  SAppend(".c4s", szRecord, _MAX_PATH);
  LogF("Original scenario is %s, creating %s.", szOrigin, szRecord);
  if (!C4Group_CopyItem(szOrigin, szRecord, false, false)) return false;

  // Merge initial
  if (!Grp.Open(szRecord) || !Grp.Merge(szInitial)) return false;

  // Process other files in stream
  chunkIter->Delete();
  chunkIter = Playback.chunks.erase(chunkIter);
  while (chunkIter != Playback.chunks.end())
    if (chunkIter->Type == RCT_File) {
      LogF("Inserting %s...", chunkIter->Filename.getData());
      StdStrBuf Temp;
      Temp.Copy(chunkIter->Filename);
      MakeTempFilename(&Temp);
      if (!chunkIter->pFileData->SaveToFile(Temp.getData())) return false;
      if (!Grp.Move(Temp.getData(), chunkIter->Filename.getData()))
        return false;
      chunkIter = Playback.chunks.erase(chunkIter);
    } else
      chunkIter++;

  // Write record data
  StdBuf RecordData = Playback.ReWriteBinary();
  if (!Grp.Add(C4CFN_CtrlRec, RecordData, false, true)) return false;

  // Done
  Log("Writing record file...");
  Grp.Close();
  pRecordFile->Copy(szRecord);
  return true;
}
Esempio n. 10
0
bool C4Network2Res::GetStandalone(char *pTo, int32_t iMaxL, bool fSetOfficial, bool fAllowUnloadable, bool fSilent)
{
	// already set?
	if (szStandalone[0])
	{
		if (pTo) SCopy(szStandalone, pTo, iMaxL);
		return true;
	}
	// already tried and failed? No point in retrying
	if (fStandaloneFailed) return false;
	// not loadable? Wo won't be able to check the standalone as the core will lack the needed information.
	// the standalone won't be interesting in this case, anyway.
	if (!fSetOfficial && !Core.isLoadable()) return false;
	// set flag, so failure below will let future calls fail
	fStandaloneFailed = true;
	// lock file
	CStdLock FileLock(&FileCSec);

	// directory?
	SCopy(szFile, szStandalone, sizeof(szStandalone)-1);
	if (DirectoryExists(szFile))
	{
		// size check for the directory, if allowed
		if (fAllowUnloadable)
		{
			uint32_t iDirSize;
			if (!DirSizeHelper::GetDirSize(szFile, &iDirSize, Config.Network.MaxLoadFileSize))
				{ if (!fSilent) LogF("Network: could not get directory size of %s!", szFile); szStandalone[0] = '\0'; return false; }
			if (iDirSize > uint32_t(Config.Network.MaxLoadFileSize))
				{ if (!fSilent) LogSilentF("Network: %s over size limit, will be marked unloadable!", szFile); szStandalone[0] = '\0'; return false; }
		}
		// log - this may take a few seconds
		if (!fSilent) LogF(LoadResStr("IDS_PRC_NETPACKING"), GetFilename(szFile));
		// pack inplace?
		if (!fTempFile)
		{
			if (!pParent->FindTempResFileName(szFile, szStandalone))
				{ if (!fSilent) Log("GetStandalone: could not find free name for temporary file!"); szStandalone[0] = '\0'; return false; }
			if (!C4Group_PackDirectoryTo(szFile, szStandalone))
				{ if (!fSilent) Log("GetStandalone: could not pack directory!"); szStandalone[0] = '\0'; return false; }
		}
		else if (!C4Group_PackDirectory(szStandalone))
			{ if (!fSilent) Log("GetStandalone: could not pack directory!"); if (!SEqual(szFile, szStandalone)) EraseDirectory(szStandalone); szStandalone[0] = '\0'; return false; }
		// make sure directory is packed
		if (DirectoryExists(szStandalone))
			{ if (!fSilent) Log("GetStandalone: directory hasn't been packed!"); if (!SEqual(szFile, szStandalone)) EraseDirectory(szStandalone); szStandalone[0] = '\0'; return false; }
		// fallthru
	}

	// doesn't exist physically?
	if (!FileExists(szStandalone))
	{
		// try C4Group (might be packed)
		if (!pParent->FindTempResFileName(szFile, szStandalone))
			{ if (!fSilent) Log("GetStandalone: could not find free name for temporary file!"); szStandalone[0] = '\0'; return false; }
		if (!C4Group_CopyItem(szFile, szStandalone))
			{ if (!fSilent) Log("GetStandalone: could not copy to temporary file!"); szStandalone[0] = '\0'; return false; }
	}

	// remains missing? give up.
	if (!FileExists(szStandalone))
		{ if (!fSilent) Log("GetStandalone: file not found!"); szStandalone[0] = '\0'; return false; }

	// do optimizations (delete unneeded entries)
	if (!OptimizeStandalone(fSilent))
		{ if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0'; return false; }

	// get file size
	size_t iSize = FileSize(szStandalone);
	// size limit
	if (fAllowUnloadable)
		if (iSize > uint32_t(Config.Network.MaxLoadFileSize))
			{ if (!fSilent) LogSilentF("Network: %s over size limit, will be marked unloadable!", szFile); szStandalone[0] = '\0'; return false; }
	// check
	if (!fSetOfficial && iSize != Core.getFileSize())
	{
		// remove file
		if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0';
		// sorry, this version isn't good enough :(
		return false;
	}

	// calc checksum
	uint32_t iCRC32;
	if (!GetFileCRC(szStandalone, &iCRC32))
		{ if (!fSilent) Log("GetStandalone: could not calculate checksum!"); return false; }
	// set / check
	if (!fSetOfficial && iCRC32 != Core.getFileCRC())
	{
		// remove file, return
		if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0';
		return false;
	}

	// we didn't fail
	fStandaloneFailed = false;
	// mark resource as loadable and safe file information
	Core.SetLoadable(iSize, iCRC32);
	// set up chunk data
	Chunks.SetComplete(Core.getChunkCnt());
	// ok
	return true;
}