UnknownFieldSet.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  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. using Google.ProtocolBuffers.DescriptorProtos;
  22. namespace Google.ProtocolBuffers {
  23. /// <summary>
  24. /// Used to keep track of fields which were seen when parsing a protocol message
  25. /// but whose field numbers or types are unrecognized. This most frequently
  26. /// occurs when new fields are added to a message type and then messages containing
  27. /// those fields are read by old software that was built before the new types were
  28. /// added.
  29. ///
  30. /// Every message contains an UnknownFieldSet.
  31. ///
  32. /// Most users will never need to use this class directly.
  33. /// </summary>
  34. public sealed class UnknownFieldSet {
  35. private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
  36. private readonly IDictionary<int, UnknownField> fields;
  37. private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
  38. this.fields = fields;
  39. }
  40. /// <summary>
  41. /// Creates a new unknown field set builder.
  42. /// </summary>
  43. public static Builder CreateBuilder() {
  44. return new Builder();
  45. }
  46. /// <summary>
  47. /// Creates a new unknown field set builder
  48. /// and initialize it from <paramref name="original"/>.
  49. /// </summary>
  50. public static Builder CreateBuilder(UnknownFieldSet original) {
  51. return new Builder().MergeFrom(original);
  52. }
  53. public static UnknownFieldSet DefaultInstance {
  54. get { return defaultInstance; }
  55. }
  56. /// <summary>
  57. /// Returns a read-only view of the mapping from field numbers to values.
  58. /// </summary>
  59. public IDictionary<int, UnknownField> FieldDictionary {
  60. get { return Dictionaries.AsReadOnly(fields); }
  61. }
  62. /// <summary>
  63. /// Checks whether or not the given field number is present in the set.
  64. /// </summary>
  65. public bool HasField(int field) {
  66. return fields.ContainsKey(field);
  67. }
  68. /// <summary>
  69. /// Fetches a field by number, returning an empty field if not present.
  70. /// Never returns null.
  71. /// </summary>
  72. public UnknownField this[int number] {
  73. get {
  74. UnknownField ret;
  75. if (!fields.TryGetValue(number, out ret)) {
  76. ret = UnknownField.DefaultInstance;
  77. }
  78. return ret;
  79. }
  80. }
  81. /// <summary>
  82. /// Serializes the set and writes it to <paramref name="output"/>.
  83. /// </summary>
  84. public void WriteTo(CodedOutputStream output) {
  85. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  86. entry.Value.WriteTo(entry.Key, output);
  87. }
  88. }
  89. /// <summary>
  90. /// Gets the number of bytes required to encode this set.
  91. /// </summary>
  92. public int SerializedSize {
  93. get {
  94. int result = 0;
  95. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  96. result += entry.Value.GetSerializedSize(entry.Key);
  97. }
  98. return result;
  99. }
  100. }
  101. /// <summary>
  102. /// Converts the set to a string in protocol buffer text format. This
  103. /// is just a trivial wrapper around TextFormat.PrintToString.
  104. /// </summary>
  105. public override String ToString() {
  106. return TextFormat.PrintToString(this);
  107. }
  108. /// <summary>
  109. /// Serializes the message to a ByteString and returns it. This is
  110. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  111. /// </summary>
  112. /// <returns></returns>
  113. public ByteString ToByteString() {
  114. ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
  115. WriteTo(codedBuilder.CodedOutput);
  116. return codedBuilder.Build();
  117. }
  118. /// <summary>
  119. /// Serializes the message to a byte array and returns it. This is
  120. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  121. /// </summary>
  122. /// <returns></returns>
  123. public byte[] ToByteArray() {
  124. byte[] data = new byte[SerializedSize];
  125. CodedOutputStream output = CodedOutputStream.CreateInstance(data);
  126. WriteTo(output);
  127. output.CheckNoSpaceLeft();
  128. return data;
  129. }
  130. /// <summary>
  131. /// Serializes the message and writes it to <paramref name="output"/>. This is
  132. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  133. /// </summary>
  134. /// <param name="output"></param>
  135. public void WriteTo(Stream output) {
  136. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  137. WriteTo(codedOutput);
  138. codedOutput.Flush();
  139. }
  140. /// <summary>
  141. /// Serializes the set and writes it to <paramref name="output"/> using
  142. /// the MessageSet wire format.
  143. /// </summary>
  144. public void WriteAsMessageSetTo(CodedOutputStream output) {
  145. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  146. entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
  147. }
  148. }
  149. /// <summary>
  150. /// Gets the number of bytes required to encode this set using the MessageSet
  151. /// wire format.
  152. /// </summary>
  153. public int SerializedSizeAsMessageSet {
  154. get {
  155. int result = 0;
  156. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  157. result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
  158. }
  159. return result;
  160. }
  161. }
  162. /// <summary>
  163. /// Parses an UnknownFieldSet from the given input.
  164. /// </summary>
  165. public static UnknownFieldSet ParseFrom(CodedInputStream input) {
  166. return CreateBuilder().MergeFrom(input).Build();
  167. }
  168. /// <summary>
  169. /// Parses an UnknownFieldSet from the given data.
  170. /// </summary>
  171. public static UnknownFieldSet ParseFrom(ByteString data) {
  172. return CreateBuilder().MergeFrom(data).Build();
  173. }
  174. /// <summary>
  175. /// Parses an UnknownFieldSet from the given data.
  176. /// </summary>
  177. public static UnknownFieldSet ParseFrom(byte[] data) {
  178. return CreateBuilder().MergeFrom(data).Build();
  179. }
  180. /// <summary>
  181. /// Parses an UnknownFieldSet from the given input.
  182. /// </summary>
  183. public static UnknownFieldSet ParseFrom(Stream input) {
  184. return CreateBuilder().MergeFrom(input).Build();
  185. }
  186. /// <summary>
  187. /// Builder for UnknownFieldSets.
  188. /// </summary>
  189. public sealed class Builder
  190. {
  191. /// <summary>
  192. /// Mapping from number to field. Note that by using a SortedList we ensure
  193. /// that the fields will be serialized in ascending order.
  194. /// </summary>
  195. private IDictionary<int, UnknownField> fields = new SortedList<int, UnknownField>();
  196. // Optimization: We keep around a builder for the last field that was
  197. // modified so that we can efficiently add to it multiple times in a
  198. // row (important when parsing an unknown repeated field).
  199. int lastFieldNumber;
  200. UnknownField.Builder lastField;
  201. internal Builder() {
  202. }
  203. /// <summary>
  204. /// Returns a field builder for the specified field number, including any values
  205. /// which already exist.
  206. /// </summary>
  207. private UnknownField.Builder GetFieldBuilder(int number) {
  208. if (lastField != null) {
  209. if (number == lastFieldNumber) {
  210. return lastField;
  211. }
  212. // Note: AddField() will reset lastField and lastFieldNumber.
  213. AddField(lastFieldNumber, lastField.Build());
  214. }
  215. if (number == 0) {
  216. return null;
  217. }
  218. lastField = UnknownField.CreateBuilder();
  219. UnknownField existing;
  220. if (fields.TryGetValue(number, out existing)) {
  221. lastField.MergeFrom(existing);
  222. }
  223. lastFieldNumber = number;
  224. return lastField;
  225. }
  226. /// <summary>
  227. /// Build the UnknownFieldSet and return it. Once this method has been called,
  228. /// this instance will no longer be usable. Calling any method after this
  229. /// will throw a NullReferenceException.
  230. /// </summary>
  231. public UnknownFieldSet Build() {
  232. GetFieldBuilder(0); // Force lastField to be built.
  233. UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
  234. fields = null;
  235. return result;
  236. }
  237. /// <summary>
  238. /// Adds a field to the set. If a field with the same number already exists, it
  239. /// is replaced.
  240. /// </summary>
  241. public Builder AddField(int number, UnknownField field) {
  242. if (number == 0) {
  243. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  244. }
  245. if (lastField != null && lastFieldNumber == number) {
  246. // Discard this.
  247. lastField = null;
  248. lastFieldNumber = 0;
  249. }
  250. fields[number] = field;
  251. return this;
  252. }
  253. /// <summary>
  254. /// Resets the builder to an empty set.
  255. /// </summary>
  256. public Builder Clear() {
  257. fields.Clear();
  258. lastFieldNumber = 0;
  259. lastField = null;
  260. return this;
  261. }
  262. /// <summary>
  263. /// Parse an entire message from <paramref name="input"/> and merge
  264. /// its fields into this set.
  265. /// </summary>
  266. public Builder MergeFrom(CodedInputStream input) {
  267. while (true) {
  268. uint tag = input.ReadTag();
  269. if (tag == 0 || !MergeFieldFrom(tag, input)) {
  270. break;
  271. }
  272. }
  273. return this;
  274. }
  275. /// <summary>
  276. /// Parse a single field from <paramref name="input"/> and merge it
  277. /// into this set.
  278. /// </summary>
  279. /// <param name="tag">The field's tag number, which was already parsed.</param>
  280. /// <param name="input">The coded input stream containing the field</param>
  281. /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
  282. public bool MergeFieldFrom(uint tag, CodedInputStream input) {
  283. int number = WireFormat.GetTagFieldNumber(tag);
  284. switch (WireFormat.GetTagWireType(tag)) {
  285. case WireFormat.WireType.Varint:
  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. if (DescriptorProtoFile.Bootstrapping) {
  418. return MergeFieldFrom(tag, input);
  419. }
  420. MessageDescriptor type = builder.DescriptorForType;
  421. if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
  422. MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
  423. return true;
  424. }
  425. WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
  426. int fieldNumber = WireFormat.GetTagFieldNumber(tag);
  427. FieldDescriptor field;
  428. IMessage defaultFieldInstance = null;
  429. if (type.IsExtensionNumber(fieldNumber)) {
  430. ExtensionInfo extension = extensionRegistry[type, fieldNumber];
  431. if (extension == null) {
  432. field = null;
  433. } else {
  434. field = extension.Descriptor;
  435. defaultFieldInstance = extension.DefaultInstance;
  436. }
  437. } else {
  438. field = type.FindFieldByNumber(fieldNumber);
  439. }
  440. // Unknown field or wrong wire type. Skip.
  441. if (field == null || wireType != WireFormat.GetWireType(field.FieldType)) {
  442. return MergeFieldFrom(tag, input);
  443. }
  444. object value;
  445. switch (field.FieldType) {
  446. case FieldType.Group:
  447. case FieldType.Message: {
  448. IBuilder subBuilder;
  449. if (defaultFieldInstance != null) {
  450. subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
  451. } else {
  452. subBuilder = builder.CreateBuilderForField(field);
  453. }
  454. if (!field.IsRepeated) {
  455. subBuilder.WeakMergeFrom((IMessage)builder[field]);
  456. }
  457. if (field.FieldType == FieldType.Group) {
  458. input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
  459. } else {
  460. input.ReadMessage(subBuilder, extensionRegistry);
  461. }
  462. value = subBuilder.WeakBuild();
  463. break;
  464. }
  465. case FieldType.Enum: {
  466. int rawValue = input.ReadEnum();
  467. value = field.EnumType.FindValueByNumber(rawValue);
  468. // If the number isn't recognized as a valid value for this enum,
  469. // drop it.
  470. if (value == null) {
  471. MergeVarintField(fieldNumber, (ulong)rawValue);
  472. return true;
  473. }
  474. break;
  475. }
  476. default:
  477. value = input.ReadPrimitiveField(field.FieldType);
  478. break;
  479. }
  480. if (field.IsRepeated) {
  481. builder.WeakAddRepeatedField(field, value);
  482. } else {
  483. builder[field] = value;
  484. }
  485. return true;
  486. }
  487. /// <summary>
  488. /// Called by MergeFieldFrom to parse a MessageSet extension.
  489. /// </summary>
  490. private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
  491. ExtensionRegistry extensionRegistry, IBuilder builder) {
  492. MessageDescriptor type = builder.DescriptorForType;
  493. // The wire format for MessageSet is:
  494. // message MessageSet {
  495. // repeated group Item = 1 {
  496. // required int32 typeId = 2;
  497. // required bytes message = 3;
  498. // }
  499. // }
  500. // "typeId" is the extension's field number. The extension can only be
  501. // a message type, where "message" contains the encoded bytes of that
  502. // message.
  503. //
  504. // In practice, we will probably never see a MessageSet item in which
  505. // the message appears before the type ID, or where either field does not
  506. // appear exactly once. However, in theory such cases are valid, so we
  507. // should be prepared to accept them.
  508. int typeId = 0;
  509. ByteString rawBytes = null; // If we encounter "message" before "typeId"
  510. IBuilder subBuilder = null;
  511. FieldDescriptor field = null;
  512. while (true) {
  513. uint tag = input.ReadTag();
  514. if (tag == 0) {
  515. break;
  516. }
  517. if (tag == WireFormat.MessageSetTag.TypeID) {
  518. typeId = input.ReadInt32();
  519. // Zero is not a valid type ID.
  520. if (typeId != 0) {
  521. ExtensionInfo extension = extensionRegistry[type, typeId];
  522. if (extension != null) {
  523. field = extension.Descriptor;
  524. subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
  525. IMessage originalMessage = (IMessage)builder[field];
  526. if (originalMessage != null) {
  527. subBuilder.WeakMergeFrom(originalMessage);
  528. }
  529. if (rawBytes != null) {
  530. // We already encountered the message. Parse it now.
  531. // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
  532. // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
  533. subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
  534. rawBytes = null;
  535. }
  536. } else {
  537. // Unknown extension number. If we already saw data, put it
  538. // in rawBytes.
  539. if (rawBytes != null) {
  540. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
  541. rawBytes = null;
  542. }
  543. }
  544. }
  545. } else if (tag == WireFormat.MessageSetTag.Message) {
  546. if (typeId == 0) {
  547. // We haven't seen a type ID yet, so we have to store the raw bytes for now.
  548. rawBytes = input.ReadBytes();
  549. } else if (subBuilder == null) {
  550. // We don't know how to parse this. Ignore it.
  551. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
  552. } else {
  553. // We already know the type, so we can parse directly from the input
  554. // with no copying. Hooray!
  555. input.ReadMessage(subBuilder, extensionRegistry);
  556. }
  557. } else {
  558. // Unknown tag. Skip it.
  559. if (!input.SkipField(tag)) {
  560. break; // end of group
  561. }
  562. }
  563. }
  564. input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
  565. if (subBuilder != null) {
  566. builder[field] = subBuilder.WeakBuild();
  567. }
  568. }
  569. }
  570. }
  571. }