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(
48     msgpack_zbuffer* zbuf, 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, size_t 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 static inline 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 static inline 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 static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size)
92 {
93     msgpack_zbuffer* zbuf = (msgpack_zbuffer*)malloc(sizeof(msgpack_zbuffer));
94     if (zbuf == NULL) return NULL;
95     if(!msgpack_zbuffer_init(zbuf, level, init_size)) {
96         free(zbuf);
97         return NULL;
98     }
99     return zbuf;
100 }
101 
msgpack_zbuffer_free(msgpack_zbuffer * zbuf)102 static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf)
103 {
104     if(zbuf == NULL) { return; }
105     msgpack_zbuffer_destroy(zbuf);
106     free(zbuf);
107 }
108 
msgpack_zbuffer_expand(msgpack_zbuffer * zbuf)109 static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf)
110 {
111     size_t used = (char*)zbuf->stream.next_out - zbuf->data;
112     size_t csize = used + zbuf->stream.avail_out;
113     size_t nsize = (csize == 0) ? zbuf->init_size : csize * 2;
114 
115     char* tmp = (char*)realloc(zbuf->data, nsize);
116     if(tmp == NULL) {
117         return false;
118     }
119 
120     zbuf->data = tmp;
121     zbuf->stream.next_out  = (Bytef*)(tmp + used);
122     zbuf->stream.avail_out = nsize - used;
123 
124     return true;
125 }
126 
msgpack_zbuffer_write(void * data,const char * buf,size_t len)127 static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len)
128 {
129     msgpack_zbuffer* zbuf = (msgpack_zbuffer*)data;
130 
131     zbuf->stream.next_in = (Bytef*)buf;
132     zbuf->stream.avail_in = len;
133 
134     while(zbuf->stream.avail_in > 0) {
135         if(zbuf->stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
136             if(!msgpack_zbuffer_expand(zbuf)) {
137                 return -1;
138             }
139         }
140 
141         if(deflate(&zbuf->stream, Z_NO_FLUSH) != Z_OK) {
142             return -1;
143         }
144     }
145 
146     return 0;
147 }
148 
msgpack_zbuffer_flush(msgpack_zbuffer * zbuf)149 static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf)
150 {
151     while(true) {
152         switch(deflate(&zbuf->stream, Z_FINISH)) {
153         case Z_STREAM_END:
154             return zbuf->data;
155         case Z_OK:
156             if(!msgpack_zbuffer_expand(zbuf)) {
157                 return NULL;
158             }
159             break;
160         default:
161             return NULL;
162         }
163     }
164 }
165 
msgpack_zbuffer_data(const msgpack_zbuffer * zbuf)166 static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf)
167 {
168     return zbuf->data;
169 }
170 
msgpack_zbuffer_size(const msgpack_zbuffer * zbuf)171 static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf)
172 {
173     return (char*)zbuf->stream.next_out - zbuf->data;
174 }
175 
msgpack_zbuffer_reset_buffer(msgpack_zbuffer * zbuf)176 static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf)
177 {
178     zbuf->stream.avail_out += (char*)zbuf->stream.next_out - zbuf->data;
179     zbuf->stream.next_out = (Bytef*)zbuf->data;
180 }
181 
msgpack_zbuffer_reset(msgpack_zbuffer * zbuf)182 static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf)
183 {
184     if(deflateReset(&zbuf->stream) != Z_OK) {
185         return false;
186     }
187     msgpack_zbuffer_reset_buffer(zbuf);
188     return true;
189 }
190 
msgpack_zbuffer_release_buffer(msgpack_zbuffer * zbuf)191 static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf)
192 {
193     char* tmp = zbuf->data;
194     zbuf->data = NULL;
195     zbuf->stream.next_out = NULL;
196     zbuf->stream.avail_out = 0;
197     return tmp;
198 }
199 
200 /** @} */
201 
202 
203 #ifdef __cplusplus
204 }
205 #endif
206 
207 #endif /* msgpack/zbuffer.h */
208 
209