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