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; }
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); }
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; }
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; }
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); }
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; }
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; }
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; }
// 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); }
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; }
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; }
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; }