annotate src/zlib-1.2.7/examples/fitblk.c @ 23:619f715526df sv_v2.1

Update Vamp plugin SDK to 2.5
author Chris Cannam
date Thu, 09 May 2013 10:52:46 +0100
parents e13257ea84a4
children
rev   line source
Chris@4 1 /* fitblk.c: example of fitting compressed output to a specified size
Chris@4 2 Not copyrighted -- provided to the public domain
Chris@4 3 Version 1.1 25 November 2004 Mark Adler */
Chris@4 4
Chris@4 5 /* Version history:
Chris@4 6 1.0 24 Nov 2004 First version
Chris@4 7 1.1 25 Nov 2004 Change deflateInit2() to deflateInit()
Chris@4 8 Use fixed-size, stack-allocated raw buffers
Chris@4 9 Simplify code moving compression to subroutines
Chris@4 10 Use assert() for internal errors
Chris@4 11 Add detailed description of approach
Chris@4 12 */
Chris@4 13
Chris@4 14 /* Approach to just fitting a requested compressed size:
Chris@4 15
Chris@4 16 fitblk performs three compression passes on a portion of the input
Chris@4 17 data in order to determine how much of that input will compress to
Chris@4 18 nearly the requested output block size. The first pass generates
Chris@4 19 enough deflate blocks to produce output to fill the requested
Chris@4 20 output size plus a specfied excess amount (see the EXCESS define
Chris@4 21 below). The last deflate block may go quite a bit past that, but
Chris@4 22 is discarded. The second pass decompresses and recompresses just
Chris@4 23 the compressed data that fit in the requested plus excess sized
Chris@4 24 buffer. The deflate process is terminated after that amount of
Chris@4 25 input, which is less than the amount consumed on the first pass.
Chris@4 26 The last deflate block of the result will be of a comparable size
Chris@4 27 to the final product, so that the header for that deflate block and
Chris@4 28 the compression ratio for that block will be about the same as in
Chris@4 29 the final product. The third compression pass decompresses the
Chris@4 30 result of the second step, but only the compressed data up to the
Chris@4 31 requested size minus an amount to allow the compressed stream to
Chris@4 32 complete (see the MARGIN define below). That will result in a
Chris@4 33 final compressed stream whose length is less than or equal to the
Chris@4 34 requested size. Assuming sufficient input and a requested size
Chris@4 35 greater than a few hundred bytes, the shortfall will typically be
Chris@4 36 less than ten bytes.
Chris@4 37
Chris@4 38 If the input is short enough that the first compression completes
Chris@4 39 before filling the requested output size, then that compressed
Chris@4 40 stream is return with no recompression.
Chris@4 41
Chris@4 42 EXCESS is chosen to be just greater than the shortfall seen in a
Chris@4 43 two pass approach similar to the above. That shortfall is due to
Chris@4 44 the last deflate block compressing more efficiently with a smaller
Chris@4 45 header on the second pass. EXCESS is set to be large enough so
Chris@4 46 that there is enough uncompressed data for the second pass to fill
Chris@4 47 out the requested size, and small enough so that the final deflate
Chris@4 48 block of the second pass will be close in size to the final deflate
Chris@4 49 block of the third and final pass. MARGIN is chosen to be just
Chris@4 50 large enough to assure that the final compression has enough room
Chris@4 51 to complete in all cases.
Chris@4 52 */
Chris@4 53
Chris@4 54 #include <stdio.h>
Chris@4 55 #include <stdlib.h>
Chris@4 56 #include <assert.h>
Chris@4 57 #include "zlib.h"
Chris@4 58
Chris@4 59 #define local static
Chris@4 60
Chris@4 61 /* print nastygram and leave */
Chris@4 62 local void quit(char *why)
Chris@4 63 {
Chris@4 64 fprintf(stderr, "fitblk abort: %s\n", why);
Chris@4 65 exit(1);
Chris@4 66 }
Chris@4 67
Chris@4 68 #define RAWLEN 4096 /* intermediate uncompressed buffer size */
Chris@4 69
Chris@4 70 /* compress from file to def until provided buffer is full or end of
Chris@4 71 input reached; return last deflate() return value, or Z_ERRNO if
Chris@4 72 there was read error on the file */
Chris@4 73 local int partcompress(FILE *in, z_streamp def)
Chris@4 74 {
Chris@4 75 int ret, flush;
Chris@4 76 unsigned char raw[RAWLEN];
Chris@4 77
Chris@4 78 flush = Z_NO_FLUSH;
Chris@4 79 do {
Chris@4 80 def->avail_in = fread(raw, 1, RAWLEN, in);
Chris@4 81 if (ferror(in))
Chris@4 82 return Z_ERRNO;
Chris@4 83 def->next_in = raw;
Chris@4 84 if (feof(in))
Chris@4 85 flush = Z_FINISH;
Chris@4 86 ret = deflate(def, flush);
Chris@4 87 assert(ret != Z_STREAM_ERROR);
Chris@4 88 } while (def->avail_out != 0 && flush == Z_NO_FLUSH);
Chris@4 89 return ret;
Chris@4 90 }
Chris@4 91
Chris@4 92 /* recompress from inf's input to def's output; the input for inf and
Chris@4 93 the output for def are set in those structures before calling;
Chris@4 94 return last deflate() return value, or Z_MEM_ERROR if inflate()
Chris@4 95 was not able to allocate enough memory when it needed to */
Chris@4 96 local int recompress(z_streamp inf, z_streamp def)
Chris@4 97 {
Chris@4 98 int ret, flush;
Chris@4 99 unsigned char raw[RAWLEN];
Chris@4 100
Chris@4 101 flush = Z_NO_FLUSH;
Chris@4 102 do {
Chris@4 103 /* decompress */
Chris@4 104 inf->avail_out = RAWLEN;
Chris@4 105 inf->next_out = raw;
Chris@4 106 ret = inflate(inf, Z_NO_FLUSH);
Chris@4 107 assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
Chris@4 108 ret != Z_NEED_DICT);
Chris@4 109 if (ret == Z_MEM_ERROR)
Chris@4 110 return ret;
Chris@4 111
Chris@4 112 /* compress what was decompresed until done or no room */
Chris@4 113 def->avail_in = RAWLEN - inf->avail_out;
Chris@4 114 def->next_in = raw;
Chris@4 115 if (inf->avail_out != 0)
Chris@4 116 flush = Z_FINISH;
Chris@4 117 ret = deflate(def, flush);
Chris@4 118 assert(ret != Z_STREAM_ERROR);
Chris@4 119 } while (ret != Z_STREAM_END && def->avail_out != 0);
Chris@4 120 return ret;
Chris@4 121 }
Chris@4 122
Chris@4 123 #define EXCESS 256 /* empirically determined stream overage */
Chris@4 124 #define MARGIN 8 /* amount to back off for completion */
Chris@4 125
Chris@4 126 /* compress from stdin to fixed-size block on stdout */
Chris@4 127 int main(int argc, char **argv)
Chris@4 128 {
Chris@4 129 int ret; /* return code */
Chris@4 130 unsigned size; /* requested fixed output block size */
Chris@4 131 unsigned have; /* bytes written by deflate() call */
Chris@4 132 unsigned char *blk; /* intermediate and final stream */
Chris@4 133 unsigned char *tmp; /* close to desired size stream */
Chris@4 134 z_stream def, inf; /* zlib deflate and inflate states */
Chris@4 135
Chris@4 136 /* get requested output size */
Chris@4 137 if (argc != 2)
Chris@4 138 quit("need one argument: size of output block");
Chris@4 139 ret = strtol(argv[1], argv + 1, 10);
Chris@4 140 if (argv[1][0] != 0)
Chris@4 141 quit("argument must be a number");
Chris@4 142 if (ret < 8) /* 8 is minimum zlib stream size */
Chris@4 143 quit("need positive size of 8 or greater");
Chris@4 144 size = (unsigned)ret;
Chris@4 145
Chris@4 146 /* allocate memory for buffers and compression engine */
Chris@4 147 blk = malloc(size + EXCESS);
Chris@4 148 def.zalloc = Z_NULL;
Chris@4 149 def.zfree = Z_NULL;
Chris@4 150 def.opaque = Z_NULL;
Chris@4 151 ret = deflateInit(&def, Z_DEFAULT_COMPRESSION);
Chris@4 152 if (ret != Z_OK || blk == NULL)
Chris@4 153 quit("out of memory");
Chris@4 154
Chris@4 155 /* compress from stdin until output full, or no more input */
Chris@4 156 def.avail_out = size + EXCESS;
Chris@4 157 def.next_out = blk;
Chris@4 158 ret = partcompress(stdin, &def);
Chris@4 159 if (ret == Z_ERRNO)
Chris@4 160 quit("error reading input");
Chris@4 161
Chris@4 162 /* if it all fit, then size was undersubscribed -- done! */
Chris@4 163 if (ret == Z_STREAM_END && def.avail_out >= EXCESS) {
Chris@4 164 /* write block to stdout */
Chris@4 165 have = size + EXCESS - def.avail_out;
Chris@4 166 if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
Chris@4 167 quit("error writing output");
Chris@4 168
Chris@4 169 /* clean up and print results to stderr */
Chris@4 170 ret = deflateEnd(&def);
Chris@4 171 assert(ret != Z_STREAM_ERROR);
Chris@4 172 free(blk);
Chris@4 173 fprintf(stderr,
Chris@4 174 "%u bytes unused out of %u requested (all input)\n",
Chris@4 175 size - have, size);
Chris@4 176 return 0;
Chris@4 177 }
Chris@4 178
Chris@4 179 /* it didn't all fit -- set up for recompression */
Chris@4 180 inf.zalloc = Z_NULL;
Chris@4 181 inf.zfree = Z_NULL;
Chris@4 182 inf.opaque = Z_NULL;
Chris@4 183 inf.avail_in = 0;
Chris@4 184 inf.next_in = Z_NULL;
Chris@4 185 ret = inflateInit(&inf);
Chris@4 186 tmp = malloc(size + EXCESS);
Chris@4 187 if (ret != Z_OK || tmp == NULL)
Chris@4 188 quit("out of memory");
Chris@4 189 ret = deflateReset(&def);
Chris@4 190 assert(ret != Z_STREAM_ERROR);
Chris@4 191
Chris@4 192 /* do first recompression close to the right amount */
Chris@4 193 inf.avail_in = size + EXCESS;
Chris@4 194 inf.next_in = blk;
Chris@4 195 def.avail_out = size + EXCESS;
Chris@4 196 def.next_out = tmp;
Chris@4 197 ret = recompress(&inf, &def);
Chris@4 198 if (ret == Z_MEM_ERROR)
Chris@4 199 quit("out of memory");
Chris@4 200
Chris@4 201 /* set up for next reocmpression */
Chris@4 202 ret = inflateReset(&inf);
Chris@4 203 assert(ret != Z_STREAM_ERROR);
Chris@4 204 ret = deflateReset(&def);
Chris@4 205 assert(ret != Z_STREAM_ERROR);
Chris@4 206
Chris@4 207 /* do second and final recompression (third compression) */
Chris@4 208 inf.avail_in = size - MARGIN; /* assure stream will complete */
Chris@4 209 inf.next_in = tmp;
Chris@4 210 def.avail_out = size;
Chris@4 211 def.next_out = blk;
Chris@4 212 ret = recompress(&inf, &def);
Chris@4 213 if (ret == Z_MEM_ERROR)
Chris@4 214 quit("out of memory");
Chris@4 215 assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */
Chris@4 216
Chris@4 217 /* done -- write block to stdout */
Chris@4 218 have = size - def.avail_out;
Chris@4 219 if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
Chris@4 220 quit("error writing output");
Chris@4 221
Chris@4 222 /* clean up and print results to stderr */
Chris@4 223 free(tmp);
Chris@4 224 ret = inflateEnd(&inf);
Chris@4 225 assert(ret != Z_STREAM_ERROR);
Chris@4 226 ret = deflateEnd(&def);
Chris@4 227 assert(ret != Z_STREAM_ERROR);
Chris@4 228 free(blk);
Chris@4 229 fprintf(stderr,
Chris@4 230 "%u bytes unused out of %u requested (%lu input)\n",
Chris@4 231 size - have, size, def.total_in);
Chris@4 232 return 0;
Chris@4 233 }