#include /* z.msg can be NULL if there's no message, in particular for zero length input inflate() returns Z_BUF_ERROR with z.msg==NULL */ Lisp_Object make_z_stream_msg (z_stream *zp, int ret) { if (zp->msg != NULL) return build_string (zp->msg); else return concat2 (build_string ("Zlib error code "), Fnumber_to_string (make_number (ret))); } DEFUN ("zlib-inflate-string", Fzlib_inflate_string, Szlib_inflate_string, 1, 1, 0, doc: /* Inflate Zlib or Gzip format compressed data. STR is a unibyte string of compressed data in either Zlib (RFC 1950) or Gzip (RFC 1952) format. The return is a unibyte string of the decompressed result. An error is thrown for invalid contents. */) (str) Lisp_Object str; { z_stream z; int ret; char buf[4096]; Lisp_Object lst = Qnil; CHECK_STRING (str); z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; z.next_in = (Bytef *) SDATA (str); z.avail_in = SBYTES (str); z.next_out = (Bytef *) buf; z.avail_out = sizeof (buf); /* ask to accept either gzip or zlib header formats */ ret = inflateInit2 (&z, 32 + 15); if (ret != Z_OK) xsignal1 (Qerror, concat2 (build_string ("Zlib inflateInit2: "), make_z_stream_msg (&z, ret))); for (;;) { ret = inflate (&z, Z_NO_FLUSH); if (ret != Z_OK && ret != Z_STREAM_END) { Lisp_Object msg = make_z_stream_msg (&z, ret); inflateEnd (&z); xsignal1 (Qerror, concat2 (build_string ("Zlib inflate: "), msg)); } if (z.avail_out == 0 || ret == Z_STREAM_END) { lst = Fcons (make_unibyte_string (buf, sizeof (buf) - z.avail_out), lst); z.next_out = (Bytef *) buf; z.avail_out = sizeof (buf); } if (ret == Z_STREAM_END) break; } if (z.avail_in != 0) { ret = inflateEnd (&z); error ("Garbage after compressed data"); } ret = inflateEnd (&z); if (ret != Z_OK) xsignal1 (Qerror, concat2 (build_string ("Zlib inflateEnd: "), make_z_stream_msg (&z, ret))); return apply1 (intern ("concat"), Fnreverse (lst)); }