blob: 40318cc319c3f2628e1fe0fcdd9fc8057f49b09e [file] [log] [blame]
/*
* 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 <activemq/util/PrimitiveValueNode.h>
#include <activemq/exceptions/ExceptionDefines.h>
#include <decaf/lang/Short.h>
#include <decaf/lang/Integer.h>
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<unsigned char> 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<unsigned char> 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<unsigned char> 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)
}