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