#include #include #include #include struct hf_content_converter { /* MODE AND CALLBACKS */ enum hf_content_conv_work_mode mode; unsigned int content_encode; hf_private_cb * data_cb; void * data_cb_user; /* ZLIB STREAM */ z_stream * z_stream_ptr; unsigned char * chunk; size_t sz_chunk; }; void hf_content_converter_destroy(struct hf_content_converter * cv_object) { if (cv_object->z_stream_ptr && cv_object->mode == HF_CONTENT_CONV_COMPRASS) { (void)deflateEnd(cv_object->z_stream_ptr); free(cv_object->z_stream_ptr); } if (cv_object->z_stream_ptr && cv_object->mode == HF_CONTENT_CONV_UNCOMPRASS) { (void)inflateEnd(cv_object->z_stream_ptr); free(cv_object->z_stream_ptr); } cv_object->z_stream_ptr = NULL; free(cv_object); } struct hf_content_converter * hf_content_converter_create(enum hf_content_conv_work_mode mode, unsigned int content_encode, hf_private_cb * data_cb, void * data_cb_user) { struct hf_content_converter * cv_object = ALLOC(struct hf_content_converter, 1); assert(data_cb != NULL); cv_object->mode = mode; cv_object->content_encode = content_encode; cv_object->data_cb = data_cb; cv_object->data_cb_user = data_cb_user; /* ZSTREAM */ cv_object->z_stream_ptr = ALLOC(z_stream, 1); cv_object->z_stream_ptr->zalloc = NULL; cv_object->z_stream_ptr->zfree = NULL; cv_object->z_stream_ptr->opaque = NULL; cv_object->z_stream_ptr->avail_in = 0; cv_object->z_stream_ptr->next_in = Z_NULL; /* CHUNK, 4K */ #define CHUNK_SIZE (1024 * 1024 * 4) cv_object->chunk = (unsigned char *)malloc(CHUNK_SIZE); cv_object->sz_chunk = CHUNK_SIZE; int ret = 0; if (content_encode == HTTP_ACCEPT_ENCODING_GZIP) { ret = inflateInit2(cv_object->z_stream_ptr, MAX_WBITS + 16); } else if (content_encode == HTTP_ACCEPT_ENCODING_DEFLATE) { ret = inflateInit2(cv_object->z_stream_ptr, -MAX_WBITS); } if (ret != Z_OK) goto __errout; return cv_object; __errout: free(cv_object->z_stream_ptr); free(cv_object->chunk); free(cv_object); return NULL; } int hf_content_converter_write(struct hf_content_converter * cv_object, struct http_half_private * hf_private, tfe_http_event http_ev, const unsigned char * data, size_t datalen) { z_stream * z_stream_ptr = cv_object->z_stream_ptr; z_stream_ptr->avail_in = (unsigned int)datalen; z_stream_ptr->next_in = (unsigned char *)data; if (z_stream_ptr->avail_in == 0) { (void)inflateEnd(z_stream_ptr); return Z_ERRNO; } int ret = 0; do { z_stream_ptr->avail_out = (unsigned int) cv_object->sz_chunk; z_stream_ptr->next_out = cv_object->chunk; ret = inflate(z_stream_ptr, Z_NO_FLUSH); assert(ret != Z_STREAM_ERROR); /* state not clobbered */ if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { goto __error; } unsigned int have = (unsigned int) cv_object->sz_chunk - z_stream_ptr->avail_out; if (have > 0 && cv_object->data_cb != NULL) { cv_object->data_cb(hf_private, http_ev, cv_object->chunk, (size_t) have, cv_object->data_cb_user); } } while (z_stream_ptr->avail_out == 0); return ret; __error: (void)inflateEnd(z_stream_ptr); return ret; }