mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
250 lines
8.7 KiB
C++
250 lines
8.7 KiB
C++
// 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.
|
|
-h Display this help message.
|
|
--in <arg> This option takes one argument which specifies the name of the
|
|
file we want to compress/decompress.
|
|
-l <arg> Set the compression level [1-3], 3 is max compression, default
|
|
is 2.
|
|
--out <arg> This option takes one argument which specifies the name of the
|
|
output file.
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "dlib/compress_stream.h"
|
|
#include "dlib/cmd_line_parser.h"
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
|
|
// 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;
|
|
|
|
// Here I am making another typedef, this time for the version of
|
|
// cmd_line_parser I want to use. This version gives me a
|
|
// command line parser object that has all the available extensions
|
|
// for command line parsers applied to it. So I will be able to use
|
|
// its command line validation utilities as well as option printing.
|
|
typedef dlib::cmd_line_parser<char>::check_1a_c clp;
|
|
|
|
|
|
using namespace std;
|
|
using namespace dlib;
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
try
|
|
{
|
|
clp 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);
|
|
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(cout);
|
|
|
|
cout << endl;
|
|
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;
|
|
}
|
|
catch (...)
|
|
{
|
|
cout << "Some error occurred" << endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|