blob: eb9baae15bb94eeb4ba2c142afdeed8cd3169925 [file] [log] [blame]
csharptest2b868842011-06-10 14:41:47 -05001using System;
2using System.Collections.Generic;
3using Google.ProtocolBuffers.Descriptors;
4
5//Disable CS3011: only CLS-compliant members can be abstract
6#pragma warning disable 3011
7
8namespace Google.ProtocolBuffers.Serialization
9{
10 /// <summary>
11 /// Provides a base-class that provides some basic functionality for handling type dispatching
12 /// </summary>
13 public abstract class AbstractReader : ICodedInputStream
14 {
csharptest3b70dd72011-06-11 12:22:17 -050015 const int MaxDepth = CodedInputStream.DefaultRecursionLimit;
16 protected int _depth;
17
csharptest2b868842011-06-10 14:41:47 -050018 /// <summary>
19 /// Merges the contents of stream into the provided message builder
20 /// </summary>
21 public TBuilder Merge<TBuilder>(TBuilder builder) where TBuilder : IBuilderLite
22 { return Merge(builder, ExtensionRegistry.Empty); }
23
24 /// <summary>
25 /// Merges the contents of stream into the provided message builder
26 /// </summary>
27 public abstract TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry) where TBuilder : IBuilderLite;
28
29 /// <summary>
30 /// Peeks at the next field in the input stream and returns what information is available.
31 /// </summary>
32 /// <remarks>
33 /// This may be called multiple times without actually reading the field. Only after the field
34 /// is either read, or skipped, should PeekNext return a different value.
35 /// </remarks>
36 protected abstract bool PeekNext(out string field);
37
38 /// <summary>
39 /// Causes the reader to skip past this field
40 /// </summary>
41 protected abstract void Skip();
42
43 /// <summary>
44 /// Returns true if it was able to read a Boolean from the input
45 /// </summary>
46 protected abstract bool Read(ref bool value);
47
48 /// <summary>
49 /// Returns true if it was able to read a Int32 from the input
50 /// </summary>
51 protected abstract bool Read(ref int value);
52
53 /// <summary>
54 /// Returns true if it was able to read a UInt32 from the input
55 /// </summary>
56 [CLSCompliant(false)]
57 protected abstract bool Read(ref uint value);
58
59 /// <summary>
60 /// Returns true if it was able to read a Int64 from the input
61 /// </summary>
62 protected abstract bool Read(ref long value);
63
64 /// <summary>
65 /// Returns true if it was able to read a UInt64 from the input
66 /// </summary>
67 [CLSCompliant(false)]
68 protected abstract bool Read(ref ulong value);
69
70 /// <summary>
71 /// Returns true if it was able to read a Single from the input
72 /// </summary>
73 protected abstract bool Read(ref float value);
74
75 /// <summary>
76 /// Returns true if it was able to read a Double from the input
77 /// </summary>
78 protected abstract bool Read(ref double value);
79
80 /// <summary>
81 /// Returns true if it was able to read a String from the input
82 /// </summary>
83 protected abstract bool Read(ref string value);
84
85 /// <summary>
86 /// Returns true if it was able to read a ByteString from the input
87 /// </summary>
88 protected abstract bool Read(ref ByteString value);
89
90 /// <summary>
91 /// returns true if it was able to read a single value into the value reference. The value
92 /// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.
93 /// </summary>
94 protected abstract bool ReadEnum(ref object value);
95
96 /// <summary>
97 /// Merges the input stream into the provided IBuilderLite
98 /// </summary>
99 protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry);
100
101 /// <summary>
102 /// Merges the input stream into the provided IBuilderLite
103 /// </summary>
104 public virtual bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)
105 {
106 return ReadMessage(value, registry);
107 }
108
109 /// <summary>
110 /// Cursors through the array elements and stops at the end of the array
111 /// </summary>
112 protected virtual IEnumerable<string> ForeachArrayItem(string field)
113 {
114 string next = field;
115 while (true)
116 {
117 yield return next;
118
119 if (!PeekNext(out next) || next != field)
120 break;
121 }
122 }
123
124 /// <summary>
125 /// Reads an array of T messages
126 /// </summary>
127 public virtual bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType, ExtensionRegistry registry)
128 {
129 bool success = false;
130 foreach (string next in ForeachArrayItem(field))
131 {
132 IBuilderLite builder = messageType.WeakCreateBuilderForType();
133 if (ReadMessage(builder, registry))
134 {
135 items.Add((T)builder.WeakBuild());
136 success |= true;
137 }
138 }
139 return success;
140 }
141
142 /// <summary>
143 /// Reads an array of T messages as a proto-buffer group
144 /// </summary>
145 public virtual bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType, ExtensionRegistry registry)
146 {
147 bool success = false;
148 foreach (string next in ForeachArrayItem(field))
149 {
150 IBuilderLite builder = messageType.WeakCreateBuilderForType();
151 if (ReadGroup(builder, registry))
152 {
153 items.Add((T)builder.WeakBuild());
154 success |= true;
155 }
156 }
157 return success;
158 }
159
160 /// <summary>
161 /// Reads an array of System.Enum type T and adds them to the collection
162 /// </summary>
163 public virtual bool ReadEnumArray(string field, ICollection<object> items)
164 {
165 bool success = false;
166 foreach (string next in ForeachArrayItem(field))
167 {
168 object temp = null;
169 if (ReadEnum(ref temp))
170 {
171 items.Add(temp);
172 success |= true;
173 }
174 }
175 return success;
176 }
177
178 /// <summary>
179 /// Reads an array of T, where T is a primitive type defined by FieldType
180 /// </summary>
181 public virtual bool ReadArray<T>(FieldType type, string field, ICollection<T> items)
182 {
183 bool success = false;
184 foreach (string next in ForeachArrayItem(field))
185 {
186 object temp = null;
187 if (ReadField(type, ref temp))
188 {
189 items.Add((T)temp);
190 success |= true;
191 }
192 }
193 return success;
194 }
195
196 /// <summary>
197 /// returns true if it was able to read a single primitive value of FieldType into the value reference
198 /// </summary>
199 public virtual bool ReadField(FieldType type, ref object value)
200 {
201 switch (type)
202 {
203 case FieldType.Bool:
204 {
205 bool temp = false;
206 if (Read(ref temp))
207 value = temp;
208 else
209 return false;
210 break;
211 }
212 case FieldType.Int64:
213 case FieldType.SInt64:
214 case FieldType.SFixed64:
215 {
216 long temp = 0;
217 if (Read(ref temp))
218 value = temp;
219 else
220 return false;
221 break;
222 }
223 case FieldType.UInt64:
224 case FieldType.Fixed64:
225 {
226 ulong temp = 0;
227 if (Read(ref temp))
228 value = temp;
229 else
230 return false;
231 break;
232 }
233 case FieldType.Int32:
234 case FieldType.SInt32:
235 case FieldType.SFixed32:
236 {
237 int temp = 0;
238 if (Read(ref temp))
239 value = temp;
240 else
241 return false;
242 break;
243 }
244 case FieldType.UInt32:
245 case FieldType.Fixed32:
246 {
247 uint temp = 0;
248 if (Read(ref temp))
249 value = temp;
250 else
251 return false;
252 break;
253 }
254 case FieldType.Float:
255 {
256 float temp = float.NaN;
257 if (Read(ref temp))
258 value = temp;
259 else
260 return false;
261 break;
262 }
263 case FieldType.Double:
264 {
265 double temp = float.NaN;
266 if (Read(ref temp))
267 value = temp;
268 else
269 return false;
270 break;
271 }
272 case FieldType.String:
273 {
274 string temp = null;
275 if (Read(ref temp))
276 value = temp;
277 else
278 return false;
279 break;
280 }
281 case FieldType.Bytes:
282 {
283 ByteString temp = null;
284 if (Read(ref temp))
285 value = temp;
286 else
287 return false;
288 break;
289 }
290 default:
291 throw InvalidProtocolBufferException.InvalidTag();
292 }
293 return true;
294 }
295
296 #region ICodedInputStream Members
297
298 bool ICodedInputStream.ReadTag(out uint fieldTag, out string fieldName)
299 {
300 fieldTag = 0;
301 if (PeekNext(out fieldName))
302 {
303 return true;
304 }
305 return false;
306 }
307
308 bool ICodedInputStream.ReadDouble(ref double value)
309 { return Read(ref value); }
310
311 bool ICodedInputStream.ReadFloat(ref float value)
312 { return Read(ref value); }
313
314 bool ICodedInputStream.ReadUInt64(ref ulong value)
315 { return Read(ref value); }
316
317 bool ICodedInputStream.ReadInt64(ref long value)
318 { return Read(ref value); }
319
320 bool ICodedInputStream.ReadInt32(ref int value)
321 { return Read(ref value); }
322
323 bool ICodedInputStream.ReadFixed64(ref ulong value)
324 { return Read(ref value); }
325
326 bool ICodedInputStream.ReadFixed32(ref uint value)
327 { return Read(ref value); }
328
329 bool ICodedInputStream.ReadBool(ref bool value)
330 { return Read(ref value); }
331
332 bool ICodedInputStream.ReadString(ref string value)
333 { return Read(ref value); }
334
335 void ICodedInputStream.ReadGroup(int fieldNumber, IBuilderLite builder, ExtensionRegistry extensionRegistry)
csharptest3b70dd72011-06-11 12:22:17 -0500336 {
337 if (_depth++ > MaxDepth)
338 throw InvalidProtocolBufferException.RecursionLimitExceeded();
339 ReadGroup(builder, extensionRegistry);
340 _depth--;
341 }
csharptest2b868842011-06-10 14:41:47 -0500342
343 void ICodedInputStream.ReadUnknownGroup(int fieldNumber, IBuilderLite builder)
344 { throw new NotSupportedException(); }
345
346 void ICodedInputStream.ReadMessage(IBuilderLite builder, ExtensionRegistry extensionRegistry)
csharptest3b70dd72011-06-11 12:22:17 -0500347 {
348 if (_depth++ > MaxDepth)
349 throw InvalidProtocolBufferException.RecursionLimitExceeded();
350 ReadMessage(builder, extensionRegistry);
351 _depth--;
352 }
csharptest2b868842011-06-10 14:41:47 -0500353
354 bool ICodedInputStream.ReadBytes(ref ByteString value)
355 { return Read(ref value); }
356
357 bool ICodedInputStream.ReadUInt32(ref uint value)
358 { return Read(ref value); }
359
360 bool ICodedInputStream.ReadEnum(ref IEnumLite value, out object unknown, IEnumLiteMap mapping)
361 {
362 value = null;
363 unknown = null;
364 if(ReadEnum(ref unknown))
365 {
366 if (unknown is int) value = mapping.FindValueByNumber((int)unknown);
367 else if (unknown is string) value = mapping.FindValueByName((string)unknown);
368 return value != null;
369 }
370 return false;
371 }
372
373 bool ICodedInputStream.ReadEnum<T>(ref T value, out object rawValue)
374 {
375 rawValue = null;
376 if (ReadEnum(ref rawValue))
377 {
378 if (Enum.IsDefined(typeof(T), rawValue))
379 {
380 if (rawValue is int)
381 value = (T)rawValue;
382 else if (rawValue is string)
383 value = (T)Enum.Parse(typeof(T), (string)rawValue, false);
384 else
385 {
386 value = default(T);
387 return false;
388 }
389 return true;
390 }
391 }
392 return false;
393 }
394
395 bool ICodedInputStream.ReadSFixed32(ref int value)
396 { return Read(ref value); }
397
398 bool ICodedInputStream.ReadSFixed64(ref long value)
399 { return Read(ref value); }
400
401 bool ICodedInputStream.ReadSInt32(ref int value)
402 { return Read(ref value); }
403
404 bool ICodedInputStream.ReadSInt64(ref long value)
405 { return Read(ref value); }
406
407 void ICodedInputStream.ReadPrimitiveArray(FieldType fieldType, uint fieldTag, string fieldName, ICollection<object> list)
408 { ReadArray(fieldType, fieldName, list); }
409
410 void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection<IEnumLite> list, out ICollection<object> unknown, IEnumLiteMap mapping)
411 {
412 unknown = null;
413 List<object> array = new List<object>();
414 if (ReadEnumArray(fieldName, array))
415 {
416 foreach (object rawValue in array)
417 {
418 IEnumLite item = null;
419 if (rawValue is int) item = mapping.FindValueByNumber((int)rawValue);
420 else if (rawValue is string) item = mapping.FindValueByName((string)rawValue);
421
422 if (item != null)
423 list.Add(item);
424 else
425 {
426 if (unknown == null) unknown = new List<object>();
427 unknown.Add(rawValue);
428 }
429 }
430 }
431 }
432
433 void ICodedInputStream.ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list, out ICollection<object> unknown)
434 {
435 unknown = null;
436 List<object> array = new List<object>();
437 if (ReadEnumArray(fieldName, array))
438 {
439 foreach (object rawValue in array)
440 {
441 if (rawValue is int)
442 list.Add((T)rawValue);
443 else if (rawValue is string)
444 list.Add((T)Enum.Parse(typeof(T), (string)rawValue, false));
445 else
446 {
447 if (unknown == null) unknown = new List<object>();
448 unknown.Add(rawValue);
449 }
450 }
451 }
452 }
453
454 void ICodedInputStream.ReadMessageArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType, ExtensionRegistry registry)
csharptest3b70dd72011-06-11 12:22:17 -0500455 {
456 if (_depth++ > MaxDepth)
457 throw InvalidProtocolBufferException.RecursionLimitExceeded();
458 ReadMessageArray(fieldName, list, messageType, registry);
459 _depth--;
460 }
csharptest2b868842011-06-10 14:41:47 -0500461
462 void ICodedInputStream.ReadGroupArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType, ExtensionRegistry registry)
csharptest3b70dd72011-06-11 12:22:17 -0500463 {
464 if (_depth++ > MaxDepth)
465 throw InvalidProtocolBufferException.RecursionLimitExceeded();
466 ReadGroupArray(fieldName, list, messageType, registry);
467 _depth--;
468 }
csharptest2b868842011-06-10 14:41:47 -0500469
470 bool ICodedInputStream.ReadPrimitiveField(FieldType fieldType, ref object value)
471 { return ReadField(fieldType, ref value); }
472
473 bool ICodedInputStream.IsAtEnd
474 {
475 get { string next; return PeekNext(out next) == false; }
476 }
477
478 bool ICodedInputStream.SkipField()
479 {
480 Skip();
481 return true;
482 }
483
484 void ICodedInputStream.ReadStringArray(uint fieldTag, string fieldName, ICollection<string> list)
485 { ReadArray(FieldType.String, fieldName, list); }
486
487 void ICodedInputStream.ReadBytesArray(uint fieldTag, string fieldName, ICollection<ByteString> list)
488 { ReadArray(FieldType.Bytes, fieldName, list); }
489
490 void ICodedInputStream.ReadBoolArray(uint fieldTag, string fieldName, ICollection<bool> list)
491 { ReadArray(FieldType.Bool, fieldName, list); }
492
493 void ICodedInputStream.ReadInt32Array(uint fieldTag, string fieldName, ICollection<int> list)
494 { ReadArray(FieldType.Int32, fieldName, list); }
495
496 void ICodedInputStream.ReadSInt32Array(uint fieldTag, string fieldName, ICollection<int> list)
497 { ReadArray(FieldType.SInt32, fieldName, list); }
498
499 void ICodedInputStream.ReadUInt32Array(uint fieldTag, string fieldName, ICollection<uint> list)
500 { ReadArray(FieldType.UInt32, fieldName, list); }
501
502 void ICodedInputStream.ReadFixed32Array(uint fieldTag, string fieldName, ICollection<uint> list)
503 { ReadArray(FieldType.Fixed32, fieldName, list); }
504
505 void ICodedInputStream.ReadSFixed32Array(uint fieldTag, string fieldName, ICollection<int> list)
506 { ReadArray(FieldType.SFixed32, fieldName, list); }
507
508 void ICodedInputStream.ReadInt64Array(uint fieldTag, string fieldName, ICollection<long> list)
509 { ReadArray(FieldType.Int64, fieldName, list); }
510
511 void ICodedInputStream.ReadSInt64Array(uint fieldTag, string fieldName, ICollection<long> list)
512 { ReadArray(FieldType.SInt64, fieldName, list); }
513
514 void ICodedInputStream.ReadUInt64Array(uint fieldTag, string fieldName, ICollection<ulong> list)
515 { ReadArray(FieldType.UInt64, fieldName, list); }
516
517 void ICodedInputStream.ReadFixed64Array(uint fieldTag, string fieldName, ICollection<ulong> list)
518 { ReadArray(FieldType.Fixed64, fieldName, list); }
519
520 void ICodedInputStream.ReadSFixed64Array(uint fieldTag, string fieldName, ICollection<long> list)
521 { ReadArray(FieldType.SFixed64, fieldName, list); }
522
523 void ICodedInputStream.ReadDoubleArray(uint fieldTag, string fieldName, ICollection<double> list)
524 { ReadArray(FieldType.Double, fieldName, list); }
525
526 void ICodedInputStream.ReadFloatArray(uint fieldTag, string fieldName, ICollection<float> list)
527 { ReadArray(FieldType.Float, fieldName, list); }
528
529 #endregion
530 }
531}