- add a KUDOS file
[m6w6/ext-http] / http_inflatestream_object.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_ZLIB
16 #include "php_http.h"
17
18 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_ZLIB)
19
20 #include "php_http_api.h"
21 #include "php_http_encoding_api.h"
22 #include "php_http_exception_object.h"
23 #include "php_http_inflatestream_object.h"
24
25 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpInflateStream, method, 0, req_args)
26 #define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpInflateStream, method, 0)
27 #define HTTP_INFLATE_ME(method, visibility) PHP_ME(HttpInflateStream, method, HTTP_ARGS(HttpInflateStream, method), visibility)
28
29 HTTP_BEGIN_ARGS(__construct, 0)
30 HTTP_ARG_VAL(flags, 0)
31 HTTP_END_ARGS;
32
33 HTTP_BEGIN_ARGS(factory, 0)
34 HTTP_ARG_VAL(flags, 0)
35 HTTP_ARG_VAL(class_name, 0)
36 HTTP_END_ARGS;
37
38 HTTP_BEGIN_ARGS(update, 1)
39 HTTP_ARG_VAL(data, 0)
40 HTTP_END_ARGS;
41
42 HTTP_BEGIN_ARGS(flush, 0)
43 HTTP_ARG_VAL(data, 0)
44 HTTP_END_ARGS;
45
46 HTTP_BEGIN_ARGS(finish, 0)
47 HTTP_ARG_VAL(data, 0)
48 HTTP_END_ARGS;
49
50 #define OBJ_PROP_CE http_inflatestream_object_ce
51 zend_class_entry *http_inflatestream_object_ce;
52 zend_function_entry http_inflatestream_object_fe[] = {
53 HTTP_INFLATE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
54 HTTP_INFLATE_ME(update, ZEND_ACC_PUBLIC)
55 HTTP_INFLATE_ME(flush, ZEND_ACC_PUBLIC)
56 HTTP_INFLATE_ME(finish, ZEND_ACC_PUBLIC)
57
58 HTTP_INFLATE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
59
60 EMPTY_FUNCTION_ENTRY
61 };
62 static zend_object_handlers http_inflatestream_object_handlers;
63
64 PHP_MINIT_FUNCTION(http_inflatestream_object)
65 {
66 HTTP_REGISTER_CLASS_EX(HttpInflateStream, http_inflatestream_object, NULL, 0);
67 http_inflatestream_object_handlers.clone_obj = _http_inflatestream_object_clone_obj;
68
69 #ifndef WONKY
70 DCL_CONST(long, "FLUSH_NONE", HTTP_ENCODING_STREAM_FLUSH_NONE);
71 DCL_CONST(long, "FLUSH_SYNC", HTTP_ENCODING_STREAM_FLUSH_SYNC);
72 DCL_CONST(long, "FLUSH_FULL", HTTP_ENCODING_STREAM_FLUSH_FULL);
73 #endif
74
75 return SUCCESS;
76 }
77
78 zend_object_value _http_inflatestream_object_new(zend_class_entry *ce TSRMLS_DC)
79 {
80 return http_inflatestream_object_new_ex(ce, NULL, NULL);
81 }
82
83 zend_object_value _http_inflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_inflatestream_object **ptr TSRMLS_DC)
84 {
85 zend_object_value ov;
86 http_inflatestream_object *o;
87
88 o = ecalloc(1, sizeof(http_inflatestream_object));
89 o->zo.ce = ce;
90
91 if (ptr) {
92 *ptr = o;
93 }
94
95 if (s) {
96 o->stream = s;
97 }
98
99 ALLOC_HASHTABLE(OBJ_PROP(o));
100 zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
101 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
102
103 ov.handle = putObject(http_inflatestream_object, o);
104 ov.handlers = &http_inflatestream_object_handlers;
105
106 return ov;
107 }
108
109 zend_object_value _http_inflatestream_object_clone_obj(zval *this_ptr TSRMLS_DC)
110 {
111 http_encoding_stream *s;
112 zend_object_value new_ov;
113 http_inflatestream_object *new_obj = NULL;
114 getObject(http_inflatestream_object, old_obj);
115
116 s = ecalloc(1, sizeof(http_encoding_stream));
117 s->flags = old_obj->stream->flags;
118 inflateCopy(&s->stream, &old_obj->stream->stream);
119 s->stream.opaque = phpstr_dup(s->stream.opaque);
120
121 new_ov = http_inflatestream_object_new_ex(old_obj->zo.ce, s, &new_obj);
122 zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
123
124 return new_ov;
125 }
126
127 void _http_inflatestream_object_free(zend_object *object TSRMLS_DC)
128 {
129 http_inflatestream_object *o = (http_inflatestream_object *) object;
130
131 if (o->stream) {
132 http_encoding_inflate_stream_free(&o->stream);
133 }
134 freeObject(o);
135 }
136
137 /* {{{ proto void HttpInflateStream::__construct([int flags = 0])
138 Creates a new HttpInflateStream object instance. */
139 PHP_METHOD(HttpInflateStream, __construct)
140 {
141 long flags = 0;
142
143 SET_EH_THROW_HTTP();
144 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) {
145 getObject(http_inflatestream_object, obj);
146
147 if (!obj->stream) {
148 obj->stream = http_encoding_inflate_stream_init(NULL, flags & 0x0fffffff);
149 } else {
150 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "HttpInflateStream cannot be initialized twice");
151 }
152 }
153 SET_EH_NORMAL();
154 }
155 /* }}} */
156
157 /* {{{ proto HttpInflateStream HttpInflateStream::factory([int flags[, string class = "HttpInflateStream"]])
158 Creates a new HttpInflateStream object instance. */
159 PHP_METHOD(HttpInflateStream, factory)
160 {
161 long flags = 0;
162 char *cn = NULL;
163 int cl = 0;
164
165 SET_EH_THROW_HTTP();
166 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &flags, &cn, &cl)) {
167 zend_object_value ov;
168 http_encoding_stream *s = http_encoding_inflate_stream_init(NULL, flags & 0x0fffffff);
169
170 if (SUCCESS == http_object_new(&ov, cn, cl, _http_inflatestream_object_new_ex, http_inflatestream_object_ce, s, NULL)) {
171 RETVAL_OBJVAL(ov, 0);
172 }
173 }
174 SET_EH_NORMAL();
175 }
176 /* }}} */
177
178 /* {{{ proto string HttpInflateStream::update(string data)
179 Passes more data through the inflate stream. */
180 PHP_METHOD(HttpInflateStream, update)
181 {
182 int data_len;
183 size_t decoded_len = 0;
184 char *data, *decoded = NULL;
185 getObject(http_inflatestream_object, obj);
186
187 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) {
188 RETURN_FALSE;
189 }
190
191 if (!data_len) {
192 RETURN_STRING("", 1);
193 }
194
195 if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) {
196 RETURN_FALSE;
197 }
198
199 if (SUCCESS == http_encoding_inflate_stream_update(obj->stream, data, data_len, &decoded, &decoded_len)) {
200 RETURN_STRINGL(decoded, decoded_len, 0);
201 } else {
202 RETURN_FALSE;
203 }
204 }
205 /* }}} */
206
207 /* {{{ proto string HttpInflateStream::flush([string data])
208 Flush the inflate stream. */
209 PHP_METHOD(HttpInflateStream, flush)
210 {
211 int data_len = 0;
212 size_t decoded_len = 0;
213 char *decoded = NULL, *data = NULL;
214 getObject(http_inflatestream_object, obj);
215
216 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) {
217 RETURN_FALSE;
218 }
219
220 if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) {
221 RETURN_FALSE;
222 }
223
224 /* flushing the inflate stream is a no-op */
225 if (!data_len) {
226 RETURN_STRINGL("", 0, 1);
227 } else if (SUCCESS == http_encoding_inflate_stream_update(obj->stream, data, data_len, &decoded, &decoded_len)) {
228 RETURN_STRINGL(decoded, decoded_len, 0);
229 } else {
230 RETURN_FALSE;
231 }
232 }
233 /* }}} */
234
235 /* {{{ proto string HttpInflateStream::finish([string data])
236 Finalizes the inflate stream. The inflate stream can be reused after finalizing. */
237 PHP_METHOD(HttpInflateStream, finish)
238 {
239 int data_len = 0;
240 size_t updated_len = 0, decoded_len = 0;
241 char *updated = NULL, *decoded = NULL, *data = NULL;
242 getObject(http_inflatestream_object, obj);
243
244 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) {
245 RETURN_FALSE;
246 }
247
248 if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) {
249 RETURN_FALSE;
250 }
251
252 if (data_len) {
253 if (SUCCESS != http_encoding_inflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) {
254 RETURN_FALSE;
255 }
256 }
257
258 if (SUCCESS == http_encoding_inflate_stream_finish(obj->stream, &decoded, &decoded_len)) {
259 if (updated_len) {
260 updated = erealloc(updated, updated_len + decoded_len + 1);
261 updated[updated_len + decoded_len] = '\0';
262 memcpy(updated + updated_len, decoded, decoded_len);
263 STR_FREE(decoded);
264 updated_len += decoded_len;
265 RETVAL_STRINGL(updated, updated_len, 0);
266 } else {
267 STR_FREE(updated);
268 RETVAL_STRINGL(decoded, decoded_len, 0);
269 }
270 } else {
271 STR_FREE(updated);
272 RETVAL_FALSE;
273 }
274
275 http_encoding_inflate_stream_dtor(obj->stream);
276 http_encoding_inflate_stream_init(obj->stream, obj->stream->flags);
277 }
278 /* }}} */
279
280 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_ZLIB*/
281
282 /*
283 * Local variables:
284 * tab-width: 4
285 * c-basic-offset: 4
286 * End:
287 * vim600: noet sw=4 ts=4 fdm=marker
288 * vim<600: noet sw=4 ts=4
289 */
290