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