1/*
2 * MessagePack for C deflate buffer implementation
3 *
4 * Copyright (C) 2010 FURUHASHI Sadayuki
5 *
6 *    Distributed under the Boost Software License, Version 1.0.
7 *    (See accompanying file LICENSE_1_0.txt or copy at
8 *    http://www.boost.org/LICENSE_1_0.txt)
9 */
10#ifndef MSGPACK_ZBUFFER_H
11#define MSGPACK_ZBUFFER_H
12
13#include "sysdep.h"
14#include <stdlib.h>
15#include <string.h>
16#include <zlib.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22
23/**
24 * @defgroup msgpack_zbuffer Compressed buffer
25 * @ingroup msgpack_buffer
26 * @{
27 */
28
29typedef struct msgpack_zbuffer {
30    z_stream stream;
31    char* data;
32    size_t init_size;
33} msgpack_zbuffer;
34
35#ifndef MSGPACK_ZBUFFER_INIT_SIZE
36#define MSGPACK_ZBUFFER_INIT_SIZE 8192
37#endif
38
39static inline bool msgpack_zbuffer_init(
40    msgpack_zbuffer* zbuf, int level, size_t init_size);
41static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf);
42
43static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size);
44static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf);
45
46static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf);
47
48static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf);
49static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf);
50
51static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf);
52static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf);
53static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf);
54
55
56#ifndef MSGPACK_ZBUFFER_RESERVE_SIZE
57#define MSGPACK_ZBUFFER_RESERVE_SIZE 512
58#endif
59
60static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len);
61
62static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf);
63
64
65static inline bool msgpack_zbuffer_init(msgpack_zbuffer* zbuf,
66        int level, size_t init_size)
67{
68    memset(zbuf, 0, sizeof(msgpack_zbuffer));
69    zbuf->init_size = init_size;
70    if(deflateInit(&zbuf->stream, level) != Z_OK) {
71        free(zbuf->data);
72        return false;
73    }
74    return true;
75}
76
77static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf)
78{
79    deflateEnd(&zbuf->stream);
80    free(zbuf->data);
81}
82
83static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size)
84{
85    msgpack_zbuffer* zbuf = (msgpack_zbuffer*)malloc(sizeof(msgpack_zbuffer));
86    if (zbuf == NULL) return NULL;
87    if(!msgpack_zbuffer_init(zbuf, level, init_size)) {
88        free(zbuf);
89        return NULL;
90    }
91    return zbuf;
92}
93
94static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf)
95{
96    if(zbuf == NULL) { return; }
97    msgpack_zbuffer_destroy(zbuf);
98    free(zbuf);
99}
100
101static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf)
102{
103    size_t used = (char*)zbuf->stream.next_out - zbuf->data;
104    size_t csize = used + zbuf->stream.avail_out;
105    size_t nsize = (csize == 0) ? zbuf->init_size : csize * 2;
106
107    char* tmp = (char*)realloc(zbuf->data, nsize);
108    if(tmp == NULL) {
109        return false;
110    }
111
112    zbuf->data = tmp;
113    zbuf->stream.next_out  = (Bytef*)(tmp + used);
114    zbuf->stream.avail_out = nsize - used;
115
116    return true;
117}
118
119static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len)
120{
121    msgpack_zbuffer* zbuf = (msgpack_zbuffer*)data;
122
123    zbuf->stream.next_in = (Bytef*)buf;
124    zbuf->stream.avail_in = len;
125
126    while(zbuf->stream.avail_in > 0) {
127        if(zbuf->stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
128            if(!msgpack_zbuffer_expand(zbuf)) {
129                return -1;
130            }
131        }
132
133        if(deflate(&zbuf->stream, Z_NO_FLUSH) != Z_OK) {
134            return -1;
135        }
136    }
137
138    return 0;
139}
140
141static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf)
142{
143    while(true) {
144        switch(deflate(&zbuf->stream, Z_FINISH)) {
145        case Z_STREAM_END:
146            return zbuf->data;
147        case Z_OK:
148            if(!msgpack_zbuffer_expand(zbuf)) {
149                return NULL;
150            }
151            break;
152        default:
153            return NULL;
154        }
155    }
156}
157
158static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf)
159{
160    return zbuf->data;
161}
162
163static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf)
164{
165    return (char*)zbuf->stream.next_out - zbuf->data;
166}
167
168static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf)
169{
170    zbuf->stream.avail_out += (char*)zbuf->stream.next_out - zbuf->data;
171    zbuf->stream.next_out = (Bytef*)zbuf->data;
172}
173
174static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf)
175{
176    if(deflateReset(&zbuf->stream) != Z_OK) {
177        return false;
178    }
179    msgpack_zbuffer_reset_buffer(zbuf);
180    return true;
181}
182
183static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf)
184{
185    char* tmp = zbuf->data;
186    zbuf->data = NULL;
187    zbuf->stream.next_out = NULL;
188    zbuf->stream.avail_out = 0;
189    return tmp;
190}
191
192/** @} */
193
194
195#ifdef __cplusplus
196}
197#endif
198
199#endif /* msgpack/zbuffer.h */
200
201