Пример #1
0
bool C4Record::AddFile(const char *szLocalFilename, const char *szAddAs,
                       bool fDelete) {
  if (!fRecording) return false;

  // Streaming?
  if (fStreaming) {
    // Special stripping for streaming
    StdCopyStrBuf szFile(szLocalFilename);
    if (SEqualNoCase(GetExtension(szAddAs), "c4p")) {
      // Create a copy
      MakeTempFilename(&szFile);
      if (!CopyItem(szLocalFilename, szFile.getData())) return false;
      // Strip it
      if (!C4Player::Strip(szFile.getData(), true)) return false;
    }

    // Add to stream
    if (!StreamFile(szFile.getData(), szAddAs)) return false;

    // Remove temporary file
    if (szFile != szLocalFilename) EraseItem(szFile.getData());
  }

  // Add to record group
  if (fDelete) {
    if (!RecordGrp.Move(szLocalFilename, szAddAs)) return false;
  } else {
    if (!RecordGrp.Add(szLocalFilename, szAddAs)) return false;
  }

  return true;
}
Пример #2
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;
}
Пример #3
0
C4ScenarioSection::~C4ScenarioSection() {
  // del following scenario sections
  while (pNext) {
    C4ScenarioSection *pDel = pNext;
    pNext = pNext->pNext;
    pDel->pNext = NULL;
    delete pDel;
  }
  // del temp file
  if (szTempFilename) {
    EraseItem(szTempFilename);
    delete szTempFilename;
  }
  // del filename if assigned
  if (szFilename) delete szFilename;
  // del name if owned
  if (szName != C4ScenSect_Main) delete szName;
}
Пример #4
0
bool C4ScenarioSection::EnsureTempStore(bool fExtractLandscape,
                                        bool fExtractObjects) {
  // if it's temp store already, don't do anything
  if (szTempFilename) return true;
  // make temp filename
  char *szTmp = const_cast<char *>(
      Config.AtTempPath(szFilename ? GetFilename(szFilename) : szName));
  MakeTempFilename(szTmp);
  // main section: extract section files from main scenario group (create group
  // as open dir)
  if (!szFilename) {
    if (!CreateDirectory(szTmp, NULL)) return false;
    C4Group hGroup;
    if (!hGroup.Open(szTmp, TRUE)) {
      EraseItem(szTmp);
      return false;
    }
    // extract all desired section files
    Game.ScenarioFile.ResetSearch();
    char fn[_MAX_FNAME + 1];
    *fn = 0;
    while (Game.ScenarioFile.FindNextEntry(C4FLS_Section, fn))
      if (fExtractLandscape || !WildcardMatch(C4FLS_SectionLandscape, fn))
        if (fExtractObjects || !WildcardMatch(C4FLS_SectionObjects, fn))
          Game.ScenarioFile.ExtractEntry(fn, szTmp);
    hGroup.Close();
  } else {
    // subsection: simply extract section from main group
    if (!Game.ScenarioFile.ExtractEntry(szFilename, szTmp)) return false;
    // delete undesired landscape/object files
    if (!fExtractLandscape || !fExtractObjects) {
      C4Group hGroup;
      if (hGroup.Open(szFilename)) {
        if (!fExtractLandscape) hGroup.Delete(C4FLS_SectionLandscape);
        if (!fExtractObjects) hGroup.Delete(C4FLS_SectionObjects);
      }
    }
  }
  // copy temp filename
  szTempFilename = new char[strlen(szTmp) + 1];
  SCopy(szTmp, szTempFilename, _MAX_PATH);
  // done, success
  return true;
}
Пример #5
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;
}
Пример #6
0
bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bool *fModified)
{
	// (CAUTION: pGrp1 may be nullptr - that means that there is no counterpart for Grp2
	//           in the base group)

	// compare headers
	if (!pGrp1 || pGrp1->EntryCRC32() != pGrp2->EntryCRC32())
		*fModified = true;
	// set header
	pUpGrp->SetHead(*pGrp2);
	// compare entries
	char strItemName[_MAX_PATH], strItemName2[_MAX_PATH]; StdStrBuf EntryList;
	strItemName[0] = strItemName2[0] = 0;
	pGrp2->ResetSearch(); if (!*fModified) pGrp1->ResetSearch();
	int iChangedEntries = 0;
	while (pGrp2->FindNextEntry("*", strItemName, nullptr, !! strItemName[0]))
	{
		// add to entry list
		if (!!EntryList) EntryList.AppendChar('|');
		EntryList.AppendFormat("%s=%d", strItemName, pGrp2->EntryCRC32(strItemName));
		// no modification detected yet? then check order
		if (!*fModified)
		{
			if (!pGrp1->FindNextEntry("*", strItemName2, nullptr, !! strItemName2[0]))
				*fModified = true;
			else if (!SEqual(strItemName, strItemName2))
				*fModified = true;
		}

		// TODO: write DeleteEntries.txt

		// a child group?
		C4GroupEx ChildGrp2;
		if (ChildGrp2.OpenAsChild(pGrp2, strItemName))
		{
			// open in Grp1
			C4Group *pChildGrp1 = new C4GroupEx();
			if (!pGrp1 || !pChildGrp1->OpenAsChild(pGrp1, strItemName))
				{ delete pChildGrp1; pChildGrp1 = nullptr; }
			// open group for update data
			C4GroupEx UpdGroup; char strTempGroupName[_MAX_FNAME + 1];
			strTempGroupName[0] = 0;
			if (!UpdGroup.OpenAsChild(pUpGrp, strItemName))
			{
				// create new group (may be temporary)
				if (C4Group_TempPath[0]) { SCopy(C4Group_TempPath,strTempGroupName,_MAX_FNAME); SAppend("~upd",strTempGroupName,_MAX_FNAME); }
				else SCopy("~upd",strTempGroupName,_MAX_FNAME);
				MakeTempFilename(strTempGroupName);
				if (!UpdGroup.Open(strTempGroupName, true)) { delete pChildGrp1; WriteLog("Error: could not create temp group\n"); return false; }
			}
			// do nested MkUp-search
			bool Modified = false;
			bool fSuccess = MkUp(pChildGrp1, &ChildGrp2, &UpdGroup, &Modified);
			// sort & close
			extern const char ** C4Group_SortList;
			UpdGroup.SortByList(C4Group_SortList, ChildGrp2.GetName());
			UpdGroup.Close(false);
			// check entry crcs
			if (!pGrp1 || (pGrp1->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName)))
				Modified = true;
			// add group (if modified)
			if (fSuccess && Modified)
			{
				if (strTempGroupName[0])
					if (!pUpGrp->Move(strTempGroupName, strItemName))
					{
						WriteLog("Error: could not add modified group\n");
						return false;
					}
				// copy core
				pUpGrp->SaveEntryCore(*pGrp2, strItemName);
				pUpGrp->SetSavedEntryCore(strItemName);
				// got a modification in a subgroup
				*fModified = true;
				iChangedEntries++;
			}
			else
				// delete group (do not remove groups that existed before!)
				if (strTempGroupName[0])
					if (!EraseItem(strTempGroupName))
							{ WriteLog("Error: could not delete temporary directory\n"); return false; }
			delete pChildGrp1;
		}
		else
		{
			// compare them (size & crc32)
			if (!pGrp1 ||
			    pGrp1->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) ||
			    pGrp1->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName))
			{
				bool fCopied = false;

				// save core (EntryCRC32 might set additional fields)
				pUpGrp->SaveEntryCore(*pGrp2, strItemName);

				// already in update grp?
				if (pUpGrp->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) ||
				    pUpGrp->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName))
				{
					// copy it
					if (!C4Group_CopyEntry(pGrp2, pUpGrp, strItemName))
					{
						WriteLog("Error: could not add changed entry to update group\n");
						return false;
					}
					// set entry core
					pUpGrp->SetSavedEntryCore(strItemName);
					// modified...
					*fModified = true;
					fCopied = true;
				}
				iChangedEntries++;

				WriteLog("%s\\%s: update%s\n", pGrp2->GetFullName().getData(), strItemName, fCopied ? "" : " (already in group)");
			}
		}
	}
	// write entries list (always)
	if (!pUpGrp->Add(C4CFN_UpdateEntries, EntryList, false, true))
	{
		WriteLog("Error: could not save entry list!");
		return false;
	}

	if (iChangedEntries > 0)
		WriteLog("%s: %d/%d changed (%s)\n", pGrp2->GetFullName().getData(), iChangedEntries, pGrp2->EntryCount(), *fModified ? "update" : "skip");

	// success
	return true;
}
Пример #7
0
bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName)
{
#ifdef UPDATE_DEBUG
	char *pData; int iSize;
	CStdFile MyFile; MyFile.Load(strFile2, (BYTE **)&pData, &iSize, 0, true);
	MyFile.Create("SoIstRichtig.txt", false);
	MyFile.Write(pData, iSize);
	MyFile.Close();
	MemScramble((BYTE *)pData, iSize);
	MyFile.Create("UndSoAuch.txt", false);
	MyFile.Write(pData, iSize);
	MyFile.Close();
#endif

	// open Log
	if (!Log.Create("Update.log"))
		return false;

	// begin message
	WriteLog("Source: %s\nTarget: %s\nOutput: %s\n\n", strFile1, strFile2, strUpdateFile);

	// open both groups
	C4Group Group1, Group2;
	if (!Group1.Open(strFile1)) { WriteLog("Error: could not open %s!\n", strFile1); return false; }
	if (!Group2.Open(strFile2)) { WriteLog("Error: could not open %s!\n", strFile2); return false; }

	// All groups to be compared need to be packed
	if (!Group1.IsPacked()) { WriteLog("Error: source group %s not packed!\n", strFile1); return false; }
	if (!Group2.IsPacked()) { WriteLog("Error: target group %s not packed!\n", strFile2); return false; }
	if (Group1.HasPackedMother()) { WriteLog("Error: source group %s must not have a packed mother group!\n", strFile1); return false; }
	if (Group2.HasPackedMother()) { WriteLog("Error: target group %s must not have a packed mother group!\n", strFile2); return false; }

	// create/open update-group
	C4GroupEx UpGroup;
	if (!UpGroup.Open(strUpdateFile, true)) { WriteLog("Error: could not open %s!\n", strUpdateFile); return false; }

	// may be continued update-file -> try to load core
	UpGrpCnt = 0;
	bool fContinued = C4UpdatePackageCore::Load(UpGroup);

	// save crc2 for later check
	unsigned int iOldChks2 = GrpChks2;

	// create core info
	if (strName)
		SCopy(strName, Name, C4MaxName);
	else
		sprintf(Name, "%s Update", GetFilename(strFile1));
	SCopy(strFile1, DestPath, _MAX_PATH);
	GrpUpdate = true;
	if (!GetFileCRC(strFile1, &GrpChks1[UpGrpCnt]))
		{ WriteLog("Error: could not calc checksum for %s!\n", strFile1); return false; }
	if (!GetFileCRC(strFile2, &GrpChks2))
		{ WriteLog("Error: could not calc checksum for %s!\n", strFile2); return false; }
	if (fContinued)
	{
		// continuation check: GrpChks2 matches?
		if (GrpChks2 != iOldChks2)
			// that would mess up the update result...
			{ WriteLog("Error: could not add to update package - target groups don't match (checksum error)\n"); return false; }
		// already supported by this update?
		int i = 0;
		for (; i < UpGrpCnt; i++)
			if (GrpChks1[UpGrpCnt] == GrpChks1[i])
				break;
		if (i < UpGrpCnt)
			{ WriteLog("This update already supports the version of the source file.\n"); return false; }
	}

	UpGrpCnt++;

	// save core
	if (!C4UpdatePackageCore::Save(UpGroup))
		{ WriteLog("Could not save update package core!\n"); return false; }

	// compare groups, create update
	bool fModified = false;
	bool fSuccess = MkUp(&Group1, &Group2, &UpGroup, &fModified);
	// close (save) it
	UpGroup.Close(false);
	// error?
	if (!fSuccess)
	{
		WriteLog("Update package not created.\n");
		EraseItem(strUpdateFile);
		return false;
	}

	WriteLog("Update package created.\n");
	return true;
}