BOOL CStdBitmap::Save(const char *szFileName) { CStdFile hFile; if (!Bits) return FALSE; int savesize = sizeof(Head) + sizeof(Info); if (Info.biBitCount == 8) savesize += 256 * sizeof(RGBQUAD); if (!hFile.Create(szFileName, FALSE) || !hFile.Write(this, savesize) || !hFile.Write(Bits, Info.biSizeImage) || !hFile.Close()) return FALSE; return TRUE; }
bool GetLogSection(size_t iStart, size_t iLength, StdStrBuf &rsOut) { if (!iLength) { rsOut.Clear(); return true; } // read section from log file CStdFile LogFileRead; char *szBuf, *szBufOrig; size_t iSize; // size exclusing terminator if (!LogFileRead.Load(sLogFileName.getData(), (BYTE **)&szBuf, (int *)&iSize, 1)) return false; szBufOrig = szBuf; // reduce to desired buffer section if (iStart > iSize) iStart = iSize; if (iStart + iLength > iSize) iLength = iSize - iStart; szBuf += iStart; szBuf[iLength] = '\0'; // strip timestamps; convert linebreaks to Clonk-linebreaks '|' char *szPosWrite = szBuf; const char *szPosRead = szBuf; while (*szPosRead) { // skip timestamp if (*szPosRead == '[') while (*szPosRead && *szPosRead != ']') { --iSize; ++szPosRead; } // skip whitespace behind timestamp if (!*szPosRead) break; szPosRead++; // copy data until linebreak size_t iLen = 0; while (*szPosRead && *szPosRead != 0x0d && *szPosRead != 0x0a) { ++szPosRead; ++iLen; } if (iLen && szPosRead - iLen != szPosWrite) memmove(szPosWrite, szPosRead - iLen, iLen); szPosWrite += iLen; // skip additional linebreaks while (*szPosRead == 0x0d || *szPosRead == 0x0a) ++szPosRead; // write a Clonk-linebreak if (*szPosRead) *szPosWrite++ = '|'; } // done; create string buffer from data rsOut.Copy(szBuf, szPosWrite - szBuf); // old buf no longer used delete[] szBufOrig; // done, success return true; }
bool CSurface8::Save(const char *szFilename, CStdPalette *bpPalette) { C4BMP256Info BitmapInfo; BitmapInfo.Set(Wdt,Hgt, bpPalette ? bpPalette : pPal); // Create file & write info CStdFile hFile; if ( !hFile.Create(szFilename) || !hFile.Write(&BitmapInfo,sizeof(BitmapInfo)) ) { return false; } // Write lines char bpEmpty[4]; ZeroMem(bpEmpty, 4); const int iEmpty = DWordAligned(Wdt)-Wdt; for (int cnt=Hgt-1; cnt>=0; cnt--) { if (!hFile.Write(Bits+(Pitch*cnt),Wdt)) { return false; } if (iEmpty) if (!hFile.Write(bpEmpty,iEmpty)) { return false; } } // Close file hFile.Close(); // Success return true; }
bool CSurface8::Save(const char *szFilename, BYTE *bpPalette) { CBitmap256Info BitmapInfo; BitmapInfo.Set(Wdt, Hgt, bpPalette ? bpPalette : pPal->Colors); // Create file & write info CStdFile hFile; if (!hFile.Create(szFilename) || !hFile.Write(&BitmapInfo, sizeof(BitmapInfo))) { return FALSE; } // Write lines char bpEmpty[4]; int iEmpty = DWordAligned(Wdt) - Wdt; for (int cnt = Hgt - 1; cnt >= 0; cnt--) { if (!hFile.Write(Bits + (Pitch * cnt), Wdt)) { return FALSE; } if (iEmpty) if (!hFile.Write(bpEmpty, iEmpty)) { return FALSE; } } // Close file hFile.Close(); // Success return TRUE; }
bool C4TableGraph::DumpToFile(const StdStrBuf &rszFilename, bool fAppend) const { assert(!!rszFilename); // nothing to write? if (!fWrapped && !iBackLogPos) return false; // try append if desired; create if unsuccessful CStdFile out; if (fAppend) if (!out.Append(rszFilename.getData())) fAppend = false; if (!fAppend) { if (!out.Create(rszFilename.getData())) return false; // print header out.WriteString("t\tv\n\r"); } // write out current timeframe int iEndTime = GetEndTime(); StdStrBuf buf; for (int iWriteTime = GetStartTime(); iWriteTime < iEndTime; ++iWriteTime) { buf.Format("%d\t%d\n\r", (int)iWriteTime, (int)GetValue(iWriteTime)); out.WriteString(buf.getData()); } return true; }
void C4Playback::Clear() { // free stuff for (chunks_t::iterator i = chunks.begin(); i != chunks.end(); i++) i->Delete(); chunks.clear(); currChunk = chunks.end(); playbackFile.Close(); sequentialBuffer.Clear(); fLoadSequential = false; #ifdef DEBUGREC C4IDPacket *pkt; while (pkt = DebugRec.firstPkt()) DebugRec.Delete(pkt); #ifdef DEBUGREC_EXTFILE DbgRecFile.Close(); #endif #endif // done Finished = TRUE; }
void C4Playback::Check(C4RecordChunkType eType, const uint8_t *pData, int iSize) { // only if enabled if (DoNoDebugRec > 0) return; if (Game.FrameCounter < DEBUGREC_START_FRAME) return; C4PktDebugRec PktInReplay; bool fHasPacketFromHead = false; #ifdef DEBUGREC_EXTFILE #ifdef DEBUGREC_EXTFILE_WRITE // writing of external debugrec file DbgRecFile.Write(&eType, sizeof eType); int32_t iSize32 = iSize; DbgRecFile.Write(&iSize32, sizeof iSize32); DbgRecFile.Write(pData, iSize); return; #else int32_t iSize32 = 0; C4RecordChunkType eTypeRec = RCT_Undefined; DbgRecFile.Read(&eTypeRec, sizeof eTypeRec); DbgRecFile.Read(&iSize32, sizeof iSize32); if (iSize32) { StdBuf buf; buf.SetSize(iSize32); DbgRecFile.Read(buf.getMData(), iSize32); PktInReplay = C4PktDebugRec(eTypeRec, buf); } #endif #else // check debug rec in list C4IDPacket *pkt; if (pkt = DebugRec.firstPkt()) { // copy from list PktInReplay = *static_cast<C4PktDebugRec *>(pkt->getPkt()); DebugRec.Delete(pkt); } else { // special sync check skip... while (currChunk != chunks.end() && currChunk->Type == RCT_CtrlPkt) { C4IDPacket Packet(*currChunk->pPkt); C4ControlPacket *pCtrlPck = static_cast<C4ControlPacket *>(Packet.getPkt()); assert(!pCtrlPck->Sync()); Game.Control.ExecControlPacket(Packet.getPktType(), pCtrlPck); NextChunk(); } // record end? if (currChunk == chunks.end() || currChunk->Type == RCT_End || Finished) { Log("DebugRec end: All in sync!"); ++DoNoDebugRec; return; } // unpack directly from head if (currChunk->Type != eType) { DebugRecError(FormatString("Playback type %x, this type %x", currChunk->Type, eType).getData()); return; } PktInReplay = *currChunk->pDbg; fHasPacketFromHead = true; } #endif // DEBUGREC_EXTFILE // record end? if (PktInReplay.getType() == RCT_End) { Log("DebugRec end: All in sync (2)!"); ++DoNoDebugRec; return; } // replay packet is unpacked to PktInReplay now; check it if (PktInReplay.getType() != eType) { DebugRecError(FormatString("Type %s != %s", GetRecordChunkTypeName(PktInReplay.getType()), GetRecordChunkTypeName(eType)).getData()); return; } if (PktInReplay.getSize() != iSize) { DebugRecError(FormatString("Size %d != %d", (int)PktInReplay.getSize(), (int)iSize).getData()); } // check packet data if (memcmp(PktInReplay.getData(), pData, iSize)) { StdStrBuf sErr; sErr.Format("DbgRecPkt Type %s, size %d", GetRecordChunkTypeName(eType), iSize); sErr.Append(" Replay: "); StdBuf replay(PktInReplay.getData(), PktInReplay.getSize()); sErr.Append(GetDbgRecPktData(eType, replay)); sErr.Append(" Here: "); StdBuf here(pData, iSize); sErr.Append(GetDbgRecPktData(eType, here)); DebugRecError(sErr.getData()); } // packet is fine, jump over it if (fHasPacketFromHead) NextChunk(); }
BOOL C4Playback::Open(C4Group &rGrp) { // clean up Clear(); fLoadSequential = false; iLastSequentialFrame = 0; bool fStrip = false; // get text record file StdStrBuf TextBuf; if (rGrp.LoadEntryString(C4CFN_CtrlRecText, TextBuf)) { if (!ReadText(TextBuf)) return FALSE; } else { // open group? Then do some sequential reading for large files // Can't do this when a dump is forced, because the dump needs all data // Also can't do this when stripping is desired if (!rGrp.IsPacked()) if (!Game.RecordDumpFile.getLength()) if (!fStrip) fLoadSequential = true; // get record file if (fLoadSequential) { if (!rGrp.FindEntry(C4CFN_CtrlRec)) return FALSE; if (!playbackFile.Open( FormatString("%s%c%s", rGrp.GetFullName().getData(), (char)DirectorySeparator, (const char *)C4CFN_CtrlRec).getData())) return FALSE; // forcing first chunk to be read; will call ReadBinary currChunk = chunks.end(); if (!NextSequentialChunk()) { // empty replay??! LogFatal("Record: Binary read error."); return FALSE; } } else { // non-sequential reading: Just read as a whole StdBuf BinaryBuf; if (rGrp.LoadEntry(C4CFN_CtrlRec, BinaryBuf)) { if (!ReadBinary(BinaryBuf)) return FALSE; } else { // file too large? Try sequential loading and parsing /* size_t iSize; if (rGrp.AccessEntry(C4CFN_CtrlRec, &iSize)) { CStdFile fOut; fOut.Create(Game.RecordDumpFile.getData()); fLoadSequential = true; const size_t iChunkSize = 1024*1024*16; // 16M while (iSize) { size_t iLoadSize = Min<size_t>(iChunkSize, iSize); BinaryBuf.SetSize(iLoadSize); if (!rGrp.Read(BinaryBuf.getMData(), iLoadSize)) { LogFatal("Record: Binary load error!"); return FALSE; } iSize -= iLoadSize; if (!ReadBinary(BinaryBuf)) return FALSE; LogF("%d binary remaining", iSize); currChunk = chunks.begin(); if (fStrip) Strip(); StdStrBuf s(ReWriteText()); fOut.WriteString(s.getData()); LogF("Wrote %d text bytes (%d binary remaining)", s.getLength(), iSize); chunks.clear(); } fOut.Close(); fLoadSequential = false; } else*/ { // no control data? LogFatal("Record: No control data found!"); return FALSE; } } } } // rewrite record if (fStrip) Strip(); if (Game.RecordDumpFile.getLength()) { if (SEqualNoCase(GetExtension(Game.RecordDumpFile.getData()), "txt")) ReWriteText().SaveToFile(Game.RecordDumpFile.getData()); else ReWriteBinary().SaveToFile(Game.RecordDumpFile.getData()); } // reset status currChunk = chunks.begin(); Finished = false; // external debugrec file #if defined(DEBUGREC_EXTFILE) && defined(DEBUGREC) #ifdef DEBUGREC_EXTFILE_WRITE if (!DbgRecFile.Create(DEBUGREC_EXTFILE)) { LogFatal("DbgRec: Creation of external file \"" DEBUGREC_EXTFILE "\" failed!"); return FALSE; } else Log("DbgRec: Writing to \"" DEBUGREC_EXTFILE "\"..."); #else if (!DbgRecFile.Open(DEBUGREC_EXTFILE)) { LogFatal("DbgRec: Opening of external file \"" DEBUGREC_EXTFILE "\" failed!"); return FALSE; } else Log("DbgRec: Checking against \"" DEBUGREC_EXTFILE "\"..."); #endif #endif // ok return TRUE; }
bool C4UpdateDlg::ApplyUpdate(const char *strUpdateFile, bool fDeleteUpdate, C4GUI::Screen *pScreen) { // Apply update: If the update file is a .ocu, it will extract c4group and apply the update. // If the update file is an installer, it will just launch that installer. StdStrBuf strUpdateProgEx, strUpdateArgs; bool fIsGroupUpdate = SEqualNoCase(GetExtension(strUpdateFile), C4CFN_UpdateGroupExtension+1); // Is this an update executable or an update group? if (fIsGroupUpdate) { // This is an update group (.ocu). Extract c4group and run it. // Find a place to extract the update Config.MakeTempUpdateFolder(); // Determine name of update program StdStrBuf strUpdateProg; strUpdateProg.Copy(C4CFN_UpdateProgram); // Windows: manually append extension because ExtractEntry() cannot properly glob and Extract() doesn't return failure values #ifdef _WIN32 strUpdateProg += ".exe"; #endif // Determine name of local extract of update program strUpdateProgEx.Copy(Config.AtTempUpdatePath(strUpdateProg.getData())); // Extract update program (the update should be applied using the new version) C4Group UpdateGroup; if (!UpdateGroup.Open(strUpdateFile)) { LogF("Error opening \"%s\": %s", strUpdateFile, UpdateGroup.GetError()); return false; } // Look for update program at top level if (!UpdateGroup.ExtractEntry(strUpdateProg.getData(), strUpdateProgEx.getData())) { LogF("Error extracting \"%s\": %s", strUpdateProg.getData(), UpdateGroup.GetError()); return false; } // Extract any needed library files UpdateGroup.Extract(C4CFN_UpdateProgramLibs, Config.AtTempUpdatePath(""), C4CFN_UpdateProgram); UpdateGroup.Close(); #ifdef _WIN32 // Notice: even if the update program and update group are in the temp path, they must be executed in our working directory DWORD ProcessID = GetCurrentProcessId(); //strUpdateArgs.Format("\"%s\" \"%s\" %s %lu", strUpdateProgEx.getData(), strUpdateFile, fDeleteUpdate ? "-yd" : "-y", (unsigned long)ProcessID); strUpdateArgs.Format("\"%s\" %s %lu", strUpdateFile, fDeleteUpdate ? "-yd" : "-y", (unsigned long)ProcessID); #if 0 // debug code to reroute updating via batch file CStdFile f; - reroute via vi f.Create(Config.AtTempUpdatePath("update.bat")); f.WriteString(FormatString("%s %s\npause\n", strUpdateProgEx.getData(), strUpdateArgs.getData()).getData()); f.Close(); strUpdateProgEx.Copy(Config.AtTempUpdatePath("update.bat")); strUpdateArgs.Copy(strUpdateProgEx); #endif #endif } else { // This "update" is actually an installer. Just run it. strUpdateProgEx = strUpdateFile; strUpdateArgs = ""; // if group was downloaded to temp path, delete it from there if (fDeleteUpdate) SCopy(strUpdateProgEx.getData(), Config.General.TempUpdatePath, CFG_MaxString); } // Execute update program Log(LoadResStr("IDS_PRC_LAUNCHINGUPDATE")); succeeded = true; #ifdef _WIN32 // Notice: even if the update program and update group are in the temp path, they must be executed in our working directory // the magic verb "runas" opens the update program in a shell requesting elevation int iError = (intptr_t)ShellExecute(NULL, L"runas", strUpdateProgEx.GetWideChar(), strUpdateArgs.GetWideChar(), Config.General.ExePath.GetWideChar(), SW_SHOW); if (iError <= 32) return false; // must quit ourselves for update program to work if (succeeded) Application.Quit(); #else if (pipe(c4group_output) == -1) { Log("Error creating pipe"); return false; } switch (pid = fork()) { // Error case -1: Log("Error creating update child process."); return false; // Child process case 0: // Close unused read end close(c4group_output[0]); // redirect stdout and stderr to the parent dup2(c4group_output[1], STDOUT_FILENO); dup2(c4group_output[1], STDERR_FILENO); if (c4group_output[1] != STDOUT_FILENO && c4group_output[1] != STDERR_FILENO) close(c4group_output[1]); if (fIsGroupUpdate) execl(C4CFN_UpdateProgram, C4CFN_UpdateProgram, "-v", strUpdateFile, (fDeleteUpdate ? "-yd" : "-y"), static_cast<char *>(0)); else execl(strUpdateFile, strUpdateFile, static_cast<char *>(0)); printf("execl failed: %s\n", strerror(errno)); exit(1); // Parent process default: // Close unused write end close(c4group_output[1]); // disable blocking fcntl(c4group_output[0], F_SETFL, O_NONBLOCK); // Open the update log dialog (this will update itself automatically from c4group_output) pScreen->ShowRemoveDlg(new C4UpdateDlg()); break; } #endif // done return succeeded; }
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, FALSE); MyFile.Close(); MemScramble((BYTE *)pData, iSize); MyFile.Create("UndSoAuch.txt", FALSE); MyFile.Write(pData, iSize, FALSE); 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 (!C4Group_GetFileCRC(strFile1, &GrpChks1[UpGrpCnt])) { WriteLog("Error: could not calc checksum for %s!\n", strFile1); return FALSE; } if (!C4Group_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"); remove(strUpdateFile); return FALSE; } WriteLog("Update package created.\n"); 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; }