| 1 | #include "msgpack/unpack.hpp" |
|---|
| 2 | #include "unpack_context.hpp" |
|---|
| 3 | #include <stdlib.h> |
|---|
| 4 | |
|---|
| 5 | namespace msgpack { |
|---|
| 6 | |
|---|
| 7 | struct 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 | |
|---|
| 49 | private: |
|---|
| 50 | msgpack_unpacker m_ctx; |
|---|
| 51 | |
|---|
| 52 | private: |
|---|
| 53 | context(); |
|---|
| 54 | context(const context&); |
|---|
| 55 | }; |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | unpacker::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 | |
|---|
| 68 | unpacker::~unpacker() |
|---|
| 69 | { |
|---|
| 70 | free(m_buffer); |
|---|
| 71 | delete m_ctx; |
|---|
| 72 | delete m_zone; |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | |
|---|
| 76 | void 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 | |
|---|
| 116 | bool 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 | |
|---|
| 128 | zone* 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 | |
|---|
| 137 | object unpacker::data() |
|---|
| 138 | { |
|---|
| 139 | return object(m_ctx->data()); |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | void 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 | |
|---|
| 154 | object 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 | |
|---|