| // The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt | |
| /* | |
| This is an example illustrating the use of the compress_stream and | |
| cmd_line_parser components from the dlib C++ Library. | |
| This example implements a simple command line compression utility. | |
| The output from the program when the -h option is given is: | |
| Usage: compress_stream_ex (-c|-d|-l) --in input_file --out output_file | |
| Options: | |
| -c Indicates that we want to compress a file. | |
| -d Indicates that we want to decompress a file. | |
| --in <arg> This option takes one argument which specifies the name of the | |
| file we want to compress/decompress. | |
| --out <arg> This option takes one argument which specifies the name of the | |
| output file. | |
| Miscellaneous Options: | |
| -h Display this help message. | |
| -l <arg> Set the compression level [1-3], 3 is max compression, default | |
| is 2. | |
| */ | |
| // I am making a typedefs for the versions of compress_stream I want to use. | |
| typedef dlib::compress_stream::kernel_1da cs1; | |
| typedef dlib::compress_stream::kernel_1ea cs2; | |
| typedef dlib::compress_stream::kernel_1ec cs3; | |
| using namespace std; | |
| using namespace dlib; | |
| int main(int argc, char** argv) | |
| { | |
| try | |
| { | |
| command_line_parser parser; | |
| // first I will define the command line options I want. | |
| // Add a -c option and tell the parser what the option is for. | |
| parser.add_option("c","Indicates that we want to compress a file."); | |
| parser.add_option("d","Indicates that we want to decompress a file."); | |
| // add a --in option that takes 1 argument | |
| parser.add_option("in","This option takes one argument which specifies the name of the file we want to compress/decompress.",1); | |
| // add a --out option that takes 1 argument | |
| parser.add_option("out","This option takes one argument which specifies the name of the output file.",1); | |
| // In the code below, we use the parser.print_options() method to print all our | |
| // options to the screen. We can tell it that we would like some options to be | |
| // grouped together by calling set_group_name() before adding those options. In | |
| // general, you can make as many groups as you like by calling set_group_name(). | |
| // However, here we make only one named group. | |
| parser.set_group_name("Miscellaneous Options"); | |
| parser.add_option("h","Display this help message."); | |
| parser.add_option("l","Set the compression level [1-3], 3 is max compression, default is 2.",1); | |
| // now I will parse the command line | |
| parser.parse(argc,argv); | |
| // Now I will use the parser to validate some things about the command line. | |
| // If any of the following checks fail then an exception will be thrown and it will | |
| // contain a message that tells the user what the problem was. | |
| // First I want to check that none of the options were given on the command line | |
| // more than once. To do this I define an array that contains the options | |
| // that shouldn't appear more than once and then I just call check_one_time_options() | |
| const char* one_time_opts[] = {"c", "d", "in", "out", "h", "l"}; | |
| parser.check_one_time_options(one_time_opts); | |
| // Here I'm checking that the user didn't pick both the c and d options at the | |
| // same time. | |
| parser.check_incompatible_options("c", "d"); | |
| // Here I'm checking that the argument to the l option is an integer in the range 1 to 3. | |
| // That is, it should be convertible to an int by dlib::string_assign and be either | |
| // 1, 2, or 3. Note that if you wanted to allow floating point values in the range 1 to | |
| // 3 then you could give a range 1.0 to 3.0 or explicitly supply a type of float or double | |
| // to the template argument of the check_option_arg_range() function. | |
| parser.check_option_arg_range("l", 1, 3); | |
| // The 'l' option is a sub-option of the 'c' option. That is, you can only select the | |
| // compression level when compressing. This command below checks that the listed | |
| // sub options are always given in the presence of their parent options. | |
| const char* c_sub_opts[] = {"l"}; | |
| parser.check_sub_options("c", c_sub_opts); | |
| // check if the -h option was given on the command line | |
| if (parser.option("h")) | |
| { | |
| // display all the command line options | |
| cout << "Usage: compress_stream_ex (-c|-d|-l) --in input_file --out output_file\n"; | |
| // This function prints out a nicely formatted list of | |
| // all the options the parser has | |
| parser.print_options(); | |
| return 0; | |
| } | |
| // Figure out what the compression level should be. If the user didn't supply | |
| // this command line option then a value of 2 will be used. | |
| int compression_level = get_option(parser,"l",2); | |
| // make sure one of the c or d options was given | |
| if (!parser.option("c") && !parser.option("d")) | |
| { | |
| cout << "Error in command line:\n You must specify either the c option or the d option.\n"; | |
| cout << "\nTry the -h option for more information." << endl; | |
| return 0; | |
| } | |
| string in_file; | |
| string out_file; | |
| // check if the user told us the input file and if they did then | |
| // get the file name | |
| if (parser.option("in")) | |
| { | |
| in_file = parser.option("in").argument(); | |
| } | |
| else | |
| { | |
| cout << "Error in command line:\n You must specify an input file.\n"; | |
| cout << "\nTry the -h option for more information." << endl; | |
| return 0; | |
| } | |
| // check if the user told us the output file and if they did then | |
| // get the file name | |
| if (parser.option("out")) | |
| { | |
| out_file = parser.option("out").argument(); | |
| } | |
| else | |
| { | |
| cout << "Error in command line:\n You must specify an output file.\n"; | |
| cout << "\nTry the -h option for more information." << endl; | |
| return 0; | |
| } | |
| // open the files we will be reading from and writing to | |
| ifstream fin(in_file.c_str(),ios::binary); | |
| ofstream fout(out_file.c_str(),ios::binary); | |
| // make sure the files opened correctly | |
| if (!fin) | |
| { | |
| cout << "Error opening file " << in_file << ".\n"; | |
| return 0; | |
| } | |
| if (!fout) | |
| { | |
| cout << "Error creating file " << out_file << ".\n"; | |
| return 0; | |
| } | |
| // now perform the actual compression or decompression. | |
| if (parser.option("c")) | |
| { | |
| // save the compression level to the output file | |
| serialize(compression_level, fout); | |
| switch (compression_level) | |
| { | |
| case 1: | |
| { | |
| cs1 compressor; | |
| compressor.compress(fin,fout); | |
| }break; | |
| case 2: | |
| { | |
| cs2 compressor; | |
| compressor.compress(fin,fout); | |
| }break; | |
| case 3: | |
| { | |
| cs3 compressor; | |
| compressor.compress(fin,fout); | |
| }break; | |
| } | |
| } | |
| else | |
| { | |
| // obtain the compression level from the input file | |
| deserialize(compression_level, fin); | |
| switch (compression_level) | |
| { | |
| case 1: | |
| { | |
| cs1 compressor; | |
| compressor.decompress(fin,fout); | |
| }break; | |
| case 2: | |
| { | |
| cs2 compressor; | |
| compressor.decompress(fin,fout); | |
| }break; | |
| case 3: | |
| { | |
| cs3 compressor; | |
| compressor.decompress(fin,fout); | |
| }break; | |
| default: | |
| { | |
| cout << "Error in compressed file, invalid compression level" << endl; | |
| }break; | |
| } | |
| } | |
| } | |
| catch (exception& e) | |
| { | |
| // Note that this will catch any cmd_line_parse_error exceptions and print | |
| // the default message. | |
| cout << e.what() << endl; | |
| } | |
| } | |