blob: b740013b1d116a055afb19817f377c5dd01406b8 [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();
77
78 }
79
80 /// <summary>
81 /// Parse a message of the given type from the given stream and extension registry.
82 /// </summary>
83 /// <param name="type"></param>
84 /// <param name="input"></param>
85 /// <param name="extensionRegistry"></param>
86 /// <returns></returns>
87 public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry) {
88 Builder builder = CreateBuilder(type);
89 Builder dynamicBuilder = builder.MergeFrom(input, extensionRegistry);
90 return dynamicBuilder.BuildParsed();
91 }
92
93 /// <summary>
94 /// Parses a message of the given type from the given stream.
95 /// </summary>
96 public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input) {
97 Builder builder = CreateBuilder(type);
98 Builder dynamicBuilder = builder.MergeFrom(input);
99 return dynamicBuilder.BuildParsed();
100 }
101
102 /// <summary>
103 /// Parse a message of the given type from the given stream and extension registry.
104 /// </summary>
105 /// <param name="type"></param>
106 /// <param name="input"></param>
107 /// <param name="extensionRegistry"></param>
108 /// <returns></returns>
109 public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input, ExtensionRegistry extensionRegistry) {
110 Builder builder = CreateBuilder(type);
111 Builder dynamicBuilder = builder.MergeFrom(input, extensionRegistry);
112 return dynamicBuilder.BuildParsed();
113 }
114
115 /// <summary>
116 /// Parse <paramref name="data"/> as a message of the given type and return it.
117 /// </summary>
118 public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data) {
119 Builder builder = CreateBuilder(type);
120 Builder dynamicBuilder = builder.MergeFrom(data);
121 return dynamicBuilder.BuildParsed();
122 }
123
124 /// <summary>
125 /// Parse <paramref name="data"/> as a message of the given type and return it.
126 /// </summary>
127 public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data, ExtensionRegistry extensionRegistry) {
128 Builder builder = CreateBuilder(type);
129 Builder dynamicBuilder = builder.MergeFrom(data, extensionRegistry);
130 return dynamicBuilder.BuildParsed();
131
132 }
133
134 /// <summary>
135 /// Parse <paramref name="data"/> as a message of the given type and return it.
136 /// </summary>
137 public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data) {
138 Builder builder = CreateBuilder(type);
139 Builder dynamicBuilder = builder.MergeFrom(data);
140 return dynamicBuilder.BuildParsed();
141 }
142
143 /// <summary>
144 /// Parse <paramref name="data"/> as a message of the given type and return it.
145 /// </summary>
146 public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data, ExtensionRegistry extensionRegistry) {
147 Builder builder = CreateBuilder(type);
148 Builder dynamicBuilder = builder.MergeFrom(data, extensionRegistry);
149 return dynamicBuilder.BuildParsed();
150 }
151
152 /// <summary>
153 /// Constructs a builder for the given type.
154 /// </summary>
155 public static Builder CreateBuilder(MessageDescriptor type) {
156 return new Builder(type);
157 }
158
159 /// <summary>
160 /// Constructs a builder for a message of the same type as <paramref name="prototype"/>,
161 /// and initializes it with the same contents.
162 /// </summary>
163 /// <param name="prototype"></param>
164 /// <returns></returns>
165 public static Builder CreateBuilder(IMessage prototype) {
166 return new Builder(prototype.DescriptorForType).MergeFrom(prototype);
167 }
168
169 // -----------------------------------------------------------------
170 // Implementation of IMessage interface.
171
172 public override MessageDescriptor DescriptorForType {
173 get { return type; }
174 }
175
176 public override DynamicMessage DefaultInstanceForType {
177 get { return GetDefaultInstance(type); }
178 }
179
180 public override IDictionary<FieldDescriptor, object> AllFields {
181 get { return fields.AllFields; }
182 }
183
184 public override bool HasField(FieldDescriptor field) {
185 VerifyContainingType(field);
186 return fields.HasField(field);
187 }
188
189 public override object this[FieldDescriptor field] {
190 get {
191 VerifyContainingType(field);
192 object result = fields[field];
193 if (result == null) {
194 result = GetDefaultInstance(field.MessageType);
195 }
196 return result;
197 }
198 }
199
200 public override int GetRepeatedFieldCount(FieldDescriptor field) {
201 VerifyContainingType(field);
202 return fields.GetRepeatedFieldCount(field);
203 }
204
205 public override object this[FieldDescriptor field, int index] {
206 get {
207 VerifyContainingType(field);
208 return fields[field, index];
209 }
210 }
211
212 public override UnknownFieldSet UnknownFields {
213 get { return unknownFields; }
214 }
215
216 public bool Initialized {
217 get { return fields.IsInitializedWithRespectTo(type); }
218 }
219
220 public override void WriteTo(CodedOutputStream output) {
221 fields.WriteTo(output);
222 if (type.Options.MessageSetWireFormat) {
223 unknownFields.WriteAsMessageSetTo(output);
224 } else {
225 unknownFields.WriteTo(output);
226 }
227 }
228
229 public override int SerializedSize {
230 get {
231 int size = memoizedSize;
232 if (size != -1) return size;
233
234 size = fields.SerializedSize;
235 if (type.Options.MessageSetWireFormat) {
236 size += unknownFields.SerializedSizeAsMessageSet;
237 } else {
238 size += unknownFields.SerializedSize;
239 }
240
241 memoizedSize = size;
242 return size;
243 }
244 }
245
246 public override Builder CreateBuilderForType() {
247 return new Builder(type);
248 }
249
250 /// <summary>
251 /// Verifies that the field is a field of this message.
252 /// </summary>
253 private void VerifyContainingType(FieldDescriptor field) {
254 if (field.ContainingType != type) {
255 throw new ArgumentException("FieldDescriptor does not match message type.");
256 }
257 }
258
259 /// <summary>
260 /// Builder for dynamic messages. Instances are created with DynamicMessage.CreateBuilder.
261 /// </summary>
262 public sealed class Builder : AbstractBuilder<DynamicMessage, Builder> {
263 private readonly MessageDescriptor type;
264 private FieldSet fields;
265 private UnknownFieldSet unknownFields;
266
267 internal Builder(MessageDescriptor type) {
268 this.type = type;
269 this.fields = FieldSet.CreateInstance();
270 this.unknownFields = UnknownFieldSet.DefaultInstance;
271 }
272
273 protected override Builder ThisBuilder {
274 get { return this; }
275 }
276
277 public override Builder Clear() {
278 fields.Clear();
279 return this;
280 }
281
282 public override Builder MergeFrom(IMessage other) {
283 if (other.DescriptorForType != type) {
284 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
285 }
286 fields.MergeFrom(other);
Jon Skeet49fcd4f2009-01-27 14:43:10 +0000287 MergeUnknownFields(other.UnknownFields);
Jon Skeet68036862008-10-22 13:30:34 +0100288 return this;
289 }
290
291 public override Builder MergeFrom(DynamicMessage other) {
Jon Skeet49fcd4f2009-01-27 14:43:10 +0000292 return MergeFrom((IMessage)other);
Jon Skeet68036862008-10-22 13:30:34 +0100293 }
294
295 public override DynamicMessage Build() {
296 if (!IsInitialized) {
297 throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields));
298 }
299 return BuildPartial();
300 }
301
302 /// <summary>
303 /// Helper for DynamicMessage.ParseFrom() methods to call. Throws
304 /// InvalidProtocolBufferException
305 /// </summary>
306 /// <returns></returns>
307 internal DynamicMessage BuildParsed() {
308 if (!IsInitialized) {
309 throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException();
310 }
311 return BuildPartial();
312 }
313
314 public override DynamicMessage BuildPartial() {
315 fields.MakeImmutable();
316 DynamicMessage result = new DynamicMessage(type, fields, unknownFields);
317 fields = null;
318 unknownFields = null;
319 return result;
320 }
321
322 public override Builder Clone() {
323 Builder result = new Builder(type);
324 result.fields.MergeFrom(fields);
325 return result;
326 }
327
328 public override bool IsInitialized {
329 get { return fields.IsInitializedWithRespectTo(type); }
330 }
331
332 public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
333 UnknownFieldSet.Builder unknownFieldsBuilder = UnknownFieldSet.CreateBuilder(unknownFields);
334 unknownFieldsBuilder.MergeFrom(input, extensionRegistry, this);
335 unknownFields = unknownFieldsBuilder.Build();
336 return this;
337 }
338
339 public override MessageDescriptor DescriptorForType {
340 get { return type; }
341 }
342
343 public override DynamicMessage DefaultInstanceForType {
344 get { return GetDefaultInstance(type); }
345 }
346
347 public override IDictionary<FieldDescriptor, object> AllFields {
348 get { return fields.AllFields; }
349 }
350
351 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
352 VerifyContainingType(field);
353 if (field.MappedType != MappedType.Message) {
354 throw new ArgumentException("CreateBuilderForField is only valid for fields with message type.");
355 }
356 return new Builder(field.MessageType);
357 }
358
359 public override bool HasField(FieldDescriptor field) {
360 VerifyContainingType(field);
361 return fields.HasField(field);
362 }
363
364 public override object this[FieldDescriptor field, int index] {
365 get {
366 VerifyContainingType(field);
367 return fields[field, index];
368 }
369 set {
370 VerifyContainingType(field);
371 fields[field, index] = value;
372 }
373 }
374
375 public override object this[FieldDescriptor field] {
376 get {
377 VerifyContainingType(field);
378 object result = fields[field];
379 if (result == null) {
380 result = GetDefaultInstance(field.MessageType);
381 }
382 return result;
383 }
384 set {
385 VerifyContainingType(field);
386 fields[field] = value;
387 }
388 }
389
390 public override Builder ClearField(FieldDescriptor field) {
391 VerifyContainingType(field);
392 fields.ClearField(field);
393 return this;
394 }
395
396 public override int GetRepeatedFieldCount(FieldDescriptor field) {
397 VerifyContainingType(field);
398 return fields.GetRepeatedFieldCount(field);
399 }
400
401 public override Builder AddRepeatedField(FieldDescriptor field, object value) {
402 VerifyContainingType(field);
403 fields.AddRepeatedField(field, value);
404 return this;
405 }
406
407 public override UnknownFieldSet UnknownFields {
408 get {
409 return unknownFields;
410 }
411 set {
412 unknownFields = value;
413 }
414 }
415
416 /// <summary>
417 /// Verifies that the field is a field of this message.
418 /// </summary>
419 /// <param name="field"></param>
420 private void VerifyContainingType(FieldDescriptor field) {
421 if (field.ContainingType != type) {
422 throw new ArgumentException("FieldDescriptor does not match message type.");
423 }
424 }
425 }
426 }
427}