1 /* CdrEncapsCodecImpl.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;
40 
41 import gnu.CORBA.CDR.BufferredCdrInput;
42 import gnu.CORBA.CDR.BufferedCdrOutput;
43 import gnu.CORBA.CDR.AbstractCdrOutput;
44 
45 import org.omg.CORBA.Any;
46 import org.omg.CORBA.LocalObject;
47 import org.omg.CORBA.MARSHAL;
48 import org.omg.CORBA.ORB;
49 import org.omg.CORBA.TCKind;
50 import org.omg.CORBA.TypeCode;
51 import org.omg.CORBA.UserException;
52 import org.omg.IOP.Codec;
53 import org.omg.IOP.CodecPackage.FormatMismatch;
54 import org.omg.IOP.CodecPackage.InvalidTypeForEncoding;
55 import org.omg.IOP.CodecPackage.TypeMismatch;
56 
57 /**
58  * The local {@link Codec} implementation for ENCODING_CDR_ENCAPS
59  * encoding. This is a local implementation; the remote side should
60  * have its own Codec of this kind.
61  *
62  *
63  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
64  */
65 public class CdrEncapsCodecImpl
66   extends LocalObject
67   implements Codec
68 {
69   /**
70    * Use serialVersionUID for interoperability.
71    */
72   private static final long serialVersionUID = 1;
73 
74   /**
75    * If set to true, no wide string or wide character is allowed (GIOP 1.0).
76    */
77   private final boolean noWide;
78 
79   /**
80    * The version of this encoding.
81    */
82   private final Version version;
83 
84   /**
85    * The associated ORB.
86    */
87   protected final ORB orb;
88 
89   /**
90    * If true, this Codec writes the record length (as int) in the beginning
91    * of the record. This indicator is part of the formal OMG standard, but it is
92    * missing in Sun's implementation. Both Suns's and this Codec detects
93    * the indicator, if present, but can also decode data where this information
94    * is missing. If the length indicator is missing, the first four bytes in
95    * Suns encoding are equal to 0 (Big Endian marker).
96    */
97   private boolean lengthIndicator = true;
98 
99   /**
100    * Create an instance of this Codec, encoding following the given version.
101    */
CdrEncapsCodecImpl(ORB _orb, Version _version)102   public CdrEncapsCodecImpl(ORB _orb, Version _version)
103   {
104     orb = _orb;
105     version = _version;
106     noWide = version.until_inclusive(1, 0);
107   }
108 
109   /**
110    * Return the array of repository ids for this object.
111    *
112    * @return { "IDL:gnu/CORBA/cdrEnapsCodec:1.0" }, always.
113    */
_ids()114   public String[] _ids()
115   {
116     return new String[] { "IDL:gnu/CORBA/cdrEnapsCodec:1.0" };
117   }
118 
119   /**
120    * Decode the contents of the byte array into Any.
121    * The byte array may have the optional four byte length indicator
122    * in the beginning. If these four bytes are zero, it is assumed,
123    * that no length indicator is present.
124    */
decode(byte[] them)125   public Any decode(byte[] them)
126              throws FormatMismatch
127   {
128     BufferredCdrInput input = createInput(them);
129     BufferredCdrInput encapsulation = createEncapsulation(them, input);
130 
131     TypeCode type = encapsulation.read_TypeCode();
132 
133     try
134       {
135         checkTypePossibility("", type);
136       }
137     catch (InvalidTypeForEncoding ex)
138       {
139         throw new FormatMismatch(ex.getMessage());
140       }
141 
142     return readAny(type, encapsulation);
143   }
144 
createEncapsulation(byte[] them, BufferredCdrInput input)145   private BufferredCdrInput createEncapsulation(byte[] them, BufferredCdrInput input)
146   {
147     BufferredCdrInput encapsulation;
148 
149     if ((them [ 0 ] | them [ 1 ] | them [ 2 ] | them [ 3 ]) == 0)
150       {
151         // Skip that appears to be the always present Big Endian marker.
152         encapsulation = input;
153         input.read_short();
154       }
155     else
156       encapsulation = input.read_encapsulation();
157     return encapsulation;
158   }
159 
160   /** {@inheritDoc} */
encode(Any that)161   public byte[] encode(Any that)
162                 throws InvalidTypeForEncoding
163   {
164     checkTypePossibility("", that.type());
165 
166     BufferedCdrOutput output = createOutput(that);
167 
168     // BufferedCdrOutput has internal support for this encoding.
169     AbstractCdrOutput encapsulation = output.createEncapsulation();
170 
171     try
172       {
173         TypeCodeHelper.write(encapsulation, that.type());
174         that.write_value(encapsulation);
175 
176         encapsulation.close();
177         output.close();
178       }
179     catch (Exception ex)
180       {
181         MARSHAL m = new MARSHAL();
182         m.minor = Minor.Encapsulation;
183         m.initCause(ex);
184         throw m;
185       }
186     return output.buffer.toByteArray();
187   }
188 
189   /**
190    * Decode the value, stored in the byte array, into Any, assuming,
191    * that the byte array holds the data structure, defined by the
192    * given typecode.
193    *
194    * The byte array may have the optional four byte length indicator
195    * in the beginning. If these four bytes are zero, it is assumed,
196    * that no length indicator is present.
197    */
decode_value(byte[] them, TypeCode type)198   public Any decode_value(byte[] them, TypeCode type)
199                    throws FormatMismatch, TypeMismatch
200   {
201     try
202       {
203         checkTypePossibility("", type);
204       }
205     catch (InvalidTypeForEncoding ex)
206       {
207         throw new TypeMismatch(ex.getMessage());
208       }
209 
210     BufferredCdrInput input = createInput(them);
211     BufferredCdrInput encapsulation = createEncapsulation(them, input);
212     return readAny(type, encapsulation);
213   }
214 
215   /**
216    * Read an Any from the given stream.
217    *
218    * @param type a type of the Any to read.
219    * @param input the encapsulation stream.
220    */
readAny(TypeCode type, BufferredCdrInput encapsulation)221   private Any readAny(TypeCode type, BufferredCdrInput encapsulation)
222                throws MARSHAL
223   {
224     gnuAny a = new gnuAny();
225     a.setOrb(orb);
226 
227     // BufferredCdrInput has internal support for this encoding.
228     a.read_value(encapsulation, type);
229     return a;
230   }
231 
232   /** {@inheritDoc} */
encode_value(Any that)233   public byte[] encode_value(Any that)
234                       throws InvalidTypeForEncoding
235   {
236     checkTypePossibility("", that.type());
237 
238     BufferedCdrOutput output = createOutput(that);
239 
240     AbstractCdrOutput encapsulation = output.createEncapsulation();
241 
242     try
243       {
244         that.write_value(encapsulation);
245 
246         encapsulation.close();
247         output.close();
248       }
249     catch (Exception ex)
250       {
251         MARSHAL m = new MARSHAL();
252         m.minor = Minor.Encapsulation;
253         m.initCause(ex);
254         throw m;
255       }
256     return output.buffer.toByteArray();
257   }
258 
259   /**
260    * Create the CDR output stream for writing the given Any.
261    * The BufferedCdrOutput has internal support for encapsulation encodings.
262    *
263    * @param that the Any that will be written.
264    *
265    * @return the stream.
266    *
267    * @throws InvalidTypeForEncoding if that Any cannot be written under the
268    * given version.
269    */
createOutput(Any that)270   private BufferedCdrOutput createOutput(Any that)
271                              throws InvalidTypeForEncoding
272   {
273     BufferedCdrOutput output = new BufferedCdrOutput();
274     output.setOrb(orb);
275     output.setVersion(version);
276     return output;
277   }
278 
279   /**
280    * Checks if the given type can be encoded. Currently only checks for wide
281    * strings and wide chars for GIOP 1.0.
282    *
283    * @param t a typecode to chek.
284    *
285    * @throws InvalidTypeForEncoding if the typecode is not valid for the given
286    * version.
287    */
checkTypePossibility(String name, TypeCode t)288   private void checkTypePossibility(String name, TypeCode t)
289                              throws InvalidTypeForEncoding
290   {
291     if (noWide)
292       {
293         try
294           {
295             int kind = t.kind().value();
296 
297             if (kind == TCKind._tk_wchar || kind == TCKind._tk_wstring)
298               throw new InvalidTypeForEncoding(name + " wide char in " +
299                                                version
300                                               );
301             else if (kind == TCKind._tk_alias || kind == TCKind._tk_array ||
302                      kind == TCKind._tk_sequence
303                     )
304               checkTypePossibility("Array member", t.content_type());
305 
306             else if (kind == TCKind._tk_struct || kind == TCKind._tk_union)
307               {
308                 for (int i = 0; i < t.member_count(); i++)
309                   {
310                     checkTypePossibility(t.member_name(i), t.member_type(i));
311                   }
312               }
313           }
314         catch (UserException ex)
315           {
316             InternalError ierr = new InternalError();
317             ierr.initCause(ex);
318             throw ierr;
319           }
320       }
321   }
322 
323   /**
324    * Create the CDR input stream for reading the given byte array.
325    *
326    * @param them a byte array to read.
327    *
328    * @return the stream.
329    */
createInput(byte[] them)330   private BufferredCdrInput createInput(byte[] them)
331   {
332     BufferredCdrInput input = new BufferredCdrInput(them);
333     input.setOrb(orb);
334     input.setVersion(version);
335     return input;
336   }
337 
338   /**
339    * Check if the Codec writes the length indicator.
340    */
hasLengthIndicator()341   public boolean hasLengthIndicator()
342   {
343     return lengthIndicator;
344   }
345 
346   /**
347    * Sets if the Codec must write the record length in the beginning of the
348    * array. Encodings both with and without that indicator are understood
349    * both by Suns and this codec, but the OMG specification seems requiring
350    * it. The default behavior is to use the length indicator.
351    *
352    * @param use_lengthIndicator
353    */
setUseLengthIndicator(boolean use_lengthIndicator)354   public void setUseLengthIndicator(boolean use_lengthIndicator)
355   {
356     lengthIndicator = use_lengthIndicator;
357   }
358 }
359