blob: c05a274b0faedf003a5c0ecfce45a158b3339d4e [file] [log] [blame]
Jon Skeet68036862008-10-22 13:30:34 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.
3// http://code.google.com/p/protobuf/
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16using System;
17using System.Collections.Generic;
18using System.IO;
19using Google.ProtocolBuffers.Descriptors;
20
21namespace Google.ProtocolBuffers {
22
23 /// <summary>
24 /// An implementation of IMessage that can represent arbitrary types, given a MessageaDescriptor.
25 /// </summary>
26 public sealed class DynamicMessage : AbstractMessage<DynamicMessage, DynamicMessage.Builder> {
27
28 private readonly MessageDescriptor type;
29 private readonly FieldSet fields;
30 private readonly UnknownFieldSet unknownFields;
31 private int memoizedSize = -1;
32
33 /// <summary>
34 /// Creates a DynamicMessage with the given FieldSet.
35 /// </summary>
36 /// <param name="type"></param>
37 /// <param name="fields"></param>
38 /// <param name="unknownFields"></param>
39 private DynamicMessage(MessageDescriptor type, FieldSet fields, UnknownFieldSet unknownFields) {
40 this.type = type;
41 this.fields = fields;
42 this.unknownFields = unknownFields;
43 }
44
45 /// <summary>
46 /// Returns a DynamicMessage representing the default instance of the given type.
47 /// </summary>
48 /// <param name="type"></param>
49 /// <returns></returns>
50 public static DynamicMessage GetDefaultInstance(MessageDescriptor type) {
51 return new DynamicMessage(type, FieldSet.DefaultInstance, UnknownFieldSet.DefaultInstance);
52 }
53
54 /// <summary>
55 /// Parses a message of the given type from the given stream.
56 /// </summary>
57 public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input) {
58 Builder builder = CreateBuilder(type);
59 Builder dynamicBuilder = builder.MergeFrom(input);
60 return dynamicBuilder.BuildParsed();
61
62 }
63
64 /// <summary>
65 /// Parse a message of the given type from the given stream and extension registry.
66 /// </summary>
67 /// <param name="type"></param>
68 /// <param name="input"></param>
69 /// <param name="extensionRegistry"></param>
70 /// <returns></returns>
71 public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry) {
72 Builder builder = CreateBuilder(type);
73 Builder dynamicBuilder = builder.MergeFrom(input, extensionRegistry);
74 return dynamicBuilder.BuildParsed();
75 }
76
77 /// <summary>
78 /// Parses a message of the given type from the given stream.
79 /// </summary>
80 public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input) {
81 Builder builder = CreateBuilder(type);
82 Builder dynamicBuilder = builder.MergeFrom(input);
83 return dynamicBuilder.BuildParsed();
84 }
85
86 /// <summary>
87 /// Parse a message of the given type from the given stream and extension registry.
88 /// </summary>
89 /// <param name="type"></param>
90 /// <param name="input"></param>
91 /// <param name="extensionRegistry"></param>
92 /// <returns></returns>
93 public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input, ExtensionRegistry extensionRegistry) {
94 Builder builder = CreateBuilder(type);
95 Builder dynamicBuilder = builder.MergeFrom(input, extensionRegistry);
96 return dynamicBuilder.BuildParsed();
97 }
98
99 /// <summary>
100 /// Parse <paramref name="data"/> as a message of the given type and return it.
101 /// </summary>
102 public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data) {
103 Builder builder = CreateBuilder(type);
104 Builder dynamicBuilder = builder.MergeFrom(data);
105 return dynamicBuilder.BuildParsed();
106 }
107
108 /// <summary>
109 /// Parse <paramref name="data"/> as a message of the given type and return it.
110 /// </summary>
111 public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data, ExtensionRegistry extensionRegistry) {
112 Builder builder = CreateBuilder(type);
113 Builder dynamicBuilder = builder.MergeFrom(data, extensionRegistry);
114 return dynamicBuilder.BuildParsed();
115
116 }
117
118 /// <summary>
119 /// Parse <paramref name="data"/> as a message of the given type and return it.
120 /// </summary>
121 public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data) {
122 Builder builder = CreateBuilder(type);
123 Builder dynamicBuilder = builder.MergeFrom(data);
124 return dynamicBuilder.BuildParsed();
125 }
126
127 /// <summary>
128 /// Parse <paramref name="data"/> as a message of the given type and return it.
129 /// </summary>
130 public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data, ExtensionRegistry extensionRegistry) {
131 Builder builder = CreateBuilder(type);
132 Builder dynamicBuilder = builder.MergeFrom(data, extensionRegistry);
133 return dynamicBuilder.BuildParsed();
134 }
135
136 /// <summary>
137 /// Constructs a builder for the given type.
138 /// </summary>
139 public static Builder CreateBuilder(MessageDescriptor type) {
140 return new Builder(type);
141 }
142
143 /// <summary>
144 /// Constructs a builder for a message of the same type as <paramref name="prototype"/>,
145 /// and initializes it with the same contents.
146 /// </summary>
147 /// <param name="prototype"></param>
148 /// <returns></returns>
149 public static Builder CreateBuilder(IMessage prototype) {
150 return new Builder(prototype.DescriptorForType).MergeFrom(prototype);
151 }
152
153 // -----------------------------------------------------------------
154 // Implementation of IMessage interface.
155
156 public override MessageDescriptor DescriptorForType {
157 get { return type; }
158 }
159
160 public override DynamicMessage DefaultInstanceForType {
161 get { return GetDefaultInstance(type); }
162 }
163
164 public override IDictionary<FieldDescriptor, object> AllFields {
165 get { return fields.AllFields; }
166 }
167
168 public override bool HasField(FieldDescriptor field) {
169 VerifyContainingType(field);
170 return fields.HasField(field);
171 }
172
173 public override object this[FieldDescriptor field] {
174 get {
175 VerifyContainingType(field);
176 object result = fields[field];
177 if (result == null) {
178 result = GetDefaultInstance(field.MessageType);
179 }
180 return result;
181 }
182 }
183
184 public override int GetRepeatedFieldCount(FieldDescriptor field) {
185 VerifyContainingType(field);
186 return fields.GetRepeatedFieldCount(field);
187 }
188
189 public override object this[FieldDescriptor field, int index] {
190 get {
191 VerifyContainingType(field);
192 return fields[field, index];
193 }
194 }
195
196 public override UnknownFieldSet UnknownFields {
197 get { return unknownFields; }
198 }
199
200 public bool Initialized {
201 get { return fields.IsInitializedWithRespectTo(type); }
202 }
203
204 public override void WriteTo(CodedOutputStream output) {
205 fields.WriteTo(output);
206 if (type.Options.MessageSetWireFormat) {
207 unknownFields.WriteAsMessageSetTo(output);
208 } else {
209 unknownFields.WriteTo(output);
210 }
211 }
212
213 public override int SerializedSize {
214 get {
215 int size = memoizedSize;
216 if (size != -1) return size;
217
218 size = fields.SerializedSize;
219 if (type.Options.MessageSetWireFormat) {
220 size += unknownFields.SerializedSizeAsMessageSet;
221 } else {
222 size += unknownFields.SerializedSize;
223 }
224
225 memoizedSize = size;
226 return size;
227 }
228 }
229
230 public override Builder CreateBuilderForType() {
231 return new Builder(type);
232 }
233
234 /// <summary>
235 /// Verifies that the field is a field of this message.
236 /// </summary>
237 private void VerifyContainingType(FieldDescriptor field) {
238 if (field.ContainingType != type) {
239 throw new ArgumentException("FieldDescriptor does not match message type.");
240 }
241 }
242
243 /// <summary>
244 /// Builder for dynamic messages. Instances are created with DynamicMessage.CreateBuilder.
245 /// </summary>
246 public sealed class Builder : AbstractBuilder<DynamicMessage, Builder> {
247 private readonly MessageDescriptor type;
248 private FieldSet fields;
249 private UnknownFieldSet unknownFields;
250
251 internal Builder(MessageDescriptor type) {
252 this.type = type;
253 this.fields = FieldSet.CreateInstance();
254 this.unknownFields = UnknownFieldSet.DefaultInstance;
255 }
256
257 protected override Builder ThisBuilder {
258 get { return this; }
259 }
260
261 public override Builder Clear() {
262 fields.Clear();
263 return this;
264 }
265
266 public override Builder MergeFrom(IMessage other) {
267 if (other.DescriptorForType != type) {
268 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
269 }
270 fields.MergeFrom(other);
271 return this;
272 }
273
274 public override Builder MergeFrom(DynamicMessage other) {
275 if (other.DescriptorForType != type) {
276 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
277 }
278 fields.MergeFrom(other);
279 return this;
280 }
281
282 public override DynamicMessage Build() {
283 if (!IsInitialized) {
284 throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields));
285 }
286 return BuildPartial();
287 }
288
289 /// <summary>
290 /// Helper for DynamicMessage.ParseFrom() methods to call. Throws
291 /// InvalidProtocolBufferException
292 /// </summary>
293 /// <returns></returns>
294 internal DynamicMessage BuildParsed() {
295 if (!IsInitialized) {
296 throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException();
297 }
298 return BuildPartial();
299 }
300
301 public override DynamicMessage BuildPartial() {
302 fields.MakeImmutable();
303 DynamicMessage result = new DynamicMessage(type, fields, unknownFields);
304 fields = null;
305 unknownFields = null;
306 return result;
307 }
308
309 public override Builder Clone() {
310 Builder result = new Builder(type);
311 result.fields.MergeFrom(fields);
312 return result;
313 }
314
315 public override bool IsInitialized {
316 get { return fields.IsInitializedWithRespectTo(type); }
317 }
318
319 public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
320 UnknownFieldSet.Builder unknownFieldsBuilder = UnknownFieldSet.CreateBuilder(unknownFields);
321 unknownFieldsBuilder.MergeFrom(input, extensionRegistry, this);
322 unknownFields = unknownFieldsBuilder.Build();
323 return this;
324 }
325
326 public override MessageDescriptor DescriptorForType {
327 get { return type; }
328 }
329
330 public override DynamicMessage DefaultInstanceForType {
331 get { return GetDefaultInstance(type); }
332 }
333
334 public override IDictionary<FieldDescriptor, object> AllFields {
335 get { return fields.AllFields; }
336 }
337
338 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
339 VerifyContainingType(field);
340 if (field.MappedType != MappedType.Message) {
341 throw new ArgumentException("CreateBuilderForField is only valid for fields with message type.");
342 }
343 return new Builder(field.MessageType);
344 }
345
346 public override bool HasField(FieldDescriptor field) {
347 VerifyContainingType(field);
348 return fields.HasField(field);
349 }
350
351 public override object this[FieldDescriptor field, int index] {
352 get {
353 VerifyContainingType(field);
354 return fields[field, index];
355 }
356 set {
357 VerifyContainingType(field);
358 fields[field, index] = value;
359 }
360 }
361
362 public override object this[FieldDescriptor field] {
363 get {
364 VerifyContainingType(field);
365 object result = fields[field];
366 if (result == null) {
367 result = GetDefaultInstance(field.MessageType);
368 }
369 return result;
370 }
371 set {
372 VerifyContainingType(field);
373 fields[field] = value;
374 }
375 }
376
377 public override Builder ClearField(FieldDescriptor field) {
378 VerifyContainingType(field);
379 fields.ClearField(field);
380 return this;
381 }
382
383 public override int GetRepeatedFieldCount(FieldDescriptor field) {
384 VerifyContainingType(field);
385 return fields.GetRepeatedFieldCount(field);
386 }
387
388 public override Builder AddRepeatedField(FieldDescriptor field, object value) {
389 VerifyContainingType(field);
390 fields.AddRepeatedField(field, value);
391 return this;
392 }
393
394 public override UnknownFieldSet UnknownFields {
395 get {
396 return unknownFields;
397 }
398 set {
399 unknownFields = value;
400 }
401 }
402
403 /// <summary>
404 /// Verifies that the field is a field of this message.
405 /// </summary>
406 /// <param name="field"></param>
407 private void VerifyContainingType(FieldDescriptor field) {
408 if (field.ContainingType != type) {
409 throw new ArgumentException("FieldDescriptor does not match message type.");
410 }
411 }
412 }
413 }
414}