2009-02-15 09:09:57 +00:00
|
|
|
//
|
|
|
|
|
// MessagePack for C++ deserializing routine
|
|
|
|
|
//
|
2009-02-15 09:10:02 +00:00
|
|
|
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
|
2009-02-15 09:09:57 +00:00
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
//
|
2009-02-15 09:09:56 +00:00
|
|
|
#ifndef MSGPACK_UNPACK_HPP__
|
|
|
|
|
#define MSGPACK_UNPACK_HPP__
|
|
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
#include "msgpack/unpack.h"
|
2009-02-15 09:09:56 +00:00
|
|
|
#include "msgpack/object.hpp"
|
|
|
|
|
#include "msgpack/zone.hpp"
|
2009-02-15 09:09:58 +00:00
|
|
|
#include <memory>
|
2009-02-15 09:09:56 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
|
|
2009-02-15 09:09:59 +00:00
|
|
|
#ifndef MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE
|
2009-02-15 09:10:01 +00:00
|
|
|
#define MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE (32*1024)
|
2009-02-15 09:09:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
namespace msgpack {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct unpack_error : public std::runtime_error {
|
|
|
|
|
unpack_error(const std::string& msg) :
|
|
|
|
|
std::runtime_error(msg) { }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
class unpacker : public msgpack_unpacker {
|
2009-02-15 09:09:56 +00:00
|
|
|
public:
|
2009-03-01 02:27:04 +09:00
|
|
|
unpacker(size_t init_buffer_size = MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE);
|
2009-02-15 09:09:56 +00:00
|
|
|
~unpacker();
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
public:
|
2009-02-22 15:14:21 +09:00
|
|
|
/*! 1. reserve buffer. at least `size' bytes of capacity will be ready */
|
|
|
|
|
void reserve_buffer(size_t size);
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
/*! 2. read data to the buffer() up to buffer_capacity() bytes */
|
2009-02-15 09:09:57 +00:00
|
|
|
char* buffer();
|
2009-02-15 09:09:56 +00:00
|
|
|
size_t buffer_capacity() const;
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
/*! 3. specify the number of bytes actually copied */
|
2009-02-22 15:14:21 +09:00
|
|
|
void buffer_consumed(size_t size);
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
/*! 4. repeat next() until it retunrs false */
|
|
|
|
|
bool next(unpacked* result);
|
2009-03-01 02:55:45 +09:00
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
/*! 5. check if the size of message doesn't exceed assumption. */
|
2009-02-26 01:27:00 +09:00
|
|
|
size_t message_size() const;
|
2009-02-26 01:15:14 +09:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
// Basic usage of the unpacker is as following:
|
|
|
|
|
//
|
|
|
|
|
// msgpack::unpacker pac;
|
2010-04-29 22:15:03 +09:00
|
|
|
// while( /* input is readable */ ) {
|
2009-02-15 09:09:58 +00:00
|
|
|
//
|
|
|
|
|
// // 1.
|
2010-04-29 22:15:03 +09:00
|
|
|
// pac.reserve_buffer(32*1024);
|
2009-02-15 09:09:58 +00:00
|
|
|
//
|
|
|
|
|
// // 2.
|
2010-04-29 22:15:03 +09:00
|
|
|
// size_t bytes = input.readsome(pac.buffer(), pac.buffer_capacity());
|
2009-02-15 09:09:58 +00:00
|
|
|
//
|
|
|
|
|
// // error handling ...
|
|
|
|
|
//
|
|
|
|
|
// // 3.
|
|
|
|
|
// pac.buffer_consumed(bytes);
|
|
|
|
|
//
|
|
|
|
|
// // 4.
|
2010-04-29 22:15:03 +09:00
|
|
|
// 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);
|
2009-02-15 09:09:58 +00:00
|
|
|
//
|
2010-04-29 22:15:03 +09:00
|
|
|
// //// boost::shared_ptr is also usable:
|
|
|
|
|
// // boost::shared_ptr<msgpack::zone> life(z.release());
|
|
|
|
|
// // on_message(result.get(), life);
|
|
|
|
|
// }
|
2009-02-15 09:09:58 +00:00
|
|
|
//
|
2010-04-29 22:15:03 +09:00
|
|
|
// // 5.
|
|
|
|
|
// if(pac.message_size() > 10*1024*1024) {
|
|
|
|
|
// throw std::runtime_error("message is too large");
|
2009-02-15 09:09:58 +00:00
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
/*! 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();
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
public:
|
|
|
|
|
// These functions are usable when non-MessagePack message follows after
|
|
|
|
|
// MessagePack message.
|
2009-02-26 01:27:00 +09:00
|
|
|
size_t parsed_size() const;
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-15 09:10:01 +00:00
|
|
|
/*! get address of the buffer that is not parsed */
|
2009-02-15 09:09:57 +00:00
|
|
|
char* nonparsed_buffer();
|
2009-02-15 09:09:56 +00:00
|
|
|
size_t nonparsed_size() const;
|
|
|
|
|
|
2009-02-15 09:10:01 +00:00
|
|
|
/*! skip specified size of non-parsed buffer, leaving the buffer */
|
2009-02-22 15:14:21 +09:00
|
|
|
// Note that the `size' argument must be smaller than nonparsed_size()
|
|
|
|
|
void skip_nonparsed_buffer(size_t size);
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
/*! remove unparsed buffer from unpacker */
|
|
|
|
|
// Note that reset() leaves non-parsed buffer.
|
|
|
|
|
void remove_nonparsed_buffer();
|
|
|
|
|
|
2009-03-01 02:27:04 +09:00
|
|
|
private:
|
|
|
|
|
typedef msgpack_unpacker base;
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
private:
|
2009-02-22 15:14:21 +09:00
|
|
|
unpacker(const unpacker&);
|
|
|
|
|
};
|
2009-02-15 09:09:58 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
|
2010-06-01 07:13:47 +09:00
|
|
|
static void unpack(unpacked* result,
|
2010-04-29 22:15:03 +09:00
|
|
|
const char* data, size_t len, size_t* offset = NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// obsolete
|
2009-02-22 15:14:21 +09:00
|
|
|
typedef enum {
|
2009-02-25 18:55:56 +09:00
|
|
|
UNPACK_SUCCESS = 2,
|
|
|
|
|
UNPACK_EXTRA_BYTES = 1,
|
|
|
|
|
UNPACK_CONTINUE = 0,
|
|
|
|
|
UNPACK_PARSE_ERROR = -1,
|
2009-02-22 15:14:21 +09:00
|
|
|
} unpack_return;
|
2009-02-15 09:09:58 +00:00
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
// obsolete
|
2009-02-22 15:14:21 +09:00
|
|
|
static unpack_return unpack(const char* data, size_t len, size_t* off,
|
|
|
|
|
zone* z, object* result);
|
2009-02-15 09:09:59 +00:00
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
// obsolete
|
|
|
|
|
static object unpack(const char* data, size_t len, zone& z, size_t* off = NULL);
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
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);
|
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-25 23:31:53 +09:00
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
inline void unpacker::reserve_buffer(size_t size)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-22 15:14:21 +09:00
|
|
|
if(!msgpack_unpacker_reserve_buffer(this, size)) {
|
|
|
|
|
throw std::bad_alloc();
|
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-15 09:09:57 +00:00
|
|
|
inline char* unpacker::buffer()
|
2009-02-22 15:14:21 +09:00
|
|
|
{
|
|
|
|
|
return msgpack_unpacker_buffer(this);
|
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
inline size_t unpacker::buffer_capacity() const
|
2009-02-22 15:14:21 +09:00
|
|
|
{
|
|
|
|
|
return msgpack_unpacker_buffer_capacity(this);
|
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
inline void unpacker::buffer_consumed(size_t size)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-22 15:14:21 +09:00
|
|
|
return msgpack_unpacker_buffer_consumed(this, size);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
inline bool unpacker::next(unpacked* result)
|
|
|
|
|
{
|
|
|
|
|
int ret = msgpack_unpacker_execute(this);
|
2010-04-29 22:32:43 +09:00
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
if(ret < 0) {
|
|
|
|
|
throw unpack_error("parse error");
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-29 22:32:43 +09:00
|
|
|
if(ret == 0) {
|
|
|
|
|
result->zone().reset();
|
|
|
|
|
result->get() = object();
|
|
|
|
|
return false;
|
2010-04-29 22:15:03 +09:00
|
|
|
|
2010-04-29 22:32:43 +09:00
|
|
|
} else {
|
|
|
|
|
result->zone().reset( release_zone() );
|
|
|
|
|
result->get() = data();
|
|
|
|
|
reset();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-04-29 22:15:03 +09:00
|
|
|
}
|
|
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
2009-02-22 15:36:02 +09:00
|
|
|
return msgpack_unpacker_data(this);
|
2009-02-22 15:14:21 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline zone* unpacker::release_zone()
|
|
|
|
|
{
|
|
|
|
|
if(!msgpack_unpacker_flush_zone(this)) {
|
|
|
|
|
throw std::bad_alloc();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zone* r = new zone();
|
|
|
|
|
|
2009-03-01 02:27:04 +09:00
|
|
|
msgpack_zone old = *base::z;
|
|
|
|
|
*base::z = *r;
|
|
|
|
|
*static_cast<msgpack_zone*>(r) = old;
|
2009-02-22 15:14:21 +09:00
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-01 02:55:45 +09:00
|
|
|
inline void unpacker::reset_zone()
|
|
|
|
|
{
|
|
|
|
|
msgpack_unpacker_reset_zone(this);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
inline void unpacker::reset()
|
|
|
|
|
{
|
|
|
|
|
msgpack_unpacker_reset(this);
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
|
2010-04-29 22:15:03 +09:00
|
|
|
|
2009-02-26 01:27:00 +09:00
|
|
|
inline size_t unpacker::message_size() const
|
|
|
|
|
{
|
|
|
|
|
return msgpack_unpacker_message_size(this);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-26 01:15:14 +09:00
|
|
|
inline size_t unpacker::parsed_size() const
|
|
|
|
|
{
|
|
|
|
|
return msgpack_unpacker_parsed_size(this);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-15 09:09:57 +00:00
|
|
|
inline char* unpacker::nonparsed_buffer()
|
2009-02-22 15:14:21 +09:00
|
|
|
{
|
2009-03-01 02:27:04 +09:00
|
|
|
return base::buffer + base::off;
|
2009-02-22 15:14:21 +09:00
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
inline size_t unpacker::nonparsed_size() const
|
2009-02-22 15:14:21 +09:00
|
|
|
{
|
2009-03-01 02:27:04 +09:00
|
|
|
return base::used - base::off;
|
2009-02-22 15:14:21 +09:00
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-22 15:14:21 +09:00
|
|
|
inline void unpacker::skip_nonparsed_buffer(size_t size)
|
|
|
|
|
{
|
2009-03-01 02:27:04 +09:00
|
|
|
base::off += size;
|
2009-02-22 15:14:21 +09:00
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
inline void unpacker::remove_nonparsed_buffer()
|
2009-02-22 15:14:21 +09:00
|
|
|
{
|
2009-03-01 02:27:04 +09:00
|
|
|
base::used = base::off;
|
2009-02-22 15:14:21 +09:00
|
|
|
}
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2010-06-01 07:13:47 +09:00
|
|
|
inline void unpack(unpacked* result,
|
2010-04-29 22:15:03 +09:00
|
|
|
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;
|
2010-06-01 07:13:47 +09:00
|
|
|
return;
|
2010-04-29 22:15:03 +09:00
|
|
|
|
|
|
|
|
case UNPACK_EXTRA_BYTES:
|
|
|
|
|
result->get() = obj;
|
|
|
|
|
result->zone() = z;
|
2010-06-01 07:13:47 +09:00
|
|
|
return;
|
2010-04-29 22:15:03 +09:00
|
|
|
|
|
|
|
|
case UNPACK_CONTINUE:
|
|
|
|
|
throw unpack_error("insufficient bytes");
|
|
|
|
|
|
|
|
|
|
case UNPACK_PARSE_ERROR:
|
|
|
|
|
default:
|
|
|
|
|
throw unpack_error("parse error");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// obsolete
|
2009-02-22 15:14:21 +09:00
|
|
|
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));
|
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
2009-02-24 16:37:47 +09:00
|
|
|
// obsolete
|
2009-02-22 15:14:21 +09:00
|
|
|
inline object unpack(const char* data, size_t len, zone& z, size_t* off)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-22 15:14:21 +09:00
|
|
|
object result;
|
|
|
|
|
|
|
|
|
|
switch( msgpack::unpack(data, len, off, &z, &result) ) {
|
2009-02-25 18:55:56 +09:00
|
|
|
case UNPACK_SUCCESS:
|
2009-02-22 15:14:21 +09:00
|
|
|
return result;
|
|
|
|
|
|
2009-02-25 18:55:56 +09:00
|
|
|
case UNPACK_EXTRA_BYTES:
|
2009-02-22 15:14:21 +09:00
|
|
|
if(off) {
|
|
|
|
|
return result;
|
|
|
|
|
} else {
|
|
|
|
|
throw unpack_error("extra bytes");
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-25 18:55:56 +09:00
|
|
|
case UNPACK_CONTINUE:
|
2009-02-22 15:14:21 +09:00
|
|
|
throw unpack_error("insufficient bytes");
|
|
|
|
|
|
2009-02-25 18:55:56 +09:00
|
|
|
case UNPACK_PARSE_ERROR:
|
2009-02-22 15:14:21 +09:00
|
|
|
default:
|
|
|
|
|
throw unpack_error("parse error");
|
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace msgpack
|
|
|
|
|
|
|
|
|
|
#endif /* msgpack/unpack.hpp */
|
|
|
|
|
|