Mercurial > pidgin.yaz
view libpurple/protocols/gg/lib/deflate.c @ 32827:4a34689eeb33 default tip
merged from im.pidgin.pidgin
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Sat, 19 Nov 2011 14:42:54 +0900 |
parents | 896e1e0dbe35 |
children |
line wrap: on
line source
/* $Id$ */ /* * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version * 2.1 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, * USA. */ /** * \file deflate.c * * \brief Funkcje kompresji Deflate */ #include <stdlib.h> #include <string.h> #include "libgadu.h" #include "deflate.h" #ifdef GG_CONFIG_HAVE_ZLIB #include <zlib.h> #endif /** * \internal Kompresuje dane wejściowe algorytmem Deflate z najwyższym * stopniem kompresji, tak samo jak oryginalny klient. * * Wynik funkcji należy zwolnić za pomocą \c free. * * \param in Ciąg znaków do skompresowania, zakończony \c \\0 * \param out_lenp Wskaźnik na zmienną, do której zostanie zapisana * długość bufora wynikowego * * \return Skompresowany ciąg znaków lub \c NULL w przypadku niepowodzenia. */ unsigned char *gg_deflate(const char *in, size_t *out_lenp) { #ifdef GG_CONFIG_HAVE_ZLIB int ret; z_stream strm; unsigned char *out, *out2; size_t out_len; if (in == NULL || out_lenp == NULL) return NULL; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = strlen(in); strm.next_in = (unsigned char*) in; ret = deflateInit(&strm, Z_BEST_COMPRESSION); if (ret != Z_OK) { gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflateInit() failed (%d)\n", ret); return NULL; } out_len = deflateBound(&strm, strm.avail_in); out = malloc(out_len); if (out == NULL) { gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len); goto fail; } strm.avail_out = out_len; strm.next_out = out; for (;;) { ret = deflate(&strm, Z_FINISH); if (ret == Z_STREAM_END) break; /* raczej nie powinno się zdarzyć przy Z_FINISH i out_len == deflateBound(), * ale dokumentacja zlib nie wyklucza takiej możliwości */ if (ret == Z_OK) { out_len *= 2; out2 = realloc(out, out_len); if (out2 == NULL) { gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len); goto fail; } out = out2; strm.avail_out = out_len / 2; strm.next_out = out + out_len / 2; } else { gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflate() failed (ret=%d, msg=%s)\n", ret, strm.msg != NULL ? strm.msg : "no error message provided"); goto fail; } } out_len = strm.total_out; out2 = realloc(out, out_len); if (out2 == NULL) { gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len); goto fail; } *out_lenp = out_len; deflateEnd(&strm); return out2; fail: *out_lenp = 0; deflateEnd(&strm); free(out); #endif return NULL; } /** * \internal Dekompresuje dane wejściowe w formacie Deflate. * * Wynik funkcji należy zwolnić za pomocą \c free. * * \param in Bufor danych skompresowanych algorytmem Deflate * \param length Długość bufora wejściowego * * \note Dokleja \c \\0 na końcu bufora wynikowego. * * \return Zdekompresowany ciąg znaków, zakończony \c \\0, * lub \c NULL w przypadku niepowodzenia. */ char *gg_inflate(const unsigned char *in, size_t length) { #ifdef GG_CONFIG_HAVE_ZLIB int ret; z_stream strm; char *out = NULL, *out2; size_t out_len = 1024; int first = 1; if (in == NULL) return NULL; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = length; strm.next_in = (unsigned char*) in; ret = inflateInit(&strm); if (ret != Z_OK) { gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflateInit() failed (%d)\n", ret); return NULL; } do { out_len *= 2; out2 = realloc(out, out_len); if (out2 == NULL) { gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for output data (%d)\n", out_len); goto fail; } out = out2; if (first) { strm.avail_out = out_len; strm.next_out = (unsigned char*) out; } else { strm.avail_out = out_len / 2; strm.next_out = (unsigned char*) out + out_len / 2; } ret = inflate(&strm, Z_NO_FLUSH); if (ret != Z_OK && ret != Z_STREAM_END) { gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflate() failed (ret=%d, msg=%s)\n", ret, strm.msg != NULL ? strm.msg : "no error message provided"); goto fail; } first = 0; } while (ret != Z_STREAM_END); /* rezerwujemy ostatni znak na NULL-a */ out_len = strm.total_out + 1; out2 = realloc(out, out_len); if (out2 == NULL) { gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for output data (%d)\n", out_len); goto fail; } out = out2; out[out_len - 1] = '\0'; inflateEnd(&strm); return out; fail: inflateEnd(&strm); free(out); #endif return NULL; }