csgo-2018-source/common/protobuf_helpers.cpp
2021-07-24 21:11:47 -07:00

300 lines
8.3 KiB
C++

//======== Copyright © 2011, Valve Corporation, All rights reserved. ========//
//
// Purpose: Helper functions for protobufs
//
//===========================================================================//
#include "tier0/dbg.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/reflection_ops.h"
#include "google/protobuf/descriptor.pb.h"
using namespace google::protobuf;
//using namespace stl;
class CProtobufLogHandler
{
public:
CProtobufLogHandler()
{
google::protobuf::SetLogHandler( LogHandler );
}
~CProtobufLogHandler()
{
google::protobuf::SetLogHandler( NULL );
}
static void LogHandler( google::protobuf::LogLevel level, const char* filename, int line, const std::string& message )
{
switch ( level )
{
case google::protobuf::LOGLEVEL_INFO:
case google::protobuf::LOGLEVEL_WARNING:
DevMsg( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
break;
case google::protobuf::LOGLEVEL_ERROR:
Warning( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
break;
case google::protobuf::LOGLEVEL_FATAL:
Warning( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
Plat_ExitProcess( 100 );
break;
}
}
};
static CProtobufLogHandler g_ProtobufLogHandler;
/*
//----------------------------------------------------------------------------
// Purpose: Copies a field into a third message if its different in the other messages
//----------------------------------------------------------------------------
bool ProtoBufDeltaMerge( const ::google::protobuf::Message &src, const ::google::protobuf::Message &delta, ::google::protobuf::Message* to )
{
const Descriptor* descriptor = src.GetDescriptor();
if ( descriptor != delta.GetDescriptor() )
{
Warning( "Tried to merge delta to a src message of a different type.");
return false;
}
if ( descriptor != to->GetDescriptor() )
{
Warning( "Tried to merge dleta to a message of a different type.");
return false;
}
to->Clear();
const Reflection* src_reflection = src.GetReflection();
const Reflection* delta_reflection = delta.GetReflection();
const Reflection* to_reflection = to->GetReflection();
Assert( src_reflection == delta_reflection );
Assert( src_reflection == to_reflection );
vector<const FieldDescriptor*> fields;
src_reflection->ListFields(src, &fields);
for ( size_t i = 0; i < fields.size(); i++ )
{
const FieldDescriptor* field = fields[i];
// We can't really delta repeated fields, it sucks
if ( field->is_repeated() )
{
int count = delta_reflection->FieldSize(delta, field);
to_reflection->ClearField( to, field );
for ( int j = 0; j < count; j++ )
{
switch ( field->cpp_type() )
{
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
to_reflection->Add##METHOD(to, field, delta_reflection->GetRepeated##METHOD(delta, field, j)); \
break;
HANDLE_TYPE(INT32 , Int32 );
HANDLE_TYPE(INT64 , Int64 );
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(FLOAT , Float );
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL , Bool );
HANDLE_TYPE(STRING, String);
HANDLE_TYPE(ENUM , Enum );
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
// We can recurse this!
Message *to_element = to_reflection->AddMessage( to, field );
if ( !ProtoBufDeltaMerge( src_reflection->GetRepeatedMessage( src, field, j ), delta_reflection->GetRepeatedMessage( delta, field, j ), to_element ) )
return false;
break;
}
}
}
else
{
switch ( field->cpp_type() )
{
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
if ( delta_reflection->HasField( delta, field ) ) \
{ \
to_reflection->Set##METHOD( to, field, delta_reflection->Get##METHOD( delta, field ) ); \
} \
else \
{ \
if ( src_reflection->HasField( src, field ) ) \
{ \
to_reflection->Set##METHOD( to, field, src_reflection->Get##METHOD( delta, field ) ); \
} \
else \
{ \
to_reflection->ClearField( to, field ); \
} \
} \
break;
HANDLE_TYPE(INT32 , Int32 );
HANDLE_TYPE(INT64 , Int64 );
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(FLOAT , Float );
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL , Bool );
HANDLE_TYPE(STRING, String);
HANDLE_TYPE(ENUM , Enum );
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
Message *to_element = to_reflection->MutableMessage( to, field );
if ( delta_reflection->HasField( delta, field ) )
{
if ( !ProtoBufDeltaMerge( src_reflection->GetMessage( src, field ), delta_reflection->GetMessage( delta, field ), to_element ) )
return false;
}
else
{
if ( src_reflection->HasField( src, field ) ) \
{
to_element->Clear();
to_element->MergeFrom( src_reflection->GetMessage( src, field ) );
}
else
{
to_reflection->ClearField( to, field );
}
}
break;
}
}
}
return true;
}
bool ProtoBufCalcDelta( const ::google::protobuf::Message &src, const ::google::protobuf::Message &dest, ::google::protobuf::Message *delta )
{
const Descriptor* descriptor = src.GetDescriptor();
if ( descriptor != dest.GetDescriptor() )
{
Warning( "Tried to calc delta to a src message of a different type.");
return false;
}
if ( descriptor != delta->GetDescriptor() )
{
Warning( "Tried to calc delta to a message of a different type.");
return false;
}
delta->Clear();
const Reflection* src_reflection = src.GetReflection();
const Reflection* dest_reflection = dest.GetReflection();
const Reflection* delta_reflection = delta->GetReflection();
Assert( src_reflection == dest_reflection );
Assert( src_reflection == delta_reflection );
vector<const FieldDescriptor*> fields;
src_reflection->ListFields(src, &fields);
for ( size_t i = 0; i < fields.size(); i++ )
{
const FieldDescriptor* field = fields[i];
// We can't really delta repeated fields, it sucks
if ( field->is_repeated() )
{
int count = dest_reflection->FieldSize(dest, field);
delta_reflection->ClearField( delta, field );
for ( int j = 0; j < count; j++ )
{
switch ( field->cpp_type() )
{
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
delta_reflection->Add##METHOD(delta, field, dest_reflection->GetRepeated##METHOD(dest, field, j)); \
break;
HANDLE_TYPE(INT32 , Int32 );
HANDLE_TYPE(INT64 , Int64 );
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(FLOAT , Float );
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL , Bool );
HANDLE_TYPE(STRING, String);
HANDLE_TYPE(ENUM , Enum );
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
// We can recurse this!
Message *delta_element = delta_reflection->AddMessage( delta, field );
if ( !ProtoBufCalcDelta( src_reflection->GetRepeatedMessage( src, field, j ), dest_reflection->GetRepeatedMessage( dest, field, j ), delta_element ) )
return false;
break;
}
}
}
else
{
switch ( field->cpp_type() )
{
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
if ( dest_reflection->HasField( dest, field ) ) \
{ \
if ( !src_reflection->HasField( src, field ) || \
src_reflection->Get##METHOD( src, field ) != dest_reflection->Get##METHOD( dest, field ) ) \
{ \
delta_reflection->Set##METHOD( delta, field, dest_reflection->Get##METHOD( dest, field ) ); \
} \
} \
else \
{ \
if ( src_reflection->HasField( src, field ) ) \
{ \
delta_reflection->Set##METHOD( delta, field, dest_reflection->Get##METHOD( dest, field ) ); \
} \
} \
break;
HANDLE_TYPE(INT32 , Int32 );
HANDLE_TYPE(INT64 , Int64 );
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(FLOAT , Float );
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL , Bool );
HANDLE_TYPE(STRING, String);
HANDLE_TYPE(ENUM , Enum );
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
Message *delta_element = delta_reflection->MutableMessage( delta, field );
if ( !ProtoBufCalcDelta( src_reflection->GetMessage( src, field ), dest_reflection->GetMessage( dest, field ), delta_element ) )
return false;
break;
}
}
}
return true;
}
*/