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 /// Throws a UserException corresponding to the given Slice type Id, such as "::Module::MyException". 17 /// If the implementation does not throw an exception, the Ice run time will fall back 18 /// to using its default behavior for instantiating the user exception. 19 /// </summary> 20 /// <param name="id">A Slice type Id corresponding to a Slice user exception.</param> UserExceptionFactory(string id)21 public delegate void UserExceptionFactory(string id); 22 23 /// <summary> 24 /// Interface for input streams used to extract Slice types from a sequence of bytes. 25 /// </summary> 26 public class InputStream 27 { 28 29 /// <summary> 30 /// Constructing an InputStream without providing a communicator means the stream will 31 /// use the default encoding version. A communicator is required in order to unmarshal 32 /// proxies. You can supply a communicator later by calling initialize(). 33 /// </summary> InputStream()34 public InputStream() 35 { 36 initialize(Util.currentEncoding); 37 _buf = new IceInternal.Buffer(); 38 } 39 40 /// <summary> 41 /// Constructing an InputStream without providing a communicator means the stream will 42 /// use the default encoding version. A communicator is required in order to unmarshal 43 /// proxies. You can supply a communicator later by calling initialize(). 44 /// </summary> 45 /// <param name="data">The byte array containing encoded Slice types.</param> InputStream(byte[] data)46 public InputStream(byte[] data) 47 { 48 initialize(Util.currentEncoding); 49 _buf = new IceInternal.Buffer(data); 50 } 51 InputStream(IceInternal.ByteBuffer buf)52 public InputStream(IceInternal.ByteBuffer buf) 53 { 54 initialize(Util.currentEncoding); 55 _buf = new IceInternal.Buffer(buf); 56 } 57 InputStream(IceInternal.Buffer buf)58 public InputStream(IceInternal.Buffer buf) : 59 this(buf, false) 60 { 61 } 62 InputStream(IceInternal.Buffer buf, bool adopt)63 public InputStream(IceInternal.Buffer buf, bool adopt) 64 { 65 initialize(Util.currentEncoding); 66 _buf = new IceInternal.Buffer(buf, adopt); 67 } 68 69 /// <summary> 70 /// This constructor uses the communicator's default encoding version. 71 /// </summary> 72 /// <param name="communicator">The communicator to use when initializing the stream.</param> InputStream(Communicator communicator)73 public InputStream(Communicator communicator) 74 { 75 initialize(communicator); 76 _buf = new IceInternal.Buffer(); 77 } 78 79 /// <summary> 80 /// This constructor uses the communicator's default encoding version. 81 /// </summary> 82 /// <param name="communicator">The communicator to use when initializing the stream.</param> 83 /// <param name="data">The byte array containing encoded Slice types.</param> InputStream(Communicator communicator, byte[] data)84 public InputStream(Communicator communicator, byte[] data) 85 { 86 initialize(communicator); 87 _buf = new IceInternal.Buffer(data); 88 } 89 InputStream(Communicator communicator, IceInternal.ByteBuffer buf)90 public InputStream(Communicator communicator, IceInternal.ByteBuffer buf) 91 { 92 initialize(communicator); 93 _buf = new IceInternal.Buffer(buf); 94 } 95 InputStream(Communicator communicator, IceInternal.Buffer buf)96 public InputStream(Communicator communicator, IceInternal.Buffer buf) : 97 this(communicator, buf, false) 98 { 99 } 100 InputStream(Communicator communicator, IceInternal.Buffer buf, bool adopt)101 public InputStream(Communicator communicator, IceInternal.Buffer buf, bool adopt) 102 { 103 initialize(communicator); 104 _buf = new IceInternal.Buffer(buf, adopt); 105 } 106 107 /// <summary> 108 /// This constructor uses the given encoding version. 109 /// </summary> 110 /// <param name="encoding">The desired encoding version.</param> InputStream(EncodingVersion encoding)111 public InputStream(EncodingVersion encoding) 112 { 113 initialize(encoding); 114 _buf = new IceInternal.Buffer(); 115 } 116 117 /// <summary> 118 /// This constructor uses the given encoding version. 119 /// </summary> 120 /// <param name="encoding">The desired encoding version.</param> 121 /// <param name="data">The byte array containing encoded Slice types.</param> InputStream(EncodingVersion encoding, byte[] data)122 public InputStream(EncodingVersion encoding, byte[] data) 123 { 124 initialize(encoding); 125 _buf = new IceInternal.Buffer(data); 126 } 127 InputStream(EncodingVersion encoding, IceInternal.ByteBuffer buf)128 public InputStream(EncodingVersion encoding, IceInternal.ByteBuffer buf) 129 { 130 initialize(encoding); 131 _buf = new IceInternal.Buffer(buf); 132 } 133 InputStream(EncodingVersion encoding, IceInternal.Buffer buf)134 public InputStream(EncodingVersion encoding, IceInternal.Buffer buf) : 135 this(encoding, buf, false) 136 { 137 } 138 InputStream(EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)139 public InputStream(EncodingVersion encoding, IceInternal.Buffer buf, bool adopt) 140 { 141 initialize(encoding); 142 _buf = new IceInternal.Buffer(buf, adopt); 143 } 144 145 /// <summary> 146 /// This constructor uses the given encoding version. 147 /// </summary> 148 /// <param name="communicator">The communicator to use when initializing the stream.</param> 149 /// <param name="encoding">The desired encoding version.</param> InputStream(Communicator communicator, EncodingVersion encoding)150 public InputStream(Communicator communicator, EncodingVersion encoding) 151 { 152 initialize(communicator, encoding); 153 _buf = new IceInternal.Buffer(); 154 } 155 156 /// <summary> 157 /// This constructor uses the given encoding version. 158 /// </summary> 159 /// <param name="communicator">The communicator to use when initializing the stream.</param> 160 /// <param name="encoding">The desired encoding version.</param> 161 /// <param name="data">The byte array containing encoded Slice types.</param> InputStream(Communicator communicator, EncodingVersion encoding, byte[] data)162 public InputStream(Communicator communicator, EncodingVersion encoding, byte[] data) 163 { 164 initialize(communicator, encoding); 165 _buf = new IceInternal.Buffer(data); 166 } 167 InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.ByteBuffer buf)168 public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.ByteBuffer buf) 169 { 170 initialize(communicator, encoding); 171 _buf = new IceInternal.Buffer(buf); 172 } 173 InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf)174 public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf) : 175 this(communicator, encoding, buf, false) 176 { 177 } 178 InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)179 public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt) 180 { 181 initialize(communicator, encoding); 182 _buf = new IceInternal.Buffer(buf, adopt); 183 } 184 InputStream(IceInternal.Instance instance, EncodingVersion encoding)185 public InputStream(IceInternal.Instance instance, EncodingVersion encoding) 186 { 187 initialize(instance, encoding); 188 _buf = new IceInternal.Buffer(); 189 } 190 InputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data)191 public InputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data) 192 { 193 initialize(instance, encoding); 194 _buf = new IceInternal.Buffer(data); 195 } 196 InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.ByteBuffer buf)197 public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.ByteBuffer buf) 198 { 199 initialize(instance, encoding); 200 _buf = new IceInternal.Buffer(buf); 201 } 202 InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf)203 public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf) : 204 this(instance, encoding, buf, false) 205 { 206 } 207 InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)208 public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt) 209 { 210 initialize(instance, encoding); 211 _buf = new IceInternal.Buffer(buf, adopt); 212 } 213 214 /// <summary> 215 /// Initializes the stream to use the communicator's default encoding version. 216 /// </summary> 217 /// <param name="communicator">The communicator to use when initializing the stream.</param> initialize(Communicator communicator)218 public void initialize(Communicator communicator) 219 { 220 Debug.Assert(communicator != null); 221 IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); 222 initialize(instance, instance.defaultsAndOverrides().defaultEncoding); 223 } 224 225 /// <summary> 226 /// Initializes the stream to use the given communicator and encoding version. 227 /// </summary> 228 /// <param name="communicator">The communicator to use when initializing the stream.</param> 229 /// <param name="encoding">The desired encoding version.</param> initialize(Communicator communicator, EncodingVersion encoding)230 public void initialize(Communicator communicator, EncodingVersion encoding) 231 { 232 Debug.Assert(communicator != null); 233 IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); 234 initialize(instance, encoding); 235 } 236 initialize(IceInternal.Instance instance, EncodingVersion encoding)237 private void initialize(IceInternal.Instance instance, EncodingVersion encoding) 238 { 239 initialize(encoding); 240 241 _instance = instance; 242 _traceSlicing = _instance.traceLevels().slicing > 0; 243 _classGraphDepthMax = _instance.classGraphDepthMax(); 244 _valueFactoryManager = _instance.initializationData().valueFactoryManager; 245 _logger = _instance.initializationData().logger; 246 _classResolver = _instance.resolveClass; 247 } 248 initialize(EncodingVersion encoding)249 private void initialize(EncodingVersion encoding) 250 { 251 _instance = null; 252 _encoding = encoding; 253 _encapsStack = null; 254 _encapsCache = null; 255 _traceSlicing = false; 256 _classGraphDepthMax = 0x7fffffff; 257 _closure = null; 258 _sliceValues = true; 259 _startSeq = -1; 260 _minSeqSize = 0; 261 } 262 263 /// <summary> 264 /// Resets this stream. This method allows the stream to be reused, to avoid creating 265 /// unnecessary garbage. 266 /// </summary> reset()267 public void reset() 268 { 269 _buf.reset(); 270 clear(); 271 } 272 273 /// <summary> 274 /// Releases any data retained by encapsulations. Internally calls clear(). 275 /// </summary> clear()276 public void clear() 277 { 278 if(_encapsStack != null) 279 { 280 Debug.Assert(_encapsStack.next == null); 281 _encapsStack.next = _encapsCache; 282 _encapsCache = _encapsStack; 283 _encapsStack = null; 284 _encapsCache.reset(); 285 } 286 287 _startSeq = -1; 288 _sliceValues = true; 289 } 290 291 /// <summary> 292 /// Sets the value factory manager to use when marshaling value instances. If the stream 293 /// was initialized with a communicator, the communicator's value factory manager will 294 /// be used by default. 295 /// </summary> 296 /// <param name="vfm">The value factory manager.</param> setValueFactoryManager(ValueFactoryManager vfm)297 public void setValueFactoryManager(ValueFactoryManager vfm) 298 { 299 _valueFactoryManager = vfm; 300 } 301 302 /// <summary> 303 /// Sets the logger to use when logging trace messages. If the stream 304 /// was initialized with a communicator, the communicator's logger will 305 /// be used by default. 306 /// </summary> 307 /// <param name="logger">The logger to use for logging trace messages.</param> setLogger(Logger logger)308 public void setLogger(Logger logger) 309 { 310 _logger = logger; 311 } 312 313 /// <summary> 314 /// Sets the compact ID resolver to use when unmarshaling value and exception 315 /// instances. If the stream was initialized with a communicator, the communicator's 316 /// resolver will be used by default. 317 /// </summary> 318 /// <param name="r">The compact ID resolver.</param> setCompactIdResolver(System.Func<int, string> r)319 public void setCompactIdResolver(System.Func<int, string> r) 320 { 321 _compactIdResolver = r; 322 } 323 324 /// <summary> 325 /// Sets the class resolver, which the stream will use when attempting to unmarshal 326 /// a value or exception. If the stream was initialized with a communicator, the communicator's 327 /// resolver will be used by default. 328 /// </summary> 329 /// <param name="r">The class resolver.</param> setClassResolver(System.Func<string, Type> r)330 public void setClassResolver(System.Func<string, Type> r) 331 { 332 _classResolver = r; 333 } 334 335 /// <summary> 336 /// Determines the behavior of the stream when extracting instances of Slice classes. 337 /// An instance is "sliced" when a factory cannot be found for a Slice type ID. 338 /// The stream's default behavior is to slice instances. 339 /// </summary> 340 /// <param name="b">If true (the default), slicing is enabled; if false, 341 /// slicing is disabled. If slicing is disabled and the stream encounters a Slice type ID 342 /// during decoding for which no value factory is installed, it raises NoValueFactoryException. 343 /// </param> setSliceValues(bool b)344 public void setSliceValues(bool b) 345 { 346 _sliceValues = b; 347 } 348 349 /// <summary> 350 /// Determines whether the stream logs messages about slicing instances of Slice values. 351 /// </summary> 352 /// <param name="b">True to enable logging, false to disable logging.</param> setTraceSlicing(bool b)353 public void setTraceSlicing(bool b) 354 { 355 _traceSlicing = b; 356 } 357 358 /// <summary> 359 /// Set the maximum depth allowed for graph of Slice class instances. 360 /// </summary> 361 /// <param name="classGraphDepthMax">The maximum depth.</param> setClassGraphDepthMax(int classGraphDepthMax)362 public void setClassGraphDepthMax(int classGraphDepthMax) 363 { 364 if(classGraphDepthMax < 1) 365 { 366 _classGraphDepthMax = 0x7fffffff; 367 } 368 else 369 { 370 _classGraphDepthMax = classGraphDepthMax; 371 } 372 } 373 374 /// <summary> 375 /// Retrieves the closure object associated with this stream. 376 /// </summary> 377 /// <returns>The closure object.</returns> getClosure()378 public object getClosure() 379 { 380 return _closure; 381 } 382 383 /// <summary> 384 /// Associates a closure object with this stream. 385 /// </summary> 386 /// <param name="p">The new closure object.</param> 387 /// <returns>The previous closure object, or null.</returns> setClosure(object p)388 public object setClosure(object p) 389 { 390 object prev = _closure; 391 _closure = p; 392 return prev; 393 } 394 instance()395 public IceInternal.Instance instance() 396 { 397 return _instance; 398 } 399 400 /// <summary> 401 /// Swaps the contents of one stream with another. 402 /// </summary> 403 /// <param name="other">The other stream.</param> swap(InputStream other)404 public void swap(InputStream other) 405 { 406 Debug.Assert(_instance == other._instance); 407 408 IceInternal.Buffer tmpBuf = other._buf; 409 other._buf = _buf; 410 _buf = tmpBuf; 411 412 EncodingVersion tmpEncoding = other._encoding; 413 other._encoding = _encoding; 414 _encoding = tmpEncoding; 415 416 bool tmpTraceSlicing = other._traceSlicing; 417 other._traceSlicing = _traceSlicing; 418 _traceSlicing = tmpTraceSlicing; 419 420 object tmpClosure = other._closure; 421 other._closure = _closure; 422 _closure = tmpClosure; 423 424 bool tmpSliceValues = other._sliceValues; 425 other._sliceValues = _sliceValues; 426 _sliceValues = tmpSliceValues; 427 428 int tmpClassGraphDepthMax = other._classGraphDepthMax; 429 other._classGraphDepthMax = _classGraphDepthMax; 430 _classGraphDepthMax = tmpClassGraphDepthMax; 431 432 // 433 // Swap is never called for InputStreams that have encapsulations being read. However, 434 // encapsulations might still be set in case un-marshalling failed. We just 435 // reset the encapsulations if there are still some set. 436 // 437 resetEncapsulation(); 438 other.resetEncapsulation(); 439 440 int tmpStartSeq = other._startSeq; 441 other._startSeq = _startSeq; 442 _startSeq = tmpStartSeq; 443 444 int tmpMinSeqSize = other._minSeqSize; 445 other._minSeqSize = _minSeqSize; 446 _minSeqSize = tmpMinSeqSize; 447 448 ValueFactoryManager tmpVfm = other._valueFactoryManager; 449 other._valueFactoryManager = _valueFactoryManager; 450 _valueFactoryManager = tmpVfm; 451 452 Logger tmpLogger = other._logger; 453 other._logger = _logger; 454 _logger = tmpLogger; 455 456 System.Func<int, string> tmpCompactIdResolver = other._compactIdResolver; 457 other._compactIdResolver = _compactIdResolver; 458 _compactIdResolver = tmpCompactIdResolver; 459 460 System.Func<string, Type> tmpClassResolver = other._classResolver; 461 other._classResolver = _classResolver; 462 _classResolver = tmpClassResolver; 463 } 464 resetEncapsulation()465 private void resetEncapsulation() 466 { 467 _encapsStack = null; 468 } 469 470 /// <summary> 471 /// Resizes the stream to a new size. 472 /// </summary> 473 /// <param name="sz">The new size.</param> resize(int sz)474 public void resize(int sz) 475 { 476 _buf.resize(sz, true); 477 _buf.b.position(sz); 478 } 479 getBuffer()480 public IceInternal.Buffer getBuffer() 481 { 482 return _buf; 483 } 484 485 /// <summary> 486 /// Marks the start of a class instance. 487 /// </summary> startValue()488 public void startValue() 489 { 490 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 491 _encapsStack.decoder.startInstance(SliceType.ValueSlice); 492 } 493 494 /// <summary> 495 /// Marks the end of a class instance. 496 /// </summary> 497 /// <param name="preserve">True if unknown slices should be preserved, false otherwise.</param> 498 /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns> endValue(bool preserve)499 public SlicedData endValue(bool preserve) 500 { 501 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 502 return _encapsStack.decoder.endInstance(preserve); 503 } 504 505 /// <summary> 506 /// Marks the start of a user exception. 507 /// </summary> startException()508 public void startException() 509 { 510 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 511 _encapsStack.decoder.startInstance(SliceType.ExceptionSlice); 512 } 513 514 /// <summary> 515 /// Marks the end of a user exception. 516 /// </summary> 517 /// <param name="preserve">True if unknown slices should be preserved, false otherwise.</param> 518 /// <returns>A SlicedData object containing the preserved slices for unknown types.</returns> endException(bool preserve)519 public SlicedData endException(bool preserve) 520 { 521 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 522 return _encapsStack.decoder.endInstance(preserve); 523 } 524 525 /// <summary> 526 /// Reads the start of an encapsulation. 527 /// </summary> 528 /// <returns>The encapsulation encoding version.</returns> startEncapsulation()529 public EncodingVersion startEncapsulation() 530 { 531 Encaps curr = _encapsCache; 532 if(curr != null) 533 { 534 curr.reset(); 535 _encapsCache = _encapsCache.next; 536 } 537 else 538 { 539 curr = new Encaps(); 540 } 541 curr.next = _encapsStack; 542 _encapsStack = curr; 543 544 _encapsStack.start = _buf.b.position(); 545 546 // 547 // I don't use readSize() for encapsulations, because when creating an encapsulation, 548 // I must know in advance how many bytes the size information will require in the data 549 // stream. If I use an Int, it is always 4 bytes. For readSize(), it could be 1 or 5 bytes. 550 // 551 int sz = readInt(); 552 if(sz < 6) 553 { 554 throw new UnmarshalOutOfBoundsException(); 555 } 556 if(sz - 4 > _buf.b.remaining()) 557 { 558 throw new UnmarshalOutOfBoundsException(); 559 } 560 _encapsStack.sz = sz; 561 562 EncodingVersion encoding = new EncodingVersion(); 563 encoding.ice_readMembers(this); 564 Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported. 565 _encapsStack.setEncoding(encoding); 566 567 return encoding; 568 } 569 570 /// <summary> 571 /// Ends the previous encapsulation. 572 /// </summary> endEncapsulation()573 public void endEncapsulation() 574 { 575 Debug.Assert(_encapsStack != null); 576 577 if(!_encapsStack.encoding_1_0) 578 { 579 skipOptionals(); 580 if(_buf.b.position() != _encapsStack.start + _encapsStack.sz) 581 { 582 throw new EncapsulationException(); 583 } 584 } 585 else if(_buf.b.position() != _encapsStack.start + _encapsStack.sz) 586 { 587 if(_buf.b.position() + 1 != _encapsStack.start + _encapsStack.sz) 588 { 589 throw new EncapsulationException(); 590 } 591 592 // 593 // Ice version < 3.3 had a bug where user exceptions with 594 // class members could be encoded with a trailing byte 595 // when dispatched with AMD. So we tolerate an extra byte 596 // in the encapsulation. 597 // 598 try 599 { 600 _buf.b.get(); 601 } 602 catch(InvalidOperationException ex) 603 { 604 throw new UnmarshalOutOfBoundsException(ex); 605 } 606 } 607 608 Encaps curr = _encapsStack; 609 _encapsStack = curr.next; 610 curr.next = _encapsCache; 611 _encapsCache = curr; 612 _encapsCache.reset(); 613 } 614 615 /// <summary> 616 /// Skips an empty encapsulation. 617 /// </summary> 618 /// <returns>The encapsulation's encoding version.</returns> skipEmptyEncapsulation()619 public EncodingVersion skipEmptyEncapsulation() 620 { 621 int sz = readInt(); 622 if(sz < 6) 623 { 624 throw new EncapsulationException(); 625 } 626 if(sz - 4 > _buf.b.remaining()) 627 { 628 throw new UnmarshalOutOfBoundsException(); 629 } 630 631 var encoding = new EncodingVersion(); 632 encoding.ice_readMembers(this); 633 Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported. 634 635 if(encoding.Equals(Util.Encoding_1_0)) 636 { 637 if(sz != 6) 638 { 639 throw new EncapsulationException(); 640 } 641 } 642 else 643 { 644 // Skip the optional content of the encapsulation if we are expecting an 645 // empty encapsulation. 646 _buf.b.position(_buf.b.position() + sz - 6); 647 } 648 return encoding; 649 } 650 651 /// <summary> 652 /// Returns a blob of bytes representing an encapsulation. The encapsulation's encoding version 653 /// is returned in the argument. 654 /// </summary> 655 /// <param name="encoding">The encapsulation's encoding version.</param> 656 /// <returns>The encoded encapsulation.</returns> readEncapsulation(out EncodingVersion encoding)657 public byte[] readEncapsulation(out EncodingVersion encoding) 658 { 659 int sz = readInt(); 660 if(sz < 6) 661 { 662 throw new UnmarshalOutOfBoundsException(); 663 } 664 665 if(sz - 4 > _buf.b.remaining()) 666 { 667 throw new UnmarshalOutOfBoundsException(); 668 } 669 670 encoding = new EncodingVersion(); 671 encoding.ice_readMembers(this); 672 _buf.b.position(_buf.b.position() - 6); 673 674 byte[] v = new byte[sz]; 675 try 676 { 677 _buf.b.get(v); 678 return v; 679 } 680 catch(InvalidOperationException ex) 681 { 682 throw new UnmarshalOutOfBoundsException(ex); 683 } 684 } 685 686 /// <summary> 687 /// Determines the current encoding version. 688 /// </summary> 689 /// <returns>The encoding version.</returns> getEncoding()690 public EncodingVersion getEncoding() 691 { 692 return _encapsStack != null ? _encapsStack.encoding : _encoding; 693 } 694 695 /// <summary> 696 /// Determines the size of the current encapsulation, excluding the encapsulation header. 697 /// </summary> 698 /// <returns>The size of the encapsulated data.</returns> getEncapsulationSize()699 public int getEncapsulationSize() 700 { 701 Debug.Assert(_encapsStack != null); 702 return _encapsStack.sz - 6; 703 } 704 705 /// <summary> 706 /// Skips over an encapsulation. 707 /// </summary> 708 /// <returns>The encoding version of the skipped encapsulation.</returns> skipEncapsulation()709 public EncodingVersion skipEncapsulation() 710 { 711 int sz = readInt(); 712 if(sz < 6) 713 { 714 throw new UnmarshalOutOfBoundsException(); 715 } 716 EncodingVersion encoding = new EncodingVersion(); 717 encoding.ice_readMembers(this); 718 try 719 { 720 _buf.b.position(_buf.b.position() + sz - 6); 721 } 722 catch(ArgumentOutOfRangeException ex) 723 { 724 throw new UnmarshalOutOfBoundsException(ex); 725 } 726 return encoding; 727 } 728 729 /// <summary> 730 /// Reads the start of a class instance or exception slice. 731 /// </summary> 732 /// <returns>The Slice type ID for this slice.</returns> startSlice()733 public string startSlice() // Returns type ID of next slice 734 { 735 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 736 return _encapsStack.decoder.startSlice(); 737 } 738 739 /// <summary> 740 /// Indicates that the end of a class instance or exception slice has been reached. 741 /// </summary> endSlice()742 public void endSlice() 743 { 744 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 745 _encapsStack.decoder.endSlice(); 746 } 747 748 /// <summary> 749 /// Skips over a class instance or exception slice. 750 /// </summary> skipSlice()751 public void skipSlice() 752 { 753 Debug.Assert(_encapsStack != null && _encapsStack.decoder != null); 754 _encapsStack.decoder.skipSlice(); 755 } 756 757 /// <summary> 758 /// Indicates that unmarshaling is complete, except for any class instances. The application must call this 759 /// method only if the stream actually contains class instances. Calling readPendingValues triggers the 760 /// calls to the System.Action delegates to inform the application that unmarshaling of an instance 761 /// is complete. 762 /// </summary> readPendingValues()763 public void readPendingValues() 764 { 765 if(_encapsStack != null && _encapsStack.decoder != null) 766 { 767 _encapsStack.decoder.readPendingValues(); 768 } 769 else if(_encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0)) 770 { 771 // 772 // If using the 1.0 encoding and no instances were read, we 773 // still read an empty sequence of pending instances if 774 // requested (i.e.: if this is called). 775 // 776 // This is required by the 1.0 encoding, even if no instances 777 // are written we do marshal an empty sequence if marshaled 778 // data types use classes. 779 // 780 skipSize(); 781 } 782 } 783 784 /// <summary> 785 /// Extracts a size from the stream. 786 /// </summary> 787 /// <returns>The extracted size.</returns> readSize()788 public int readSize() 789 { 790 try 791 { 792 byte b = _buf.b.get(); 793 if(b == 255) 794 { 795 int v = _buf.b.getInt(); 796 if(v < 0) 797 { 798 throw new UnmarshalOutOfBoundsException(); 799 } 800 return v; 801 } 802 else 803 { 804 return b; // byte is unsigned 805 } 806 } 807 catch(InvalidOperationException ex) 808 { 809 throw new UnmarshalOutOfBoundsException(ex); 810 } 811 } 812 813 /// <summary> 814 /// Reads and validates a sequence size. 815 /// </summary> 816 /// <returns>The extracted size.</returns> readAndCheckSeqSize(int minSize)817 public int readAndCheckSeqSize(int minSize) 818 { 819 int sz = readSize(); 820 821 if(sz == 0) 822 { 823 return 0; 824 } 825 826 // 827 // The _startSeq variable points to the start of the sequence for which 828 // we expect to read at least _minSeqSize bytes from the stream. 829 // 830 // If not initialized or if we already read more data than _minSeqSize, 831 // we reset _startSeq and _minSeqSize for this sequence (possibly a 832 // top-level sequence or enclosed sequence it doesn't really matter). 833 // 834 // Otherwise, we are reading an enclosed sequence and we have to bump 835 // _minSeqSize by the minimum size that this sequence will require on 836 // the stream. 837 // 838 // The goal of this check is to ensure that when we start un-marshalling 839 // a new sequence, we check the minimal size of this new sequence against 840 // the estimated remaining buffer size. This estimatation is based on 841 // the minimum size of the enclosing sequences, it's _minSeqSize. 842 // 843 if(_startSeq == -1 || _buf.b.position() > (_startSeq + _minSeqSize)) 844 { 845 _startSeq = _buf.b.position(); 846 _minSeqSize = sz * minSize; 847 } 848 else 849 { 850 _minSeqSize += sz * minSize; 851 } 852 853 // 854 // If there isn't enough data to read on the stream for the sequence (and 855 // possibly enclosed sequences), something is wrong with the marshalled 856 // data: it's claiming having more data that what is possible to read. 857 // 858 if(_startSeq + _minSeqSize > _buf.size()) 859 { 860 throw new UnmarshalOutOfBoundsException(); 861 } 862 863 return sz; 864 } 865 866 /// <summary> 867 /// Reads a blob of bytes from the stream. The length of the given array determines how many bytes are read. 868 /// </summary> 869 /// <param name="v">Bytes from the stream.</param> readBlob(byte[] v)870 public void readBlob(byte[] v) 871 { 872 try 873 { 874 _buf.b.get(v); 875 } 876 catch(InvalidOperationException ex) 877 { 878 throw new UnmarshalOutOfBoundsException(ex); 879 } 880 } 881 882 /// <summary> 883 /// Reads a blob of bytes from the stream. 884 /// </summary> 885 /// <param name="sz">The number of bytes to read.</param> 886 /// <returns>The requested bytes as a byte array.</returns> readBlob(int sz)887 public byte[] readBlob(int sz) 888 { 889 if(_buf.b.remaining() < sz) 890 { 891 throw new UnmarshalOutOfBoundsException(); 892 } 893 byte[] v = new byte[sz]; 894 try 895 { 896 _buf.b.get(v); 897 return v; 898 } 899 catch(InvalidOperationException ex) 900 { 901 throw new UnmarshalOutOfBoundsException(ex); 902 } 903 } 904 905 /// <summary> 906 /// Determine if an optional value is available for reading. 907 /// </summary> 908 /// <param name="tag">The tag associated with the value.</param> 909 /// <param name="expectedFormat">The optional format for the value.</param> 910 /// <returns>True if the value is present, false otherwise.</returns> readOptional(int tag, OptionalFormat expectedFormat)911 public bool readOptional(int tag, OptionalFormat expectedFormat) 912 { 913 Debug.Assert(_encapsStack != null); 914 if(_encapsStack.decoder != null) 915 { 916 return _encapsStack.decoder.readOptional(tag, expectedFormat); 917 } 918 else 919 { 920 return readOptImpl(tag, expectedFormat); 921 } 922 } 923 924 /// <summary> 925 /// Extracts a byte value from the stream. 926 /// </summary> 927 /// <returns>The extracted byte.</returns> readByte()928 public byte readByte() 929 { 930 try 931 { 932 return _buf.b.get(); 933 } 934 catch(InvalidOperationException ex) 935 { 936 throw new UnmarshalOutOfBoundsException(ex); 937 } 938 } 939 940 /// <summary> 941 /// Extracts an optional byte value from the stream. 942 /// </summary> 943 /// <param name="tag">The numeric tag associated with the value.</param> 944 /// <returns>The optional value.</returns> readByte(int tag)945 public Optional<byte> readByte(int tag) 946 { 947 if(readOptional(tag, OptionalFormat.F1)) 948 { 949 return new Optional<byte>(readByte()); 950 } 951 else 952 { 953 return new Optional<byte>(); 954 } 955 } 956 957 /// <summary> 958 /// Extracts an optional byte value from the stream. 959 /// </summary> 960 /// <param name="tag">The numeric tag associated with the value.</param> 961 /// <param name="isset">True if the optional value is present, false otherwise.</param> 962 /// <param name="v">The optional value.</param> readByte(int tag, out bool isset, out byte v)963 public void readByte(int tag, out bool isset, out byte v) 964 { 965 if(isset = readOptional(tag, OptionalFormat.F1)) 966 { 967 v = readByte(); 968 } 969 else 970 { 971 v = 0; 972 } 973 } 974 975 /// <summary> 976 /// Extracts a sequence of byte values from the stream. 977 /// </summary> 978 /// <returns>The extracted byte sequence.</returns> readByteSeq()979 public byte[] readByteSeq() 980 { 981 try 982 { 983 int sz = readAndCheckSeqSize(1); 984 byte[] v = new byte[sz]; 985 _buf.b.get(v); 986 return v; 987 } 988 catch(InvalidOperationException ex) 989 { 990 throw new UnmarshalOutOfBoundsException(ex); 991 } 992 } 993 994 /// <summary> 995 /// Extracts a sequence of byte values from the stream. 996 /// </summary> 997 /// <param name="l">The extracted byte sequence as a list.</param> readByteSeq(out List<byte> l)998 public void readByteSeq(out List<byte> l) 999 { 1000 // 1001 // Reading into an array and copy-constructing the 1002 // list is faster than constructing the list 1003 // and adding to it one element at a time. 1004 // 1005 l = new List<byte>(readByteSeq()); 1006 } 1007 1008 /// <summary> 1009 /// Extracts a sequence of byte values from the stream. 1010 /// </summary> 1011 /// <param name="l">The extracted byte sequence as a linked list.</param> readByteSeq(out LinkedList<byte> l)1012 public void readByteSeq(out LinkedList<byte> l) 1013 { 1014 // 1015 // Reading into an array and copy-constructing the 1016 // list is faster than constructing the list 1017 // and adding to it one element at a time. 1018 // 1019 l = new LinkedList<byte>(readByteSeq()); 1020 } 1021 1022 /// <summary> 1023 /// Extracts a sequence of byte values from the stream. 1024 /// </summary> 1025 /// <param name="l">The extracted byte sequence as a queue.</param> readByteSeq(out Queue<byte> l)1026 public void readByteSeq(out Queue<byte> l) 1027 { 1028 // 1029 // Reading into an array and copy-constructing the 1030 // queue is faster than constructing the queue 1031 // and adding to it one element at a time. 1032 // 1033 l = new Queue<byte>(readByteSeq()); 1034 } 1035 1036 /// <summary> 1037 /// Extracts a sequence of byte values from the stream. 1038 /// </summary> 1039 /// <param name="l">The extracted byte sequence as a stack.</param> readByteSeq(out Stack<byte> l)1040 public void readByteSeq(out Stack<byte> l) 1041 { 1042 // 1043 // Reverse the contents by copying into an array first 1044 // because the stack is marshaled in top-to-bottom order. 1045 // 1046 byte[] array = readByteSeq(); 1047 Array.Reverse(array); 1048 l = new Stack<byte>(array); 1049 } 1050 1051 /// <summary> 1052 /// Extracts an optional byte sequence from the stream. 1053 /// </summary> 1054 /// <param name="tag">The numeric tag associated with the value.</param> 1055 /// <returns>The optional value.</returns> readByteSeq(int tag)1056 public Optional<byte[]> readByteSeq(int tag) 1057 { 1058 if(readOptional(tag, OptionalFormat.VSize)) 1059 { 1060 return new Optional<byte[]>(readByteSeq()); 1061 } 1062 else 1063 { 1064 return new Optional<byte[]>(); 1065 } 1066 } 1067 1068 /// <summary> 1069 /// Extracts an optional byte sequence from the stream. 1070 /// </summary> 1071 /// <param name="tag">The numeric tag associated with the value.</param> 1072 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1073 /// <param name="v">The optional value.</param> readByteSeq(int tag, out bool isset, out byte[] v)1074 public void readByteSeq(int tag, out bool isset, out byte[] v) 1075 { 1076 if(isset = readOptional(tag, OptionalFormat.VSize)) 1077 { 1078 v = readByteSeq(); 1079 } 1080 else 1081 { 1082 v = null; 1083 } 1084 } 1085 1086 /// <summary> 1087 /// Extracts a serializable object from the stream. 1088 /// </summary> 1089 /// <returns>The serializable object.</returns> readSerializable()1090 public object readSerializable() 1091 { 1092 int sz = readAndCheckSeqSize(1); 1093 if(sz == 0) 1094 { 1095 return null; 1096 } 1097 try 1098 { 1099 var f = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.All, _instance)); 1100 return f.Deserialize(new IceInternal.InputStreamWrapper(sz, this)); 1101 } 1102 catch(System.Exception ex) 1103 { 1104 throw new MarshalException("cannot deserialize object:", ex); 1105 } 1106 } 1107 1108 /// <summary> 1109 /// Extracts a boolean value from the stream. 1110 /// </summary> 1111 /// <returns>The extracted boolean.</returns> readBool()1112 public bool readBool() 1113 { 1114 try 1115 { 1116 return _buf.b.get() == 1; 1117 } 1118 catch(InvalidOperationException ex) 1119 { 1120 throw new UnmarshalOutOfBoundsException(ex); 1121 } 1122 } 1123 1124 /// <summary> 1125 /// Extracts an optional boolean value from the stream. 1126 /// </summary> 1127 /// <param name="tag">The numeric tag associated with the value.</param> 1128 /// <returns>The optional value.</returns> readBool(int tag)1129 public Optional<bool> readBool(int tag) 1130 { 1131 if(readOptional(tag, OptionalFormat.F1)) 1132 { 1133 return new Optional<bool>(readBool()); 1134 } 1135 else 1136 { 1137 return new Optional<bool>(); 1138 } 1139 } 1140 1141 /// <summary> 1142 /// Extracts an optional boolean value from the stream. 1143 /// </summary> 1144 /// <param name="tag">The numeric tag associated with the value.</param> 1145 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1146 /// <param name="v">The optional value.</param> readBool(int tag, out bool isset, out bool v)1147 public void readBool(int tag, out bool isset, out bool v) 1148 { 1149 if(isset = readOptional(tag, OptionalFormat.F1)) 1150 { 1151 v = readBool(); 1152 } 1153 else 1154 { 1155 v = false; 1156 } 1157 } 1158 1159 /// <summary> 1160 /// Extracts a sequence of boolean values from the stream. 1161 /// </summary> 1162 /// <returns>The extracted boolean sequence.</returns> readBoolSeq()1163 public bool[] readBoolSeq() 1164 { 1165 try 1166 { 1167 int sz = readAndCheckSeqSize(1); 1168 bool[] v = new bool[sz]; 1169 _buf.b.getBoolSeq(v); 1170 return v; 1171 } 1172 catch(InvalidOperationException ex) 1173 { 1174 throw new UnmarshalOutOfBoundsException(ex); 1175 } 1176 } 1177 1178 /// <summary> 1179 /// Extracts a sequence of boolean values from the stream. 1180 /// </summary> 1181 /// <param name="l">The extracted boolean sequence as a list.</param> readBoolSeq(out List<bool> l)1182 public void readBoolSeq(out List<bool> l) 1183 { 1184 // 1185 // Reading into an array and copy-constructing the 1186 // list is faster than constructing the list 1187 // and adding to it one element at a time. 1188 // 1189 l = new List<bool>(readBoolSeq()); 1190 } 1191 1192 /// <summary> 1193 /// Extracts a sequence of boolean values from the stream. 1194 /// </summary> 1195 /// <param name="l">The extracted boolean sequence as a linked list.</param> readBoolSeq(out LinkedList<bool> l)1196 public void readBoolSeq(out LinkedList<bool> l) 1197 { 1198 // 1199 // Reading into an array and copy-constructing the 1200 // list is faster than constructing the list 1201 // and adding to it one element at a time. 1202 // 1203 l = new LinkedList<bool>(readBoolSeq()); 1204 } 1205 1206 /// <summary> 1207 /// Extracts a sequence of boolean values from the stream. 1208 /// </summary> 1209 /// <param name="l">The extracted boolean sequence as a queue.</param> readBoolSeq(out Queue<bool> l)1210 public void readBoolSeq(out Queue<bool> l) 1211 { 1212 // 1213 // Reading into an array and copy-constructing the 1214 // queue is faster than constructing the queue 1215 // and adding to it one element at a time. 1216 // 1217 l = new Queue<bool>(readBoolSeq()); 1218 } 1219 1220 /// <summary> 1221 /// Extracts a sequence of boolean values from the stream. 1222 /// </summary> 1223 /// <param name="l">The extracted boolean sequence as a stack.</param> readBoolSeq(out Stack<bool> l)1224 public void readBoolSeq(out Stack<bool> l) 1225 { 1226 // 1227 // Reverse the contents by copying into an array first 1228 // because the stack is marshaled in top-to-bottom order. 1229 // 1230 bool[] array = readBoolSeq(); 1231 Array.Reverse(array); 1232 l = new Stack<bool>(array); 1233 } 1234 1235 /// <summary> 1236 /// Extracts an optional boolean sequence from the stream. 1237 /// </summary> 1238 /// <param name="tag">The numeric tag associated with the value.</param> 1239 /// <returns>The optional value.</returns> readBoolSeq(int tag)1240 public Optional<bool[]> readBoolSeq(int tag) 1241 { 1242 if(readOptional(tag, OptionalFormat.VSize)) 1243 { 1244 return new Optional<bool[]>(readBoolSeq()); 1245 } 1246 else 1247 { 1248 return new Optional<bool[]>(); 1249 } 1250 } 1251 1252 /// <summary> 1253 /// Extracts an optional boolean sequence from the stream. 1254 /// </summary> 1255 /// <param name="tag">The numeric tag associated with the value.</param> 1256 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1257 /// <param name="v">The optional value.</param> readBoolSeq(int tag, out bool isset, out bool[] v)1258 public void readBoolSeq(int tag, out bool isset, out bool[] v) 1259 { 1260 if(isset = readOptional(tag, OptionalFormat.VSize)) 1261 { 1262 v = readBoolSeq(); 1263 } 1264 else 1265 { 1266 v = null; 1267 } 1268 } 1269 1270 /// <summary> 1271 /// Extracts a short value from the stream. 1272 /// </summary> 1273 /// <returns>The extracted short.</returns> readShort()1274 public short readShort() 1275 { 1276 try 1277 { 1278 return _buf.b.getShort(); 1279 } 1280 catch(InvalidOperationException ex) 1281 { 1282 throw new UnmarshalOutOfBoundsException(ex); 1283 } 1284 } 1285 1286 /// <summary> 1287 /// Extracts an optional short value from the stream. 1288 /// </summary> 1289 /// <param name="tag">The numeric tag associated with the value.</param> 1290 /// <returns>The optional value.</returns> readShort(int tag)1291 public Optional<short> readShort(int tag) 1292 { 1293 if(readOptional(tag, OptionalFormat.F2)) 1294 { 1295 return new Optional<short>(readShort()); 1296 } 1297 else 1298 { 1299 return new Optional<short>(); 1300 } 1301 } 1302 1303 /// <summary> 1304 /// Extracts an optional short value from the stream. 1305 /// </summary> 1306 /// <param name="tag">The numeric tag associated with the value.</param> 1307 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1308 /// <param name="v">The optional value.</param> readShort(int tag, out bool isset, out short v)1309 public void readShort(int tag, out bool isset, out short v) 1310 { 1311 if(isset = readOptional(tag, OptionalFormat.F2)) 1312 { 1313 v = readShort(); 1314 } 1315 else 1316 { 1317 v = 0; 1318 } 1319 } 1320 1321 /// <summary> 1322 /// Extracts a sequence of short values from the stream. 1323 /// </summary> 1324 /// <returns>The extracted short sequence.</returns> readShortSeq()1325 public short[] readShortSeq() 1326 { 1327 try 1328 { 1329 int sz = readAndCheckSeqSize(2); 1330 short[] v = new short[sz]; 1331 _buf.b.getShortSeq(v); 1332 return v; 1333 } 1334 catch(InvalidOperationException ex) 1335 { 1336 throw new UnmarshalOutOfBoundsException(ex); 1337 } 1338 } 1339 1340 /// <summary> 1341 /// Extracts a sequence of short values from the stream. 1342 /// </summary> 1343 /// <param name="l">The extracted short sequence as a list.</param> readShortSeq(out List<short> l)1344 public void readShortSeq(out List<short> l) 1345 { 1346 // 1347 // Reading into an array and copy-constructing the 1348 // list is faster than constructing the list 1349 // and adding to it one element at a time. 1350 // 1351 l = new List<short>(readShortSeq()); 1352 } 1353 1354 /// <summary> 1355 /// Extracts a sequence of short values from the stream. 1356 /// </summary> 1357 /// <param name="l">The extracted short sequence as a linked list.</param> readShortSeq(out LinkedList<short> l)1358 public void readShortSeq(out LinkedList<short> l) 1359 { 1360 // 1361 // Reading into an array and copy-constructing the 1362 // list is faster than constructing the list 1363 // and adding to it one element at a time. 1364 // 1365 l = new LinkedList<short>(readShortSeq()); 1366 } 1367 1368 /// <summary> 1369 /// Extracts a sequence of short values from the stream. 1370 /// </summary> 1371 /// <param name="l">The extracted short sequence as a queue.</param> readShortSeq(out Queue<short> l)1372 public void readShortSeq(out Queue<short> l) 1373 { 1374 // 1375 // Reading into an array and copy-constructing the 1376 // queue is faster than constructing the queue 1377 // and adding to it one element at a time. 1378 // 1379 l = new Queue<short>(readShortSeq()); 1380 } 1381 1382 /// <summary> 1383 /// Extracts a sequence of short values from the stream. 1384 /// </summary> 1385 /// <param name="l">The extracted short sequence as a stack.</param> readShortSeq(out Stack<short> l)1386 public void readShortSeq(out Stack<short> l) 1387 { 1388 // 1389 // Reverse the contents by copying into an array first 1390 // because the stack is marshaled in top-to-bottom order. 1391 // 1392 short[] array = readShortSeq(); 1393 Array.Reverse(array); 1394 l = new Stack<short>(array); 1395 } 1396 1397 /// <summary> 1398 /// Extracts an optional short sequence from the stream. 1399 /// </summary> 1400 /// <param name="tag">The numeric tag associated with the value.</param> 1401 /// <returns>The optional value.</returns> readShortSeq(int tag)1402 public Optional<short[]> readShortSeq(int tag) 1403 { 1404 if(readOptional(tag, OptionalFormat.VSize)) 1405 { 1406 skipSize(); 1407 return new Optional<short[]>(readShortSeq()); 1408 } 1409 else 1410 { 1411 return new Optional<short[]>(); 1412 } 1413 } 1414 1415 /// <summary> 1416 /// Extracts an optional short sequence from the stream. 1417 /// </summary> 1418 /// <param name="tag">The numeric tag associated with the value.</param> 1419 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1420 /// <param name="v">The optional value.</param> readShortSeq(int tag, out bool isset, out short[] v)1421 public void readShortSeq(int tag, out bool isset, out short[] v) 1422 { 1423 if(isset = readOptional(tag, OptionalFormat.VSize)) 1424 { 1425 skipSize(); 1426 v = readShortSeq(); 1427 } 1428 else 1429 { 1430 v = null; 1431 } 1432 } 1433 1434 /// <summary> 1435 /// Extracts an int value from the stream. 1436 /// </summary> 1437 /// <returns>The extracted int.</returns> readInt()1438 public int readInt() 1439 { 1440 try 1441 { 1442 return _buf.b.getInt(); 1443 } 1444 catch(InvalidOperationException ex) 1445 { 1446 throw new UnmarshalOutOfBoundsException(ex); 1447 } 1448 } 1449 1450 /// <summary> 1451 /// Extracts an optional int value from the stream. 1452 /// </summary> 1453 /// <param name="tag">The numeric tag associated with the value.</param> 1454 /// <returns>The optional value.</returns> readInt(int tag)1455 public Optional<int> readInt(int tag) 1456 { 1457 if(readOptional(tag, OptionalFormat.F4)) 1458 { 1459 return new Optional<int>(readInt()); 1460 } 1461 else 1462 { 1463 return new Optional<int>(); 1464 } 1465 } 1466 1467 /// <summary> 1468 /// Extracts an optional int value from the stream. 1469 /// </summary> 1470 /// <param name="tag">The numeric tag associated with the value.</param> 1471 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1472 /// <param name="v">The optional value.</param> readInt(int tag, out bool isset, out int v)1473 public void readInt(int tag, out bool isset, out int v) 1474 { 1475 if(isset = readOptional(tag, OptionalFormat.F4)) 1476 { 1477 v = readInt(); 1478 } 1479 else 1480 { 1481 v = 0; 1482 } 1483 } 1484 1485 /// <summary> 1486 /// Extracts a sequence of int values from the stream. 1487 /// </summary> 1488 /// <returns>The extracted int sequence.</returns> readIntSeq()1489 public int[] readIntSeq() 1490 { 1491 try 1492 { 1493 int sz = readAndCheckSeqSize(4); 1494 int[] v = new int[sz]; 1495 _buf.b.getIntSeq(v); 1496 return v; 1497 } 1498 catch(InvalidOperationException ex) 1499 { 1500 throw new UnmarshalOutOfBoundsException(ex); 1501 } 1502 } 1503 1504 /// <summary> 1505 /// Extracts a sequence of int values from the stream. 1506 /// </summary> 1507 /// <param name="l">The extracted int sequence as a list.</param> readIntSeq(out List<int> l)1508 public void readIntSeq(out List<int> l) 1509 { 1510 // 1511 // Reading into an array and copy-constructing the 1512 // list is faster than constructing the list 1513 // and adding to it one element at a time. 1514 // 1515 l = new List<int>(readIntSeq()); 1516 } 1517 1518 /// <summary> 1519 /// Extracts a sequence of int values from the stream. 1520 /// </summary> 1521 /// <param name="l">The extracted int sequence as a linked list.</param> readIntSeq(out LinkedList<int> l)1522 public void readIntSeq(out LinkedList<int> l) 1523 { 1524 try 1525 { 1526 int sz = readAndCheckSeqSize(4); 1527 l = new LinkedList<int>(); 1528 for(int i = 0; i < sz; ++i) 1529 { 1530 l.AddLast(_buf.b.getInt()); 1531 } 1532 } 1533 catch(InvalidOperationException ex) 1534 { 1535 throw new UnmarshalOutOfBoundsException(ex); 1536 } 1537 } 1538 1539 /// <summary> 1540 /// Extracts a sequence of int values from the stream. 1541 /// </summary> 1542 /// <param name="l">The extracted int sequence as a queue.</param> readIntSeq(out Queue<int> l)1543 public void readIntSeq(out Queue<int> l) 1544 { 1545 // 1546 // Reading into an array and copy-constructing the 1547 // queue takes the same time as constructing the queue 1548 // and adding to it one element at a time, so 1549 // we avoid the copy. 1550 // 1551 try 1552 { 1553 int sz = readAndCheckSeqSize(4); 1554 l = new Queue<int>(sz); 1555 for(int i = 0; i < sz; ++i) 1556 { 1557 l.Enqueue(_buf.b.getInt()); 1558 } 1559 } 1560 catch(InvalidOperationException ex) 1561 { 1562 throw new UnmarshalOutOfBoundsException(ex); 1563 } 1564 } 1565 1566 /// <summary> 1567 /// Extracts a sequence of int values from the stream. 1568 /// </summary> 1569 /// <param name="l">The extracted int sequence as a stack.</param> readIntSeq(out Stack<int> l)1570 public void readIntSeq(out Stack<int> l) 1571 { 1572 // 1573 // Reverse the contents by copying into an array first 1574 // because the stack is marshaled in top-to-bottom order. 1575 // 1576 int[] array = readIntSeq(); 1577 Array.Reverse(array); 1578 l = new Stack<int>(array); 1579 } 1580 1581 /// <summary> 1582 /// Extracts an optional int sequence from the stream. 1583 /// </summary> 1584 /// <param name="tag">The numeric tag associated with the value.</param> 1585 /// <returns>The optional value.</returns> readIntSeq(int tag)1586 public Optional<int[]> readIntSeq(int tag) 1587 { 1588 if(readOptional(tag, OptionalFormat.VSize)) 1589 { 1590 skipSize(); 1591 return new Optional<int[]>(readIntSeq()); 1592 } 1593 else 1594 { 1595 return new Optional<int[]>(); 1596 } 1597 } 1598 1599 /// <summary> 1600 /// Extracts an optional int sequence from the stream. 1601 /// </summary> 1602 /// <param name="tag">The numeric tag associated with the value.</param> 1603 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1604 /// <param name="v">The optional value.</param> readIntSeq(int tag, out bool isset, out int[] v)1605 public void readIntSeq(int tag, out bool isset, out int[] v) 1606 { 1607 if(isset = readOptional(tag, OptionalFormat.VSize)) 1608 { 1609 skipSize(); 1610 v = readIntSeq(); 1611 } 1612 else 1613 { 1614 v = null; 1615 } 1616 } 1617 1618 /// <summary> 1619 /// Extracts a long value from the stream. 1620 /// </summary> 1621 /// <returns>The extracted long.</returns> readLong()1622 public long readLong() 1623 { 1624 try 1625 { 1626 return _buf.b.getLong(); 1627 } 1628 catch(InvalidOperationException ex) 1629 { 1630 throw new UnmarshalOutOfBoundsException(ex); 1631 } 1632 } 1633 1634 /// <summary> 1635 /// Extracts an optional long value from the stream. 1636 /// </summary> 1637 /// <param name="tag">The numeric tag associated with the value.</param> 1638 /// <returns>The optional value.</returns> readLong(int tag)1639 public Optional<long> readLong(int tag) 1640 { 1641 if(readOptional(tag, OptionalFormat.F8)) 1642 { 1643 return new Optional<long>(readLong()); 1644 } 1645 else 1646 { 1647 return new Optional<long>(); 1648 } 1649 } 1650 1651 /// <summary> 1652 /// Extracts an optional long value from the stream. 1653 /// </summary> 1654 /// <param name="tag">The numeric tag associated with the value.</param> 1655 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1656 /// <param name="v">The optional value.</param> readLong(int tag, out bool isset, out long v)1657 public void readLong(int tag, out bool isset, out long v) 1658 { 1659 if(isset = readOptional(tag, OptionalFormat.F8)) 1660 { 1661 v = readLong(); 1662 } 1663 else 1664 { 1665 v = 0; 1666 } 1667 } 1668 1669 /// <summary> 1670 /// Extracts a sequence of long values from the stream. 1671 /// </summary> 1672 /// <returns>The extracted long sequence.</returns> readLongSeq()1673 public long[] readLongSeq() 1674 { 1675 try 1676 { 1677 int sz = readAndCheckSeqSize(8); 1678 long[] v = new long[sz]; 1679 _buf.b.getLongSeq(v); 1680 return v; 1681 } 1682 catch(InvalidOperationException ex) 1683 { 1684 throw new UnmarshalOutOfBoundsException(ex); 1685 } 1686 } 1687 1688 /// <summary> 1689 /// Extracts a sequence of long values from the stream. 1690 /// </summary> 1691 /// <param name="l">The extracted long sequence as a list.</param> readLongSeq(out List<long> l)1692 public void readLongSeq(out List<long> l) 1693 { 1694 // 1695 // Reading into an array and copy-constructing the 1696 // list is faster than constructing the list 1697 // and adding to it one element at a time. 1698 // 1699 l = new List<long>(readLongSeq()); 1700 } 1701 1702 /// <summary> 1703 /// Extracts a sequence of long values from the stream. 1704 /// </summary> 1705 /// <param name="l">The extracted long sequence as a linked list.</param> readLongSeq(out LinkedList<long> l)1706 public void readLongSeq(out LinkedList<long> l) 1707 { 1708 try 1709 { 1710 int sz = readAndCheckSeqSize(4); 1711 l = new LinkedList<long>(); 1712 for(int i = 0; i < sz; ++i) 1713 { 1714 l.AddLast(_buf.b.getLong()); 1715 } 1716 } 1717 catch(InvalidOperationException ex) 1718 { 1719 throw new UnmarshalOutOfBoundsException(ex); 1720 } 1721 } 1722 1723 /// <summary> 1724 /// Extracts a sequence of long values from the stream. 1725 /// </summary> 1726 /// <param name="l">The extracted long sequence as a queue.</param> readLongSeq(out Queue<long> l)1727 public void readLongSeq(out Queue<long> l) 1728 { 1729 // 1730 // Reading into an array and copy-constructing the 1731 // queue takes the same time as constructing the queue 1732 // and adding to it one element at a time, so 1733 // we avoid the copy. 1734 // 1735 try 1736 { 1737 int sz = readAndCheckSeqSize(4); 1738 l = new Queue<long>(sz); 1739 for(int i = 0; i < sz; ++i) 1740 { 1741 l.Enqueue(_buf.b.getLong()); 1742 } 1743 } 1744 catch(InvalidOperationException ex) 1745 { 1746 throw new UnmarshalOutOfBoundsException(ex); 1747 } 1748 } 1749 1750 /// <summary> 1751 /// Extracts a sequence of long values from the stream. 1752 /// </summary> 1753 /// <param name="l">The extracted long sequence as a stack.</param> readLongSeq(out Stack<long> l)1754 public void readLongSeq(out Stack<long> l) 1755 { 1756 // 1757 // Reverse the contents by copying into an array first 1758 // because the stack is marshaled in top-to-bottom order. 1759 // 1760 long[] array = readLongSeq(); 1761 Array.Reverse(array); 1762 l = new Stack<long>(array); 1763 } 1764 1765 /// <summary> 1766 /// Extracts an optional long sequence from the stream. 1767 /// </summary> 1768 /// <param name="tag">The numeric tag associated with the value.</param> 1769 /// <returns>The optional value.</returns> readLongSeq(int tag)1770 public Optional<long[]> readLongSeq(int tag) 1771 { 1772 if(readOptional(tag, OptionalFormat.VSize)) 1773 { 1774 skipSize(); 1775 return new Optional<long[]>(readLongSeq()); 1776 } 1777 else 1778 { 1779 return new Optional<long[]>(); 1780 } 1781 } 1782 1783 /// <summary> 1784 /// Extracts an optional long sequence from the stream. 1785 /// </summary> 1786 /// <param name="tag">The numeric tag associated with the value.</param> 1787 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1788 /// <param name="v">The optional value.</param> readLongSeq(int tag, out bool isset, out long[] v)1789 public void readLongSeq(int tag, out bool isset, out long[] v) 1790 { 1791 if(isset = readOptional(tag, OptionalFormat.VSize)) 1792 { 1793 skipSize(); 1794 v = readLongSeq(); 1795 } 1796 else 1797 { 1798 v = null; 1799 } 1800 } 1801 1802 /// <summary> 1803 /// Extracts a float value from the stream. 1804 /// </summary> 1805 /// <returns>The extracted float.</returns> readFloat()1806 public float readFloat() 1807 { 1808 try 1809 { 1810 return _buf.b.getFloat(); 1811 } 1812 catch(InvalidOperationException ex) 1813 { 1814 throw new UnmarshalOutOfBoundsException(ex); 1815 } 1816 } 1817 1818 /// <summary> 1819 /// Extracts an optional float value from the stream. 1820 /// </summary> 1821 /// <param name="tag">The numeric tag associated with the value.</param> 1822 /// <returns>The optional value.</returns> readFloat(int tag)1823 public Optional<float> readFloat(int tag) 1824 { 1825 if(readOptional(tag, OptionalFormat.F4)) 1826 { 1827 return new Optional<float>(readFloat()); 1828 } 1829 else 1830 { 1831 return new Optional<float>(); 1832 } 1833 } 1834 1835 /// <summary> 1836 /// Extracts an optional float value from the stream. 1837 /// </summary> 1838 /// <param name="tag">The numeric tag associated with the value.</param> 1839 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1840 /// <param name="v">The optional value.</param> readFloat(int tag, out bool isset, out float v)1841 public void readFloat(int tag, out bool isset, out float v) 1842 { 1843 if(isset = readOptional(tag, OptionalFormat.F4)) 1844 { 1845 v = readFloat(); 1846 } 1847 else 1848 { 1849 v = 0; 1850 } 1851 } 1852 1853 /// <summary> 1854 /// Extracts a sequence of float values from the stream. 1855 /// </summary> 1856 /// <returns>The extracted float sequence.</returns> readFloatSeq()1857 public float[] readFloatSeq() 1858 { 1859 try 1860 { 1861 int sz = readAndCheckSeqSize(4); 1862 float[] v = new float[sz]; 1863 _buf.b.getFloatSeq(v); 1864 return v; 1865 } 1866 catch(InvalidOperationException ex) 1867 { 1868 throw new UnmarshalOutOfBoundsException(ex); 1869 } 1870 } 1871 1872 /// <summary> 1873 /// Extracts a sequence of float values from the stream. 1874 /// </summary> 1875 /// <param name="l">The extracted float sequence as a list.</param> readFloatSeq(out List<float> l)1876 public void readFloatSeq(out List<float> l) 1877 { 1878 // 1879 // Reading into an array and copy-constructing the 1880 // list is faster than constructing the list 1881 // and adding to it one element at a time. 1882 // 1883 l = new List<float>(readFloatSeq()); 1884 } 1885 1886 /// <summary> 1887 /// Extracts a sequence of float values from the stream. 1888 /// </summary> 1889 /// <param name="l">The extracted float sequence as a linked list.</param> readFloatSeq(out LinkedList<float> l)1890 public void readFloatSeq(out LinkedList<float> l) 1891 { 1892 try 1893 { 1894 int sz = readAndCheckSeqSize(4); 1895 l = new LinkedList<float>(); 1896 for(int i = 0; i < sz; ++i) 1897 { 1898 l.AddLast(_buf.b.getFloat()); 1899 } 1900 } 1901 catch(InvalidOperationException ex) 1902 { 1903 throw new UnmarshalOutOfBoundsException(ex); 1904 } 1905 } 1906 1907 /// <summary> 1908 /// Extracts a sequence of float values from the stream. 1909 /// </summary> 1910 /// <param name="l">The extracted float sequence as a queue.</param> readFloatSeq(out Queue<float> l)1911 public void readFloatSeq(out Queue<float> l) 1912 { 1913 // 1914 // Reading into an array and copy-constructing the 1915 // queue takes the same time as constructing the queue 1916 // and adding to it one element at a time, so 1917 // we avoid the copy. 1918 // 1919 try 1920 { 1921 int sz = readAndCheckSeqSize(4); 1922 l = new Queue<float>(sz); 1923 for(int i = 0; i < sz; ++i) 1924 { 1925 l.Enqueue(_buf.b.getFloat()); 1926 } 1927 } 1928 catch(InvalidOperationException ex) 1929 { 1930 throw new UnmarshalOutOfBoundsException(ex); 1931 } 1932 } 1933 1934 /// <summary> 1935 /// Extracts a sequence of float values from the stream. 1936 /// </summary> 1937 /// <param name="l">The extracted float sequence as a stack.</param> readFloatSeq(out Stack<float> l)1938 public void readFloatSeq(out Stack<float> l) 1939 { 1940 // 1941 // Reverse the contents by copying into an array first 1942 // because the stack is marshaled in top-to-bottom order. 1943 // 1944 float[] array = readFloatSeq(); 1945 Array.Reverse(array); 1946 l = new Stack<float>(array); 1947 } 1948 1949 /// <summary> 1950 /// Extracts an optional float sequence from the stream. 1951 /// </summary> 1952 /// <param name="tag">The numeric tag associated with the value.</param> 1953 /// <returns>The optional value.</returns> readFloatSeq(int tag)1954 public Optional<float[]> readFloatSeq(int tag) 1955 { 1956 if(readOptional(tag, OptionalFormat.VSize)) 1957 { 1958 skipSize(); 1959 return new Optional<float[]>(readFloatSeq()); 1960 } 1961 else 1962 { 1963 return new Optional<float[]>(); 1964 } 1965 } 1966 1967 /// <summary> 1968 /// Extracts an optional float sequence from the stream. 1969 /// </summary> 1970 /// <param name="tag">The numeric tag associated with the value.</param> 1971 /// <param name="isset">True if the optional value is present, false otherwise.</param> 1972 /// <param name="v">The optional value.</param> readFloatSeq(int tag, out bool isset, out float[] v)1973 public void readFloatSeq(int tag, out bool isset, out float[] v) 1974 { 1975 if(isset = readOptional(tag, OptionalFormat.VSize)) 1976 { 1977 skipSize(); 1978 v = readFloatSeq(); 1979 } 1980 else 1981 { 1982 v = null; 1983 } 1984 } 1985 1986 /// <summary> 1987 /// Extracts a double value from the stream. 1988 /// </summary> 1989 /// <returns>The extracted double.</returns> readDouble()1990 public double readDouble() 1991 { 1992 try 1993 { 1994 return _buf.b.getDouble(); 1995 } 1996 catch(InvalidOperationException ex) 1997 { 1998 throw new UnmarshalOutOfBoundsException(ex); 1999 } 2000 } 2001 2002 /// <summary> 2003 /// Extracts an optional double value from the stream. 2004 /// </summary> 2005 /// <param name="tag">The numeric tag associated with the value.</param> 2006 /// <returns>The optional value.</returns> readDouble(int tag)2007 public Optional<double> readDouble(int tag) 2008 { 2009 if(readOptional(tag, OptionalFormat.F8)) 2010 { 2011 return new Optional<double>(readDouble()); 2012 } 2013 else 2014 { 2015 return new Optional<double>(); 2016 } 2017 } 2018 2019 /// <summary> 2020 /// Extracts an optional double value from the stream. 2021 /// </summary> 2022 /// <param name="tag">The numeric tag associated with the value.</param> 2023 /// <param name="isset">True if the optional value is present, false otherwise.</param> 2024 /// <param name="v">The optional value.</param> readDouble(int tag, out bool isset, out double v)2025 public void readDouble(int tag, out bool isset, out double v) 2026 { 2027 if(isset = readOptional(tag, OptionalFormat.F8)) 2028 { 2029 v = readDouble(); 2030 } 2031 else 2032 { 2033 v = 0; 2034 } 2035 } 2036 2037 /// <summary> 2038 /// Extracts a sequence of double values from the stream. 2039 /// </summary> 2040 /// <returns>The extracted double sequence.</returns> readDoubleSeq()2041 public double[] readDoubleSeq() 2042 { 2043 try 2044 { 2045 int sz = readAndCheckSeqSize(8); 2046 double[] v = new double[sz]; 2047 _buf.b.getDoubleSeq(v); 2048 return v; 2049 } 2050 catch(InvalidOperationException ex) 2051 { 2052 throw new UnmarshalOutOfBoundsException(ex); 2053 } 2054 } 2055 2056 /// <summary> 2057 /// Extracts a sequence of double values from the stream. 2058 /// </summary> 2059 /// <param name="l">The extracted double sequence as a list.</param> readDoubleSeq(out List<double> l)2060 public void readDoubleSeq(out List<double> l) 2061 { 2062 // 2063 // Reading into an array and copy-constructing the 2064 // list is faster than constructing the list 2065 // and adding to it one element at a time. 2066 // 2067 l = new List<double>(readDoubleSeq()); 2068 } 2069 2070 /// <summary> 2071 /// Extracts a sequence of double values from the stream. 2072 /// </summary> 2073 /// <param name="l">The extracted double sequence as a linked list.</param> readDoubleSeq(out LinkedList<double> l)2074 public void readDoubleSeq(out LinkedList<double> l) 2075 { 2076 try 2077 { 2078 int sz = readAndCheckSeqSize(4); 2079 l = new LinkedList<double>(); 2080 for(int i = 0; i < sz; ++i) 2081 { 2082 l.AddLast(_buf.b.getDouble()); 2083 } 2084 } 2085 catch(InvalidOperationException ex) 2086 { 2087 throw new UnmarshalOutOfBoundsException(ex); 2088 } 2089 } 2090 2091 /// <summary> 2092 /// Extracts a sequence of double values from the stream. 2093 /// </summary> 2094 /// <param name="l">The extracted double sequence as a queue.</param> readDoubleSeq(out Queue<double> l)2095 public void readDoubleSeq(out Queue<double> l) 2096 { 2097 // 2098 // Reading into an array and copy-constructing the 2099 // queue takes the same time as constructing the queue 2100 // and adding to it one element at a time, so 2101 // we avoid the copy. 2102 // 2103 try 2104 { 2105 int sz = readAndCheckSeqSize(4); 2106 l = new Queue<double>(sz); 2107 for(int i = 0; i < sz; ++i) 2108 { 2109 l.Enqueue(_buf.b.getDouble()); 2110 } 2111 } 2112 catch(InvalidOperationException ex) 2113 { 2114 throw new UnmarshalOutOfBoundsException(ex); 2115 } 2116 } 2117 2118 /// <summary> 2119 /// Extracts a sequence of double values from the stream. 2120 /// </summary> 2121 /// <param name="l">The extracted double sequence as a stack.</param> readDoubleSeq(out Stack<double> l)2122 public void readDoubleSeq(out Stack<double> l) 2123 { 2124 // 2125 // Reverse the contents by copying into an array first 2126 // because the stack is marshaled in top-to-bottom order. 2127 // 2128 double[] array = readDoubleSeq(); 2129 Array.Reverse(array); 2130 l = new Stack<double>(array); 2131 } 2132 2133 /// <summary> 2134 /// Extracts an optional double sequence from the stream. 2135 /// </summary> 2136 /// <param name="tag">The numeric tag associated with the value.</param> 2137 /// <returns>The optional value.</returns> readDoubleSeq(int tag)2138 public Optional<double[]> readDoubleSeq(int tag) 2139 { 2140 if(readOptional(tag, OptionalFormat.VSize)) 2141 { 2142 skipSize(); 2143 return new Optional<double[]>(readDoubleSeq()); 2144 } 2145 else 2146 { 2147 return new Optional<double[]>(); 2148 } 2149 } 2150 2151 /// <summary> 2152 /// Extracts an optional double sequence from the stream. 2153 /// </summary> 2154 /// <param name="tag">The numeric tag associated with the value.</param> 2155 /// <param name="isset">True if the optional value is present, false otherwise.</param> 2156 /// <param name="v">The optional value.</param> readDoubleSeq(int tag, out bool isset, out double[] v)2157 public void readDoubleSeq(int tag, out bool isset, out double[] v) 2158 { 2159 if(isset = readOptional(tag, OptionalFormat.VSize)) 2160 { 2161 skipSize(); 2162 v = readDoubleSeq(); 2163 } 2164 else 2165 { 2166 v = null; 2167 } 2168 } 2169 2170 private static System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true); 2171 2172 /// <summary> 2173 /// Extracts a string from the stream. 2174 /// </summary> 2175 /// <returns>The extracted string.</returns> readString()2176 public string readString() 2177 { 2178 int len = readSize(); 2179 2180 if(len == 0) 2181 { 2182 return ""; 2183 } 2184 2185 // 2186 // Check the buffer has enough bytes to read. 2187 // 2188 if(_buf.b.remaining() < len) 2189 { 2190 throw new UnmarshalOutOfBoundsException(); 2191 } 2192 2193 try 2194 { 2195 // 2196 // We reuse the _stringBytes array to avoid creating 2197 // excessive garbage 2198 // 2199 if(_stringBytes == null || len > _stringBytes.Length) 2200 { 2201 _stringBytes = new byte[len]; 2202 } 2203 _buf.b.get(_stringBytes, 0, len); 2204 return utf8.GetString(_stringBytes, 0, len); 2205 } 2206 catch(InvalidOperationException ex) 2207 { 2208 throw new UnmarshalOutOfBoundsException(ex); 2209 } 2210 catch(ArgumentException ex) 2211 { 2212 throw new MarshalException("Invalid UTF8 string", ex); 2213 } 2214 } 2215 2216 /// <summary> 2217 /// Extracts an optional string from the stream. 2218 /// </summary> 2219 /// <param name="tag">The numeric tag associated with the value.</param> 2220 /// <returns>The optional value.</returns> readString(int tag)2221 public Optional<string> readString(int tag) 2222 { 2223 if(readOptional(tag, OptionalFormat.VSize)) 2224 { 2225 return new Optional<string>(readString()); 2226 } 2227 else 2228 { 2229 return new Optional<string>(); 2230 } 2231 } 2232 2233 /// <summary> 2234 /// Extracts an optional string from the stream. 2235 /// </summary> 2236 /// <param name="tag">The numeric tag associated with the value.</param> 2237 /// <param name="isset">True if the optional value is present, false otherwise.</param> 2238 /// <param name="v">The optional value.</param> readString(int tag, out bool isset, out string v)2239 public void readString(int tag, out bool isset, out string v) 2240 { 2241 if(isset = readOptional(tag, OptionalFormat.VSize)) 2242 { 2243 v = readString(); 2244 } 2245 else 2246 { 2247 v = null; 2248 } 2249 } 2250 2251 /// <summary> 2252 /// Extracts a sequence of strings from the stream. 2253 /// </summary> 2254 /// <returns>The extracted string sequence.</returns> readStringSeq()2255 public string[] readStringSeq() 2256 { 2257 int sz = readAndCheckSeqSize(1); 2258 string[] v = new string[sz]; 2259 for(int i = 0; i < sz; i++) 2260 { 2261 v[i] = readString(); 2262 } 2263 return v; 2264 } 2265 2266 /// <summary> 2267 /// Extracts a sequence of strings from the stream. 2268 /// </summary> 2269 /// <param name="l">The extracted string sequence as a list.</param> readStringSeq(out List<string> l)2270 public void readStringSeq(out List<string> l) 2271 { 2272 // 2273 // Reading into an array and copy-constructing the 2274 // list is slower than constructing the list 2275 // and adding to it one element at a time. 2276 // 2277 int sz = readAndCheckSeqSize(1); 2278 l = new List<string>(sz); 2279 for(int i = 0; i < sz; ++i) 2280 { 2281 l.Add(readString()); 2282 } 2283 } 2284 2285 /// <summary> 2286 /// Extracts a sequence of strings from the stream. 2287 /// </summary> 2288 /// <param name="l">The extracted string sequence as a linked list.</param> readStringSeq(out LinkedList<string> l)2289 public void readStringSeq(out LinkedList<string> l) 2290 { 2291 // 2292 // Reading into an array and copy-constructing the 2293 // list is slower than constructing the list 2294 // and adding to it one element at a time. 2295 // 2296 int sz = readAndCheckSeqSize(1); 2297 l = new LinkedList<string>(); 2298 for(int i = 0; i < sz; ++i) 2299 { 2300 l.AddLast(readString()); 2301 } 2302 } 2303 2304 /// <summary> 2305 /// Extracts a sequence of strings from the stream. 2306 /// </summary> 2307 /// <param name="l">The extracted string sequence as a queue.</param> readStringSeq(out Queue<string> l)2308 public void readStringSeq(out Queue<string> l) 2309 { 2310 // 2311 // Reading into an array and copy-constructing the 2312 // queue is slower than constructing the queue 2313 // and adding to it one element at a time. 2314 // 2315 int sz = readAndCheckSeqSize(1); 2316 l = new Queue<string>(); 2317 for(int i = 0; i < sz; ++i) 2318 { 2319 l.Enqueue(readString()); 2320 } 2321 } 2322 2323 /// <summary> 2324 /// Extracts a sequence of strings from the stream. 2325 /// </summary> 2326 /// <param name="l">The extracted string sequence as a stack.</param> readStringSeq(out Stack<string> l)2327 public void readStringSeq(out Stack<string> l) 2328 { 2329 // 2330 // Reverse the contents by copying into an array first 2331 // because the stack is marshaled in top-to-bottom order. 2332 // 2333 string[] array = readStringSeq(); 2334 Array.Reverse(array); 2335 l = new Stack<string>(array); 2336 } 2337 2338 /// <summary> 2339 /// Extracts an optional string sequence from the stream. 2340 /// </summary> 2341 /// <param name="tag">The numeric tag associated with the value.</param> 2342 /// <returns>The optional value.</returns> readStringSeq(int tag)2343 public Optional<string[]> readStringSeq(int tag) 2344 { 2345 if(readOptional(tag, OptionalFormat.FSize)) 2346 { 2347 skip(4); 2348 return new Optional<string[]>(readStringSeq()); 2349 } 2350 else 2351 { 2352 return new Optional<string[]>(); 2353 } 2354 } 2355 2356 /// <summary> 2357 /// Extracts an optional string sequence from the stream. 2358 /// </summary> 2359 /// <param name="tag">The numeric tag associated with the value.</param> 2360 /// <param name="isset">True if the optional value is present, false otherwise.</param> 2361 /// <param name="v">The optional value.</param> readStringSeq(int tag, out bool isset, out string[] v)2362 public void readStringSeq(int tag, out bool isset, out string[] v) 2363 { 2364 if(isset = readOptional(tag, OptionalFormat.FSize)) 2365 { 2366 skip(4); 2367 v = readStringSeq(); 2368 } 2369 else 2370 { 2371 v = null; 2372 } 2373 } 2374 2375 /// <summary> 2376 /// Extracts a proxy from the stream. The stream must have been initialized with a communicator. 2377 /// </summary> 2378 /// <returns>The extracted proxy.</returns> readProxy()2379 public ObjectPrx readProxy() 2380 { 2381 return _instance.proxyFactory().streamToProxy(this); 2382 } 2383 2384 /// <summary> 2385 /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator. 2386 /// </summary> 2387 /// <param name="tag">The numeric tag associated with the value.</param> 2388 /// <returns>The optional value.</returns> readProxy(int tag)2389 public Optional<ObjectPrx> readProxy(int tag) 2390 { 2391 if(readOptional(tag, OptionalFormat.FSize)) 2392 { 2393 skip(4); 2394 return new Optional<ObjectPrx>(readProxy()); 2395 } 2396 else 2397 { 2398 return new Optional<ObjectPrx>(); 2399 } 2400 } 2401 2402 /// <summary> 2403 /// Extracts an optional proxy from the stream. The stream must have been initialized with a communicator. 2404 /// </summary> 2405 /// <param name="tag">The numeric tag associated with the value.</param> 2406 /// <param name="isset">True if the optional value is present, false otherwise.</param> 2407 /// <param name="v">The optional value.</param> readProxy(int tag, out bool isset, out ObjectPrx v)2408 public void readProxy(int tag, out bool isset, out ObjectPrx v) 2409 { 2410 if(isset = readOptional(tag, OptionalFormat.FSize)) 2411 { 2412 skip(4); 2413 v = readProxy(); 2414 } 2415 else 2416 { 2417 v = null; 2418 } 2419 } 2420 2421 /// <summary> 2422 /// Read an enumerated value. 2423 /// </summary> 2424 /// <param name="maxValue">The maximum enumerator value in the definition.</param> 2425 /// <returns>The enumerator.</returns> readEnum(int maxValue)2426 public int readEnum(int maxValue) 2427 { 2428 if(getEncoding().Equals(Util.Encoding_1_0)) 2429 { 2430 if(maxValue < 127) 2431 { 2432 return readByte(); 2433 } 2434 else if(maxValue < 32767) 2435 { 2436 return readShort(); 2437 } 2438 else 2439 { 2440 return readInt(); 2441 } 2442 } 2443 else 2444 { 2445 return readSize(); 2446 } 2447 } 2448 2449 /// <summary> 2450 /// Extracts the index of a Slice value from the stream. 2451 /// </summary> 2452 /// <param name="cb">The callback to notify the application when the extracted instance is available. 2453 /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the 2454 /// corresponding instance has been fully unmarshaled.</param> 2455 public void readValue<T>(System.Action<T> cb) where T : Value 2456 { 2457 readValue(v => { 2458 if(v == null || v is T) 2459 { 2460 cb((T)v); 2461 } 2462 else 2463 { 2464 IceInternal.Ex.throwUOE(typeof(T), v); 2465 } 2466 }); 2467 } 2468 2469 /// <summary> 2470 /// Extracts the index of a Slice value from the stream. 2471 /// </summary> 2472 /// <param name="cb">The callback to notify the application when the extracted instance is available. 2473 /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the 2474 /// corresponding instance has been fully unmarshaled.</param> readValue(System.Action<Value> cb)2475 public void readValue(System.Action<Value> cb) 2476 { 2477 initEncaps(); 2478 _encapsStack.decoder.readValue(cb); 2479 } 2480 2481 /// <summary> 2482 /// Extracts the index of an optional Slice value from the stream. 2483 /// </summary> 2484 /// <param name="tag">The numeric tag associated with the value.</param> 2485 /// <param name="cb">The callback to notify the application when the extracted instance is available (if any). 2486 /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the 2487 /// corresponding instance has been fully unmarshaled.</param> 2488 public void readValue<T>(int tag, System.Action<T> cb) where T : Value 2489 { 2490 readValue(tag, v => { 2491 if(v == null || v is T) 2492 { 2493 cb((T)v); 2494 } 2495 else 2496 { 2497 IceInternal.Ex.throwUOE(typeof(T), v); 2498 } 2499 }); 2500 } 2501 2502 /// <summary> 2503 /// Extracts the index of an optional Slice value from the stream. 2504 /// </summary> 2505 /// <param name="tag">The numeric tag associated with the value.</param> 2506 /// <param name="cb">The callback to notify the application when the extracted instance is available (if any). 2507 /// The stream extracts Slice values in stages. The Ice run time invokes the delegate when the 2508 /// corresponding instance has been fully unmarshaled.</param> readValue(int tag, System.Action<Value> cb)2509 public void readValue(int tag, System.Action<Value> cb) 2510 { 2511 if(readOptional(tag, OptionalFormat.Class)) 2512 { 2513 readValue(cb); 2514 } 2515 } 2516 2517 /// <summary> 2518 /// Extracts a user exception from the stream and throws it. 2519 /// </summary> throwException()2520 public void throwException() 2521 { 2522 throwException(null); 2523 } 2524 2525 /// <summary> 2526 /// Extracts a user exception from the stream and throws it. 2527 /// </summary> 2528 /// <param name="factory">The user exception factory, or null to use the stream's default behavior.</param> throwException(UserExceptionFactory factory)2529 public void throwException(UserExceptionFactory factory) 2530 { 2531 initEncaps(); 2532 _encapsStack.decoder.throwException(factory); 2533 } 2534 2535 /// <summary> 2536 /// Skip the given number of bytes. 2537 /// </summary> 2538 /// <param name="size">The number of bytes to skip</param> skip(int size)2539 public void skip(int size) 2540 { 2541 if(size < 0 || size > _buf.b.remaining()) 2542 { 2543 throw new UnmarshalOutOfBoundsException(); 2544 } 2545 _buf.b.position(_buf.b.position() + size); 2546 } 2547 2548 /// <summary> 2549 /// Skip over a size value. 2550 /// </summary> skipSize()2551 public void skipSize() 2552 { 2553 byte b = readByte(); 2554 if(b == 255) 2555 { 2556 skip(4); 2557 } 2558 } 2559 2560 /// <summary> 2561 /// Determines the current position in the stream. 2562 /// </summary> 2563 /// <returns>The current position.</returns> pos()2564 public int pos() 2565 { 2566 return _buf.b.position(); 2567 } 2568 2569 /// <summary> 2570 /// Sets the current position in the stream. 2571 /// </summary> 2572 /// <param name="n">The new position.</param> pos(int n)2573 public void pos(int n) 2574 { 2575 _buf.b.position(n); 2576 } 2577 2578 /// <summary> 2579 /// Determines the current size of the stream. 2580 /// </summary> 2581 /// <returns>The current size.</returns> size()2582 public int size() 2583 { 2584 return _buf.size(); 2585 } 2586 2587 /// <summary> 2588 /// Determines whether the stream is empty. 2589 /// </summary> 2590 /// <returns>True if the internal buffer has no data, false otherwise.</returns> isEmpty()2591 public bool isEmpty() 2592 { 2593 return _buf.empty(); 2594 } 2595 readOptImpl(int readTag, OptionalFormat expectedFormat)2596 private bool readOptImpl(int readTag, OptionalFormat expectedFormat) 2597 { 2598 if(isEncoding_1_0()) 2599 { 2600 return false; // Optional members aren't supported with the 1.0 encoding. 2601 } 2602 2603 while(true) 2604 { 2605 if(_buf.b.position() >= _encapsStack.start + _encapsStack.sz) 2606 { 2607 return false; // End of encapsulation also indicates end of optionals. 2608 } 2609 2610 int v = readByte(); 2611 if(v == Protocol.OPTIONAL_END_MARKER) 2612 { 2613 _buf.b.position(_buf.b.position() - 1); // Rewind. 2614 return false; 2615 } 2616 2617 OptionalFormat format = (OptionalFormat)(v & 0x07); // First 3 bits. 2618 int tag = v >> 3; 2619 if(tag == 30) 2620 { 2621 tag = readSize(); 2622 } 2623 2624 if(tag > readTag) 2625 { 2626 int offset = tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind 2627 _buf.b.position(_buf.b.position() - offset); 2628 return false; // No optional data members with the requested tag. 2629 } 2630 else if(tag < readTag) 2631 { 2632 skipOptional(format); // Skip optional data members 2633 } 2634 else 2635 { 2636 if(format != expectedFormat) 2637 { 2638 throw new MarshalException("invalid optional data member `" + tag + "': unexpected format"); 2639 } 2640 return true; 2641 } 2642 } 2643 } 2644 skipOptional(OptionalFormat format)2645 private void skipOptional(OptionalFormat format) 2646 { 2647 switch(format) 2648 { 2649 case OptionalFormat.F1: 2650 { 2651 skip(1); 2652 break; 2653 } 2654 case OptionalFormat.F2: 2655 { 2656 skip(2); 2657 break; 2658 } 2659 case OptionalFormat.F4: 2660 { 2661 skip(4); 2662 break; 2663 } 2664 case OptionalFormat.F8: 2665 { 2666 skip(8); 2667 break; 2668 } 2669 case OptionalFormat.Size: 2670 { 2671 skipSize(); 2672 break; 2673 } 2674 case OptionalFormat.VSize: 2675 { 2676 skip(readSize()); 2677 break; 2678 } 2679 case OptionalFormat.FSize: 2680 { 2681 skip(readInt()); 2682 break; 2683 } 2684 case OptionalFormat.Class: 2685 { 2686 readValue(null); 2687 break; 2688 } 2689 } 2690 } 2691 skipOptionals()2692 private bool skipOptionals() 2693 { 2694 // 2695 // Skip remaining un-read optional members. 2696 // 2697 while(true) 2698 { 2699 if(_buf.b.position() >= _encapsStack.start + _encapsStack.sz) 2700 { 2701 return false; // End of encapsulation also indicates end of optionals. 2702 } 2703 2704 int v = readByte(); 2705 if(v == Protocol.OPTIONAL_END_MARKER) 2706 { 2707 return true; 2708 } 2709 2710 OptionalFormat format = (OptionalFormat)(v & 0x07); // Read first 3 bits. 2711 if((v >> 3) == 30) 2712 { 2713 skipSize(); 2714 } 2715 skipOptional(format); 2716 } 2717 } 2718 createUserException(string id)2719 private UserException createUserException(string id) 2720 { 2721 UserException userEx = null; 2722 2723 try 2724 { 2725 if(_classResolver != null) 2726 { 2727 Type c = _classResolver(id); 2728 if(c != null) 2729 { 2730 Debug.Assert(!c.IsAbstract && !c.IsInterface); 2731 userEx = (UserException)IceInternal.AssemblyUtil.createInstance(c); 2732 } 2733 } 2734 } 2735 catch(Exception ex) 2736 { 2737 throw new MarshalException(ex); 2738 } 2739 2740 return userEx; 2741 } 2742 2743 private IceInternal.Instance _instance; 2744 private IceInternal.Buffer _buf; 2745 private object _closure; 2746 private byte[] _stringBytes; // Reusable array for reading strings. 2747 2748 private enum SliceType { NoSlice, ValueSlice, ExceptionSlice } 2749 2750 abstract private class EncapsDecoder 2751 { 2752 protected struct PatchEntry 2753 { PatchEntryIce.InputStream.EncapsDecoder.PatchEntry2754 public PatchEntry(System.Action<Value> cb, int classGraphDepth) 2755 { 2756 this.cb = cb; 2757 this.classGraphDepth = classGraphDepth; 2758 } 2759 2760 public System.Action<Value> cb; 2761 public int classGraphDepth; 2762 }; 2763 EncapsDecoder(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, ValueFactoryManager f, System.Func<string, Type> cr)2764 internal EncapsDecoder(InputStream stream, Encaps encaps, bool sliceValues, 2765 int classGraphDepthMax, ValueFactoryManager f, 2766 System.Func<string, Type> cr) 2767 { 2768 _stream = stream; 2769 _encaps = encaps; 2770 _sliceValues = sliceValues; 2771 _classGraphDepthMax = classGraphDepthMax; 2772 _classGraphDepth = 0; 2773 _valueFactoryManager = f; 2774 _classResolver = cr; 2775 _typeIdIndex = 0; 2776 _unmarshaledMap = new Dictionary<int, Value>(); 2777 } 2778 readValue(System.Action<Value> cb)2779 internal abstract void readValue(System.Action<Value> cb); throwException(UserExceptionFactory factory)2780 internal abstract void throwException(UserExceptionFactory factory); 2781 startInstance(SliceType type)2782 internal abstract void startInstance(SliceType type); endInstance(bool preserve)2783 internal abstract SlicedData endInstance(bool preserve); startSlice()2784 internal abstract string startSlice(); endSlice()2785 internal abstract void endSlice(); skipSlice()2786 internal abstract void skipSlice(); 2787 readOptional(int tag, OptionalFormat format)2788 internal virtual bool readOptional(int tag, OptionalFormat format) 2789 { 2790 return false; 2791 } 2792 readPendingValues()2793 internal virtual void readPendingValues() 2794 { 2795 } 2796 readTypeId(bool isIndex)2797 protected string readTypeId(bool isIndex) 2798 { 2799 if(_typeIdMap == null) 2800 { 2801 _typeIdMap = new Dictionary<int, string>(); 2802 } 2803 2804 if(isIndex) 2805 { 2806 int index = _stream.readSize(); 2807 string typeId; 2808 if(!_typeIdMap.TryGetValue(index, out typeId)) 2809 { 2810 throw new UnmarshalOutOfBoundsException(); 2811 } 2812 return typeId; 2813 } 2814 else 2815 { 2816 string typeId = _stream.readString(); 2817 _typeIdMap.Add(++_typeIdIndex, typeId); 2818 return typeId; 2819 } 2820 } 2821 resolveClass(string typeId)2822 protected Type resolveClass(string typeId) 2823 { 2824 Type cls = null; 2825 if(_typeIdCache == null) 2826 { 2827 _typeIdCache = new Dictionary<string, Type>(); // Lazy initialization. 2828 } 2829 else 2830 { 2831 _typeIdCache.TryGetValue(typeId, out cls); 2832 } 2833 2834 if(cls == typeof(EncapsDecoder)) // Marker for non-existent class. 2835 { 2836 cls = null; 2837 } 2838 else if(cls == null) 2839 { 2840 try 2841 { 2842 if(_classResolver != null) 2843 { 2844 cls = _classResolver(typeId); 2845 _typeIdCache.Add(typeId, cls != null ? cls : typeof(EncapsDecoder)); 2846 } 2847 } 2848 catch(Exception ex) 2849 { 2850 throw new NoValueFactoryException("no value factory", typeId, ex); 2851 } 2852 } 2853 2854 return cls; 2855 } 2856 newInstance(string typeId)2857 protected Value newInstance(string typeId) 2858 { 2859 // 2860 // Try to find a factory registered for the specific type. 2861 // 2862 var userFactory = _valueFactoryManager.find(typeId); 2863 Value v = null; 2864 if(userFactory != null) 2865 { 2866 v = userFactory(typeId); 2867 } 2868 2869 // 2870 // If that fails, invoke the default factory if one has been 2871 // registered. 2872 // 2873 if(v == null) 2874 { 2875 userFactory = _valueFactoryManager.find(""); 2876 if(userFactory != null) 2877 { 2878 v = userFactory(typeId); 2879 } 2880 } 2881 2882 // 2883 // Last chance: try to instantiate the class dynamically. 2884 // 2885 if(v == null) 2886 { 2887 Type cls = resolveClass(typeId); 2888 2889 if(cls != null) 2890 { 2891 try 2892 { 2893 Debug.Assert(!cls.IsAbstract && !cls.IsInterface); 2894 v = (Value)IceInternal.AssemblyUtil.createInstance(cls); 2895 } 2896 catch(Exception ex) 2897 { 2898 throw new NoValueFactoryException("no value factory", typeId, ex); 2899 } 2900 } 2901 } 2902 2903 return v; 2904 } 2905 addPatchEntry(int index, System.Action<Value> cb)2906 protected void addPatchEntry(int index, System.Action<Value> cb) 2907 { 2908 Debug.Assert(index > 0); 2909 2910 // 2911 // Check if we already unmarshaled the instance. If that's the case, 2912 // just call the callback and we're done. 2913 // 2914 Value obj; 2915 if(_unmarshaledMap.TryGetValue(index, out obj)) 2916 { 2917 cb(obj); 2918 return; 2919 } 2920 2921 if(_patchMap == null) 2922 { 2923 _patchMap = new Dictionary<int, LinkedList<PatchEntry>>(); 2924 } 2925 2926 // 2927 // Add patch entry if the instance isn't unmarshaled yet, 2928 // the callback will be called when the instance is 2929 // unmarshaled. 2930 // 2931 LinkedList<PatchEntry> l; 2932 if(!_patchMap.TryGetValue(index, out l)) 2933 { 2934 // 2935 // We have no outstanding instances to be patched for this 2936 // index, so make a new entry in the patch map. 2937 // 2938 l = new LinkedList<PatchEntry>(); 2939 _patchMap.Add(index, l); 2940 } 2941 2942 // 2943 // Append a patch entry for this instance. 2944 // 2945 l.AddLast(new PatchEntry(cb, _classGraphDepth)); 2946 } 2947 unmarshal(int index, Value v)2948 protected void unmarshal(int index, Value v) 2949 { 2950 // 2951 // Add the instance to the map of unmarshaled instances, this must 2952 // be done before reading the instances (for circular references). 2953 // 2954 _unmarshaledMap.Add(index, v); 2955 2956 // 2957 // Read the instance. 2958 // 2959 v.iceRead(_stream); 2960 2961 if(_patchMap != null) 2962 { 2963 // 2964 // Patch all instances now that the instance is unmarshaled. 2965 // 2966 LinkedList<PatchEntry> l; 2967 if(_patchMap.TryGetValue(index, out l)) 2968 { 2969 Debug.Assert(l.Count > 0); 2970 2971 // 2972 // Patch all pointers that refer to the instance. 2973 // 2974 foreach(PatchEntry entry in l) 2975 { 2976 entry.cb(v); 2977 } 2978 2979 // 2980 // Clear out the patch map for that index -- there is nothing left 2981 // to patch for that index for the time being. 2982 // 2983 _patchMap.Remove(index); 2984 } 2985 } 2986 2987 if((_patchMap == null || _patchMap.Count == 0) && _valueList == null) 2988 { 2989 try 2990 { 2991 v.ice_postUnmarshal(); 2992 } 2993 catch(System.Exception ex) 2994 { 2995 string s = "exception raised by ice_postUnmarshal:\n" + ex; 2996 _stream.instance().initializationData().logger.warning(s); 2997 } 2998 } 2999 else 3000 { 3001 if(_valueList == null) 3002 { 3003 _valueList = new List<Value>(); 3004 } 3005 _valueList.Add(v); 3006 3007 if(_patchMap == null || _patchMap.Count == 0) 3008 { 3009 // 3010 // Iterate over the instance list and invoke ice_postUnmarshal on 3011 // each instance. We must do this after all instances have been 3012 // unmarshaled in order to ensure that any instance data members 3013 // have been properly patched. 3014 // 3015 foreach(var p in _valueList) 3016 { 3017 try 3018 { 3019 p.ice_postUnmarshal(); 3020 } 3021 catch(System.Exception ex) 3022 { 3023 string s = "exception raised by ice_postUnmarshal:\n" + ex; 3024 _stream.instance().initializationData().logger.warning(s); 3025 } 3026 } 3027 _valueList.Clear(); 3028 } 3029 } 3030 } 3031 3032 protected readonly InputStream _stream; 3033 protected readonly Encaps _encaps; 3034 protected readonly bool _sliceValues; 3035 protected readonly int _classGraphDepthMax; 3036 protected int _classGraphDepth; 3037 protected ValueFactoryManager _valueFactoryManager; 3038 protected System.Func<string, Type> _classResolver; 3039 3040 // 3041 // Encapsulation attributes for object unmarshaling. 3042 // 3043 protected Dictionary<int, LinkedList<PatchEntry>> _patchMap; 3044 private Dictionary<int, Value> _unmarshaledMap; 3045 private Dictionary<int, string> _typeIdMap; 3046 private int _typeIdIndex; 3047 private List<Value> _valueList; 3048 private Dictionary<string, Type> _typeIdCache; 3049 } 3050 3051 private sealed class EncapsDecoder10 : EncapsDecoder 3052 { EncapsDecoder10(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, ValueFactoryManager f, System.Func<string, Type> cr)3053 internal EncapsDecoder10(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, 3054 ValueFactoryManager f, System.Func<string, Type> cr) 3055 : base(stream, encaps, sliceValues, classGraphDepthMax, f, cr) 3056 { 3057 _sliceType = SliceType.NoSlice; 3058 } 3059 readValue(System.Action<Value> cb)3060 internal override void readValue(System.Action<Value> cb) 3061 { 3062 Debug.Assert(cb != null); 3063 3064 // 3065 // Object references are encoded as a negative integer in 1.0. 3066 // 3067 int index = _stream.readInt(); 3068 if(index > 0) 3069 { 3070 throw new MarshalException("invalid object id"); 3071 } 3072 index = -index; 3073 3074 if(index == 0) 3075 { 3076 cb(null); 3077 } 3078 else 3079 { 3080 addPatchEntry(index, cb); 3081 } 3082 } 3083 throwException(UserExceptionFactory factory)3084 internal override void throwException(UserExceptionFactory factory) 3085 { 3086 Debug.Assert(_sliceType == SliceType.NoSlice); 3087 3088 // 3089 // User exception with the 1.0 encoding start with a bool flag 3090 // that indicates whether or not the exception has classes. 3091 // 3092 // This allows reading the pending instances even if some part of 3093 // the exception was sliced. 3094 // 3095 bool usesClasses = _stream.readBool(); 3096 3097 _sliceType = SliceType.ExceptionSlice; 3098 _skipFirstSlice = false; 3099 3100 // 3101 // Read the first slice header. 3102 // 3103 startSlice(); 3104 string mostDerivedId = _typeId; 3105 while(true) 3106 { 3107 UserException userEx = null; 3108 3109 // 3110 // Use a factory if one was provided. 3111 // 3112 if(factory != null) 3113 { 3114 try 3115 { 3116 factory(_typeId); 3117 } 3118 catch(UserException ex) 3119 { 3120 userEx = ex; 3121 } 3122 } 3123 3124 if(userEx == null) 3125 { 3126 userEx = _stream.createUserException(_typeId); 3127 } 3128 3129 // 3130 // We found the exception. 3131 // 3132 if(userEx != null) 3133 { 3134 userEx.iceRead(_stream); 3135 if(usesClasses) 3136 { 3137 readPendingValues(); 3138 } 3139 throw userEx; 3140 3141 // Never reached. 3142 } 3143 3144 // 3145 // Slice off what we don't understand. 3146 // 3147 skipSlice(); 3148 try 3149 { 3150 startSlice(); 3151 } 3152 catch(UnmarshalOutOfBoundsException ex) 3153 { 3154 // 3155 // An oversight in the 1.0 encoding means there is no marker to indicate 3156 // the last slice of an exception. As a result, we just try to read the 3157 // next type ID, which raises UnmarshalOutOfBoundsException when the 3158 // input buffer underflows. 3159 // 3160 // Set the reason member to a more helpful message. 3161 // 3162 ex.reason = "unknown exception type `" + mostDerivedId + "'"; 3163 throw; 3164 } 3165 } 3166 } 3167 startInstance(SliceType sliceType)3168 internal override void startInstance(SliceType sliceType) 3169 { 3170 Debug.Assert(_sliceType == sliceType); 3171 _skipFirstSlice = true; 3172 } 3173 endInstance(bool preserve)3174 internal override SlicedData endInstance(bool preserve) 3175 { 3176 // 3177 // Read the Ice::Object slice. 3178 // 3179 if(_sliceType == SliceType.ValueSlice) 3180 { 3181 startSlice(); 3182 int sz = _stream.readSize(); // For compatibility with the old AFM. 3183 if(sz != 0) 3184 { 3185 throw new MarshalException("invalid Object slice"); 3186 } 3187 endSlice(); 3188 } 3189 3190 _sliceType = SliceType.NoSlice; 3191 return null; 3192 } 3193 startSlice()3194 internal override string startSlice() 3195 { 3196 // 3197 // If first slice, don't read the header, it was already read in 3198 // readInstance or throwException to find the factory. 3199 // 3200 if(_skipFirstSlice) 3201 { 3202 _skipFirstSlice = false; 3203 return _typeId; 3204 } 3205 3206 // 3207 // For instances, first read the type ID bool which indicates 3208 // whether or not the type ID is encoded as a string or as an 3209 // index. For exceptions, the type ID is always encoded as a 3210 // string. 3211 // 3212 if(_sliceType == SliceType.ValueSlice) // For exceptions, the type ID is always encoded as a string 3213 { 3214 bool isIndex = _stream.readBool(); 3215 _typeId = readTypeId(isIndex); 3216 } 3217 else 3218 { 3219 _typeId = _stream.readString(); 3220 } 3221 3222 _sliceSize = _stream.readInt(); 3223 if(_sliceSize < 4) 3224 { 3225 throw new UnmarshalOutOfBoundsException(); 3226 } 3227 3228 return _typeId; 3229 } 3230 endSlice()3231 internal override void endSlice() 3232 { 3233 } 3234 skipSlice()3235 internal override void skipSlice() 3236 { 3237 if(_stream.instance().traceLevels().slicing > 0) 3238 { 3239 Logger logger = _stream.instance().initializationData().logger; 3240 string slicingCat = _stream.instance().traceLevels().slicingCat; 3241 if(_sliceType == SliceType.ValueSlice) 3242 { 3243 IceInternal.TraceUtil.traceSlicing("object", _typeId, slicingCat, logger); 3244 } 3245 else 3246 { 3247 IceInternal.TraceUtil.traceSlicing("exception", _typeId, slicingCat, logger); 3248 } 3249 } 3250 3251 Debug.Assert(_sliceSize >= 4); 3252 _stream.skip(_sliceSize - 4); 3253 } 3254 readPendingValues()3255 internal override void readPendingValues() 3256 { 3257 int num; 3258 do 3259 { 3260 num = _stream.readSize(); 3261 for(int k = num; k > 0; --k) 3262 { 3263 readInstance(); 3264 } 3265 } 3266 while(num > 0); 3267 3268 if(_patchMap != null && _patchMap.Count > 0) 3269 { 3270 // 3271 // If any entries remain in the patch map, the sender has sent an index for an instance, but failed 3272 // to supply the instance. 3273 // 3274 throw new MarshalException("index for class received, but no instance"); 3275 } 3276 } 3277 readInstance()3278 private void readInstance() 3279 { 3280 int index = _stream.readInt(); 3281 3282 if(index <= 0) 3283 { 3284 throw new MarshalException("invalid object id"); 3285 } 3286 3287 _sliceType = SliceType.ValueSlice; 3288 _skipFirstSlice = false; 3289 3290 // 3291 // Read the first slice header. 3292 // 3293 startSlice(); 3294 string mostDerivedId = _typeId; 3295 Value v = null; 3296 while(true) 3297 { 3298 // 3299 // For the 1.0 encoding, the type ID for the base Object class 3300 // marks the last slice. 3301 // 3302 if(_typeId.Equals(Value.ice_staticId())) 3303 { 3304 throw new NoValueFactoryException("", mostDerivedId); 3305 } 3306 3307 v = newInstance(_typeId); 3308 3309 // 3310 // We found a factory, we get out of this loop. 3311 // 3312 if(v != null) 3313 { 3314 break; 3315 } 3316 3317 // 3318 // If slicing is disabled, stop unmarshaling. 3319 // 3320 if(!_sliceValues) 3321 { 3322 throw new NoValueFactoryException("no value factory found and slicing is disabled", _typeId); 3323 } 3324 3325 // 3326 // Slice off what we don't understand. 3327 // 3328 skipSlice(); 3329 startSlice(); // Read next Slice header for next iteration. 3330 } 3331 3332 // 3333 // Compute the biggest class graph depth of this object. To compute this, 3334 // we get the class graph depth of each ancestor from the patch map and 3335 // keep the biggest one. 3336 // 3337 _classGraphDepth = 0; 3338 LinkedList<PatchEntry> l; 3339 if(_patchMap != null && _patchMap.TryGetValue(index, out l)) 3340 { 3341 Debug.Assert(l.Count > 0); 3342 foreach(PatchEntry entry in l) 3343 { 3344 if(entry.classGraphDepth > _classGraphDepth) 3345 { 3346 _classGraphDepth = entry.classGraphDepth; 3347 } 3348 } 3349 } 3350 3351 if(++_classGraphDepth > _classGraphDepthMax) 3352 { 3353 throw new MarshalException("maximum class graph depth reached"); 3354 } 3355 3356 // 3357 // Unmarshal the instance and add it to the map of unmarshaled instances. 3358 // 3359 unmarshal(index, v); 3360 } 3361 3362 // Object/exception attributes 3363 private SliceType _sliceType; 3364 private bool _skipFirstSlice; 3365 3366 // Slice attributes 3367 private int _sliceSize; 3368 private string _typeId; 3369 } 3370 3371 private sealed class EncapsDecoder11 : EncapsDecoder 3372 { EncapsDecoder11(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, ValueFactoryManager f, System.Func<string, Type> cr, System.Func<int, string> r)3373 internal EncapsDecoder11(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, 3374 ValueFactoryManager f, System.Func<string, Type> cr, System.Func<int, string> r) 3375 : base(stream, encaps, sliceValues, classGraphDepthMax, f, cr) 3376 { 3377 _compactIdResolver = r; 3378 _current = null; 3379 _valueIdIndex = 1; 3380 } 3381 readValue(System.Action<Value> cb)3382 internal override void readValue(System.Action<Value> cb) 3383 { 3384 int index = _stream.readSize(); 3385 if(index < 0) 3386 { 3387 throw new MarshalException("invalid object id"); 3388 } 3389 else if(index == 0) 3390 { 3391 if(cb != null) 3392 { 3393 cb(null); 3394 } 3395 } 3396 else if(_current != null && (_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0) 3397 { 3398 // 3399 // When reading an instance within a slice and there's an 3400 // indirect instance table, always read an indirect reference 3401 // that points to an instance from the indirect instance table 3402 // marshaled at the end of the Slice. 3403 // 3404 // Maintain a list of indirect references. Note that the 3405 // indirect index starts at 1, so we decrement it by one to 3406 // derive an index into the indirection table that we'll read 3407 // at the end of the slice. 3408 // 3409 if(cb != null) 3410 { 3411 if(_current.indirectPatchList == null) 3412 { 3413 _current.indirectPatchList = new Stack<IndirectPatchEntry>(); 3414 } 3415 IndirectPatchEntry e = new IndirectPatchEntry(); 3416 e.index = index - 1; 3417 e.patcher = cb; 3418 _current.indirectPatchList.Push(e); 3419 } 3420 } 3421 else 3422 { 3423 readInstance(index, cb); 3424 } 3425 } 3426 throwException(UserExceptionFactory factory)3427 internal override void throwException(UserExceptionFactory factory) 3428 { 3429 Debug.Assert(_current == null); 3430 3431 push(SliceType.ExceptionSlice); 3432 3433 // 3434 // Read the first slice header. 3435 // 3436 startSlice(); 3437 string mostDerivedId = _current.typeId; 3438 while(true) 3439 { 3440 UserException userEx = null; 3441 3442 // 3443 // Use a factory if one was provided. 3444 // 3445 if(factory != null) 3446 { 3447 try 3448 { 3449 factory(_current.typeId); 3450 } 3451 catch(UserException ex) 3452 { 3453 userEx = ex; 3454 } 3455 } 3456 3457 if(userEx == null) 3458 { 3459 userEx = _stream.createUserException(_current.typeId); 3460 } 3461 3462 // 3463 // We found the exception. 3464 // 3465 if(userEx != null) 3466 { 3467 userEx.iceRead(_stream); 3468 throw userEx; 3469 3470 // Never reached. 3471 } 3472 3473 // 3474 // Slice off what we don't understand. 3475 // 3476 skipSlice(); 3477 3478 if((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0) 3479 { 3480 if(mostDerivedId.StartsWith("::", StringComparison.Ordinal)) 3481 { 3482 throw new UnknownUserException(mostDerivedId.Substring(2)); 3483 } 3484 else 3485 { 3486 throw new UnknownUserException(mostDerivedId); 3487 } 3488 } 3489 3490 startSlice(); 3491 } 3492 } 3493 startInstance(SliceType sliceType)3494 internal override void startInstance(SliceType sliceType) 3495 { 3496 Debug.Assert(_current.sliceType == sliceType); 3497 _current.skipFirstSlice = true; 3498 } 3499 endInstance(bool preserve)3500 internal override SlicedData endInstance(bool preserve) 3501 { 3502 SlicedData slicedData = null; 3503 if(preserve) 3504 { 3505 slicedData = readSlicedData(); 3506 } 3507 if(_current.slices != null) 3508 { 3509 _current.slices.Clear(); 3510 _current.indirectionTables.Clear(); 3511 } 3512 _current = _current.previous; 3513 return slicedData; 3514 } 3515 startSlice()3516 internal override string startSlice() 3517 { 3518 // 3519 // If first slice, don't read the header, it was already read in 3520 // readInstance or throwException to find the factory. 3521 // 3522 if(_current.skipFirstSlice) 3523 { 3524 _current.skipFirstSlice = false; 3525 return _current.typeId; 3526 } 3527 3528 _current.sliceFlags = _stream.readByte(); 3529 3530 // 3531 // Read the type ID, for instance slices the type ID is encoded as a 3532 // string or as an index, for exceptions it's always encoded as a 3533 // string. 3534 // 3535 if(_current.sliceType == SliceType.ValueSlice) 3536 { 3537 // 3538 // Must be checked first! 3539 // 3540 if((_current.sliceFlags & Protocol.FLAG_HAS_TYPE_ID_COMPACT) == Protocol.FLAG_HAS_TYPE_ID_COMPACT) 3541 { 3542 _current.typeId = ""; 3543 _current.compactId = _stream.readSize(); 3544 } 3545 else if((_current.sliceFlags & 3546 (Protocol.FLAG_HAS_TYPE_ID_INDEX | Protocol.FLAG_HAS_TYPE_ID_STRING)) != 0) 3547 { 3548 _current.typeId = readTypeId((_current.sliceFlags & Protocol.FLAG_HAS_TYPE_ID_INDEX) != 0); 3549 _current.compactId = -1; 3550 } 3551 else 3552 { 3553 // Only the most derived slice encodes the type ID for the compact format. 3554 _current.typeId = ""; 3555 _current.compactId = -1; 3556 } 3557 } 3558 else 3559 { 3560 _current.typeId = _stream.readString(); 3561 _current.compactId = -1; 3562 } 3563 3564 // 3565 // Read the slice size if necessary. 3566 // 3567 if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0) 3568 { 3569 _current.sliceSize = _stream.readInt(); 3570 if(_current.sliceSize < 4) 3571 { 3572 throw new UnmarshalOutOfBoundsException(); 3573 } 3574 } 3575 else 3576 { 3577 _current.sliceSize = 0; 3578 } 3579 3580 return _current.typeId; 3581 } 3582 endSlice()3583 internal override void endSlice() 3584 { 3585 if((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0) 3586 { 3587 _stream.skipOptionals(); 3588 } 3589 3590 // 3591 // Read the indirection table if one is present and transform the 3592 // indirect patch list into patch entries with direct references. 3593 // 3594 if((_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0) 3595 { 3596 // 3597 // The table is written as a sequence<size> to conserve space. 3598 // 3599 int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)]; 3600 for(int i = 0; i < indirectionTable.Length; ++i) 3601 { 3602 indirectionTable[i] = readInstance(_stream.readSize(), null); 3603 } 3604 3605 // 3606 // Sanity checks. If there are optional members, it's possible 3607 // that not all instance references were read if they are from 3608 // unknown optional data members. 3609 // 3610 if(indirectionTable.Length == 0) 3611 { 3612 throw new MarshalException("empty indirection table"); 3613 } 3614 if((_current.indirectPatchList == null || _current.indirectPatchList.Count == 0) && 3615 (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) == 0) 3616 { 3617 throw new MarshalException("no references to indirection table"); 3618 } 3619 3620 // 3621 // Convert indirect references into direct references. 3622 // 3623 if(_current.indirectPatchList != null) 3624 { 3625 foreach(IndirectPatchEntry e in _current.indirectPatchList) 3626 { 3627 Debug.Assert(e.index >= 0); 3628 if(e.index >= indirectionTable.Length) 3629 { 3630 throw new MarshalException("indirection out of range"); 3631 } 3632 addPatchEntry(indirectionTable[e.index], e.patcher); 3633 } 3634 _current.indirectPatchList.Clear(); 3635 } 3636 } 3637 } 3638 skipSlice()3639 internal override void skipSlice() 3640 { 3641 if(_stream.instance().traceLevels().slicing > 0) 3642 { 3643 Logger logger = _stream.instance().initializationData().logger; 3644 string slicingCat = _stream.instance().traceLevels().slicingCat; 3645 if(_current.sliceType == SliceType.ExceptionSlice) 3646 { 3647 IceInternal.TraceUtil.traceSlicing("exception", _current.typeId, slicingCat, logger); 3648 } 3649 else 3650 { 3651 IceInternal.TraceUtil.traceSlicing("object", _current.typeId, slicingCat, logger); 3652 } 3653 } 3654 3655 int start = _stream.pos(); 3656 3657 if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0) 3658 { 3659 Debug.Assert(_current.sliceSize >= 4); 3660 _stream.skip(_current.sliceSize - 4); 3661 } 3662 else 3663 { 3664 if(_current.sliceType == SliceType.ValueSlice) 3665 { 3666 throw new NoValueFactoryException("no value factory found and compact format prevents " + 3667 "slicing (the sender should use the sliced format " + 3668 "instead)", _current.typeId); 3669 } 3670 else 3671 { 3672 if(_current.typeId.StartsWith("::", StringComparison.Ordinal)) 3673 { 3674 throw new UnknownUserException(_current.typeId.Substring(2)); 3675 } 3676 else 3677 { 3678 throw new UnknownUserException(_current.typeId); 3679 } 3680 } 3681 } 3682 3683 // 3684 // Preserve this slice. 3685 // 3686 SliceInfo info = new SliceInfo(); 3687 info.typeId = _current.typeId; 3688 info.compactId = _current.compactId; 3689 info.hasOptionalMembers = (_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0; 3690 info.isLastSlice = (_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0; 3691 IceInternal.ByteBuffer b = _stream.getBuffer().b; 3692 int end = b.position(); 3693 int dataEnd = end; 3694 if(info.hasOptionalMembers) 3695 { 3696 // 3697 // Don't include the optional member end marker. It will be re-written by 3698 // endSlice when the sliced data is re-written. 3699 // 3700 --dataEnd; 3701 } 3702 info.bytes = new byte[dataEnd - start]; 3703 b.position(start); 3704 b.get(info.bytes); 3705 b.position(end); 3706 3707 if(_current.slices == null) 3708 { 3709 _current.slices = new List<SliceInfo>(); 3710 _current.indirectionTables = new List<int[]>(); 3711 } 3712 3713 // 3714 // Read the indirect instance table. We read the instances or their 3715 // IDs if the instance is a reference to an already unmarshaled 3716 // instance. 3717 // 3718 if((_current.sliceFlags & Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0) 3719 { 3720 int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)]; 3721 for(int i = 0; i < indirectionTable.Length; ++i) 3722 { 3723 indirectionTable[i] = readInstance(_stream.readSize(), null); 3724 } 3725 _current.indirectionTables.Add(indirectionTable); 3726 } 3727 else 3728 { 3729 _current.indirectionTables.Add(null); 3730 } 3731 3732 _current.slices.Add(info); 3733 } 3734 readOptional(int readTag, OptionalFormat expectedFormat)3735 internal override bool readOptional(int readTag, OptionalFormat expectedFormat) 3736 { 3737 if(_current == null) 3738 { 3739 return _stream.readOptImpl(readTag, expectedFormat); 3740 } 3741 else if((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0) 3742 { 3743 return _stream.readOptImpl(readTag, expectedFormat); 3744 } 3745 return false; 3746 } 3747 readInstance(int index, System.Action<Value> cb)3748 private int readInstance(int index, System.Action<Value> cb) 3749 { 3750 Debug.Assert(index > 0); 3751 3752 if(index > 1) 3753 { 3754 if(cb != null) 3755 { 3756 addPatchEntry(index, cb); 3757 } 3758 return index; 3759 } 3760 3761 push(SliceType.ValueSlice); 3762 3763 // 3764 // Get the instance ID before we start reading slices. If some 3765 // slices are skipped, the indirect instance table are still read and 3766 // might read other instances. 3767 // 3768 index = ++_valueIdIndex; 3769 3770 // 3771 // Read the first slice header. 3772 // 3773 startSlice(); 3774 string mostDerivedId = _current.typeId; 3775 Value v = null; 3776 while(true) 3777 { 3778 bool updateCache = false; 3779 3780 if(_current.compactId >= 0) 3781 { 3782 updateCache = true; 3783 3784 // 3785 // Translate a compact (numeric) type ID into a class. 3786 // 3787 if(_compactIdCache == null) 3788 { 3789 _compactIdCache = new Dictionary<int, Type>(); // Lazy initialization. 3790 } 3791 else 3792 { 3793 // 3794 // Check the cache to see if we've already translated the compact type ID into a class. 3795 // 3796 Type cls = null; 3797 _compactIdCache.TryGetValue(_current.compactId, out cls); 3798 if(cls != null) 3799 { 3800 try 3801 { 3802 Debug.Assert(!cls.IsAbstract && !cls.IsInterface); 3803 v = (Value)IceInternal.AssemblyUtil.createInstance(cls); 3804 updateCache = false; 3805 } 3806 catch(Exception ex) 3807 { 3808 throw new NoValueFactoryException("no value factory", "compact ID " + 3809 _current.compactId, ex); 3810 } 3811 } 3812 } 3813 3814 // 3815 // If we haven't already cached a class for the compact ID, then try to translate the 3816 // compact ID into a type ID. 3817 // 3818 if(v == null) 3819 { 3820 _current.typeId = ""; 3821 if(_compactIdResolver != null) 3822 { 3823 try 3824 { 3825 _current.typeId = _compactIdResolver(_current.compactId); 3826 } 3827 catch(LocalException) 3828 { 3829 throw; 3830 } 3831 catch(System.Exception ex) 3832 { 3833 throw new MarshalException("exception in CompactIdResolver for ID " + 3834 _current.compactId, ex); 3835 } 3836 } 3837 3838 if(_current.typeId.Length == 0) 3839 { 3840 _current.typeId = _stream.instance().resolveCompactId(_current.compactId); 3841 } 3842 } 3843 } 3844 3845 if(v == null && _current.typeId.Length > 0) 3846 { 3847 v = newInstance(_current.typeId); 3848 } 3849 3850 if(v != null) 3851 { 3852 if(updateCache) 3853 { 3854 Debug.Assert(_current.compactId >= 0); 3855 _compactIdCache.Add(_current.compactId, v.GetType()); 3856 } 3857 3858 // 3859 // We have an instance, get out of this loop. 3860 // 3861 break; 3862 } 3863 3864 // 3865 // If slicing is disabled, stop unmarshaling. 3866 // 3867 if(!_sliceValues) 3868 { 3869 throw new NoValueFactoryException("no value factory found and slicing is disabled", 3870 _current.typeId); 3871 } 3872 3873 // 3874 // Slice off what we don't understand. 3875 // 3876 skipSlice(); 3877 3878 // 3879 // If this is the last slice, keep the instance as an opaque 3880 // UnknownSlicedValue object. 3881 // 3882 if((_current.sliceFlags & Protocol.FLAG_IS_LAST_SLICE) != 0) 3883 { 3884 // 3885 // Provide a factory with an opportunity to supply the instance. 3886 // We pass the "::Ice::Object" ID to indicate that this is the 3887 // last chance to preserve the instance. 3888 // 3889 v = newInstance(Value.ice_staticId()); 3890 if(v == null) 3891 { 3892 v = new UnknownSlicedValue(mostDerivedId); 3893 } 3894 3895 break; 3896 } 3897 3898 startSlice(); // Read next Slice header for next iteration. 3899 } 3900 3901 if(++_classGraphDepth > _classGraphDepthMax) 3902 { 3903 throw new MarshalException("maximum class graph depth reached"); 3904 } 3905 3906 // 3907 // Unmarshal the instance. 3908 // 3909 unmarshal(index, v); 3910 3911 --_classGraphDepth; 3912 3913 if(_current == null && _patchMap != null && _patchMap.Count > 0) 3914 { 3915 // 3916 // If any entries remain in the patch map, the sender has sent an index for an instance, but failed 3917 // to supply the instance. 3918 // 3919 throw new MarshalException("index for class received, but no instance"); 3920 } 3921 3922 if(cb != null) 3923 { 3924 cb(v); 3925 } 3926 return index; 3927 } 3928 readSlicedData()3929 private SlicedData readSlicedData() 3930 { 3931 if(_current.slices == null) // No preserved slices. 3932 { 3933 return null; 3934 } 3935 3936 // 3937 // The _indirectionTables member holds the indirection table for each slice 3938 // in _slices. 3939 // 3940 Debug.Assert(_current.slices.Count == _current.indirectionTables.Count); 3941 for(int n = 0; n < _current.slices.Count; ++n) 3942 { 3943 // 3944 // We use the "instances" list in SliceInfo to hold references 3945 // to the target instances. Note that the instances might not have 3946 // been read yet in the case of a circular reference to an 3947 // enclosing instance. 3948 // 3949 int[] table = _current.indirectionTables[n]; 3950 SliceInfo info = _current.slices[n]; 3951 info.instances = new Value[table != null ? table.Length : 0]; 3952 for(int j = 0; j < info.instances.Length; ++j) 3953 { 3954 var cj = j; 3955 addPatchEntry(table[j], (Ice.Value v) => info.instances[cj] = v); 3956 } 3957 } 3958 3959 return new SlicedData(_current.slices.ToArray()); 3960 } 3961 push(SliceType sliceType)3962 private void push(SliceType sliceType) 3963 { 3964 if(_current == null) 3965 { 3966 _current = new InstanceData(null); 3967 } 3968 else 3969 { 3970 _current = _current.next == null ? new InstanceData(_current) : _current.next; 3971 } 3972 _current.sliceType = sliceType; 3973 _current.skipFirstSlice = false; 3974 } 3975 3976 private sealed class IndirectPatchEntry 3977 { 3978 public int index; 3979 public System.Action<Value> patcher; 3980 } 3981 3982 private sealed class InstanceData 3983 { InstanceData(InstanceData previous)3984 internal InstanceData(InstanceData previous) 3985 { 3986 if(previous != null) 3987 { 3988 previous.next = this; 3989 } 3990 this.previous = previous; 3991 this.next = null; 3992 } 3993 3994 // Instance attributes 3995 internal SliceType sliceType; 3996 internal bool skipFirstSlice; 3997 internal List<SliceInfo> slices; // Preserved slices. 3998 internal List<int[]> indirectionTables; 3999 4000 // Slice attributes 4001 internal byte sliceFlags; 4002 internal int sliceSize; 4003 internal string typeId; 4004 internal int compactId; 4005 internal Stack<IndirectPatchEntry> indirectPatchList; 4006 4007 internal InstanceData previous; 4008 internal InstanceData next; 4009 } 4010 4011 private System.Func<int, string> _compactIdResolver; 4012 private InstanceData _current; 4013 private int _valueIdIndex; // The ID of the next instance to unmarshal. 4014 private Dictionary<int, Type> _compactIdCache; 4015 } 4016 4017 private sealed class Encaps 4018 { reset()4019 internal void reset() 4020 { 4021 decoder = null; 4022 } 4023 setEncoding(EncodingVersion encoding)4024 internal void setEncoding(EncodingVersion encoding) 4025 { 4026 this.encoding = encoding; 4027 encoding_1_0 = encoding.Equals(Util.Encoding_1_0); 4028 } 4029 4030 internal int start; 4031 internal int sz; 4032 internal EncodingVersion encoding; 4033 internal bool encoding_1_0; 4034 4035 internal EncapsDecoder decoder; 4036 4037 internal Encaps next; 4038 } 4039 4040 // 4041 // The encoding version to use when there's no encapsulation to 4042 // read from. This is for example used to read message headers. 4043 // 4044 private EncodingVersion _encoding; 4045 isEncoding_1_0()4046 private bool isEncoding_1_0() 4047 { 4048 return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0); 4049 } 4050 4051 private Encaps _encapsStack; 4052 private Encaps _encapsCache; 4053 initEncaps()4054 private void initEncaps() 4055 { 4056 if(_encapsStack == null) // Lazy initialization 4057 { 4058 _encapsStack = _encapsCache; 4059 if(_encapsStack != null) 4060 { 4061 _encapsCache = _encapsCache.next; 4062 } 4063 else 4064 { 4065 _encapsStack = new Encaps(); 4066 } 4067 _encapsStack.setEncoding(_encoding); 4068 _encapsStack.sz = _buf.b.limit(); 4069 } 4070 4071 if(_encapsStack.decoder == null) // Lazy initialization. 4072 { 4073 if(_encapsStack.encoding_1_0) 4074 { 4075 _encapsStack.decoder = new EncapsDecoder10(this, _encapsStack, _sliceValues, _classGraphDepthMax, 4076 _valueFactoryManager, _classResolver); 4077 } 4078 else 4079 { 4080 _encapsStack.decoder = new EncapsDecoder11(this, _encapsStack, _sliceValues, _classGraphDepthMax, 4081 _valueFactoryManager, _classResolver, _compactIdResolver); 4082 } 4083 } 4084 } 4085 4086 private bool _sliceValues; 4087 private bool _traceSlicing; 4088 private int _classGraphDepthMax; 4089 4090 private int _startSeq; 4091 private int _minSeqSize; 4092 4093 private ValueFactoryManager _valueFactoryManager; 4094 private Logger _logger; 4095 private System.Func<int, string> _compactIdResolver; 4096 private System.Func<string, Type> _classResolver; 4097 } 4098 4099 /// <summary> 4100 /// Base class for extracting class instances from an input stream. 4101 /// </summary> 4102 public abstract class ValueReader : Value 4103 { 4104 /// <summary> 4105 /// Read the instance's data members. 4106 /// </summary> 4107 /// <param name="inStream">The input stream to read from.</param> read(InputStream inStream)4108 public abstract void read(InputStream inStream); 4109 iceWrite(OutputStream os)4110 public override void iceWrite(OutputStream os) 4111 { 4112 Debug.Assert(false); 4113 } 4114 iceRead(InputStream istr)4115 public override void iceRead(InputStream istr) 4116 { 4117 read(istr); 4118 } 4119 } 4120 4121 } 4122