#include #include #include #include #include #include /* Older versions of the hdf library may define H5PL_type_t here */ #include #ifndef DLL_EXPORT #define DLL_EXPORT #endif #include "h5bzip2.h" const H5Z_class2_t H5Z_BZIP2[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ (H5Z_filter_t)H5Z_FILTER_BZIP2, /* Filter id number */ 1, /* encoder_present flag (set to true) */ 1, /* decoder_present flag (set to true) */ "bzip2", /* Filter name for debugging */ (H5Z_can_apply_func_t)H5Z_bzip2_can_apply, /* The "can apply" callback */ NULL, /* The "set local" callback */ (H5Z_func_t)H5Z_filter_bzip2, /* The actual filter function */ }}; /* External Discovery Functions */ H5PL_type_t H5PLget_plugin_type(void) { return H5PL_TYPE_FILTER; } const void* H5PLget_plugin_info(void) { return H5Z_BZIP2; } /* Make this explicit */ /* * The "can_apply" callback returns positive a valid combination, zero for an * invalid combination and negative for an error. */ htri_t H5Z_bzip2_can_apply(hid_t dcpl_id, hid_t type_id, hid_t space_id) { return 1; /* Assume it can always apply */ } size_t H5Z_filter_bzip2(unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[], size_t nbytes, size_t *buf_size, void **buf) { char *outbuf = NULL; size_t outbuflen, outdatalen; int ret; if (flags & H5Z_FLAG_REVERSE) { /** Decompress data. ** ** This process is troublesome since the size of uncompressed data ** is unknown, so the low-level interface must be used. ** Data is decompressed to the output buffer (which is sized ** for the average case); if it gets full, its size is doubled ** and decompression continues. This avoids repeatedly trying to ** decompress the whole block, which could be really inefficient. **/ bz_stream stream; char *newbuf = NULL; size_t newbuflen; /* Prepare the output buffer. */ outbuflen = nbytes * 3 + 1; /* average bzip2 compression ratio is 3:1 */ outbuf = malloc(outbuflen); if (outbuf == NULL) { fprintf(stderr, "memory allocation failed for bzip2 decompression\n"); goto cleanupAndFail; } /* Use standard malloc()/free() for internal memory handling. */ stream.bzalloc = NULL; stream.bzfree = NULL; stream.opaque = NULL; /* Start decompression. */ ret = BZ2_bzDecompressInit(&stream, 0, 0); if (ret != BZ_OK) { fprintf(stderr, "bzip2 decompression start failed with error %d\n", ret); goto cleanupAndFail; } /* Feed data to the decompression process and get decompressed data. */ stream.next_out = outbuf; stream.avail_out = outbuflen; stream.next_in = *buf; stream.avail_in = nbytes; do { ret = BZ2_bzDecompress(&stream); if (ret < 0) { fprintf(stderr, "BUG: bzip2 decompression failed with error %d\n", ret); goto cleanupAndFail; } if (ret != BZ_STREAM_END && stream.avail_out == 0) { /* Grow the output buffer. */ newbuflen = outbuflen * 2; newbuf = realloc(outbuf, newbuflen); if (newbuf == NULL) { fprintf(stderr, "memory allocation failed for bzip2 decompression\n"); goto cleanupAndFail; } stream.next_out = newbuf + outbuflen; /* half the new buffer behind */ stream.avail_out = outbuflen; /* half the new buffer ahead */ outbuf = newbuf; outbuflen = newbuflen; } } while (ret != BZ_STREAM_END); /* End compression. */ outdatalen = stream.total_out_lo32; ret = BZ2_bzDecompressEnd(&stream); if (ret != BZ_OK) { fprintf(stderr, "bzip2 compression end failed with error %d\n", ret); goto cleanupAndFail; } } else { /** Compress data. ** ** This is quite simple, since the size of compressed data in the worst ** case is known and it is not much bigger than the size of uncompressed ** data. This allows us to use the simplified one-shot interface to ** compression. **/ unsigned int odatalen; /* maybe not the same size as outdatalen */ int blockSize100k = 9; /* Get compression block size if present. */ if (cd_nelmts > 0) { blockSize100k = cd_values[0]; if (blockSize100k < 1 || blockSize100k > 9) { fprintf(stderr, "invalid compression block size: %d\n", blockSize100k); goto cleanupAndFail; } } /* Prepare the output buffer. */ outbuflen = nbytes + nbytes / 100 + 600; /* worst case (bzip2 docs) */ outbuf = malloc(outbuflen); if (outbuf == NULL) { fprintf(stderr, "memory allocation failed for bzip2 compression\n"); goto cleanupAndFail; } /* Compress data. */ odatalen = outbuflen; ret = BZ2_bzBuffToBuffCompress(outbuf, &odatalen, *buf, nbytes, blockSize100k, 0, 0); outdatalen = odatalen; if (ret != BZ_OK) { fprintf(stderr, "bzip2 compression failed with error %d\n", ret); goto cleanupAndFail; } } /* Always replace the input buffer with the output buffer. */ free(*buf); *buf = outbuf; *buf_size = outbuflen; return outdatalen; cleanupAndFail: if (outbuf) free(outbuf); return 0; }