1 /*
   2  * Copyright (c) 1998, 2003, 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 /*
  26  * Licensed Materials - Property of IBM
  27  * RMI-IIOP v1.0
  28  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  29  *
  30  */
  31 
  32 package com.sun.corba.se.impl.encoding;
  33 
  34 import java.util.StringTokenizer;
  35 import java.util.ArrayList;
  36 import java.util.Arrays;
  37 import java.util.List;
  38 import java.util.NoSuchElementException;
  39 import org.omg.CORBA.INITIALIZE;
  40 import org.omg.CORBA.CompletionStatus;
  41 
  42 import com.sun.corba.se.spi.logging.CORBALogDomains;
  43 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  44 
  45 public final class CodeSetComponentInfo {
  46 
  47     /**
  48      * CodeSetComponent is part of an IOR multi-component profile.  Two
  49      * instances constitute a CodeSetComponentInfo (one for char and one
  50      * for wchar data)
  51      */
  52     public static final class CodeSetComponent {
  53         int nativeCodeSet;
  54         int[] conversionCodeSets;
  55 
  56         public boolean equals( Object obj )
  57         {
  58             if (this == obj)
  59                 return true ;
  60 
  61             if (!(obj instanceof CodeSetComponent))
  62                 return false ;
  63 
  64             CodeSetComponent other = (CodeSetComponent)obj ;
  65 
  66             return (nativeCodeSet == other.nativeCodeSet) &&
  67                 Arrays.equals( conversionCodeSets, other.conversionCodeSets ) ;
  68         }
  69 
  70         public int hashCode()
  71         {
  72             int result = nativeCodeSet ;
  73             for (int ctr=0; ctr<conversionCodeSets.length; ctr++)
  74                 result = 37*result + conversionCodeSets[ctr] ;
  75             return result ;
  76         }
  77 
  78         public CodeSetComponent() {}
  79 
  80         public CodeSetComponent(int nativeCodeSet, int[] conversionCodeSets) {
  81             this.nativeCodeSet = nativeCodeSet;
  82             if (conversionCodeSets == null)
  83                 this.conversionCodeSets = new int[0];
  84             else
  85                 this.conversionCodeSets = conversionCodeSets;
  86         }
  87 
  88         public void read(MarshalInputStream in) {
  89             nativeCodeSet = in.read_ulong();
  90             int len = in.read_long();
  91             conversionCodeSets = new int[len];
  92             in.read_ulong_array(conversionCodeSets, 0, len);
  93 
  94         }
  95 
  96         public void write(MarshalOutputStream out) {
  97             out.write_ulong(nativeCodeSet);
  98             out.write_long(conversionCodeSets.length);
  99             out.write_ulong_array(conversionCodeSets, 0, conversionCodeSets.length);
 100         }
 101 
 102         public String toString() {
 103             StringBuffer sbuf = new StringBuffer("CodeSetComponent(");
 104 
 105             sbuf.append("native:");
 106             sbuf.append(Integer.toHexString(nativeCodeSet));
 107             sbuf.append(" conversion:");
 108             if (conversionCodeSets == null)
 109                 sbuf.append("null");
 110             else {
 111                 for (int i = 0; i < conversionCodeSets.length; i++) {
 112                     sbuf.append(Integer.toHexString(conversionCodeSets[i]));
 113                     sbuf.append(' ');
 114                 }
 115             }
 116             sbuf.append( ")" ) ;
 117 
 118             return sbuf.toString();
 119         }
 120     }
 121 
 122     private CodeSetComponent forCharData;
 123     private CodeSetComponent forWCharData;
 124 
 125     public boolean equals( Object obj )
 126     {
 127         if (this == obj)
 128             return true ;
 129 
 130         if (!(obj instanceof CodeSetComponentInfo))
 131             return false ;
 132 
 133         CodeSetComponentInfo other = (CodeSetComponentInfo)obj ;
 134         return forCharData.equals( other.forCharData ) &&
 135             forWCharData.equals( other.forWCharData ) ;
 136     }
 137 
 138     public int hashCode()
 139     {
 140         return forCharData.hashCode() ^ forWCharData.hashCode() ;
 141     }
 142 
 143     public String toString() {
 144         StringBuffer sbuf = new StringBuffer("CodeSetComponentInfo(");
 145 
 146         sbuf.append("char_data:");
 147         sbuf.append(forCharData.toString());
 148         sbuf.append(" wchar_data:");
 149         sbuf.append(forWCharData.toString());
 150         sbuf.append(")");
 151 
 152         return sbuf.toString();
 153     }
 154 
 155     public CodeSetComponentInfo() {
 156         forCharData = CodeSetComponentInfo.JAVASOFT_DEFAULT_CODESETS.forCharData;
 157         forWCharData = CodeSetComponentInfo.JAVASOFT_DEFAULT_CODESETS.forWCharData;
 158     }
 159 
 160     public CodeSetComponentInfo(CodeSetComponent charData,
 161                                 CodeSetComponent wcharData) {
 162         forCharData = charData;
 163         forWCharData = wcharData;
 164     }
 165 
 166     public void read(MarshalInputStream in) {
 167         forCharData = new CodeSetComponent();
 168         forCharData.read(in);
 169         forWCharData = new CodeSetComponent();
 170         forWCharData.read(in);
 171     }
 172 
 173     public void write(MarshalOutputStream out) {
 174         forCharData.write(out);
 175         forWCharData.write(out);
 176     }
 177 
 178     public CodeSetComponent getCharComponent() {
 179         return forCharData;
 180     }
 181 
 182     public CodeSetComponent getWCharComponent() {
 183         return forWCharData;
 184     }
 185 
 186     /**
 187      * CodeSetContext goes in a GIOP service context
 188      */
 189     public static final class CodeSetContext {
 190         private int char_data;
 191         private int wchar_data;
 192 
 193         public CodeSetContext() {}
 194 
 195         public CodeSetContext(int charEncoding, int wcharEncoding) {
 196             char_data = charEncoding;
 197             wchar_data = wcharEncoding;
 198         }
 199 
 200         public void read(MarshalInputStream in) {
 201             char_data = in.read_ulong();
 202             wchar_data = in.read_ulong();
 203         }
 204 
 205         public void write(MarshalOutputStream out) {
 206             out.write_ulong(char_data);
 207             out.write_ulong(wchar_data);
 208         }
 209 
 210         public int getCharCodeSet() {
 211             return char_data;
 212         }
 213 
 214         public int getWCharCodeSet() {
 215             return wchar_data;
 216         }
 217 
 218         public String toString() {
 219             StringBuffer sbuf = new StringBuffer();
 220             sbuf.append("CodeSetContext char set: ");
 221             sbuf.append(Integer.toHexString(char_data));
 222             sbuf.append(" wchar set: ");
 223             sbuf.append(Integer.toHexString(wchar_data));
 224             return sbuf.toString();
 225         }
 226     }
 227 
 228     /**
 229      * Our default code set scheme is as follows:
 230      *
 231      * char data:
 232      *
 233      * Native code set:  ISO 8859-1 (8-bit)
 234      * Conversion sets:  UTF-8, ISO 646 (7-bit)
 235      *
 236      * wchar data:
 237      *
 238      * Native code set:  UTF-16
 239      * Conversion sets:  UCS-2
 240      *
 241      * Pre-Merlin/J2EE 1.3 JavaSoft ORBs listed ISO646 for char and
 242      * UCS-2 for wchar, and provided no conversion sets.  They also
 243      * didn't do correct negotiation or provide the fallback sets.
 244      * UCS-2 is still in the conversion list for backwards compatibility.
 245      *
 246      * The fallbacks are UTF-8 for char and UTF-16 for wchar.
 247      *
 248      * In GIOP 1.1, interoperability with wchar is limited to 2 byte fixed
 249      * width encodings since its wchars aren't preceded by a length.
 250      * Thus, I've chosen not to include UTF-8 in the conversion set
 251      * for wchar data.
 252      *
 253      */
 254     public static final CodeSetComponentInfo JAVASOFT_DEFAULT_CODESETS;
 255     static {
 256         CodeSetComponent charData
 257             = new CodeSetComponent(OSFCodeSetRegistry.ISO_8859_1.getNumber(),
 258                                    new int[] {
 259                                        OSFCodeSetRegistry.UTF_8.getNumber(),
 260                                        OSFCodeSetRegistry.ISO_646.getNumber()
 261                                    });
 262 
 263         CodeSetComponent wcharData
 264             = new CodeSetComponent(OSFCodeSetRegistry.UTF_16.getNumber(),
 265                                    new int[]
 266                                    {
 267                                        OSFCodeSetRegistry.UCS_2.getNumber()
 268                                    });
 269 
 270         JAVASOFT_DEFAULT_CODESETS = new CodeSetComponentInfo(charData, wcharData);
 271     }
 272 
 273     /**
 274      * Creates a CodeSetComponent from a String which contains a comma
 275      * delimited list of OSF Code Set Registry numbers.  An INITIALIZE
 276      * exception is thrown if any of the numbers are not known by our
 277      * registry.  Used by corba.ORB init.
 278      *
 279      * The first number in the list is taken as the native code set,
 280      * and the rest is the conversion code set list.
 281      *
 282      * The numbers can either be decimal or hex.
 283      */
 284     public static CodeSetComponent createFromString(String str) {
 285         ORBUtilSystemException wrapper = ORBUtilSystemException.get(
 286             CORBALogDomains.RPC_ENCODING ) ;
 287 
 288         if (str == null || str.length() == 0)
 289             throw wrapper.badCodeSetString() ;
 290 
 291         StringTokenizer stok = new StringTokenizer(str, ", ", false);
 292         int nativeSet = 0;
 293         int conversionInts[] = null;
 294 
 295         try {
 296 
 297             // The first value is the native code set
 298             nativeSet = Integer.decode(stok.nextToken()).intValue();
 299 
 300             if (OSFCodeSetRegistry.lookupEntry(nativeSet) == null)
 301                 throw wrapper.unknownNativeCodeset( new Integer(nativeSet) ) ;
 302 
 303             List conversionList = new ArrayList(10);
 304 
 305             // Now process the other values as part of the
 306             // conversion code set list.
 307             while (stok.hasMoreTokens()) {
 308 
 309                 // decode allows us to specify hex, decimal, etc
 310                 Integer value = Integer.decode(stok.nextToken());
 311 
 312                 if (OSFCodeSetRegistry.lookupEntry(value.intValue()) == null)
 313                     throw wrapper.unknownConversionCodeSet( value ) ;
 314 
 315                 conversionList.add(value);
 316             }
 317 
 318             conversionInts = new int[conversionList.size()];
 319 
 320             for (int i = 0; i < conversionInts.length; i++)
 321                 conversionInts[i] = ((Integer)conversionList.get(i)).intValue();
 322 
 323         } catch (NumberFormatException nfe) {
 324             throw wrapper.invalidCodeSetNumber( nfe ) ;
 325         } catch (NoSuchElementException nsee) {
 326             throw wrapper.invalidCodeSetString( nsee, str ) ;
 327         }
 328 
 329         // Otherwise return the CodeSetComponent representing
 330         // the given values
 331         return new CodeSetComponent(nativeSet, conversionInts);
 332     }
 333 
 334     /**
 335      * Code sets for local cases without a connection.
 336      */
 337     public static final CodeSetContext LOCAL_CODE_SETS
 338         = new CodeSetContext(OSFCodeSetRegistry.ISO_8859_1.getNumber(),
 339                              OSFCodeSetRegistry.UTF_16.getNumber());
 340 }