root/lang/c/msgpack/trunk/cpp/unpack.cpp @ 18657

Revision 18657, 2.7 kB (checked in by frsyuki, 6 years ago)

lang/c/msgpack: C++ binding: implemented built-in buffer.

Line 
1#include "msgpack/unpack.hpp"
2#include "unpack_context.hpp"
3#include <stdlib.h>
4
5namespace msgpack {
6
7struct unpacker::context {
8        context(zone* z)
9        {
10                msgpack_unpacker_init(&m_ctx);
11                m_ctx.user = z;
12        }
13
14        ~context() { }
15
16        int execute(const void* data, size_t len, size_t* off)
17        {
18                return msgpack_unpacker_execute(&m_ctx, (const char*)data, len, off);
19        }
20
21        object_class* data()
22        {
23                return msgpack_unpacker_data(&m_ctx);
24        }
25
26        void reset()
27        {
28                zone* z = m_ctx.user;
29                msgpack_unpacker_init(&m_ctx);
30                m_ctx.user = z;
31        }
32
33        void reset(zone* z)
34        {
35                msgpack_unpacker_init(&m_ctx);
36                m_ctx.user = z;
37        }
38
39        zone* user()
40        {
41                return m_ctx.user;
42        }
43
44        void user(zone* z)
45        {
46                m_ctx.user = z;
47        }
48
49private:
50        msgpack_unpacker m_ctx;
51
52private:
53        context();
54        context(const context&);
55};
56
57
58unpacker::unpacker() :
59        m_zone(new zone()),
60        m_ctx(new context(m_zone)),
61        m_buffer(NULL),
62        m_used(0),
63        m_free(0),
64        m_off(0)
65{ }
66
67
68unpacker::~unpacker()
69{
70        free(m_buffer);
71        delete m_ctx;
72        delete m_zone;
73}
74
75
76void unpacker::expand_buffer(size_t len)
77{
78        if(m_off == 0) {
79                size_t next_size;
80                if(m_free != 0) { next_size = m_free * 2; }
81                else { next_size = MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE; }
82                while(next_size < len + m_used) { next_size *= 2; }
83
84                // FIXME realloc?
85
86                void* tmp = malloc(next_size);
87                if(!tmp) { throw std::bad_alloc(); }
88                memcpy(tmp, m_buffer, m_used);
89
90                free(m_buffer);
91                m_buffer = tmp;
92                m_free = next_size - m_used;
93
94        } else {
95                size_t next_size = MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE;
96                while(next_size < len + m_used - m_off) { next_size *= 2; }
97
98                void* tmp = malloc(next_size);
99                if(!tmp) { throw std::bad_alloc(); }
100                memcpy(tmp, ((char*)m_buffer)+m_off, m_used-m_off);
101
102                try {
103                        m_zone->push_finalizer<void>(&zone::finalize_free, NULL, m_buffer);
104                } catch (...) {
105                        free(tmp);
106                        throw;
107                }
108
109                m_buffer = tmp;
110                m_used = m_used - m_off;
111                m_free = next_size - m_used;
112                m_off = 0;
113        }
114}
115
116bool unpacker::execute()
117{
118        int ret = m_ctx->execute(m_buffer, m_used, &m_off);
119        if(ret < 0) {
120                throw unpack_error("parse error");
121        } else if(ret == 0) {
122                return false;
123        } else {
124                return true;
125        }
126}
127
128zone* unpacker::release_zone()
129{
130        zone* z = m_zone;
131        m_zone = NULL;
132        m_zone = new zone();
133        m_ctx->user(m_zone);
134        return z;
135}
136
137object unpacker::data()
138{
139        return object(m_ctx->data());
140}
141
142void unpacker::reset()
143{
144        if(!m_zone->empty()) {
145                delete m_zone;
146                m_zone = NULL;
147                m_zone = new zone();
148        }
149        expand_buffer(0);
150        m_ctx->reset();
151}
152
153
154object unpacker::unpack(const void* data, size_t len, zone& z)
155{
156        context ctx(&z);
157        size_t off = 0;
158        int ret = ctx.execute(data, len, &off);
159        if(ret < 0) {
160                throw unpack_error("parse error");
161        } else if(ret == 0) {
162                throw unpack_error("insufficient bytes");
163        } else if(off < len) {
164                throw unpack_error("extra bytes");
165        }
166        return ctx.data();
167}
168
169
170}  // namespace msgpack
171
Note: See TracBrowser for help on using the browser.