1 /* AbstractCdrOutput.java --
2    Copyright (C) 2005 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.CORBA.CDR;
40 
41 import gnu.CORBA.BigDecimalHelper;
42 import gnu.CORBA.IOR;
43 import gnu.CORBA.IorProvider;
44 import gnu.CORBA.Minor;
45 import gnu.CORBA.TypeCodeHelper;
46 import gnu.CORBA.Unexpected;
47 import gnu.CORBA.Version;
48 import gnu.CORBA.GIOP.CharSets_OSF;
49 import gnu.CORBA.GIOP.CodeSetServiceContext;
50 import gnu.CORBA.typecodes.PrimitiveTypeCode;
51 
52 import org.omg.CORBA.Any;
53 import org.omg.CORBA.BAD_OPERATION;
54 import org.omg.CORBA.Context;
55 import org.omg.CORBA.ContextList;
56 import org.omg.CORBA.DataInputStream;
57 import org.omg.CORBA.MARSHAL;
58 import org.omg.CORBA.NO_IMPLEMENT;
59 import org.omg.CORBA.ORB;
60 import org.omg.CORBA.TCKind;
61 import org.omg.CORBA.TypeCode;
62 import org.omg.CORBA.UserException;
63 import org.omg.CORBA.TypeCodePackage.BadKind;
64 import org.omg.CORBA.portable.Delegate;
65 import org.omg.CORBA.portable.ObjectImpl;
66 import org.omg.CORBA.portable.OutputStream;
67 import org.omg.CORBA.portable.Streamable;
68 
69 import java.io.IOException;
70 import java.io.OutputStreamWriter;
71 import java.io.Serializable;
72 import java.math.BigDecimal;
73 
74 /**
75  * A simple CORBA CDR (common data representation)
76  * output stream, writing data into the
77  * given {@link java.io.OutputStream}.
78  *
79  * The same class also implements the {@link DataInputStream},
80  * providing support for writing the value type objects
81  * in a user defined way.
82  *
83  * TODO This class uses 16 bits per Unicode character only, as it was until
84  * jdk 1.4 inclusive.
85  *
86  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
87  */
88 public abstract class AbstractCdrOutput
89   extends org.omg.CORBA_2_3.portable.OutputStream
90   implements org.omg.CORBA.DataOutputStream
91 {
92   /**
93    * The runtime, associated with this stream. This field is only used when
94    * reading and writing value types and filled-in in gnu.CORBA.CDR.Vio.
95    */
96   public transient gnuRuntime runtime;
97 
98   /**
99    * This instance is used to convert primitive data types into the
100    * byte sequences.
101    */
102   protected AbstractDataOutput b;
103 
104   /**
105    * The associated orb, if any.
106    */
107   protected ORB orb;
108 
109   /**
110    * The GIOP version.
111    */
112   protected Version giop = new Version(1, 2);
113 
114   /**
115    * The code set information.
116    */
117   protected CodeSetServiceContext codeset;
118 
119   /**
120    * The name of the currently used narrow charset.
121    */
122   private String narrow_charset;
123 
124   /**
125    * The name of the currently used wide charset, null if
126    * the native wide charset is used.
127    */
128   private String wide_charset;
129 
130   /**
131    * True if the native code set is used for narrow characters.
132    * If the set is native, no the intermediate Reader object
133    * is instantiated when writing characters.
134    */
135   private boolean narrow_native;
136 
137   /**
138    * True if the native code set is used for wide characters.
139    * If the set is native, no the intermediate Reader object
140    * is instantiated when writing characters.
141    */
142   private boolean wide_native;
143 
144   /**
145    * If true, the Little Endian encoding is used to write the
146    * data. Otherwise, the Big Endian encoding is used.
147    */
148   private boolean little_endian;
149 
150   /**
151    * The stream whre the data are actually written.
152    */
153   private java.io.OutputStream actual_stream;
154 
155   /**
156    * Creates the stream.
157    *
158    * @param writeTo a stream to write CORBA output to.
159    */
AbstractCdrOutput(java.io.OutputStream writeTo)160   public AbstractCdrOutput(java.io.OutputStream writeTo)
161   {
162     setOutputStream(writeTo);
163     setCodeSet(CodeSetServiceContext.STANDARD);
164   }
165 
166   /**
167    * Creates the stream, requiring the subsequent call
168    * of {@link #setOutputStream(java.io.OutputStream)}.
169    */
AbstractCdrOutput()170   public AbstractCdrOutput()
171   {
172     setCodeSet(CodeSetServiceContext.STANDARD);
173   }
174 
175   /**
176    * Set the alignment offset, if the index of the first byte in the
177    * stream is different from 0.
178    */
setOffset(int an_offset)179   public abstract void setOffset(int an_offset);
180 
181   /**
182    * Clone all important settings to another stream.
183    */
cloneSettings(AbstractCdrOutput stream)184   public void cloneSettings(AbstractCdrOutput stream)
185   {
186     stream.setBigEndian(!little_endian);
187     stream.setCodeSet(getCodeSet());
188     stream.setVersion(giop);
189     stream.setOrb(orb);
190   }
191 
192   /**
193    * Set the current code set context.
194    */
setCodeSet(CodeSetServiceContext a_codeset)195   public void setCodeSet(CodeSetServiceContext a_codeset)
196   {
197     this.codeset = a_codeset;
198     narrow_charset = CharSets_OSF.getName(codeset.char_data);
199     wide_charset = CharSets_OSF.getName(codeset.wide_char_data);
200 
201     narrow_native = CharSets_OSF.NATIVE_CHARACTER == codeset.char_data;
202     wide_native = CharSets_OSF.NATIVE_WIDE_CHARACTER == codeset.wide_char_data;
203   }
204 
205   /**
206    * Get the current code set context.
207    */
getCodeSet()208   public CodeSetServiceContext getCodeSet()
209   {
210     return codeset;
211   }
212 
213   /**
214    * Set the orb, associated with this stream.
215    * @param an_orb
216    */
setOrb(ORB an_orb)217   public void setOrb(ORB an_orb)
218   {
219     orb = an_orb;
220   }
221 
222   /**
223    * Set the output stream that receives the CORBA output.
224    *
225    * @param writeTo the stream.
226    */
setOutputStream(java.io.OutputStream writeTo)227   public void setOutputStream(java.io.OutputStream writeTo)
228   {
229     if (little_endian)
230       b = new LittleEndianOutputStream(writeTo);
231     else
232       b = new BigEndianOutputStream(writeTo);
233 
234     actual_stream = writeTo;
235   }
236 
237   /**
238    * Set the GIOP version. Some data types are written differently
239    * for the different versions. The default version is 1.0 .
240    */
setVersion(Version giop_version)241   public void setVersion(Version giop_version)
242   {
243     giop = giop_version;
244   }
245 
246   /**
247    * Specify if the stream should use the Big Endian (usual for java)
248    * or Little Encoding. The default is Big Endian.
249    *
250    * @param use_big_endian if true, use Big Endian, if false,
251    * use Little Endian.
252    */
setBigEndian(boolean use_big_endian)253   public void setBigEndian(boolean use_big_endian)
254   {
255     little_endian = !use_big_endian;
256     setOutputStream(actual_stream);
257   }
258 
259   /**
260    * Align the curretn position at the given natural boundary.
261    */
align(int boundary)262   public abstract void align(int boundary);
263 
264   /**
265    * Create the encapsulation stream, associated with the current
266    * stream. The encapsulated stream must be closed. When being
267    * closed, the encapsulation stream writes its buffer into
268    * this stream using the CORBA CDR encapsulation rules.
269    *
270    * It is not allowed to write to the current stream directly
271    * before the encapsulation stream is closed.
272    *
273    * The encoding (Big/Little Endian) inside the encapsulated
274    * sequence is the same as used into the parent stream.
275    *
276    * @return the encapsulated stream.
277    */
createEncapsulation()278   public AbstractCdrOutput createEncapsulation()
279   {
280     return new EncapsulationStream(this, !little_endian);
281   }
282 
283   /**
284    * Return the associated {@link ORB}.
285    * @return the associated {@link ORB} or null is no such is set.
286    */
orb()287   public ORB orb()
288   {
289     return orb;
290   }
291 
292   /**
293    * Write a single byte.
294    * @param n byte to write (low 8 bits are written).
295    */
write(int n)296   public void write(int n)
297   {
298     try
299       {
300         b.write(n);
301       }
302     catch (IOException ex)
303       {
304         Unexpected.error(ex);
305       }
306   }
307 
308   /**
309    * Write bytes directly into the underlying stream.
310    */
write(byte[] x)311   public void write(byte[] x)
312              throws java.io.IOException
313   {
314     b.write(x);
315   }
316 
317   /**
318    * Write bytes directly into the underlying stream.
319    */
write(byte[] x, int ofs, int len)320   public void write(byte[] x, int ofs, int len)
321              throws java.io.IOException
322   {
323     b.write(x, ofs, len);
324   }
325 
326   /**
327    * Following the specification, this is not implemented.
328    * Override to get the functionality.
329    */
write_Context(Context context, ContextList contexts)330   public void write_Context(Context context, ContextList contexts)
331   {
332     throw new NO_IMPLEMENT();
333   }
334 
335   /**
336    * Read the CORBA object. The object is written form of the plain (not a
337    * string-encoded) IOR profile without the heading endian indicator. The
338    * responsible method for reading such data is {@link IOR.write_no_endian}.
339    *
340    * The null value is written as defined in OMG specification (zero length
341    * string, followed by an empty set of profiles).
342    */
write_Object(org.omg.CORBA.Object x)343   public void write_Object(org.omg.CORBA.Object x)
344   {
345     ORB w_orb = orb;
346     if (x instanceof IorProvider)
347       {
348         ((IorProvider) x).getIor()._write_no_endian(this);
349         return;
350       }
351     else if (x == null)
352       {
353         IOR.write_null(this);
354         return;
355       }
356     else if (x instanceof ObjectImpl)
357       {
358         Delegate d = ((ObjectImpl) x)._get_delegate();
359 
360         if (d instanceof IorProvider)
361           {
362             ((IorProvider) d).getIor()._write_no_endian(this);
363             return;
364           }
365         else
366           {
367             ORB d_orb = d.orb(x);
368             if (d_orb != null)
369               w_orb = d_orb;
370           }
371       }
372 
373     // Either this is not an ObjectImpl or it has the
374     // unexpected delegate. Try to convert via ORBs
375     // object_to_string().
376     if (w_orb != null)
377       {
378         IOR ior = IOR.parse(w_orb.object_to_string(x));
379         ior._write_no_endian(this);
380         return;
381       }
382     else
383       throw new BAD_OPERATION(
384         "Please set the ORB for this stream, cannot write "
385           + x.getClass().getName());
386   }
387 
388   /**
389    * Write the TypeCode. This implementation delegates functionality
390    * to {@link cdrTypeCode}.
391    *
392    * @param x a TypeCode to write.
393    */
write_TypeCode(TypeCode x)394   public void write_TypeCode(TypeCode x)
395   {
396     try
397       {
398         TypeCodeHelper.write(this, x);
399       }
400     catch (UserException ex)
401       {
402         Unexpected.error(ex);
403       }
404   }
405 
406   /**
407    * Writes an instance of the CORBA {@link Any}.
408    * This method writes the typecode, followed
409    * by value itself. In Any contains null
410    * (value not set), the {@link TCKind#tk_null}
411    * is written.
412    *
413    * @param x the {@link Any} to write.
414    */
write_any(Any x)415   public void write_any(Any x)
416   {
417     Streamable value = x.extract_Streamable();
418     if (value != null)
419       {
420         write_TypeCode(x.type());
421         value._write(this);
422       }
423     else
424       {
425         PrimitiveTypeCode p = new PrimitiveTypeCode(TCKind.tk_null);
426         write_TypeCode(p);
427       }
428   }
429 
430   /**
431    * Writes a single byte, 0 for <code>false</code>,
432    * 1 for <code>true</code>.
433    *
434    * @param x the value to write
435    */
write_boolean(boolean x)436   public void write_boolean(boolean x)
437   {
438     try
439       {
440         b.write(x ? 1 : 0);
441       }
442     catch (IOException ex)
443       {
444         Unexpected.error(ex);
445       }
446   }
447 
448   /**
449    * Writes the boolean array.
450    *
451    * @param x array
452    * @param ofs offset
453    * @param len length.
454    */
write_boolean_array(boolean[] x, int ofs, int len)455   public void write_boolean_array(boolean[] x, int ofs, int len)
456   {
457     try
458       {
459         for (int i = ofs; i < ofs + len; i++)
460           {
461             b.write(x [ i ] ? 1 : 0);
462           }
463       }
464     catch (IOException ex)
465       {
466         Unexpected.error(ex);
467       }
468   }
469 
470   /**
471    * Writes the lower byte of the passed parameter.
472    * @param x the char to write
473    *
474    * It is effective to write more characters at once.
475    */
write_char(char x)476   public void write_char(char x)
477   {
478     try
479       {
480         if (narrow_native)
481           b.write(x);
482         else
483           {
484             OutputStreamWriter ow =
485               new OutputStreamWriter((OutputStream) b, narrow_charset);
486             ow.write(x);
487             ow.flush();
488           }
489       }
490     catch (IOException ex)
491       {
492         Unexpected.error(ex);
493       }
494   }
495 
496   /**
497    * Writes the lower bytes of the passed array members.
498    *
499    * @param chars an array
500    * @param offset offset
501    * @param length length
502    */
write_char_array(char[] chars, int offset, int length)503   public void write_char_array(char[] chars, int offset, int length)
504   {
505     try
506       {
507         if (narrow_native)
508           {
509             for (int i = offset; i < offset + length; i++)
510               {
511                 b.write(chars [ i ]);
512               }
513           }
514         else
515           {
516             OutputStreamWriter ow =
517               new OutputStreamWriter((OutputStream) b, narrow_charset);
518             ow.write(chars, offset, length);
519             ow.flush();
520           }
521       }
522     catch (IOException ex)
523       {
524         Unexpected.error(ex);
525       }
526   }
527 
528   /**
529    * Writes the double value (IEEE 754 format).
530    */
write_double(double x)531   public void write_double(double x)
532   {
533     try
534       {
535         align(8);
536         b.writeDouble(x);
537       }
538     catch (Exception ex)
539       {
540         Unexpected.error(ex);
541       }
542   }
543 
544   /**
545    * Writes the array of double values.
546    */
write_double_array(double[] x, int ofs, int len)547   public void write_double_array(double[] x, int ofs, int len)
548   {
549     try
550       {
551         align(8);
552         for (int i = ofs; i < ofs + len; i++)
553           {
554             b.writeDouble(x [ i ]);
555           }
556       }
557     catch (IOException ex)
558       {
559         Unexpected.error(ex);
560       }
561   }
562 
563   /**
564    * Writes CORBA fixed, storing all digits but not the scale.
565    * The end of the record on <code>fixed</code> can
566    * be determined from its last byte.
567    */
write_fixed(BigDecimal fixed)568   public void write_fixed(BigDecimal fixed)
569   {
570     try
571       {
572         BigDecimalHelper.write(this, fixed);
573       }
574     catch (IOException ex)
575       {
576         Unexpected.error(ex);
577       }
578     catch (BadKind ex)
579       {
580         Unexpected.error(ex);
581       }
582   }
583 
584   /**
585    * Write the float value (IEEE 754 format).
586    */
write_float(float x)587   public void write_float(float x)
588   {
589     try
590       {
591         align(4);
592         b.writeFloat(x);
593       }
594     catch (IOException ex)
595       {
596         Unexpected.error(ex);
597       }
598   }
599 
600   /**
601    *  Writes an array of the float values.
602    */
write_float_array(float[] x, int ofs, int len)603   public void write_float_array(float[] x, int ofs, int len)
604   {
605     try
606       {
607         align(4);
608         for (int i = ofs; i < ofs + len; i++)
609           {
610             b.writeFloat(x [ i ]);
611           }
612       }
613     catch (IOException ex)
614       {
615         Unexpected.error(ex);
616       }
617   }
618 
619   /**
620    * Writes the integer value (CORBA long, four bytes, high byte first).
621    * @param x the value to write.
622    */
write_long(int x)623   public void write_long(int x)
624   {
625     try
626       {
627         align(4);
628         b.writeInt(x);
629       }
630     catch (IOException ex)
631       {
632         Unexpected.error(ex);
633       }
634   }
635 
636   /**
637    * Writes the array of integer (CORBA long) values.
638    *
639    * @param x value
640    * @param ofs offset
641    * @param len length
642    */
write_long_array(int[] x, int ofs, int len)643   public void write_long_array(int[] x, int ofs, int len)
644   {
645     try
646       {
647         align(4);
648         for (int i = ofs; i < ofs + len; i++)
649           {
650             b.writeInt(x [ i ]);
651           }
652       }
653     catch (IOException ex)
654       {
655         Unexpected.error(ex);
656       }
657   }
658 
659   /**
660    * Writes the long (CORBA long long) value, 8 bytes,
661    * high byte first.
662    *
663    * @param x the value to write.
664    */
write_longlong(long x)665   public void write_longlong(long x)
666   {
667     try
668       {
669         align(8);
670         b.writeLong(x);
671       }
672     catch (IOException ex)
673       {
674         Unexpected.error(ex);
675       }
676   }
677 
678   /**
679    * Writes the array of longs (CORBA long longs) values.
680    *
681    * @param x value
682    * @param ofs offset
683    * @param len length
684    */
write_longlong_array(long[] x, int ofs, int len)685   public void write_longlong_array(long[] x, int ofs, int len)
686   {
687     try
688       {
689         align(8);
690         for (int i = ofs; i < ofs + len; i++)
691           {
692             b.writeLong(x [ i ]);
693           }
694       }
695     catch (IOException ex)
696       {
697         Unexpected.error(ex);
698       }
699   }
700 
701   /**
702    * Writes this byte.
703    * @param x
704    */
write_octet(byte x)705   public void write_octet(byte x)
706   {
707     try
708       {
709         b.writeByte(x);
710       }
711     catch (IOException ex)
712       {
713         Unexpected.error(ex);
714       }
715   }
716 
717   /**
718    * Writes the array of bytes (CORBA octets) values.
719    *
720    * @param x value
721    * @param ofs offset
722    * @param len length
723    */
write_octet_array(byte[] x, int ofs, int len)724   public void write_octet_array(byte[] x, int ofs, int len)
725   {
726     try
727       {
728         b.write(x, ofs, len);
729       }
730     catch (IOException ex)
731       {
732         Unexpected.error(ex);
733       }
734   }
735 
736   /**
737    * Writes first the size of array, and then the byte array using
738    * the {@link java.io.OutputStream#write(byte[]) }. The sequence
739    * being written is preceeded by the int, representing the array
740    * length.
741    */
write_sequence(byte[] buf)742   public void write_sequence(byte[] buf)
743   {
744     try
745       {
746         write_long(buf.length);
747         write(buf);
748       }
749     catch (IOException ex)
750       {
751         MARSHAL t = new MARSHAL();
752         t.minor = Minor.CDR;
753         t.initCause(ex);
754         throw t;
755       }
756   }
757 
758   /**
759    * Writes the contents of the provided stream.
760    * The sequence being written is preceeded by the int,
761    * representing the stream buffer length (the number of
762    * bytes being subsequently written).
763    */
write_sequence(BufferedCdrOutput from)764   public void write_sequence(BufferedCdrOutput from)
765   {
766     try
767       {
768         write_long(from.buffer.size());
769         from.buffer.writeTo(this);
770       }
771     catch (IOException ex)
772       {
773         MARSHAL t = new MARSHAL();
774         t.minor = Minor.CDR;
775         t.initCause(ex);
776         throw t;
777       }
778   }
779 
780   /**
781    * Writes the two byte integer (short), high byte first.
782    *
783    * @param x the integer to write.
784    */
write_short(short x)785   public void write_short(short x)
786   {
787     try
788       {
789         align(2);
790         b.writeShort(x);
791       }
792     catch (IOException ex)
793       {
794         Unexpected.error(ex);
795       }
796   }
797 
798   /**
799    * Writes the array of short (two byte integer) values.
800    *
801    * @param x value
802    * @param ofs offset
803    * @param len length
804    */
write_short_array(short[] x, int ofs, int len)805   public void write_short_array(short[] x, int ofs, int len)
806   {
807     try
808       {
809         align(2);
810         for (int i = ofs; i < ofs + len; i++)
811           {
812             b.writeShort(x [ i ]);
813           }
814       }
815     catch (IOException ex)
816       {
817         Unexpected.error(ex);
818       }
819   }
820 
821   /**
822    * Writes the string. This implementation first calls
823    * String.getBytes() and then writes the length of the returned
824    * array (as CORBA ulong) and the returned array itself.
825    *
826    * The encoding information, if previously set, is taken
827    * into consideration.
828    *
829    * @param x the string to write.
830    */
write_string(String x)831   public void write_string(String x)
832   {
833     try
834       {
835         byte[] ab = x.getBytes(narrow_charset);
836         write_long(ab.length + 1);
837         write(ab);
838 
839         // write null terminator.
840         write(0);
841       }
842     catch (IOException ex)
843       {
844         Unexpected.error(ex);
845       }
846   }
847 
848   /**
849    * Writes the CORBA unsigned long in the same way as CORBA long.
850    */
write_ulong(int x)851   public void write_ulong(int x)
852   {
853     write_long(x);
854   }
855 
856   /**
857    * Writes the array of CORBA unsigned longs in the same way as
858    * array of ordinary longs.
859    */
write_ulong_array(int[] x, int ofs, int len)860   public void write_ulong_array(int[] x, int ofs, int len)
861   {
862     write_long_array(x, ofs, len);
863   }
864 
865   /**
866    * Write the unsigned long long in the same way as an ordinary long long.
867    *
868    * @param x a value to write.
869    */
write_ulonglong(long x)870   public void write_ulonglong(long x)
871   {
872     write_longlong(x);
873   }
874 
875   /**
876    * Write the array of unsingel long longs in the same way
877    * an an array of the ordinary long longs.
878    */
write_ulonglong_array(long[] x, int ofs, int len)879   public void write_ulonglong_array(long[] x, int ofs, int len)
880   {
881     write_longlong_array(x, ofs, len);
882   }
883 
884   /**
885    * Write the unsigned short in the same way as an ordinary short.
886    */
write_ushort(short x)887   public void write_ushort(short x)
888   {
889     write_short(x);
890   }
891 
892   /**
893    * Write an array of unsigned short integersin the same way
894    * as an array of ordinary short integers.
895    */
write_ushort_array(short[] x, int ofs, int len)896   public void write_ushort_array(short[] x, int ofs, int len)
897   {
898     write_short_array(x, ofs, len);
899   }
900 
901   /**
902    * Writes the character as two byte short integer (Unicode value), high byte
903    * first. Writes in Big Endian, but never writes the endian indicator.
904    *
905    * The character is always written using the native UTF-16BE charset because
906    * its size under arbitrary encoding is not evident.
907    */
write_wchar(char x)908   public void write_wchar(char x)
909   {
910     try
911       {
912         if (giop.until_inclusive(1, 1))
913           {
914             align(2);
915 
916             if (wide_native)
917               b.writeShort(x);
918             else
919               {
920                 OutputStreamWriter ow = new OutputStreamWriter(
921                   (OutputStream) b, wide_charset);
922                 ow.write(x);
923                 ow.flush();
924               }
925           }
926         else if (wide_native)
927           {
928             b.writeByte(2);
929             b.writeChar(x);
930           }
931         else
932           {
933             String encoded = new String(new char[] { x });
934             byte[] bytes = encoded.getBytes(wide_charset);
935             b.write(bytes.length + 2);
936             b.write(bytes);
937           }
938       }
939     catch (IOException ex)
940       {
941         Unexpected.error(ex);
942       }
943   }
944 
945   /**
946    * Write the array of wide chars.
947    *
948    * @param chars the array of wide chars
949    * @param offset offset
950    * @param length length
951    *
952    * The char array is always written using the native UTF-16BE charset because
953    * the character size under arbitrary encoding is not evident.
954    */
write_wchar_array(char[] chars, int offset, int length)955   public void write_wchar_array(char[] chars, int offset, int length)
956   {
957     try
958       {
959         if (giop.until_inclusive(1, 1))
960           align(2);
961 
962         if (wide_native)
963           {
964             for (int i = offset; i < offset + length; i++)
965               {
966                 b.writeShort(chars [ i ]);
967               }
968           }
969         else
970           {
971             OutputStreamWriter ow =
972               new OutputStreamWriter((OutputStream) b, wide_charset);
973             ow.write(chars, offset, length);
974             ow.flush();
975           }
976       }
977     catch (IOException ex)
978       {
979         Unexpected.error(ex);
980       }
981   }
982 
983   /**
984    * Writes the length of the string in bytes (not characters) and
985    * then all characters as two byte unicode chars. Adds the
986    * Big Endian indicator, 0xFFFE, at the beginning and null wide char at
987    * the end.
988    *
989    * @param x the string to write.
990    */
write_wstring(String x)991   public void write_wstring(String x)
992   {
993     try
994       {
995         if (giop.since_inclusive(1, 2))
996           {
997             byte[] bytes = x.getBytes(wide_charset);
998             write_sequence(bytes);
999           }
1000         else
1001           {
1002             // Encoding with null terminator always in UTF-16.
1003             // The wide null terminator needs extra two bytes.
1004             write_long(2 * x.length() + 2);
1005 
1006             for (int i = 0; i < x.length(); i++)
1007               {
1008                 b.writeShort(x.charAt(i));
1009               }
1010 
1011             // Write null terminator.
1012             b.writeShort(0);
1013           }
1014       }
1015     catch (IOException ex)
1016       {
1017         Unexpected.error(ex);
1018       }
1019   }
1020 
1021   /** {@inheritDoc} */
write_any_array(Any[] anys, int offset, int length)1022   public void write_any_array(Any[] anys, int offset, int length)
1023   {
1024     for (int i = offset; i < offset + length; i++)
1025       {
1026         write_any(anys [ i ]);
1027       }
1028   }
1029 
_truncatable_ids()1030   public String[] _truncatable_ids()
1031   {
1032     /**@todo Implement this org.omg.CORBA.portable.ValueBase abstract method*/
1033     throw new java.lang.UnsupportedOperationException("Method _truncatable_ids() not yet implemented.");
1034   }
1035 
1036   /** {@inheritDoc} */
write_Abstract(java.lang.Object value)1037   public void write_Abstract(java.lang.Object value)
1038   {
1039     write_abstract_interface(value);
1040   }
1041 
1042   /** {@inheritDoc} */
write_Value(Serializable value)1043   public void write_Value(Serializable value)
1044   {
1045     write_value(value);
1046   }
1047 }
1048