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 }