blob: 4b3a406062fbecdbd9c989642d3f2a6978a59c64 [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() {
299 if (!IsInitialized) {
300 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() {
318 fields.MakeImmutable();
319 DynamicMessage result = new DynamicMessage(type, fields, unknownFields);
320 fields = null;
321 unknownFields = null;
322 return result;
323 }
324
325 public override Builder Clone() {
326 Builder result = new Builder(type);
327 result.fields.MergeFrom(fields);
328 return result;
329 }
330
331 public override bool IsInitialized {
332 get { return fields.IsInitializedWithRespectTo(type); }
333 }
334
335 public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
336 UnknownFieldSet.Builder unknownFieldsBuilder = UnknownFieldSet.CreateBuilder(unknownFields);
337 unknownFieldsBuilder.MergeFrom(input, extensionRegistry, this);
338 unknownFields = unknownFieldsBuilder.Build();
339 return this;
340 }
341
342 public override MessageDescriptor DescriptorForType {
343 get { return type; }
344 }
345
346 public override DynamicMessage DefaultInstanceForType {
347 get { return GetDefaultInstance(type); }
348 }
349
350 public override IDictionary<FieldDescriptor, object> AllFields {
351 get { return fields.AllFields; }
352 }
353
354 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
355 VerifyContainingType(field);
356 if (field.MappedType != MappedType.Message) {
357 throw new ArgumentException("CreateBuilderForField is only valid for fields with message type.");
358 }
359 return new Builder(field.MessageType);
360 }
361
362 public override bool HasField(FieldDescriptor field) {
363 VerifyContainingType(field);
364 return fields.HasField(field);
365 }
366
367 public override object this[FieldDescriptor field, int index] {
368 get {
369 VerifyContainingType(field);
370 return fields[field, index];
371 }
372 set {
373 VerifyContainingType(field);
374 fields[field, index] = value;
375 }
376 }
377
378 public override object this[FieldDescriptor field] {
379 get {
380 VerifyContainingType(field);
381 object result = fields[field];
382 if (result == null) {
383 result = GetDefaultInstance(field.MessageType);
384 }
385 return result;
386 }
387 set {
388 VerifyContainingType(field);
389 fields[field] = value;
390 }
391 }
392
393 public override Builder ClearField(FieldDescriptor field) {
394 VerifyContainingType(field);
395 fields.ClearField(field);
396 return this;
397 }
398
399 public override int GetRepeatedFieldCount(FieldDescriptor field) {
400 VerifyContainingType(field);
401 return fields.GetRepeatedFieldCount(field);
402 }
403
404 public override Builder AddRepeatedField(FieldDescriptor field, object value) {
405 VerifyContainingType(field);
406 fields.AddRepeatedField(field, value);
407 return this;
408 }
409
410 public override UnknownFieldSet UnknownFields {
411 get {
412 return unknownFields;
413 }
414 set {
415 unknownFields = value;
416 }
417 }
418
419 /// <summary>
420 /// Verifies that the field is a field of this message.
421 /// </summary>
422 /// <param name="field"></param>
423 private void VerifyContainingType(FieldDescriptor field) {
424 if (field.ContainingType != type) {
425 throw new ArgumentException("FieldDescriptor does not match message type.");
426 }
427 }
428 }
429 }
430}