#ifndef _framing_FieldValue_h #define _framing_FieldValue_h /* * * 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 "qpid/Exception.h" #include "amqp_types.h" #include "Buffer.h" #include "FieldTable.h" #include "qpid/CommonImportExport.h" #include "assert.h" #include #include #include namespace qpid { namespace framing { //class Array; /** * Exception that is the base exception for all field table errors. * * \ingroup clientapi */ class FieldValueException : public qpid::Exception {}; /** * Exception thrown when we can't perform requested conversion * * \ingroup clientapi */ struct InvalidConversionException : public FieldValueException { InvalidConversionException() {} }; /** * Value that can appear in an AMQP field table * * \ingroup clientapi */ class FieldValue { public: /* * Abstract type for content of different types */ class Data { public: virtual ~Data() {}; virtual uint32_t encodedSize() const = 0; virtual void encode(Buffer& buffer) = 0; virtual void decode(Buffer& buffer) = 0; virtual bool operator==(const Data&) const = 0; virtual bool convertsToInt() const { return false; } virtual bool convertsToString() const { return false; } virtual int64_t getInt() const { throw InvalidConversionException();} virtual std::string getString() const { throw InvalidConversionException(); } virtual void print(std::ostream& out) const = 0; }; FieldValue(): data(0) {}; // Default assignment operator is fine void setType(uint8_t type); uint8_t getType(); Data& getData() { return *data; } uint32_t encodedSize() const { return 1 + data->encodedSize(); }; bool empty() const { return data.get() == 0; } void encode(Buffer& buffer); void decode(Buffer& buffer); QPID_COMMON_EXTERN bool operator==(const FieldValue&) const; QPID_COMMON_EXTERN bool operator!=(const FieldValue& v) const { return !(*this == v); } void print(std::ostream& out) const; template bool convertsTo() const { return false; } template T get() const { throw InvalidConversionException(); } protected: FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {} private: uint8_t typeOctet; std::auto_ptr data; }; template <> inline bool FieldValue::convertsTo() const { return data->convertsToInt(); } template <> inline bool FieldValue::convertsTo() const { return data->convertsToInt(); } template <> inline bool FieldValue::convertsTo() const { return data->convertsToString(); } template <> inline int FieldValue::get() const { return data->getInt(); } template <> inline int64_t FieldValue::get() const { return data->getInt(); } template <> inline std::string FieldValue::get() const { return data->getString(); } inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) { v.print(out); return out; } template class FixedWidthValue : public FieldValue::Data { uint8_t octets[width]; public: FixedWidthValue() {} FixedWidthValue(const uint8_t (&data)[width]) : octets(data) {} FixedWidthValue(const uint8_t* const data) { for (int i = 0; i < width; i++) octets[i] = data[i]; } FixedWidthValue(uint64_t v) { for (int i = width; i > 1; --i) { octets[i-1] = (uint8_t) (0xFF & v); v >>= 8; } octets[0] = (uint8_t) (0xFF & v); } uint32_t encodedSize() const { return width; } void encode(Buffer& buffer) { buffer.putRawData(octets, width); } void decode(Buffer& buffer) { buffer.getRawData(octets, width); } bool operator==(const Data& d) const { const FixedWidthValue* rhs = dynamic_cast< const FixedWidthValue* >(&d); if (rhs == 0) return false; else return std::equal(&octets[0], &octets[width], &rhs->octets[0]); } bool convertsToInt() const { return true; } int64_t getInt() const { int64_t v = 0; for (int i = 0; i < width-1; ++i) { v |= octets[i]; v <<= 8; } v |= octets[width-1]; return v; } uint8_t* rawOctets() { return octets; } void print(std::ostream& o) const { o << "F" << width << ":"; }; }; template <> class FixedWidthValue<0> : public FieldValue::Data { public: // Implicit default constructor is fine uint32_t encodedSize() const { return 0; } void encode(Buffer&) {}; void decode(Buffer&) {}; bool operator==(const Data& d) const { const FixedWidthValue<0>* rhs = dynamic_cast< const FixedWidthValue<0>* >(&d); return rhs != 0; } void print(std::ostream& o) const { o << "F0"; }; }; template class VariableWidthValue : public FieldValue::Data { std::vector octets; public: VariableWidthValue() {} VariableWidthValue(const std::vector& data) : octets(data) {} VariableWidthValue(const uint8_t* start, const uint8_t* end) : octets(start, end) {} uint32_t encodedSize() const { return lenwidth + octets.size(); } void encode(Buffer& buffer) { buffer.putUInt(octets.size()); if (octets.size() > 0) buffer.putRawData(&octets[0], octets.size()); }; void decode(Buffer& buffer) { uint32_t len = buffer.getUInt(); octets.resize(len); if (len > 0) buffer.getRawData(&octets[0], len); } bool operator==(const Data& d) const { const VariableWidthValue* rhs = dynamic_cast< const VariableWidthValue* >(&d); if (rhs == 0) return false; else return octets==rhs->octets; } bool convertsToString() const { return true; } std::string getString() const { return std::string(octets.begin(), octets.end()); } void print(std::ostream& o) const { o << "V" << lenwidth << ":" << octets.size() << ":"; }; }; template class EncodedValue : public FieldValue::Data { T value; public: EncodedValue() {} EncodedValue(const T& v) : value(v) {} T& getValue() { return value; } const T& getValue() const { return value; } uint32_t encodedSize() const { return value.encodedSize(); } void encode(Buffer& buffer) { value.encode(buffer); }; void decode(Buffer& buffer) { value.decode(buffer); } bool operator==(const Data& d) const { const EncodedValue* rhs = dynamic_cast< const EncodedValue* >(&d); if (rhs == 0) return false; else return value==rhs->value; } void print(std::ostream& o) const { o << "[" << value << "]"; }; }; class Str8Value : public FieldValue { public: QPID_COMMON_EXTERN Str8Value(const std::string& v); }; class Str16Value : public FieldValue { public: QPID_COMMON_EXTERN Str16Value(const std::string& v); }; class Struct32Value : public FieldValue { public: QPID_COMMON_EXTERN Struct32Value(const std::string& v); }; class FloatValue : public FieldValue { public: QPID_COMMON_EXTERN FloatValue(float f); }; class DoubleValue : public FieldValue { public: QPID_COMMON_EXTERN DoubleValue(double f); }; /* * Basic integer value encodes as signed 32 bit */ class IntegerValue : public FieldValue { public: QPID_COMMON_EXTERN IntegerValue(int v); }; class TimeValue : public FieldValue { public: QPID_COMMON_EXTERN TimeValue(uint64_t v); }; class Integer64Value : public FieldValue { public: QPID_COMMON_EXTERN Integer64Value(int64_t v); }; class Unsigned64Value : public FieldValue { public: QPID_COMMON_EXTERN Unsigned64Value(uint64_t v); }; class FieldTableValue : public FieldValue { public: QPID_COMMON_EXTERN FieldTableValue(const FieldTable&); }; class ArrayValue : public FieldValue { public: QPID_COMMON_EXTERN ArrayValue(const Array&); }; template bool getEncodedValue(FieldTable::ValuePtr vptr, T& value) { if (vptr) { const EncodedValue* ev = dynamic_cast< EncodedValue* >(&(vptr->getData())); if (ev != 0) { value = ev->getValue(); return true; } } return false; } }} // qpid::framing #endif