blob: a60ff0aaf20fc33f8e76767a9d0517455785247a [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
91 public IBuilder WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
92 return MergeFrom(input, registry);
93 }
94
95 public IBuilder WeakMergeFrom(ByteString data) {
96 return MergeFrom(data);
97 }
98
99 public IBuilder WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
100 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) {
176 UnknownFieldSet.Builder unknownFields = UnknownFieldSet.CreateBuilder(UnknownFields);
177 unknownFields.MergeFrom(input, extensionRegistry, this);
178 UnknownFields = unknownFields.Build();
179 return ThisBuilder;
180 }
181
182 public virtual TBuilder MergeUnknownFields(UnknownFieldSet unknownFields) {
183 UnknownFields = UnknownFieldSet.CreateBuilder(UnknownFields)
184 .MergeFrom(unknownFields)
185 .Build();
186 return ThisBuilder;
187 }
188
189 public virtual TBuilder MergeFrom(ByteString data) {
190 CodedInputStream input = data.CreateCodedInput();
191 MergeFrom(input);
192 input.CheckLastTagWas(0);
193 return ThisBuilder;
194 }
195
196 public virtual TBuilder MergeFrom(ByteString data, ExtensionRegistry extensionRegistry) {
197 CodedInputStream input = data.CreateCodedInput();
198 MergeFrom(input, extensionRegistry);
199 input.CheckLastTagWas(0);
200 return ThisBuilder;
201 }
202
203 public virtual TBuilder MergeFrom(byte[] data) {
204 CodedInputStream input = CodedInputStream.CreateInstance(data);
205 MergeFrom(input);
206 input.CheckLastTagWas(0);
207 return ThisBuilder;
208 }
209
210 public virtual TBuilder MergeFrom(byte[] data, ExtensionRegistry extensionRegistry) {
211 CodedInputStream input = CodedInputStream.CreateInstance(data);
212 MergeFrom(input, extensionRegistry);
213 input.CheckLastTagWas(0);
214 return ThisBuilder;
215 }
216
217 public virtual TBuilder MergeFrom(Stream input) {
218 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
219 MergeFrom(codedInput);
220 codedInput.CheckLastTagWas(0);
221 return ThisBuilder;
222 }
223
224 public virtual TBuilder MergeFrom(Stream input, ExtensionRegistry extensionRegistry) {
225 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
226 MergeFrom(codedInput, extensionRegistry);
227 codedInput.CheckLastTagWas(0);
228 return ThisBuilder;
229 }
230
Jon Skeet2e6dc122009-05-29 06:34:52 +0100231 public TBuilder MergeDelimitedFrom(Stream input, ExtensionRegistry extensionRegistry) {
Jon Skeetc298c892009-05-30 10:07:09 +0100232 int size = (int) CodedInputStream.ReadRawVarint32(input);
Jon Skeet2e6dc122009-05-29 06:34:52 +0100233 Stream limitedStream = new LimitedInputStream(input, size);
234 return MergeFrom(limitedStream, extensionRegistry);
235 }
236
237 public TBuilder MergeDelimitedFrom(Stream input) {
238 return MergeDelimitedFrom(input, ExtensionRegistry.Empty);
239 }
240
Jon Skeet68036862008-10-22 13:30:34 +0100241 public virtual IBuilder SetField(FieldDescriptor field, object value) {
242 this[field] = value;
243 return ThisBuilder;
244 }
245
246 public virtual IBuilder SetRepeatedField(FieldDescriptor field, int index, object value) {
247 this[field, index] = value;
248 return ThisBuilder;
249 }
Jon Skeet2e6dc122009-05-29 06:34:52 +0100250
251 /// <summary>
252 /// Stream implementation which proxies another stream, only allowing a certain amount
253 /// of data to be read. Note that this is only used to read delimited streams, so it
254 /// doesn't attempt to implement everything.
255 /// </summary>
256 private class LimitedInputStream : Stream {
257
258 private readonly Stream proxied;
259 private int bytesLeft;
260
261 internal LimitedInputStream(Stream proxied, int size) {
262 this.proxied = proxied;
263 bytesLeft = size;
264 }
265
266 public override bool CanRead {
267 get { return true; }
268 }
269
270 public override bool CanSeek {
271 get { return false; }
272 }
273
274 public override bool CanWrite {
275 get { return false; }
276 }
277
278 public override void Flush() {
279 }
280
281 public override long Length {
282 get { throw new NotImplementedException(); }
283 }
284
285 public override long Position {
286 get {
287 throw new NotImplementedException();
288 }
289 set {
290 throw new NotImplementedException();
291 }
292 }
293
294 public override int Read(byte[] buffer, int offset, int count) {
295 if (bytesLeft > 0) {
296 int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
297 bytesLeft -= bytesRead;
298 return bytesRead;
299 }
300 return 0;
301 }
302
303 public override long Seek(long offset, SeekOrigin origin) {
304 throw new NotImplementedException();
305 }
306
307 public override void SetLength(long value) {
308 throw new NotImplementedException();
309 }
310
311 public override void Write(byte[] buffer, int offset, int count) {
312 throw new NotImplementedException();
313 }
314 }
Jon Skeet68036862008-10-22 13:30:34 +0100315 }
316}