diff --git a/parser/common/convert/pb2json.cc b/parser/common/convert/pb2json.cc new file mode 100644 index 0000000..0a5d24e --- /dev/null +++ b/parser/common/convert/pb2json.cc @@ -0,0 +1,248 @@ +/** + * Copyright 2019-2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// File: pb2json.h +// Description: This imply file for protobuf message and json interconversion + +#include "common/convert/pb2json.h" +#include +#include +#include "securec.h" +#include "framework/common/fmk_types.h" +#include "framework/common/debug/ge_log.h" + +using std::set; +using std::string; + +namespace ge { +namespace { +const int kSignificantDigits = 10; +} +// JSON parses non utf8 character throwing exceptions, so some fields need to be shielded through black fields +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void Pb2Json::Message2Json(const ProtobufMsg &message, + const set &black_fields, Json &json, + bool enum2str) { + auto descriptor = message.GetDescriptor(); + auto reflection = message.GetReflection(); + if (descriptor == nullptr || reflection == nullptr) { + return; + } + + auto count = descriptor->field_count(); + + for (auto i = 0; i < count; ++i) { + const auto field = descriptor->field(i); + if (field == nullptr) { + return; + } + + // Do not display weight data + if (black_fields.find(field->name()) != black_fields.end()) { + continue; + } + + if (field->is_repeated()) { + if (reflection->FieldSize(message, field) > 0) { + RepeatedMessage2Json(message, field, reflection, black_fields, json[field->name()], enum2str); + } + continue; + } + + if (!reflection->HasField(message, field)) { + continue; + } + + OneField2Json(message, field, reflection, black_fields, json, enum2str); + } +} + +void Pb2Json::OneField2Json(const ProtobufMsg &message, const ProtobufFieldDescriptor *field, + const ProtobufReflection *reflection, const set &black_fields, Json &json, + bool enum2str) { + switch (field->type()) { + case ProtobufFieldDescriptor::TYPE_MESSAGE: { + const ProtobufMsg &tmp_message = reflection->GetMessage(message, field); + if (0 != tmp_message.ByteSize()) { + Message2Json(tmp_message, black_fields, json[field->name()], enum2str); + } + break; + } + + case ProtobufFieldDescriptor::TYPE_BOOL: + json[field->name()] = reflection->GetBool(message, field); + break; + + case ProtobufFieldDescriptor::TYPE_ENUM: { + auto *enum_value_desc = reflection->GetEnum(message, field); + Enum2Json(enum_value_desc, field, enum2str, json); + break; + } + + case ProtobufFieldDescriptor::TYPE_INT32: + case ProtobufFieldDescriptor::TYPE_SINT32: + case ProtobufFieldDescriptor::TYPE_SFIXED32: + json[field->name()] = reflection->GetInt32(message, field); + break; + + case ProtobufFieldDescriptor::TYPE_UINT32: + case ProtobufFieldDescriptor::TYPE_FIXED32: + json[field->name()] = reflection->GetUInt32(message, field); + break; + + case ProtobufFieldDescriptor::TYPE_INT64: + case ProtobufFieldDescriptor::TYPE_SINT64: + case ProtobufFieldDescriptor::TYPE_SFIXED64: + json[field->name()] = reflection->GetInt64(message, field); + break; + + case ProtobufFieldDescriptor::TYPE_UINT64: + case ProtobufFieldDescriptor::TYPE_FIXED64: + json[field->name()] = reflection->GetUInt64(message, field); + break; + + case ProtobufFieldDescriptor::TYPE_FLOAT: + char str[kSignificantDigits]; + if (sprintf_s(str, kSignificantDigits, "%g", reflection->GetFloat(message, field)) != -1) { + json[field->name()] = str; + } else { + json[field->name()] = reflection->GetFloat(message, field); + } + + break; + + case ProtobufFieldDescriptor::TYPE_STRING: + json[field->name()] = reflection->GetString(message, field); + break; + + case ProtobufFieldDescriptor::TYPE_BYTES: { + string field_name = field->name(); + string type_bytes = reflection->GetString(message, field); + json[field_name] = TypeBytes2String(field_name, type_bytes); + break; + } + + default: + break; + } +} + +string Pb2Json::TypeBytes2String(string &field_name, string &type_bytes) { + if (field_name != "offset") { + return type_bytes; + } + string result = ""; + for (char temp_value : type_bytes) { + uint8_t *value = 0; + value = reinterpret_cast(&temp_value); + char str[kSignificantDigits]; + if (sprintf_s(str, kSignificantDigits, "%d", *value) == -1) { + GELOGW("Convert bytes to string fail, filed name:%s", field_name.c_str()); + continue; + } + result += str; + } + return result; +} + +void Pb2Json::RepeatedMessage2Json(const ProtobufMsg &message, const ProtobufFieldDescriptor *field, + const ProtobufReflection *reflection, const set &black_fields, Json &json, + bool enum2str) { + if ((field == nullptr) || (reflection == nullptr)) { + Message2Json(message, black_fields, json, enum2str); + return; + } + + for (auto i = 0; i < reflection->FieldSize(message, field); ++i) { + Json tmp_json; + switch (field->type()) { + case ProtobufFieldDescriptor::TYPE_MESSAGE: { + const ProtobufMsg &tmp_message = reflection->GetRepeatedMessage(message, field, i); + if (0 != tmp_message.ByteSize()) { + Message2Json(tmp_message, black_fields, tmp_json, enum2str); + } + } break; + + case ProtobufFieldDescriptor::TYPE_BOOL: + tmp_json = reflection->GetRepeatedBool(message, field, i); + break; + + case ProtobufFieldDescriptor::TYPE_ENUM: { + auto *enum_value_desc = reflection->GetRepeatedEnum(message, field, i); + RepeatedEnum2Json(enum_value_desc, enum2str, tmp_json); + } break; + + case ProtobufFieldDescriptor::TYPE_INT32: + case ProtobufFieldDescriptor::TYPE_SINT32: + case ProtobufFieldDescriptor::TYPE_SFIXED32: + tmp_json = reflection->GetRepeatedInt32(message, field, i); + break; + + case ProtobufFieldDescriptor::TYPE_UINT32: + case ProtobufFieldDescriptor::TYPE_FIXED32: + tmp_json = reflection->GetRepeatedUInt32(message, field, i); + break; + + case ProtobufFieldDescriptor::TYPE_INT64: + case ProtobufFieldDescriptor::TYPE_SINT64: + case ProtobufFieldDescriptor::TYPE_SFIXED64: + tmp_json = reflection->GetRepeatedInt64(message, field, i); + break; + + case ProtobufFieldDescriptor::TYPE_UINT64: + case ProtobufFieldDescriptor::TYPE_FIXED64: + tmp_json = reflection->GetRepeatedUInt64(message, field, i); + break; + + case ProtobufFieldDescriptor::TYPE_FLOAT: + tmp_json = reflection->GetRepeatedFloat(message, field, i); + break; + + case ProtobufFieldDescriptor::TYPE_STRING: + case ProtobufFieldDescriptor::TYPE_BYTES: + tmp_json = reflection->GetRepeatedString(message, field, i); + break; + + default: + break; + } + json += tmp_json; + } +} + +void Pb2Json::Enum2Json(const ProtobufEnumValueDescriptor *enum_value_desc, const ProtobufFieldDescriptor *field, + bool enum2str, Json &json) { + if (enum_value_desc != nullptr) { + if (field == nullptr) { + return; + } + if (enum2str) { + json[field->name()] = enum_value_desc->name(); + } else { + json[field->name()] = enum_value_desc->number(); + } + } +} + +void Pb2Json::RepeatedEnum2Json(const ProtobufEnumValueDescriptor *enum_value_desc, bool enum2str, Json &json) { + if (enum_value_desc != nullptr) { + if (enum2str) { + json = enum_value_desc->name(); + } else { + json = enum_value_desc->number(); + } + } +} +} // namespace ge diff --git a/parser/common/convert/pb2json.h b/parser/common/convert/pb2json.h new file mode 100644 index 0000000..88ded50 --- /dev/null +++ b/parser/common/convert/pb2json.h @@ -0,0 +1,68 @@ +/** + * Copyright 2019-2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// File: pb2json.h +// Description: This header file for protobuf message and json interconversion + +#ifndef GE_COMMON_CONVERT_PB2JSON_H_ +#define GE_COMMON_CONVERT_PB2JSON_H_ +#include +#include +#include +#include +#include "google/protobuf/descriptor.h" +#include "google/protobuf/message.h" +#include "nlohmann/json.hpp" + +namespace ge { +using Json = nlohmann::json; +using ProtobufMsg = ::google::protobuf::Message; +using ProtobufReflection = ::google::protobuf::Reflection; +using ProtobufFieldDescriptor = ::google::protobuf::FieldDescriptor; +using ProtobufDescriptor = ::google::protobuf::Descriptor; +using ProtobufEnumValueDescriptor = ::google::protobuf::EnumValueDescriptor; + +class Pb2Json { + public: + /** + * @ingroup domi_omg + * @brief Transfer protobuf object to JSON object + * @param [out] json Converted JSON object + * @return void success + * @author + */ + static void Message2Json(const ProtobufMsg &message, const std::set &black_fields, Json &json, + bool enum2str = false); + + protected: + static void RepeatedMessage2Json(const ProtobufMsg &message, const ProtobufFieldDescriptor *field, + const ProtobufReflection *reflection, const std::set &black_fields, + Json &json, bool enum2str); + + static void Enum2Json(const ProtobufEnumValueDescriptor *enum_value_desc, const ProtobufFieldDescriptor *field, + bool enum2str, Json &json); + + static void RepeatedEnum2Json(const ProtobufEnumValueDescriptor *enum_value_desc, bool enum2str, Json &json); + + static void OneField2Json(const ProtobufMsg &message, const ProtobufFieldDescriptor *field, + const ProtobufReflection *reflection, const std::set &black_fields, Json &json, + bool enum2str); + + static std::string TypeBytes2String(std::string &field_name, std::string &type_bytes); +}; +} // namespace ge + +#endif // GE_COMMON_CONVERT_PB2JSON_H_