| OLD | NEW |
| (Empty) | |
| 1 /* Copyright 2014 Google Inc. All Rights Reserved. |
| 2 |
| 3 Distributed under MIT license. |
| 4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT |
| 5 */ |
| 6 |
| 7 /* Example main() function for Brotli library. */ |
| 8 |
| 9 #include <fcntl.h> |
| 10 #include <stdio.h> |
| 11 #include <sys/stat.h> |
| 12 #include <sys/types.h> |
| 13 |
| 14 #include <cstdlib> |
| 15 #include <cstring> |
| 16 #include <ctime> |
| 17 #include <string> |
| 18 |
| 19 #include "../dec/decode.h" |
| 20 #include "../enc/compressor.h" |
| 21 |
| 22 #if !defined(_WIN32) |
| 23 #include <unistd.h> |
| 24 #else |
| 25 #include <io.h> |
| 26 |
| 27 #define STDIN_FILENO _fileno(stdin) |
| 28 #define STDOUT_FILENO _fileno(stdout) |
| 29 #define S_IRUSR S_IREAD |
| 30 #define S_IWUSR S_IWRITE |
| 31 #define fdopen _fdopen |
| 32 #define unlink _unlink |
| 33 |
| 34 #define fopen ms_fopen |
| 35 #define open ms_open |
| 36 |
| 37 #if defined(_MSC_VER) && (_MSC_VER >= 1400) |
| 38 #define fseek _fseeki64 |
| 39 #define ftell _ftelli64 |
| 40 #endif |
| 41 |
| 42 static inline FILE* ms_fopen(const char *filename, const char *mode) { |
| 43 FILE* result = 0; |
| 44 fopen_s(&result, filename, mode); |
| 45 return result; |
| 46 } |
| 47 |
| 48 static inline int ms_open(const char *filename, int oflag, int pmode) { |
| 49 int result = -1; |
| 50 _sopen_s(&result, filename, oflag | O_BINARY, _SH_DENYNO, pmode); |
| 51 return result; |
| 52 } |
| 53 #endif /* WIN32 */ |
| 54 |
| 55 |
| 56 static bool ParseQuality(const char* s, int* quality) { |
| 57 if (s[0] >= '0' && s[0] <= '9') { |
| 58 *quality = s[0] - '0'; |
| 59 if (s[1] >= '0' && s[1] <= '9') { |
| 60 *quality = *quality * 10 + s[1] - '0'; |
| 61 return s[2] == 0; |
| 62 } |
| 63 return s[1] == 0; |
| 64 } |
| 65 return false; |
| 66 } |
| 67 |
| 68 static void ParseArgv(int argc, char **argv, |
| 69 char **input_path, |
| 70 char **output_path, |
| 71 int *force, |
| 72 int *quality, |
| 73 int *decompress, |
| 74 int *repeat, |
| 75 int *verbose, |
| 76 int *lgwin) { |
| 77 *force = 0; |
| 78 *input_path = 0; |
| 79 *output_path = 0; |
| 80 *repeat = 1; |
| 81 *verbose = 0; |
| 82 *lgwin = 22; |
| 83 { |
| 84 size_t argv0_len = strlen(argv[0]); |
| 85 *decompress = |
| 86 argv0_len >= 5 && strcmp(&argv[0][argv0_len - 5], "unbro") == 0; |
| 87 } |
| 88 for (int k = 1; k < argc; ++k) { |
| 89 if (!strcmp("--force", argv[k]) || |
| 90 !strcmp("-f", argv[k])) { |
| 91 if (*force != 0) { |
| 92 goto error; |
| 93 } |
| 94 *force = 1; |
| 95 continue; |
| 96 } else if (!strcmp("--decompress", argv[k]) || |
| 97 !strcmp("--uncompress", argv[k]) || |
| 98 !strcmp("-d", argv[k])) { |
| 99 *decompress = 1; |
| 100 continue; |
| 101 } else if (!strcmp("--verbose", argv[k]) || |
| 102 !strcmp("-v", argv[k])) { |
| 103 if (*verbose != 0) { |
| 104 goto error; |
| 105 } |
| 106 *verbose = 1; |
| 107 continue; |
| 108 } |
| 109 if (k < argc - 1) { |
| 110 if (!strcmp("--input", argv[k]) || |
| 111 !strcmp("--in", argv[k]) || |
| 112 !strcmp("-i", argv[k])) { |
| 113 if (*input_path != 0) { |
| 114 goto error; |
| 115 } |
| 116 *input_path = argv[k + 1]; |
| 117 ++k; |
| 118 continue; |
| 119 } else if (!strcmp("--output", argv[k]) || |
| 120 !strcmp("--out", argv[k]) || |
| 121 !strcmp("-o", argv[k])) { |
| 122 if (*output_path != 0) { |
| 123 goto error; |
| 124 } |
| 125 *output_path = argv[k + 1]; |
| 126 ++k; |
| 127 continue; |
| 128 } else if (!strcmp("--quality", argv[k]) || |
| 129 !strcmp("-q", argv[k])) { |
| 130 if (!ParseQuality(argv[k + 1], quality)) { |
| 131 goto error; |
| 132 } |
| 133 ++k; |
| 134 continue; |
| 135 } else if (!strcmp("--repeat", argv[k]) || |
| 136 !strcmp("-r", argv[k])) { |
| 137 if (!ParseQuality(argv[k + 1], repeat)) { |
| 138 goto error; |
| 139 } |
| 140 ++k; |
| 141 continue; |
| 142 } else if (!strcmp("--window", argv[k]) || |
| 143 !strcmp("-w", argv[k])) { |
| 144 if (!ParseQuality(argv[k + 1], lgwin)) { |
| 145 goto error; |
| 146 } |
| 147 if (*lgwin < 10 || *lgwin >= 25) { |
| 148 goto error; |
| 149 } |
| 150 ++k; |
| 151 continue; |
| 152 } |
| 153 } |
| 154 goto error; |
| 155 } |
| 156 return; |
| 157 error: |
| 158 fprintf(stderr, |
| 159 "Usage: %s [--force] [--quality n] [--decompress]" |
| 160 " [--input filename] [--output filename] [--repeat iters]" |
| 161 " [--verbose] [--window n]\n", |
| 162 argv[0]); |
| 163 exit(1); |
| 164 } |
| 165 |
| 166 static FILE* OpenInputFile(const char* input_path) { |
| 167 if (input_path == 0) { |
| 168 return fdopen(STDIN_FILENO, "rb"); |
| 169 } |
| 170 FILE* f = fopen(input_path, "rb"); |
| 171 if (f == 0) { |
| 172 perror("fopen"); |
| 173 exit(1); |
| 174 } |
| 175 return f; |
| 176 } |
| 177 |
| 178 static FILE *OpenOutputFile(const char *output_path, const int force) { |
| 179 if (output_path == 0) { |
| 180 return fdopen(STDOUT_FILENO, "wb"); |
| 181 } |
| 182 int excl = force ? 0 : O_EXCL; |
| 183 int fd = open(output_path, O_CREAT | excl | O_WRONLY | O_TRUNC, |
| 184 S_IRUSR | S_IWUSR); |
| 185 if (fd < 0) { |
| 186 if (!force) { |
| 187 struct stat statbuf; |
| 188 if (stat(output_path, &statbuf) == 0) { |
| 189 fprintf(stderr, "output file exists\n"); |
| 190 exit(1); |
| 191 } |
| 192 } |
| 193 perror("open"); |
| 194 exit(1); |
| 195 } |
| 196 return fdopen(fd, "wb"); |
| 197 } |
| 198 |
| 199 static int64_t FileSize(char *path) { |
| 200 FILE *f = fopen(path, "rb"); |
| 201 if (f == NULL) { |
| 202 return -1; |
| 203 } |
| 204 if (fseek(f, 0L, SEEK_END) != 0) { |
| 205 fclose(f); |
| 206 return -1; |
| 207 } |
| 208 int64_t retval = ftell(f); |
| 209 if (fclose(f) != 0) { |
| 210 return -1; |
| 211 } |
| 212 return retval; |
| 213 } |
| 214 |
| 215 static const size_t kFileBufferSize = 65536; |
| 216 |
| 217 static void Decompresss(FILE* fin, FILE* fout) { |
| 218 BrotliState* s = BrotliCreateState(NULL, NULL, NULL); |
| 219 if (!s) { |
| 220 fprintf(stderr, "out of memory\n"); |
| 221 exit(1); |
| 222 } |
| 223 uint8_t* input = new uint8_t[kFileBufferSize]; |
| 224 uint8_t* output = new uint8_t[kFileBufferSize]; |
| 225 size_t total_out; |
| 226 size_t available_in; |
| 227 const uint8_t* next_in; |
| 228 size_t available_out = kFileBufferSize; |
| 229 uint8_t* next_out = output; |
| 230 BrotliResult result = BROTLI_RESULT_NEEDS_MORE_INPUT; |
| 231 while (1) { |
| 232 if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) { |
| 233 if (feof(fin)) { |
| 234 break; |
| 235 } |
| 236 available_in = fread(input, 1, kFileBufferSize, fin); |
| 237 next_in = input; |
| 238 if (ferror(fin)) { |
| 239 break; |
| 240 } |
| 241 } else if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) { |
| 242 fwrite(output, 1, kFileBufferSize, fout); |
| 243 if (ferror(fout)) { |
| 244 break; |
| 245 } |
| 246 available_out = kFileBufferSize; |
| 247 next_out = output; |
| 248 } else { |
| 249 break; /* Error or success. */ |
| 250 } |
| 251 result = BrotliDecompressStream(&available_in, &next_in, |
| 252 &available_out, &next_out, &total_out, s); |
| 253 } |
| 254 if (next_out != output) { |
| 255 fwrite(output, 1, static_cast<size_t>(next_out - output), fout); |
| 256 } |
| 257 delete[] input; |
| 258 delete[] output; |
| 259 BrotliDestroyState(s); |
| 260 if ((result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) || ferror(fout)) { |
| 261 fprintf(stderr, "failed to write output\n"); |
| 262 exit(1); |
| 263 } else if (result != BROTLI_RESULT_SUCCESS) { /* Error or needs more input. */ |
| 264 fprintf(stderr, "corrupt input\n"); |
| 265 exit(1); |
| 266 } |
| 267 } |
| 268 |
| 269 int main(int argc, char** argv) { |
| 270 char *input_path = 0; |
| 271 char *output_path = 0; |
| 272 int force = 0; |
| 273 int quality = 11; |
| 274 int decompress = 0; |
| 275 int repeat = 1; |
| 276 int verbose = 0; |
| 277 int lgwin = 0; |
| 278 ParseArgv(argc, argv, &input_path, &output_path, &force, |
| 279 &quality, &decompress, &repeat, &verbose, &lgwin); |
| 280 const clock_t clock_start = clock(); |
| 281 for (int i = 0; i < repeat; ++i) { |
| 282 FILE* fin = OpenInputFile(input_path); |
| 283 FILE* fout = OpenOutputFile(output_path, force); |
| 284 if (decompress) { |
| 285 Decompresss(fin, fout); |
| 286 } else { |
| 287 brotli::BrotliParams params; |
| 288 params.lgwin = lgwin; |
| 289 params.quality = quality; |
| 290 try { |
| 291 brotli::BrotliFileIn in(fin, 1 << 16); |
| 292 brotli::BrotliFileOut out(fout); |
| 293 if (!BrotliCompress(params, &in, &out)) { |
| 294 fprintf(stderr, "compression failed\n"); |
| 295 unlink(output_path); |
| 296 exit(1); |
| 297 } |
| 298 } catch (std::bad_alloc&) { |
| 299 fprintf(stderr, "not enough memory\n"); |
| 300 unlink(output_path); |
| 301 exit(1); |
| 302 } |
| 303 } |
| 304 if (fclose(fin) != 0) { |
| 305 perror("fclose"); |
| 306 exit(1); |
| 307 } |
| 308 if (fclose(fout) != 0) { |
| 309 perror("fclose"); |
| 310 exit(1); |
| 311 } |
| 312 } |
| 313 if (verbose) { |
| 314 const clock_t clock_end = clock(); |
| 315 double duration = |
| 316 static_cast<double>(clock_end - clock_start) / CLOCKS_PER_SEC; |
| 317 if (duration < 1e-9) { |
| 318 duration = 1e-9; |
| 319 } |
| 320 int64_t uncompressed_size = FileSize(decompress ? output_path : input_path); |
| 321 if (uncompressed_size == -1) { |
| 322 fprintf(stderr, "failed to determine uncompressed file size\n"); |
| 323 exit(1); |
| 324 } |
| 325 double uncompressed_bytes_in_MB = |
| 326 static_cast<double>(repeat * uncompressed_size) / (1024.0 * 1024.0); |
| 327 if (decompress) { |
| 328 printf("Brotli decompression speed: "); |
| 329 } else { |
| 330 printf("Brotli compression speed: "); |
| 331 } |
| 332 printf("%g MB/s\n", uncompressed_bytes_in_MB / duration); |
| 333 } |
| 334 return 0; |
| 335 } |
| OLD | NEW |