├── CMakeLists.txt ├── ProtobufHelper.cpp ├── ProtobufHelper.h ├── README.md └── test.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | project(ParsePb) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | if (MSVC) 7 | add_compile_options( 8 | $<$:/MT> #---------| 9 | $<$:/MTd> #---|-- Statically link the runtime libraries 10 | $<$:/MT> #--| 11 | ) 12 | add_compile_options(/EHsc) 13 | endif () 14 | add_compile_options("$<$:/utf-8>") 15 | add_compile_options("$<$:/utf-8>") 16 | 17 | include(FetchContent) 18 | 19 | FetchContent_Declare(googletest 20 | GIT_REPOSITORY https://github.com/google/googletest.git 21 | GIT_TAG v1.12.0 22 | ) 23 | FETCHCONTENT_GETPROPERTIES(googletest) 24 | if (NOT googletest_POPULATED) 25 | 26 | FETCHCONTENT_POPULATE(googletest) 27 | MESSAGE("-> ${googletest_SOURCE_DIR}") 28 | MESSAGE("-> ${googletest_BUILD_DIR}") 29 | add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BUILD_DIR}) 30 | endif () 31 | 32 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 33 | 34 | FetchContent_Declare(nlohmann_json 35 | GIT_REPOSITORY https://github.com/nlohmann/json.git 36 | GIT_TAG v3.11.2 37 | ) 38 | set(protobuf_BUILD_TESTS OFF) 39 | set(protobuf_WITH_ZLIB OFF) 40 | set(protobuf_USE_EXTERNAL_GTEST ON) 41 | set(ABSL_PROPAGATE_CXX_STD ON) 42 | FetchContent_MakeAvailable(nlohmann_json) 43 | 44 | 45 | FetchContent_Declare(protobuf 46 | GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git 47 | GIT_TAG v23.2) 48 | FetchContent_MakeAvailable(protobuf) 49 | 50 | 51 | add_executable(${PROJECT_NAME} 52 | ProtobufHelper.cpp 53 | ProtobufHelper.h 54 | test.cpp 55 | ) 56 | 57 | MESSAGE("11-> ${googlemock_source_dir}") 58 | target_include_directories(${PROJECT_NAME} PRIVATE 59 | ${GOOGLETEST_INCLUDE_DIR} 60 | ) 61 | 62 | 63 | get_cmake_property(_variableNames VARIABLES) 64 | foreach(_variableName ${_variableNames}) 65 | if(_variableName MATCHES "^protobuf_.*") 66 | message("${_variableName} = ${${_variableName}}") 67 | endif() 68 | endforeach() 69 | 70 | target_link_libraries(${PROJECT_NAME} nlohmann_json protobuf::libprotobuf gmock_main gtest ) 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /ProtobufHelper.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 28264 on 2023/5/27. 3 | // 4 | 5 | #include "ProtobufHelper.h" 6 | 7 | 8 | #define TAG_TYPE_BITS 3 //Number of bits used to hold type info in a proto tag. 9 | #define TAG_TYPE_MASK (1 << TAG_TYPE_BITS) - 1 //0x7 10 | 11 | using namespace google::protobuf; 12 | using JSON_Type = nlohmann::detail::value_t; 13 | 14 | unsigned long getULongTimeStmp(){ 15 | auto now = std::chrono::system_clock::now(); 16 | auto timestamp = std::chrono::duration_cast(now.time_since_epoch()).count(); 17 | unsigned long timestamp_ull = static_cast(timestamp); 18 | 19 | return timestamp_ull; 20 | 21 | } 22 | //shared_ptr ProtobufHelper::newMsg(uint32_t& pb_len) { 23 | // 24 | // tutorial::NewSendMsgRequest request; 25 | // request.set_cnt(1); 26 | // 27 | // tutorial::ChatInfo* chatInfo = request.mutable_info(); 28 | // chatInfo->set_client_msg_id(getULongTimeStmp()); 29 | // chatInfo->set_content("121212"); 30 | // chatInfo->set_utc(getULongTimeStmp()); 31 | // chatInfo->set_type(1); 32 | // chatInfo->set_msg_source(""); 33 | // 34 | // tutorial::wxid* toId = chatInfo->mutable_toid(); 35 | // toId->set_toid("wxid_4zr616ir6fi122"); 36 | // 37 | // std::string string_ret = request.SerializeAsString(); 38 | // 39 | // std::vector bytes(string_ret.begin(), string_ret.end()); 40 | // 41 | // pb_len=bytes.size(); 42 | // 43 | // auto buff = std::make_shared(pb_len); 44 | // memcpy(buff.get(), bytes.data(), pb_len); 45 | // 46 | // 47 | // return buff; 48 | //} 49 | string byte2string(const std::uint8_t *buf, std::size_t buf_size) { 50 | std::ostringstream oss; 51 | oss << std::hex << std::setfill('0'); 52 | for (std::size_t i = 0; i < buf_size; i++) { 53 | oss << std::setw(2) << static_cast(buf[i]); 54 | } 55 | return oss.str(); 56 | } 57 | 58 | bool is_utf8(const uint8_t* hex,uint32_t size) { 59 | uint32_t index=0; 60 | do { 61 | int tmp_index=0; 62 | uint8_t By_te=hex[index++]; 63 | auto tmp_flag=By_te & 0b11110000; 64 | bool one_byte_flag= false; 65 | if(!(tmp_flag>>7)){ 66 | tmp_index=1; 67 | one_byte_flag= true; 68 | }else{ 69 | switch (tmp_flag) { 70 | case 0b11000000:{//2字节 71 | tmp_index=2-1; 72 | break; 73 | } 74 | case 0b11100000:{//3字节 75 | tmp_index=3-1; 76 | break; 77 | } 78 | case 0b11110000:{//4字节 79 | tmp_index=4-1; 80 | break; 81 | } 82 | } 83 | } 84 | while (tmp_index>0){ 85 | // 0x9 \t 86 | // 0xA \r 87 | // 0xD \n 88 | if(one_byte_flag && By_te !=0x9 && By_te !=0xA && By_te!=0xD && By_te<=0x1f && By_te!='\0'){ 89 | return false; 90 | } 91 | if(tmp_index==1 && !one_byte_flag){ 92 | By_te=hex[index++]; 93 | if(By_te<=0x1f || (By_te & 0b10000000) != 0b10000000) return false;//变长的最后一个字节的最高位为10 94 | }else if(!one_byte_flag){ 95 | By_te=hex[index++]; 96 | if ( !(By_te & 0b10000000)){ 97 | return false; 98 | } 99 | } 100 | tmp_index--; 101 | } 102 | 103 | 104 | } while (index(data[i]); 111 | } 112 | return ss.str(); 113 | } 114 | /// 此函数经AI 优化 115 | /// \tparam T 116 | /// \param parent_index_str 父级的key 117 | /// \param childJson 解析为子json的时候才设置 118 | /// \param json 最顶级json 119 | /// \param is_child 是否是子节点 120 | /// \param parent_node 父节点 121 | /// \param no_json_value 非json类型的值 122 | /// \param is_json 判断是否是json类型的值 123 | //template 124 | //void addToJson(JSON& target, const std::string& key, T&& value) { 125 | // if (target.find(key) != target.end()) { 126 | // if (target[key].is_array()) { 127 | // target[key].push_back(std::forward(value)); 128 | // } else { 129 | // JSON newArray; 130 | // newArray.push_back(std::move(target[key])); 131 | // newArray.push_back(std::forward(value)); 132 | // target[key] = std::move(newArray); 133 | // } 134 | // } else { 135 | // target[key] = std::forward(value); 136 | // } 137 | //} 138 | // 139 | //void setJsonData(std::string& parent_index_str, JSON* childJson, JSON& json, 140 | // bool is_child, JSON* parent_node, bool is_json = false) { 141 | // JSON* targetJson = is_child ? parent_node : &json; 142 | // if (is_json && childJson != nullptr) { 143 | // addToJson(*targetJson, parent_index_str, std::move(*childJson)); 144 | // } else { 145 | // auto no_json_value = nullptr; 146 | // addToJson(*targetJson, parent_index_str, std::move(no_json_value)); 147 | // } 148 | //} 149 | 150 | template 151 | void setJsonData(std::string& parent_index_str,JSON* childJson, JSON& json,bool is_child,JSON* parent_node,T no_json_value= nullptr,bool is_json= false){ 152 | if (is_child){ 153 | if(is_json && childJson!= nullptr){ //子节点 json返回值 154 | if(parent_node->find(parent_index_str)!=parent_node->end()){ //如果这个key重复了,说明这个字段是repeat 155 | if ((*parent_node)[parent_index_str].is_array()) { 156 | (*parent_node)[parent_index_str].push_back(std::move(*childJson)); 157 | } else { 158 | JSON newArray; 159 | newArray.push_back(std::move((*parent_node)[parent_index_str])); 160 | newArray.push_back(std::move(*childJson)); 161 | (*parent_node)[parent_index_str] = std::move(newArray); 162 | } 163 | }else{ 164 | (*parent_node)[parent_index_str]=*childJson; 165 | } 166 | }else{ //子节点 非json值 //不是json值的话 就是普通的值 uint64_t uint32_t 167 | if (parent_node->find(parent_index_str)!=parent_node->end()){ 168 | 169 | if (parent_node->find(parent_index_str)->is_array()){ //不是arry 就重新设置为arry 170 | (*parent_node)[parent_index_str].push_back(std::move(no_json_value)); 171 | }else{ //不是arry 就重新设置为arry 172 | JSON newArray; 173 | newArray.push_back(std::move((*parent_node)[parent_index_str])); 174 | newArray.push_back(std::move(no_json_value)); 175 | (*parent_node)[parent_index_str] = std::move(newArray); 176 | } 177 | }else{ 178 | (*parent_node)[parent_index_str]=std::move(no_json_value); 179 | } 180 | } 181 | }else{ //非子节点 直接操作顶级json 182 | 183 | if(is_json && childJson!= nullptr) { //子节点 而且设置的值为json 184 | if(json.find(parent_index_str)!=json.end()){ 185 | if (json[parent_index_str].is_array()) { //如果是arry的话直接往里存 186 | json[parent_index_str].push_back(*childJson); 187 | } else { //不是arry就修改成arry 在放入值 188 | JSON newArray; 189 | newArray.push_back(std::move(json[parent_index_str])); 190 | newArray.push_back(std::move(*childJson)); 191 | json[parent_index_str] = std::move(newArray); 192 | } 193 | }else{ 194 | json[parent_index_str]=std::move(*childJson); 195 | } 196 | }else{ //非json返回值 197 | if(json.find(parent_index_str)!=json.end()){ 198 | if (json.find(parent_index_str)->is_array()){ //arry的话直接push 199 | json[parent_index_str].push_back(std::move(no_json_value)); 200 | }else{ //不是arry就要设置为arry 201 | JSON newArray; 202 | newArray.push_back(std::move(json[parent_index_str])); 203 | newArray.push_back(std::move(no_json_value)); 204 | json[parent_index_str] = std::move(newArray); 205 | } 206 | }else{ 207 | json[parent_index_str]=std::move(no_json_value); 208 | } 209 | } 210 | } 211 | 212 | 213 | } 214 | 215 | bool ProtobufHelper::parse_pb(std::uint8_t *pb_data, std::uint32_t pb_len,JSON& json,bool is_child,JSON* parent_node){ 216 | google::protobuf::io::ArrayInputStream raw_input(pb_data,pb_len); 217 | google::protobuf::io::CodedInputStream input(&raw_input); 218 | while (true){ 219 | auto tag=input.ReadTag(); 220 | if (tag==0) return true; 221 | auto Wire_Type =internal::WireFormatLite::GetTagWireType(tag); 222 | int field_number = internal::WireFormatLite::GetTagFieldNumber(tag); 223 | if(!field_number) return false; 224 | switch (Wire_Type) { 225 | case internal::WireFormatLite::WIRETYPE_START_GROUP :{//reptead 字段会使用这个作为开始 226 | return false; 227 | } 228 | case internal::WireFormatLite::WIRETYPE_END_GROUP :{//End-Group类型的字段,标识一个消息组的结束。 229 | return false; 230 | } 231 | case internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED:{//Length-Delimited类型的字段,使用长度前缀编码表示长度可变的字符串、字节数组和嵌套消息。 232 | std::uint32_t lenght=0x0; 233 | if(!input.ReadVarint32(&lenght)){ 234 | return false; 235 | } 236 | if (lenght>pb_len) return false; 237 | std::string str; 238 | input.ReadString(&str,lenght); 239 | 240 | if (lenght>2){ //去掉可能是tag的第一个字节 241 | std::string parent_index_str=std::to_string(field_number); 242 | const std::uint8_t * check_ptr= (std::uint8_t *)str.c_str(); 243 | // const char *message= nullptr; 244 | int faulty_bytes = 0; 245 | check_ptr=check_ptr+1; 246 | // std::uint32_t is_utf8_ret=is_utf8(check_ptr,lenght-1,&message,&faulty_bytes); 247 | bool is_utf8_ret=is_utf8(check_ptr,lenght-1); 248 | if (is_utf8_ret){ //检测到就是字符串直接当字符串处理 249 | 250 | str= to_utf8_string((uint8*)str.c_str(),str.size()); 251 | setJsonData(parent_index_str, nullptr,json,is_child,parent_node, str, true); 252 | break; 253 | } 254 | std::uint32_t first_byte=str[0]; 255 | std::uint32_t child_wire=first_byte & 0b111; 256 | std::uint32_t child_field_num=first_byte >>3; 257 | 258 | // if (first_Byte==0x8 || str[0]==0xA || str[0]==0xD || str[0]==0x12){ //长度大于2才可能是嵌套类型 tag需要一个字节 后面一个字节的值 259 | if (child_wire <= internal::WireFormatLite::WIRETYPE_FIXED32 260 | && child_wire!=internal::WireFormatLite::WIRETYPE_START_GROUP 261 | && child_wire!=internal::WireFormatLite::WIRETYPE_END_GROUP 262 | && child_field_num < 0b1111 //field_num 0b1111 0xf 认为是最大的pb的起始字段号 263 | ){ //长度大于2才可能是嵌套类型 tag需要一个字节 后面一个字节的值 264 | 265 | JSON childJson={}; 266 | bool parse_sub_succ= parse_pb((uint8_t *) str.c_str(), str.size(),json,true,&childJson); 267 | if (parse_sub_succ){ 268 | setJsonData(parent_index_str, &childJson,json,is_child,parent_node, 0, true); 269 | break; 270 | } 271 | string strsss=json.dump(); 272 | //继续执行到下面的unhandle_content 273 | } 274 | goto unhandle_content; 275 | }else{ //长度小于2 还不是string和嵌套类型,无法解析 直接把内容返回 276 | //repeat int32 和 bytes无法区分 277 | unhandle_content: 278 | std::string string_hex =byte2string((std::uint8_t *)str.c_str(),str.size()); 279 | if(is_child){ //如果是嵌套类型的数据 放到父级下面 280 | (*parent_node)[std::to_string(field_number)]=string_hex; 281 | }else{ 282 | json[std::to_string(field_number)]=string_hex; 283 | } 284 | break; 285 | } 286 | break; 287 | } 288 | case internal::WireFormatLite::WIRETYPE_FIXED64:{ 289 | std::uint64_t value=0x0; 290 | // input.ReadVarint64(&value); 291 | input.ReadLittleEndian64(&value); 292 | std::string parent_index_str=std::to_string(field_number); 293 | setJsonData(parent_index_str, nullptr,json,is_child,parent_node,value,true); 294 | break; 295 | } 296 | case internal::WireFormatLite::WIRETYPE_VARINT:{ 297 | std::uint64_t value=0x0; 298 | input.ReadVarint64(&value); 299 | std::string parent_index_str=std::to_string(field_number); 300 | setJsonData(parent_index_str, nullptr,json,is_child,parent_node,value,true); 301 | break; 302 | } 303 | case internal::WireFormatLite::WIRETYPE_FIXED32:{ 304 | std::uint32_t value=0x0; 305 | input.ReadLittleEndian32(&value); 306 | std::string parent_index_str=std::to_string(field_number); 307 | setJsonData(parent_index_str, nullptr,json,is_child,parent_node,value,true); 308 | break; 309 | } 310 | default:{ 311 | return false; 312 | } 313 | } 314 | } 315 | } 316 | ProtobufHelper::ProtobufHelper() { 317 | 318 | 319 | } 320 | 321 | 322 | enum fix_num : std::uint8_t{ 323 | no_fix =0, 324 | fix32_num =1, 325 | fix64_num =2, 326 | }; 327 | enum parent_type : std::uint8_t { 328 | from_null =0, 329 | from_arry = 1, 330 | from_object =2 , 331 | }; 332 | /// 设置json数据到pb buffer 333 | /// \param output 334 | /// \param value 335 | /// \param fix_type 336 | /// \param p_type 337 | void setPbData(google::protobuf::io::CodedOutputStream& output,JSON& value,fix_num fix_type = fix_num::no_fix, parent_type p_type=parent_type::from_null){ 338 | switch (p_type) { 339 | case parent_type::from_arry:{ //arry 类型 340 | switch(fix_type){ 341 | case fix_num::no_fix:{ 342 | auto real_value=value.get(); 343 | output.WriteVarint32(real_value); 344 | break; 345 | } 346 | case fix_num::fix32_num:{ 347 | auto real_value=value.get(); 348 | output.WriteLittleEndian32(real_value); 349 | break; 350 | } 351 | case fix_num::fix64_num:{ 352 | auto real_value=value.get(); 353 | output.WriteLittleEndian64(real_value); 354 | break; 355 | } 356 | } 357 | break; 358 | } 359 | } 360 | 361 | 362 | } 363 | //enum class value_t : std::uint8_t 364 | //{ 365 | // null, ///< null value 366 | // object, ///< object (unordered set of name/value pairs) 367 | // array, ///< array (ordered collection of values) 368 | // string, ///< string value 369 | // boolean, ///< boolean value 370 | // number_integer, ///< number value (signed integer) 371 | // number_unsigned, ///< number value (unsigned integer) 372 | // number_float, ///< number value (floating-point) 373 | // binary, ///< binary array (ordered collection of bytes) 374 | // discarded ///< discarded by the parser callback function 375 | //}; 376 | 377 | std::uint32_t ProtobufHelper::json2pb(JSON& input_json,std::uint8_t* pb_data,std::uint32_t pb_buff_size,std::uint32_t arry_field_num) { 378 | google::protobuf::io::ArrayOutputStream raw_output(pb_data,pb_buff_size); 379 | google::protobuf::io::CodedOutputStream output(&raw_output); 380 | 381 | fix_num fix_type=no_fix; 382 | 383 | if (input_json.begin().value().is_string() && arry_field_num!=0){//arry 下fix 类型的设置 384 | std::uint32_t total_byte_size=0x0; 385 | std::string begin_value=input_json.begin().value().get(); 386 | if(begin_value=="fix32_num") { 387 | fix_type=fix32_num; 388 | input_json.erase(input_json.begin()); 389 | total_byte_size=input_json.size()*4; 390 | }else if(begin_value=="fix64_num"){ 391 | fix_type=fix64_num; 392 | input_json.erase(input_json.begin()); 393 | total_byte_size=input_json.size()*8; 394 | } 395 | if( fix_type!=no_fix){ 396 | std::uint32_t tag=internal::WireFormatLite::MakeTag(arry_field_num,internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); 397 | output.WriteTag(tag); 398 | output.WriteVarint32(total_byte_size); 399 | } 400 | } 401 | 402 | 403 | for ( auto const& [key, value]: input_json.items()) { 404 | 405 | switch (value.type()) { 406 | case JSON_Type::number_integer: 407 | case JSON_Type::number_float: 408 | case JSON_Type::number_unsigned:{ 409 | 410 | // setPbData(output,value,fix_type); 411 | switch(fix_type){ 412 | case fix_num::no_fix:{ 413 | uint32_t tag=0x0; 414 | if(arry_field_num!=0){ 415 | tag=internal::WireFormatLite::MakeTag(arry_field_num,internal::WireFormatLite::WIRETYPE_VARINT); 416 | }else{ 417 | tag=internal::WireFormatLite::MakeTag(std::atoi(key.c_str()),internal::WireFormatLite::WIRETYPE_VARINT); 418 | } 419 | output.WriteTag(tag); 420 | auto real_value=value.get(); 421 | output.WriteVarint64(real_value); 422 | break; 423 | } 424 | case fix_num::fix32_num:{ 425 | auto real_value=value.get(); 426 | output.WriteLittleEndian32(real_value); 427 | break; 428 | } 429 | case fix_num::fix64_num:{ 430 | auto real_value=value.get(); 431 | output.WriteLittleEndian64(real_value); 432 | break; 433 | } 434 | } 435 | 436 | break; 437 | } 438 | case JSON_Type::object:{ 439 | if(!value.empty() ){//fix 类型的值以对象的的形式传入 440 | auto begin_key=value.begin().key(); 441 | if(begin_key=="fix32_num"){ 442 | 443 | uint32_t tag=0x0; 444 | if(arry_field_num!=0){ 445 | tag=internal::WireFormatLite::MakeTag(arry_field_num,internal::WireFormatLite::WIRETYPE_FIXED32); 446 | }else{ 447 | tag=internal::WireFormatLite::MakeTag(std::atoi(key.c_str()),internal::WireFormatLite::WIRETYPE_FIXED32); 448 | } 449 | output.WriteTag(tag); 450 | auto real_value=value.begin().value().get(); 451 | output.WriteLittleEndian32(real_value); 452 | break; 453 | }else if(begin_key=="fix64_num"){ 454 | uint32_t tag=0x0; 455 | if(arry_field_num!=0){ 456 | tag=internal::WireFormatLite::MakeTag(arry_field_num,internal::WireFormatLite::WIRETYPE_FIXED64); 457 | }else{ 458 | tag=internal::WireFormatLite::MakeTag(std::atoi(key.c_str()),internal::WireFormatLite::WIRETYPE_FIXED64); 459 | } 460 | output.WriteTag(tag); 461 | auto real_value=value.begin().value().get(); 462 | output.WriteLittleEndian64(real_value); 463 | break; 464 | } 465 | 466 | } 467 | 468 | std::vector inner_pb_data; 469 | 470 | std::uint32_t inner_json_size=value.dump().size(); 471 | inner_pb_data.resize(inner_json_size); 472 | std::uint32_t inner_size=json2pb(value,inner_pb_data.data(),inner_json_size); 473 | 474 | uint32_t tag=0x0; 475 | if(arry_field_num!=0){ 476 | tag=internal::WireFormatLite::MakeTag(arry_field_num,internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); 477 | }else{ 478 | tag=internal::WireFormatLite::MakeTag(std::atoi(key.c_str()),internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); 479 | } 480 | output.WriteTag(tag); 481 | output.WriteVarint32(inner_size); 482 | output.WriteRaw(inner_pb_data.data(),inner_size); 483 | 484 | break; 485 | } 486 | case JSON_Type::string:{ 487 | uint32_t tag=0x0; 488 | if(arry_field_num!=0){ 489 | tag=internal::WireFormatLite::MakeTag(arry_field_num,internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); 490 | }else{ 491 | tag=internal::WireFormatLite::MakeTag(std::atoi(key.c_str()),internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); 492 | } 493 | output.WriteTag(tag); 494 | auto read_value=value.get(); 495 | output.WriteVarint32(read_value.size()); 496 | 497 | output.WriteString(read_value); 498 | 499 | break; 500 | } 501 | //如果是数字 PB 是直接写在一起的,没有Tag区分,string就有tag区分 502 | case JSON_Type::array:{ 503 | auto tag=internal::WireFormatLite::MakeTag(std::atoi(key.c_str()),internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); 504 | // output.WriteTag(tag); 505 | 506 | auto offset=output.ByteCount(); 507 | auto ret_size=json2pb(value,pb_data+offset,pb_buff_size, std::atoi(key.c_str())); 508 | output.SetCur(output.Cur()+ret_size); 509 | 510 | 511 | // append_arry2pb(output,value); 512 | 513 | break; 514 | } 515 | 516 | } 517 | 518 | 519 | } 520 | return output.ByteCount(); 521 | } 522 | 523 | 524 | -------------------------------------------------------------------------------- /ProtobufHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 28264 on 2023/5/27. 3 | // 4 | 5 | #ifndef WEHELPER_PROTOBUFHELPER_H 6 | #define WEHELPER_PROTOBUFHELPER_H 7 | #include 8 | #include 9 | #include "google/protobuf/io/coded_stream.h" 10 | #include "google/protobuf/wire_format.h" 11 | #include "google/protobuf/wire_format_lite.h" 12 | #include 13 | using JSON = nlohmann::json; 14 | 15 | using namespace std; 16 | 17 | 18 | class ProtobufHelper { 19 | 20 | 21 | // 22 | public: 23 | ProtobufHelper(); 24 | 25 | bool parse_pb(std::uint8_t *pb_data, std::uint32_t pb_len,JSON& json,bool is_child= false,JSON* parent_node= nullptr); 26 | 27 | std::uint32_t json2pb(JSON& input_json,std::uint8_t* pb_data,std::uint32_t pb_buff_size,std::uint32_t arry_field_num=0); 28 | void append_arry2pb(google::protobuf::io::CodedOutputStream& output,JSON& json,bool fix_size=false); 29 | }; 30 | 31 | 32 | #endif //WEHELPER_PROTOBUFHELPER_H 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ParsePb 2 | 无proto文件解析protobuf序列化后的内容 3 | 4 | #### 欢迎提issue,给出一些解析不了我pb,我会尽力去修bug的 5 | ## 使用方法 6 | 7 | ## 支持解析protbuf 8 | ## 支持json转protbuf 9 | ### 特殊案例 10 | fix32和fix64较为特殊,如下案例 字段2是protobuf的repeat fixed32类型,需要特别著名采用fix32_num 11 | fix64则为 fix64_num,否则默认为普通的int32 12 | ```json 13 | { 14 | "2":["fix32_num",1,2,3] 15 | } 16 | 17 | ``` 18 | 直接拷贝如下两个文件到自己项目(本质上就一个函数) 19 | - ProtobufHelper.h 20 | - ProtobufHelper.cpp 21 | ### test.cpp是写的测试 作为参考案例 22 | 23 | ## 参考项目 24 | - PyProto https://github.com/Ccccccccvvm/PyProto 25 | 26 | ## 参考文章 27 | - UTF-8编码的原理 https://blog.csdn.net/whahu1989/article/details/118314154 28 | - 官网对protobuf编码解释 https://protobuf.dev/programming-guides/encoding/ 29 | - Protobuf编码解析 https://blog.csdn.net/u013688006/article/details/114009522 -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 28264 on 2023/6/10. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "ProtobufHelper.h" 7 | 8 | 9 | //TEST(PROTOBUF_TEST, Trivial) {//这个PB 格式错误的 10 | // 11 | // ProtobufHelper helper; 12 | // uint8_t pb_data[]={0xf0,0x0d,0x00,0x00,0x10,0x08,0x00,0x00,0x04,0x34,0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x14,0x3b,0x39,0x67,0x08,0x00,0x81,0x00,0x00,0x00,0x05,0x73,0x6f,0x73,0x6f,0x0a,0x00,0x41,0x4b,0x73,0xbd,0x72,0x09,0x00,0x90,0x00,0x00,0x07,0x69,0x50,0x68,0x6f,0x6e,0x65,0x0b,0x00,0x51,0x00,0x46,0xa9,0x3e,0x0c,0x09,0x00,0xf0,0x06,0x00,0x00,0x13,0xe5,0xa4,0xaa,0xe9,0x98,0xb3,0xe7,0x85,0xa7,0xe5,0xb8,0xb8,0xe5,0x8d,0x87,0xe8,0xb5,0xb7,0x17,0x00,0x51,0x00,0x12,0x18,0x54,0x03,0x09,0x00,0x62,0x00,0x00,0x0d,0x62,0x69,0x75,0x03,0x00,0x30,0xef,0xbd,0x9e,0x11,0x00,0x40,0x00,0x18,0xfa,0x63,0x7c,0x00,0x00,0x02,0x00,0xf0,0x02,0x11,0xe6,0x95,0xb0,0xe6,0x8d,0xae,0xe9,0x87,0x87,0xe9,0x9b,0x86,0x74,0x65,0x73,0x74,0x15,0x00,0x51,0x00,0x28,0xb4,0xff,0x9c,0x09,0x00,0xf0,0x06,0x00,0x00,0x13,0x2f,0x2f,0x2f,0xe6,0x97,0xa0,0xe6,0x83,0x85,0xe6,0x97,0xa0,0xe4,0xb9,0x89,0x40,0x40,0x40,0x17,0x00,0x51,0x00,0x6a,0xd1,0xd3,0xf4,0x09,0x00,0xb0,0x00,0x00,0x04,0xe5,0x93,0x8e,0x00,0x00,0x00,0x00,0x00,0x74,0x73,0x66,0x34,0x67,0x06}; 13 | // JSON json; 14 | // helper.parse_pb(pb_data,sizeof(pb_data),json); 15 | // 16 | // std::cout<\n\t\n\t\t2\n\t\n\tv1_gzQ72FmR\n\t\n\t\t<![CDATA[]]>\n\t\n\n","11":"zhuzhu : 11111111","12":8684474064623330158,"13":783971074,"2":{"1":"wxid_4zr616ir6fi122"},"3":{"1":"wxid_8d124lgymw8o22"},"4":1,"5":{"1":"11111111"},"6":3,"7":1,"8":"0800","9":1686453147}}}},"3":0,"4":{"1":362,"2":{"1":47,"2":[{"1":1,"2":783971061},{"1":101,"2":0},{"1":2,"2":783971074},{"1":102,"2":0},{"1":13,"2":0},{"1":204,"2":0},{"1":3,"2":783971052},{"1":103,"2":0},{"1":11,"2":783970039},{"1":111,"2":0},{"1":4,"2":0},{"1":104,"2":0},{"1":5,"2":0},{"1":105,"2":0},{"1":7,"2":0},{"1":107,"2":0},{"1":8,"2":0},{"1":108,"2":0},{"1":9,"2":783970039},{"1":109,"2":0},{"1":22,"2":783971047},{"1":6,"2":0},{"1":122,"2":0},{"1":106,"2":0},{"1":16,"2":783970039},{"1":17,"2":783970039},{"1":114,"2":0},{"1":14,"2":783970039},{"1":112,"2":0},{"1":19,"2":33295},{"1":26,"2":0},{"1":27,"2":8168},{"1":24,"2":1686453147},{"1":23,"2":1686453011},{"1":10,"2":0},{"1":201,"2":1686453147},{"1":205,"2":0},{"1":202,"2":0},{"1":203,"2":0},{"1":206,"2":101},{"1":207,"2":0},{"1":20,"2":0},{"1":21,"2":0},{"1":1000,"2":1686436216},{"1":1001,"2":1686439861},{"1":2001,"2":1686377104},{"1":2003,"2":1686405903}]}},"5":1,"6":532822812,"7":1686453150,"8":{"1":17,"2":{"1":{"1":[2,26,27],"2":2814644561,"3":1001}}}} 148 | )"); 149 | std::string str=json.dump(); 150 | std::cout< expect_value={0x0a,0x0c,0x7a,0x68,0x75,0x7a,0x68,0x75,0xe4,0xb8,0xad,0x31,0x32,0x33}; 194 | //0a 0c 7a 68 75 7a 68 75 e4 b8 ad 31 32 33 195 | std::uint32_t input_json_size=input_json.dump().size(); 196 | ProtobufHelper helper; 197 | std::vector pb_data; 198 | pb_data.resize(input_json_size); 199 | auto pb_len= helper.json2pb(input_json,pb_data.data(),input_json_size); 200 | pb_data.resize(pb_len); 201 | std::string str=input_json.dump(); 202 | std::cout< expect_value={0x0a,0x0c,0x7a,0x68,0x75,0x7a,0x68,0x75,0xe4,0xb8,0xad,0x31,0x32,0x33,0x0a,0x03,0x32,0x32,0x32,0x12,0x0c,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00}; 239 | //0a 0c 7a 68 75 7a 68 75 e4 b8 ad 31 32 33 240 | std::uint32_t input_json_size=input_json.dump().size(); 241 | ProtobufHelper helper; 242 | std::vector pb_data; 243 | pb_data.resize(input_json_size); 244 | auto pb_len= helper.json2pb(input_json,pb_data.data(),input_json_size); 245 | pb_data.resize(pb_len); 246 | 247 | std::cout< expect_value={0x1a,0x07,0x0d,0x0b,0x00,0x00,0x00,0x10,0x16}; 264 | //0a 0c 7a 68 75 7a 68 75 e4 b8 ad 31 32 33 265 | std::uint32_t input_json_size=input_json.dump().size(); 266 | ProtobufHelper helper; 267 | std::vector pb_data; 268 | pb_data.resize(input_json_size); 269 | auto pb_len= helper.json2pb(input_json,pb_data.data(),input_json_size); 270 | pb_data.resize(pb_len); 271 | 272 | std::cout< expect_value={0x08,0x01,0x12,0x2f,0x0a,0x14,0x0a,0x12,0x77,0x78,0x69,0x64,0x5f,0x34,0x7a,0x72,0x36,0x78,0x78,0x78,0x36,0x66,0x69,0x31,0x32,0x32,0x12,0x09,0x31,0x32,0x33,0x31,0x32,0x33,0x31,0x31,0x31,0x18,0x01,0x20,0xf8,0x8e,0xa2,0xa4,0x06,0x28,0xf8,0x8e,0xa2,0xa4,0x06}; 293 | //0a 0c 7a 68 75 7a 68 75 e4 b8 ad 31 32 33 294 | std::uint32_t input_json_size=input_json.dump().size(); 295 | ProtobufHelper helper; 296 | std::vector pb_data; 297 | pb_data.resize(input_json_size); 298 | auto pb_len= helper.json2pb(input_json,pb_data.data(),input_json_size); 299 | pb_data.resize(pb_len); 300 | 301 | std::cout<