pb2json.cc
1 // Copyright 2018, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 #include "util/pb2json.h"
5 
6 #include <google/protobuf/reflection.h>
7 #include <google/protobuf/repeated_field.h>
8 #include <rapidjson/error/en.h>
9 #include <rapidjson/reader.h>
10 #include <rapidjson/writer.h>
11 
12 #include "absl/container/inlined_vector.h"
13 #include "absl/strings/str_cat.h"
14 #include "absl/strings/str_format.h"
15 #include "absl/types/optional.h"
16 #include "absl/types/variant.h"
17 
18 #include "base/logging.h"
19 #include "util/pb/refl.h"
20 
21 using std::string;
22 namespace gpb = ::google::protobuf;
23 namespace rj = ::rapidjson;
24 
25 namespace util {
26 namespace {
27 
28 typedef gpb::FieldDescriptor FD;
29 using RapidWriter =
30  rj::Writer<rj::StringBuffer, rj::UTF8<>, rj::UTF8<>, rj::CrtAllocator, rj::kWriteNanAndInfFlag>;
31 
32 void PrintValue(const gpb::Message& msg, const Pb2JsonOptions& options,
33  const gpb::FieldDescriptor* fd, const gpb::Reflection* refl, RapidWriter* res);
34 void PrintRepeated(const gpb::Message& msg, const Pb2JsonOptions& options,
35  const gpb::FieldDescriptor* fd, const gpb::Reflection* refl, RapidWriter* res);
36 
37 void Pb2JsonInternal(const ::google::protobuf::Message& msg, const Pb2JsonOptions& options,
38  RapidWriter* res) {
39  const gpb::Descriptor* descr = msg.GetDescriptor();
40  const gpb::Reflection* refl = msg.GetReflection();
41  res->StartObject();
42  for (int i = 0; i < descr->field_count(); ++i) {
43  const gpb::FieldDescriptor* fd = descr->field(i);
44  bool is_set = (fd->is_repeated() && refl->FieldSize(msg, fd) > 0) || fd->is_required() ||
45  (fd->is_optional() && refl->HasField(msg, fd));
46  if (!is_set)
47  continue;
48 
49  const string& fname = options.field_name_cb ? options.field_name_cb(*fd) : fd->name();
50  if (fname.empty())
51  continue;
52  res->Key(fname.c_str(), fname.size());
53  if (fd->is_repeated()) {
54  PrintRepeated(msg, options, fd, refl, res);
55  } else {
56  PrintValue(msg, options, fd, refl, res);
57  }
58  }
59  res->EndObject();
60 }
61 
62 void PrintValue(const gpb::Message& msg, const Pb2JsonOptions& options,
63  const gpb::FieldDescriptor* fd, const gpb::Reflection* refl, RapidWriter* res) {
64  switch (fd->cpp_type()) {
65  case FD::CPPTYPE_INT32:
66  res->Int(refl->GetInt32(msg, fd));
67  break;
68  case FD::CPPTYPE_UINT32:
69  res->Uint(refl->GetUInt32(msg, fd));
70  break;
71  case FD::CPPTYPE_INT64:
72  res->Int64(refl->GetInt64(msg, fd));
73  break;
74  case FD::CPPTYPE_UINT64:
75  res->Uint64(refl->GetUInt64(msg, fd));
76  break;
77  case FD::CPPTYPE_FLOAT: {
78  float fval = refl->GetFloat(msg, fd);
79  char buf[40];
80  int sz = absl::SNPrintF(buf, sizeof(buf), "%.7g", fval);
81  res->RawValue(buf, sz, rj::kNumberType);
82  } break;
83  case FD::CPPTYPE_DOUBLE:
84  res->Double(refl->GetDouble(msg, fd));
85  break;
86  case FD::CPPTYPE_STRING: {
87  string scratch;
88  const string& value = refl->GetStringReference(msg, fd, &scratch);
89  res->String(value.c_str(), value.size());
90  } break;
91  case FD::CPPTYPE_BOOL: {
92  bool b = refl->GetBool(msg, fd);
93  // Unfortunate hack in our company code.
94  if (options.bool_as_int && options.bool_as_int(*fd)) {
95  res->Int(int(b));
96  } else {
97  res->Bool(b);
98  }
99  } break;
100 
101  case FD::CPPTYPE_ENUM:
102  if (options.enum_as_ints) {
103  res->Int(refl->GetEnum(msg, fd)->number());
104  } else {
105  const auto& tmp = refl->GetEnum(msg, fd)->name();
106  res->String(tmp.c_str(), tmp.size());
107  }
108  break;
109  case FD::CPPTYPE_MESSAGE:
110  Pb2JsonInternal(refl->GetMessage(msg, fd), options, res);
111  break;
112  default:
113  LOG(FATAL) << "Not supported field " << fd->cpp_type_name();
114  }
115 }
116 
117 template <FD::CppType t, typename Cb>
118 void UnwindArr(const gpb::Message& msg, const gpb::FieldDescriptor* fd, const gpb::Reflection* refl,
119  Cb cb) {
120  using CppType = typename pb::FD_Traits_t<t>;
121  const auto& arr = refl->GetRepeatedFieldRef<CppType>(msg, fd);
122  std::for_each(std::begin(arr), std::end(arr), cb);
123 }
124 
125 void PrintRepeated(const gpb::Message& msg, const Pb2JsonOptions& options,
126  const gpb::FieldDescriptor* fd, const gpb::Reflection* refl, RapidWriter* res) {
127  res->StartArray();
128  switch (fd->cpp_type()) {
129  case FD::CPPTYPE_INT32:
130  UnwindArr<FD::CPPTYPE_INT32>(msg, fd, refl, [res](auto val) { res->Int(val); });
131  break;
132  case FD::CPPTYPE_UINT32:
133  UnwindArr<FD::CPPTYPE_UINT32>(msg, fd, refl, [res](auto val) { res->Uint(val); });
134  break;
135  case FD::CPPTYPE_INT64:
136  UnwindArr<FD::CPPTYPE_INT64>(msg, fd, refl, [res](auto val) { res->Int64(val); });
137  break;
138  case FD::CPPTYPE_UINT64:
139  UnwindArr<FD::CPPTYPE_UINT64>(msg, fd, refl, [res](auto val) { res->Uint64(val); });
140  break;
141  case FD::CPPTYPE_FLOAT:
142  UnwindArr<FD::CPPTYPE_FLOAT>(msg, fd, refl, [res](auto val) { res->Double(val); });
143  break;
144  case FD::CPPTYPE_DOUBLE:
145  UnwindArr<FD::CPPTYPE_DOUBLE>(msg, fd, refl, [res](auto val) { res->Double(val); });
146  break;
147  case FD::CPPTYPE_STRING:
148  UnwindArr<FD::CPPTYPE_STRING>(
149  msg, fd, refl, [res](const string& val) { res->String(val.c_str(), val.size()); });
150  break;
151  case FD::CPPTYPE_BOOL:
152  UnwindArr<FD::CPPTYPE_BOOL>(msg, fd, refl, [res](auto val) { res->Bool(val); });
153  break;
154 
155  case FD::CPPTYPE_ENUM: {
156  int sz = refl->FieldSize(msg, fd);
157  for (int i = 0; i < sz; ++i) {
158  const gpb::EnumValueDescriptor* edescr = refl->GetRepeatedEnum(msg, fd, i);
159  const string& name = edescr->name();
160  res->String(name.c_str(), name.size());
161  }
162  } break;
163  case FD::CPPTYPE_MESSAGE: {
164  const auto& arr = refl->GetRepeatedFieldRef<gpb::Message>(msg, fd);
165  std::unique_ptr<gpb::Message> scratch_space(arr.NewMessage());
166  for (int i = 0; i < arr.size(); ++i) {
167  Pb2JsonInternal(arr.Get(i, scratch_space.get()), options, res);
168  }
169  } break;
170  default:
171  LOG(FATAL) << "Not supported field " << fd->cpp_type_name();
172  }
173  res->EndArray();
174 }
175 
176 class PbHandler {
177  const Json2PbOptions& opts_;
178 
179  public:
180  string err_msg;
181  using Ch = char;
182 
183  PbHandler(const Json2PbOptions& opts, ::google::protobuf::Message* msg) : opts_(opts) {
184  stack_.emplace_back(msg->GetReflection(), msg);
185  }
186 
187  bool Key(const Ch* str, size_t len, bool copy);
188 
189  bool String(const Ch* str, size_t len, bool);
190 
191  bool StartObject();
192 
193  bool EndObject(size_t member_count);
194 
195  bool Null();
196  bool Bool(bool b);
197  bool Int(int i);
198  bool Uint(unsigned i);
199  bool Int64(int64_t i);
200  bool Uint64(uint64_t i);
201  bool Double(double d);
202 
204  bool RawNumber(const Ch* str, size_t length, bool copy) { return false; }
205 
206  bool StartArray();
207  bool EndArray(size_t elementCount);
208 
209  private:
210  bool IntRepeated(int i);
211  bool UintRepeated(unsigned i);
212  bool Int64Repeated(int64_t i);
213  bool UInt64Repeated(uint64_t i);
214  bool DoubleRepeated(double d);
215 
216  using FD = gpb::FieldDescriptor;
217  template <typename T> using MRFR = gpb::MutableRepeatedFieldRef<T>;
218 
219  using ArrRef =
220  absl::variant<MRFR<bool>, MRFR<uint32_t>, MRFR<int32_t>, MRFR<uint64_t>, MRFR<int64_t>,
221  MRFR<float>, MRFR<double>, MRFR<string>, MRFR<gpb::Message>>;
222 
223  struct Object {
224  const gpb::Reflection* refl;
225  gpb::Message* msg;
226 
227  absl::optional<std::pair<const FD*, ArrRef>> arr_ref;
228 
229  Object(const gpb::Reflection* r, gpb::Message* m) : refl(r), msg(m) {}
230 
231  template <FD::CppType t> auto& GetArray() {
232  return absl::get<MRFR<pb::FD_Traits_t<t>>>(arr_ref->second);
233  }
234  };
235 
236  template <FD::CppType t> static auto MakeArr(const FD* f, const Object& o) {
237  return std::pair<const FD*, ArrRef>{f, pb::GetMutableArray<t>(o.refl, f, o.msg)};
238  }
239 
240  absl::InlinedVector<Object, 16> stack_;
241  const gpb::FieldDescriptor* field_ = nullptr;
242  string key_name_;
243 
244  unsigned disabled_level_ = 0;
245 };
246 
247 bool PbHandler::Key(const Ch* str, size_t len, bool copy) {
248  if (disabled_level_ > 1) {
249  return true;
250  }
251 
252  key_name_.assign(str, len);
253 
254  DCHECK(!stack_.empty());
255  auto& obj = stack_.back();
256 
257  const auto& msg = *obj.msg;
258  field_ = msg.GetDescriptor()->FindFieldByName(key_name_);
259 
260  return field_ != nullptr || opts_.skip_unknown_fields;
261 }
262 
263 bool PbHandler::String(const Ch* str, size_t len, bool) {
264  DCHECK(!stack_.empty());
265  auto& obj = stack_.back();
266 
267  const string str_val(str, len);
268 
269  if (obj.arr_ref) {
270  obj.GetArray<FD::CPPTYPE_STRING>().Add(str_val);
271  return true;
272  }
273 
274  if (!field_)
275  return opts_.skip_unknown_fields;
276 
277  switch (field_->cpp_type()) {
278  case FD::CPPTYPE_STRING:
279  obj.refl->SetString(obj.msg, field_, str_val);
280  break;
281  case FD::CPPTYPE_ENUM: {
282  const gpb::EnumValueDescriptor* ev = field_->enum_type()->FindValueByName(str_val);
283  if (!ev)
284  return false;
285  obj.refl->SetEnum(obj.msg, field_, ev);
286  } break;
287 
288  default:
289  return false;
290  }
291  field_ = nullptr;
292 
293  return true;
294 }
295 
296 bool PbHandler::StartObject() {
297  DCHECK(!stack_.empty());
298 
299  auto& obj = stack_.back();
300  if (obj.arr_ref) {
301  const FD* field = obj.arr_ref->first;
302  if (field->cpp_type() != FD::CPPTYPE_MESSAGE) {
303  err_msg = absl::StrCat("Expected msg type but found ", field->cpp_type_name());
304  return false;
305  }
306  gpb::Message* child = obj.refl->AddMessage(obj.msg, field);
307  stack_.emplace_back(child->GetReflection(), child);
308  return true;
309  }
310 
311  if (!field_) {
312  ++disabled_level_;
313  return disabled_level_ == 1 || opts_.skip_unknown_fields;
314  }
315 
316  if (field_->cpp_type() != gpb::FieldDescriptor::CPPTYPE_MESSAGE) {
317  err_msg = absl::StrCat("Error in StartObject, type ", field_->cpp_type_name());
318  return false;
319  }
320 
321  gpb::Message* child = obj.refl->MutableMessage(obj.msg, field_);
322  stack_.emplace_back(child->GetReflection(), child);
323  return true;
324 }
325 
326 bool PbHandler::EndObject(size_t member_count) {
327  if (disabled_level_ > 1) {
328  --disabled_level_;
329  DCHECK(field_ == nullptr);
330  return true;
331  }
332 
333  DVLOG(2) << "EndObject " << member_count;
334  stack_.pop_back();
335  field_ = nullptr;
336  return true;
337 }
338 
339 bool PbHandler::Null() {
340  auto& obj = stack_.back();
341  if (field_ && !obj.arr_ref) {
342  obj.refl->ClearField(obj.msg, field_);
343  }
344  return true;
345 }
346 
347 #define CASE(Type) \
348  case FD::Type: \
349  SetField<FD::Type>(obj.refl, field_, i, obj.msg); \
350  break
351 
352 bool PbHandler::Bool(bool b) {
353  auto& obj = stack_.back();
354  if (obj.arr_ref) {
355  const FD* field = obj.arr_ref->first;
356  if (field->cpp_type() != FD::CPPTYPE_BOOL) {
357  err_msg = absl::StrCat("Expected msg type but found ", field->cpp_type_name());
358  return false;
359  }
360  obj.GetArray<FD::CPPTYPE_BOOL>().Add(b);
361  return true;
362  }
363 
364  if (!field_)
365  return opts_.skip_unknown_fields;
366 
367  if (field_->cpp_type() != FD::CPPTYPE_BOOL) {
368  err_msg = absl::StrCat("Expected BOOL, found ", field_->cpp_type_name());
369  return false;
370  }
371 
372  pb::SetField<FD::CPPTYPE_BOOL>(obj.refl, field_, b, obj.msg);
373 
374  return true;
375 }
376 
377 bool PbHandler::Int(int i) {
378  auto& obj = stack_.back();
379 
380  if (obj.arr_ref) {
381  return IntRepeated(i);
382  }
383 
384  if (!field_) {
385  return !key_name_.empty() && opts_.skip_unknown_fields;
386  }
387 
388  using namespace pb;
389  switch (field_->cpp_type()) {
390  CASE(CPPTYPE_INT32);
391  CASE(CPPTYPE_INT64);
392  CASE(CPPTYPE_FLOAT);
393  CASE(CPPTYPE_DOUBLE);
394  default:
395  err_msg = absl::StrCat("Unexpected int type ", field_->cpp_type_name());
396  return false;
397  }
398  return true;
399 }
400 
401 bool PbHandler::IntRepeated(int i) {
402  auto& obj = stack_.back();
403 
404  const FD* field = obj.arr_ref->first;
405  switch (field->cpp_type()) {
406  case FD::CPPTYPE_INT32:
407  obj.GetArray<FD::CPPTYPE_INT32>().Add(i);
408  break;
409  case FD::CPPTYPE_INT64:
410  obj.GetArray<FD::CPPTYPE_INT64>().Add(i);
411  break;
412  case FD::CPPTYPE_FLOAT:
413  obj.GetArray<FD::CPPTYPE_FLOAT>().Add(i);
414  break;
415  case FD::CPPTYPE_DOUBLE:
416  obj.GetArray<FD::CPPTYPE_DOUBLE>().Add(i);
417  break;
418  default:
419  err_msg = absl::StrCat("Unexpected int type ", field_->cpp_type_name());
420  return false;
421  }
422 
423  return true;
424 }
425 
426 bool PbHandler::Uint(unsigned i) {
427  auto& obj = stack_.back();
428  if (obj.arr_ref) {
429  return UintRepeated(i);
430  }
431 
432  if (!field_) {
433  return !key_name_.empty() && opts_.skip_unknown_fields;
434  }
435 
436  using namespace pb;
437  switch (field_->cpp_type()) {
438  CASE(CPPTYPE_INT32);
439  CASE(CPPTYPE_UINT32);
440  CASE(CPPTYPE_INT64);
441  CASE(CPPTYPE_UINT64);
442  CASE(CPPTYPE_FLOAT);
443  CASE(CPPTYPE_DOUBLE);
444  case FD::CPPTYPE_BOOL:
445  if (i > 1) {
446  err_msg = absl::StrCat("Invalid bool value ", i);
447  return false;
448  }
449  SetField<FD::CPPTYPE_BOOL>(obj.refl, field_, i != 0, obj.msg);
450  break;
451  default:
452  err_msg = absl::StrCat("Unexpected Uint type ", field_->cpp_type_name());
453  return false;
454  }
455  key_name_.clear();
456 
457  return true;
458 }
459 
460 bool PbHandler::Int64(int64_t i) {
461  auto& obj = stack_.back();
462  if (obj.arr_ref) {
463  return Int64Repeated(i);
464  }
465 
466  if (!field_) {
467  return !key_name_.empty() && opts_.skip_unknown_fields;
468  }
469 
470  using namespace pb;
471 
472  switch (field_->cpp_type()) {
473  CASE(CPPTYPE_INT64);
474  CASE(CPPTYPE_FLOAT);
475  CASE(CPPTYPE_DOUBLE);
476  default:
477  return false;
478  }
479  key_name_.clear();
480 
481  return true;
482 }
483 
484 bool PbHandler::Uint64(uint64_t i) {
485  auto& obj = stack_.back();
486  if (obj.arr_ref) {
487  return UInt64Repeated(i);
488  }
489 
490  if (!field_) {
491  return !key_name_.empty() && opts_.skip_unknown_fields;
492  }
493 
494  using namespace pb;
495  switch (field_->cpp_type()) {
496  CASE(CPPTYPE_UINT64);
497  CASE(CPPTYPE_FLOAT);
498  CASE(CPPTYPE_DOUBLE);
499  default:
500  err_msg = absl::StrCat("Unexpected Uint64 type ", field_->cpp_type_name());
501  return false;
502  }
503  key_name_.clear();
504 
505  return true;
506 }
507 
508 bool PbHandler::Double(double i) {
509  auto& obj = stack_.back();
510  if (obj.arr_ref) {
511  return DoubleRepeated(i);
512  }
513 
514  if (!field_) {
515  return !key_name_.empty() && opts_.skip_unknown_fields;
516  }
517 
518  using namespace pb;
519 
520  switch (field_->cpp_type()) {
521  CASE(CPPTYPE_FLOAT);
522  CASE(CPPTYPE_DOUBLE);
523  default:
524  err_msg = absl::StrCat("Unexpected Double type ", field_->cpp_type_name());
525  return false;
526  }
527  key_name_.clear();
528 
529  return true;
530 }
531 
532 #undef CASE
533 
534 bool PbHandler::UintRepeated(unsigned i) {
535  auto& obj = stack_.back();
536 
537  const FD* field = obj.arr_ref->first;
538 
539  switch (field->cpp_type()) {
540  case FD::CPPTYPE_INT32:
541  obj.GetArray<FD::CPPTYPE_INT32>().Add(i);
542  break;
543  case FD::CPPTYPE_UINT32:
544  obj.GetArray<FD::CPPTYPE_UINT32>().Add(i);
545  break;
546  case FD::CPPTYPE_INT64:
547  obj.GetArray<FD::CPPTYPE_INT64>().Add(i);
548  break;
549  case FD::CPPTYPE_UINT64:
550  obj.GetArray<FD::CPPTYPE_UINT64>().Add(i);
551  break;
552  case FD::CPPTYPE_FLOAT:
553  obj.GetArray<FD::CPPTYPE_FLOAT>().Add(i);
554  break;
555  case FD::CPPTYPE_DOUBLE:
556  obj.GetArray<FD::CPPTYPE_DOUBLE>().Add(i);
557  break;
558  case FD::CPPTYPE_BOOL:
559  if (i > 1) {
560  err_msg = absl::StrCat("Invalid bool value ", i);
561  return false;
562  }
563  obj.GetArray<FD::CPPTYPE_BOOL>().Add(i != 0);
564  break;
565  default:
566  err_msg = absl::StrCat("Unexpected uint type ", field_->cpp_type_name());
567  return false;
568  }
569 
570  return true;
571 }
572 
573 bool PbHandler::Int64Repeated(int64_t i) {
574  auto& obj = stack_.back();
575 
576  const FD* field = obj.arr_ref->first;
577 
578  switch (field->cpp_type()) {
579  case FD::CPPTYPE_INT64:
580  obj.GetArray<FD::CPPTYPE_INT64>().Add(i);
581  break;
582  case FD::CPPTYPE_FLOAT:
583  obj.GetArray<FD::CPPTYPE_FLOAT>().Add(i);
584  break;
585  case FD::CPPTYPE_DOUBLE:
586  obj.GetArray<FD::CPPTYPE_DOUBLE>().Add(i);
587  break;
588  default:
589  err_msg = absl::StrCat("Unexpected uint type ", field_->cpp_type_name());
590  return false;
591  }
592 
593  return true;
594 }
595 
596 bool PbHandler::UInt64Repeated(uint64_t i) {
597  auto& obj = stack_.back();
598 
599  const FD* field = obj.arr_ref->first;
600 
601  switch (field->cpp_type()) {
602  case FD::CPPTYPE_UINT64:
603  obj.GetArray<FD::CPPTYPE_UINT64>().Add(i);
604  break;
605  case FD::CPPTYPE_FLOAT:
606  obj.GetArray<FD::CPPTYPE_FLOAT>().Add(i);
607  break;
608  case FD::CPPTYPE_DOUBLE:
609  obj.GetArray<FD::CPPTYPE_DOUBLE>().Add(i);
610  break;
611  default:
612  err_msg = absl::StrCat("Unexpected uint type ", field_->cpp_type_name());
613  return false;
614  }
615 
616  return true;
617 }
618 
619 bool PbHandler::DoubleRepeated(double d) {
620  auto& obj = stack_.back();
621 
622  const FD* field = obj.arr_ref->first;
623 
624  switch (field->cpp_type()) {
625  case FD::CPPTYPE_FLOAT:
626  obj.GetArray<FD::CPPTYPE_FLOAT>().Add(d);
627  break;
628  case FD::CPPTYPE_DOUBLE:
629  obj.GetArray<FD::CPPTYPE_DOUBLE>().Add(d);
630  break;
631  default:
632  err_msg = absl::StrCat("Unexpected double type ", field_->cpp_type_name());
633  return false;
634  }
635 
636  return true;
637 }
638 
639 bool PbHandler::StartArray() {
640  if (!field_) {
641  ++disabled_level_;
642  return opts_.skip_unknown_fields;
643  }
644 
645  if (!field_->is_repeated()) {
646  err_msg = absl::StrCat("Bad array ", key_name_);
647  return false;
648  }
649  using FD = gpb::FieldDescriptor;
650  auto& obj = stack_.back();
651  DCHECK(!obj.arr_ref);
652 
653 #define CASE(Type) \
654  case FD::Type: \
655  obj.arr_ref.emplace(MakeArr<FD::Type>(field_, obj)); \
656  break
657 
658  switch (field_->cpp_type()) {
659  CASE(CPPTYPE_UINT32);
660  CASE(CPPTYPE_INT32);
661  CASE(CPPTYPE_UINT64);
662  CASE(CPPTYPE_INT64);
663  CASE(CPPTYPE_DOUBLE);
664  CASE(CPPTYPE_FLOAT);
665  CASE(CPPTYPE_STRING);
666  CASE(CPPTYPE_MESSAGE);
667 
668  default:
669  err_msg = absl::StrCat("Unknown array type ", field_->cpp_type_name());
670  return false;
671  }
672 #undef CASE
673  return true;
674 }
675 
676 bool PbHandler::EndArray(size_t elementCount) {
677  auto& obj = stack_.back();
678 
679  if (disabled_level_ > 1) {
680  DCHECK(!obj.arr_ref && field_ == nullptr);
681  --disabled_level_;
682  } else {
683  DCHECK(obj.arr_ref);
684  obj.arr_ref.reset();
685  field_ = nullptr;
686  key_name_.clear();
687  }
688  return true;
689 }
690 
691 } // namespace
692 
693 std::string Pb2Json(const ::google::protobuf::Message& msg, const Pb2JsonOptions& options) {
694  rj::StringBuffer sb;
695  RapidWriter rw(sb);
696  rw.SetMaxDecimalPlaces(9);
697 
698  Pb2JsonInternal(msg, options, &rw);
699  return string(sb.GetString(), sb.GetSize());
700 }
701 
702 Status Json2Pb(std::string json, ::google::protobuf::Message* msg, const Json2PbOptions& opts) {
703  rj::Reader reader;
704 
705  PbHandler h(opts, msg);
706  rj::InsituStringStream stream(&json.front());
707 
708  rj::ParseResult pr = reader.Parse<rj::kParseInsituFlag | rj::kParseTrailingCommasFlag>(stream, h);
709  if (pr.IsError()) {
710  Status st(StatusCode::PARSE_ERROR,
711  absl::StrCat(rj::GetParseError_En(pr.Code()), "/", h.err_msg));
712  return st;
713  }
714  return Status::OK;
715 }
716 
717 } // namespace util