UnknownFieldSet.cs 14 KB

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