blob: 12f2186cf42927e26df1490d3ccbc34f78d29374 [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
Jon Skeet60c059b2008-10-23 21:17:56 +01002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01006// http://code.google.com/p/protobuf/
7//
Jon Skeet60c059b2008-10-23 21:17:56 +01008// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
Jon Skeet68036862008-10-22 13:30:34 +010011//
Jon Skeet60c059b2008-10-23 21:17:56 +010012// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010021//
Jon Skeet60c059b2008-10-23 21:17:56 +010022// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeet68036862008-10-22 13:30:34 +010035using System;
36using System.Collections.Generic;
37using System.IO;
38using Google.ProtocolBuffers.Descriptors;
39
40namespace Google.ProtocolBuffers {
41
42 /// <summary>
43 /// An implementation of IMessage that can represent arbitrary types, given a MessageaDescriptor.
44 /// </summary>
45 public sealed class DynamicMessage : AbstractMessage<DynamicMessage, DynamicMessage.Builder> {
46
47 private readonly MessageDescriptor type;
48 private readonly FieldSet fields;
49 private readonly UnknownFieldSet unknownFields;
50 private int memoizedSize = -1;
51
52 /// <summary>
53 /// Creates a DynamicMessage with the given FieldSet.
54 /// </summary>
55 /// <param name="type"></param>
56 /// <param name="fields"></param>
57 /// <param name="unknownFields"></param>
58 private DynamicMessage(MessageDescriptor type, FieldSet fields, UnknownFieldSet unknownFields) {
59 this.type = type;
60 this.fields = fields;
61 this.unknownFields = unknownFields;
62 }
63
64 /// <summary>
65 /// Returns a DynamicMessage representing the default instance of the given type.
66 /// </summary>
67 /// <param name="type"></param>
68 /// <returns></returns>
69 public static DynamicMessage GetDefaultInstance(MessageDescriptor type) {
70 return new DynamicMessage(type, FieldSet.DefaultInstance, UnknownFieldSet.DefaultInstance);
71 }
72
73 /// <summary>
74 /// Parses a message of the given type from the given stream.
75 /// </summary>
76 public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input) {
77 Builder builder = CreateBuilder(type);
78 Builder dynamicBuilder = builder.MergeFrom(input);
79 return dynamicBuilder.BuildParsed();
Jon Skeet68036862008-10-22 13:30:34 +010080 }
81
82 /// <summary>
83 /// Parse a message of the given type from the given stream and extension registry.
84 /// </summary>
85 /// <param name="type"></param>
86 /// <param name="input"></param>
87 /// <param name="extensionRegistry"></param>
88 /// <returns></returns>
89 public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry) {
90 Builder builder = CreateBuilder(type);
91 Builder dynamicBuilder = builder.MergeFrom(input, extensionRegistry);
92 return dynamicBuilder.BuildParsed();
93 }
94
95 /// <summary>
96 /// Parses a message of the given type from the given stream.
97 /// </summary>
98 public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input) {
99 Builder builder = CreateBuilder(type);
100 Builder dynamicBuilder = builder.MergeFrom(input);
101 return dynamicBuilder.BuildParsed();
102 }
103
104 /// <summary>
105 /// Parse a message of the given type from the given stream and extension registry.
106 /// </summary>
107 /// <param name="type"></param>
108 /// <param name="input"></param>
109 /// <param name="extensionRegistry"></param>
110 /// <returns></returns>
111 public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input, ExtensionRegistry extensionRegistry) {
112 Builder builder = CreateBuilder(type);
113 Builder dynamicBuilder = builder.MergeFrom(input, extensionRegistry);
114 return dynamicBuilder.BuildParsed();
115 }
116
117 /// <summary>
118 /// Parse <paramref name="data"/> as a message of the given type and return it.
119 /// </summary>
120 public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data) {
121 Builder builder = CreateBuilder(type);
122 Builder dynamicBuilder = builder.MergeFrom(data);
123 return dynamicBuilder.BuildParsed();
124 }
125
126 /// <summary>
127 /// Parse <paramref name="data"/> as a message of the given type and return it.
128 /// </summary>
129 public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data, ExtensionRegistry extensionRegistry) {
130 Builder builder = CreateBuilder(type);
131 Builder dynamicBuilder = builder.MergeFrom(data, extensionRegistry);
132 return dynamicBuilder.BuildParsed();
133
134 }
135
136 /// <summary>
137 /// Parse <paramref name="data"/> as a message of the given type and return it.
138 /// </summary>
139 public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data) {
140 Builder builder = CreateBuilder(type);
141 Builder dynamicBuilder = builder.MergeFrom(data);
142 return dynamicBuilder.BuildParsed();
143 }
144
145 /// <summary>
146 /// Parse <paramref name="data"/> as a message of the given type and return it.
147 /// </summary>
148 public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data, ExtensionRegistry extensionRegistry) {
149 Builder builder = CreateBuilder(type);
150 Builder dynamicBuilder = builder.MergeFrom(data, extensionRegistry);
151 return dynamicBuilder.BuildParsed();
152 }
153
154 /// <summary>
155 /// Constructs a builder for the given type.
156 /// </summary>
157 public static Builder CreateBuilder(MessageDescriptor type) {
158 return new Builder(type);
159 }
160
161 /// <summary>
162 /// Constructs a builder for a message of the same type as <paramref name="prototype"/>,
163 /// and initializes it with the same contents.
164 /// </summary>
165 /// <param name="prototype"></param>
166 /// <returns></returns>
167 public static Builder CreateBuilder(IMessage prototype) {
168 return new Builder(prototype.DescriptorForType).MergeFrom(prototype);
169 }
170
171 // -----------------------------------------------------------------
172 // Implementation of IMessage interface.
173
174 public override MessageDescriptor DescriptorForType {
175 get { return type; }
176 }
177
178 public override DynamicMessage DefaultInstanceForType {
179 get { return GetDefaultInstance(type); }
180 }
181
182 public override IDictionary<FieldDescriptor, object> AllFields {
183 get { return fields.AllFields; }
184 }
185
186 public override bool HasField(FieldDescriptor field) {
187 VerifyContainingType(field);
188 return fields.HasField(field);
189 }
190
191 public override object this[FieldDescriptor field] {
192 get {
193 VerifyContainingType(field);
194 object result = fields[field];
195 if (result == null) {
196 result = GetDefaultInstance(field.MessageType);
197 }
198 return result;
199 }
200 }
201
202 public override int GetRepeatedFieldCount(FieldDescriptor field) {
203 VerifyContainingType(field);
204 return fields.GetRepeatedFieldCount(field);
205 }
206
207 public override object this[FieldDescriptor field, int index] {
208 get {
209 VerifyContainingType(field);
210 return fields[field, index];
211 }
212 }
213
214 public override UnknownFieldSet UnknownFields {
215 get { return unknownFields; }
216 }
217
218 public bool Initialized {
219 get { return fields.IsInitializedWithRespectTo(type); }
220 }
221
222 public override void WriteTo(CodedOutputStream output) {
223 fields.WriteTo(output);
224 if (type.Options.MessageSetWireFormat) {
225 unknownFields.WriteAsMessageSetTo(output);
226 } else {
227 unknownFields.WriteTo(output);
228 }
229 }
230
231 public override int SerializedSize {
232 get {
233 int size = memoizedSize;
234 if (size != -1) return size;
235
236 size = fields.SerializedSize;
237 if (type.Options.MessageSetWireFormat) {
238 size += unknownFields.SerializedSizeAsMessageSet;
239 } else {
240 size += unknownFields.SerializedSize;
241 }
242
243 memoizedSize = size;
244 return size;
245 }
246 }
247
248 public override Builder CreateBuilderForType() {
249 return new Builder(type);
250 }
251
Jon Skeete81a9d72009-02-24 16:50:56 +0000252 public override Builder ToBuilder() {
253 return CreateBuilderForType().MergeFrom(this);
254 }
255
Jon Skeet68036862008-10-22 13:30:34 +0100256 /// <summary>
257 /// Verifies that the field is a field of this message.
258 /// </summary>
259 private void VerifyContainingType(FieldDescriptor field) {
260 if (field.ContainingType != type) {
261 throw new ArgumentException("FieldDescriptor does not match message type.");
262 }
263 }
264
265 /// <summary>
266 /// Builder for dynamic messages. Instances are created with DynamicMessage.CreateBuilder.
267 /// </summary>
268 public sealed class Builder : AbstractBuilder<DynamicMessage, Builder> {
269 private readonly MessageDescriptor type;
270 private FieldSet fields;
271 private UnknownFieldSet unknownFields;
272
273 internal Builder(MessageDescriptor type) {
274 this.type = type;
275 this.fields = FieldSet.CreateInstance();
276 this.unknownFields = UnknownFieldSet.DefaultInstance;
277 }
278
279 protected override Builder ThisBuilder {
280 get { return this; }
281 }
282
283 public override Builder Clear() {
284 fields.Clear();
285 return this;
286 }
287
288 public override Builder MergeFrom(IMessage other) {
289 if (other.DescriptorForType != type) {
290 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
291 }
292 fields.MergeFrom(other);
Jon Skeet49fcd4f2009-01-27 14:43:10 +0000293 MergeUnknownFields(other.UnknownFields);
Jon Skeet68036862008-10-22 13:30:34 +0100294 return this;
295 }
296
297 public override Builder MergeFrom(DynamicMessage other) {
Jon Skeet49fcd4f2009-01-27 14:43:10 +0000298 return MergeFrom((IMessage)other);
Jon Skeet68036862008-10-22 13:30:34 +0100299 }
300
301 public override DynamicMessage Build() {
Jon Skeetc298c892009-05-30 10:07:09 +0100302 if (fields != null && !IsInitialized) {
Jon Skeet68036862008-10-22 13:30:34 +0100303 throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields));
304 }
305 return BuildPartial();
306 }
307
308 /// <summary>
309 /// Helper for DynamicMessage.ParseFrom() methods to call. Throws
310 /// InvalidProtocolBufferException
311 /// </summary>
312 /// <returns></returns>
313 internal DynamicMessage BuildParsed() {
314 if (!IsInitialized) {
315 throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException();
316 }
317 return BuildPartial();
318 }
319
320 public override DynamicMessage BuildPartial() {
Jon Skeetc298c892009-05-30 10:07:09 +0100321 if (fields == null) {
322 throw new InvalidOperationException("Build() has already been called on this Builder.");
323 }
Jon Skeet68036862008-10-22 13:30:34 +0100324 fields.MakeImmutable();
325 DynamicMessage result = new DynamicMessage(type, fields, unknownFields);
326 fields = null;
327 unknownFields = null;
328 return result;
329 }
330
331 public override Builder Clone() {
332 Builder result = new Builder(type);
333 result.fields.MergeFrom(fields);
334 return result;
335 }
336
337 public override bool IsInitialized {
Jon Skeet57599ef2010-11-03 11:21:52 +0000338 get { return fields.IsInitializedWithRespectTo(type); }
Jon Skeet68036862008-10-22 13:30:34 +0100339 }
340
341 public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
342 UnknownFieldSet.Builder unknownFieldsBuilder = UnknownFieldSet.CreateBuilder(unknownFields);
343 unknownFieldsBuilder.MergeFrom(input, extensionRegistry, this);
344 unknownFields = unknownFieldsBuilder.Build();
345 return this;
346 }
347
348 public override MessageDescriptor DescriptorForType {
349 get { return type; }
350 }
351
352 public override DynamicMessage DefaultInstanceForType {
353 get { return GetDefaultInstance(type); }
354 }
355
356 public override IDictionary<FieldDescriptor, object> AllFields {
357 get { return fields.AllFields; }
358 }
359
360 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
361 VerifyContainingType(field);
362 if (field.MappedType != MappedType.Message) {
363 throw new ArgumentException("CreateBuilderForField is only valid for fields with message type.");
364 }
365 return new Builder(field.MessageType);
366 }
367
368 public override bool HasField(FieldDescriptor field) {
369 VerifyContainingType(field);
370 return fields.HasField(field);
371 }
372
373 public override object this[FieldDescriptor field, int index] {
374 get {
375 VerifyContainingType(field);
376 return fields[field, index];
377 }
378 set {
379 VerifyContainingType(field);
380 fields[field, index] = value;
381 }
382 }
383
384 public override object this[FieldDescriptor field] {
385 get {
386 VerifyContainingType(field);
387 object result = fields[field];
388 if (result == null) {
389 result = GetDefaultInstance(field.MessageType);
390 }
391 return result;
392 }
393 set {
394 VerifyContainingType(field);
395 fields[field] = value;
396 }
397 }
398
399 public override Builder ClearField(FieldDescriptor field) {
400 VerifyContainingType(field);
401 fields.ClearField(field);
402 return this;
403 }
404
405 public override int GetRepeatedFieldCount(FieldDescriptor field) {
406 VerifyContainingType(field);
407 return fields.GetRepeatedFieldCount(field);
408 }
409
410 public override Builder AddRepeatedField(FieldDescriptor field, object value) {
411 VerifyContainingType(field);
412 fields.AddRepeatedField(field, value);
413 return this;
414 }
415
416 public override UnknownFieldSet UnknownFields {
417 get {
418 return unknownFields;
419 }
420 set {
421 unknownFields = value;
422 }
423 }
424
425 /// <summary>
426 /// Verifies that the field is a field of this message.
427 /// </summary>
428 /// <param name="field"></param>
429 private void VerifyContainingType(FieldDescriptor field) {
430 if (field.ContainingType != type) {
431 throw new ArgumentException("FieldDescriptor does not match message type.");
432 }
433 }
434 }
435 }
436}