UnknownFieldSet.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Collections.Generic;
  36. using System.IO;
  37. using Google.ProtocolBuffers.Collections;
  38. using Google.ProtocolBuffers.Descriptors;
  39. using Google.ProtocolBuffers.DescriptorProtos;
  40. namespace Google.ProtocolBuffers {
  41. /// <summary>
  42. /// Used to keep track of fields which were seen when parsing a protocol message
  43. /// but whose field numbers or types are unrecognized. This most frequently
  44. /// occurs when new fields are added to a message type and then messages containing
  45. /// those fields are read by old software that was built before the new types were
  46. /// added.
  47. ///
  48. /// Every message contains an UnknownFieldSet.
  49. ///
  50. /// Most users will never need to use this class directly.
  51. /// </summary>
  52. public sealed class UnknownFieldSet : IMessageLite {
  53. private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
  54. private readonly IDictionary<int, UnknownField> fields;
  55. private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
  56. this.fields = fields;
  57. }
  58. /// <summary>
  59. /// Creates a new unknown field set builder.
  60. /// </summary>
  61. public static Builder CreateBuilder() {
  62. return new Builder();
  63. }
  64. /// <summary>
  65. /// Creates a new unknown field set builder
  66. /// and initialize it from <paramref name="original"/>.
  67. /// </summary>
  68. public static Builder CreateBuilder(UnknownFieldSet original) {
  69. return new Builder().MergeFrom(original);
  70. }
  71. public static UnknownFieldSet DefaultInstance {
  72. get { return defaultInstance; }
  73. }
  74. /// <summary>
  75. /// Returns a read-only view of the mapping from field numbers to values.
  76. /// </summary>
  77. public IDictionary<int, UnknownField> FieldDictionary {
  78. get { return Dictionaries.AsReadOnly(fields); }
  79. }
  80. /// <summary>
  81. /// Checks whether or not the given field number is present in the set.
  82. /// </summary>
  83. public bool HasField(int field) {
  84. return fields.ContainsKey(field);
  85. }
  86. /// <summary>
  87. /// Fetches a field by number, returning an empty field if not present.
  88. /// Never returns null.
  89. /// </summary>
  90. public UnknownField this[int number] {
  91. get {
  92. UnknownField ret;
  93. if (!fields.TryGetValue(number, out ret)) {
  94. ret = UnknownField.DefaultInstance;
  95. }
  96. return ret;
  97. }
  98. }
  99. /// <summary>
  100. /// Serializes the set and writes it to <paramref name="output"/>.
  101. /// </summary>
  102. public void WriteTo(CodedOutputStream output) {
  103. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  104. entry.Value.WriteTo(entry.Key, output);
  105. }
  106. }
  107. /// <summary>
  108. /// Gets the number of bytes required to encode this set.
  109. /// </summary>
  110. public int SerializedSize {
  111. get {
  112. int result = 0;
  113. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  114. result += entry.Value.GetSerializedSize(entry.Key);
  115. }
  116. return result;
  117. }
  118. }
  119. /// <summary>
  120. /// Converts the set to a string in protocol buffer text format. This
  121. /// is just a trivial wrapper around TextFormat.PrintToString.
  122. /// </summary>
  123. public override String ToString() {
  124. return TextFormat.PrintToString(this);
  125. }
  126. /// <summary>
  127. /// Serializes the message to a ByteString and returns it. This is
  128. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  129. /// </summary>
  130. /// <returns></returns>
  131. public ByteString ToByteString() {
  132. ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
  133. WriteTo(codedBuilder.CodedOutput);
  134. return codedBuilder.Build();
  135. }
  136. /// <summary>
  137. /// Serializes the message to a byte array and returns it. This is
  138. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  139. /// </summary>
  140. /// <returns></returns>
  141. public byte[] ToByteArray() {
  142. byte[] data = new byte[SerializedSize];
  143. CodedOutputStream output = CodedOutputStream.CreateInstance(data);
  144. WriteTo(output);
  145. output.CheckNoSpaceLeft();
  146. return data;
  147. }
  148. /// <summary>
  149. /// Serializes the message and writes it to <paramref name="output"/>. This is
  150. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  151. /// </summary>
  152. /// <param name="output"></param>
  153. public void WriteTo(Stream output) {
  154. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  155. WriteTo(codedOutput);
  156. codedOutput.Flush();
  157. }
  158. /// <summary>
  159. /// Serializes the set and writes it to <paramref name="output"/> using
  160. /// the MessageSet wire format.
  161. /// </summary>
  162. public void WriteAsMessageSetTo(CodedOutputStream output) {
  163. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  164. entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
  165. }
  166. }
  167. /// <summary>
  168. /// Gets the number of bytes required to encode this set using the MessageSet
  169. /// wire format.
  170. /// </summary>
  171. public int SerializedSizeAsMessageSet {
  172. get {
  173. int result = 0;
  174. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  175. result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
  176. }
  177. return result;
  178. }
  179. }
  180. public override bool Equals(object other) {
  181. if (ReferenceEquals(this, other)) {
  182. return true;
  183. }
  184. UnknownFieldSet otherSet = other as UnknownFieldSet;
  185. return otherSet != null && Dictionaries.Equals(fields, otherSet.fields);
  186. }
  187. public override int GetHashCode() {
  188. return Dictionaries.GetHashCode(fields);
  189. }
  190. /// <summary>
  191. /// Parses an UnknownFieldSet from the given input.
  192. /// </summary>
  193. public static UnknownFieldSet ParseFrom(CodedInputStream input) {
  194. return CreateBuilder().MergeFrom(input).Build();
  195. }
  196. /// <summary>
  197. /// Parses an UnknownFieldSet from the given data.
  198. /// </summary>
  199. public static UnknownFieldSet ParseFrom(ByteString data) {
  200. return CreateBuilder().MergeFrom(data).Build();
  201. }
  202. /// <summary>
  203. /// Parses an UnknownFieldSet from the given data.
  204. /// </summary>
  205. public static UnknownFieldSet ParseFrom(byte[] data) {
  206. return CreateBuilder().MergeFrom(data).Build();
  207. }
  208. /// <summary>
  209. /// Parses an UnknownFieldSet from the given input.
  210. /// </summary>
  211. public static UnknownFieldSet ParseFrom(Stream input) {
  212. return CreateBuilder().MergeFrom(input).Build();
  213. }
  214. #region IMessageLite Members
  215. public bool IsInitialized {
  216. get { return fields != null; }
  217. }
  218. public void WriteDelimitedTo(Stream output) {
  219. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  220. codedOutput.WriteRawVarint32((uint) SerializedSize);
  221. WriteTo(codedOutput);
  222. codedOutput.Flush();
  223. }
  224. public IBuilderLite WeakCreateBuilderForType() {
  225. return new Builder();
  226. }
  227. public IBuilderLite WeakToBuilder() {
  228. return new Builder(fields);
  229. }
  230. public IMessageLite WeakDefaultInstanceForType {
  231. get { return defaultInstance; }
  232. }
  233. #endregion
  234. /// <summary>
  235. /// Builder for UnknownFieldSets.
  236. /// </summary>
  237. public sealed class Builder : IBuilderLite
  238. {
  239. /// <summary>
  240. /// Mapping from number to field. Note that by using a SortedList we ensure
  241. /// that the fields will be serialized in ascending order.
  242. /// </summary>
  243. private IDictionary<int, UnknownField> fields;
  244. // Optimization: We keep around a builder for the last field that was
  245. // modified so that we can efficiently add to it multiple times in a
  246. // row (important when parsing an unknown repeated field).
  247. private int lastFieldNumber;
  248. private UnknownField.Builder lastField;
  249. internal Builder() {
  250. fields = new SortedList<int, UnknownField>();
  251. }
  252. internal Builder(IDictionary<int, UnknownField> dictionary) {
  253. fields = new SortedList<int, UnknownField>(dictionary);
  254. }
  255. /// <summary>
  256. /// Returns a field builder for the specified field number, including any values
  257. /// which already exist.
  258. /// </summary>
  259. private UnknownField.Builder GetFieldBuilder(int number) {
  260. if (lastField != null) {
  261. if (number == lastFieldNumber) {
  262. return lastField;
  263. }
  264. // Note: AddField() will reset lastField and lastFieldNumber.
  265. AddField(lastFieldNumber, lastField.Build());
  266. }
  267. if (number == 0) {
  268. return null;
  269. }
  270. lastField = UnknownField.CreateBuilder();
  271. UnknownField existing;
  272. if (fields.TryGetValue(number, out existing)) {
  273. lastField.MergeFrom(existing);
  274. }
  275. lastFieldNumber = number;
  276. return lastField;
  277. }
  278. /// <summary>
  279. /// Build the UnknownFieldSet and return it. Once this method has been called,
  280. /// this instance will no longer be usable. Calling any method after this
  281. /// will throw a NullReferenceException.
  282. /// </summary>
  283. public UnknownFieldSet Build() {
  284. GetFieldBuilder(0); // Force lastField to be built.
  285. UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
  286. fields = null;
  287. return result;
  288. }
  289. /// <summary>
  290. /// Adds a field to the set. If a field with the same number already exists, it
  291. /// is replaced.
  292. /// </summary>
  293. public Builder AddField(int number, UnknownField field) {
  294. if (number == 0) {
  295. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  296. }
  297. if (lastField != null && lastFieldNumber == number) {
  298. // Discard this.
  299. lastField = null;
  300. lastFieldNumber = 0;
  301. }
  302. fields[number] = field;
  303. return this;
  304. }
  305. /// <summary>
  306. /// Resets the builder to an empty set.
  307. /// </summary>
  308. public Builder Clear() {
  309. fields.Clear();
  310. lastFieldNumber = 0;
  311. lastField = null;
  312. return this;
  313. }
  314. /// <summary>
  315. /// Parse an entire message from <paramref name="input"/> and merge
  316. /// its fields into this set.
  317. /// </summary>
  318. public Builder MergeFrom(CodedInputStream input) {
  319. while (true) {
  320. uint tag = input.ReadTag();
  321. if (tag == 0 || !MergeFieldFrom(tag, input)) {
  322. break;
  323. }
  324. }
  325. return this;
  326. }
  327. /// <summary>
  328. /// Parse a single field from <paramref name="input"/> and merge it
  329. /// into this set.
  330. /// </summary>
  331. /// <param name="tag">The field's tag number, which was already parsed.</param>
  332. /// <param name="input">The coded input stream containing the field</param>
  333. /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
  334. [CLSCompliant(false)]
  335. public bool MergeFieldFrom(uint tag, CodedInputStream input) {
  336. int number = WireFormat.GetTagFieldNumber(tag);
  337. switch (WireFormat.GetTagWireType(tag)) {
  338. case WireFormat.WireType.Varint:
  339. GetFieldBuilder(number).AddVarint(input.ReadUInt64());
  340. return true;
  341. case WireFormat.WireType.Fixed64:
  342. GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
  343. return true;
  344. case WireFormat.WireType.LengthDelimited:
  345. GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
  346. return true;
  347. case WireFormat.WireType.StartGroup: {
  348. Builder subBuilder = CreateBuilder();
  349. #pragma warning disable 0612
  350. input.ReadUnknownGroup(number, subBuilder);
  351. #pragma warning restore 0612
  352. GetFieldBuilder(number).AddGroup(subBuilder.Build());
  353. return true;
  354. }
  355. case WireFormat.WireType.EndGroup:
  356. return false;
  357. case WireFormat.WireType.Fixed32:
  358. GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
  359. return true;
  360. default:
  361. throw InvalidProtocolBufferException.InvalidWireType();
  362. }
  363. }
  364. /// <summary>
  365. /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
  366. /// with the set being built. This is just a small wrapper around
  367. /// MergeFrom(CodedInputStream).
  368. /// </summary>
  369. public Builder MergeFrom(Stream input) {
  370. CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
  371. MergeFrom(codedInput);
  372. codedInput.CheckLastTagWas(0);
  373. return this;
  374. }
  375. /// <summary>
  376. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  377. /// with the set being built. This is just a small wrapper around
  378. /// MergeFrom(CodedInputStream).
  379. /// </summary>
  380. public Builder MergeFrom(ByteString data) {
  381. CodedInputStream input = data.CreateCodedInput();
  382. MergeFrom(input);
  383. input.CheckLastTagWas(0);
  384. return this;
  385. }
  386. /// <summary>
  387. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  388. /// with the set being built. This is just a small wrapper around
  389. /// MergeFrom(CodedInputStream).
  390. /// </summary>
  391. public Builder MergeFrom(byte[] data) {
  392. CodedInputStream input = CodedInputStream.CreateInstance(data);
  393. MergeFrom(input);
  394. input.CheckLastTagWas(0);
  395. return this;
  396. }
  397. /// <summary>
  398. /// Convenience method for merging a new field containing a single varint
  399. /// value. This is used in particular when an unknown enum value is
  400. /// encountered.
  401. /// </summary>
  402. [CLSCompliant(false)]
  403. public Builder MergeVarintField(int number, ulong value) {
  404. if (number == 0) {
  405. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  406. }
  407. GetFieldBuilder(number).AddVarint(value);
  408. return this;
  409. }
  410. /// <summary>
  411. /// Merges the fields from <paramref name="other"/> into this set.
  412. /// If a field number exists in both sets, the values in <paramref name="other"/>
  413. /// will be appended to the values in this set.
  414. /// </summary>
  415. public Builder MergeFrom(UnknownFieldSet other) {
  416. if (other != DefaultInstance) {
  417. foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
  418. MergeField(entry.Key, entry.Value);
  419. }
  420. }
  421. return this;
  422. }
  423. /// <summary>
  424. /// Checks if the given field number is present in the set.
  425. /// </summary>
  426. public bool HasField(int number) {
  427. if (number == 0) {
  428. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  429. }
  430. return number == lastFieldNumber || fields.ContainsKey(number);
  431. }
  432. /// <summary>
  433. /// Adds a field to the unknown field set. If a field with the same
  434. /// number already exists, the two are merged.
  435. /// </summary>
  436. public Builder MergeField(int number, UnknownField field) {
  437. if (number == 0) {
  438. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  439. }
  440. if (HasField(number)) {
  441. GetFieldBuilder(number).MergeFrom(field);
  442. } else {
  443. // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
  444. // in this case, but that would create a copy of the Field object.
  445. // We'd rather reuse the one passed to us, so call AddField() instead.
  446. AddField(number, field);
  447. }
  448. return this;
  449. }
  450. internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {
  451. while (true) {
  452. uint tag = input.ReadTag();
  453. if (tag == 0) {
  454. break;
  455. }
  456. if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {
  457. // end group tag
  458. break;
  459. }
  460. }
  461. }
  462. /// <summary>
  463. /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
  464. /// but parses a single field.
  465. /// </summary>
  466. /// <param name="input">The input to read the field from</param>
  467. /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
  468. /// <param name="builder">Builder to merge field into, if it's a known field</param>
  469. /// <param name="tag">The tag, which should already have been read from the input</param>
  470. /// <returns>true unless the tag is an end-group tag</returns>
  471. internal bool MergeFieldFrom(CodedInputStream input,
  472. ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) {
  473. MessageDescriptor type = builder.DescriptorForType;
  474. if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
  475. MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
  476. return true;
  477. }
  478. WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
  479. int fieldNumber = WireFormat.GetTagFieldNumber(tag);
  480. FieldDescriptor field;
  481. IMessage defaultFieldInstance = null;
  482. if (type.IsExtensionNumber(fieldNumber)) {
  483. ExtensionInfo extension = extensionRegistry[type, fieldNumber];
  484. if (extension == null) {
  485. field = null;
  486. } else {
  487. field = extension.Descriptor;
  488. defaultFieldInstance = extension.DefaultInstance;
  489. }
  490. } else {
  491. field = type.FindFieldByNumber(fieldNumber);
  492. }
  493. // Unknown field or wrong wire type. Skip.
  494. if (field == null || wireType != WireFormat.GetWireType(field)) {
  495. return MergeFieldFrom(tag, input);
  496. }
  497. if (field.IsPacked) {
  498. int length = (int)input.ReadRawVarint32();
  499. int limit = input.PushLimit(length);
  500. if (field.FieldType == FieldType.Enum) {
  501. while (!input.ReachedLimit) {
  502. int rawValue = input.ReadEnum();
  503. object value = field.EnumType.FindValueByNumber(rawValue);
  504. if (value == null) {
  505. // If the number isn't recognized as a valid value for this
  506. // enum, drop it (don't even add it to unknownFields).
  507. return true;
  508. }
  509. builder.WeakAddRepeatedField(field, value);
  510. }
  511. } else {
  512. while (!input.ReachedLimit) {
  513. Object value = input.ReadPrimitiveField(field.FieldType);
  514. builder.WeakAddRepeatedField(field, value);
  515. }
  516. }
  517. input.PopLimit(limit);
  518. } else {
  519. object value;
  520. switch (field.FieldType) {
  521. case FieldType.Group:
  522. case FieldType.Message: {
  523. IBuilder subBuilder;
  524. if (defaultFieldInstance != null) {
  525. subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
  526. } else {
  527. subBuilder = builder.CreateBuilderForField(field);
  528. }
  529. if (!field.IsRepeated) {
  530. subBuilder.WeakMergeFrom((IMessage)builder[field]);
  531. }
  532. if (field.FieldType == FieldType.Group) {
  533. input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
  534. } else {
  535. input.ReadMessage(subBuilder, extensionRegistry);
  536. }
  537. value = subBuilder.WeakBuild();
  538. break;
  539. }
  540. case FieldType.Enum: {
  541. int rawValue = input.ReadEnum();
  542. value = field.EnumType.FindValueByNumber(rawValue);
  543. // If the number isn't recognized as a valid value for this enum,
  544. // drop it.
  545. if (value == null) {
  546. MergeVarintField(fieldNumber, (ulong)rawValue);
  547. return true;
  548. }
  549. break;
  550. }
  551. default:
  552. value = input.ReadPrimitiveField(field.FieldType);
  553. break;
  554. }
  555. if (field.IsRepeated) {
  556. builder.WeakAddRepeatedField(field, value);
  557. } else {
  558. builder[field] = value;
  559. }
  560. }
  561. return true;
  562. }
  563. /// <summary>
  564. /// Called by MergeFieldFrom to parse a MessageSet extension.
  565. /// </summary>
  566. private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
  567. ExtensionRegistry extensionRegistry, IBuilder builder) {
  568. MessageDescriptor type = builder.DescriptorForType;
  569. // The wire format for MessageSet is:
  570. // message MessageSet {
  571. // repeated group Item = 1 {
  572. // required int32 typeId = 2;
  573. // required bytes message = 3;
  574. // }
  575. // }
  576. // "typeId" is the extension's field number. The extension can only be
  577. // a message type, where "message" contains the encoded bytes of that
  578. // message.
  579. //
  580. // In practice, we will probably never see a MessageSet item in which
  581. // the message appears before the type ID, or where either field does not
  582. // appear exactly once. However, in theory such cases are valid, so we
  583. // should be prepared to accept them.
  584. int typeId = 0;
  585. ByteString rawBytes = null; // If we encounter "message" before "typeId"
  586. IBuilder subBuilder = null;
  587. FieldDescriptor field = null;
  588. while (true) {
  589. uint tag = input.ReadTag();
  590. if (tag == 0) {
  591. break;
  592. }
  593. if (tag == WireFormat.MessageSetTag.TypeID) {
  594. typeId = input.ReadInt32();
  595. // Zero is not a valid type ID.
  596. if (typeId != 0) {
  597. ExtensionInfo extension = extensionRegistry[type, typeId];
  598. if (extension != null) {
  599. field = extension.Descriptor;
  600. subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
  601. IMessage originalMessage = (IMessage)builder[field];
  602. if (originalMessage != null) {
  603. subBuilder.WeakMergeFrom(originalMessage);
  604. }
  605. if (rawBytes != null) {
  606. // We already encountered the message. Parse it now.
  607. // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
  608. // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
  609. subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
  610. rawBytes = null;
  611. }
  612. } else {
  613. // Unknown extension number. If we already saw data, put it
  614. // in rawBytes.
  615. if (rawBytes != null) {
  616. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
  617. rawBytes = null;
  618. }
  619. }
  620. }
  621. } else if (tag == WireFormat.MessageSetTag.Message) {
  622. if (typeId == 0) {
  623. // We haven't seen a type ID yet, so we have to store the raw bytes for now.
  624. rawBytes = input.ReadBytes();
  625. } else if (subBuilder == null) {
  626. // We don't know how to parse this. Ignore it.
  627. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
  628. } else {
  629. // We already know the type, so we can parse directly from the input
  630. // with no copying. Hooray!
  631. input.ReadMessage(subBuilder, extensionRegistry);
  632. }
  633. } else {
  634. // Unknown tag. Skip it.
  635. if (!input.SkipField(tag)) {
  636. break; // end of group
  637. }
  638. }
  639. }
  640. input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
  641. if (subBuilder != null) {
  642. builder[field] = subBuilder.WeakBuild();
  643. }
  644. }
  645. #region IBuilderLite Members
  646. bool IBuilderLite.IsInitialized {
  647. get { return fields != null; }
  648. }
  649. IBuilderLite IBuilderLite.WeakClear() {
  650. return Clear();
  651. }
  652. IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message) {
  653. return MergeFrom((UnknownFieldSet)message);
  654. }
  655. IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data) {
  656. return MergeFrom(data);
  657. }
  658. IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
  659. return MergeFrom(data);
  660. }
  661. IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input) {
  662. return MergeFrom(input);
  663. }
  664. IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
  665. return MergeFrom(input);
  666. }
  667. IMessageLite IBuilderLite.WeakBuild() {
  668. return Build();
  669. }
  670. IMessageLite IBuilderLite.WeakBuildPartial() {
  671. return Build();
  672. }
  673. IBuilderLite IBuilderLite.WeakClone() {
  674. return Build().WeakToBuilder();
  675. }
  676. IMessageLite IBuilderLite.WeakDefaultInstanceForType {
  677. get { return DefaultInstance; }
  678. }
  679. #endregion
  680. }
  681. }
  682. }