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

Revision 18666, 2.8 kB (checked in by frsyuki, 5 years ago)

lang/c/msgpack: C++ binding: support non-MessagePack? message that follows after MessagePack? message

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                void* tmp = malloc(next_size);
86                if(!tmp) { throw std::bad_alloc(); }
87                memcpy(tmp, m_buffer, m_used);
88
89                free(m_buffer);
90                m_buffer = tmp;
91                m_free = next_size - m_used;
92
93        } else {
94                size_t next_size = MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE;
95                while(next_size < len + m_used - m_off) { next_size *= 2; }
96
97                void* tmp = malloc(next_size);
98                if(!tmp) { throw std::bad_alloc(); }
99                memcpy(tmp, ((char*)m_buffer)+m_off, m_used-m_off);
100
101                try {
102                        m_zone->push_finalizer<void>(&zone::finalize_free, NULL, m_buffer);
103                } catch (...) {
104                        free(tmp);
105                        throw;
106                }
107
108                m_buffer = tmp;
109                m_used = m_used - m_off;
110                m_free = next_size - m_used;
111                m_off = 0;
112        }
113}
114
115bool unpacker::execute()
116{
117        int ret = m_ctx->execute(m_buffer, m_used, &m_off);
118        if(ret < 0) {
119                throw unpack_error("parse error");
120        } else if(ret == 0) {
121                return false;
122        } else {
123                expand_buffer(0);
124                return true;
125        }
126}
127
128zone* unpacker::release_zone()
129{
130        zone* nz = new zone();
131        zone* z = m_zone;
132        m_zone = nz;
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_off != 0) { expand_buffer(0); }
145        if(!m_zone->empty()) {
146                delete m_zone;
147                m_zone = NULL;
148                m_zone = new zone();
149        }
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.