summaryrefslogtreecommitdiff
path: root/cpp/src/msgpack/unpack.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/msgpack/unpack.hpp')
-rw-r--r--cpp/src/msgpack/unpack.hpp384
1 files changed, 384 insertions, 0 deletions
diff --git a/cpp/src/msgpack/unpack.hpp b/cpp/src/msgpack/unpack.hpp
new file mode 100644
index 0000000..51580b6
--- /dev/null
+++ b/cpp/src/msgpack/unpack.hpp
@@ -0,0 +1,384 @@
+//
+// MessagePack for C++ deserializing routine
+//
+// Copyright (C) 2008-2009 FURUHASHI Sadayuki
+//
+// Licensed 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.
+//
+#ifndef MSGPACK_UNPACK_HPP__
+#define MSGPACK_UNPACK_HPP__
+
+#include "unpack.h"
+#include "object.hpp"
+#include "zone.hpp"
+#include <memory>
+#include <stdexcept>
+
+// backward compatibility
+#ifndef MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE
+#define MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE MSGPACK_UNPACKER_INIT_BUFFER_SIZE
+#endif
+
+namespace msgpack {
+
+
+struct unpack_error : public std::runtime_error {
+ unpack_error(const std::string& msg) :
+ std::runtime_error(msg) { }
+};
+
+
+class unpacked {
+public:
+ unpacked() { }
+
+ unpacked(object obj, std::auto_ptr<msgpack::zone> z) :
+ m_obj(obj), m_zone(z) { }
+
+ object& get()
+ { return m_obj; }
+
+ const object& get() const
+ { return m_obj; }
+
+ std::auto_ptr<msgpack::zone>& zone()
+ { return m_zone; }
+
+ const std::auto_ptr<msgpack::zone>& zone() const
+ { return m_zone; }
+
+private:
+ object m_obj;
+ std::auto_ptr<msgpack::zone> m_zone;
+};
+
+
+class unpacker : public msgpack_unpacker {
+public:
+ unpacker(size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
+ ~unpacker();
+
+public:
+ /*! 1. reserve buffer. at least `size' bytes of capacity will be ready */
+ void reserve_buffer(size_t size = MSGPACK_UNPACKER_RESERVE_SIZE);
+
+ /*! 2. read data to the buffer() up to buffer_capacity() bytes */
+ char* buffer();
+ size_t buffer_capacity() const;
+
+ /*! 3. specify the number of bytes actually copied */
+ void buffer_consumed(size_t size);
+
+ /*! 4. repeat next() until it retunrs false */
+ bool next(unpacked* result);
+
+ /*! 5. check if the size of message doesn't exceed assumption. */
+ size_t message_size() const;
+
+ // Basic usage of the unpacker is as following:
+ //
+ // msgpack::unpacker pac;
+ // while( /* input is readable */ ) {
+ //
+ // // 1.
+ // pac.reserve_buffer(32*1024);
+ //
+ // // 2.
+ // size_t bytes = input.readsome(pac.buffer(), pac.buffer_capacity());
+ //
+ // // error handling ...
+ //
+ // // 3.
+ // pac.buffer_consumed(bytes);
+ //
+ // // 4.
+ // msgpack::unpacked result;
+ // while(pac.next(&result)) {
+ // // do some with the object with the zone.
+ // msgpack::object obj = result.get();
+ // std::auto_ptr<msgpack:zone> z = result.zone();
+ // on_message(obj, z);
+ //
+ // //// boost::shared_ptr is also usable:
+ // // boost::shared_ptr<msgpack::zone> life(z.release());
+ // // on_message(result.get(), life);
+ // }
+ //
+ // // 5.
+ // if(pac.message_size() > 10*1024*1024) {
+ // throw std::runtime_error("message is too large");
+ // }
+ // }
+ //
+
+ /*! for backward compatibility */
+ bool execute();
+
+ /*! for backward compatibility */
+ object data();
+
+ /*! for backward compatibility */
+ zone* release_zone();
+
+ /*! for backward compatibility */
+ void reset_zone();
+
+ /*! for backward compatibility */
+ void reset();
+
+public:
+ // These functions are usable when non-MessagePack message follows after
+ // MessagePack message.
+ size_t parsed_size() const;
+
+ /*! get address of the buffer that is not parsed */
+ char* nonparsed_buffer();
+ size_t nonparsed_size() const;
+
+ /*! skip specified size of non-parsed buffer, leaving the buffer */
+ // Note that the `size' argument must be smaller than nonparsed_size()
+ void skip_nonparsed_buffer(size_t size);
+
+ /*! remove unparsed buffer from unpacker */
+ // Note that reset() leaves non-parsed buffer.
+ void remove_nonparsed_buffer();
+
+private:
+ typedef msgpack_unpacker base;
+
+private:
+ unpacker(const unpacker&);
+};
+
+
+static void unpack(unpacked* result,
+ const char* data, size_t len, size_t* offset = NULL);
+
+
+// obsolete
+typedef enum {
+ UNPACK_SUCCESS = 2,
+ UNPACK_EXTRA_BYTES = 1,
+ UNPACK_CONTINUE = 0,
+ UNPACK_PARSE_ERROR = -1,
+} unpack_return;
+
+// obsolete
+static unpack_return unpack(const char* data, size_t len, size_t* off,
+ zone* z, object* result);
+
+
+// obsolete
+static object unpack(const char* data, size_t len, zone& z, size_t* off = NULL);
+
+
+inline unpacker::unpacker(size_t initial_buffer_size)
+{
+ if(!msgpack_unpacker_init(this, initial_buffer_size)) {
+ throw std::bad_alloc();
+ }
+}
+
+inline unpacker::~unpacker()
+{
+ msgpack_unpacker_destroy(this);
+}
+
+
+inline void unpacker::reserve_buffer(size_t size)
+{
+ if(!msgpack_unpacker_reserve_buffer(this, size)) {
+ throw std::bad_alloc();
+ }
+}
+
+inline char* unpacker::buffer()
+{
+ return msgpack_unpacker_buffer(this);
+}
+
+inline size_t unpacker::buffer_capacity() const
+{
+ return msgpack_unpacker_buffer_capacity(this);
+}
+
+inline void unpacker::buffer_consumed(size_t size)
+{
+ return msgpack_unpacker_buffer_consumed(this, size);
+}
+
+inline bool unpacker::next(unpacked* result)
+{
+ int ret = msgpack_unpacker_execute(this);
+
+ if(ret < 0) {
+ throw unpack_error("parse error");
+ }
+
+ if(ret == 0) {
+ result->zone().reset();
+ result->get() = object();
+ return false;
+
+ } else {
+ result->zone().reset( release_zone() );
+ result->get() = data();
+ reset();
+ return true;
+ }
+}
+
+
+inline bool unpacker::execute()
+{
+ int ret = msgpack_unpacker_execute(this);
+ if(ret < 0) {
+ throw unpack_error("parse error");
+ } else if(ret == 0) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+inline object unpacker::data()
+{
+ return msgpack_unpacker_data(this);
+}
+
+inline zone* unpacker::release_zone()
+{
+ if(!msgpack_unpacker_flush_zone(this)) {
+ throw std::bad_alloc();
+ }
+
+ zone* r = new zone();
+
+ msgpack_zone old = *base::z;
+ *base::z = *r;
+ *static_cast<msgpack_zone*>(r) = old;
+
+ return r;
+}
+
+inline void unpacker::reset_zone()
+{
+ msgpack_unpacker_reset_zone(this);
+}
+
+inline void unpacker::reset()
+{
+ msgpack_unpacker_reset(this);
+}
+
+
+inline size_t unpacker::message_size() const
+{
+ return msgpack_unpacker_message_size(this);
+}
+
+inline size_t unpacker::parsed_size() const
+{
+ return msgpack_unpacker_parsed_size(this);
+}
+
+inline char* unpacker::nonparsed_buffer()
+{
+ return base::buffer + base::off;
+}
+
+inline size_t unpacker::nonparsed_size() const
+{
+ return base::used - base::off;
+}
+
+inline void unpacker::skip_nonparsed_buffer(size_t size)
+{
+ base::off += size;
+}
+
+inline void unpacker::remove_nonparsed_buffer()
+{
+ base::used = base::off;
+}
+
+
+inline void unpack(unpacked* result,
+ const char* data, size_t len, size_t* offset)
+{
+ msgpack::object obj;
+ std::auto_ptr<msgpack::zone> z(new zone());
+
+ unpack_return ret = (unpack_return)msgpack_unpack(
+ data, len, offset, z.get(),
+ reinterpret_cast<msgpack_object*>(&obj));
+
+ switch(ret) {
+ case UNPACK_SUCCESS:
+ result->get() = obj;
+ result->zone() = z;
+ return;
+
+ case UNPACK_EXTRA_BYTES:
+ result->get() = obj;
+ result->zone() = z;
+ return;
+
+ case UNPACK_CONTINUE:
+ throw unpack_error("insufficient bytes");
+
+ case UNPACK_PARSE_ERROR:
+ default:
+ throw unpack_error("parse error");
+ }
+}
+
+
+// obsolete
+inline unpack_return unpack(const char* data, size_t len, size_t* off,
+ zone* z, object* result)
+{
+ return (unpack_return)msgpack_unpack(data, len, off,
+ z, reinterpret_cast<msgpack_object*>(result));
+}
+
+// obsolete
+inline object unpack(const char* data, size_t len, zone& z, size_t* off)
+{
+ object result;
+
+ switch( msgpack::unpack(data, len, off, &z, &result) ) {
+ case UNPACK_SUCCESS:
+ return result;
+
+ case UNPACK_EXTRA_BYTES:
+ if(off) {
+ return result;
+ } else {
+ throw unpack_error("extra bytes");
+ }
+
+ case UNPACK_CONTINUE:
+ throw unpack_error("insufficient bytes");
+
+ case UNPACK_PARSE_ERROR:
+ default:
+ throw unpack_error("parse error");
+ }
+}
+
+
+} // namespace msgpack
+
+#endif /* msgpack/unpack.hpp */
+