Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
8.3 KiB

  1. //======== Copyright � 2011, Valve Corporation, All rights reserved. ========//
  2. //
  3. // Purpose: Helper functions for protobufs
  4. //
  5. //===========================================================================//
  6. #include "tier0/dbg.h"
  7. #include "google/protobuf/descriptor.h"
  8. #include "google/protobuf/reflection_ops.h"
  9. #include "google/protobuf/descriptor.pb.h"
  10. using namespace google::protobuf;
  11. //using namespace stl;
  12. class CProtobufLogHandler
  13. {
  14. public:
  15. CProtobufLogHandler()
  16. {
  17. google::protobuf::SetLogHandler( LogHandler );
  18. }
  19. ~CProtobufLogHandler()
  20. {
  21. google::protobuf::SetLogHandler( NULL );
  22. }
  23. static void LogHandler( google::protobuf::LogLevel level, const char* filename, int line, const std::string& message )
  24. {
  25. switch ( level )
  26. {
  27. case google::protobuf::LOGLEVEL_INFO:
  28. case google::protobuf::LOGLEVEL_WARNING:
  29. DevMsg( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
  30. break;
  31. case google::protobuf::LOGLEVEL_ERROR:
  32. Warning( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
  33. break;
  34. case google::protobuf::LOGLEVEL_FATAL:
  35. Warning( "Protobuf: %s(%d): %s\n", filename, line, message.c_str() );
  36. Plat_ExitProcess( 100 );
  37. break;
  38. }
  39. }
  40. };
  41. static CProtobufLogHandler g_ProtobufLogHandler;
  42. /*
  43. //----------------------------------------------------------------------------
  44. // Purpose: Copies a field into a third message if its different in the other messages
  45. //----------------------------------------------------------------------------
  46. bool ProtoBufDeltaMerge( const ::google::protobuf::Message &src, const ::google::protobuf::Message &delta, ::google::protobuf::Message* to )
  47. {
  48. const Descriptor* descriptor = src.GetDescriptor();
  49. if ( descriptor != delta.GetDescriptor() )
  50. {
  51. Warning( "Tried to merge delta to a src message of a different type.");
  52. return false;
  53. }
  54. if ( descriptor != to->GetDescriptor() )
  55. {
  56. Warning( "Tried to merge dleta to a message of a different type.");
  57. return false;
  58. }
  59. to->Clear();
  60. const Reflection* src_reflection = src.GetReflection();
  61. const Reflection* delta_reflection = delta.GetReflection();
  62. const Reflection* to_reflection = to->GetReflection();
  63. Assert( src_reflection == delta_reflection );
  64. Assert( src_reflection == to_reflection );
  65. vector<const FieldDescriptor*> fields;
  66. src_reflection->ListFields(src, &fields);
  67. for ( size_t i = 0; i < fields.size(); i++ )
  68. {
  69. const FieldDescriptor* field = fields[i];
  70. // We can't really delta repeated fields, it sucks
  71. if ( field->is_repeated() )
  72. {
  73. int count = delta_reflection->FieldSize(delta, field);
  74. to_reflection->ClearField( to, field );
  75. for ( int j = 0; j < count; j++ )
  76. {
  77. switch ( field->cpp_type() )
  78. {
  79. #define HANDLE_TYPE(CPPTYPE, METHOD) \
  80. case FieldDescriptor::CPPTYPE_##CPPTYPE: \
  81. to_reflection->Add##METHOD(to, field, delta_reflection->GetRepeated##METHOD(delta, field, j)); \
  82. break;
  83. HANDLE_TYPE(INT32 , Int32 );
  84. HANDLE_TYPE(INT64 , Int64 );
  85. HANDLE_TYPE(UINT32, UInt32);
  86. HANDLE_TYPE(UINT64, UInt64);
  87. HANDLE_TYPE(FLOAT , Float );
  88. HANDLE_TYPE(DOUBLE, Double);
  89. HANDLE_TYPE(BOOL , Bool );
  90. HANDLE_TYPE(STRING, String);
  91. HANDLE_TYPE(ENUM , Enum );
  92. #undef HANDLE_TYPE
  93. case FieldDescriptor::CPPTYPE_MESSAGE:
  94. // We can recurse this!
  95. Message *to_element = to_reflection->AddMessage( to, field );
  96. if ( !ProtoBufDeltaMerge( src_reflection->GetRepeatedMessage( src, field, j ), delta_reflection->GetRepeatedMessage( delta, field, j ), to_element ) )
  97. return false;
  98. break;
  99. }
  100. }
  101. }
  102. else
  103. {
  104. switch ( field->cpp_type() )
  105. {
  106. #define HANDLE_TYPE(CPPTYPE, METHOD) \
  107. case FieldDescriptor::CPPTYPE_##CPPTYPE: \
  108. if ( delta_reflection->HasField( delta, field ) ) \
  109. { \
  110. to_reflection->Set##METHOD( to, field, delta_reflection->Get##METHOD( delta, field ) ); \
  111. } \
  112. else \
  113. { \
  114. if ( src_reflection->HasField( src, field ) ) \
  115. { \
  116. to_reflection->Set##METHOD( to, field, src_reflection->Get##METHOD( delta, field ) ); \
  117. } \
  118. else \
  119. { \
  120. to_reflection->ClearField( to, field ); \
  121. } \
  122. } \
  123. break;
  124. HANDLE_TYPE(INT32 , Int32 );
  125. HANDLE_TYPE(INT64 , Int64 );
  126. HANDLE_TYPE(UINT32, UInt32);
  127. HANDLE_TYPE(UINT64, UInt64);
  128. HANDLE_TYPE(FLOAT , Float );
  129. HANDLE_TYPE(DOUBLE, Double);
  130. HANDLE_TYPE(BOOL , Bool );
  131. HANDLE_TYPE(STRING, String);
  132. HANDLE_TYPE(ENUM , Enum );
  133. #undef HANDLE_TYPE
  134. case FieldDescriptor::CPPTYPE_MESSAGE:
  135. Message *to_element = to_reflection->MutableMessage( to, field );
  136. if ( delta_reflection->HasField( delta, field ) )
  137. {
  138. if ( !ProtoBufDeltaMerge( src_reflection->GetMessage( src, field ), delta_reflection->GetMessage( delta, field ), to_element ) )
  139. return false;
  140. }
  141. else
  142. {
  143. if ( src_reflection->HasField( src, field ) ) \
  144. {
  145. to_element->Clear();
  146. to_element->MergeFrom( src_reflection->GetMessage( src, field ) );
  147. }
  148. else
  149. {
  150. to_reflection->ClearField( to, field );
  151. }
  152. }
  153. break;
  154. }
  155. }
  156. }
  157. return true;
  158. }
  159. bool ProtoBufCalcDelta( const ::google::protobuf::Message &src, const ::google::protobuf::Message &dest, ::google::protobuf::Message *delta )
  160. {
  161. const Descriptor* descriptor = src.GetDescriptor();
  162. if ( descriptor != dest.GetDescriptor() )
  163. {
  164. Warning( "Tried to calc delta to a src message of a different type.");
  165. return false;
  166. }
  167. if ( descriptor != delta->GetDescriptor() )
  168. {
  169. Warning( "Tried to calc delta to a message of a different type.");
  170. return false;
  171. }
  172. delta->Clear();
  173. const Reflection* src_reflection = src.GetReflection();
  174. const Reflection* dest_reflection = dest.GetReflection();
  175. const Reflection* delta_reflection = delta->GetReflection();
  176. Assert( src_reflection == dest_reflection );
  177. Assert( src_reflection == delta_reflection );
  178. vector<const FieldDescriptor*> fields;
  179. src_reflection->ListFields(src, &fields);
  180. for ( size_t i = 0; i < fields.size(); i++ )
  181. {
  182. const FieldDescriptor* field = fields[i];
  183. // We can't really delta repeated fields, it sucks
  184. if ( field->is_repeated() )
  185. {
  186. int count = dest_reflection->FieldSize(dest, field);
  187. delta_reflection->ClearField( delta, field );
  188. for ( int j = 0; j < count; j++ )
  189. {
  190. switch ( field->cpp_type() )
  191. {
  192. #define HANDLE_TYPE(CPPTYPE, METHOD) \
  193. case FieldDescriptor::CPPTYPE_##CPPTYPE: \
  194. delta_reflection->Add##METHOD(delta, field, dest_reflection->GetRepeated##METHOD(dest, field, j)); \
  195. break;
  196. HANDLE_TYPE(INT32 , Int32 );
  197. HANDLE_TYPE(INT64 , Int64 );
  198. HANDLE_TYPE(UINT32, UInt32);
  199. HANDLE_TYPE(UINT64, UInt64);
  200. HANDLE_TYPE(FLOAT , Float );
  201. HANDLE_TYPE(DOUBLE, Double);
  202. HANDLE_TYPE(BOOL , Bool );
  203. HANDLE_TYPE(STRING, String);
  204. HANDLE_TYPE(ENUM , Enum );
  205. #undef HANDLE_TYPE
  206. case FieldDescriptor::CPPTYPE_MESSAGE:
  207. // We can recurse this!
  208. Message *delta_element = delta_reflection->AddMessage( delta, field );
  209. if ( !ProtoBufCalcDelta( src_reflection->GetRepeatedMessage( src, field, j ), dest_reflection->GetRepeatedMessage( dest, field, j ), delta_element ) )
  210. return false;
  211. break;
  212. }
  213. }
  214. }
  215. else
  216. {
  217. switch ( field->cpp_type() )
  218. {
  219. #define HANDLE_TYPE(CPPTYPE, METHOD) \
  220. case FieldDescriptor::CPPTYPE_##CPPTYPE: \
  221. if ( dest_reflection->HasField( dest, field ) ) \
  222. { \
  223. if ( !src_reflection->HasField( src, field ) || \
  224. src_reflection->Get##METHOD( src, field ) != dest_reflection->Get##METHOD( dest, field ) ) \
  225. { \
  226. delta_reflection->Set##METHOD( delta, field, dest_reflection->Get##METHOD( dest, field ) ); \
  227. } \
  228. } \
  229. else \
  230. { \
  231. if ( src_reflection->HasField( src, field ) ) \
  232. { \
  233. delta_reflection->Set##METHOD( delta, field, dest_reflection->Get##METHOD( dest, field ) ); \
  234. } \
  235. } \
  236. break;
  237. HANDLE_TYPE(INT32 , Int32 );
  238. HANDLE_TYPE(INT64 , Int64 );
  239. HANDLE_TYPE(UINT32, UInt32);
  240. HANDLE_TYPE(UINT64, UInt64);
  241. HANDLE_TYPE(FLOAT , Float );
  242. HANDLE_TYPE(DOUBLE, Double);
  243. HANDLE_TYPE(BOOL , Bool );
  244. HANDLE_TYPE(STRING, String);
  245. HANDLE_TYPE(ENUM , Enum );
  246. #undef HANDLE_TYPE
  247. case FieldDescriptor::CPPTYPE_MESSAGE:
  248. Message *delta_element = delta_reflection->MutableMessage( delta, field );
  249. if ( !ProtoBufCalcDelta( src_reflection->GetMessage( src, field ), dest_reflection->GetMessage( dest, field ), delta_element ) )
  250. return false;
  251. break;
  252. }
  253. }
  254. }
  255. return true;
  256. }
  257. */