| /* |
| * MessagePack for C deflate buffer implementation |
| * |
| * Copyright (C) 2010 FURUHASHI Sadayuki |
| * |
| * Distributed under the Boost Software License, Version 1.0. |
| * (See accompanying file LICENSE_1_0.txt or copy at |
| * http://www.boost.org/LICENSE_1_0.txt) |
| */ |
| #ifndef MSGPACK_ZBUFFER_H |
| #define MSGPACK_ZBUFFER_H |
| |
| #include "sysdep.h" |
| #include <stdlib.h> |
| #include <string.h> |
| #include <zlib.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| |
| /** |
| * @defgroup msgpack_zbuffer Compressed buffer |
| * @ingroup msgpack_buffer |
| * @{ |
| */ |
| |
| typedef struct msgpack_zbuffer { |
| z_stream stream; |
| char* data; |
| size_t init_size; |
| } msgpack_zbuffer; |
| |
| #ifndef MSGPACK_ZBUFFER_INIT_SIZE |
| #define MSGPACK_ZBUFFER_INIT_SIZE 8192 |
| #endif |
| |
| static inline bool msgpack_zbuffer_init( |
| msgpack_zbuffer* zbuf, int level, size_t init_size); |
| static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf); |
| |
| static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size); |
| static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf); |
| |
| static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf); |
| |
| static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf); |
| static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf); |
| |
| static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf); |
| static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf); |
| static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf); |
| |
| |
| #ifndef MSGPACK_ZBUFFER_RESERVE_SIZE |
| #define MSGPACK_ZBUFFER_RESERVE_SIZE 512 |
| #endif |
| |
| static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len); |
| |
| static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf); |
| |
| |
| static inline bool msgpack_zbuffer_init(msgpack_zbuffer* zbuf, |
| int level, size_t init_size) |
| { |
| memset(zbuf, 0, sizeof(msgpack_zbuffer)); |
| zbuf->init_size = init_size; |
| if(deflateInit(&zbuf->stream, level) != Z_OK) { |
| free(zbuf->data); |
| return false; |
| } |
| return true; |
| } |
| |
| static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf) |
| { |
| deflateEnd(&zbuf->stream); |
| free(zbuf->data); |
| } |
| |
| static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size) |
| { |
| msgpack_zbuffer* zbuf = (msgpack_zbuffer*)malloc(sizeof(msgpack_zbuffer)); |
| if (zbuf == NULL) return NULL; |
| if(!msgpack_zbuffer_init(zbuf, level, init_size)) { |
| free(zbuf); |
| return NULL; |
| } |
| return zbuf; |
| } |
| |
| static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf) |
| { |
| if(zbuf == NULL) { return; } |
| msgpack_zbuffer_destroy(zbuf); |
| free(zbuf); |
| } |
| |
| static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf) |
| { |
| size_t used = (char*)zbuf->stream.next_out - zbuf->data; |
| size_t csize = used + zbuf->stream.avail_out; |
| size_t nsize = (csize == 0) ? zbuf->init_size : csize * 2; |
| |
| char* tmp = (char*)realloc(zbuf->data, nsize); |
| if(tmp == NULL) { |
| return false; |
| } |
| |
| zbuf->data = tmp; |
| zbuf->stream.next_out = (Bytef*)(tmp + used); |
| zbuf->stream.avail_out = nsize - used; |
| |
| return true; |
| } |
| |
| static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len) |
| { |
| msgpack_zbuffer* zbuf = (msgpack_zbuffer*)data; |
| |
| zbuf->stream.next_in = (Bytef*)buf; |
| zbuf->stream.avail_in = len; |
| |
| while(zbuf->stream.avail_in > 0) { |
| if(zbuf->stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) { |
| if(!msgpack_zbuffer_expand(zbuf)) { |
| return -1; |
| } |
| } |
| |
| if(deflate(&zbuf->stream, Z_NO_FLUSH) != Z_OK) { |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf) |
| { |
| while(true) { |
| switch(deflate(&zbuf->stream, Z_FINISH)) { |
| case Z_STREAM_END: |
| return zbuf->data; |
| case Z_OK: |
| if(!msgpack_zbuffer_expand(zbuf)) { |
| return NULL; |
| } |
| break; |
| default: |
| return NULL; |
| } |
| } |
| } |
| |
| static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf) |
| { |
| return zbuf->data; |
| } |
| |
| static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf) |
| { |
| return (char*)zbuf->stream.next_out - zbuf->data; |
| } |
| |
| static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf) |
| { |
| zbuf->stream.avail_out += (char*)zbuf->stream.next_out - zbuf->data; |
| zbuf->stream.next_out = (Bytef*)zbuf->data; |
| } |
| |
| static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf) |
| { |
| if(deflateReset(&zbuf->stream) != Z_OK) { |
| return false; |
| } |
| msgpack_zbuffer_reset_buffer(zbuf); |
| return true; |
| } |
| |
| static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf) |
| { |
| char* tmp = zbuf->data; |
| zbuf->data = NULL; |
| zbuf->stream.next_out = NULL; |
| zbuf->stream.avail_out = 0; |
| return tmp; |
| } |
| |
| /** @} */ |
| |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* msgpack/zbuffer.h */ |
| |