/* * 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. */ #include "MarshallingSupport.h" #include #include #include #include using namespace activemq; using namespace activemq::util; using namespace decaf; using namespace decaf::io; using namespace decaf::lang; using namespace std; //////////////////////////////////////////////////////////////////////////////// MarshallingSupport::MarshallingSupport() { } //////////////////////////////////////////////////////////////////////////////// MarshallingSupport::~MarshallingSupport() { } //////////////////////////////////////////////////////////////////////////////// void MarshallingSupport::writeString(decaf::io::DataOutputStream& dataOut, const std::string& value) { try { if ((int)value.length() <= Short::MAX_VALUE / 4) { dataOut.write(PrimitiveValueNode::STRING_TYPE); MarshallingSupport::writeString16(dataOut, value); } else { dataOut.write(PrimitiveValueNode::BIG_STRING_TYPE); MarshallingSupport::writeString32(dataOut, value); } } AMQ_CATCH_RETHROW(decaf::io::IOException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::IOException) AMQ_CATCHALL_THROW(decaf::io::IOException) } //////////////////////////////////////////////////////////////////////////////// void MarshallingSupport::writeString16(decaf::io::DataOutputStream& dataOut, const std::string& value) { try { int strSize = (int) value.length(); if (strSize > Short::MAX_VALUE) { throw IOException(__FILE__, __LINE__, "String size exceeds Short::MAX_VALUE and cannot be sent via Openwire."); } dataOut.writeShort((short) strSize); if (strSize > 0) { dataOut.write((unsigned char*) value.c_str(), strSize, 0, strSize); } } AMQ_CATCH_RETHROW(decaf::io::IOException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::IOException) AMQ_CATCHALL_THROW(decaf::io::IOException) } //////////////////////////////////////////////////////////////////////////////// void MarshallingSupport::writeString32(decaf::io::DataOutputStream& dataOut, const std::string& value) { try { int strSize = (int) value.length(); if (strSize > Integer::MAX_VALUE) { throw IOException(__FILE__, __LINE__, "String size exceeds Integer::MAX_VALUE and cannot be sent via Openwire."); } dataOut.writeInt(strSize); if (strSize > 0) { dataOut.write((unsigned char*) value.c_str(), strSize, 0, strSize); } } AMQ_CATCH_RETHROW(decaf::io::IOException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::IOException) AMQ_CATCHALL_THROW(decaf::io::IOException) } //////////////////////////////////////////////////////////////////////////////// std::string MarshallingSupport::readString16(decaf::io::DataInputStream& dataIn) { try { int utfLength = dataIn.readShort(); if (utfLength > 0) { std::vector buffer(utfLength); dataIn.readFully(&buffer[0], utfLength); return std::string((char*) (&buffer[0]), utfLength); } return ""; } AMQ_CATCH_RETHROW(decaf::io::IOException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::IOException) AMQ_CATCHALL_THROW(decaf::io::IOException) } //////////////////////////////////////////////////////////////////////////////// std::string MarshallingSupport::readString32(decaf::io::DataInputStream& dataIn) { try { int utfLength = dataIn.readInt(); if (utfLength > 0) { std::vector buffer(utfLength); dataIn.readFully(&buffer[0], utfLength); return std::string((char*) (&buffer[0]), utfLength); } return ""; } AMQ_CATCH_RETHROW(decaf::io::IOException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::IOException) AMQ_CATCHALL_THROW(decaf::io::IOException) } //////////////////////////////////////////////////////////////////////////////// std::string MarshallingSupport::asciiToModifiedUtf8(const std::string& asciiString) { try { if (asciiString.length() > 0) { int utfLength = 0; std::size_t length = asciiString.length(); for (std::size_t i = 0; i < length; ++i) { unsigned int charValue = (unsigned char) asciiString.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) { utfLength++; } else if (charValue <= 2047) { utfLength += 2; } else { utfLength += 3; } } if (utfLength > Integer::MAX_VALUE) { throw UTFDataFormatException(__FILE__, __LINE__, (std::string("MarshallingSupport::asciiToModifiedUtf8 - Cannot marshall ") + "string utf8 encoding longer than: 2^31 bytes, supplied string utf8 encoding was: " + Integer::toString((int) utfLength) + " bytes long.").c_str()); } std::string utfBytes((std::size_t) utfLength, '\0'); unsigned int utfIndex = 0; for (std::size_t i = 0; i < length; i++) { unsigned int charValue = (unsigned char) asciiString.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++] = (char) charValue; } else if (charValue <= 2047) { utfBytes[utfIndex++] = (char) (0xc0 | (0x1f & (charValue >> 6))); utfBytes[utfIndex++] = (char) (0x80 | (0x3f & charValue)); } else { utfBytes[utfIndex++] = (char) (0xe0 | (0x0f & (charValue >> 12))); utfBytes[utfIndex++] = (char) (0x80 | (0x3f & (charValue >> 6))); utfBytes[utfIndex++] = (char) (0x80 | (0x3f & charValue)); } } return utfBytes; } else { return ""; } } AMQ_CATCH_RETHROW(decaf::io::UTFDataFormatException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::UTFDataFormatException) AMQ_CATCHALL_THROW(decaf::io::UTFDataFormatException) } //////////////////////////////////////////////////////////////////////////////// std::string MarshallingSupport::modifiedUtf8ToAscii(const std::string modifiedUtf8String) { try { std::size_t utfLength = modifiedUtf8String.length(); if (utfLength == 0) { return ""; } std::vector result(utfLength); std::size_t count = 0; std::size_t index = 0; unsigned char a = 0; while (count < utfLength) { if ((result[index] = modifiedUtf8String[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 = modifiedUtf8String[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++] = (unsigned 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 = modifiedUtf8String[count++]; //int c = modifiedUtf8String[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++] = ( ( a & 0x0F ) << 12 ) | // ( ( b & 0x3F ) << 6 ) | ( c & 0x3F ); } else { throw UTFDataFormatException(__FILE__, __LINE__, "Invalid UTF-8 encoding found, aborting."); } } return std::string((char*) (&result[0]), index); } AMQ_CATCH_RETHROW(decaf::io::UTFDataFormatException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, decaf::io::UTFDataFormatException) AMQ_CATCHALL_THROW(decaf::io::UTFDataFormatException) }