blob: 812be1c84871c846b839dd00d589ef32173b4822 [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);
287 return this;
288 }
289
290 public override Builder MergeFrom(DynamicMessage other) {
291 if (other.DescriptorForType != type) {
292 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
293 }
294 fields.MergeFrom(other);
295 return this;
296 }
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}