annotate src/zlib-1.2.8/examples/fitblk.c @ 56:af97cad61ff0

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