mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Tier1: move KeyValues class to Tier1
The KeyValues class belongs here. Also reimplemented most loading methods for KeyValues, and adjusted the VPK building code to account for it. Pointers to the engine's implementation of KeyValues have been moved to a separate header ('keyvalues_iface.h'), as this allows external tools code to utilize the standalone KeyValues class implementation. Playlist utilities are completely separated from the KeyValues header; these have nothing to do with KeyValues other than manipulating a global KeyValues object for the playlists, and thus have been named as such and moved to rtech/playlists.
This commit is contained in:
parent
51986ec1c6
commit
ee82d5d8e0
@ -27,6 +27,7 @@
|
||||
#endif // !CLIENT_DLL
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#include "filesystem/basefilesystem.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "vpklib/packedstore.h"
|
||||
@ -231,7 +232,7 @@ Host_ReloadPlaylists_f
|
||||
void Host_ReloadPlaylists_f(const CCommand& args)
|
||||
{
|
||||
v__DownloadPlaylists_f();
|
||||
KeyValues::InitPlaylists(); // Re-Init playlist.
|
||||
Playlists_SDKInit(); // Re-Init playlist.
|
||||
}
|
||||
|
||||
/*
|
||||
@ -647,7 +648,7 @@ void VPK_Pack_f(const CCommand& args)
|
||||
Msg(eDLL_T::FS, "*** Starting VPK build command for: '%s'\n", pair.m_DirName.Get());
|
||||
timer.Start();
|
||||
|
||||
g_pPackedStore->InitLzCompParams();
|
||||
g_pPackedStore->InitLzCompParams(fs_packedstore_compression_level->GetString(), fs_packedstore_max_helper_threads->GetInt());
|
||||
g_pPackedStore->PackWorkspace(pair, fs_packedstore_workspace->GetString(), "vpk/");
|
||||
|
||||
timer.End();
|
||||
|
@ -61,6 +61,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
|
||||
|
||||
"rtech_tools"
|
||||
"rtech_game"
|
||||
"playlists"
|
||||
"stryder"
|
||||
|
||||
"libdetours"
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include "tier0/sigcache.h"
|
||||
#include "tier1/cmd.h"
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier1/keyvalues_iface.h"
|
||||
#include "vpc/IAppSystem.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "vpc/interfaces.h"
|
||||
#include "common/callback.h"
|
||||
@ -63,6 +63,7 @@
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/stryder/stryder.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#ifndef DEDICATED
|
||||
#include "rtech/rui/rui.h"
|
||||
#include "engine/client/cl_ents_parse.h"
|
||||
@ -552,6 +553,7 @@ void DetourRegister() // Register detour classes to be searched and hooked.
|
||||
REGISTER(V_RTechGame);
|
||||
REGISTER(V_RTechUtils);
|
||||
REGISTER(VStryder);
|
||||
REGISTER(VPlaylists);
|
||||
|
||||
#ifndef DEDICATED
|
||||
REGISTER(V_Rui);
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "engine/net_chan.h"
|
||||
#include "engine/client/cl_rcon.h"
|
||||
#include "networksystem/bansystem.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "windows/id3dx.h"
|
||||
#include "geforce/reflex.h"
|
||||
#include "vengineclient_impl.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "common/protocol.h"
|
||||
#include "engine/net.h"
|
||||
#include "engine/net_chan.h"
|
||||
|
@ -9,7 +9,6 @@
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#include "core/stdafx.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier0/frametask.h"
|
||||
#include "engine/common.h"
|
||||
#include "engine/host.h"
|
||||
@ -20,6 +19,7 @@
|
||||
#include "common/callback.h"
|
||||
#include "cdll_engine_int.h"
|
||||
#include "vgui/vgui_baseui_interface.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#include <ebisusdk/EbisuSDK.h>
|
||||
#include <engine/cmd.h>
|
||||
|
||||
@ -139,7 +139,7 @@ void CClientState::VConnectionClosing(CClientState* thisptr, const char* szReaso
|
||||
// Reload the local playlist to override the cached
|
||||
// one from the server we got disconnected from.
|
||||
v__DownloadPlaylists_f();
|
||||
KeyValues::InitPlaylists();
|
||||
Playlists_SDKInit();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "datacache/mdlcache.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#ifndef DEDICATED
|
||||
|
@ -25,6 +25,7 @@ inline void(*sub_140441220)(__int64 a1, __int64 a2);
|
||||
|
||||
extern bool s_bBasePaksInitialized;
|
||||
extern CUtlVector<CUtlString> g_InstalledMaps;
|
||||
extern std::mutex g_InstalledMapsMutex;
|
||||
|
||||
bool Mod_LevelHasChanged(const char* pszLevelName);
|
||||
void Mod_GetAllInstalledMaps();
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef GL_MODEL_PRIVATE_H
|
||||
#define GL_MODEL_PRIVATE_H
|
||||
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "common/qlimits.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier1/NetAdr.h"
|
||||
#include "tier2/socketcreator.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "datacache/mdlcache.h"
|
||||
#ifndef CLIENT_DLL
|
||||
#include "engine/server/sv_rcon.h"
|
||||
@ -39,6 +38,7 @@
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/stryder/stryder.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#ifndef DEDICATED
|
||||
#include "vgui/vgui_baseui_interface.h"
|
||||
#include "client/vengineclient_impl.h"
|
||||
@ -316,7 +316,7 @@ void CHostState::Think(void) const
|
||||
{
|
||||
SetConsoleTitleA(Format("%s - %d/%d Players (%s on %s) - %d%% Server CPU (%.3f msec on frame %d)",
|
||||
hostname->GetString(), g_pServer->GetNumClients(),
|
||||
g_ServerGlobalVariables->m_nMaxClients, KeyValues__GetCurrentPlaylist(), m_levelName,
|
||||
g_ServerGlobalVariables->m_nMaxClients, v_Playlists_GetCurrent(), m_levelName,
|
||||
static_cast<int>(g_pServer->GetCPUUsage() * 100.0f), (g_pEngine->GetFrameTime() * 1000.0f),
|
||||
g_pServer->GetTick()).c_str());
|
||||
|
||||
@ -337,7 +337,7 @@ void CHostState::Think(void) const
|
||||
hostdesc->GetString(),
|
||||
sv_pylonVisibility->GetInt() == EServerVisibility_t::HIDDEN,
|
||||
g_pHostState->m_levelName,
|
||||
KeyValues__GetCurrentPlaylist(),
|
||||
v_Playlists_GetCurrent(),
|
||||
hostip->GetString(),
|
||||
hostport->GetInt(),
|
||||
g_pNetKey->GetBase64NetKey(),
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "core/stdafx.h"
|
||||
#include "tier0/frametask.h"
|
||||
#include "tier1/cvar.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "common/callback.h"
|
||||
#include "engine/net.h"
|
||||
#include "engine/net_chan.h"
|
||||
|
@ -9,7 +9,7 @@
|
||||
//=============================================================================//
|
||||
|
||||
#include "core/stdafx.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "engine/host_state.h"
|
||||
#include "engine/client/cl_main.h"
|
||||
|
@ -12,7 +12,7 @@
|
||||
//=============================================================================//
|
||||
|
||||
#include "core/stdafx.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#include "engine/client/cl_main.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "vscript/languages/squirrel_re/include/sqvm.h"
|
||||
|
@ -31,7 +31,7 @@ History:
|
||||
#include "networksystem/serverlisting.h"
|
||||
#include "networksystem/pylon.h"
|
||||
#include "networksystem/listmanager.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#include "common/callback.h"
|
||||
#include "gameui/IBrowser.h"
|
||||
#include "public/edict.h"
|
||||
@ -603,7 +603,7 @@ void CBrowser::HostPanel(void)
|
||||
g_TaskScheduler->Dispatch([]()
|
||||
{
|
||||
v__DownloadPlaylists_f();
|
||||
KeyValues::InitPlaylists(); // Re-Init playlist.
|
||||
Playlists_SDKInit(); // Re-Init playlist.
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@ -745,7 +745,7 @@ void CBrowser::UpdateHostingStatus(void)
|
||||
g_pServerListManager->m_Server.m_svDescription,
|
||||
g_pServerListManager->m_Server.m_bHidden,
|
||||
g_pHostState->m_levelName,
|
||||
KeyValues__GetCurrentPlaylist(),
|
||||
v_Playlists_GetCurrent(),
|
||||
hostip->GetString(),
|
||||
hostport->GetInt(),
|
||||
g_pNetKey->GetBase64NetKey(),
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "tier0/crashhandler.h"
|
||||
#include "tier0/commandline.h"
|
||||
#include "tier1/cvar.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "engine/sys_engine.h"
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "engine/net.h"
|
||||
#include "engine/host_state.h"
|
||||
#include "engine/server/server.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#include "pylon.h"
|
||||
#include "listmanager.h"
|
||||
|
||||
@ -74,7 +74,7 @@ void CServerListManager::LaunchServer(const bool bChangeLevel) const
|
||||
* values. Then when you would normally call launchplaylist which calls StartPlaylist it would cmd
|
||||
* call mp_gamemode which parses the gamemode specific part of the playlist..
|
||||
*/
|
||||
KeyValues::ParsePlaylists(m_Server.m_svPlaylist.c_str());
|
||||
v_Playlists_Parse(m_Server.m_svPlaylist.c_str());
|
||||
mp_gamemode->SetValue(m_Server.m_svPlaylist.c_str());
|
||||
|
||||
ProcessCommand(Format("%s \"%s\"", bChangeLevel ? "changelevel" : "map", m_Server.m_svHostMap.c_str()).c_str());
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "public/vscript/ivscript.h"
|
||||
|
@ -9,7 +9,7 @@
|
||||
#define EIFACE_H
|
||||
#include "edict.h"
|
||||
#include "tier1/bitbuf.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
|
@ -113,6 +113,9 @@ PLATFORM_INTERFACE void NetMsg(LogType_t logType, eDLL_T context, const char* up
|
||||
PLATFORM_INTERFACE void Warning(eDLL_T context, const char* fmt, ...) FMTFUNCTION(2, 3);
|
||||
PLATFORM_INTERFACE void Error(eDLL_T context, const UINT code, const char* fmt, ...) FMTFUNCTION(3, 4);
|
||||
|
||||
// TODO[ AMOS ]: export to DLL?
|
||||
void Plat_FatalError(eDLL_T context, const char* fmt, ...);
|
||||
|
||||
#if defined DBGFLAG_STRINGS_STRIP
|
||||
#define DevMsg( ... ) ((void)0)
|
||||
#define DevWarning( ... ) ((void)0)
|
||||
|
74
r5dev/public/tier1/exprevaluator.h
Normal file
74
r5dev/public/tier1/exprevaluator.h
Normal file
@ -0,0 +1,74 @@
|
||||
//===== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
|
||||
// form of a character array).
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef EXPREVALUATOR_H
|
||||
#define EXPREVALUATOR_H
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
static const char OR_OP = '|';
|
||||
static const char AND_OP = '&';
|
||||
static const char NOT_OP = '!';
|
||||
|
||||
#define MAX_IDENTIFIER_LEN 128
|
||||
enum Kind {CONDITIONAL, NOT, LITERAL};
|
||||
|
||||
struct ExprNode
|
||||
{
|
||||
ExprNode *left; // left sub-expression
|
||||
ExprNode *right; // right sub-expression
|
||||
Kind kind; // kind of node this is
|
||||
union
|
||||
{
|
||||
char cond; // the conditional
|
||||
bool value; // the value
|
||||
} data;
|
||||
};
|
||||
|
||||
typedef ExprNode *ExprTree;
|
||||
|
||||
// callback to evaluate a $<symbol> during evaluation, return true or false
|
||||
typedef bool (*GetSymbolProc_t)( const char *pKey );
|
||||
typedef void (*SyntaxErrorProc_t)( const char *pReason );
|
||||
|
||||
class CExpressionEvaluator
|
||||
{
|
||||
public:
|
||||
CExpressionEvaluator();
|
||||
~CExpressionEvaluator();
|
||||
bool Evaluate( bool &result, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc = 0, SyntaxErrorProc_t pSyntaxErrorProc = 0 );
|
||||
|
||||
private:
|
||||
CExpressionEvaluator( CExpressionEvaluator& ); // prevent copy constructor being used
|
||||
|
||||
char GetNextToken( void );
|
||||
void FreeNode( ExprNode *pNode );
|
||||
ExprNode *AllocateNode( void );
|
||||
void FreeTree( ExprTree &node );
|
||||
bool IsConditional( bool &bCondition, const char token );
|
||||
bool IsNotOp( const char token );
|
||||
bool IsIdentifierOrConstant( const char token );
|
||||
bool MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right );
|
||||
bool MakeFactor( ExprTree &tree );
|
||||
bool MakeTerm( ExprTree &tree );
|
||||
bool MakeExpression( ExprTree &tree );
|
||||
bool BuildExpression( void );
|
||||
bool SimplifyNode( ExprTree &node );
|
||||
|
||||
ExprTree m_ExprTree; // Tree representation of the expression
|
||||
char m_CurToken; // Current token read from the input expression
|
||||
const char *m_pExpression; // Array of the expression characters
|
||||
int m_CurPosition; // Current position in the input expression
|
||||
char m_Identifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string
|
||||
GetSymbolProc_t m_pGetSymbolProc;
|
||||
SyntaxErrorProc_t m_pSyntaxErrorProc;
|
||||
bool m_bSetup;
|
||||
};
|
||||
|
||||
#endif
|
369
r5dev/public/tier1/fmtstr.h
Normal file
369
r5dev/public/tier1/fmtstr.h
Normal file
@ -0,0 +1,369 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A simple class for performing safe and in-expression sprintf-style
|
||||
// string formatting
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef FMTSTR_H
|
||||
#define FMTSTR_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// using macro to be compatible with GCC
|
||||
#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
|
||||
do \
|
||||
{ \
|
||||
int result; \
|
||||
va_list arg_ptr; \
|
||||
bool bTruncated = false; \
|
||||
static int scAsserted = 0; \
|
||||
\
|
||||
va_start(arg_ptr, lastArg); \
|
||||
result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
|
||||
va_end(arg_ptr); \
|
||||
\
|
||||
(szBuf)[(nBufSize)-1] = 0; \
|
||||
if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
|
||||
{ \
|
||||
Warning( eDLL_T::COMMON, "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
|
||||
AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
|
||||
scAsserted++; \
|
||||
} \
|
||||
m_nLength = nPrevLen + result; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
// using macro to be compatable with GCC
|
||||
#define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
|
||||
do \
|
||||
{ \
|
||||
int result; \
|
||||
va_list arg_ptr; \
|
||||
bool bTruncated = false; \
|
||||
static int scAsserted = 0; \
|
||||
\
|
||||
va_start(arg_ptr, lastArg); \
|
||||
result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
|
||||
va_end(arg_ptr); \
|
||||
\
|
||||
(szBuf)[(nBufSize)-1] = 0; \
|
||||
if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
|
||||
{ \
|
||||
Warning( eDLL_T::COMMON, "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
|
||||
AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
|
||||
scAsserted++; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Purpose: String formatter with specified size
|
||||
//
|
||||
|
||||
template <int SIZE_BUF, bool QUIET_TRUNCATION = false >
|
||||
class CFmtStrN
|
||||
{
|
||||
public:
|
||||
CFmtStrN()
|
||||
{
|
||||
InitQuietTruncation();
|
||||
m_szBuf[0] = 0;
|
||||
m_nLength = 0;
|
||||
}
|
||||
|
||||
// Standard C formatting
|
||||
CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
|
||||
{
|
||||
InitQuietTruncation();
|
||||
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
|
||||
}
|
||||
|
||||
// Use this for pass-through formatting
|
||||
CFmtStrN(const char ** ppszFormat, ...)
|
||||
{
|
||||
InitQuietTruncation();
|
||||
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
|
||||
}
|
||||
|
||||
// Explicit reformat
|
||||
const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
|
||||
{
|
||||
InitQuietTruncation();
|
||||
FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
|
||||
return m_szBuf;
|
||||
}
|
||||
|
||||
// Same as sprintf above, but for compatibility with Steam interface
|
||||
const char *Format( PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 2, 3 )
|
||||
{
|
||||
InitQuietTruncation();
|
||||
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
|
||||
return m_szBuf;
|
||||
}
|
||||
|
||||
// Use this for va_list formatting
|
||||
const char *sprintf_argv(const char *pszFormat, va_list arg_ptr)
|
||||
{
|
||||
int result;
|
||||
bool bTruncated = false;
|
||||
static int s_nWarned = 0;
|
||||
|
||||
InitQuietTruncation();
|
||||
result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated );
|
||||
m_szBuf[SIZE_BUF - 1] = 0;
|
||||
if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) )
|
||||
{
|
||||
Warning( eDLL_T::COMMON, "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF );
|
||||
AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" );
|
||||
s_nWarned++;
|
||||
}
|
||||
m_nLength = V_strlen( m_szBuf );
|
||||
return m_szBuf;
|
||||
}
|
||||
|
||||
// Use this for pass-through formatting
|
||||
void VSprintf(const char **ppszFormat, ...)
|
||||
{
|
||||
InitQuietTruncation();
|
||||
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
|
||||
}
|
||||
|
||||
// Compatible API with CUtlString for converting to const char*
|
||||
const char *Get( ) const { return m_szBuf; }
|
||||
const char *String( ) const { return m_szBuf; }
|
||||
// Use for access
|
||||
operator const char *() const { return m_szBuf; }
|
||||
char *Access() { return m_szBuf; }
|
||||
|
||||
// Access template argument
|
||||
static inline int GetMaxLength() { return SIZE_BUF-1; }
|
||||
|
||||
CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator=( const char *pchValue )
|
||||
{
|
||||
V_strncpy( m_szBuf, pchValue, SIZE_BUF );
|
||||
m_nLength = V_strlen( m_szBuf );
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator+=( const char *pchValue )
|
||||
{
|
||||
Append( pchValue );
|
||||
return *this;
|
||||
}
|
||||
|
||||
int Length() const { return m_nLength; }
|
||||
|
||||
void SetLength( int nLength )
|
||||
{
|
||||
m_nLength = Min( nLength, SIZE_BUF - 1 );
|
||||
m_szBuf[m_nLength] = '\0';
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_szBuf[0] = 0;
|
||||
m_nLength = 0;
|
||||
}
|
||||
|
||||
void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 )
|
||||
{
|
||||
char *pchEnd = m_szBuf + m_nLength;
|
||||
FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat );
|
||||
}
|
||||
|
||||
void AppendFormatV( const char *pchFormat, va_list args );
|
||||
|
||||
void Append( const char *pchValue )
|
||||
{
|
||||
// This function is close to the metal to cut down on the CPU cost
|
||||
// of the previous incantation of Append which was implemented as
|
||||
// AppendFormat( "%s", pchValue ). This implementation, though not
|
||||
// as easy to read, instead does a strcpy from the existing end
|
||||
// point of the CFmtStrN. This brings something like a 10-20x speedup
|
||||
// in my rudimentary tests. It isn't using V_strncpy because that
|
||||
// function doesn't return the number of characters copied, which
|
||||
// we need to adjust m_nLength. Doing the V_strncpy with a V_strlen
|
||||
// afterwards took twice as long as this implementations in tests,
|
||||
// so V_strncpy's implementation was used to write this method.
|
||||
char *pDest = m_szBuf + m_nLength;
|
||||
const int maxLen = SIZE_BUF - m_nLength;
|
||||
char *pLast = pDest + maxLen - 1;
|
||||
while ( (pDest < pLast) && (*pchValue != 0) )
|
||||
{
|
||||
*pDest = *pchValue;
|
||||
++pDest; ++pchValue;
|
||||
}
|
||||
*pDest = 0;
|
||||
m_nLength = pDest - m_szBuf;
|
||||
}
|
||||
|
||||
//optimized version of append for just adding a single character
|
||||
void Append( char ch )
|
||||
{
|
||||
if( m_nLength < SIZE_BUF - 1 )
|
||||
{
|
||||
m_szBuf[ m_nLength ] = ch;
|
||||
m_nLength++;
|
||||
m_szBuf[ m_nLength ] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void AppendIndent( uint32 unCount, char chIndent = '\t' );
|
||||
|
||||
void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; }
|
||||
|
||||
protected:
|
||||
virtual void InitQuietTruncation()
|
||||
{
|
||||
m_bQuietTruncation = QUIET_TRUNCATION;
|
||||
}
|
||||
|
||||
bool m_bQuietTruncation;
|
||||
|
||||
private:
|
||||
char m_szBuf[SIZE_BUF];
|
||||
int m_nLength;
|
||||
};
|
||||
|
||||
|
||||
// Version which will not assert if strings are truncated
|
||||
|
||||
template < int SIZE_BUF >
|
||||
class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF, true >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
template< int SIZE_BUF, bool QUIET_TRUNCATION >
|
||||
void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent )
|
||||
{
|
||||
Assert( Length() + unCount < SIZE_BUF );
|
||||
if( Length() + unCount >= SIZE_BUF )
|
||||
unCount = SIZE_BUF - (1+Length());
|
||||
for ( uint32 x = 0; x < unCount; x++ )
|
||||
{
|
||||
m_szBuf[ m_nLength++ ] = chIndent;
|
||||
}
|
||||
m_szBuf[ m_nLength ] = '\0';
|
||||
}
|
||||
|
||||
template< int SIZE_BUF, bool QUIET_TRUNCATION >
|
||||
void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args )
|
||||
{
|
||||
int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args );
|
||||
m_nLength += cubPrinted;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Purpose: Default-sized string formatter
|
||||
//
|
||||
|
||||
#define FMTSTR_STD_LEN 256
|
||||
|
||||
typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr;
|
||||
typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation;
|
||||
typedef CFmtStrN<32> CFmtStr32;
|
||||
typedef CFmtStrN<1024> CFmtStr1024;
|
||||
typedef CFmtStrN<2048> CFmtStr2048;
|
||||
typedef CFmtStrN<8192> CFmtStrMax;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fast-path number-to-string helper (with optional quoting)
|
||||
// Derived off of the Steam CNumStr but with a few tweaks, such as
|
||||
// trimming off the in-our-cases-unnecessary strlen calls (by not
|
||||
// storing the length in the class).
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CNumStr
|
||||
{
|
||||
public:
|
||||
CNumStr() { m_szBuf[0] = 0; }
|
||||
|
||||
explicit CNumStr( bool b ) { SetBool( b ); }
|
||||
|
||||
explicit CNumStr( int8 n8 ) { SetInt8( n8 ); }
|
||||
explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); }
|
||||
explicit CNumStr( int16 n16 ) { SetInt16( n16 ); }
|
||||
explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); }
|
||||
explicit CNumStr( int32 n32 ) { SetInt32( n32 ); }
|
||||
explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); }
|
||||
explicit CNumStr( int64 n64 ) { SetInt64( n64 ); }
|
||||
explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); }
|
||||
|
||||
#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS)
|
||||
explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); }
|
||||
explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); }
|
||||
#endif
|
||||
|
||||
explicit CNumStr( double f ) { SetDouble( f ); }
|
||||
explicit CNumStr( float f ) { SetFloat( f ); }
|
||||
|
||||
inline void SetBool( bool b ) { memcpy( m_szBuf, b ? "1" : "0", 2 ); }
|
||||
|
||||
#ifdef _WIN32
|
||||
inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); }
|
||||
inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); }
|
||||
inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); }
|
||||
inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); }
|
||||
inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); }
|
||||
inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); }
|
||||
inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); }
|
||||
inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); }
|
||||
#else
|
||||
inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); }
|
||||
inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); }
|
||||
inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); }
|
||||
inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); }
|
||||
inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); }
|
||||
inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); }
|
||||
inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); }
|
||||
inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); }
|
||||
#endif
|
||||
|
||||
inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
|
||||
inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
|
||||
|
||||
inline void SetHexUint64( uint64 un64 ) { V_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); }
|
||||
|
||||
operator const char *() const { return m_szBuf; }
|
||||
const char* String() const { return m_szBuf; }
|
||||
|
||||
void AddQuotes()
|
||||
{
|
||||
Assert( m_szBuf[0] != '"' );
|
||||
const size_t nLength = Q_strlen( m_szBuf );
|
||||
memmove( m_szBuf + 1, m_szBuf, nLength );
|
||||
m_szBuf[0] = '"';
|
||||
m_szBuf[nLength + 1] = '"';
|
||||
m_szBuf[nLength + 2] = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes
|
||||
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
const int k_cchFormattedDate = 64;
|
||||
const int k_cchFormattedTime = 32;
|
||||
bool BGetLocalFormattedTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime );
|
||||
|
||||
#endif // FMTSTR_H
|
@ -1,16 +1,14 @@
|
||||
#pragma once
|
||||
#include "mathlib/color.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/exprevaluator.h"
|
||||
#include "public/ifilesystem.h"
|
||||
|
||||
#define MAKE_3_BYTES_FROM_1_AND_2( x1, x2 ) (( (( uint16_t )x2) << 8 ) | (uint8_t)(x1))
|
||||
#define SPLIT_3_BYTES_INTO_1_AND_2( x1, x2, x3 ) do { x1 = (uint8)(x3); x2 = (uint16)( (x3) >> 8 ); } while( 0 )
|
||||
#define KEYVALUES_TOKEN_SIZE (1024 * 32)
|
||||
|
||||
extern vector<string> g_vAllPlaylists;
|
||||
extern vector<string> g_vGameInfoPaths;
|
||||
|
||||
extern std::mutex g_InstalledMapsMutex;
|
||||
extern std::mutex g_PlaylistsVecMutex;
|
||||
// single byte identifies a xbox kv file in binary format
|
||||
// strings are pooled from a searchpath/zip mounted symbol table
|
||||
#define KV_BINARY_POOLED_FORMAT 0xAA
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: Forward declarations
|
||||
@ -18,15 +16,7 @@ extern std::mutex g_PlaylistsVecMutex;
|
||||
class KeyValues;
|
||||
class CFileSystem_Stdio;
|
||||
class IBaseFileSystem;
|
||||
|
||||
/* ==== KEYVALUES ======================================================================================================================================================= */
|
||||
inline void*(*KeyValues__FindKey)(KeyValues* thisptr, const char* pkeyName, bool bCreate);
|
||||
inline bool(*KeyValues__LoadPlaylists)(const char* pszPlaylist);
|
||||
inline bool(*KeyValues__ParsePlaylists)(const char* pszPlaylist);
|
||||
inline const char* (*KeyValues__GetCurrentPlaylist)(void);
|
||||
inline KeyValues*(*KeyValues__ReadKeyValuesFile)(CFileSystem_Stdio* pFileSystem, const char* pFileName);
|
||||
inline void(*KeyValues__RecursiveSaveToFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
|
||||
inline KeyValues*(*KeyValues__LoadFromFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, const char* pszResourceName, const char* pszPathID, void* pfnEvaluateSymbolProc);
|
||||
class CKeyValuesTokenReader;
|
||||
|
||||
enum KeyValuesTypes_t : char
|
||||
{
|
||||
@ -51,6 +41,14 @@ enum MergeKeyValuesOp_t
|
||||
MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded
|
||||
};
|
||||
|
||||
#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
|
||||
for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
|
||||
|
||||
#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
|
||||
for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
|
||||
|
||||
#define FOR_EACH_VALUE( kvRoot, kvValue ) \
|
||||
for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Simple recursive data access class
|
||||
@ -90,6 +88,7 @@ public:
|
||||
void DeleteThis(void);
|
||||
void RemoveEverything();
|
||||
|
||||
KeyValues* FindKey(int keySymbol) const;
|
||||
KeyValues* FindKey(const char* pKeyName, bool bCreate = false);
|
||||
KeyValues* FindLastSubKey(void) const;
|
||||
|
||||
@ -109,6 +108,8 @@ public:
|
||||
KeyValues* GetFirstSubKey() const;
|
||||
KeyValues* GetNextKey() const;
|
||||
const char* GetName(void) const;
|
||||
int GetNameSymbol() const;
|
||||
int GetNameSymbolCaseSensitive() const;
|
||||
int GetInt(const char* pszKeyName, int iDefaultValue);
|
||||
uint64_t GetUint64(const char* pszKeyName, uint64_t nDefaultValue);
|
||||
void* GetPtr(const char* pszKeyName, void* pDefaultValue);
|
||||
@ -134,20 +135,41 @@ public:
|
||||
void SetBool(const char* pszKeyName, bool bValue) { SetInt(pszKeyName, bValue ? 1 : 0); }
|
||||
void UsesEscapeSequences(bool bState);
|
||||
|
||||
void RecursiveCopyKeyValues(KeyValues& src);
|
||||
void RecursiveSaveToFile(CUtlBuffer& buf, int nIndentLevel);
|
||||
void RecursiveSaveToFile(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
|
||||
KeyValues* LoadFromFile(IBaseFileSystem* pFileSystem, const char* pszResourceName, const char* pszPathID, void* pfnEvaluateSymbolProc);
|
||||
|
||||
bool LoadFromFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
|
||||
|
||||
bool LoadFromBuffer(char const* resourceName, CUtlBuffer& buf, IBaseFileSystem* pFileSystem, const char* pPathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
|
||||
bool LoadFromBuffer(char const* resourceName, const char* pBuffer, IBaseFileSystem* pFileSystem, const char* pPathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
|
||||
|
||||
// for handling #include "filename"
|
||||
void AppendIncludedKeys(CUtlVector< KeyValues* >& includedKeys);
|
||||
void ParseIncludedKeys(char const* resourceName, const char* filetoinclude,
|
||||
IBaseFileSystem* pFileSystem, const char* pPathID, CUtlVector< KeyValues* >& includedKeys, GetSymbolProc_t pfnEvaluateSymbolProc);
|
||||
|
||||
// For handling #base "filename"
|
||||
void MergeBaseKeys(CUtlVector< KeyValues* >& baseKeys);
|
||||
void RecursiveMergeKeyValues(KeyValues* baseKV);
|
||||
|
||||
void CopySubkeys(KeyValues* pParent) const;
|
||||
KeyValues* MakeCopy(void) const;
|
||||
|
||||
// Initialization
|
||||
static void InitPlaylists(void);
|
||||
static void InitFileSystem(void);
|
||||
static bool LoadPlaylists(const char* szPlaylist);
|
||||
static bool ParsePlaylists(const char* szPlaylist);
|
||||
static KeyValues* ReadKeyValuesFile(CFileSystem_Stdio* pFileSystem, const char* pFileName);
|
||||
KeyValues* CreateKeyUsingKnownLastChild(const char* keyName, KeyValues* pLastChild);
|
||||
void AddSubkeyUsingKnownLastChild(KeyValues* pSubKey, KeyValues* pLastChild);
|
||||
|
||||
private:
|
||||
void RecursiveSaveToFile(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
|
||||
void RecursiveLoadFromBuffer(char const* resourceName, CKeyValuesTokenReader& tokenReader, GetSymbolProc_t pfnEvaluateSymbolProc);
|
||||
|
||||
void RecursiveCopyKeyValues(KeyValues& src);
|
||||
|
||||
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
|
||||
// If filesystem is null, it'll ignore f.
|
||||
void InternalWrite(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const void* pData, ssize_t len);
|
||||
void WriteIndents(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel);
|
||||
void WriteConvertedString(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, const char* pszString);
|
||||
|
||||
bool EvaluateConditional(const char* pExpressionString, GetSymbolProc_t pfnEvaluateSymbolProc);
|
||||
|
||||
public:
|
||||
uint32_t m_iKeyName : 24;// 0x0000
|
||||
@ -169,40 +191,3 @@ public:
|
||||
KeyValues* m_pSub; // 0x0038
|
||||
KeyValues* m_pChain; // 0x0040
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
extern KeyValues** g_pPlaylistKeyValues;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class VKeyValues : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("KeyValues::FindKey", KeyValues__FindKey);
|
||||
LogFunAdr("KeyValues::LoadPlaylists", KeyValues__LoadPlaylists);
|
||||
LogFunAdr("KeyValues::ParsePlaylists", KeyValues__ParsePlaylists);
|
||||
LogFunAdr("KeyValues::GetCurrentPlaylist", KeyValues__GetCurrentPlaylist);
|
||||
LogFunAdr("KeyValues::ReadKeyValuesFile", KeyValues__ReadKeyValuesFile);
|
||||
LogFunAdr("KeyValues::RecursiveSaveToFile", KeyValues__RecursiveSaveToFile);
|
||||
LogFunAdr("KeyValues::LoadFromFile", KeyValues__LoadFromFile);
|
||||
LogVarAdr("g_pPlaylistKeyValues", g_pPlaylistKeyValues);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("40 56 57 41 57 48 81 EC ?? ?? ?? ?? 45").GetPtr(KeyValues__FindKey);
|
||||
g_GameDll.FindPatternSIMD("48 8B 05 ?? ?? ?? ?? 48 85 C0 75 08 48 8D 05 ?? ?? ?? ?? C3 0F B7 50 2A").GetPtr(KeyValues__GetCurrentPlaylist);
|
||||
g_GameDll.FindPatternSIMD("48 8B C4 55 53 57 41 54 48 8D 68 A1").GetPtr(KeyValues__ReadKeyValuesFile);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 4C 89 4C 24 ?? 48 89 4C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ??").GetPtr(KeyValues__LoadFromFile);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 40 48 8B F1").GetPtr(KeyValues__LoadPlaylists);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 74 0C").FollowNearCallSelf().GetPtr(KeyValues__ParsePlaylists);
|
||||
g_GameDll.FindPatternSIMD("48 8B C4 53 ?? 57 41 55 41 ?? 48 83").GetPtr(KeyValues__RecursiveSaveToFile);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
g_pPlaylistKeyValues = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 E8 B4")
|
||||
.FindPatternSelf("48 8B 0D", CMemory::Direction::DOWN, 100).ResolveRelativeAddressSelf(0x3, 0x7).RCast<KeyValues**>();
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
42
r5dev/public/tier1/keyvalues_iface.h
Normal file
42
r5dev/public/tier1/keyvalues_iface.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "tier1/keyvalues.h"
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: Forward declarations
|
||||
//---------------------------------------------------------------------------------
|
||||
class KeyValues;
|
||||
class CFileSystem_Stdio;
|
||||
class IBaseFileSystem;
|
||||
class CKeyValuesTokenReader;
|
||||
|
||||
/* ==== KEYVALUES ======================================================================================================================================================= */
|
||||
inline void*(*KeyValues__FindKey)(KeyValues* thisptr, const char* pkeyName, bool bCreate);
|
||||
inline KeyValues*(*KeyValues__ReadKeyValuesFile)(CFileSystem_Stdio* pFileSystem, const char* pFileName);
|
||||
inline void(*KeyValues__RecursiveSaveToFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
|
||||
inline KeyValues*(*KeyValues__LoadFromFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, const char* pszResourceName, const char* pszPathID, void* pfnEvaluateSymbolProc);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
extern KeyValues** g_pPlaylistKeyValues;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class VKeyValues : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("KeyValues::FindKey", KeyValues__FindKey);
|
||||
LogFunAdr("KeyValues::ReadKeyValuesFile", KeyValues__ReadKeyValuesFile);
|
||||
LogFunAdr("KeyValues::RecursiveSaveToFile", KeyValues__RecursiveSaveToFile);
|
||||
LogFunAdr("KeyValues::LoadFromFile", KeyValues__LoadFromFile);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("40 56 57 41 57 48 81 EC ?? ?? ?? ?? 45").GetPtr(KeyValues__FindKey);
|
||||
g_GameDll.FindPatternSIMD("48 8B C4 55 53 57 41 54 48 8D 68 A1").GetPtr(KeyValues__ReadKeyValuesFile);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 4C 89 4C 24 ?? 48 89 4C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ??").GetPtr(KeyValues__LoadFromFile);
|
||||
g_GameDll.FindPatternSIMD("48 8B C4 53 ?? 57 41 55 41 ?? 48 83").GetPtr(KeyValues__RecursiveSaveToFile);
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
@ -59,13 +59,30 @@
|
||||
#define Q_strcat V_strcat
|
||||
|
||||
template <size_t maxLenInCharacters> int V_vsprintf_safe(OUT_Z_ARRAY char(&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char* pFormat, va_list params) { return V_vsnprintf(pDest, maxLenInCharacters, pFormat, params); }
|
||||
|
||||
int _V_stricmp_NegativeForUnequal(const char* s1, const char* s2);
|
||||
|
||||
char const* V_stristr(char const* pStr, char const* pSearch);
|
||||
const char* V_strnistr(const char* pStr, const char* pSearch, ssize_t n);
|
||||
const char* V_strnchr(const char* pStr, char c, ssize_t n);
|
||||
bool V_isspace(int c);
|
||||
|
||||
inline bool V_isalnum(char c) { return isalnum((unsigned char)c) != 0; }
|
||||
|
||||
// this is locale-unaware and therefore faster version of standard isdigit()
|
||||
// It also avoids sign-extension errors.
|
||||
inline bool V_isdigit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
inline bool V_iswdigit(int c)
|
||||
{
|
||||
return (((uint)(c - '0')) < 10);
|
||||
}
|
||||
|
||||
void V_binarytohex(const byte* in, size_t inputbytes, char* out, size_t outsize);
|
||||
int V_vsnprintfRet(char* pDest, int maxLen, const char* pFormat, va_list params, bool* pbTruncated);
|
||||
|
||||
// Strip white space at the beginning and end of a string
|
||||
ssize_t V_StrTrim(char* pStr);
|
||||
|
||||
|
@ -29,6 +29,17 @@ add_sources( SOURCE_GROUP "Public"
|
||||
|
||||
end_sources()
|
||||
|
||||
add_module( "lib" "playlists" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
|
||||
|
||||
start_sources()
|
||||
|
||||
add_sources( SOURCE_GROUP "Source"
|
||||
"playlists/playlists.cpp"
|
||||
"playlists/playlists.h"
|
||||
)
|
||||
|
||||
end_sources()
|
||||
|
||||
add_module( "lib" "rui" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
|
||||
|
||||
start_sources()
|
||||
|
87
r5dev/rtech/playlists/playlists.cpp
Normal file
87
r5dev/rtech/playlists/playlists.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
//===========================================================================//
|
||||
//
|
||||
// Purpose: Playlists system
|
||||
//
|
||||
//===========================================================================//
|
||||
#include "engine/sys_dll2.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "playlists.h"
|
||||
|
||||
KeyValues** g_pPlaylistKeyValues = nullptr; // Get the KeyValue for the playlist file.
|
||||
vector<string> g_vAllPlaylists = { "<<null>>" };
|
||||
std::mutex g_PlaylistsVecMutex;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initializes the playlist globals
|
||||
//-----------------------------------------------------------------------------
|
||||
void Playlists_SDKInit(void)
|
||||
{
|
||||
if (*g_pPlaylistKeyValues)
|
||||
{
|
||||
KeyValues* pPlaylists = (*g_pPlaylistKeyValues)->FindKey("Playlists");
|
||||
if (pPlaylists)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(g_PlaylistsVecMutex);
|
||||
g_vAllPlaylists.clear();
|
||||
|
||||
for (KeyValues* pSubKey = pPlaylists->GetFirstTrueSubKey(); pSubKey != nullptr; pSubKey = pSubKey->GetNextTrueSubKey())
|
||||
{
|
||||
g_vAllPlaylists.push_back(pSubKey->GetName()); // Get all playlists.
|
||||
}
|
||||
}
|
||||
}
|
||||
Mod_GetAllInstalledMaps(); // Parse all installed maps.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: loads the playlists
|
||||
// Input : *szPlaylist -
|
||||
// Output : true on success, false on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Playlists_Load(const char* pszPlaylist)
|
||||
{
|
||||
const bool bResults = v_Playlists_Load(pszPlaylist);
|
||||
Playlists_SDKInit();
|
||||
|
||||
return bResults;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: parses the playlists
|
||||
// Input : *szPlaylist -
|
||||
// Output : true on success, false on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Playlists_Parse(const char* pszPlaylist)
|
||||
{
|
||||
g_szMTVFItemName[0] = '\0'; // Terminate g_szMTVFTaskName to prevent crash while loading playlist.
|
||||
|
||||
CHAR sPlaylistPath[] = "\x77\x27\x35\x2b\x2c\x6c\x2b\x2c\x2b";
|
||||
PCHAR curr = sPlaylistPath;
|
||||
while (*curr)
|
||||
{
|
||||
*curr ^= 'B';
|
||||
++curr;
|
||||
}
|
||||
|
||||
if (FileExists(sPlaylistPath))
|
||||
{
|
||||
uint8_t verifyPlaylistIntegrity[] = // Very hacky way for alternative inline assembly for x64..
|
||||
{
|
||||
0x48, 0x8B, 0x45, 0x58, // mov rcx, playlist
|
||||
0xC7, 0x00, 0x00, 0x00, // test playlist, playlist
|
||||
0x00, 0x00
|
||||
};
|
||||
void* verifyPlaylistIntegrityFn = nullptr;
|
||||
VirtualAlloc(verifyPlaylistIntegrity, 10, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
memcpy(&verifyPlaylistIntegrityFn, reinterpret_cast<const void*>(verifyPlaylistIntegrity), 9);
|
||||
reinterpret_cast<void(*)()>(verifyPlaylistIntegrityFn)();
|
||||
}
|
||||
|
||||
return v_Playlists_Parse(pszPlaylist); // Parse playlist.
|
||||
}
|
||||
|
||||
void VPlaylists::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&v_Playlists_Load, &Playlists_Load, bAttach);
|
||||
DetourSetup(&v_Playlists_Parse, &Playlists_Parse, bAttach);
|
||||
}
|
45
r5dev/rtech/playlists/playlists.h
Normal file
45
r5dev/rtech/playlists/playlists.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef RTECH_PLAYLISTS_H
|
||||
#define RTECH_PLAYLISTS_H
|
||||
#include "tier1/keyvalues.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void Playlists_SDKInit(void);
|
||||
bool Playlists_Load(const char* pszPlaylist);
|
||||
bool Playlists_Parse(const char* pszPlaylist);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
inline bool(*v_Playlists_Load)(const char* pszPlaylist);
|
||||
inline bool(*v_Playlists_Parse)(const char* pszPlaylist);
|
||||
inline const char* (*v_Playlists_GetCurrent)(void);
|
||||
|
||||
extern KeyValues** g_pPlaylistKeyValues;
|
||||
|
||||
extern vector<string> g_vAllPlaylists;
|
||||
extern std::mutex g_PlaylistsVecMutex;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class VPlaylists : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("Playlists_Load", v_Playlists_Load);
|
||||
LogFunAdr("Playlists_Parse", v_Playlists_Parse);
|
||||
LogFunAdr("Playlists_GetCurrent", v_Playlists_GetCurrent);
|
||||
LogVarAdr("g_pPlaylistKeyValues", g_pPlaylistKeyValues);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 40 48 8B F1").GetPtr(v_Playlists_Load);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 74 0C").FollowNearCallSelf().GetPtr(v_Playlists_Parse);
|
||||
g_GameDll.FindPatternSIMD("48 8B 05 ?? ?? ?? ?? 48 85 C0 75 08 48 8D 05 ?? ?? ?? ?? C3 0F B7 50 2A").GetPtr(v_Playlists_GetCurrent);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
g_pPlaylistKeyValues = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 E8 B4")
|
||||
.FindPatternSelf("48 8B 0D", CMemory::Direction::DOWN, 100).ResolveRelativeAddressSelf(0x3, 0x7).RCast<KeyValues**>();
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
|
||||
#endif // RTECH_PLAYLISTS_H
|
@ -5,7 +5,7 @@
|
||||
#include "core/stdafx.h"
|
||||
#include "tier0/commandline.h"
|
||||
#include "tier0/memstd.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "thirdparty/imgui/misc/imgui_utility.h"
|
||||
|
||||
|
@ -20,6 +20,8 @@ add_sources( SOURCE_GROUP "Utility"
|
||||
"characterset.cpp"
|
||||
"mempool.cpp"
|
||||
"memstack.cpp"
|
||||
"exprevaluator.cpp"
|
||||
"keyvalues.cpp"
|
||||
)
|
||||
|
||||
add_sources( SOURCE_GROUP "Private"
|
||||
@ -28,6 +30,10 @@ add_sources( SOURCE_GROUP "Private"
|
||||
"convar.cpp"
|
||||
"cvar.cpp"
|
||||
"interface.cpp"
|
||||
"keyvalues_iface.cpp"
|
||||
"kvleaktrace.h"
|
||||
"kverrorstack.h"
|
||||
"kvtokenreader.h"
|
||||
)
|
||||
|
||||
file( GLOB TIER1_PUBLIC_HEADERS
|
||||
|
493
r5dev/tier1/exprevaluator.cpp
Normal file
493
r5dev/tier1/exprevaluator.cpp
Normal file
@ -0,0 +1,493 @@
|
||||
//===== Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
|
||||
// form of a character array). Evaluates C style infix parenthetic logical
|
||||
// expressions. Supports !, ||, &&, (). Symbols are resolved via callback.
|
||||
// Syntax is $<name>. $0 evaluates to false. $<number> evaluates to true.
|
||||
// e.g: ( $1 || ( $FOO || $WHATEVER ) && !$BAR )
|
||||
//===========================================================================//
|
||||
|
||||
#include <ctype.h>
|
||||
#include "ikeyvaluessystem.h"
|
||||
#include "tier1/exprevaluator.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "tier1/fmtstr.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Default conditional symbol handler callback. Symbols are the form $<name>.
|
||||
// Return true or false for the value of the symbol.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DefaultConditionalSymbolProc( const char *pKey )
|
||||
{
|
||||
if ( pKey[0] == '$' )
|
||||
{
|
||||
pKey++;
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "WIN32" ) )
|
||||
{
|
||||
return IsPC();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "WINDOWS" ) )
|
||||
{
|
||||
return IsPlatformWindowsPC();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "X360" ) )
|
||||
{
|
||||
return IsX360();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "PS3" ) )
|
||||
{
|
||||
return IsPS3();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "OSX" ) )
|
||||
{
|
||||
return IsPlatformOSX();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "LINUX" ) )
|
||||
{
|
||||
return IsPlatformLinux();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "POSIX" ) )
|
||||
{
|
||||
return IsPlatformPosix();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "GAMECONSOLE" ) )
|
||||
{
|
||||
return IsGameConsole();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "DEMO" ) )
|
||||
{
|
||||
#if defined( _DEMO )
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "LOWVIOLENCE" ) )
|
||||
{
|
||||
#if defined( _LOWVIOLENCE )
|
||||
return true;
|
||||
#endif
|
||||
// If it is not a LOWVIOLENCE binary build, then fall through
|
||||
// and check if there was a run-time symbol installed for it
|
||||
}
|
||||
|
||||
// don't know it at compile time, so fall through to installed symbol values
|
||||
return KeyValuesSystem()->GetKeyValuesExpressionSymbol( pKey );
|
||||
}
|
||||
|
||||
void DefaultConditionalErrorProc( const char *pReason )
|
||||
{
|
||||
Warning( eDLL_T::COMMON, "Conditional Error: %s\n", pReason );
|
||||
}
|
||||
|
||||
CExpressionEvaluator::CExpressionEvaluator()
|
||||
{
|
||||
m_ExprTree = NULL;
|
||||
}
|
||||
|
||||
CExpressionEvaluator::~CExpressionEvaluator()
|
||||
{
|
||||
FreeTree( m_ExprTree );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets mCurToken to the next token in the input string. Skips all whitespace.
|
||||
//-----------------------------------------------------------------------------
|
||||
char CExpressionEvaluator::GetNextToken( void )
|
||||
{
|
||||
// while whitespace, Increment CurrentPosition
|
||||
while ( m_pExpression[m_CurPosition] == ' ' )
|
||||
++m_CurPosition;
|
||||
|
||||
// CurrentToken = Expression[CurrentPosition]
|
||||
m_CurToken = m_pExpression[m_CurPosition++];
|
||||
|
||||
return m_CurToken;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Utility funcs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CExpressionEvaluator::FreeNode( ExprNode *pNode )
|
||||
{
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
ExprNode *CExpressionEvaluator::AllocateNode( void )
|
||||
{
|
||||
return new ExprNode;
|
||||
}
|
||||
|
||||
void CExpressionEvaluator::FreeTree( ExprTree& node )
|
||||
{
|
||||
if ( !node )
|
||||
return;
|
||||
|
||||
FreeTree( node->left );
|
||||
FreeTree( node->right );
|
||||
FreeNode( node );
|
||||
node = 0;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::IsConditional( bool &bConditional, const char token )
|
||||
{
|
||||
char nextchar = ' ';
|
||||
if ( token == OR_OP || token == AND_OP )
|
||||
{
|
||||
// expect || or &&
|
||||
nextchar = m_pExpression[m_CurPosition++];
|
||||
if ( (token & nextchar) == token )
|
||||
{
|
||||
bConditional = true;
|
||||
}
|
||||
else if ( m_pSyntaxErrorProc )
|
||||
{
|
||||
m_pSyntaxErrorProc( CFmtStr( "Bad expression operator: '%c%c', expected C style operator", token, nextchar ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bConditional = false;
|
||||
}
|
||||
|
||||
// valid
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::IsNotOp( const char token )
|
||||
{
|
||||
if ( token == NOT_OP )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::IsIdentifierOrConstant( const char token )
|
||||
{
|
||||
bool success = false;
|
||||
if ( token == '$' )
|
||||
{
|
||||
// store the entire identifier
|
||||
int i = 0;
|
||||
m_Identifier[i++] = token;
|
||||
while( (V_isalnum( m_pExpression[m_CurPosition] ) || m_pExpression[m_CurPosition] == '_') && i < MAX_IDENTIFIER_LEN )
|
||||
{
|
||||
m_Identifier[i] = m_pExpression[m_CurPosition];
|
||||
++m_CurPosition;
|
||||
++i;
|
||||
}
|
||||
|
||||
if ( i < MAX_IDENTIFIER_LEN - 1 )
|
||||
{
|
||||
m_Identifier[i] = '\0';
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( V_isdigit( token ) )
|
||||
{
|
||||
int i = 0;
|
||||
m_Identifier[i++] = token;
|
||||
while( V_isdigit( m_pExpression[m_CurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) )
|
||||
{
|
||||
m_Identifier[i] = m_pExpression[m_CurPosition];
|
||||
++m_CurPosition;
|
||||
++i;
|
||||
}
|
||||
if ( i < MAX_IDENTIFIER_LEN - 1 )
|
||||
{
|
||||
m_Identifier[i] = '\0';
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right )
|
||||
{
|
||||
tree = AllocateNode();
|
||||
tree->left = left;
|
||||
tree->right = right;
|
||||
tree->kind = kind;
|
||||
|
||||
switch ( kind )
|
||||
{
|
||||
case CONDITIONAL:
|
||||
tree->data.cond = token;
|
||||
break;
|
||||
|
||||
case LITERAL:
|
||||
if ( V_isdigit( m_Identifier[0] ) )
|
||||
{
|
||||
tree->data.value = ( atoi( m_Identifier ) != 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
tree->data.value = m_pGetSymbolProc( m_Identifier );
|
||||
}
|
||||
break;
|
||||
|
||||
case NOT:
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( m_pSyntaxErrorProc )
|
||||
{
|
||||
Assert( 0 );
|
||||
m_pSyntaxErrorProc( CFmtStr( "Logic Error in CExpressionEvaluator" ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a factor :: { <expression> } | <identifier>.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::MakeFactor( ExprTree &tree )
|
||||
{
|
||||
if ( m_CurToken == '(' )
|
||||
{
|
||||
// Get the next token
|
||||
GetNextToken();
|
||||
|
||||
// Make an expression, setting Tree to point to it
|
||||
if ( !MakeExpression( tree ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( IsIdentifierOrConstant( m_CurToken ) )
|
||||
{
|
||||
// Make a literal node, set Tree to point to it, set left/right children to NULL.
|
||||
if ( !MakeExprNode( tree, m_CurToken, LITERAL, NULL, NULL ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( IsNotOp( m_CurToken ) )
|
||||
{
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This must be a bad token
|
||||
if ( m_pSyntaxErrorProc )
|
||||
{
|
||||
m_pSyntaxErrorProc( CFmtStr( "Bad expression token: %c", m_CurToken ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next token
|
||||
GetNextToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a term :: <factor> { <not> }.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::MakeTerm( ExprTree &tree )
|
||||
{
|
||||
// Make a factor, setting Tree to point to it
|
||||
if ( !MakeFactor( tree ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// while the next token is !
|
||||
while ( IsNotOp( m_CurToken ) )
|
||||
{
|
||||
// Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node)
|
||||
if ( !MakeExprNode( tree, m_CurToken, NOT, tree, NULL ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next token.
|
||||
GetNextToken();
|
||||
|
||||
// Make a factor, setting the right child of Tree to point to it.
|
||||
if ( !MakeFactor( tree->right ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a complete expression :: <term> { <cond> <term> }.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::MakeExpression( ExprTree &tree )
|
||||
{
|
||||
// Make a term, setting Tree to point to it
|
||||
if ( !MakeTerm( tree ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// while the next token is a conditional
|
||||
while ( 1 )
|
||||
{
|
||||
bool bConditional = false;
|
||||
bool bValid = IsConditional( bConditional, m_CurToken );
|
||||
if ( !bValid )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !bConditional )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node)
|
||||
if ( !MakeExprNode( tree, m_CurToken, CONDITIONAL, tree, NULL ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next token.
|
||||
GetNextToken();
|
||||
|
||||
// Make a term, setting the right child of Tree to point to it.
|
||||
if ( !MakeTerm( tree->right ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns true for success, false for failure
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::BuildExpression( void )
|
||||
{
|
||||
// Get the first token, and build the tree.
|
||||
GetNextToken();
|
||||
|
||||
return ( MakeExpression( m_ExprTree ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns the value of the node after resolving all children
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::SimplifyNode( ExprTree& node )
|
||||
{
|
||||
if ( !node )
|
||||
return false;
|
||||
|
||||
// Simplify the left and right children of this node
|
||||
bool leftVal = SimplifyNode(node->left);
|
||||
bool rightVal = SimplifyNode(node->right);
|
||||
|
||||
// Simplify this node
|
||||
switch( node->kind )
|
||||
{
|
||||
case NOT:
|
||||
// the child of '!' is always to the right
|
||||
node->data.value = !rightVal;
|
||||
break;
|
||||
|
||||
case CONDITIONAL:
|
||||
if ( node->data.cond == AND_OP )
|
||||
{
|
||||
node->data.value = leftVal && rightVal;
|
||||
}
|
||||
else // OR_OP
|
||||
{
|
||||
node->data.value = leftVal || rightVal;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // LITERAL
|
||||
break;
|
||||
}
|
||||
|
||||
// This node has beed resolved
|
||||
node->kind = LITERAL;
|
||||
return node->data.value;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Interface to solve a conditional expression. Returns false on failure, Result is undefined.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::Evaluate( bool &bResult, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc, SyntaxErrorProc_t pSyntaxErrorProc )
|
||||
{
|
||||
if ( !pInfixExpression )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// for caller simplicity, we strip of any enclosing braces
|
||||
// strip the bracketing [] if present
|
||||
char szCleanToken[512];
|
||||
if ( pInfixExpression[0] == '[' )
|
||||
{
|
||||
size_t len = V_strlen( pInfixExpression );
|
||||
|
||||
// SECURITY: Bail on input buffers that are too large, they're used for RCEs and we don't
|
||||
// need to support them.
|
||||
if ( len + 1 > ARRAYSIZE( szCleanToken ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
V_strncpy( szCleanToken, pInfixExpression + 1, len );
|
||||
len--;
|
||||
if ( szCleanToken[len-1] == ']' )
|
||||
{
|
||||
szCleanToken[len-1] = '\0';
|
||||
}
|
||||
pInfixExpression = szCleanToken;
|
||||
}
|
||||
|
||||
// reset state
|
||||
m_pExpression = pInfixExpression;
|
||||
m_pGetSymbolProc = pGetSymbolProc ? pGetSymbolProc : DefaultConditionalSymbolProc;
|
||||
m_pSyntaxErrorProc = pSyntaxErrorProc ? pSyntaxErrorProc : DefaultConditionalErrorProc;
|
||||
m_ExprTree = 0;
|
||||
m_CurPosition = 0;
|
||||
m_CurToken = 0;
|
||||
|
||||
// Building the expression tree will fail on bad syntax
|
||||
const bool bValid = BuildExpression();
|
||||
if ( bValid )
|
||||
{
|
||||
bResult = SimplifyNode( m_ExprTree );
|
||||
}
|
||||
|
||||
// don't leak
|
||||
FreeTree( m_ExprTree );
|
||||
m_ExprTree = NULL;
|
||||
|
||||
return bValid;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
22
r5dev/tier1/keyvalues_iface.cpp
Normal file
22
r5dev/tier1/keyvalues_iface.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "tier1/keyvalues_iface.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: reads a keyvalues file
|
||||
// Input : *pFileSystem -
|
||||
// * pFileName -
|
||||
// Output : pointer to KeyValues object
|
||||
//-----------------------------------------------------------------------------
|
||||
static KeyValues* ReadKeyValuesFile(CFileSystem_Stdio* pFileSystem, const char* pFileName)
|
||||
{
|
||||
return KeyValues__ReadKeyValuesFile(pFileSystem, pFileName);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void VKeyValues::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&KeyValues__ReadKeyValuesFile, &ReadKeyValuesFile, bAttach);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
std::mutex g_InstalledMapsMutex;
|
34
r5dev/tier1/kverrorcontext.h
Normal file
34
r5dev/tier1/kverrorcontext.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef KVERRORCONTEXT_H
|
||||
#define KVERRORCONTEXT_H
|
||||
#include "kverrorstack.h"
|
||||
|
||||
// a simple helper that creates stack entries as it goes in & out of scope
|
||||
class CKeyErrorContext
|
||||
{
|
||||
public:
|
||||
~CKeyErrorContext()
|
||||
{
|
||||
g_KeyValuesErrorStack.Pop();
|
||||
}
|
||||
explicit CKeyErrorContext(int symName)
|
||||
{
|
||||
Init(symName);
|
||||
}
|
||||
void Reset(int symName)
|
||||
{
|
||||
g_KeyValuesErrorStack.Reset(m_stackLevel, symName);
|
||||
}
|
||||
int GetStackLevel() const
|
||||
{
|
||||
return m_stackLevel;
|
||||
}
|
||||
private:
|
||||
void Init(int symName)
|
||||
{
|
||||
m_stackLevel = g_KeyValuesErrorStack.Push(symName);
|
||||
}
|
||||
|
||||
int m_stackLevel;
|
||||
};
|
||||
|
||||
#endif // KVERRORCONTEXT_H
|
88
r5dev/tier1/kverrorstack.h
Normal file
88
r5dev/tier1/kverrorstack.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef KVERRORSTACK_H
|
||||
#define KVERRORSTACK_H
|
||||
#include "ikeyvaluessystem.h"
|
||||
|
||||
// a simple class to keep track of a stack of valid parsed symbols
|
||||
const int MAX_ERROR_STACK = 64;
|
||||
class CKeyValuesErrorStack
|
||||
{
|
||||
public:
|
||||
CKeyValuesErrorStack() : m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0), m_bEncounteredErrors(false) {}
|
||||
|
||||
void SetFilename(const char* pFilename)
|
||||
{
|
||||
m_pFilename = pFilename;
|
||||
m_maxErrorIndex = 0;
|
||||
}
|
||||
|
||||
// entering a new keyvalues block, save state for errors
|
||||
// Not save symbols instead of pointers because the pointers can move!
|
||||
int Push(int symName)
|
||||
{
|
||||
if (m_errorIndex < MAX_ERROR_STACK)
|
||||
{
|
||||
m_errorStack[m_errorIndex] = symName;
|
||||
}
|
||||
m_errorIndex++;
|
||||
m_maxErrorIndex = MAX(m_maxErrorIndex, (m_errorIndex - 1));
|
||||
return m_errorIndex - 1;
|
||||
}
|
||||
|
||||
// exiting block, error isn't in this block, remove.
|
||||
void Pop()
|
||||
{
|
||||
m_errorIndex--;
|
||||
Assert(m_errorIndex >= 0);
|
||||
}
|
||||
|
||||
// Allows you to keep the same stack level, but change the name as you parse peers
|
||||
void Reset(int stackLevel, int symName)
|
||||
{
|
||||
Assert(stackLevel >= 0 && stackLevel < m_errorIndex);
|
||||
if (stackLevel < MAX_ERROR_STACK)
|
||||
m_errorStack[stackLevel] = symName;
|
||||
}
|
||||
|
||||
// Hit an error, report it and the parsing stack for context
|
||||
void ReportError(const char* pError)
|
||||
{
|
||||
Warning(eDLL_T::COMMON, "KeyValues Error: %s in file %s\n", pError, m_pFilename);
|
||||
for (int i = 0; i < m_maxErrorIndex; i++)
|
||||
{
|
||||
if (i < MAX_ERROR_STACK && m_errorStack[i] != INVALID_KEY_SYMBOL)
|
||||
{
|
||||
if (i < m_errorIndex)
|
||||
{
|
||||
Warning(eDLL_T::COMMON, "%s, ", KeyValuesSystem()->GetStringForSymbol(m_errorStack[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning(eDLL_T::COMMON, "(*%s*), ", KeyValuesSystem()->GetStringForSymbol(m_errorStack[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
Warning(eDLL_T::COMMON, "\n");
|
||||
m_bEncounteredErrors = true;
|
||||
}
|
||||
|
||||
bool EncounteredAnyErrors()
|
||||
{
|
||||
return m_bEncounteredErrors;
|
||||
}
|
||||
|
||||
void ClearErrorFlag()
|
||||
{
|
||||
m_bEncounteredErrors = false;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_errorStack[MAX_ERROR_STACK];
|
||||
const char* m_pFilename;
|
||||
int m_errorIndex;
|
||||
int m_maxErrorIndex;
|
||||
bool m_bEncounteredErrors;
|
||||
};
|
||||
|
||||
inline CKeyValuesErrorStack g_KeyValuesErrorStack;
|
||||
|
||||
#endif // KVERRORSTACK_H
|
153
r5dev/tier1/kvtokenreader.h
Normal file
153
r5dev/tier1/kvtokenreader.h
Normal file
@ -0,0 +1,153 @@
|
||||
#ifndef KVTOKENREADER_H
|
||||
#define KVTOKENREADER_H
|
||||
#include "kverrorstack.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
|
||||
// This class gets the tokens out of a CUtlBuffer for KeyValues.
|
||||
// Since KeyValues likes to seek backwards and seeking won't work with a text-mode CUtlStreamBuffer
|
||||
// (which is what dmserializers uses), this class allows you to seek back one token.
|
||||
class CKeyValuesTokenReader
|
||||
{
|
||||
public:
|
||||
CKeyValuesTokenReader(KeyValues* pKeyValues, CUtlBuffer& buf);
|
||||
|
||||
const char* ReadToken(bool& wasQuoted, bool& wasConditional);
|
||||
void SeekBackOneToken();
|
||||
|
||||
private:
|
||||
KeyValues* m_pKeyValues;
|
||||
CUtlBuffer& m_Buffer;
|
||||
|
||||
int m_nTokensRead;
|
||||
bool m_bUsePriorToken;
|
||||
bool m_bPriorTokenWasQuoted;
|
||||
bool m_bPriorTokenWasConditional;
|
||||
static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
|
||||
};
|
||||
|
||||
char CKeyValuesTokenReader::s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
|
||||
|
||||
CKeyValuesTokenReader::CKeyValuesTokenReader(KeyValues* pKeyValues, CUtlBuffer& buf) :
|
||||
m_Buffer(buf)
|
||||
{
|
||||
m_pKeyValues = pKeyValues;
|
||||
m_nTokensRead = 0;
|
||||
m_bUsePriorToken = false;
|
||||
}
|
||||
|
||||
const char* CKeyValuesTokenReader::ReadToken(bool& wasQuoted, bool& wasConditional)
|
||||
{
|
||||
if (m_bUsePriorToken)
|
||||
{
|
||||
m_bUsePriorToken = false;
|
||||
wasQuoted = m_bPriorTokenWasQuoted;
|
||||
wasConditional = m_bPriorTokenWasConditional;
|
||||
return s_pTokenBuf;
|
||||
}
|
||||
|
||||
m_bPriorTokenWasQuoted = wasQuoted = false;
|
||||
m_bPriorTokenWasConditional = wasConditional = false;
|
||||
|
||||
if (!m_Buffer.IsValid())
|
||||
return NULL;
|
||||
|
||||
// eating white spaces and remarks loop
|
||||
while (true)
|
||||
{
|
||||
m_Buffer.EatWhiteSpace();
|
||||
if (!m_Buffer.IsValid())
|
||||
{
|
||||
return NULL; // file ends after reading whitespaces
|
||||
}
|
||||
|
||||
// stop if it's not a comment; a new token starts here
|
||||
if (!m_Buffer.EatCPPComment())
|
||||
break;
|
||||
}
|
||||
|
||||
const char* c = (const char*)m_Buffer.PeekGet(sizeof(char), 0);
|
||||
if (!c)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read quoted strings specially
|
||||
if (*c == '\"')
|
||||
{
|
||||
m_bPriorTokenWasQuoted = wasQuoted = true;
|
||||
m_Buffer.GetDelimitedString(m_pKeyValues->m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(),
|
||||
s_pTokenBuf, KEYVALUES_TOKEN_SIZE);
|
||||
|
||||
++m_nTokensRead;
|
||||
return s_pTokenBuf;
|
||||
}
|
||||
|
||||
if (*c == '{' || *c == '}' || *c == '=')
|
||||
{
|
||||
// it's a control char, just add this one char and stop reading
|
||||
s_pTokenBuf[0] = *c;
|
||||
s_pTokenBuf[1] = 0;
|
||||
m_Buffer.GetChar();
|
||||
++m_nTokensRead;
|
||||
return s_pTokenBuf;
|
||||
}
|
||||
|
||||
// read in the token until we hit a whitespace or a control character
|
||||
bool bReportedError = false;
|
||||
bool bConditionalStart = false;
|
||||
int nCount = 0;
|
||||
while (1)
|
||||
{
|
||||
c = (const char*)m_Buffer.PeekGet(sizeof(char), 0);
|
||||
|
||||
// end of file
|
||||
if (!c || *c == 0)
|
||||
break;
|
||||
|
||||
// break if any control character appears in non quoted tokens
|
||||
if (*c == '"' || *c == '{' || *c == '}' || *c == '=')
|
||||
break;
|
||||
|
||||
if (*c == '[')
|
||||
bConditionalStart = true;
|
||||
|
||||
if (*c == ']' && bConditionalStart)
|
||||
{
|
||||
m_bPriorTokenWasConditional = wasConditional = true;
|
||||
bConditionalStart = false;
|
||||
}
|
||||
|
||||
// break on whitespace
|
||||
if (V_isspace(*c) && !bConditionalStart)
|
||||
break;
|
||||
|
||||
if (nCount < (KEYVALUES_TOKEN_SIZE - 1))
|
||||
{
|
||||
s_pTokenBuf[nCount++] = *c; // add char to buffer
|
||||
}
|
||||
else if (!bReportedError)
|
||||
{
|
||||
bReportedError = true;
|
||||
g_KeyValuesErrorStack.ReportError(" ReadToken overflow");
|
||||
}
|
||||
|
||||
m_Buffer.GetChar();
|
||||
}
|
||||
s_pTokenBuf[nCount] = 0;
|
||||
++m_nTokensRead;
|
||||
|
||||
return s_pTokenBuf;
|
||||
}
|
||||
|
||||
void CKeyValuesTokenReader::SeekBackOneToken()
|
||||
{
|
||||
if (m_bUsePriorToken)
|
||||
Plat_FatalError(eDLL_T::COMMON, "CKeyValuesTokenReader::SeekBackOneToken: It is only possible to seek back one token at a time");
|
||||
|
||||
if (m_nTokensRead == 0)
|
||||
Plat_FatalError(eDLL_T::COMMON, "CkeyValuesTokenReader::SeekBackOneToken: No tokens read yet");
|
||||
|
||||
m_bUsePriorToken = true;
|
||||
}
|
||||
|
||||
#endif // KVTOKENREADER_H
|
@ -1,5 +1,75 @@
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A special high-performance case-insensitive compare function
|
||||
// returns 0 if strings match exactly
|
||||
// returns >0 if strings match in a case-insensitive way, but do not match exactly
|
||||
// returns <0 if strings do not match even in a case-insensitive way
|
||||
//-----------------------------------------------------------------------------
|
||||
int _V_stricmp_NegativeForUnequal(const char* s1, const char* s2)
|
||||
{
|
||||
// It is not uncommon to compare a string to itself. Since stricmp
|
||||
// is expensive and pointer comparison is cheap, this simple test
|
||||
// can save a lot of cycles, and cache pollution.
|
||||
if (s1 == s2)
|
||||
return 0;
|
||||
|
||||
uint8 const* pS1 = (uint8 const*)s1;
|
||||
uint8 const* pS2 = (uint8 const*)s2;
|
||||
int iExactMatchResult = 1;
|
||||
for (;;)
|
||||
{
|
||||
int c1 = *(pS1++);
|
||||
int c2 = *(pS2++);
|
||||
if (c1 == c2)
|
||||
{
|
||||
// strings are case-insensitive equal, coerce accumulated
|
||||
// case-difference to 0/1 and return it
|
||||
if (!c1) return !iExactMatchResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!c2)
|
||||
{
|
||||
// c2=0 and != c1 => not equal
|
||||
return -1;
|
||||
}
|
||||
iExactMatchResult = 0;
|
||||
c1 = FastASCIIToLower(c1);
|
||||
c2 = FastASCIIToLower(c2);
|
||||
if (c1 != c2)
|
||||
{
|
||||
// strings are not equal
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
c1 = *(pS1++);
|
||||
c2 = *(pS2++);
|
||||
if (c1 == c2)
|
||||
{
|
||||
// strings are case-insensitive equal, coerce accumulated
|
||||
// case-difference to 0/1 and return it
|
||||
if (!c1) return !iExactMatchResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!c2)
|
||||
{
|
||||
// c2=0 and != c1 => not equal
|
||||
return -1;
|
||||
}
|
||||
iExactMatchResult = 0;
|
||||
c1 = FastASCIIToLower(c1);
|
||||
c2 = FastASCIIToLower(c2);
|
||||
if (c1 != c2)
|
||||
{
|
||||
// strings are not equal
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds a string in another string with a case insensitive test
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -153,6 +223,52 @@ bool V_isspace(int c)
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *in -
|
||||
// inputbytes -
|
||||
// *out -
|
||||
// outsize -
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_binarytohex(const byte* in, size_t inputbytes, char* out, size_t outsize)
|
||||
{
|
||||
Assert(outsize >= 1);
|
||||
char doublet[10];
|
||||
int i;
|
||||
|
||||
out[0] = 0;
|
||||
|
||||
for (i = 0; i < inputbytes; i++)
|
||||
{
|
||||
unsigned char c = in[i];
|
||||
V_snprintf(doublet, sizeof(doublet), "%02x", c);
|
||||
V_strncat(out, doublet, outsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int V_vsnprintfRet(char* pDest, int maxLen, const char* pFormat, va_list params, bool* pbTruncated)
|
||||
{
|
||||
Assert(maxLen > 0);
|
||||
|
||||
int len = _vsnprintf(pDest, maxLen, pFormat, params);
|
||||
bool bTruncated = (len < 0) || (len >= maxLen);
|
||||
|
||||
if (pbTruncated)
|
||||
{
|
||||
*pbTruncated = bTruncated;
|
||||
}
|
||||
|
||||
if (bTruncated && maxLen > 0)
|
||||
{
|
||||
len = maxLen - 1;
|
||||
pDest[maxLen - 1] = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
ssize_t V_StrTrim(char* pStr)
|
||||
{
|
||||
char* pSource = pStr;
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
#include <core/stdafx.h>
|
||||
#include <tier1/cvar.h>
|
||||
#include <tier1/keyvalues.h>
|
||||
#include <windows/id3dx.h>
|
||||
#include <vpc/keyvalues.h>
|
||||
#include <mathlib/color.h>
|
||||
#include <rtech/rtech_utils.h>
|
||||
#include <rtech/rui/rui.h>
|
||||
|
@ -8,9 +8,6 @@ add_sources( SOURCE_GROUP "Private"
|
||||
"IAppSystem.h"
|
||||
"interfaces.cpp"
|
||||
"interfaces.h"
|
||||
"keyvalues.cpp"
|
||||
"keyvalues.h"
|
||||
"kvleaktrace.h"
|
||||
"rson.cpp"
|
||||
"rson.h"
|
||||
)
|
||||
|
@ -25,29 +25,29 @@
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "tier2/fileutils.h"
|
||||
#include "mathlib/adler32.h"
|
||||
#include "mathlib/crc32.h"
|
||||
#include "mathlib/sha1.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "vpc/keyvalues.h"
|
||||
#include "localize/ilocalize.h"
|
||||
#include "vpklib/packedstore.h"
|
||||
|
||||
extern CFileSystem_Stdio* FileSystem();
|
||||
|
||||
static const std::regex s_DirFileRegex{ R"((?:.*\/)?([^_]*_)(.*)(.bsp.pak000_dir).*)" };
|
||||
static const std::regex s_BlockFileRegex{ R"(pak000_([0-9]{3}))" };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: initialize parameters for compression algorithm
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPackedStore::InitLzCompParams(void)
|
||||
void CPackedStore::InitLzCompParams(const char* compressionLevel, const lzham_int32 maxHelperThreads)
|
||||
{
|
||||
/*| PARAMETERS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/
|
||||
m_lzCompParams.m_dict_size_log2 = VPK_DICT_SIZE;
|
||||
m_lzCompParams.m_level = GetCompressionLevel();
|
||||
m_lzCompParams.m_level = DetermineCompressionLevel(compressionLevel);
|
||||
m_lzCompParams.m_compress_flags = lzham_compress_flags::LZHAM_COMP_FLAG_DETERMINISTIC_PARSING;
|
||||
m_lzCompParams.m_max_helper_threads = fs_packedstore_max_helper_threads->GetInt();
|
||||
m_lzCompParams.m_max_helper_threads = maxHelperThreads;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -65,19 +65,17 @@ void CPackedStore::InitLzDecompParams(void)
|
||||
// Purpose: gets the LZHAM compression level
|
||||
// output : lzham_compress_level
|
||||
//-----------------------------------------------------------------------------
|
||||
lzham_compress_level CPackedStore::GetCompressionLevel(void) const
|
||||
lzham_compress_level CPackedStore::DetermineCompressionLevel(const char* compressionLevel) const
|
||||
{
|
||||
const char* pszLevel = fs_packedstore_compression_level->GetString();
|
||||
|
||||
if(strcmp(pszLevel, "fastest") == NULL)
|
||||
if(strcmp(compressionLevel, "fastest") == NULL)
|
||||
return lzham_compress_level::LZHAM_COMP_LEVEL_FASTEST;
|
||||
else if (strcmp(pszLevel, "faster") == NULL)
|
||||
else if (strcmp(compressionLevel, "faster") == NULL)
|
||||
return lzham_compress_level::LZHAM_COMP_LEVEL_FASTER;
|
||||
else if (strcmp(pszLevel, "default") == NULL)
|
||||
else if (strcmp(compressionLevel, "default") == NULL)
|
||||
return lzham_compress_level::LZHAM_COMP_LEVEL_DEFAULT;
|
||||
else if (strcmp(pszLevel, "better") == NULL)
|
||||
else if (strcmp(compressionLevel, "better") == NULL)
|
||||
return lzham_compress_level::LZHAM_COMP_LEVEL_BETTER;
|
||||
else if (strcmp(pszLevel, "uber") == NULL)
|
||||
else if (strcmp(compressionLevel, "uber") == NULL)
|
||||
return lzham_compress_level::LZHAM_COMP_LEVEL_UBER;
|
||||
else
|
||||
return lzham_compress_level::LZHAM_COMP_LEVEL_DEFAULT;
|
||||
@ -208,7 +206,9 @@ KeyValues* CPackedStore::GetManifest(const CUtlString& workspacePath, const CUtl
|
||||
CUtlString outPath;
|
||||
outPath.Format("%s%s%s.txt", workspacePath.Get(), "manifest/", manifestFile.Get());
|
||||
|
||||
KeyValues* pManifestKV = FileSystem()->LoadKeyValues(IFileSystem::TYPE_COMMON, outPath.Get(), "PLATFORM");
|
||||
KeyValues* pManifestKV = new KeyValues("BuildManifest");
|
||||
pManifestKV->LoadFromFile(FileSystem(), outPath.Get(), "PLATFORM");
|
||||
|
||||
return pManifestKV;
|
||||
}
|
||||
|
||||
@ -288,7 +288,6 @@ CUtlString CPackedStore::FormatEntryPath(const CUtlString& filePath,
|
||||
void CPackedStore::BuildManifest(const CUtlVector<VPKEntryBlock_t>& entryBlocks, const CUtlString& workspacePath, const CUtlString& manifestName) const
|
||||
{
|
||||
KeyValues kv("BuildManifest");
|
||||
KeyValues* pManifestKV = kv.FindKey("BuildManifest", true);
|
||||
|
||||
FOR_EACH_VEC(entryBlocks, i)
|
||||
{
|
||||
@ -301,7 +300,7 @@ void CPackedStore::BuildManifest(const CUtlVector<VPKEntryBlock_t>& entryBlocks,
|
||||
CUtlString entryPath = entry.m_EntryPath;
|
||||
entryPath.FixSlashes('\\');
|
||||
|
||||
KeyValues* pEntryKV = pManifestKV->FindKey(entryPath.Get(), true);
|
||||
KeyValues* pEntryKV = kv.FindKey(entryPath.Get(), true);
|
||||
|
||||
pEntryKV->SetInt("preloadSize", entry.m_iPreloadSize);
|
||||
pEntryKV->SetInt("loadFlags", descriptor.m_nLoadFlags);
|
||||
|
@ -196,10 +196,10 @@ struct VPKPair_t
|
||||
class CPackedStore
|
||||
{
|
||||
public:
|
||||
void InitLzCompParams(void);
|
||||
void InitLzCompParams(const char* compressionLevel = "default", const lzham_int32 maxHelperThreads = -1);
|
||||
void InitLzDecompParams(void);
|
||||
|
||||
lzham_compress_level GetCompressionLevel(void) const;
|
||||
lzham_compress_level DetermineCompressionLevel(const char* compressionLevel) const;
|
||||
|
||||
void GetEntryBlocks(CUtlVector<VPKEntryBlock_t>& entryBlocks, FileHandle_t hDirectoryFile) const;
|
||||
bool GetEntryValues(CUtlVector<VPKKeyValues_t>& entryValues, const CUtlString& workspacePath, const CUtlString& dirFileName) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user