| /** |
| * 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 "PrimitiveTypesMarshaller.h" |
| |
| #include <decaf/io/ByteArrayInputStream.h> |
| #include <decaf/io/ByteArrayOutputStream.h> |
| #include <decaf/io/DataInputStream.h> |
| #include <decaf/io/DataOutputStream.h> |
| #include <activemq/exceptions/ActiveMQException.h> |
| #include <decaf/lang/Short.h> |
| |
| #include <memory> |
| |
| using namespace std; |
| using namespace activemq; |
| using namespace activemq::util; |
| using namespace activemq::exceptions; |
| using namespace activemq::wireformat; |
| using namespace activemq::wireformat::openwire; |
| using namespace activemq::wireformat::openwire::marshal; |
| using namespace decaf; |
| using namespace decaf::io; |
| using namespace decaf::lang; |
| using namespace decaf::util; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshal(const PrimitiveMap* map, std::vector<unsigned char>& buffer) { |
| |
| try { |
| |
| ByteArrayOutputStream bytesOut; |
| DataOutputStream dataOut(&bytesOut); |
| |
| if (map == NULL) { |
| dataOut.writeInt(-1); |
| } else { |
| PrimitiveTypesMarshaller::marshalPrimitiveMap(dataOut, *map); |
| } |
| |
| if (bytesOut.size() > 0) { |
| std::pair<unsigned char*, int> array = bytesOut.toByteArray(); |
| buffer.insert(buffer.begin(), array.first, array.first + array.second); |
| delete[] array.first; |
| } |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::unmarshal(PrimitiveMap* map, const std::vector<unsigned char>& buffer) { |
| |
| try { |
| |
| if (map == NULL || buffer.empty()) { |
| return; |
| } |
| |
| // Clear old data |
| map->clear(); |
| |
| ByteArrayInputStream bytesIn(buffer); |
| DataInputStream dataIn(&bytesIn); |
| PrimitiveTypesMarshaller::unmarshalPrimitiveMap(dataIn, *map); |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshal(const PrimitiveList* list, std::vector<unsigned char>& buffer) { |
| |
| try { |
| |
| ByteArrayOutputStream bytesOut; |
| DataOutputStream dataOut(&bytesOut); |
| |
| if (list == NULL) { |
| dataOut.writeInt(-1); |
| } else { |
| PrimitiveTypesMarshaller::marshalPrimitiveList(dataOut, *list); |
| } |
| |
| if (bytesOut.size() > 0) { |
| std::pair<unsigned char*, int> array = bytesOut.toByteArray(); |
| buffer.insert(buffer.begin(), array.first, array.first + array.second); |
| delete[] array.first; |
| } |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::unmarshal(PrimitiveList* list, const std::vector<unsigned char>& buffer) { |
| |
| try { |
| |
| if (list == NULL || buffer.empty()) { |
| return; |
| } |
| |
| // Clear old data |
| list->clear(); |
| |
| ByteArrayInputStream bytesIn(buffer); |
| DataInputStream dataIn(&bytesIn); |
| PrimitiveTypesMarshaller::unmarshalPrimitiveList(dataIn, *list); |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshalMap(const PrimitiveMap* map, DataOutputStream& dataOut) { |
| |
| try { |
| |
| if (map == NULL) { |
| dataOut.writeInt(-1); |
| } else { |
| PrimitiveTypesMarshaller::marshalPrimitiveMap(dataOut, *map); |
| } |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| PrimitiveMap* PrimitiveTypesMarshaller::unmarshalMap(DataInputStream& dataIn) { |
| |
| try { |
| |
| std::auto_ptr<PrimitiveMap> map(new PrimitiveMap()); |
| PrimitiveTypesMarshaller::unmarshalPrimitiveMap(dataIn, *(map.get())); |
| return map.release(); |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshalList(const PrimitiveList* list, DataOutputStream& dataOut) { |
| |
| try { |
| |
| if (list == NULL) { |
| dataOut.writeInt(-1); |
| } else { |
| PrimitiveTypesMarshaller::marshalPrimitiveList(dataOut, *list); |
| } |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| PrimitiveList* PrimitiveTypesMarshaller::unmarshalList(DataInputStream& dataIn) { |
| |
| try { |
| |
| std::auto_ptr<PrimitiveList> list(new PrimitiveList()); |
| PrimitiveTypesMarshaller::unmarshalPrimitiveList(dataIn, *(list.get())); |
| return list.release(); |
| } |
| AMQ_CATCH_RETHROW(decaf::lang::Exception) |
| AMQ_CATCHALL_THROW(decaf::lang::Exception) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshalPrimitiveMap(decaf::io::DataOutputStream& dataOut, const decaf::util::Map<std::string, PrimitiveValueNode>& map) { |
| |
| try { |
| |
| dataOut.writeInt((int) map.size()); |
| |
| Pointer<Iterator<std::string> > keys(map.keySet().iterator()); |
| while (keys->hasNext()) { |
| std::string key = keys->next(); |
| dataOut.writeUTF(key); |
| PrimitiveValueNode value = map.get(key); |
| marshalPrimitive(dataOut, value); |
| } |
| } |
| AMQ_CATCH_RETHROW(io::IOException) |
| AMQ_CATCH_EXCEPTION_CONVERT(Exception, io::IOException) |
| AMQ_CATCHALL_THROW(io::IOException) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshalPrimitiveList(decaf::io::DataOutputStream& dataOut, const decaf::util::List<PrimitiveValueNode>& list) { |
| |
| try { |
| |
| dataOut.writeInt((int) list.size()); |
| |
| for (int ix = 0; ix < list.size(); ++ix) { |
| marshalPrimitive(dataOut, list.get(ix)); |
| } |
| } |
| AMQ_CATCH_RETHROW(io::IOException) |
| AMQ_CATCH_EXCEPTION_CONVERT(Exception, io::IOException) |
| AMQ_CATCHALL_THROW(io::IOException) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::marshalPrimitive(io::DataOutputStream& dataOut, const activemq::util::PrimitiveValueNode& value) { |
| |
| try { |
| |
| if (value.getType() == PrimitiveValueNode::BOOLEAN_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::BOOLEAN_TYPE); |
| dataOut.writeBoolean(value.getBool()); |
| |
| } else if (value.getType() == PrimitiveValueNode::BYTE_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::BYTE_TYPE); |
| dataOut.writeByte(value.getByte()); |
| |
| } else if (value.getType() == PrimitiveValueNode::CHAR_TYPE) { |
| |
| // Java Char is two bytes, for now we can only send ASCII |
| dataOut.writeByte(PrimitiveValueNode::CHAR_TYPE); |
| dataOut.writeChar(0); |
| dataOut.writeChar(value.getChar()); |
| |
| } else if (value.getType() == PrimitiveValueNode::SHORT_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::SHORT_TYPE); |
| dataOut.writeShort(value.getShort()); |
| |
| } else if (value.getType() == PrimitiveValueNode::INTEGER_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::INTEGER_TYPE); |
| dataOut.writeInt(value.getInt()); |
| |
| } else if (value.getType() == PrimitiveValueNode::LONG_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::LONG_TYPE); |
| dataOut.writeLong(value.getLong()); |
| |
| } else if (value.getType() == PrimitiveValueNode::FLOAT_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::FLOAT_TYPE); |
| dataOut.writeFloat(value.getFloat()); |
| |
| } else if (value.getType() == PrimitiveValueNode::DOUBLE_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::DOUBLE_TYPE); |
| dataOut.writeDouble(value.getDouble()); |
| |
| } else if (value.getType() == PrimitiveValueNode::BYTE_ARRAY_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::BYTE_ARRAY_TYPE); |
| |
| std::vector<unsigned char> data = value.getByteArray(); |
| |
| dataOut.writeInt((int) data.size()); |
| if (!data.empty()) { |
| dataOut.write(&data[0], (int) data.size()); |
| } |
| |
| } else if (value.getType() == PrimitiveValueNode::STRING_TYPE) { |
| |
| std::string data = value.getString(); |
| int size = (int) data.size(); |
| |
| // is the string big?? |
| if (size == 0) { |
| dataOut.writeByte(PrimitiveValueNode::STRING_TYPE); |
| dataOut.writeShort((short) size); |
| } else if ((int) data.size() > Short::MAX_VALUE / 4) { |
| dataOut.writeByte(PrimitiveValueNode::BIG_STRING_TYPE); |
| dataOut.writeInt(size); |
| dataOut.write((unsigned char*) data.c_str(), size, 0, size); |
| } else { |
| dataOut.writeByte(PrimitiveValueNode::STRING_TYPE); |
| dataOut.writeShort((short) size); |
| dataOut.write((unsigned char*) data.c_str(), size, 0, size); |
| } |
| |
| } else if (value.getType() == PrimitiveValueNode::LIST_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::LIST_TYPE); |
| marshalPrimitiveList(dataOut, value.getList()); |
| |
| } else if (value.getType() == PrimitiveValueNode::MAP_TYPE) { |
| |
| dataOut.writeByte(PrimitiveValueNode::MAP_TYPE); |
| marshalPrimitiveMap(dataOut, value.getMap()); |
| |
| } else { |
| throw IOException( |
| __FILE__, |
| __LINE__, "Object is not a primitive: "); |
| } |
| } |
| AMQ_CATCH_RETHROW(io::IOException) |
| AMQ_CATCH_EXCEPTION_CONVERT(Exception, io::IOException) |
| AMQ_CATCHALL_THROW(io::IOException) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::unmarshalPrimitiveMap(decaf::io::DataInputStream& dataIn, PrimitiveMap& map) { |
| |
| try { |
| |
| int size = dataIn.readInt(); |
| |
| if (size > 0) { |
| for (int i = 0; i < size; i++) { |
| std::string key = dataIn.readUTF(); |
| map.put(key, unmarshalPrimitive(dataIn)); |
| } |
| } |
| } |
| AMQ_CATCH_RETHROW(io::IOException) |
| AMQ_CATCH_EXCEPTION_CONVERT(Exception, io::IOException) |
| AMQ_CATCHALL_THROW(io::IOException) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| void PrimitiveTypesMarshaller::unmarshalPrimitiveList(decaf::io::DataInputStream& dataIn, decaf::util::LinkedList<PrimitiveValueNode>& list) { |
| |
| try { |
| |
| int size = dataIn.readInt(); |
| while (size-- > 0) { |
| list.add(unmarshalPrimitive(dataIn)); |
| } |
| } |
| AMQ_CATCH_RETHROW(io::IOException) |
| AMQ_CATCH_EXCEPTION_CONVERT(Exception, io::IOException) |
| AMQ_CATCHALL_THROW(io::IOException) |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| PrimitiveValueNode PrimitiveTypesMarshaller::unmarshalPrimitive(io::DataInputStream& dataIn) { |
| |
| try { |
| |
| unsigned char type = dataIn.readByte(); |
| PrimitiveValueNode value; |
| |
| switch (type) { |
| |
| case PrimitiveValueNode::NULL_TYPE: |
| value.clear(); |
| break; |
| case PrimitiveValueNode::BYTE_TYPE: |
| value.setByte(dataIn.readByte()); |
| break; |
| case PrimitiveValueNode::BOOLEAN_TYPE: |
| value.setBool(dataIn.readBoolean()); |
| break; |
| case PrimitiveValueNode::CHAR_TYPE: |
| // Java Char is two bytes, for now we can read ASCII, throw away byte 1 |
| dataIn.readByte(); |
| value.setChar(dataIn.readChar()); |
| break; |
| case PrimitiveValueNode::SHORT_TYPE: |
| value.setShort(dataIn.readShort()); |
| break; |
| case PrimitiveValueNode::INTEGER_TYPE: |
| value.setInt(dataIn.readInt()); |
| break; |
| case PrimitiveValueNode::LONG_TYPE: |
| value.setLong(dataIn.readLong()); |
| break; |
| case PrimitiveValueNode::FLOAT_TYPE: |
| value.setFloat(dataIn.readFloat()); |
| break; |
| case PrimitiveValueNode::DOUBLE_TYPE: |
| value.setDouble(dataIn.readDouble()); |
| break; |
| case PrimitiveValueNode::BYTE_ARRAY_TYPE: { |
| int size = dataIn.readInt(); |
| std::vector<unsigned char> data; |
| if (size > 0) { |
| data.resize(size); |
| dataIn.readFully(&data[0], size); |
| } |
| value.setByteArray(data); |
| break; |
| } |
| case PrimitiveValueNode::STRING_TYPE: { |
| int utfLength = dataIn.readShort(); |
| if (utfLength > 0) { |
| |
| std::vector<unsigned char> buffer(utfLength); |
| dataIn.readFully(&buffer[0], utfLength); |
| value.setString(std::string((char*) (&buffer[0]), utfLength)); |
| } |
| break; |
| } |
| case PrimitiveValueNode::BIG_STRING_TYPE: { |
| int utfLength = dataIn.readInt(); |
| if (utfLength > 0) { |
| |
| std::vector<unsigned char> buffer(utfLength); |
| dataIn.readFully(&buffer[0], utfLength); |
| value.setString(std::string((char*) (&buffer[0]), utfLength)); |
| } |
| break; |
| } |
| case PrimitiveValueNode::LIST_TYPE: { |
| PrimitiveList list; |
| PrimitiveTypesMarshaller::unmarshalPrimitiveList(dataIn, list); |
| value.setList(list); |
| break; |
| } |
| case PrimitiveValueNode::MAP_TYPE: { |
| PrimitiveMap map; |
| PrimitiveTypesMarshaller::unmarshalPrimitiveMap(dataIn, map); |
| value.setMap(map); |
| break; |
| } |
| default: |
| throw IOException( |
| __FILE__, |
| __LINE__, "PrimitiveTypesMarshaller::unmarshalPrimitive - " |
| "Unsupported data type: "); |
| } |
| |
| return value; |
| } |
| AMQ_CATCH_RETHROW(io::IOException) |
| AMQ_CATCH_EXCEPTION_CONVERT(Exception, io::IOException) |
| AMQ_CATCHALL_THROW(io::IOException) |
| } |