diff --git a/c/object.c b/c/object.c new file mode 100644 index 00000000..7a410640 --- /dev/null +++ b/c/object.c @@ -0,0 +1,167 @@ +/* + * MessagePack for C dynamic typing 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. + */ +#include "msgpack/unpack.h" +#include "msgpack/unpack_define.h" +#include "msgpack/object.h" + +typedef struct { + msgpack_zone* z; + bool referenced; + bool failed; +} unpack_user; + +#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 + +#define msgpack_unpack_object msgpack_object + +#define msgpack_unpack_user unpack_user + + +struct msgpack_unpacker_context; + +static void msgpack_unpacker_init(struct msgpack_unpacker_context* ctx); + +static msgpack_object msgpack_unpacker_data(struct msgpack_unpacker_context* ctx); + +static int msgpack_unpacker_execute(struct msgpack_unpacker_context* ctx, + const char* data, size_t len, size_t* off); + +static inline msgpack_object msgpack_unpack_init(unpack_user* u) +{ msgpack_object o; return o; } + +static inline msgpack_object msgpack_unpack_uint8(unpack_user* u, uint8_t d) +{ msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + +static inline msgpack_object msgpack_unpack_uint16(unpack_user* u, uint16_t d) +{ msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + +static inline msgpack_object msgpack_unpack_uint32(unpack_user* u, uint32_t d) +{ msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + +static inline msgpack_object msgpack_unpack_uint64(unpack_user* u, uint64_t d) +{ msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + +static inline msgpack_object msgpack_unpack_int8(unpack_user* u, int8_t d) +{ if(d >= 0) { msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + else { msgpack_object o; o.type = MSGPACK_OBJECT_NEGATIVE_INTEGER; o.via.i64 = d; return o; } } + +static inline msgpack_object msgpack_unpack_int16(unpack_user* u, int16_t d) +{ if(d >= 0) { msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + else { msgpack_object o; o.type = MSGPACK_OBJECT_NEGATIVE_INTEGER; o.via.i64 = d; return o; } } + +static inline msgpack_object msgpack_unpack_int32(unpack_user* u, int32_t d) +{ if(d >= 0) { msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + else { msgpack_object o; o.type = MSGPACK_OBJECT_NEGATIVE_INTEGER; o.via.i64 = d; return o; } } + +static inline msgpack_object msgpack_unpack_int64(unpack_user* u, int64_t d) +{ if(d >= 0) { msgpack_object o; o.type = MSGPACK_OBJECT_POSITIVE_INTEGER; o.via.u64 = d; return o; } + else { msgpack_object o; o.type = MSGPACK_OBJECT_NEGATIVE_INTEGER; o.via.i64 = d; return o; } } + +static inline msgpack_object msgpack_unpack_float(unpack_user* u, float d) +{ msgpack_object o; o.type = MSGPACK_OBJECT_DOUBLE; o.via.dec = d; return o; } + +static inline msgpack_object msgpack_unpack_double(unpack_user* u, double d) +{ msgpack_object o; o.type = MSGPACK_OBJECT_DOUBLE; o.via.dec = d; return o; } + +static inline msgpack_object msgpack_unpack_nil(unpack_user* u) +{ msgpack_object o; o.type = MSGPACK_OBJECT_NIL; return o; } + +static inline msgpack_object msgpack_unpack_true(unpack_user* u) +{ msgpack_object o; o.type = MSGPACK_OBJECT_BOOLEAN; o.via.boolean = true; return o; } + +static inline msgpack_object msgpack_unpack_false(unpack_user* u) +{ msgpack_object o; o.type = MSGPACK_OBJECT_BOOLEAN; o.via.boolean = false; return o; } + +static inline msgpack_object msgpack_unpack_array(unpack_user* u, unsigned int n) +{ + msgpack_object o; + o.type = MSGPACK_OBJECT_ARRAY; + o.via.container.size = 0; + o.via.container.ptr = msgpack_zone_malloc(u->z, n*sizeof(msgpack_object)); + if(o.via.container.ptr == NULL) { u->failed = true; } + return o; +} + +static inline void msgpack_unpack_array_item(unpack_user* u, msgpack_object* c, msgpack_object o) +{ + if(u->failed) { return; } + c->via.container.ptr[ c->via.container.size++ ] = o; +} + +static inline msgpack_object msgpack_unpack_map(unpack_user* u, unsigned int n) +{ + msgpack_object o; + o.type = MSGPACK_OBJECT_MAP; + o.via.container.size = 0; + o.via.container.ptr = msgpack_zone_malloc(u->z, n*2*sizeof(msgpack_object)); + if(o.via.container.ptr == NULL) { u->failed = true; } + return o; +} + +static inline void msgpack_unpack_map_item(unpack_user* u, msgpack_object* c, msgpack_object k, msgpack_object v) +{ + if(u->failed) { return; } + c->via.container.ptr[ c->via.container.size ] = k; + c->via.container.ptr[ c->via.container.size+1 ] = v; + ++c->via.container.size; +} + +static inline msgpack_object msgpack_unpack_raw(unpack_user* u, const char* b, const char* p, unsigned int l) +{ + msgpack_object o; + o.type = MSGPACK_OBJECT_RAW; + o.via.ref.ptr = p; + o.via.ref.size = l; + u->referenced = true; + return o; +} + +#include "msgpack/unpack_template.h" + +msgpack_object_unpack_return +msgpack_object_unpack(const char* data, size_t len, size_t* off, + msgpack_zone* z, msgpack_object* result) +{ + struct msgpack_unpacker_context ctx; + msgpack_unpacker_init(&ctx); + unpack_user u = {z, false, false}; + ctx.user = u; + + size_t noff = (off ? *off : 0); + int ret = msgpack_unpacker_execute(&ctx, data, len, &noff); + if(ret < 0 || ctx.user.failed) { + return MSGPACK_OBJECT_PARSE_ERROR; + } else if(ret == 0) { + return MSGPACK_OBJECT_INSUFFICIENT_BYTES; + } + *result = msgpack_unpacker_data(&ctx); + if(off) { *off = noff; } + if(ret == 0) { + return MSGPACK_OBJECT_EXTRA_BYTES; + } + return MSGPACK_OBJECT_PARSE_SUCCESS; +} + + diff --git a/c/object.h b/c/object.h new file mode 100644 index 00000000..1b60c572 --- /dev/null +++ b/c/object.h @@ -0,0 +1,82 @@ +/* + * MessagePack for C dynamic typing 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_OBJECT_H__ +#define MSGPACK_OBJECT_H__ + +#include "msgpack/zone.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum { + MSGPACK_OBJECT_NIL = 0x01, + MSGPACK_OBJECT_BOOLEAN = 0x02, + MSGPACK_OBJECT_POSITIVE_INTEGER = 0x03, + MSGPACK_OBJECT_NEGATIVE_INTEGER = 0x04, + MSGPACK_OBJECT_DOUBLE = 0x05, + MSGPACK_OBJECT_RAW = 0x06, + MSGPACK_OBJECT_ARRAY = 0x07, + MSGPACK_OBJECT_MAP = 0x08, +} msgpack_object_type; + +struct _msgpack_object; + +typedef union { + bool boolean; + uint64_t u64; + int64_t i64; + double dec; + struct { + struct _msgpack_object* ptr; + uint32_t size; + } container; + struct { + const char* ptr; + uint32_t size; + } ref; +} msgpack_object_union; + +typedef struct _msgpack_object { + msgpack_object_type type; + msgpack_object_union via; +} msgpack_object; + + +typedef enum { + MSGPACK_OBJECT_PARSE_SUCCESS = 0, + MSGPACK_OBJECT_EXTRA_BYTES = 1, + MSGPACK_OBJECT_INSUFFICIENT_BYTES = -1, + MSGPACK_OBJECT_PARSE_ERROR = -2, +} msgpack_object_unpack_return; + +msgpack_object_unpack_return +msgpack_object_unpack(const char* data, size_t len, size_t* off, + msgpack_zone* z, msgpack_object* result); + + +#ifdef __cplusplus +} +#endif + +#endif /* msgpack/object.h */ + diff --git a/c/zone.c b/c/zone.c new file mode 100644 index 00000000..a41bb444 --- /dev/null +++ b/c/zone.c @@ -0,0 +1,103 @@ +/* + * MessagePack for C memory pool implementation + * + * 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. + */ +#include "msgpack/zone.h" +#include +#include + +typedef struct { + size_t free; + void* ptr; + void* alloc; +} msgpack_zone_chunk; + +struct _msgpack_zone { + msgpack_zone_chunk* array; + size_t ntail; + size_t usable; +}; + +msgpack_zone* msgpack_zone_new() +{ + return calloc(1, sizeof(msgpack_zone)); +} + +void msgpack_zone_free(msgpack_zone* z) +{ + if(z->array) { + size_t i; + for(i=0; i <= z->ntail; ++i) { + free(z->array[i].ptr); + } + } + free(z); +} + + +void* msgpack_zone_malloc(msgpack_zone* z, size_t size) +{ + if(!z->array) { + const size_t n = (sizeof(msgpack_zone_chunk) < 72/2) ? + 72 / sizeof(msgpack_zone_chunk) : 8; + msgpack_zone_chunk* array = + (msgpack_zone_chunk*)malloc(sizeof(msgpack_zone_chunk) * n); + if(!array) { return NULL; } + + size_t sz = 2048; /* FIXME chunk_size */ + while(sz < size) { sz *= 2; } + char* p = (char*)malloc(sz); + if(!p) { + free(array); + return NULL; + } + + z->array = array; + z->usable = n - 1; + array[0].free = sz - size; + array[0].ptr = p + size; + array[0].alloc = p; + return p; + } + + if(z->array[z->ntail].free > size) { + char* p = (char*)z->array[z->ntail].ptr; + z->array[z->ntail].ptr = p + size; + z->array[z->ntail].free -= size; + return p; + } + + if(z->usable <= z->ntail) { + const size_t n = (z->usable + 1) * 2; + msgpack_zone_chunk* tmp = + (msgpack_zone_chunk*)realloc(z->array, sizeof(msgpack_zone_chunk) * n); + if(!tmp) { return NULL; } + z->array = tmp; + z->usable = n - 1; + } + + size_t sz = 2048; /* FIXME chunk_size */ + while(sz < size) { sz *= 2; } + char* p = (char*)malloc(sz); + if(!p) { return NULL; } + + ++z->ntail; + z->array[z->ntail].free = sz - size; + z->array[z->ntail].ptr = p + size; + z->array[z->ntail].alloc = p; + return p; +} + diff --git a/c/zone.h b/c/zone.h new file mode 100644 index 00000000..ff6ca62f --- /dev/null +++ b/c/zone.h @@ -0,0 +1,42 @@ +/* + * MessagePack for C memory pool implementation + * + * 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_ZONE_H__ +#define MSGPACK_ZONE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +struct _msgpack_zone; +typedef struct _msgpack_zone msgpack_zone; + +msgpack_zone* msgpack_zone_new(); +void msgpack_zone_free(msgpack_zone* z); + +void* msgpack_zone_malloc(msgpack_zone* z, size_t size); + + +#ifdef __cplusplus +} +#endif + +#endif /* msgpack/zone.h */ +