1 /* 2 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <getopt.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 #include <File.h> 16 17 #include <package/hpkg/HPKGDefs.h> 18 #include <package/hpkg/PackageReader.h> 19 #include <package/hpkg/PackageWriter.h> 20 21 #include <DataPositionIOWrapper.h> 22 #include <FdIO.h> 23 24 #include "package.h" 25 #include "PackageWriterListener.h" 26 27 28 using BPackageKit::BHPKG::BPackageReader; 29 using BPackageKit::BHPKG::BPackageWriter; 30 using BPackageKit::BHPKG::BPackageWriterListener; 31 using BPackageKit::BHPKG::BPackageWriterParameters; 32 33 34 static BPositionIO* 35 create_stdio(bool isInput) 36 { 37 BFdIO* dataIO = new BFdIO(isInput ? 0 : 1, false); 38 return new BDataPositionIOWrapper(dataIO); 39 } 40 41 42 int 43 command_recompress(int argc, const char* const* argv) 44 { 45 bool quiet = false; 46 bool verbose = false; 47 int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST; 48 int32 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZLIB; 49 50 while (true) { 51 static struct option sLongOptions[] = { 52 { "help", no_argument, 0, 'h' }, 53 { "quiet", no_argument, 0, 'q' }, 54 { "verbose", no_argument, 0, 'v' }, 55 { 0, 0, 0, 0 } 56 }; 57 58 opterr = 0; // don't print errors 59 int c = getopt_long(argc, (char**)argv, "+0123456789:hqvz", 60 sLongOptions, NULL); 61 if (c == -1) 62 break; 63 64 switch (c) { 65 case '0': 66 case '1': 67 case '2': 68 case '3': 69 case '4': 70 case '5': 71 case '6': 72 case '7': 73 case '8': 74 case '9': 75 compressionLevel = c - '0'; 76 break; 77 78 case 'h': 79 print_usage_and_exit(false); 80 break; 81 82 case 'q': 83 quiet = true; 84 break; 85 86 case 'v': 87 verbose = true; 88 break; 89 90 case 'z': 91 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZSTD; 92 break; 93 94 default: 95 print_usage_and_exit(true); 96 break; 97 } 98 } 99 100 // The remaining arguments are the input package file and the output 101 // package file, i.e. two more arguments. 102 if (argc - optind != 2) 103 print_usage_and_exit(true); 104 105 const char* inputPackageFileName = argv[optind++]; 106 const char* outputPackageFileName = argv[optind++]; 107 108 // open the input package 109 status_t error = B_OK; 110 BPositionIO* inputFile; 111 if (strcmp(inputPackageFileName, "-") == 0) { 112 inputFile = create_stdio(true); 113 } else { 114 BFile* inputFileFile = new BFile; 115 error = inputFileFile->SetTo(inputPackageFileName, O_RDONLY); 116 if (error != B_OK) { 117 fprintf(stderr, "Error: Failed to open input file \"%s\": %s\n", 118 inputPackageFileName, strerror(error)); 119 return 1; 120 } 121 inputFile = inputFileFile; 122 } 123 124 // write the output package 125 BPackageWriterParameters writerParameters; 126 writerParameters.SetCompressionLevel(compressionLevel); 127 if (compressionLevel == 0) { 128 writerParameters.SetCompression( 129 BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE); 130 } 131 132 if (compressionLevel == 0) 133 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE; 134 writerParameters.SetCompression(compression); 135 136 PackageWriterListener listener(verbose, quiet); 137 BPackageWriter packageWriter(&listener); 138 if (strcmp(outputPackageFileName, "-") == 0) { 139 if (compressionLevel != 0) { 140 fprintf(stderr, "Error: Writing to stdout is supported only with " 141 "compression level 0.\n"); 142 return 1; 143 } 144 145 error = packageWriter.Init(create_stdio(false), true, 146 &writerParameters); 147 } else 148 error = packageWriter.Init(outputPackageFileName, &writerParameters); 149 if (error != B_OK) 150 return 1; 151 152 error = packageWriter.Recompress(inputFile); 153 if (error != B_OK) 154 return 1; 155 156 if (verbose) 157 printf("\nsuccessfully wrote package '%s'\n", outputPackageFileName); 158 159 return 0; 160 } 161