UnknownFieldSet.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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. public class UnknownFieldSet {
  22. private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
  23. private readonly IDictionary<int, UnknownField> fields;
  24. private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
  25. this.fields = fields;
  26. }
  27. /// <summary>
  28. /// Creates a new unknown field set builder.
  29. /// </summary>
  30. public static Builder CreateBuilder() {
  31. return new Builder();
  32. }
  33. /// <summary>
  34. /// Creates a new unknown field set builder
  35. /// and initialize it from <paramref name="original"/>.
  36. /// </summary>
  37. public static Builder CreateBuilder(UnknownFieldSet original) {
  38. return new Builder().MergeFrom(original);
  39. }
  40. public static UnknownFieldSet DefaultInstance {
  41. get { return defaultInstance; }
  42. }
  43. /// <summary>
  44. /// Returns a read-only view of the mapping from field numbers to values.
  45. /// </summary>
  46. public IDictionary<int, UnknownField> FieldDictionary {
  47. get { return Dictionaries.AsReadOnly(fields); }
  48. }
  49. /// <summary>
  50. /// Checks whether or not the given field number is present in the set.
  51. /// </summary>
  52. public bool HasField(int field) {
  53. return fields.ContainsKey(field);
  54. }
  55. /// <summary>
  56. /// Fetches a field by number, returning an empty field if not present.
  57. /// Never returns null.
  58. /// </summary>
  59. public UnknownField this[int number] {
  60. get {
  61. UnknownField ret;
  62. if (!fields.TryGetValue(number, out ret)) {
  63. ret = UnknownField.DefaultInstance;
  64. }
  65. return ret;
  66. }
  67. }
  68. /// <summary>
  69. /// Serializes the set and writes it to <paramref name="output"/>.
  70. /// </summary>
  71. public void WriteTo(CodedOutputStream output) {
  72. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  73. entry.Value.WriteTo(entry.Key, output);
  74. }
  75. }
  76. /// <summary>
  77. /// Gets the number of bytes required to encode this set.
  78. /// </summary>
  79. public int SerializedSize {
  80. get {
  81. int result = 0;
  82. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  83. result += entry.Value.GetSerializedSize(entry.Key);
  84. }
  85. return result;
  86. }
  87. }
  88. /// <summary>
  89. /// Converts the set to a string in protocol buffer text format. This
  90. /// is just a trivial wrapper around TextFormat.PrintToString.
  91. /// </summary>
  92. public override String ToString() {
  93. return TextFormat.PrintToString(this);
  94. }
  95. /// <summary>
  96. /// Serializes the message to a ByteString and returns it. This is
  97. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  98. /// </summary>
  99. /// <returns></returns>
  100. public ByteString ToByteString() {
  101. ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
  102. WriteTo(codedBuilder.CodedOutput);
  103. return codedBuilder.Build();
  104. }
  105. /// <summary>
  106. /// Serializes the message to a byte array and returns it. This is
  107. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  108. /// </summary>
  109. /// <returns></returns>
  110. public byte[] ToByteArray() {
  111. byte[] data = new byte[SerializedSize];
  112. CodedOutputStream output = CodedOutputStream.CreateInstance(data);
  113. WriteTo(output);
  114. output.CheckNoSpaceLeft();
  115. return data;
  116. }
  117. /// <summary>
  118. /// Serializes the message and writes it to <paramref name="output"/>. This is
  119. /// just a trivial wrapper around WriteTo(CodedOutputStream).
  120. /// </summary>
  121. /// <param name="output"></param>
  122. public void WriteTo(Stream output) {
  123. CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
  124. WriteTo(codedOutput);
  125. codedOutput.Flush();
  126. }
  127. /// <summary>
  128. /// Serializes the set and writes it to <paramref name="output"/> using
  129. /// the MessageSet wire format.
  130. /// </summary>
  131. public void WriteAsMessageSetTo(CodedOutputStream output) {
  132. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  133. entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
  134. }
  135. }
  136. /// <summary>
  137. /// Gets the number of bytes required to encode this set using the MessageSet
  138. /// wire format.
  139. /// </summary>
  140. public int SerializedSizeAsMessageSet {
  141. get {
  142. int result = 0;
  143. foreach (KeyValuePair<int, UnknownField> entry in fields) {
  144. result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
  145. }
  146. return result;
  147. }
  148. }
  149. /// <summary>
  150. /// Parses an UnknownFieldSet from the given input.
  151. /// </summary>
  152. public static UnknownFieldSet ParseFrom(CodedInputStream input) {
  153. return CreateBuilder().MergeFrom(input).Build();
  154. }
  155. /// <summary>
  156. /// Parses an UnknownFieldSet from the given data.
  157. /// </summary>
  158. public static UnknownFieldSet ParseFrom(ByteString data) {
  159. return CreateBuilder().MergeFrom(data).Build();
  160. }
  161. /// <summary>
  162. /// Parses an UnknownFieldSet from the given data.
  163. /// </summary>
  164. public static UnknownFieldSet ParseFrom(byte[] data) {
  165. return CreateBuilder().MergeFrom(data).Build();
  166. }
  167. /// <summary>
  168. /// Parses an UnknownFieldSet from the given input.
  169. /// </summary>
  170. public static UnknownFieldSet ParseFrom(Stream input) {
  171. return CreateBuilder().MergeFrom(input).Build();
  172. }
  173. public class Builder
  174. {
  175. /// <summary>
  176. /// Mapping from number to field. Note that by using a SortedList we ensure
  177. /// that the fields will be serialized in ascending order.
  178. /// </summary>
  179. private IDictionary<int, UnknownField> fields = new SortedList<int, UnknownField>();
  180. // Optimization: We keep around a builder for the last field that was
  181. // modified so that we can efficiently add to it multiple times in a
  182. // row (important when parsing an unknown repeated field).
  183. int lastFieldNumber;
  184. UnknownField.Builder lastField;
  185. internal Builder() {
  186. }
  187. /// <summary>
  188. /// Returns a field builder for the specified field number, including any values
  189. /// which already exist.
  190. /// </summary>
  191. private UnknownField.Builder GetFieldBuilder(int number) {
  192. if (lastField != null) {
  193. if (number == lastFieldNumber) {
  194. return lastField;
  195. }
  196. // Note: AddField() will reset lastField and lastFieldNumber.
  197. AddField(lastFieldNumber, lastField.Build());
  198. }
  199. if (number == 0) {
  200. return null;
  201. }
  202. lastField = UnknownField.CreateBuilder();
  203. UnknownField existing;
  204. if (fields.TryGetValue(number, out existing)) {
  205. lastField.MergeFrom(existing);
  206. }
  207. lastFieldNumber = number;
  208. return lastField;
  209. }
  210. /// <summary>
  211. /// Build the UnknownFieldSet and return it. Once this method has been called,
  212. /// this instance will no longer be usable. Calling any method after this
  213. /// will throw a NullReferenceException.
  214. /// </summary>
  215. public UnknownFieldSet Build() {
  216. GetFieldBuilder(0); // Force lastField to be built.
  217. UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
  218. fields = null;
  219. return result;
  220. }
  221. /// <summary>
  222. /// Adds a field to the set. If a field with the same number already exists, it
  223. /// is replaced.
  224. /// </summary>
  225. public Builder AddField(int number, UnknownField field) {
  226. if (number == 0) {
  227. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  228. }
  229. if (lastField != null && lastFieldNumber == number) {
  230. // Discard this.
  231. lastField = null;
  232. lastFieldNumber = 0;
  233. }
  234. fields[number] = field;
  235. return this;
  236. }
  237. /// <summary>
  238. /// Resets the builder to an empty set.
  239. /// </summary>
  240. public Builder Clear() {
  241. fields.Clear();
  242. lastFieldNumber = 0;
  243. lastField = null;
  244. return this;
  245. }
  246. /// <summary>
  247. /// Parse an entire message from <paramref name="input"/> and merge
  248. /// its fields into this set.
  249. /// </summary>
  250. public Builder MergeFrom(CodedInputStream input) {
  251. while (true) {
  252. uint tag = input.ReadTag();
  253. if (tag == 0 || !MergeFieldFrom(tag, input)) {
  254. break;
  255. }
  256. }
  257. return this;
  258. }
  259. /// <summary>
  260. /// Parse a single field from <paramref name="input"/> and merge it
  261. /// into this set.
  262. /// </summary>
  263. /// <param name="tag">The field's tag number, which was already parsed.</param>
  264. /// <param name="input">The coded input stream containing the field</param>
  265. /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
  266. public bool MergeFieldFrom(uint tag, CodedInputStream input) {
  267. int number = WireFormat.GetTagFieldNumber(tag);
  268. switch (WireFormat.GetTagWireType(tag)) {
  269. case WireFormat.WireType.Varint:
  270. // TODO(jonskeet): Check this is correct (different to Java)
  271. GetFieldBuilder(number).AddVarint(input.ReadUInt64());
  272. return true;
  273. case WireFormat.WireType.Fixed64:
  274. GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
  275. return true;
  276. case WireFormat.WireType.LengthDelimited:
  277. GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
  278. return true;
  279. case WireFormat.WireType.StartGroup: {
  280. Builder subBuilder = CreateBuilder();
  281. input.ReadUnknownGroup(number, subBuilder);
  282. GetFieldBuilder(number).AddGroup(subBuilder.Build());
  283. return true;
  284. }
  285. case WireFormat.WireType.EndGroup:
  286. return false;
  287. case WireFormat.WireType.Fixed32:
  288. GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
  289. return true;
  290. default:
  291. throw InvalidProtocolBufferException.InvalidWireType();
  292. }
  293. }
  294. /// <summary>
  295. /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
  296. /// with the set being built. This is just a small wrapper around
  297. /// MergeFrom(CodedInputStream).
  298. /// </summary>
  299. public Builder MergeFrom(Stream input) {
  300. CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
  301. MergeFrom(codedInput);
  302. codedInput.CheckLastTagWas(0);
  303. return this;
  304. }
  305. /// <summary>
  306. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  307. /// with the set being built. This is just a small wrapper around
  308. /// MergeFrom(CodedInputStream).
  309. /// </summary>
  310. public Builder MergeFrom(ByteString data) {
  311. CodedInputStream input = data.CreateCodedInput();
  312. MergeFrom(input);
  313. input.CheckLastTagWas(0);
  314. return this;
  315. }
  316. /// <summary>
  317. /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
  318. /// with the set being built. This is just a small wrapper around
  319. /// MergeFrom(CodedInputStream).
  320. /// </summary>
  321. public Builder MergeFrom(byte[] data) {
  322. CodedInputStream input = CodedInputStream.CreateInstance(data);
  323. MergeFrom(input);
  324. input.CheckLastTagWas(0);
  325. return this;
  326. }
  327. /// <summary>
  328. /// Convenience method for merging a new field containing a single varint
  329. /// value. This is used in particular when an unknown enum value is
  330. /// encountered.
  331. /// </summary>
  332. public Builder MergeVarintField(int number, ulong value) {
  333. if (number == 0) {
  334. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  335. }
  336. GetFieldBuilder(number).AddVarint(value);
  337. return this;
  338. }
  339. /// <summary>
  340. /// Merges the fields from <paramref name="other"/> into this set.
  341. /// If a field number exists in both sets, the values in <paramref name="other"/>
  342. /// will be appended to the values in this set.
  343. /// </summary>
  344. public Builder MergeFrom(UnknownFieldSet other) {
  345. if (other != DefaultInstance) {
  346. foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
  347. MergeField(entry.Key, entry.Value);
  348. }
  349. }
  350. return this;
  351. }
  352. /// <summary>
  353. /// Checks if the given field number is present in the set.
  354. /// </summary>
  355. public bool HasField(int number) {
  356. if (number == 0) {
  357. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  358. }
  359. return number == lastFieldNumber || fields.ContainsKey(number);
  360. }
  361. /// <summary>
  362. /// Adds a field to the unknown field set. If a field with the same
  363. /// number already exists, the two are merged.
  364. /// </summary>
  365. public Builder MergeField(int number, UnknownField field) {
  366. if (number == 0) {
  367. throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
  368. }
  369. if (HasField(number)) {
  370. GetFieldBuilder(number).MergeFrom(field);
  371. } else {
  372. // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
  373. // in this case, but that would create a copy of the Field object.
  374. // We'd rather reuse the one passed to us, so call AddField() instead.
  375. AddField(number, field);
  376. }
  377. return this;
  378. }
  379. }
  380. }
  381. }