protostream_objectsource.cc 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  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_objectsource.h>
  31. #include <utility>
  32. #include <google/protobuf/stubs/casts.h>
  33. #include <google/protobuf/stubs/logging.h>
  34. #include <google/protobuf/stubs/common.h>
  35. #include <google/protobuf/stubs/stringprintf.h>
  36. #include <google/protobuf/stubs/time.h>
  37. #include <google/protobuf/io/coded_stream.h>
  38. #include <google/protobuf/io/zero_copy_stream_impl.h>
  39. #include <google/protobuf/descriptor.h>
  40. #include <google/protobuf/wire_format.h>
  41. #include <google/protobuf/wire_format_lite.h>
  42. #include <google/protobuf/util/internal/field_mask_utility.h>
  43. #include <google/protobuf/util/internal/constants.h>
  44. #include <google/protobuf/util/internal/utility.h>
  45. #include <google/protobuf/stubs/strutil.h>
  46. #include <google/protobuf/stubs/map_util.h>
  47. #include <google/protobuf/stubs/status_macros.h>
  48. namespace google {
  49. namespace protobuf {
  50. namespace util {
  51. using util::Status;
  52. using util::StatusOr;
  53. namespace error {
  54. using util::error::Code;
  55. using util::error::INTERNAL;
  56. }
  57. namespace converter {
  58. using google::protobuf::Descriptor;
  59. using google::protobuf::EnumValueDescriptor;
  60. using google::protobuf::FieldDescriptor;
  61. using google::protobuf::internal::WireFormat;
  62. using google::protobuf::internal::WireFormatLite;
  63. using util::Status;
  64. using util::StatusOr;
  65. namespace {
  66. static int kDefaultMaxRecursionDepth = 64;
  67. // Finds a field with the given number. nullptr if none found.
  68. const google::protobuf::Field* FindFieldByNumber(
  69. const google::protobuf::Type& type, int number);
  70. // Returns true if the field is packable.
  71. bool IsPackable(const google::protobuf::Field& field);
  72. // Finds an enum value with the given number. nullptr if none found.
  73. const google::protobuf::EnumValue* FindEnumValueByNumber(
  74. const google::protobuf::Enum& tech_enum, int number);
  75. // Utility function to format nanos.
  76. const string FormatNanos(uint32 nanos, bool with_trailing_zeros);
  77. StatusOr<string> MapKeyDefaultValueAsString(
  78. const google::protobuf::Field& field) {
  79. switch (field.kind()) {
  80. case google::protobuf::Field_Kind_TYPE_BOOL:
  81. return string("false");
  82. case google::protobuf::Field_Kind_TYPE_INT32:
  83. case google::protobuf::Field_Kind_TYPE_INT64:
  84. case google::protobuf::Field_Kind_TYPE_UINT32:
  85. case google::protobuf::Field_Kind_TYPE_UINT64:
  86. case google::protobuf::Field_Kind_TYPE_SINT32:
  87. case google::protobuf::Field_Kind_TYPE_SINT64:
  88. case google::protobuf::Field_Kind_TYPE_SFIXED32:
  89. case google::protobuf::Field_Kind_TYPE_SFIXED64:
  90. case google::protobuf::Field_Kind_TYPE_FIXED32:
  91. case google::protobuf::Field_Kind_TYPE_FIXED64:
  92. return string("0");
  93. case google::protobuf::Field_Kind_TYPE_STRING:
  94. return string();
  95. default:
  96. return Status(util::error::INTERNAL, "Invalid map key type.");
  97. }
  98. }
  99. } // namespace
  100. ProtoStreamObjectSource::ProtoStreamObjectSource(
  101. google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver,
  102. const google::protobuf::Type& type)
  103. : stream_(stream),
  104. typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
  105. own_typeinfo_(true),
  106. type_(type),
  107. use_lower_camel_for_enums_(false),
  108. use_ints_for_enums_(false),
  109. preserve_proto_field_names_(false),
  110. recursion_depth_(0),
  111. max_recursion_depth_(kDefaultMaxRecursionDepth),
  112. render_unknown_fields_(false),
  113. render_unknown_enum_values_(true),
  114. add_trailing_zeros_for_timestamp_and_duration_(false) {
  115. GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
  116. }
  117. ProtoStreamObjectSource::ProtoStreamObjectSource(
  118. google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo,
  119. const google::protobuf::Type& type)
  120. : stream_(stream),
  121. typeinfo_(typeinfo),
  122. own_typeinfo_(false),
  123. type_(type),
  124. use_lower_camel_for_enums_(false),
  125. use_ints_for_enums_(false),
  126. preserve_proto_field_names_(false),
  127. recursion_depth_(0),
  128. max_recursion_depth_(kDefaultMaxRecursionDepth),
  129. render_unknown_fields_(false),
  130. render_unknown_enum_values_(true),
  131. add_trailing_zeros_for_timestamp_and_duration_(false) {
  132. GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
  133. }
  134. ProtoStreamObjectSource::~ProtoStreamObjectSource() {
  135. if (own_typeinfo_) {
  136. delete typeinfo_;
  137. }
  138. }
  139. Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name,
  140. ObjectWriter* ow) const {
  141. return WriteMessage(type_, name, 0, true, ow);
  142. }
  143. const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField(
  144. const google::protobuf::Type& type, uint32 tag) const {
  145. // Lookup the new field in the type by tag number.
  146. const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3);
  147. // Verify if the field corresponds to the wire type in tag.
  148. // If there is any discrepancy, mark the field as not found.
  149. if (field != nullptr) {
  150. WireFormatLite::WireType expected_type =
  151. WireFormatLite::WireTypeForFieldType(
  152. static_cast<WireFormatLite::FieldType>(field->kind()));
  153. WireFormatLite::WireType actual_type = WireFormatLite::GetTagWireType(tag);
  154. if (actual_type != expected_type &&
  155. (!IsPackable(*field) ||
  156. actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
  157. field = nullptr;
  158. }
  159. }
  160. return field;
  161. }
  162. Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
  163. StringPiece name,
  164. const uint32 end_tag,
  165. bool include_start_and_end,
  166. ObjectWriter* ow) const {
  167. const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
  168. if (type_renderer != nullptr) {
  169. return (*type_renderer)(this, type, name, ow);
  170. }
  171. const google::protobuf::Field* field = nullptr;
  172. string field_name;
  173. // last_tag set to dummy value that is different from tag.
  174. uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
  175. google::protobuf::UnknownFieldSet unknown_fields;
  176. if (include_start_and_end) {
  177. ow->StartObject(name);
  178. }
  179. while (tag != end_tag) {
  180. if (tag != last_tag) { // Update field only if tag is changed.
  181. last_tag = tag;
  182. field = FindAndVerifyField(type, tag);
  183. if (field != nullptr) {
  184. if (preserve_proto_field_names_) {
  185. field_name = field->name();
  186. } else {
  187. field_name = field->json_name();
  188. }
  189. }
  190. }
  191. if (field == nullptr) {
  192. // If we didn't find a field, skip this unknown tag.
  193. // TODO(wpoon): Check return boolean value.
  194. WireFormat::SkipField(stream_, tag,
  195. render_unknown_fields_ ? &unknown_fields : nullptr);
  196. tag = stream_->ReadTag();
  197. continue;
  198. }
  199. if (field->cardinality() ==
  200. google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
  201. bool check_maps = true;
  202. if (check_maps && IsMap(*field)) {
  203. ow->StartObject(field_name);
  204. ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
  205. ow->EndObject();
  206. } else {
  207. ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow));
  208. }
  209. } else {
  210. // Render the field.
  211. RETURN_IF_ERROR(RenderField(field, field_name, ow));
  212. tag = stream_->ReadTag();
  213. }
  214. }
  215. if (include_start_and_end) {
  216. ow->EndObject();
  217. }
  218. return util::Status();
  219. }
  220. StatusOr<uint32> ProtoStreamObjectSource::RenderList(
  221. const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
  222. ObjectWriter* ow) const {
  223. uint32 tag_to_return = 0;
  224. ow->StartList(name);
  225. if (IsPackable(*field) &&
  226. list_tag ==
  227. WireFormatLite::MakeTag(field->number(),
  228. WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
  229. RETURN_IF_ERROR(RenderPacked(field, ow));
  230. // Since packed fields have a single tag, read another tag from stream to
  231. // return.
  232. tag_to_return = stream_->ReadTag();
  233. } else {
  234. do {
  235. RETURN_IF_ERROR(RenderField(field, "", ow));
  236. } while ((tag_to_return = stream_->ReadTag()) == list_tag);
  237. }
  238. ow->EndList();
  239. return tag_to_return;
  240. }
  241. StatusOr<uint32> ProtoStreamObjectSource::RenderMap(
  242. const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
  243. ObjectWriter* ow) const {
  244. const google::protobuf::Type* field_type =
  245. typeinfo_->GetTypeByTypeUrl(field->type_url());
  246. uint32 tag_to_return = 0;
  247. do {
  248. // Render map entry message type.
  249. uint32 buffer32;
  250. stream_->ReadVarint32(&buffer32); // message length
  251. int old_limit = stream_->PushLimit(buffer32);
  252. string map_key;
  253. for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
  254. const google::protobuf::Field* field =
  255. FindAndVerifyField(*field_type, tag);
  256. if (field == nullptr) {
  257. WireFormat::SkipField(stream_, tag, nullptr);
  258. continue;
  259. }
  260. // Map field numbers are key = 1 and value = 2
  261. if (field->number() == 1) {
  262. map_key = ReadFieldValueAsString(*field);
  263. } else if (field->number() == 2) {
  264. if (map_key.empty()) {
  265. // An absent map key is treated as the default.
  266. const google::protobuf::Field* key_field =
  267. FindFieldByNumber(*field_type, 1);
  268. if (key_field == nullptr) {
  269. // The Type info for this map entry is incorrect. It should always
  270. // have a field named "key" and with field number 1.
  271. return Status(util::error::INTERNAL, "Invalid map entry.");
  272. }
  273. ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field));
  274. }
  275. RETURN_IF_ERROR(RenderField(field, map_key, ow));
  276. } else {
  277. // The Type info for this map entry is incorrect. It should contain
  278. // exactly two fields with field number 1 and 2.
  279. return Status(util::error::INTERNAL, "Invalid map entry.");
  280. }
  281. }
  282. stream_->PopLimit(old_limit);
  283. } while ((tag_to_return = stream_->ReadTag()) == list_tag);
  284. return tag_to_return;
  285. }
  286. Status ProtoStreamObjectSource::RenderPacked(
  287. const google::protobuf::Field* field, ObjectWriter* ow) const {
  288. uint32 length;
  289. stream_->ReadVarint32(&length);
  290. int old_limit = stream_->PushLimit(length);
  291. while (stream_->BytesUntilLimit() > 0) {
  292. RETURN_IF_ERROR(RenderField(field, StringPiece(), ow));
  293. }
  294. stream_->PopLimit(old_limit);
  295. return util::Status();
  296. }
  297. Status ProtoStreamObjectSource::RenderTimestamp(
  298. const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
  299. StringPiece field_name, ObjectWriter* ow) {
  300. std::pair<int64, int32> p = os->ReadSecondsAndNanos(type);
  301. int64 seconds = p.first;
  302. int32 nanos = p.second;
  303. if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) {
  304. return Status(
  305. util::error::INTERNAL,
  306. StrCat("Timestamp seconds exceeds limit for field: ", field_name));
  307. }
  308. if (nanos < 0 || nanos >= kNanosPerSecond) {
  309. return Status(
  310. util::error::INTERNAL,
  311. StrCat("Timestamp nanos exceeds limit for field: ", field_name));
  312. }
  313. ow->RenderString(field_name,
  314. ::google::protobuf::internal::FormatTime(seconds, nanos));
  315. return util::Status();
  316. }
  317. Status ProtoStreamObjectSource::RenderDuration(
  318. const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
  319. StringPiece field_name, ObjectWriter* ow) {
  320. std::pair<int64, int32> p = os->ReadSecondsAndNanos(type);
  321. int64 seconds = p.first;
  322. int32 nanos = p.second;
  323. if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) {
  324. return Status(
  325. util::error::INTERNAL,
  326. StrCat("Duration seconds exceeds limit for field: ", field_name));
  327. }
  328. if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
  329. return Status(
  330. util::error::INTERNAL,
  331. StrCat("Duration nanos exceeds limit for field: ", field_name));
  332. }
  333. string sign = "";
  334. if (seconds < 0) {
  335. if (nanos > 0) {
  336. return Status(util::error::INTERNAL,
  337. StrCat("Duration nanos is non-negative, but seconds is "
  338. "negative for field: ",
  339. field_name));
  340. }
  341. sign = "-";
  342. seconds = -seconds;
  343. nanos = -nanos;
  344. } else if (seconds == 0 && nanos < 0) {
  345. sign = "-";
  346. nanos = -nanos;
  347. }
  348. string formatted_duration = StringPrintf(
  349. "%s%lld%ss", sign.c_str(), seconds,
  350. FormatNanos(nanos, os->add_trailing_zeros_for_timestamp_and_duration_)
  351. .c_str());
  352. ow->RenderString(field_name, formatted_duration);
  353. return util::Status();
  354. }
  355. Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os,
  356. const google::protobuf::Type& type,
  357. StringPiece field_name,
  358. ObjectWriter* ow) {
  359. uint32 tag = os->stream_->ReadTag();
  360. uint64 buffer64 = 0; // default value of Double wrapper value
  361. if (tag != 0) {
  362. os->stream_->ReadLittleEndian64(&buffer64);
  363. os->stream_->ReadTag();
  364. }
  365. ow->RenderDouble(field_name, bit_cast<double>(buffer64));
  366. return util::Status();
  367. }
  368. Status ProtoStreamObjectSource::RenderFloat(const ProtoStreamObjectSource* os,
  369. const google::protobuf::Type& type,
  370. StringPiece field_name,
  371. ObjectWriter* ow) {
  372. uint32 tag = os->stream_->ReadTag();
  373. uint32 buffer32 = 0; // default value of Float wrapper value
  374. if (tag != 0) {
  375. os->stream_->ReadLittleEndian32(&buffer32);
  376. os->stream_->ReadTag();
  377. }
  378. ow->RenderFloat(field_name, bit_cast<float>(buffer32));
  379. return util::Status();
  380. }
  381. Status ProtoStreamObjectSource::RenderInt64(const ProtoStreamObjectSource* os,
  382. const google::protobuf::Type& type,
  383. StringPiece field_name,
  384. ObjectWriter* ow) {
  385. uint32 tag = os->stream_->ReadTag();
  386. uint64 buffer64 = 0; // default value of Int64 wrapper value
  387. if (tag != 0) {
  388. os->stream_->ReadVarint64(&buffer64);
  389. os->stream_->ReadTag();
  390. }
  391. ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
  392. return util::Status();
  393. }
  394. Status ProtoStreamObjectSource::RenderUInt64(const ProtoStreamObjectSource* os,
  395. const google::protobuf::Type& type,
  396. StringPiece field_name,
  397. ObjectWriter* ow) {
  398. uint32 tag = os->stream_->ReadTag();
  399. uint64 buffer64 = 0; // default value of UInt64 wrapper value
  400. if (tag != 0) {
  401. os->stream_->ReadVarint64(&buffer64);
  402. os->stream_->ReadTag();
  403. }
  404. ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
  405. return util::Status();
  406. }
  407. Status ProtoStreamObjectSource::RenderInt32(const ProtoStreamObjectSource* os,
  408. const google::protobuf::Type& type,
  409. StringPiece field_name,
  410. ObjectWriter* ow) {
  411. uint32 tag = os->stream_->ReadTag();
  412. uint32 buffer32 = 0; // default value of Int32 wrapper value
  413. if (tag != 0) {
  414. os->stream_->ReadVarint32(&buffer32);
  415. os->stream_->ReadTag();
  416. }
  417. ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
  418. return util::Status();
  419. }
  420. Status ProtoStreamObjectSource::RenderUInt32(const ProtoStreamObjectSource* os,
  421. const google::protobuf::Type& type,
  422. StringPiece field_name,
  423. ObjectWriter* ow) {
  424. uint32 tag = os->stream_->ReadTag();
  425. uint32 buffer32 = 0; // default value of UInt32 wrapper value
  426. if (tag != 0) {
  427. os->stream_->ReadVarint32(&buffer32);
  428. os->stream_->ReadTag();
  429. }
  430. ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
  431. return util::Status();
  432. }
  433. Status ProtoStreamObjectSource::RenderBool(const ProtoStreamObjectSource* os,
  434. const google::protobuf::Type& type,
  435. StringPiece field_name,
  436. ObjectWriter* ow) {
  437. uint32 tag = os->stream_->ReadTag();
  438. uint64 buffer64 = 0; // results in 'false' value as default, which is the
  439. // default value of Bool wrapper
  440. if (tag != 0) {
  441. os->stream_->ReadVarint64(&buffer64);
  442. os->stream_->ReadTag();
  443. }
  444. ow->RenderBool(field_name, buffer64 != 0);
  445. return util::Status();
  446. }
  447. Status ProtoStreamObjectSource::RenderString(const ProtoStreamObjectSource* os,
  448. const google::protobuf::Type& type,
  449. StringPiece field_name,
  450. ObjectWriter* ow) {
  451. uint32 tag = os->stream_->ReadTag();
  452. uint32 buffer32;
  453. string str; // default value of empty for String wrapper
  454. if (tag != 0) {
  455. os->stream_->ReadVarint32(&buffer32); // string size.
  456. os->stream_->ReadString(&str, buffer32);
  457. os->stream_->ReadTag();
  458. }
  459. ow->RenderString(field_name, str);
  460. return util::Status();
  461. }
  462. Status ProtoStreamObjectSource::RenderBytes(const ProtoStreamObjectSource* os,
  463. const google::protobuf::Type& type,
  464. StringPiece field_name,
  465. ObjectWriter* ow) {
  466. uint32 tag = os->stream_->ReadTag();
  467. uint32 buffer32;
  468. string str;
  469. if (tag != 0) {
  470. os->stream_->ReadVarint32(&buffer32);
  471. os->stream_->ReadString(&str, buffer32);
  472. os->stream_->ReadTag();
  473. }
  474. ow->RenderBytes(field_name, str);
  475. return util::Status();
  476. }
  477. Status ProtoStreamObjectSource::RenderStruct(const ProtoStreamObjectSource* os,
  478. const google::protobuf::Type& type,
  479. StringPiece field_name,
  480. ObjectWriter* ow) {
  481. const google::protobuf::Field* field = nullptr;
  482. uint32 tag = os->stream_->ReadTag();
  483. ow->StartObject(field_name);
  484. while (tag != 0) {
  485. field = os->FindAndVerifyField(type, tag);
  486. // google.protobuf.Struct has only one field that is a map. Hence we use
  487. // RenderMap to render that field.
  488. if (os->IsMap(*field)) {
  489. ASSIGN_OR_RETURN(tag, os->RenderMap(field, field_name, tag, ow));
  490. }
  491. }
  492. ow->EndObject();
  493. return util::Status();
  494. }
  495. Status ProtoStreamObjectSource::RenderStructValue(
  496. const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
  497. StringPiece field_name, ObjectWriter* ow) {
  498. const google::protobuf::Field* field = nullptr;
  499. for (uint32 tag = os->stream_->ReadTag(); tag != 0;
  500. tag = os->stream_->ReadTag()) {
  501. field = os->FindAndVerifyField(type, tag);
  502. if (field == nullptr) {
  503. WireFormat::SkipField(os->stream_, tag, nullptr);
  504. continue;
  505. }
  506. RETURN_IF_ERROR(os->RenderField(field, field_name, ow));
  507. }
  508. return util::Status();
  509. }
  510. // TODO(skarvaje): Avoid code duplication of for loops and SkipField logic.
  511. Status ProtoStreamObjectSource::RenderStructListValue(
  512. const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
  513. StringPiece field_name, ObjectWriter* ow) {
  514. uint32 tag = os->stream_->ReadTag();
  515. // Render empty list when we find empty ListValue message.
  516. if (tag == 0) {
  517. ow->StartList(field_name);
  518. ow->EndList();
  519. return util::Status();
  520. }
  521. while (tag != 0) {
  522. const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
  523. if (field == nullptr) {
  524. WireFormat::SkipField(os->stream_, tag, nullptr);
  525. tag = os->stream_->ReadTag();
  526. continue;
  527. }
  528. ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow));
  529. }
  530. return util::Status();
  531. }
  532. Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os,
  533. const google::protobuf::Type& type,
  534. StringPiece field_name,
  535. ObjectWriter* ow) {
  536. // An Any is of the form { string type_url = 1; bytes value = 2; }
  537. uint32 tag;
  538. string type_url;
  539. string value;
  540. // First read out the type_url and value from the proto stream
  541. for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) {
  542. const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
  543. if (field == nullptr) {
  544. WireFormat::SkipField(os->stream_, tag, nullptr);
  545. continue;
  546. }
  547. // 'type_url' has field number of 1 and 'value' has field number 2
  548. // //google/protobuf/any.proto
  549. if (field->number() == 1) {
  550. // read type_url
  551. uint32 type_url_size;
  552. os->stream_->ReadVarint32(&type_url_size);
  553. os->stream_->ReadString(&type_url, type_url_size);
  554. } else if (field->number() == 2) {
  555. // read value
  556. uint32 value_size;
  557. os->stream_->ReadVarint32(&value_size);
  558. os->stream_->ReadString(&value, value_size);
  559. }
  560. }
  561. // If there is no value, we don't lookup the type, we just output it (if
  562. // present). If both type and value are empty we output an empty object.
  563. if (value.empty()) {
  564. ow->StartObject(field_name);
  565. if (!type_url.empty()) {
  566. ow->RenderString("@type", type_url);
  567. }
  568. ow->EndObject();
  569. return util::Status();
  570. }
  571. // If there is a value but no type, we cannot render it, so report an error.
  572. if (type_url.empty()) {
  573. // TODO(sven): Add an external message once those are ready.
  574. return util::Status(util::error::INTERNAL,
  575. "Invalid Any, the type_url is missing.");
  576. }
  577. util::StatusOr<const google::protobuf::Type*> resolved_type =
  578. os->typeinfo_->ResolveTypeUrl(type_url);
  579. if (!resolved_type.ok()) {
  580. // Convert into an internal error, since this means the backend gave us
  581. // an invalid response (missing or invalid type information).
  582. return util::Status(util::error::INTERNAL,
  583. resolved_type.status().error_message());
  584. }
  585. // nested_type cannot be null at this time.
  586. const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
  587. google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size());
  588. google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream);
  589. // We know the type so we can render it. Recursively parse the nested stream
  590. // using a nested ProtoStreamObjectSource using our nested type information.
  591. ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type);
  592. // We manually call start and end object here so we can inject the @type.
  593. ow->StartObject(field_name);
  594. ow->RenderString("@type", type_url);
  595. util::Status result =
  596. nested_os.WriteMessage(nested_os.type_, "value", 0, false, ow);
  597. ow->EndObject();
  598. return result;
  599. }
  600. Status ProtoStreamObjectSource::RenderFieldMask(
  601. const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
  602. StringPiece field_name, ObjectWriter* ow) {
  603. string combined;
  604. uint32 buffer32;
  605. uint32 paths_field_tag = 0;
  606. for (uint32 tag = os->stream_->ReadTag(); tag != 0;
  607. tag = os->stream_->ReadTag()) {
  608. if (paths_field_tag == 0) {
  609. const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
  610. if (field != nullptr && field->number() == 1 &&
  611. field->name() == "paths") {
  612. paths_field_tag = tag;
  613. }
  614. }
  615. if (paths_field_tag != tag) {
  616. return util::Status(util::error::INTERNAL,
  617. "Invalid FieldMask, unexpected field.");
  618. }
  619. string str;
  620. os->stream_->ReadVarint32(&buffer32); // string size.
  621. os->stream_->ReadString(&str, buffer32);
  622. if (!combined.empty()) {
  623. combined.append(",");
  624. }
  625. combined.append(ConvertFieldMaskPath(str, &ToCamelCase));
  626. }
  627. ow->RenderString(field_name, combined);
  628. return util::Status();
  629. }
  630. hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
  631. ProtoStreamObjectSource::renderers_ = NULL;
  632. GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
  633. void ProtoStreamObjectSource::InitRendererMap() {
  634. renderers_ = new hash_map<string, ProtoStreamObjectSource::TypeRenderer>();
  635. (*renderers_)["google.protobuf.Timestamp"] =
  636. &ProtoStreamObjectSource::RenderTimestamp;
  637. (*renderers_)["google.protobuf.Duration"] =
  638. &ProtoStreamObjectSource::RenderDuration;
  639. (*renderers_)["google.protobuf.DoubleValue"] =
  640. &ProtoStreamObjectSource::RenderDouble;
  641. (*renderers_)["google.protobuf.FloatValue"] =
  642. &ProtoStreamObjectSource::RenderFloat;
  643. (*renderers_)["google.protobuf.Int64Value"] =
  644. &ProtoStreamObjectSource::RenderInt64;
  645. (*renderers_)["google.protobuf.UInt64Value"] =
  646. &ProtoStreamObjectSource::RenderUInt64;
  647. (*renderers_)["google.protobuf.Int32Value"] =
  648. &ProtoStreamObjectSource::RenderInt32;
  649. (*renderers_)["google.protobuf.UInt32Value"] =
  650. &ProtoStreamObjectSource::RenderUInt32;
  651. (*renderers_)["google.protobuf.BoolValue"] =
  652. &ProtoStreamObjectSource::RenderBool;
  653. (*renderers_)["google.protobuf.StringValue"] =
  654. &ProtoStreamObjectSource::RenderString;
  655. (*renderers_)["google.protobuf.BytesValue"] =
  656. &ProtoStreamObjectSource::RenderBytes;
  657. (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
  658. (*renderers_)["google.protobuf.Struct"] =
  659. &ProtoStreamObjectSource::RenderStruct;
  660. (*renderers_)["google.protobuf.Value"] =
  661. &ProtoStreamObjectSource::RenderStructValue;
  662. (*renderers_)["google.protobuf.ListValue"] =
  663. &ProtoStreamObjectSource::RenderStructListValue;
  664. (*renderers_)["google.protobuf.FieldMask"] =
  665. &ProtoStreamObjectSource::RenderFieldMask;
  666. ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
  667. }
  668. void ProtoStreamObjectSource::DeleteRendererMap() {
  669. delete ProtoStreamObjectSource::renderers_;
  670. renderers_ = NULL;
  671. }
  672. // static
  673. ProtoStreamObjectSource::TypeRenderer*
  674. ProtoStreamObjectSource::FindTypeRenderer(const string& type_url) {
  675. ::google::protobuf::GoogleOnceInit(&source_renderers_init_, &InitRendererMap);
  676. return FindOrNull(*renderers_, type_url);
  677. }
  678. Status ProtoStreamObjectSource::RenderField(
  679. const google::protobuf::Field* field, StringPiece field_name,
  680. ObjectWriter* ow) const {
  681. // Short-circuit message types as it tends to call WriteMessage recursively
  682. // and ends up using a lot of stack space. Keep the stack usage of this
  683. // message small in order to preserve stack space and not crash.
  684. if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
  685. uint32 buffer32;
  686. stream_->ReadVarint32(&buffer32); // message length
  687. int old_limit = stream_->PushLimit(buffer32);
  688. // Get the nested message type for this field.
  689. const google::protobuf::Type* type =
  690. typeinfo_->GetTypeByTypeUrl(field->type_url());
  691. if (type == nullptr) {
  692. return Status(util::error::INTERNAL,
  693. StrCat("Invalid configuration. Could not find the type: ",
  694. field->type_url()));
  695. }
  696. // Short-circuit any special type rendering to save call-stack space.
  697. const TypeRenderer* type_renderer = FindTypeRenderer(type->name());
  698. bool use_type_renderer = type_renderer != nullptr;
  699. if (use_type_renderer) {
  700. RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
  701. } else {
  702. RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name));
  703. RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
  704. --recursion_depth_;
  705. }
  706. if (!stream_->ConsumedEntireMessage()) {
  707. return Status(util::error::INVALID_ARGUMENT,
  708. "Nested protocol message not parsed in its entirety.");
  709. }
  710. stream_->PopLimit(old_limit);
  711. } else {
  712. // Render all other non-message types.
  713. return RenderNonMessageField(field, field_name, ow);
  714. }
  715. return util::Status();
  716. }
  717. Status ProtoStreamObjectSource::RenderNonMessageField(
  718. const google::protobuf::Field* field, StringPiece field_name,
  719. ObjectWriter* ow) const {
  720. // Temporary buffers of different types.
  721. uint32 buffer32;
  722. uint64 buffer64;
  723. string strbuffer;
  724. switch (field->kind()) {
  725. case google::protobuf::Field_Kind_TYPE_BOOL: {
  726. stream_->ReadVarint64(&buffer64);
  727. ow->RenderBool(field_name, buffer64 != 0);
  728. break;
  729. }
  730. case google::protobuf::Field_Kind_TYPE_INT32: {
  731. stream_->ReadVarint32(&buffer32);
  732. ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
  733. break;
  734. }
  735. case google::protobuf::Field_Kind_TYPE_INT64: {
  736. stream_->ReadVarint64(&buffer64);
  737. ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
  738. break;
  739. }
  740. case google::protobuf::Field_Kind_TYPE_UINT32: {
  741. stream_->ReadVarint32(&buffer32);
  742. ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
  743. break;
  744. }
  745. case google::protobuf::Field_Kind_TYPE_UINT64: {
  746. stream_->ReadVarint64(&buffer64);
  747. ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
  748. break;
  749. }
  750. case google::protobuf::Field_Kind_TYPE_SINT32: {
  751. stream_->ReadVarint32(&buffer32);
  752. ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
  753. break;
  754. }
  755. case google::protobuf::Field_Kind_TYPE_SINT64: {
  756. stream_->ReadVarint64(&buffer64);
  757. ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
  758. break;
  759. }
  760. case google::protobuf::Field_Kind_TYPE_SFIXED32: {
  761. stream_->ReadLittleEndian32(&buffer32);
  762. ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
  763. break;
  764. }
  765. case google::protobuf::Field_Kind_TYPE_SFIXED64: {
  766. stream_->ReadLittleEndian64(&buffer64);
  767. ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
  768. break;
  769. }
  770. case google::protobuf::Field_Kind_TYPE_FIXED32: {
  771. stream_->ReadLittleEndian32(&buffer32);
  772. ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
  773. break;
  774. }
  775. case google::protobuf::Field_Kind_TYPE_FIXED64: {
  776. stream_->ReadLittleEndian64(&buffer64);
  777. ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
  778. break;
  779. }
  780. case google::protobuf::Field_Kind_TYPE_FLOAT: {
  781. stream_->ReadLittleEndian32(&buffer32);
  782. ow->RenderFloat(field_name, bit_cast<float>(buffer32));
  783. break;
  784. }
  785. case google::protobuf::Field_Kind_TYPE_DOUBLE: {
  786. stream_->ReadLittleEndian64(&buffer64);
  787. ow->RenderDouble(field_name, bit_cast<double>(buffer64));
  788. break;
  789. }
  790. case google::protobuf::Field_Kind_TYPE_ENUM: {
  791. stream_->ReadVarint32(&buffer32);
  792. // If the field represents an explicit NULL value, render null.
  793. if (field->type_url() == kStructNullValueTypeUrl) {
  794. ow->RenderNull(field_name);
  795. break;
  796. }
  797. // Get the nested enum type for this field.
  798. // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
  799. // up.
  800. const google::protobuf::Enum* en =
  801. typeinfo_->GetEnumByTypeUrl(field->type_url());
  802. // Lookup the name of the enum, and render that. Unknown enum values
  803. // are printed as integers.
  804. if (en != nullptr) {
  805. const google::protobuf::EnumValue* enum_value =
  806. FindEnumValueByNumber(*en, buffer32);
  807. if (enum_value != nullptr) {
  808. if (use_ints_for_enums_) {
  809. ow->RenderInt32(field_name, buffer32);
  810. } else if (use_lower_camel_for_enums_) {
  811. ow->RenderString(field_name,
  812. EnumValueNameToLowerCamelCase(enum_value->name()));
  813. } else {
  814. ow->RenderString(field_name, enum_value->name());
  815. }
  816. } else if (render_unknown_enum_values_) {
  817. ow->RenderInt32(field_name, buffer32);
  818. }
  819. } else if (render_unknown_enum_values_) {
  820. ow->RenderInt32(field_name, buffer32);
  821. }
  822. break;
  823. }
  824. case google::protobuf::Field_Kind_TYPE_STRING: {
  825. stream_->ReadVarint32(&buffer32); // string size.
  826. stream_->ReadString(&strbuffer, buffer32);
  827. ow->RenderString(field_name, strbuffer);
  828. break;
  829. }
  830. case google::protobuf::Field_Kind_TYPE_BYTES: {
  831. stream_->ReadVarint32(&buffer32); // bytes size.
  832. stream_->ReadString(&strbuffer, buffer32);
  833. ow->RenderBytes(field_name, strbuffer);
  834. break;
  835. }
  836. default:
  837. break;
  838. }
  839. return util::Status();
  840. }
  841. // TODO(skarvaje): Fix this to avoid code duplication.
  842. const string ProtoStreamObjectSource::ReadFieldValueAsString(
  843. const google::protobuf::Field& field) const {
  844. string result;
  845. switch (field.kind()) {
  846. case google::protobuf::Field_Kind_TYPE_BOOL: {
  847. uint64 buffer64;
  848. stream_->ReadVarint64(&buffer64);
  849. result = buffer64 != 0 ? "true" : "false";
  850. break;
  851. }
  852. case google::protobuf::Field_Kind_TYPE_INT32: {
  853. uint32 buffer32;
  854. stream_->ReadVarint32(&buffer32);
  855. result = SimpleItoa(bit_cast<int32>(buffer32));
  856. break;
  857. }
  858. case google::protobuf::Field_Kind_TYPE_INT64: {
  859. uint64 buffer64;
  860. stream_->ReadVarint64(&buffer64);
  861. result = SimpleItoa(bit_cast<int64>(buffer64));
  862. break;
  863. }
  864. case google::protobuf::Field_Kind_TYPE_UINT32: {
  865. uint32 buffer32;
  866. stream_->ReadVarint32(&buffer32);
  867. result = SimpleItoa(bit_cast<uint32>(buffer32));
  868. break;
  869. }
  870. case google::protobuf::Field_Kind_TYPE_UINT64: {
  871. uint64 buffer64;
  872. stream_->ReadVarint64(&buffer64);
  873. result = SimpleItoa(bit_cast<uint64>(buffer64));
  874. break;
  875. }
  876. case google::protobuf::Field_Kind_TYPE_SINT32: {
  877. uint32 buffer32;
  878. stream_->ReadVarint32(&buffer32);
  879. result = SimpleItoa(WireFormatLite::ZigZagDecode32(buffer32));
  880. break;
  881. }
  882. case google::protobuf::Field_Kind_TYPE_SINT64: {
  883. uint64 buffer64;
  884. stream_->ReadVarint64(&buffer64);
  885. result = SimpleItoa(WireFormatLite::ZigZagDecode64(buffer64));
  886. break;
  887. }
  888. case google::protobuf::Field_Kind_TYPE_SFIXED32: {
  889. uint32 buffer32;
  890. stream_->ReadLittleEndian32(&buffer32);
  891. result = SimpleItoa(bit_cast<int32>(buffer32));
  892. break;
  893. }
  894. case google::protobuf::Field_Kind_TYPE_SFIXED64: {
  895. uint64 buffer64;
  896. stream_->ReadLittleEndian64(&buffer64);
  897. result = SimpleItoa(bit_cast<int64>(buffer64));
  898. break;
  899. }
  900. case google::protobuf::Field_Kind_TYPE_FIXED32: {
  901. uint32 buffer32;
  902. stream_->ReadLittleEndian32(&buffer32);
  903. result = SimpleItoa(bit_cast<uint32>(buffer32));
  904. break;
  905. }
  906. case google::protobuf::Field_Kind_TYPE_FIXED64: {
  907. uint64 buffer64;
  908. stream_->ReadLittleEndian64(&buffer64);
  909. result = SimpleItoa(bit_cast<uint64>(buffer64));
  910. break;
  911. }
  912. case google::protobuf::Field_Kind_TYPE_FLOAT: {
  913. uint32 buffer32;
  914. stream_->ReadLittleEndian32(&buffer32);
  915. result = SimpleFtoa(bit_cast<float>(buffer32));
  916. break;
  917. }
  918. case google::protobuf::Field_Kind_TYPE_DOUBLE: {
  919. uint64 buffer64;
  920. stream_->ReadLittleEndian64(&buffer64);
  921. result = SimpleDtoa(bit_cast<double>(buffer64));
  922. break;
  923. }
  924. case google::protobuf::Field_Kind_TYPE_ENUM: {
  925. uint32 buffer32;
  926. stream_->ReadVarint32(&buffer32);
  927. // Get the nested enum type for this field.
  928. // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
  929. // up.
  930. const google::protobuf::Enum* en =
  931. typeinfo_->GetEnumByTypeUrl(field.type_url());
  932. // Lookup the name of the enum, and render that. Skips unknown enums.
  933. if (en != nullptr) {
  934. const google::protobuf::EnumValue* enum_value =
  935. FindEnumValueByNumber(*en, buffer32);
  936. if (enum_value != nullptr) {
  937. result = enum_value->name();
  938. }
  939. }
  940. break;
  941. }
  942. case google::protobuf::Field_Kind_TYPE_STRING: {
  943. uint32 buffer32;
  944. stream_->ReadVarint32(&buffer32); // string size.
  945. stream_->ReadString(&result, buffer32);
  946. break;
  947. }
  948. case google::protobuf::Field_Kind_TYPE_BYTES: {
  949. uint32 buffer32;
  950. stream_->ReadVarint32(&buffer32); // bytes size.
  951. stream_->ReadString(&result, buffer32);
  952. break;
  953. }
  954. default:
  955. break;
  956. }
  957. return result;
  958. }
  959. // Field is a map if it is a repeated message and it has an option "map_type".
  960. // TODO(skarvaje): Consider pre-computing the IsMap() into Field directly.
  961. bool ProtoStreamObjectSource::IsMap(
  962. const google::protobuf::Field& field) const {
  963. const google::protobuf::Type* field_type =
  964. typeinfo_->GetTypeByTypeUrl(field.type_url());
  965. return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE &&
  966. google::protobuf::util::converter::IsMap(field, *field_type);
  967. }
  968. std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
  969. const google::protobuf::Type& type) const {
  970. uint64 seconds = 0;
  971. uint32 nanos = 0;
  972. uint32 tag = 0;
  973. int64 signed_seconds = 0;
  974. int32 signed_nanos = 0;
  975. for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
  976. const google::protobuf::Field* field = FindAndVerifyField(type, tag);
  977. if (field == nullptr) {
  978. WireFormat::SkipField(stream_, tag, nullptr);
  979. continue;
  980. }
  981. // 'seconds' has field number of 1 and 'nanos' has field number 2
  982. // //google/protobuf/timestamp.proto & duration.proto
  983. if (field->number() == 1) {
  984. // read seconds
  985. stream_->ReadVarint64(&seconds);
  986. signed_seconds = bit_cast<int64>(seconds);
  987. } else if (field->number() == 2) {
  988. // read nanos
  989. stream_->ReadVarint32(&nanos);
  990. signed_nanos = bit_cast<int32>(nanos);
  991. }
  992. }
  993. return std::pair<int64, int32>(signed_seconds, signed_nanos);
  994. }
  995. Status ProtoStreamObjectSource::IncrementRecursionDepth(
  996. StringPiece type_name, StringPiece field_name) const {
  997. if (++recursion_depth_ > max_recursion_depth_) {
  998. return Status(
  999. util::error::INVALID_ARGUMENT,
  1000. StrCat("Message too deep. Max recursion depth reached for type '",
  1001. type_name, "', field '", field_name, "'"));
  1002. }
  1003. return util::Status();
  1004. }
  1005. namespace {
  1006. // TODO(skarvaje): Speed this up by not doing a linear scan.
  1007. const google::protobuf::Field* FindFieldByNumber(
  1008. const google::protobuf::Type& type, int number) {
  1009. for (int i = 0; i < type.fields_size(); ++i) {
  1010. if (type.fields(i).number() == number) {
  1011. return &type.fields(i);
  1012. }
  1013. }
  1014. return nullptr;
  1015. }
  1016. // TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable()
  1017. // using tech Field.
  1018. bool IsPackable(const google::protobuf::Field& field) {
  1019. return field.cardinality() ==
  1020. google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
  1021. google::protobuf::FieldDescriptor::IsTypePackable(
  1022. static_cast<google::protobuf::FieldDescriptor::Type>(field.kind()));
  1023. }
  1024. // TODO(skarvaje): Speed this up by not doing a linear scan.
  1025. const google::protobuf::EnumValue* FindEnumValueByNumber(
  1026. const google::protobuf::Enum& tech_enum, int number) {
  1027. for (int i = 0; i < tech_enum.enumvalue_size(); ++i) {
  1028. const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i);
  1029. if (ev.number() == number) {
  1030. return &ev;
  1031. }
  1032. }
  1033. return nullptr;
  1034. }
  1035. // TODO(skarvaje): Look into optimizing this by not doing computation on
  1036. // double.
  1037. const string FormatNanos(uint32 nanos, bool with_trailing_zeros) {
  1038. if (nanos == 0) {
  1039. return with_trailing_zeros ? ".000" : "";
  1040. }
  1041. const char* format =
  1042. (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f";
  1043. string formatted =
  1044. StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond);
  1045. // remove the leading 0 before decimal.
  1046. return formatted.substr(1);
  1047. }
  1048. } // namespace
  1049. } // namespace converter
  1050. } // namespace util
  1051. } // namespace protobuf
  1052. } // namespace google