1d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne/* 2d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneCopyright 2011 Google Inc. All Rights Reserved. 3d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 4d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneLicensed under the Apache License, Version 2.0 (the "License"); 5d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenneyou may not use this file except in compliance with the License. 6d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneYou may obtain a copy of the License at 7d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 8d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne http://www.apache.org/licenses/LICENSE-2.0 9d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 10d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneUnless required by applicable law or agreed to in writing, software 11d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennedistributed under the License is distributed on an "AS IS" BASIS, 12d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneSee the License for the specific language governing permissions and 14d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennelimitations under the License. 15d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 16d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneAuthor: lode.vandevenne@gmail.com (Lode Vandevenne) 17d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneAuthor: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne*/ 19d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 20d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne/* 21d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneZopfli compressor program. It can output gzip-, zlib- or deflate-compatible 22d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennedata. By default it creates a .gz file. This tool can only compress, not 23d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennedecompress. Decompression can be done by any standard gzip, zlib or deflate 24d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennedecompressor. 25d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne*/ 26d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 27d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include <assert.h> 28d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include <stdio.h> 29d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include <stdlib.h> 30d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include <string.h> 31d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 32d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include "deflate.h" 33d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include "gzip_container.h" 34d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne#include "zlib_container.h" 35d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 36d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne/* 37d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneLoads a file into a memory array. 38d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne*/ 39d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennestatic void LoadFile(const char* filename, 40d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne unsigned char** out, size_t* outsize) { 41d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne FILE* file; 42d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 43d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne *out = 0; 44d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne *outsize = 0; 45d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne file = fopen(filename, "rb"); 46d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (!file) return; 47d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 48d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fseek(file , 0 , SEEK_END); 49d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne *outsize = ftell(file); 50d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne rewind(file); 51d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 52d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne *out = (unsigned char*)malloc(*outsize); 53d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 54d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (*outsize && (*out)) { 55d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne size_t testsize = fread(*out, 1, *outsize, file); 56d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (testsize != *outsize) { 57d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne /* It could be a directory */ 58d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne free(*out); 59d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne *out = 0; 60d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne *outsize = 0; 61d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 62d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 63d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 64d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne assert(!(*outsize) || out); /* If size is not zero, out must be allocated. */ 65d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fclose(file); 66d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne} 67d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 68d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne/* 69d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneSaves a file from a memory array, overwriting the file if it existed. 70d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne*/ 71d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennestatic void SaveFile(const char* filename, 72d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne const unsigned char* in, size_t insize) { 73d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne FILE* file = fopen(filename, "wb" ); 74d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne assert(file); 75d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fwrite((char*)in, 1, insize, file); 76d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fclose(file); 77d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne} 78d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 79d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne/* 80d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenneoutfilename: filename to write output to, or 0 to write to stdout instead 81d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne*/ 82981df0fe897c94382b9b963eb72bc36cbc2e729cLode Vandevennestatic void CompressFile(const ZopfliOptions* options, 838c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne ZopfliFormat output_type, 84981df0fe897c94382b9b963eb72bc36cbc2e729cLode Vandevenne const char* infilename, 85981df0fe897c94382b9b963eb72bc36cbc2e729cLode Vandevenne const char* outfilename) { 86d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne unsigned char* in; 87d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne size_t insize; 88d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne unsigned char* out = 0; 89d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne size_t outsize = 0; 90d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne LoadFile(infilename, &in, &insize); 91d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (insize == 0) { 92d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fprintf(stderr, "Invalid filename: %s\n", infilename); 93d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne return; 94d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 958c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne 968c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne ZopfliCompress(options, output_type, in, insize, &out, &outsize); 978c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne 98d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (outfilename) { 99d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne SaveFile(outfilename, out, outsize); 100d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } else { 101d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne size_t i; 102d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne for (i = 0; i < outsize; i++) { 103d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne /* Works only if terminal does not convert newlines. */ 104d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne printf("%c", out[i]); 105d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 106d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 107d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 108d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne free(out); 109d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne free(in); 110d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne} 111d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 112d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne/* 113d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode VandevenneAdd two strings together. Size does not matter. Result must be freed. 114d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne*/ 115d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennestatic char* AddStrings(const char* str1, const char* str2) { 116d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne size_t len = strlen(str1) + strlen(str2); 117d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne char* result = (char*)malloc(len + 1); 118d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (!result) exit(-1); /* Allocation failed. */ 119d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne strcpy(result, str1); 120d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne strcat(result, str2); 121d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne return result; 122d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne} 123d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 124d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevennestatic char StringsEqual(const char* str1, const char* str2) { 125d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne return strcmp(str1, str2) == 0; 126d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne} 127d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 128d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenneint main(int argc, char* argv[]) { 129981df0fe897c94382b9b963eb72bc36cbc2e729cLode Vandevenne ZopfliOptions options; 1308c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne ZopfliFormat output_type = ZOPFLI_FORMAT_GZIP; 131d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne const char* filename = 0; 132d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne int output_to_stdout = 0; 133d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne int i; 134d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 135981df0fe897c94382b9b963eb72bc36cbc2e729cLode Vandevenne ZopfliInitOptions(&options); 136d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 137d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne for (i = 1; i < argc; i++) { 138806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne const char* arg = argv[i]; 139806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne if (StringsEqual(arg, "-v")) options.verbose = 1; 140806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (StringsEqual(arg, "-c")) output_to_stdout = 1; 141806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (StringsEqual(arg, "--deflate")) { 1428c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne output_type = ZOPFLI_FORMAT_DEFLATE; 1438c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne } 144806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (StringsEqual(arg, "--zlib")) output_type = ZOPFLI_FORMAT_ZLIB; 145806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (StringsEqual(arg, "--gzip")) output_type = ZOPFLI_FORMAT_GZIP; 146806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (StringsEqual(arg, "--splitlast")) options.blocksplittinglast = 1; 147806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (arg[0] == '-' && arg[1] == '-' && arg[2] == 'i' 148806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne && arg[3] >= '0' && arg[3] <= '9') { 149806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne options.numiterations = atoi(arg + 3); 150806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne } 151806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne else if (StringsEqual(arg, "-h")) { 152806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne fprintf(stderr, 153806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne "Usage: zopfli [OPTION]... FILE\n" 154d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne " -h gives this help\n" 155d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne " -c write the result on standard output, instead of disk" 156d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne " filename + '.gz'\n" 157d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne " -v verbose mode\n" 158806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " --i# perform # iterations (default 15). More gives" 159806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " more compression but is slower." 160806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " Examples: --i10, --i50, --i1000\n"); 161806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne fprintf(stderr, 162806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " --gzip output to gzip format (default)\n" 163806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " --zlib output to zlib format instead of gzip\n" 164806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " --deflate output to deflate format instead of gzip\n" 165806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne " --splitlast do block splitting last instead of first\n"); 166d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne return 0; 167d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 168d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 169d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 170806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne if (options.numiterations < 1) { 171806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne fprintf(stderr, "Error: must have 1 or more iterations"); 172806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne return 0; 173806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne } 174806be49c750347eb78f4d94bb21ad37aa9121f93Lode Vandevenne 175d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne for (i = 1; i < argc; i++) { 176d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (argv[i][0] != '-') { 177d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne char* outfilename; 178d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne filename = argv[i]; 179d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (output_to_stdout) { 180d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne outfilename = 0; 1818c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne } else if (output_type == ZOPFLI_FORMAT_GZIP) { 182d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne outfilename = AddStrings(filename, ".gz"); 1838c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne } else if (output_type == ZOPFLI_FORMAT_ZLIB) { 184d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne outfilename = AddStrings(filename, ".zlib"); 185d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } else { 1868c218eff39749e738c92bf34155099ad280c16f7Lode Vandevenne assert(output_type == ZOPFLI_FORMAT_DEFLATE); 187981df0fe897c94382b9b963eb72bc36cbc2e729cLode Vandevenne outfilename = AddStrings(filename, ".deflate"); 188d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 189d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (options.verbose && outfilename) { 190d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fprintf(stderr, "Saving to: %s\n", outfilename); 191d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 192d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne CompressFile(&options, output_type, filename, outfilename); 193d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne free(outfilename); 194d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 195d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 196d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 197d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne if (!filename) { 198d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne fprintf(stderr, 199d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne "Please provide filename\nFor help, type: %s -h\n", argv[0]); 200d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne } 201d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne 202d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne return 0; 203d5eb5f507386e9933f2d8248d311ceca41fe1df1Lode Vandevenne} 204