You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2009/04/14 16:32:36 UTC

svn commit: r764791 - in /activemq/activemq-cpp/branches/activemq-cpp-2.x/src: main/ main/activemq/connector/openwire/marshal/ main/activemq/connector/openwire/utils/ main/decaf/io/ test/activemq/connector/openwire/utils/ test/decaf/io/

Author: tabish
Date: Tue Apr 14 14:32:36 2009
New Revision: 764791

URL: http://svn.apache.org/viewvc?rev=764791&view=rev
Log:
http://issues.apache.org/activemq/browse/AMQCPP-235

Fixed the DataInputStream, DataOutputStream and OpenwireStringSupport classes to all read and write correct modified UTF-8 strings for all ascii values 0-255.   OpenwireStringSupport now correctly write the data with an int size prefix to support larger strings enabling primitive maps to store strings larger than 65535 characters.

Added:
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/UTFDataFormatException.h   (with props)
Modified:
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/Makefile.am
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/marshal/PrimitiveMapMarshaller.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/utils/OpenwireStringSupport.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.h
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.h
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.h
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.h
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.cpp
    activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.h

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/Makefile.am
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/Makefile.am?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/Makefile.am (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/Makefile.am Tue Apr 14 14:32:36 2009
@@ -385,6 +385,7 @@
     decaf/io/BufferedInputStream.h \
     decaf/io/InputStream.h \
     decaf/io/IOException.h \
+    decaf/io/UTFDataFormatException.h \
     decaf/io/InterruptedIOException.h \
     decaf/util/concurrent/BrokenBarrierException.h \
     decaf/util/concurrent/Delayed.h \

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/marshal/PrimitiveMapMarshaller.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/marshal/PrimitiveMapMarshaller.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/marshal/PrimitiveMapMarshaller.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/marshal/PrimitiveMapMarshaller.cpp Tue Apr 14 14:32:36 2009
@@ -21,6 +21,7 @@
 #include <decaf/io/ByteArrayOutputStream.h>
 #include <decaf/io/DataInputStream.h>
 #include <decaf/io/DataOutputStream.h>
+#include <decaf/lang/Short.h>
 #include <activemq/connector/openwire/utils/OpenwireStringSupport.h>
 #include <activemq/exceptions/ActiveMQException.h>
 
@@ -72,7 +73,7 @@
             PrimitiveMap* map = new PrimitiveMap;
 
             for( int i=0; i < size; i++ ) {
-                std::string key = OpenwireStringSupport::readString( dataIn );
+                std::string key = dataIn.readUTF();
                 map->setValue( key, unmarshalPrimitive( dataIn ) );
             }
 
@@ -124,7 +125,7 @@
 
         for(; iter != keys.end(); ++iter ) {
 
-            OpenwireStringSupport::writeString( dataOut, &(*iter) );
+            dataOut.writeUTF( *iter );
             PrimitiveValueNode value = map.getValue( *iter );
             marshalPrimitive( dataOut, value );
         }
@@ -213,14 +214,14 @@
             std::string data = value.getString();
 
             // is the string big??
-            if( data.size() > 8191 ) {
+            if( data.size() > Short::MAX_VALUE / 4 ) {
                 dataOut.writeByte( PrimitiveValueNode::BIG_STRING_TYPE );
+                OpenwireStringSupport::writeString( dataOut, &data );
             } else {
                 dataOut.writeByte( PrimitiveValueNode::STRING_TYPE );
+                dataOut.writeUTF( data );
             }
 
-            OpenwireStringSupport::writeString( dataOut, &data );
-
         } else if( value.getValueType() == PrimitiveValueNode::LIST_TYPE ) {
 
             dataOut.writeByte( PrimitiveValueNode::LIST_TYPE );
@@ -254,7 +255,7 @@
 
         if( size > 0 ) {
             for( int i=0; i < size; i++ ) {
-                std::string key = OpenwireStringSupport::readString( dataIn );
+                std::string key = dataIn.readUTF();
                 map.setValue( key, unmarshalPrimitive( dataIn ) );
             }
         }
@@ -331,6 +332,8 @@
                 break;
             }
             case PrimitiveValueNode::STRING_TYPE:
+                value.setString( dataIn.readUTF() );
+                break;
             case PrimitiveValueNode::BIG_STRING_TYPE:
                 value.setString( OpenwireStringSupport::readString( dataIn ) );
                 break;

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/utils/OpenwireStringSupport.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/utils/OpenwireStringSupport.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/utils/OpenwireStringSupport.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/activemq/connector/openwire/utils/OpenwireStringSupport.cpp Tue Apr 14 14:32:36 2009
@@ -34,71 +34,86 @@
 
     try {
 
-        short utflen = dataIn.readShort();
+        int utfLength = dataIn.readInt();
 
-        if( utflen > -1 )
-        {
-            // Let the stream get us all that data.
-            std::vector<unsigned char> value;
-            value.resize( utflen );
-            dataIn.readFully( value );
-
-            unsigned char c = 0;
-            int count = 0;
-
-            // x counts the number of 2-byte UTF8 sequences decoded
-            int x = 0;
-
-            while( count+x < utflen )
-            {
-                c = value[count+x];
-                switch( c >> 4 )
-                {
-                    case 0:
-                    case 1:
-                    case 2:
-                    case 3:
-                    case 4:
-                    case 5:
-                    case 6:
-                    case 7:
-                        // 1-byte UTF8 encoding: 0xxxxxxx
-                        value[count] = c;
-                        count++;
-                        break;
-                    case 12:
-                    case 13:
-                        // 2-byte UTF8 encoding: 110X XXxx 10xx xxxx
-                        // Bits set at 'X' means we have encountered a UTF8 encoded value
-                        // greater than 255, which is not supported.
-                        if( c & 0x1C ) {
-                            throw IOException(
-                                __FILE__,
-                                __LINE__,
-                                "OpenwireStringSupport::readString - Encoding not supported" );
-                        }
-                        // Place the decoded UTF8 character back into the value array
-                        value[count] = ((c & 0x1F) << 6) | (value[count+x+1] & 0x3F);
-                        count++;
-                        x++;
-                        break;
-                    case 14:
-                    default:
-                    {
-                        // 3-byte UTF8 encoding: 1110 xxxx  10xx xxxx  10xx xxxx
-                        throw IOException(
-                            __FILE__,
-                            __LINE__,
-                            "OpenwireStringSupport::readString - Encoding not supported" );
-                    }
+        if( utfLength == -1 ) {
+            return "";
+        }
+
+        std::vector<unsigned char> buffer( utfLength );
+        std::string result( utfLength, char() );
+
+        dataIn.readFully( &buffer[0], 0, utfLength );
+
+        int count = 0;
+        int index = 0;
+        unsigned char a = 0;
+
+        while( count < utfLength ) {
+            if( (unsigned char)( result[index] = (char)buffer[count++] ) < 0x80 ) {
+                index++;
+            } else if( ( ( a = result[index++] ) & 0xE0 ) == 0xC0 ) {
+                if( count >= utfLength ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid UTF-8 encoding found, start of two byte char found at end.");
+                }
+
+                unsigned char b = buffer[count++];
+                if( ( b & 0xC0 ) != 0x80 ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid UTF-8 encoding found, byte two does not start with 0x80." );
                 }
-            }
 
-            // Let the Compiler give us a string.
-            return std::string(reinterpret_cast<const char*>(&value[0]), count);
+                // 2-byte UTF8 encoding: 110X XXxx 10xx xxxx
+                // Bits set at 'X' means we have encountered a UTF8 encoded value
+                // greater than 255, which is not supported.
+                if( a & 0x1C ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid 2 byte UTF-8 encoding found, "
+                        "This method only supports encoded ASCII values of (0-255)." );
+                }
+
+                result[index++] = (char)( ( ( a & 0x1F ) << 6 ) | ( b & 0x3F ) );
+
+            } else if( ( a & 0xF0 ) == 0xE0 ) {
+
+                if( count + 1 >= utfLength ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid UTF-8 encoding found, start of three byte char found at end.");
+                } else {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid 3 byte UTF-8 encoding found, "
+                        "This method only supports encoded ASCII values of (0-255)." );
+                }
+
+                // If we were to support multibyte strings in the future this would be
+                // the remainder of this method decoding logic.
+                //
+                //int b = buffer[count++];
+                //int c = buffer[count++];
+                //if( ( ( b & 0xC0 ) != 0x80 ) || ( ( c & 0xC0 ) != 0x80 ) ) {
+                //    throw UTFDataFormatException(
+                //        __FILE__, __LINE__,
+                //        "Invalid UTF-8 encoding found, byte two does not start with 0x80." );
+                //}
+                //
+                //result[inde++] = (char)( ( ( a & 0x0F ) << 12 ) |
+                //                         ( ( b & 0x3F ) << 6 ) | ( c & 0x3F ) );
+
+            } else {
+                throw UTFDataFormatException(
+                    __FILE__, __LINE__, "Invalid UTF-8 encoding found, aborting.");
+            }
         }
 
-        return "";
+        result.resize( index );
+
+        return result;
     }
     AMQ_CATCH_RETHROW( decaf::io::IOException )
     AMQ_CATCH_EXCEPTION_CONVERT( Exception, decaf::io::IOException )
@@ -114,50 +129,60 @@
 
         if( str != NULL ) {
 
-            if( str->size() > 65536 ) {
+            int utfLength = 0;
+            std::size_t length = str->length();
 
-                throw IOException(
-                    __FILE__,
-                    __LINE__,
-                    ( std::string( "OpenwireStringSupport::writeString - Cannot marshall " ) +
-                    "string longer than: 65536 characters, supplied string was: " +
-                    Integer::toString( (int)str->size() ) + " characters long." ).c_str() );
-            }
+            for( std::size_t i = 0; i < length; ++i ) {
+
+                unsigned int charValue = (unsigned char)str->at( i );
 
-            unsigned short utflen = 0;
-            int count = 0;
-            unsigned char c;
-
-            std::string::const_iterator iter = str->begin();
-
-            for(; iter != str->end(); ++iter ) {
-                c = *iter;
-                if( c < 0x80 ) {
-                    utflen++;
+                // Written to allow for expansion to wide character strings at some
+                // point, as it stands now the value can never be > 255 since the
+                // string class returns a single byte char.
+                if( charValue > 0 && charValue <= 127 ) {
+                    utfLength++;
+                } else if( charValue <= 2047 ) {
+                    utfLength += 2;
                 } else {
-                    utflen += 2;
+                    utfLength += 3;
                 }
             }
 
-            dataOut.writeUnsignedShort( utflen );
-            std::vector<unsigned char> byteArr;
-            byteArr.resize( utflen );
-
-            for( iter = str->begin(); iter != str->end(); ++iter ) {
-
-                c = *iter;
-                if( c < 0x80 ) {
-                    byteArr[count++] = (unsigned char)c;
+            if( utfLength > Integer::MAX_VALUE ) {
+                throw UTFDataFormatException(
+                    __FILE__, __LINE__,
+                    ( std::string( "OpenwireStringSupport::writeString - Cannot marshall " ) +
+                    "string utf8 encoding longer than: 2^31 bytes, supplied string utf8 encoding was: " +
+                    Integer::toString( (int)utfLength ) + " bytes long." ).c_str() );
+            }
+
+            std::vector<unsigned char> utfBytes( (std::size_t)utfLength );
+            unsigned int utfIndex = 0;
+
+            for( std::size_t i = 0; i < length; i++ ) {
+
+                unsigned int charValue = (unsigned char)str->at( i );
+
+                // Written to allow for expansion to wide character strings at some
+                // point, as it stands now the value can never be > 255 since the
+                // string class returns a single byte char.
+                if( charValue > 0 && charValue <= 127 ) {
+                    utfBytes[utfIndex++] = (unsigned char)charValue;
+                } else if( charValue <= 2047 ) {
+                    utfBytes[utfIndex++] = (unsigned char)(0xc0 | (0x1f & (charValue >> 6)));
+                    utfBytes[utfIndex++] = (unsigned char)(0x80 | (0x3f & charValue));
                 } else {
-                    byteArr[count++] = (unsigned char)( 0xC0 | ( (c >> 6) & 0x1F) );
-                    byteArr[count++] = (unsigned char)( 0x80 | ( (c >> 0) & 0x3F) );
+                    utfBytes[utfIndex++] = (unsigned char)(0xe0 | (0x0f & (charValue >> 12)));
+                    utfBytes[utfIndex++] = (unsigned char)(0x80 | (0x3f & (charValue >> 6)));
+                    utfBytes[utfIndex++] = (unsigned char)(0x80 | (0x3f & charValue));
                 }
             }
 
-            dataOut.write( byteArr );
+            dataOut.writeInt( utfLength );
+            dataOut.write( &utfBytes[0], 0, utfLength );
 
         } else {
-            dataOut.writeShort( (short)-1 );
+            dataOut.writeInt( -1 );
         }
     }
     AMQ_CATCH_RETHROW( decaf::io::IOException )

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.cpp Tue Apr 14 14:32:36 2009
@@ -271,7 +271,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 std::string DataInputStream::readUTF()
-    throw ( io::IOException, io::EOFException ) {
+    throw ( io::IOException, io::EOFException, io::UTFDataFormatException ) {
+
     try {
 
         if( inputStream == NULL ) {
@@ -280,23 +281,83 @@
                 "DataInputStream::readFully - Base input stream is null" );
         }
 
-        std::vector<unsigned char> buffer;
-        unsigned short length = readUnsignedShort();
-        buffer.resize(length + 1);  // Add one for a null charactor.
-
-        std::size_t n = 0;
-        while( n < length ) {
-            int count = inputStream->read( &buffer[n], 0, (length - n) );
-            if( count == -1 ) {
-                throw EOFException(
-                    __FILE__, __LINE__,
-                    "DataInputStream::readUTF - Reached EOF" );
+        unsigned short utfLength = readUnsignedShort();
+        std::vector<unsigned char> buffer( utfLength );
+        std::string result( utfLength, char() );
+
+        this->readFully( &buffer[0], 0, utfLength );
+
+        std::size_t count = 0;
+        std::size_t index = 0;
+        unsigned char a = 0;
+
+        while( count < utfLength ) {
+            if( (unsigned char)( result[index] = (char)buffer[count++] ) < 0x80 ) {
+                index++;
+            } else if( ( ( a = result[index++] ) & 0xE0 ) == 0xC0 ) {
+                if( count >= utfLength ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid UTF-8 encoding found, start of two byte char found at end.");
+                }
+
+                unsigned char b = buffer[count++];
+                if( ( b & 0xC0 ) != 0x80 ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid UTF-8 encoding found, byte two does not start with 0x80." );
+                }
+
+                // 2-byte UTF8 encoding: 110X XXxx 10xx xxxx
+                // Bits set at 'X' means we have encountered a UTF8 encoded value
+                // greater than 255, which is not supported.
+                if( a & 0x1C ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid 2 byte UTF-8 encoding found, "
+                        "This method only supports encoded ASCII values of (0-255)." );
+                }
+
+                result[index++] = (char)( ( ( a & 0x1F ) << 6 ) | ( b & 0x3F ) );
+
+            } else if( ( a & 0xF0 ) == 0xE0 ) {
+
+                if( count + 1 >= utfLength ) {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid UTF-8 encoding found, start of three byte char found at end.");
+                } else {
+                    throw UTFDataFormatException(
+                        __FILE__, __LINE__,
+                        "Invalid 3 byte UTF-8 encoding found, "
+                        "This method only supports encoded ASCII values of (0-255)." );
+                }
+
+                // If we were to support multibyte strings in the future this would be
+                // the remainder of this method decoding logic.
+                //
+                //int b = buffer[count++];
+                //int c = buffer[count++];
+                //if( ( ( b & 0xC0 ) != 0x80 ) || ( ( c & 0xC0 ) != 0x80 ) ) {
+                //    throw UTFDataFormatException(
+                //        __FILE__, __LINE__,
+                //        "Invalid UTF-8 encoding found, byte two does not start with 0x80." );
+                //}
+                //
+                //result[inde++] = (char)( ( ( a & 0x0F ) << 12 ) |
+                //                         ( ( b & 0x3F ) << 6 ) | ( c & 0x3F ) );
+
+            } else {
+                throw UTFDataFormatException(
+                    __FILE__, __LINE__, "Invalid UTF-8 encoding found, aborting.");
             }
-            n += count;
         }
 
-        return (char*)&buffer[0];
+        result.resize( index );
+
+        return result;
     }
+    DECAF_CATCH_RETHROW( UTFDataFormatException )
     DECAF_CATCH_RETHROW( EOFException )
     DECAF_CATCH_RETHROW( IOException )
     DECAF_CATCHALL_THROW( IOException )

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.h?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.h (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataInputStream.h Tue Apr 14 14:32:36 2009
@@ -21,6 +21,7 @@
 #include <decaf/io/FilterInputStream.h>
 #include <decaf/io/IOException.h>
 #include <decaf/io/EOFException.h>
+#include <decaf/io/UTFDataFormatException.h>
 #include <decaf/lang/exceptions/NullPointerException.h>
 #include <decaf/lang/exceptions/IndexOutOfBoundsException.h>
 
@@ -272,9 +273,10 @@
          * @returns string read from stream.
          * @throws IOException
          * @throws EOFException
+         * @throws UTFDataFormatException
          */
         virtual std::string readUTF()
-            throw ( io::IOException, io::EOFException );
+            throw ( io::IOException, io::EOFException, io::UTFDataFormatException );
 
         /**
          * Reads some bytes from an input stream and stores them into the

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.cpp Tue Apr 14 14:32:36 2009
@@ -16,6 +16,7 @@
  */
 
 #include <decaf/io/DataOutputStream.h>
+#include <decaf/io/UTFDataFormatException.h>
 #include <decaf/util/Config.h>
 #include <string.h>
 #include <stdio.h>
@@ -314,16 +315,72 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-void DataOutputStream::writeUTF( const std::string& value ) throw ( IOException ) {
+void DataOutputStream::writeUTF( const std::string& value )
+    throw ( IOException, UTFDataFormatException ) {
+
     try {
 
-        if( value.length() == 0 ) {
-            return;
+        unsigned int utfLength = this->countUTFLength( value );
+
+        if( utfLength > 65535 ) {
+            throw UTFDataFormatException(
+                __FILE__, __LINE__,
+                "Attempted to write a string as UTF-8 whose length is longer "
+                "than the supported 65535 bytes" );
         }
 
-        this->writeUnsignedShort( (unsigned short)value.length() );
-        this->write( (const unsigned char*)value.c_str(), 0, value.length() );
+        std::size_t length = value.length();
+        std::vector<unsigned char> utfBytes( (std::size_t)utfLength );
+        unsigned int utfIndex = 0;
+
+        for( std::size_t i = 0; i < length; i++ ) {
+
+            unsigned int charValue = (unsigned char)value.at( i );
+
+            // Written to allow for expansion to wide character strings at some
+            // point, as it stands now the value can never be > 255 since the
+            // string class returns a single byte char.
+            if( charValue > 0 && charValue <= 127 ) {
+                utfBytes[utfIndex++] = (unsigned char)charValue;
+            } else if( charValue <= 2047 ) {
+                utfBytes[utfIndex++] = (unsigned char)(0xc0 | (0x1f & (charValue >> 6)));
+                utfBytes[utfIndex++] = (unsigned char)(0x80 | (0x3f & charValue));
+            } else {
+                utfBytes[utfIndex++] = (unsigned char)(0xe0 | (0x0f & (charValue >> 12)));
+                utfBytes[utfIndex++] = (unsigned char)(0x80 | (0x3f & (charValue >> 6)));
+                utfBytes[utfIndex++] = (unsigned char)(0x80 | (0x3f & charValue));
+            }
+        }
+
+        this->writeUnsignedShort( (unsigned short)utfLength );
+        this->write( &utfBytes[0], 0, utfIndex );
     }
+    DECAF_CATCH_RETHROW( UTFDataFormatException )
     DECAF_CATCH_RETHROW( IOException )
     DECAF_CATCHALL_THROW( IOException )
 }
+
+////////////////////////////////////////////////////////////////////////////////
+unsigned int DataOutputStream::countUTFLength( const std::string& value ) {
+
+    unsigned int utfCount = 0;
+    std::size_t length = value.length();
+
+    for( std::size_t i = 0; i < length; ++i ) {
+
+        unsigned int charValue = (unsigned char)value.at( i );
+
+        // Written to allow for expansion to wide character strings at some
+        // point, as it stands now the value can never be > 255 since the
+        // string class returns a single byte char.
+        if( charValue > 0 && charValue <= 127 ) {
+            utfCount++;
+        } else if( charValue <= 2047 ) {
+            utfCount += 2;
+        } else {
+            utfCount += 3;
+        }
+    }
+
+    return utfCount;
+}

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.h?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.h (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/DataOutputStream.h Tue Apr 14 14:32:36 2009
@@ -19,6 +19,9 @@
 #define _DECAF_IO_DATAOUTPUTSTREAM_H_
 
 #include <decaf/io/FilterOutputStream.h>
+#include <decaf/io/IOException.h>
+#include <decaf/io/UTFDataFormatException.h>
+#include <string>
 
 namespace decaf{
 namespace io{
@@ -190,20 +193,33 @@
          * characters. Each character is written to the data output stream
          * as if by the writeChar method. If no exception is thrown, the
          * counter written is incremented by the length of value.  The trailing
-         * NULL charactor is written by this method.
+         * NULL character is written by this method.
          * @param value the value to write.
          * @throws IOException
          */
         virtual void writeChars( const std::string& value ) throw ( IOException );
 
         /**
-         * Writes out the string to the underlying output stream as a
-         * unsigned short indicating its length followed by the rest of
-         * the string.
-         * @param value the value to write.
-         * @throws IOException
+         * Writes out the string to the underlying output stream as a modeified UTF-8
+         * encoded sequence of bytes.  The first two bytes written are indicate its
+         * encoded length followed by the rest of the string's characters encoded as
+         * modified UTF-8.  The length represent the encoded length of the data not the
+         * actual length of the string.
+         *
+         * @param value
+         *        the value to write.
+         *
+         * @throws IOException - on a write error
+         * @throws UTFDataFormatException - if encoded size if greater than 65535
          */
-        virtual void writeUTF( const std::string& value ) throw ( IOException );
+        virtual void writeUTF( const std::string& value )
+            throw ( IOException, UTFDataFormatException );
+
+    private:
+
+        // Determine the encoded length of a string when written as modified UTF-8
+        unsigned int countUTFLength( const std::string& value );
+
     };
 
 }}

Added: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/UTFDataFormatException.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/UTFDataFormatException.h?rev=764791&view=auto
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/UTFDataFormatException.h (added)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/UTFDataFormatException.h Tue Apr 14 14:32:36 2009
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DECAF_IO_UTFDATAFORMATEXCEPTION_H_
+#define _DECAF_IO_UTFDATAFORMATEXCEPTION_H_
+
+#include <decaf/io/IOException.h>
+
+namespace decaf {
+namespace io {
+
+    /**
+     * Thrown from classes that attempt to read or write a UTF-8 encoded string
+     * and an encoding error is encountered.
+     *
+     * @since 1.0
+     */
+    class DECAF_API UTFDataFormatException : public decaf::io::IOException {
+    public:
+
+        /**
+         * Default Constructor
+         */
+        UTFDataFormatException() throw() {}
+
+        /**
+         * Copy Constructor
+         * @param ex the exception to copy
+         */
+        UTFDataFormatException( const lang::Exception& ex ) throw()
+        : IOException()
+        {
+            *(lang::Exception*)this = ex;
+        }
+
+        /**
+         * Copy Constructor
+         * @param ex the exception to copy, which is an instance of this type
+         */
+        UTFDataFormatException( const UTFDataFormatException& ex ) throw()
+        : IOException()
+        {
+            *(lang::Exception*)this = ex;
+        }
+
+        /**
+         * Constructor - Initializes the file name and line number where
+         * this message occurred.  Sets the message to report, using an
+         * optional list of arguments to parse into the message
+         * @param file name where exception occurs
+         * @param line number where the exception occurred.
+         * @param cause The exception that was the cause for this one to be thrown.
+         * @param message to report
+         * @param list of primitives that are formatted into the message
+         */
+        UTFDataFormatException( const char* file, const int lineNumber,
+                                const std::exception* cause,
+                                const char* msg, ... ) throw() : IOException( cause )
+        {
+            va_list vargs;
+            va_start( vargs, msg );
+            buildMessage( msg, vargs );
+
+            // Set the first mark for this exception.
+            setMark( file, lineNumber );
+        }
+
+        /**
+         * Constructor
+         * @param cause Pointer to the exception that caused this one to
+         * be thrown, the object is cloned caller retains ownership.
+         */
+        UTFDataFormatException( const std::exception* cause ) throw() : IOException( cause ) {}
+
+        /**
+         * Constructor
+         * @param file name of the file were the exception occurred.
+         * @param lineNumber line where the exception occurred
+         * @param msg the message that was generated
+         */
+        UTFDataFormatException( const char* file, const int lineNumber,
+                                const char* msg, ... ) throw()
+        : IOException()
+        {
+            va_list vargs;
+            va_start( vargs, msg );
+            buildMessage( msg, vargs );
+
+            // Set the first mark for this exception.
+            setMark( file, lineNumber );
+        }
+
+        /**
+         * Clones this exception.  This is useful for cases where you need
+         * to preserve the type of the original exception as well as the message.
+         * All subclasses should override.
+         */
+        virtual UTFDataFormatException* clone() const{
+            return new UTFDataFormatException( *this );
+        }
+
+        virtual ~UTFDataFormatException() throw() {}
+
+    };
+
+}}
+
+#endif /* _DECAF_IO_UTFDATAFORMATEXCEPTION_H_ */

Propchange: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/main/decaf/io/UTFDataFormatException.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.cpp Tue Apr 14 14:32:36 2009
@@ -34,100 +34,194 @@
 using namespace activemq::connector::openwire::utils;
 
 ////////////////////////////////////////////////////////////////////////////////
-void OpenwireStringSupportTest::testHelper( unsigned char* input, int inputLength,
-                                            unsigned char* output, int outputLength,
-                                            bool negative ) {
-    try {
-
-        ByteArrayInputStream bytesIn;
-        ByteArrayOutputStream bytesOut;
-
-        DataInputStream dataIn( &bytesIn );
-        DataOutputStream dataOut( &bytesOut );
-
-        bytesIn.setByteArray( input, inputLength );
-
-        string resultStr = OpenwireStringSupport::readString( dataIn );
-        if( !negative ) {
-            CPPUNIT_ASSERT( resultStr == std::string( (char*)output, outputLength ) );
-
-            OpenwireStringSupport::writeString( dataOut, &resultStr );
-            CPPUNIT_ASSERT( bytesOut.toString() == std::string( (char*)input, inputLength ) );
-        } else {
-            CPPUNIT_ASSERT( 0 );
-        }
+void OpenwireStringSupportTest::writeTestHelper( unsigned char* input, int inputLength,
+                                                 unsigned char* expect, int expectLength ) {
 
-    } catch( Exception& e ) {
-        CPPUNIT_ASSERT( negative );
+    ByteArrayOutputStream baos;
+    DataOutputStream writer( &baos );
+
+    std::string testStr( (char*)input, inputLength );
+    OpenwireStringSupport::writeString( writer, &testStr );
+
+    const unsigned char* result = baos.toByteArray();
+
+    CPPUNIT_ASSERT( result[0] == 0x00 );
+    CPPUNIT_ASSERT( result[1] == 0x00 );
+    CPPUNIT_ASSERT( result[2] == 0x00 );
+    CPPUNIT_ASSERT( result[3] == (unsigned char)( expectLength ) );
+
+    for( std::size_t i = 4; i < baos.size(); ++i ) {
+        CPPUNIT_ASSERT( result[i] == expect[i-4] );
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-void OpenwireStringSupportTest::test()
-{
-    ByteArrayInputStream bytesIn;
-    ByteArrayOutputStream bytesOut;
+void OpenwireStringSupportTest::testWriteString() {
 
-    DataInputStream dataIn( &bytesIn );
-    DataOutputStream dataOut( &bytesOut );
+    // Test data with 1-byte UTF8 encoding.
+    {
+        unsigned char input[] = {0x00, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+        unsigned char expect[] = {0xC0, 0x80, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
 
-    string testStr = "This is a test string for Openwire";
+        writeTestHelper( input, sizeof(input)/sizeof(unsigned char),
+                         expect, sizeof(expect)/sizeof(unsigned char) );
+    }
 
-    OpenwireStringSupport::writeString( dataOut, &testStr );
+    // Test data with 2-byte UT8 encoding.
+    {
+        unsigned char input[] = {0x00, 0xC2, 0xA9, 0xC3, 0xA6 };
+        unsigned char expect[] = {0xC0, 0x80, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC2, 0xA6 };
+        writeTestHelper( input, sizeof(input)/sizeof(unsigned char),
+                         expect, sizeof(expect)/sizeof(unsigned char)  );
+    }
 
-    // Move the output back to the input.
-    bytesIn.setByteArray( bytesOut.toByteArray(), bytesOut.size() );
+    // Test data with 1-byte and 2-byte encoding with embedded NULL's.
+    {
+        unsigned char input[] = {0x00, 0x04, 0xC2, 0xA9, 0xC3, 0x00, 0xA6 };
+        unsigned char expect[] = {0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
 
-    string resultStr = OpenwireStringSupport::readString( dataIn );
+        writeTestHelper( input, sizeof(input)/sizeof(unsigned char),
+                         expect, sizeof(expect)/sizeof(unsigned char) );
+    }
 
-    CPPUNIT_ASSERT( testStr == resultStr );
+    // Test data with 1-byte and 2-byte encoding with embedded NULL's.
+    {
+        ByteArrayOutputStream baos;
+        ByteArrayInputStream bais;
+        DataOutputStream writer( &baos );
+        DataInputStream dataIn( &bais );
+
+        OpenwireStringSupport::writeString( writer, NULL );
+
+        bais.setByteArray( baos.toByteArray(), baos.size() );
+
+        CPPUNIT_ASSERT( dataIn.readInt() == -1 );
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void OpenwireStringSupportTest::readTestHelper( unsigned char* input, int inputLength,
+                                                unsigned char* expect, int expectLength ) {
+
+    ByteArrayInputStream myStream( input, inputLength );
+    DataInputStream reader( &myStream );
+
+    std::string result = reader.readUTF();
+
+    for( std::size_t i; i < result.length(); ++i ) {
+        CPPUNIT_ASSERT( (unsigned char)result[i] == expect[i] );
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void OpenwireStringSupportTest::testReadString() {
 
     // Test data with 1-byte UTF8 encoding.
     {
-        unsigned char input[] = {0x00, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
-        unsigned char output[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+        unsigned char expect[] = {0x00, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x0E ,0xC0, 0x80, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
 
-        testHelper( input, sizeof(input)/sizeof(unsigned char),
-                    output, sizeof(output)/sizeof(unsigned char), false );
+        readTestHelper( input, sizeof(input)/sizeof(unsigned char),
+                        expect, sizeof(expect)/sizeof(unsigned char) );
     }
 
     // Test data with 2-byte UT8 encoding.
     {
-        unsigned char input[] = {0x00, 0x04, 0xC2, 0xA9, 0xC3, 0xA6};
-        unsigned char output[] = {0xA9, 0xE6};
-        testHelper( input, sizeof(input)/sizeof(unsigned char),
-                    output, sizeof(output)/sizeof(unsigned char), false );
+        unsigned char expect[] = {0x00, 0xC2, 0xA9, 0xC3, 0xA6 };
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x0A, 0xC0, 0x80, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC2, 0xA6 };
+        readTestHelper( input, sizeof(input)/sizeof(unsigned char),
+                        expect, sizeof(expect)/sizeof(unsigned char)  );
     }
 
-    // Test data with value greater than 255 in 2-byte encoding.
-    // Expect : IO Exception
+    // Test data with 1-byte and 2-byte encoding with embedded NULL's.
     {
-        unsigned char input[] = {0x00, 0x04, 0xC8, 0xA9, 0xC3, 0xA6};
-        testHelper( input, sizeof(input)/sizeof(unsigned char), NULL, 0, true );
+        unsigned char expect[] = {0x00, 0x04, 0xC2, 0xA9, 0xC3, 0x00, 0xA6 };
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        readTestHelper( input, sizeof(input)/sizeof(unsigned char),
+                        expect, sizeof(expect)/sizeof(unsigned char) );
     }
 
-    // Test data with value greater than 255 in 3-byte encoding.
-    // Expect : IO Exception
+    // Test with bad UTF-8 encoding, missing 2nd byte of two byte value
     {
-        unsigned char input[] = {0x00, 0x05, 0xE8, 0xA8, 0xA9, 0xC3, 0xA6};
-        testHelper( input, sizeof(input)/sizeof(unsigned char), NULL, 0, true );
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xC2, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a IOException",
+            OpenwireStringSupport::readString( reader ),
+            IOException );
     }
 
-    // Test data with 1-byte encoding with embedded NULL's.
+    // Test with bad UTF-8 encoding, encoded value greater than 255
     {
-        unsigned char input[] = {0x00, 0x0D, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x00, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00};
-        unsigned char output[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x00, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00};
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xC2, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
 
-        testHelper( input, sizeof(input)/sizeof(unsigned char),
-                    output, sizeof(output)/sizeof(unsigned char), false );
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a IOException",
+            OpenwireStringSupport::readString( reader ),
+            IOException );
     }
 
-    // Test data with 1-byte and 2-byte encoding with embedded NULL's.
+    // Test data with value greater than 255 in 2-byte encoding.
     {
-        unsigned char input[] = {0x00, 0x11, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x00, 0xC2, 0xA9, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0xC3, 0xA6};
-        unsigned char output[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x00, 0xA9, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0xE6};
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x04, 0xC8, 0xA9, 0xC3, 0xA6};
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a IOException",
+            OpenwireStringSupport::readString( reader ),
+            IOException );
+    }
 
-        testHelper( input, sizeof(input)/sizeof(unsigned char),
-                    output, sizeof(output)/sizeof(unsigned char), false );
+    // Test data with value greater than 255 in 3-byte encoding.
+    {
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x05, 0xE8, 0xA8, 0xA9, 0xC3, 0xA6};
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a IOException",
+            OpenwireStringSupport::readString( reader ),
+            IOException );
+    }
+
+    // Test with three byte encode that's missing a last byte.
+    {
+        unsigned char input[] = { 0x00, 0x00, 0x00, 0x02, 0xE8, 0xA8};
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a IOException",
+            OpenwireStringSupport::readString( reader ),
+            IOException );
     }
 }
+
+////////////////////////////////////////////////////////////////////////////////
+void OpenwireStringSupportTest::test() {
+
+    ByteArrayInputStream bytesIn;
+    ByteArrayOutputStream bytesOut;
+
+    DataInputStream dataIn( &bytesIn );
+    DataOutputStream dataOut( &bytesOut );
+
+    string testStr = "This is a test string for Openwire";
+
+    OpenwireStringSupport::writeString( dataOut, &testStr );
+
+    // Move the output back to the input.
+    bytesIn.setByteArray( bytesOut.toByteArray(), bytesOut.size() );
+
+    string resultStr = OpenwireStringSupport::readString( dataIn );
+
+    CPPUNIT_ASSERT( testStr == resultStr );
+}

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.h?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.h (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/activemq/connector/openwire/utils/OpenwireStringSupportTest.h Tue Apr 14 14:32:36 2009
@@ -30,6 +30,8 @@
 
         CPPUNIT_TEST_SUITE( OpenwireStringSupportTest );
         CPPUNIT_TEST( test );
+        CPPUNIT_TEST( testWriteString );
+        CPPUNIT_TEST( testReadString );
         CPPUNIT_TEST_SUITE_END();
 
     public:
@@ -39,9 +41,16 @@
 
         void test();
 
-        // Support Method
-        void testHelper( unsigned char* input, int inputLength,
-                         unsigned char* output, int outputLength, bool negative );
+        void testWriteString();
+        void testReadString();
+
+    private:
+
+        void readTestHelper( unsigned char* input, int inputLength,
+                             unsigned char* expect, int expectLength );
+
+        void writeTestHelper( unsigned char* input, int inputLength,
+                              unsigned char* expect, int expectLength );
 
     };
 

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.cpp Tue Apr 14 14:32:36 2009
@@ -516,3 +516,110 @@
         CPPUNIT_ASSERT( true );
     }
 }
+
+////////////////////////////////////////////////////////////////////////////////
+void DataInputStreamTest::testHelper( unsigned char* input, int inputLength,
+                                      unsigned char* expect, int expectLength ) {
+
+    ByteArrayInputStream myStream( input, inputLength );
+    DataInputStream reader( &myStream );
+
+    std::string result = reader.readUTF();
+
+    for( std::size_t i; i < result.length(); ++i ) {
+        CPPUNIT_ASSERT( (unsigned char)result[i] == expect[i] );
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DataInputStreamTest::testUTFDecoding() {
+
+    // Test data with 1-byte UTF8 encoding.
+    {
+        unsigned char expect[] = {0x00, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+        unsigned char input[] = { 0x00, 0x0E ,0xC0, 0x80, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+
+        testHelper( input, sizeof(input)/sizeof(unsigned char),
+                    expect, sizeof(expect)/sizeof(unsigned char) );
+    }
+
+    // Test data with 2-byte UT8 encoding.
+    {
+        unsigned char expect[] = {0x00, 0xC2, 0xA9, 0xC3, 0xA6 };
+        unsigned char input[] = { 0x00, 0x0A, 0xC0, 0x80, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC2, 0xA6 };
+        testHelper( input, sizeof(input)/sizeof(unsigned char),
+                    expect, sizeof(expect)/sizeof(unsigned char)  );
+    }
+
+    // Test data with 1-byte and 2-byte encoding with embedded NULL's.
+    {
+        unsigned char expect[] = {0x00, 0x04, 0xC2, 0xA9, 0xC3, 0x00, 0xA6 };
+        unsigned char input[] = { 0x00, 0x0D, 0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        testHelper( input, sizeof(input)/sizeof(unsigned char),
+                    expect, sizeof(expect)/sizeof(unsigned char) );
+    }
+
+    // Test with bad UTF-8 encoding, missing 2nd byte of two byte value
+    {
+        unsigned char input[] = { 0x00, 0x0D, 0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xC2, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a UTFDataFormatException",
+            reader.readUTF(),
+            UTFDataFormatException );
+    }
+
+    // Test with bad UTF-8 encoding, encoded value greater than 255
+    {
+        unsigned char input[] = { 0x00, 0x0D, 0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xC2, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a UTFDataFormatException",
+            reader.readUTF(),
+            UTFDataFormatException );
+    }
+
+    // Test data with value greater than 255 in 2-byte encoding.
+    {
+        unsigned char input[] = {0x00, 0x04, 0xC8, 0xA9, 0xC3, 0xA6};
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a UTFDataFormatException",
+            reader.readUTF(),
+            UTFDataFormatException );
+    }
+
+    // Test data with value greater than 255 in 3-byte encoding.
+    {
+        unsigned char input[] = {0x00, 0x05, 0xE8, 0xA8, 0xA9, 0xC3, 0xA6};
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a UTFDataFormatException",
+            reader.readUTF(),
+            UTFDataFormatException );
+    }
+
+    // Test with three byte encode that's missing a last byte.
+    {
+        unsigned char input[] = {0x00, 0x02, 0xE8, 0xA8};
+        ByteArrayInputStream myStream( input, sizeof(input)/sizeof(unsigned char) );
+        DataInputStream reader( &myStream );
+
+        CPPUNIT_ASSERT_THROW_MESSAGE(
+            "Should throw a UTFDataFormatException",
+            reader.readUTF(),
+            UTFDataFormatException );
+    }
+
+}

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.h?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.h (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataInputStreamTest.h Tue Apr 14 14:32:36 2009
@@ -38,6 +38,7 @@
         CPPUNIT_TEST( test );
         CPPUNIT_TEST( testString );
         CPPUNIT_TEST( testUTF );
+        CPPUNIT_TEST( testUTFDecoding );
         CPPUNIT_TEST( testConstructor );
         CPPUNIT_TEST( testRead1 );
         CPPUNIT_TEST( testRead2 );
@@ -89,6 +90,7 @@
         void test();
         void testString();
         void testUTF();
+        void testUTFDecoding();
         void testConstructor();
         void testRead1();
         void testRead2();
@@ -111,6 +113,9 @@
 
     private:
 
+        void testHelper( unsigned char* input, int inputLength,
+                         unsigned char* expect, int expectLength );
+
         void openDataInputStream() {
             delete bais;
             delete is;

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.cpp?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.cpp (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.cpp Tue Apr 14 14:32:36 2009
@@ -251,6 +251,95 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+void DataOutputStreamTest::testWriteUTFStringLength() {
+
+    // String of length 65536 of Null Characters.
+    // Expect: UTFDataFormatException.
+    std::string testStr( 65536, char('a') );
+    CPPUNIT_ASSERT_THROW_MESSAGE(
+        "Should throw a UTFDataFormatException",
+        os->writeUTF( testStr ),
+        UTFDataFormatException );
+
+    baos->reset();
+    // String of length 65535 of non Null Characters since Null encodes as UTF-8.
+    // Expect: Success.
+    testStr.resize( 65535 );
+    CPPUNIT_ASSERT_NO_THROW_MESSAGE(
+        "String of 65535 Non-Null chars should not throw.",
+        os->writeUTF( testStr ) );
+
+    baos->reset();
+    // Set one of the 65535 bytes to a value that will result in a 2 byte UTF8 encoded sequence.
+    // This will cause the string of length 65535 to have a utf length of 65536.
+    // Expect: UTFDataFormatException.
+    testStr[0] = char( 255 );
+    CPPUNIT_ASSERT_THROW_MESSAGE(
+        "Should throw an UTFDataFormatException",
+        os->writeUTF( testStr ),
+        UTFDataFormatException );
+
+    // Test that a zero length string write the zero size marker.
+    ByteArrayInputStream byteIn;
+    ByteArrayOutputStream byteOut;
+    DataInputStream dataIn( &byteIn );
+    DataOutputStream dataOut( &byteOut );
+    dataOut.writeUTF( "" );
+    CPPUNIT_ASSERT( dataOut.size() == 2 );
+    byteIn.setByteArray( byteOut.toByteArray(), byteOut.size() );
+    CPPUNIT_ASSERT( dataIn.readUnsignedShort() == 0 );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DataOutputStreamTest::testHelper( unsigned char* input, int inputLength,
+                                       unsigned char* expect, int expectLength ) {
+
+    std::string testStr( (char*)input, inputLength );
+    os->writeUTF( testStr );
+
+    const unsigned char* result = baos->toByteArray();
+
+    CPPUNIT_ASSERT( result[0] == 0x00 );
+    CPPUNIT_ASSERT( result[1] == (unsigned char)( expectLength ) );
+
+    for( std::size_t i = 2; i < baos->size(); ++i ) {
+        CPPUNIT_ASSERT( result[i] == expect[i-2] );
+    }
+
+    baos->reset();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DataOutputStreamTest::testWriteUTFEncoding() {
+
+    // Test data with 1-byte UTF8 encoding.
+    {
+        unsigned char input[] = {0x00, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+        unsigned char expect[] = {0xC0, 0x80, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
+
+        testHelper( input, sizeof(input)/sizeof(unsigned char),
+                    expect, sizeof(expect)/sizeof(unsigned char) );
+    }
+
+    // Test data with 2-byte UT8 encoding.
+    {
+        unsigned char input[] = {0x00, 0xC2, 0xA9, 0xC3, 0xA6 };
+        unsigned char expect[] = {0xC0, 0x80, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC2, 0xA6 };
+        testHelper( input, sizeof(input)/sizeof(unsigned char),
+                    expect, sizeof(expect)/sizeof(unsigned char)  );
+    }
+
+    // Test data with 1-byte and 2-byte encoding with embedded NULL's.
+    {
+        unsigned char input[] = {0x00, 0x04, 0xC2, 0xA9, 0xC3, 0x00, 0xA6 };
+        unsigned char expect[] = {0xC0, 0x80, 0x04, 0xC3, 0x82, 0xC2, 0xA9, 0xC3, 0x83, 0xC0, 0x80, 0xC2, 0xA6 };
+
+        testHelper( input, sizeof(input)/sizeof(unsigned char),
+                    expect, sizeof(expect)/sizeof(unsigned char) );
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
 void DataOutputStreamTest::test(){
 
     unsigned char byteVal = (unsigned char)'T';

Modified: activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.h?rev=764791&r1=764790&r2=764791&view=diff
==============================================================================
--- activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.h (original)
+++ activemq/activemq-cpp/branches/activemq-cpp-2.x/src/test/decaf/io/DataOutputStreamTest.h Tue Apr 14 14:32:36 2009
@@ -49,6 +49,8 @@
         CPPUNIT_TEST( testWriteLong );
         CPPUNIT_TEST( testWriteShort );
         CPPUNIT_TEST( testWriteUTF );
+        CPPUNIT_TEST( testWriteUTFStringLength );
+        CPPUNIT_TEST( testWriteUTFEncoding );
         CPPUNIT_TEST_SUITE_END();
 
         ByteArrayOutputStream* baos;
@@ -94,9 +96,14 @@
         void testWriteLong();
         void testWriteShort();
         void testWriteUTF();
+        void testWriteUTFStringLength();
+        void testWriteUTFEncoding();
 
     private:
 
+        void testHelper( unsigned char* input, int inputLength,
+                         unsigned char* expect, int expectLength );
+
         void openDataInputStream() {
             bais = new ByteArrayInputStream( baos->toByteArray(), baos->size() );
             is = new DataInputStream( bais );