bool C4Language::Init() { // Clear (to allow clean re-init) Clear(); // Make sure Language.ocg is unpacked (TODO: This won't work properly if Language.ocg is in system data path) // Assume for now that Language.ocg is either at a writable location or unpacked already. // TODO: Use all Language.c4gs that we find, and merge them. // TODO: Use gettext instead? StdStrBuf langPath; C4Reloc::iterator iter; for(iter = Reloc.begin(); iter != Reloc.end(); ++iter) { langPath.Copy((*iter).strBuf + DirSep + C4CFN_Languages); if(ItemExists(langPath.getData())) { if(DirectoryExists(langPath.getData())) break; if(C4Group_UnpackDirectory(langPath.getData())) break; } } // Break if no language.ocg found if(iter != Reloc.end()) { // Look for available language packs in Language.ocg C4Group *pPack; char strPackFilename[_MAX_FNAME + 1], strEntry[_MAX_FNAME + 1]; if (PackDirectory.Open(langPath.getData())) { while (PackDirectory.FindNextEntry("*.ocg", strEntry)) { sprintf(strPackFilename, "%s" DirSep "%s", C4CFN_Languages, strEntry); pPack = new C4Group(); if (pPack->Open(strPackFilename)) { Packs.RegisterGroup(*pPack, true, C4GSCnt_Language, false); } else { delete pPack; } } } // Now create a pack group for each language pack (these pack groups are child groups // that browse along each pack to access requested data) for (int iPack = 0; (pPack = Packs.GetGroup(iPack)); iPack++) PackGroups.RegisterGroup(*(new C4Group), true, C4GSPrio_Base, C4GSCnt_Language); } // Load language infos by scanning string tables (the engine doesn't really need this at the moment) InitInfos(); // Done return true; }
BOOL C4Record::Start(bool fInitial) { // no double record if (fRecording) return FALSE; // create demos folder if (!Config.General.CreateSaveFolder(Config.General.SaveDemoFolder.getData(), LoadResStr("IDS_GAME_RECORDSTITLE"))) return FALSE; // various infos StdStrBuf sDemoFolder; sDemoFolder.Ref(Config.General.SaveDemoFolder); char sScenName[_MAX_FNAME + 1]; SCopy(GetFilenameOnly(Game.Parameters.Scenario.getFile()), sScenName, _MAX_FNAME); // remove trailing numbers from scenario name (e.g. from savegames) - could we // perhaps use C4S.Head.Origin instead...? char *pScenNameEnd = sScenName + SLen(sScenName); while (Inside<char>(*--pScenNameEnd, '0', '9')) if (pScenNameEnd == sScenName) break; pScenNameEnd[1] = 0; // determine index (by total number of records) Index = 1; for (DirectoryIterator i(Config.General.SaveDemoFolder.getData()); *i; ++i) if (WildcardMatch(C4CFN_ScenarioFiles, *i)) Index++; // compose record filename sFilename.Format("%s" DirSep "%03i-%s.c4s", sDemoFolder.getData(), Index, sScenName); // log StdStrBuf sLog; sLog.Format(LoadResStr("IDS_PRC_RECORDINGTO"), sFilename.getData()); if (Game.FrameCounter) sLog.AppendFormat(" (Frame %d)", Game.FrameCounter); Log(sLog.getData()); // save game - this also saves player info list C4GameSaveRecord saveRec(fInitial, Index, Game.Parameters.isLeague()); if (!saveRec.Save(sFilename.getData())) return FALSE; saveRec.Close(); // unpack group, if neccessary if (!DirectoryExists(sFilename.getData()) && !C4Group_UnpackDirectory(sFilename.getData())) return FALSE; // open control record file char szCtrlRecFilename[_MAX_PATH + 1 + _MAX_FNAME]; sprintf(szCtrlRecFilename, "%s" DirSep C4CFN_CtrlRec, sFilename.getData()); if (!CtrlRec.Create(szCtrlRecFilename)) return FALSE; // open record group if (!RecordGrp.Open(sFilename.getData())) return FALSE; // record go fStreaming = false; fRecording = true; iLastFrame = 0; return TRUE; }
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::Execute(C4Group *pGroup) { // search target C4GroupEx TargetGrp; char strTarget[_MAX_PATH]; SCopy(DestPath, strTarget, _MAX_PATH); char *p = strTarget, *lp = strTarget; while (p = strchr(p + 1, '\\')) { *p = 0; if (!*(p + 1)) break; if (!SEqual(lp, "..")) if (TargetGrp.Open(strTarget)) { // packed? bool fPacked = TargetGrp.IsPacked(); // maker check (someone might try to unpack directories w/o asking user) if (fPacked) if (!SEqual(TargetGrp.GetMaker(), pGroup->GetMaker())) return FALSE; // Close Group TargetGrp.Close(TRUE); if (fPacked) // Unpack C4Group_UnpackDirectory(strTarget); } else { // GrpUpdate -> file must exist if (GrpUpdate) return FALSE; // create dir CreateDirectory(strTarget, NULL); } *p = '\\'; lp = p + 1; } // try to open it if (!TargetGrp.Open(strTarget, !GrpUpdate)) return FALSE; // check if the update is allowed if (GrpUpdate) { // maker must match /*if(!SEqual(TargetGrp.GetMaker(), pGroup->GetMaker())) - now allowing updates from different makers return FALSE;*/ // check checksum uint32_t iCRC32; if (!C4Group_GetFileCRC(TargetGrp.GetFullName().getData(), &iCRC32)) return FALSE; int i = 0; for (; i < UpGrpCnt; i++) if (iCRC32 == GrpChks1[i]) break; if (i >= UpGrpCnt) return FALSE; } else { // only allow Extra.c4g-Updates if (!SEqual2(DestPath, "Extra.c4g")) return FALSE; } // update children char ItemFileName[_MAX_PATH]; pGroup->ResetSearch(); while (pGroup->FindNextEntry("*", ItemFileName)) if (!SEqual(ItemFileName, C4CFN_UpdateCore) && !SEqual(ItemFileName, C4CFN_UpdateEntries)) DoUpdate(pGroup, &TargetGrp, ItemFileName); // do GrpUpdate if (GrpUpdate) DoGrpUpdate(pGroup, &TargetGrp); // close the group TargetGrp.Close(FALSE); if (GrpUpdate) { // check the result uint32_t iResChks; if (!C4Group_GetFileCRC(strTarget, &iResChks)) return FALSE; if (iResChks != GrpChks2) { #ifdef UPDATE_DEBUG char *pData; int iSize; CStdFile MyFile; MyFile.Load(strTarget, (BYTE **)&pData, &iSize, 0, TRUE); MyFile.Create("DiesesDingIstMist.txt", FALSE); MyFile.Write(pData, iSize, FALSE); MyFile.Close(); #endif return FALSE; } } return TRUE; }