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)); }
size_t C4AulDebug::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) { // Find line separation const char *pSep = reinterpret_cast<const char *>(memchr(rInBuf.getData(), '\n', rInBuf.getSize())); if (!pSep) return 0; // Check if it's windows-style separation int iSize = pSep - getBufPtr<char>(rInBuf) + 1, iLength = iSize - 1; if (iLength && *(pSep - 1) == '\r') iLength--; // Copy the line StdStrBuf Buf; Buf.Copy(getBufPtr<char>(rInBuf), iLength); // Password line? if (fConnected) { ProcessLineResult result = ProcessLine(Buf); // Send answer SendLine(result.okay ? "OK" : "ERR", result.answer.length() > 0 ? result.answer.c_str() : NULL); } else if (!Password.getSize() || Password == Buf) { fConnected = true; SendLine("HLO", "This is " C4ENGINECAPTION ", " C4VERSION); Log("C4Aul debugger connected successfully!"); } else C4NetIOTCP::Close(PeerAddr); // Consume line return iSize; }
StdBuf C4NetpuncherPacketID<TYPE>::PackInto() const { StdBuf buf; auto id = GetID(); buf.New(sizeof(id)); buf.Write(&id, sizeof(id)); return buf; }
size_t C4Network2IRCClient::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) { // Find line seperation const char *pSep = reinterpret_cast<const char *>(memchr(rInBuf.getData(), '\n', rInBuf.getSize())); if(!pSep) return 0; // Check if it's actually correct seperation (rarely the case) int iSize = pSep - getBufPtr<char>(rInBuf) + 1, iLength = iSize - 1; if(iLength && *(pSep - 1) == '\r') iLength--; // Copy the line StdStrBuf Buf; Buf.Copy(getBufPtr<char>(rInBuf), iLength); // Ignore prefix const char *pMsg = Buf.getData(); StdStrBuf Prefix; if(*pMsg == ':') { Prefix.CopyUntil(pMsg + 1, ' '); pMsg += Prefix.getLength() + 1; } // Strip whitespace while(*pMsg == ' ') pMsg++; // Ignore empty message if(!*pMsg) return iSize; // Get command StdStrBuf Cmd; Cmd.CopyUntil(pMsg, ' '); // Precess command const char *szParameters = SSearch(pMsg, " "); OnCommand(Prefix.getData(), Cmd.getData(), szParameters ? szParameters : ""); // Consume the line return iSize; }
void StdCompilerINIRead::String(char **pszString, RawCompileType eType) { // Get length size_t iLength = GetStringLength(eType); // Read data StdBuf Buf = ReadString(iLength, eType, true); // Set *pszString = reinterpret_cast<char *>(Buf.GrabPointer()); }
BOOL C4Scenario::Save(C4Group &hGroup, bool fSaveSection) { char *Buffer; int32_t BufferSize; if (!Decompile(&Buffer,&BufferSize, fSaveSection)) return FALSE; if (!hGroup.Add(C4CFN_ScenarioCore,Buffer,BufferSize,FALSE,TRUE)) { StdBuf Buf; Buf.Take(Buffer, BufferSize); return FALSE; } return TRUE; }
void StdCompilerConfigWrite::WriteString(const char *szString) { // Append or set the value if (LastString.getLength()) LastString.Append(szString); else LastString.Copy(szString); StdBuf v = LastString.GetWideCharBuf(); if (RegSetValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(), 0, REG_SZ, getBufPtr<BYTE>(v), v.getSize()) != ERROR_SUCCESS) excCorrupt("Could not write key %s!", pKey->Name.getData()); }
void StdCompilerINIRead::Raw(void *pData, size_t iSize, RawCompileType eType) { // Read data StdBuf Buf = ReadString(iSize, eType, false); // Correct size? if (Buf.getSize() != iSize) Warn("got %u bytes raw data, but %u bytes expected!", Buf.getSize(), iSize); // Copy MemCopy(Buf.getData(), pData, iSize); }
StdBuf C4NetpuncherPacketCReq::PackInto() const { StdBuf buf; auto sin6 = static_cast<sockaddr_in6>(addr.AsIPv6()); auto port = addr.GetPort(); buf.New(sizeof(port) + sizeof(sin6.sin6_addr)); size_t offset = 0; buf.Write(&port, sizeof(port), offset); offset += sizeof(port); buf.Write(&sin6.sin6_addr, sizeof(sin6.sin6_addr), offset); static_assert(sizeof(sin6.sin6_addr) == 16, "expected sin6_addr to be 16 bytes"); return buf; }
void C4Network2IRCClient::PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf) { // Enlarge buffer int iSize = rPacket.getSize(), iPos = rOutBuf.getSize(); rOutBuf.Grow(iSize + 2); // Write packet rOutBuf.Write(rPacket, iPos); // Terminate uint8_t *pPos = getMBufPtr<uint8_t>(rOutBuf, iPos + iSize); *pPos = '\r'; *(pPos + 1) = '\n'; }
bool C4KeyboardInput::LoadCustomConfig() { // load from INI file (2do: load from registry) C4Group GrpExtra; if (!GrpExtra.Open(C4CFN_Extra)) return false; StdBuf sFileContents; if (!GrpExtra.LoadEntry(C4CFN_KeyConfig, &sFileContents)) return false; StdStrBuf sFileContentsString((const char *) sFileContents.getData()); if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(*this, sFileContentsString, "Custom keys from" C4CFN_Extra DirSep C4CFN_KeyConfig)) return false; LogF(LoadResStr("IDS_PRC_LOADEDKEYCONF"), C4CFN_Extra DirSep C4CFN_KeyConfig); return true; }
BOOL C4SoundEffect::Load(const char *szFileName, C4Group &hGroup, BOOL fStatic) { // Sound check if (!Config.Sound.RXSound) return FALSE; // Locate sound in file StdBuf WaveBuffer; if (!hGroup.LoadEntry(szFileName, WaveBuffer)) return FALSE; // load it from mem if (!Load((BYTE *)WaveBuffer.getData(), WaveBuffer.getSize(), fStatic)) return FALSE; // Set name SCopy(szFileName, Name, C4MaxSoundName); return TRUE; }
StdBuf StdCompilerINIRead::ReadString(size_t iLength, RawCompileType eRawType, bool fAppendNull) { // Excpect valid position if (!pPos) { notFound("String"); return StdBuf(); } // Skip whitespace SkipWhitespace(); // Escaped? Go over '"' if (eRawType == RCT_Escaped && *pPos++ != '"') { notFound("Escaped string"); return StdBuf(); } // Create buffer StdBuf OutBuf; OutBuf.New(iLength + (fAppendNull ? sizeof('\0') : 0)); // Read char *pOut = getMBufPtr<char>(OutBuf); while (iLength && !TestStringEnd(eRawType)) { // Read a character if (eRawType == RCT_Escaped) *pOut++ = ReadEscapedChar(); else *pOut++ = *pPos++; // Count it iLength--; } // Escaped: Go over '"' if (eRawType == RCT_Escaped) { while (*pPos != '"') { if (!*pPos || *pPos == '\n' || *pPos == '\r') { Warn("string not terminated!"); pPos--; break; } pPos++; } pPos++; } // Nothing read? Identifiers need to be non-empty if (pOut == OutBuf.getData() && (eRawType == RCT_Idtf || eRawType == RCT_ID)) { notFound("String"); return StdBuf(); } // Append null if (fAppendNull) *pOut = '\0'; // Shrink, if less characters were read OutBuf.Shrink(iLength); // Done return OutBuf; }
StdStrBuf GetDbgRecPktData(C4RecordChunkType eType, const StdBuf &RawData) { StdStrBuf r; switch (eType) { case RCT_AulFunc: r.Ref(reinterpret_cast<const char *>(RawData.getData()), RawData.getSize() - 1); break; default: for (int i = 0; i < RawData.getSize(); ++i) r.AppendFormat("%02x ", (uint32_t)((uint8_t *)RawData.getData())[i]); break; } return r; }
bool C4Record::StreamFile(const char *szLocalFilename, const char *szAddAs) { // Load file into memory StdBuf FileData; if (!FileData.LoadFromFile(szLocalFilename)) return false; // Prepend name StdBuf Packed = DecompileToBuf<StdCompilerBinWrite>( mkInsertAdapt(StdStrBuf(szAddAs), FileData, false)); // Add to stream C4RecordChunkHead Head = {0, RCT_File}; Stream(Head, Packed); return true; }
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; }
bool C4Record::Rec(int iFrame, const StdBuf &sBuf, C4RecordChunkType eType) { // filler chunks (this should never be necessary, though) while (iFrame > iLastFrame + 0xff) Rec(iLastFrame + 0xff, StdBuf(), RCT_Frame); // get frame difference uint32_t iFrameDiff = Max<uint32_t>(0, iFrame - iLastFrame); iLastFrame += iFrameDiff; // create head C4RecordChunkHead Head = {static_cast<uint8_t>(iFrameDiff), static_cast<uint8_t>(eType)}; // pack CtrlRec.Write(&Head, sizeof(Head)); CtrlRec.Write(sBuf.getData(), sBuf.getSize()); #ifdef IMMEDIATEREC // immediate rec: always flush CtrlRec.Flush(); #endif // Stream if (fStreaming) Stream(Head, sBuf); return true; }
bool SetRegistryString(const char *szSubKey, const char *szValueName, const char *szValue) { long qerr; HKEY ckey; DWORD disposition; // Open the key if ((qerr=RegCreateKeyExW(HKEY_CURRENT_USER, GetWideChar(szSubKey), 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &ckey, &disposition ))!=ERROR_SUCCESS) return false; // Set the value StdBuf v = GetWideCharBuf(szValue); if ((qerr=RegSetValueExW(ckey, GetWideChar(szValueName), 0, REG_SZ, getBufPtr<BYTE>(v), v.getSize() ))!=ERROR_SUCCESS) { RegCloseKey(ckey); return false; } // Close the key RegCloseKey(ckey); 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; }
void C4Record::Stream(const C4RecordChunkHead &Head, const StdBuf &sBuf) { if (!fStreaming) return; StreamingData.Append(&Head, sizeof(Head)); StreamingData.Append(sBuf.getData(), sBuf.getSize()); }
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::ReadBinary(const StdBuf &Buf) { // sequential reading: Take over rest from last buffer const StdBuf *pUseBuf; uint32_t iFrame = 0; if (fLoadSequential) { sequentialBuffer.Append(Buf); pUseBuf = &sequentialBuffer; iFrame = iLastSequentialFrame; } else pUseBuf = &Buf; // get buffer data size_t iPos = 0; bool fFinished = false; do { // unpack header if (pUseBuf->getSize() - iPos < sizeof(C4RecordChunkHead)) break; const C4RecordChunkHead *pHead = getBufPtr<C4RecordChunkHead>(*pUseBuf, iPos); // get chunk iPos += sizeof(C4RecordChunkHead); StdBuf Chunk = pUseBuf->getPart(iPos, pUseBuf->getSize() - iPos); // Create entry C4RecordChunk c; c.Frame = (iFrame += pHead->iFrm); c.Type = pHead->Type; // Unpack data try { // Initialize compiler StdCompilerBinRead Compiler; Compiler.setInput(Chunk.getRef()); Compiler.Begin(); // Read chunk switch (pHead->Type) { case RCT_Ctrl: Compiler.Value(mkPtrAdaptNoNull(c.pCtrl)); break; case RCT_CtrlPkt: Compiler.Value(mkPtrAdaptNoNull(c.pPkt)); break; case RCT_End: fFinished = true; break; case RCT_File: Compiler.Value(c.Filename); Compiler.Value(mkPtrAdaptNoNull(c.pFileData)); break; default: // debugrec if (pHead->Type >= 0x80) Compiler.Value(mkPtrAdaptNoNull(c.pDbg)); } // Advance over data Compiler.End(); iPos += Compiler.getPosition(); } catch (StdCompiler::EOFException *pEx) { // This is to be expected for sequential reading if (fLoadSequential) { iPos -= sizeof(C4RecordChunkHead); iFrame -= pHead->iFrm; delete pEx; break; } LogF("Record: Binary unpack error: %s", pEx->Msg.getData()); c.Delete(); delete pEx; return FALSE; } catch (StdCompiler::Exception *pEx) { LogF("Record: Binary unpack error: %s", pEx->Msg.getData()); c.Delete(); delete pEx; return FALSE; } // Add to list chunks.push_back(c); c.pPkt = NULL; } while (!fFinished); // erase everything but the trailing part from sequential buffer if (fLoadSequential) { if (iPos >= sequentialBuffer.getSize()) sequentialBuffer.Clear(); else if (iPos) { sequentialBuffer.Move(iPos, sequentialBuffer.getSize() - iPos); sequentialBuffer.Shrink(iPos); } iLastSequentialFrame = iFrame; } return TRUE; }