diff options
author | Phil Mesnier <mesnier_p@ociweb.com> | 2004-05-21 03:01:27 +0000 |
---|---|---|
committer | Phil Mesnier <mesnier_p@ociweb.com> | 2004-05-21 03:01:27 +0000 |
commit | 74fa743a42c15559c7460a876e4d7927cff1498e (patch) | |
tree | f0783923f6a7d47e5e296354b76dc4832012b8d3 /TAO | |
parent | 2f4ac18e616081eaa860d3e6c579c5d9cc52d734 (diff) | |
download | ATCD-74fa743a42c15559c7460a876e4d7927cff1498e.tar.gz |
Thu May 20 21:28:41 2004 Phil Mesnier <mesnier_p@ociweb.com>
Diffstat (limited to 'TAO')
24 files changed, 2659 insertions, 142 deletions
diff --git a/TAO/interop-tests/wchar/Client.java b/TAO/interop-tests/wchar/Client.java new file mode 100644 index 00000000000..821582b167e --- /dev/null +++ b/TAO/interop-tests/wchar/Client.java @@ -0,0 +1,207 @@ +package interop.wchar; + +import org.omg.CORBA.*; +import java.io.*; +import interop.*; + +/** + * Client.java + * + * Java implemention of the interoperability tests for wchars. + * + * @author Phil Mesnier + * @version $Id$ + */ + +public class Client +{ + + private static WCharReference ref = new WCharReference(); + private static org.omg.CORBA.ORB orb; + + private static int WCHAR_TO_SERVER = 0x0001; + private static int WSTRING_TO_SERVER = 0x0002; + private static int WARRAY_TO_SERVER = 0x0004; + private static int ANY_WCHAR_TO_SERVER = 0x0008; + private static int WSTRING_EXCEPTION = 0x0010; + private static int WCHAR_FROM_SERVER = 0x0020; + private static int WSTRING_FROM_SERVER = 0x0040; + private static int WARRAY_FROM_SERVER = 0x0080; + private static int ANY_WCHAR_FROM_SERVER = 0x0100; + private static int TBD_6 = 0x0200; + private static int TBD_5 = 0x0400; + private static int TBD_4 = 0x0800; + private static int TBD_3 = 0x1000; + private static int TBD_2 = 0x2000; + private static int TBD_1 = 0x4000; + private static int TBD_0 = 0x8000; + private static int ALL_TESTS = 0xFFFF; + + private static String test_name[] = + { + "wchar_to_server", "wstring_to_server", "warray_to_server", + "any(wchar)_to_server", "wstring_exception", "wchar_from_server", + "wstring_from_server", "warray_from_server", "any(wchar)_from_server" + }; + + private static int tests_to_run = 0; + private static short data_set = 0; + private static boolean verbose = false; + + private static boolean runOneTest (WChar_Passer server, int test_num) + { + switch (test_num) + { + case 0x0001: //WCHAR_TO_SERVER: + return server.wchar_to_server (Client. + ref.get_wchar(data_set), + data_set); + case 0x0002: //WSTRING_TO_SERVER: + return server.wstring_to_server (Client. + ref.get_wstring(data_set), + data_set); + case 0x0004: //WARRAY_TO_SERVER: + return server.warray_to_server (Client. + ref.get_warray(data_set), + data_set); + case 0x0008: //ANY_WCHAR_TO_SERVER: + { + Any a = orb.create_any(); + a.insert_wchar (ref.get_wchar(data_set)); + return server.any_to_server (a,data_set); + } + case 0x0010: //WSTRING_EXCEPTION: + { + try { + server.exception_test(data_set); + } catch (interop.WChar_PasserPackage.WStringException ex) { + return Client.ref.match_except (data_set,ex.why); + } + break; + } + case 0x0020: // WCHAR_FROM_SERVER: + { + char wc = server.wchar_from_server (data_set); + return Client.ref.match_wchar (data_set,wc); + } + case 0x0040: //WSTRING_FROM_SERVER: + { + String ws = server.wstring_from_server (data_set); + return Client.ref.match_wstring (data_set,ws); + } + case 0x0080: //WARRAY_FROM_SERVER: + { + char wa[] = server.warray_from_server (data_set); + return Client.ref.match_warray (data_set,wa); + } + case 0x0100: // ANY_WCHAR_FROM_SERVER: + { + if (verbose) + System.out.println ("test any(wchar) from server not yet implemented"); + return true; + } + default: + break; + } + return false; + } + + public static boolean runTests (WChar_Passer server) + { + int successes = 0; + int numtests = 0; + ref.set_verbose (verbose); + int t = 1; + for (int i = 0; i < test_name.length; i++, t <<= 1) + if ((tests_to_run & t) == t) + { + boolean result = runOneTest (server,t); + ++numtests; + if (result) ++successes; + if (verbose) + System.out.println (test_name[i] + + "[" + data_set + "] " + + (result ? "passed" : "failed")); + } + if (verbose) + System.out.println ("Total of " + successes + + "successes out of " + numtests + " tests"); + return successes == numtests; + } + + public static void main( String[] args ) + throws Exception + { + String iorfile = "IOR"; + boolean kill_server = false; + + for (int i = 0; i < args.length; i++) + { + if (args[i].equals ("-i")) + iorfile = args[++i]; + else if (args[i].equals ("-v")) + verbose = true; + else if (args[i].equals ("-x")) + kill_server = true; + else if (args[i].equals ("-t")) + { + int tnum = Integer.decode(args[++i]).intValue(); + if (tnum >= 0 && tnum < test_name.length) + tests_to_run |= (1 << tnum); + } + else + { + System.out.println( "Usage: jaco interop.wchar.Client " + + "-i <ior_file> " + + "-t <0 <= num < " + test_name.length + "> " + + "-v " + + "-x "); + System.out.println ("Available tests:"); + for (int j = 0; i < test_name.length; i++) + System.out.println (j + " - " + test_name[i]); + System.exit( 1 ); + } + } + if (tests_to_run == 0) + tests_to_run = ALL_TESTS; + + File f = new File(iorfile); + + //check if file exists + if( ! f.exists() ) + { + System.out.println("File " + iorfile + + " does not exist."); + System.exit( -1 ); + } + + //check if args[0] points to a directory + if( f.isDirectory() ) + { + System.out.println("File " + iorfile + + " is a directory."); + System.exit( -1 ); + } + + // initialize the ORB. + orb = org.omg.CORBA.ORB.init( args, null ); + + BufferedReader br = + new BufferedReader( new FileReader( f )); + + // get object reference from command-line argument file + org.omg.CORBA.Object obj = + orb.string_to_object( br.readLine() ); + + br.close(); + + WChar_Passer wp = WChar_PasserHelper.narrow( obj ); + + boolean result = Client.runTests (wp); + System.out.println ("wchar_interop test (Jacorb client, " + + wp.orb_name() + " server) " + + (result ? "passed" : "failed")); + if (kill_server) + wp.shutdown(); + } +}// Client diff --git a/TAO/interop-tests/wchar/README b/TAO/interop-tests/wchar/README new file mode 100644 index 00000000000..99335123e81 --- /dev/null +++ b/TAO/interop-tests/wchar/README @@ -0,0 +1,32 @@ +Test for passing wchar data between TAO and JacORB processes. +This test may also be run for tao-tao on different platforms. + +To build this test for JacORB requires a JacORB 2.0 installation, and the +ant build tool. The Java classpath must include $JACORB_HOME/lib/jacorb.jar +and $TAO_ROOT/interop-tests/classes. + +To build the tao test client and server, first run mwc.pl in the ordinary +way to generate makefiles or project files. Then to build the JacORB client +and server, use "ant" which assumes $JACORB_HOME is set to the JacORB home +directory. + +The TAO server command line is: + ./server [-o iorfile] [-v] +The default ior file for the server is "./IOR" +The -v option causes the server to output some details of its operation. + +The TAO client command line is: + ./client [-k ior] [[-t 0 < n <= 8]...] [-v] [-x] +The default ior is "file://IOR". Note that it is an IOR, not a filename. +The -t option selects individual tests, no selection implies all tests, + the -t option may be repeated to select a number of tests +The -v option make the test more verbose, not adding it only outputs final + pass/fail message. +The -x option makes the client send a shutdown request to the server. +Anything else, such as -?, will yield a list of options and test descriptions. + +To run the JacORB client or server, use the "jaco" utility, + +jaco interop.wchar.Server [-o iorfile] [-v] +jaco interop.wchar.Client [-i iorfile] [-t 0..8] [-v] [-x] +Note that Client takes -i iorfile, not -k ior. diff --git a/TAO/interop-tests/wchar/Server.java b/TAO/interop-tests/wchar/Server.java new file mode 100644 index 00000000000..710f1ee775b --- /dev/null +++ b/TAO/interop-tests/wchar/Server.java @@ -0,0 +1,75 @@ +package interop.wchar; + +import java.io.*; + +import org.omg.CORBA.*; +import org.omg.PortableServer.*; +import interop.*; + +/** + * Server.java + * + * Java implemention of the interoperability tests for wchars. + * + * @author Phil Mesnier + * @version $Id$ + */ + +public class Server +{ + public static void main(String[] args) + { + String iorfile = "IOR"; + boolean verbose = false; + for (int i = 0; i < args.length; i++) + { + if (args[i].equals ("-o")) + iorfile = args[++i]; + else if (args[i].equals ("-v")) + verbose = true; + else + { + System.out.println( "Usage: jaco interop.wchar.Server " + + "-o <ior_file> " + + "-v "); + System.exit( 1 ); + } + } + + try + { + //init ORB + ORB orb = ORB.init( args, null ); + + //init POA + POA poa = + POAHelper.narrow( orb.resolve_initial_references( "RootPOA" )); + + poa.the_POAManager().activate(); + + // create a GoodDay object + WChar_PasserImpl servant = new WChar_PasserImpl(orb, verbose); + + // create the object reference + org.omg.CORBA.Object obj = + poa.servant_to_reference( servant ); + + PrintWriter pw = + new PrintWriter( new FileWriter( args[ 0 ] )); + + // print stringified object reference to file + pw.println( orb.object_to_string( obj )); + + pw.flush(); + pw.close(); + + // wait for requests + orb.run(); + } + catch( Exception e ) + { + System.out.println( e ); + e.printStackTrace(); + } + } +} diff --git a/TAO/interop-tests/wchar/WCharReference.java b/TAO/interop-tests/wchar/WCharReference.java new file mode 100644 index 00000000000..ae62392afcf --- /dev/null +++ b/TAO/interop-tests/wchar/WCharReference.java @@ -0,0 +1,97 @@ +package interop.wchar; + + +/** + * Client.java + * + * Java implemention of the reference wchar data supplied to both + * clients and servers. This is independently maintained in parallel + * with the c++ version, wchar_reference.cpp + * + * @author Phil Mesnier + * @version $Id$ + */ + +public class WCharReference +{ + private char ref_wchar[] = {1234}; + private String ref_wstring[] = {"have a nice day"}; + private char ref_warray[][] = + { {'a','A','!','1','4','[','?','%','X','E'} }; + private String ref_except[] = {"TEST EXCEPTION"}; + + private boolean verbose = false; + + public WCharReference () + { + } + + public WCharReference (boolean v) + { + verbose = v; + } + + public void set_verbose (boolean v) + { + verbose = v; + } + + public char get_wchar (int key) { + return ref_wchar[key]; + } + + public String get_wstring (int key) { + return ref_wstring[key]; + } + + public char[] get_warray (int key) { + return ref_warray[key]; + } + + public String get_except (int key) { + return ref_except[key]; + } + + public boolean match_wchar (short key, char test) + { + if (verbose) + System.out.println ("match_wchar: expecting " + + ref_wchar[key] + " got " + + test + " for key " + key); + return ref_wchar[key] == test; + } + + public boolean match_wstring (short key, String test) + { + if (verbose) + System.out.println ("match_wstring: expecting " + + ref_wstring[key] + " got " + + test + " for key " + key); + return test.equals(ref_wstring[key]); + } + + public boolean match_warray (short key, char test[]) + { + if (verbose) + System.out.println ("match_warray: key " + key); + for (int i = 0; i < test.length; i++) + { + if (verbose) + System.out.println (" expecting[" + i + "] " + + ref_warray[key][i] + ", got " + + test[i]); + if (ref_warray[key][i] != test[i]) + return false; + } + return true; + } + + public boolean match_except (short key, String test) + { + if (verbose) + System.out.println ("match_except: expecting " + + ref_except[key] + " got " + + test + " for key " + key); + return test.equals(ref_except[key]); + } +} diff --git a/TAO/interop-tests/wchar/WChar_PasserImpl.java b/TAO/interop-tests/wchar/WChar_PasserImpl.java new file mode 100644 index 00000000000..575ba37fbe2 --- /dev/null +++ b/TAO/interop-tests/wchar/WChar_PasserImpl.java @@ -0,0 +1,137 @@ +package interop.wchar; + +import org.omg.CORBA.*; +import interop.*; + +/** + * WChar_PasserImpl.java + * + * Java implemention of the interoperability tests for wchars. + * + * @author Phil Mesnier + * @version $Id$ + */ + +public class WChar_PasserImpl + extends WChar_PasserPOA +{ + private ORB orb; + private WCharReference ref; + + public WChar_PasserImpl( ORB o, boolean v ) + { + this.orb = o; + this.ref = new WCharReference(v); + } + + public String orb_name () + { + return "JacORB"; + } + + public boolean wchar_to_server (char test, short key) + { + System.out.println ("wchar_to_server called, test = " + (int)test + + " key = " + key); + if (key != 0) + return false; + return ref.match_wchar(key,test); + } + + public char wchar_from_server (short key) + { + return ref.get_wchar(key); + } + + public boolean wstring_to_server (String test, short key) + { + return ref.match_wstring (key,test); + } + + public String wstring_from_server (short key) + { + return ref.get_wstring (key); + } + + public boolean warray_to_server (char test[], short key) + { + return ref.match_warray (key,test); + } + + public char[] warray_from_server (short key) + { + return ref.get_warray (key); + } + + public boolean wstruct_to_server (wstruct test, short key) + { + return false; + } + + public wstruct wstruct_from_server (short key) + { + return new wstruct(); + } + + public boolean wunion_to_server (wunion test, short key) + { + return false; + } + + public wunion wunion_from_server (short key, wchar_types type) + { + return new wunion(); + } + + public boolean any_to_server (Any test, short key) + { + int kind = test.type().kind().value(); + switch( kind ) + { + case TCKind._tk_wchar: + return wchar_to_server(test.extract_wchar(),key); + case TCKind._tk_wstring: + return wstring_to_server(test.extract_wstring(),key); + default: + System.out.println ("WChar_PasserImpl.any_to_server " + + kind + " is not an implemented kind"); + } + return false; + } + + public Any any_from_server (short key, wchar_types type) + { + Any a = orb.create_any(); + switch (type.value()) { + case interop.wchar_types._is_wchar: + a.insert_wchar(ref.get_wchar(key)); + break; + case interop.wchar_types._is_wstring: + a.insert_wstring(ref.get_wstring(key)); + break; + case interop.wchar_types._is_warray: + break; + } + return a; + } + + public Any any_echo (Any test) + { + return test; + } + + public void exception_test(short key) + throws interop.WChar_PasserPackage.WStringException + { + throw new interop. + WChar_PasserPackage. + WStringException(ref.get_except(key),ref.get_wchar(key)); + } + + public void shutdown () + { + orb.shutdown(false); + } + + +} diff --git a/TAO/interop-tests/wchar/build.xml b/TAO/interop-tests/wchar/build.xml new file mode 100644 index 00000000000..f948d0a5939 --- /dev/null +++ b/TAO/interop-tests/wchar/build.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +/* + * + */ +--> + +<project name="wc_test" default="compile" basedir="."> + <target name="init" > + <property environment="env" /> + <property name="jacorb.home" value="${env.JACORB_HOME}" /> + <property name="debug" value="on" /> + + <!-- generated source --> + <mkdir dir="gensrc" /> + <!-- compiled java --> + <mkdir dir="../classes" /> + <taskdef name="jacidl" classname="org.jacorb.idl.JacIDL"> + <classpath> + <fileset dir="${jacorb.home}/lib"> + <include name="*.jar"/> + </fileset> + </classpath> + </taskdef> + </target> + + <target name="compile" depends="init"> + <jacidl srcdir="." destdir="gensrc" /> + <javac debug="${debug}" + debuglevel="${debuglevel}" + srcdir="." + destdir="../classes" > + <classpath> + <fileset dir="${jacorb.home}/lib"> + <include name="*.jar"/> + </fileset> + </classpath> + </javac> + </target> + +</project> diff --git a/TAO/interop-tests/wchar/client.cpp b/TAO/interop-tests/wchar/client.cpp new file mode 100644 index 00000000000..c3d05e8bb67 --- /dev/null +++ b/TAO/interop-tests/wchar/client.cpp @@ -0,0 +1,269 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// interop_test/wchar +// +// = FILENAME +// client.cpp +// +// = DESCRIPTION +// C++ client side for testing interoperability with wchar data. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ + +#include "interop_wcharC.h" +#include "wchar_reference.h" + +#include <ace/streams.h> +#include <ace/Get_Opt.h> + +const int WCHAR_TO_SERVER = 0x0001; +const int WSTRING_TO_SERVER = 0x0002; +const int WARRAY_TO_SERVER = 0x0004; +const int ANY_WCHAR_TO_SERVER = 0x0008; +const int WSTRING_EXCEPTION = 0x0010; +const int WCHAR_FROM_SERVER = 0x0020; +const int WSTRING_FROM_SERVER = 0x0040; +const int WARRAY_FROM_SERVER = 0x0080; +const int ANY_WCHAR_FROM_SERVER = 0x0100; +const int ANY_WSTRING_TO_SERVER = 0x0200; +const int ANY_WSTRING_FROM_SERVER = 0x0400; +const int ANY_WSTRING_ECHO = 0x0800; +const int TBD_3 = 0x1000; +const int TBD_2 = 0x2000; +const int TBD_1 = 0x4000; +const int TBD_0 = 0x8000; +const int ALL_TESTS = 0xFFFF; + +const char * test_name[] = + { + "wchar_to_server", "wstring_to_server", "warray_to_server", + "any(wchar)_to_server", "wstring_exception", "wchar_from_server", + "wstring_from_server", "warray_from_server", "any(wchar)_from_server", + "any(wstring)_to_server", "any(wstring)_from_server", "any(wstring)_echo" + }; + +const int LAST_TEST = sizeof (test_name) / sizeof (test_name[0]); +const char *ior = "file://IOR"; +int tests_to_run = 0; +int verbose = 0; +int kill_server = 0; +int data_set = 0; + +#if defined (ACE_HAS_WCHAR) || defined (ACE_HAS_XPG4_MULTIBYTE_CHAR) + +wchar_reference ref; + +CORBA::Boolean +run_one_test (interop::WChar_Passer_ptr server, + int test_num) +{ + switch (test_num) + { + case WCHAR_TO_SERVER: + return server->wchar_to_server (ref.get_wchar(data_set),data_set); + case WSTRING_TO_SERVER: + return server->wstring_to_server (ref.get_wstring(data_set),data_set); + case WARRAY_TO_SERVER: + return server->warray_to_server (ref.get_warray(data_set),data_set); + case ANY_WCHAR_TO_SERVER: + { + CORBA::Any a; + a <<= CORBA::Any::from_wchar(ref.get_wchar(data_set)); + return server->any_to_server (a,data_set); + } + case WSTRING_EXCEPTION: + { + try { + server->exception_test(data_set); + } catch (interop::WChar_Passer::WStringException &e) { + return ref.match_except (data_set,e.why.in()); + } + break; + } + case WCHAR_FROM_SERVER: + { + CORBA::WChar wc = server->wchar_from_server (data_set); + return ref.match_wchar (data_set,wc); + } + case WSTRING_FROM_SERVER: + { + CORBA::WString_var ws = server->wstring_from_server (data_set); + return ref.match_wstring (data_set,ws.in()); + } + case WARRAY_FROM_SERVER: + { + interop::warray_var wa = server->warray_from_server (data_set); + return ref.match_warray (data_set,wa.in()); + } + case ANY_WCHAR_FROM_SERVER: + { + CORBA::WChar wc; + CORBA::Any_var test = server->any_from_server (data_set, + interop::is_wchar); + if (test >>= CORBA::Any::to_wchar(wc)) + { + return ref.match_wchar (data_set,wc); + } + return 0; + } + case ANY_WSTRING_TO_SERVER: + { + CORBA::Any a; + a <<= ref.get_wstring(data_set); + return server->any_to_server (a,data_set); + } + case ANY_WSTRING_FROM_SERVER: + { + const CORBA::WChar *ws; + CORBA::Any_var test = server->any_from_server (data_set, + interop::is_wstring); + if (test >>= ws) + { + return ref.match_wstring (data_set,ws); + } + return 0; + } + case ANY_WSTRING_ECHO: + { + CORBA::Any a; + a <<= ref.get_wstring(data_set); + const CORBA::WChar *ws; + CORBA::Any_var test = server->any_echo (a); + if (test >>= ws) + { + return ref.match_wstring (data_set,ws); + } + return 0; + } + default: + break; + } + return 0; +} + +short +run_tests (interop::WChar_Passer_ptr server) +{ + short successes = 0; + short numtests = 0; + ref.set_verbose (verbose); + int t = 1; + for (int i = 0; i < LAST_TEST; i++, t <<= 1) + if ((tests_to_run & t) == t) + { + CORBA::Boolean result = run_one_test (server,t); + ++numtests; + if (result) ++successes; + if (verbose) + ACE_DEBUG ((LM_DEBUG, "%s[%d] %s\n", + test_name[i],data_set, + (result ? "passed" : "failed"))); + } + if (verbose) + ACE_DEBUG ((LM_DEBUG, "Total of %d successes out of %d tests\n", + successes, numtests)); + return successes == numtests; +} +#endif // ACE_HAS_WCHAR || ACE_HAS_XPG4_MULTIBYTE_CHAR + +int +parse_args (int argc, char *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, "k:t:vx"); + int c; + while ((c = get_opts ()) != -1) + switch (c) + { + case 'k': + ior = get_opts.opt_arg (); + break; + case 't': + { + int tnum = atoi(get_opts.opt_arg()); + if (tnum >= 0 && tnum < LAST_TEST) + tests_to_run |= (1 << tnum); + else + ACE_ERROR_RETURN ((LM_ERROR,"test %d is out of range\n",tnum),-1); + break; + } + case 'v': + verbose = 1; + break; + case 'x': + kill_server = 1; + break; + case '?': + default: + { + ACE_ERROR ((LM_ERROR, + "usage: %s " + "-k <ior> " + "[-t <0 <= test_num < %d>][ -t ...] " + "[-v] " + "[-x] " + "\n", + argv [0], LAST_TEST)); + ACE_ERROR ((LM_ERROR, "Available tests:\n")); + for (int i = 0; i < LAST_TEST; i++) + ACE_ERROR ((LM_ERROR, " %d - %s\n",i, test_name[i])); + return -1; + } + } + + if (tests_to_run == 0) + tests_to_run = ALL_TESTS; + // Indicates sucessful parsing of the command line + return 0; +} + +int +main( int argc, char *argv[] ) +{ +#if (!defined ACE_HAS_WCHAR) && (!defined ACE_HAS_XPG4_MULTIBYTE_CHAR) + ACE_ERROR_RETURN ((LM_ERROR,"This test requires wchar support\n"),-1); +#else + try { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init( argc, argv ); + if (parse_args(argc, argv) == -1) + return 0; + + // Destringify ior + CORBA::Object_var obj = orb->string_to_object( ior ); + if( CORBA::is_nil( obj.in() ) ) + ACE_ERROR_RETURN ((LM_ERROR, + "arg is not a valid ior sting"), + -1); + + // Narrow + interop::WChar_Passer_var server = + interop::WChar_Passer::_narrow( obj.in() ); + + if( CORBA::is_nil( server.in() )) + ACE_ERROR_RETURN ((LM_ERROR, + "arg is not a interop::WChar_Passer reference\n"), + -1); + + short result = run_tests (server.in()); + CORBA::String_var server_orb = server->orb_name(); + ACE_ERROR ((LM_ERROR, + "wchar_interop test (TAO client, %s server) %s \n", + server_orb.in(), + (result ? "passed" : "failed"))); + if (kill_server) + server->shutdown(); + } + catch( const CORBA::Exception &ex ) { + ACE_PRINT_EXCEPTION(ex, "Uncaught CORBA exception: "); + return 1; + } + return 0; +#endif +} diff --git a/TAO/interop-tests/wchar/interop_wchar.idl b/TAO/interop-tests/wchar/interop_wchar.idl new file mode 100644 index 00000000000..bb15e237584 --- /dev/null +++ b/TAO/interop-tests/wchar/interop_wchar.idl @@ -0,0 +1,62 @@ +// $Id$ + +// Tests for interoperability between TAO and JacORB for sending wchar data +// The CDR defines separate serialization functions for reading and writing +// wchar, wchar[] and wstring data. Encapsulated wchar data is also tested. + +module interop { + typedef wchar warray[10]; + + struct wstruct { + wchar st_char; + wstring st_string; + warray st_array; + any st_any; + }; + + enum wchar_types {is_wchar, is_wstring, is_warray}; + + union wunion switch (wchar_types) { + case is_wchar: wchar u_char; + case is_wstring: wstring u_string; + case is_warray: warray u_array; + }; + + interface WChar_Passer { + // The server and client for this test should both use a well known test + // data to allow individual string comparisons against reference strings. + // The separate test key value allows the tester to devise several strings, + // arrays, or wchar values that may be tested separately. + + readonly attribute string orb_name; + + boolean wchar_to_server (in wchar test, in short key); + wchar wchar_from_server (in short key); + + boolean wstring_to_server (in wstring test, in short key); + wstring wstring_from_server (in short key); + + boolean warray_to_server (in warray test, in short key); + warray warray_from_server (in short key); + + boolean wstruct_to_server (in wstruct test, in short key); + wstruct wstruct_from_server (in short key); + + boolean wunion_to_server (in wunion test, in short key); + wunion wunion_from_server (in short key, in wchar_types type); + + boolean any_to_server (in any test, in short key); + any any_from_server (in short key, in wchar_types type); + + any any_echo (in any test); + + exception WStringException { wstring why; wchar whynot;}; + void exception_test(in short key) raises (WStringException); + + /// A method to shutdown the ORB + /** + * This method is used to simplify the test shutdown process + */ + oneway void shutdown (); + }; +}; diff --git a/TAO/interop-tests/wchar/interop_wchar.mpc b/TAO/interop-tests/wchar/interop_wchar.mpc new file mode 100644 index 00000000000..0eca7aaab0b --- /dev/null +++ b/TAO/interop-tests/wchar/interop_wchar.mpc @@ -0,0 +1,15 @@ +project(*Server): taoexe, portableserver { + Source_Files { + interop_wchar_i.cpp + wchar_reference.cpp + server.cpp + } +} + +project(*Client): taoexe { + Source_Files { + interop_wcharC.cpp + wchar_reference.cpp + client.cpp + } +} diff --git a/TAO/interop-tests/wchar/interop_wchar_i.cpp b/TAO/interop-tests/wchar/interop_wchar_i.cpp new file mode 100644 index 00000000000..b395b419880 --- /dev/null +++ b/TAO/interop-tests/wchar/interop_wchar_i.cpp @@ -0,0 +1,225 @@ +// -*- C++ -*- +// +// $Id$ + +// **** Code generated by the The ACE ORB (TAO) IDL Compiler **** +// TAO and the TAO IDL Compiler have been developed by: +// Center for Distributed Object Computing +// Washington University +// St. Louis, MO +// USA +// http://www.cs.wustl.edu/~schmidt/doc-center.html +// and +// Distributed Object Computing Laboratory +// University of California at Irvine +// Irvine, CA +// USA +// http://doc.ece.uci.edu/ +// +// Information about TAO is available at: +// http://www.cs.wustl.edu/~schmidt/TAO.html + +// TAO_IDL - Generated from +// be/be_codegen.cpp:986 + +#include "interop_wchar_i.h" + +// Implementation skeleton constructor +interop_WChar_Passer_i::interop_WChar_Passer_i (CORBA::ORB_ptr o, + int verbose) + : orb_(CORBA::ORB::_duplicate (o)), + ref_ (verbose) +{ +} + +// Implementation skeleton destructor +interop_WChar_Passer_i::~interop_WChar_Passer_i (void) +{ +} + +char * +interop_WChar_Passer_i::orb_name (void) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return CORBA::string_dup ("TAO"); +} + +CORBA::Boolean +interop_WChar_Passer_i::wchar_to_server (CORBA::WChar test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return ref_.match_wchar (key,test); +} + +CORBA::WChar +interop_WChar_Passer_i::wchar_from_server (CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return ref_.get_wchar (key); +} + +CORBA::Boolean +interop_WChar_Passer_i::wstring_to_server (const CORBA::WChar * test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return ref_.match_wstring(key,test); +} + +CORBA::WChar * +interop_WChar_Passer_i::wstring_from_server (CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return CORBA::wstring_dup (ref_.get_wstring(key)); +} + +CORBA::Boolean +interop_WChar_Passer_i::warray_to_server (const interop::warray test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return ref_.match_warray(key,test); +} + +interop::warray_slice * +interop_WChar_Passer_i::warray_from_server (CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return interop::warray_dup (ref_.get_warray(key)); +} + +CORBA::Boolean +interop_WChar_Passer_i::wstruct_to_server (const interop::wstruct & test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return + ref_.match_wchar (key,test.st_char) && + ref_.match_wstring (key,test.st_string) && + ref_.match_warray (key,test.st_array) && + this->any_to_server (test.st_any,key); +} + +interop::wstruct * +interop_WChar_Passer_i::wstruct_from_server (CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + interop::wstruct *ws = new interop::wstruct (); + ws->st_char = this->wchar_from_server(key); + ws->st_string = this->wstring_from_server(key); + ref_.assign_warray (key, ws->st_array); + ws->st_any <<= ref_.get_wstring(key); + return ws; +} + +CORBA::Boolean +interop_WChar_Passer_i::wunion_to_server (const interop::wunion & test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + switch (test._d()) { + case interop::is_wchar : + return this->wchar_to_server (test.u_char(),key); + case interop::is_wstring : + return this->wstring_to_server (test.u_string(),key); + case interop::is_warray : + return this->warray_to_server (test.u_array(),key); + default: + return 0; + } + return 0; +} + +interop::wunion * +interop_WChar_Passer_i::wunion_from_server (CORBA::Short key, + interop::wchar_types type) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + interop::wunion *wu = new interop::wunion (); + switch (type) { + case interop::is_wchar : + wu->u_char (ref_.get_wchar(key)); + break; + case interop::is_wstring : + wu->u_string (ref_.get_wstring(key)); + break; + case interop::is_warray : + wu->u_array (ref_.get_warray(key)); + break; + } + return wu; +} + + +CORBA::Boolean +interop_WChar_Passer_i::any_to_server (const CORBA::Any &test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + CORBA::WChar wc; + const CORBA::WChar *ws; + CORBA::WString_var wstr; + interop::warray_forany forany; + + if (test >>= CORBA::Any::to_wchar(wc)) + { + return this->wchar_to_server(wc,key); + } + else if (test >>= ws) + { + return this->wstring_to_server (ws,key); + } + else if (test >>= forany) + { + return this->warray_to_server (forany.in(),key); + } + return 0; +} + +CORBA::Any* +interop_WChar_Passer_i::any_from_server (CORBA::Short key, + interop::wchar_types type) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + CORBA::Any *any = new CORBA::Any; + switch (type) { + case interop::is_wchar : + (*any) <<= CORBA::Any::from_wchar(ref_.get_wchar(key)); + break; + case interop::is_wstring : + (*any) <<= ref_.get_wstring(key); + break; + case interop::is_warray : + { + interop::warray_forany forany(ref_.get_warray(key)); + (*any) <<= forany.in(); + break; + } + } + return any; +} + +CORBA::Any * +interop_WChar_Passer_i::any_echo (const CORBA::Any &test) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + return new CORBA::Any (test); +} + +void +interop_WChar_Passer_i::exception_test ( CORBA::Short key ) + ACE_THROW_SPEC ((CORBA::SystemException, + interop::WChar_Passer::WStringException)) +{ + interop::WChar_Passer::WStringException ex(ref_.get_except(key), + this->wchar_from_server(key)); + throw ex; +} + +void +interop_WChar_Passer_i::shutdown ( ) + ACE_THROW_SPEC (( CORBA::SystemException )) +{ + this->orb_->shutdown(0); +} diff --git a/TAO/interop-tests/wchar/interop_wchar_i.h b/TAO/interop-tests/wchar/interop_wchar_i.h new file mode 100644 index 00000000000..ae8aecbade5 --- /dev/null +++ b/TAO/interop-tests/wchar/interop_wchar_i.h @@ -0,0 +1,109 @@ +// -*- C++ -*- +// +// $Id$ + +// **** Code generated by the The ACE ORB (TAO) IDL Compiler **** +// TAO and the TAO IDL Compiler have been developed by: +// Center for Distributed Object Computing +// Washington University +// St. Louis, MO +// USA +// http://www.cs.wustl.edu/~schmidt/doc-center.html +// and +// Distributed Object Computing Laboratory +// University of California at Irvine +// Irvine, CA +// USA +// http://doc.ece.uci.edu/ +// +// Information about TAO is available at: +// http://www.cs.wustl.edu/~schmidt/TAO.html + +// TAO_IDL - Generated from +// be/be_codegen.cpp:923 + +#ifndef INTEROP_WCHAR_I_H_ +#define INTEROP_WCHAR_I_H_ + +#include "interop_wcharS.h" +#include "wchar_reference.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +//Class interop_WChar_Passer_i +class interop_WChar_Passer_i : public virtual POA_interop::WChar_Passer +{ +public: + //Constructor + interop_WChar_Passer_i (CORBA::ORB_ptr o, int verbose); + + //Destructor + virtual ~interop_WChar_Passer_i (void); + + virtual char * orb_name (void) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Boolean wchar_to_server ( CORBA::WChar test, + CORBA::Short key ) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::WChar wchar_from_server ( CORBA::Short key ) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Boolean wstring_to_server ( const CORBA::WChar * test, + CORBA::Short key ) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::WChar * wstring_from_server ( CORBA::Short key ) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Boolean warray_to_server (const interop::warray test, + CORBA::Short key ) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual interop::warray_slice * warray_from_server ( CORBA::Short key ) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Boolean wstruct_to_server (const interop::wstruct & test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual interop::wstruct * wstruct_from_server (CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Boolean wunion_to_server (const interop::wunion & test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual interop::wunion * wunion_from_server (CORBA::Short key, + interop::wchar_types type) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Boolean any_to_server (const CORBA::Any &test, + CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Any* any_from_server (CORBA::Short key, + interop::wchar_types type) + ACE_THROW_SPEC (( CORBA::SystemException )); + + virtual CORBA::Any* any_echo (const CORBA::Any &test) + ACE_THROW_SPEC (( CORBA::SystemException )); + +virtual void exception_test (CORBA::Short key) + ACE_THROW_SPEC (( CORBA::SystemException, + interop::WChar_Passer::WStringException )); + +virtual void shutdown () + ACE_THROW_SPEC (( CORBA::SystemException )); + +private: + CORBA::ORB_var orb_; + wchar_reference ref_; + +}; + + +#endif /* INTEROP_WCHAR_I_H_ */ diff --git a/TAO/interop-tests/wchar/run_test.pl b/TAO/interop-tests/wchar/run_test.pl new file mode 100755 index 00000000000..99cd6ccf720 --- /dev/null +++ b/TAO/interop-tests/wchar/run_test.pl @@ -0,0 +1,42 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib '../../../bin'; +use PerlACE::Run_Test; + +$iorfile = PerlACE::LocalFile ("server.ior"); +unlink $iorfile; +$status = 0; + +$SV = new PerlACE::Process ("server", "-o $iorfile"); +$CL = new PerlACE::Process ("client", "-k file://$iorfile"); + +$SV->Spawn (); + +if (PerlACE::waitforfile_timed ($iorfile, 5) == -1) { + print STDERR "ERROR: cannot find file <$iorfile>\n"; + $SV->Kill (); $SV->TimedWait (1); + exit 1; +} + +$client = $CL->SpawnWaitKill (300); + +if ($client != 0) { + print STDERR "ERROR: client returned $client\n"; + $status = 1; +} + +$server = $SV->WaitKill (10); + +if ($server != 0) { + print STDERR "ERROR: server returned $server\n"; + $status = 1; +} + +unlink $iorfile; + +exit $status; diff --git a/TAO/interop-tests/wchar/server.cpp b/TAO/interop-tests/wchar/server.cpp new file mode 100644 index 00000000000..b89d797c497 --- /dev/null +++ b/TAO/interop-tests/wchar/server.cpp @@ -0,0 +1,111 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// interop_test/wchar +// +// = FILENAME +// server.cpp +// +// = DESCRIPTION +// C++ server side for testing interoperability with wchar data. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ + +#include "interop_wchar_i.h" +#include <ace/streams.h> +#include <ace/Get_Opt.h> + +const char *ior_output_file = "IOR"; +int verbose = 0; + +int +parse_args (int argc, char *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, "o:v"); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'o': + ior_output_file = get_opts.opt_arg (); + break; + case 'v': + verbose = 1; + break; + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s " + "-o <iorfile> " + "-v " + "\n", + argv [0]), + -1); + } + // Indicates sucessful parsing of the command line + return 0; +} + +int +main( int argc, char *argv[] ) +{ + if (parse_args(argc, argv)) + ACE_ERROR_RETURN ((LM_ERROR, "failed to parse args\n"), 1); + try + { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init( argc, argv ); + + //Get reference to Root POA + CORBA::Object_var obj = orb->resolve_initial_references( "RootPOA" ); + PortableServer::POA_var poa = PortableServer::POA::_narrow( obj.in() ); + + PortableServer::POAManager_var mgr = poa->the_POAManager(); + + // Activate POA Manager + mgr->activate(); + + // Create an object + interop_WChar_Passer_i servant(orb.in(), verbose); + + // Register the servant with the RootPOA, obtain its object + // reference, stringify it, and write it to a file. + obj = poa->servant_to_reference( &servant ); + + CORBA::String_var str = orb->object_to_string( obj.in() ); + + if (parse_args(argc, argv)) + { + ACE_ERROR_RETURN ((LM_ERROR, + "failed to parse args"), + 1); + } + + FILE *output_file= ACE_OS::fopen (ior_output_file, "w"); + if (output_file == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Cannot open output file for writing IOR: %s", + ior_output_file), + 1); + ACE_OS::fprintf (output_file, "%s", str.in ()); + ACE_OS::fclose (output_file); + + // Accept requests + orb->run(); + orb->destroy(); + } + + catch( const CORBA::Exception &ex ) { + ACE_PRINT_EXCEPTION(ex, "uncaught exception"); + return 1; + } + + return 0; +} diff --git a/TAO/interop-tests/wchar/wchar_reference.cpp b/TAO/interop-tests/wchar/wchar_reference.cpp new file mode 100644 index 00000000000..5103b9e1526 --- /dev/null +++ b/TAO/interop-tests/wchar/wchar_reference.cpp @@ -0,0 +1,131 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// interop_test/wchar +// +// = FILENAME +// wchar_reference.cpp +// +// = DESCRIPTION +// C++ reference data for testing interoperability with wchars. This is +// linked into both clients and servers so that both sides have common +// values for testing what is received or sent. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ +#include "wchar_reference.h" +#include <ace/Log_Msg.h> + +#if (defined ACE_HAS_WCHAR) || defined (ACE_HAS_XPG4_MULTIBYTE_CHAR) + +ACE_OS::WChar +wchar_reference::ref_wchar[NUM_KEYS] = + {1234}; + +const ACE_OS::WChar * +wchar_reference::ref_wstring[NUM_KEYS] = + {L"have a nice day"}; + +ACE_OS::WChar +wchar_reference::ref_warray[NUM_KEYS][10] = + { {L'a',L'A',L'!',L'1',L'4',L'[',L'?',L'%',L'X',L'E'} }; + +const ACE_OS::WChar * +wchar_reference::ref_except[NUM_KEYS] = + {L"TEST EXCEPTION"}; + +wchar_reference::wchar_reference(int v) + : verbose_ (v) +{ +} + +void +wchar_reference::set_verbose(int v) +{ + this->verbose_ = v; +} + +ACE_OS::WChar +wchar_reference::get_wchar (short key) +{ + return wchar_reference::ref_wchar[key]; +} + +const ACE_OS::WChar * +wchar_reference::get_wstring (short key) +{ + return wchar_reference::ref_wstring[key]; +} + +ACE_OS::WChar * +wchar_reference::get_warray (short key) +{ + return wchar_reference::ref_warray[key]; +} + +void +wchar_reference::assign_warray (short key, + ACE_OS::WChar *warray) +{ + ACE_OS::memcpy(warray, + wchar_reference::ref_warray[key], + 10*(sizeof(ACE_OS::WChar)) + ); +} + +const ACE_OS::WChar * +wchar_reference::get_except (short key) +{ + return wchar_reference::ref_except[key]; +} + +int +wchar_reference::match_wchar (short key, ACE_OS::WChar test) +{ + if (verbose_) + ACE_DEBUG ((LM_DEBUG,"match_wchar, expecting %x, got %x for key %d\n", + wchar_reference::ref_wchar[key],test,key)); + return wchar_reference::ref_wchar[key] == test; +} + +int +wchar_reference::match_wstring (short key, const ACE_OS::WChar *test) +{ + if (verbose_) + ACE_DEBUG ((LM_DEBUG,"match_wstring: expecting %W, got %W for key %d\n", + wchar_reference::ref_wstring[key],test,key)); + return ACE_OS::strcmp(wchar_reference::ref_wstring[key],test) == 0; +} + +int +wchar_reference::match_warray (short key, const ACE_OS::WChar *test) +{ + if (verbose_) + ACE_DEBUG ((LM_DEBUG, "match_warray: key %d\n",key)); + for (int i = 0; i < 10; i++) + { + if (verbose_) + ACE_DEBUG ((LM_DEBUG," expecting[%d] %x, got %x\n", + i, wchar_reference::ref_warray[key][i], + test[i])); + if (wchar_reference::ref_warray[key][i] != test[i]) + return 0; + } + return 1; +} + +int +wchar_reference::match_except(short key, const ACE_OS::WChar *test) +{ + if (verbose_) + ACE_DEBUG ((LM_DEBUG,"match_except: expecting %W, got %W for key %d\n", + wchar_reference::ref_except[key],test,key)); + return ACE_OS::strcmp(wchar_reference::ref_except[key],test) == 0; +} + +#endif // ACE_HAS_WCHAR diff --git a/TAO/interop-tests/wchar/wchar_reference.h b/TAO/interop-tests/wchar/wchar_reference.h new file mode 100644 index 00000000000..289b25305c4 --- /dev/null +++ b/TAO/interop-tests/wchar/wchar_reference.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// interop_test/wchar +// +// = FILENAME +// wchar_reference.cpp +// +// = DESCRIPTION +// C++ reference data for testing interoperability with wchars. This is +// linked into both clients and servers so that both sides have common +// values for testing what is received or sent. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ +#ifndef WCHAR_REFERENCE_H +#define WCHAR_REFERENCE_H + +#include <ace/OS.h> + +#if (defined ACE_HAS_WCHAR) || defined (ACE_HAS_XPG4_MULTIBYTE_CHAR) + +#define NUM_KEYS 1 + +class wchar_reference +{ + public: + wchar_reference (int v = 0); + void set_verbose (int v); + ACE_OS::WChar get_wchar (short key); + const ACE_OS::WChar *get_wstring (short key); + ACE_OS::WChar *get_warray (short key); + void assign_warray (short key, ACE_OS::WChar *warray); + + const ACE_OS::WChar *get_except (short key); + + int match_wchar (short key, ACE_OS::WChar test); + int match_wstring (short key, const ACE_OS::WChar* test); + int match_warray (short key, const ACE_OS::WChar *test); + int match_except (short key, const ACE_OS::WChar *test); + + private: + static ACE_OS::WChar ref_wchar[NUM_KEYS]; + static const ACE_OS::WChar *ref_wstring[NUM_KEYS]; + static ACE_OS::WChar ref_warray[NUM_KEYS][10]; + static const ACE_OS::WChar *ref_except[NUM_KEYS]; + + int verbose_; +}; + +#endif // ACE_HAS_WCHAR +#endif // WCHAR_REFERENCE_H diff --git a/TAO/tao/Codeset_Manager.cpp b/TAO/tao/Codeset_Manager.cpp index fc100a7c326..5d1f4419aaf 100644 --- a/TAO/tao/Codeset_Manager.cpp +++ b/TAO/tao/Codeset_Manager.cpp @@ -11,7 +11,7 @@ #include "ace/Dynamic_Service.h" #include "ace/Codeset_Registry.h" #include "ace/OS_NS_string.h" - +#include "tao/UTF16_BOM_Factory.h" ACE_RCSID (tao, Codeset_Manager, @@ -45,7 +45,8 @@ TAO_Codeset_Manager::default_wchar_codeset = TAO_DEFAULT_WCHAR_CODESET_ID; TAO_Codeset_Manager::TAO_Codeset_Manager () : codeset_info_ (), char_factories_ (), - wchar_factories_ () + wchar_factories_ (), + utf16_bom_translator_ (0) { this->codeset_info_.ForCharData.native_code_set = TAO_Codeset_Manager::default_char_codeset; @@ -76,6 +77,8 @@ TAO_Codeset_Manager::~TAO_Codeset_Manager () } this->wchar_factories_.reset (); + + delete this->utf16_bom_translator_; } void @@ -113,7 +116,7 @@ TAO_Codeset_Manager::set_tcs (TAO_Profile &theProfile, { ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("TAO (%P|%t) - Codeset_Manager::set_tcs, ") - ACE_LIB_TEXT ("No codeset componnet in profile\n"))); + ACE_LIB_TEXT ("No codeset component in profile\n"))); } remote.ForCharData.native_code_set = @@ -121,31 +124,28 @@ TAO_Codeset_Manager::set_tcs (TAO_Profile &theProfile, remote.ForWcharData.native_code_set = TAO_Codeset_Manager::default_wchar_codeset; } - - CONV_FRAME::CodeSetId tcs = computeTCS (remote.ForCharData, - this->codeset_info_.ForCharData); - if (TAO_debug_level > 2) - { - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("TAO (%P|%t) - Codeset_Manager::set_tcs, ") - ACE_LIB_TEXT ("setting char translator(%08x)\n"), - tcs)); - } - - trans.char_translator (this->get_char_trans (tcs)); - - tcs = computeTCS (remote.ForWcharData, - this->codeset_info_.ForWcharData); - - if (TAO_debug_level > 2) - { - ACE_DEBUG ((LM_DEBUG, - ACE_LIB_TEXT ("TAO (%P|%t) - Codeset_Manager::set_tcs, ") - ACE_LIB_TEXT ("setting wchar translator (%08x)\n"), - tcs)); - } - - trans.wchar_translator (this->get_wchar_trans (tcs)); + else + { + CONV_FRAME::CodeSetId tcs = + computeTCS (remote.ForCharData, + this->codeset_info_.ForCharData); + if (TAO_debug_level > 2) + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT("TAO (%P|%t) - Codeset_Manager::set_tcs ") + ACE_LIB_TEXT("setting char translator(%08x)\n"), + tcs)); + trans.char_translator(this->get_char_trans (tcs)); + + tcs = computeTCS (remote.ForWcharData, + this->codeset_info_.ForWcharData); + + if (TAO_debug_level > 2) + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT("TAO (%P|%t) - Codeset_Manager::set_tcs ") + ACE_LIB_TEXT("setting wchar translator (%08x)\n"), + tcs)); + trans.wchar_translator(this->get_wchar_trans (tcs)); + } } void @@ -161,9 +161,9 @@ TAO_Codeset_Manager::process_service_context (TAO_ServerRequest &request) TAO_Service_Context &service_cntx = request.request_service_context (); IOP::ServiceContext context; context.context_id = IOP::CodeSets; + CONV_FRAME::CodeSetId tcs_c = TAO_Codeset_Manager::default_char_codeset; CONV_FRAME::CodeSetId tcs_w = TAO_Codeset_Manager::default_wchar_codeset; - if (service_cntx.get_context(context)) { // Convert the Service Context to Codeset Context @@ -180,7 +180,13 @@ TAO_Codeset_Manager::process_service_context (TAO_ServerRequest &request) cdr >> tcs_w; } } - + else + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT("TAO (%P|%t) - Codeset_Manager::process_service_context ") + ACE_LIB_TEXT("no codeset context in request, inferring TAO backwards compatibility\n"))); + } if (TAO_debug_level > 2) { ACE_DEBUG ((LM_DEBUG, @@ -447,7 +453,19 @@ TAO_Codeset_Manager::get_char_trans (CONV_FRAME::CodeSetId tcs) { if (this->codeset_info_.ForCharData.native_code_set == tcs) { - return 0; + if (tcs != ACE_CODESET_ID_ISO_UTF_16) + return 0; + else + { + if (this->utf16_bom_translator_ == 0) + { + ACE_NEW_RETURN (this->utf16_bom_translator_, + UTF16_BOM_Factory, + 0); + this->utf16_bom_translator_->init(0,0); + } + return this->utf16_bom_translator_; + } } return this->get_translator_i (this->char_factories_,tcs); diff --git a/TAO/tao/Codeset_Manager.h b/TAO/tao/Codeset_Manager.h index 479e707a75a..24da96db154 100644 --- a/TAO/tao/Codeset_Manager.h +++ b/TAO/tao/Codeset_Manager.h @@ -25,6 +25,8 @@ #include "ace/Unbounded_Set.h" +class ACE_WChar_Codeset_Translator; + class TAO_Profile; class TAO_Transport; class TAO_Operation_Details; @@ -205,6 +207,13 @@ private: // The lists of available translators for both chars and wchars. TAO_CodesetFactorySet char_factories_; TAO_CodesetFactorySet wchar_factories_; + + // The UTF16 BOM (Byte Order Marker) translator is unique in that it is + // required when UTF16 is used as both the native and transmitted codeset. + // It exists to insert or extract the BOM preceeding Wchar data in the + // stream. + TAO_Codeset_Translator_Factory *utf16_bom_translator_; + }; #include /**/ "ace/post.h" diff --git a/TAO/tao/UTF16_BOM_Factory.cpp b/TAO/tao/UTF16_BOM_Factory.cpp new file mode 100644 index 00000000000..3330fcfaeac --- /dev/null +++ b/TAO/tao/UTF16_BOM_Factory.cpp @@ -0,0 +1,39 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tao +// +// = FILENAME +// UTF16_BOM_Factory.cpp +// +// = DESCRIPTION +// Loader for an instance of the UTF16_BOM_Translator. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ + +#include "UTF16_BOM_Factory.h" + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) + +template class TAO_Codeset_Translator_Factory_T<UTF16_BOM_Translator>; + +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) + +#pragma instantiate TAO_Codeset_Translator_Factory_T<UTF16_BOM_Translator> + +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ + +ACE_STATIC_SVC_DEFINE (UTF16_BOM_Factory, + ACE_TEXT ("UTF16_BOM_Factory"), + ACE_SVC_OBJ_T, + &ACE_SVC_NAME (UTF16_BOM_Factory), + ACE_Service_Type::DELETE_THIS + | ACE_Service_Type::DELETE_OBJ, + 0) +ACE_FACTORY_DEFINE (TAO, UTF16_BOM_Factory) diff --git a/TAO/tao/UTF16_BOM_Factory.h b/TAO/tao/UTF16_BOM_Factory.h new file mode 100644 index 00000000000..5e8fad0e10f --- /dev/null +++ b/TAO/tao/UTF16_BOM_Factory.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO +// +// = FILENAME +// UTF16_BOM_Factory.h +// +// = DESCRIPTION +// Loader for an instance of the UTF16_BOM_Translator. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ + +#ifndef UTF16_BOM_FACTORY_H +#define UTF16_BOM_FACTORY_H + +#include <ace/pre.h> +#include <ace/Service_Config.h> +#include <tao/Codeset_Translator_Factory.h> + +#include "UTF16_BOM_Translator.h" + +typedef TAO_Export TAO_Codeset_Translator_Factory_T<UTF16_BOM_Translator> UTF16_BOM_Factory; + +ACE_STATIC_SVC_DECLARE_EXPORT (TAO, UTF16_BOM_Factory) +ACE_FACTORY_DECLARE (TAO, UTF16_BOM_Factory) + +#include <ace/post.h> +#endif /* UTF16_BOM_FACTORY_H */ diff --git a/TAO/tao/UTF16_BOM_Translator.cpp b/TAO/tao/UTF16_BOM_Translator.cpp new file mode 100644 index 00000000000..12a5ef44ac3 --- /dev/null +++ b/TAO/tao/UTF16_BOM_Translator.cpp @@ -0,0 +1,369 @@ +// -*- C++ -*- +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tao +// +// = FILENAME +// UTF16_BOM_Translator.cpp +// +// = DESCRIPTION +// Manages the transformation between native and transmitted UTF-16. It is +// Required because transmitted UTF-16 may carry a byte order marker (BOM) +// that is not part of the data contents. If no BOM is present, then the +// serialized UTF-16 data is big-endian, regardless of the byte order of +// the containing encapsulation. +// +// = AUTHOR +// Phil Mesnier <mesnier_p@ociweb.com> +// +// ============================================================================ + +#include "UTF16_BOM_Translator.h" +#include "ace/OS_Memory.h" + +// **************************************************************** + + +typedef ACE_CDR::UShort ACE_UTF16_T; +static const size_t ACE_UTF16_CODEPOINT_SIZE = sizeof(ACE_UTF16_T); +static const unsigned short ACE_UNICODE_BOM_CORRECT = 0xFEFFU; +static const unsigned short ACE_UNICODE_BOM_SWAPPED = 0xFFFEU; + +///////////////////////////// +// UTF16_BOM_Translator implementation + +UTF16_BOM_Translator::UTF16_BOM_Translator (void) +{ + +} + +UTF16_BOM_Translator::~UTF16_BOM_Translator (void) +{ + +} + +// = Documented in $ACE_ROOT/ace/CDR_Stream.h +ACE_CDR::Boolean +UTF16_BOM_Translator::read_wchar (ACE_InputCDR &cdr, ACE_CDR::WChar &x) +{ + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 && + ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 2) + { + ACE_CDR::Octet len; + if (! this->read_1 (cdr, &len)) + return 0; + + if (len == 2) // no BOM present + { + ACE_CDR::Short sx; + + if (!this->read_array (cdr, + ACE_reinterpret_cast (char *,&sx),1,1,2)) + return 0; + +#if defined (ACE_LITTLE_ENDIAN) + ACE_CDR::Short ux; + ACE_CDR::swap_2 (ACE_reinterpret_cast (const char*,&sx), + ACE_reinterpret_cast(char *,&ux)); + x = ACE_static_cast (ACE_CDR::WChar, ux); +#else + x = ACE_static_cast(ACE_CDR::WChar, sx); +#endif // ACE_LITTLE_ENDIAN + return 1; + } + + ACE_UTF16_T buf[2]; + if (len != 4 || !this->read_array (cdr, + ACE_reinterpret_cast(char *,buf), + 1,1,4)) // get BO & payload + return 0; + // Check for byte order mark, if found, consume and honor it. + if (buf[0] == ACE_UNICODE_BOM_CORRECT || + buf[0] == ACE_UNICODE_BOM_SWAPPED) + { + // if we found it, but it came in in the wrong order + // invert the byte order flag for the duration of this method + if (buf[0] == ACE_UNICODE_BOM_SWAPPED) + { + ACE_CDR::Short ux; + ACE_CDR::swap_2 (ACE_reinterpret_cast (const char*,&buf[1]), + ACE_reinterpret_cast(char *,&ux)); + x = ACE_static_cast (ACE_CDR::WChar, ux); + } + else + x = ACE_static_cast(ACE_CDR::WChar, buf[1]); + return 1; + } + // What do we do here? The length is > 2 but the first word + // is not a BOM. Just return an error I suppose + return 0; + } + + ACE_UTF16_T sx; + if (this->read_2 (cdr, &sx)) + { + x = ACE_static_cast(ACE_CDR::WChar, sx); + return 1; + } + return 0; +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::read_wstring (ACE_InputCDR &cdr, + ACE_CDR::WChar *&x) +{ + ACE_CDR::ULong len; + if (!this->read_4 (cdr, &len)) + return 0; + + // A check for the length being too great is done later in the + // call to read_char_array but we want to have it done before + // the memory is allocated. + if (len > 0 && len <= cdr.length()) + { + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) + { + len /= ACE_UTF16_CODEPOINT_SIZE; + + //allocating one extra for the null character needed by applications + ACE_NEW_RETURN (x, + ACE_CDR::WChar [len + 1], + 0); + + x[len] = L'\x00'; + if (this->read_wchar_array_i (cdr, x, len,1)) + { + // Since reading the array may have adjusted the length, + // we simply rewrite the null terminator + x[len] = L'\x00'; + return 1; + } + } + else + { + ACE_NEW_RETURN (x, + ACE_CDR::WChar [len], + 0); + if (this->read_wchar_array (cdr, x, len)) + return 1; + } + delete [] x; + } + else if (len == 0) + { + // Convert any null strings to empty strings since empty + // strings can cause crashes. (See bug 58.) + ACE_NEW_RETURN (x, + ACE_CDR::WChar[1], + 0); + x[0] = '\x00'; + return 1; + } + x = 0; + return 0; +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::read_wchar_array_i (ACE_InputCDR & cdr, + ACE_CDR::WChar *x, + ACE_CDR::ULong &length, + int adjust_len) +{ + int has_bom = 0; + int must_swap = 0; + char* buf; + size_t align = ACE_CDR::SHORT_ALIGN; + if (cdr.adjust (ACE_UTF16_CODEPOINT_SIZE * length, align, buf) == 0) + { + // check for byte order mark. If found, honor it then discard it + ACE_UTF16_T *sb = ACE_reinterpret_cast(ACE_UTF16_T *, buf); + if (*sb == ACE_UNICODE_BOM_CORRECT || *sb == ACE_UNICODE_BOM_SWAPPED) + { + must_swap = (*sb == ACE_UNICODE_BOM_SWAPPED); + has_bom = 1; + } + else + { +#if defined (ACE_LITTLE_ENDIAN) + must_swap = 1; +#endif // ACE_LITTLE_ENDIAN + } + + if (has_bom) + { + buf += ACE_UTF16_CODEPOINT_SIZE; + sb++; + if (adjust_len) + length -= 1; + } + + for (size_t i = 0; i < length; i++) +#if defined (ACE_DISABLE_SWAP_ON_READ) + x[i] = ACE_static_cast (ACE_CDR::WChar, sb[i]); +#else + if (!must_swap) + { + x[i] = ACE_static_cast (ACE_CDR::WChar, sb[i]); + } + else + { + ACE_CDR::UShort sx; + ACE_CDR::swap_2 (&buf[i*2], ACE_reinterpret_cast(char *,&sx)); + x[i] = ACE_static_cast (ACE_CDR::WChar,sx); + } +#endif /* ACE_DISABLE_SWAP_ON_READ */ + + if (has_bom && !adjust_len) + { + cdr.adjust (ACE_UTF16_CODEPOINT_SIZE, align, buf); + } + return 1; + } + return 0; +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::read_wchar_array (ACE_InputCDR & cdr, + ACE_CDR::WChar *x, + ACE_CDR::ULong length) +{ + if (length == 0) + return 1; + + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) + { + for (size_t i = 0; i < length; i++) + if (!this->read_wchar(cdr,x[i])) + return 0; + return 1; + } + else + return this->read_wchar_array_i(cdr,x,length); +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::write_wchar (ACE_OutputCDR &cdr, + ACE_CDR::WChar x) +{ + return this->write_wchar_i (cdr,x,1); +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::write_wchar_i (ACE_OutputCDR &cdr, + ACE_CDR::WChar x, + int use_BOM) +{ + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) + { + int len = 0; + ACE_CDR::UShort buffer[2]; + if (use_BOM) + { + len = 2; + buffer[0] = ACE_UNICODE_BOM_CORRECT; + buffer[1] = ACE_static_cast(ACE_CDR::Short,x); + } + else + { + len = 1; + if (cdr.byte_order()) + ACE_CDR::swap_2 (ACE_reinterpret_cast (const char *,&x), + ACE_reinterpret_cast (char *,buffer)); + else + buffer[0] = ACE_static_cast(ACE_CDR::Short,x); + } + unsigned char tcsize = ACE_static_cast (unsigned char, + len * ACE_UTF16_CODEPOINT_SIZE); + if (this->write_1 (cdr, &tcsize)) + return this->write_array(cdr, &buffer, tcsize, 1, 1); + else + return 0; + } + else if (ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) != 0) + { + // GIOP 1.1 simple support + ACE_UTF16_T sx = ACE_static_cast (ACE_UTF16_T, x); + return this->write_2 (cdr, &sx); + } + else + { // wchar is not allowed with GIOP 1.0. + errno = EINVAL; + return 0; + } +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::write_wstring (ACE_OutputCDR & cdr, + ACE_CDR::ULong len, + const ACE_CDR::WChar *x) +{ + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) + { + ACE_CDR::ULong l = (len+1) * ACE_UTF16_CODEPOINT_SIZE; + if (this->write_4 (cdr, &l) && + this->write_2 (cdr, &ACE_UNICODE_BOM_CORRECT) && + x != 0) + return this->write_wchar_array_i (cdr, x, len); + } + else + { + ACE_CDR::ULong l = len + 1; + if (this->write_4 (cdr, &l)) + if (x != 0) + return this->write_wchar_array_i (cdr, x, len + 1); + else + { + ACE_UTF16_T s = 0; + return this->write_2 (cdr,&s); + } + } + return 0; +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::write_wchar_array (ACE_OutputCDR & cdr, + const ACE_CDR::WChar *x, + ACE_CDR::ULong length) +{ + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) + { + for (size_t i = 0; i < length; i++) + if (this->write_wchar_i (cdr,x[i]) == 0) + return 0; + return 1; + } + return this->write_wchar_array_i (cdr, x, length); +} + +ACE_CDR::Boolean +UTF16_BOM_Translator::write_wchar_array_i (ACE_OutputCDR & cdr, + const ACE_CDR::WChar *x, + ACE_CDR::ULong length) +{ + if (length == 0) + return 1; + char* buf; + size_t align = ACE_CDR::SHORT_ALIGN; + if (cdr.adjust (ACE_UTF16_CODEPOINT_SIZE * length, align, buf) + != 0) + { + return 0; + } + + ACE_UTF16_T *sb = ACE_reinterpret_cast(ACE_UTF16_T *, buf); + + for (size_t i = 0; i < length; i++) + { + sb[i] = ACE_static_cast (ACE_UTF16_T,x[i]); + } + return 1; + +} diff --git a/TAO/tao/UTF16_BOM_Translator.h b/TAO/tao/UTF16_BOM_Translator.h new file mode 100644 index 00000000000..1be88977e07 --- /dev/null +++ b/TAO/tao/UTF16_BOM_Translator.h @@ -0,0 +1,85 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Wchar_UCS4_UTC16_Translator.h + * + * $Id$ + * + * + * + * @author Phil Mesnier <mesnier_p@ociweb.com> + */ +//============================================================================= + +#ifndef UTF16_BOM_TRANSLATOR_H +#define UTF16_BOM_TRANSLATOR_H +#include "ace/pre.h" + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/CDR_Stream.h" +#include "TAO_Export.h" + +// **************************************************************** + +/** + * @class UTF16_BOM_Translator + * + * @brief Codeset translation specialization. + * + * This class performs the codeset translation: + * - Native: UTF16 (i.e. Unicode) + * - Stream: UTF16 with Byte Order Marker + */ +class TAO_Export UTF16_BOM_Translator : public ACE_WChar_Codeset_Translator +{ +public: + /// A do nothing constructor. + UTF16_BOM_Translator (void); + + /// Virtual destruction + virtual ~UTF16_BOM_Translator (void); + + // = Documented in $ACE_ROOT/ace/CDR_Stream.h + virtual ACE_CDR::Boolean read_wchar (ACE_InputCDR &, + ACE_CDR::WChar &); + virtual ACE_CDR::Boolean read_wstring (ACE_InputCDR &, + ACE_CDR::WChar *&); + virtual ACE_CDR::Boolean read_wchar_array (ACE_InputCDR &, + ACE_CDR::WChar *, + ACE_CDR::ULong); + virtual ACE_CDR::Boolean write_wchar (ACE_OutputCDR &, + ACE_CDR::WChar); + virtual ACE_CDR::Boolean write_wstring (ACE_OutputCDR &, + ACE_CDR::ULong, + const ACE_CDR::WChar *); + virtual ACE_CDR::Boolean write_wchar_array (ACE_OutputCDR &, + const ACE_CDR::WChar *, + ACE_CDR::ULong); + virtual ACE_CDR::ULong ncs () {return 0x00010109;} + virtual ACE_CDR::ULong tcs () {return 0x00010109;} + +private: + ACE_CDR::Boolean read_wchar_array_i (ACE_InputCDR &, + ACE_CDR::WChar *, + ACE_CDR::ULong&, + int adjust_len = 0); + + ACE_CDR::Boolean write_wchar_array_i (ACE_OutputCDR &, + const ACE_CDR::WChar *, + ACE_CDR::ULong); + + ACE_CDR::Boolean write_wchar_i (ACE_OutputCDR &, + ACE_CDR::WChar , + int use_BOM = 0); + + +}; + +#include "ace/post.h" +#endif /* UTF16_BOM_TRANSLATOR_H */ diff --git a/TAO/tao/tao.mpc b/TAO/tao/tao.mpc index b01056aeeeb..5a78cb71a06 100644 --- a/TAO/tao/tao.mpc +++ b/TAO/tao/tao.mpc @@ -151,6 +151,8 @@ project(TAO) : acelib, taoversion, core, tao_output, taodefaults, extra_core { UShortSeqC.cpp Codeset_Manager.cpp Codeset_Translator_Factory.cpp + UTF16_BOM_Translator.cpp + UTF16_BOM_Factory.cpp ORB_Core.cpp ORB_Core_Auto_Ptr.cpp Collocation_Resolver.cpp diff --git a/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.cpp b/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.cpp index 2508e98eb6b..9e34dac66e6 100644 --- a/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.cpp +++ b/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.cpp @@ -10,17 +10,8 @@ // WUCS4_UTF16.cpp // // = DESCRIPTION -// Defines the actions required to convert between UCS-4, a 4 byte wide char -// codeset as the native wchar codeset, and UCS-16, aka unicode, a 2-byte -// codeset for the transport wchar codeset. -// -// This translator does not alter any codepoint values, but it does -// illustrate how to deal with the unicode byte order marker (BOM) and how -// to deal with codepoint size differences. -// -// Note that the BOM is an optional value. The write_*() methods do not -// encode this value. When BOM is not encoded, the byte order of the -// encapsulation is used. +// Defines the arrays required to convert between UCS-4 a 4 byte wide char +// codeset, and UCS-16, aka unicode, a 2-byte codeset. // // = AUTHOR // Phil Mesnier <mesnier_p@ociweb.com> @@ -28,14 +19,202 @@ // ============================================================================ #include "WUCS4_UTF16.h" -#include "ace/OS_Memory.h" ACE_RCSID(UCS4_UTF16, WUCS4_UTF16, "$Id$") // **************************************************************** + +// @@ TODO: Find a better home for these definition +// Note: unlike the UNICODE standard we define these as +// half-closed ranges i.e. +// *BEGIN is the first value in the range +// *END is the first value beyond the range (END is not included +// in the range) +// Note the use of unsigned short for UTF-16 codepoints. wchar_t may +// by four bytes +typedef ACE_CDR::UShort ACE_UTF16_T; +static const size_t ACE_UTF16_CODEPOINT_SIZE = sizeof(ACE_UTF16_T); + +// surrogate high 1101.10HH.HHHH.HHHH +// surrogate low 1101.11LL.LLLL.LLLL +// 4 byte result: 0000.0000.0000.HHHH.HHHH.HHLL.LLLL.LLLL +// add offset 0000.0000.0000.0000.0001.0000.0000.0000 + +// range of surrogate values for high-order bits +static const unsigned short ACE_UTF16_SURROGATE_HIGH_BEGIN = 0xD800U; +static const unsigned short ACE_UTF16_SURROGATE_HIGH_END = 0xDC00U; + +static const unsigned short ACE_UTF16_SURROGATE_LOW_BEGIN = 0xDC00U; +static const unsigned short ACE_UTF16_SURROGATE_LOW_END = 0xE000U; + +// offset to UTF16 values encoded with surrogates start at 2^16 +static const unsigned long ACE_UTF16_SURROGATE_OFFSET = 0x000010000UL; + +// shift high order bits from surrogate into correct postion +static const int ACE_UTF16_SURROGATE_HIGH_SHIFT = 10; +static const unsigned short ACE_UTF16_SURROGATE_LOW_MASK = 0x3FF; + +// largest value that can be represented in UTF16 without using surrogates + 1 +static const unsigned long ACE_UTF16_RAW_END = 0x00010000LU; + +// largest value that can be represented in UTF16 + 1 +static const unsigned long ACE_UTF16_END = 0x00110000LU; + +// largest value that can be represented in UTF-32 + 1 +static const unsigned long ACE_UTF32_END = 0x80000000LU; + +static const unsigned short ACE_UNICODE_SUBSTITUTE_CHARACTER = 0xFFFDU; +static const unsigned short ACE_UNICODE_BOM_CORRECT = 0xFEFFU; +static const unsigned short ACE_UNICODE_BOM_SWAPPED = 0xFFFEU; + +///////////////////////////////////////////////////// +// Static inline routines to simplify conversion code +// @@ should be in anonymous namespace when ACE allows it +// or better yet, there should be a UTF-16 support thingie(technical term) +// that provides these methods. +// Performance: depends on compiler inlining + optimization for performance + +/// load next two bytes from buffer into a short. Byte swapping as necessary +static +ACE_INLINE +ACE_UTF16_T +load_raw_wchar (const char * buffer, size_t & pos, int do_byte_swap) +{ + // need a two byte object to load the UTF16 2 byte codepoint + ACE_UTF16_T utf16_char = * ACE_reinterpret_cast (ACE_UTF16_T const *, + &buffer[pos*ACE_UTF16_CODEPOINT_SIZE]); +#if ! defined (ACE_DISABLE_SWAP_ON_READ) + if (do_byte_swap) + { + ACE_CDR::swap_2 ( + &buffer[pos*ACE_UTF16_CODEPOINT_SIZE], + ACE_reinterpret_cast(char *,&utf16_char)); + } +#endif + pos ++; + return utf16_char; +} + +/// convert UTF-16 surrogate pair to wchar_t +static +ACE_INLINE +ACE_CDR::WChar +convert_surrogate_pair (ACE_UTF16_T high, ACE_UTF16_T low) +{ + return ACE_static_cast (ACE_CDR::WChar, + ((high - ACE_UTF16_SURROGATE_HIGH_BEGIN) << ACE_UTF16_SURROGATE_HIGH_SHIFT) + + (low - ACE_UTF16_SURROGATE_LOW_BEGIN) + + ACE_UTF16_SURROGATE_OFFSET + ); +} + +/// load wchar from utf16 buffer +/// converts surrogate pairs +/// substitutes SUBSTITUTE_CHAR for bad encoding +static +ACE_INLINE +ACE_CDR::WChar +load_wchar (const char * buffer, size_t & pos, size_t length, int do_byte_swap) +{ + ACE_CDR::WChar rc = ACE_UNICODE_SUBSTITUTE_CHARACTER; + if (pos < length) + { + rc = ACE_static_cast (ACE_CDR::WChar, load_raw_wchar (buffer, pos, do_byte_swap)); + // Is this a UTF16 surrogate? + // note assumpton that SURROGATE_HIGH_END == SURROGATE_LOW_BEGIN + if (rc >= ACE_UTF16_SURROGATE_HIGH_BEGIN && rc < ACE_UTF16_SURROGATE_LOW_END) + { + // if we still have two bytes available + if (pos < length) + { + // expecting high surrogate + if (rc < ACE_UTF16_SURROGATE_HIGH_END) + { + ACE_UTF16_T low = load_raw_wchar (buffer, pos, do_byte_swap); + if (low >= ACE_UTF16_SURROGATE_LOW_BEGIN + && low < ACE_UTF16_SURROGATE_LOW_END) + { + rc = convert_surrogate_pair ( + ACE_static_cast (ACE_UTF16_T, rc), low); + } + else + { + rc = ACE_UNICODE_SUBSTITUTE_CHARACTER; + } + } + else + { + rc = ACE_UNICODE_SUBSTITUTE_CHARACTER; + } + } + else + { + rc = ACE_UNICODE_SUBSTITUTE_CHARACTER; + } + } + } + return rc; +} + +static +ACE_INLINE +size_t encode_utf16 (ACE_UTF16_T * buffer, ACE_CDR::WChar value) +{ + buffer[0] = ACE_static_cast (ACE_UTF16_T, value); + size_t length = 1; + if (value >= ACE_UTF16_SURROGATE_HIGH_BEGIN) + { + if (value < ACE_UTF16_SURROGATE_LOW_END) + { + buffer[0] = ACE_UNICODE_SUBSTITUTE_CHARACTER; + } + else if ((unsigned long)value >= ACE_UTF16_RAW_END) + { + if ((unsigned long)value >= ACE_UTF16_END) + { + buffer[0] = ACE_UNICODE_SUBSTITUTE_CHARACTER; + } + else + { + ACE_CDR::WChar offset = ACE_static_cast (ACE_CDR::WChar, + value - ACE_UTF16_SURROGATE_OFFSET); + buffer[0] = (offset >> ACE_UTF16_SURROGATE_HIGH_SHIFT) + + ACE_UTF16_SURROGATE_HIGH_BEGIN; + buffer[1] = (offset & ACE_UTF16_SURROGATE_LOW_MASK) + + ACE_UTF16_SURROGATE_LOW_BEGIN; + length = 2; + } + } + } + return length; +} + +/// count number of characters in native WString that will be converted +/// to UTF-16 surrogate pairs +static +size_t count_potential_surrogates ( + const ACE_CDR::WChar *buffer, + ACE_CDR::ULong len) +{ + size_t count = 0; + for (size_t i = 0; i < len; ++i) + { + ACE_CDR::WChar value = buffer[i]; + if ((unsigned long)value >= ACE_UTF16_RAW_END && + (unsigned long)value < ACE_UTF16_END) + { + count += 1; + } + } + return count; +} + + +///////////////////////////// +// WUCS4_UTF16 implementation + WUCS4_UTF16::WUCS4_UTF16 (void) - : tcs_size_ (2) { } @@ -49,31 +228,75 @@ WUCS4_UTF16::~WUCS4_UTF16 (void) ACE_CDR::Boolean WUCS4_UTF16::read_wchar (ACE_InputCDR &cdr, ACE_CDR::WChar &x) { - ACE_CDR::UShort sx = 0; if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 - && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 2) + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) { ACE_CDR::Octet len; - if (!this->read_1 (cdr, &len)) - return 0; + if (! this->read_1 (cdr, &len)) + { + return 0; + } + + int old_bo = cdr.byte_order(); + + ACE_UTF16_T sx = 0; if (! this->read_2 (cdr,&sx)) - return 0; - // We need to consume the optional byte-order-marker - if (sx == 0xFEFE || sx == 0xFFFE) { - int old_bo = cdr.byte_order(); - cdr.reset_byte_order (sx == 0xFFFE); + return 0; + } + + // Check for byte order mark, if found, consume and honor it. + if (sx == ACE_UNICODE_BOM_CORRECT || sx == ACE_UNICODE_BOM_SWAPPED) + { + // if we found it, but it came in in the wrong order + // invert the byte order flag for the duration of this method + if (sx == ACE_UNICODE_BOM_SWAPPED) + { + cdr.reset_byte_order (! old_bo); + } this->read_2 (cdr,&sx); - cdr.reset_byte_order (old_bo); - return 1; } + + // check for UTF-16 surrogate pair, and if found interpret it + if (sx >= ACE_UTF16_SURROGATE_HIGH_BEGIN + && sx < ACE_UTF16_SURROGATE_LOW_END) + { + if (sx >= ACE_UTF16_SURROGATE_HIGH_END) + { + cdr.reset_byte_order (old_bo); + return 0; + } + + ACE_UTF16_T low; + if (! this->read_2 (cdr, &low)) + { + cdr.reset_byte_order (old_bo); + return 0;; + } + if (low < ACE_UTF16_SURROGATE_LOW_BEGIN + || low >= ACE_UTF16_SURROGATE_LOW_END) + { + cdr.reset_byte_order (old_bo); + return 0; + } + x = convert_surrogate_pair (sx, low); + } + else + { + x = ACE_static_cast(ACE_CDR::WChar, sx); + } + + cdr.reset_byte_order (old_bo); } else { + ACE_UTF16_T sx = 0; if (!this->read_2 (cdr, &sx)) - return 0; + { + return 0; + } + x = ACE_static_cast(ACE_CDR::WChar, sx); } - x = ACE_static_cast(ACE_CDR::WChar, sx); return 1; } @@ -91,20 +314,20 @@ WUCS4_UTF16::read_wstring (ACE_InputCDR &cdr, if (len > 0 && len <= cdr.length()) { if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 - && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 2) + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) { - len /= this->tcs_size_; + len /= ACE_UTF16_CODEPOINT_SIZE; //allocating one extra for the null character needed by applications ACE_NEW_RETURN (x, ACE_CDR::WChar [len + 1], 0); - if (this->read_wchar_array (cdr, x, len)) + x[len] = L'\x00'; + if (this->read_wchar_array_i (cdr, x, len,1)) { - //Null character used by applications to find the end of - //the wstring - //Is this okay with the GIOP 1.2 spec?? - x[len] = '\x00'; + // Since reading the array may have adjusted the length, + // we simply rewrite the null terminator + x[len] = L'\x00'; return 1; } } @@ -133,118 +356,235 @@ WUCS4_UTF16::read_wstring (ACE_InputCDR &cdr, } ACE_CDR::Boolean -WUCS4_UTF16::read_wchar_array (ACE_InputCDR & cdr, - ACE_CDR::WChar *x, - ACE_CDR::ULong length) +WUCS4_UTF16::read_wchar_array_i (ACE_InputCDR & cdr, + ACE_CDR::WChar *x, + ACE_CDR::ULong &length, + int adjust_len) { if (length == 0) return 1; char* buf; size_t align = ACE_CDR::SHORT_ALIGN; - if (cdr.adjust (this->tcs_size_ * length, align, buf) == 0) + if (cdr.adjust (ACE_UTF16_CODEPOINT_SIZE * length, align, buf) == 0) { - ACE_CDR::UShort *sb = ACE_reinterpret_cast(ACE_CDR::UShort *, buf); - int old_bo = cdr.byte_order(); - if (*sb == 0xFEFE || *sb == 0xFFFE) + int byte_swap = cdr.do_byte_swap(); + size_t pos = 0; + + // check for byte order mark. If found, honor it then discard it + ACE_UTF16_T bom = load_raw_wchar (buf, pos, byte_swap); + if (bom == ACE_UNICODE_BOM_CORRECT || bom == ACE_UNICODE_BOM_SWAPPED) { - cdr.reset_byte_order (*sb == 0xFFFE); - sb ++; - length --; + if (bom == ACE_UNICODE_BOM_SWAPPED) + { + byte_swap = !byte_swap; + } + buf += ACE_UTF16_CODEPOINT_SIZE; + if (adjust_len) + length -= 1; } - for (size_t i = 0; i < length; i++) -#if defined (ACE_DISABLE_SWAP_ON_READ) - x[i] = ACE_static_cast (ACE_CDR::WChar, sb[i]); -#else - if (!cdr.do_byte_swap ()) - x[i] = ACE_static_cast (ACE_CDR::WChar, sb[i]); - else + size_t bpos = 0; + for (size_t xpos = 0; xpos < length; ++xpos) { - ACE_CDR::UShort sx; - ACE_CDR::swap_2 (&buf[i*2], ACE_reinterpret_cast(char *,&sx)); - x[i] = ACE_static_cast (ACE_CDR::WChar,sx); + x[xpos] = load_wchar (buf, bpos, length, byte_swap); } -#endif /* ACE_DISABLE_SWAP_ON_READ */ - cdr.reset_byte_order (old_bo); return 1; } return 0; + } + ACE_CDR::Boolean -WUCS4_UTF16::write_wchar (ACE_OutputCDR &cdr, - ACE_CDR::WChar x) +WUCS4_UTF16::read_wchar_array (ACE_InputCDR & cdr, + ACE_CDR::WChar *x, + ACE_CDR::ULong length) { - ACE_CDR::UShort sx = ACE_static_cast(ACE_CDR::Short,x); + if (length == 0) + return 1; + if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 - && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 2) + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) { - if (this->write_1 (cdr, &this->tcs_size_)) - return this->write_array(cdr, &sx, this->tcs_size_, ACE_CDR::SHORT_ALIGN, 1); - else - return 0; + for (size_t i = 0; i < length; i++) + if (!this->read_wchar(cdr,x[i])) + return 0; + return 1; } - else if (ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 0) - { // wchar is not allowed with GIOP 1.0. + else + return this->read_wchar_array_i(cdr,x,length); +} + +ACE_CDR::Boolean +WUCS4_UTF16::write_wchar (ACE_OutputCDR &cdr, + ACE_CDR::WChar x) +{ + int encode_len = 1; + if (ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 0) + { // wchar is not allowed with GIOP 1.0 errno = EINVAL; return 0; } - return this->write_2 (cdr, &sx); + else if (ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 1) + encode_len = 0; + + return write_wchar_i(cdr,x,1,encode_len); +} + +ACE_CDR::Boolean +WUCS4_UTF16::write_wchar_i (ACE_OutputCDR &cdr, + ACE_CDR::WChar x, + int use_BOM, + int encode_len) +{ + // If the desired char cannot be translated into a single unicode char, + // we must raise a marshal exception. + if ((unsigned long)x >= ACE_UTF16_RAW_END && + (unsigned long)x < ACE_UTF16_END) + return 0; + + int len = 0; + ACE_CDR::UShort buffer[2]; + if (use_BOM) + { + len = 2; + buffer[0] = ACE_UNICODE_BOM_CORRECT; + buffer[1] = ACE_static_cast(ACE_CDR::Short,x); + } + else + { + len = 1; + if (cdr.byte_order()) + ACE_CDR::swap_2 (ACE_reinterpret_cast (const char *,&x), + ACE_reinterpret_cast (char *,buffer)); + else + buffer[0] = ACE_static_cast(ACE_CDR::Short,x); + } + + if (encode_len) + { + unsigned char tcsize = ACE_static_cast (unsigned char, + len * ACE_UTF16_CODEPOINT_SIZE); + if (this->write_1 (cdr, &tcsize)) + return this->write_array(cdr, &buffer, tcsize, 1, 1); + else + return 0; + } + if (this->write_2 (cdr, buffer) == 0) + return 0; + if (len == 2) + return this->write_2 (cdr,buffer+1); + return 1; } ACE_CDR::Boolean WUCS4_UTF16::write_wstring (ACE_OutputCDR & cdr, - ACE_CDR::ULong len, - const ACE_CDR::WChar *x) + ACE_CDR::ULong len, + const ACE_CDR::WChar *x) { - ACE_CDR::ULong l = 0; if (ACE_static_cast (ACE_CDR::Short, this->major_version(cdr)) == 1 - && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 2) + && ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) > 1) { - l = len * this->tcs_size_; + // count characters that will require surrogates to + // determine transmission length + len++; // make room for BOM + ACE_UTF16_T bom = ACE_UNICODE_BOM_CORRECT; + ACE_CDR::ULong length = len + count_potential_surrogates (x, len); + ACE_CDR::ULong l = length * ACE_UTF16_CODEPOINT_SIZE; if (this->write_4 (cdr, &l) && x != 0) - return this->write_wchar_array (cdr, x, len); + { + this->write_2 (cdr,&bom); + return this->write_measured_wchar_array (cdr, x, len, length); + } } else { - l = len + 1; + ACE_CDR::ULong l = len + 1; if (this->write_4 (cdr, &l)) if (x != 0) return this->write_wchar_array (cdr, x, len + 1); - else - { - ACE_CDR::UShort s = 0; - return this->write_2 (cdr,&s); - } + else + { + ACE_UTF16_T s = 0; + return this->write_2 (cdr,&s); + } } return 0; } ACE_CDR::Boolean WUCS4_UTF16::write_wchar_array (ACE_OutputCDR & cdr, - const ACE_CDR::WChar *x, - ACE_CDR::ULong length) + const ACE_CDR::WChar *x, + ACE_CDR::ULong length) +{ +#if 0 + // I do not believe this is correct, because this could yield an array + // with an incorrect number of elements for the space allotted. + return this->write_measured_wchar_array ( + cdr, + x, + length, + length + count_potential_surrogates (x, length)); +#endif + + int encode_len = 1; + if (ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 0) + { // wchar is not allowed with GIOP 1.0 + errno = EINVAL; + return 0; + } + else if (ACE_static_cast (ACE_CDR::Short, this->minor_version(cdr)) == 1) + encode_len = 0; + + for (size_t i = 0; i < length; i++) + if (this->write_wchar_i (cdr,x[i],0,encode_len) == 0) + return 0; + return 1; +} + +ACE_CDR::Boolean +WUCS4_UTF16::write_measured_wchar_array (ACE_OutputCDR & cdr, + const ACE_CDR::WChar *x, + ACE_CDR::ULong length, + ACE_CDR::ULong transmission_length) { if (length == 0) return 1; char* buf; size_t align = ACE_CDR::SHORT_ALIGN; - if (cdr.adjust (this->tcs_size_ * length, align, buf) == 0) + if (cdr.adjust (ACE_UTF16_CODEPOINT_SIZE * transmission_length, align, buf) + != 0) { - ACE_CDR::UShort *sb = ACE_reinterpret_cast(ACE_CDR::UShort *, buf); - for (size_t i = 0; i < length; i++) -#if !defined (ACE_ENABLE_SWAP_ON_WRITE) - sb[i] = ACE_static_cast (ACE_CDR::UShort, x[i]); -#else - if (!cdr.do_byte_swap()) - sb[i] = ACE_static_cast (ACE_CDR::UShort, x[i]);; - else + return 0; + } + + ACE_UTF16_T *sb = ACE_reinterpret_cast(ACE_UTF16_T *, buf); + size_t sbpos = 0; + + for (size_t i = 0; i < length; i++) + { + sbpos += encode_utf16 (& sb[sbpos], x[i]); + } +#if defined (ACE_ENABLE_SWAP_ON_WRITE) + // NOTE this will rarely be enabled. See the comments in ace/OS.h + if (cdr.do_byte_swap()) + { + // note can't use swap_2_array because in-place swaps are not safe :-< + // and we don't want to allocate a new array + for (size_t i = 0; i < sbpos; i++) { - ACE_CDR::UShort sx = ACE_static_cast (ACE_CDR::UShort, x[i]); - ACE_CDR::swap_2 (ACE_reinterpret_cast(char *,&sx),&buf[i*2]); + char * pchar = ACE_static_cast (char *, &sb[i]); + // ACE_CDR::swap_2 (pchar, pchar); + // can't use swap_2 because inplace swaps are not safe + // and work-arounds like copying to another buffer lose + // any performance improvement from + // that fancy asm code, so we might as well just: + char temp = pchar[0]; + pchar[0] = pchar[1]; + pchar[1] = temp; + //@@TODO write swap_2(char * inplace_buffer); } -#endif /* ACE_DISABLE_SWAP_ON_READ */ - return 1; } - return 0; +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + return 1; } diff --git a/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.h b/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.h index e7feca60d8d..a71fea1e927 100644 --- a/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.h +++ b/TAO/tests/CodeSets/libs/UCS4_UTF16/WUCS4_UTF16.h @@ -2,7 +2,7 @@ //============================================================================= /** - * @file WUCS4_UTF16.h + * @file Wchar_UCS4_UTC16_Translator.h * * $Id$ * @@ -14,7 +14,7 @@ #ifndef WUCS4_UTF16_H #define WUCS4_UTF16_H -#include /**/ "ace/pre.h" +#include "ace/pre.h" #include "ace/config-all.h" @@ -33,19 +33,8 @@ * @brief Codeset translation specialization. * * This class performs the codeset translation: - * - Native: UCS4 (4-byte codepoints, lower 16 match Unicode) - * - Stream: UTF16 (i.e. Unicode) - * Defines the actions required to convert between UCS-4, a 4 byte wide char - * codeset as the native wchar codeset, and UCS-16, aka unicode, a 2-byte - * codeset for the transport wchar codeset. - * - * This translator does not alter any codepoint values, but it does - * illustrate how to deal with the unicode byte order marker (BOM) and how - * to deal with codepoint size differences. - * - * Note that the BOM is an optional value. The write_*() methods do not - * encode this value. When BOM is not encoded, the byte order of the - * encapsulation is used. + * - Native: IBM_1047 (i.e. EBCDIC) + * - Stream: ISO-8859 (i.e. Latin/1) */ class UCS4_UTF16_Export WUCS4_UTF16 : public ACE_WChar_Codeset_Translator { @@ -76,8 +65,28 @@ public: virtual ACE_CDR::ULong tcs () {return 0x00010109;} private: - ACE_CDR::Octet tcs_size_; + ACE_CDR::Boolean read_wchar_array_i (ACE_InputCDR &, + ACE_CDR::WChar *, + ACE_CDR::ULong&, + int adjust_len = 0); + + ACE_CDR::Boolean write_wchar_i (ACE_OutputCDR &, + ACE_CDR::WChar , + int use_BOM, + int encode_len); + + /** + Due to surrogate pair substution the transmitted length of a wstring can + differ from the logical strength length. This version of write_wchar_array + accepts both lengths and uses them as necessary. + */ + ACE_CDR::Boolean write_measured_wchar_array ( + ACE_OutputCDR & cdr, + const ACE_CDR::WChar *x, + ACE_CDR::ULong length, + ACE_CDR::ULong transmission_length); + }; -#include /**/ "ace/post.h" +#include "ace/post.h" #endif /* WCHAR_UCS4_UTF16_TRANSLATOR */ |