protostream_objectwriter.cc 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #include <google/protobuf/util/internal/protostream_objectwriter.h>
  31. #include <functional>
  32. #include <stack>
  33. #include <google/protobuf/stubs/once.h>
  34. #include <google/protobuf/stubs/time.h>
  35. #include <google/protobuf/wire_format_lite.h>
  36. #include <google/protobuf/util/internal/field_mask_utility.h>
  37. #include <google/protobuf/util/internal/object_location_tracker.h>
  38. #include <google/protobuf/util/internal/constants.h>
  39. #include <google/protobuf/util/internal/utility.h>
  40. #include <google/protobuf/stubs/strutil.h>
  41. #include <google/protobuf/stubs/map_util.h>
  42. #include <google/protobuf/stubs/statusor.h>
  43. namespace google {
  44. namespace protobuf {
  45. namespace util {
  46. namespace converter {
  47. using google::protobuf::internal::WireFormatLite;
  48. using util::error::INVALID_ARGUMENT;
  49. using util::Status;
  50. using util::StatusOr;
  51. ProtoStreamObjectWriter::ProtoStreamObjectWriter(
  52. TypeResolver* type_resolver, const google::protobuf::Type& type,
  53. strings::ByteSink* output, ErrorListener* listener,
  54. const ProtoStreamObjectWriter::Options& options)
  55. : ProtoWriter(type_resolver, type, output, listener),
  56. master_type_(type),
  57. current_(nullptr),
  58. options_(options) {
  59. set_ignore_unknown_fields(options_.ignore_unknown_fields);
  60. set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums);
  61. }
  62. ProtoStreamObjectWriter::ProtoStreamObjectWriter(
  63. const TypeInfo* typeinfo, const google::protobuf::Type& type,
  64. strings::ByteSink* output, ErrorListener* listener)
  65. : ProtoWriter(typeinfo, type, output, listener),
  66. master_type_(type),
  67. current_(nullptr),
  68. options_(ProtoStreamObjectWriter::Options::Defaults()) {}
  69. ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
  70. if (current_ == nullptr) return;
  71. // Cleanup explicitly in order to avoid destructor stack overflow when input
  72. // is deeply nested.
  73. // Cast to BaseElement to avoid doing additional checks (like missing fields)
  74. // during pop().
  75. std::unique_ptr<BaseElement> element(
  76. static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
  77. while (element != nullptr) {
  78. element.reset(element->pop<BaseElement>());
  79. }
  80. }
  81. namespace {
  82. // Utility method to split a string representation of Timestamp or Duration and
  83. // return the parts.
  84. void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
  85. StringPiece* nanos) {
  86. size_t idx = input.rfind('.');
  87. if (idx != string::npos) {
  88. *seconds = input.substr(0, idx);
  89. *nanos = input.substr(idx + 1);
  90. } else {
  91. *seconds = input;
  92. *nanos = StringPiece();
  93. }
  94. }
  95. Status GetNanosFromStringPiece(StringPiece s_nanos,
  96. const char* parse_failure_message,
  97. const char* exceeded_limit_message,
  98. int32* nanos) {
  99. *nanos = 0;
  100. // Count the number of leading 0s and consume them.
  101. int num_leading_zeros = 0;
  102. while (s_nanos.Consume("0")) {
  103. num_leading_zeros++;
  104. }
  105. int32 i_nanos = 0;
  106. // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
  107. // "0." + s_nanos.ToString() seconds. An int32 is used for the
  108. // conversion to 'nanos', rather than a double, so that there is no
  109. // loss of precision.
  110. if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
  111. return Status(INVALID_ARGUMENT, parse_failure_message);
  112. }
  113. if (i_nanos > kNanosPerSecond || i_nanos < 0) {
  114. return Status(INVALID_ARGUMENT, exceeded_limit_message);
  115. }
  116. // s_nanos should only have digits. No whitespace.
  117. if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
  118. return Status(INVALID_ARGUMENT, parse_failure_message);
  119. }
  120. if (i_nanos > 0) {
  121. // 'scale' is the number of digits to the right of the decimal
  122. // point in "0." + s_nanos.ToString()
  123. int32 scale = num_leading_zeros + s_nanos.size();
  124. // 'conversion' converts i_nanos into nanoseconds.
  125. // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
  126. // For efficiency, we precompute the conversion factor.
  127. int32 conversion = 0;
  128. switch (scale) {
  129. case 1:
  130. conversion = 100000000;
  131. break;
  132. case 2:
  133. conversion = 10000000;
  134. break;
  135. case 3:
  136. conversion = 1000000;
  137. break;
  138. case 4:
  139. conversion = 100000;
  140. break;
  141. case 5:
  142. conversion = 10000;
  143. break;
  144. case 6:
  145. conversion = 1000;
  146. break;
  147. case 7:
  148. conversion = 100;
  149. break;
  150. case 8:
  151. conversion = 10;
  152. break;
  153. case 9:
  154. conversion = 1;
  155. break;
  156. default:
  157. return Status(INVALID_ARGUMENT, exceeded_limit_message);
  158. }
  159. *nanos = i_nanos * conversion;
  160. }
  161. return Status();
  162. }
  163. } // namespace
  164. ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
  165. : parent_(parent),
  166. ow_(),
  167. invalid_(false),
  168. data_(),
  169. output_(&data_),
  170. depth_(0),
  171. is_well_known_type_(false),
  172. well_known_type_render_(nullptr) {}
  173. ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}
  174. void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
  175. ++depth_;
  176. // If an object writer is absent, that means we have not called StartAny()
  177. // before reaching here, which happens when we have data before the "@type"
  178. // field.
  179. if (ow_ == nullptr) {
  180. // Save data before the "@type" field for later replay.
  181. uninterpreted_events_.push_back(Event(Event::START_OBJECT, name));
  182. } else if (is_well_known_type_ && depth_ == 1) {
  183. // For well-known types, the only other field besides "@type" should be a
  184. // "value" field.
  185. if (name != "value" && !invalid_) {
  186. parent_->InvalidValue("Any",
  187. "Expect a \"value\" field for well-known types.");
  188. invalid_ = true;
  189. }
  190. ow_->StartObject("");
  191. } else {
  192. // Forward the call to the child writer if:
  193. // 1. the type is not a well-known type.
  194. // 2. or, we are in a nested Any, Struct, or Value object.
  195. ow_->StartObject(name);
  196. }
  197. }
  198. bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
  199. --depth_;
  200. if (ow_ == nullptr) {
  201. if (depth_ >= 0) {
  202. // Save data before the "@type" field for later replay.
  203. uninterpreted_events_.push_back(Event(Event::END_OBJECT));
  204. }
  205. } else if (depth_ >= 0 || !is_well_known_type_) {
  206. // As long as depth_ >= 0, we know we haven't reached the end of Any.
  207. // Propagate these EndObject() calls to the contained ow_. For regular
  208. // message types, we propagate the end of Any as well.
  209. ow_->EndObject();
  210. }
  211. // A negative depth_ implies that we have reached the end of Any
  212. // object. Now we write out its contents.
  213. if (depth_ < 0) {
  214. WriteAny();
  215. return false;
  216. }
  217. return true;
  218. }
  219. void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
  220. ++depth_;
  221. if (ow_ == nullptr) {
  222. // Save data before the "@type" field for later replay.
  223. uninterpreted_events_.push_back(Event(Event::START_LIST, name));
  224. } else if (is_well_known_type_ && depth_ == 1) {
  225. if (name != "value" && !invalid_) {
  226. parent_->InvalidValue("Any",
  227. "Expect a \"value\" field for well-known types.");
  228. invalid_ = true;
  229. }
  230. ow_->StartList("");
  231. } else {
  232. ow_->StartList(name);
  233. }
  234. }
  235. void ProtoStreamObjectWriter::AnyWriter::EndList() {
  236. --depth_;
  237. if (depth_ < 0) {
  238. GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
  239. depth_ = 0;
  240. }
  241. if (ow_ == nullptr) {
  242. // Save data before the "@type" field for later replay.
  243. uninterpreted_events_.push_back(Event(Event::END_LIST));
  244. } else {
  245. ow_->EndList();
  246. }
  247. }
  248. void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
  249. StringPiece name, const DataPiece& value) {
  250. // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type"
  251. // should go to the contained ow_ as they indicate nested Anys.
  252. if (depth_ == 0 && ow_ == nullptr && name == "@type") {
  253. StartAny(value);
  254. } else if (ow_ == nullptr) {
  255. // Save data before the "@type" field.
  256. uninterpreted_events_.push_back(Event(name, value));
  257. } else if (depth_ == 0 && is_well_known_type_) {
  258. if (name != "value" && !invalid_) {
  259. parent_->InvalidValue("Any",
  260. "Expect a \"value\" field for well-known types.");
  261. invalid_ = true;
  262. }
  263. if (well_known_type_render_ == nullptr) {
  264. // Only Any and Struct don't have a special type render but both of
  265. // them expect a JSON object (i.e., a StartObject() call).
  266. if (value.type() != DataPiece::TYPE_NULL && !invalid_) {
  267. parent_->InvalidValue("Any", "Expect a JSON object.");
  268. invalid_ = true;
  269. }
  270. } else {
  271. ow_->ProtoWriter::StartObject("");
  272. Status status = (*well_known_type_render_)(ow_.get(), value);
  273. if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
  274. ow_->ProtoWriter::EndObject();
  275. }
  276. } else {
  277. ow_->RenderDataPiece(name, value);
  278. }
  279. }
  280. void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
  281. // Figure out the type url. This is a copy-paste from WriteString but we also
  282. // need the value, so we can't just call through to that.
  283. if (value.type() == DataPiece::TYPE_STRING) {
  284. type_url_ = value.str().ToString();
  285. } else {
  286. StatusOr<string> s = value.ToString();
  287. if (!s.ok()) {
  288. parent_->InvalidValue("String", s.status().error_message());
  289. invalid_ = true;
  290. return;
  291. }
  292. type_url_ = s.ValueOrDie();
  293. }
  294. // Resolve the type url, and report an error if we failed to resolve it.
  295. StatusOr<const google::protobuf::Type*> resolved_type =
  296. parent_->typeinfo()->ResolveTypeUrl(type_url_);
  297. if (!resolved_type.ok()) {
  298. parent_->InvalidValue("Any", resolved_type.status().error_message());
  299. invalid_ = true;
  300. return;
  301. }
  302. // At this point, type is never null.
  303. const google::protobuf::Type* type = resolved_type.ValueOrDie();
  304. well_known_type_render_ = FindTypeRenderer(type_url_);
  305. if (well_known_type_render_ != nullptr ||
  306. // Explicitly list Any and Struct here because they don't have a
  307. // custom renderer.
  308. type->name() == kAnyType || type->name() == kStructType) {
  309. is_well_known_type_ = true;
  310. }
  311. // Create our object writer and initialize it with the first StartObject
  312. // call.
  313. ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
  314. parent_->listener()));
  315. // Don't call StartObject() for well-known types yet. Depending on the
  316. // type of actual data, we may not need to call StartObject(). For
  317. // example:
  318. // {
  319. // "@type": "type.googleapis.com/google.protobuf.Value",
  320. // "value": [1, 2, 3],
  321. // }
  322. // With the above JSON representation, we will only call StartList() on the
  323. // contained ow_.
  324. if (!is_well_known_type_) {
  325. ow_->StartObject("");
  326. }
  327. // Now we know the proto type and can interpret all data fields we gathered
  328. // before the "@type" field.
  329. for (int i = 0; i < uninterpreted_events_.size(); ++i) {
  330. uninterpreted_events_[i].Replay(this);
  331. }
  332. }
  333. void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
  334. if (ow_ == nullptr) {
  335. if (uninterpreted_events_.empty()) {
  336. // We never got any content, so just return immediately, which is
  337. // equivalent to writing an empty Any.
  338. return;
  339. } else {
  340. // There are uninterpreted data, but we never got a "@type" field.
  341. if (!invalid_) {
  342. parent_->InvalidValue("Any", StrCat("Missing @type for any field in ",
  343. parent_->master_type_.name()));
  344. invalid_ = true;
  345. }
  346. return;
  347. }
  348. }
  349. // Render the type_url and value fields directly to the stream.
  350. // type_url has tag 1 and value has tag 2.
  351. WireFormatLite::WriteString(1, type_url_, parent_->stream());
  352. if (!data_.empty()) {
  353. WireFormatLite::WriteBytes(2, data_, parent_->stream());
  354. }
  355. }
  356. void ProtoStreamObjectWriter::AnyWriter::Event::Replay(
  357. AnyWriter* writer) const {
  358. switch (type_) {
  359. case START_OBJECT:
  360. writer->StartObject(name_);
  361. break;
  362. case END_OBJECT:
  363. writer->EndObject();
  364. break;
  365. case START_LIST:
  366. writer->StartList(name_);
  367. break;
  368. case END_LIST:
  369. writer->EndList();
  370. break;
  371. case RENDER_DATA_PIECE:
  372. writer->RenderDataPiece(name_, value_);
  373. break;
  374. }
  375. }
  376. void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() {
  377. // DataPiece only contains a string reference. To make sure the referenced
  378. // string value stays valid, we make a copy of the string value and update
  379. // DataPiece to reference our own copy.
  380. if (value_.type() == DataPiece::TYPE_STRING) {
  381. StrAppend(&value_storage_, value_.str());
  382. value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding());
  383. } else if (value_.type() == DataPiece::TYPE_BYTES) {
  384. value_storage_ = value_.ToBytes().ValueOrDie();
  385. value_ =
  386. DataPiece(value_storage_, true, value_.use_strict_base64_decoding());
  387. }
  388. }
  389. ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
  390. ItemType item_type, bool is_placeholder,
  391. bool is_list)
  392. : BaseElement(nullptr),
  393. ow_(enclosing),
  394. any_(),
  395. item_type_(item_type),
  396. is_placeholder_(is_placeholder),
  397. is_list_(is_list) {
  398. if (item_type_ == ANY) {
  399. any_.reset(new AnyWriter(ow_));
  400. }
  401. if (item_type == MAP) {
  402. map_keys_.reset(new hash_set<string>);
  403. }
  404. }
  405. ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
  406. ItemType item_type, bool is_placeholder,
  407. bool is_list)
  408. : BaseElement(parent),
  409. ow_(this->parent()->ow_),
  410. any_(),
  411. item_type_(item_type),
  412. is_placeholder_(is_placeholder),
  413. is_list_(is_list) {
  414. if (item_type == ANY) {
  415. any_.reset(new AnyWriter(ow_));
  416. }
  417. if (item_type == MAP) {
  418. map_keys_.reset(new hash_set<string>);
  419. }
  420. }
  421. bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
  422. StringPiece map_key) {
  423. return InsertIfNotPresent(map_keys_.get(), map_key.ToString());
  424. }
  425. ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
  426. StringPiece name) {
  427. if (invalid_depth() > 0) {
  428. IncrementInvalidDepth();
  429. return this;
  430. }
  431. // Starting the root message. Create the root Item and return.
  432. // ANY message type does not need special handling, just set the ItemType
  433. // to ANY.
  434. if (current_ == nullptr) {
  435. ProtoWriter::StartObject(name);
  436. current_.reset(new Item(
  437. this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
  438. false, false));
  439. // If master type is a special type that needs extra values to be written to
  440. // stream, we write those values.
  441. if (master_type_.name() == kStructType) {
  442. // Struct has a map<string, Value> field called "fields".
  443. // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
  444. // "fields": [
  445. Push("fields", Item::MAP, true, true);
  446. return this;
  447. }
  448. if (master_type_.name() == kStructValueType) {
  449. // We got a StartObject call with google.protobuf.Value field. The only
  450. // object within that type is a struct type. So start a struct.
  451. //
  452. // The struct field in Value type is named "struct_value"
  453. // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
  454. // Also start the map field "fields" within the struct.
  455. // "struct_value": {
  456. // "fields": [
  457. Push("struct_value", Item::MESSAGE, true, false);
  458. Push("fields", Item::MAP, true, true);
  459. return this;
  460. }
  461. if (master_type_.name() == kStructListValueType) {
  462. InvalidValue(kStructListValueType,
  463. "Cannot start root message with ListValue.");
  464. }
  465. return this;
  466. }
  467. // Send all ANY events to AnyWriter.
  468. if (current_->IsAny()) {
  469. current_->any()->StartObject(name);
  470. return this;
  471. }
  472. // If we are within a map, we render name as keys and send StartObject to the
  473. // value field.
  474. if (current_->IsMap()) {
  475. if (!ValidMapKey(name)) {
  476. IncrementInvalidDepth();
  477. return this;
  478. }
  479. // Map is a repeated field of message type with a "key" and a "value" field.
  480. // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
  481. // message MapFieldEntry {
  482. // key_type key = 1;
  483. // value_type value = 2;
  484. // }
  485. //
  486. // repeated MapFieldEntry map_field = N;
  487. //
  488. // That means, we render the following element within a list (hence no
  489. // name):
  490. // { "key": "<name>", "value": {
  491. Push("", Item::MESSAGE, false, false);
  492. ProtoWriter::RenderDataPiece("key",
  493. DataPiece(name, use_strict_base64_decoding()));
  494. Push("value", Item::MESSAGE, true, false);
  495. // Make sure we are valid so far after starting map fields.
  496. if (invalid_depth() > 0) return this;
  497. // If top of stack is g.p.Struct type, start the struct the map field within
  498. // it.
  499. if (element() != nullptr && IsStruct(*element()->parent_field())) {
  500. // Render "fields": [
  501. Push("fields", Item::MAP, true, true);
  502. return this;
  503. }
  504. // If top of stack is g.p.Value type, start the Struct within it.
  505. if (element() != nullptr && IsStructValue(*element()->parent_field())) {
  506. // Render
  507. // "struct_value": {
  508. // "fields": [
  509. Push("struct_value", Item::MESSAGE, true, false);
  510. Push("fields", Item::MAP, true, true);
  511. }
  512. return this;
  513. }
  514. const google::protobuf::Field* field = BeginNamed(name, false);
  515. if (field == nullptr) return this;
  516. if (IsStruct(*field)) {
  517. // Start a struct object.
  518. // Render
  519. // "<name>": {
  520. // "fields": {
  521. Push(name, Item::MESSAGE, false, false);
  522. Push("fields", Item::MAP, true, true);
  523. return this;
  524. }
  525. if (IsStructValue(*field)) {
  526. // We got a StartObject call with google.protobuf.Value field. The only
  527. // object within that type is a struct type. So start a struct.
  528. // Render
  529. // "<name>": {
  530. // "struct_value": {
  531. // "fields": {
  532. Push(name, Item::MESSAGE, false, false);
  533. Push("struct_value", Item::MESSAGE, true, false);
  534. Push("fields", Item::MAP, true, true);
  535. return this;
  536. }
  537. if (IsMap(*field)) {
  538. // Begin a map. A map is triggered by a StartObject() call if the current
  539. // field has a map type.
  540. // A map type is always repeated, hence set is_list to true.
  541. // Render
  542. // "<name>": [
  543. Push(name, Item::MAP, false, true);
  544. return this;
  545. }
  546. // A regular message type. Pass it directly to ProtoWriter.
  547. // Render
  548. // "<name>": {
  549. Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
  550. return this;
  551. }
  552. ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
  553. if (invalid_depth() > 0) {
  554. DecrementInvalidDepth();
  555. return this;
  556. }
  557. if (current_ == nullptr) return this;
  558. if (current_->IsAny()) {
  559. if (current_->any()->EndObject()) return this;
  560. }
  561. Pop();
  562. return this;
  563. }
  564. ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
  565. if (invalid_depth() > 0) {
  566. IncrementInvalidDepth();
  567. return this;
  568. }
  569. // Since we cannot have a top-level repeated item in protobuf, the only way
  570. // this is valid is if we start a special type google.protobuf.ListValue or
  571. // google.protobuf.Value.
  572. if (current_ == nullptr) {
  573. if (!name.empty()) {
  574. InvalidName(name, "Root element should not be named.");
  575. IncrementInvalidDepth();
  576. return this;
  577. }
  578. // If master type is a special type that needs extra values to be written to
  579. // stream, we write those values.
  580. if (master_type_.name() == kStructValueType) {
  581. // We got a StartList with google.protobuf.Value master type. This means
  582. // we have to start the "list_value" within google.protobuf.Value.
  583. //
  584. // See
  585. // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
  586. //
  587. // Render
  588. // "<name>": {
  589. // "list_value": {
  590. // "values": [ // Start this list.
  591. ProtoWriter::StartObject(name);
  592. current_.reset(new Item(this, Item::MESSAGE, false, false));
  593. Push("list_value", Item::MESSAGE, true, false);
  594. Push("values", Item::MESSAGE, true, true);
  595. return this;
  596. }
  597. if (master_type_.name() == kStructListValueType) {
  598. // We got a StartList with google.protobuf.ListValue master type. This
  599. // means we have to start the "values" within google.protobuf.ListValue.
  600. //
  601. // Render
  602. // "<name>": {
  603. // "values": [ // Start this list.
  604. ProtoWriter::StartObject(name);
  605. current_.reset(new Item(this, Item::MESSAGE, false, false));
  606. Push("values", Item::MESSAGE, true, true);
  607. return this;
  608. }
  609. // Send the event to ProtoWriter so proper errors can be reported.
  610. //
  611. // Render a regular list:
  612. // "<name>": [
  613. ProtoWriter::StartList(name);
  614. current_.reset(new Item(this, Item::MESSAGE, false, true));
  615. return this;
  616. }
  617. if (current_->IsAny()) {
  618. current_->any()->StartList(name);
  619. return this;
  620. }
  621. // If the top of stack is a map, we are starting a list value within a map.
  622. // Since map does not allow repeated values, this can only happen when the map
  623. // value is of a special type that renders a list in JSON. These can be one
  624. // of 3 cases:
  625. // i. We are rendering a list value within google.protobuf.Struct
  626. // ii. We are rendering a list value within google.protobuf.Value
  627. // iii. We are rendering a list value with type google.protobuf.ListValue.
  628. if (current_->IsMap()) {
  629. if (!ValidMapKey(name)) {
  630. IncrementInvalidDepth();
  631. return this;
  632. }
  633. // Start the repeated map entry object.
  634. // Render
  635. // { "key": "<name>", "value": {
  636. Push("", Item::MESSAGE, false, false);
  637. ProtoWriter::RenderDataPiece("key",
  638. DataPiece(name, use_strict_base64_decoding()));
  639. Push("value", Item::MESSAGE, true, false);
  640. // Make sure we are valid after pushing all above items.
  641. if (invalid_depth() > 0) return this;
  642. // case i and ii above. Start "list_value" field within g.p.Value
  643. if (element() != nullptr && element()->parent_field() != nullptr) {
  644. // Render
  645. // "list_value": {
  646. // "values": [ // Start this list
  647. if (IsStructValue(*element()->parent_field())) {
  648. Push("list_value", Item::MESSAGE, true, false);
  649. Push("values", Item::MESSAGE, true, true);
  650. return this;
  651. }
  652. // Render
  653. // "values": [
  654. if (IsStructListValue(*element()->parent_field())) {
  655. // case iii above. Bind directly to g.p.ListValue
  656. Push("values", Item::MESSAGE, true, true);
  657. return this;
  658. }
  659. }
  660. // Report an error.
  661. InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
  662. "') within a map."));
  663. return this;
  664. }
  665. // When name is empty and stack is not empty, we are rendering an item within
  666. // a list.
  667. if (name.empty()) {
  668. if (element() != nullptr && element()->parent_field() != nullptr) {
  669. if (IsStructValue(*element()->parent_field())) {
  670. // Since it is g.p.Value, we bind directly to the list_value.
  671. // Render
  672. // { // g.p.Value item within the list
  673. // "list_value": {
  674. // "values": [
  675. Push("", Item::MESSAGE, false, false);
  676. Push("list_value", Item::MESSAGE, true, false);
  677. Push("values", Item::MESSAGE, true, true);
  678. return this;
  679. }
  680. if (IsStructListValue(*element()->parent_field())) {
  681. // Since it is g.p.ListValue, we bind to it directly.
  682. // Render
  683. // { // g.p.ListValue item within the list
  684. // "values": [
  685. Push("", Item::MESSAGE, false, false);
  686. Push("values", Item::MESSAGE, true, true);
  687. return this;
  688. }
  689. }
  690. // Pass the event to underlying ProtoWriter.
  691. Push(name, Item::MESSAGE, false, true);
  692. return this;
  693. }
  694. // name is not empty
  695. const google::protobuf::Field* field = Lookup(name);
  696. if (field == nullptr) {
  697. IncrementInvalidDepth();
  698. return this;
  699. }
  700. if (IsStructValue(*field)) {
  701. // If g.p.Value is repeated, start that list. Otherwise, start the
  702. // "list_value" within it.
  703. if (IsRepeated(*field)) {
  704. // Render it just like a regular repeated field.
  705. // "<name>": [
  706. Push(name, Item::MESSAGE, false, true);
  707. return this;
  708. }
  709. // Start the "list_value" field.
  710. // Render
  711. // "<name>": {
  712. // "list_value": {
  713. // "values": [
  714. Push(name, Item::MESSAGE, false, false);
  715. Push("list_value", Item::MESSAGE, true, false);
  716. Push("values", Item::MESSAGE, true, true);
  717. return this;
  718. }
  719. if (IsStructListValue(*field)) {
  720. // If g.p.ListValue is repeated, start that list. Otherwise, start the
  721. // "values" within it.
  722. if (IsRepeated(*field)) {
  723. // Render it just like a regular repeated field.
  724. // "<name>": [
  725. Push(name, Item::MESSAGE, false, true);
  726. return this;
  727. }
  728. // Start the "values" field within g.p.ListValue.
  729. // Render
  730. // "<name>": {
  731. // "values": [
  732. Push(name, Item::MESSAGE, false, false);
  733. Push("values", Item::MESSAGE, true, true);
  734. return this;
  735. }
  736. // If we are here, the field should be repeated. Report an error otherwise.
  737. if (!IsRepeated(*field)) {
  738. IncrementInvalidDepth();
  739. InvalidName(name, "Proto field is not repeating, cannot start list.");
  740. return this;
  741. }
  742. if (IsMap(*field)) {
  743. InvalidValue("Map",
  744. StrCat("Cannot bind a list to map for field '", name, "'."));
  745. IncrementInvalidDepth();
  746. return this;
  747. }
  748. // Pass the event to ProtoWriter.
  749. // Render
  750. // "<name>": [
  751. Push(name, Item::MESSAGE, false, true);
  752. return this;
  753. }
  754. ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
  755. if (invalid_depth() > 0) {
  756. DecrementInvalidDepth();
  757. return this;
  758. }
  759. if (current_ == nullptr) return this;
  760. if (current_->IsAny()) {
  761. current_->any()->EndList();
  762. return this;
  763. }
  764. Pop();
  765. return this;
  766. }
  767. Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
  768. const DataPiece& data) {
  769. string struct_field_name;
  770. switch (data.type()) {
  771. // Our JSON parser parses numbers as either int64, uint64, or double.
  772. case DataPiece::TYPE_INT64: {
  773. // If the option to treat integers as strings is set, then render them as
  774. // strings. Otherwise, fallback to rendering them as double.
  775. if (ow->options_.struct_integers_as_strings) {
  776. StatusOr<int64> int_value = data.ToInt64();
  777. if (int_value.ok()) {
  778. ow->ProtoWriter::RenderDataPiece(
  779. "string_value",
  780. DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
  781. return Status();
  782. }
  783. }
  784. struct_field_name = "number_value";
  785. break;
  786. }
  787. case DataPiece::TYPE_UINT64: {
  788. // If the option to treat integers as strings is set, then render them as
  789. // strings. Otherwise, fallback to rendering them as double.
  790. if (ow->options_.struct_integers_as_strings) {
  791. StatusOr<uint64> int_value = data.ToUint64();
  792. if (int_value.ok()) {
  793. ow->ProtoWriter::RenderDataPiece(
  794. "string_value",
  795. DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
  796. return Status();
  797. }
  798. }
  799. struct_field_name = "number_value";
  800. break;
  801. }
  802. case DataPiece::TYPE_DOUBLE: {
  803. if (ow->options_.struct_integers_as_strings) {
  804. StatusOr<double> double_value = data.ToDouble();
  805. if (double_value.ok()) {
  806. ow->ProtoWriter::RenderDataPiece(
  807. "string_value",
  808. DataPiece(SimpleDtoa(double_value.ValueOrDie()), true));
  809. return Status();
  810. }
  811. }
  812. struct_field_name = "number_value";
  813. break;
  814. }
  815. case DataPiece::TYPE_STRING: {
  816. struct_field_name = "string_value";
  817. break;
  818. }
  819. case DataPiece::TYPE_BOOL: {
  820. struct_field_name = "bool_value";
  821. break;
  822. }
  823. case DataPiece::TYPE_NULL: {
  824. struct_field_name = "null_value";
  825. break;
  826. }
  827. default: {
  828. return Status(INVALID_ARGUMENT,
  829. "Invalid struct data type. Only number, string, boolean or "
  830. "null values are supported.");
  831. }
  832. }
  833. ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
  834. return Status();
  835. }
  836. Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
  837. const DataPiece& data) {
  838. if (data.type() == DataPiece::TYPE_NULL) return Status();
  839. if (data.type() != DataPiece::TYPE_STRING) {
  840. return Status(INVALID_ARGUMENT,
  841. StrCat("Invalid data type for timestamp, value is ",
  842. data.ValueAsStringOrDefault("")));
  843. }
  844. StringPiece value(data.str());
  845. int64 seconds;
  846. int32 nanos;
  847. if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
  848. &nanos)) {
  849. return Status(INVALID_ARGUMENT, StrCat("Invalid time format: ", value));
  850. }
  851. ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
  852. ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
  853. return Status();
  854. }
  855. static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
  856. StringPiece path) {
  857. ow->ProtoWriter::RenderDataPiece(
  858. "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
  859. return Status();
  860. }
  861. Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
  862. const DataPiece& data) {
  863. if (data.type() == DataPiece::TYPE_NULL) return Status();
  864. if (data.type() != DataPiece::TYPE_STRING) {
  865. return Status(INVALID_ARGUMENT,
  866. StrCat("Invalid data type for field mask, value is ",
  867. data.ValueAsStringOrDefault("")));
  868. }
  869. // TODO(tsun): figure out how to do proto descriptor based snake case
  870. // conversions as much as possible. Because ToSnakeCase sometimes returns the
  871. // wrong value.
  872. std::unique_ptr<ResultCallback1<util::Status, StringPiece> > callback(
  873. ::google::protobuf::NewPermanentCallback(&RenderOneFieldPath, ow));
  874. return DecodeCompactFieldMaskPaths(data.str(), callback.get());
  875. }
  876. Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
  877. const DataPiece& data) {
  878. if (data.type() == DataPiece::TYPE_NULL) return Status();
  879. if (data.type() != DataPiece::TYPE_STRING) {
  880. return Status(INVALID_ARGUMENT,
  881. StrCat("Invalid data type for duration, value is ",
  882. data.ValueAsStringOrDefault("")));
  883. }
  884. StringPiece value(data.str());
  885. if (!StringEndsWith(value, "s")) {
  886. return Status(INVALID_ARGUMENT,
  887. "Illegal duration format; duration must end with 's'");
  888. }
  889. value = value.substr(0, value.size() - 1);
  890. int sign = 1;
  891. if (StringStartsWith(value, "-")) {
  892. sign = -1;
  893. value = value.substr(1);
  894. }
  895. StringPiece s_secs, s_nanos;
  896. SplitSecondsAndNanos(value, &s_secs, &s_nanos);
  897. uint64 unsigned_seconds;
  898. if (!safe_strtou64(s_secs, &unsigned_seconds)) {
  899. return Status(INVALID_ARGUMENT,
  900. "Invalid duration format, failed to parse seconds");
  901. }
  902. int32 nanos = 0;
  903. Status nanos_status = GetNanosFromStringPiece(
  904. s_nanos, "Invalid duration format, failed to parse nano seconds",
  905. "Duration value exceeds limits", &nanos);
  906. if (!nanos_status.ok()) {
  907. return nanos_status;
  908. }
  909. nanos = sign * nanos;
  910. int64 seconds = sign * unsigned_seconds;
  911. if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
  912. nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
  913. return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
  914. }
  915. ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
  916. ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
  917. return Status();
  918. }
  919. Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
  920. const DataPiece& data) {
  921. if (data.type() == DataPiece::TYPE_NULL) return Status();
  922. ow->ProtoWriter::RenderDataPiece("value", data);
  923. return Status();
  924. }
  925. ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
  926. StringPiece name, const DataPiece& data) {
  927. Status status;
  928. if (invalid_depth() > 0) return this;
  929. if (current_ == nullptr) {
  930. const TypeRenderer* type_renderer =
  931. FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
  932. if (type_renderer == nullptr) {
  933. InvalidName(name, "Root element must be a message.");
  934. return this;
  935. }
  936. // Render the special type.
  937. // "<name>": {
  938. // ... Render special type ...
  939. // }
  940. ProtoWriter::StartObject(name);
  941. status = (*type_renderer)(this, data);
  942. if (!status.ok()) {
  943. InvalidValue(master_type_.name(),
  944. StrCat("Field '", name, "', ", status.error_message()));
  945. }
  946. ProtoWriter::EndObject();
  947. return this;
  948. }
  949. if (current_->IsAny()) {
  950. current_->any()->RenderDataPiece(name, data);
  951. return this;
  952. }
  953. const google::protobuf::Field* field = nullptr;
  954. if (current_->IsMap()) {
  955. if (!ValidMapKey(name)) return this;
  956. // Render an item in repeated map list.
  957. // { "key": "<name>", "value":
  958. Push("", Item::MESSAGE, false, false);
  959. ProtoWriter::RenderDataPiece("key",
  960. DataPiece(name, use_strict_base64_decoding()));
  961. field = Lookup("value");
  962. if (field == nullptr) {
  963. Pop();
  964. GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
  965. return this;
  966. }
  967. const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
  968. if (type_renderer != nullptr) {
  969. // Map's value type is a special type. Render it like a message:
  970. // "value": {
  971. // ... Render special type ...
  972. // }
  973. Push("value", Item::MESSAGE, true, false);
  974. status = (*type_renderer)(this, data);
  975. if (!status.ok()) {
  976. InvalidValue(field->type_url(),
  977. StrCat("Field '", name, "', ", status.error_message()));
  978. }
  979. Pop();
  980. return this;
  981. }
  982. // If we are rendering explicit null values and the backend proto field is
  983. // not of the google.protobuf.NullType type, we do nothing.
  984. if (data.type() == DataPiece::TYPE_NULL &&
  985. field->type_url() != kStructNullValueTypeUrl) {
  986. Pop();
  987. return this;
  988. }
  989. // Render the map value as a primitive type.
  990. ProtoWriter::RenderDataPiece("value", data);
  991. Pop();
  992. return this;
  993. }
  994. field = Lookup(name);
  995. if (field == nullptr) return this;
  996. // Check if the field is of special type. Render it accordingly if so.
  997. const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
  998. if (type_renderer != nullptr) {
  999. // Pass through null value only for google.protobuf.Value. For other
  1000. // types we ignore null value just like for regular field types.
  1001. if (data.type() != DataPiece::TYPE_NULL ||
  1002. field->type_url() == kStructValueTypeUrl) {
  1003. Push(name, Item::MESSAGE, false, false);
  1004. status = (*type_renderer)(this, data);
  1005. if (!status.ok()) {
  1006. InvalidValue(field->type_url(),
  1007. StrCat("Field '", name, "', ", status.error_message()));
  1008. }
  1009. Pop();
  1010. }
  1011. return this;
  1012. }
  1013. // If we are rendering explicit null values and the backend proto field is
  1014. // not of the google.protobuf.NullType type, we do nothing.
  1015. if (data.type() == DataPiece::TYPE_NULL &&
  1016. field->type_url() != kStructNullValueTypeUrl) {
  1017. return this;
  1018. }
  1019. ProtoWriter::RenderDataPiece(name, data);
  1020. return this;
  1021. }
  1022. // Map of functions that are responsible for rendering well known type
  1023. // represented by the key.
  1024. hash_map<string, ProtoStreamObjectWriter::TypeRenderer>*
  1025. ProtoStreamObjectWriter::renderers_ = NULL;
  1026. GOOGLE_PROTOBUF_DECLARE_ONCE(writer_renderers_init_);
  1027. void ProtoStreamObjectWriter::InitRendererMap() {
  1028. renderers_ = new hash_map<string, ProtoStreamObjectWriter::TypeRenderer>();
  1029. (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] =
  1030. &ProtoStreamObjectWriter::RenderTimestamp;
  1031. (*renderers_)["type.googleapis.com/google.protobuf.Duration"] =
  1032. &ProtoStreamObjectWriter::RenderDuration;
  1033. (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] =
  1034. &ProtoStreamObjectWriter::RenderFieldMask;
  1035. (*renderers_)["type.googleapis.com/google.protobuf.Double"] =
  1036. &ProtoStreamObjectWriter::RenderWrapperType;
  1037. (*renderers_)["type.googleapis.com/google.protobuf.Float"] =
  1038. &ProtoStreamObjectWriter::RenderWrapperType;
  1039. (*renderers_)["type.googleapis.com/google.protobuf.Int64"] =
  1040. &ProtoStreamObjectWriter::RenderWrapperType;
  1041. (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] =
  1042. &ProtoStreamObjectWriter::RenderWrapperType;
  1043. (*renderers_)["type.googleapis.com/google.protobuf.Int32"] =
  1044. &ProtoStreamObjectWriter::RenderWrapperType;
  1045. (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] =
  1046. &ProtoStreamObjectWriter::RenderWrapperType;
  1047. (*renderers_)["type.googleapis.com/google.protobuf.Bool"] =
  1048. &ProtoStreamObjectWriter::RenderWrapperType;
  1049. (*renderers_)["type.googleapis.com/google.protobuf.String"] =
  1050. &ProtoStreamObjectWriter::RenderWrapperType;
  1051. (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] =
  1052. &ProtoStreamObjectWriter::RenderWrapperType;
  1053. (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] =
  1054. &ProtoStreamObjectWriter::RenderWrapperType;
  1055. (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] =
  1056. &ProtoStreamObjectWriter::RenderWrapperType;
  1057. (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] =
  1058. &ProtoStreamObjectWriter::RenderWrapperType;
  1059. (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] =
  1060. &ProtoStreamObjectWriter::RenderWrapperType;
  1061. (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] =
  1062. &ProtoStreamObjectWriter::RenderWrapperType;
  1063. (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] =
  1064. &ProtoStreamObjectWriter::RenderWrapperType;
  1065. (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] =
  1066. &ProtoStreamObjectWriter::RenderWrapperType;
  1067. (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] =
  1068. &ProtoStreamObjectWriter::RenderWrapperType;
  1069. (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] =
  1070. &ProtoStreamObjectWriter::RenderWrapperType;
  1071. (*renderers_)["type.googleapis.com/google.protobuf.Value"] =
  1072. &ProtoStreamObjectWriter::RenderStructValue;
  1073. ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
  1074. }
  1075. void ProtoStreamObjectWriter::DeleteRendererMap() {
  1076. delete ProtoStreamObjectWriter::renderers_;
  1077. renderers_ = NULL;
  1078. }
  1079. ProtoStreamObjectWriter::TypeRenderer*
  1080. ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) {
  1081. ::google::protobuf::GoogleOnceInit(&writer_renderers_init_, &InitRendererMap);
  1082. return FindOrNull(*renderers_, type_url);
  1083. }
  1084. bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
  1085. if (current_ == nullptr) return true;
  1086. if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
  1087. listener()->InvalidName(
  1088. location(), unnormalized_name,
  1089. StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
  1090. return false;
  1091. }
  1092. return true;
  1093. }
  1094. void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
  1095. bool is_placeholder, bool is_list) {
  1096. is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
  1097. // invalid_depth == 0 means it is a successful StartObject or StartList.
  1098. if (invalid_depth() == 0)
  1099. current_.reset(
  1100. new Item(current_.release(), item_type, is_placeholder, is_list));
  1101. }
  1102. void ProtoStreamObjectWriter::Pop() {
  1103. // Pop all placeholder items sending StartObject or StartList events to
  1104. // ProtoWriter according to is_list value.
  1105. while (current_ != nullptr && current_->is_placeholder()) {
  1106. PopOneElement();
  1107. }
  1108. if (current_ != nullptr) {
  1109. PopOneElement();
  1110. }
  1111. }
  1112. void ProtoStreamObjectWriter::PopOneElement() {
  1113. current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
  1114. current_.reset(current_->pop<Item>());
  1115. }
  1116. bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
  1117. if (field.type_url().empty() ||
  1118. field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE ||
  1119. field.cardinality() !=
  1120. google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
  1121. return false;
  1122. }
  1123. const google::protobuf::Type* field_type =
  1124. typeinfo()->GetTypeByTypeUrl(field.type_url());
  1125. return google::protobuf::util::converter::IsMap(field, *field_type);
  1126. }
  1127. bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
  1128. return GetTypeWithoutUrl(field.type_url()) == kAnyType;
  1129. }
  1130. bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
  1131. return GetTypeWithoutUrl(field.type_url()) == kStructType;
  1132. }
  1133. bool ProtoStreamObjectWriter::IsStructValue(
  1134. const google::protobuf::Field& field) {
  1135. return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
  1136. }
  1137. bool ProtoStreamObjectWriter::IsStructListValue(
  1138. const google::protobuf::Field& field) {
  1139. return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
  1140. }
  1141. } // namespace converter
  1142. } // namespace util
  1143. } // namespace protobuf
  1144. } // namespace google