UnknownFieldSet.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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. GetFieldBuilder(number).AddVarint(input.ReadUInt64());
  286. return true;
  287. case WireFormat.WireType.Fixed64:
  288. GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
  289. return true;
  290. case WireFormat.WireType.LengthDelimited:
  291. GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
  292. return true;
  293. case WireFormat.WireType.StartGroup: {
  294. Builder subBuilder = CreateBuilder();
  295. input.ReadUnknownGroup(number, subBuilder);
  296. GetFieldBuilder(number).AddGroup(subBuilder.Build());
  297. return true;
  298. }
  299. case WireFormat.WireType.EndGroup:
  300. return false;
  301. case WireFormat.WireType.Fixed32:
  302. GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
  303. return true;
  304. default:
  305. throw InvalidProtocolBufferException.InvalidWireType();
  306. }
  307. }
  308. /// <summary>
  309. /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
  310. /// with the set being built. This is just a small wrapper around
  311. /// MergeFrom(CodedInputStream).
  312. /// </summary>
  313. public Builder MergeFrom(Stream input) {
  314. CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
  315. MergeFrom(codedInput);
  316. codedInput.CheckLastTagWas(0);
  317. return this;
  318. }
  319. /// <summary>
  320. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  321. /// with the set being built. This is just a small wrapper around
  322. /// MergeFrom(CodedInputStream).
  323. /// </summary>
  324. public Builder MergeFrom(ByteString data) {
  325. CodedInputStream input = data.CreateCodedInput();
  326. MergeFrom(input);
  327. input.CheckLastTagWas(0);
  328. return this;
  329. }
  330. /// <summary>
  331. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  332. /// with the set being built. This is just a small wrapper around
  333. /// MergeFrom(CodedInputStream).
  334. /// </summary>
  335. public Builder MergeFrom(byte[] data) {
  336. CodedInputStream input = CodedInputStream.CreateInstance(data);
  337. MergeFrom(input);
  338. input.CheckLastTagWas(0);
  339. return this;
  340. }
  341. /// <summary>
  342. /// Convenience method for merging a new field containing a single varint
  343. /// value. This is used in particular when an unknown enum value is
  344. /// encountered.
  345. /// </summary>
  346. public Builder MergeVarintField(int number, ulong value) {
  347. if (number == 0) {
  348. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  349. }
  350. GetFieldBuilder(number).AddVarint(value);
  351. return this;
  352. }
  353. /// <summary>
  354. /// Merges the fields from <paramref name="other"/> into this set.
  355. /// If a field number exists in both sets, the values in <paramref name="other"/>
  356. /// will be appended to the values in this set.
  357. /// </summary>
  358. public Builder MergeFrom(UnknownFieldSet other) {
  359. if (other != DefaultInstance) {
  360. foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
  361. MergeField(entry.Key, entry.Value);
  362. }
  363. }
  364. return this;
  365. }
  366. /// <summary>
  367. /// Checks if the given field number is present in the set.
  368. /// </summary>
  369. public bool HasField(int number) {
  370. if (number == 0) {
  371. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  372. }
  373. return number == lastFieldNumber || fields.ContainsKey(number);
  374. }
  375. /// <summary>
  376. /// Adds a field to the unknown field set. If a field with the same
  377. /// number already exists, the two are merged.
  378. /// </summary>
  379. public Builder MergeField(int number, UnknownField field) {
  380. if (number == 0) {
  381. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  382. }
  383. if (HasField(number)) {
  384. GetFieldBuilder(number).MergeFrom(field);
  385. } else {
  386. // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
  387. // in this case, but that would create a copy of the Field object.
  388. // We'd rather reuse the one passed to us, so call AddField() instead.
  389. AddField(number, field);
  390. }
  391. return this;
  392. }
  393. internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {
  394. while (true) {
  395. uint tag = input.ReadTag();
  396. if (tag == 0) {
  397. break;
  398. }
  399. if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {
  400. // end group tag
  401. break;
  402. }
  403. }
  404. }
  405. /// <summary>
  406. /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
  407. /// but parses a single field.
  408. /// </summary>
  409. /// <param name="input">The input to read the field from</param>
  410. /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
  411. /// <param name="builder">Builder to merge field into, if it's a known field</param>
  412. /// <param name="tag">The tag, which should already have been read from the input</param>
  413. /// <returns>true unless the tag is an end-group tag</returns>
  414. internal bool MergeFieldFrom(CodedInputStream input,
  415. ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) {
  416. MessageDescriptor type = builder.DescriptorForType;
  417. if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
  418. MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
  419. return true;
  420. }
  421. WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
  422. int fieldNumber = WireFormat.GetTagFieldNumber(tag);
  423. FieldDescriptor field;
  424. IMessage defaultFieldInstance = null;
  425. if (type.IsExtensionNumber(fieldNumber)) {
  426. ExtensionInfo extension = extensionRegistry[type, fieldNumber];
  427. if (extension == null) {
  428. field = null;
  429. } else {
  430. field = extension.Descriptor;
  431. defaultFieldInstance = extension.DefaultInstance;
  432. }
  433. } else {
  434. field = type.FindFieldByNumber(fieldNumber);
  435. }
  436. // Unknown field or wrong wire type. Skip.
  437. if (field == null || wireType != WireFormat.GetWireType(field.FieldType)) {
  438. return MergeFieldFrom(tag, input);
  439. }
  440. object value;
  441. switch (field.FieldType) {
  442. case FieldType.Group:
  443. case FieldType.Message: {
  444. IBuilder subBuilder;
  445. if (defaultFieldInstance != null) {
  446. subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
  447. } else {
  448. subBuilder = builder.CreateBuilderForField(field);
  449. }
  450. if (!field.IsRepeated) {
  451. subBuilder.WeakMergeFrom((IMessage)builder[field]);
  452. }
  453. if (field.FieldType == FieldType.Group) {
  454. input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
  455. } else {
  456. input.ReadMessage(subBuilder, extensionRegistry);
  457. }
  458. value = subBuilder.WeakBuild();
  459. break;
  460. }
  461. case FieldType.Enum: {
  462. int rawValue = input.ReadEnum();
  463. value = field.EnumType.FindValueByNumber(rawValue);
  464. // If the number isn't recognized as a valid value for this enum,
  465. // drop it.
  466. if (value == null) {
  467. MergeVarintField(fieldNumber, (ulong)rawValue);
  468. return true;
  469. }
  470. break;
  471. }
  472. default:
  473. value = input.ReadPrimitiveField(field.FieldType);
  474. break;
  475. }
  476. if (field.IsRepeated) {
  477. builder.WeakAddRepeatedField(field, value);
  478. } else {
  479. builder[field] = value;
  480. }
  481. return true;
  482. }
  483. /// <summary>
  484. /// Called by MergeFieldFrom to parse a MessageSet extension.
  485. /// </summary>
  486. private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
  487. ExtensionRegistry extensionRegistry, IBuilder builder) {
  488. MessageDescriptor type = builder.DescriptorForType;
  489. // The wire format for MessageSet is:
  490. // message MessageSet {
  491. // repeated group Item = 1 {
  492. // required int32 typeId = 2;
  493. // required bytes message = 3;
  494. // }
  495. // }
  496. // "typeId" is the extension's field number. The extension can only be
  497. // a message type, where "message" contains the encoded bytes of that
  498. // message.
  499. //
  500. // In practice, we will probably never see a MessageSet item in which
  501. // the message appears before the type ID, or where either field does not
  502. // appear exactly once. However, in theory such cases are valid, so we
  503. // should be prepared to accept them.
  504. int typeId = 0;
  505. ByteString rawBytes = null; // If we encounter "message" before "typeId"
  506. IBuilder subBuilder = null;
  507. FieldDescriptor field = null;
  508. while (true) {
  509. uint tag = input.ReadTag();
  510. if (tag == 0) {
  511. break;
  512. }
  513. if (tag == WireFormat.MessageSetTag.TypeID) {
  514. typeId = input.ReadInt32();
  515. // Zero is not a valid type ID.
  516. if (typeId != 0) {
  517. ExtensionInfo extension = extensionRegistry[type, typeId];
  518. if (extension != null) {
  519. field = extension.Descriptor;
  520. subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
  521. IMessage originalMessage = (IMessage)builder[field];
  522. if (originalMessage != null) {
  523. subBuilder.WeakMergeFrom(originalMessage);
  524. }
  525. if (rawBytes != null) {
  526. // We already encountered the message. Parse it now.
  527. // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
  528. // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
  529. subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
  530. rawBytes = null;
  531. }
  532. } else {
  533. // Unknown extension number. If we already saw data, put it
  534. // in rawBytes.
  535. if (rawBytes != null) {
  536. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
  537. rawBytes = null;
  538. }
  539. }
  540. }
  541. } else if (tag == WireFormat.MessageSetTag.Message) {
  542. if (typeId == 0) {
  543. // We haven't seen a type ID yet, so we have to store the raw bytes for now.
  544. rawBytes = input.ReadBytes();
  545. } else if (subBuilder == null) {
  546. // We don't know how to parse this. Ignore it.
  547. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
  548. } else {
  549. // We already know the type, so we can parse directly from the input
  550. // with no copying. Hooray!
  551. input.ReadMessage(subBuilder, extensionRegistry);
  552. }
  553. } else {
  554. // Unknown tag. Skip it.
  555. if (!input.SkipField(tag)) {
  556. break; // end of group
  557. }
  558. }
  559. }
  560. input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
  561. if (subBuilder != null) {
  562. builder[field] = subBuilder.WeakBuild();
  563. }
  564. }
  565. }
  566. }
  567. }