proto_writer.cc 28 KB

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