summaryrefslogtreecommitdiff
path: root/qpid/cpp/src/qpid/amqp/Encoder.cpp
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2015-06-25 10:22:51 +0000
committerRobert Gemmell <robbie@apache.org>2015-06-25 10:22:51 +0000
commit32ae758bc2e8fd962b66a4ab6341b14009f1907e (patch)
tree2f4d8174813284a6ea58bb6b7f6520aa92287476 /qpid/cpp/src/qpid/amqp/Encoder.cpp
parent116d91ad7825a98af36a869fc751206fbce0c59f (diff)
parentf7e896076143de4572b4f1f67ef0765125f2498d (diff)
downloadqpid-python-32ae758bc2e8fd962b66a4ab6341b14009f1907e.tar.gz
NO-JIRA: create branch for qpid-cpp 0.34 RC process
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid-cpp-0.34-rc@1687469 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp/src/qpid/amqp/Encoder.cpp')
-rw-r--r--qpid/cpp/src/qpid/amqp/Encoder.cpp523
1 files changed, 523 insertions, 0 deletions
diff --git a/qpid/cpp/src/qpid/amqp/Encoder.cpp b/qpid/cpp/src/qpid/amqp/Encoder.cpp
new file mode 100644
index 0000000000..86b59fb1a2
--- /dev/null
+++ b/qpid/cpp/src/qpid/amqp/Encoder.cpp
@@ -0,0 +1,523 @@
+/*
+ *
+ * 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/amqp/Encoder.h"
+#include "qpid/amqp/CharSequence.h"
+#include "qpid/amqp/Descriptor.h"
+#include "qpid/amqp/typecodes.h"
+#include "qpid/types/Uuid.h"
+#include "qpid/types/Variant.h"
+#include "qpid/types/encodings.h"
+#include "qpid/log/Statement.h"
+#include "qpid/Exception.h"
+#include <assert.h>
+#include <string.h>
+
+using namespace qpid::types::encodings;
+using qpid::types::Variant;
+
+namespace qpid {
+namespace amqp {
+
+Encoder::Overflow::Overflow() : Exception("Buffer overflow in encoder!") {}
+
+Encoder::Encoder(char* d, size_t s) : data(d), size(s), position(0), grow(false) {}
+
+Encoder::Encoder() : data(0), size(0), position(0), grow(true) {}
+
+namespace {
+template <typename T> size_t encode(char* data, T i);
+template <> size_t encode<uint8_t>(char* data, uint8_t i)
+{
+ *data = i;
+ return 1;
+}
+template <> size_t encode<uint16_t>(char* data, uint16_t i)
+{
+ uint16_t b = i;
+ size_t position(0);
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+ return position;
+}
+template <> size_t encode<uint32_t>(char* data, uint32_t i)
+{
+ uint32_t b = i;
+ size_t position(0);
+ data[position++] = (uint8_t) (0xFF & (b >> 24));
+ data[position++] = (uint8_t) (0xFF & (b >> 16));
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+ return position;
+}
+template <> size_t encode<uint64_t>(char* data, uint64_t i)
+{
+ uint32_t hi = i >> 32;
+ uint32_t lo = i;
+ size_t r(0);
+ r += encode(data, hi);
+ r += encode(data + r, lo);
+ return r;
+}
+template<typename T> struct Backfill
+{
+ T size;
+ T count;
+ char* location;
+};
+
+template<typename T> void end(T count, void* token, char* current)
+{
+ Backfill<T> b;
+ b.location = (char*) token;
+ b.size = (T) (current - b.location) - sizeof(b.size);
+ b.count = count;
+ b.location += encode<T>(b.location, b.size);
+ encode<T>(b.location, b.count);
+}
+}
+char* Encoder::skip(size_t n)
+{
+ char* current = data + position;
+ check(n);
+ position += n;
+ return current;
+}
+
+void Encoder::write(bool b)
+{
+ check(sizeof(b));
+ position += encode<uint8_t>(data+position, b ? 1u : 0u);
+}
+void Encoder::write(uint8_t i)
+{
+ check(sizeof(i));
+ position += encode<uint8_t>(data+position, i);
+}
+void Encoder::write(uint16_t i)
+{
+ check(sizeof(i));
+ position += encode<uint16_t>(data+position, i);
+}
+void Encoder::write(uint32_t i)
+{
+ check(sizeof(i));
+ position += encode<uint32_t>(data+position, i);
+}
+void Encoder::write(uint64_t i)
+{
+ check(sizeof(i));
+ position += encode<uint64_t>(data+position, i);
+}
+void Encoder::write(int8_t i)
+{
+ check(sizeof(i));
+ position += encode(data+position, (uint8_t) i);
+}
+void Encoder::write(int16_t i)
+{
+ check(sizeof(i));
+ position += encode(data+position, (uint16_t) i);
+}
+void Encoder::write(int32_t i)
+{
+ check(sizeof(i));
+ position += encode(data+position, (uint32_t) i);
+}
+void Encoder::write(int64_t i)
+{
+ check(sizeof(i));
+ position += encode(data+position, (uint64_t) i);
+}
+void Encoder::write(float f)
+{
+ check(sizeof(f));
+ union {
+ uint32_t i;
+ float f;
+ } val;
+
+ val.f = f;
+ write(val.i);
+}
+void Encoder::write(double d)
+{
+ check(sizeof(d));
+ union {
+ uint64_t i;
+ double d;
+ } val;
+
+ val.d = d;
+ write(val.i);
+}
+void Encoder::write(const qpid::types::Uuid& uuid)
+{
+ writeBytes((const char*) uuid.data(), uuid.size());
+}
+
+void Encoder::writeBytes(const char* bytes, size_t count)
+{
+ check(count);
+ ::memcpy(data + position, bytes, count);
+ position += count;
+}
+
+void Encoder::writeCode(uint8_t code)
+{
+ write(code);
+}
+
+void Encoder::writeNull(const Descriptor* d)
+{
+ if (d) writeDescriptor(*d);
+ writeCode(typecodes::NULL_VALUE);
+}
+void Encoder::writeBoolean(bool b, const Descriptor* d)
+{
+ if (d) writeDescriptor(*d);
+ writeCode(b ? typecodes::BOOLEAN_TRUE : typecodes::BOOLEAN_FALSE);
+}
+void Encoder::writeUByte(uint8_t i, const Descriptor* d)
+{
+ write(i, typecodes::UBYTE, d);
+}
+
+void Encoder::writeUShort(uint16_t i, const Descriptor* d)
+{
+ write(i, typecodes::USHORT, d);
+}
+
+void Encoder::writeUInt(uint32_t i, const Descriptor* d)
+{
+ if (i == 0) {
+ if (d) writeDescriptor(*d);
+ writeCode(typecodes::UINT_ZERO);
+ } else {
+ if (i < 256) {
+ write((uint8_t) i, typecodes::UINT_SMALL, d);
+ } else {
+ write(i, typecodes::UINT, d);
+ }
+ }
+}
+
+void Encoder::writeULong(uint64_t i, const Descriptor* d)
+{
+ if (i == 0) {
+ if (d) writeDescriptor(*d);
+ writeCode(typecodes::ULONG_ZERO);
+ } else {
+ if (i < 256) {
+ write((uint8_t) i, typecodes::ULONG_SMALL, d);
+ } else {
+ write(i, typecodes::ULONG, d);
+ }
+ }
+}
+
+void Encoder::writeByte(int8_t i, const Descriptor* d)
+{
+ write((uint8_t) i, typecodes::LONG, d);
+}
+
+void Encoder::writeShort(int16_t i, const Descriptor* d)
+{
+ write((uint16_t) i, typecodes::SHORT, d);
+}
+
+void Encoder::writeInt(int32_t i, const Descriptor* d)
+{
+ write((uint32_t) i, typecodes::INT, d);
+}
+
+void Encoder::writeLong(int64_t i, const Descriptor* d)
+{
+ write((uint64_t) i, typecodes::LONG, d);
+}
+
+void Encoder::writeTimestamp(int64_t t, const Descriptor* d)
+{
+ write((uint64_t) t, typecodes::TIMESTAMP, d);
+}
+
+
+void Encoder::writeFloat(float f, const Descriptor* d)
+{
+ write(f, typecodes::FLOAT, d);
+}
+
+void Encoder::writeDouble(double f, const Descriptor* d)
+{
+ write(f, typecodes::DOUBLE, d);
+}
+
+void Encoder::writeUuid(const qpid::types::Uuid& uuid, const Descriptor* d)
+{
+ write(uuid, typecodes::UUID, d);
+}
+
+void Encoder::write(const CharSequence& v, std::pair<uint8_t, uint8_t> codes, const Descriptor* d)
+{
+ if (d) writeDescriptor(*d);
+ if (v.size < 256) {
+ writeCode(codes.first);
+ write((uint8_t) v.size);
+ } else {
+ writeCode(codes.second);
+ write((uint32_t) v.size);
+ }
+ writeBytes(v.data, v.size);
+}
+
+void Encoder::write(const std::string& v, std::pair<uint8_t, uint8_t> codes, const Descriptor* d)
+{
+ if (d) writeDescriptor(*d);
+ if (v.size() < 256) {
+ writeCode(codes.first);
+ write((uint8_t) v.size());
+ } else {
+ writeCode(codes.second);
+ write((uint32_t) v.size());
+ }
+ writeBytes(v.data(), v.size());
+}
+
+void Encoder::writeSymbol(const CharSequence& v, const Descriptor* d)
+{
+ write(v, typecodes::SYMBOL, d);
+}
+
+void Encoder::writeSymbol(const std::string& v, const Descriptor* d)
+{
+ write(v, typecodes::SYMBOL, d);
+}
+
+void Encoder::writeString(const CharSequence& v, const Descriptor* d)
+{
+ write(v, typecodes::STRING, d);
+}
+
+void Encoder::writeString(const std::string& v, const Descriptor* d)
+{
+ write(v, typecodes::STRING, d);
+}
+
+void Encoder::writeBinary(const CharSequence& v, const Descriptor* d)
+{
+ write(v, typecodes::BINARY, d);
+}
+
+void Encoder::writeBinary(const std::string& v, const Descriptor* d)
+{
+ write(v, typecodes::BINARY, d);
+}
+
+void* Encoder::startList8(const Descriptor* d)
+{
+ return start<uint8_t>(typecodes::LIST8, d);
+}
+
+void* Encoder::startList32(const Descriptor* d)
+{
+ return start<uint32_t>(typecodes::LIST32, d);
+}
+
+void Encoder::endList8(uint8_t count, void* token)
+{
+ end<uint8_t>(count, token, data+position);
+}
+
+void Encoder::endList32(uint32_t count, void* token)
+{
+ end<uint32_t>(count, token, data+position);
+}
+
+void* Encoder::startMap8(const Descriptor* d)
+{
+ return start<uint8_t>(typecodes::MAP8, d);
+}
+
+void* Encoder::startMap32(const Descriptor* d)
+{
+ return start<uint32_t>(typecodes::MAP32, d);
+}
+
+void Encoder::endMap8(uint8_t count, void* token)
+{
+ end<uint8_t>(count, token, data+position);
+}
+
+void Encoder::endMap32(uint32_t count, void* token)
+{
+ end<uint32_t>(count, token, data+position);
+}
+
+void* Encoder::startArray8(const Constructor& c, const Descriptor* d)
+{
+ return startArray<uint8_t>(typecodes::ARRAY8, d, c);
+}
+
+void* Encoder::startArray32(const Constructor& c, const Descriptor* d)
+{
+ return startArray<uint8_t>(typecodes::ARRAY32, d, c);
+}
+
+void Encoder::endArray8(size_t count, void* token)
+{
+ end<uint8_t>(count, token, data+position);
+}
+
+void Encoder::endArray32(size_t count, void* token)
+{
+ end<uint32_t>(count, token, data+position);
+}
+
+void Encoder::writeMap(const std::map<std::string, qpid::types::Variant>& value, const Descriptor* d, bool large)
+{
+ void* token = large ? startMap32(d) : startMap8(d);
+ for (qpid::types::Variant::Map::const_iterator i = value.begin(); i != value.end(); ++i) {
+ writeString(i->first);
+ writeValue(i->second);
+ }
+ if (large) endMap32(value.size()*2, token);
+ else endMap8(value.size()*2, token);
+}
+
+void Encoder::writeList(const std::list<qpid::types::Variant>& value, const Descriptor* d, bool large)
+{
+ void* token = large ? startList32(d) : startList8(d);
+ for (qpid::types::Variant::List::const_iterator i = value.begin(); i != value.end(); ++i) {
+ writeValue(*i);
+ }
+ if (large) endList32(value.size(), token);
+ else endList8(value.size(), token);
+}
+
+void Encoder::writeValue(const qpid::types::Variant& value, const Descriptor* d)
+{
+ if (d) {
+ writeDescriptor(*d); // Write this descriptor before any in the value.
+ d = 0;
+ }
+ // Write any descriptors attached to the value.
+ const Variant::List& descriptors = value.getDescriptors();
+ for (Variant::List::const_iterator i = descriptors.begin(); i != descriptors.end(); ++i) {
+ if (i->getType() == types::VAR_STRING)
+ writeDescriptor(Descriptor(CharSequence::create(i->asString())));
+ else
+ writeDescriptor(Descriptor(i->asUint64()));
+ }
+ switch (value.getType()) {
+ case qpid::types::VAR_VOID:
+ writeNull(d);
+ break;
+ case qpid::types::VAR_BOOL:
+ writeBoolean(value.asBool(), d);
+ break;
+ case qpid::types::VAR_UINT8:
+ writeUByte(value.asUint8(), d);
+ break;
+ case qpid::types::VAR_UINT16:
+ writeUShort(value.asUint16(), d);
+ break;
+ case qpid::types::VAR_UINT32:
+ writeUInt(value.asUint32(), d);
+ break;
+ case qpid::types::VAR_UINT64:
+ writeULong(value.asUint64(), d);
+ break;
+ case qpid::types::VAR_INT8:
+ writeByte(value.asInt8(), d);
+ break;
+ case qpid::types::VAR_INT16:
+ writeShort(value.asInt16(), d);
+ break;
+ case qpid::types::VAR_INT32:
+ writeInt(value.asInt32(), d);
+ break;
+ case qpid::types::VAR_INT64:
+ writeLong(value.asInt64(), d);
+ break;
+ case qpid::types::VAR_FLOAT:
+ writeFloat(value.asFloat(), d);
+ break;
+ case qpid::types::VAR_DOUBLE:
+ writeDouble(value.asDouble(), d);
+ break;
+ case qpid::types::VAR_STRING:
+ if (value.getEncoding() == UTF8) {
+ writeString(value.getString(), d);
+ } else if (value.getEncoding() == ASCII) {
+ writeSymbol(value.getString(), d);
+ } else {
+ writeBinary(value.getString(), d);
+ }
+ break;
+ case qpid::types::VAR_MAP:
+ writeMap(value.asMap(), d);
+ break;
+ case qpid::types::VAR_LIST:
+ writeList(value.asList(), d);
+ break;
+ case qpid::types::VAR_UUID:
+ writeUuid(value.asUuid(), d);
+ break;
+ }
+
+}
+
+void Encoder::writeDescriptor(const Descriptor& d)
+{
+ writeCode(typecodes::DESCRIPTOR);
+ switch (d.type) {
+ case Descriptor::NUMERIC:
+ writeULong(d.value.code, 0);
+ break;
+ case Descriptor::SYMBOLIC:
+ writeSymbol(d.value.symbol, 0);
+ break;
+ }
+}
+
+void Encoder::check(size_t s)
+{
+ if (position + s > size) {
+ if (grow) {
+ buffer.resize(buffer.size() + s);
+ data = const_cast<char*>(buffer.data());
+ size = buffer.size();
+ }
+ else {
+ QPID_LOG(notice, "Buffer overflow for write of size " << s
+ << " to buffer of size " << size << " at position " << position);
+ assert(false);
+ throw Overflow();
+ }
+ }
+}
+
+size_t Encoder::getPosition() { return position; }
+size_t Encoder::getSize() const { return size; }
+char* Encoder::getData() { return data + position; }
+std::string Encoder::getBuffer() { return buffer; }
+void Encoder::resetPosition(size_t p) { assert(p <= size); position = p; }
+
+}} // namespace qpid::amqp