protostream_objectwriter.cc 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274
  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