diff options
-rw-r--r-- | README | 15 | ||||
-rw-r--r-- | blocksplitter.c | 6 | ||||
-rw-r--r-- | gzip.c | 271 | ||||
-rw-r--r-- | gzip_container.c | 115 | ||||
-rw-r--r-- | gzip_container.h | 42 | ||||
-rw-r--r-- | squeeze.c | 8 | ||||
-rw-r--r-- | zlib_container.c | 78 | ||||
-rw-r--r-- | zlib_container.h | 42 | ||||
-rw-r--r-- | zopfli.c | 216 |
9 files changed, 509 insertions, 284 deletions
@@ -1,17 +1,20 @@ Zopfli Compression Algorithm is a compression library programmed in C to perform very good, but slow, deflate or zlib compression. -gzip.c is separate from the library and contains an example program to create +zopfli.c is separate from the library and contains an example program to create very well compressed gzip files. -The basic function to compress data is Deflate in deflate.h. Use the Options +The basic functions to compress data are Deflate in deflate.h, ZlibCompress in +zlib_container.h and GzipCompress in gzip_container.h. Use the Options object to set parameters that affect the speed and compression. Use the InitOptions function to place the default values in the Options first. -This function creates a valid deflate stream. To get a valid zlib stream -instead, you need to add a small zlib header and a checksum around this stream -yourself. Please see the Zlib specification for more details: -http://www.ietf.org/rfc/rfc1950.txt. +Deflate creates a valid deflate stream in memory, see: +http://www.ietf.org/rfc/rfc1951.txt +ZlibCompress creates a valid zlib stream in memory, see: +http://www.ietf.org/rfc/rfc1950.txt +GzipCompress creates a valid gzip stream in memory, see: +http://www.ietf.org/rfc/rfc1952.txt This library can only compress, not decompress. Existing zlib or deflate libraries can decompress the data. diff --git a/blocksplitter.c b/blocksplitter.c index c54ef77..157273e 100644 --- a/blocksplitter.c +++ b/blocksplitter.c @@ -223,13 +223,13 @@ void BlockSplitLZ77(const Options* options, size_t i; size_t llpos = 0; size_t numblocks = 1; - unsigned char* done = (unsigned char*)malloc(llsize); + unsigned char* done; double splitcost, origcost; - if (!done) exit(-1); /* Allocation failed. */ - if (llsize < 10) return; /* This code fails on tiny files. */ + done = (unsigned char*)malloc(llsize); + if (!done) exit(-1); /* Allocation failed. */ for (i = 0; i < llsize; i++) done[i] = 0; lstart = 0; @@ -1,271 +0,0 @@ -/* -Copyright 2011 Google Inc. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Author: lode.vandevenne@gmail.com (Lode Vandevenne) -Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) -*/ - -/* -Example program using the zopfli compression algorithm library. It is a tool -which behaves like a subset of gzip which can only compress, not decompress. -*/ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "deflate.h" -#include "util.h" - -/* -Loads a file into a memory array. -*/ -static void LoadFile(const char* filename, - unsigned char** out, size_t* outsize) { - FILE* file; - - *out = 0; - *outsize = 0; - file = fopen(filename, "rb"); - if (!file) return; - - fseek(file , 0 , SEEK_END); - *outsize = ftell(file); - rewind(file); - - *out = (unsigned char*)malloc(*outsize); - - if (*outsize && (*out)) { - size_t testsize = fread(*out, 1, *outsize, file); - if (testsize != *outsize) { - /* It could be a directory */ - free(*out); - *out = 0; - *outsize = 0; - } - } - - assert(!(*outsize) || out); /* If size is not zero, out must be allocated. */ - fclose(file); -} - -/* -Saves a file from a memory array, overwriting the file if it existed. -*/ -static void SaveFile(const char* filename, - const unsigned char* in, size_t insize) { - FILE* file = fopen(filename, "wb" ); - assert(file); - fwrite((char*)in, 1, insize, file); - fclose(file); -} - -/* Table of CRCs of all 8-bit messages. */ -static unsigned long crc_table[256]; - -/* Flag: has the table been computed? Initially false. */ -static int crc_table_computed = 0; - -/* Makes the table for a fast CRC. */ -void MakeCRCTable() { - unsigned long c; - int n, k; - for (n = 0; n < 256; n++) { - c = (unsigned long) n; - for (k = 0; k < 8; k++) { - if (c & 1) { - c = 0xedb88320L ^ (c >> 1); - } else { - c = c >> 1; - } - } - crc_table[n] = c; - } - crc_table_computed = 1; -} - -/* -Updates a running crc with the bytes buf[0..len-1] and returns -the updated crc. The crc should be initialized to zero. -*/ -unsigned long UpdateCRC(unsigned long crc, - const unsigned char *buf, size_t len) { - unsigned long c = crc ^ 0xffffffffL; - unsigned n; - - if (!crc_table_computed) - MakeCRCTable(); - for (n = 0; n < len; n++) { - c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); - } - return c ^ 0xffffffffL; -} - -/* Returns the CRC of the bytes buf[0..len-1]. */ -unsigned long CRC(const unsigned char* buf, int len) { - return UpdateCRC(0L, buf, len); -} - -/* -Compresses the data according to the gzip specification. -*/ -void Gzip(const Options* options, - const unsigned char* in, size_t insize, - unsigned char** out, size_t* outsize) { - unsigned long crcvalue = CRC(in, insize); - unsigned char bp = 0; - - APPEND_DATA(31, out, outsize); /* ID1 */ - APPEND_DATA(139, out, outsize); /* ID2 */ - APPEND_DATA(8, out, outsize); /* CM */ - APPEND_DATA(0, out, outsize); /* FLG */ - /* MTIME */ - APPEND_DATA(0, out, outsize); - APPEND_DATA(0, out, outsize); - APPEND_DATA(0, out, outsize); - APPEND_DATA(0, out, outsize); - - APPEND_DATA(2, out, outsize); /* XFL, 2 indicates best compression. */ - APPEND_DATA(3, out, outsize); /* OS follows Unix conventions. */ - - Deflate(options, 2 /* Dynamic block */, 1, in, insize, &bp, out, outsize); - - /* CRC */ - APPEND_DATA(crcvalue % 256, out, outsize); - APPEND_DATA((crcvalue >> 8) % 256, out, outsize); - APPEND_DATA((crcvalue >> 16) % 256, out, outsize); - APPEND_DATA((crcvalue >> 24) % 256, out, outsize); - - /* ISIZE */ - APPEND_DATA(insize % 256, out, outsize); - APPEND_DATA((insize >> 8) % 256, out, outsize); - APPEND_DATA((insize >> 16) % 256, out, outsize); - APPEND_DATA((insize >> 24) % 256, out, outsize); - - if (options->verbose) { - fprintf(stderr, - "Original Size: %d, Compressed: %d, Compression: %f%% Removed\n", - (int)insize, (int)*outsize, - 100.0f * (float)(insize - *outsize) / (float)insize); - } -} - -/* -outfilename: filename to write output to, or 0 to write to stdout instead -*/ -void GzipFile(const Options* options, - const char* infilename, - const char* outfilename) { - unsigned char* in; - size_t insize; - unsigned char* out = 0; - size_t outsize = 0; - LoadFile(infilename, &in, &insize); - if (insize == 0) { - fprintf(stderr, "Invalid filename: %s\n", infilename); - return; - } - Gzip(options, in, insize, &out, &outsize); - if (outfilename) { - SaveFile(outfilename, out, outsize); - } else { - size_t i; - for (i = 0; i < outsize; i++) { - /* Works only if terminal does not convert newlines. */ - printf("%c", out[i]); - } - } - - free(out); - free(in); -} - -/* -Add two strings together. Size does not matter. Result must be freed. -*/ -static char* AddStrings(const char* str1, const char* str2) { - size_t len = strlen(str1) + strlen(str2); - char* result = (char*)malloc(len + 1); - if (!result) exit(-1); /* Allocation failed. */ - strcpy(result, str1); - strcat(result, str2); - return result; -} - -static char StringsEqual(const char* str1, const char* str2) { - return strcmp(str1, str2) == 0; -} - -int main(int argc, char* argv[]) { - Options options; - const char* filename = 0; - int output_to_stdout = 0; - int i; - - InitOptions(&options); - - for (i = 1; i < argc; i++) { - if (StringsEqual(argv[i], "-v")) options.verbose = 1; - else if (StringsEqual(argv[i], "-c")) output_to_stdout = 1; - else if (StringsEqual(argv[i], "-i5")) options.numiterations = 5; - else if (StringsEqual(argv[i], "-i10")) options.numiterations = 10; - else if (StringsEqual(argv[i], "-i15")) options.numiterations = 15; - else if (StringsEqual(argv[i], "-i25")) options.numiterations = 25; - else if (StringsEqual(argv[i], "-i50")) options.numiterations = 50; - else if (StringsEqual(argv[i], "-i100")) options.numiterations = 100; - else if (StringsEqual(argv[i], "-i250")) options.numiterations = 250; - else if (StringsEqual(argv[i], "-i500")) options.numiterations = 500; - else if (StringsEqual(argv[i], "-i1000")) options.numiterations = 1000; - else if (StringsEqual(argv[i], "-h")) { - fprintf(stderr, "Usage: zopfli [OPTION]... FILE\n" - " -h gives this help\n" - " -c write the result on standard output, instead of disk" - " filename + '.gz'\n" - " -v verbose mode\n" - " -i5 less compression, but faster\n" - " -i10 less compression, but faster\n" - " -i15 default compression, 15 iterations\n" - " -i25 more compression, but slower\n" - " -i50 more compression, but slower\n" - " -i100 more compression, but slower\n" - " -i250 more compression, but slower\n" - " -i500 more compression, but slower\n" - " -i1000 more compression, but slower\n"); - return 0; - } - } - - for (i = 1; i < argc; i++) { - if (argv[i][0] != '-') { - char* outfilename; - filename = argv[i]; - outfilename = output_to_stdout ? - 0 : AddStrings(filename, ".gz"); - if (options.verbose && outfilename) { - fprintf(stderr, "Saving to: %s\n", outfilename); - } - GzipFile(&options, filename, outfilename); - free(outfilename); - } - } - - if (!filename) { - fprintf(stderr, - "Please provide filename\nFor help, type: %s -h\n", argv[0]); - } - - return 0; -} diff --git a/gzip_container.c b/gzip_container.c new file mode 100644 index 0000000..6d38381 --- /dev/null +++ b/gzip_container.c @@ -0,0 +1,115 @@ +/* +Copyright 2013 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: lode.vandevenne@gmail.com (Lode Vandevenne) +Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) +*/ + +#include "gzip_container.h" + +#include <stdio.h> + +#include "deflate.h" + +/* Table of CRCs of all 8-bit messages. */ +static unsigned long crc_table[256]; + +/* Flag: has the table been computed? Initially false. */ +static int crc_table_computed = 0; + +/* Makes the table for a fast CRC. */ +void MakeCRCTable() { + unsigned long c; + int n, k; + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) { + c = 0xedb88320L ^ (c >> 1); + } else { + c = c >> 1; + } + } + crc_table[n] = c; + } + crc_table_computed = 1; +} + + +/* +Updates a running crc with the bytes buf[0..len-1] and returns +the updated crc. The crc should be initialized to zero. +*/ +unsigned long UpdateCRC(unsigned long crc, + const unsigned char *buf, size_t len) { + unsigned long c = crc ^ 0xffffffffL; + unsigned n; + + if (!crc_table_computed) + MakeCRCTable(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; +} + +/* Returns the CRC of the bytes buf[0..len-1]. */ +unsigned long CRC(const unsigned char* buf, int len) { + return UpdateCRC(0L, buf, len); +} + +/* +Compresses the data according to the gzip specification. +*/ +void GzipCompress(const Options* options, + const unsigned char* in, size_t insize, + unsigned char** out, size_t* outsize) { + unsigned long crcvalue = CRC(in, insize); + unsigned char bp = 0; + + APPEND_DATA(31, out, outsize); /* ID1 */ + APPEND_DATA(139, out, outsize); /* ID2 */ + APPEND_DATA(8, out, outsize); /* CM */ + APPEND_DATA(0, out, outsize); /* FLG */ + /* MTIME */ + APPEND_DATA(0, out, outsize); + APPEND_DATA(0, out, outsize); + APPEND_DATA(0, out, outsize); + APPEND_DATA(0, out, outsize); + + APPEND_DATA(2, out, outsize); /* XFL, 2 indicates best compression. */ + APPEND_DATA(3, out, outsize); /* OS follows Unix conventions. */ + + Deflate(options, 2 /* Dynamic block */, 1, in, insize, &bp, out, outsize); + + /* CRC */ + APPEND_DATA(crcvalue % 256, out, outsize); + APPEND_DATA((crcvalue >> 8) % 256, out, outsize); + APPEND_DATA((crcvalue >> 16) % 256, out, outsize); + APPEND_DATA((crcvalue >> 24) % 256, out, outsize); + + /* ISIZE */ + APPEND_DATA(insize % 256, out, outsize); + APPEND_DATA((insize >> 8) % 256, out, outsize); + APPEND_DATA((insize >> 16) % 256, out, outsize); + APPEND_DATA((insize >> 24) % 256, out, outsize); + + if (options->verbose) { + fprintf(stderr, + "Original Size: %d, Compressed: %d, Compression: %f%% Removed\n", + (int)insize, (int)*outsize, + 100.0f * (float)(insize - *outsize) / (float)insize); + } +} diff --git a/gzip_container.h b/gzip_container.h new file mode 100644 index 0000000..c03e9cd --- /dev/null +++ b/gzip_container.h @@ -0,0 +1,42 @@ +/* +Copyright 2013 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: lode.vandevenne@gmail.com (Lode Vandevenne) +Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) +*/ + +#ifndef ZOPFLI_GZIP_H_ +#define ZOPFLI_GZIP_H_ + +/* +Functions to compress according to the Gzip specification. +*/ + +#include "util.h" + +/* +Compresses according to the gzip specification and append the compressed +result to the output. + +options: global program options +out: pointer to the dynamic output array to which the result is appended. Must + be freed after use. +outsize: pointer to the dynamic output array size. +*/ +void GzipCompress(const Options* options, + const unsigned char* in, size_t insize, + unsigned char** out, size_t* outsize); + +#endif /* ZOPFLI_GZIP_H_ */ @@ -205,8 +205,7 @@ static double GetBestLengths(BlockState *s, unsigned short* length_array) { /* Best cost to get here so far. */ size_t blocksize = inend - instart; - float* costs = (float*)malloc(sizeof(float) * (blocksize + 1)); - + float* costs; size_t i = 0, k; unsigned short leng; unsigned short dist; @@ -217,10 +216,11 @@ static double GetBestLengths(BlockState *s, double result; double mincost = GetCostModelMinCost(costmodel, costcontext); - if (!costs) exit(-1); /* Allocation failed. */ - if (instart == inend) return 0; + costs = (float*)malloc(sizeof(float) * (blocksize + 1)); + if (!costs) exit(-1); /* Allocation failed. */ + InitHash(WINDOW_SIZE, h); WarmupHash(in, windowstart, inend, h); for (i = windowstart; i < instart; i++) { diff --git a/zlib_container.c b/zlib_container.c new file mode 100644 index 0000000..b77d023 --- /dev/null +++ b/zlib_container.c @@ -0,0 +1,78 @@ +/* +Copyright 2013 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: lode.vandevenne@gmail.com (Lode Vandevenne) +Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) +*/ + +#include "zlib_container.h" + +#include <stdio.h> + +#include "deflate.h" + + +/* Calculates the adler32 checksum of the data */ +static unsigned adler32(const unsigned char* data, size_t size) +{ + static const unsigned sums_overflow = 5550; + unsigned s1 = 1; + unsigned s2 = 1 >> 16; + + while (size > 0) { + size_t amount = size > sums_overflow ? sums_overflow : size; + size -= amount; + while (amount > 0) { + s1 += (*data++); + s2 += s1; + amount--; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +void ZlibCompress(const Options* options, + const unsigned char* in, size_t insize, + unsigned char** out, size_t* outsize) { + unsigned char bitpointer = 0; + unsigned checksum = adler32(in, (unsigned)insize); + unsigned cmf = 120; /* CM 8, CINFO 7. See zlib spec.*/ + unsigned flevel = 0; + unsigned fdict = 0; + unsigned cmfflg = 256 * cmf + fdict * 32 + flevel * 64; + unsigned fcheck = 31 - cmfflg % 31; + cmfflg += fcheck; + + APPEND_DATA(cmfflg / 256, out, outsize); + APPEND_DATA(cmfflg % 256, out, outsize); + + Deflate(options, 2 /* dynamic block */, 1 /* final */, + in, insize, &bitpointer, out, outsize); + + APPEND_DATA((checksum >> 24) % 256, out, outsize); + APPEND_DATA((checksum >> 16) % 256, out, outsize); + APPEND_DATA((checksum >> 8) % 256, out, outsize); + APPEND_DATA(checksum % 256, out, outsize); + + if (options->verbose) { + fprintf(stderr, + "Original Size: %d, Compressed: %d, Compression: %f%% Removed\n", + (int)insize, (int)*outsize, + 100.0f * (float)(insize - *outsize) / (float)insize); + } +} diff --git a/zlib_container.h b/zlib_container.h new file mode 100644 index 0000000..3b11e7a --- /dev/null +++ b/zlib_container.h @@ -0,0 +1,42 @@ +/* +Copyright 2013 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: lode.vandevenne@gmail.com (Lode Vandevenne) +Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) +*/ + +#ifndef ZOPFLI_ZLIB_H_ +#define ZOPFLI_ZLIB_H_ + +/* +Functions to compress according to the Zlib specification. +*/ + +#include "util.h" + +/* +Compresses according to the zlib specification and append the compressed +result to the output. + +options: global program options +out: pointer to the dynamic output array to which the result is appended. Must + be freed after use. +outsize: pointer to the dynamic output array size. +*/ +void ZlibCompress(const Options* options, + const unsigned char* in, size_t insize, + unsigned char** out, size_t* outsize); + +#endif /* ZOPFLI_ZLIB_H_ */ diff --git a/zopfli.c b/zopfli.c new file mode 100644 index 0000000..377b43f --- /dev/null +++ b/zopfli.c @@ -0,0 +1,216 @@ +/* +Copyright 2011 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: lode.vandevenne@gmail.com (Lode Vandevenne) +Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) +*/ + +/* +Zopfli compressor program. It can output gzip-, zlib- or deflate-compatible +data. By default it creates a .gz file. This tool can only compress, not +decompress. Decompression can be done by any standard gzip, zlib or deflate +decompressor. +*/ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "deflate.h" +#include "gzip_container.h" +#include "zlib_container.h" + +/* +Loads a file into a memory array. +*/ +static void LoadFile(const char* filename, + unsigned char** out, size_t* outsize) { + FILE* file; + + *out = 0; + *outsize = 0; + file = fopen(filename, "rb"); + if (!file) return; + + fseek(file , 0 , SEEK_END); + *outsize = ftell(file); + rewind(file); + + *out = (unsigned char*)malloc(*outsize); + + if (*outsize && (*out)) { + size_t testsize = fread(*out, 1, *outsize, file); + if (testsize != *outsize) { + /* It could be a directory */ + free(*out); + *out = 0; + *outsize = 0; + } + } + + assert(!(*outsize) || out); /* If size is not zero, out must be allocated. */ + fclose(file); +} + +/* +Saves a file from a memory array, overwriting the file if it existed. +*/ +static void SaveFile(const char* filename, + const unsigned char* in, size_t insize) { + FILE* file = fopen(filename, "wb" ); + assert(file); + fwrite((char*)in, 1, insize, file); + fclose(file); +} + +typedef enum { + OUTPUT_GZIP, + OUTPUT_ZLIB, + OUTPUT_DEFLATE +} OutputType; + +/* +outfilename: filename to write output to, or 0 to write to stdout instead +*/ +void CompressFile(const Options* options, + OutputType output_type, + const char* infilename, + const char* outfilename) { + unsigned char* in; + size_t insize; + unsigned char* out = 0; + size_t outsize = 0; + LoadFile(infilename, &in, &insize); + if (insize == 0) { + fprintf(stderr, "Invalid filename: %s\n", infilename); + return; + } + if (output_type == OUTPUT_GZIP) { + GzipCompress(options, in, insize, &out, &outsize); + } else if (output_type == OUTPUT_ZLIB) { + ZlibCompress(options, in, insize, &out, &outsize); + } else if (output_type == OUTPUT_DEFLATE) { + unsigned char bp = 0; + Deflate(options, 2 /* Dynamic block */, 1, in, insize, &bp, &out, &outsize); + } else { + assert(0); + } + if (outfilename) { + SaveFile(outfilename, out, outsize); + } else { + size_t i; + for (i = 0; i < outsize; i++) { + /* Works only if terminal does not convert newlines. */ + printf("%c", out[i]); + } + } + + free(out); + free(in); +} + +/* +Add two strings together. Size does not matter. Result must be freed. +*/ +static char* AddStrings(const char* str1, const char* str2) { + size_t len = strlen(str1) + strlen(str2); + char* result = (char*)malloc(len + 1); + if (!result) exit(-1); /* Allocation failed. */ + strcpy(result, str1); + strcat(result, str2); + return result; +} + +static char StringsEqual(const char* str1, const char* str2) { + return strcmp(str1, str2) == 0; +} + +int main(int argc, char* argv[]) { + Options options; + const char* filename = 0; + int output_to_stdout = 0; + int i; + OutputType output_type = OUTPUT_GZIP; + + InitOptions(&options); + + for (i = 1; i < argc; i++) { + if (StringsEqual(argv[i], "-v")) options.verbose = 1; + else if (StringsEqual(argv[i], "-c")) output_to_stdout = 1; + else if (StringsEqual(argv[i], "--deflate")) output_type = OUTPUT_DEFLATE; + else if (StringsEqual(argv[i], "--zlib")) output_type = OUTPUT_ZLIB; + else if (StringsEqual(argv[i], "--gzip")) output_type = OUTPUT_GZIP; + else if (StringsEqual(argv[i], "--i5")) options.numiterations = 5; + else if (StringsEqual(argv[i], "--i10")) options.numiterations = 10; + else if (StringsEqual(argv[i], "--i15")) options.numiterations = 15; + else if (StringsEqual(argv[i], "--i25")) options.numiterations = 25; + else if (StringsEqual(argv[i], "--i50")) options.numiterations = 50; + else if (StringsEqual(argv[i], "--i100")) options.numiterations = 100; + else if (StringsEqual(argv[i], "--i250")) options.numiterations = 250; + else if (StringsEqual(argv[i], "--i500")) options.numiterations = 500; + else if (StringsEqual(argv[i], "--i1000")) options.numiterations = 1000; + else if (StringsEqual(argv[i], "-h")) { + fprintf(stderr, "Usage: zopfli [OPTION]... FILE\n" + " -h gives this help\n" + " -c write the result on standard output, instead of disk" + " filename + '.gz'\n" + " -v verbose mode\n" + " --gzip output to gzip format (default)\n" + " --deflate output to deflate format instead of gzip\n" + " --zlib output to zlib format instead of gzip\n"); + fprintf(stderr, " --i5 less compression, but faster\n" + " --i10 less compression, but faster\n" + " --i15 default compression, 15 iterations\n" + " --i25 more compression, but slower\n" + " --i50 more compression, but slower\n" + " --i100 more compression, but slower\n" + " --i250 more compression, but slower\n" + " --i500 more compression, but slower\n" + " --i1000 more compression, but slower\n"); + return 0; + } + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + char* outfilename; + filename = argv[i]; + if (output_to_stdout) { + outfilename = 0; + } else if (output_type == OUTPUT_GZIP) { + outfilename = AddStrings(filename, ".gz"); + } else if (output_type == OUTPUT_ZLIB) { + outfilename = AddStrings(filename, ".zlib"); + } else if (output_type == OUTPUT_DEFLATE) { + outfilename = AddStrings(filename, ".deflate"); + } else { + assert(0); + } + if (options.verbose && outfilename) { + fprintf(stderr, "Saving to: %s\n", outfilename); + } + CompressFile(&options, output_type, filename, outfilename); + free(outfilename); + } + } + + if (!filename) { + fprintf(stderr, + "Please provide filename\nFor help, type: %s -h\n", argv[0]); + } + + return 0; +} |