summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfrsyuki <frsyuki@5a5092ae-2292-43ba-b2d5-dcab9c1a2731>2009-02-15 09:09:55 +0000
committerfrsyuki <frsyuki@5a5092ae-2292-43ba-b2d5-dcab9c1a2731>2009-02-15 09:09:55 +0000
commit269cda016dd6ea92b66e55ebe283965924e67bc1 (patch)
treefbfe2f8e3720be165a0180045b9be941d506417b
downloadmsgpack-python-269cda016dd6ea92b66e55ebe283965924e67bc1.tar.gz
lang/c/msgpack: added Messagepack, a binary-based efficient data interchange format.
git-svn-id: file:///Users/frsyuki/project/msgpack-git/svn/x@48 5a5092ae-2292-43ba-b2d5-dcab9c1a2731
-rw-r--r--README20
-rw-r--r--c/Makefile17
-rw-r--r--c/bench.c338
-rw-r--r--c/bench_inline.c329
l---------c/msgpack1
-rw-r--r--c/pack.c40
-rw-r--r--c/pack.h38
-rw-r--r--c/pack_inline.h14
-rw-r--r--c/unpack.c56
-rw-r--r--c/unpack.h59
-rw-r--r--c/unpack_context.h30
-rw-r--r--c/unpack_inline.c82
-rw-r--r--cpp/unpack.cc30
-rw-r--r--cpp/unpack.h126
-rw-r--r--cpp/unpack_context.h13
-rw-r--r--msgpack/pack/inline_context.h2
-rw-r--r--msgpack/pack/inline_impl.h287
-rw-r--r--msgpack/unpack/callback.h24
-rw-r--r--msgpack/unpack/inline_context.h52
-rw-r--r--msgpack/unpack/inline_impl.h438
-rw-r--r--ruby/Makefile153
-rw-r--r--ruby/bench.rb60
-rw-r--r--ruby/extconf.rb4
-rwxr-xr-xruby/gem.sh19
-rw-r--r--ruby/gem/AUTHORS1
-rw-r--r--ruby/gem/History.txt0
-rw-r--r--ruby/gem/License.txt13
-rw-r--r--ruby/gem/Manifest.txt26
-rw-r--r--ruby/gem/PostInstall.txt1
-rw-r--r--ruby/gem/Rakefile4
-rw-r--r--ruby/gem/config/hoe.rb75
-rw-r--r--ruby/gem/config/requirements.rb15
-rw-r--r--ruby/gem/lib/msgpack/version.rb9
-rwxr-xr-xruby/gem/script/console10
-rwxr-xr-xruby/gem/script/destroy14
-rwxr-xr-xruby/gem/script/generate14
-rwxr-xr-xruby/gem/script/txt2html82
-rw-r--r--ruby/gem/setup.rb1585
-rw-r--r--ruby/gem/tasks/deployment.rake34
-rw-r--r--ruby/gem/tasks/environment.rake7
-rw-r--r--ruby/pack.c131
-rw-r--r--ruby/pack.h26
-rw-r--r--ruby/pack_inline.h33
-rw-r--r--ruby/rbinit.c29
-rw-r--r--ruby/test_format.rb128
-rw-r--r--ruby/test_pack.rb56
-rw-r--r--ruby/unpack.c202
-rw-r--r--ruby/unpack.h26
-rw-r--r--ruby/unpack_context.h35
-rw-r--r--ruby/unpack_inline.c81
50 files changed, 4869 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..31a482a
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+MessagePack
+-----------
+Binary-based efficient data interchange format.
+
+
+
+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.
+
diff --git a/c/Makefile b/c/Makefile
new file mode 100644
index 0000000..d4b2226
--- /dev/null
+++ b/c/Makefile
@@ -0,0 +1,17 @@
+
+CFLAGS = -I.. -Wall -g -O4
+LDFLAGS = -L.
+
+all: bench
+
+bench: pack.o unpack.o unpack_inline.o bench.o pack.h pack_inline.h unpack.h unpack_context.h
+ $(CC) $(LDFLAGS) unpack.o unpack_inline.o pack.o bench.o -lyajl_s -o $@
+
+bench_inline: pack.o bench_inline.o pack.h pack_inline.h
+ $(CC) $(LDFLAGS) pack.o bench_inline.o -lyajl_s -o $@
+
+.PHONY: clean
+clean:
+ $(RM) unpack.o unpack_inline.o pack.o test.o bench.o bench_inline.o
+ $(RM) bench bench_inline
+
diff --git a/c/bench.c b/c/bench.c
new file mode 100644
index 0000000..f27350a
--- /dev/null
+++ b/c/bench.c
@@ -0,0 +1,338 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <msgpack/pack.h>
+#include <msgpack/unpack.h>
+#include <yajl/yajl_parse.h>
+#include <yajl/yajl_gen.h>
+
+
+static struct timeval g_timer;
+
+void reset_timer()
+{
+ gettimeofday(&g_timer, NULL);
+}
+
+double show_timer()
+{
+ struct timeval endtime;
+ gettimeofday(&endtime, NULL);
+ double sec = (endtime.tv_sec - g_timer.tv_sec)
+ + (double)(endtime.tv_usec - g_timer.tv_usec) / 1000 / 1000;
+ printf("%f sec\n", sec);
+ return sec;
+}
+
+
+static int reformat_null(void * ctx) { return 1; }
+static int reformat_boolean(void * ctx, int boolean) { return 1; }
+static int reformat_number(void * ctx, const char * s, unsigned int l) { return 1; }
+static int reformat_string(void * ctx, const unsigned char * stringVal, unsigned int stringLen) { return 1; }
+static int reformat_map_key(void * ctx, const unsigned char * stringVal, unsigned int stringLen) { return 1; }
+static int reformat_start_map(void * ctx) { return 1; }
+static int reformat_end_map(void * ctx) { return 1; }
+static int reformat_start_array(void * ctx) { return 1; }
+static int reformat_end_array(void * ctx) { return 1; }
+
+
+static void* unpack_unsigned_int_8(void* data, uint8_t d) { return NULL; }
+static void* unpack_unsigned_int_16(void* data, uint16_t d) { return NULL; }
+static void* unpack_unsigned_int_32(void* data, uint32_t d) { return NULL; }
+static void* unpack_unsigned_int_64(void* data, uint64_t d) { return NULL; }
+static void* unpack_signed_int_8(void* data, int8_t d) { return NULL; }
+static void* unpack_signed_int_16(void* data, int16_t d) { return NULL; }
+static void* unpack_signed_int_32(void* data, int32_t d) { return NULL; }
+static void* unpack_signed_int_64(void* data, int64_t d) { return NULL; }
+static void* unpack_float(void* data, float d) { return NULL; }
+static void* unpack_double(void* data, double d) { return NULL; }
+static void* unpack_nil(void* data) { return NULL; }
+static void* unpack_true(void* data) { return NULL; }
+static void* unpack_false(void* data) { return NULL; }
+static void* unpack_array_start(void* data, unsigned int n) { return NULL; }
+static void unpack_array_item(void* data, void* c, void* o) { }
+static void* unpack_map_start(void* data, unsigned int n) { return NULL; }
+static void unpack_map_item(void* data, void* c, void* k, void* v) { }
+static void* unpack_string(void* data, const void* b, size_t l) { return NULL; }
+static void* unpack_raw(void* data, const void* b, size_t l) { /*printf("unpack raw %p %lu\n",b,l);*/ return NULL; }
+
+typedef struct {
+ size_t allocated;
+ size_t length;
+ char* buffer;
+} pack_buffer;
+
+static const size_t PACK_INITIAL_BUFFER_SIZE = 512;
+
+static void pack_buffer_init(pack_buffer* data)
+{
+ data->buffer = malloc(PACK_INITIAL_BUFFER_SIZE);
+ data->length = 0;
+ data->allocated = PACK_INITIAL_BUFFER_SIZE;
+}
+
+static void pack_buffer_reset(pack_buffer* data)
+{
+ data->buffer = realloc(data->buffer, PACK_INITIAL_BUFFER_SIZE);
+ data->allocated = PACK_INITIAL_BUFFER_SIZE;
+ data->length = 0;
+}
+
+static void pack_buffer_free(pack_buffer* data)
+{
+ free(data->buffer);
+}
+
+static void pack_append_buffer(void* user, const unsigned char* b, unsigned int l)
+{
+ pack_buffer* data = (pack_buffer*)user;
+ if(data->allocated - data->length < l) {
+ data->buffer = realloc(data->buffer, data->allocated*2);
+ data->allocated *= 2;
+ }
+ memcpy(data->buffer + data->length, b, l);
+ data->length += l;
+}
+
+
+static const unsigned int TASK_INT_NUM = 1<<24;
+static const unsigned int TASK_STR_LEN = 1<<15;
+//static const unsigned int TASK_INT_NUM = 1<<20;
+//static const unsigned int TASK_STR_LEN = 1<<12;
+static const char* TASK_STR_PTR;
+
+
+void bench_json(void)
+{
+ puts("== JSON ==");
+
+
+ yajl_gen_config gcfg = {0, NULL};
+ yajl_gen g = yajl_gen_alloc(&gcfg);
+
+ yajl_parser_config hcfg = { 0, 0 };
+ yajl_callbacks callbacks = {
+ reformat_null,
+ reformat_boolean,
+ NULL,
+ NULL,
+ reformat_number,
+ reformat_string,
+ reformat_start_map,
+ reformat_map_key,
+ reformat_end_map,
+ reformat_start_array,
+ reformat_end_array
+ };
+ yajl_handle h = yajl_alloc(&callbacks, &hcfg, NULL);
+
+
+ double sec;
+ const unsigned char * buf;
+ unsigned int len;
+
+
+ puts("generate integer");
+ reset_timer();
+ {
+ unsigned int i;
+ yajl_gen_array_open(g);
+ for(i=0; i < TASK_INT_NUM; ++i) {
+ yajl_gen_integer(g, i);
+ }
+ yajl_gen_array_close(g);
+ }
+ sec = show_timer();
+
+ yajl_gen_get_buf(g, &buf, &len);
+ printf("%u KB\n", len / 1024);
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("parse integer");
+ reset_timer();
+ {
+ yajl_status stat = yajl_parse(h, buf, len);
+ if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
+ unsigned char * str = yajl_get_error(h, 1, buf, len);
+ fprintf(stderr, (const char *) str);
+ }
+ }
+ sec = show_timer();
+
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+
+ //yajl_gen_clear(g);
+ yajl_gen_free(g);
+ g = yajl_gen_alloc(&gcfg);
+ yajl_free(h);
+ h = yajl_alloc(&callbacks, &hcfg, NULL);
+
+
+ puts("----");
+ puts("generate string");
+ reset_timer();
+ {
+ unsigned int i;
+ yajl_gen_array_open(g);
+ for(i=0; i < TASK_STR_LEN; ++i) {
+ yajl_gen_string(g, (const unsigned char*)TASK_STR_PTR, i);
+ }
+ yajl_gen_array_close(g);
+ }
+ sec = show_timer();
+
+ yajl_gen_get_buf(g, &buf, &len);
+ printf("%u KB\n", len / 1024);
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("parse string");
+ reset_timer();
+ {
+ yajl_status stat = yajl_parse(h, buf, len);
+ if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
+ unsigned char * str = yajl_get_error(h, 1, buf, len);
+ fprintf(stderr, (const char *) str);
+ }
+ }
+ sec = show_timer();
+
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+
+ yajl_gen_free(g);
+ yajl_free(h);
+}
+
+void bench_msgpack(void)
+{
+ puts("== MessagePack ==");
+
+
+ pack_buffer mpkbuf;
+ pack_buffer_init(&mpkbuf);
+ msgpack_pack_t* mpk = msgpack_pack_new(
+ &mpkbuf, pack_append_buffer);
+
+ msgpack_unpack_callback cb = {
+ unpack_unsigned_int_8,
+ unpack_unsigned_int_16,
+ unpack_unsigned_int_32,
+ unpack_unsigned_int_64,
+ unpack_signed_int_8,
+ unpack_signed_int_16,
+ unpack_signed_int_32,
+ unpack_signed_int_64,
+ unpack_float,
+ unpack_double,
+ unpack_nil,
+ unpack_true,
+ unpack_false,
+ unpack_array_start,
+ unpack_array_item,
+ unpack_map_start,
+ unpack_map_item,
+ unpack_string,
+ unpack_raw,
+ };
+ msgpack_unpack_t* mupk = msgpack_unpack_new(NULL, &cb);
+
+
+ double sec;
+ size_t len;
+ const char* buf;
+
+
+ puts("pack integer");
+ reset_timer();
+ {
+ unsigned int i;
+ msgpack_pack_array(mpk, TASK_INT_NUM);
+ for(i=0; i < TASK_INT_NUM; ++i) {
+ msgpack_pack_unsigned_int(mpk, i);
+ }
+ }
+ sec = show_timer();
+
+ len = mpkbuf.length;
+ buf = mpkbuf.buffer;
+ printf("%lu KB\n", len / 1024);
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("unpack integer");
+ reset_timer();
+ {
+ size_t off = 0;
+ int ret = msgpack_unpack_execute(mupk, buf, len, &off);
+ if(ret < 0) {
+ fprintf(stderr, "Parse error.\n");
+ } else if(ret == 0) {
+ fprintf(stderr, "Not finished.\n");
+ }
+ }
+ sec = show_timer();
+
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+
+ pack_buffer_reset(&mpkbuf);
+ msgpack_unpack_reset(mupk);
+
+
+ puts("----");
+ puts("pack string");
+ reset_timer();
+ {
+ unsigned int i;
+ msgpack_pack_array(mpk, TASK_STR_LEN);
+ for(i=0; i < TASK_STR_LEN; ++i) {
+ msgpack_pack_raw(mpk, TASK_STR_PTR, i);
+ }
+ }
+ sec = show_timer();
+
+ len = mpkbuf.length;
+ buf = mpkbuf.buffer;
+ printf("%lu KB\n", len / 1024);
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("unpack string");
+ reset_timer();
+ {
+ size_t off = 0;
+ int ret = msgpack_unpack_execute(mupk, buf, len, &off);
+ if(ret < 0) {
+ fprintf(stderr, "Parse error.\n");
+ } else if(ret == 0) {
+ fprintf(stderr, "Not finished.\n");
+ }
+ }
+ sec = show_timer();
+
+ printf("%f MB/s\n", len / sec / 1024 / 1024);
+
+
+ msgpack_unpack_free(mupk);
+ msgpack_pack_free(mpk);
+ pack_buffer_free(&mpkbuf);
+}
+
+int main(int argc, char* argv[])
+{
+ char* str = malloc(TASK_STR_LEN);
+ memset(str, 'a', TASK_STR_LEN);
+ TASK_STR_PTR = str;
+
+ bench_msgpack();
+ bench_json();
+
+ return 0;
+}
+
+
diff --git a/c/bench_inline.c b/c/bench_inline.c
new file mode 100644
index 0000000..2901508
--- /dev/null
+++ b/c/bench_inline.c
@@ -0,0 +1,329 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <msgpack/pack.h>
+#include <msgpack/unpack.h>
+#include <yajl/yajl_parse.h>
+#include <yajl/yajl_gen.h>
+
+
+static struct timeval g_timer;
+
+void reset_timer()
+{
+ gettimeofday(&g_timer, NULL);
+}
+
+double show_timer()
+{
+ struct timeval endtime;
+ gettimeofday(&endtime, NULL);
+ double sec = (endtime.tv_sec - g_timer.tv_sec)
+ + (double)(endtime.tv_usec - g_timer.tv_usec) / 1000 / 1000;
+ printf("%f sec\n", sec);
+ return sec;
+}
+
+
+static int reformat_null(void * ctx) { return 1; }
+static int reformat_boolean(void * ctx, int boolean) { return 1; }
+static int reformat_number(void * ctx, const char * s, unsigned int l) { return 1; }
+static int reformat_string(void * ctx, const unsigned char * stringVal, unsigned int stringLen) { return 1; }
+static int reformat_map_key(void * ctx, const unsigned char * stringVal, unsigned int stringLen) { return 1; }
+static int reformat_start_map(void * ctx) { return 1; }
+static int reformat_end_map(void * ctx) { return 1; }
+static int reformat_start_array(void * ctx) { return 1; }
+static int reformat_end_array(void * ctx) { return 1; }
+
+
+typedef void* msgpack_object;
+
+typedef struct {
+} msgpack_unpack_context;
+
+#include "msgpack/unpack/inline_context.h"
+
+static inline void* msgpack_unpack_init(msgpack_unpack_context* x) { return NULL; }
+static inline void* msgpack_unpack_unsigned_int_8(msgpack_unpack_context* x, uint8_t d) { return NULL; }
+static inline void* msgpack_unpack_unsigned_int_16(msgpack_unpack_context* x, uint16_t d) { return NULL; }
+static inline void* msgpack_unpack_unsigned_int_32(msgpack_unpack_context* x, uint32_t d) { return NULL; }
+static inline void* msgpack_unpack_unsigned_int_64(msgpack_unpack_context* x, uint64_t d) { return NULL; }
+static inline void* msgpack_unpack_signed_int_8(msgpack_unpack_context* x, int8_t d) { return NULL; }
+static inline void* msgpack_unpack_signed_int_16(msgpack_unpack_context* x, int16_t d) { return NULL; }
+static inline void* msgpack_unpack_signed_int_32(msgpack_unpack_context* x, int32_t d) { return NULL; }
+static inline void* msgpack_unpack_signed_int_64(msgpack_unpack_context* x, int64_t d) { return NULL; }
+static inline void* msgpack_unpack_float(msgpack_unpack_context* x, float d) { return NULL; }
+static inline void* msgpack_unpack_double(msgpack_unpack_context* x, double d) { return NULL; }
+static inline void* msgpack_unpack_big_int(msgpack_unpack_context* x, const void* b, unsigned int l) { return NULL; }
+static inline void* msgpack_unpack_big_float(msgpack_unpack_context* x, const void* b, unsigned int l) { return NULL; }
+static inline void* msgpack_unpack_nil(msgpack_unpack_context* x) { return NULL; }
+static inline void* msgpack_unpack_true(msgpack_unpack_context* x) { return NULL; }
+static inline void* msgpack_unpack_false(msgpack_unpack_context* x) { return NULL; }
+static inline void* msgpack_unpack_array_start(msgpack_unpack_context* x, unsigned int n) { return NULL; }
+static inline void msgpack_unpack_array_item(msgpack_unpack_context* x, void* c, void* o) { }
+static inline void* msgpack_unpack_map_start(msgpack_unpack_context* x, unsigned int n) { return NULL; }
+static inline void msgpack_unpack_map_item(msgpack_unpack_context* x, void* c, void* k, void* v) { }
+static inline void* msgpack_unpack_string(msgpack_unpack_context* x, const void* b, size_t l) { return NULL; }
+static inline void* msgpack_unpack_raw(msgpack_unpack_context* x, const void* b, size_t l) { return NULL; }
+
+#include "msgpack/unpack/inline_impl.h"
+
+typedef struct {
+ size_t allocated;
+ size_t length;
+ char* buffer;
+} pack_buffer;
+
+static const size_t PACK_INITIAL_BUFFER_SIZE = 512;
+
+static void pack_buffer_init(pack_buffer* data)
+{
+ data->buffer = malloc(PACK_INITIAL_BUFFER_SIZE);
+ data->length = 0;
+ data->allocated = PACK_INITIAL_BUFFER_SIZE;
+}
+
+static void pack_buffer_reset(pack_buffer* data)
+{
+ data->buffer = realloc(data->buffer, PACK_INITIAL_BUFFER_SIZE);
+ data->allocated = PACK_INITIAL_BUFFER_SIZE;
+ data->length = 0;
+}
+
+static void pack_buffer_free(pack_buffer* data)
+{
+ free(data->buffer);
+}
+
+static void pack_append_buffer(void* user, const unsigned char* b, unsigned int l)
+{
+ pack_buffer* data = (pack_buffer*)user;
+ if(data->allocated - data->length < l) {
+ data->buffer = realloc(data->buffer, data->allocated*2);
+ data->allocated *= 2;
+ }
+ memcpy(data->buffer + data->length, b, l);
+ data->length += l;
+}
+
+
+static const unsigned int TASK_INT_NUM = 1<<24;
+static const unsigned int TASK_STR_LEN = 1<<15;
+//static const unsigned int TASK_INT_NUM = 1<<20;
+//static const unsigned int TASK_STR_LEN = 1<<12;
+static const char* TASK_STR_PTR;
+
+
+void bench_json(void)
+{
+ puts("== JSON ==");
+
+
+ yajl_gen_config gcfg = {0, NULL};
+ yajl_gen g = yajl_gen_alloc(&gcfg);
+
+ yajl_parser_config hcfg = { 0, 0 };
+ yajl_callbacks callbacks = {
+ reformat_null,
+ reformat_boolean,
+ NULL,
+ NULL,
+ reformat_number,
+ reformat_string,
+ reformat_start_map,
+ reformat_map_key,
+ reformat_end_map,
+ reformat_start_array,
+ reformat_end_array
+ };
+ yajl_handle h = yajl_alloc(&callbacks, &hcfg, NULL);
+
+
+ double sec;
+ const unsigned char * buf;
+ unsigned int len;
+
+
+ puts("generate integer");
+ reset_timer();
+ {
+ unsigned int i;
+ yajl_gen_array_open(g);
+ for(i=0; i < TASK_INT_NUM; ++i) {
+ yajl_gen_integer(g, i);
+ }
+ yajl_gen_array_close(g);
+ }
+ sec = show_timer();
+
+ yajl_gen_get_buf(g, &buf, &len);
+ printf("%u KB\n", len / 1024);
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("parse integer");
+ reset_timer();
+ {
+ yajl_status stat = yajl_parse(h, buf, len);
+ if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
+ unsigned char * str = yajl_get_error(h, 1, buf, len);
+ fprintf(stderr, (const char *) str);
+ }
+ }
+ sec = show_timer();
+
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+
+ //yajl_gen_clear(g);
+ yajl_gen_free(g);
+ g = yajl_gen_alloc(&gcfg);
+ yajl_free(h);
+ h = yajl_alloc(&callbacks, &hcfg, NULL);
+
+
+ puts("----");
+ puts("generate string");
+ reset_timer();
+ {
+ unsigned int i;
+ yajl_gen_array_open(g);
+ for(i=0; i < TASK_STR_LEN; ++i) {
+ yajl_gen_string(g, (const unsigned char*)TASK_STR_PTR, i);
+ }
+ yajl_gen_array_close(g);
+ }
+ sec = show_timer();
+
+ yajl_gen_get_buf(g, &buf, &len);
+ printf("%u KB\n", len / 1024);
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("parse string");
+ reset_timer();
+ {
+ yajl_status stat = yajl_parse(h, buf, len);
+ if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
+ unsigned char * str = yajl_get_error(h, 1, buf, len);
+ fprintf(stderr, (const char *) str);
+ }
+ }
+ sec = show_timer();
+
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+
+ yajl_gen_free(g);
+ yajl_free(h);
+}
+
+void bench_msgpack(void)
+{
+ puts("== MessagePack ==");
+
+
+ pack_buffer mpkbuf;
+ pack_buffer_init(&mpkbuf);
+ msgpack_pack_t* mpk = msgpack_pack_new(
+ &mpkbuf, pack_append_buffer);
+
+ msgpack_unpacker mupk;
+ msgpack_unpacker_init(&mupk);
+
+ double sec;
+ size_t len;
+ const char* buf;
+
+
+ puts("pack integer");
+ reset_timer();
+ {
+ unsigned int i;
+ msgpack_pack_array(mpk, TASK_INT_NUM);
+ for(i=0; i < TASK_INT_NUM; ++i) {
+ msgpack_pack_unsigned_int(mpk, i);
+ }
+ }
+ sec = show_timer();
+
+ len = mpkbuf.length;
+ buf = mpkbuf.buffer;
+ printf("%lu KB\n", len / 1024);
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("unpack integer");
+ reset_timer();
+ {
+ size_t off = 0;
+ int ret = msgpack_unpacker_execute(&mupk, buf, len, &off);
+ if(ret < 0) {
+ fprintf(stderr, "Parse error.\n");
+ } else if(ret == 0) {
+ fprintf(stderr, "Not finished.\n");
+ }
+ }
+ sec = show_timer();
+
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+
+ pack_buffer_reset(&mpkbuf);
+ msgpack_unpacker_init(&mupk);
+
+
+ puts("----");
+ puts("pack string");
+ reset_timer();
+ {
+ unsigned int i;
+ msgpack_pack_array(mpk, TASK_STR_LEN);
+ for(i=0; i < TASK_STR_LEN; ++i) {
+ msgpack_pack_raw(mpk, TASK_STR_PTR, i);
+ }
+ }
+ sec = show_timer();
+
+ len = mpkbuf.length;
+ buf = mpkbuf.buffer;
+ printf("%lu KB\n", len / 1024);
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+ puts("----");
+ puts("unpack string");
+ reset_timer();
+ {
+ size_t off = 0;
+ int ret = msgpack_unpacker_execute(&mupk, buf, len, &off);
+ if(ret < 0) {
+ fprintf(stderr, "Parse error.\n");
+ } else if(ret == 0) {
+ fprintf(stderr, "Not finished.\n");
+ }
+ }
+ sec = show_timer();
+
+ printf("%f Mbps\n", len / sec / 1024 / 1024);
+
+
+ msgpack_pack_free(mpk);
+ pack_buffer_free(&mpkbuf);
+}
+
+int main(int argc, char* argv[])
+{
+ char* str = malloc(TASK_STR_LEN);
+ memset(str, 'a', TASK_STR_LEN);
+ TASK_STR_PTR = str;
+
+ bench_msgpack();
+ //bench_json();
+
+ return 0;
+}
+
+
+
diff --git a/c/msgpack b/c/msgpack
new file mode 120000
index 0000000..945c9b4
--- /dev/null
+++ b/c/msgpack
@@ -0,0 +1 @@
+. \ No newline at end of file
diff --git a/c/pack.c b/c/pack.c
new file mode 100644
index 0000000..05bd38d
--- /dev/null
+++ b/c/pack.c
@@ -0,0 +1,40 @@
+/*
+ * MessagePack packing routine for C
+ *
+ * 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.
+ */
+#include "pack_inline.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+msgpack_pack_t* msgpack_pack_new(void* data, msgpack_pack_callback_t callback)
+{
+ msgpack_pack_t* ctx = calloc(1, sizeof(msgpack_pack_t));
+ if(!ctx) { return NULL; }
+ ctx->data = data;
+ ctx->callback = callback;
+ return ctx;
+}
+
+void msgpack_pack_free(msgpack_pack_t* ctx)
+{
+ free(ctx);
+}
+
+static inline void msgpack_pack_append_buffer(msgpack_pack_t* ctx, const unsigned char* b, unsigned int l)
+{
+ ctx->callback(ctx->data, b, l);
+}
+
diff --git a/c/pack.h b/c/pack.h
new file mode 100644
index 0000000..8107d9f
--- /dev/null
+++ b/c/pack.h
@@ -0,0 +1,38 @@
+#ifndef MSGPACK_PACK_H__
+#define MSGPACK_PACK_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef void (*msgpack_pack_callback_t)(void* data, const unsigned char* b, unsigned int i);
+
+typedef struct {
+ void* data;
+ msgpack_pack_callback_t callback;
+} msgpack_pack_t;
+
+msgpack_pack_t* msgpack_pack_new(void* data, msgpack_pack_callback_t callback);
+void msgpack_pack_free(msgpack_pack_t* ctx);
+
+void msgpack_pack_int(msgpack_pack_t* ctx, int d);
+void msgpack_pack_unsigned_int(msgpack_pack_t* ctx, unsigned int d);
+void msgpack_pack_unsigned_int_8(msgpack_pack_t* ctx, uint8_t d);
+void msgpack_pack_unsigned_int_16(msgpack_pack_t* ctx, uint16_t d);
+void msgpack_pack_unsigned_int_32(msgpack_pack_t* ctx, uint32_t d);
+void msgpack_pack_unsigned_int_64(msgpack_pack_t* ctx, uint64_t d);
+void msgpack_pack_signed_int_8(msgpack_pack_t* ctx, int8_t d);
+void msgpack_pack_signed_int_16(msgpack_pack_t* ctx, int16_t d);
+void msgpack_pack_signed_int_32(msgpack_pack_t* ctx, int32_t d);
+void msgpack_pack_signed_int_64(msgpack_pack_t* ctx, int64_t d);
+void msgpack_pack_float(msgpack_pack_t* ctx, float d);
+void msgpack_pack_double(msgpack_pack_t* ctx, double d);
+void msgpack_pack_nil(msgpack_pack_t* ctx);
+void msgpack_pack_true(msgpack_pack_t* ctx);
+void msgpack_pack_false(msgpack_pack_t* ctx);
+void msgpack_pack_array(msgpack_pack_t* ctx, unsigned int n);
+void msgpack_pack_map(msgpack_pack_t* ctx, unsigned int n);
+void msgpack_pack_string(msgpack_pack_t* ctx, const char* b);
+void msgpack_pack_raw(msgpack_pack_t* ctx, const void* b, size_t l);
+
+#endif /* msgpack/pack.h */
+
diff --git a/c/pack_inline.h b/c/pack_inline.h
new file mode 100644
index 0000000..d943464
--- /dev/null
+++ b/c/pack_inline.h
@@ -0,0 +1,14 @@
+#ifndef PACK_INLINE_H__
+#define PACK_INLINE_H__
+
+#include "pack.h"
+
+typedef msgpack_pack_t* msgpack_pack_context;
+
+static inline void msgpack_pack_append_buffer(msgpack_pack_t* x, const unsigned char* b, unsigned int l);
+
+#include "msgpack/pack/inline_impl.h"
+
+
+#endif /* pack_inline.h */
+
diff --git a/c/unpack.c b/c/unpack.c
new file mode 100644
index 0000000..9fe3695
--- /dev/null
+++ b/c/unpack.c
@@ -0,0 +1,56 @@
+/*
+ * MessagePack packing routine for C
+ *
+ * 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.
+ */
+#include "unpack.h"
+#include "unpack_context.h"
+#include <stdlib.h>
+
+msgpack_unpack_t* msgpack_unpack_new(void* data, msgpack_unpack_callback* callback)
+{
+ msgpack_unpacker* ctx;
+ ctx = (msgpack_unpacker*)calloc(1, sizeof(msgpack_unpacker));
+ if(ctx == NULL) { return NULL; }
+ msgpack_unpacker_init(ctx);
+ ((msgpack_unpack_t*)ctx)->data = data;
+ ((msgpack_unpack_t*)ctx)->callback = *callback;
+ return (msgpack_unpack_t*)ctx;
+}
+
+void msgpack_unpack_free(msgpack_unpack_t* ctx)
+{
+ free((msgpack_unpacker*)ctx);
+}
+
+void* msgpack_unpack_data(msgpack_unpack_t* ctx)
+{
+ return msgpack_unpacker_data((msgpack_unpacker*)ctx);
+}
+
+void msgpack_unpack_reset(msgpack_unpack_t* ctx)
+{
+ msgpack_unpack_t x = ((msgpack_unpacker*)ctx)->user;
+ msgpack_unpacker_init((msgpack_unpacker*)ctx);
+ ((msgpack_unpacker*)ctx)->user = x;
+}
+
+int msgpack_unpack_execute(msgpack_unpack_t* ctx, const char* data, size_t len, size_t* off)
+{
+ return msgpack_unpacker_execute(
+ (msgpack_unpacker*)ctx,
+ data, len, off);
+}
+
diff --git a/c/unpack.h b/c/unpack.h
new file mode 100644
index 0000000..3230a0d
--- /dev/null
+++ b/c/unpack.h
@@ -0,0 +1,59 @@
+/*
+ * MessagePack unpacking routine for C
+ *
+ * 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.
+ */
+#ifndef MSGPACK_UNPACK_H__
+#define MSGPACK_UNPACK_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct {
+ void* (*unpack_unsigned_int_8)(void* data, uint8_t d);
+ void* (*unpack_unsigned_int_16)(void* data, uint16_t d);
+ void* (*unpack_unsigned_int_32)(void* data, uint32_t d);
+ void* (*unpack_unsigned_int_64)(void* data, uint64_t d);
+ void* (*unpack_signed_int_8)(void* data, int8_t d);
+ void* (*unpack_signed_int_16)(void* data, int16_t d);
+ void* (*unpack_signed_int_32)(void* data, int32_t d);
+ void* (*unpack_signed_int_64)(void* data, int64_t d);
+ void* (*unpack_float)(void* data, float d);
+ void* (*unpack_double)(void* data, double d);
+ void* (*unpack_nil)(void* data);
+ void* (*unpack_true)(void* data);
+ void* (*unpack_false)(void* data);
+ void* (*unpack_array_start)(void* data, unsigned int n);
+ void (*unpack_array_item)(void* data, void* c, void* o);
+ void* (*unpack_map_start)(void* data, unsigned int n);
+ void (*unpack_map_item)(void* data, void* c, void* k, void* v);
+ void* (*unpack_string)(void* data, const void* b, size_t l);
+ void* (*unpack_raw)(void* data, const void* b, size_t l);
+} msgpack_unpack_callback;
+
+typedef struct {
+ void* data;
+ msgpack_unpack_callback callback;
+} msgpack_unpack_t;
+
+msgpack_unpack_t* msgpack_unpack_new(void* data, msgpack_unpack_callback* callback);
+void msgpack_unpack_free(msgpack_unpack_t* ctx);
+void msgpack_unpack_reset(msgpack_unpack_t* ctx);
+
+int msgpack_unpack_execute(msgpack_unpack_t* ctx, const char* data, size_t len, size_t* off);
+void* msgpack_unpack_data(msgpack_unpack_t* ctx);
+
+#endif /* msgpack/unpack.h */
+
diff --git a/c/unpack_context.h b/c/unpack_context.h
new file mode 100644
index 0000000..7337c9e
--- /dev/null
+++ b/c/unpack_context.h
@@ -0,0 +1,30 @@
+/*
+ * MessagePack unpacking routine for C
+ *
+ * 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.
+ */
+#ifndef UNPACK_CONTEXT_H__
+#define UNPACK_CONTEXT_H__
+
+#include "unpack.h"
+
+typedef void* msgpack_object;
+
+typedef msgpack_unpack_t msgpack_unpack_context;
+
+#include "msgpack/unpack/inline_context.h"
+
+#endif /* unpack_context.h */
+
diff --git a/c/unpack_inline.c b/c/unpack_inline.c
new file mode 100644
index 0000000..3525468
--- /dev/null
+++ b/c/unpack_inline.c
@@ -0,0 +1,82 @@
+/*
+ * MessagePack unpacking routine for C
+ *
+ * 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.
+ */
+#include "unpack_context.h"
+
+static inline void* msgpack_unpack_init(msgpack_unpack_t* x)
+{ return NULL; }
+
+static inline void* msgpack_unpack_unsigned_int_8(msgpack_unpack_t* x, uint8_t d)
+{ return x->callback.unpack_unsigned_int_8(x->data, d); }
+
+static inline void* msgpack_unpack_unsigned_int_16(msgpack_unpack_t* x, uint16_t d)
+{ return x->callback.unpack_unsigned_int_16(x->data, d); }
+
+static inline void* msgpack_unpack_unsigned_int_32(msgpack_unpack_t* x, uint32_t d)
+{ return x->callback.unpack_unsigned_int_32(x->data, d); }
+
+static inline void* msgpack_unpack_unsigned_int_64(msgpack_unpack_t* x, uint64_t d)
+{ return x->callback.unpack_unsigned_int_64(x->data, d); }
+
+static inline void* msgpack_unpack_signed_int_8(msgpack_unpack_t* x, int8_t d)
+{ return x->callback.unpack_signed_int_8(x->data, d); }
+
+static inline void* msgpack_unpack_signed_int_16(msgpack_unpack_t* x, int16_t d)
+{ return x->callback.unpack_signed_int_16(x->data, d); }
+
+static inline void* msgpack_unpack_signed_int_32(msgpack_unpack_t* x, int32_t d)
+{ return x->callback.unpack_signed_int_32(x->data, d); }
+
+static inline void* msgpack_unpack_signed_int_64(msgpack_unpack_t* x, int64_t d)
+{ return x->callback.unpack_signed_int_64(x->data, d); }
+
+static inline void* msgpack_unpack_float(msgpack_unpack_t* x, float d)
+{ return x->callback.unpack_float(x->data, d); }
+
+static inline void* msgpack_unpack_double(msgpack_unpack_t* x, double d)
+{ return x->callback.unpack_double(x->data, d); }
+
+static inline void* msgpack_unpack_nil(msgpack_unpack_t* x)
+{ return x->callback.unpack_nil(x->data); }
+
+static inline void* msgpack_unpack_true(msgpack_unpack_t* x)
+{ return x->callback.unpack_true(x->data); }
+
+static inline void* msgpack_unpack_false(msgpack_unpack_t* x)
+{ return x->callback.unpack_false(x->data); }
+
+static inline void* msgpack_unpack_array_start(msgpack_unpack_t* x, unsigned int n)
+{ return x->callback.unpack_array_start(x->data, n); }
+
+static inline void msgpack_unpack_array_item(msgpack_unpack_t* x, void* c, void* o)
+{ x->callback.unpack_array_item(x->data, c, o); }
+
+static inline void* msgpack_unpack_map_start(msgpack_unpack_t* x, unsigned int n)
+{ return x->callback.unpack_map_start(x->data, n); }
+
+static inline void msgpack_unpack_map_item(msgpack_unpack_t* x, void* c, void* k, void* v)
+{ x->callback.unpack_map_item(x->data, c, k, v); }
+
+static inline void* msgpack_unpack_string(msgpack_unpack_t* x, const void* b, size_t l)
+{ return x->callback.unpack_string(x->data, b, l); }
+
+static inline void* msgpack_unpack_raw(msgpack_unpack_t* x, const void* b, size_t l)
+{ return x->callback.unpack_raw(x->data, b, l); }
+
+
+#include "msgpack/unpack/inline_impl.h"
+
diff --git a/cpp/unpack.cc b/cpp/unpack.cc
new file mode 100644
index 0000000..ce57e67
--- /dev/null
+++ b/cpp/unpack.cc
@@ -0,0 +1,30 @@
+#include "unpack.h"
+#include "unpack_context.h"
+#include <stdlib.h>
+
+msgpack_unpack_t* msgpack_unpack_new(void)
+{
+ msgpack_unpacker* ctx;
+ ctx = (msgpack_unpacker*)calloc(1, sizeof(msgpack_unpacker));
+ if(ctx == NULL) { return NULL; }
+ msgpack_unpacker_init(ctx);
+ return (msgpack_unpack_t*)ctx;
+}
+
+void msgpack_unpack_free(msgpack_unpack_t* ctx)
+{
+ free((msgpack_unpacker*)ctx);
+}
+
+int msgpack_unpack_execute(msgpack_unpack_t* ctx, const char* data, size_t len, size_t* off)
+{
+ return msgpack_unpacker_execute(
+ (msgpack_unpacker*)ctx,
+ data, len, off);
+}
+
+void* msgpack_unpack_data(msgpack_unpack_t* ctx)
+{
+ return msgpack_unpacker_data((msgpack_unpacker*)ctx);
+}
+
diff --git a/cpp/unpack.h b/cpp/unpack.h
new file mode 100644
index 0000000..cf7a168
--- /dev/null
+++ b/cpp/unpack.h
@@ -0,0 +1,126 @@
+#ifndef MSGPACK_UNPACK_H__
+#define MSGPACK_UNPACK_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+namespace MessagePack {
+
+class Unpacker {
+ class object {
+ template <typename T>
+ object(const T& x) : m_obj(new holder<T>(x)) {}
+ };
+
+ class type_error : public std::exception { };
+ class cast_error : public type_error { };
+ class overflow_error : public type_error { };
+ class underflow_error : public type_error { };
+
+ struct object {
+ virtual ~object() {}
+ virtual bool isnil() const { return false; }
+ virtual bool xbool() const { throw cast_error(); }
+ virtual uint8_t xu8() const { throw cast_error(); }
+ virtual uint16_t xu16() const { throw cast_error(); }
+ virtual uint32_t xu32() const { throw cast_error(); }
+ virtual uint64_t xu64() const { throw cast_error(); }
+ virtual int8_t xi8() const { throw cast_error(); }
+ virtual int16_t xi16() const { throw cast_error(); }
+ virtual int32_t xi32() const { throw cast_error(); }
+ virtual int64_t xi64() const { throw cast_error(); }
+ virtual float xfloat() const { throw cast_error(); }
+ virtual double xdouble() const { throw cast_error(); }
+ virtual std::map<object, object>& xmap() const { throw cast_error(); }
+ virtual std::string& xstring() const { throw cast_error(); }
+ virtual std::pair<const char*, size_t> xraw() const { throw cast_error(); }
+ public:
+ template <typename T, typename X>
+ inline void check_overflow(X x) {
+ if(std::numeric_limits<T>::max() < x) { throw overflow_error(); }
+ }
+ template <typename T, typename X>
+ inline void check_underflow(X x) {
+ if(std::numeric_limits<T>::min() > x) { throw overflow_error(); }
+ }
+ };
+
+private:
+ struct object_nil : object {
+ bool isnil() const { return true; }
+ };
+
+ struct object_true : object {
+ bool xbool() const { return true; }
+ };
+
+ struct object_false : object {
+ bool xbool() const { return false; }
+ };
+
+ struct object_u8 : object {
+ object_u8(uint8_t val) : m_val(val) {}
+ uint8_t xu8() const { return m_val; }
+ uint16_t xu16() const { return static_cast<uint16_t>(m_val); }
+ uint32_t xu32() const { return static_cast<uint32_t>(m_val); }
+ uint64_t xu64() const { return static_cast<uint64_t>(m_val); }
+ int8_t xi8() const { check_overflow<int8_t>(m_val); return m_val; }
+ int16_t xi16() const { return static_cast<int16_t>(m_val); }
+ int32_t xi32() const { return static_cast<int32_t>(m_val); }
+ int64_t xi64() const { return static_cast<int64_t>(m_val); }
+ private:
+ uint8_t m_val;
+ };
+
+ struct object_u16 : object {
+ object_u16(uint16_t val) : m_val(val) {}
+ uint8_t xu8() const { check_overflow<uint8_t>(m_val); return m_val; }
+ uint16_t xu16() const { return m_val; }
+ uint32_t xu32() const { return static_cast<uint32_t>(m_val); }
+ uint64_t xu64() const { return static_cast<uint64_t>(m_val); }
+ int8_t xi8() const { check_overflow< int8_t>(m_val); return m_val; }
+ int16_t xi16() const { check_overflow<int16_t>(m_val); return m_val; }
+ int32_t xi32() const { return static_cast<int32_t>(m_val); }
+ int64_t xi64() const { return static_cast<int64_t>(m_val); }
+ private:
+ uint16_t m_val;
+ };
+
+ ...
+};
+
+} // namespace MessagePack
+
+typedef struct {
+ void* (*unpack_unsigned_int_8)(void* data, uint8_t d);
+ void* (*unpack_unsigned_int_16)(void* data, uint16_t d);
+ void* (*unpack_unsigned_int_32)(void* data, uint32_t d);
+ void* (*unpack_unsigned_int_64)(void* data, uint64_t d);
+ void* (*unpack_signed_int_8)(void* data, int8_t d);
+ void* (*unpack_signed_int_16)(void* data, int16_t d);
+ void* (*unpack_signed_int_32)(void* data, int32_t d);
+ void* (*unpack_signed_int_64)(void* data, int64_t d);
+ void* (*unpack_float)(void* data, float d);
+ void* (*unpack_double)(void* data, double d);
+ void* (*unpack_big_int)(void* data, const void* b, unsigned int l);
+ void* (*unpack_big_float)(void* data, const void* b, unsigned int l);
+ void* (*unpack_nil)(void* data);
+ void* (*unpack_true)(void* data);
+ void* (*unpack_false)(void* data);
+ void* (*unpack_array_start)(void* data, unsigned int n);
+ void (*unpack_array_item)(void* data, void* c, void* o);
+ void* (*unpack_map_start)(void* data, unsigned int n);
+ void (*unpack_map_item)(void* data, void* c, void* k, void* v);
+ void* (*unpack_string)(void* data, const void* b, size_t l);
+ void* (*unpack_raw)(void* data, const void* b, size_t l);
+ void* data;
+} msgpack_unpack_t;
+
+msgpack_unpack_t* msgpack_unpack_new(void);
+void msgpack_unpack_free(msgpack_unpack_t* ctx);
+int msgpack_unpack_execute(msgpack_unpack_t* ctx, const char* data, size_t len, size_t* off);
+void* msgpack_unpack_data(msgpack_unpack_t* ctx);
+
+#endif /* msgpack/unpack.h */
+
+
diff --git a/cpp/unpack_context.h b/cpp/unpack_context.h
new file mode 100644
index 0000000..caf2271
--- /dev/null
+++ b/cpp/unpack_context.h
@@ -0,0 +1,13 @@
+#ifndef UNPACK_CONTEXT_H__
+#define UNPACK_CONTEXT_H__
+
+#include "unpack.h"
+
+typedef void* msgpack_object;
+
+typedef msgpack_unpack_t msgpack_unpack_context;
+
+#include "msgpack/unpack/inline_context.h"
+
+#endif /* unpack_context.h */
+
diff --git a/msgpack/pack/inline_context.h b/msgpack/pack/inline_context.h
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/msgpack/pack/inline_context.h
@@ -0,0 +1,2 @@
+
+
diff --git a/msgpack/pack/inline_impl.h b/msgpack/pack/inline_impl.h
new file mode 100644
index 0000000..5c4bfed
--- /dev/null
+++ b/msgpack/pack/inline_impl.h
@@ -0,0 +1,287 @@
+/*
+ * MessagePack packing 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.
+ */
+#ifndef MSGPACK_PACK_INLINE_IMPL_H__
+#define MSGPACK_PACK_INLINE_IMPL_H__
+
+#include <string.h>
+#include <arpa/inet.h>
+
+#ifdef __LITTLE_ENDIAN__
+
+#define STORE_16(d) \
+ ((char*)&d)[1], ((char*)&d)[0]
+
+#define STORE_32(d) \
+ ((char*)&d)[3], ((char*)&d)[2], ((char*)&d)[1], ((char*)&d)[0]
+
+#define STORE_64(d) \
+ ((char*)&d)[7], ((char*)&d)[6], ((char*)&d)[5], ((char*)&d)[4], \
+ ((char*)&d)[3], ((char*)&d)[2], ((char*)&d)[1], ((char*)&d)[0]
+
+#elif __BIG_ENDIAN__
+
+#define STORE_16(d) \
+ ((char*)&d)[2], ((char*)&d)[3]
+
+#define STORE_32(d) \
+ ((char*)&d)[0], ((char*)&d)[1], ((char*)&d)[2], ((char*)&d)[3]
+
+#define STORE_32(d) \
+ ((char*)&d)[0], ((char*)&d)[1], ((char*)&d)[2], ((char*)&d)[3], \
+ ((char*)&d)[4], ((char*)&d)[5], ((char*)&d)[6], ((char*)&d)[7]
+
+#endif
+
+
+/*
+ * Integer
+ */
+
+// wrapper
+inline void msgpack_pack_int(msgpack_pack_context x, int d)
+{
+ if(d < -32) {
+ if(d < -32768) { // signed 32
+ const unsigned char buf[5] = {0xd2, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+ } else if(d < -128) { // signed 16
+ const unsigned char buf[3] = {0xd1, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+ } else { // signed 8
+ const unsigned char buf[2] = {0xd0, (uint8_t)d};
+ msgpack_pack_append_buffer(x, buf, 2);
+ }
+ } else if(d < 128) { // fixnum
+ msgpack_pack_append_buffer(x, (uint8_t*)&d, 1);
+ } else {
+ if(d < 256) {
+ // unsigned 8
+ const unsigned char buf[2] = {0xcc, (uint8_t)d};
+ msgpack_pack_append_buffer(x, buf, 2);
+ } else if(d < 65536) {
+ // unsigned 16
+ const unsigned char buf[3] = {0xcd, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+ } else {
+ // unsigned 32
+ const unsigned char buf[5] = {0xce, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+ }
+ }
+}
+
+// wrapper
+inline void msgpack_pack_unsigned_int(msgpack_pack_context x, unsigned int d)
+{
+ if(d < 128) {
+ // fixnum
+ msgpack_pack_append_buffer(x, (uint8_t*)&d, 1);
+ } else if(d < 256) {
+ // unsigned 8
+ const unsigned char buf[2] = {0xcc, (uint8_t)d};
+ msgpack_pack_append_buffer(x, buf, 2);
+ } else if(d < 65536) {
+ // unsigned 16
+ const unsigned char buf[3] = {0xcd, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+ } else {
+ // unsigned 32
+ const unsigned char buf[5] = {0xce, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+ }
+}
+
+inline void msgpack_pack_unsigned_int_8(msgpack_pack_context x, uint8_t d)
+{
+ if(d < 128) {
+ msgpack_pack_append_buffer(x, &d, 1);
+ } else {
+ const unsigned char buf[2] = {0xcc, d};
+ msgpack_pack_append_buffer(x, buf, 2);
+ }
+}
+
+inline void msgpack_pack_unsigned_int_16(msgpack_pack_context x, uint16_t d)
+{
+ const unsigned char buf[3] = {0xcd, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+}
+
+inline void msgpack_pack_unsigned_int_32(msgpack_pack_context x, uint32_t d)
+{
+ const unsigned char buf[5] = {0xce, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+}
+
+inline void msgpack_pack_unsigned_int_64(msgpack_pack_context x, uint64_t d)
+{
+ // FIXME
+ const unsigned char buf[9] = {0xcf, STORE_64(d)};
+ msgpack_pack_append_buffer(x, buf, 9);
+}
+
+inline void msgpack_pack_signed_int_8(msgpack_pack_context x, int8_t d)
+{
+ if(d > 0) {
+ msgpack_pack_append_buffer(x, (uint8_t*)&d, 1);
+ } else if(d >= -32) {
+ msgpack_pack_append_buffer(x, (uint8_t*)&d, 1);
+ } else {
+ const unsigned char buf[2] = {0xd0, d};
+ msgpack_pack_append_buffer(x, buf, 2);
+ }
+}
+
+inline void msgpack_pack_signed_int_16(msgpack_pack_context x, int16_t d)
+{
+ const unsigned char buf[3] = {0xd1, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+}
+
+inline void msgpack_pack_signed_int_32(msgpack_pack_context x, int32_t d)
+{
+ const unsigned char buf[5] = {0xd2, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+}
+
+inline void msgpack_pack_signed_int_64(msgpack_pack_context x, int64_t d)
+{
+ // FIXME
+ const unsigned char buf[9] = {0xd3, STORE_64(d)};
+ msgpack_pack_append_buffer(x, buf, 9);
+}
+
+
+/*
+ * Float
+ */
+
+inline void msgpack_pack_float(msgpack_pack_context x, float d)
+{
+ uint32_t n = *((uint32_t*)&d); // FIXME
+ const unsigned char buf[5] = {0xca, STORE_32(n)};
+ msgpack_pack_append_buffer(x, buf, 5);
+}
+
+inline void msgpack_pack_double(msgpack_pack_context x, double d)
+{
+ uint64_t n = *((uint64_t*)&d); // FIXME
+ const unsigned char buf[9] = {0xcb, STORE_64(n)};
+ msgpack_pack_append_buffer(x, buf, 9);
+}
+
+
+/*
+ * Nil
+ */
+
+inline void msgpack_pack_nil(msgpack_pack_context x)
+{
+ static const unsigned char d = 0xc0;
+ msgpack_pack_append_buffer(x, &d, 1);
+}
+
+
+/*
+ * Boolean
+ */
+inline void msgpack_pack_true(msgpack_pack_context x)
+{
+ static const unsigned char d = 0xc3;
+ msgpack_pack_append_buffer(x, &d, 1);
+}
+
+inline void msgpack_pack_false(msgpack_pack_context x)
+{
+ static const unsigned char d = 0xc2;
+ msgpack_pack_append_buffer(x, &d, 1);
+}
+
+
+/*
+ * Array
+ */
+
+inline void msgpack_pack_array(msgpack_pack_context x, unsigned int n)
+{
+ if(n < 16) {
+ unsigned char d = 0x90 | n;
+ msgpack_pack_append_buffer(x, &d, 1);
+ } else if(n < 65536) {
+ uint16_t d = (uint16_t)n;
+ unsigned char buf[3] = {0xdc, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+ } else {
+ uint32_t d = (uint32_t)n;
+ unsigned char buf[5] = {0xdd, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+ }
+}
+
+
+/*
+ * Map
+ */
+
+inline void msgpack_pack_map(msgpack_pack_context x, unsigned int n)
+{
+ if(n < 16) {
+ unsigned char d = 0x80 | n;
+ msgpack_pack_append_buffer(x, &d, 1);
+ } else if(n < 65536) {
+ uint16_t d = (uint16_t)n;
+ unsigned char buf[3] = {0xde, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+ } else {
+ uint32_t d = (uint32_t)n;
+ unsigned char buf[5] = {0xdf, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+ }
+}
+
+
+/*
+ * String
+ */
+
+inline void msgpack_pack_string(msgpack_pack_context x, const char* b)
+{
+ uint32_t l = strlen(b);
+ msgpack_pack_append_buffer(x, (const unsigned char*)b, l+1);
+}
+
+inline void msgpack_pack_raw(msgpack_pack_context x, const void* b, size_t l)
+{
+ if(l < 32) {
+ unsigned char d = 0xa0 | l;
+ msgpack_pack_append_buffer(x, &d, 1);
+ } else if(l < 65536) {
+ uint16_t d = (uint16_t)l;
+ unsigned char buf[3] = {0xda, STORE_16(d)};
+ msgpack_pack_append_buffer(x, buf, 3);
+ } else {
+ uint32_t d = (uint32_t)l;
+ unsigned char buf[5] = {0xdb, STORE_32(d)};
+ msgpack_pack_append_buffer(x, buf, 5);
+ }
+ msgpack_pack_append_buffer(x, b, l);
+}
+
+
+#endif /* msgpack/pack/inline_impl.h */
+
diff --git a/msgpack/unpack/callback.h b/msgpack/unpack/callback.h
new file mode 100644
index 0000000..b058a15
--- /dev/null
+++ b/msgpack/unpack/callback.h
@@ -0,0 +1,24 @@
+
+msgpack_object msgpack_unpack_init(msgpack_unpack_context* x);
+msgpack_object msgpack_unpack_unsigned_int_8(msgpack_unpack_context* x, uint8_t d);
+msgpack_object msgpack_unpack_unsigned_int_16(msgpack_unpack_context* x, uint16_t d);
+msgpack_object msgpack_unpack_unsigned_int_32(msgpack_unpack_context* x, uint32_t d);
+msgpack_object msgpack_unpack_unsigned_int_64(msgpack_unpack_context* x, uint64_t d);
+msgpack_object msgpack_unpack_signed_int_8(msgpack_unpack_context* x, int8_t d);
+msgpack_object msgpack_unpack_signed_int_16(msgpack_unpack_context* x, int16_t d);
+msgpack_object msgpack_unpack_signed_int_32(msgpack_unpack_context* x, int32_t d);
+msgpack_object msgpack_unpack_signed_int_64(msgpack_unpack_context* x, int64_t d);
+msgpack_object msgpack_unpack_float(msgpack_unpack_context* x, float d);
+msgpack_object msgpack_unpack_double(msgpack_unpack_context* x, double d);
+msgpack_object msgpack_unpack_big_int(msgpack_unpack_context* x, const void* b, unsigned int l);
+msgpack_object msgpack_unpack_big_float(msgpack_unpack_context* x, const void* b, unsigned int l);
+msgpack_object msgpack_unpack_nil(msgpack_unpack_context* x);
+msgpack_object msgpack_unpack_true(msgpack_unpack_context* x);
+msgpack_object msgpack_unpack_false(msgpack_unpack_context* x);
+msgpack_object msgpack_unpack_array_start(msgpack_unpack_context* x, unsigned int n);
+ void msgpack_unpack_array_item(msgpack_unpack_context* x, msgpack_object c, msgpack_object o);
+msgpack_object msgpack_unpack_map_start(msgpack_unpack_context* x, unsigned int n);
+ void msgpack_unpack_map_item(msgpack_unpack_context* x, msgpack_object c, msgpack_object k, msgpack_object v);
+msgpack_object msgpack_unpack_string(msgpack_unpack_context* x, const void* b, size_t l);
+msgpack_object msgpack_unpack_raw(msgpack_unpack_context* x, const void* b, size_t l);
+
diff --git a/msgpack/unpack/inline_context.h b/msgpack/unpack/inline_context.h
new file mode 100644
index 0000000..aecd566
--- /dev/null
+++ b/msgpack/unpack/inline_context.h
@@ -0,0 +1,52 @@
+/*
+ * MessagePack unpacking 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.
+ */
+#ifndef MSGPACK_UNPACK_INLINE_CONTEXT_H__
+#define MSGPACK_UNPACK_INLINE_CONTEXT_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifndef MSG_STACK_SIZE
+#define MSG_STACK_SIZE 16
+#endif
+
+typedef struct {
+ msgpack_object obj;
+ size_t count;
+ unsigned int ct;
+ union {
+ const unsigned char* terminal_trail_start;
+ msgpack_object map_key;
+ } tmp;
+} msgpack_unpacker_stack;
+
+typedef struct {
+ msgpack_unpack_context user; // must be first
+ unsigned int cs;
+ size_t trail;
+ unsigned int top;
+ msgpack_unpacker_stack stack[MSG_STACK_SIZE];
+} msgpack_unpacker;
+
+void msgpack_unpacker_init(msgpack_unpacker* ctx);
+int msgpack_unpacker_execute(msgpack_unpacker* ctx, const char* data, size_t len, size_t* off);
+#define msgpack_unpacker_data(unpacker) (unpacker)->stack[0].obj
+
+
+#endif /* msgpack/unpack/inline_context.h */
+
diff --git a/msgpack/unpack/inline_impl.h b/msgpack/unpack/inline_impl.h
new file mode 100644
index 0000000..ec7f0fc
--- /dev/null
+++ b/msgpack/unpack/inline_impl.h
@@ -0,0 +1,438 @@
+/*
+ * MessagePack unpacking 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.
+ */
+#ifndef MSGPACK_UNPACK_INLINE_IMPL_H__
+#define MSGPACK_UNPACK_INLINE_IMPL_H__
+
+#include <string.h>
+#include <assert.h>
+#include <arpa/inet.h>
+/*#include <stdio.h>*/
+
+// Positive FixNum 0xxxxxxx 0x00 - 0x7f
+// Negative FixNum 111xxxxx 0xe0 - 0xff
+// Variable 110xxxxx 0xc0 - 0xdf
+// nil 00000 0xc0
+// string 00001 0xc1
+// false 00010 0xc2
+// true 00011 0xc3
+// (?) 00100 0xc4
+// (?) 00101 0xc5
+// (?) 00110 0xc6
+// (?) 00111 0xc7
+// (?) 01000 0xc8
+// (?) 01001 0xc9
+// float 01010 0xca
+// double 01011 0xcb
+// uint 8 01100 0xcc
+// uint 16 01101 0xcd
+// uint 32 01110 0xce
+// uint 64 01111 0xcf
+// int 8 10000 0xd0
+// int 16 10001 0xd1
+// int 32 10010 0xd2
+// int 64 10011 0xd3
+// (?) 10100 0xd4
+// (?) 10101 0xd5
+// (big float 16) 10110 0xd6
+// (big float 32) 10111 0xd7
+// (big integer 16) 11000 0xd8
+// (big integer 32) 11001 0xd9
+// raw 16 11010 0xda
+// raw 32 11011 0xdb
+// array 16 11100 0xdc
+// array 32 11101 0xdd
+// map 16 11110 0xde
+// map 32 11111 0xdf
+// FixRaw 101xxxxx 0xa0 - 0xbf
+// FixArray 1001xxxx 0x90 - 0x9f
+// FixMap 1000xxxx 0x80 - 0x8f
+
+
+#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN__
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define __BIG_ENDIAN__
+#endif
+#endif
+
+static inline uint64_t ntohll(uint64_t x) {
+#ifdef __LITTLE_ENDIAN__ // FIXME
+#if defined(__bswap_64)
+ return __bswap_64(x);
+#elif defined(__DARWIN_OSSwapInt64)
+ return __DARWIN_OSSwapInt64(x);
+#else
+ return ((x << 56) & 0xff00000000000000ULL ) |
+ ((x << 40) & 0x00ff000000000000ULL ) |
+ ((x << 24) & 0x0000ff0000000000ULL ) |
+ ((x << 8) & 0x000000ff00000000ULL ) |
+ ((x >> 8) & 0x00000000ff000000ULL ) |
+ ((x >> 24) & 0x0000000000ff0000ULL ) |
+ ((x >> 40) & 0x000000000000ff00ULL ) |
+ ((x >> 56) & 0x00000000000000ffULL ) ;
+#endif
+#else
+ return x;
+#endif
+}
+
+typedef enum {
+ CS_HEADER = 0x00, // nil
+
+ CS_STRING = 0x01,
+ //CS_ = 0x02, // false
+ //CS_ = 0x03, // true
+
+ //CS_ = 0x04,
+ //CS_ = 0x05,
+ //CS_ = 0x06,
+ //CS_ = 0x07,
+
+ //CS_ = 0x08,
+ //CS_ = 0x09,
+ CS_FLOAT = 0x0a,
+ CS_DOUBLE = 0x0b,
+ CS_UNSIGNED_INT_8 = 0x0c,
+ CS_UNSIGNED_INT_16 = 0x0d,
+ CS_UNSIGNED_INT_32 = 0x0e,
+ CS_UNSIGNED_INT_64 = 0x0f,
+ CS_SIGNED_INT_8 = 0x10,
+ CS_SIGNED_INT_16 = 0x11,
+ CS_SIGNED_INT_32 = 0x12,
+ CS_SIGNED_INT_64 = 0x13,
+
+ //CS_ = 0x14,
+ //CS_ = 0x15,
+ //CS_BIG_INT_16 = 0x16,
+ //CS_BIG_INT_32 = 0x17,
+ //CS_BIG_FLOAT_16 = 0x18,
+ //CS_BIG_FLOAT_32 = 0x19,
+ CS_RAW_16 = 0x1a,
+ CS_RAW_32 = 0x1b,
+ CS_ARRAY_16 = 0x1c,
+ CS_ARRAY_32 = 0x1d,
+ CS_MAP_16 = 0x1e,
+ CS_MAP_32 = 0x1f,
+
+ //ACS_BIG_INT_VALUE,
+ //ACS_BIG_FLOAT_VALUE,
+ ACS_RAW_VALUE,
+} current_state_t;
+
+
+typedef enum {
+ CT_ARRAY_ITEM,
+ CT_MAP_KEY,
+ CT_MAP_VALUE,
+} container_type_t;
+
+
+void msgpack_unpacker_init(msgpack_unpacker* ctx)
+{
+ memset(ctx, 0, sizeof(msgpack_unpacker)); // FIXME init ctx->user?
+ ctx->cs = CS_HEADER;
+ ctx->trail = 0;
+ ctx->top = 0;
+ ctx->stack[0].obj = msgpack_unpack_init(&ctx->user);
+}
+
+int msgpack_unpacker_execute(msgpack_unpacker* ctx, const char* data, size_t len, size_t* off)
+{
+ assert(len >= *off);
+
+ const unsigned char* p = (unsigned char*)data + *off;
+ const unsigned char* const pe = (unsigned char*)data + len;
+ const void* n = NULL;
+
+ size_t trail = ctx->trail;
+ unsigned int cs = ctx->cs;
+ unsigned int top = ctx->top;
+ msgpack_unpacker_stack* stack = ctx->stack;
+ msgpack_unpack_context* user = &ctx->user;
+
+ msgpack_object obj;
+
+ int ret;
+
+#define push_simple_value(func) \
+ obj = func(user); \
+ /*printf("obj %d\n",obj);*/ \
+ goto _push
+#define push_fixed_value(func, arg) \
+ obj = func(user, arg); \
+ /*printf("obj %d\n",obj);*/ \
+ goto _push
+#define push_variable_value(func, arg, arglen) \
+ obj = func(user, arg, arglen); \
+ /*printf("obj %d\n",obj);*/ \
+ goto _push
+
+#define again_terminal_trail(_cs, from) \
+ cs = _cs; \
+ stack[top].tmp.terminal_trail_start = from; \
+ goto _terminal_trail_again
+#define again_fixed_trail(_cs, trail_len) \
+ trail = trail_len; \
+ cs = _cs; \
+ goto _fixed_trail_again
+#define again_fixed_trail_if_zero(_cs, trail_len, ifzero) \
+ trail = trail_len; \
+ if(trail == 0) { goto ifzero; } \
+ cs = _cs; \
+ goto _fixed_trail_again
+
+#define start_container(func, count_, ct_) \
+ stack[top].obj = func(user, count_); \
+ if((count_) == 0) { obj = stack[top].obj; goto _push; } \
+ if(top >= MSG_STACK_SIZE) { goto _failed; } \
+ stack[top].ct = ct_; \
+ stack[top].count = count_; \
+ /*printf("container %d count %d stack %d\n",stack[top].obj,count_,top);*/ \
+ /*printf("stack push %d\n", top);*/ \
+ ++top; \
+ goto _header_again
+
+#define NEXT_CS(p) \
+ ((unsigned int)*p & 0x1f)
+
+#define PTR_CAST_8(ptr) (*(uint8_t*)ptr)
+#define PTR_CAST_16(ptr) ntohs(*(uint16_t*)ptr)
+#define PTR_CAST_32(ptr) ntohl(*(uint32_t*)ptr)
+#define PTR_CAST_64(ptr) ntohll(*(uint64_t*)ptr)
+
+ if(p == pe) { goto _out; }
+ do {
+ switch(cs) {
+ case CS_HEADER:
+ switch(*p) {
+ case 0x00 ... 0x7f: // Positive Fixnum
+ push_fixed_value(msgpack_unpack_unsigned_int_8, *(uint8_t*)p);
+ case 0xe0 ... 0xff: // Negative Fixnum
+ push_fixed_value(msgpack_unpack_signed_int_8, *(int8_t*)p);
+ case 0xc0 ... 0xdf: // Variable
+ switch(*p) {
+ case 0xc0: // nil
+ push_simple_value(msgpack_unpack_nil);
+ case 0xc1: // string
+ again_terminal_trail(NEXT_CS(p), p+1);
+ case 0xc2: // false
+ push_simple_value(msgpack_unpack_false);
+ case 0xc3: // true
+ push_simple_value(msgpack_unpack_true);
+ //case 0xc4:
+ //case 0xc5:
+ //case 0xc6:
+ //case 0xc7:
+ //case 0xc8:
+ //case 0xc9:
+ case 0xca: // float
+ case 0xcb: // double
+ case 0xcc: // unsigned int 8
+ case 0xcd: // unsigned int 16
+ case 0xce: // unsigned int 32
+ case 0xcf: // unsigned int 64
+ case 0xd0: // signed int 8
+ case 0xd1: // signed int 16
+ case 0xd2: // signed int 32
+ case 0xd3: // signed int 64
+ again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03));
+ //case 0xd4:
+ //case 0xd5:
+ //case 0xd6: // big integer 16
+ //case 0xd7: // big integer 32
+ //case 0xd8: // big float 16
+ //case 0xd9: // big float 32
+ case 0xda: // raw 16
+ case 0xdb: // raw 32
+ case 0xdc: // array 16
+ case 0xdd: // array 32
+ case 0xde: // map 16
+ case 0xdf: // map 32
+ again_fixed_trail(NEXT_CS(p), 2 << (((unsigned int)*p) & 0x01));
+ default:
+ goto _failed;
+ }
+ case 0xa0 ... 0xbf: // FixRaw
+ again_fixed_trail_if_zero(ACS_RAW_VALUE, ((unsigned int)*p & 0x1f), _raw_zero);
+ case 0x90 ... 0x9f: // FixArray
+ start_container(msgpack_unpack_array_start, ((unsigned int)*p) & 0x0f, CT_ARRAY_ITEM);
+ case 0x80 ... 0x8f: // FixMap
+ start_container(msgpack_unpack_map_start, ((unsigned int)*p) & 0x0f, CT_MAP_KEY);
+
+ default:
+ goto _failed;
+ }
+ // end CS_HEADER
+
+
+ _terminal_trail_again:
+ ++p;
+
+ case CS_STRING:
+ if(*p == 0) {
+ const unsigned char* start = stack[top].tmp.terminal_trail_start;
+ obj = msgpack_unpack_string(user, start, p-start);
+ goto _push;
+ }
+ goto _terminal_trail_again;
+
+
+ _fixed_trail_again:
+ ++p;
+
+ default:
+ if((size_t)(pe - p) < trail) { goto _out; }
+ n = p; p += trail - 1;
+ switch(cs) {
+ //case CS_
+ //case CS_
+ case CS_FLOAT: {
+ uint32_t x = PTR_CAST_32(n); // FIXME
+ push_fixed_value(msgpack_unpack_float, *((float*)&x)); }
+ case CS_DOUBLE: {
+ uint64_t x = PTR_CAST_64(n); // FIXME
+ push_fixed_value(msgpack_unpack_double, *((double*)&x)); }
+ case CS_UNSIGNED_INT_8:
+ push_fixed_value(msgpack_unpack_unsigned_int_8, (uint8_t)PTR_CAST_8(n));
+ case CS_UNSIGNED_INT_16:
+ push_fixed_value(msgpack_unpack_unsigned_int_16, (uint16_t)PTR_CAST_16(n));
+ case CS_UNSIGNED_INT_32:
+ push_fixed_value(msgpack_unpack_unsigned_int_32, (uint32_t)PTR_CAST_32(n));
+ case CS_UNSIGNED_INT_64:
+ push_fixed_value(msgpack_unpack_unsigned_int_64, (uint64_t)PTR_CAST_64(n));
+
+ case CS_SIGNED_INT_8:
+ push_fixed_value(msgpack_unpack_signed_int_8, (int8_t)PTR_CAST_8(n));
+ case CS_SIGNED_INT_16:
+ push_fixed_value(msgpack_unpack_signed_int_16, (int16_t)PTR_CAST_16(n));
+ case CS_SIGNED_INT_32:
+ push_fixed_value(msgpack_unpack_signed_int_32, (int32_t)PTR_CAST_32(n));
+ case CS_SIGNED_INT_64:
+ push_fixed_value(msgpack_unpack_signed_int_64, (int64_t)PTR_CAST_64(n));
+
+ //case CS_
+ //case CS_
+ //case CS_BIG_INT_16:
+ // again_fixed_trail_if_zero(ACS_BIG_INT_VALUE, (uint16_t)PTR_CAST_16(n), _big_int_zero);
+ //case CS_BIG_INT_32:
+ // again_fixed_trail_if_zero(ACS_BIG_INT_VALUE, (uint32_t)PTR_CAST_32(n), _big_int_zero);
+ //case ACS_BIG_INT_VALUE:
+ //_big_int_zero:
+ // // FIXME
+ // push_variable_value(msgpack_unpack_big_int, n, trail);
+
+ //case CS_BIG_FLOAT_16:
+ // again_fixed_trail_if_zero(ACS_BIG_FLOAT_VALUE, (uint16_t)PTR_CAST_16(n), _big_float_zero);
+ //case CS_BIG_FLOAT_32:
+ // again_fixed_trail_if_zero(ACS_BIG_FLOAT_VALUE, (uint32_t)PTR_CAST_32(n), _big_float_zero);
+ //case ACS_BIG_FLOAT_VALUE:
+ //_big_float_zero:
+ // // FIXME
+ // push_variable_value(msgpack_unpack_big_float, n, trail);
+
+ case CS_RAW_16:
+ again_fixed_trail_if_zero(ACS_RAW_VALUE, (uint16_t)PTR_CAST_16(n), _raw_zero);
+ case CS_RAW_32:
+ again_fixed_trail_if_zero(ACS_RAW_VALUE, (uint32_t)PTR_CAST_32(n), _raw_zero);
+ case ACS_RAW_VALUE:
+ _raw_zero:
+ push_variable_value(msgpack_unpack_raw, n, trail);
+
+ case CS_ARRAY_16:
+ start_container(msgpack_unpack_array_start, (uint16_t)PTR_CAST_16(n), CT_ARRAY_ITEM);
+ case CS_ARRAY_32:
+ start_container(msgpack_unpack_array_start, (uint32_t)PTR_CAST_32(n), CT_ARRAY_ITEM);
+
+ case CS_MAP_16:
+ start_container(msgpack_unpack_map_start, (uint16_t)PTR_CAST_16(n), CT_MAP_KEY);
+ case CS_MAP_32:
+ start_container(msgpack_unpack_map_start, (uint32_t)PTR_CAST_32(n), CT_MAP_KEY);
+
+ default:
+ goto _failed;
+ }
+ }
+
+_push:
+ if(top == 0) { goto _finish; }
+ msgpack_unpacker_stack* c = &stack[top-1];
+ switch(c->ct) {
+ case CT_ARRAY_ITEM:
+ msgpack_unpack_array_item(user, c->obj, obj);
+ if(--c->count == 0) {
+ obj = c->obj;
+ --top;
+ /*printf("stack pop %d\n", top);*/
+ goto _push;
+ }
+ goto _header_again;
+ case CT_MAP_KEY:
+ c->tmp.map_key = obj;
+ c->ct = CT_MAP_VALUE;
+ goto _header_again;
+ case CT_MAP_VALUE:
+ msgpack_unpack_map_item(user, c->obj, c->tmp.map_key, obj);
+ if(--c->count == 0) {
+ obj = c->obj;
+ --top;
+ /*printf("stack pop %d\n", top);*/
+ goto _push;
+ }
+ c->ct = CT_MAP_KEY;
+ goto _header_again;
+
+ default:
+ goto _failed;
+ }
+
+_header_again:
+ cs = CS_HEADER;
+ ++p;
+ } while(p != pe);
+ goto _out;
+
+
+_finish:
+ stack[0].obj = obj;
+ ++p;
+ ret = 1;
+ /*printf("-- finish --\n"); */
+ goto _end;
+
+_failed:
+ /*printf("** FAILED **\n"); */
+ ret = -1;
+ goto _end;
+
+_out:
+ ret = 0;
+ goto _end;
+
+_end:
+ ctx->cs = cs;
+ ctx->trail = trail;
+ ctx->top = top;
+ *off = p - (const unsigned char*)data;
+
+ return ret;
+}
+
+
+#endif /* msgpack/unpack/inline_impl.h */
+
diff --git a/ruby/Makefile b/ruby/Makefile
new file mode 100644
index 0000000..6ef04b0
--- /dev/null
+++ b/ruby/Makefile
@@ -0,0 +1,153 @@
+
+SHELL = /bin/sh
+
+#### Start of system configuration section. ####
+
+srcdir = .
+topdir = /Users/frsyuki/ports/lib/ruby/1.8/i686-darwin9.1.0
+hdrdir = $(topdir)
+VPATH = $(srcdir):$(topdir):$(hdrdir)
+prefix = $(DESTDIR)/Users/frsyuki/ports
+exec_prefix = $(prefix)
+sitedir = $(prefix)/lib/ruby/site_ruby
+rubylibdir = $(libdir)/ruby/$(ruby_version)
+docdir = $(datarootdir)/doc/$(PACKAGE)
+dvidir = $(docdir)
+datarootdir = $(prefix)/share
+archdir = $(rubylibdir)/$(arch)
+sbindir = $(exec_prefix)/sbin
+psdir = $(docdir)
+vendordir = $(prefix)/lib/ruby/vendor_ruby
+localedir = $(datarootdir)/locale
+htmldir = $(docdir)
+datadir = $(datarootdir)
+includedir = $(prefix)/include
+infodir = $(datarootdir)/info
+sysconfdir = $(prefix)/etc
+mandir = $(DESTDIR)/Users/frsyuki/ports/share/man
+libdir = $(exec_prefix)/lib
+sharedstatedir = $(prefix)/com
+oldincludedir = $(DESTDIR)/usr/include
+pdfdir = $(docdir)
+sitearchdir = $(sitelibdir)/$(sitearch)
+vendorarchdir = $(vendorlibdir)/$(vendorarch)
+bindir = $(exec_prefix)/bin
+localstatedir = $(prefix)/var
+vendorlibdir = $(vendordir)/$(ruby_version)
+sitelibdir = $(sitedir)/$(ruby_version)
+libexecdir = $(exec_prefix)/libexec
+
+CC = /usr/bin/gcc-4.0
+LIBRUBY = $(LIBRUBY_SO)
+LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
+LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
+LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
+
+RUBY_EXTCONF_H =
+CFLAGS = -fno-common -O2 -fno-common -pipe -fno-common -I.. -Wall -O9
+INCFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir)
+CPPFLAGS = -I/Users/frsyuki/ports/include
+CXXFLAGS = $(CFLAGS)
+DLDFLAGS = -L. -L/Users/frsyuki/ports/lib
+LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
+AR = ar
+EXEEXT =
+
+RUBY_INSTALL_NAME = ruby
+RUBY_SO_NAME = ruby
+arch = i686-darwin9.1.0
+sitearch = i686-darwin9.1.0
+vendorarch = i686-darwin9.1.0
+ruby_version = 1.8
+ruby = /Users/frsyuki/ports/bin/ruby
+RUBY = $(ruby)
+RM = rm -f
+MAKEDIRS = mkdir -p
+INSTALL = /usr/bin/install
+INSTALL_PROG = $(INSTALL) -m 0755
+INSTALL_DATA = $(INSTALL) -m 644
+COPY = cp
+
+#### End of system configuration section. ####
+
+preload =
+
+libpath = . $(libdir)
+LIBPATH = -L"." -L"$(libdir)"
+DEFFILE =
+
+CLEANFILES = mkmf.log
+DISTCLEANFILES =
+
+extout =
+extout_prefix =
+target_prefix =
+LOCAL_LIBS =
+LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
+SRCS = pack.c rbinit.c unpack.c unpack_inline.c
+OBJS = pack.o rbinit.o unpack.o unpack_inline.o
+TARGET = msgpack
+DLLIB = $(TARGET).bundle
+EXTSTATIC =
+STATIC_LIB =
+
+RUBYCOMMONDIR = $(sitedir)$(target_prefix)
+RUBYLIBDIR = $(sitelibdir)$(target_prefix)
+RUBYARCHDIR = $(sitearchdir)$(target_prefix)
+
+TARGET_SO = $(DLLIB)
+CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
+CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
+
+all: $(DLLIB)
+static: $(STATIC_LIB)
+
+clean:
+ @-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
+
+distclean: clean
+ @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
+ @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
+
+realclean: distclean
+install: install-so install-rb
+
+install-so: $(RUBYARCHDIR)
+install-so: $(RUBYARCHDIR)/$(DLLIB)
+$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
+install-rb: pre-install-rb install-rb-default
+install-rb-default: pre-install-rb-default
+pre-install-rb: Makefile
+pre-install-rb-default: Makefile
+$(RUBYARCHDIR):
+ $(MAKEDIRS) $@
+
+site-install: site-install-so site-install-rb
+site-install-so: install-so
+site-install-rb: install-rb
+
+.SUFFIXES: .c .m .cc .cxx .cpp .C .o
+
+.cc.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.cxx.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.cpp.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.C.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.c.o:
+ $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
+
+$(DLLIB): $(OBJS)
+ @-$(RM) $@
+ $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
+
+
+
+$(OBJS): ruby.h defines.h
diff --git a/ruby/bench.rb b/ruby/bench.rb
new file mode 100644
index 0000000..1e6e27b
--- /dev/null
+++ b/ruby/bench.rb
@@ -0,0 +1,60 @@
+require 'rubygems'
+require 'json'
+require 'msgpack'
+
+def show10(str)
+ puts "#{str.length/1024} KB"
+ puts str[0, 10].unpack('C*').map{|x|"%02x"%x}.join(' ') + " ..."
+end
+
+ary = []
+i = 0
+while i < (1<<23)
+ ary << (1<<23)
+ #ary << i
+ i += 1
+end
+
+GC.start
+
+puts "----"
+puts "MessagePack"
+a = Time.now
+packed = MessagePack::pack(ary)
+b = Time.now
+show10(packed)
+puts "#{b-a} sec."
+
+GC.start
+
+puts "----"
+puts "JSON"
+a = Time.now
+json = ary.to_json
+b = Time.now
+show10(json)
+puts "#{b-a} sec."
+
+ary = nil
+GC.start
+
+
+puts "----"
+puts "MessagePack"
+a = Time.now
+ary = MessagePack::unpack(packed)
+b = Time.now
+puts "#{b-a} sec."
+
+ary = nil
+GC.start
+
+
+puts "----"
+puts "JSON"
+a = Time.now
+ary = JSON::load(json)
+b = Time.now
+puts "#{b-a} sec."
+
+
diff --git a/ruby/extconf.rb b/ruby/extconf.rb
new file mode 100644
index 0000000..88abb55
--- /dev/null
+++ b/ruby/extconf.rb
@@ -0,0 +1,4 @@
+require 'mkmf'
+$CFLAGS << " -I.. -Wall -O9"
+create_makefile('msgpack')
+
diff --git a/ruby/gem.sh b/ruby/gem.sh
new file mode 100755
index 0000000..9d9f429
--- /dev/null
+++ b/ruby/gem.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+cp extconf.rb gem/ext/
+cp pack.c gem/ext/
+cp pack.h gem/ext/
+cp pack_inline.h gem/ext/
+cp rbinit.c gem/ext/
+cp unpack.c gem/ext/
+cp unpack.h gem/ext/
+cp unpack_context.h gem/ext/
+cp unpack_inline.c gem/ext/
+cp ../README gem/README.txt
+cp ../msgpack/pack/inline_context.h gem/msgpack/pack/
+cp ../msgpack/pack/inline_impl.h gem/msgpack/pack/
+cp ../msgpack/unpack/inline_context.h gem/msgpack/unpack/
+cp ../msgpack/unpack/inline_impl.h gem/msgpack/unpack/
+
+cd gem && rake --trace package
+
diff --git a/ruby/gem/AUTHORS b/ruby/gem/AUTHORS
new file mode 100644
index 0000000..ababacb
--- /dev/null
+++ b/ruby/gem/AUTHORS
@@ -0,0 +1 @@
+FURUHASHI Sadayuki <frsyuki _at_ users.sourceforge.jp>
diff --git a/ruby/gem/History.txt b/ruby/gem/History.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ruby/gem/History.txt
diff --git a/ruby/gem/License.txt b/ruby/gem/License.txt
new file mode 100644
index 0000000..f4000b7
--- /dev/null
+++ b/ruby/gem/License.txt
@@ -0,0 +1,13 @@
+Copyright 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.
diff --git a/ruby/gem/Manifest.txt b/ruby/gem/Manifest.txt
new file mode 100644
index 0000000..fac8555
--- /dev/null
+++ b/ruby/gem/Manifest.txt
@@ -0,0 +1,26 @@
+License.txt
+Manifest.txt
+README.txt
+Rakefile
+config/hoe.rb
+config/requirements.rb
+ext/extconf.rb
+ext/pack.c
+ext/pack.h
+ext/pack_inline.h
+ext/rbinit.c
+ext/unpack.c
+ext/unpack.h
+ext/unpack_context.h
+ext/unpack_inline.c
+msgpack/pack/inline_context.h
+msgpack/pack/inline_impl.h
+msgpack/unpack/inline_context.h
+msgpack/unpack/inline_impl.h
+lib/msgpack/version.rb
+script/console
+script/destroy
+script/generate
+setup.rb
+tasks/deployment.rake
+tasks/environment.rake
diff --git a/ruby/gem/PostInstall.txt b/ruby/gem/PostInstall.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ruby/gem/PostInstall.txt
@@ -0,0 +1 @@
+
diff --git a/ruby/gem/Rakefile b/ruby/gem/Rakefile
new file mode 100644
index 0000000..e469154
--- /dev/null
+++ b/ruby/gem/Rakefile
@@ -0,0 +1,4 @@
+require 'config/requirements'
+require 'config/hoe' # setup Hoe + all gem configuration
+
+Dir['tasks/**/*.rake'].each { |rake| load rake } \ No newline at end of file
diff --git a/ruby/gem/config/hoe.rb b/ruby/gem/config/hoe.rb
new file mode 100644
index 0000000..8500acf
--- /dev/null
+++ b/ruby/gem/config/hoe.rb
@@ -0,0 +1,75 @@
+require 'msgpack/version'
+
+AUTHOR = 'FURUHASHI Sadayuki' # can also be an array of Authors
+EMAIL = "fr _at_ syuki.skr.jp"
+DESCRIPTION = "An object-oriented parser generator based on Parser Expression Grammar"
+GEM_NAME = 'msgpack' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'msgpack' # The unix name for your project
+HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
+DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
+EXTRA_DEPENDENCIES = [
+# ['activesupport', '>= 1.3.1']
+] # An array of rubygem dependencies [name, version]
+
+@config_file = "~/.rubyforge/user-config.yml"
+@config = nil
+RUBYFORGE_USERNAME = "unknown"
+def rubyforge_username
+ unless @config
+ begin
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
+ rescue
+ puts <<-EOS
+ERROR: No rubyforge config file found: #{@config_file}
+Run 'rubyforge setup' to prepare your env for access to Rubyforge
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
+ EOS
+ exit
+ end
+ end
+ RUBYFORGE_USERNAME.replace @config["username"]
+end
+
+
+REV = nil
+# UNCOMMENT IF REQUIRED:
+# REV = YAML.load(`svn info`)['Revision']
+VERS = MessagePack::VERSION::STRING + (REV ? ".#{REV}" : "")
+RDOC_OPTS = ['--quiet', '--title', 'msgpack documentation',
+ "--opname", "index.html",
+ "--line-numbers",
+ "--main", "README",
+ "--inline-source"]
+
+class Hoe
+ def extra_deps
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
+ @extra_deps
+ end
+end
+
+# Generate all the Rake tasks
+# Run 'rake -T' to see list of generated tasks (from gem root directory)
+$hoe = Hoe.new(GEM_NAME, VERS) do |p|
+ p.developer(AUTHOR, EMAIL)
+ p.description = DESCRIPTION
+ p.summary = DESCRIPTION
+ p.url = HOMEPATH
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
+ p.test_globs = ["test/**/test_*.rb"]
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
+
+ # == Optional
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
+ #p.extra_deps = EXTRA_DEPENDENCIES
+
+ p.spec_extras = { # A hash of extra values to set in the gemspec.
+ :extensions => %w[ext/extconf.rb]
+ }
+end
+
+CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
+PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
+$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
+$hoe.rsync_args = '-av --delete --ignore-errors'
+$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
diff --git a/ruby/gem/config/requirements.rb b/ruby/gem/config/requirements.rb
new file mode 100644
index 0000000..9292b69
--- /dev/null
+++ b/ruby/gem/config/requirements.rb
@@ -0,0 +1,15 @@
+require 'fileutils'
+include FileUtils
+
+require 'rubygems'
+%w[rake hoe newgem rubigen].each do |req_gem|
+ begin
+ require req_gem
+ rescue LoadError
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
+ puts "Installation: gem install #{req_gem} -y"
+ exit
+ end
+end
+
+$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
diff --git a/ruby/gem/lib/msgpack/version.rb b/ruby/gem/lib/msgpack/version.rb
new file mode 100644
index 0000000..44d1dc0
--- /dev/null
+++ b/ruby/gem/lib/msgpack/version.rb
@@ -0,0 +1,9 @@
+module MessagePack
+ module VERSION #:nodoc:
+ MAJOR = 0
+ MINOR = 0
+ TINY = 1
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+end
diff --git a/ruby/gem/script/console b/ruby/gem/script/console
new file mode 100755
index 0000000..76f32a0
--- /dev/null
+++ b/ruby/gem/script/console
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+# File: script/console
+irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
+
+libs = " -r irb/completion"
+# Perhaps use a console_lib to store any extra methods I may want available in the cosole
+# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
+libs << " -r #{File.dirname(__FILE__) + '/../lib/msgpack.rb'}"
+puts "Loading msgpack gem"
+exec "#{irb} #{libs} --simple-prompt"
diff --git a/ruby/gem/script/destroy b/ruby/gem/script/destroy
new file mode 100755
index 0000000..e48464d
--- /dev/null
+++ b/ruby/gem/script/destroy
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/destroy'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
+RubiGen::Scripts::Destroy.new.run(ARGV)
diff --git a/ruby/gem/script/generate b/ruby/gem/script/generate
new file mode 100755
index 0000000..c27f655
--- /dev/null
+++ b/ruby/gem/script/generate
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/generate'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
+RubiGen::Scripts::Generate.new.run(ARGV)
diff --git a/ruby/gem/script/txt2html b/ruby/gem/script/txt2html
new file mode 100755
index 0000000..09c583f
--- /dev/null
+++ b/ruby/gem/script/txt2html
@@ -0,0 +1,82 @@
+#!/usr/bin/env ruby
+
+GEM_NAME = 'msgpack' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'msgpack'
+
+require 'rubygems'
+begin
+ require 'newgem'
+ require 'rubyforge'
+rescue LoadError
+ puts "\n\nGenerating the website requires the newgem RubyGem"
+ puts "Install: gem install newgem\n\n"
+ exit(1)
+end
+require 'redcloth'
+require 'syntax/convertors/html'
+require 'erb'
+require File.dirname(__FILE__) + "/../lib/#{GEM_NAME}/version.rb"
+
+version = MessagePack::VERSION::STRING
+download = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
+
+def rubyforge_project_id
+ RubyForge.new.autoconfig["group_ids"][RUBYFORGE_PROJECT]
+end
+
+class Fixnum
+ def ordinal
+ # teens
+ return 'th' if (10..19).include?(self % 100)
+ # others
+ case self % 10
+ when 1: return 'st'
+ when 2: return 'nd'
+ when 3: return 'rd'
+ else return 'th'
+ end
+ end
+end
+
+class Time
+ def pretty
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
+ end
+end
+
+def convert_syntax(syntax, source)
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
+end
+
+if ARGV.length >= 1
+ src, template = ARGV
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
+else
+ puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
+ exit!
+end
+
+template = ERB.new(File.open(template).read)
+
+title = nil
+body = nil
+File.open(src) do |fsrc|
+ title_text = fsrc.readline
+ body_text_template = fsrc.read
+ body_text = ERB.new(body_text_template).result(binding)
+ syntax_items = []
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
+ ident = syntax_items.length
+ element, syntax, source = $1, $2, $3
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
+ "syntax-temp-#{ident}"
+ }
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
+ body = RedCloth.new(body_text).to_html
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
+end
+stat = File.stat(src)
+created = stat.ctime
+modified = stat.mtime
+
+$stdout << template.result(binding)
diff --git a/ruby/gem/setup.rb b/ruby/gem/setup.rb
new file mode 100644
index 0000000..424a5f3
--- /dev/null
+++ b/ruby/gem/setup.rb
@@ -0,0 +1,1585 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2005 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map) # Ruby 1.4.6
+ module Enumerable
+ alias map collect
+ end
+end
+
+unless File.respond_to?(:read) # Ruby 1.6
+ def File.read(fname)
+ open(fname) {|f|
+ return f.read
+ }
+ end
+end
+
+unless Errno.const_defined?(:ENOTEMPTY) # Windows?
+ module Errno
+ class ENOTEMPTY
+ # We do not raise this exception, implementation is not needed.
+ end
+ end
+end
+
+def File.binread(fname)
+ open(fname, 'rb') {|f|
+ return f.read
+ }
+end
+
+# for corrupted Windows' stat(2)
+def File.dir?(path)
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class ConfigTable
+
+ include Enumerable
+
+ def initialize(rbconfig)
+ @rbconfig = rbconfig
+ @items = []
+ @table = {}
+ # options
+ @install_prefix = nil
+ @config_opt = nil
+ @verbose = true
+ @no_harm = false
+ end
+
+ attr_accessor :install_prefix
+ attr_accessor :config_opt
+
+ attr_writer :verbose
+
+ def verbose?
+ @verbose
+ end
+
+ attr_writer :no_harm
+
+ def no_harm?
+ @no_harm
+ end
+
+ def [](key)
+ lookup(key).resolve(self)
+ end
+
+ def []=(key, val)
+ lookup(key).set val
+ end
+
+ def names
+ @items.map {|i| i.name }
+ end
+
+ def each(&block)
+ @items.each(&block)
+ end
+
+ def key?(name)
+ @table.key?(name)
+ end
+
+ def lookup(name)
+ @table[name] or setup_rb_error "no such config item: #{name}"
+ end
+
+ def add(item)
+ @items.push item
+ @table[item.name] = item
+ end
+
+ def remove(name)
+ item = lookup(name)
+ @items.delete_if {|i| i.name == name }
+ @table.delete_if {|name, i| i.name == name }
+ item
+ end
+
+ def load_script(path, inst = nil)
+ if File.file?(path)
+ MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
+ end
+ end
+
+ def savefile
+ '.config'
+ end
+
+ def load_savefile
+ begin
+ File.foreach(savefile()) do |line|
+ k, v = *line.split(/=/, 2)
+ self[k] = v.strip
+ end
+ rescue Errno::ENOENT
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
+ end
+ end
+
+ def save
+ @items.each {|i| i.value }
+ File.open(savefile(), 'w') {|f|
+ @items.each do |i|
+ f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
+ end
+ }
+ end
+
+ def load_standard_entries
+ standard_entries(@rbconfig).each do |ent|
+ add ent
+ end
+ end
+
+ def standard_entries(rbconfig)
+ c = rbconfig
+
+ rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
+
+ major = c['MAJOR'].to_i
+ minor = c['MINOR'].to_i
+ teeny = c['TEENY'].to_i
+ version = "#{major}.#{minor}"
+
+ # ruby ver. >= 1.4.4?
+ newpath_p = ((major >= 2) or
+ ((major == 1) and
+ ((minor >= 5) or
+ ((minor == 4) and (teeny >= 4)))))
+
+ if c['rubylibdir']
+ # V > 1.6.3
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = c['rubylibdir']
+ librubyverarch = c['archdir']
+ siteruby = c['sitedir']
+ siterubyver = c['sitelibdir']
+ siterubyverarch = c['sitearchdir']
+ elsif newpath_p
+ # 1.4.4 <= V <= 1.6.3
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+ siteruby = c['sitedir']
+ siterubyver = "$siteruby/#{version}"
+ siterubyverarch = "$siterubyver/#{c['arch']}"
+ else
+ # V < 1.4.4
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+ siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
+ siterubyver = siteruby
+ siterubyverarch = "$siterubyver/#{c['arch']}"
+ end
+ parameterize = lambda {|path|
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
+ }
+
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+ else
+ makeprog = 'make'
+ end
+
+ [
+ ExecItem.new('installdirs', 'std/site/home',
+ 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
+ {|val, table|
+ case val
+ when 'std'
+ table['rbdir'] = '$librubyver'
+ table['sodir'] = '$librubyverarch'
+ when 'site'
+ table['rbdir'] = '$siterubyver'
+ table['sodir'] = '$siterubyverarch'
+ when 'home'
+ setup_rb_error '$HOME was not set' unless ENV['HOME']
+ table['prefix'] = ENV['HOME']
+ table['rbdir'] = '$libdir/ruby'
+ table['sodir'] = '$libdir/ruby'
+ end
+ },
+ PathItem.new('prefix', 'path', c['prefix'],
+ 'path prefix of target environment'),
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+ 'the directory for commands'),
+ PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
+ 'the directory for libraries'),
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+ 'the directory for shared data'),
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+ 'the directory for man pages'),
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+ 'the directory for system configuration files'),
+ PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
+ 'the directory for local state data'),
+ PathItem.new('libruby', 'path', libruby,
+ 'the directory for ruby libraries'),
+ PathItem.new('librubyver', 'path', librubyver,
+ 'the directory for standard ruby libraries'),
+ PathItem.new('librubyverarch', 'path', librubyverarch,
+ 'the directory for standard ruby extensions'),
+ PathItem.new('siteruby', 'path', siteruby,
+ 'the directory for version-independent aux ruby libraries'),
+ PathItem.new('siterubyver', 'path', siterubyver,
+ 'the directory for aux ruby libraries'),
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
+ 'the directory for aux ruby binaries'),
+ PathItem.new('rbdir', 'path', '$siterubyver',
+ 'the directory for ruby scripts'),
+ PathItem.new('sodir', 'path', '$siterubyverarch',
+ 'the directory for ruby extentions'),
+ PathItem.new('rubypath', 'path', rubypath,
+ 'the path to set to #! line'),
+ ProgramItem.new('rubyprog', 'name', rubypath,
+ 'the ruby program using for installation'),
+ ProgramItem.new('makeprog', 'name', makeprog,
+ 'the make program to compile ruby extentions'),
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+ 'shebang line (#!) editing mode'),
+ BoolItem.new('without-ext', 'yes/no', 'no',
+ 'does not compile/install ruby extentions')
+ ]
+ end
+ private :standard_entries
+
+ def load_multipackage_entries
+ multipackage_entries().each do |ent|
+ add ent
+ end
+ end
+
+ def multipackage_entries
+ [
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+ 'package names that you want to install'),
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+ 'package names that you do not want to install')
+ ]
+ end
+ private :multipackage_entries
+
+ ALIASES = {
+ 'std-ruby' => 'librubyver',
+ 'stdruby' => 'librubyver',
+ 'rubylibdir' => 'librubyver',
+ 'archdir' => 'librubyverarch',
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
+ 'site-ruby' => 'siterubyver', # For backward compatibility
+ 'bin-dir' => 'bindir',
+ 'bin-dir' => 'bindir',
+ 'rb-dir' => 'rbdir',
+ 'so-dir' => 'sodir',
+ 'data-dir' => 'datadir',
+ 'ruby-path' => 'rubypath',
+ 'ruby-prog' => 'rubyprog',
+ 'ruby' => 'rubyprog',
+ 'make-prog' => 'makeprog',
+ 'make' => 'makeprog'
+ }
+
+ def fixup
+ ALIASES.each do |ali, name|
+ @table[ali] = @table[name]
+ end
+ @items.freeze
+ @table.freeze
+ @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
+ end
+
+ def parse_opt(opt)
+ m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
+ m.to_a[1,2]
+ end
+
+ def dllext
+ @rbconfig['DLEXT']
+ end
+
+ def value_config?(name)
+ lookup(name).value?
+ end
+
+ class Item
+ def initialize(name, template, default, desc)
+ @name = name.freeze
+ @template = template
+ @value = default
+ @default = default
+ @description = desc
+ end
+
+ attr_reader :name
+ attr_reader :description
+
+ attr_accessor :default
+ alias help_default default
+
+ def help_opt
+ "--#{@name}=#{@template}"
+ end
+
+ def value?
+ true
+ end
+
+ def value
+ @value
+ end
+
+ def resolve(table)
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
+ end
+
+ def set(val)
+ @value = check(val)
+ end
+
+ private
+
+ def check(val)
+ setup_rb_error "config: --#{name} requires argument" unless val
+ val
+ end
+ end
+
+ class BoolItem < Item
+ def config_type
+ 'bool'
+ end
+
+ def help_opt
+ "--#{@name}"
+ end
+
+ private
+
+ def check(val)
+ return 'yes' unless val
+ case val
+ when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
+ when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
+ else
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+ end
+ end
+ end
+
+ class PathItem < Item
+ def config_type
+ 'path'
+ end
+
+ private
+
+ def check(path)
+ setup_rb_error "config: --#{@name} requires argument" unless path
+ path[0,1] == '$' ? path : File.expand_path(path)
+ end
+ end
+
+ class ProgramItem < Item
+ def config_type
+ 'program'
+ end
+ end
+
+ class SelectItem < Item
+ def initialize(name, selection, default, desc)
+ super
+ @ok = selection.split('/')
+ end
+
+ def config_type
+ 'select'
+ end
+
+ private
+
+ def check(val)
+ unless @ok.include?(val.strip)
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+ end
+ val.strip
+ end
+ end
+
+ class ExecItem < Item
+ def initialize(name, selection, desc, &block)
+ super name, selection, nil, desc
+ @ok = selection.split('/')
+ @action = block
+ end
+
+ def config_type
+ 'exec'
+ end
+
+ def value?
+ false
+ end
+
+ def resolve(table)
+ setup_rb_error "$#{name()} wrongly used as option value"
+ end
+
+ undef set
+
+ def evaluate(val, table)
+ v = val.strip.downcase
+ unless @ok.include?(v)
+ setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
+ end
+ @action.call v, table
+ end
+ end
+
+ class PackageSelectionItem < Item
+ def initialize(name, template, default, help_default, desc)
+ super name, template, default, desc
+ @help_default = help_default
+ end
+
+ attr_reader :help_default
+
+ def config_type
+ 'package'
+ end
+
+ private
+
+ def check(val)
+ unless File.dir?("packages/#{val}")
+ setup_rb_error "config: no such package: #{val}"
+ end
+ val
+ end
+ end
+
+ class MetaConfigEnvironment
+ def initialize(config, installer)
+ @config = config
+ @installer = installer
+ end
+
+ def config_names
+ @config.names
+ end
+
+ def config?(name)
+ @config.key?(name)
+ end
+
+ def bool_config?(name)
+ @config.lookup(name).config_type == 'bool'
+ end
+
+ def path_config?(name)
+ @config.lookup(name).config_type == 'path'
+ end
+
+ def value_config?(name)
+ @config.lookup(name).config_type != 'exec'
+ end
+
+ def add_config(item)
+ @config.add item
+ end
+
+ def add_bool_config(name, default, desc)
+ @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+ end
+
+ def add_path_config(name, default, desc)
+ @config.add PathItem.new(name, 'path', default, desc)
+ end
+
+ def set_config_default(name, default)
+ @config.lookup(name).default = default
+ end
+
+ def remove_config(name)
+ @config.remove(name)
+ end
+
+ # For only multipackage
+ def packages
+ raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
+ @installer.packages
+ end
+
+ # For only multipackage
+ def declare_packages(list)
+ raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
+ @installer.packages = list
+ end
+ end
+
+end # class ConfigTable
+
+
+# This module requires: #verbose?, #no_harm?
+module FileOperations
+
+ def mkdir_p(dirname, prefix = nil)
+ dirname = prefix + File.expand_path(dirname) if prefix
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
+ return if no_harm?
+
+ # Does not check '/', it's too abnormal.
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
+ if /\A[a-z]:\z/i =~ dirs[0]
+ disk = dirs.shift
+ dirs[0] = disk + dirs[0]
+ end
+ dirs.each_index do |idx|
+ path = dirs[0..idx].join('')
+ Dir.mkdir path unless File.dir?(path)
+ end
+ end
+
+ def rm_f(path)
+ $stderr.puts "rm -f #{path}" if verbose?
+ return if no_harm?
+ force_remove_file path
+ end
+
+ def rm_rf(path)
+ $stderr.puts "rm -rf #{path}" if verbose?
+ return if no_harm?
+ remove_tree path
+ end
+
+ def remove_tree(path)
+ if File.symlink?(path)
+ remove_file path
+ elsif File.dir?(path)
+ remove_tree0 path
+ else
+ force_remove_file path
+ end
+ end
+
+ def remove_tree0(path)
+ Dir.foreach(path) do |ent|
+ next if ent == '.'
+ next if ent == '..'
+ entpath = "#{path}/#{ent}"
+ if File.symlink?(entpath)
+ remove_file entpath
+ elsif File.dir?(entpath)
+ remove_tree0 entpath
+ else
+ force_remove_file entpath
+ end
+ end
+ begin
+ Dir.rmdir path
+ rescue Errno::ENOTEMPTY
+ # directory may not be empty
+ end
+ end
+
+ def move_file(src, dest)
+ force_remove_file dest
+ begin
+ File.rename src, dest
+ rescue
+ File.open(dest, 'wb') {|f|
+ f.write File.binread(src)
+ }
+ File.chmod File.stat(src).mode, dest
+ File.unlink src
+ end
+ end
+
+ def force_remove_file(path)
+ begin
+ remove_file path
+ rescue
+ end
+ end
+
+ def remove_file(path)
+ File.chmod 0777, path
+ File.unlink path
+ end
+
+ def install(from, dest, mode, prefix = nil)
+ $stderr.puts "install #{from} #{dest}" if verbose?
+ return if no_harm?
+
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+ str = File.binread(from)
+ if diff?(str, realdest)
+ verbose_off {
+ rm_f realdest if File.exist?(realdest)
+ }
+ File.open(realdest, 'wb') {|f|
+ f.write str
+ }
+ File.chmod mode, realdest
+
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+ if prefix
+ f.puts realdest.sub(prefix, '')
+ else
+ f.puts realdest
+ end
+ }
+ end
+ end
+
+ def diff?(new_content, path)
+ return true unless File.exist?(path)
+ new_content != File.binread(path)
+ end
+
+ def command(*args)
+ $stderr.puts args.join(' ') if verbose?
+ system(*args) or raise RuntimeError,
+ "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
+ end
+
+ def ruby(*args)
+ command config('rubyprog'), *args
+ end
+
+ def make(task = nil)
+ command(*[config('makeprog'), task].compact)
+ end
+
+ def extdir?(dir)
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
+ end
+
+ def files_of(dir)
+ Dir.open(dir) {|d|
+ return d.select {|ent| File.file?("#{dir}/#{ent}") }
+ }
+ end
+
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
+
+ def directories_of(dir)
+ Dir.open(dir) {|d|
+ return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
+ }
+ end
+
+end
+
+
+# This module requires: #srcdir_root, #objdir_root, #relpath
+module HookScriptAPI
+
+ def get_config(key)
+ @config[key]
+ end
+
+ alias config get_config
+
+ # obsolete: use metaconfig to change configuration
+ def set_config(key, val)
+ @config[key] = val
+ end
+
+ #
+ # srcdir/objdir (works only in the package directory)
+ #
+
+ def curr_srcdir
+ "#{srcdir_root()}/#{relpath()}"
+ end
+
+ def curr_objdir
+ "#{objdir_root()}/#{relpath()}"
+ end
+
+ def srcfile(path)
+ "#{curr_srcdir()}/#{path}"
+ end
+
+ def srcexist?(path)
+ File.exist?(srcfile(path))
+ end
+
+ def srcdirectory?(path)
+ File.dir?(srcfile(path))
+ end
+
+ def srcfile?(path)
+ File.file?(srcfile(path))
+ end
+
+ def srcentries(path = '.')
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
+ return d.to_a - %w(. ..)
+ }
+ end
+
+ def srcfiles(path = '.')
+ srcentries(path).select {|fname|
+ File.file?(File.join(curr_srcdir(), path, fname))
+ }
+ end
+
+ def srcdirectories(path = '.')
+ srcentries(path).select {|fname|
+ File.dir?(File.join(curr_srcdir(), path, fname))
+ }
+ end
+
+end
+
+
+class ToplevelInstaller
+
+ Version = '3.4.1'
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
+
+ TASKS = [
+ [ 'all', 'do config, setup, then install' ],
+ [ 'config', 'saves your configurations' ],
+ [ 'show', 'shows current configuration' ],
+ [ 'setup', 'compiles ruby extentions and others' ],
+ [ 'install', 'installs files' ],
+ [ 'test', 'run all tests in test/' ],
+ [ 'clean', "does `make clean' for each extention" ],
+ [ 'distclean',"does `make distclean' for each extention" ]
+ ]
+
+ def ToplevelInstaller.invoke
+ config = ConfigTable.new(load_rbconfig())
+ config.load_standard_entries
+ config.load_multipackage_entries if multipackage?
+ config.fixup
+ klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
+ klass.new(File.dirname($0), config).invoke
+ end
+
+ def ToplevelInstaller.multipackage?
+ File.dir?(File.dirname($0) + '/packages')
+ end
+
+ def ToplevelInstaller.load_rbconfig
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+ ARGV.delete(arg)
+ load File.expand_path(arg.split(/=/, 2)[1])
+ $".push 'rbconfig.rb'
+ else
+ require 'rbconfig'
+ end
+ ::Config::CONFIG
+ end
+
+ def initialize(ardir_root, config)
+ @ardir = File.expand_path(ardir_root)
+ @config = config
+ # cache
+ @valid_task_re = nil
+ end
+
+ def config(key)
+ @config[key]
+ end
+
+ def inspect
+ "#<#{self.class} #{__id__()}>"
+ end
+
+ def invoke
+ run_metaconfigs
+ case task = parsearg_global()
+ when nil, 'all'
+ parsearg_config
+ init_installers
+ exec_config
+ exec_setup
+ exec_install
+ else
+ case task
+ when 'config', 'test'
+ ;
+ when 'clean', 'distclean'
+ @config.load_savefile if File.exist?(@config.savefile)
+ else
+ @config.load_savefile
+ end
+ __send__ "parsearg_#{task}"
+ init_installers
+ __send__ "exec_#{task}"
+ end
+ end
+
+ def run_metaconfigs
+ @config.load_script "#{@ardir}/metaconfig"
+ end
+
+ def init_installers
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
+ end
+
+ #
+ # Hook Script API bases
+ #
+
+ def srcdir_root
+ @ardir
+ end
+
+ def objdir_root
+ '.'
+ end
+
+ def relpath
+ '.'
+ end
+
+ #
+ # Option Parsing
+ #
+
+ def parsearg_global
+ while arg = ARGV.shift
+ case arg
+ when /\A\w+\z/
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
+ return arg
+ when '-q', '--quiet'
+ @config.verbose = false
+ when '--verbose'
+ @config.verbose = true
+ when '--help'
+ print_usage $stdout
+ exit 0
+ when '--version'
+ puts "#{File.basename($0)} version #{Version}"
+ exit 0
+ when '--copyright'
+ puts Copyright
+ exit 0
+ else
+ setup_rb_error "unknown global option '#{arg}'"
+ end
+ end
+ nil
+ end
+
+ def valid_task?(t)
+ valid_task_re() =~ t
+ end
+
+ def valid_task_re
+ @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
+ end
+
+ def parsearg_no_options
+ unless ARGV.empty?
+ task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
+ setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
+ end
+ end
+
+ alias parsearg_show parsearg_no_options
+ alias parsearg_setup parsearg_no_options
+ alias parsearg_test parsearg_no_options
+ alias parsearg_clean parsearg_no_options
+ alias parsearg_distclean parsearg_no_options
+
+ def parsearg_config
+ evalopt = []
+ set = []
+ @config.config_opt = []
+ while i = ARGV.shift
+ if /\A--?\z/ =~ i
+ @config.config_opt = ARGV.dup
+ break
+ end
+ name, value = *@config.parse_opt(i)
+ if @config.value_config?(name)
+ @config[name] = value
+ else
+ evalopt.push [name, value]
+ end
+ set.push name
+ end
+ evalopt.each do |name, value|
+ @config.lookup(name).evaluate value, @config
+ end
+ # Check if configuration is valid
+ set.each do |n|
+ @config[n] if @config.value_config?(n)
+ end
+ end
+
+ def parsearg_install
+ @config.no_harm = false
+ @config.install_prefix = ''
+ while a = ARGV.shift
+ case a
+ when '--no-harm'
+ @config.no_harm = true
+ when /\A--prefix=/
+ path = a.split(/=/, 2)[1]
+ path = File.expand_path(path) unless path[0,1] == '/'
+ @config.install_prefix = path
+ else
+ setup_rb_error "install: unknown option #{a}"
+ end
+ end
+ end
+
+ def print_usage(out)
+ out.puts 'Typical Installation Procedure:'
+ out.puts " $ ruby #{File.basename $0} config"
+ out.puts " $ ruby #{File.basename $0} setup"
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
+ out.puts
+ out.puts 'Detailed Usage:'
+ out.puts " ruby #{File.basename $0} <global option>"
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+ fmt = " %-24s %s\n"
+ out.puts
+ out.puts 'Global options:'
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
+ out.printf fmt, ' --verbose', 'output messages verbosely'
+ out.printf fmt, ' --help', 'print this message'
+ out.printf fmt, ' --version', 'print version and quit'
+ out.printf fmt, ' --copyright', 'print copyright and quit'
+ out.puts
+ out.puts 'Tasks:'
+ TASKS.each do |name, desc|
+ out.printf fmt, name, desc
+ end
+
+ fmt = " %-24s %s [%s]\n"
+ out.puts
+ out.puts 'Options for CONFIG or ALL:'
+ @config.each do |item|
+ out.printf fmt, item.help_opt, item.description, item.help_default
+ end
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+ out.puts
+ out.puts 'Options for INSTALL:'
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+ out.printf fmt, '--prefix=path', 'install path prefix', ''
+ out.puts
+ end
+
+ #
+ # Task Handlers
+ #
+
+ def exec_config
+ @installer.exec_config
+ @config.save # must be final
+ end
+
+ def exec_setup
+ @installer.exec_setup
+ end
+
+ def exec_install
+ @installer.exec_install
+ end
+
+ def exec_test
+ @installer.exec_test
+ end
+
+ def exec_show
+ @config.each do |i|
+ printf "%-20s %s\n", i.name, i.value if i.value?
+ end
+ end
+
+ def exec_clean
+ @installer.exec_clean
+ end
+
+ def exec_distclean
+ @installer.exec_distclean
+ end
+
+end # class ToplevelInstaller
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+ include FileOperations
+
+ def initialize(ardir_root, config)
+ super
+ @packages = directories_of("#{@ardir}/packages")
+ raise 'no package exists' if @packages.empty?
+ @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
+ end
+
+ def run_metaconfigs
+ @config.load_script "#{@ardir}/metaconfig", self
+ @packages.each do |name|
+ @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
+ end
+ end
+
+ attr_reader :packages
+
+ def packages=(list)
+ raise 'package list is empty' if list.empty?
+ list.each do |name|
+ raise "directory packages/#{name} does not exist"\
+ unless File.dir?("#{@ardir}/packages/#{name}")
+ end
+ @packages = list
+ end
+
+ def init_installers
+ @installers = {}
+ @packages.each do |pack|
+ @installers[pack] = Installer.new(@config,
+ "#{@ardir}/packages/#{pack}",
+ "packages/#{pack}")
+ end
+ with = extract_selection(config('with'))
+ without = extract_selection(config('without'))
+ @selected = @installers.keys.select {|name|
+ (with.empty? or with.include?(name)) \
+ and not without.include?(name)
+ }
+ end
+
+ def extract_selection(list)
+ a = list.split(/,/)
+ a.each do |name|
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
+ end
+ a
+ end
+
+ def print_usage(f)
+ super
+ f.puts 'Inluded packages:'
+ f.puts ' ' + @packages.sort.join(' ')
+ f.puts
+ end
+
+ #
+ # Task Handlers
+ #
+
+ def exec_config
+ run_hook 'pre-config'
+ each_selected_installers {|inst| inst.exec_config }
+ run_hook 'post-config'
+ @config.save # must be final
+ end
+
+ def exec_setup
+ run_hook 'pre-setup'
+ each_selected_installers {|inst| inst.exec_setup }
+ run_hook 'post-setup'
+ end
+
+ def exec_install
+ run_hook 'pre-install'
+ each_selected_installers {|inst| inst.exec_install }
+ run_hook 'post-install'
+ end
+
+ def exec_test
+ run_hook 'pre-test'
+ each_selected_installers {|inst| inst.exec_test }
+ run_hook 'post-test'
+ end
+
+ def exec_clean
+ rm_f @config.savefile
+ run_hook 'pre-clean'
+ each_selected_installers {|inst| inst.exec_clean }
+ run_hook 'post-clean'
+ end
+
+ def exec_distclean
+ rm_f @config.savefile
+ run_hook 'pre-distclean'
+ each_selected_installers {|inst| inst.exec_distclean }
+ run_hook 'post-distclean'
+ end
+
+ #
+ # lib
+ #
+
+ def each_selected_installers
+ Dir.mkdir 'packages' unless File.dir?('packages')
+ @selected.each do |pack|
+ $stderr.puts "Processing the package `#{pack}' ..." if verbose?
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+ Dir.chdir "packages/#{pack}"
+ yield @installers[pack]
+ Dir.chdir '../..'
+ end
+ end
+
+ def run_hook(id)
+ @root_installer.run_hook id
+ end
+
+ # module FileOperations requires this
+ def verbose?
+ @config.verbose?
+ end
+
+ # module FileOperations requires this
+ def no_harm?
+ @config.no_harm?
+ end
+
+end # class ToplevelInstallerMulti
+
+
+class Installer
+
+ FILETYPES = %w( bin lib ext data conf man )
+
+ include FileOperations
+ include HookScriptAPI
+
+ def initialize(config, srcroot, objroot)
+ @config = config
+ @srcdir = File.expand_path(srcroot)
+ @objdir = File.expand_path(objroot)
+ @currdir = '.'
+ end
+
+ def inspect
+ "#<#{self.class} #{File.basename(@srcdir)}>"
+ end
+
+ def noop(rel)
+ end
+
+ #
+ # Hook Script API base methods
+ #
+
+ def srcdir_root
+ @srcdir
+ end
+
+ def objdir_root
+ @objdir
+ end
+
+ def relpath
+ @currdir
+ end
+
+ #
+ # Config Access
+ #
+
+ # module FileOperations requires this
+ def verbose?
+ @config.verbose?
+ end
+
+ # module FileOperations requires this
+ def no_harm?
+ @config.no_harm?
+ end
+
+ def verbose_off
+ begin
+ save, @config.verbose = @config.verbose?, false
+ yield
+ ensure
+ @config.verbose = save
+ end
+ end
+
+ #
+ # TASK config
+ #
+
+ def exec_config
+ exec_task_traverse 'config'
+ end
+
+ alias config_dir_bin noop
+ alias config_dir_lib noop
+
+ def config_dir_ext(rel)
+ extconf if extdir?(curr_srcdir())
+ end
+
+ alias config_dir_data noop
+ alias config_dir_conf noop
+ alias config_dir_man noop
+
+ def extconf
+ ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
+ end
+
+ #
+ # TASK setup
+ #
+
+ def exec_setup
+ exec_task_traverse 'setup'
+ end
+
+ def setup_dir_bin(rel)
+ files_of(curr_srcdir()).each do |fname|
+ update_shebang_line "#{curr_srcdir()}/#{fname}"
+ end
+ end
+
+ alias setup_dir_lib noop
+
+ def setup_dir_ext(rel)
+ make if extdir?(curr_srcdir())
+ end
+
+ alias setup_dir_data noop
+ alias setup_dir_conf noop
+ alias setup_dir_man noop
+
+ def update_shebang_line(path)
+ return if no_harm?
+ return if config('shebang') == 'never'
+ old = Shebang.load(path)
+ if old
+ $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
+ new = new_shebang(old)
+ return if new.to_s == old.to_s
+ else
+ return unless config('shebang') == 'all'
+ new = Shebang.new(config('rubypath'))
+ end
+ $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
+ open_atomic_writer(path) {|output|
+ File.open(path, 'rb') {|f|
+ f.gets if old # discard
+ output.puts new.to_s
+ output.print f.read
+ }
+ }
+ end
+
+ def new_shebang(old)
+ if /\Aruby/ =~ File.basename(old.cmd)
+ Shebang.new(config('rubypath'), old.args)
+ elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
+ Shebang.new(config('rubypath'), old.args[1..-1])
+ else
+ return old unless config('shebang') == 'all'
+ Shebang.new(config('rubypath'))
+ end
+ end
+
+ def open_atomic_writer(path, &block)
+ tmpfile = File.basename(path) + '.tmp'
+ begin
+ File.open(tmpfile, 'wb', &block)
+ File.rename tmpfile, File.basename(path)
+ ensure
+ File.unlink tmpfile if File.exist?(tmpfile)
+ end
+ end
+
+ class Shebang
+ def Shebang.load(path)
+ line = nil
+ File.open(path) {|f|
+ line = f.gets
+ }
+ return nil unless /\A#!/ =~ line
+ parse(line)
+ end
+
+ def Shebang.parse(line)
+ cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
+ new(cmd, args)
+ end
+
+ def initialize(cmd, args = [])
+ @cmd = cmd
+ @args = args
+ end
+
+ attr_reader :cmd
+ attr_reader :args
+
+ def to_s
+ "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
+ end
+ end
+
+ #
+ # TASK install
+ #
+
+ def exec_install
+ rm_f 'InstalledFiles'
+ exec_task_traverse 'install'
+ end
+
+ def install_dir_bin(rel)
+ install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
+ end
+
+ def install_dir_lib(rel)
+ install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
+ end
+
+ def install_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ install_files rubyextentions('.'),
+ "#{config('sodir')}/#{File.dirname(rel)}",
+ 0555
+ end
+
+ def install_dir_data(rel)
+ install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
+ end
+
+ def install_dir_conf(rel)
+ # FIXME: should not remove current config files
+ # (rename previous file to .old/.org)
+ install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
+ end
+
+ def install_dir_man(rel)
+ install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
+ end
+
+ def install_files(list, dest, mode)
+ mkdir_p dest, @config.install_prefix
+ list.each do |fname|
+ install fname, dest, mode, @config.install_prefix
+ end
+ end
+
+ def libfiles
+ glob_reject(%w(*.y *.output), targetfiles())
+ end
+
+ def rubyextentions(dir)
+ ents = glob_select("*.#{@config.dllext}", targetfiles())
+ if ents.empty?
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+ end
+ ents
+ end
+
+ def targetfiles
+ mapdir(existfiles() - hookfiles())
+ end
+
+ def mapdir(ents)
+ ents.map {|ent|
+ if File.exist?(ent)
+ then ent # objdir
+ else "#{curr_srcdir()}/#{ent}" # srcdir
+ end
+ }
+ end
+
+ # picked up many entries from cvs-1.11.1/src/ignore.c
+ JUNK_FILES = %w(
+ core RCSLOG tags TAGS .make.state
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+ *.org *.in .*
+ )
+
+ def existfiles
+ glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
+ end
+
+ def hookfiles
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
+ }.flatten
+ end
+
+ def glob_select(pat, ents)
+ re = globs2re([pat])
+ ents.select {|ent| re =~ ent }
+ end
+
+ def glob_reject(pats, ents)
+ re = globs2re(pats)
+ ents.reject {|ent| re =~ ent }
+ end
+
+ GLOB2REGEX = {
+ '.' => '\.',
+ '$' => '\$',
+ '#' => '\#',
+ '*' => '.*'
+ }
+
+ def globs2re(pats)
+ /\A(?:#{
+ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
+ })\z/
+ end
+
+ #
+ # TASK test
+ #
+
+ TESTDIR = 'test'
+
+ def exec_test
+ unless File.directory?('test')
+ $stderr.puts 'no test in this package' if verbose?
+ return
+ end
+ $stderr.puts 'Running tests...' if verbose?
+ begin
+ require 'test/unit'
+ rescue LoadError
+ setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
+ end
+ runner = Test::Unit::AutoRunner.new(true)
+ runner.to_run << TESTDIR
+ runner.run
+ end
+
+ #
+ # TASK clean
+ #
+
+ def exec_clean
+ exec_task_traverse 'clean'
+ rm_f @config.savefile
+ rm_f 'InstalledFiles'
+ end
+
+ alias clean_dir_bin noop
+ alias clean_dir_lib noop
+ alias clean_dir_data noop
+ alias clean_dir_conf noop
+ alias clean_dir_man noop
+
+ def clean_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ make 'clean' if File.file?('Makefile')
+ end
+
+ #
+ # TASK distclean
+ #
+
+ def exec_distclean
+ exec_task_traverse 'distclean'
+ rm_f @config.savefile
+ rm_f 'InstalledFiles'
+ end
+
+ alias distclean_dir_bin noop
+ alias distclean_dir_lib noop
+
+ def distclean_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ make 'distclean' if File.file?('Makefile')
+ end
+
+ alias distclean_dir_data noop
+ alias distclean_dir_conf noop
+ alias distclean_dir_man noop
+
+ #
+ # Traversing
+ #
+
+ def exec_task_traverse(task)
+ run_hook "pre-#{task}"
+ FILETYPES.each do |type|
+ if type == 'ext' and config('without-ext') == 'yes'
+ $stderr.puts 'skipping ext/* by user option' if verbose?
+ next
+ end
+ traverse task, type, "#{task}_dir_#{type}"
+ end
+ run_hook "post-#{task}"
+ end
+
+ def traverse(task, rel, mid)
+ dive_into(rel) {
+ run_hook "pre-#{task}"
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+ directories_of(curr_srcdir()).each do |d|
+ traverse task, "#{rel}/#{d}", mid
+ end
+ run_hook "post-#{task}"
+ }
+ end
+
+ def dive_into(rel)
+ return unless File.dir?("#{@srcdir}/#{rel}")
+
+ dir = File.basename(rel)
+ Dir.mkdir dir unless File.dir?(dir)
+ prevdir = Dir.pwd
+ Dir.chdir dir
+ $stderr.puts '---> ' + rel if verbose?
+ @currdir = rel
+ yield
+ Dir.chdir prevdir
+ $stderr.puts '<--- ' + rel if verbose?
+ @currdir = File.dirname(rel)
+ end
+
+ def run_hook(id)
+ path = [ "#{curr_srcdir()}/#{id}",
+ "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
+ return unless path
+ begin
+ instance_eval File.read(path), path, 1
+ rescue
+ raise if $DEBUG
+ setup_rb_error "hook #{path} failed:\n" + $!.message
+ end
+ end
+
+end # class Installer
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+ raise SetupError, msg
+end
+
+if $0 == __FILE__
+ begin
+ ToplevelInstaller.invoke
+ rescue SetupError
+ raise if $DEBUG
+ $stderr.puts $!.message
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+ exit 1
+ end
+end
diff --git a/ruby/gem/tasks/deployment.rake b/ruby/gem/tasks/deployment.rake
new file mode 100644
index 0000000..2f43742
--- /dev/null
+++ b/ruby/gem/tasks/deployment.rake
@@ -0,0 +1,34 @@
+desc 'Release the website and new gem version'
+task :deploy => [:check_version, :website, :release] do
+ puts "Remember to create SVN tag:"
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
+ puts "Suggested comment:"
+ puts "Tagging release #{CHANGES}"
+end
+
+desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
+task :local_deploy => [:website_generate, :install_gem]
+
+task :check_version do
+ unless ENV['VERSION']
+ puts 'Must pass a VERSION=x.y.z release version'
+ exit
+ end
+ unless ENV['VERSION'] == VERS
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
+ exit
+ end
+end
+
+desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
+task :install_gem_no_doc => [:clean, :package] do
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
+end
+
+namespace :manifest do
+ desc 'Recreate Manifest.txt to include ALL files'
+ task :refresh do
+ `rake check_manifest | patch -p0 > Manifest.txt`
+ end
+end \ No newline at end of file
diff --git a/ruby/gem/tasks/environment.rake b/ruby/gem/tasks/environment.rake
new file mode 100644
index 0000000..691ed3b
--- /dev/null
+++ b/ruby/gem/tasks/environment.rake
@@ -0,0 +1,7 @@
+task :ruby_env do
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
+ "jruby"
+ else
+ "ruby"
+ end unless defined? RUBY_APP
+end
diff --git a/ruby/pack.c b/ruby/pack.c
new file mode 100644
index 0000000..3520f9f
--- /dev/null
+++ b/ruby/pack.c
@@ -0,0 +1,131 @@
+/*
+ * MessagePack packing routine for Ruby
+ *
+ * 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.
+ */
+#include "pack_inline.h"
+
+#ifndef RUBY_VM
+#include "st.h" // ruby hash
+#endif
+
+static ID s_to_msgpack;
+
+#define ARG_BUFFER(name, argc, argv) \
+ VALUE name; \
+ if(argc == 1) { \
+ name = argv[0]; \
+ } else if(argc == 0) { \
+ name = rb_str_buf_new(0); \
+ } else { \
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); \
+ }
+
+static VALUE MessagePack_NilClass_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_nil(out);
+ return out;
+}
+
+static VALUE MessagePack_TrueClass_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_true(out);
+ return out;
+}
+
+static VALUE MessagePack_FalseClass_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_false(out);
+ return out;
+}
+
+
+static VALUE MessagePack_Fixnum_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_int(out, FIX2INT(self));
+ return out;
+}
+
+static VALUE MessagePack_Float_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_double(out, rb_num2dbl(self));
+ return out;
+}
+
+static VALUE MessagePack_String_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_raw(out, RSTRING_PTR(self), RSTRING_LEN(self));
+ return out;
+}
+
+static VALUE MessagePack_Array_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_array(out, RARRAY_LEN(self));
+ VALUE* p = RARRAY_PTR(self);
+ VALUE* const pend = p + RARRAY_LEN(self);
+ for(;p != pend; ++p) {
+ rb_funcall(*p, s_to_msgpack, 1, out);
+ }
+ return out;
+}
+
+#ifndef RHASH_SIZE // Ruby 1.8
+#define RHASH_SIZE(h) (RHASH(h)->tbl ? RHASH(h)->tbl->num_entries : 0)
+#endif
+
+static int MessagePack_Hash_to_msgpack_foreach(VALUE key, VALUE value, VALUE out)
+{
+ if (key == Qundef) { return ST_CONTINUE; }
+ rb_funcall(key, s_to_msgpack, 1, out);
+ rb_funcall(value, s_to_msgpack, 1, out);
+ return ST_CONTINUE;
+}
+
+static VALUE MessagePack_Hash_to_msgpack(int argc, VALUE *argv, VALUE self)
+{
+ ARG_BUFFER(out, argc, argv);
+ msgpack_pack_map(out, RHASH_SIZE(self));
+ rb_hash_foreach(self, MessagePack_Hash_to_msgpack_foreach, out);
+ return out;
+}
+
+
+static VALUE MessagePack_pack(VALUE self, VALUE data)
+{
+ return rb_funcall(data, s_to_msgpack, 0);
+}
+
+
+void Init_msgpack_pack(VALUE mMessagePack)
+{
+ s_to_msgpack = rb_intern("to_msgpack");
+ rb_define_method_id(rb_cNilClass, s_to_msgpack, MessagePack_NilClass_to_msgpack, -1);
+ rb_define_method_id(rb_cTrueClass, s_to_msgpack, MessagePack_TrueClass_to_msgpack, -1);
+ rb_define_method_id(rb_cFalseClass, s_to_msgpack, MessagePack_FalseClass_to_msgpack, -1);
+ rb_define_method_id(rb_cFixnum, s_to_msgpack, MessagePack_Fixnum_to_msgpack, -1);
+ rb_define_method_id(rb_cFloat, s_to_msgpack, MessagePack_Float_to_msgpack, -1);
+ rb_define_method_id(rb_cString, s_to_msgpack, MessagePack_String_to_msgpack, -1);
+ rb_define_method_id(rb_cArray, s_to_msgpack, MessagePack_Array_to_msgpack, -1);
+ rb_define_method_id(rb_cHash, s_to_msgpack, MessagePack_Hash_to_msgpack, -1);
+ rb_define_module_function(mMessagePack, "pack", MessagePack_pack, 1);
+}
+
diff --git a/ruby/pack.h b/ruby/pack.h
new file mode 100644
index 0000000..c38ac48
--- /dev/null
+++ b/ruby/pack.h
@@ -0,0 +1,26 @@
+/*
+ * MessagePack packing routine for Ruby
+ *
+ * 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.
+ */
+#ifndef PACK_H__
+#define PACK_H__
+
+#include "ruby.h"
+
+void Init_msgpack_pack(VALUE mMessagePack);
+
+#endif /* pack.h */
+
diff --git a/ruby/pack_inline.h b/ruby/pack_inline.h
new file mode 100644
index 0000000..ab4b092
--- /dev/null
+++ b/ruby/pack_inline.h
@@ -0,0 +1,33 @@
+/*
+ * MessagePack packing routine for Ruby
+ *
+ * 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.
+ */
+#ifndef PACK_INLINE_H__
+#define PACK_INLINE_H__
+
+#include "ruby.h"
+
+typedef VALUE msgpack_pack_context;
+
+static inline void msgpack_pack_append_buffer(VALUE x, const unsigned char* b, unsigned int l)
+{
+ rb_str_buf_cat(x, (const void*)b, l);
+}
+
+#include "msgpack/pack/inline_impl.h"
+
+#endif /* pack_inline.h */
+
diff --git a/ruby/rbinit.c b/ruby/rbinit.c
new file mode 100644
index 0000000..7ef92fb
--- /dev/null
+++ b/ruby/rbinit.c
@@ -0,0 +1,29 @@
+/*
+ * MessagePack for Ruby
+ *
+ * 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.
+ */
+#include "pack.h"
+#include "unpack.h"
+
+static VALUE mMessagePack;
+
+void Init_msgpack(void)
+{
+ mMessagePack = rb_define_module("MessagePack");
+ Init_msgpack_unpack(mMessagePack);
+ Init_msgpack_pack(mMessagePack);
+}
+
diff --git a/ruby/test_format.rb b/ruby/test_format.rb
new file mode 100644
index 0000000..7c2e8fc
--- /dev/null
+++ b/ruby/test_format.rb
@@ -0,0 +1,128 @@
+require 'msgpack'
+
+@up = MessagePack::Unpacker.new
+
+def check(bytes, should)
+ puts "----"
+ @up.reset
+ src = bytes.pack('C*')
+ ret = @up.execute(src, 0)
+ if ret != src.length
+ puts "** EXTRA BYTES **"
+ end
+ puts bytes.map{|x|"%x"%x}.join(' ')
+ data = @up.data
+ p data
+ if data != should
+ puts "** TEST FAILED **"
+ p should
+ end
+end
+
+# SimpleValue
+check([
+ 0x93, 0xc0, 0xc2, 0xc3,
+], [nil,false,true])
+
+# Fixnum
+check([
+ 0x92,
+ 0x93, 0x00, 0x40, 0x7f,
+ 0x93, 0xe0, 0xf0, 0xff,
+], [[0,64,127], [-32,-16,-1]])
+
+# FixArray
+check([
+ 0x92,
+ 0x90,
+ 0x91,
+ 0x91, 0xc0,
+], [[],[[nil]]])
+
+
+# FixRaw
+check([
+ 0x94,
+ 0xa0,
+ 0xa1, ?a,
+ 0xa2, ?b, ?c,
+ 0xa3, ?d, ?e, ?f,
+], ["","a","bc","def"])
+
+# FixMap
+check([
+ 0x82,
+ 0xc2, 0x81,
+ 0xc0, 0xc0,
+ 0xc3, 0x81,
+ 0xc0, 0x80,
+], {false=>{nil=>nil}, true=>{nil=>{}}})
+
+# unsigned int
+check([
+ 0x99,
+ 0xcc, 0,
+ 0xcc, 128,
+ 0xcc, 255,
+ 0xcd, 0x00, 0x00,
+ 0xcd, 0x80, 0x00,
+ 0xcd, 0xff, 0xff,
+ 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0xce, 0x80, 0x00, 0x00, 0x00,
+ 0xce, 0xff, 0xff, 0xff, 0xff,
+], [0, 128, 255, 0, 32768, 65535, 0, 2147483648, 4294967295])
+
+# signed int
+check([
+ 0x99,
+ 0xd0, 0,
+ 0xd0, 128,
+ 0xd0, 255,
+ 0xd1, 0x00, 0x00,
+ 0xd1, 0x80, 0x00,
+ 0xd1, 0xff, 0xff,
+ 0xd2, 0x00, 0x00, 0x00, 0x00,
+ 0xd2, 0x80, 0x00, 0x00, 0x00,
+ 0xd2, 0xff, 0xff, 0xff, 0xff,
+], [0, -128, -1, 0, -32768, -1, 0, -2147483648, -1])
+
+# raw
+check([
+ 0x96,
+ 0xda, 0x00, 0x00,
+ 0xda, 0x00, 0x01, ?a,
+ 0xda, 0x00, 0x02, ?a, ?b,
+ 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0x00, 0x00, 0x01, ?a,
+ 0xdb, 0x00, 0x00, 0x00, 0x02, ?a, ?b,
+], ["", "a", "ab", "", "a", "ab"])
+
+# array
+check([
+ 0x96,
+ 0xdc, 0x00, 0x00,
+ 0xdc, 0x00, 0x01, 0xc0,
+ 0xdc, 0x00, 0x02, 0xc2, 0xc3,
+ 0xdd, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0x00, 0x00, 0x01, 0xc0,
+ 0xdd, 0x00, 0x00, 0x00, 0x02, 0xc2, 0xc3
+], [[], [nil], [false,true], [], [nil], [false,true]])
+
+# map
+check([
+ 0x96,
+ 0xde, 0x00, 0x00,
+ 0xde, 0x00, 0x01, 0xc0, 0xc2,
+ 0xde, 0x00, 0x02, 0xc0, 0xc2, 0xc3, 0xc2,
+ 0xdf, 0x00, 0x00, 0x00, 0x00,
+ 0xdf, 0x00, 0x00, 0x00, 0x01, 0xc0, 0xc2,
+ 0xdf, 0x00, 0x00, 0x00, 0x02, 0xc0, 0xc2, 0xc3, 0xc2,
+], [{}, {nil=>false}, {true=>false, nil=>false}, {}, {nil=>false}, {true=>false, nil=>false}])
+
+# string
+check([
+ 0x92,
+ 0xc1, 0x00,
+ 0xc1, ?a, ?b, ?c, 0x00,
+], ["", "abc"])
+
diff --git a/ruby/test_pack.rb b/ruby/test_pack.rb
new file mode 100644
index 0000000..16a8ccf
--- /dev/null
+++ b/ruby/test_pack.rb
@@ -0,0 +1,56 @@
+require 'msgpack'
+
+def check(data)
+ puts "---"
+ pack = data.to_msgpack
+ p data
+ puts pack.unpack('C*').map{|x|"%02x"%x}.join(' ')
+ re = MessagePack::unpack(pack)
+ if re != data
+ p re
+ puts "** TEST FAILED **"
+ end
+end
+
+check 0
+check 1
+check 127
+check 128
+check 255
+check 256
+check 65535
+check 65536
+check -1
+check -128
+check -129
+check -32768
+check -32769
+
+check 1.0
+
+check ""
+check "a"
+check "a"*31
+check "a"*32
+
+check nil
+check true
+check false
+
+check []
+check [[]]
+check [[], nil]
+
+check( {nil=>0} )
+
+check (1<<23)
+__END__
+
+ary = []
+i = 0
+while i < (1<<16)
+ ary << i
+ i += 1
+end
+check ary
+
diff --git a/ruby/unpack.c b/ruby/unpack.c
new file mode 100644
index 0000000..fa2996d
--- /dev/null
+++ b/ruby/unpack.c
@@ -0,0 +1,202 @@
+/*
+ * MessagePack unpacking routine for Ruby
+ *
+ * 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.
+ */
+#include "ruby.h"
+#include "unpack_context.h"
+#include <stdio.h>
+
+#define UNPACKER(from, name) \
+ msgpack_unpacker *name = NULL; \
+ Data_Get_Struct(from, msgpack_unpacker, name); \
+ if(name == NULL) { \
+ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
+ }
+
+#define CHECK_STRING_TYPE(value) \
+ value = rb_check_string_type(value); \
+ if( NIL_P(value) ) { \
+ rb_raise(rb_eTypeError, "instance of String needed"); \
+ }
+
+static VALUE cUnpacker;
+static VALUE eUnpackError;
+
+static void MessagePack_Unpacker_free(void* data)
+{
+ if(data) { free(data); }
+}
+
+static void MessagePack_Unpacker_mark(msgpack_unpacker *mp)
+{
+ unsigned int i;
+ for(i=0; i < mp->top; ++i) {
+ rb_gc_mark(mp->stack[i].obj);
+ rb_gc_mark(mp->stack[i].tmp.map_key);
+ }
+}
+
+static VALUE MessagePack_Unpacker_alloc(VALUE klass)
+{
+ VALUE obj;
+ msgpack_unpacker* mp = ALLOC_N(msgpack_unpacker, 1);
+ obj = Data_Wrap_Struct(klass, MessagePack_Unpacker_mark,
+ MessagePack_Unpacker_free, mp);
+ return obj;
+}
+
+static VALUE MessagePack_Unpacker_reset(VALUE self)
+{
+ UNPACKER(self, mp);
+ mp->user.finished = false;
+ msgpack_unpacker_init(mp);
+ return self;
+}
+
+static VALUE MessagePack_Unpacker_initialize(VALUE self)
+{
+ return MessagePack_Unpacker_reset(self);
+}
+
+
+static VALUE MessagePack_Unpacker_execute_impl(VALUE args)
+{
+ VALUE self = ((VALUE*)args)[0];
+ VALUE data = ((VALUE*)args)[1];
+ VALUE off = ((VALUE*)args)[2];
+
+ UNPACKER(self, mp);
+ size_t from = NUM2UINT(off);
+ char* dptr = RSTRING_PTR(data);
+ long dlen = RSTRING_LEN(data);
+ int ret;
+
+ if(from >= dlen) {
+ rb_raise(eUnpackError, "Requested start is after data buffer end.");
+ }
+
+ ret = msgpack_unpacker_execute(mp, dptr, (size_t)dlen, &from);
+
+ if(ret < 0) {
+ rb_raise(eUnpackError, "Parse error.");
+ } else if(ret > 0) {
+ mp->user.finished = true;
+ return ULONG2NUM(from);
+ } else {
+ mp->user.finished = false;
+ return ULONG2NUM(from);
+ }
+}
+
+static VALUE MessagePack_Unpacker_execute_rescue(VALUE nouse)
+{
+ rb_gc_enable();
+#ifdef RUBY_VM
+ rb_exc_raise(rb_errinfo());
+#else
+ rb_exc_raise(ruby_errinfo);
+#endif
+}
+
+static VALUE MessagePack_Unpacker_execute(VALUE self, VALUE data, VALUE off)
+{
+ // FIXME execute実行中はmp->topが更新されないのでGC markが機能しない
+ rb_gc_disable();
+ VALUE args[3] = {self, data, off};
+ VALUE ret = rb_rescue(MessagePack_Unpacker_execute_impl, (VALUE)args,
+ MessagePack_Unpacker_execute_rescue, Qnil);
+ rb_gc_enable();
+ return ret;
+}
+
+static VALUE MessagePack_Unpacker_finished_p(VALUE self)
+{
+ UNPACKER(self, mp);
+ if(mp->user.finished) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+static VALUE MessagePack_Unpacker_data(VALUE self)
+{
+ UNPACKER(self, mp);
+ return msgpack_unpacker_data(mp);
+}
+
+
+static VALUE MessagePack_unpack_impl(VALUE args)
+{
+ msgpack_unpacker* mp = (msgpack_unpacker*)((VALUE*)args)[0];
+ VALUE data = ((VALUE*)args)[1];
+
+ size_t from = 0;
+ char* dptr = RSTRING_PTR(data);
+ long dlen = RSTRING_LEN(data);
+ int ret;
+
+ ret = msgpack_unpacker_execute(mp, dptr, (size_t)dlen, &from);
+
+ if(ret < 0) {
+ rb_raise(eUnpackError, "Parse error.");
+ } else if(ret == 0) {
+ rb_raise(eUnpackError, "Insufficient bytes.");
+ } else {
+ if(from < dlen) {
+ rb_raise(eUnpackError, "Extra bytes.");
+ }
+ return msgpack_unpacker_data(mp);
+ }
+}
+
+static VALUE MessagePack_unpack_rescue(VALUE args)
+{
+ rb_gc_enable();
+#ifdef RUBY_VM
+ rb_exc_raise(rb_errinfo());
+#else
+ rb_exc_raise(ruby_errinfo);
+#endif
+}
+
+static VALUE MessagePack_unpack(VALUE self, VALUE data)
+{
+ CHECK_STRING_TYPE(data);
+ msgpack_unpacker mp;
+ msgpack_unpacker_init(&mp);
+ rb_gc_disable();
+ VALUE args[2] = {(VALUE)&mp, data};
+ VALUE ret = rb_rescue(MessagePack_unpack_impl, (VALUE)args,
+ MessagePack_unpack_rescue, Qnil);
+ rb_gc_enable();
+ return ret;
+}
+
+
+void Init_msgpack_unpack(VALUE mMessagePack)
+{
+ eUnpackError = rb_define_class_under(mMessagePack, "UnpackError", rb_eStandardError);
+ cUnpacker = rb_define_class_under(mMessagePack, "Unpacker", rb_cObject);
+ rb_define_alloc_func(cUnpacker, MessagePack_Unpacker_alloc);
+ rb_define_method(cUnpacker, "initialize", MessagePack_Unpacker_initialize, 0);
+ rb_define_method(cUnpacker, "execute", MessagePack_Unpacker_execute, 2);
+ rb_define_method(cUnpacker, "finished?", MessagePack_Unpacker_finished_p, 0);
+ rb_define_method(cUnpacker, "data", MessagePack_Unpacker_data, 0);
+ rb_define_method(cUnpacker, "reset", MessagePack_Unpacker_reset, 0);
+ rb_define_module_function(mMessagePack, "unpack", MessagePack_unpack, 1);
+}
+
+
diff --git a/ruby/unpack.h b/ruby/unpack.h
new file mode 100644
index 0000000..0fe01ec
--- /dev/null
+++ b/ruby/unpack.h
@@ -0,0 +1,26 @@
+/*
+ * MessagePack unpacking routine for Ruby
+ *
+ * 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.
+ */
+#ifndef UNPACK_H__
+#define UNPACK_H__
+
+#include "ruby.h"
+
+void Init_msgpack_unpack(VALUE mMessagePack);
+
+#endif /* unpack.h */
+
diff --git a/ruby/unpack_context.h b/ruby/unpack_context.h
new file mode 100644
index 0000000..35e0132
--- /dev/null
+++ b/ruby/unpack_context.h
@@ -0,0 +1,35 @@
+/*
+ * MessagePack unpacking routine for Ruby
+ *
+ * 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.
+ */
+#ifndef UNPACK_CONTEXT_H__
+#define UNPACK_CONTEXT_H__
+
+#include "ruby.h"
+#include <stddef.h>
+#include <stdbool.h>
+
+typedef VALUE msgpack_object;
+
+typedef struct {
+ bool finished;
+} msgpack_unpack_context;
+
+
+#include "msgpack/unpack/inline_context.h"
+
+#endif /* unpack_context.h */
+
diff --git a/ruby/unpack_inline.c b/ruby/unpack_inline.c
new file mode 100644
index 0000000..fa684c9
--- /dev/null
+++ b/ruby/unpack_inline.c
@@ -0,0 +1,81 @@
+/*
+ * MessagePack unpacking routine for Ruby
+ *
+ * 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.
+ */
+#include "unpack_context.h"
+
+static inline VALUE msgpack_unpack_init(msgpack_unpack_context* x)
+{ return Qnil; }
+
+static inline VALUE msgpack_unpack_unsigned_int_8(msgpack_unpack_context* x, uint8_t d)
+{ return INT2FIX(d); }
+
+static inline VALUE msgpack_unpack_unsigned_int_16(msgpack_unpack_context* x, uint16_t d)
+{ return INT2FIX(d); }
+
+static inline VALUE msgpack_unpack_unsigned_int_32(msgpack_unpack_context* x, uint32_t d)
+{ return UINT2NUM(d); }
+
+static inline VALUE msgpack_unpack_unsigned_int_64(msgpack_unpack_context* x, uint64_t d)
+{ return UINT2NUM(d); } // FIXME
+
+static inline VALUE msgpack_unpack_signed_int_8(msgpack_unpack_context* x, int8_t d)
+{ return INT2FIX((long)d); }
+
+static inline VALUE msgpack_unpack_signed_int_16(msgpack_unpack_context* x, int16_t d)
+{ return INT2FIX((long)d); }
+
+static inline VALUE msgpack_unpack_signed_int_32(msgpack_unpack_context* x, int32_t d)
+{ return INT2NUM((long)d); }
+
+static inline VALUE msgpack_unpack_signed_int_64(msgpack_unpack_context* x, int64_t d)
+{ return INT2NUM(d); } // FIXME
+
+static inline VALUE msgpack_unpack_float(msgpack_unpack_context* x, float d)
+{ return rb_float_new(d); }
+
+static inline VALUE msgpack_unpack_double(msgpack_unpack_context* x, double d)
+{ return rb_float_new(d); }
+
+static inline VALUE msgpack_unpack_nil(msgpack_unpack_context* x)
+{ return Qnil; }
+
+static inline VALUE msgpack_unpack_true(msgpack_unpack_context* x)
+{ return Qtrue; }
+
+static inline VALUE msgpack_unpack_false(msgpack_unpack_context* x)
+{ return Qfalse; }
+
+static inline VALUE msgpack_unpack_array_start(msgpack_unpack_context* x, unsigned int n)
+{ return rb_ary_new2(n); }
+
+static inline void msgpack_unpack_array_item(msgpack_unpack_context* x, VALUE c, VALUE o)
+{ rb_ary_push(c, o); }
+
+static inline VALUE msgpack_unpack_map_start(msgpack_unpack_context* x, unsigned int n)
+{ return rb_hash_new(); }
+
+static inline void msgpack_unpack_map_item(msgpack_unpack_context* x, VALUE c, VALUE k, VALUE v)
+{ rb_hash_aset(c, k, v); }
+
+static inline VALUE msgpack_unpack_string(msgpack_unpack_context* x, const void* b, size_t l)
+{ return rb_str_new(b, l); }
+
+static inline VALUE msgpack_unpack_raw(msgpack_unpack_context* x, const void* b, size_t l)
+{ return rb_str_new(b, l); }
+
+#include "msgpack/unpack/inline_impl.h"
+