UnknownFieldSet.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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. namespace Google.ProtocolBuffers {
  21. /// <summary>
  22. /// Used to keep track of fields which were seen when parsing a protocol message
  23. /// but whose field numbers or types are unrecognized. This most frequently
  24. /// occurs when new fields are added to a message type and then messages containing
  25. /// those fields are read by old software that was built before the new types were
  26. /// added.
  27. ///
  28. /// Every message contains an UnknownFieldSet.
  29. ///
  30. /// Most users will never need to use this class directly.
  31. /// </summary>
  32. public sealed class UnknownFieldSet {
  33. private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
  34. private readonly IDictionary<int, UnknownField> fields;
  35. private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
  36. this.fields = fields;
  37. }
  38. /// <summary>
  39. /// Creates a new unknown field set builder.
  40. /// </summary>
  41. public static Builder CreateBuilder() {
  42. return new Builder();
  43. }
  44. /// <summary>
  45. /// Creates a new unknown field set builder
  46. /// and initialize it from <paramref name="original"/>.
  47. /// </summary>
  48. public static Builder CreateBuilder(UnknownFieldSet original) {
  49. return new Builder().MergeFrom(original);
  50. }
  51. public static UnknownFieldSet DefaultInstance {
  52. get { return defaultInstance; }
  53. }
  54. /// <summary>
  55. /// Returns a read-only view of the mapping from field numbers to values.
  56. /// </summary>
  57. public IDictionary<int, UnknownField> FieldDictionary {
  58. get { return Dictionaries.AsReadOnly(fields); }
  59. }
  60. /// <summary>
  61. /// Checks whether or not the given field number is present in the set.
  62. /// </summary>
  63. public bool HasField(int field) {
  64. return fields.ContainsKey(field);
  65. }
  66. /// <summary>
  67. /// Fetches a field by number, returning an empty field if not present.
  68. /// Never returns null.
  69. /// </summary>
  70. public UnknownField this[int number] {
  71. get {
  72. UnknownField ret;
  73. if (!fields.TryGetValue(number, out ret)) {
  74. ret = UnknownField.DefaultInstance;
  75. }
  76. return ret;
  77. }
  78. }
  79. /// <summary>
  80. /// Serializes the set and writes it to <paramref name="output"/>.
  81. /// </summary>
  82. public void WriteTo(CodedOutputStream output) {
  83. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  84. entry.Value.WriteTo(entry.Key, output);
  85. }
  86. }
  87. /// <summary>
  88. /// Gets the number of bytes required to encode this set.
  89. /// </summary>
  90. public int SerializedSize {
  91. get {
  92. int result = 0;
  93. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  94. result += entry.Value.GetSerializedSize(entry.Key);
  95. }
  96. return result;
  97. }
  98. }
  99. /// <summary>
  100. /// Converts the set to a string in protocol buffer text format. This
  101. /// is just a trivial wrapper around TextFormat.PrintToString.
  102. /// </summary>
  103. public override String ToString() {
  104. return TextFormat.PrintToString(this);
  105. }
  106. /// <summary>
  107. /// Serializes the message to a ByteString and returns it. This is
  108. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  109. /// </summary>
  110. /// <returns></returns>
  111. public ByteString ToByteString() {
  112. ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
  113. WriteTo(codedBuilder.CodedOutput);
  114. return codedBuilder.Build();
  115. }
  116. /// <summary>
  117. /// Serializes the message to a byte array and returns it. This is
  118. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  119. /// </summary>
  120. /// <returns></returns>
  121. public byte[] ToByteArray() {
  122. byte[] data = new byte[SerializedSize];
  123. CodedOutputStream output = CodedOutputStream.CreateInstance(data);
  124. WriteTo(output);
  125. output.CheckNoSpaceLeft();
  126. return data;
  127. }
  128. /// <summary>
  129. /// Serializes the message and writes it to <paramref name="output"/>. This is
  130. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  131. /// </summary>
  132. /// <param name="output"></param>
  133. public void WriteTo(Stream output) {
  134. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  135. WriteTo(codedOutput);
  136. codedOutput.Flush();
  137. }
  138. /// <summary>
  139. /// Serializes the set and writes it to <paramref name="output"/> using
  140. /// the MessageSet wire format.
  141. /// </summary>
  142. public void WriteAsMessageSetTo(CodedOutputStream output) {
  143. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  144. entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
  145. }
  146. }
  147. /// <summary>
  148. /// Gets the number of bytes required to encode this set using the MessageSet
  149. /// wire format.
  150. /// </summary>
  151. public int SerializedSizeAsMessageSet {
  152. get {
  153. int result = 0;
  154. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  155. result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
  156. }
  157. return result;
  158. }
  159. }
  160. /// <summary>
  161. /// Parses an UnknownFieldSet from the given input.
  162. /// </summary>
  163. public static UnknownFieldSet ParseFrom(CodedInputStream input) {
  164. return CreateBuilder().MergeFrom(input).Build();
  165. }
  166. /// <summary>
  167. /// Parses an UnknownFieldSet from the given data.
  168. /// </summary>
  169. public static UnknownFieldSet ParseFrom(ByteString data) {
  170. return CreateBuilder().MergeFrom(data).Build();
  171. }
  172. /// <summary>
  173. /// Parses an UnknownFieldSet from the given data.
  174. /// </summary>
  175. public static UnknownFieldSet ParseFrom(byte[] data) {
  176. return CreateBuilder().MergeFrom(data).Build();
  177. }
  178. /// <summary>
  179. /// Parses an UnknownFieldSet from the given input.
  180. /// </summary>
  181. public static UnknownFieldSet ParseFrom(Stream input) {
  182. return CreateBuilder().MergeFrom(input).Build();
  183. }
  184. /// <summary>
  185. /// Builder for UnknownFieldSets.
  186. /// </summary>
  187. public sealed class Builder
  188. {
  189. /// <summary>
  190. /// Mapping from number to field. Note that by using a SortedList we ensure
  191. /// that the fields will be serialized in ascending order.
  192. /// </summary>
  193. private IDictionary<int, UnknownField> fields = new SortedList<int, UnknownField>();
  194. // Optimization: We keep around a builder for the last field that was
  195. // modified so that we can efficiently add to it multiple times in a
  196. // row (important when parsing an unknown repeated field).
  197. int lastFieldNumber;
  198. UnknownField.Builder lastField;
  199. internal Builder() {
  200. }
  201. /// <summary>
  202. /// Returns a field builder for the specified field number, including any values
  203. /// which already exist.
  204. /// </summary>
  205. private UnknownField.Builder GetFieldBuilder(int number) {
  206. if (lastField != null) {
  207. if (number == lastFieldNumber) {
  208. return lastField;
  209. }
  210. // Note: AddField() will reset lastField and lastFieldNumber.
  211. AddField(lastFieldNumber, lastField.Build());
  212. }
  213. if (number == 0) {
  214. return null;
  215. }
  216. lastField = UnknownField.CreateBuilder();
  217. UnknownField existing;
  218. if (fields.TryGetValue(number, out existing)) {
  219. lastField.MergeFrom(existing);
  220. }
  221. lastFieldNumber = number;
  222. return lastField;
  223. }
  224. /// <summary>
  225. /// Build the UnknownFieldSet and return it. Once this method has been called,
  226. /// this instance will no longer be usable. Calling any method after this
  227. /// will throw a NullReferenceException.
  228. /// </summary>
  229. public UnknownFieldSet Build() {
  230. GetFieldBuilder(0); // Force lastField to be built.
  231. UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
  232. fields = null;
  233. return result;
  234. }
  235. /// <summary>
  236. /// Adds a field to the set. If a field with the same number already exists, it
  237. /// is replaced.
  238. /// </summary>
  239. public Builder AddField(int number, UnknownField field) {
  240. if (number == 0) {
  241. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  242. }
  243. if (lastField != null && lastFieldNumber == number) {
  244. // Discard this.
  245. lastField = null;
  246. lastFieldNumber = 0;
  247. }
  248. fields[number] = field;
  249. return this;
  250. }
  251. /// <summary>
  252. /// Resets the builder to an empty set.
  253. /// </summary>
  254. public Builder Clear() {
  255. fields.Clear();
  256. lastFieldNumber = 0;
  257. lastField = null;
  258. return this;
  259. }
  260. /// <summary>
  261. /// Parse an entire message from <paramref name="input"/> and merge
  262. /// its fields into this set.
  263. /// </summary>
  264. public Builder MergeFrom(CodedInputStream input) {
  265. while (true) {
  266. uint tag = input.ReadTag();
  267. if (tag == 0 || !MergeFieldFrom(tag, input)) {
  268. break;
  269. }
  270. }
  271. return this;
  272. }
  273. /// <summary>
  274. /// Parse a single field from <paramref name="input"/> and merge it
  275. /// into this set.
  276. /// </summary>
  277. /// <param name="tag">The field's tag number, which was already parsed.</param>
  278. /// <param name="input">The coded input stream containing the field</param>
  279. /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
  280. public bool MergeFieldFrom(uint tag, CodedInputStream input) {
  281. int number = WireFormat.GetTagFieldNumber(tag);
  282. switch (WireFormat.GetTagWireType(tag)) {
  283. case WireFormat.WireType.Varint:
  284. // TODO(jonskeet): Check this is correct (different to Java)
  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. }
  394. }
  395. }