StdStrBuf StdCompilerConfigRead::ReadString() { // Virtual key? if (pKey->Virtual) { excNotFound("Could not read value %s! Parent key doesn't exist!", pKey->Name.getData()); return StdStrBuf(); } // Wrong type? if (pKey->Type != REG_SZ) { excNotFound("Wrong value type!"); return StdStrBuf(); } // Get size of string DWORD iSize; if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(), 0, NULL, NULL, &iSize) != ERROR_SUCCESS) { excNotFound("Could not read value %s!", pKey->Name.getData()); return StdStrBuf(); } // Allocate string StdBuf Result; Result.SetSize(iSize); // Read if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(), 0, NULL, reinterpret_cast<BYTE *>(Result.getMData()), &iSize) != ERROR_SUCCESS) { excNotFound("Could not read value %s!", pKey->Name.getData()); return StdStrBuf(); } // Check size if (wcslen(getBufPtr<wchar_t>(Result)) + 1 != iSize / sizeof(wchar_t)) { excCorrupt("Wrong size of a string!"); return StdStrBuf(); } return StdStrBuf(getBufPtr<wchar_t>(Result)); }
StdBuf C4Playback::ReWriteBinary() { const int OUTPUT_GROW = 16 * 1024; StdBuf Output; int iPos = 0; bool fFinished = false; uint32_t iFrame = 0; for (chunks_t::const_iterator i = chunks.begin(); !fFinished && i != chunks.end(); i++) { // Check frame difference if (i->Frame - iFrame < 0 || i->Frame - iFrame > 0xff) LogF( "ERROR: Invalid frame difference between chunks (0-255 allowed)! " "Data will be invalid!"); // Pack data StdBuf Chunk; try { switch (i->Type) { case RCT_Ctrl: Chunk = DecompileToBuf<StdCompilerBinWrite>(*i->pCtrl); break; case RCT_CtrlPkt: Chunk = DecompileToBuf<StdCompilerBinWrite>(*i->pPkt); break; case RCT_End: fFinished = true; break; default: // debugrec if (i->pDbg) Chunk = DecompileToBuf<StdCompilerBinWrite>(*i->pDbg); break; } } catch (StdCompiler::Exception *pEx) { LogF("Record: Binary unpack error: %s", pEx->Msg.getData()); delete pEx; return StdBuf(); } // Grow output while (Output.getSize() - iPos < sizeof(C4RecordChunkHead) + Chunk.getSize()) Output.Grow(OUTPUT_GROW); // Write header C4RecordChunkHead *pHead = getMBufPtr<C4RecordChunkHead>(Output, iPos); pHead->Type = i->Type; pHead->iFrm = i->Frame - iFrame; iPos += sizeof(C4RecordChunkHead); iFrame = i->Frame; // Write chunk Output.Write(Chunk, iPos); iPos += Chunk.getSize(); } Output.SetSize(iPos); return Output; }
bool C4Playback::NextSequentialChunk() { StdBuf BinaryBuf; size_t iRealSize; BinaryBuf.New(4096); // load data until a chunk could be filled for (;;) { iRealSize = 0; playbackFile.Read(BinaryBuf.getMData(), 4096, &iRealSize); if (!iRealSize) return false; BinaryBuf.SetSize(iRealSize); if (!ReadBinary(BinaryBuf)) return false; // okay, at least one chunk has been read! if (chunks.size()) { currChunk = chunks.begin(); return true; } } // playback file reading failed - looks like we're done return false; }
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::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; }