UnknownFieldSet.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. using System;
  17. using System.Collections.Generic;
  18. using System.IO;
  19. using Google.ProtocolBuffers.Collections;
  20. using Google.ProtocolBuffers.Descriptors;
  21. namespace Google.ProtocolBuffers {
  22. /// <summary>
  23. /// Used to keep track of fields which were seen when parsing a protocol message
  24. /// but whose field numbers or types are unrecognized. This most frequently
  25. /// occurs when new fields are added to a message type and then messages containing
  26. /// those fields are read by old software that was built before the new types were
  27. /// added.
  28. ///
  29. /// Every message contains an UnknownFieldSet.
  30. ///
  31. /// Most users will never need to use this class directly.
  32. /// </summary>
  33. public sealed class UnknownFieldSet {
  34. private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
  35. private readonly IDictionary<int, UnknownField> fields;
  36. private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
  37. this.fields = fields;
  38. }
  39. /// <summary>
  40. /// Creates a new unknown field set builder.
  41. /// </summary>
  42. public static Builder CreateBuilder() {
  43. return new Builder();
  44. }
  45. /// <summary>
  46. /// Creates a new unknown field set builder
  47. /// and initialize it from <paramref name="original"/>.
  48. /// </summary>
  49. public static Builder CreateBuilder(UnknownFieldSet original) {
  50. return new Builder().MergeFrom(original);
  51. }
  52. public static UnknownFieldSet DefaultInstance {
  53. get { return defaultInstance; }
  54. }
  55. /// <summary>
  56. /// Returns a read-only view of the mapping from field numbers to values.
  57. /// </summary>
  58. public IDictionary<int, UnknownField> FieldDictionary {
  59. get { return Dictionaries.AsReadOnly(fields); }
  60. }
  61. /// <summary>
  62. /// Checks whether or not the given field number is present in the set.
  63. /// </summary>
  64. public bool HasField(int field) {
  65. return fields.ContainsKey(field);
  66. }
  67. /// <summary>
  68. /// Fetches a field by number, returning an empty field if not present.
  69. /// Never returns null.
  70. /// </summary>
  71. public UnknownField this[int number] {
  72. get {
  73. UnknownField ret;
  74. if (!fields.TryGetValue(number, out ret)) {
  75. ret = UnknownField.DefaultInstance;
  76. }
  77. return ret;
  78. }
  79. }
  80. /// <summary>
  81. /// Serializes the set and writes it to <paramref name="output"/>.
  82. /// </summary>
  83. public void WriteTo(CodedOutputStream output) {
  84. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  85. entry.Value.WriteTo(entry.Key, output);
  86. }
  87. }
  88. /// <summary>
  89. /// Gets the number of bytes required to encode this set.
  90. /// </summary>
  91. public int SerializedSize {
  92. get {
  93. int result = 0;
  94. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  95. result += entry.Value.GetSerializedSize(entry.Key);
  96. }
  97. return result;
  98. }
  99. }
  100. /// <summary>
  101. /// Converts the set to a string in protocol buffer text format. This
  102. /// is just a trivial wrapper around TextFormat.PrintToString.
  103. /// </summary>
  104. public override String ToString() {
  105. return TextFormat.PrintToString(this);
  106. }
  107. /// <summary>
  108. /// Serializes the message to a ByteString and returns it. This is
  109. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  110. /// </summary>
  111. /// <returns></returns>
  112. public ByteString ToByteString() {
  113. ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
  114. WriteTo(codedBuilder.CodedOutput);
  115. return codedBuilder.Build();
  116. }
  117. /// <summary>
  118. /// Serializes the message to a byte array and returns it. This is
  119. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  120. /// </summary>
  121. /// <returns></returns>
  122. public byte[] ToByteArray() {
  123. byte[] data = new byte[SerializedSize];
  124. CodedOutputStream output = CodedOutputStream.CreateInstance(data);
  125. WriteTo(output);
  126. output.CheckNoSpaceLeft();
  127. return data;
  128. }
  129. /// <summary>
  130. /// Serializes the message and writes it to <paramref name="output"/>. This is
  131. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  132. /// </summary>
  133. /// <param name="output"></param>
  134. public void WriteTo(Stream output) {
  135. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  136. WriteTo(codedOutput);
  137. codedOutput.Flush();
  138. }
  139. /// <summary>
  140. /// Serializes the set and writes it to <paramref name="output"/> using
  141. /// the MessageSet wire format.
  142. /// </summary>
  143. public void WriteAsMessageSetTo(CodedOutputStream output) {
  144. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  145. entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
  146. }
  147. }
  148. /// <summary>
  149. /// Gets the number of bytes required to encode this set using the MessageSet
  150. /// wire format.
  151. /// </summary>
  152. public int SerializedSizeAsMessageSet {
  153. get {
  154. int result = 0;
  155. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  156. result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
  157. }
  158. return result;
  159. }
  160. }
  161. /// <summary>
  162. /// Parses an UnknownFieldSet from the given input.
  163. /// </summary>
  164. public static UnknownFieldSet ParseFrom(CodedInputStream input) {
  165. return CreateBuilder().MergeFrom(input).Build();
  166. }
  167. /// <summary>
  168. /// Parses an UnknownFieldSet from the given data.
  169. /// </summary>
  170. public static UnknownFieldSet ParseFrom(ByteString data) {
  171. return CreateBuilder().MergeFrom(data).Build();
  172. }
  173. /// <summary>
  174. /// Parses an UnknownFieldSet from the given data.
  175. /// </summary>
  176. public static UnknownFieldSet ParseFrom(byte[] data) {
  177. return CreateBuilder().MergeFrom(data).Build();
  178. }
  179. /// <summary>
  180. /// Parses an UnknownFieldSet from the given input.
  181. /// </summary>
  182. public static UnknownFieldSet ParseFrom(Stream input) {
  183. return CreateBuilder().MergeFrom(input).Build();
  184. }
  185. /// <summary>
  186. /// Builder for UnknownFieldSets.
  187. /// </summary>
  188. public sealed class Builder
  189. {
  190. /// <summary>
  191. /// Mapping from number to field. Note that by using a SortedList we ensure
  192. /// that the fields will be serialized in ascending order.
  193. /// </summary>
  194. private IDictionary<int, UnknownField> fields = new SortedList<int, UnknownField>();
  195. // Optimization: We keep around a builder for the last field that was
  196. // modified so that we can efficiently add to it multiple times in a
  197. // row (important when parsing an unknown repeated field).
  198. int lastFieldNumber;
  199. UnknownField.Builder lastField;
  200. internal Builder() {
  201. }
  202. /// <summary>
  203. /// Returns a field builder for the specified field number, including any values
  204. /// which already exist.
  205. /// </summary>
  206. private UnknownField.Builder GetFieldBuilder(int number) {
  207. if (lastField != null) {
  208. if (number == lastFieldNumber) {
  209. return lastField;
  210. }
  211. // Note: AddField() will reset lastField and lastFieldNumber.
  212. AddField(lastFieldNumber, lastField.Build());
  213. }
  214. if (number == 0) {
  215. return null;
  216. }
  217. lastField = UnknownField.CreateBuilder();
  218. UnknownField existing;
  219. if (fields.TryGetValue(number, out existing)) {
  220. lastField.MergeFrom(existing);
  221. }
  222. lastFieldNumber = number;
  223. return lastField;
  224. }
  225. /// <summary>
  226. /// Build the UnknownFieldSet and return it. Once this method has been called,
  227. /// this instance will no longer be usable. Calling any method after this
  228. /// will throw a NullReferenceException.
  229. /// </summary>
  230. public UnknownFieldSet Build() {
  231. GetFieldBuilder(0); // Force lastField to be built.
  232. UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
  233. fields = null;
  234. return result;
  235. }
  236. /// <summary>
  237. /// Adds a field to the set. If a field with the same number already exists, it
  238. /// is replaced.
  239. /// </summary>
  240. public Builder AddField(int number, UnknownField field) {
  241. if (number == 0) {
  242. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  243. }
  244. if (lastField != null && lastFieldNumber == number) {
  245. // Discard this.
  246. lastField = null;
  247. lastFieldNumber = 0;
  248. }
  249. fields[number] = field;
  250. return this;
  251. }
  252. /// <summary>
  253. /// Resets the builder to an empty set.
  254. /// </summary>
  255. public Builder Clear() {
  256. fields.Clear();
  257. lastFieldNumber = 0;
  258. lastField = null;
  259. return this;
  260. }
  261. /// <summary>
  262. /// Parse an entire message from <paramref name="input"/> and merge
  263. /// its fields into this set.
  264. /// </summary>
  265. public Builder MergeFrom(CodedInputStream input) {
  266. while (true) {
  267. uint tag = input.ReadTag();
  268. if (tag == 0 || !MergeFieldFrom(tag, input)) {
  269. break;
  270. }
  271. }
  272. return this;
  273. }
  274. /// <summary>
  275. /// Parse a single field from <paramref name="input"/> and merge it
  276. /// into this set.
  277. /// </summary>
  278. /// <param name="tag">The field's tag number, which was already parsed.</param>
  279. /// <param name="input">The coded input stream containing the field</param>
  280. /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
  281. public bool MergeFieldFrom(uint tag, CodedInputStream input) {
  282. int number = WireFormat.GetTagFieldNumber(tag);
  283. switch (WireFormat.GetTagWireType(tag)) {
  284. case WireFormat.WireType.Varint:
  285. // TODO(jonskeet): Check this is correct (different to Java)
  286. GetFieldBuilder(number).AddVarint(input.ReadUInt64());
  287. return true;
  288. case WireFormat.WireType.Fixed64:
  289. GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
  290. return true;
  291. case WireFormat.WireType.LengthDelimited:
  292. GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
  293. return true;
  294. case WireFormat.WireType.StartGroup: {
  295. Builder subBuilder = CreateBuilder();
  296. input.ReadUnknownGroup(number, subBuilder);
  297. GetFieldBuilder(number).AddGroup(subBuilder.Build());
  298. return true;
  299. }
  300. case WireFormat.WireType.EndGroup:
  301. return false;
  302. case WireFormat.WireType.Fixed32:
  303. GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
  304. return true;
  305. default:
  306. throw InvalidProtocolBufferException.InvalidWireType();
  307. }
  308. }
  309. /// <summary>
  310. /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
  311. /// with the set being built. This is just a small wrapper around
  312. /// MergeFrom(CodedInputStream).
  313. /// </summary>
  314. public Builder MergeFrom(Stream input) {
  315. CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
  316. MergeFrom(codedInput);
  317. codedInput.CheckLastTagWas(0);
  318. return this;
  319. }
  320. /// <summary>
  321. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  322. /// with the set being built. This is just a small wrapper around
  323. /// MergeFrom(CodedInputStream).
  324. /// </summary>
  325. public Builder MergeFrom(ByteString data) {
  326. CodedInputStream input = data.CreateCodedInput();
  327. MergeFrom(input);
  328. input.CheckLastTagWas(0);
  329. return this;
  330. }
  331. /// <summary>
  332. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  333. /// with the set being built. This is just a small wrapper around
  334. /// MergeFrom(CodedInputStream).
  335. /// </summary>
  336. public Builder MergeFrom(byte[] data) {
  337. CodedInputStream input = CodedInputStream.CreateInstance(data);
  338. MergeFrom(input);
  339. input.CheckLastTagWas(0);
  340. return this;
  341. }
  342. /// <summary>
  343. /// Convenience method for merging a new field containing a single varint
  344. /// value. This is used in particular when an unknown enum value is
  345. /// encountered.
  346. /// </summary>
  347. public Builder MergeVarintField(int number, ulong value) {
  348. if (number == 0) {
  349. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  350. }
  351. GetFieldBuilder(number).AddVarint(value);
  352. return this;
  353. }
  354. /// <summary>
  355. /// Merges the fields from <paramref name="other"/> into this set.
  356. /// If a field number exists in both sets, the values in <paramref name="other"/>
  357. /// will be appended to the values in this set.
  358. /// </summary>
  359. public Builder MergeFrom(UnknownFieldSet other) {
  360. if (other != DefaultInstance) {
  361. foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
  362. MergeField(entry.Key, entry.Value);
  363. }
  364. }
  365. return this;
  366. }
  367. /// <summary>
  368. /// Checks if the given field number is present in the set.
  369. /// </summary>
  370. public bool HasField(int number) {
  371. if (number == 0) {
  372. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  373. }
  374. return number == lastFieldNumber || fields.ContainsKey(number);
  375. }
  376. /// <summary>
  377. /// Adds a field to the unknown field set. If a field with the same
  378. /// number already exists, the two are merged.
  379. /// </summary>
  380. public Builder MergeField(int number, UnknownField field) {
  381. if (number == 0) {
  382. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  383. }
  384. if (HasField(number)) {
  385. GetFieldBuilder(number).MergeFrom(field);
  386. } else {
  387. // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
  388. // in this case, but that would create a copy of the Field object.
  389. // We'd rather reuse the one passed to us, so call AddField() instead.
  390. AddField(number, field);
  391. }
  392. return this;
  393. }
  394. internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {
  395. while (true) {
  396. uint tag = input.ReadTag();
  397. if (tag == 0) {
  398. break;
  399. }
  400. if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {
  401. // end group tag
  402. break;
  403. }
  404. }
  405. }
  406. /// <summary>
  407. /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
  408. /// but parses a single field.
  409. /// </summary>
  410. /// <param name="input">The input to read the field from</param>
  411. /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
  412. /// <param name="builder">Builder to merge field into, if it's a known field</param>
  413. /// <param name="tag">The tag, which should already have been read from the input</param>
  414. /// <returns>true unless the tag is an end-group tag</returns>
  415. internal bool MergeFieldFrom(CodedInputStream input,
  416. ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) {
  417. MessageDescriptor type = builder.DescriptorForType;
  418. if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
  419. MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
  420. return true;
  421. }
  422. WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
  423. int fieldNumber = WireFormat.GetTagFieldNumber(tag);
  424. FieldDescriptor field;
  425. IMessage defaultFieldInstance = null;
  426. if (type.IsExtensionNumber(fieldNumber)) {
  427. ExtensionInfo extension = extensionRegistry[type, fieldNumber];
  428. if (extension == null) {
  429. field = null;
  430. } else {
  431. field = extension.Descriptor;
  432. defaultFieldInstance = extension.DefaultInstance;
  433. }
  434. } else {
  435. field = type.FindFieldByNumber(fieldNumber);
  436. }
  437. // Unknown field or wrong wire type. Skip.
  438. if (field == null || wireType != WireFormat.GetWireType(field.FieldType)) {
  439. return MergeFieldFrom(tag, input);
  440. }
  441. object value;
  442. switch (field.FieldType) {
  443. case FieldType.Group:
  444. case FieldType.Message: {
  445. IBuilder subBuilder;
  446. if (defaultFieldInstance != null) {
  447. subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
  448. } else {
  449. subBuilder = builder.CreateBuilderForField(field);
  450. }
  451. if (!field.IsRepeated) {
  452. subBuilder.WeakMergeFrom((IMessage)builder[field]);
  453. }
  454. if (field.FieldType == FieldType.Group) {
  455. input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
  456. } else {
  457. input.ReadMessage(subBuilder, extensionRegistry);
  458. }
  459. value = subBuilder.WeakBuild();
  460. break;
  461. }
  462. case FieldType.Enum: {
  463. int rawValue = input.ReadEnum();
  464. value = field.EnumType.FindValueByNumber(rawValue);
  465. // If the number isn't recognized as a valid value for this enum,
  466. // drop it.
  467. if (value == null) {
  468. MergeVarintField(fieldNumber, (ulong)rawValue);
  469. return true;
  470. }
  471. break;
  472. }
  473. default:
  474. value = input.ReadPrimitiveField(field.FieldType);
  475. break;
  476. }
  477. if (field.IsRepeated) {
  478. builder.WeakAddRepeatedField(field, value);
  479. } else {
  480. builder[field] = value;
  481. }
  482. return true;
  483. }
  484. /// <summary>
  485. /// Called by MergeFieldFrom to parse a MessageSet extension.
  486. /// </summary>
  487. private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
  488. ExtensionRegistry extensionRegistry, IBuilder builder) {
  489. MessageDescriptor type = builder.DescriptorForType;
  490. // The wire format for MessageSet is:
  491. // message MessageSet {
  492. // repeated group Item = 1 {
  493. // required int32 typeId = 2;
  494. // required bytes message = 3;
  495. // }
  496. // }
  497. // "typeId" is the extension's field number. The extension can only be
  498. // a message type, where "message" contains the encoded bytes of that
  499. // message.
  500. //
  501. // In practice, we will probably never see a MessageSet item in which
  502. // the message appears before the type ID, or where either field does not
  503. // appear exactly once. However, in theory such cases are valid, so we
  504. // should be prepared to accept them.
  505. int typeId = 0;
  506. ByteString rawBytes = null; // If we encounter "message" before "typeId"
  507. IBuilder subBuilder = null;
  508. FieldDescriptor field = null;
  509. while (true) {
  510. uint tag = input.ReadTag();
  511. if (tag == 0) {
  512. break;
  513. }
  514. if (tag == WireFormat.MessageSetTag.TypeID) {
  515. typeId = input.ReadInt32();
  516. // Zero is not a valid type ID.
  517. if (typeId != 0) {
  518. ExtensionInfo extension = extensionRegistry[type, typeId];
  519. if (extension != null) {
  520. field = extension.Descriptor;
  521. subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
  522. IMessage originalMessage = (IMessage)builder[field];
  523. if (originalMessage != null) {
  524. subBuilder.WeakMergeFrom(originalMessage);
  525. }
  526. if (rawBytes != null) {
  527. // We already encountered the message. Parse it now.
  528. // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
  529. // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
  530. subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
  531. rawBytes = null;
  532. }
  533. } else {
  534. // Unknown extension number. If we already saw data, put it
  535. // in rawBytes.
  536. if (rawBytes != null) {
  537. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
  538. rawBytes = null;
  539. }
  540. }
  541. }
  542. } else if (tag == WireFormat.MessageSetTag.Message) {
  543. if (typeId == 0) {
  544. // We haven't seen a type ID yet, so we have to store the raw bytes for now.
  545. rawBytes = input.ReadBytes();
  546. } else if (subBuilder == null) {
  547. // We don't know how to parse this. Ignore it.
  548. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
  549. } else {
  550. // We already know the type, so we can parse directly from the input
  551. // with no copying. Hooray!
  552. input.ReadMessage(subBuilder, extensionRegistry);
  553. }
  554. } else {
  555. // Unknown tag. Skip it.
  556. if (!input.SkipField(tag)) {
  557. break; // end of group
  558. }
  559. }
  560. }
  561. input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
  562. if (subBuilder != null) {
  563. builder[field] = subBuilder.WeakBuild();
  564. }
  565. }
  566. }
  567. }
  568. }