1 /* 2 * Copyright (c) 1998-2002 The Jgroup Team. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software 15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 16 * 17 */ 18 19 package jgroup.util; 20 21 import java.io.EOFException; 22 import java.io.Externalizable; 23 import java.io.IOException; 24 import java.io.InputStream; 25 import java.io.ObjectInput; 26 import java.io.ObjectInputStream; 27 import java.io.ObjectOutput; 28 import java.io.PushbackInputStream; 29 import java.io.UTFDataFormatException; 30 31 import jgroup.core.ConfigManager; 32 33 /** 34 * Input stream message optimized to avoid message copying. 35 * 36 * @author Alberto Montresor 37 * @author Hein Meling 38 * @since Jgroup 0.8 39 */ 40 public final class InMessage 41 extends InputStream 42 implements ObjectInput, Externalizable 43 { 44 45 //////////////////////////////////////////////////////////////////////////////////////////// 46 // Constants 47 //////////////////////////////////////////////////////////////////////////////////////////// 48 49 private static final long serialVersionUID = 9133407439996893111L; 50 51 /** Initial number of fragments composing a message; can grow */ 52 private static final int NUM_BUFFER = 16; 53 54 55 //////////////////////////////////////////////////////////////////////////////////////////// 56 // Static section 57 //////////////////////////////////////////////////////////////////////////////////////////// 58 59 /** Temporary buffer used in writeTemp */ 60 private static byte[] temp = new byte[8]; 61 62 63 //////////////////////////////////////////////////////////////////////////////////////////// 64 // Fields 65 //////////////////////////////////////////////////////////////////////////////////////////// 66 67 private int payload; // Payload size in bytes 68 private int header; // Header size in bytes 69 private int trailer; // Trailer size in bytes 70 private int totlen; // Total length of a fragment 71 private int endpayload; // Last byte used for payload 72 73 private int position; // Current position in the stream [0..byteCount] 74 private int fragment; // Current fragment number 75 private int offset; // Current offset in the fragment 76 77 private int fragmentCount; // Total number of fragments used 78 private int byteCount; // Total number of bytes written 79 80 private byte[] buffer; // Current buffer 81 private byte[][] fragments; // Byte array fragments 82 83 private int marked; // Mark position 84 85 86 //////////////////////////////////////////////////////////////////////////////////////////// 87 // Constructors 88 //////////////////////////////////////////////////////////////////////////////////////////// 89 90 /** 91 * This constructor builds an empty message subdivided in fragments. 92 * Each fragment has a length of <code> header + payload + trailer</code>. 93 * <p> 94 * A <tt>IndexOutOfBoundsException</tt> is thrown if: <tt>payload</tt> is 95 * negative or equal to zero; <tt>header</tt> is negative; <tt>trailer</tt> 96 * is negative; <tt>size</tt> is negative or equal to zero. 97 */ 98 public InMessage(int payload, int header, int trailer) 99 { 100 if (payload <= 0 || header < 0 || trailer < 0) 101 throw new IndexOutOfBoundsException(); 102 103 // Store and compute fixed limits 104 this.payload = payload; 105 this.header = header; 106 this.trailer = trailer; 107 endpayload = payload + header; 108 totlen = endpayload + trailer; 109 110 // Initialize variables regarding message size 111 byteCount = 0; 112 fragmentCount = 0; 113 114 // Initialize variables regarding message position in the stream 115 position = 0; 116 fragment = 0; 117 offset = header; 118 119 // Create fragments 120 fragments = new byte[NUM_BUFFER][]; 121 } 122 123 124 /** 125 * This constructor builds a message input stream subdivided in 126 * fragments with length <code> header + payload + trailer</code>. 127 * 128 * @exception IndexOutOfBoundsException 129 * Raised if <code>payload</code> is negative or equal to zero; 130 * <code>header</code> is negative; <code>trailer</code> is 131 * negative; <code>size</code> is negative or equal to zero. 132 */ 133 public InMessage(int payload, int header, int trailer, int size) 134 { 135 if (payload <= 0 || header < 0 || trailer < 0 || size <= 0) 136 throw new IndexOutOfBoundsException(); 137 138 // Store and compute fixed limits 139 this.payload = payload; 140 this.header = header; 141 this.trailer = trailer; 142 endpayload = payload + header; 143 totlen = endpayload + trailer; 144 145 // Initialize variables regarding message size 146 byteCount = 0; 147 fragmentCount = 0; 148 149 // Initialize variables regarding message position in the stream 150 position = 0; 151 fragment = 0; 152 offset = header; 153 154 // Create fragments 155 fragments = new byte[size % payload + 1][]; 156 } 157 158 159 /** 160 * Construct a InMessage starting from an OutMessage. In this way, it possible 161 * to local deliver messages without copying them. 162 */ 163 public InMessage(OutMessage msg) 164 { 165 // Store and compute fixed limits 166 this.payload = msg.getPayload(); 167 this.header = msg.getHeader(); 168 this.trailer = msg.getTrailer(); 169 endpayload = payload + header; 170 totlen = endpayload + trailer; 171 172 // Initialize variables regarding message size 173 byteCount = msg.getByteCount(); 174 fragmentCount = msg.getFragmentCount(); 175 176 // Initialize variables regarding message position in the stream 177 position = 0; 178 fragment = 0; 179 offset = header; 180 181 // Create fragments 182 fragments = msg.getFragments(); 183 buffer = fragments[0]; 184 } 185 186 187 //////////////////////////////////////////////////////////////////////////////////////////// 188 // Methods from Externalizable 189 //////////////////////////////////////////////////////////////////////////////////////////// 190 191 /** 192 * Default constructor for externalization. 193 */ 194 public InMessage() { } 195 196 197 /** 198 * Restores the content of this object from the marshalled data contained 199 * in the specified input stream. 200 * 201 * @param in the stream to be read 202 */ 203 public void readExternal(ObjectInput in) 204 throws IOException 205 { 206 payload = in.readInt(); 207 header = in.readInt(); 208 trailer = in.readInt(); 209 endpayload = payload + header; 210 totlen = endpayload + trailer; 211 fragmentCount = in.readInt(); 212 byteCount = in.readInt(); 213 fragment = in.readInt(); 214 position = in.readInt(); 215 marked = in.readInt(); 216 217 // Initialize the offset variable based on the parameters from the stream 218 offset = header + position; 219 220 // Reconstruct fragments from stream 221 fragments = new byte[fragmentCount][]; 222 int fcount = fragmentCount - 1; 223 for (int i = 0; i < fcount; i++) { 224 fragments[i] = new byte[totlen]; 225 in.readFully(fragments[i], 0, totlen); 226 } 227 fragments[fcount] = new byte[totlen]; 228 int lastFragLen = getLastPayload() + header + trailer; 229 in.readFully(fragments[fcount], 0, lastFragLen); 230 buffer = fragments[0]; 231 232 // System.out.println("readExternal: " + this.toString(true)); 233 } 234 235 /** 236 * Marshals the content of this object to the specified output stream. 237 * 238 * @param out the stream to be written 239 */ 240 public void writeExternal(ObjectOutput out) 241 throws IOException 242 { 243 out.writeInt(payload); 244 out.writeInt(header); 245 out.writeInt(trailer); 246 out.writeInt(fragmentCount); 247 out.writeInt(byteCount); 248 out.writeInt(fragment); 249 out.writeInt(position); 250 out.writeInt(marked); 251 252 int fcount = fragmentCount - 1; 253 for (int i = 0; i < fcount; i++) { 254 out.write(fragments[i]); 255 } 256 int lastFragLen = getLastPayload() + header + trailer; 257 out.write(fragments[fcount], 0, lastFragLen); 258 259 // System.out.println("writeExternal: " + this.toString(true)); 260 } 261 262 263 //////////////////////////////////////////////////////////////////////////////////////////// 264 // Methods inherited from InputStream 265 //////////////////////////////////////////////////////////////////////////////////////////// 266 267 /** 268 * Reads the next byte of data from the input stream. The value byte is 269 * returned as an <code>int</code> in the range <code>0</code> to 270 * <code>255</code>. If no byte is available because the end of the stream 271 * has been reached, the value <code>-1</code> is returned. This method 272 * blocks until input data is available, the end of the stream is detected, 273 * or an exception is thrown. 274 * 275 * @return the next byte of data, or <code>-1</code> if the end of the 276 * stream is reached. 277 * @exception IOException if an I/O error occurs. 278 */ 279 public int read() 280 { 281 if (position == byteCount) { 282 /* 283 * The end of the stream has been reached 284 */ 285 return -1; 286 } 287 288 if (offset == endpayload) { 289 /* 290 * The end of the current fragment has been reached; we move to the next 291 * fragment and we reset the offset. 292 */ 293 fragment++; 294 buffer = fragments[fragment]; 295 offset = header; 296 } 297 position++; 298 return buffer[offset++] & 0xFF; 299 } 300 301 302 /** 303 * Reads some number of bytes from the input stream and stores them into 304 * the buffer array <code>b</code>. The number of bytes actually read is 305 * returned as an integer. This method blocks until input data is 306 * available, end of file is detected, or an exception is thrown. 307 * 308 * <p> If <code>b</code> is <code>null</code>, a 309 * <code>NullPointerException</code> is thrown. If the length of 310 * <code>b</code> is zero, then no bytes are read and <code>0</code> is 311 * returned; otherwise, there is an attempt to read at least one byte. If 312 * no byte is available because the stream is at end of file, the value 313 * <code>-1</code> is returned; otherwise, at least one byte is read and 314 * stored into <code>b</code>. 315 * 316 * <p> The first byte read is stored into element <code>b[0]</code>, the 317 * next one into <code>b[1]</code>, and so on. The number of bytes read is, 318 * at most, equal to the length of <code>b</code>. Let <i>k</i> be the 319 * number of bytes actually read; these bytes will be stored in elements 320 * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>, 321 * leaving elements <code>b[</code><i>k</i><code>]</code> through 322 * <code>b[b.length-1]</code> unaffected. 323 * 324 * <p> The <code>read(b)</code> method for class <code>InputStream</code> 325 * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre> 326 * 327 * @param b the buffer into which the data is read. 328 * @return the total number of bytes read into the buffer, or 329 * <code>-1</code> is there is no more data because the end of 330 * the stream has been reached. 331 */ 332 public int read(byte b[]) 333 { 334 return read(b, 0, b.length); 335 } 336 337 /** 338 * Reads up to <code>len</code> bytes of data from the input stream into 339 * an array of bytes. An attempt is made to read as many as 340 * <code>len</code> bytes, but a smaller number may be read, possibly 341 * zero. The number of bytes actually read is returned as an integer. 342 * 343 * <p> If <code>b</code> is <code>null</code>, a 344 * <code>NullPointerException</code> is thrown. 345 * 346 * <p> If <code>off</code> is negative, or <code>len</code> is negative, or 347 * <code>off+len</code> is greater than the length of the array 348 * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is 349 * thrown. 350 * 351 * <p> If <code>len</code> is zero, then no bytes are read and 352 * <code>0</code> is returned; otherwise, there is an attempt to read at 353 * least one byte. If no byte is available because the stream is at end of 354 * file, the value <code>-1</code> is returned; otherwise, at least one 355 * byte is read and stored into <code>b</code>. 356 * 357 * <p> The first byte read is stored into element <code>b[off]</code>, the 358 * next one into <code>b[off+1]</code>, and so on. The number of bytes read 359 * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of 360 * bytes actually read; these bytes will be stored in elements 361 * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>, 362 * leaving elements <code>b[off+</code><i>k</i><code>]</code> through 363 * <code>b[off+len-1]</code> unaffected. 364 * 365 * <p> In every case, elements <code>b[0]</code> through 366 * <code>b[off]</code> and elements <code>b[off+len]</code> through 367 * <code>b[b.length-1]</code> are unaffected. 368 * 369 * @param b the buffer into which the data is read. 370 * @param off the start offset in array <code>b</code> 371 * at which the data is written. 372 * @param len the maximum number of bytes to read. 373 * @return the total number of bytes read into the buffer, or 374 * <code>-1</code> if there is no more data because the end of 375 * the stream has been reached. 376 */ 377 public int read(byte b[], int off, int len) 378 { 379 int tobecopied; 380 int remained; 381 382 if (b == null) 383 throw new NullPointerException(); 384 if (off < 0 || off > b.length || len < 0 || (off + len > b.length) || (off + len < 0)) 385 throw new IndexOutOfBoundsException(); 386 if (len == 0) 387 return 0; 388 if (position == byteCount) 389 return -1; 390 391 if (position + len > byteCount) 392 len = byteCount - position; 393 if (b.length < len) 394 len = b.length; 395 position += len; 396 remained = len; 397 tobecopied = endpayload - offset; 398 while (remained > tobecopied) { 399 System.arraycopy(fragments[fragment], offset, b, off, tobecopied); 400 off += tobecopied; 401 remained -= tobecopied; 402 fragment++; 403 offset = header; 404 tobecopied = payload; 405 } 406 buffer = fragments[fragment]; 407 System.arraycopy(buffer, offset, b, off, remained); 408 offset += remained; 409 410 return len; 411 } 412 413 /** 414 * Skips over and discards <code>n</code> bytes of data from this input 415 * stream. The <code>skip</code> method may, for a variety of reasons, end 416 * up skipping over some smaller number of bytes, possibly <code>0</code>. 417 * This may result from any of a number of conditions; reaching end of file 418 * before <code>n</code> bytes have been skipped is only one possibility. 419 * The actual number of bytes skipped is returned. If <code>n</code> is 420 * negative, no bytes are skipped. 421 * 422 * <p> The <code>skip</code> method of <code>InputStream</code> creates a 423 * byte array and then repeatedly reads into it until <code>n</code> bytes 424 * have been read or the end of the stream has been reached. Subclasses are 425 * encouraged to provide a more efficient implementation of this method. 426 * 427 * @param n the number of bytes to be skipped. 428 * @return the actual number of bytes skipped. 429 * @exception IOException if an I/O error occurs. 430 */ 431 public long skip(long n) 432 { 433 long value = n; 434 position += n; 435 if (position > byteCount) { 436 value -= (position - byteCount); 437 position = byteCount; 438 } 439 return value; 440 } 441 442 /** 443 * Marks the current position in this input stream. A subsequent call to 444 * the <code>reset</code> method repositions this stream at the last marked 445 * position so that subsequent reads re-read the same bytes. 446 * 447 * <p> The <code>readlimit</code> arguments tells this input stream to 448 * allow that many bytes to be read before the mark position gets 449 * invalidated. 450 * 451 * <p> The general contract of <code>mark</code> is that, if the method 452 * <code>markSupported</code> returns <code>true</code>, the stream somehow 453 * remembers all the bytes read after the call to <code>mark</code> and 454 * stands ready to supply those same bytes again if and whenever the method 455 * <code>reset</code> is called. However, the stream is not required to 456 * remember any data at all if more than <code>readlimit</code> bytes are 457 * read from the stream before <code>reset</code> is called. 458 * 459 * 460 * @param readlimit not used 461 */ 462 public synchronized void mark(int readlimit) 463 { 464 marked = position; 465 } 466 467 468 /** 469 * Repositions this stream to the position at the time the 470 * <code>mark</code> method was last called on this input stream. 471 * 472 * <p> The general contract of <code>reset</code> is: 473 * 474 * <p><ul> 475 * 476 * <li> If the method <code>markSupported</code> returns 477 * <code>true</code>, then: 478 * 479 * <ul><li> If the method <code>mark</code> has not been called since 480 * the stream was created, or the number of bytes read from the stream 481 * since <code>mark</code> was last called is larger than the argument 482 * to <code>mark</code> at that last call, then an 483 * <code>IOException</code> might be thrown. 484 * 485 * <li> If such an <code>IOException</code> is not thrown, then the 486 * stream is reset to a state such that all the bytes read since the 487 * most recent call to <code>mark</code> (or since the start of the 488 * file, if <code>mark</code> has not been called) will be resupplied 489 * to subsequent callers of the <code>read</code> method, followed by 490 * any bytes that otherwise would have been the next input data as of 491 * the time of the call to <code>reset</code>. </ul> 492 * 493 * <li> If the method <code>markSupported</code> returns 494 * <code>false</code>, then: 495 * 496 * <ul><li> The call to <code>reset</code> may throw an 497 * <code>IOException</code>. 498 * 499 * <li> If an <code>IOException</code> is not thrown, then the stream 500 * is reset to a fixed state that depends on the particular type of the 501 * input stream and how it was created. The bytes that will be supplied 502 * to subsequent callers of the <code>read</code> method depend on the 503 * particular type of the input stream. </ul></ul> 504 * 505 * <p> The method <code>reset</code> for class <code>InputStream</code> 506 * does nothing and always throws an <code>IOException</code>. 507 * 508 * @exception IOException if this stream has not been marked or if the 509 * mark has been invalidated. 510 */ 511 public synchronized void reset() 512 throws IOException 513 { 514 fragment = marked / payload; 515 offset = header + marked % payload; 516 position = marked; 517 buffer = fragments[fragment]; 518 } 519 520 /** 521 * Tests if this input stream supports the <code>mark</code> and 522 * <code>reset</code> methods. The <code>markSupported</code> method of 523 * <code>InputStream</code> returns <code>false</code>. 524 * 525 * @return <code>true</code> if this true type supports the mark and reset 526 * method; <code>false</code> otherwise. 527 */ 528 public boolean markSupported() 529 { 530 return true; 531 } 532 533 //////////////////////////////////////////////////////////////////////////////////////////// 534 // Methods from DataInput 535 //////////////////////////////////////////////////////////////////////////////////////////// 536 537 /** 538 * Reads some bytes from an input stream and stores them into the 539 * buffer array <code>b</code>. The number of bytes read is equal to 540 * the length of <code>b</code>. <p> 541 * 542 * This method blocks until one of the following conditions occurs: 543 * <p> 544 * 545 * <ul> 546 * 547 * <li><code>b.length</code> bytes of input data are available, in 548 * which case a normal return is made. 549 * 550 * <li>End of file is detected, in which case an 551 * <code>EOFException</code> is thrown. 552 * 553 * <li>An I/O error occurs, in which case an <code>IOException</code> 554 * other than <code>EOFException</code> is thrown. 555 * 556 * </ul> 557 * <p> 558 * 559 * If <code>b.length</code> is zero, then no bytes are read. 560 * Otherwise, the first byte read is stored into element 561 * <code>b[0]</code>, the next one into <code>b[1]</code>, and so on. 562 * If an exception is thrown from this method, then it may be that 563 * some but not all bytes of <code>b</code> have been updated with 564 * data from the input stream. 565 * 566 * @param b 567 * The buffer into which the data is read. 568 * @exception EOFException 569 * If this stream reaches the end before reading all the bytes. 570 * @exception IOException 571 * If an I/O error occurs. 572 * @exception NullPointerException 573 * Thrown if <code>b</code> is <code>null</code>. 574 */ 575 public void readFully(byte b[]) throws IOException 576 { 577 read(b); 578 } 579 580 /** 581 * 582 * Reads <code>len</code> 583 * bytes from 584 * an input stream. 585 * <p> 586 * This method 587 * blocks until one of the following conditions 588 * occurs:<p> 589 * <ul> 590 * <li><code>len</code> bytes 591 * of input data are available, in which case 592 * a normal return is made. 593 * 594 * <li>End of file 595 * is detected, in which case an <code>EOFException</code> 596 * is thrown. 597 * 598 * <li>An I/O error occurs, in 599 * which case an <code>IOException</code> other 600 * than <code>EOFException</code> is thrown. 601 * </ul> 602 * <p> 603 * If <code>b</code> is <code>null</code>, 604 * a <code>NullPointerException</code> is thrown. 605 * If <code>off</code> is negative, or <code>len</code> 606 * is negative, or <code>off+len</code> is 607 * greater than the length of the array <code>b</code>, 608 * then an <code>IndexOutOfBoundsException</code> 609 * is thrown. 610 * If <code>len</code> is zero, 611 * then no bytes are read. Otherwise, the first 612 * byte read is stored into element <code>b[off]</code>, 613 * the next one into <code>b[off+1]</code>, 614 * and so on. The number of bytes read is, 615 * at most, equal to <code>len</code>. 616 * 617 * @param b the buffer into which the data is read. 618 * @exception EOFException if this stream reaches the end before reading 619 * all the bytes. 620 * @exception IOException if an I/O error occurs. 621 */ 622 public void readFully(byte b[], int off, int len) throws IOException 623 { 624 read(b, off, len); 625 } 626 627 /** 628 * Makes an attempt to skip over 629 * <code>n</code> bytes 630 * of data from the input 631 * stream, discarding the skipped bytes. However, 632 * it may skip 633 * over some smaller number of 634 * bytes, possibly zero. This may result from 635 * any of a 636 * number of conditions; reaching 637 * end of file before <code>n</code> bytes 638 * have been skipped is 639 * only one possibility. 640 * This method never throws an <code>EOFException</code>. 641 * The actual 642 * number of bytes skipped is returned. 643 * 644 * @param n the number of bytes to be skipped. 645 * @return the number of bytes skipped, which is always <code>n</code>. 646 * @exception EOFException if this stream reaches the end before skipping 647 * all the bytes. 648 * @exception IOException if an I/O error occurs. 649 */ 650 public int skipBytes(int n) throws IOException 651 { 652 return (int) skip(n); 653 } 654 655 /** 656 * Reads one input byte and returns 657 * <code>true</code> if that byte is nonzero, 658 * <code>false</code> if that byte is zero. 659 * This method is suitable for reading 660 * the byte written by the <code>writeBoolean</code> 661 * method of interface <code>DataOutput</code>. 662 * 663 * @return the <code>boolean</code> value read. 664 * @exception EOFException if this stream reaches the end before reading 665 * all the bytes. 666 * @exception IOException if an I/O error occurs. 667 */ 668 public boolean readBoolean() throws IOException 669 { 670 int ch = read(); 671 if (ch < 0) 672 throw new EOFException(); 673 return (ch != 0); 674 } 675 676 /** 677 * Reads and returns one input byte. 678 * The byte is treated as a signed value in 679 * the range <code>-128</code> through <code>127</code>, 680 * inclusive. 681 * This method is suitable for 682 * reading the byte written by the <code>writeByte</code> 683 * method of interface <code>DataOutput</code>. 684 * 685 * @return the 8-bit value read. 686 * @exception EOFException if this stream reaches the end before reading 687 * all the bytes. 688 * @exception IOException if an I/O error occurs. 689 */ 690 public byte readByte() throws IOException 691 { 692 int ch = read(); 693 if (ch < 0) 694 throw new EOFException(); 695 return (byte)(ch); 696 } 697 698 /** 699 * Reads one input byte, zero-extends 700 * it to type <code>int</code>, and returns 701 * the result, which is therefore in the range 702 * <code>0</code> 703 * through <code>255</code>. 704 * This method is suitable for reading 705 * the byte written by the <code>writeByte</code> 706 * method of interface <code>DataOutput</code> 707 * if the argument to <code>writeByte</code> 708 * was intended to be a value in the range 709 * <code>0</code> through <code>255</code>. 710 * 711 * @return the unsigned 8-bit value read. 712 * @exception EOFException if this stream reaches the end before reading 713 * all the bytes. 714 * @exception IOException if an I/O error occurs. 715 */ 716 public int readUnsignedByte() throws IOException 717 { 718 int ch = read(); 719 if (ch < 0) 720 throw new EOFException(); 721 return ch; 722 } 723 724 /** 725 * Reads two input bytes and returns 726 * a <code>short</code> value. Let <code>a</code> 727 * be the first byte read and <code>b</code> 728 * be the second byte. The value 729 * returned 730 * is: 731 * <p><pre><code>(short)((a << 8) * | (b & 0xff)) 732 * </code></pre> 733 * This method 734 * is suitable for reading the bytes written 735 * by the <code>writeShort</code> method of 736 * interface <code>DataOutput</code>. 737 * 738 * @return the 16-bit value read. 739 * @exception EOFException if this stream reaches the end before reading 740 * all the bytes. 741 * @exception IOException if an I/O error occurs. 742 */ 743 public short readShort() throws IOException 744 { 745 return (short) read2(); 746 } 747 748 /** 749 * Reads two input bytes and returns 750 * an <code>int</code> value in the range <code>0</code> 751 * through <code>65535</code>. Let <code>a</code> 752 * be the first byte read and 753 * <code>b</code> 754 * be the second byte. The value returned is: 755 * <p><pre><code>(((a & 0xff) << 8) | (b & 0xff)) 756 * </code></pre> 757 * This method is suitable for reading the bytes 758 * written by the <code>writeShort</code> method 759 * of interface <code>DataOutput</code> if 760 * the argument to <code>writeShort</code> 761 * was intended to be a value in the range 762 * <code>0</code> through <code>65535</code>. 763 * 764 * @return the unsigned 16-bit value read. 765 * @exception EOFException if this stream reaches the end before reading 766 * all the bytes. 767 * @exception IOException if an I/O error occurs. 768 */ 769 public int readUnsignedShort() throws IOException 770 { 771 return read2(); 772 } 773 774 /** 775 * Reads an input <code>char</code> and returns the <code>char</code> value. 776 * A Unicode <code>char</code> is made up of two bytes. 777 * Let <code>a</code> 778 * be the first byte read and <code>b</code> 779 * be the second byte. The value 780 * returned is: 781 * <p><pre><code>(char)((a << 8) | (b & 0xff)) 782 * </code></pre> 783 * This method 784 * is suitable for reading bytes written by 785 * the <code>writeChar</code> method of interface 786 * <code>DataOutput</code>. 787 * 788 * @return the Unicode <code>char</code> read. 789 * @exception EOFException if this stream reaches the end before reading 790 * all the bytes. 791 * @exception IOException if an I/O error occurs. 792 */ 793 public char readChar() throws IOException 794 { 795 return (char) read2(); 796 } 797 798 /** 799 * Reads four input bytes and returns an 800 * <code>int</code> value. Let <code>a</code> 801 * be the first byte read, <code>b</code> be 802 * the second byte, <code>c</code> be the third 803 * byte, 804 * and <code>d</code> be the fourth 805 * byte. The value returned is: 806 * <p><pre> 807 * <code> 808 * (((a & 0xff) << 24) | ((b & 0xff) << 16) | 809 *  ((c & 0xff) << 8) | (d & 0xff)) 810 * </code></pre> 811 * This method is suitable 812 * for reading bytes written by the <code>writeInt</code> 813 * method of interface <code>DataOutput</code>. 814 * 815 * @return the <code>int</code> value read. 816 * @exception EOFException if this stream reaches the end before reading 817 * all the bytes. 818 * @exception IOException if an I/O error occurs. 819 */ 820 public int readInt() throws IOException 821 { 822 return read4(); 823 } 824 825 /** 826 * Reads eight input bytes and returns 827 * a <code>long</code> value. Let <code>a</code> 828 * be the first byte read, <code>b</code> be 829 * the second byte, <code>c</code> be the third 830 * byte, <code>d</code> 831 * be the fourth byte, 832 * <code>e</code> be the fifth byte, <code>f</code> 833 * be the sixth byte, <code>g</code> be the 834 * seventh byte, 835 * and <code>h</code> be the 836 * eighth byte. The value returned is: 837 * <p><pre> <code> 838 * (((long)(a & 0xff) << 56) | 839 * ((long)(b & 0xff) << 48) | 840 * ((long)(c & 0xff) << 40) | 841 * ((long)(d & 0xff) << 32) | 842 * ((long)(e & 0xff) << 24) | 843 * ((long)(f & 0xff) << 16) | 844 * ((long)(g & 0xff) << 8) | 845 * ((long)(h & 0xff))) 846 * </code></pre> 847 * <p> 848 * This method is suitable 849 * for reading bytes written by the <code>writeLong</code> 850 * method of interface <code>DataOutput</code>. 851 * 852 * @return the <code>long</code> value read. 853 * @exception EOFException if this stream reaches the end before reading 854 * all the bytes. 855 * @exception IOException if an I/O error occurs. 856 */ 857 public long readLong() throws IOException 858 { 859 return read8(); 860 } 861 862 /** 863 * Reads four input bytes and returns 864 * a <code>float</code> value. It does this 865 * by first constructing an <code>int</code> 866 * value in exactly the manner 867 * of the <code>readInt</code> 868 * method, then converting this <code>int</code> 869 * value to a <code>float</code> in 870 * exactly the manner of the method <code>Float.intBitsToFloat</code>. 871 * This method is suitable for reading 872 * bytes written by the <code>writeFloat</code> 873 * method of interface <code>DataOutput</code>. 874 * 875 * @return the <code>float</code> value read. 876 * @exception EOFException if this stream reaches the end before reading 877 * all the bytes. 878 * @exception IOException if an I/O error occurs. 879 */ 880 public float readFloat() throws IOException 881 { 882 return Float.intBitsToFloat(read4()); 883 } 884 885 /** 886 * Reads eight input bytes and returns 887 * a <code>double</code> value. It does this 888 * by first constructing a <code>long</code> 889 * value in exactly the manner 890 * of the <code>readlong</code> 891 * method, then converting this <code>long</code> 892 * value to a <code>double</code> in exactly 893 * the manner of the method <code>Double.longBitsToDouble</code>. 894 * This method is suitable for reading 895 * bytes written by the <code>writeDouble</code> 896 * method of interface <code>DataOutput</code>. 897 * 898 * @return the <code>double</code> value read. 899 * @exception EOFException if this stream reaches the end before reading 900 * all the bytes. 901 * @exception IOException if an I/O error occurs. 902 */ 903 public double readDouble() throws IOException 904 { 905 return Double.longBitsToDouble(read8()); 906 } 907 908 private char lineBuffer[]; 909 910 /** 911 * Reads the next line of text from the input stream. 912 * It reads successive bytes, converting 913 * each byte separately into a character, 914 * until it encounters a line terminator or 915 * end of 916 * file; the characters read are then 917 * returned as a <code>String</code>. Note 918 * that because this 919 * method processes bytes, 920 * it does not support input of the full Unicode 921 * character set. 922 * <p> 923 * If end of file is encountered 924 * before even one byte can be read, then <code>null</code> 925 * is returned. Otherwise, each byte that is 926 * read is converted to type <code>char</code> 927 * by zero-extension. If the character <code>'\n'</code> 928 * is encountered, it is discarded and reading 929 * ceases. If the character <code>'\r'</code> 930 * is encountered, it is discarded and, if 931 * the following byte converts  to the 932 * character <code>'\n'</code>, then that is 933 * discarded also; reading then ceases. If 934 * end of file is encountered before either 935 * of the characters <code>'\n'</code> and 936 * <code>'\r'</code> is encountered, reading 937 * ceases. Once reading has ceased, a <code>String</code> 938 * is returned that contains all the characters 939 * read and not discarded, taken in order. 940 * Note that every character in this string 941 * will have a value less than <code>\u0100</code>, 942 * that is, <code>(char)256</code>. 943 * 944 * @return if this stream reaches the end before reading all the bytes. 945 * @exception IOException if an I/O error occurs. 946 */ 947 public String readLine() throws IOException 948 { 949 PushbackInputStream in = new PushbackInputStream(this); 950 951 char buf[] = lineBuffer; 952 953 if (buf == null) { 954 buf = lineBuffer = new char[128]; 955 } 956 957 int room = buf.length; 958 int offset = 0; 959 int c; 960 961 loop: while (true) { 962 switch (c = in.read()) { 963 case -1: 964 case '\n': 965 break loop; 966 967 case '\r': 968 int c2 = in.read(); 969 if ((c2 != '\n') && (c2 != -1)) { 970 in.unread(c2); 971 } 972 break loop; 973 974 default: 975 if (--room < 0) { 976 buf = new char[offset + 128]; 977 room = buf.length - offset - 1; 978 System.arraycopy(lineBuffer, 0, buf, 0, offset); 979 lineBuffer = buf; 980 } 981 buf[offset++] = (char) c; 982 break; 983 } 984 } 985 if ((c == -1) && (offset == 0)) { 986 return null; 987 } 988 return String.copyValueOf(buf, 0, offset); 989 } 990 991 /** 992 * Reads in a string that has been encoded using a modified UTF-8 format. 993 * The general contract of <code>readUTF</code> 994 * is that it reads a representation of a Unicode 995 * character string encoded in Java modified 996 * UTF-8 format; this string of characters 997 * is then returned as a <code>String</code>. 998 * <p> 999 * First, two bytes are read and used to 1000 * construct an unsigned 16-bit integer in 1001 * exactly the manner of the <code>readUnsignedShort</code> 1002 * method . This integer value is called the 1003 * <i>UTF length</i> and specifies the number 1004 * of additional bytes to be read. These bytes 1005 * are then converted to characters by considering 1006 * them in groups. The length of each group 1007 * is computed from the value of the first 1008 * byte of the group. The byte following a 1009 * group, if any, is the first byte of the 1010 * next group. 1011 * <p> 1012 * If the first byte of a group 1013 * matches the bit pattern <code>0xxxxxxx</code> 1014 * (where <code>x</code> means "may be <code>0</code> 1015 * or <code>1</code>"), then the group consists 1016 * of just that byte. The byte is zero-extended 1017 * to form a character. 1018 * <p> 1019 * If the first byte 1020 * of a group matches the bit pattern <code>110xxxxx</code>, 1021 * then the group consists of that byte <code>a</code> 1022 * and a second byte <code>b</code>. If there 1023 * is no byte <code>b</code> (because byte 1024 * <code>a</code> was the last of the bytes 1025 * to be read), or if byte <code>b</code> does 1026 * not match the bit pattern <code>10xxxxxx</code>, 1027 * then a <code>UTFDataFormatException</code> 1028 * is thrown. Otherwise, the group is converted 1029 * to the character:<p> 1030 * <pre><code>(char)(((a& 0x1F) << 6) | (b & 0x3F)) 1031 * </code></pre> 1032 * If the first byte of a group 1033 * matches the bit pattern <code>1110xxxx</code>, 1034 * then the group consists of that byte <code>a</code> 1035 * and two more bytes <code>b</code> and <code>c</code>. 1036 * If there is no byte <code>c</code> (because 1037 * byte <code>a</code> was one of the last 1038 * two of the bytes to be read), or either 1039 * byte <code>b</code> or byte <code>c</code> 1040 * does not match the bit pattern <code>10xxxxxx</code>, 1041 * then a <code>UTFDataFormatException</code> 1042 * is thrown. Otherwise, the group is converted 1043 * to the character:<p> 1044 * <pre><code> 1045 * (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)) 1046 * </code></pre> 1047 * If the first byte of a group matches the 1048 * pattern <code>1111xxxx</code> or the pattern 1049 * <code>10xxxxxx</code>, then a <code>UTFDataFormatException</code> 1050 * is thrown. 1051 * <p> 1052 * If end of file is encountered 1053 * at any time during this entire process, 1054 * then an <code>EOFException</code> is thrown. 1055 * <p> 1056 * After every group has been converted to 1057 * a character by this process, the characters 1058 * are gathered, in the same order in which 1059 * their corresponding groups were read from 1060 * the input stream, to form a <code>String</code>, 1061 * which is returned. 1062 * <p> 1063 * The <code>writeUTF</code> 1064 * method of interface <code>DataOutput</code> 1065 * may be used to write data that is suitable 1066 * for reading by this method. 1067 * @return a Unicode string. 1068 * @exception EOFException if this stream reaches the end 1069 * before reading all the bytes. 1070 * @exception IOException if an I/O error occurs. 1071 * @exception UTFDataFormatException if the bytes do not represent a 1072 * valid UTF-8 encoding of a string. 1073 */ 1074 public String readUTF() throws IOException 1075 { 1076 int utflen = readUnsignedShort(); 1077 StringBuilder str = new StringBuilder(utflen); 1078 byte bytearr [] = new byte[utflen]; 1079 int c, char2, char3; 1080 int count = 0; 1081 1082 readFully(bytearr, 0, utflen); 1083 1084 while (count < utflen) { 1085 c = bytearr[count] & 0xff; 1086 switch (c >> 4) { 1087 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: 1088 /* 0xxxxxxx*/ 1089 count++; 1090 str.append((char)c); 1091 break; 1092 case 12: case 13: 1093 /* 110x xxxx 10xx xxxx*/ 1094 count += 2; 1095 if (count > utflen) 1096 throw new UTFDataFormatException(); 1097 char2 = bytearr[count-1]; 1098 if ((char2 & 0xC0) != 0x80) 1099 throw new UTFDataFormatException(); 1100 str.append((char)(((c & 0x1F) << 6) | (char2 & 0x3F))); 1101 break; 1102 case 14: 1103 /* 1110 xxxx 10xx xxxx 10xx xxxx */ 1104 count += 3; 1105 if (count > utflen) 1106 throw new UTFDataFormatException(); 1107 char2 = bytearr[count-2]; 1108 char3 = bytearr[count-1]; 1109 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) 1110 throw new UTFDataFormatException(); 1111 str.append((char)(((c & 0x0F) << 12) | 1112 ((char2 & 0x3F) << 6) | 1113 ((char3 & 0x3F) << 0))); 1114 break; 1115 default: 1116 /* 10xx xxxx, 1111 xxxx */ 1117 throw new UTFDataFormatException(); 1118 } 1119 } 1120 // The number of chars produced may be less than utflen 1121 return new String(str); 1122 } 1123 1124 1125 //////////////////////////////////////////////////////////////////////////////////////////// 1126 // Methods from ObjectInput 1127 //////////////////////////////////////////////////////////////////////////////////////////// 1128 1129 1130 /** 1131 * Read and return an object. The class that implements this interface 1132 * defines where the object is "read" from. 1133 * 1134 * @exception java.lang.ClassNotFoundException If the class of a serialized 1135 * object cannot be found. 1136 * @exception IOException If any of the usual Input/Output 1137 * related exceptions occur. 1138 */ 1139 public Object readObject() 1140 throws ClassNotFoundException, IOException 1141 { 1142 // workaround since InMessage don't provide native support for readObject() 1143 ObjectInputStream ois = new ObjectInputStream(this); 1144 return ois.readObject(); 1145 } 1146 1147 //////////////////////////////////////////////////////////////////////////////////////////// 1148 // Public methods 1149 //////////////////////////////////////////////////////////////////////////////////////////// 1150 1151 /** 1152 * Move the current position in the stream to the specified 1153 * <code>position</code>. <p> 1154 * 1155 * @exception IndexOutOfBoundsException 1156 * Raised if the new position in the message exceeds the maximum 1157 * length. 1158 */ 1159 public void seek(int newpos) 1160 { 1161 if (newpos > byteCount) { 1162 throw new IndexOutOfBoundsException("New position (" + newpos 1163 + ") exceeds maximum length:" + byteCount); 1164 } 1165 fragment = newpos / payload; 1166 offset = header + newpos % payload; 1167 position = newpos; 1168 buffer = fragments[fragment]; 1169 } 1170 1171 /** 1172 * Read a short integer from the stream at the current offset. 1173 * <p> 1174 * If the message ends before having the possibility to read the 1175 * value, a <tt>ArrayIndexOutOfBoundsException</tt> is thrown. 1176 */ 1177 private int read2() 1178 throws IOException 1179 { 1180 position += 2; 1181 if (position > byteCount) { 1182 position = byteCount; 1183 throw new EOFException("pos="+position+" > byteCount="+byteCount); 1184 } 1185 if (offset + 2 > endpayload) { 1186 readTemp(2); 1187 return ((temp[0] << 8) & 0xFF00) | (temp[1] & 0xFF); 1188 } else { 1189 return ((buffer[offset++] << 8) & 0xFF00) | (buffer[offset++] & 0xFF); 1190 } 1191 } 1192 1193 1194 /** 1195 * Read an integer from the stream at the current offset. 1196 * <p> 1197 * 1198 * If the message ends before all four bytes of the <code>int</code> 1199 * value can be read, a <code>EOFException</code> is thrown. 1200 */ 1201 private int read4() 1202 throws IOException 1203 { 1204 position += 4; 1205 if (position > byteCount) { 1206 position = byteCount; 1207 throw new EOFException("pos: "+ position + ", byteCount: " + byteCount + ", offset: " + offset); 1208 } 1209 if (offset + 4 > endpayload) { 1210 readTemp(4); 1211 return ((temp[0] << 24) & 0xFF000000) | ((temp[1] << 16) 1212 & 0xFF0000) | ((temp[2] << 8) & 0xFF00) | (temp[3] & 0xFF); 1213 } else { 1214 return ((buffer[offset++] << 24) & 0xFF000000) | ((buffer[offset++] << 16) 1215 & 0xFF0000) | ((buffer[offset++] << 8) & 0xFF00) | (buffer[offset++] & 0xFF); 1216 } 1217 } 1218 1219 1220 /** 1221 * Read a long integer from the stream at the current offset. 1222 * <p> 1223 * If the message ends before having the possibility to read the 1224 * value, a <tt>ArrayIndexOutOfBoundsException</tt> is thrown. 1225 */ 1226 private long read8() 1227 throws IOException 1228 { 1229 int v1, v2; 1230 1231 position += 8; 1232 if (position > byteCount) { 1233 position = byteCount; 1234 throw new EOFException(); 1235 } 1236 if (offset + 8 > endpayload) { 1237 readTemp(8); 1238 v1 = ((temp[0] << 24) & 0xFF000000) | ((temp[1] << 16) & 0xFF0000) | 1239 ((temp[2] << 8) & 0xFF00) | (temp[3] & 0xFF); 1240 v2 = ((temp[4] << 24) & 0xFF000000) | ((temp[5] << 16) & 0xFF0000) | 1241 ((temp[6] << 8) & 0xFF00) | (temp[7] & 0xFF); 1242 } else { 1243 v1 = ((buffer[offset++] << 24) & 0xFF000000) | ((buffer[offset++] << 16) 1244 & 0xFF0000) | ((buffer[offset++] << 8) & 0xFF00) | (buffer[offset++] & 0xFF); 1245 v2 = ((buffer[offset++] << 24) & 0xFF000000) | ((buffer[offset++] << 16) 1246 & 0xFF0000) | ((buffer[offset++] << 8) & 0xFF00) | (buffer[offset++] & 0xFF); 1247 } 1248 return ((long)(v1) << 32) | (v2 & 0xFFFFFFFFL); 1249 } 1250 1251 1252 /** 1253 * Compares the bytes contained in this InMessage with those 1254 * contained in another InMessage. Starting from position 1255 * <t>pos1</t> in this message and from position <t>pos2</t> 1256 * from the other message, compares <t>len</t> bytes and 1257 * returns false if they differ. 1258 * 1259 * @param pos1 starting position in this message 1260 * @param msg the meessage to be compared 1261 * @param pos2 starting position in <t>msg</t> 1262 * @param len the number of bytes to be compared 1263 */ 1264 public boolean compare(int pos1, InMessage msg, int pos2, int len) 1265 { 1266 /* 1267 * Verify that comparison arguments are regular 1268 * FIX 16/11/2000: Fixed the check by removing unnecessary (and wrong) 1269 * comparison between pos2+len and byteCount 1270 */ 1271 if (pos1 >= byteCount || pos2 >= msg.byteCount) 1272 throw new IllegalArgumentException("Pos1: " + pos1 + "Pos2: " + pos2 + " byteCount: " + byteCount + " len " + len); 1273 1274 /* 1275 * Compute start positions for comparison 1276 */ 1277 int frag1 = pos1 / payload; 1278 int frag2 = pos2 / msg.payload; 1279 int index1 = header + pos1 % payload; 1280 int index2 = msg.header + pos2 % msg.payload; 1281 1282 for (int i = 0; i < len; i++) { 1283 /* 1284 * Stop comparison if bytes in byte arrays differ 1285 */ 1286 if (fragments[frag1][index1] != msg.fragments[frag2][index2]) 1287 return false; 1288 1289 /* 1290 * Go to the next byte, moving to the next fragment if necessary 1291 */ 1292 index1++; 1293 index2++; 1294 if (index1 == endpayload) { 1295 index1 = header; 1296 frag1++; 1297 } 1298 if (index2 == msg.endpayload) { 1299 index2 = header; 1300 frag2++; 1301 } 1302 } 1303 1304 /* 1305 * The byte arrays are equal. 1306 */ 1307 return true; 1308 } 1309 1310 1311 //////////////////////////////////////////////////////////////////////////////////////////// 1312 // Package methods 1313 //////////////////////////////////////////////////////////////////////////////////////////// 1314 1315 /** 1316 * Insert a new fragment in the message whose payload field is 1317 * <tt>blen</tt> bytes long. 1318 */ 1319 public void insert(byte[] data, int blen) 1320 { 1321 byteCount += blen; 1322 if (fragmentCount == fragments.length) { 1323 // Double the space 1324 byte[][] btemp = new byte[fragments.length*2][]; 1325 System.arraycopy(fragments, 0, btemp, 0, fragments.length); 1326 fragments = btemp; 1327 } 1328 fragments[fragmentCount] = data; 1329 if (fragmentCount == 0) 1330 buffer = fragments[0]; 1331 fragmentCount++; 1332 } 1333 1334 1335 /** 1336 * Returns the total number of bytes stored in this message output stream. 1337 */ 1338 public int getByteCount() 1339 { 1340 return byteCount; 1341 } 1342 1343 1344 /** 1345 * Returns the current position in the message. 1346 */ 1347 public int getPosition() 1348 { 1349 return position; 1350 } 1351 1352 1353 /** 1354 * Returns the number of fragments composing the message. 1355 */ 1356 public int getFragmentCount() 1357 { 1358 return fragmentCount; 1359 } 1360 1361 1362 public byte[][] getFragments() 1363 { 1364 return fragments; 1365 } 1366 1367 1368 /** 1369 * Returns the length of the payload field for this message. 1370 */ 1371 public int getPayload() 1372 { 1373 return payload; 1374 } 1375 1376 /** 1377 * Returns the length of the payload of the last fragment composing 1378 * the message. 1379 */ 1380 public int getLastPayload() 1381 { 1382 if (byteCount % payload == 0) 1383 return payload; 1384 else 1385 return (byteCount % payload); 1386 } 1387 1388 /** 1389 * 1390 */ 1391 public int getHeader() 1392 { 1393 return header; 1394 } 1395 1396 /** 1397 * 1398 */ 1399 public int getTrailer() 1400 { 1401 return trailer; 1402 } 1403 1404 1405 //////////////////////////////////////////////////////////////////////////////////////////// 1406 // Private methods 1407 //////////////////////////////////////////////////////////////////////////////////////////// 1408 1409 /** 1410 * Copy <tt>size</tt> bytes in the temp array; this function is invoked when 1411 * the bytes read are part in fragment and part in the following one. 1412 */ 1413 private void readTemp(int size) 1414 { 1415 for (int i = 0; i < size; i++) { 1416 if (offset == endpayload) { 1417 fragment++; 1418 buffer = fragments[fragment]; 1419 offset = header; 1420 } 1421 temp[i] = buffer[offset++]; 1422 } 1423 } 1424 1425 1426 //////////////////////////////////////////////////////////////////////////////////////////// 1427 // Object methods 1428 //////////////////////////////////////////////////////////////////////////////////////////// 1429 1430 /** 1431 * Returns a string representation of this object 1432 */ 1433 public String toString() 1434 { 1435 StringBuilder buf = new StringBuilder(); 1436 buf.append("[InMessage: byteCnt="); 1437 buf.append(byteCount); 1438 buf.append(", payload="); 1439 buf.append(payload); 1440 buf.append(", header="); 1441 buf.append(header); 1442 buf.append(", trailer="); 1443 buf.append(trailer); 1444 buf.append(", totlen="); 1445 buf.append(totlen); 1446 buf.append(", endpayload="); 1447 buf.append(endpayload); 1448 buf.append(", position="); 1449 buf.append(position); 1450 buf.append(", fragment="); 1451 buf.append(fragment); 1452 buf.append(", offset="); 1453 buf.append(offset); 1454 buf.append(", fragmentCount="); 1455 buf.append(fragmentCount); 1456 buf.append(", marked="); 1457 buf.append(marked); 1458 buf.append("]"); 1459 1460 if (ConfigManager.logMsgContent) { 1461 buf.append(": "); 1462 } else { 1463 // Return without logging message content 1464 return buf.toString(); 1465 } 1466 1467 for (int i = 0; i < fragmentCount-1; i++) { 1468 for (int j = header; j < endpayload; j++) { 1469 buf.append(" "); 1470 if (j-header+1 == position) { 1471 buf.append(">> "); 1472 } 1473 buf.append(Util.byte2str(fragments[i][j])); 1474 if (j-header+1 == position) { 1475 buf.append(" << "); 1476 } 1477 } 1478 } 1479 1480 if (fragmentCount > 0) { 1481 /* 1482 * Print the content of the fragments, assuming that the InMessage 1483 * object has been initialized; that is fragmentCount > 0. 1484 */ 1485 int stop = byteCount - (fragmentCount-1)*payload + header; 1486 int lastFragStop = getLastPayload() + header; 1487 1488 for (int j = header; j < stop; j++) { 1489 buf.append(" "); 1490 if (j-header+1 == position) { 1491 buf.append(">> "); 1492 } 1493 buf.append(Util.byte2str(fragments[fragmentCount-1][j])); 1494 if (j-header+1 == position) { 1495 buf.append(" << "); 1496 } 1497 } 1498 buf.append(" --- stop="); 1499 buf.append(stop); 1500 buf.append(", lastFragStop="); 1501 buf.append(lastFragStop); 1502 } 1503 1504 return buf.toString(); 1505 } 1506 1507 } // END InMessage