json_to_pb.cpp 23.5 KB
Newer Older
gejun's avatar
gejun committed
1
// Copyright (c) 2014 Baidu, Inc.
gejun's avatar
gejun committed
2

gejun's avatar
gejun committed
3 4 5 6 7 8 9 10 11 12 13 14
#include <vector>
#include <map>
#include <string>
#include <sstream>
#include <sys/time.h>
#include <time.h>
#include <typeinfo>
#include <limits> 
#include <google/protobuf/descriptor.h>
#include "json_to_pb.h"
#include "zero_copy_stream_reader.h"       // ZeroCopyStreamReader
#include "encode_decode.h"
15 16
#include "butil/base64.h"
#include "butil/string_printf.h"
gejun's avatar
gejun committed
17 18 19 20 21 22 23 24
#include "protobuf_map.h"
#include "rapidjson.h"

#define J2PERROR(perr, fmt, ...)                                        \
    if (perr) {                                                         \
        if (!perr->empty()) {                                           \
            perr->append(", ", 2);                                      \
        }                                                               \
25
        butil::string_appendf(perr, fmt, ##__VA_ARGS__);                 \
gejun's avatar
gejun committed
26 27 28 29
    } else { }

namespace json2pb {

zhujiashun's avatar
zhujiashun committed
30 31 32 33 34 35 36 37
Json2PbOptions::Json2PbOptions()
#ifdef BAIDU_INTERNAL
    : base64_to_bytes(false) {
#else
    : base64_to_bytes(true) {
#endif
}

gejun's avatar
gejun committed
38 39 40 41 42 43
enum MatchType { 
    TYPE_MATCH = 0x00, 
    REQUIRED_OR_REPEATED_TYPE_MISMATCH = 0x01, 
    OPTIONAL_TYPE_MISMATCH = 0x02 
};
 
44
static void string_append_value(const BUTIL_RAPIDJSON_NAMESPACE::Value& value,
gejun's avatar
gejun committed
45 46 47 48 49 50
                                std::string* output) {
    if (value.IsNull()) {
        output->append("null");
    } else if (value.IsBool()) {
        output->append(value.GetBool() ? "true" : "false");
    } else if (value.IsInt()) {
51
        butil::string_appendf(output, "%d", value.GetInt());
gejun's avatar
gejun committed
52
    } else if (value.IsUint()) {
53
        butil::string_appendf(output, "%u", value.GetUint());
gejun's avatar
gejun committed
54
    } else if (value.IsInt64()) {
gejun's avatar
gejun committed
55
        butil::string_appendf(output, "%" PRId64, value.GetInt64());
gejun's avatar
gejun committed
56
    } else if (value.IsUint64()) {
gejun's avatar
gejun committed
57
        butil::string_appendf(output, "%" PRIu64, value.GetUint64());
gejun's avatar
gejun committed
58
    } else if (value.IsDouble()) {
59
        butil::string_appendf(output, "%f", value.GetDouble());
gejun's avatar
gejun committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    } else if (value.IsString()) {
        output->push_back('"');
        output->append(value.GetString(), value.GetStringLength());
        output->push_back('"');
    } else if (value.IsArray()) {
        output->append("array");
    } else if (value.IsObject()) {
        output->append("object");
    }
}

//It will be called when type mismatch occurs, fg: convert string to uint, 
//and will also be called when invalid value appears, fg: invalid enum name,
//invalid enum number, invalid string content to convert to double or float.
//for optional field error will just append error into error message
//and ends with ',' and return true.
//otherwise will append error into error message and return false.
inline bool value_invalid(const google::protobuf::FieldDescriptor* field, const char* type,
78
                          const BUTIL_RAPIDJSON_NAMESPACE::Value& value, std::string* err) {
gejun's avatar
gejun committed
79 80 81 82 83 84 85
    bool optional = field->is_optional();
    if (err) {
        if (!err->empty()) {
            err->append(", ");
        }
        err->append("Invalid value `");
        string_append_value(value, err);
86
        butil::string_appendf(err, "' for %sfield `%s' which SHOULD be %s",
gejun's avatar
gejun committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
                       optional ? "optional " : "",
                       field->full_name().c_str(), type);
    }
    if (!optional) {
        return false;                                           
    } 
    return true;
}

template<typename T>
inline bool convert_string_to_double_float_type(
    void (google::protobuf::Reflection::*func)(
        google::protobuf::Message* message,
        const google::protobuf::FieldDescriptor* field, T value) const,
    google::protobuf::Message* message,
    const google::protobuf::FieldDescriptor* field, 
    const google::protobuf::Reflection* reflection,
104
    const BUTIL_RAPIDJSON_NAMESPACE::Value& item,
gejun's avatar
gejun committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    std::string* err) {
    const char* limit_type = item.GetString();  // MUST be string here 
    if (std::numeric_limits<T>::has_quiet_NaN &&
        strcasecmp(limit_type, "NaN") == 0) { 
        (reflection->*func)(message, field, std::numeric_limits<T>::quiet_NaN());
        return true;
    } 
    if (std::numeric_limits<T>::has_infinity &&
        strcasecmp(limit_type, "Infinity") == 0) {
        (reflection->*func)(message, field, std::numeric_limits<T>::infinity());
        return true;
    } 
    if (std::numeric_limits<T>::has_infinity &&
        strcasecmp(limit_type, "-Infinity") == 0) { 
        (reflection->*func)(message, field, -std::numeric_limits<T>::infinity());
        return true;
    }
    return value_invalid(field, typeid(T).name(), item, err);
}

125
inline bool convert_float_type(const BUTIL_RAPIDJSON_NAMESPACE::Value& item, bool repeated,
gejun's avatar
gejun committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
                               google::protobuf::Message* message,
                               const google::protobuf::FieldDescriptor* field, 
                               const google::protobuf::Reflection* reflection,
                               std::string* err) { 
    if (item.IsNumber()) {
        if (repeated) {
            reflection->AddFloat(message, field, item.GetDouble());
        } else {
            reflection->SetFloat(message, field, item.GetDouble());
        }
    } else if (item.IsString()) {
        if (!convert_string_to_double_float_type(
                (repeated ? &google::protobuf::Reflection::AddFloat
                 : &google::protobuf::Reflection::SetFloat),
                message, field, reflection, item, err)) { 
            return false;
        }                                                                               
    } else {                                         
        return value_invalid(field, "float", item, err);
    } 
    return true;
}

149
inline bool convert_double_type(const BUTIL_RAPIDJSON_NAMESPACE::Value& item, bool repeated,
gejun's avatar
gejun committed
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
                                google::protobuf::Message* message,
                                const google::protobuf::FieldDescriptor* field, 
                                const google::protobuf::Reflection* reflection,
                                std::string* err) {  
    if (item.IsNumber()) {
        if (repeated) {
            reflection->AddDouble(message, field, item.GetDouble());
        } else {
            reflection->SetDouble(message, field, item.GetDouble());
        }
    } else if (item.IsString()) {
        if (!convert_string_to_double_float_type(
                (repeated ? &google::protobuf::Reflection::AddDouble
                 : &google::protobuf::Reflection::SetDouble),
                message, field, reflection, item, err)) { 
            return false; 
        }
    } else {
        return value_invalid(field, "double", item, err); 
    }
    return true;
}

173
inline bool convert_enum_type(const BUTIL_RAPIDJSON_NAMESPACE::Value&item, bool repeated,
gejun's avatar
gejun committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
                              google::protobuf::Message* message,
                              const google::protobuf::FieldDescriptor* field,
                              const google::protobuf::Reflection* reflection,
                              std::string* err) {
    const google::protobuf::EnumValueDescriptor * enum_value_descriptor = NULL; 
    if (item.IsInt()) {
        enum_value_descriptor = field->enum_type()->FindValueByNumber(item.GetInt()); 
    } else if (item.IsString()) {                                          
        enum_value_descriptor = field->enum_type()->FindValueByName(item.GetString()); 
    }                                                                      
    if (!enum_value_descriptor) {                                      
        return value_invalid(field, "enum", item, err); 
    }                                                                  
    if (repeated) {
        reflection->AddEnum(message, field, enum_value_descriptor);
    } else {
        reflection->SetEnum(message, field, enum_value_descriptor);
    }
    return true;
}

195
bool JsonValueToProtoMessage(const BUTIL_RAPIDJSON_NAMESPACE::Value& json_value,
zhujiashun's avatar
zhujiashun committed
196 197 198
                             google::protobuf::Message* message,
                             const Json2PbOptions& options,
                             std::string* err);
gejun's avatar
gejun committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

//Json value to protobuf convert rules for type:
//Json value type                 Protobuf type                convert rules
//int                             int uint int64 uint64        valid convert is available
//uint                            int uint int64 uint64        valid convert is available
//int64                           int uint int64 uint64        valid convert is available
//uint64                          int uint int64 uint64        valid convert is available
//int uint int64 uint64           float double                 available
//"NaN" "Infinity" "-Infinity"    float double                 only "NaN" "Infinity" "-Infinity" is available    
//int                             enum                         valid enum number value is available
//string                          enum                         valid enum name value is available         
//other mismatch type convertion will be regarded as error.
#define J2PCHECKTYPE(value, cpptype, jsontype) ({                   \
            MatchType match_type = TYPE_MATCH;                      \
            if (!value.Is##jsontype()) {                            \
                match_type = OPTIONAL_TYPE_MISMATCH;                \
                if (!value_invalid(field, #cpptype, value, err)) {  \
                    return false;                                   \
                }                                                   \
            }                                                       \
            match_type;                                             \
        })

222
static bool JsonValueToProtoField(const BUTIL_RAPIDJSON_NAMESPACE::Value& value,
gejun's avatar
gejun committed
223
                                  const google::protobuf::FieldDescriptor* field,
zhujiashun's avatar
zhujiashun committed
224 225 226
                                  google::protobuf::Message* message,
                                  const Json2PbOptions& options,
                                  std::string* err) {
gejun's avatar
gejun committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    if (value.IsNull()) {
        if (field->is_required()) {
            J2PERROR(err, "Missing required field: %s", field->full_name().c_str());
            return false;
        }
        return true;
    }
        
    if (field->is_repeated()) {
        if (!value.IsArray()) {
            J2PERROR(err, "Invalid value for repeated field: %s",
                     field->full_name().c_str());
            return false;
        }
    } 

    const google::protobuf::Reflection* reflection = message->GetReflection();
    switch (field->cpp_type()) {
#define CASE_FIELD_TYPE(cpptype, method, jsontype)                      \
        case google::protobuf::FieldDescriptor::CPPTYPE_##cpptype: {                      \
            if (field->is_repeated()) {                                 \
248 249 250
                const BUTIL_RAPIDJSON_NAMESPACE::SizeType size = value.Size();          \
                for (BUTIL_RAPIDJSON_NAMESPACE::SizeType index = 0; index < size; ++index) { \
                    const BUTIL_RAPIDJSON_NAMESPACE::Value & item = value[index];       \
gejun's avatar
gejun committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
                    if (TYPE_MATCH == J2PCHECKTYPE(item, cpptype, jsontype)) { \
                        reflection->Add##method(message, field, item.Get##jsontype()); \
                    }                                                   \
                }                                                       \
            } else if (TYPE_MATCH == J2PCHECKTYPE(value, cpptype, jsontype)) { \
                reflection->Set##method(message, field, value.Get##jsontype()); \
            }                                                           \
            break;                                                      \
        }                                                           
        CASE_FIELD_TYPE(INT32,  Int32,  Int);
        CASE_FIELD_TYPE(UINT32, UInt32, Uint);
        CASE_FIELD_TYPE(BOOL,   Bool,   Bool);
        CASE_FIELD_TYPE(INT64,  Int64,  Int64);
        CASE_FIELD_TYPE(UINT64, UInt64, Uint64);
#undef CASE_FIELD_TYPE

    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:  
        if (field->is_repeated()) {
269 270 271
            const BUTIL_RAPIDJSON_NAMESPACE::SizeType size = value.Size();
            for (BUTIL_RAPIDJSON_NAMESPACE::SizeType index = 0; index < size; ++index) {
                const BUTIL_RAPIDJSON_NAMESPACE::Value & item = value[index];
gejun's avatar
gejun committed
272 273 274 275 276 277 278 279 280 281 282 283 284
                if (!convert_float_type(item, true, message, field,
                                        reflection, err)) {
                    return false;
                }
            }
        } else if (!convert_float_type(value, false, message, field,
                                       reflection, err)) {
            return false;
        }
        break;

    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: 
        if (field->is_repeated()) {
285 286 287
            const BUTIL_RAPIDJSON_NAMESPACE::SizeType size = value.Size();
            for (BUTIL_RAPIDJSON_NAMESPACE::SizeType index = 0; index < size; ++index) {
                const BUTIL_RAPIDJSON_NAMESPACE::Value & item = value[index];
gejun's avatar
gejun committed
288 289 290 291 292 293 294 295 296 297 298 299 300
                if (!convert_double_type(item, true, message, field,
                                         reflection, err)) {
                    return false;
                }
            }
        } else if (!convert_double_type(value, false, message, field,
                                        reflection, err)) {
            return false;
        }
        break;
        
    case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
        if (field->is_repeated()) {
301 302 303
            const BUTIL_RAPIDJSON_NAMESPACE::SizeType size = value.Size();
            for (BUTIL_RAPIDJSON_NAMESPACE::SizeType index = 0; index < size; ++index) {
                const BUTIL_RAPIDJSON_NAMESPACE::Value & item = value[index];
gejun's avatar
gejun committed
304 305
                if (TYPE_MATCH == J2PCHECKTYPE(item, string, String)) { 
                    std::string str(item.GetString(), item.GetStringLength());
zhujiashun's avatar
zhujiashun committed
306 307 308
                    if (field->type() == google::protobuf::FieldDescriptor::TYPE_BYTES &&
                        options.base64_to_bytes) {
                        std::string str_decoded;
309
                        if (!butil::Base64Decode(str, &str_decoded)) {
zhujiashun's avatar
zhujiashun committed
310 311 312 313 314
                            J2PERROR(err, "Fail to decode base64 string=%s", str.c_str());
                            return false;
                        }
                        str = str_decoded;
                    }
gejun's avatar
gejun committed
315 316 317 318 319
                    reflection->AddString(message, field, str);
                }  
            }
        } else if (TYPE_MATCH == J2PCHECKTYPE(value, string, String)) {
            std::string str(value.GetString(), value.GetStringLength());
zhujiashun's avatar
zhujiashun committed
320 321 322
            if (field->type() == google::protobuf::FieldDescriptor::TYPE_BYTES &&
                options.base64_to_bytes) {
                std::string str_decoded;
323
                if (!butil::Base64Decode(str, &str_decoded)) {
zhujiashun's avatar
zhujiashun committed
324 325 326 327 328
                    J2PERROR(err, "Fail to decode base64 string=%s", str.c_str());
                    return false;
                }
                str = str_decoded;
            }
gejun's avatar
gejun committed
329 330 331 332 333 334
            reflection->SetString(message, field, str);
        }
        break;

    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
        if (field->is_repeated()) {
335 336 337
            const BUTIL_RAPIDJSON_NAMESPACE::SizeType size = value.Size();
            for (BUTIL_RAPIDJSON_NAMESPACE::SizeType index = 0; index < size; ++index) {
                const BUTIL_RAPIDJSON_NAMESPACE::Value & item = value[index];
gejun's avatar
gejun committed
338 339 340 341 342 343 344 345 346 347 348 349 350
                if (!convert_enum_type(item, true, message, field,
                                       reflection, err)) {
                    return false;
                }
            }
        } else if (!convert_enum_type(value, false, message, field,
                                      reflection, err)) {
            return false;
        }
        break;
        
    case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
        if (field->is_repeated()) {
351 352 353
            const BUTIL_RAPIDJSON_NAMESPACE::SizeType size = value.Size();
            for (BUTIL_RAPIDJSON_NAMESPACE::SizeType index = 0; index < size; ++index) {
                const BUTIL_RAPIDJSON_NAMESPACE::Value& item = value[index];
gejun's avatar
gejun committed
354 355
                if (TYPE_MATCH == J2PCHECKTYPE(item, message, Object)) { 
                    if (!JsonValueToProtoMessage(
zhujiashun's avatar
zhujiashun committed
356
                            item, reflection->AddMessage(message, field), options, err)) {
gejun's avatar
gejun committed
357 358 359 360 361
                        return false;
                    }
                } 
            }
        } else if (!JsonValueToProtoMessage(
zhujiashun's avatar
zhujiashun committed
362
            value, reflection->MutableMessage(message, field), options, err)) {
gejun's avatar
gejun committed
363 364 365 366 367 368 369
            return false;
        }
        break;
    }
    return true;
}

370
bool JsonMapToProtoMap(const BUTIL_RAPIDJSON_NAMESPACE::Value& value,
gejun's avatar
gejun committed
371
                       const google::protobuf::FieldDescriptor* map_desc,
zhujiashun's avatar
zhujiashun committed
372 373 374
                       google::protobuf::Message* message,
                       const Json2PbOptions& options,
                       std::string* err) {
gejun's avatar
gejun committed
375 376 377 378 379 380 381 382 383 384 385 386
    if (!value.IsObject()) {
        J2PERROR(err, "Non-object value for map field: %s",
                 map_desc->full_name().c_str());
        return false;
    }

    const google::protobuf::Reflection* reflection = message->GetReflection();
    const google::protobuf::FieldDescriptor* key_desc =
            map_desc->message_type()->FindFieldByName(KEY_NAME);
    const google::protobuf::FieldDescriptor* value_desc =
            map_desc->message_type()->FindFieldByName(VALUE_NAME);

387
    for (BUTIL_RAPIDJSON_NAMESPACE::Value::ConstMemberIterator it =
gejun's avatar
gejun committed
388 389 390 391 392 393
                 value.MemberBegin(); it != value.MemberEnd(); ++it) {
        google::protobuf::Message* entry = reflection->AddMessage(message, map_desc);
        const google::protobuf::Reflection* entry_reflection = entry->GetReflection();
        entry_reflection->SetString(
            entry, key_desc, std::string(it->name.GetString(),
                                         it->name.GetStringLength()));
zhujiashun's avatar
zhujiashun committed
394
        if (!JsonValueToProtoField(it->value, value_desc, entry, options, err)) {
gejun's avatar
gejun committed
395 396 397 398 399 400
            return false;
        }
    }
    return true;
}

401
bool JsonValueToProtoMessage(const BUTIL_RAPIDJSON_NAMESPACE::Value& json_value,
zhujiashun's avatar
zhujiashun committed
402 403 404
                             google::protobuf::Message* message,
                             const Json2PbOptions& options,
                             std::string* err) {
gejun's avatar
gejun committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
    if (!json_value.IsObject()) {
        J2PERROR(err, "`json_value' is not a json object");
        return false;
    }

    const google::protobuf::Reflection* reflection = message->GetReflection();
    const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
    
    std::vector<const google::protobuf::FieldDescriptor*> fields;
    fields.reserve(64);
    for (int i = 0; i < descriptor->extension_range_count(); ++i) {
        const google::protobuf::Descriptor::ExtensionRange*
            ext_range = descriptor->extension_range(i);
        for (int tag_number = ext_range->start; tag_number < ext_range->end;
             ++tag_number) {
            const google::protobuf::FieldDescriptor* field =
                reflection->FindKnownExtensionByNumber(tag_number);
            if (field) {
                fields.push_back(field);
            }
        }
    }
    for (int i = 0; i < descriptor->field_count(); ++i) {
        fields.push_back(descriptor->field(i));
    }

    std::string field_name_str_temp; 
432
    const BUTIL_RAPIDJSON_NAMESPACE::Value* value_ptr = NULL;
gejun's avatar
gejun committed
433 434 435 436 437 438 439 440
    for (size_t i = 0; i < fields.size(); ++i) {
        const google::protobuf::FieldDescriptor* field = fields[i];
        
        const std::string& orig_name = field->name();
        bool res = decode_name(orig_name, field_name_str_temp); 
        const std::string& field_name_str = (res ? field_name_str_temp : orig_name);

#ifndef RAPIDJSON_VERSION_0_1
441
        BUTIL_RAPIDJSON_NAMESPACE::Value::ConstMemberIterator member =
gejun's avatar
gejun committed
442 443 444 445 446 447 448 449 450 451
                json_value.FindMember(field_name_str.data());
        if (member == json_value.MemberEnd()) {
            if (field->is_required()) {
                J2PERROR(err, "Missing required field: %s", field->full_name().c_str());
                return false;
            }
            continue; 
        }
        value_ptr = &(member->value);
#else 
452
        const BUTIL_RAPIDJSON_NAMESPACE::Value::Member* member =
gejun's avatar
gejun committed
453 454 455 456 457 458 459 460 461 462 463 464 465
                json_value.FindMember(field_name_str.data());
        if (member == NULL) {
            if (field->is_required()) {
                J2PERROR(err, "Missing required field: %s", field->full_name().c_str());
                return false;
            }
            continue; 
        }
        value_ptr = &(member->value);
#endif

        if (IsProtobufMap(field) && value_ptr->IsObject()) {
            // Try to parse json like {"key":value, ...} into protobuf map
zhujiashun's avatar
zhujiashun committed
466
            if (!JsonMapToProtoMap(*value_ptr, field, message, options, err)) {
gejun's avatar
gejun committed
467 468 469
                return false;
            }
        } else {
zhujiashun's avatar
zhujiashun committed
470
            if (!JsonValueToProtoField(*value_ptr, field, message, options, err)) {
gejun's avatar
gejun committed
471 472 473 474 475 476 477
                return false;
            }
        }
    }
    return true;
}

478
bool ZeroCopyStreamToJson(BUTIL_RAPIDJSON_NAMESPACE::Document *dest, 
gejun's avatar
gejun committed
479 480
                          google::protobuf::io::ZeroCopyInputStream *stream) {
    ZeroCopyStreamReader stream_reader(stream);
481
    dest->ParseStream<0, BUTIL_RAPIDJSON_NAMESPACE::UTF8<> >(stream_reader);
gejun's avatar
gejun committed
482 483 484 485 486
    return !dest->HasParseError();
}

inline bool JsonToProtoMessageInline(const std::string& json_string, 
                        google::protobuf::Message* message,
zhujiashun's avatar
zhujiashun committed
487
                        const Json2PbOptions& options,
gejun's avatar
gejun committed
488 489 490 491
                        std::string* error) {
    if (error) {
        error->clear();
    }
492
    BUTIL_RAPIDJSON_NAMESPACE::Document d;
gejun's avatar
gejun committed
493
    d.Parse<0>(json_string.c_str());
zhujiashun's avatar
zhujiashun committed
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    return json2pb::JsonValueToProtoMessage(d, message, options, error);
}

bool JsonToProtoMessage(const std::string& json_string,
                        google::protobuf::Message* message,
                        const Json2PbOptions& options,
                        std::string* error) {
    return JsonToProtoMessageInline(json_string, message, options, error);
}

bool JsonToProtoMessage(google::protobuf::io::ZeroCopyInputStream* stream,
                        google::protobuf::Message* message,
                        const Json2PbOptions& options,
                        std::string* error) {
    if (error) {
        error->clear();
    }
511
    BUTIL_RAPIDJSON_NAMESPACE::Document d;
zhujiashun's avatar
zhujiashun committed
512 513 514 515 516
    if (!json2pb::ZeroCopyStreamToJson(&d, stream)) {
        J2PERROR(error, "Invalid json format");
        return false;
    }
    return json2pb::JsonValueToProtoMessage(d, message, options, error);
gejun's avatar
gejun committed
517 518 519 520 521
}

bool JsonToProtoMessage(const std::string& json_string, 
                        google::protobuf::Message* message,
                        std::string* error) {
zhujiashun's avatar
zhujiashun committed
522
    return JsonToProtoMessageInline(json_string, message, Json2PbOptions(), error);
gejun's avatar
gejun committed
523 524 525 526 527 528 529 530 531
}

// For ABI compatibility with 1.0.0.0
// (https://svn.baidu.com/public/tags/protobuf-json/protobuf-json_1-0-0-0_PD_BL)
// This method should not be exposed in header, otherwise calls to
// JsonToProtoMessage will be ambiguous.
bool JsonToProtoMessage(std::string json_string, 
                        google::protobuf::Message* message,
                        std::string* error) {
zhujiashun's avatar
zhujiashun committed
532
    return JsonToProtoMessageInline(json_string, message, Json2PbOptions(), error);
gejun's avatar
gejun committed
533 534 535 536 537 538 539 540
}

bool JsonToProtoMessage(google::protobuf::io::ZeroCopyInputStream *stream,
                        google::protobuf::Message* message,
                        std::string* error) {
    if (error) {
        error->clear();
    }
541
    BUTIL_RAPIDJSON_NAMESPACE::Document d;
gejun's avatar
gejun committed
542 543 544 545
    if (!json2pb::ZeroCopyStreamToJson(&d, stream)) {
        J2PERROR(error, "Invalid json format");
        return false;
    }
zhujiashun's avatar
zhujiashun committed
546
    return json2pb::JsonValueToProtoMessage(d, message, Json2PbOptions(), error);
gejun's avatar
gejun committed
547 548 549 550 551
}
} //namespace json2pb

#undef J2PERROR
#undef J2PCHECKTYPE