| // Copyright 2010-2015, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "net/json_util.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "base/number_util.h" |
| #include "base/port.h" |
| #include "base/protobuf/descriptor.h" |
| #include "net/jsoncpp.h" |
| |
| using mozc::protobuf::Message; |
| using mozc::protobuf::Descriptor; |
| using mozc::protobuf::EnumValueDescriptor; |
| using mozc::protobuf::Reflection; |
| using mozc::protobuf::FieldDescriptor; |
| |
| // <WinUser.h> defines GetMessage as a macro, which eventually |
| // conflicts with mozc::protobuf::Reflection::GetMessage. |
| #ifdef GetMessage |
| #undef GetMessage |
| #endif // GetMessage |
| |
| namespace mozc { |
| namespace net { |
| namespace { |
| |
| bool ProtobufRepeatedFieldValueToJsonValue( |
| const Message &message, const Reflection &reflection, |
| const FieldDescriptor &field, int index, Json::Value *value) { |
| switch (field.cpp_type()) { |
| case FieldDescriptor::CPPTYPE_INT32: { |
| *value = Json::Value( |
| reflection.GetRepeatedInt32(message, &field, index)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_INT64: { |
| *value = Json::Value(NumberUtil::SimpleItoa(static_cast<int64>( |
| reflection.GetRepeatedInt64(message, &field, index)))); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_UINT32: { |
| *value = Json::Value( |
| reflection.GetRepeatedUInt32(message, &field, index)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_UINT64: { |
| *value = Json::Value(NumberUtil::SimpleItoa(static_cast<uint64>( |
| reflection.GetRepeatedUInt64(message, &field, index)))); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_FLOAT: { |
| *value = Json::Value(reflection.GetRepeatedFloat(message, &field, index)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_DOUBLE: { |
| *value = Json::Value( |
| reflection.GetRepeatedDouble(message, &field, index)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_BOOL: { |
| *value = Json::Value(reflection.GetRepeatedBool(message, &field, index)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_ENUM: { |
| *value = Json::Value( |
| reflection.GetRepeatedEnum(message, &field, index)->name()); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_STRING: { |
| string scratch; |
| const string &str = reflection.GetRepeatedStringReference( |
| message, &field, index, &scratch); |
| *value = Json::Value(str); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_MESSAGE: { |
| return JsonUtil::ProtobufMessageToJsonValue( |
| reflection.GetRepeatedMessage(message, &field, index), value); |
| } |
| default: { |
| DLOG(WARNING) << "unsupported filed CppType: " << field.cpp_type(); |
| break; |
| } |
| } |
| return false; |
| } |
| |
| bool ProtobufFieldValueToJsonValue( |
| const Message &message, const Reflection &reflection, |
| const FieldDescriptor &field, Json::Value *value) { |
| switch (field.cpp_type()) { |
| case FieldDescriptor::CPPTYPE_INT32: { |
| *value = Json::Value(reflection.GetInt32(message, &field)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_INT64: { |
| *value = Json::Value(NumberUtil::SimpleItoa(static_cast<int64>( |
| reflection.GetInt64(message, &field)))); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_UINT32: { |
| *value = Json::Value(reflection.GetUInt32(message, &field)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_UINT64: { |
| *value = Json::Value(NumberUtil::SimpleItoa(static_cast<uint64>( |
| reflection.GetUInt64(message, &field)))); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_FLOAT: { |
| *value = Json::Value(reflection.GetFloat(message, &field)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_DOUBLE: { |
| *value = Json::Value(reflection.GetDouble(message, &field)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_BOOL: { |
| *value = Json::Value(reflection.GetBool(message, &field)); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_ENUM: { |
| *value = Json::Value(reflection.GetEnum(message, &field)->name()); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_STRING: { |
| string scratch; |
| const string &str = |
| reflection.GetStringReference(message, &field, &scratch); |
| *value = Json::Value(str); |
| return true; |
| } |
| case FieldDescriptor::CPPTYPE_MESSAGE: { |
| return JsonUtil::ProtobufMessageToJsonValue( |
| reflection.GetMessage(message, &field), value); |
| } |
| default: { |
| DLOG(WARNING) << "unsupported filed CppType: " << field.cpp_type(); |
| break; |
| } |
| } |
| return false; |
| } |
| |
| bool JsonValueToProtobufFieldValue( |
| const Json::Value &value, const FieldDescriptor *field, |
| const Reflection *reflection, Message *message) { |
| DCHECK(!field->is_repeated()); |
| switch (field->cpp_type()) { |
| case FieldDescriptor::CPPTYPE_INT32: { |
| if (!value.isConvertibleTo(Json::intValue)) { |
| DLOG(ERROR) << "value is not convertible to intValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetInt32(message, field, value.asInt()); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_INT64: { |
| if (!value.isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| int64 int_value; |
| if (!NumberUtil::SafeStrToInt64(value.asString(), &int_value)) { |
| DLOG(ERROR) << "value is not convertible to int64: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetInt64(message, field, int_value); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_UINT32: { |
| if (!value.isConvertibleTo(Json::uintValue)) { |
| DLOG(ERROR) << "value is not convertible to uintValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetUInt32(message, field, value.asUInt()); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_UINT64: { |
| if (!value.isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| uint64 uint_value; |
| if (!NumberUtil::SafeStrToUInt64(value.asString(), &uint_value)) { |
| DLOG(ERROR) << "value is not convertible to uint64: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetUInt64(message, field, uint_value); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_DOUBLE: { |
| if (!value.isConvertibleTo(Json::realValue)) { |
| DLOG(ERROR) << "value is not convertible to realValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetDouble(message, field, value.asDouble()); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_FLOAT: { |
| if (!value.isConvertibleTo(Json::realValue)) { |
| DLOG(ERROR) << "value is not convertible to realValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetFloat(message, field, value.asFloat()); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_BOOL: { |
| if (!value.isConvertibleTo(Json::booleanValue)) { |
| DLOG(ERROR) << "value is not convertible to booleanValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetBool(message, field, value.asBool()); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_ENUM: { |
| if (!value.isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| const EnumValueDescriptor *enum_value = |
| field->enum_type()->FindValueByName(value.asString()); |
| if (!enum_value) { |
| DLOG(ERROR) << "value is not enum: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetEnum(message, field, enum_value); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_STRING: { |
| if (!value.isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| reflection->SetString(message, field, value.asString()); |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_MESSAGE: { |
| if (!value.isConvertibleTo(Json::objectValue)) { |
| DLOG(ERROR) << "value is not convertible to objectValue: " |
| << Json::FastWriter().write(value); |
| return false; |
| } |
| return JsonUtil::JsonValueToProtobufMessage( |
| value, reflection->MutableMessage(message, field, NULL)); |
| break; |
| } |
| default: { |
| DLOG(ERROR) << "Unknown or unsupported type: " << field->cpp_type(); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool JsonValueToProtobufRepeatedFieldValue( |
| const Json::Value &value, const FieldDescriptor *field, |
| const Reflection *reflection, Message *message) { |
| DCHECK(field->is_repeated()); |
| DCHECK(value.isArray()); |
| bool result = true; |
| switch (field->cpp_type()) { |
| case FieldDescriptor::CPPTYPE_INT32: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::intValue)) { |
| DLOG(ERROR) << "value is not convertible to intValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddInt32(message, field, value[i].asInt()); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_INT64: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| int64 int_value; |
| if (!value[i].isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else if (!NumberUtil::SafeStrToInt64(value[i].asString(), |
| &int_value)) { |
| DLOG(ERROR) << "value is not convertible to int64: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddInt64(message, field, int_value); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_UINT32: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::uintValue)) { |
| DLOG(ERROR) << "value is not convertible to uintValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddUInt32(message, field, value[i].asUInt()); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_UINT64: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| uint64 uint_value; |
| if (!value[i].isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else if (!NumberUtil::SafeStrToUInt64(value[i].asString(), |
| &uint_value)) { |
| DLOG(ERROR) << "value is not convertible to uint64: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddUInt64(message, field, uint_value); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_DOUBLE: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::realValue)) { |
| DLOG(ERROR) << "value is not convertible to realValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddDouble(message, field, value[i].asDouble()); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_FLOAT: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::realValue)) { |
| DLOG(ERROR) << "value is not convertible to realValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddFloat(message, field, value[i].asFloat()); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_BOOL: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::booleanValue)) { |
| DLOG(ERROR) << "value is not convertible to booleanValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddBool(message, field, value[i].asBool()); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_ENUM: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| const EnumValueDescriptor *enum_value = |
| field->enum_type()->FindValueByName(value[i].asString()); |
| if (!enum_value) { |
| DLOG(ERROR) << "value is not enum: " << value[i].asString(); |
| result = false; |
| } else { |
| reflection->AddEnum(message, field, enum_value); |
| } |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_STRING: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::stringValue)) { |
| DLOG(ERROR) << "value is not convertible to stringValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| reflection->AddString(message, field, value[i].asString()); |
| } |
| } |
| break; |
| } |
| case FieldDescriptor::CPPTYPE_MESSAGE: { |
| for (Json::ArrayIndex i = 0; i < value.size(); ++i) { |
| if (!value[i].isConvertibleTo(Json::objectValue)) { |
| DLOG(ERROR) << "value is not convertible to objectValue: " |
| << Json::FastWriter().write(value[i]); |
| result = false; |
| } else { |
| if (!JsonUtil::JsonValueToProtobufMessage( |
| value[i], reflection->AddMessage(message, field, NULL))) { |
| result = false; |
| } |
| } |
| } |
| break; |
| } |
| default: { |
| DLOG(ERROR) << "Unknown or unsupported type: " << field->cpp_type(); |
| return false; |
| } |
| } |
| return result; |
| } |
| |
| } // namespace |
| |
| bool JsonUtil::ProtobufMessageToJsonValue( |
| const Message &message, Json::Value *value) { |
| *value = Json::Value(Json::objectValue); |
| const Descriptor *descriptor = message.GetDescriptor(); |
| const Reflection *reflection = message.GetReflection(); |
| const int field_count = descriptor->field_count(); |
| bool result = true; |
| for (size_t i = 0; i < field_count; ++i) { |
| const FieldDescriptor *field = descriptor->field(i); |
| if (!field) { |
| result = false; |
| continue; |
| } |
| if (field->is_repeated()) { |
| Json::Value *items = &(*value)[field->name()]; |
| *items = Json::Value(Json::arrayValue); |
| const int count = reflection->FieldSize(message, field); |
| for (int j = 0; j < count; ++j) { |
| if (!ProtobufRepeatedFieldValueToJsonValue(message, |
| *reflection, |
| *field, |
| j, |
| &(*items)[j])) { |
| result = false; |
| } |
| } |
| } else { |
| if (reflection->HasField(message, field) || field->is_required()) { |
| if (!ProtobufFieldValueToJsonValue(message, |
| *reflection, |
| *field, |
| &(*value)[field->name()])) { |
| result = false; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| bool JsonUtil::JsonValueToProtobufMessage( |
| const Json::Value &value, Message *message) { |
| const Descriptor *descriptor = message->GetDescriptor(); |
| const Reflection *reflection = message->GetReflection(); |
| const Json::Value::Members &members = value.getMemberNames(); |
| |
| bool result = true; |
| for (size_t i = 0; i < members.size(); ++i) { |
| const FieldDescriptor *field = descriptor->FindFieldByName(members[i]); |
| if (!field) { |
| DLOG(ERROR) << "Unknown field: \"" << members[i] << "\""; |
| result = false; |
| continue; |
| } |
| if (field->is_repeated()) { |
| if (!value[members[i]].isArray()) { |
| DLOG(ERROR) << "\"" << members[i] << "\" is repeated." |
| << "But json is not array"; |
| result = false; |
| continue; |
| } |
| if (!JsonValueToProtobufRepeatedFieldValue(value[members[i]], field, |
| reflection, message)) { |
| DLOG(ERROR) << "JsonValueToProtobufRepeatedFieldValue error: \"" |
| << members[i] << "\""; |
| result = false; |
| } |
| } else { |
| if (!JsonValueToProtobufFieldValue(value[members[i]], field, reflection, |
| message)) { |
| DLOG(ERROR) << "JsonValueToProtobufFieldValue error: \"" |
| << members[i] << "\""; |
| result = false; |
| } |
| } |
| } |
| return result; |
| } |
| |
| } // namespace net |
| } // namespace mozc |