1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 namespace Ice
6 {
7 
8     using System;
9     using System.Collections.Generic;
10     using System.Diagnostics;
11     using System.Runtime.Serialization;
12     using System.Runtime.Serialization.Formatters.Binary;
13     using Protocol = IceInternal.Protocol;
14 
15     /// <summary>
16     /// Interface for output streams used to write Slice types to a sequence
17     /// of bytes.
18     /// </summary>
19     public class OutputStream
20     {
21 
22         /// <summary>
23         /// Constructing an OutputStream without providing a communicator means the stream will
24         /// use the default encoding version and the default format for class encoding.
25         /// You can supply a communicator later by calling initialize().
26         /// </summary>
OutputStream()27         public OutputStream()
28         {
29             _buf = new IceInternal.Buffer();
30             _instance = null;
31             _closure = null;
32             _encoding = Util.currentEncoding;
33             _format = FormatType.CompactFormat;
34         }
35 
36         /// <summary>
37         /// This constructor uses the communicator's default encoding version.
38         /// </summary>
39         /// <param name="communicator">The communicator to use when initializing the stream.</param>
OutputStream(Communicator communicator)40         public OutputStream(Communicator communicator)
41         {
42             Debug.Assert(communicator != null);
43             IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
44             initialize(instance, instance.defaultsAndOverrides().defaultEncoding);
45         }
46 
47         /// <summary>
48         /// This constructor uses the given communicator and encoding version.
49         /// </summary>
50         /// <param name="communicator">The communicator to use when initializing the stream.</param>
51         /// <param name="encoding">The desired encoding version.</param>
OutputStream(Communicator communicator, EncodingVersion encoding)52         public OutputStream(Communicator communicator, EncodingVersion encoding)
53         {
54             Debug.Assert(communicator != null);
55             IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
56             initialize(instance, encoding);
57         }
58 
OutputStream(IceInternal.Instance instance, EncodingVersion encoding)59         public OutputStream(IceInternal.Instance instance, EncodingVersion encoding)
60         {
61             initialize(instance, encoding);
62         }
63 
OutputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)64         public OutputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)
65         {
66             initialize(instance, encoding, new IceInternal.Buffer(buf, adopt));
67         }
68 
OutputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data)69         public OutputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data)
70         {
71             initialize(instance, encoding);
72             _buf = new IceInternal.Buffer(data);
73         }
74 
75         /// <summary>
76         /// Initializes the stream to use the communicator's default encoding version and class
77         /// encoding format.
78         /// </summary>
79         /// <param name="communicator">The communicator to use when initializing the stream.</param>
initialize(Communicator communicator)80         public void initialize(Communicator communicator)
81         {
82             Debug.Assert(communicator != null);
83             IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
84             initialize(instance, instance.defaultsAndOverrides().defaultEncoding);
85         }
86 
87         /// <summary>
88         /// Initializes the stream to use the given encoding version and the communicator's
89         /// default class encoding format.
90         /// </summary>
91         /// <param name="communicator">The communicator to use when initializing the stream.</param>
92         /// <param name="encoding">The desired encoding version.</param>
initialize(Communicator communicator, EncodingVersion encoding)93         public void initialize(Communicator communicator, EncodingVersion encoding)
94         {
95             Debug.Assert(communicator != null);
96             IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
97             initialize(instance, encoding);
98         }
99 
initialize(IceInternal.Instance instance, EncodingVersion encoding)100         private void initialize(IceInternal.Instance instance, EncodingVersion encoding)
101         {
102             initialize(instance, encoding, new IceInternal.Buffer());
103         }
104 
initialize(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf)105         private void initialize(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf)
106         {
107             Debug.Assert(instance != null);
108 
109             _instance = instance;
110             _buf = buf;
111             _closure = null;
112             _encoding = encoding;
113 
114             _format = _instance.defaultsAndOverrides().defaultFormat;
115 
116             _encapsStack = null;
117             _encapsCache = null;
118         }
119 
120         /// <summary>
121         /// Resets this output stream. This method allows the stream to be reused, to avoid creating
122         /// unnecessary garbage.
123         /// </summary>
reset()124         public void reset()
125         {
126             _buf.reset();
127             clear();
128         }
129 
130         /// <summary>
131         /// Releases any data retained by encapsulations. The reset() method internally calls clear().
132         /// </summary>
clear()133         public void clear()
134         {
135             if(_encapsStack != null)
136             {
137                 Debug.Assert(_encapsStack.next == null);
138                 _encapsStack.next = _encapsCache;
139                 _encapsCache = _encapsStack;
140                 _encapsStack = null;
141                 _encapsCache.reset();
142             }
143         }
144 
instance()145         public IceInternal.Instance instance()
146         {
147             return _instance;
148         }
149 
150         /// <summary>
151         /// Sets the encoding format for class and exception instances.
152         /// </summary>
153         /// <param name="fmt">The encoding format.</param>
setFormat(FormatType fmt)154         public void setFormat(FormatType fmt)
155         {
156             _format = fmt;
157         }
158 
159         /// <summary>
160         /// Retrieves the closure object associated with this stream.
161         /// </summary>
162         /// <returns>The closure object.</returns>
getClosure()163         public object getClosure()
164         {
165             return _closure;
166         }
167 
168         /// <summary>
169         /// Associates a closure object with this stream.
170         /// </summary>
171         /// <param name="p">The new closure object.</param>
172         /// <returns>The previous closure object, or null.</returns>
setClosure(object p)173         public object setClosure(object p)
174         {
175             object prev = _closure;
176             _closure = p;
177             return prev;
178         }
179 
180         /// <summary>
181         /// Indicates that the marshaling of a request or reply is finished.
182         /// </summary>
183         /// <returns>The byte sequence containing the encoded request or reply.</returns>
finished()184         public byte[] finished()
185         {
186             IceInternal.Buffer buf = prepareWrite();
187             byte[] result = new byte[buf.b.limit()];
188             buf.b.get(result);
189             return result;
190         }
191 
192         /// <summary>
193         /// Swaps the contents of one stream with another.
194         /// </summary>
195         /// <param name="other">The other stream.</param>
swap(OutputStream other)196         public void swap(OutputStream other)
197         {
198             Debug.Assert(_instance == other._instance);
199 
200             IceInternal.Buffer tmpBuf = other._buf;
201             other._buf = _buf;
202             _buf = tmpBuf;
203 
204             EncodingVersion tmpEncoding = other._encoding;
205             other._encoding = _encoding;
206             _encoding = tmpEncoding;
207 
208             object tmpClosure = other._closure;
209             other._closure = _closure;
210             _closure = tmpClosure;
211 
212             //
213             // Swap is never called for streams that have encapsulations being written. However,
214             // encapsulations might still be set in case marshalling failed. We just
215             // reset the encapsulations if there are still some set.
216             //
217             resetEncapsulation();
218             other.resetEncapsulation();
219         }
220 
resetEncapsulation()221         private void resetEncapsulation()
222         {
223             _encapsStack = null;
224         }
225 
226         /// <summary>
227         /// Resizes the stream to a new size.
228         /// </summary>
229         /// <param name="sz">The new size.</param>
resize(int sz)230         public void resize(int sz)
231         {
232             _buf.resize(sz, false);
233             _buf.b.position(sz);
234         }
235 
236         /// <summary>
237         /// Prepares the internal data buffer to be written to a socket.
238         /// </summary>
prepareWrite()239         public IceInternal.Buffer prepareWrite()
240         {
241             _buf.b.limit(_buf.size());
242             _buf.b.position(0);
243             return _buf;
244         }
245 
246         /// <summary>
247         /// Retrieves the internal data buffer.
248         /// </summary>
249         /// <returns>The buffer.</returns>
getBuffer()250         public IceInternal.Buffer getBuffer()
251         {
252             return _buf;
253         }
254 
255         /// <summary>
256         /// Marks the start of a class instance.
257         /// </summary>
258         /// <param name="data">Preserved slices for this instance, or null.</param>
startValue(SlicedData data)259         public void startValue(SlicedData data)
260         {
261             Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
262             _encapsStack.encoder.startInstance(SliceType.ValueSlice, data);
263         }
264 
265         /// <summary>
266         /// Marks the end of a class instance.
267         /// </summary>
endValue()268         public void endValue()
269         {
270             Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
271             _encapsStack.encoder.endInstance();
272         }
273 
274         /// <summary>
275         /// Marks the start of a user exception.
276         /// </summary>
277         /// <param name="data">Preserved slices for this exception, or null.</param>
startException(SlicedData data)278         public void startException(SlicedData data)
279         {
280             Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
281             _encapsStack.encoder.startInstance(SliceType.ExceptionSlice, data);
282         }
283 
284         /// <summary>
285         /// Marks the end of a user exception.
286         /// </summary>
endException()287         public void endException()
288         {
289             Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
290             _encapsStack.encoder.endInstance();
291         }
292 
293         /// <summary>
294         /// Writes the start of an encapsulation to the stream.
295         /// </summary>
startEncapsulation()296         public void startEncapsulation()
297         {
298             //
299             // If no encoding version is specified, use the current write
300             // encapsulation encoding version if there's a current write
301             // encapsulation, otherwise, use the stream encoding version.
302             //
303 
304             if(_encapsStack != null)
305             {
306                 startEncapsulation(_encapsStack.encoding, _encapsStack.format);
307             }
308             else
309             {
310                 startEncapsulation(_encoding, FormatType.DefaultFormat);
311             }
312         }
313 
314         /// <summary>
315         /// Writes the start of an encapsulation to the stream.
316         /// </summary>
317         /// <param name="encoding">The encoding version of the encapsulation.</param>
318         /// <param name="format">Specify the compact or sliced format.</param>
startEncapsulation(EncodingVersion encoding, FormatType format)319         public void startEncapsulation(EncodingVersion encoding, FormatType format)
320         {
321             Protocol.checkSupportedEncoding(encoding);
322 
323             Encaps curr = _encapsCache;
324             if(curr != null)
325             {
326                 curr.reset();
327                 _encapsCache = _encapsCache.next;
328             }
329             else
330             {
331                 curr = new Encaps();
332             }
333             curr.next = _encapsStack;
334             _encapsStack = curr;
335 
336             _encapsStack.format = format;
337             _encapsStack.setEncoding(encoding);
338             _encapsStack.start = _buf.b.position();
339 
340             writeInt(0); // Placeholder for the encapsulation length.
341             _encapsStack.encoding.ice_writeMembers(this);
342         }
343 
344         /// <summary>
345         /// Ends the previous encapsulation.
346         /// </summary>
endEncapsulation()347         public void endEncapsulation()
348         {
349             Debug.Assert(_encapsStack != null);
350 
351             // Size includes size and version.
352             int start = _encapsStack.start;
353             int sz = _buf.size() - start;
354             _buf.b.putInt(start, sz);
355 
356             Encaps curr = _encapsStack;
357             _encapsStack = curr.next;
358             curr.next = _encapsCache;
359             _encapsCache = curr;
360             _encapsCache.reset();
361         }
362 
363         /// <summary>
364         /// Writes an empty encapsulation using the given encoding version.
365         /// </summary>
366         /// <param name="encoding">The encoding version of the encapsulation.</param>
writeEmptyEncapsulation(EncodingVersion encoding)367         public void writeEmptyEncapsulation(EncodingVersion encoding)
368         {
369             Protocol.checkSupportedEncoding(encoding);
370             writeInt(6); // Size
371             encoding.ice_writeMembers(this);
372         }
373 
374         /// <summary>
375         /// Writes a pre-encoded encapsulation.
376         /// </summary>
377         /// <param name="v">The encapsulation data.</param>
writeEncapsulation(byte[] v)378         public void writeEncapsulation(byte[] v)
379         {
380             if(v.Length < 6)
381             {
382                 throw new EncapsulationException();
383             }
384             expand(v.Length);
385             _buf.b.put(v);
386         }
387 
388         /// <summary>
389         /// Determines the current encoding version.
390         /// </summary>
391         /// <returns>The encoding version.</returns>
getEncoding()392         public EncodingVersion getEncoding()
393         {
394             return _encapsStack != null ? _encapsStack.encoding : _encoding;
395         }
396 
397         /// <summary>
398         /// Marks the start of a new slice for a class instance or user exception.
399         /// </summary>
400         /// <param name="typeId">The Slice type ID corresponding to this slice.</param>
401         /// <param name="compactId">The Slice compact type ID corresponding to this slice or -1 if no compact ID
402         /// is defined for the type ID.</param>
403         /// <param name="last">True if this is the last slice, false otherwise.</param>
startSlice(string typeId, int compactId, bool last)404         public void startSlice(string typeId, int compactId, bool last)
405         {
406             Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
407             _encapsStack.encoder.startSlice(typeId, compactId, last);
408         }
409 
410         /// <summary>
411         /// Marks the end of a slice for a class instance or user exception.
412         /// </summary>
endSlice()413         public void endSlice()
414         {
415             Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
416             _encapsStack.encoder.endSlice();
417         }
418 
419         /// <summary>
420         /// Writes the state of Slice classes whose index was previously written with writeValue() to the stream.
421         /// </summary>
writePendingValues()422         public void writePendingValues()
423         {
424             if(_encapsStack != null && _encapsStack.encoder != null)
425             {
426                 _encapsStack.encoder.writePendingValues();
427             }
428             else if(_encapsStack != null ?
429                     _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0))
430             {
431                 //
432                 // If using the 1.0 encoding and no instances were written, we
433                 // still write an empty sequence for pending instances if
434                 // requested (i.e.: if this is called).
435                 //
436                 // This is required by the 1.0 encoding, even if no instances
437                 // are written we do marshal an empty sequence if marshaled
438                 // data types use classes.
439                 //
440                 writeSize(0);
441             }
442         }
443 
444         /// <summary>
445         /// Writes a size to the stream.
446         /// </summary>
447         /// <param name="v">The size to write.</param>
writeSize(int v)448         public void writeSize(int v)
449         {
450             if(v > 254)
451             {
452                 expand(5);
453                 _buf.b.put(255);
454                 _buf.b.putInt(v);
455             }
456             else
457             {
458                 expand(1);
459                 _buf.b.put((byte)v);
460             }
461         }
462 
463         /// <summary>
464         /// Returns the current position and allocates four bytes for a fixed-length (32-bit) size value.
465         /// </summary>
startSize()466         public int startSize()
467         {
468             int pos = _buf.b.position();
469             writeInt(0); // Placeholder for 32-bit size
470             return pos;
471         }
472 
473         /// <summary>
474         /// Computes the amount of data written since the previous call to startSize and writes that value
475         /// at the saved position.
476         /// </summary>
477         /// <param name="pos">The saved position.</param>
endSize(int pos)478         public void endSize(int pos)
479         {
480             Debug.Assert(pos >= 0);
481             rewriteInt(_buf.b.position() - pos - 4, pos);
482         }
483 
484         /// <summary>
485         /// Writes a blob of bytes to the stream.
486         /// </summary>
487         /// <param name="v">The byte array to be written. All of the bytes in the array are written.</param>
writeBlob(byte[] v)488         public void writeBlob(byte[] v)
489         {
490             if(v == null)
491             {
492                 return;
493             }
494             expand(v.Length);
495             _buf.b.put(v);
496         }
497 
498         /// <summary>
499         /// Writes a blob of bytes to the stream.
500         /// </summary>
501         /// <param name="v">The byte array to be written. All of the bytes in the array are written.</param>
502         /// <param name="off">The offset into the byte array from which to copy.</param>
503         /// <param name="len">The number of bytes from the byte array to copy.</param>
writeBlob(byte[] v, int off, int len)504         public void writeBlob(byte[] v, int off, int len)
505         {
506             if(v == null)
507             {
508                 return;
509             }
510             expand(len);
511             _buf.b.put(v, off, len);
512         }
513 
514         /// <summary>
515         /// Write the header information for an optional value.
516         /// </summary>
517         /// <param name="tag">The numeric tag associated with the value.</param>
518         /// <param name="format">The optional format of the value.</param>
writeOptional(int tag, OptionalFormat format)519         public bool writeOptional(int tag, OptionalFormat format)
520         {
521             Debug.Assert(_encapsStack != null);
522             if(_encapsStack.encoder != null)
523             {
524                 return _encapsStack.encoder.writeOptional(tag, format);
525             }
526             else
527             {
528                 return writeOptionalImpl(tag, format);
529             }
530         }
531 
532         /// <summary>
533         /// Writes a byte to the stream.
534         /// </summary>
535         /// <param name="v">The byte to write to the stream.</param>
writeByte(byte v)536         public void writeByte(byte v)
537         {
538             expand(1);
539             _buf.b.put(v);
540         }
541 
542         /// <summary>
543         /// Writes an optional byte to the stream.
544         /// </summary>
545         /// <param name="tag">The optional tag.</param>
546         /// <param name="v">The optional byte to write to the stream.</param>
writeByte(int tag, Optional<byte> v)547         public void writeByte(int tag, Optional<byte> v)
548         {
549             if(v.HasValue)
550             {
551                 writeByte(tag, v.Value);
552             }
553         }
554 
555         /// <summary>
556         /// Writes an optional byte to the stream.
557         /// </summary>
558         /// <param name="tag">The optional tag.</param>
559         /// <param name="v">The byte to write to the stream.</param>
writeByte(int tag, byte v)560         public void writeByte(int tag, byte v)
561         {
562             if(writeOptional(tag, OptionalFormat.F1))
563             {
564                 writeByte(v);
565             }
566         }
567 
568         /// <summary>
569         /// Writes a byte to the stream at the given position. The current position of the stream is not modified.
570         /// </summary>
571         /// <param name="v">The byte to write to the stream.</param>
572         /// <param name="dest">The position at which to store the byte in the buffer.</param>
rewriteByte(byte v, int dest)573         public void rewriteByte(byte v, int dest)
574         {
575             _buf.b.put(dest, v);
576         }
577 
578         /// <summary>
579         /// Writes a byte sequence to the stream.
580         /// </summary>
581         /// <param name="v">The byte sequence to write to the stream.
582         /// Passing null causes an empty sequence to be written to the stream.</param>
writeByteSeq(byte[] v)583         public void writeByteSeq(byte[] v)
584         {
585             if(v == null)
586             {
587                 writeSize(0);
588             }
589             else
590             {
591                 writeSize(v.Length);
592                 expand(v.Length);
593                 _buf.b.put(v);
594             }
595         }
596 
597         /// <summary>
598         /// Writes a byte sequence to the stream.
599         /// </summary>
600         /// <param name="count">The number of elements in the sequence.</param>
601         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeByteSeq(int count, IEnumerable<byte> v)602         public void writeByteSeq(int count, IEnumerable<byte> v)
603         {
604             if(count == 0)
605             {
606                 writeSize(0);
607                 return;
608             }
609 
610             {
611                 List<byte> value = v as List<byte>;
612                 if(value != null)
613                 {
614                     writeByteSeq(value.ToArray());
615                     return;
616                 }
617             }
618 
619             {
620                 LinkedList<byte> value = v as LinkedList<byte>;
621                 if(value != null)
622                 {
623                     writeSize(count);
624                     expand(count);
625                     IEnumerator<byte> i = v.GetEnumerator();
626                     while(i.MoveNext())
627                     {
628                         _buf.b.put(i.Current);
629                     }
630                     return;
631                 }
632             }
633 
634             {
635                 Queue<byte> value = v as Queue<byte>;
636                 if(value != null)
637                 {
638                     writeByteSeq(value.ToArray());
639                     return;
640                 }
641             }
642 
643             {
644                 Stack<byte> value = v as Stack<byte>;
645                 if(value != null)
646                 {
647                     writeByteSeq(value.ToArray());
648                     return;
649                 }
650             }
651 
652             writeSize(count);
653             expand(count);
654             foreach(byte b in v)
655             {
656                 _buf.b.put(b);
657             }
658         }
659 
660         /// <summary>
661         /// Writes an optional byte sequence to the stream.
662         /// </summary>
663         /// <param name="tag">The optional tag.</param>
664         /// <param name="v">The optional byte sequence to write to the stream.</param>
writeByteSeq(int tag, Optional<byte[]> v)665         public void writeByteSeq(int tag, Optional<byte[]> v)
666         {
667             if(v.HasValue)
668             {
669                 writeByteSeq(tag, v.Value);
670             }
671         }
672 
673         /// <summary>
674         /// Writes an optional byte sequence to the stream.
675         /// </summary>
676         /// <param name="tag">The optional tag.</param>
677         /// <param name="count">The number of elements in the sequence.</param>
678         /// <param name="v">An enumerator for the optional byte sequence.</param>
679         public void writeByteSeq<T>(int tag, int count, Optional<T> v)
680             where T : IEnumerable<byte>
681         {
682             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
683             {
684                 writeByteSeq(count, v.Value);
685             }
686         }
687 
688         /// <summary>
689         /// Writes an optional byte sequence to the stream.
690         /// </summary>
691         /// <param name="tag">The optional tag.</param>
692         /// <param name="v">The byte sequence to write to the stream.</param>
writeByteSeq(int tag, byte[] v)693         public void writeByteSeq(int tag, byte[] v)
694         {
695             if(writeOptional(tag, OptionalFormat.VSize))
696             {
697                 writeByteSeq(v);
698             }
699         }
700 
701         /// <summary>
702         /// Writes an optional byte sequence to the stream.
703         /// </summary>
704         /// <param name="tag">The optional tag.</param>
705         /// <param name="count">The number of elements in the sequence.</param>
706         /// <param name="v">An enumerator for the byte sequence.</param>
writeByteSeq(int tag, int count, IEnumerable<byte> v)707         public void writeByteSeq(int tag, int count, IEnumerable<byte> v)
708         {
709             if(writeOptional(tag, OptionalFormat.VSize))
710             {
711                 writeByteSeq(count, v);
712             }
713         }
714 
715         /// <summary>
716         /// Writes a serializable object to the stream.
717         /// </summary>
718         /// <param name="o">The serializable object to write.</param>
writeSerializable(object o)719         public void writeSerializable(object o)
720         {
721             if(o == null)
722             {
723                 writeSize(0);
724                 return;
725             }
726             try
727             {
728                 IceInternal.OutputStreamWrapper w = new IceInternal.OutputStreamWrapper(this);
729                 IFormatter f = new BinaryFormatter();
730                 f.Serialize(w, o);
731                 w.Close();
732             }
733             catch(System.Exception ex)
734             {
735                 throw new MarshalException("cannot serialize object:", ex);
736             }
737         }
738 
739         /// <summary>
740         /// Writes a boolean to the stream.
741         /// </summary>
742         /// <param name="v">The boolean to write to the stream.</param>
writeBool(bool v)743         public void writeBool(bool v)
744         {
745             expand(1);
746             _buf.b.put(v ? (byte)1 : (byte)0);
747         }
748 
749         /// <summary>
750         /// Writes an optional boolean to the stream.
751         /// </summary>
752         /// <param name="tag">The optional tag.</param>
753         /// <param name="v">The optional boolean to write to the stream.</param>
writeBool(int tag, Optional<bool> v)754         public void writeBool(int tag, Optional<bool> v)
755         {
756             if(v.HasValue)
757             {
758                 writeBool(tag, v.Value);
759             }
760         }
761 
762         /// <summary>
763         /// Writes an optional boolean to the stream.
764         /// </summary>
765         /// <param name="tag">The optional tag.</param>
766         /// <param name="v">The boolean to write to the stream.</param>
writeBool(int tag, bool v)767         public void writeBool(int tag, bool v)
768         {
769             if(writeOptional(tag, OptionalFormat.F1))
770             {
771                 writeBool(v);
772             }
773         }
774 
775         /// <summary>
776         /// Writes a boolean to the stream at the given position. The current position of the stream is not modified.
777         /// </summary>
778         /// <param name="v">The boolean to write to the stream.</param>
779         /// <param name="dest">The position at which to store the boolean in the buffer.</param>
rewriteBool(bool v, int dest)780         public void rewriteBool(bool v, int dest)
781         {
782             _buf.b.put(dest, v ? (byte)1 : (byte)0);
783         }
784 
785         /// <summary>
786         /// Writes a boolean sequence to the stream.
787         /// </summary>
788         /// <param name="v">The boolean sequence to write to the stream.
789         /// Passing null causes an empty sequence to be written to the stream.</param>
writeBoolSeq(bool[] v)790         public void writeBoolSeq(bool[] v)
791         {
792             if(v == null)
793             {
794                 writeSize(0);
795             }
796             else
797             {
798                 writeSize(v.Length);
799                 expand(v.Length);
800                 _buf.b.putBoolSeq(v);
801             }
802         }
803 
804         /// <summary>
805         /// Writes a boolean sequence to the stream.
806         /// </summary>
807         /// <param name="count">The number of elements in the sequence.</param>
808         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeBoolSeq(int count, IEnumerable<bool> v)809         public void writeBoolSeq(int count, IEnumerable<bool> v)
810         {
811             if(count == 0)
812             {
813                 writeSize(0);
814                 return;
815             }
816 
817             {
818                 List<bool> value = v as List<bool>;
819                 if(value != null)
820                 {
821                     writeBoolSeq(value.ToArray());
822                     return;
823                 }
824             }
825 
826             {
827                 LinkedList<bool> value = v as LinkedList<bool>;
828                 if(value != null)
829                 {
830                     writeSize(count);
831                     expand(count);
832                     IEnumerator<bool> i = v.GetEnumerator();
833                     while(i.MoveNext())
834                     {
835                         _buf.b.putBool(i.Current);
836                     }
837                     return;
838                 }
839             }
840 
841             {
842                 Queue<bool> value = v as Queue<bool>;
843                 if(value != null)
844                 {
845                     writeBoolSeq(value.ToArray());
846                     return;
847                 }
848             }
849 
850             {
851                 Stack<bool> value = v as Stack<bool>;
852                 if(value != null)
853                 {
854                     writeBoolSeq(value.ToArray());
855                     return;
856                 }
857             }
858 
859             writeSize(count);
860             expand(count);
861             foreach(bool b in v)
862             {
863                 _buf.b.putBool(b);
864             }
865         }
866 
867         /// <summary>
868         /// Writes an optional boolean sequence to the stream.
869         /// </summary>
870         /// <param name="tag">The optional tag.</param>
871         /// <param name="v">The optional boolean sequence to write to the stream.</param>
writeBoolSeq(int tag, Optional<bool[]> v)872         public void writeBoolSeq(int tag, Optional<bool[]> v)
873         {
874             if(v.HasValue)
875             {
876                 writeBoolSeq(tag, v.Value);
877             }
878         }
879 
880         /// <summary>
881         /// Writes an optional boolean sequence to the stream.
882         /// </summary>
883         /// <param name="tag">The optional tag.</param>
884         /// <param name="count">The number of elements in the sequence.</param>
885         /// <param name="v">An enumerator for the optional boolean sequence.</param>
886         public void writeBoolSeq<T>(int tag, int count, Optional<T> v)
887             where T : IEnumerable<bool>
888         {
889             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
890             {
891                 writeBoolSeq(count, v.Value);
892             }
893         }
894 
895         /// <summary>
896         /// Writes an optional boolean sequence to the stream.
897         /// </summary>
898         /// <param name="tag">The optional tag.</param>
899         /// <param name="v">The boolean sequence to write to the stream.</param>
writeBoolSeq(int tag, bool[] v)900         public void writeBoolSeq(int tag, bool[] v)
901         {
902             if(writeOptional(tag, OptionalFormat.VSize))
903             {
904                 writeBoolSeq(v);
905             }
906         }
907 
908         /// <summary>
909         /// Writes an optional boolean sequence to the stream.
910         /// </summary>
911         /// <param name="tag">The optional tag.</param>
912         /// <param name="count">The number of elements in the sequence.</param>
913         /// <param name="v">An enumerator for the boolean sequence.</param>
writeBoolSeq(int tag, int count, IEnumerable<bool> v)914         public void writeBoolSeq(int tag, int count, IEnumerable<bool> v)
915         {
916             if(writeOptional(tag, OptionalFormat.VSize))
917             {
918                 writeBoolSeq(count, v);
919             }
920         }
921 
922         /// <summary>
923         /// Writes a short to the stream.
924         /// </summary>
925         /// <param name="v">The short to write to the stream.</param>
writeShort(short v)926         public void writeShort(short v)
927         {
928             expand(2);
929             _buf.b.putShort(v);
930         }
931 
932         /// <summary>
933         /// Writes an optional short to the stream.
934         /// </summary>
935         /// <param name="tag">The optional tag.</param>
936         /// <param name="v">The optional short to write to the stream.</param>
writeShort(int tag, Optional<short> v)937         public void writeShort(int tag, Optional<short> v)
938         {
939             if(v.HasValue)
940             {
941                 writeShort(tag, v.Value);
942             }
943         }
944 
945         /// <summary>
946         /// Writes an optional short to the stream.
947         /// </summary>
948         /// <param name="tag">The optional tag.</param>
949         /// <param name="v">The short to write to the stream.</param>
writeShort(int tag, short v)950         public void writeShort(int tag, short v)
951         {
952             if(writeOptional(tag, OptionalFormat.F2))
953             {
954                 writeShort(v);
955             }
956         }
957 
958         /// <summary>
959         /// Writes a short sequence to the stream.
960         /// </summary>
961         /// <param name="v">The short sequence to write to the stream.
962         /// Passing null causes an empty sequence to be written to the stream.</param>
writeShortSeq(short[] v)963         public void writeShortSeq(short[] v)
964         {
965             if(v == null)
966             {
967                 writeSize(0);
968             }
969             else
970             {
971                 writeSize(v.Length);
972                 expand(v.Length * 2);
973                 _buf.b.putShortSeq(v);
974             }
975         }
976 
977         /// <summary>
978         /// Writes a short sequence to the stream.
979         /// </summary>
980         /// <param name="count">The number of elements in the sequence.</param>
981         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeShortSeq(int count, IEnumerable<short> v)982         public void writeShortSeq(int count, IEnumerable<short> v)
983         {
984             if(count == 0)
985             {
986                 writeSize(0);
987                 return;
988             }
989 
990             {
991                 List<short> value = v as List<short>;
992                 if(value != null)
993                 {
994                     writeShortSeq(value.ToArray());
995                     return;
996                 }
997             }
998 
999             {
1000                 LinkedList<short> value = v as LinkedList<short>;
1001                 if(value != null)
1002                 {
1003                     writeSize(count);
1004                     expand(count * 2);
1005                     IEnumerator<short> i = v.GetEnumerator();
1006                     while(i.MoveNext())
1007                     {
1008                         _buf.b.putShort(i.Current);
1009                     }
1010                     return;
1011                 }
1012             }
1013 
1014             {
1015                 Queue<short> value = v as Queue<short>;
1016                 if(value != null)
1017                 {
1018                     writeShortSeq(value.ToArray());
1019                     return;
1020                 }
1021             }
1022 
1023             {
1024                 Stack<short> value = v as Stack<short>;
1025                 if(value != null)
1026                 {
1027                     writeShortSeq(value.ToArray());
1028                     return;
1029                 }
1030             }
1031 
1032             writeSize(count);
1033             expand(count * 2);
1034             foreach(short s in v)
1035             {
1036                 _buf.b.putShort(s);
1037             }
1038         }
1039 
1040         /// <summary>
1041         /// Writes an optional short sequence to the stream.
1042         /// </summary>
1043         /// <param name="tag">The optional tag.</param>
1044         /// <param name="v">The optional short sequence to write to the stream.</param>
writeShortSeq(int tag, Optional<short[]> v)1045         public void writeShortSeq(int tag, Optional<short[]> v)
1046         {
1047             if(v.HasValue)
1048             {
1049                 writeShortSeq(tag, v.Value);
1050             }
1051         }
1052 
1053         /// <summary>
1054         /// Writes an optional short sequence to the stream.
1055         /// </summary>
1056         /// <param name="tag">The optional tag.</param>
1057         /// <param name="count">The number of elements in the sequence.</param>
1058         /// <param name="v">An enumerator for the optional short sequence.</param>
1059         public void writeShortSeq<T>(int tag, int count, Optional<T> v)
1060             where T : IEnumerable<short>
1061         {
1062             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
1063             {
1064                 writeSize(count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
1065                 writeShortSeq(count, v.Value);
1066             }
1067         }
1068 
1069         /// <summary>
1070         /// Writes an optional short sequence to the stream.
1071         /// </summary>
1072         /// <param name="tag">The optional tag.</param>
1073         /// <param name="v">The short sequence to write to the stream.</param>
writeShortSeq(int tag, short[] v)1074         public void writeShortSeq(int tag, short[] v)
1075         {
1076             if(writeOptional(tag, OptionalFormat.VSize))
1077             {
1078                 writeSize(v == null || v.Length == 0 ? 1 : v.Length * 2 + (v.Length > 254 ? 5 : 1));
1079                 writeShortSeq(v);
1080             }
1081         }
1082 
1083         /// <summary>
1084         /// Writes an optional short sequence to the stream.
1085         /// </summary>
1086         /// <param name="tag">The optional tag.</param>
1087         /// <param name="count">The number of elements in the sequence.</param>
1088         /// <param name="v">An enumerator for the short sequence.</param>
writeShortSeq(int tag, int count, IEnumerable<short> v)1089         public void writeShortSeq(int tag, int count, IEnumerable<short> v)
1090         {
1091             if(writeOptional(tag, OptionalFormat.VSize))
1092             {
1093                 writeSize(v == null || count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
1094                 writeShortSeq(count, v);
1095             }
1096         }
1097 
1098         /// <summary>
1099         /// Writes an int to the stream.
1100         /// </summary>
1101         /// <param name="v">The int to write to the stream.</param>
writeInt(int v)1102         public void writeInt(int v)
1103         {
1104             expand(4);
1105             _buf.b.putInt(v);
1106         }
1107 
1108         /// <summary>
1109         /// Writes an optional int to the stream.
1110         /// </summary>
1111         /// <param name="tag">The optional tag.</param>
1112         /// <param name="v">The optional int to write to the stream.</param>
writeInt(int tag, Optional<int> v)1113         public void writeInt(int tag, Optional<int> v)
1114         {
1115             if(v.HasValue)
1116             {
1117                 writeInt(tag, v.Value);
1118             }
1119         }
1120 
1121         /// <summary>
1122         /// Writes an optional int to the stream.
1123         /// </summary>
1124         /// <param name="tag">The optional tag.</param>
1125         /// <param name="v">The int to write to the stream.</param>
writeInt(int tag, int v)1126         public void writeInt(int tag, int v)
1127         {
1128             if(writeOptional(tag, OptionalFormat.F4))
1129             {
1130                 writeInt(v);
1131             }
1132         }
1133 
1134         /// <summary>
1135         /// Writes an int to the stream at the given position. The current position of the stream is not modified.
1136         /// </summary>
1137         /// <param name="v">The int to write to the stream.</param>
1138         /// <param name="dest">The position at which to store the int in the buffer.</param>
rewriteInt(int v, int dest)1139         public void rewriteInt(int v, int dest)
1140         {
1141             _buf.b.putInt(dest, v);
1142         }
1143 
1144         /// <summary>
1145         /// Writes an int sequence to the stream.
1146         /// </summary>
1147         /// <param name="v">The int sequence to write to the stream.
1148         /// Passing null causes an empty sequence to be written to the stream.</param>
writeIntSeq(int[] v)1149         public void writeIntSeq(int[] v)
1150         {
1151             if(v == null)
1152             {
1153                 writeSize(0);
1154             }
1155             else
1156             {
1157                 writeSize(v.Length);
1158                 expand(v.Length * 4);
1159                 _buf.b.putIntSeq(v);
1160             }
1161         }
1162 
1163         /// <summary>
1164         /// Writes an int sequence to the stream.
1165         /// </summary>
1166         /// <param name="count">The number of elements in the sequence.</param>
1167         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeIntSeq(int count, IEnumerable<int> v)1168         public void writeIntSeq(int count, IEnumerable<int> v)
1169         {
1170             if(count == 0)
1171             {
1172                 writeSize(0);
1173                 return;
1174             }
1175 
1176             {
1177                 List<int> value = v as List<int>;
1178                 if(value != null)
1179                 {
1180                     writeIntSeq(value.ToArray());
1181                     return;
1182                 }
1183             }
1184 
1185             {
1186                 LinkedList<int> value = v as LinkedList<int>;
1187                 if(value != null)
1188                 {
1189                     writeSize(count);
1190                     expand(count * 4);
1191                     IEnumerator<int> i = v.GetEnumerator();
1192                     while(i.MoveNext())
1193                     {
1194                         _buf.b.putInt(i.Current);
1195                     }
1196                     return;
1197                 }
1198             }
1199 
1200             {
1201                 Queue<int> value = v as Queue<int>;
1202                 if(value != null)
1203                 {
1204                     writeIntSeq(value.ToArray());
1205                     return;
1206                 }
1207             }
1208 
1209             {
1210                 Stack<int> value = v as Stack<int>;
1211                 if(value != null)
1212                 {
1213                     writeIntSeq(value.ToArray());
1214                     return;
1215                 }
1216             }
1217 
1218             writeSize(count);
1219             expand(count * 4);
1220             foreach(int i in v)
1221             {
1222                 _buf.b.putInt(i);
1223             }
1224         }
1225 
1226         /// <summary>
1227         /// Writes an optional int sequence to the stream.
1228         /// </summary>
1229         /// <param name="tag">The optional tag.</param>
1230         /// <param name="v">The optional int sequence to write to the stream.</param>
writeIntSeq(int tag, Optional<int[]> v)1231         public void writeIntSeq(int tag, Optional<int[]> v)
1232         {
1233             if(v.HasValue)
1234             {
1235                 writeIntSeq(tag, v.Value);
1236             }
1237         }
1238 
1239         /// <summary>
1240         /// Writes an optional int sequence to the stream.
1241         /// </summary>
1242         /// <param name="tag">The optional tag.</param>
1243         /// <param name="count">The number of elements in the sequence.</param>
1244         /// <param name="v">An enumerator for the optional byte sequence.</param>
1245         public void writeIntSeq<T>(int tag, int count, Optional<T> v)
1246             where T : IEnumerable<int>
1247         {
1248             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
1249             {
1250                 writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
1251                 writeIntSeq(count, v.Value);
1252             }
1253         }
1254 
1255         /// <summary>
1256         /// Writes an optional int sequence to the stream.
1257         /// </summary>
1258         /// <param name="tag">The optional tag.</param>
1259         /// <param name="v">The int sequence to write to the stream.</param>
writeIntSeq(int tag, int[] v)1260         public void writeIntSeq(int tag, int[] v)
1261         {
1262             if(writeOptional(tag, OptionalFormat.VSize))
1263             {
1264                 writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
1265                 writeIntSeq(v);
1266             }
1267         }
1268 
1269         /// <summary>
1270         /// Writes an optional int sequence to the stream.
1271         /// </summary>
1272         /// <param name="tag">The optional tag.</param>
1273         /// <param name="count">The number of elements in the sequence.</param>
1274         /// <param name="v">An enumerator for the int sequence.</param>
writeIntSeq(int tag, int count, IEnumerable<int> v)1275         public void writeIntSeq(int tag, int count, IEnumerable<int> v)
1276         {
1277             if(writeOptional(tag, OptionalFormat.VSize))
1278             {
1279                 writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
1280                 writeIntSeq(count, v);
1281             }
1282         }
1283 
1284         /// <summary>
1285         /// Writes a long to the stream.
1286         /// </summary>
1287         /// <param name="v">The long to write to the stream.</param>
writeLong(long v)1288         public void writeLong(long v)
1289         {
1290             expand(8);
1291             _buf.b.putLong(v);
1292         }
1293 
1294         /// <summary>
1295         /// Writes an optional long to the stream.
1296         /// </summary>
1297         /// <param name="tag">The optional tag.</param>
1298         /// <param name="v">The optional long to write to the stream.</param>
writeLong(int tag, Optional<long> v)1299         public void writeLong(int tag, Optional<long> v)
1300         {
1301             if(v.HasValue)
1302             {
1303                 writeLong(tag, v.Value);
1304             }
1305         }
1306 
1307         /// <summary>
1308         /// Writes an optional long to the stream.
1309         /// </summary>
1310         /// <param name="tag">The optional tag.</param>
1311         /// <param name="v">The long to write to the stream.</param>
writeLong(int tag, long v)1312         public void writeLong(int tag, long v)
1313         {
1314             if(writeOptional(tag, OptionalFormat.F8))
1315             {
1316                 writeLong(v);
1317             }
1318         }
1319 
1320         /// <summary>
1321         /// Writes a long sequence to the stream.
1322         /// </summary>
1323         /// <param name="v">The long sequence to write to the stream.
1324         /// Passing null causes an empty sequence to be written to the stream.</param>
writeLongSeq(long[] v)1325         public void writeLongSeq(long[] v)
1326         {
1327             if(v == null)
1328             {
1329                 writeSize(0);
1330             }
1331             else
1332             {
1333                 writeSize(v.Length);
1334                 expand(v.Length * 8);
1335                 _buf.b.putLongSeq(v);
1336             }
1337         }
1338 
1339         /// <summary>
1340         /// Writes a long sequence to the stream.
1341         /// </summary>
1342         /// <param name="count">The number of elements in the sequence.</param>
1343         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeLongSeq(int count, IEnumerable<long> v)1344         public void writeLongSeq(int count, IEnumerable<long> v)
1345         {
1346             if(count == 0)
1347             {
1348                 writeSize(0);
1349                 return;
1350             }
1351 
1352             {
1353                 List<long> value = v as List<long>;
1354                 if(value != null)
1355                 {
1356                     writeLongSeq(value.ToArray());
1357                     return;
1358                 }
1359             }
1360 
1361             {
1362                 LinkedList<long> value = v as LinkedList<long>;
1363                 if(value != null)
1364                 {
1365                     writeSize(count);
1366                     expand(count * 8);
1367                     IEnumerator<long> i = v.GetEnumerator();
1368                     while(i.MoveNext())
1369                     {
1370                         _buf.b.putLong(i.Current);
1371                     }
1372                     return;
1373                 }
1374             }
1375 
1376             {
1377                 Queue<long> value = v as Queue<long>;
1378                 if(value != null)
1379                 {
1380                     writeLongSeq(value.ToArray());
1381                     return;
1382                 }
1383             }
1384 
1385             {
1386                 Stack<long> value = v as Stack<long>;
1387                 if(value != null)
1388                 {
1389                     writeLongSeq(value.ToArray());
1390                     return;
1391                 }
1392             }
1393 
1394             writeSize(count);
1395             expand(count * 8);
1396             foreach(long l in v)
1397             {
1398                 _buf.b.putLong(l);
1399             }
1400         }
1401 
1402         /// <summary>
1403         /// Writes an optional long sequence to the stream.
1404         /// </summary>
1405         /// <param name="tag">The optional tag.</param>
1406         /// <param name="v">The optional long sequence to write to the stream.</param>
writeLongSeq(int tag, Optional<long[]> v)1407         public void writeLongSeq(int tag, Optional<long[]> v)
1408         {
1409             if(v.HasValue)
1410             {
1411                 writeLongSeq(tag, v.Value);
1412             }
1413         }
1414 
1415         /// <summary>
1416         /// Writes an optional long sequence to the stream.
1417         /// </summary>
1418         /// <param name="tag">The optional tag.</param>
1419         /// <param name="count">The number of elements in the sequence.</param>
1420         /// <param name="v">An enumerator for the optional long sequence.</param>
1421         public void writeLongSeq<T>(int tag, int count, Optional<T> v)
1422             where T : IEnumerable<long>
1423         {
1424             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
1425             {
1426                 writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
1427                 writeLongSeq(count, v.Value);
1428             }
1429         }
1430 
1431         /// <summary>
1432         /// Writes an optional long sequence to the stream.
1433         /// </summary>
1434         /// <param name="tag">The optional tag.</param>
1435         /// <param name="v">The long sequence to write to the stream.</param>
writeLongSeq(int tag, long[] v)1436         public void writeLongSeq(int tag, long[] v)
1437         {
1438             if(writeOptional(tag, OptionalFormat.VSize))
1439             {
1440                 writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
1441                 writeLongSeq(v);
1442             }
1443         }
1444 
1445         /// <summary>
1446         /// Writes an optional long sequence to the stream.
1447         /// </summary>
1448         /// <param name="tag">The optional tag.</param>
1449         /// <param name="count">The number of elements in the sequence.</param>
1450         /// <param name="v">An enumerator for the long sequence.</param>
writeLongSeq(int tag, int count, IEnumerable<long> v)1451         public void writeLongSeq(int tag, int count, IEnumerable<long> v)
1452         {
1453             if(writeOptional(tag, OptionalFormat.VSize))
1454             {
1455                 writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
1456                 writeLongSeq(count, v);
1457             }
1458         }
1459 
1460         /// <summary>
1461         /// Writes a float to the stream.
1462         /// </summary>
1463         /// <param name="v">The float to write to the stream.</param>
writeFloat(float v)1464         public void writeFloat(float v)
1465         {
1466             expand(4);
1467             _buf.b.putFloat(v);
1468         }
1469 
1470         /// <summary>
1471         /// Writes an optional float to the stream.
1472         /// </summary>
1473         /// <param name="tag">The optional tag.</param>
1474         /// <param name="v">The optional float to write to the stream.</param>
writeFloat(int tag, Optional<float> v)1475         public void writeFloat(int tag, Optional<float> v)
1476         {
1477             if(v.HasValue)
1478             {
1479                 writeFloat(tag, v.Value);
1480             }
1481         }
1482 
1483         /// <summary>
1484         /// Writes an optional float to the stream.
1485         /// </summary>
1486         /// <param name="tag">The optional tag.</param>
1487         /// <param name="v">The float to write to the stream.</param>
writeFloat(int tag, float v)1488         public void writeFloat(int tag, float v)
1489         {
1490             if(writeOptional(tag, OptionalFormat.F4))
1491             {
1492                 writeFloat(v);
1493             }
1494         }
1495 
1496         /// <summary>
1497         /// Writes a float sequence to the stream.
1498         /// </summary>
1499         /// <param name="v">The float sequence to write to the stream.
1500         /// Passing null causes an empty sequence to be written to the stream.</param>
writeFloatSeq(float[] v)1501         public void writeFloatSeq(float[] v)
1502         {
1503             if(v == null)
1504             {
1505                 writeSize(0);
1506             }
1507             else
1508             {
1509                 writeSize(v.Length);
1510                 expand(v.Length * 4);
1511                 _buf.b.putFloatSeq(v);
1512             }
1513         }
1514 
1515         /// <summary>
1516         /// Writes a float sequence to the stream.
1517         /// </summary>
1518         /// <param name="count">The number of elements in the sequence.</param>
1519         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeFloatSeq(int count, IEnumerable<float> v)1520         public void writeFloatSeq(int count, IEnumerable<float> v)
1521         {
1522             if(count == 0)
1523             {
1524                 writeSize(0);
1525                 return;
1526             }
1527 
1528             {
1529                 List<float> value = v as List<float>;
1530                 if(value != null)
1531                 {
1532                     writeFloatSeq(value.ToArray());
1533                     return;
1534                 }
1535             }
1536 
1537             {
1538                 LinkedList<float> value = v as LinkedList<float>;
1539                 if(value != null)
1540                 {
1541                     writeSize(count);
1542                     expand(count * 4);
1543                     IEnumerator<float> i = v.GetEnumerator();
1544                     while(i.MoveNext())
1545                     {
1546                         _buf.b.putFloat(i.Current);
1547                     }
1548                     return;
1549                 }
1550             }
1551 
1552             {
1553                 Queue<float> value = v as Queue<float>;
1554                 if(value != null)
1555                 {
1556                     writeFloatSeq(value.ToArray());
1557                     return;
1558                 }
1559             }
1560 
1561             {
1562                 Stack<float> value = v as Stack<float>;
1563                 if(value != null)
1564                 {
1565                     writeFloatSeq(value.ToArray());
1566                     return;
1567                 }
1568             }
1569 
1570             writeSize(count);
1571             expand(count * 4);
1572             foreach(float f in v)
1573             {
1574                 _buf.b.putFloat(f);
1575             }
1576         }
1577 
1578         /// <summary>
1579         /// Writes an optional float sequence to the stream.
1580         /// </summary>
1581         /// <param name="tag">The optional tag.</param>
1582         /// <param name="v">The optional float sequence to write to the stream.</param>
writeFloatSeq(int tag, Optional<float[]> v)1583         public void writeFloatSeq(int tag, Optional<float[]> v)
1584         {
1585             if(v.HasValue)
1586             {
1587                 writeFloatSeq(tag, v.Value);
1588             }
1589         }
1590 
1591         /// <summary>
1592         /// Writes an optional float sequence to the stream.
1593         /// </summary>
1594         /// <param name="tag">The optional tag.</param>
1595         /// <param name="count">The number of elements in the sequence.</param>
1596         /// <param name="v">An enumerator for the optional float sequence.</param>
1597         public void writeFloatSeq<T>(int tag, int count, Optional<T> v)
1598             where T : IEnumerable<float>
1599         {
1600             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
1601             {
1602                 writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
1603                 writeFloatSeq(count, v.Value);
1604             }
1605         }
1606 
1607         /// <summary>
1608         /// Writes an optional float sequence to the stream.
1609         /// </summary>
1610         /// <param name="tag">The optional tag.</param>
1611         /// <param name="v">The float sequence to write to the stream.</param>
writeFloatSeq(int tag, float[] v)1612         public void writeFloatSeq(int tag, float[] v)
1613         {
1614             if(writeOptional(tag, OptionalFormat.VSize))
1615             {
1616                 writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
1617                 writeFloatSeq(v);
1618             }
1619         }
1620 
1621         /// <summary>
1622         /// Writes an optional float sequence to the stream.
1623         /// </summary>
1624         /// <param name="tag">The optional tag.</param>
1625         /// <param name="count">The number of elements in the sequence.</param>
1626         /// <param name="v">An enumerator for the float sequence.</param>
writeFloatSeq(int tag, int count, IEnumerable<float> v)1627         public void writeFloatSeq(int tag, int count, IEnumerable<float> v)
1628         {
1629             if(writeOptional(tag, OptionalFormat.VSize))
1630             {
1631                 writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
1632                 writeFloatSeq(count, v);
1633             }
1634         }
1635 
1636         /// <summary>
1637         /// Writes a double to the stream.
1638         /// </summary>
1639         /// <param name="v">The double to write to the stream.</param>
writeDouble(double v)1640         public void writeDouble(double v)
1641         {
1642             expand(8);
1643             _buf.b.putDouble(v);
1644         }
1645 
1646         /// <summary>
1647         /// Writes an optional double to the stream.
1648         /// </summary>
1649         /// <param name="tag">The optional tag.</param>
1650         /// <param name="v">The optional double to write to the stream.</param>
writeDouble(int tag, Optional<double> v)1651         public void writeDouble(int tag, Optional<double> v)
1652         {
1653             if(v.HasValue)
1654             {
1655                 writeDouble(tag, v.Value);
1656             }
1657         }
1658 
1659         /// <summary>
1660         /// Writes an optional double to the stream.
1661         /// </summary>
1662         /// <param name="tag">The optional tag.</param>
1663         /// <param name="v">The double to write to the stream.</param>
writeDouble(int tag, double v)1664         public void writeDouble(int tag, double v)
1665         {
1666             if(writeOptional(tag, OptionalFormat.F8))
1667             {
1668                 writeDouble(v);
1669             }
1670         }
1671 
1672         /// <summary>
1673         /// Writes a double sequence to the stream.
1674         /// </summary>
1675         /// <param name="v">The double sequence to write to the stream.
1676         /// Passing null causes an empty sequence to be written to the stream.</param>
writeDoubleSeq(double[] v)1677         public void writeDoubleSeq(double[] v)
1678         {
1679             if(v == null)
1680             {
1681                 writeSize(0);
1682             }
1683             else
1684             {
1685                 writeSize(v.Length);
1686                 expand(v.Length * 8);
1687                 _buf.b.putDoubleSeq(v);
1688             }
1689         }
1690 
1691         /// <summary>
1692         /// Writes a double sequence to the stream.
1693         /// </summary>
1694         /// <param name="count">The number of elements in the sequence.</param>
1695         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeDoubleSeq(int count, IEnumerable<double> v)1696         public void writeDoubleSeq(int count, IEnumerable<double> v)
1697         {
1698             if(count == 0)
1699             {
1700                 writeSize(0);
1701                 return;
1702             }
1703 
1704             {
1705                 List<double> value = v as List<double>;
1706                 if(value != null)
1707                 {
1708                     writeDoubleSeq(value.ToArray());
1709                     return;
1710                 }
1711             }
1712 
1713             {
1714                 LinkedList<double> value = v as LinkedList<double>;
1715                 if(value != null)
1716                 {
1717                     writeSize(count);
1718                     expand(count * 8);
1719                     IEnumerator<double> i = v.GetEnumerator();
1720                     while(i.MoveNext())
1721                     {
1722                         _buf.b.putDouble(i.Current);
1723                     }
1724                     return;
1725                 }
1726             }
1727 
1728             {
1729                 Queue<double> value = v as Queue<double>;
1730                 if(value != null)
1731                 {
1732                     writeDoubleSeq(value.ToArray());
1733                     return;
1734                 }
1735             }
1736 
1737             {
1738                 Stack<double> value = v as Stack<double>;
1739                 if (value != null)
1740                 {
1741                     writeDoubleSeq(value.ToArray());
1742                     return;
1743                 }
1744             }
1745 
1746             writeSize(count);
1747             expand(count * 8);
1748             foreach(double d in v)
1749             {
1750                 _buf.b.putDouble(d);
1751             }
1752         }
1753 
1754         /// <summary>
1755         /// Writes an optional double sequence to the stream.
1756         /// </summary>
1757         /// <param name="tag">The optional tag.</param>
1758         /// <param name="v">The optional double sequence to write to the stream.</param>
writeDoubleSeq(int tag, Optional<double[]> v)1759         public void writeDoubleSeq(int tag, Optional<double[]> v)
1760         {
1761             if(v.HasValue)
1762             {
1763                 writeDoubleSeq(tag, v.Value);
1764             }
1765         }
1766 
1767         /// <summary>
1768         /// Writes an optional double sequence to the stream.
1769         /// </summary>
1770         /// <param name="tag">The optional tag.</param>
1771         /// <param name="count">The number of elements in the sequence.</param>
1772         /// <param name="v">An enumerator for the optional double sequence.</param>
1773         public void writeDoubleSeq<T>(int tag, int count, Optional<T> v)
1774             where T : IEnumerable<double>
1775         {
1776             if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
1777             {
1778                 writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
1779                 writeDoubleSeq(count, v.Value);
1780             }
1781         }
1782 
1783         /// <summary>
1784         /// Writes an optional double sequence to the stream.
1785         /// </summary>
1786         /// <param name="tag">The optional tag.</param>
1787         /// <param name="v">The double sequence to write to the stream.</param>
writeDoubleSeq(int tag, double[] v)1788         public void writeDoubleSeq(int tag, double[] v)
1789         {
1790             if(writeOptional(tag, OptionalFormat.VSize))
1791             {
1792                 writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
1793                 writeDoubleSeq(v);
1794             }
1795         }
1796 
1797         /// <summary>
1798         /// Writes an optional double sequence to the stream.
1799         /// </summary>
1800         /// <param name="tag">The optional tag.</param>
1801         /// <param name="count">The number of elements in the sequence.</param>
1802         /// <param name="v">An enumerator for the double sequence.</param>
writeDoubleSeq(int tag, int count, IEnumerable<double> v)1803         public void writeDoubleSeq(int tag, int count, IEnumerable<double> v)
1804         {
1805             if(writeOptional(tag, OptionalFormat.VSize))
1806             {
1807                 writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
1808                 writeDoubleSeq(count, v);
1809             }
1810         }
1811 
1812         private static System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true);
1813 
1814         /// <summary>
1815         /// Writes a string to the stream.
1816         /// </summary>
1817         /// <param name="v">The string to write to the stream. Passing null causes
1818         /// an empty string to be written to the stream.</param>
writeString(string v)1819         public void writeString(string v)
1820         {
1821             if(v == null || v.Length == 0)
1822             {
1823                 writeSize(0);
1824                 return;
1825             }
1826             byte[] arr = utf8.GetBytes(v);
1827             writeSize(arr.Length);
1828             expand(arr.Length);
1829             _buf.b.put(arr);
1830         }
1831 
1832         /// <summary>
1833         /// Writes an optional string to the stream.
1834         /// </summary>
1835         /// <param name="tag">The optional tag.</param>
1836         /// <param name="v">The optional string to write to the stream.</param>
writeString(int tag, Optional<string> v)1837         public void writeString(int tag, Optional<string> v)
1838         {
1839             if(v.HasValue)
1840             {
1841                 writeString(tag, v.Value);
1842             }
1843         }
1844 
1845         /// <summary>
1846         /// Writes an optional string to the stream.
1847         /// </summary>
1848         /// <param name="tag">The optional tag.</param>
1849         /// <param name="v">The string to write to the stream.</param>
writeString(int tag, string v)1850         public void writeString(int tag, string v)
1851         {
1852             if(writeOptional(tag, OptionalFormat.VSize))
1853             {
1854                 writeString(v);
1855             }
1856         }
1857 
1858         /// <summary>
1859         /// Writes a string sequence to the stream.
1860         /// </summary>
1861         /// <param name="v">The string sequence to write to the stream.
1862         /// Passing null causes an empty sequence to be written to the stream.</param>
writeStringSeq(string[] v)1863         public void writeStringSeq(string[] v)
1864         {
1865             if(v == null)
1866             {
1867                 writeSize(0);
1868             }
1869             else
1870             {
1871                 writeSize(v.Length);
1872                 for(int i = 0; i < v.Length; i++)
1873                 {
1874                     writeString(v[i]);
1875                 }
1876             }
1877         }
1878 
1879         /// <summary>
1880         /// Writes a string sequence to the stream.
1881         /// </summary>
1882         /// <param name="count">The number of elements in the sequence.</param>
1883         /// <param name="v">An enumerator for the container holding the sequence.</param>
writeStringSeq(int count, IEnumerable<string> v)1884         public void writeStringSeq(int count, IEnumerable<string> v)
1885         {
1886             writeSize(count);
1887             if(count != 0)
1888             {
1889                 foreach(string s in v)
1890                 {
1891                     writeString(s);
1892                 }
1893             }
1894         }
1895 
1896         /// <summary>
1897         /// Writes an optional string sequence to the stream.
1898         /// </summary>
1899         /// <param name="tag">The optional tag.</param>
1900         /// <param name="v">The optional string sequence to write to the stream.</param>
writeStringSeq(int tag, Optional<string[]> v)1901         public void writeStringSeq(int tag, Optional<string[]> v)
1902         {
1903             if(v.HasValue)
1904             {
1905                 writeStringSeq(tag, v.Value);
1906             }
1907         }
1908 
1909         /// <summary>
1910         /// Writes an optional string sequence to the stream.
1911         /// </summary>
1912         /// <param name="tag">The optional tag.</param>
1913         /// <param name="count">The number of elements in the sequence.</param>
1914         /// <param name="v">An enumerator for the optional string sequence.</param>
1915         public void writeStringSeq<T>(int tag, int count, Optional<T> v)
1916             where T : IEnumerable<string>
1917         {
1918             if(v.HasValue && writeOptional(tag, OptionalFormat.FSize))
1919             {
1920                 int pos = startSize();
1921                 writeStringSeq(count, v.Value);
1922                 endSize(pos);
1923             }
1924         }
1925 
1926         /// <summary>
1927         /// Writes an optional string sequence to the stream.
1928         /// </summary>
1929         /// <param name="tag">The optional tag.</param>
1930         /// <param name="v">The string sequence to write to the stream.</param>
writeStringSeq(int tag, string[] v)1931         public void writeStringSeq(int tag, string[] v)
1932         {
1933             if(writeOptional(tag, OptionalFormat.FSize))
1934             {
1935                 int pos = startSize();
1936                 writeStringSeq(v);
1937                 endSize(pos);
1938             }
1939         }
1940 
1941         /// <summary>
1942         /// Writes an optional string sequence to the stream.
1943         /// </summary>
1944         /// <param name="tag">The optional tag.</param>
1945         /// <param name="count">The number of elements in the sequence.</param>
1946         /// <param name="v">An enumerator for the string sequence.</param>
writeStringSeq(int tag, int count, IEnumerable<string> v)1947         public void writeStringSeq(int tag, int count, IEnumerable<string> v)
1948         {
1949             if(writeOptional(tag, OptionalFormat.FSize))
1950             {
1951                 int pos = startSize();
1952                 writeStringSeq(count, v);
1953                 endSize(pos);
1954             }
1955         }
1956 
1957         /// <summary>
1958         /// Writes a proxy to the stream.
1959         /// </summary>
1960         /// <param name="v">The proxy to write.</param>
writeProxy(ObjectPrx v)1961         public void writeProxy(ObjectPrx v)
1962         {
1963             if(v != null)
1964             {
1965                 v.iceWrite(this);
1966             }
1967             else
1968             {
1969                 Identity ident = new Identity();
1970                 ident.ice_writeMembers(this);
1971             }
1972         }
1973 
1974         /// <summary>
1975         /// Writes an optional proxy to the stream.
1976         /// </summary>
1977         /// <param name="tag">The optional tag.</param>
1978         /// <param name="v">The optional proxy to write.</param>
writeProxy(int tag, Optional<ObjectPrx> v)1979         public void writeProxy(int tag, Optional<ObjectPrx> v)
1980         {
1981             if(v.HasValue)
1982             {
1983                 writeProxy(tag, v.Value);
1984             }
1985         }
1986 
1987         /// <summary>
1988         /// Writes an optional proxy to the stream.
1989         /// </summary>
1990         /// <param name="tag">The optional tag.</param>
1991         /// <param name="v">The proxy to write.</param>
writeProxy(int tag, ObjectPrx v)1992         public void writeProxy(int tag, ObjectPrx v)
1993         {
1994             if(writeOptional(tag, OptionalFormat.FSize))
1995             {
1996                 int pos = startSize();
1997                 writeProxy(v);
1998                 endSize(pos);
1999             }
2000         }
2001 
2002         /// <summary>
2003         /// Writes an enumerated value.
2004         /// </summary>
2005         /// <param name="v">The enumerator.</param>
2006         /// <param name="maxValue">The maximum enumerator value in the definition.</param>
writeEnum(int v, int maxValue)2007         public void writeEnum(int v, int maxValue)
2008         {
2009             if(isEncoding_1_0())
2010             {
2011                 if(maxValue < 127)
2012                 {
2013                     writeByte((byte)v);
2014                 }
2015                 else if(maxValue < 32767)
2016                 {
2017                     writeShort((short)v);
2018                 }
2019                 else
2020                 {
2021                     writeInt(v);
2022                 }
2023             }
2024             else
2025             {
2026                 writeSize(v);
2027             }
2028         }
2029 
2030         /// <summary>
2031         /// Writes an optional enumerator to the stream.
2032         /// </summary>
2033         /// <param name="tag">The optional tag.</param>
2034         /// <param name="v">The enumerator.</param>
2035         /// <param name="maxValue">The maximum enumerator value in the definition.</param>
writeEnum(int tag, int v, int maxValue)2036         public void writeEnum(int tag, int v, int maxValue)
2037         {
2038             if(writeOptional(tag, OptionalFormat.Size))
2039             {
2040                 writeEnum(v, maxValue);
2041             }
2042         }
2043 
2044         /// <summary>
2045         /// Writes a class instance to the stream.
2046         /// </summary>
2047         /// <param name="v">The value to write. This method writes the index of an instance; the state of the value is
2048         /// written once writePendingValues() is called.</param>
writeValue(Value v)2049         public void writeValue(Value v)
2050         {
2051             initEncaps();
2052             _encapsStack.encoder.writeValue(v);
2053         }
2054 
2055         /// <summary>
2056         /// Writes an optional class instance to the stream.
2057         /// </summary>
2058         /// <param name="tag">The optional tag.</param>
2059         /// <param name="v">The optional value to write.</param>
2060         public void writeValue<T>(int tag, Optional<T> v) where T : Value
2061         {
2062             if(v.HasValue)
2063             {
2064                 writeValue(tag, v.Value);
2065             }
2066         }
2067 
2068         /// <summary>
2069         /// Writes an optional class instance to the stream.
2070         /// </summary>
2071         /// <param name="tag">The optional tag.</param>
2072         /// <param name="v">The value to write.</param>
writeValue(int tag, Value v)2073         public void writeValue(int tag, Value v)
2074         {
2075             if(writeOptional(tag, OptionalFormat.Class))
2076             {
2077                 writeValue(v);
2078             }
2079         }
2080 
2081         /// <summary>
2082         /// Writes a user exception to the stream.
2083         /// </summary>
2084         /// <param name="v">The user exception to write.</param>
writeException(UserException v)2085         public void writeException(UserException v)
2086         {
2087             initEncaps();
2088             _encapsStack.encoder.writeException(v);
2089         }
2090 
writeOptionalImpl(int tag, OptionalFormat format)2091         private bool writeOptionalImpl(int tag, OptionalFormat format)
2092         {
2093             if(isEncoding_1_0())
2094             {
2095                 return false; // Optional members aren't supported with the 1.0 encoding.
2096             }
2097 
2098             int v = (int)format;
2099             if(tag < 30)
2100             {
2101                 v |= tag << 3;
2102                 writeByte((byte)v);
2103             }
2104             else
2105             {
2106                 v |= 0x0F0; // tag = 30
2107                 writeByte((byte)v);
2108                 writeSize(tag);
2109             }
2110             return true;
2111         }
2112 
2113         /// <summary>
2114         /// Determines the current position in the stream.
2115         /// </summary>
2116         /// <returns>The current position.</returns>
pos()2117         public int pos()
2118         {
2119             return _buf.b.position();
2120         }
2121 
2122         /// <summary>
2123         /// Sets the current position in the stream.
2124         /// </summary>
2125         /// <param name="n">The new position.</param>
pos(int n)2126         public void pos(int n)
2127         {
2128             _buf.b.position(n);
2129         }
2130 
2131         /// <summary>
2132         /// Determines the current size of the stream.
2133         /// </summary>
2134         /// <returns>The current size.</returns>
size()2135         public int size()
2136         {
2137             return _buf.size();
2138         }
2139 
2140         /// <summary>
2141         /// Determines whether the stream is empty.
2142         /// </summary>
2143         /// <returns>True if no data has been written yet, false otherwise.</returns>
isEmpty()2144         public bool isEmpty()
2145         {
2146             return _buf.empty();
2147         }
2148 
2149         /// <summary>
2150         /// Expand the stream to accept more data.
2151         /// </summary>
2152         /// <param name="n">The number of bytes to accommodate in the stream.</param>
expand(int n)2153         public void expand(int n)
2154         {
2155             _buf.expand(n);
2156         }
2157 
2158         private IceInternal.Instance _instance;
2159         private IceInternal.Buffer _buf;
2160         private object _closure;
2161         private FormatType _format;
2162 
2163         private enum SliceType { NoSlice, ValueSlice, ExceptionSlice }
2164 
2165         abstract private class EncapsEncoder
2166         {
EncapsEncoder(OutputStream stream, Encaps encaps)2167             protected EncapsEncoder(OutputStream stream, Encaps encaps)
2168             {
2169                 _stream = stream;
2170                 _encaps = encaps;
2171                 _typeIdIndex = 0;
2172                 _marshaledMap = new Dictionary<Value, int>();
2173             }
2174 
writeValue(Value v)2175             internal abstract void writeValue(Value v);
writeException(UserException v)2176             internal abstract void writeException(UserException v);
2177 
startInstance(SliceType type, SlicedData data)2178             internal abstract void startInstance(SliceType type, SlicedData data);
endInstance()2179             internal abstract void endInstance();
startSlice(string typeId, int compactId, bool last)2180             internal abstract void startSlice(string typeId, int compactId, bool last);
endSlice()2181             internal abstract void endSlice();
2182 
writeOptional(int tag, OptionalFormat format)2183             internal virtual bool writeOptional(int tag, OptionalFormat format)
2184             {
2185                 return false;
2186             }
2187 
writePendingValues()2188             internal virtual void writePendingValues()
2189             {
2190             }
2191 
registerTypeId(string typeId)2192             protected int registerTypeId(string typeId)
2193             {
2194                 if(_typeIdMap == null)
2195                 {
2196                     _typeIdMap = new Dictionary<string, int>();
2197                 }
2198 
2199                 int p;
2200                 if(_typeIdMap.TryGetValue(typeId, out p))
2201                 {
2202                     return p;
2203                 }
2204                 else
2205                 {
2206                     _typeIdMap.Add(typeId, ++_typeIdIndex);
2207                     return -1;
2208                 }
2209             }
2210 
2211             protected readonly OutputStream _stream;
2212             protected readonly Encaps _encaps;
2213 
2214             // Encapsulation attributes for instance marshaling.
2215             protected readonly Dictionary<Value, int> _marshaledMap;
2216 
2217             // Encapsulation attributes for instance marshaling.
2218             private Dictionary<string, int> _typeIdMap;
2219             private int _typeIdIndex;
2220         }
2221 
2222         private sealed class EncapsEncoder10 : EncapsEncoder
2223         {
EncapsEncoder10(OutputStream stream, Encaps encaps)2224             internal EncapsEncoder10(OutputStream stream, Encaps encaps) : base(stream, encaps)
2225             {
2226                 _sliceType = SliceType.NoSlice;
2227                 _valueIdIndex = 0;
2228                 _toBeMarshaledMap = new Dictionary<Value, int>();
2229             }
2230 
writeValue(Value v)2231             internal override void writeValue(Value v)
2232             {
2233                 //
2234                 // Object references are encoded as a negative integer in 1.0.
2235                 //
2236                 if(v != null)
2237                 {
2238                     _stream.writeInt(-registerValue(v));
2239                 }
2240                 else
2241                 {
2242                     _stream.writeInt(0);
2243                 }
2244             }
2245 
writeException(UserException v)2246             internal override void writeException(UserException v)
2247             {
2248                 //
2249                 // User exception with the 1.0 encoding start with a bool
2250                 // flag that indicates whether or not the exception uses
2251                 // classes.
2252                 //
2253                 // This allows reading the pending instances even if some part of
2254                 // the exception was sliced.
2255                 //
2256                 bool usesClasses = v.iceUsesClasses();
2257                 _stream.writeBool(usesClasses);
2258                 v.iceWrite(_stream);
2259                 if(usesClasses)
2260                 {
2261                     writePendingValues();
2262                 }
2263             }
2264 
startInstance(SliceType sliceType, SlicedData sliceData)2265             internal override void startInstance(SliceType sliceType, SlicedData sliceData)
2266             {
2267                 _sliceType = sliceType;
2268             }
2269 
endInstance()2270             internal override void endInstance()
2271             {
2272                 if(_sliceType == SliceType.ValueSlice)
2273                 {
2274                     //
2275                     // Write the Object slice.
2276                     //
2277                     startSlice(Value.ice_staticId(), -1, true);
2278                     _stream.writeSize(0); // For compatibility with the old AFM.
2279                     endSlice();
2280                 }
2281                 _sliceType = SliceType.NoSlice;
2282             }
2283 
startSlice(string typeId, int compactId, bool last)2284             internal override void startSlice(string typeId, int compactId, bool last)
2285             {
2286                 //
2287                 // For instance slices, encode a bool to indicate how the type ID
2288                 // is encoded and the type ID either as a string or index. For
2289                 // exception slices, always encode the type ID as a string.
2290                 //
2291                 if(_sliceType == SliceType.ValueSlice)
2292                 {
2293                     int index = registerTypeId(typeId);
2294                     if(index < 0)
2295                     {
2296                         _stream.writeBool(false);
2297                         _stream.writeString(typeId);
2298                     }
2299                     else
2300                     {
2301                         _stream.writeBool(true);
2302                         _stream.writeSize(index);
2303                     }
2304                 }
2305                 else
2306                 {
2307                     _stream.writeString(typeId);
2308                 }
2309 
2310                 _stream.writeInt(0); // Placeholder for the slice length.
2311 
2312                 _writeSlice = _stream.pos();
2313             }
2314 
endSlice()2315             internal override void endSlice()
2316             {
2317                 //
2318                 // Write the slice length.
2319                 //
2320                 int sz = _stream.pos() - _writeSlice + 4;
2321                 _stream.rewriteInt(sz, _writeSlice - 4);
2322             }
2323 
writePendingValues()2324             internal override void writePendingValues()
2325             {
2326                 while(_toBeMarshaledMap.Count > 0)
2327                 {
2328                     //
2329                     // Consider the to be marshalled instances as marshalled now,
2330                     // this is necessary to avoid adding again the "to be
2331                     // marshalled instances" into _toBeMarshaledMap while writing
2332                     // instances.
2333                     //
2334                     foreach(var e in _toBeMarshaledMap)
2335                     {
2336                         _marshaledMap.Add(e.Key, e.Value);
2337                     }
2338 
2339                     var savedMap = _toBeMarshaledMap;
2340                     _toBeMarshaledMap = new Dictionary<Value, int>();
2341                     _stream.writeSize(savedMap.Count);
2342                     foreach(var p in savedMap)
2343                     {
2344                         //
2345                         // Ask the instance to marshal itself. Any new class
2346                         // instances that are triggered by the classes marshaled
2347                         // are added to toBeMarshaledMap.
2348                         //
2349                         _stream.writeInt(p.Value);
2350 
2351                         try
2352                         {
2353                             p.Key.ice_preMarshal();
2354                         }
2355                         catch(System.Exception ex)
2356                         {
2357                             string s = "exception raised by ice_preMarshal:\n" + ex;
2358                             _stream.instance().initializationData().logger.warning(s);
2359                         }
2360 
2361                         p.Key.iceWrite(_stream);
2362                     }
2363                 }
2364                 _stream.writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
2365             }
2366 
registerValue(Value v)2367             private int registerValue(Value v)
2368             {
2369                 Debug.Assert(v != null);
2370 
2371                 //
2372                 // Look for this instance in the to-be-marshaled map.
2373                 //
2374                 int p;
2375                 if(_toBeMarshaledMap.TryGetValue(v, out p))
2376                 {
2377                     return p;
2378                 }
2379 
2380                 //
2381                 // Didn't find it, try the marshaled map next.
2382                 //
2383                 if(_marshaledMap.TryGetValue(v, out p))
2384                 {
2385                     return p;
2386                 }
2387 
2388                 //
2389                 // We haven't seen this instance previously, create a new
2390                 // index, and insert it into the to-be-marshaled map.
2391                 //
2392                 _toBeMarshaledMap.Add(v, ++_valueIdIndex);
2393                 return _valueIdIndex;
2394             }
2395 
2396             // Instance attributes
2397             private SliceType _sliceType;
2398 
2399             // Slice attributes
2400             private int _writeSlice;        // Position of the slice data members
2401 
2402             // Encapsulation attributes for instance marshaling.
2403             private int _valueIdIndex;
2404             private Dictionary<Value, int> _toBeMarshaledMap;
2405         }
2406 
2407         private sealed class EncapsEncoder11 : EncapsEncoder
2408         {
EncapsEncoder11(OutputStream stream, Encaps encaps)2409             internal EncapsEncoder11(OutputStream stream, Encaps encaps) : base(stream, encaps)
2410             {
2411                 _current = null;
2412                 _valueIdIndex = 1;
2413             }
2414 
writeValue(Value v)2415             internal override void writeValue(Value v)
2416             {
2417                 if(v == null)
2418                 {
2419                     _stream.writeSize(0);
2420                 }
2421                 else if(_current != null && _encaps.format == FormatType.SlicedFormat)
2422                 {
2423                     if(_current.indirectionTable == null)
2424                     {
2425                         _current.indirectionTable = new List<Value>();
2426                         _current.indirectionMap = new Dictionary<Value, int>();
2427                     }
2428 
2429                     //
2430                     // If writing an instance within a slice and using the sliced
2431                     // format, write an index from the instance indirection table.
2432                     //
2433                     int index;
2434                     if(!_current.indirectionMap.TryGetValue(v, out index))
2435                     {
2436                         _current.indirectionTable.Add(v);
2437                         int idx = _current.indirectionTable.Count; // Position + 1 (0 is reserved for nil)
2438                         _current.indirectionMap.Add(v, idx);
2439                         _stream.writeSize(idx);
2440                     }
2441                     else
2442                     {
2443                         _stream.writeSize(index);
2444                     }
2445                 }
2446                 else
2447                 {
2448                     writeInstance(v); // Write the instance or a reference if already marshaled.
2449                 }
2450             }
2451 
writeException(UserException v)2452             internal override void writeException(UserException v)
2453             {
2454                 v.iceWrite(_stream);
2455             }
2456 
startInstance(SliceType sliceType, SlicedData data)2457             internal override void startInstance(SliceType sliceType, SlicedData data)
2458             {
2459                 if(_current == null)
2460                 {
2461                     _current = new InstanceData(null);
2462                 }
2463                 else
2464                 {
2465                     _current = _current.next == null ? new InstanceData(_current) : _current.next;
2466                 }
2467                 _current.sliceType = sliceType;
2468                 _current.firstSlice = true;
2469 
2470                 if(data != null)
2471                 {
2472                     writeSlicedData(data);
2473                 }
2474             }
2475 
endInstance()2476             internal override void endInstance()
2477             {
2478                 _current = _current.previous;
2479             }
2480 
startSlice(string typeId, int compactId, bool last)2481             internal override void startSlice(string typeId, int compactId, bool last)
2482             {
2483                 Debug.Assert((_current.indirectionTable == null || _current.indirectionTable.Count == 0) &&
2484                              (_current.indirectionMap == null || _current.indirectionMap.Count == 0));
2485 
2486                 _current.sliceFlagsPos = _stream.pos();
2487 
2488                 _current.sliceFlags = 0;
2489                 if(_encaps.format == FormatType.SlicedFormat)
2490                 {
2491                     //
2492                     // Encode the slice size if using the sliced format.
2493                     //
2494                     _current.sliceFlags |= Protocol.FLAG_HAS_SLICE_SIZE;
2495                 }
2496                 if(last)
2497                 {
2498                     _current.sliceFlags |= Protocol.FLAG_IS_LAST_SLICE; // This is the last slice.
2499                 }
2500 
2501                 _stream.writeByte(0); // Placeholder for the slice flags
2502 
2503                 //
2504                 // For instance slices, encode the flag and the type ID either as a
2505                 // string or index. For exception slices, always encode the type
2506                 // ID a string.
2507                 //
2508                 if(_current.sliceType == SliceType.ValueSlice)
2509                 {
2510                     //
2511                     // Encode the type ID (only in the first slice for the compact
2512                     // encoding).
2513                     //
2514                     if(_encaps.format == FormatType.SlicedFormat || _current.firstSlice)
2515                     {
2516                         if(compactId >= 0)
2517                         {
2518                             _current.sliceFlags |= Protocol.FLAG_HAS_TYPE_ID_COMPACT;
2519                             _stream.writeSize(compactId);
2520                         }
2521                         else
2522                         {
2523                             int index = registerTypeId(typeId);
2524                             if(index < 0)
2525                             {
2526                                 _current.sliceFlags |= Protocol.FLAG_HAS_TYPE_ID_STRING;
2527                                 _stream.writeString(typeId);
2528                             }
2529                             else
2530                             {
2531                                 _current.sliceFlags |= Protocol.FLAG_HAS_TYPE_ID_INDEX;
2532                                 _stream.writeSize(index);
2533                             }
2534                         }
2535                     }
2536                 }
2537                 else
2538                 {
2539                     _stream.writeString(typeId);
2540                 }
2541 
2542                 if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
2543                 {
2544                     _stream.writeInt(0); // Placeholder for the slice length.
2545                 }
2546 
2547                 _current.writeSlice = _stream.pos();
2548                 _current.firstSlice = false;
2549             }
2550 
endSlice()2551             internal override void endSlice()
2552             {
2553                 //
2554                 // Write the optional member end marker if some optional members
2555                 // were encoded. Note that the optional members are encoded before
2556                 // the indirection table and are included in the slice size.
2557                 //
2558                 if((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0)
2559                 {
2560                     _stream.writeByte(Protocol.OPTIONAL_END_MARKER);
2561                 }
2562 
2563                 //
2564                 // Write the slice length if necessary.
2565                 //
2566                 if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
2567                 {
2568                     int sz = _stream.pos() - _current.writeSlice + 4;
2569                     _stream.rewriteInt(sz, _current.writeSlice - 4);
2570                 }
2571 
2572                 //
2573                 // Only write the indirection table if it contains entries.
2574                 //
2575                 if(_current.indirectionTable != null && _current.indirectionTable.Count > 0)
2576                 {
2577                     Debug.Assert(_encaps.format == FormatType.SlicedFormat);
2578                     _current.sliceFlags |= Protocol.FLAG_HAS_INDIRECTION_TABLE;
2579 
2580                     //
2581                     // Write the indirect instance table.
2582                     //
2583                     _stream.writeSize(_current.indirectionTable.Count);
2584                     foreach(var v in _current.indirectionTable)
2585                     {
2586                         writeInstance(v);
2587                     }
2588                     _current.indirectionTable.Clear();
2589                     _current.indirectionMap.Clear();
2590                 }
2591 
2592                 //
2593                 // Finally, update the slice flags.
2594                 //
2595                 _stream.rewriteByte(_current.sliceFlags, _current.sliceFlagsPos);
2596             }
2597 
writeOptional(int tag, OptionalFormat format)2598             internal override bool writeOptional(int tag, OptionalFormat format)
2599             {
2600                 if(_current == null)
2601                 {
2602                     return _stream.writeOptionalImpl(tag, format);
2603                 }
2604                 else
2605                 {
2606                     if(_stream.writeOptionalImpl(tag, format))
2607                     {
2608                         _current.sliceFlags |= Protocol.FLAG_HAS_OPTIONAL_MEMBERS;
2609                         return true;
2610                     }
2611                     else
2612                     {
2613                         return false;
2614                     }
2615                 }
2616             }
2617 
writeSlicedData(SlicedData slicedData)2618             private void writeSlicedData(SlicedData slicedData)
2619             {
2620                 Debug.Assert(slicedData != null);
2621 
2622                 //
2623                 // We only remarshal preserved slices if we are using the sliced
2624                 // format. Otherwise, we ignore the preserved slices, which
2625                 // essentially "slices" the instance into the most-derived type
2626                 // known by the sender.
2627                 //
2628                 if(_encaps.format != FormatType.SlicedFormat)
2629                 {
2630                     return;
2631                 }
2632 
2633                 foreach(var info in slicedData.slices)
2634                 {
2635                     startSlice(info.typeId, info.compactId, info.isLastSlice);
2636 
2637                     //
2638                     // Write the bytes associated with this slice.
2639                     //
2640                     _stream.writeBlob(info.bytes);
2641 
2642                     if(info.hasOptionalMembers)
2643                     {
2644                         _current.sliceFlags |= Protocol.FLAG_HAS_OPTIONAL_MEMBERS;
2645                     }
2646 
2647                     //
2648                     // Make sure to also re-write the instance indirection table.
2649                     //
2650                     if(info.instances != null && info.instances.Length > 0)
2651                     {
2652                         if(_current.indirectionTable == null)
2653                         {
2654                             _current.indirectionTable = new List<Value>();
2655                             _current.indirectionMap = new Dictionary<Value, int>();
2656                         }
2657                         foreach(var o in info.instances)
2658                         {
2659                             _current.indirectionTable.Add(o);
2660                         }
2661                     }
2662 
2663                     endSlice();
2664                 }
2665             }
2666 
writeInstance(Value v)2667             private void writeInstance(Value v)
2668             {
2669                 Debug.Assert(v != null);
2670 
2671                 //
2672                 // If the instance was already marshaled, just write it's ID.
2673                 //
2674                 int p;
2675                 if(_marshaledMap.TryGetValue(v, out p))
2676                 {
2677                     _stream.writeSize(p);
2678                     return;
2679                 }
2680 
2681                 //
2682                 // We haven't seen this instance previously, create a new ID,
2683                 // insert it into the marshaled map, and write the instance.
2684                 //
2685                 _marshaledMap.Add(v, ++_valueIdIndex);
2686 
2687                 try
2688                 {
2689                     v.ice_preMarshal();
2690                 }
2691                 catch(System.Exception ex)
2692                 {
2693                     string s = "exception raised by ice_preMarshal:\n" + ex;
2694                     _stream.instance().initializationData().logger.warning(s);
2695                 }
2696 
2697                 _stream.writeSize(1); // Object instance marker.
2698                 v.iceWrite(_stream);
2699             }
2700 
2701             private sealed class InstanceData
2702             {
InstanceData(InstanceData previous)2703                 internal InstanceData(InstanceData previous)
2704                 {
2705                     if(previous != null)
2706                     {
2707                         previous.next = this;
2708                     }
2709                     this.previous = previous;
2710                     next = null;
2711                 }
2712 
2713                 // Instance attributes
2714                 internal SliceType sliceType;
2715                 internal bool firstSlice;
2716 
2717                 // Slice attributes
2718                 internal byte sliceFlags;
2719                 internal int writeSlice;    // Position of the slice data members
2720                 internal int sliceFlagsPos; // Position of the slice flags
2721                 internal List<Value> indirectionTable;
2722                 internal Dictionary<Value, int> indirectionMap;
2723 
2724                 internal InstanceData previous;
2725                 internal InstanceData next;
2726             }
2727 
2728             private InstanceData _current;
2729 
2730             private int _valueIdIndex; // The ID of the next instance to marhsal
2731         }
2732 
2733         private sealed class Encaps
2734         {
reset()2735             internal void reset()
2736             {
2737                 encoder = null;
2738             }
2739 
setEncoding(EncodingVersion encoding)2740             internal void setEncoding(EncodingVersion encoding)
2741             {
2742                 this.encoding = encoding;
2743                 encoding_1_0 = encoding.Equals(Util.Encoding_1_0);
2744             }
2745 
2746             internal int start;
2747             internal EncodingVersion encoding;
2748             internal bool encoding_1_0;
2749             internal FormatType format = FormatType.DefaultFormat;
2750 
2751             internal EncapsEncoder encoder;
2752 
2753             internal Encaps next;
2754         }
2755 
2756         //
2757         // The encoding version to use when there's no encapsulation to
2758         // read from or write to. This is for example used to read message
2759         // headers or when the user is using the streaming API with no
2760         // encapsulation.
2761         //
2762         private EncodingVersion _encoding;
2763 
isEncoding_1_0()2764         private bool isEncoding_1_0()
2765         {
2766             return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0);
2767         }
2768 
2769         private Encaps _encapsStack;
2770         private Encaps _encapsCache;
2771 
initEncaps()2772         private void initEncaps()
2773         {
2774             if(_encapsStack == null) // Lazy initialization
2775             {
2776                 _encapsStack = _encapsCache;
2777                 if(_encapsStack != null)
2778                 {
2779                     _encapsCache = _encapsCache.next;
2780                 }
2781                 else
2782                 {
2783                     _encapsStack = new Encaps();
2784                 }
2785                 _encapsStack.setEncoding(_encoding);
2786             }
2787 
2788             if(_encapsStack.format == FormatType.DefaultFormat)
2789             {
2790                 _encapsStack.format = _instance.defaultsAndOverrides().defaultFormat;
2791             }
2792 
2793             if(_encapsStack.encoder == null) // Lazy initialization.
2794             {
2795                 if(_encapsStack.encoding_1_0)
2796                 {
2797                     _encapsStack.encoder = new EncapsEncoder10(this, _encapsStack);
2798                 }
2799                 else
2800                 {
2801                     _encapsStack.encoder = new EncapsEncoder11(this, _encapsStack);
2802                 }
2803             }
2804         }
2805     }
2806 
2807     /// <summary>
2808     /// Base class for writing class instances to an output stream.
2809     /// </summary>
2810     public abstract class ValueWriter : Value
2811     {
2812         /// <summary>
2813         /// Writes the state of this Slice class instance to an output stream.
2814         /// </summary>
2815         /// <param name="outStream">The stream to write to.</param>
write(OutputStream outStream)2816         public abstract void write(OutputStream outStream);
2817 
iceWrite(OutputStream os)2818         public override void iceWrite(OutputStream os)
2819         {
2820             write(os);
2821         }
2822 
iceRead(InputStream istr)2823         public override void iceRead(InputStream istr)
2824         {
2825             Debug.Assert(false);
2826         }
2827     }
2828 
2829 }
2830