xref: /netbsd-src/external/zlib/pigz/dist/zopfli/zopfli_bin.c (revision 9fd8799cb5ceb66c69f2eb1a6d26a1d587ba1f1e)
1 /*
2 Copyright 2011 Google Inc. All Rights Reserved.
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8     http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 Author: lode.vandevenne@gmail.com (Lode Vandevenne)
17 Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
18 */
19 
20 /*
21 Zopfli compressor program. It can output gzip-, zlib- or deflate-compatible
22 data. By default it creates a .gz file. This tool can only compress, not
23 decompress. Decompression can be done by any standard gzip, zlib or deflate
24 decompressor.
25 */
26 
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "deflate.h"
33 #include "gzip_container.h"
34 #include "zlib_container.h"
35 
36 /*
37 Loads a file into a memory array.
38 */
39 static void LoadFile(const char* filename,
40                      unsigned char** out, size_t* outsize) {
41   FILE* file;
42 
43   *out = 0;
44   *outsize = 0;
45   file = fopen(filename, "rb");
46   if (!file) return;
47 
48   fseek(file , 0 , SEEK_END);
49   *outsize = ftell(file);
50   rewind(file);
51 
52   *out = (unsigned char*)malloc(*outsize);
53 
54   if (*outsize && (*out)) {
55     size_t testsize = fread(*out, 1, *outsize, file);
56     if (testsize != *outsize) {
57       /* It could be a directory */
58       free(*out);
59       *out = 0;
60       *outsize = 0;
61     }
62   }
63 
64   assert(!(*outsize) || out);  /* If size is not zero, out must be allocated. */
65   fclose(file);
66 }
67 
68 /*
69 Saves a file from a memory array, overwriting the file if it existed.
70 */
71 static void SaveFile(const char* filename,
72                      const unsigned char* in, size_t insize) {
73   FILE* file = fopen(filename, "wb" );
74   assert(file);
75   fwrite((char*)in, 1, insize, file);
76   fclose(file);
77 }
78 
79 /*
80 outfilename: filename to write output to, or 0 to write to stdout instead
81 */
82 static void CompressFile(const ZopfliOptions* options,
83                          ZopfliFormat output_type,
84                          const char* infilename,
85                          const char* outfilename) {
86   unsigned char* in;
87   size_t insize;
88   unsigned char* out = 0;
89   size_t outsize = 0;
90   LoadFile(infilename, &in, &insize);
91   if (insize == 0) {
92     fprintf(stderr, "Invalid filename: %s\n", infilename);
93     return;
94   }
95 
96   ZopfliCompress(options, output_type, in, insize, &out, &outsize);
97 
98   if (outfilename) {
99     SaveFile(outfilename, out, outsize);
100   } else {
101     size_t i;
102     for (i = 0; i < outsize; i++) {
103       /* Works only if terminal does not convert newlines. */
104       printf("%c", out[i]);
105     }
106   }
107 
108   free(out);
109   free(in);
110 }
111 
112 /*
113 Add two strings together. Size does not matter. Result must be freed.
114 */
115 static char* AddStrings(const char* str1, const char* str2) {
116   size_t len = strlen(str1) + strlen(str2);
117   char* result = (char*)malloc(len + 1);
118   if (!result) exit(-1); /* Allocation failed. */
119   strcpy(result, str1);
120   strcat(result, str2);
121   return result;
122 }
123 
124 static char StringsEqual(const char* str1, const char* str2) {
125   return strcmp(str1, str2) == 0;
126 }
127 
128 int main(int argc, char* argv[]) {
129   ZopfliOptions options;
130   ZopfliFormat output_type = ZOPFLI_FORMAT_GZIP;
131   const char* filename = 0;
132   int output_to_stdout = 0;
133   int i;
134 
135   ZopfliInitOptions(&options);
136 
137   for (i = 1; i < argc; i++) {
138     if (StringsEqual(argv[i], "-v")) options.verbose = 1;
139     else if (StringsEqual(argv[i], "-c")) output_to_stdout = 1;
140     else if (StringsEqual(argv[i], "--deflate")) {
141       output_type = ZOPFLI_FORMAT_DEFLATE;
142     }
143     else if (StringsEqual(argv[i], "--zlib")) output_type = ZOPFLI_FORMAT_ZLIB;
144     else if (StringsEqual(argv[i], "--gzip")) output_type = ZOPFLI_FORMAT_GZIP;
145     else if (StringsEqual(argv[i], "--i5")) options.numiterations = 5;
146     else if (StringsEqual(argv[i], "--i10")) options.numiterations = 10;
147     else if (StringsEqual(argv[i], "--i15")) options.numiterations = 15;
148     else if (StringsEqual(argv[i], "--i25")) options.numiterations = 25;
149     else if (StringsEqual(argv[i], "--i50")) options.numiterations = 50;
150     else if (StringsEqual(argv[i], "--i100")) options.numiterations = 100;
151     else if (StringsEqual(argv[i], "--i250")) options.numiterations = 250;
152     else if (StringsEqual(argv[i], "--i500")) options.numiterations = 500;
153     else if (StringsEqual(argv[i], "--i1000")) options.numiterations = 1000;
154     else if (StringsEqual(argv[i], "-h")) {
155       fprintf(stderr, "Usage: zopfli [OPTION]... FILE\n"
156           "  -h    gives this help\n"
157           "  -c    write the result on standard output, instead of disk"
158           " filename + '.gz'\n"
159           "  -v    verbose mode\n"
160           "  --gzip  output to gzip format (default)\n"
161           "  --deflate  output to deflate format instead of gzip\n"
162           "  --zlib  output to zlib format instead of gzip\n");
163       fprintf(stderr, "  --i5  less compression, but faster\n"
164           "  --i10  less compression, but faster\n"
165           "  --i15  default compression, 15 iterations\n"
166           "  --i25  more compression, but slower\n"
167           "  --i50  more compression, but slower\n"
168           "  --i100  more compression, but slower\n"
169           "  --i250  more compression, but slower\n"
170           "  --i500  more compression, but slower\n"
171           "  --i1000  more compression, but slower\n");
172       return 0;
173     }
174   }
175 
176   for (i = 1; i < argc; i++) {
177     if (argv[i][0] != '-') {
178       char* outfilename;
179       filename = argv[i];
180       if (output_to_stdout) {
181         outfilename = 0;
182       } else if (output_type == ZOPFLI_FORMAT_GZIP) {
183         outfilename = AddStrings(filename, ".gz");
184       } else if (output_type == ZOPFLI_FORMAT_ZLIB) {
185         outfilename = AddStrings(filename, ".zlib");
186       } else {
187         assert(output_type == ZOPFLI_FORMAT_DEFLATE);
188         outfilename = AddStrings(filename, ".deflate");
189       }
190       if (options.verbose && outfilename) {
191         fprintf(stderr, "Saving to: %s\n", outfilename);
192       }
193       CompressFile(&options, output_type, filename, outfilename);
194       free(outfilename);
195     }
196   }
197 
198   if (!filename) {
199     fprintf(stderr,
200             "Please provide filename\nFor help, type: %s -h\n", argv[0]);
201   }
202 
203   return 0;
204 }
205