/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Programmer: Robb Matzke * Friday, August 27, 1999 */ #define H5Z_PACKAGE /*suppress error about including H5Zpkg */ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5MMprivate.h" /* Memory management */ #include "H5Zpkg.h" /* Data filters */ #ifdef H5_HAVE_FILTER_DEFLATE #ifdef H5_HAVE_ZLIB_H # include "zlib.h" #endif /* Local function prototypes */ static size_t H5Z_filter_deflate (unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ const H5Z_class_t H5Z_DEFLATE[1] = {{ H5Z_FILTER_DEFLATE, /* Filter id number */ "deflate", /* Filter name for debugging */ NULL, /* The "can apply" callback */ NULL, /* The "set local" callback */ H5Z_filter_deflate, /* The actual filter function */ }}; #define H5Z_DEFLATE_SIZE_ADJUST(s) (HDceil(((double)(s))*1.001)+12) /*------------------------------------------------------------------------- * Function: H5Z_filter_deflate * * Purpose: Implement an I/O filter around the 'deflate' algorithm in * libz * * Return: Success: Size of buffer filtered * Failure: 0 * * Programmer: Robb Matzke * Thursday, April 16, 1998 * * Modifications: * *------------------------------------------------------------------------- */ static size_t H5Z_filter_deflate (unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf) { void *outbuf = NULL; /* Pointer to new buffer */ int status; /* Status from zlib operation */ size_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5Z_filter_deflate, 0) /* Check arguments */ if (cd_nelmts!=1 || cd_values[0]>9) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid deflate aggression level") if (flags & H5Z_FLAG_REVERSE) { /* Input; uncompress */ z_stream z_strm; /* zlib parameters */ size_t nalloc = *buf_size; /* Number of bytes for output (compressed) buffer */ /* Allocate space for the compressed buffer */ if (NULL==(outbuf = H5MM_malloc(nalloc))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for deflate uncompression") /* Set the uncompression parameters */ HDmemset(&z_strm, 0, sizeof(z_strm)); z_strm.next_in = *buf; H5_ASSIGN_OVERFLOW(z_strm.avail_in,nbytes,size_t,uInt); z_strm.next_out = outbuf; H5_ASSIGN_OVERFLOW(z_strm.avail_out,nalloc,size_t,uInt); /* Initialize the uncompression routines */ if (Z_OK!=inflateInit(&z_strm)) HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "inflateInit() failed") /* Loop to uncompress the buffer */ do { /* Uncompress some data */ status = inflate(&z_strm, Z_SYNC_FLUSH); /* Check if we are done uncompressing data */ if (Z_STREAM_END==status) break; /*done*/ /* Check for error */ if (Z_OK!=status) { (void)inflateEnd(&z_strm); HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "inflate() failed") } else { /* If we're not done and just ran out of buffer space, get more */ if (0==z_strm.avail_out) { /* Allocate a buffer twice as big */ nalloc *= 2; if (NULL==(outbuf = H5MM_realloc(outbuf, nalloc))) { (void)inflateEnd(&z_strm); HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for deflate uncompression") } /* Update pointers to buffer for next set of uncompressed data */ z_strm.next_out = (unsigned char*)outbuf + z_strm.total_out; z_strm.avail_out = (uInt)(nalloc - z_strm.total_out); } } /* end else */ } while(status==Z_OK); /* Free the input buffer */ H5MM_xfree(*buf); /* Set return values */ *buf = outbuf; outbuf = NULL; *buf_size = nalloc; ret_value = z_strm.total_out; /* Finish uncompressing the stream */ (void)inflateEnd(&z_strm); } else { /* * Output; compress but fail if the result would be larger than the * input. The library doesn't provide in-place compression, so we * must allocate a separate buffer for the result. */ const Bytef *z_src = (const Bytef*)(*buf); Bytef *z_dst; /*destination buffer */ uLongf z_dst_nbytes = (uLongf)H5Z_DEFLATE_SIZE_ADJUST(nbytes); uLong z_src_nbytes = (uLong)nbytes; int aggression; /* Compression aggression setting */ /* Set the compression aggression level */ H5_ASSIGN_OVERFLOW(aggression,cd_values[0],unsigned,int); /* Allocate output (compressed) buffer */ if (NULL==(z_dst=outbuf=H5MM_malloc(z_dst_nbytes))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "unable to allocate deflate destination buffer") /* Perform compression from the source to the destination buffer */ status = compress2 (z_dst, &z_dst_nbytes, z_src, z_src_nbytes, aggression); /* Check for various zlib errors */ if (Z_BUF_ERROR==status) HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, 0, "overflow") else if (Z_MEM_ERROR==status) HGOTO_ERROR (H5E_PLINE, H5E_CANTINIT, 0, "deflate memory error") else if (Z_OK!=status) HGOTO_ERROR (H5E_PLINE, H5E_CANTINIT, 0, "other deflate error") /* Successfully uncompressed the buffer */ else { /* Free the input buffer */ H5MM_xfree(*buf); /* Set return values */ *buf = outbuf; outbuf = NULL; *buf_size = nbytes; ret_value = z_dst_nbytes; } } done: if(outbuf) H5MM_xfree(outbuf); FUNC_LEAVE_NOAPI(ret_value) } #endif /* H5_HAVE_FILTER_DEFLATE */