2009-02-15 09:09:57 +00:00
|
|
|
//
|
|
|
|
// MessagePack for C++ deserializing routine
|
|
|
|
//
|
|
|
|
// Copyright (C) 2008 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.
|
|
|
|
//
|
2009-02-15 09:09:56 +00:00
|
|
|
#include "msgpack/unpack.hpp"
|
2009-02-15 09:09:57 +00:00
|
|
|
#include "msgpack/unpack_define.h"
|
2009-02-15 09:09:56 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
namespace msgpack {
|
|
|
|
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:57 +00:00
|
|
|
#define msgpack_unpack_struct(name) \
|
|
|
|
struct msgpack_unpacker_##name
|
|
|
|
|
|
|
|
#define msgpack_unpack_func(ret, name) \
|
|
|
|
ret msgpack_unpacker_##name
|
|
|
|
|
|
|
|
#define msgpack_unpack_callback(name) \
|
|
|
|
msgpack_unpack_##name
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
#define msgpack_unpack_object object
|
2009-02-15 09:09:57 +00:00
|
|
|
|
|
|
|
#define msgpack_unpack_user zone*
|
|
|
|
|
|
|
|
|
|
|
|
struct msgpack_unpacker_context;
|
|
|
|
|
|
|
|
static void msgpack_unpacker_init(struct msgpack_unpacker_context* ctx);
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static object msgpack_unpacker_data(struct msgpack_unpacker_context* ctx);
|
2009-02-15 09:09:57 +00:00
|
|
|
|
|
|
|
static int msgpack_unpacker_execute(struct msgpack_unpacker_context* ctx,
|
|
|
|
const char* data, size_t len, size_t* off);
|
|
|
|
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_init(zone** z)
|
|
|
|
{ return object(); }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_uint8(zone** z, uint8_t d)
|
|
|
|
{ object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_uint16(zone** z, uint16_t d)
|
|
|
|
{ object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_uint32(zone** z, uint32_t d)
|
|
|
|
{ object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_uint64(zone** z, uint64_t d)
|
|
|
|
{ object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_int8(zone** z, int8_t d)
|
|
|
|
{ if(d >= 0) { object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
|
|
|
else { object o; o.type = type::NEGATIVE_INTEGER; o.via.i64 = d; return o; } }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_int16(zone** z, int16_t d)
|
|
|
|
{ if(d >= 0) { object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
|
|
|
else { object o; o.type = type::NEGATIVE_INTEGER; o.via.i64 = d; return o; } }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_int32(zone** z, int32_t d)
|
|
|
|
{ if(d >= 0) { object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
|
|
|
else { object o; o.type = type::NEGATIVE_INTEGER; o.via.i64 = d; return o; } }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_int64(zone** z, int64_t d)
|
|
|
|
{ if(d >= 0) { object o; o.type = type::POSITIVE_INTEGER; o.via.u64 = d; return o; }
|
|
|
|
else { object o; o.type = type::NEGATIVE_INTEGER; o.via.i64 = d; return o; } }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_float(zone** z, float d)
|
|
|
|
{ object o; o.type = type::DOUBLE; o.via.dec = d; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_double(zone** z, double d)
|
|
|
|
{ object o; o.type = type::DOUBLE; o.via.dec = d; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_nil(zone** z)
|
|
|
|
{ object o; o.type = type::NIL; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_true(zone** z)
|
|
|
|
{ object o; o.type = type::BOOLEAN; o.via.boolean = true; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_false(zone** z)
|
|
|
|
{ object o; o.type = type::BOOLEAN; o.via.boolean = false; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_array(zone** z, unsigned int n)
|
|
|
|
{
|
|
|
|
object o;
|
|
|
|
o.type = type::ARRAY;
|
|
|
|
o.via.container.size = 0;
|
|
|
|
o.via.container.ptr = (*z)->malloc_container(n);
|
|
|
|
return o;
|
|
|
|
}
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline void msgpack_unpack_array_item(zone** z, object* c, object o)
|
|
|
|
{ c->via.container.ptr[ c->via.container.size++ ] = o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_map(zone** z, unsigned int n)
|
|
|
|
{
|
|
|
|
object o;
|
|
|
|
o.type = type::MAP;
|
|
|
|
o.via.container.size = 0;
|
|
|
|
o.via.container.ptr = (*z)->malloc_container(n*2);
|
|
|
|
return o;
|
|
|
|
}
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline void msgpack_unpack_map_item(zone** z, object* c, object k, object v)
|
|
|
|
{
|
|
|
|
c->via.container.ptr[ c->via.container.size ] = k;
|
|
|
|
c->via.container.ptr[ c->via.container.size+1 ] = v;
|
|
|
|
++c->via.container.size;
|
|
|
|
}
|
2009-02-15 09:09:57 +00:00
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
static inline object msgpack_unpack_raw(zone** z, const char* b, const char* p, unsigned int l)
|
|
|
|
{ object o; o.type = type::RAW; o.via.ref.ptr = p; o.via.ref.size = l; return o; }
|
2009-02-15 09:09:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
#include "msgpack/unpack_template.h"
|
|
|
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
struct unpacker::context {
|
2009-02-15 09:09:56 +00:00
|
|
|
context(zone* z)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
|
|
|
msgpack_unpacker_init(&m_ctx);
|
2009-02-15 09:09:56 +00:00
|
|
|
m_ctx.user = z;
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~context() { }
|
|
|
|
|
2009-02-15 09:09:57 +00:00
|
|
|
int execute(const char* data, size_t len, size_t* off)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-15 09:09:57 +00:00
|
|
|
return msgpack_unpacker_execute(&m_ctx, data, len, off);
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
object data()
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
|
|
|
return msgpack_unpacker_data(&m_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
zone* z = m_ctx.user;
|
|
|
|
msgpack_unpacker_init(&m_ctx);
|
|
|
|
m_ctx.user = z;
|
|
|
|
}
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
void reset(zone* z)
|
|
|
|
{
|
|
|
|
msgpack_unpacker_init(&m_ctx);
|
|
|
|
m_ctx.user = z;
|
|
|
|
}
|
|
|
|
|
|
|
|
zone* user()
|
|
|
|
{
|
|
|
|
return m_ctx.user;
|
|
|
|
}
|
|
|
|
|
|
|
|
void user(zone* z)
|
|
|
|
{
|
|
|
|
m_ctx.user = z;
|
|
|
|
}
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
private:
|
2009-02-15 09:09:57 +00:00
|
|
|
msgpack_unpacker_context m_ctx;
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
context();
|
|
|
|
context(const context&);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
unpacker::unpacker(zone& z) :
|
|
|
|
m_ctx(new context(&z)),
|
2009-02-15 09:09:56 +00:00
|
|
|
m_buffer(NULL),
|
|
|
|
m_used(0),
|
|
|
|
m_free(0),
|
|
|
|
m_off(0)
|
2009-02-15 09:09:56 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
unpacker::~unpacker()
|
|
|
|
{
|
|
|
|
delete m_ctx;
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
|
2009-02-15 09:09:56 +00:00
|
|
|
void unpacker::expand_buffer(size_t len)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-15 09:09:56 +00:00
|
|
|
if(m_off == 0) {
|
|
|
|
size_t next_size;
|
|
|
|
if(m_free != 0) { next_size = m_free * 2; }
|
2009-02-15 09:09:56 +00:00
|
|
|
else { next_size = UNPACKER_INITIAL_BUFFER_SIZE; }
|
2009-02-15 09:09:56 +00:00
|
|
|
while(next_size < len + m_used) { next_size *= 2; }
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
m_buffer = m_ctx->user()->realloc(m_buffer, next_size);
|
2009-02-15 09:09:56 +00:00
|
|
|
m_free = next_size - m_used;
|
|
|
|
|
|
|
|
} else {
|
2009-02-15 09:09:56 +00:00
|
|
|
size_t next_size = UNPACKER_INITIAL_BUFFER_SIZE;
|
2009-02-15 09:09:56 +00:00
|
|
|
while(next_size < len + m_used - m_off) { next_size *= 2; }
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
char* tmp = m_ctx->user()->malloc(next_size);
|
2009-02-15 09:09:57 +00:00
|
|
|
memcpy(tmp, m_buffer+m_off, m_used-m_off);
|
2009-02-15 09:09:56 +00:00
|
|
|
|
|
|
|
m_buffer = tmp;
|
|
|
|
m_used = m_used - m_off;
|
|
|
|
m_free = next_size - m_used;
|
|
|
|
m_off = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool unpacker::execute()
|
|
|
|
{
|
|
|
|
int ret = m_ctx->execute(m_buffer, m_used, &m_off);
|
2009-02-15 09:09:56 +00:00
|
|
|
if(ret < 0) {
|
|
|
|
throw unpack_error("parse error");
|
2009-02-15 09:09:56 +00:00
|
|
|
} else if(ret == 0) {
|
|
|
|
return false;
|
2009-02-15 09:09:56 +00:00
|
|
|
} else {
|
2009-02-15 09:09:56 +00:00
|
|
|
expand_buffer(0);
|
2009-02-15 09:09:56 +00:00
|
|
|
return true;
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object unpacker::data()
|
|
|
|
{
|
2009-02-15 09:09:58 +00:00
|
|
|
return m_ctx->data();
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
2009-02-15 09:09:58 +00:00
|
|
|
void unpacker::reset(zone& z)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-15 09:09:56 +00:00
|
|
|
if(m_off != 0) { expand_buffer(0); }
|
2009-02-15 09:09:58 +00:00
|
|
|
m_ctx->reset(&z);
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-15 09:09:57 +00:00
|
|
|
object unpacker::unpack(const char* data, size_t len, zone& z, size_t* off)
|
2009-02-15 09:09:56 +00:00
|
|
|
{
|
2009-02-15 09:09:56 +00:00
|
|
|
context ctx(&z);
|
2009-02-15 09:09:57 +00:00
|
|
|
if(off) {
|
|
|
|
int ret = ctx.execute(data, len, off);
|
|
|
|
if(ret < 0) {
|
|
|
|
throw unpack_error("parse error");
|
|
|
|
} else if(ret == 0) {
|
|
|
|
throw unpack_error("insufficient bytes");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
size_t noff = 0;
|
|
|
|
int ret = ctx.execute(data, len, &noff);
|
|
|
|
if(ret < 0) {
|
|
|
|
throw unpack_error("parse error");
|
|
|
|
} else if(ret == 0) {
|
|
|
|
throw unpack_error("insufficient bytes");
|
|
|
|
} else if(noff < len) {
|
|
|
|
throw unpack_error("extra bytes");
|
|
|
|
}
|
2009-02-15 09:09:56 +00:00
|
|
|
}
|
|
|
|
return ctx.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace msgpack
|
|
|
|
|