| 1 | #ifndef MSGPACK_UNPACK_HPP__ |
|---|
| 2 | #define MSGPACK_UNPACK_HPP__ |
|---|
| 3 | |
|---|
| 4 | #include "msgpack/object.hpp" |
|---|
| 5 | #include "msgpack/zone.hpp" |
|---|
| 6 | #include <stdexcept> |
|---|
| 7 | |
|---|
| 8 | #ifndef MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE |
|---|
| 9 | #define MSGPACK_UNPACKER_INITIAL_BUFFER_SIZE 8*1024 |
|---|
| 10 | #endif |
|---|
| 11 | |
|---|
| 12 | namespace msgpack { |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | struct unpack_error : public std::runtime_error { |
|---|
| 16 | unpack_error(const std::string& msg) : |
|---|
| 17 | std::runtime_error(msg) { } |
|---|
| 18 | }; |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | class unpacker { |
|---|
| 22 | public: |
|---|
| 23 | unpacker(); |
|---|
| 24 | ~unpacker(); |
|---|
| 25 | |
|---|
| 26 | public: |
|---|
| 27 | /*! 1. reserve buffer. at least `len' bytes of capacity will be ready */ |
|---|
| 28 | void reserve_buffer(size_t len); |
|---|
| 29 | |
|---|
| 30 | /*! 2. read data to the buffer() up to buffer_capacity() bytes */ |
|---|
| 31 | void* buffer(); |
|---|
| 32 | size_t buffer_capacity() const; |
|---|
| 33 | |
|---|
| 34 | /*! 3. specify the number of bytes actually copied */ |
|---|
| 35 | void buffer_consumed(size_t len); |
|---|
| 36 | |
|---|
| 37 | /*! 4. repeat execute() until it retunrs false */ |
|---|
| 38 | bool execute(); |
|---|
| 39 | |
|---|
| 40 | /*! 5.1. if execute() returns true, take out the parsed object */ |
|---|
| 41 | object data(); |
|---|
| 42 | |
|---|
| 43 | /*! 5.2. the parsed object is valid until the zone is deleted */ |
|---|
| 44 | // Note that once release_zone() from unpacker, you must delete it |
|---|
| 45 | // otherwise the memrory will leak. |
|---|
| 46 | zone* release_zone(); |
|---|
| 47 | |
|---|
| 48 | /*! 5.3. after release_zone(), re-initialize unpacker */ |
|---|
| 49 | void reset(); |
|---|
| 50 | |
|---|
| 51 | public: |
|---|
| 52 | // These functions are usable when non-MessagePack message follows after |
|---|
| 53 | // MessagePack message. |
|---|
| 54 | // Note that there are no parsed buffer when execute() returned true. |
|---|
| 55 | |
|---|
| 56 | /*! get address of buffer that is not parsed */ |
|---|
| 57 | void* nonparsed_buffer(); |
|---|
| 58 | size_t nonparsed_size() const; |
|---|
| 59 | |
|---|
| 60 | /*! get the number of bytes that is already parsed */ |
|---|
| 61 | size_t parsed_size() const; |
|---|
| 62 | |
|---|
| 63 | /*! remove unparsed buffer from unpacker */ |
|---|
| 64 | // Note that reset() leaves non-parsed buffer. |
|---|
| 65 | void remove_nonparsed_buffer(); |
|---|
| 66 | |
|---|
| 67 | private: |
|---|
| 68 | zone* m_zone; |
|---|
| 69 | |
|---|
| 70 | struct context; |
|---|
| 71 | context* m_ctx; |
|---|
| 72 | |
|---|
| 73 | void* m_buffer; |
|---|
| 74 | size_t m_used; |
|---|
| 75 | size_t m_free; |
|---|
| 76 | size_t m_off; |
|---|
| 77 | void expand_buffer(size_t len); |
|---|
| 78 | |
|---|
| 79 | private: |
|---|
| 80 | unpacker(const unpacker&); |
|---|
| 81 | |
|---|
| 82 | public: |
|---|
| 83 | static object unpack(const void* data, size_t len, zone& z); |
|---|
| 84 | }; |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | inline void unpacker::reserve_buffer(size_t len) |
|---|
| 88 | { |
|---|
| 89 | if(m_free >= len) { return; } |
|---|
| 90 | expand_buffer(len); |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | inline void* unpacker::buffer() |
|---|
| 94 | { return (void*)(((char*)m_buffer)+m_used); } |
|---|
| 95 | |
|---|
| 96 | inline size_t unpacker::buffer_capacity() const |
|---|
| 97 | { return m_free; } |
|---|
| 98 | |
|---|
| 99 | inline void unpacker::buffer_consumed(size_t len) |
|---|
| 100 | { |
|---|
| 101 | m_used += len; |
|---|
| 102 | m_free -= len; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | inline void* unpacker::nonparsed_buffer() |
|---|
| 107 | { return (void*)(((char*)m_buffer)+m_off); } |
|---|
| 108 | |
|---|
| 109 | inline size_t unpacker::nonparsed_size() const |
|---|
| 110 | { return m_used - m_off; } |
|---|
| 111 | |
|---|
| 112 | inline size_t unpacker::parsed_size() const |
|---|
| 113 | { return m_off; } |
|---|
| 114 | |
|---|
| 115 | inline void unpacker::remove_nonparsed_buffer() |
|---|
| 116 | { m_used = m_off; } |
|---|
| 117 | |
|---|
| 118 | |
|---|
| 119 | inline object unpack(const void* data, size_t len, zone& z) |
|---|
| 120 | { |
|---|
| 121 | return unpacker::unpack(data, len, z); |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | } // namespace msgpack |
|---|
| 126 | |
|---|
| 127 | #endif /* msgpack/unpack.hpp */ |
|---|
| 128 | |
|---|