#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include <assert.h>
#define SIZE_CHUNK (8 * 1024)
static int __do_inflate_write(z_stream &strm,
FILE *fp, void *data, size_t size)
{
int res = -1;
char out[SIZE_CHUNK];
strm.next_in = (Bytef *)data;
strm.avail_in = size;
//printf("inflate: %u\n", strm.avail_in);
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = sizeof(out);
strm.next_out = (Bytef *)out;
res = inflate(&strm, Z_NO_FLUSH);
assert(res != Z_STREAM_ERROR); /* state not clobbered */
switch (res) {
case Z_NEED_DICT:
res = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
goto out;
}
size_t wlen = fwrite(out, 1, sizeof(out) - strm.avail_out, fp);
assert(wlen == sizeof(out) - strm.avail_out);
//printf(" write: %zu\n", wlen);
} while (strm.avail_out == 0);
out:
return res;
}
/***************************************************************************************
* Name: file_inflate
* Desc: Decompress from file source to file dest until stream ends or EOF.
* Input:
* Output:
* Return: Z_OK on success
* Z_MEM_ERROR if memory could not be allocated for processing
* Z_DATA_ERROR if the deflate data isinvalid or incomplete
* Z_VERSION_ERROR if the version of zlib.h and the version of
* the library linked do not match
* Z_ERRNO if there is an error reading or writing the files
* Others: -
***************************************************************************************/
int file_inflate(const char *fsrc, const char *fdst)
{
int res = -1;
FILE *src = fopen(fsrc, "r");
FILE *dst = fopen(fdst, "w+");
assert(src && dst);
z_stream strm = {Z_NULL};
res = inflateInit(&strm);
assert(res == Z_OK);
/* decompress until deflate stream ends or end of file */
do {
char in[SIZE_CHUNK];
size_t rlen = fread(in, 1, sizeof(in), src);
if (rlen == 0) {
printf("EOF\n");
break;
}
/* done when inflate() says it's done */
res = __do_inflate_write(strm, dst, in, rlen);
} while (res != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
fclose(src);
fclose(dst);
return res == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
static void __do_deflate_write(z_stream &strm,
FILE *fp, void *data, size_t size, int flush)
{
char out[SIZE_CHUNK];
strm.avail_in = size;
strm.next_in = (Bytef *)data;
//printf("deflate: %u\n", strm.avail_in);
/* run deflate() on input until output buffer not full, finish
* compression if all of source has been read in */
do {
strm.next_out = (Bytef *)out;
strm.avail_out = sizeof(out);
int res = deflate(&strm, flush);
assert(res != Z_STREAM_ERROR); // state not clobbered
size_t wlen = fwrite(out, 1, sizeof(out) - strm.avail_out, fp);
assert(wlen == sizeof(out) - strm.avail_out);
//printf(" write: %zu\n", wlen);
} while (strm.avail_out == 0); // 返回0,则表示正好out空间不够大了
assert(strm.avail_in == 0); /* all input will be used */
}
/***************************************************************************************
* Name: file_deflate
* Desc: Compress from file source to file dest until EOF on source
* Input:
* @fname - source file name
* Output:
* Return: Z_OK on success
* Z_MEM_ERROR if memory could not be allocated for processing
* Z_STREAM_ERROR if an invalid compression level is supplied
* Z_VERSION_ERROR if the version of zlib.h and the version of
* the library linked do not match
* Z_ERRNO if there is an error reading or writing the files
* Others: -
***************************************************************************************/
int file_deflate(const char *fsrc, const char *fdst)
{
int res = -1;
int flush = Z_NO_FLUSH;
FILE *src = fopen(fsrc, "r");
FILE *dst = fopen(fdst, "w+");
assert(src && dst);
z_stream strm = {Z_NULL};
res = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
assert(res == Z_OK);
/* Compress until end of file */
do {
char in[SIZE_CHUNK];
size_t rlen = fread(in, 1, sizeof(in), src);
if (rlen == 0) {
printf("EOF\n");
break;
}
// 这里需要区分文件尾或者文件中间
flush = feof(src) ? Z_FINISH : Z_NO_FLUSH;
__do_deflate_write(strm, dst, in, rlen, flush);
} while (flush != Z_FINISH);
/* clean up and return */
(void)deflateEnd(&strm);
fclose(src);
fclose(dst);
return Z_OK;
}
int main(int argc, char *argv[])
{
int res = -1;
if (argv[1] && argv[2] && argv[3] && 0 == strcmp(argv[1], "-d")) {
/* -d模式 表示压缩文件 */
res = file_deflate(argv[2], argv[3]);
}
else if (argv[1] && argv[2]) {
/* 解压文件 */
res = file_inflate(argv[1], argv[2]);
}
else {
printf("%s [ -d[mean compress]] < source > < dest >\n", argv[0]);
printf("or %s < source > < dest >\n", argv[0]);
exit(EXIT_FAILURE);
}
printf("Result:\t\t\t\t[%s]\n", res ? "Failure" : "Success");
exit(res ? EXIT_FAILURE : EXIT_SUCCESS);
}