1 /*
   2  * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.corba.se.impl.encoding;
  26 
  27 import java.io.IOException;
  28 import java.io.ObjectOutputStream;
  29 import java.io.ByteArrayOutputStream;
  30 
  31 import java.nio.ByteBuffer;
  32 
  33 import com.sun.corba.se.spi.orb.ORB;
  34 import com.sun.corba.se.spi.ior.IOR;
  35 import com.sun.corba.se.spi.ior.IORFactories;
  36 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  37 import com.sun.corba.se.spi.logging.CORBALogDomains;
  38 import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
  39 
  40 import com.sun.corba.se.impl.util.Utility;
  41 import com.sun.corba.se.impl.orbutil.ORBConstants;
  42 import com.sun.corba.se.impl.orbutil.ORBUtility;
  43 import com.sun.corba.se.impl.corba.TypeCodeImpl;
  44 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  45 import com.sun.corba.se.impl.protocol.giopmsgheaders.Message;
  46 
  47 import org.omg.CORBA.Any;
  48 import org.omg.CORBA.TypeCode;
  49 import org.omg.CORBA.Principal;
  50 import org.omg.CORBA.CompletionStatus;
  51 
  52 /**
  53  * Implementation class that uses Java serialization for output streams.
  54  * This assumes a GIOP version 1.2 message format.
  55  *
  56  * This class uses a ByteArrayOutputStream as the underlying buffer. The
  57  * first 16 bytes are direct writes into the underlying buffer. This allows
  58  * [GIOPHeader (12 bytes) + requestID (4 bytes)] to be written as bytes.
  59  * Subsequent write operations on this output stream object uses
  60  * ObjectOutputStream class to write into the buffer. This allows marshaling
  61  * complex types and graphs using the ObjectOutputStream implementation.
  62  *
  63  * Note, this class assumes a GIOP 1.2 style header. Note, we expect that the
  64  * first 16 bytes are written only using the write_octet, write_long or
  65  * write_ulong method calls.
  66  *
  67  * @author Ram Jeyaraman
  68  */
  69 final class IDLJavaSerializationOutputStream extends CDROutputStreamBase {
  70 
  71     private ORB orb;
  72     private byte encodingVersion;
  73     private ObjectOutputStream os;
  74     private _ByteArrayOutputStream bos;
  75     private BufferManagerWrite bufferManager;
  76 
  77     // [GIOPHeader(12) + requestID(4)] bytes
  78     private final int directWriteLength = Message.GIOPMessageHeaderLength + 4;
  79 
  80     protected ORBUtilSystemException wrapper;
  81 
  82     class _ByteArrayOutputStream extends ByteArrayOutputStream {
  83 
  84         _ByteArrayOutputStream(int initialSize) {
  85             super(initialSize);
  86         }
  87 
  88         byte[] getByteArray() {
  89             return this.buf;
  90         }
  91     }
  92 
  93     class MarshalObjectOutputStream extends ObjectOutputStream {
  94 
  95         ORB orb;
  96 
  97         MarshalObjectOutputStream(java.io.OutputStream out, ORB orb)
  98                 throws IOException {
  99 
 100             super(out);
 101             this.orb = orb;
 102             java.security.AccessController.doPrivileged(
 103                 new java.security.PrivilegedAction() {
 104                     public Object run() {
 105                         // needs SerializablePermission("enableSubstitution")
 106                         enableReplaceObject(true);
 107                         return null;
 108                     }
 109                 }
 110             );
 111         }
 112 
 113         /**
 114          * Checks for objects that are instances of java.rmi.Remote
 115          * that need to be serialized as proxy (Stub) objects.
 116          */
 117         protected final Object replaceObject(Object obj) throws IOException {
 118             try {
 119                 if ((obj instanceof java.rmi.Remote) &&
 120                         !(StubAdapter.isStub(obj))) {
 121                     return Utility.autoConnect(obj, orb, true);
 122                 }
 123             } catch (Exception e) {
 124                 IOException ie = new IOException("replaceObject failed");
 125                 ie.initCause(e);
 126                 throw ie;
 127             }
 128             return obj;
 129         }
 130     }
 131 
 132     public IDLJavaSerializationOutputStream(byte encodingVersion) {
 133         super();
 134         this.encodingVersion = encodingVersion;
 135     }
 136 
 137     public void init(org.omg.CORBA.ORB orb, boolean littleEndian,
 138                      BufferManagerWrite bufferManager,
 139                      byte streamFormatVersion,
 140                      boolean usePooledByteBuffers) {
 141         this.orb = (ORB) orb;
 142         this.bufferManager = bufferManager;
 143         wrapper = ORBUtilSystemException.get((ORB) orb,
 144                                              CORBALogDomains.RPC_ENCODING);
 145         bos =
 146             new _ByteArrayOutputStream(ORBConstants.GIOP_DEFAULT_BUFFER_SIZE);
 147     }
 148 
 149     // Called from read_octet or read_long or read_ulong method.
 150     private void initObjectOutputStream() {
 151         //System.out.print(" os ");
 152         if (os != null) {
 153             throw wrapper.javaStreamInitFailed();
 154         }
 155         try {
 156             os = new MarshalObjectOutputStream(bos, orb);
 157         } catch (Exception e) {
 158             throw wrapper.javaStreamInitFailed(e);
 159         }
 160     }
 161 
 162     // org.omg.CORBA.portable.OutputStream
 163 
 164     // Primitive types.
 165 
 166     public final void write_boolean(boolean value) {
 167         try {
 168             os.writeBoolean(value);
 169         } catch (Exception e) {
 170             throw wrapper.javaSerializationException(e, "write_boolean");
 171         }
 172     }
 173 
 174     public final void write_char(char value) {
 175         try {
 176             os.writeChar(value);
 177         } catch (Exception e) {
 178             throw wrapper.javaSerializationException(e, "write_char");
 179         }
 180     }
 181 
 182     public final void write_wchar(char value) {
 183         this.write_char(value);
 184     }
 185 
 186     public final void write_octet(byte value) {
 187 
 188         // check if size < [ GIOPHeader(12) + requestID(4)] bytes
 189         if (bos.size() < directWriteLength) {
 190             bos.write(value); // direct write.
 191             if (bos.size() == directWriteLength) {
 192                 initObjectOutputStream();
 193             }
 194             return;
 195         }
 196 
 197         try {
 198             os.writeByte(value);
 199         } catch (Exception e) {
 200             throw wrapper.javaSerializationException(e, "write_octet");
 201         }
 202     }
 203 
 204     public final void write_short(short value) {
 205         try {
 206             os.writeShort(value);
 207         } catch (Exception e) {
 208             throw wrapper.javaSerializationException(e, "write_short");
 209         }
 210     }
 211 
 212     public final void write_ushort(short value) {
 213         this.write_short(value);
 214     }
 215 
 216     public final void write_long(int value) {
 217 
 218         // check if size < [ GIOPHeader(12) + requestID(4)] bytes
 219         if (bos.size() < directWriteLength) {
 220 
 221             // Use big endian (network byte order). This is fixed.
 222             // Both the writer and reader use the same byte order.
 223             bos.write((byte)((value >>> 24) & 0xFF));
 224             bos.write((byte)((value >>> 16) & 0xFF));
 225             bos.write((byte)((value >>> 8) & 0xFF));
 226             bos.write((byte)((value >>> 0) & 0xFF));
 227 
 228             if (bos.size() == directWriteLength) {
 229                 initObjectOutputStream();
 230             } else if (bos.size() > directWriteLength) {
 231                 // Cannot happen. All direct writes are contained
 232                 // within the first 16 bytes.
 233                 wrapper.javaSerializationException("write_long");
 234             }
 235             return;
 236         }
 237 
 238         try {
 239             os.writeInt(value);
 240         } catch (Exception e) {
 241             throw wrapper.javaSerializationException(e, "write_long");
 242         }
 243     }
 244 
 245     public final void write_ulong(int value) {
 246         this.write_long(value);
 247     }
 248 
 249     public final void write_longlong(long value) {
 250         try {
 251             os.writeLong(value);
 252         } catch (Exception e) {
 253             throw wrapper.javaSerializationException(e, "write_longlong");
 254         }
 255     }
 256 
 257     public final void write_ulonglong(long value) {
 258         this.write_longlong(value);
 259     }
 260 
 261     public final void write_float(float value) {
 262         try {
 263             os.writeFloat(value);
 264         } catch (Exception e) {
 265             throw wrapper.javaSerializationException(e, "write_float");
 266         }
 267     }
 268 
 269     public final void write_double(double value) {
 270         try {
 271             os.writeDouble(value);
 272         } catch (Exception e) {
 273             throw wrapper.javaSerializationException(e, "write_double");
 274         }
 275     }
 276 
 277     // String types.
 278 
 279     public final void write_string(String value) {
 280         try {
 281             os.writeUTF(value);
 282         } catch (Exception e) {
 283             throw wrapper.javaSerializationException(e, "write_string");
 284         }
 285     }
 286 
 287     public final void write_wstring(String value) {
 288         try {
 289             os.writeObject(value);
 290         } catch (Exception e) {
 291             throw wrapper.javaSerializationException(e, "write_wstring");
 292         }
 293     }
 294 
 295     // Array types.
 296 
 297     public final void write_boolean_array(boolean[] value,
 298                                           int offset, int length) {
 299         for (int i = 0; i < length; i++) {
 300             write_boolean(value[offset + i]);
 301         }
 302     }
 303 
 304     public final void write_char_array(char[] value, int offset, int length) {
 305         for (int i = 0; i < length; i++) {
 306             write_char(value[offset + i]);
 307         }
 308     }
 309 
 310     public final void write_wchar_array(char[] value, int offset, int length) {
 311         write_char_array(value, offset, length);
 312     }
 313 
 314     public final void write_octet_array(byte[] value, int offset, int length) {
 315         try {
 316             os.write(value, offset, length);
 317         } catch (Exception e) {
 318             throw wrapper.javaSerializationException(e, "write_octet_array");
 319         }
 320     }
 321 
 322     public final void write_short_array(short[] value,
 323                                         int offset, int length) {
 324         for (int i = 0; i < length; i++) {
 325             write_short(value[offset + i]);
 326         }
 327     }
 328 
 329     public final void write_ushort_array(short[] value,
 330                                          int offset, int length){
 331         write_short_array(value, offset, length);
 332     }
 333 
 334     public final void write_long_array(int[] value, int offset, int length) {
 335         for (int i = 0; i < length; i++) {
 336             write_long(value[offset + i]);
 337         }
 338     }
 339 
 340     public final void write_ulong_array(int[] value, int offset, int length) {
 341         write_long_array(value, offset, length);
 342     }
 343 
 344     public final void write_longlong_array(long[] value,
 345                                            int offset, int length) {
 346         for (int i = 0; i < length; i++) {
 347             write_longlong(value[offset + i]);
 348         }
 349     }
 350 
 351     public final void write_ulonglong_array(long[] value,
 352                                             int offset,int length) {
 353         write_longlong_array(value, offset, length);
 354     }
 355 
 356     public final void write_float_array(float[] value,
 357                                         int offset, int length) {
 358         for (int i = 0; i < length; i++) {
 359             write_float(value[offset + i]);
 360         }
 361     }
 362 
 363     public final void write_double_array(double[] value,
 364                                          int offset, int length) {
 365         for (int i = 0; i < length; i++) {
 366             write_double(value[offset + i]);
 367         }
 368     }
 369 
 370     // Complex types (objects and graphs).
 371 
 372     public final void write_Object(org.omg.CORBA.Object value) {
 373         if (value == null) {
 374             IOR nullIOR = IORFactories.makeIOR(orb);
 375             nullIOR.write(parent);
 376             return;
 377         }
 378         // IDL to Java formal 01-06-06 1.21.4.2
 379         if (value instanceof org.omg.CORBA.LocalObject) {
 380             throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE);
 381         }
 382         IOR ior = ORBUtility.connectAndGetIOR(orb, value);
 383         ior.write(parent);
 384         return;
 385     }
 386 
 387     public final void write_TypeCode(TypeCode tc) {
 388         if (tc == null) {
 389             throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
 390         }
 391         TypeCodeImpl tci;
 392         if (tc instanceof TypeCodeImpl) {
 393             tci = (TypeCodeImpl) tc;
 394         } else {
 395             tci = new TypeCodeImpl(orb, tc);
 396         }
 397         tci.write_value((org.omg.CORBA_2_3.portable.OutputStream) parent);
 398     }
 399 
 400     public final void write_any(Any any) {
 401         if (any == null) {
 402             throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
 403         }
 404         write_TypeCode(any.type());
 405         any.write_value(parent);
 406     }
 407 
 408     public final void write_Principal(Principal p) {
 409         // We don't need an implementation for this method, since principal
 410         // is absent in GIOP version 1.2 or above.
 411         write_long(p.name().length);
 412         write_octet_array(p.name(), 0, p.name().length);
 413     }
 414 
 415     public final void write_fixed(java.math.BigDecimal bigDecimal) {
 416         // This string might contain sign and/or dot
 417         this.write_fixed(bigDecimal.toString(), bigDecimal.signum());
 418     }
 419 
 420     // The string may contain a sign and dot
 421     private void write_fixed(String string, int signum) {
 422 
 423         int stringLength = string.length();
 424 
 425         // Each octet contains (up to) two decimal digits.
 426         byte doubleDigit = 0;
 427         char ch;
 428         byte digit;
 429 
 430         // First calculate the string length without optional sign and dot.
 431         int numDigits = 0;
 432         for (int i=0; i<stringLength; i++) {
 433             ch = string.charAt(i);
 434             if (ch == '-' || ch == '+' || ch == '.')
 435                 continue;
 436             numDigits++;
 437         }
 438 
 439         for (int i=0; i<stringLength; i++) {
 440             ch = string.charAt(i);
 441             if (ch == '-' || ch == '+' || ch == '.')
 442                 continue;
 443             digit = (byte)Character.digit(ch, 10);
 444             if (digit == -1) {
 445                 throw wrapper.badDigitInFixed(
 446                                             CompletionStatus.COMPLETED_MAYBE);
 447             }
 448             // If the fixed type has an odd number of decimal digits, then the
 449             // representation begins with the first (most significant) digit.
 450             // Otherwise, this first half-octet is all zero, and the first
 451             // digit is in the second half-octet.
 452             if (numDigits % 2 == 0) {
 453                 doubleDigit |= digit;
 454                 this.write_octet(doubleDigit);
 455                 doubleDigit = 0;
 456             } else {
 457                 doubleDigit |= (digit << 4);
 458             }
 459             numDigits--;
 460         }
 461 
 462         // The sign configuration in the last half-octet of the representation,
 463         // is 0xD for negative numbers and 0xC for positive and zero values.
 464         if (signum == -1) {
 465             doubleDigit |= 0xd;
 466         } else {
 467             doubleDigit |= 0xc;
 468         }
 469         this.write_octet(doubleDigit);
 470     }
 471 
 472     public final org.omg.CORBA.ORB orb() {
 473         return this.orb;
 474     }
 475 
 476     // org.omg.CORBA_2_3.portable.OutputStream
 477 
 478     public final void write_value(java.io.Serializable value) {
 479         write_value(value, (String) null);
 480     }
 481 
 482     public final void write_value(java.io.Serializable value,
 483                                   java.lang.Class clz) {
 484         write_value(value);
 485     }
 486 
 487     public final void write_value(java.io.Serializable value,
 488                                   String repository_id) {
 489         try {
 490             os.writeObject(value);
 491         } catch (Exception e) {
 492             throw wrapper.javaSerializationException(e, "write_value");
 493         }
 494     }
 495 
 496     public final void write_value(java.io.Serializable value,
 497                              org.omg.CORBA.portable.BoxedValueHelper factory) {
 498         this.write_value(value, (String) null);
 499     }
 500 
 501     public final void write_abstract_interface(java.lang.Object obj) {
 502 
 503         boolean isCorbaObject = false; // Assume value type.
 504         org.omg.CORBA.Object theCorbaObject = null;
 505 
 506         // Is it a CORBA.Object?
 507         if (obj != null && obj instanceof org.omg.CORBA.Object) {
 508             theCorbaObject = (org.omg.CORBA.Object)obj;
 509             isCorbaObject = true;
 510         }
 511 
 512         // Write the boolean flag.
 513         this.write_boolean(isCorbaObject);
 514 
 515         // Now write out the object.
 516         if (isCorbaObject) {
 517             write_Object(theCorbaObject);
 518         } else {
 519             try {
 520                 write_value((java.io.Serializable)obj);
 521             } catch(ClassCastException cce) {
 522                 if (obj instanceof java.io.Serializable) {
 523                     throw cce;
 524                 } else {
 525                     ORBUtility.throwNotSerializableForCorba(
 526                                                     obj.getClass().getName());
 527                 }
 528             }
 529         }
 530     }
 531 
 532     // com.sun.corba.se.os.encoding.MarshalOutputStream
 533 
 534     public final void start_block() {
 535         throw wrapper.giopVersionError();
 536     }
 537 
 538     public final void end_block() {
 539         throw wrapper.giopVersionError();
 540     }
 541 
 542     public final void putEndian() {
 543         throw wrapper.giopVersionError();
 544     }
 545 
 546     public void writeTo(java.io.OutputStream s) throws IOException {
 547         try {
 548             os.flush();
 549             bos.writeTo(s);
 550         } catch (Exception e) {
 551             throw wrapper.javaSerializationException(e, "writeTo");
 552         }
 553     }
 554 
 555     public final byte[] toByteArray() {
 556         try {
 557             os.flush();
 558             return bos.toByteArray(); // new copy.
 559         } catch (Exception e) {
 560             throw wrapper.javaSerializationException(e, "toByteArray");
 561         }
 562     }
 563 
 564     // org.omg.CORBA.DataOutputStream
 565 
 566     public final void write_Abstract (java.lang.Object value) {
 567         write_abstract_interface(value);
 568     }
 569 
 570     public final void write_Value(java.io.Serializable value) {
 571         write_value(value);
 572     }
 573 
 574     public final void write_any_array(org.omg.CORBA.Any[] value,
 575                                       int offset, int length) {
 576         for(int i = 0; i < length; i++) {
 577             write_any(value[offset + i]);
 578         }
 579     }
 580 
 581     // org.omg.CORBA.portable.ValueBase
 582 
 583     public final String[] _truncatable_ids() {
 584         throw wrapper.giopVersionError();
 585     }
 586 
 587     // Other.
 588 
 589     public final int getSize() {
 590         try {
 591             os.flush();
 592             return bos.size();
 593         } catch (Exception e) {
 594             throw wrapper.javaSerializationException(e, "write_boolean");
 595         }
 596     }
 597 
 598     public final int getIndex() {
 599         return getSize();
 600     }
 601 
 602     protected int getRealIndex(int index) {
 603         return getSize();
 604     }
 605 
 606     public final void setIndex(int value) {
 607         throw wrapper.giopVersionError();
 608     }
 609 
 610     public final ByteBuffer getByteBuffer() {
 611         throw wrapper.giopVersionError();
 612     }
 613 
 614     public final void setByteBuffer(ByteBuffer byteBuffer) {
 615         throw wrapper.giopVersionError();
 616     }
 617 
 618     public final boolean isLittleEndian() {
 619         // Java serialization uses network byte order, that is, big-endian.
 620         return false;
 621     }
 622 
 623     public ByteBufferWithInfo getByteBufferWithInfo() {
 624         try {
 625             os.flush();
 626         } catch (Exception e) {
 627             throw wrapper.javaSerializationException(
 628                                             e, "getByteBufferWithInfo");
 629         }
 630         ByteBuffer byteBuffer = ByteBuffer.wrap(bos.getByteArray());
 631         byteBuffer.limit(bos.size());
 632         return new ByteBufferWithInfo(this.orb, byteBuffer, bos.size());
 633     }
 634 
 635     public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
 636         throw wrapper.giopVersionError();
 637     }
 638 
 639     public final BufferManagerWrite getBufferManager() {
 640         return bufferManager;
 641     }
 642 
 643     // This will stay a custom add-on until the java-rtf issue is resolved.
 644     // Then it should be declared in org.omg.CORBA.portable.OutputStream.
 645     //
 646     // Pads the string representation of bigDecimal with zeros to fit the given
 647     // digits and scale before it gets written to the stream.
 648     public final void write_fixed(java.math.BigDecimal bigDecimal,
 649                                   short digits, short scale) {
 650         String string = bigDecimal.toString();
 651         String integerPart;
 652         String fractionPart;
 653         StringBuffer stringBuffer;
 654 
 655         // Get rid of the sign
 656         if (string.charAt(0) == '-' || string.charAt(0) == '+') {
 657             string = string.substring(1);
 658         }
 659 
 660         // Determine integer and fraction parts
 661         int dotIndex = string.indexOf('.');
 662         if (dotIndex == -1) {
 663             integerPart = string;
 664             fractionPart = null;
 665         } else if (dotIndex == 0 ) {
 666             integerPart = null;
 667             fractionPart = string;
 668         } else {
 669             integerPart = string.substring(0, dotIndex);
 670             fractionPart = string.substring(dotIndex + 1);
 671         }
 672 
 673         // Pad both parts with zeros as necessary
 674         stringBuffer = new StringBuffer(digits);
 675         if (fractionPart != null) {
 676             stringBuffer.append(fractionPart);
 677         }
 678         while (stringBuffer.length() < scale) {
 679             stringBuffer.append('0');
 680         }
 681         if (integerPart != null) {
 682             stringBuffer.insert(0, integerPart);
 683         }
 684         while (stringBuffer.length() < digits) {
 685             stringBuffer.insert(0, '0');
 686         }
 687 
 688         // This string contains no sign or dot
 689         this.write_fixed(stringBuffer.toString(), bigDecimal.signum());
 690     }
 691 
 692     public final void writeOctetSequenceTo(
 693             org.omg.CORBA.portable.OutputStream s) {
 694         byte[] buf = this.toByteArray(); // new copy.
 695         s.write_long(buf.length);
 696         s.write_octet_array(buf, 0, buf.length);
 697     }
 698 
 699     public final GIOPVersion getGIOPVersion() {
 700         return GIOPVersion.V1_2;
 701     }
 702 
 703     public final void writeIndirection(int tag, int posIndirectedTo) {
 704         throw wrapper.giopVersionError();
 705     }
 706 
 707     void freeInternalCaches() {}
 708 
 709     void printBuffer() {
 710         byte[] buf = this.toByteArray();
 711 
 712         System.out.println("+++++++ Output Buffer ++++++++");
 713         System.out.println();
 714         System.out.println("Current position: " + buf.length);
 715         //System.out.println("Total length : " + buf.length);
 716         System.out.println();
 717 
 718         char[] charBuf = new char[16];
 719 
 720         try {
 721 
 722             for (int i = 0; i < buf.length; i += 16) {
 723 
 724                 int j = 0;
 725 
 726                 // For every 16 bytes, there is one line
 727                 // of output.  First, the hex output of
 728                 // the 16 bytes with each byte separated
 729                 // by a space.
 730                 while (j < 16 && j + i < buf.length) {
 731                     int k = buf[i + j];
 732                     if (k < 0)
 733                         k = 256 + k;
 734                     String hex = Integer.toHexString(k);
 735                     if (hex.length() == 1)
 736                         hex = "0" + hex;
 737                     System.out.print(hex + " ");
 738                     j++;
 739                 }
 740 
 741                 // Add any extra spaces to align the
 742                 // text column in case we didn't end
 743                 // at 16
 744                 while (j < 16) {
 745                     System.out.print("   ");
 746                     j++;
 747                 }
 748 
 749                 // Now output the ASCII equivalents.  Non-ASCII
 750                 // characters are shown as periods.
 751                 int x = 0;
 752 
 753                 while (x < 16 && x + i < buf.length) {
 754                     if (ORBUtility.isPrintable((char)buf[i + x])) {
 755                         charBuf[x] = (char) buf[i + x];
 756                     } else {
 757                         charBuf[x] = '.';
 758                     }
 759                     x++;
 760                 }
 761                 System.out.println(new String(charBuf, 0, x));
 762             }
 763         } catch (Throwable t) {
 764             t.printStackTrace();
 765         }
 766         System.out.println("++++++++++++++++++++++++++++++");
 767     }
 768 
 769     public void alignOnBoundary(int octetBoundary) {
 770         throw wrapper.giopVersionError();
 771     }
 772 
 773     // Needed by request and reply messages for GIOP versions >= 1.2 only.
 774     public void setHeaderPadding(boolean headerPadding) {
 775         // no-op. We don't care about body alignment while using
 776         // Java serialization. What the GIOP spec states does not apply here.
 777     }
 778 
 779     // ValueOutputStream -----------------------------
 780 
 781     public void start_value(String rep_id) {
 782         throw wrapper.giopVersionError();
 783     }
 784 
 785     public void end_value() {
 786         throw wrapper.giopVersionError();
 787     }
 788 
 789     // java.io.OutputStream
 790 
 791     // Note: These methods are defined in the super class and accessible.
 792 
 793     //public abstract void write(byte b[]) throws IOException;
 794     //public abstract void write(byte b[], int off, int len)
 795     //    throws IOException;
 796     //public abstract void flush() throws IOException;
 797     //public abstract void close() throws IOException;
 798 }