blob: 2ba9855a5f3a0c4a6d75fd52b6aa10c26de6f7d3 [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
Jon Skeet60c059b2008-10-23 21:17:56 +01002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01006// http://code.google.com/p/protobuf/
7//
Jon Skeet60c059b2008-10-23 21:17:56 +01008// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
Jon Skeet68036862008-10-22 13:30:34 +010011//
Jon Skeet60c059b2008-10-23 21:17:56 +010012// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010021//
Jon Skeet60c059b2008-10-23 21:17:56 +010022// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeet68036862008-10-22 13:30:34 +010035using System;
36using System.Collections;
37using System.Collections.Generic;
38using System.IO;
39using Google.ProtocolBuffers.Descriptors;
40
41namespace Google.ProtocolBuffers {
42 /// <summary>
43 /// Implementation of the non-generic IMessage interface as far as possible.
44 /// </summary>
45 public abstract class AbstractBuilder<TMessage, TBuilder> : IBuilder<TMessage, TBuilder>
46 where TMessage : AbstractMessage<TMessage, TBuilder>
47 where TBuilder : AbstractBuilder<TMessage, TBuilder> {
48
49 protected abstract TBuilder ThisBuilder { get; }
50
51 #region Unimplemented members of IBuilder
52 public abstract UnknownFieldSet UnknownFields { get; set; }
53 public abstract TBuilder MergeFrom(TMessage other);
54 public abstract bool IsInitialized { get; }
55 public abstract IDictionary<FieldDescriptor, object> AllFields { get; }
56 public abstract object this[FieldDescriptor field] { get; set; }
57 public abstract MessageDescriptor DescriptorForType { get; }
58 public abstract int GetRepeatedFieldCount(FieldDescriptor field);
59 public abstract object this[FieldDescriptor field, int index] { get; set; }
60 public abstract bool HasField(FieldDescriptor field);
61 public abstract TMessage Build();
62 public abstract TMessage BuildPartial();
63 public abstract TBuilder Clone();
64 public abstract TMessage DefaultInstanceForType { get; }
65 public abstract IBuilder CreateBuilderForField(FieldDescriptor field);
66 public abstract TBuilder ClearField(FieldDescriptor field);
67 public abstract TBuilder AddRepeatedField(FieldDescriptor field, object value);
68 #endregion
69
70 #region Implementation of methods which don't require type parameter information
71 public IMessage WeakBuild() {
72 return Build();
73 }
74
75 public IBuilder WeakAddRepeatedField(FieldDescriptor field, object value) {
76 return AddRepeatedField(field, value);
77 }
78
79 public IBuilder WeakClear() {
80 return Clear();
81 }
82
83 public IBuilder WeakMergeFrom(IMessage message) {
84 return MergeFrom(message);
85 }
86
87 public IBuilder WeakMergeFrom(CodedInputStream input) {
88 return MergeFrom(input);
89 }
90
csharptestd9c59e62010-11-04 19:36:28 -050091 public IBuilder WeakMergeFrom(CodedInputStream input, ExtensionRegistryLite registry) {
Jon Skeet68036862008-10-22 13:30:34 +010092 return MergeFrom(input, registry);
93 }
94
95 public IBuilder WeakMergeFrom(ByteString data) {
96 return MergeFrom(data);
97 }
98
csharptestd9c59e62010-11-04 19:36:28 -050099 public IBuilder WeakMergeFrom(ByteString data, ExtensionRegistryLite registry) {
Jon Skeet68036862008-10-22 13:30:34 +0100100 return MergeFrom(data, registry);
101 }
102
103 public IMessage WeakBuildPartial() {
104 return BuildPartial();
105 }
106
107 public IBuilder WeakClone() {
108 return Clone();
109 }
110
111 public IMessage WeakDefaultInstanceForType {
112 get { return DefaultInstanceForType; }
113 }
114
115 public IBuilder WeakClearField(FieldDescriptor field) {
116 return ClearField(field);
117 }
118 #endregion
119
120 public TBuilder SetUnknownFields(UnknownFieldSet fields) {
121 UnknownFields = fields;
122 return ThisBuilder;
123 }
124
125 public virtual TBuilder Clear() {
126 foreach(FieldDescriptor field in AllFields.Keys) {
127 ClearField(field);
128 }
129 return ThisBuilder;
130 }
131
132 public virtual TBuilder MergeFrom(IMessage other) {
133 if (other.DescriptorForType != DescriptorForType) {
134 throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type.");
135 }
136
137 // Note: We don't attempt to verify that other's fields have valid
138 // types. Doing so would be a losing battle. We'd have to verify
139 // all sub-messages as well, and we'd have to make copies of all of
140 // them to insure that they don't change after verification (since
141 // the Message interface itself cannot enforce immutability of
142 // implementations).
143 // TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
144 // which allows people to make secure deep copies of messages.
145 foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields) {
146 FieldDescriptor field = entry.Key;
147 if (field.IsRepeated) {
148 // Concatenate repeated fields
149 foreach (object element in (IEnumerable) entry.Value) {
150 AddRepeatedField(field, element);
151 }
152 } else if (field.MappedType == MappedType.Message) {
153 // Merge singular messages
154 IMessage existingValue = (IMessage) this[field];
155 if (existingValue == existingValue.WeakDefaultInstanceForType) {
156 this[field] = entry.Value;
157 } else {
158 this[field] = existingValue.WeakCreateBuilderForType()
159 .WeakMergeFrom(existingValue)
160 .WeakMergeFrom((IMessage) entry.Value)
161 .WeakBuild();
162 }
163 } else {
164 // Overwrite simple values
165 this[field] = entry.Value;
166 }
167 }
168 return ThisBuilder;
169 }
170
171 public virtual TBuilder MergeFrom(CodedInputStream input) {
172 return MergeFrom(input, ExtensionRegistry.Empty);
173 }
174
175 public virtual TBuilder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
csharptestd9c59e62010-11-04 19:36:28 -0500176 return MergeFrom(input, (ExtensionRegistryLite)extensionRegistry);
177 }
178
179 public virtual TBuilder MergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) {
Jon Skeet68036862008-10-22 13:30:34 +0100180 UnknownFieldSet.Builder unknownFields = UnknownFieldSet.CreateBuilder(UnknownFields);
181 unknownFields.MergeFrom(input, extensionRegistry, this);
182 UnknownFields = unknownFields.Build();
183 return ThisBuilder;
184 }
185
186 public virtual TBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
187 UnknownFields = UnknownFieldSet.CreateBuilder(UnknownFields)
188 .MergeFrom(unknownFields)
189 .Build();
190 return ThisBuilder;
191 }
192
193 public virtual TBuilder MergeFrom(ByteString data) {
194 CodedInputStream input = data.CreateCodedInput();
195 MergeFrom(input);
196 input.CheckLastTagWas(0);
197 return ThisBuilder;
198 }
199
200 public virtual TBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
csharptestd9c59e62010-11-04 19:36:28 -0500201 return MergeFrom(data, (ExtensionRegistryLite)extensionRegistry);
202 }
203
204 public virtual TBuilder MergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry) {
Jon Skeet68036862008-10-22 13:30:34 +0100205 CodedInputStream input = data.CreateCodedInput();
206 MergeFrom(input, extensionRegistry);
207 input.CheckLastTagWas(0);
208 return ThisBuilder;
209 }
210
211 public virtual TBuilder MergeFrom(byte[] data) {
212 CodedInputStream input = CodedInputStream.CreateInstance(data);
213 MergeFrom(input);
214 input.CheckLastTagWas(0);
215 return ThisBuilder;
216 }
217
218 public virtual TBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
csharptestd9c59e62010-11-04 19:36:28 -0500219 return MergeFrom(data, (ExtensionRegistryLite)extensionRegistry);
220 }
221
222 public virtual TBuilder MergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry) {
Jon Skeet68036862008-10-22 13:30:34 +0100223 CodedInputStream input = CodedInputStream.CreateInstance(data);
224 MergeFrom(input, extensionRegistry);
225 input.CheckLastTagWas(0);
226 return ThisBuilder;
227 }
228
229 public virtual TBuilder MergeFrom(Stream input) {
230 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
231 MergeFrom(codedInput);
232 codedInput.CheckLastTagWas(0);
233 return ThisBuilder;
234 }
235
236 public virtual TBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry) {
csharptestd9c59e62010-11-04 19:36:28 -0500237 return MergeFrom(input, (ExtensionRegistryLite)extensionRegistry);
238 }
239
240 public virtual TBuilder MergeFrom(Stream input, ExtensionRegistryLite extensionRegistry) {
Jon Skeet68036862008-10-22 13:30:34 +0100241 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
242 MergeFrom(codedInput, extensionRegistry);
243 codedInput.CheckLastTagWas(0);
244 return ThisBuilder;
245 }
246
Jon Skeet2e6dc122009-05-29 06:34:52 +0100247 public TBuilder MergeDelimitedFrom(Stream input, ExtensionRegistry extensionRegistry) {
csharptestd9c59e62010-11-04 19:36:28 -0500248 return MergeDelimitedFrom(input, (ExtensionRegistryLite)extensionRegistry);
249 }
250
251 public TBuilder MergeDelimitedFrom(Stream input, ExtensionRegistryLite extensionRegistry) {
Jon Skeetc298c892009-05-30 10:07:09 +0100252 int size = (int) CodedInputStream.ReadRawVarint32(input);
Jon Skeet2e6dc122009-05-29 06:34:52 +0100253 Stream limitedStream = new LimitedInputStream(input, size);
254 return MergeFrom(limitedStream, extensionRegistry);
255 }
256
257 public TBuilder MergeDelimitedFrom(Stream input) {
258 return MergeDelimitedFrom(input, ExtensionRegistry.Empty);
259 }
260
Jon Skeet68036862008-10-22 13:30:34 +0100261 public virtual IBuilder SetField(FieldDescriptor field, object value) {
262 this[field] = value;
263 return ThisBuilder;
264 }
265
266 public virtual IBuilder SetRepeatedField(FieldDescriptor field, int index, object value) {
267 this[field, index] = value;
268 return ThisBuilder;
269 }
Jon Skeet2e6dc122009-05-29 06:34:52 +0100270
271 /// <summary>
272 /// Stream implementation which proxies another stream, only allowing a certain amount
273 /// of data to be read. Note that this is only used to read delimited streams, so it
274 /// doesn't attempt to implement everything.
275 /// </summary>
276 private class LimitedInputStream : Stream {
277
278 private readonly Stream proxied;
279 private int bytesLeft;
280
281 internal LimitedInputStream(Stream proxied, int size) {
282 this.proxied = proxied;
283 bytesLeft = size;
284 }
285
286 public override bool CanRead {
287 get { return true; }
288 }
289
290 public override bool CanSeek {
291 get { return false; }
292 }
293
294 public override bool CanWrite {
295 get { return false; }
296 }
297
298 public override void Flush() {
299 }
300
301 public override long Length {
csharptestd9c59e62010-11-04 19:36:28 -0500302 get { throw new NotSupportedException(); }
Jon Skeet2e6dc122009-05-29 06:34:52 +0100303 }
304
305 public override long Position {
306 get {
csharptestd9c59e62010-11-04 19:36:28 -0500307 throw new NotSupportedException();
Jon Skeet2e6dc122009-05-29 06:34:52 +0100308 }
309 set {
csharptestd9c59e62010-11-04 19:36:28 -0500310 throw new NotSupportedException();
Jon Skeet2e6dc122009-05-29 06:34:52 +0100311 }
312 }
313
314 public override int Read(byte[] buffer, int offset, int count) {
315 if (bytesLeft > 0) {
316 int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
317 bytesLeft -= bytesRead;
318 return bytesRead;
319 }
320 return 0;
321 }
322
323 public override long Seek(long offset, SeekOrigin origin) {
csharptestd9c59e62010-11-04 19:36:28 -0500324 throw new NotSupportedException();
Jon Skeet2e6dc122009-05-29 06:34:52 +0100325 }
326
327 public override void SetLength(long value) {
csharptestd9c59e62010-11-04 19:36:28 -0500328 throw new NotSupportedException();
Jon Skeet2e6dc122009-05-29 06:34:52 +0100329 }
330
331 public override void Write(byte[] buffer, int offset, int count) {
csharptestd9c59e62010-11-04 19:36:28 -0500332 throw new NotSupportedException();
Jon Skeet2e6dc122009-05-29 06:34:52 +0100333 }
334 }
csharptestd9c59e62010-11-04 19:36:28 -0500335
336 IBuilderLite IBuilderLite.WeakClear() {
337 return WeakClear();
338 }
339
340 public IBuilderLite WeakMergeFrom(IMessageLite message) {
341 return MergeFrom(message);
342 }
343
344 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data) {
345 return WeakMergeFrom(data);
346 }
347
348 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistryLite registry) {
349 throw new NotImplementedException();
350 }
351
352 IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input) {
353 return WeakMergeFrom(input);
354 }
355
356 IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input, ExtensionRegistryLite registry) {
357 throw new NotImplementedException();
358 }
359
360 IMessageLite IBuilderLite.WeakBuild() {
361 return WeakBuild();
362 }
363
364 IMessageLite IBuilderLite.WeakBuildPartial() {
365 return WeakBuildPartial();
366 }
367
368 IBuilderLite IBuilderLite.WeakClone() {
369 return WeakClone();
370 }
371
372 IMessageLite IBuilderLite.WeakDefaultInstanceForType {
373 get { return WeakDefaultInstanceForType; }
374 }
375
376 public TBuilder MergeFrom(IMessageLite other) {
377 throw new NotImplementedException();
378 }
Jon Skeet68036862008-10-22 13:30:34 +0100379 }
380}