proto_writer.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  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/proto_writer.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 google::protobuf::io::CodedOutputStream;
  49. using util::error::INVALID_ARGUMENT;
  50. using util::Status;
  51. using util::StatusOr;
  52. ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
  53. const google::protobuf::Type& type,
  54. strings::ByteSink* output, ErrorListener* listener)
  55. : master_type_(type),
  56. typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
  57. own_typeinfo_(true),
  58. done_(false),
  59. ignore_unknown_fields_(false),
  60. use_lower_camel_for_enums_(false),
  61. element_(nullptr),
  62. size_insert_(),
  63. output_(output),
  64. buffer_(),
  65. adapter_(&buffer_),
  66. stream_(new CodedOutputStream(&adapter_)),
  67. listener_(listener),
  68. invalid_depth_(0),
  69. tracker_(new ObjectLocationTracker()) {}
  70. ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
  71. const google::protobuf::Type& type,
  72. strings::ByteSink* output, ErrorListener* listener)
  73. : master_type_(type),
  74. typeinfo_(typeinfo),
  75. own_typeinfo_(false),
  76. done_(false),
  77. ignore_unknown_fields_(false),
  78. use_lower_camel_for_enums_(false),
  79. element_(nullptr),
  80. size_insert_(),
  81. output_(output),
  82. buffer_(),
  83. adapter_(&buffer_),
  84. stream_(new CodedOutputStream(&adapter_)),
  85. listener_(listener),
  86. invalid_depth_(0),
  87. tracker_(new ObjectLocationTracker()) {}
  88. ProtoWriter::~ProtoWriter() {
  89. if (own_typeinfo_) {
  90. delete typeinfo_;
  91. }
  92. if (element_ == nullptr) return;
  93. // Cleanup explicitly in order to avoid destructor stack overflow when input
  94. // is deeply nested.
  95. // Cast to BaseElement to avoid doing additional checks (like missing fields)
  96. // during pop().
  97. std::unique_ptr<BaseElement> element(
  98. static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
  99. while (element != nullptr) {
  100. element.reset(element->pop<BaseElement>());
  101. }
  102. }
  103. namespace {
  104. // Writes an INT32 field, including tag to the stream.
  105. inline Status WriteInt32(int field_number, const DataPiece& data,
  106. CodedOutputStream* stream) {
  107. StatusOr<int32> i32 = data.ToInt32();
  108. if (i32.ok()) {
  109. WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
  110. }
  111. return i32.status();
  112. }
  113. // writes an SFIXED32 field, including tag, to the stream.
  114. inline Status WriteSFixed32(int field_number, const DataPiece& data,
  115. CodedOutputStream* stream) {
  116. StatusOr<int32> i32 = data.ToInt32();
  117. if (i32.ok()) {
  118. WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
  119. }
  120. return i32.status();
  121. }
  122. // Writes an SINT32 field, including tag, to the stream.
  123. inline Status WriteSInt32(int field_number, const DataPiece& data,
  124. CodedOutputStream* stream) {
  125. StatusOr<int32> i32 = data.ToInt32();
  126. if (i32.ok()) {
  127. WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
  128. }
  129. return i32.status();
  130. }
  131. // Writes a FIXED32 field, including tag, to the stream.
  132. inline Status WriteFixed32(int field_number, const DataPiece& data,
  133. CodedOutputStream* stream) {
  134. StatusOr<uint32> u32 = data.ToUint32();
  135. if (u32.ok()) {
  136. WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
  137. }
  138. return u32.status();
  139. }
  140. // Writes a UINT32 field, including tag, to the stream.
  141. inline Status WriteUInt32(int field_number, const DataPiece& data,
  142. CodedOutputStream* stream) {
  143. StatusOr<uint32> u32 = data.ToUint32();
  144. if (u32.ok()) {
  145. WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
  146. }
  147. return u32.status();
  148. }
  149. // Writes an INT64 field, including tag, to the stream.
  150. inline Status WriteInt64(int field_number, const DataPiece& data,
  151. CodedOutputStream* stream) {
  152. StatusOr<int64> i64 = data.ToInt64();
  153. if (i64.ok()) {
  154. WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
  155. }
  156. return i64.status();
  157. }
  158. // Writes an SFIXED64 field, including tag, to the stream.
  159. inline Status WriteSFixed64(int field_number, const DataPiece& data,
  160. CodedOutputStream* stream) {
  161. StatusOr<int64> i64 = data.ToInt64();
  162. if (i64.ok()) {
  163. WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
  164. }
  165. return i64.status();
  166. }
  167. // Writes an SINT64 field, including tag, to the stream.
  168. inline Status WriteSInt64(int field_number, const DataPiece& data,
  169. CodedOutputStream* stream) {
  170. StatusOr<int64> i64 = data.ToInt64();
  171. if (i64.ok()) {
  172. WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
  173. }
  174. return i64.status();
  175. }
  176. // Writes a FIXED64 field, including tag, to the stream.
  177. inline Status WriteFixed64(int field_number, const DataPiece& data,
  178. CodedOutputStream* stream) {
  179. StatusOr<uint64> u64 = data.ToUint64();
  180. if (u64.ok()) {
  181. WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
  182. }
  183. return u64.status();
  184. }
  185. // Writes a UINT64 field, including tag, to the stream.
  186. inline Status WriteUInt64(int field_number, const DataPiece& data,
  187. CodedOutputStream* stream) {
  188. StatusOr<uint64> u64 = data.ToUint64();
  189. if (u64.ok()) {
  190. WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
  191. }
  192. return u64.status();
  193. }
  194. // Writes a DOUBLE field, including tag, to the stream.
  195. inline Status WriteDouble(int field_number, const DataPiece& data,
  196. CodedOutputStream* stream) {
  197. StatusOr<double> d = data.ToDouble();
  198. if (d.ok()) {
  199. WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
  200. }
  201. return d.status();
  202. }
  203. // Writes a FLOAT field, including tag, to the stream.
  204. inline Status WriteFloat(int field_number, const DataPiece& data,
  205. CodedOutputStream* stream) {
  206. StatusOr<float> f = data.ToFloat();
  207. if (f.ok()) {
  208. WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
  209. }
  210. return f.status();
  211. }
  212. // Writes a BOOL field, including tag, to the stream.
  213. inline Status WriteBool(int field_number, const DataPiece& data,
  214. CodedOutputStream* stream) {
  215. StatusOr<bool> b = data.ToBool();
  216. if (b.ok()) {
  217. WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
  218. }
  219. return b.status();
  220. }
  221. // Writes a BYTES field, including tag, to the stream.
  222. inline Status WriteBytes(int field_number, const DataPiece& data,
  223. CodedOutputStream* stream) {
  224. StatusOr<string> c = data.ToBytes();
  225. if (c.ok()) {
  226. WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
  227. }
  228. return c.status();
  229. }
  230. // Writes a STRING field, including tag, to the stream.
  231. inline Status WriteString(int field_number, const DataPiece& data,
  232. CodedOutputStream* stream) {
  233. StatusOr<string> s = data.ToString();
  234. if (s.ok()) {
  235. WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
  236. }
  237. return s.status();
  238. }
  239. // Writes an ENUM field, including tag, to the stream.
  240. inline Status WriteEnum(int field_number, const DataPiece& data,
  241. const google::protobuf::Enum* enum_type,
  242. CodedOutputStream* stream,
  243. bool use_lower_camel_for_enums,
  244. bool ignore_unknown_values) {
  245. StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums, ignore_unknown_values);
  246. if (e.ok()) {
  247. WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
  248. }
  249. return e.status();
  250. }
  251. // Given a google::protobuf::Type, returns the set of all required fields.
  252. std::set<const google::protobuf::Field*> GetRequiredFields(
  253. const google::protobuf::Type& type) {
  254. std::set<const google::protobuf::Field*> required;
  255. for (int i = 0; i < type.fields_size(); i++) {
  256. const google::protobuf::Field& field = type.fields(i);
  257. if (field.cardinality() ==
  258. google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
  259. required.insert(&field);
  260. }
  261. }
  262. return required;
  263. }
  264. } // namespace
  265. ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
  266. const google::protobuf::Type& type,
  267. ProtoWriter* enclosing)
  268. : BaseElement(nullptr),
  269. ow_(enclosing),
  270. parent_field_(nullptr),
  271. typeinfo_(typeinfo),
  272. proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
  273. type_(type),
  274. size_index_(-1),
  275. array_index_(-1),
  276. // oneof_indices_ values are 1-indexed (0 means not present).
  277. oneof_indices_(type.oneofs_size() + 1) {
  278. if (!proto3_) {
  279. required_fields_ = GetRequiredFields(type_);
  280. }
  281. }
  282. ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
  283. const google::protobuf::Field* field,
  284. const google::protobuf::Type& type,
  285. bool is_list)
  286. : BaseElement(parent),
  287. ow_(this->parent()->ow_),
  288. parent_field_(field),
  289. typeinfo_(this->parent()->typeinfo_),
  290. proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
  291. type_(type),
  292. size_index_(
  293. !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
  294. ? ow_->size_insert_.size()
  295. : -1),
  296. array_index_(is_list ? 0 : -1),
  297. // oneof_indices_ values are 1-indexed (0 means not present).
  298. oneof_indices_(type_.oneofs_size() + 1) {
  299. if (!is_list) {
  300. if (ow_->IsRepeated(*field)) {
  301. // Update array_index_ if it is an explicit list.
  302. if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
  303. } else if (!proto3_) {
  304. // For required fields tracking.
  305. this->parent()->RegisterField(field);
  306. }
  307. if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
  308. if (!proto3_) {
  309. required_fields_ = GetRequiredFields(type_);
  310. }
  311. int start_pos = ow_->stream_->ByteCount();
  312. // length of serialized message is the final buffer position minus
  313. // starting buffer position, plus length adjustments for size fields
  314. // of any nested messages. We start with -start_pos here, so we only
  315. // need to add the final buffer position to it at the end.
  316. SizeInfo info = {start_pos, -start_pos};
  317. ow_->size_insert_.push_back(info);
  318. }
  319. }
  320. }
  321. ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
  322. if (!proto3_) {
  323. // Calls the registered error listener for any required field(s) not yet
  324. // seen.
  325. for (std::set<const google::protobuf::Field*>::iterator it =
  326. required_fields_.begin();
  327. it != required_fields_.end(); ++it) {
  328. ow_->MissingField((*it)->name());
  329. }
  330. }
  331. // Computes the total number of proto bytes used by a message, also adjusts
  332. // the size of all parent messages by the length of this size field.
  333. // If size_index_ < 0, this is not a message, so no size field is added.
  334. if (size_index_ >= 0) {
  335. // Add the final buffer position to compute the total length of this
  336. // serialized message. The stored value (before this addition) already
  337. // contains the total length of the size fields of all nested messages
  338. // minus the initial buffer position.
  339. ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
  340. // Calculate the length required to serialize the size field of the
  341. // message, and propagate this additional size information upward to
  342. // all enclosing messages.
  343. int size = ow_->size_insert_[size_index_].size;
  344. int length = CodedOutputStream::VarintSize32(size);
  345. for (ProtoElement* e = parent(); e != nullptr; e = e->parent()) {
  346. // Only nested messages have size field, lists do not have size field.
  347. if (e->size_index_ >= 0) {
  348. ow_->size_insert_[e->size_index_].size += length;
  349. }
  350. }
  351. }
  352. return BaseElement::pop<ProtoElement>();
  353. }
  354. void ProtoWriter::ProtoElement::RegisterField(
  355. const google::protobuf::Field* field) {
  356. if (!required_fields_.empty() &&
  357. field->cardinality() ==
  358. google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
  359. required_fields_.erase(field);
  360. }
  361. }
  362. string ProtoWriter::ProtoElement::ToString() const {
  363. if (parent() == nullptr) return "";
  364. string loc = parent()->ToString();
  365. if (!ow_->IsRepeated(*parent_field_) ||
  366. parent()->parent_field_ != parent_field_) {
  367. string name = parent_field_->name();
  368. int i = 0;
  369. while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
  370. if (i > 0 && i == name.size()) { // safe field name
  371. if (loc.empty()) {
  372. loc = name;
  373. } else {
  374. StrAppend(&loc, ".", name);
  375. }
  376. } else {
  377. StrAppend(&loc, "[\"", CEscape(name), "\"]");
  378. }
  379. }
  380. if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
  381. StrAppend(&loc, "[", array_index_ - 1, "]");
  382. }
  383. return loc.empty() ? "." : loc;
  384. }
  385. bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
  386. return oneof_indices_[index];
  387. }
  388. void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
  389. oneof_indices_[index] = true;
  390. }
  391. void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) {
  392. listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
  393. }
  394. void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) {
  395. listener_->InvalidValue(location(), type_name, value);
  396. }
  397. void ProtoWriter::MissingField(StringPiece missing_name) {
  398. listener_->MissingField(location(), missing_name);
  399. }
  400. ProtoWriter* ProtoWriter::StartObject(StringPiece name) {
  401. // Starting the root message. Create the root ProtoElement and return.
  402. if (element_ == nullptr) {
  403. if (!name.empty()) {
  404. InvalidName(name, "Root element should not be named.");
  405. }
  406. element_.reset(new ProtoElement(typeinfo_, master_type_, this));
  407. return this;
  408. }
  409. const google::protobuf::Field* field = nullptr;
  410. field = BeginNamed(name, false);
  411. if (field == nullptr) return this;
  412. // Check to see if this field is a oneof and that no oneof in that group has
  413. // already been set.
  414. if (!ValidOneof(*field, name)) {
  415. ++invalid_depth_;
  416. return this;
  417. }
  418. const google::protobuf::Type* type = LookupType(field);
  419. if (type == nullptr) {
  420. ++invalid_depth_;
  421. InvalidName(name,
  422. StrCat("Missing descriptor for field: ", field->type_url()));
  423. return this;
  424. }
  425. return StartObjectField(*field, *type);
  426. }
  427. ProtoWriter* ProtoWriter::EndObject() {
  428. if (invalid_depth_ > 0) {
  429. --invalid_depth_;
  430. return this;
  431. }
  432. if (element_ != nullptr) {
  433. element_.reset(element_->pop());
  434. }
  435. // If ending the root element,
  436. // then serialize the full message with calculated sizes.
  437. if (element_ == nullptr) {
  438. WriteRootMessage();
  439. }
  440. return this;
  441. }
  442. ProtoWriter* ProtoWriter::StartList(StringPiece name) {
  443. const google::protobuf::Field* field = BeginNamed(name, true);
  444. if (field == nullptr) return this;
  445. if (!ValidOneof(*field, name)) {
  446. ++invalid_depth_;
  447. return this;
  448. }
  449. const google::protobuf::Type* type = LookupType(field);
  450. if (type == nullptr) {
  451. ++invalid_depth_;
  452. InvalidName(name,
  453. StrCat("Missing descriptor for field: ", field->type_url()));
  454. return this;
  455. }
  456. return StartListField(*field, *type);
  457. }
  458. ProtoWriter* ProtoWriter::EndList() {
  459. if (invalid_depth_ > 0) {
  460. --invalid_depth_;
  461. } else if (element_ != nullptr) {
  462. element_.reset(element_->pop());
  463. }
  464. return this;
  465. }
  466. ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name,
  467. const DataPiece& data) {
  468. Status status;
  469. if (invalid_depth_ > 0) return this;
  470. const google::protobuf::Field* field = Lookup(name);
  471. if (field == nullptr) return this;
  472. if (!ValidOneof(*field, name)) return this;
  473. const google::protobuf::Type* type = LookupType(field);
  474. if (type == nullptr) {
  475. InvalidName(name,
  476. StrCat("Missing descriptor for field: ", field->type_url()));
  477. return this;
  478. }
  479. return RenderPrimitiveField(*field, *type, data);
  480. }
  481. bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
  482. StringPiece unnormalized_name) {
  483. if (element_ == nullptr) return true;
  484. if (field.oneof_index() > 0) {
  485. if (element_->IsOneofIndexTaken(field.oneof_index())) {
  486. InvalidValue(
  487. "oneof",
  488. StrCat("oneof field '",
  489. element_->type().oneofs(field.oneof_index() - 1),
  490. "' is already set. Cannot set '", unnormalized_name, "'"));
  491. return false;
  492. }
  493. element_->TakeOneofIndex(field.oneof_index());
  494. }
  495. return true;
  496. }
  497. bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
  498. return field.cardinality() ==
  499. google::protobuf::Field_Cardinality_CARDINALITY_REPEATED;
  500. }
  501. ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field,
  502. const google::protobuf::Type& type) {
  503. WriteTag(field);
  504. element_.reset(new ProtoElement(element_.release(), &field, type, false));
  505. return this;
  506. }
  507. ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field,
  508. const google::protobuf::Type& type) {
  509. element_.reset(new ProtoElement(element_.release(), &field, type, true));
  510. return this;
  511. }
  512. ProtoWriter* ProtoWriter::RenderPrimitiveField(
  513. const google::protobuf::Field& field, const google::protobuf::Type& type,
  514. const DataPiece& data) {
  515. Status status;
  516. // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
  517. // error location reporting and required field accounting.
  518. //
  519. // For proto3, since there is no required field tracking, we only need to push
  520. // ProtoElement for error cases.
  521. if (!element_->proto3()) {
  522. element_.reset(new ProtoElement(element_.release(), &field, type, false));
  523. }
  524. if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
  525. field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
  526. // Push a ProtoElement for location reporting purposes.
  527. if (element_->proto3()) {
  528. element_.reset(new ProtoElement(element_.release(), &field, type, false));
  529. }
  530. InvalidValue(field.type_url().empty()
  531. ? google::protobuf::Field_Kind_Name(field.kind())
  532. : field.type_url(),
  533. data.ValueAsStringOrDefault(""));
  534. element_.reset(element()->pop());
  535. return this;
  536. }
  537. switch (field.kind()) {
  538. case google::protobuf::Field_Kind_TYPE_INT32: {
  539. status = WriteInt32(field.number(), data, stream_.get());
  540. break;
  541. }
  542. case google::protobuf::Field_Kind_TYPE_SFIXED32: {
  543. status = WriteSFixed32(field.number(), data, stream_.get());
  544. break;
  545. }
  546. case google::protobuf::Field_Kind_TYPE_SINT32: {
  547. status = WriteSInt32(field.number(), data, stream_.get());
  548. break;
  549. }
  550. case google::protobuf::Field_Kind_TYPE_FIXED32: {
  551. status = WriteFixed32(field.number(), data, stream_.get());
  552. break;
  553. }
  554. case google::protobuf::Field_Kind_TYPE_UINT32: {
  555. status = WriteUInt32(field.number(), data, stream_.get());
  556. break;
  557. }
  558. case google::protobuf::Field_Kind_TYPE_INT64: {
  559. status = WriteInt64(field.number(), data, stream_.get());
  560. break;
  561. }
  562. case google::protobuf::Field_Kind_TYPE_SFIXED64: {
  563. status = WriteSFixed64(field.number(), data, stream_.get());
  564. break;
  565. }
  566. case google::protobuf::Field_Kind_TYPE_SINT64: {
  567. status = WriteSInt64(field.number(), data, stream_.get());
  568. break;
  569. }
  570. case google::protobuf::Field_Kind_TYPE_FIXED64: {
  571. status = WriteFixed64(field.number(), data, stream_.get());
  572. break;
  573. }
  574. case google::protobuf::Field_Kind_TYPE_UINT64: {
  575. status = WriteUInt64(field.number(), data, stream_.get());
  576. break;
  577. }
  578. case google::protobuf::Field_Kind_TYPE_DOUBLE: {
  579. status = WriteDouble(field.number(), data, stream_.get());
  580. break;
  581. }
  582. case google::protobuf::Field_Kind_TYPE_FLOAT: {
  583. status = WriteFloat(field.number(), data, stream_.get());
  584. break;
  585. }
  586. case google::protobuf::Field_Kind_TYPE_BOOL: {
  587. status = WriteBool(field.number(), data, stream_.get());
  588. break;
  589. }
  590. case google::protobuf::Field_Kind_TYPE_BYTES: {
  591. status = WriteBytes(field.number(), data, stream_.get());
  592. break;
  593. }
  594. case google::protobuf::Field_Kind_TYPE_STRING: {
  595. status = WriteString(field.number(), data, stream_.get());
  596. break;
  597. }
  598. case google::protobuf::Field_Kind_TYPE_ENUM: {
  599. status = WriteEnum(field.number(), data,
  600. typeinfo_->GetEnumByTypeUrl(field.type_url()),
  601. stream_.get(), use_lower_camel_for_enums_,
  602. ignore_unknown_fields_);
  603. break;
  604. }
  605. default: // TYPE_GROUP or TYPE_MESSAGE
  606. status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
  607. }
  608. if (!status.ok()) {
  609. // Push a ProtoElement for location reporting purposes.
  610. if (element_->proto3()) {
  611. element_.reset(new ProtoElement(element_.release(), &field, type, false));
  612. }
  613. InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
  614. status.error_message());
  615. element_.reset(element()->pop());
  616. return this;
  617. }
  618. if (!element_->proto3()) element_.reset(element()->pop());
  619. return this;
  620. }
  621. const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
  622. bool is_list) {
  623. if (invalid_depth_ > 0) {
  624. ++invalid_depth_;
  625. return nullptr;
  626. }
  627. const google::protobuf::Field* field = Lookup(name);
  628. if (field == nullptr) {
  629. ++invalid_depth_;
  630. // InvalidName() already called in Lookup().
  631. return nullptr;
  632. }
  633. if (is_list && !IsRepeated(*field)) {
  634. ++invalid_depth_;
  635. InvalidName(name, "Proto field is not repeating, cannot start list.");
  636. return nullptr;
  637. }
  638. return field;
  639. }
  640. const google::protobuf::Field* ProtoWriter::Lookup(
  641. StringPiece unnormalized_name) {
  642. ProtoElement* e = element();
  643. if (e == nullptr) {
  644. InvalidName(unnormalized_name, "Root element must be a message.");
  645. return nullptr;
  646. }
  647. if (unnormalized_name.empty()) {
  648. // Objects in repeated field inherit the same field descriptor.
  649. if (e->parent_field() == nullptr) {
  650. InvalidName(unnormalized_name, "Proto fields must have a name.");
  651. } else if (!IsRepeated(*e->parent_field())) {
  652. InvalidName(unnormalized_name, "Proto fields must have a name.");
  653. return nullptr;
  654. }
  655. return e->parent_field();
  656. }
  657. const google::protobuf::Field* field =
  658. typeinfo_->FindField(&e->type(), unnormalized_name);
  659. if (field == nullptr && !ignore_unknown_fields_) {
  660. InvalidName(unnormalized_name, "Cannot find field.");
  661. }
  662. return field;
  663. }
  664. const google::protobuf::Type* ProtoWriter::LookupType(
  665. const google::protobuf::Field* field) {
  666. return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE ||
  667. field->kind() == google::protobuf::Field_Kind_TYPE_GROUP)
  668. ? typeinfo_->GetTypeByTypeUrl(field->type_url())
  669. : &element_->type());
  670. }
  671. void ProtoWriter::WriteRootMessage() {
  672. GOOGLE_DCHECK(!done_);
  673. int curr_pos = 0;
  674. // Calls the destructor of CodedOutputStream to remove any uninitialized
  675. // memory from the Cord before we read it.
  676. stream_.reset(nullptr);
  677. const void* data;
  678. int length;
  679. google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
  680. while (input_stream.Next(&data, &length)) {
  681. if (length == 0) continue;
  682. int num_bytes = length;
  683. // Write up to where we need to insert the size field.
  684. // The number of bytes we may write is the smaller of:
  685. // - the current fragment size
  686. // - the distance to the next position where a size field needs to be
  687. // inserted.
  688. if (!size_insert_.empty() &&
  689. size_insert_.front().pos - curr_pos < num_bytes) {
  690. num_bytes = size_insert_.front().pos - curr_pos;
  691. }
  692. output_->Append(static_cast<const char*>(data), num_bytes);
  693. if (num_bytes < length) {
  694. input_stream.BackUp(length - num_bytes);
  695. }
  696. curr_pos += num_bytes;
  697. // Insert the size field.
  698. // size_insert_.front(): the next <index, size> pair to be written.
  699. // size_insert_.front().pos: position of the size field.
  700. // size_insert_.front().size: the size (integer) to be inserted.
  701. if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
  702. // Varint32 occupies at most 10 bytes.
  703. uint8 insert_buffer[10];
  704. uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
  705. size_insert_.front().size, insert_buffer);
  706. output_->Append(reinterpret_cast<const char*>(insert_buffer),
  707. insert_buffer_pos - insert_buffer);
  708. size_insert_.pop_front();
  709. }
  710. }
  711. output_->Flush();
  712. stream_.reset(new CodedOutputStream(&adapter_));
  713. done_ = true;
  714. }
  715. void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
  716. WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
  717. static_cast<WireFormatLite::FieldType>(field.kind()));
  718. stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
  719. }
  720. } // namespace converter
  721. } // namespace util
  722. } // namespace protobuf
  723. } // namespace google