Example #1
0
BOOL C4SDefinitions::AssertModules(const char *szPath, char *sMissing)
	{
	// Local only
	if (LocalOnly) return TRUE;

	// Check all listed modules for availability
	BOOL fAllAvailable=TRUE;
	char szModule[_MAX_PATH+1];
	if (sMissing) sMissing[0]=0;
	// Check all definition files
	for (int32_t cnt=0; cnt<C4S_MaxDefinitions; cnt++)
		if (Definition[cnt][0])
			{
			// Compose filename using path specified by caller
			szModule[0]=0;
			if (szPath) SCopy(szPath,szModule); if (szModule[0]) AppendBackslash(szModule);
			SAppend(Definition[cnt],szModule);
			// Missing
			if (!C4Group_IsGroup(szModule))
				{
				// Add to list
				if (sMissing) { SNewSegment(sMissing,", "); SAppend(Definition[cnt],sMissing); }
				fAllAvailable=FALSE;
				}
			}

	return fAllAvailable;
	}
Example #2
0
bool C4MaterialMap::SaveEnumeration(C4Group &hGroup)
{
	char *mapbuf = new char [1000];
	mapbuf[0]=0;
	SAppend("[Enumeration]",mapbuf); SAppend(LineFeed,mapbuf);
	for (int32_t cnt=0; cnt<Num; cnt++)
	{
		SAppend(Map[cnt].Name,mapbuf);
		SAppend(LineFeed,mapbuf);
	}
	return hGroup.Add(C4CFN_MatMap,mapbuf,SLen(mapbuf),false,true);
}
Example #3
0
int32_t C4TextureMap::LoadTextures(C4Group &hGroup, C4Group* OverloadFile)
  {
  int32_t texnum=0;

#ifdef C4ENGINE

	// overload: load from other file
	if (OverloadFile) texnum+=LoadTextures(*OverloadFile);

  char texname[256+1];
	C4Surface *ctex;
  size_t binlen;
	// newgfx: load PNG-textures first
  hGroup.ResetSearch();
  while (hGroup.AccessNextEntry(C4CFN_PNGFiles,&binlen,texname))		
		{
		// check if it already exists in the map
    SReplaceChar(texname,'.',0);
		if (GetTexture(texname)) continue;
		SAppend(".png", texname);
		// load
    if (ctex=GroupReadSurfacePNG(hGroup))
      {
      SReplaceChar(texname,'.',0);
      if (AddTexture(texname,ctex)) texnum++;
      else delete ctex;
      }
		}
	// Load all bitmap files from group
	hGroup.ResetSearch();
	CSurface8 *ctex8;
	while (hGroup.AccessNextEntry(C4CFN_BitmapFiles,&binlen,texname))		
		{
		// check if it already exists in the map
		SReplaceChar(texname,'.',0);
		if (GetTexture(texname)) continue;
		SAppend(".bmp", texname);
		if (ctex8=GroupReadSurface8(hGroup))
			{
			ctex8->AllowColor(0,2,TRUE);
			SReplaceChar(texname,'.',0);
			if (AddTexture(texname,ctex8)) texnum++;
			else delete ctex;
			}
		}

#endif

	return texnum;
	}
Example #4
0
bool C4VectorFont::Init(C4Group &hGrp, const char *szFilename, C4Config &rCfg)
	{
	// name by file
	Name.Copy(GetFilenameOnly(szFilename));
#if defined(_WIN32) && !defined(HAVE_FREETYPE)
	// check whether group is directory or packed
	if (!hGrp.IsPacked())
		{
		// it's open: use the file directly
		SCopy(hGrp.GetFullName().getData(), FileName, _MAX_PATH);
		AppendBackslash(FileName);
		SAppend(szFilename, FileName);
		if (!FileExists(FileName)) { *FileName=0; return false; }
		fIsTempFile = false;
		}
	else
		{
		// it's packed: extract to temp path
		SCopy(rCfg.AtTempPath(szFilename), FileName, _MAX_PATH);
		// make sure the filename is not in use, in case multiple instances of the engine are run
		if (FileExists(FileName))
			{
			RemoveExtension(FileName);
			StdStrBuf sNewFilename;
			for (int i=0; i<1000; ++i)
				{
				sNewFilename.Format("%s%x", FileName, (int)rand());
				if (*GetExtension(szFilename))
					{
					sNewFilename.AppendChar('.');
					sNewFilename.Append(GetExtension(szFilename));
					}
				if (!FileExists(sNewFilename.getData())) break;
				}
			SCopy(sNewFilename.getData(), FileName, _MAX_PATH);
			}
		if (!hGrp.ExtractEntry(szFilename, FileName)) { *FileName=0; return false; }
		fIsTempFile = true;
		}
	// add the font resource
	//if (!AddFontResourceEx(FileName, FR_PRIVATE, NULL)) requires win2k
	if (!AddFontResource(FileName))
		{
		if (fIsTempFile) EraseFile(FileName);
		*FileName='\0';
		return false;
		}
#else
	if (!hGrp.LoadEntry(szFilename, Data)) return false;
#endif
	// success
	return true;
	}
bool C4Network2ResList::FindTempResFileName(const char *szFilename, char *pTarget)
{
	char safeFilename[_MAX_PATH];
	char* safePos = safeFilename;
	while (*szFilename)
	{
		if ((*szFilename >= 'a' && *szFilename <= 'z') ||
		    (*szFilename >= 'A' && *szFilename <= 'Z') ||
		    (*szFilename >= '0' && *szFilename <= '9') ||
		    (*szFilename == '.') || (*szFilename == '/'))
			*safePos = *szFilename;
		else
			*safePos = '_';

		++safePos;
		++szFilename;
	}
	*safePos = 0;
	szFilename = safeFilename;

	// create temporary file
	SCopy(Config.AtNetworkPath(GetFilename(szFilename)), pTarget, _MAX_PATH);
	// file name is free?
	if (!ItemExists(pTarget)) return true;
	// find another file name
	char szFileMask[_MAX_PATH+1];
	SCopy(pTarget, szFileMask, GetExtension(pTarget)-1-pTarget);
	SAppend("_%d", szFileMask, _MAX_PATH);
	SAppend(GetExtension(pTarget)-1, szFileMask, _MAX_PATH);
	for (int32_t i = 2; i < 1000; i++)
	{
		snprintf(pTarget, _MAX_PATH, szFileMask, i);
		// doesn't exist?
		if (!ItemExists(pTarget))
			return true;
	}
	// not found
	return false;
}
Example #6
0
bool C4ObjectList::Write(char *szTarget)
{
	char ostr[25];
	szTarget[0]=0;
	C4ObjectLink *cLnk;
	for (cLnk=First; cLnk && cLnk->Obj; cLnk=cLnk->Next)
		if (cLnk->Obj->Status)
		{
			sprintf(ostr,"%d;",cLnk->Obj->Number);
			SAppend(ostr,szTarget);
		}
	return true;
}
void SetClientPrefix(char *szFilename, const char *szClient)
{
	char szTemp[1024+1];
	// Compose prefix
	char szPrefix[1024+1];
	SCopy(szClient,szPrefix); SAppendChar('-',szPrefix);
	// Prefix already set?
	SCopy(GetFilename(szFilename),szTemp,SLen(szPrefix));
	if (SEqualNoCase(szTemp,szPrefix)) return;
	// Insert prefix
	SCopy(GetFilename(szFilename),szTemp);
	SCopy(szPrefix,GetFilename(szFilename));
	SAppend(szTemp,szFilename);
}
Example #8
0
BOOL C4UpdatePackage::DoGrpUpdate(C4Group *pUpdateData, C4GroupEx *pGrpTo) {
    char *pData;
    // sort entries
    if (pUpdateData->LoadEntry(C4CFN_UpdateEntries, &pData, NULL, 1)) {
        // delete all entries that do not appear in the entries list
        char strItemName[_MAX_FNAME + 1], strItemName2[_MAX_FNAME + 1];
        pGrpTo->ResetSearch();
        while (pGrpTo->FindNextEntry("*", strItemName)) {
            BOOL fGotIt = FALSE;
            for (int i = 0;
                    fGotIt = SCopySegment(pData, i, strItemName2, '|', _MAX_FNAME);
                    i++) {
                // remove seperator
                char *pSep = strchr(strItemName2, '=');
                if (pSep) *pSep = '\0';
                // in list?
                if (SEqual(strItemName, strItemName2)) break;
            }
            if (!fGotIt) pGrpTo->DeleteEntry(strItemName);
        }
        // set entry times, set sort list
        char strSortList[32767] = "";
        for (int i = 0; SCopySegment(pData, i, strItemName, '|', _MAX_FNAME); i++) {
            // get time (if given)
            char *pTime = strchr(strItemName, '=');
            if (pTime) *pTime++ = '\0';
            // set
            if (pTime) pGrpTo->SetEntryTime(strItemName, atoi(pTime));
            // update EntryCRC32. This will make updates to old groups invalid
            // however, it's needed so updates will update the EntryCRC of *unchanged*
            // files correctly
            pGrpTo->EntryCRC32(strItemName);
            // copy to sort list
            SAppend(strItemName, strSortList);
            SAppendChar('|', strSortList);
        }
        // sort by list
        pGrpTo->Sort(strSortList);
        delete[] pData;
    }
    // copy header from update group
    pGrpTo->SetHead(*pUpdateData);
    // ok
    return TRUE;
}
Example #9
0
bool C4UpdatePackage::DoGrpUpdate(C4Group *pUpdateData, C4GroupEx *pGrpTo)
{
	char *pData;
	// sort entries
	if (pUpdateData->LoadEntry(C4CFN_UpdateEntries, &pData, nullptr, 1))
	{
		// delete all entries that do not appear in the entries list
		char strItemName[_MAX_FNAME+1], strItemName2[_MAX_FNAME+1];
		pGrpTo->ResetSearch();
		while (pGrpTo->FindNextEntry("*", strItemName))
		{
			bool fGotIt = false;
			for (int i = 0; (fGotIt = SCopySegment(pData, i, strItemName2, '|', _MAX_FNAME)); i++)
			{
				// remove separator
				char *pSep = strchr(strItemName2, '=');
				if (pSep) *pSep = '\0';
				// in list?
				if (SEqual(strItemName, strItemName2))
					break;
			}
			if (!fGotIt)
				pGrpTo->DeleteEntry(strItemName);
		}
		// set entry times, set sort list
		char strSortList[32767] = "";
		for (int i = 0; SCopySegment(pData, i, strItemName, '|', _MAX_FNAME); i++)
		{
			// strip checksum/time (if given)
			char *pTime = strchr(strItemName, '=');
			if (pTime) *pTime = '\0';
			// copy to sort list
			SAppend(strItemName, strSortList);
			SAppendChar('|', strSortList);
		}
		// sort by list
		pGrpTo->Sort(strSortList);
		delete[] pData;
	}
	// copy header from update group
	pGrpTo->SetHead(*pUpdateData);
	// ok
	return true;
}
Example #10
0
bool C4ComponentHost::GetLanguageString(const char *szLanguage,
                                        StdStrBuf &rTarget) {
  const char *cptr;
  // No good parameters
  if (!szLanguage || !Data) return false;
  // Search for two-letter language identifier in text body, i.e. "DE:"
  char langindex[4] = "";
  for (int clseg = 0;
       SCopySegment(szLanguage ? szLanguage : "", clseg, langindex, ',', 2);
       clseg++) {
    SAppend(":", langindex);
    if (cptr = SSearch(Data.getData(), langindex)) {
      // Return the according string
      int iEndPos = SCharPos('\r', cptr);
      if (iEndPos < 0) iEndPos = SCharPos('\n', cptr);
      if (iEndPos < 0) iEndPos = strlen(cptr);
      rTarget.Copy(cptr, iEndPos);
      return true;
    }
  }
  // Language string not found
  return false;
}
bool C4DefGraphics::Load(C4Group &hGroup, StdMeshSkeletonLoader &loader, bool fColorByOwner)
{
	char Filename[_MAX_PATH+1]; *Filename=0;

	// load skeletons
	hGroup.ResetSearch();
	while (hGroup.FindNextEntry("*", Filename, NULL, !!*Filename))
	{
		if (!WildcardMatch(C4CFN_DefSkeleton, Filename) && !WildcardMatch(C4CFN_DefSkeletonXml, Filename)) continue;
		LoadSkeleton(hGroup, Filename, loader);
	}

	// Try from Mesh first
	if (!LoadMesh(hGroup, C4CFN_DefMesh, loader))
		if(!LoadMesh(hGroup, C4CFN_DefMeshXml, loader))
			LoadBitmap(hGroup, C4CFN_DefGraphics, C4CFN_ClrByOwner, C4CFN_NormalMap, fColorByOwner);

	// load additional graphics
	C4DefGraphics *pLastGraphics = this;
	const int32_t iOverlayWildcardPos = SCharPos('*', C4CFN_ClrByOwnerEx);
	hGroup.ResetSearch(); *Filename=0;
	const char* const AdditionalGraphics[] = { C4CFN_DefGraphicsEx, C4CFN_DefGraphicsExMesh, C4CFN_DefGraphicsExMeshXml, NULL };
	while (hGroup.FindNextEntry("*", Filename, NULL, !!*Filename))
	{
		for(const char* const* szWildcard = AdditionalGraphics; *szWildcard != NULL; ++szWildcard)
		{
			if(!WildcardMatch(*szWildcard, Filename)) continue;
			// skip def graphics
			if (SEqualNoCase(Filename, C4CFN_DefGraphics) || SEqualNoCase(Filename, C4CFN_DefMesh) || SEqualNoCase(Filename, C4CFN_DefMeshXml)) continue;
			// skip scaled def graphics
			if (WildcardMatch(C4CFN_DefGraphicsScaled, Filename)) continue;
			// get name
			char GrpName[_MAX_PATH+1];
			const int32_t iWildcardPos = SCharPos('*', *szWildcard);
			SCopy(Filename + iWildcardPos, GrpName, _MAX_PATH);
			RemoveExtension(GrpName);
			// remove trailing number for scaled graphics
			int32_t extpos; int scale;
			if ((extpos = SCharLastPos('.', GrpName)) > -1)
				if (sscanf(GrpName+extpos+1, "%d", &scale) == 1)
					GrpName[extpos] = '\0';
			// clip to max length
			GrpName[C4MaxName]=0;
			// create new graphics
			pLastGraphics->pNext = new C4AdditionalDefGraphics(pDef, GrpName);
			pLastGraphics = pLastGraphics->pNext;
			if(*szWildcard == AdditionalGraphics[0])
			{
				// create overlay-filename
				char OverlayFn[_MAX_PATH+1];
				if(fColorByOwner)
				{
					// GraphicsX.png -> OverlayX.png
					SCopy(C4CFN_ClrByOwnerEx, OverlayFn, _MAX_PATH);
					OverlayFn[iOverlayWildcardPos]=0;
					SAppend(Filename + iWildcardPos, OverlayFn);
					EnforceExtension(OverlayFn, GetExtension(C4CFN_ClrByOwnerEx));
				}

				// create normal filename
				char NormalFn[_MAX_PATH+1];
				SCopy(C4CFN_NormalMapEx, NormalFn, _MAX_PATH);
				NormalFn[iOverlayWildcardPos]=0;
				SAppend(Filename + iWildcardPos, NormalFn);
				EnforceExtension(NormalFn, GetExtension(C4CFN_NormalMapEx));

				// load them
				if (!pLastGraphics->LoadBitmap(hGroup, Filename, fColorByOwner ? OverlayFn : NULL, NormalFn, fColorByOwner))
					return false;
			}
			else
			{
				if (!pLastGraphics->LoadMesh(hGroup, Filename, loader))
					return false;
			}
		}
	}
	// done, success
	return true;
}
bool C4ObjectInfo::Save(C4Group &hGroup, bool fStoreTiny, C4DefList *pDefs)
{
	// Set group file name; rename if necessary
	char szTempGroup[_MAX_PATH+1];
	SCopy(Name, szTempGroup, _MAX_PATH);
	MakeFilenameFromTitle(szTempGroup);
	SAppend(".oci",szTempGroup, _MAX_PATH);
	if (!SEqualNoCase(Filename, szTempGroup))
	{
		if (!Filename[0])
		{
			// first time creation of file - make sure it's not a duplicate
			SCopy(szTempGroup, Filename, _MAX_PATH);
			while (hGroup.FindEntry(Filename))
			{
				// if a crew info of that name exists already, rename!
				RemoveExtension(Filename);
				int32_t iFinNum = GetTrailingNumber(Filename), iLen = SLen(Filename);
				while (iLen && Inside(Filename[iLen-1], '0', '9')) --iLen;
				if (iLen>_MAX_PATH-22) { LogF("Error generating unique filename for %s(%s): Path overflow", Name, hGroup.GetFullName().getData()); break; }
				snprintf(Filename+iLen, 22, "%d", iFinNum+1);
				EnforceExtension(Filename, "oci");
			}
		}
		else
		{
			// Crew was renamed; file rename necessary, if the name is not blocked by another crew info
			if (!hGroup.FindEntry(szTempGroup))
			{
				if (hGroup.Rename(Filename, szTempGroup))
					SCopy(szTempGroup, Filename, _MAX_PATH);
				else
				{
					// could not rename. Not fatal; just use old file
					LogF("Error adjusting crew info for %s into %s: Rename error from %s to %s!", Name, hGroup.GetFullName().getData(), Filename, szTempGroup);
				}
			}
		}
	}
	// Open group
	C4Group hTemp;
	if (!hTemp.OpenAsChild(&hGroup, Filename, false, true))
		return false;
	// custom rank image present?
	if (pDefs && !fStoreTiny)
	{
		C4Def *pDef = pDefs->ID2Def(id);
		if (pDef)
		{
			if (pDef->pRankSymbols)
			{
				C4FacetSurface fctRankSymbol;
				if (C4RankSystem::DrawRankSymbol(&fctRankSymbol, Rank, pDef->pRankSymbols, pDef->iNumRankSymbols, true))
				{
					fctRankSymbol.GetFace().SavePNG(hTemp, C4CFN_ClonkRank);
				}
			}
			else
			{
				// definition does not have custom rank symbols: Remove any rank image from Clonk
				hTemp.Delete(C4CFN_ClonkRank);
			}
		}
	}

	// Save info to temp group
	if (!C4ObjectInfoCore::Save(hTemp, pDefs))
		{ hTemp.Close(); return false; }
	// Close temp group
	hTemp.Close();
	// Success
	return true;
}
Example #13
0
// Construct full path
void C4ComponentHost::CopyFilePathFromGroup(const C4Group &hGroup) {
  SCopy(pConfig->AtExeRelativePath(hGroup.GetFullName().getData()), FilePath,
        _MAX_PATH - 1);
  SAppendChar(DirectorySeparator, FilePath);
  SAppend(Filename, FilePath, _MAX_PATH);
}
Example #14
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;
}
Example #15
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;
}
Example #16
0
C4GroupSet C4Language::GetPackGroups(C4Group & hGroup)
{
	// Build a group set containing the provided group and
	// alternative groups for cross-loading from a language pack
	char strRelativePath[_MAX_PATH + 1];
	char strTargetLocation[_MAX_PATH + 1];
	char strPackPath[_MAX_PATH + 1];
	char strPackGroupLocation[_MAX_PATH + 1];
	char strAdvance[_MAX_PATH + 1];

	// Store wanted target location
	SCopy(Config.AtRelativePath(hGroup.GetFullName().getData()), strRelativePath, _MAX_PATH);
	SCopy(strRelativePath, strTargetLocation, _MAX_PATH);

	// Adjust location by scenario origin
	if (Game.C4S.Head.Origin.getLength() && SEqualNoCase(GetExtension(Game.C4S.Head.Origin.getData()), "ocs"))
	{
		const char *szScenarioRelativePath = GetRelativePathS(strRelativePath, Config.AtRelativePath(Game.ScenarioFilename));
		if (szScenarioRelativePath != strRelativePath)
		{
			// this is a path within the scenario! Change to origin.
			size_t iRestPathLen = SLen(szScenarioRelativePath);
			if (Game.C4S.Head.Origin.getLength() + 1 + iRestPathLen <= _MAX_PATH)
			{
				SCopy(Game.C4S.Head.Origin.getData(), strTargetLocation);
				if (iRestPathLen)
				{
					SAppendChar(DirectorySeparator, strTargetLocation);
					SAppend(szScenarioRelativePath, strTargetLocation);
				}
			}
		}
	}

	// Process all language packs (and their respective pack groups)
	C4Group *pPack, *pPackGroup;
	for (int iPack = 0; (pPack = Packs.GetGroup(iPack)) && (pPackGroup = PackGroups.GetGroup(iPack)); iPack++)
	{
		// Get current pack group position within pack
		SCopy(pPack->GetFullName().getData(), strPackPath, _MAX_PATH);
		GetRelativePath(pPackGroup->GetFullName().getData(), strPackPath, strPackGroupLocation);

		// Pack group is at correct position within pack: continue with next pack
		if (SEqualNoCase(strPackGroupLocation, strTargetLocation))
			continue;

		// Try to backtrack until we can reach the target location as a relative child
		while ( strPackGroupLocation[0]
		        && !GetRelativePath(strTargetLocation, strPackGroupLocation, strAdvance)
		        && pPackGroup->OpenMother() )
		{
			// Update pack group location
			GetRelativePath(pPackGroup->GetFullName().getData(), strPackPath, strPackGroupLocation);
		}

		// We can reach the target location as a relative child
		if (strPackGroupLocation[0] && GetRelativePath(strTargetLocation, strPackGroupLocation, strAdvance))
		{
			// Advance pack group to relative child
			pPackGroup->OpenChild(strAdvance);
		}

		// Cannot reach by advancing: need to close and reopen (rewinding group file)
		else
		{
			// Close pack group (if it is open at all)
			pPackGroup->Close();
			// Reopen pack group to relative position in language pack if possible
			pPackGroup->OpenAsChild(pPack, strTargetLocation);
		}

	}

	// Store new target location
	SCopy(strTargetLocation, PackGroupLocation, _MAX_FNAME);

	C4GroupSet r;
	// Provided group gets highest priority
	r.RegisterGroup(hGroup, false, 1000, C4GSCnt_Component);
	// register currently open pack groups
	r.RegisterGroups(PackGroups, C4GSCnt_Language);
	return r;
}