00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00026 #include <cstdio>
00027 #include <fstream>
00028
00029
00030 #include "defs.h"
00031 #include "encodings.h"
00032 #include "exaltcodec.h"
00033 #include "list.h"
00034 #include "options.h"
00035
00036
00038 #define PRINT_VERSION \
00039 { \
00040 OUTPUTNL("This is " << PACKAGE \
00041 << ", XML data compressor."); \
00042 OUTPUTNL("Version " << VERSION << ", build date: " \
00043 << __DATE__); \
00044 OUTPUTNL("Built against expat " << EXPAT_VERSION); \
00045 OUTPUTNL("Copyright 2002 Vojtech Toman"); \
00046 }
00047
00048
00054 #define OPT(_x_) !strcmp(argv[i], (_x_))
00055
00056
00057
00063 #define OPT_ERROR(_i_) \
00064 { \
00065 ERR("'" << argv[_i_-1] << "' requires an argument"); \
00066 throw ExaltOptionException(); \
00067 }
00068
00069
00070
00076 #define OPT_UNKNOWN(_opt_) \
00077 { \
00078 ERR("Unknown option: '" << _opt_ << "'."); \
00079 throw ExaltOptionException(); \
00080 }
00081
00082
00083
00087 #define OPT_NONE \
00088 { \
00089 ERR("No input files specified."); \
00090 throw ExaltOptionException(); \
00091 }
00092
00093
00094
00100 #define ENCODING_UNKNOWN(_name_) \
00101 { \
00102 ERR("Unknown encoding: '" << _name_ << "'."); \
00103 throw ExaltUnknownEncodingException(); \
00104 }
00105
00106
00107
00113 #define SET_OUTPUT_ENCODING(_enc_) \
00114 { \
00115 size_t j = 0; \
00116 Encodings::MIB mib = Encodings::Unknown; \
00117 \
00118 while (encodingNames[j].name) \
00119 { \
00120 if (!strcmp(_enc_, encodingNames[j].name)) \
00121 mib = encodingNames[j].mib; \
00122 j++; \
00123 } \
00124 if (mib != Encodings::Unknown) \
00125 encodingMIB = mib; \
00126 else \
00127 { \
00128 ENCODING_UNKNOWN(_enc_); \
00129 } \
00130 }
00131
00132
00133
00139 #define ENCODE_DECODE(_action_) \
00140 { \
00141 bool canContinue = true; \
00142 \
00143 if (fileName) \
00144 { \
00145 ifstream inFile(fileName); \
00146 \
00147 if (inFile) \
00148 inFile.close(); \
00149 else \
00150 { \
00151 ERR("'" << fileName << "' doesn't exist!"); \
00152 canContinue = false; \
00153 } \
00154 } \
00155 \
00156 if (!useStdout && canContinue) \
00157 { \
00158 if (outputFileNameLength != -1) \
00159 { \
00160 ifstream outFile(outputFileName); \
00161 \
00162 if (outFile && !force) \
00163 { \
00164 char c; \
00165 outFile.close(); \
00166 \
00167 OUTPUTE("File '" << outputFileName \
00168 << "' exists. Overwrite (y or n)? "); \
00169 \
00170 do { c = getchar(); } while (c == '\n'); \
00171 \
00172 canContinue = (c == 'y' || c == 'Y'); \
00173 \
00174 if (!canContinue && verbose) \
00175 OUTPUTENL("Not overwritten."); \
00176 } \
00177 } \
00178 } \
00179 \
00180 if (canContinue && outputFileNameLength != -1) \
00181 { \
00182 if (exaltCodec._action_(fileName, outputFileName)) \
00183 { \
00184 if (erase && fileName) \
00185 remove(fileName); \
00186 } \
00187 else \
00188 throw ExaltIOException(); \
00189 } \
00190 }
00191
00192
00193
00201 static int testFileNameSuffix(const char *str, const char *suf)
00202 {
00203 int i = strlen(str)-1;
00204 int j = strlen(suf)-1;
00205
00206 while (j > -1)
00207 {
00208 if (str[i] != suf[j])
00209 return -1;
00210
00211 i--;
00212 j--;
00213 }
00214
00215 return i+1;
00216 }
00217
00218
00219
00220
00224 static void usage(void)
00225 {
00226 OUTPUTNL("Usage: " << PACKAGE << " [options and files in any order]");
00227 OUTPUTNL("where options are:");
00228 OUTPUTENDLINE;
00229 OUTPUTNL(" -s|--suffix .suf use suffix .suf on compressed files");
00230 OUTPUTNL(" -d|--decompress decompress");
00231 OUTPUTNL(" -f|--force overwrite files, don't stop on errors");
00232 OUTPUTNL(" -c|--stdout write on standard output");
00233 OUTPUTNL(" -a|--adaptive use the adaptive model");
00234 OUTPUTNL(" -x|--erase erase source files after (de)compression");
00235 OUTPUTNL(" -e|--encoding enc set decompressed output encoding (to be implemented)");
00236 OUTPUTNL(" -l|--list-encodings list recognized encodings");
00237 OUTPUTNL(" -v|--verbose be verbose");
00238 OUTPUTNL(" -m|--print-models display the models of the elements (requires the adaptive model)");
00239 OUTPUTNL(" (warning: the models may be huge!)");
00240 OUTPUTNL(" -g|--print-grammar display the content of the resulting grammar");
00241 OUTPUTNL(" (warning: the grammar may be huge!)");
00242 OUTPUTNL(" -V|--version display version number");
00243 OUTPUTNL(" -L|--license display version number and software license");
00244 OUTPUTNL(" -h|--help show this help");
00245
00246 OUTPUTENDLINE;
00247 OUTPUTNL("The default action is to compress. If no file names are given,");
00248 OUTPUTNL("or if a file name is '-', " << PACKAGE << " compresses or decompresses");
00249 OUTPUTNL("from standard input to standard output.");
00250
00251 }
00252
00253
00254
00258
00259
00260
00271 int main(int argc, char **argv)
00272 {
00273
00274 UserAction selectedAction = Compress;
00275 char *outputFileSuffix = 0;
00276 bool force = false;
00277 bool verbose = false;
00278 bool printGrammar = false;
00279 bool printModels = false;
00280 bool useStdout = false;
00281 bool adaptiveModel = false;
00282 bool erase = false;
00283
00284
00285 Encodings::EncodingName encodingNames[] = { ENCODING_NAMES };
00286
00287
00288 Encodings::MIB encodingMIB = DEFAULT_OUTPUT_ENCODING;
00289
00290
00291 List<char> unrecognizedParamList;
00292 List<char> filesToProcess;
00293
00294 ExaltOptions::resetOptions();
00295
00296 try
00297 {
00298 for (int i = 1; i < argc; ++i)
00299 {
00300 if (OPT("--suffix") || OPT("-s"))
00301 {
00302
00303 if ((++i) >= argc)
00304 OPT_ERROR(i);
00305
00306 outputFileSuffix = argv[i];
00307 }
00308
00309 else if (OPT("--force") || OPT("-f"))
00310 {
00311
00312 force = true;
00313 }
00314
00315 else if (OPT("--verbose") || OPT("-v"))
00316 {
00317 verbose = true;
00318 }
00319
00320 else if (OPT("--print-models") || OPT("-m"))
00321 {
00322 printModels = true;
00323 }
00324
00325 else if (OPT("--print-grammar") || OPT("-g"))
00326 {
00327 printGrammar = true;
00328 }
00329
00330 else if (OPT("--stdout") || OPT("-c"))
00331 {
00332 useStdout = true;
00333 }
00334
00335 else if (OPT("--decompress") || OPT("-d"))
00336 {
00337 selectedAction = Decompress;
00338 }
00339
00340 else if (OPT("--adaptive") || OPT("-a"))
00341 {
00342 adaptiveModel = true;
00343 }
00344
00345 else if (OPT("--encoding") || OPT("-e"))
00346 {
00347
00348 if ((++i) >= argc)
00349 OPT_ERROR(i);
00350
00351 SET_OUTPUT_ENCODING(argv[i]);
00352 }
00353
00354 else if (OPT("--list-encodings") || OPT("-l"))
00355 {
00356 OUTPUTNL("List of recognized input/output encodings (not necessarily supported!):");
00357 OUTPUTENDLINE;
00358 LIST_ENCODINGS;
00359 exit(EXIT_SUCCESS);
00360 }
00361
00362 else if (OPT("--erase") || OPT("-x"))
00363 {
00364 erase = true;
00365 }
00366
00367 else if (OPT("--version") || OPT("-V"))
00368 {
00369
00370 PRINT_VERSION;
00371 exit(EXIT_SUCCESS);
00372 }
00373
00374 else if (OPT("--license") || OPT("-L"))
00375 {
00376
00377 PRINT_VERSION;
00378
00379
00380 OUTPUTENDLINE;
00381 OUTPUTNL("This program comes with ABSOLUTELY NO WARRANTY. You may redistribute");
00382 OUTPUTNL("copies of this program under the terms of the GNU General Public License.");
00383 OUTPUTNL("For more information about these matters, see the file named COPYING.");
00384
00385 OUTPUTENDLINE;
00386 OUTPUTNL("Arithmetic coding routines are based on the sources originally written");
00387 OUTPUTNL("by Alistair Moffat. Their use is restricted by the following license:");
00388 OUTPUTENDLINE;
00389
00390 OUTPUTNL("These programs are supplied free of charge for research purposes only,");
00391 OUTPUTNL("and may not sold or incorporated into any commercial product. There is");
00392 OUTPUTNL("ABSOLUTELY NO WARRANTY of any sort, nor any undertaking that they are");
00393 OUTPUTNL("fit for ANY PURPOSE WHATSOEVER. Use them at your own risk. If you do");
00394 OUTPUTNL("happen to find a bug, or have modifications to suggest, please report");
00395 OUTPUTNL("the same to Alistair Moffat, alistair@cs.mu.oz.au. The copyright");
00396 OUTPUTNL("notice above and this statement of conditions must remain an integral");
00397 OUTPUTNL("part of each and every copy made of these files.");
00398
00399 OUTPUTNL("(Search for the license text in the sources to find the concrete files.)");
00400 OUTPUTEENDLINE;
00401
00402 exit(EXIT_SUCCESS);
00403 }
00404
00405 else if (OPT("--help") || OPT("-h"))
00406 {
00407 throw ExaltOptionException();
00408 }
00409
00410 else
00411 {
00412
00413 unrecognizedParamList.append(argv[i]);
00414 }
00415 }
00416
00417 for (char *unrecognized = unrecognizedParamList.first(); unrecognized; unrecognized = unrecognizedParamList.next())
00418 {
00419 if (strcmp(unrecognized, "-") && unrecognized[0] == '-')
00420 {
00421 OPT_UNKNOWN(unrecognized);
00422 }
00423 else
00424 filesToProcess.append(unrecognized);
00425 }
00426 }
00427
00428 catch (ExaltException)
00429 {
00430 usage();
00431 exit(EXIT_FAILURE);
00432 }
00433
00434
00435
00436 if (verbose)
00437 ExaltOptions::setOption(ExaltOptions::Verbose, ExaltOptions::Yes);
00438 else
00439 ExaltOptions::setOption(ExaltOptions::Verbose, ExaltOptions::No);
00440
00441 if (printModels)
00442 ExaltOptions::setOption(ExaltOptions::PrintModels, ExaltOptions::Yes);
00443 else
00444 ExaltOptions::setOption(ExaltOptions::PrintModels, ExaltOptions::No);
00445
00446 if (printGrammar)
00447 ExaltOptions::setOption(ExaltOptions::PrintGrammar, ExaltOptions::Yes);
00448 else
00449 ExaltOptions::setOption(ExaltOptions::PrintGrammar, ExaltOptions::No);
00450
00451 if (adaptiveModel)
00452 ExaltOptions::setOption(ExaltOptions::Model, ExaltOptions::AdaptiveModel);
00453 else
00454 ExaltOptions::setOption(ExaltOptions::Model, ExaltOptions::SimpleModel);
00455
00456
00457 ExaltOptions::setOption(ExaltOptions::Encoding, encodingMIB);
00458
00459
00460
00461 switch (selectedAction)
00462 {
00463 case Compress:
00464 if (filesToProcess.isEmpty())
00465
00466 filesToProcess.append("-");
00467
00468 for (char *fileName = filesToProcess.first(); fileName; fileName = filesToProcess.next())
00469 {
00470 char *outputFileName = 0;
00471 int outputFileNameLength = 0;
00472
00473 if (!strcmp(fileName, "-"))
00474 {
00475 OUTPUTENL("Compressing standard input to standard output.");
00476 fileName = 0;
00477 }
00478
00479 if (useStdout)
00480 {
00481 if (fileName)
00482 {
00483
00484 outputFileName = 0;
00485
00486 if (verbose)
00487 OUTPUTENL("Encoding '" << fileName << "' to standard output.");
00488 }
00489 }
00490 else
00491 {
00492 if (fileName)
00493 {
00494 outputFileNameLength = strlen(fileName);
00495 if (outputFileSuffix)
00496 outputFileNameLength += strlen(outputFileSuffix);
00497 else
00498 outputFileNameLength += strlen(DEFAULT_FILE_SUFFIX);
00499
00500 NEW(outputFileName, char[outputFileNameLength+1]);
00501
00502 strcpy(outputFileName, fileName);
00503 if (outputFileSuffix)
00504 strcat(outputFileName, outputFileSuffix);
00505 else
00506 strcat(outputFileName, DEFAULT_FILE_SUFFIX);
00507
00508 if (verbose)
00509 OUTPUTENL("Encoding '" << fileName << "' to '" << outputFileName << "'.");
00510 }
00511 }
00512
00513
00514
00515 try
00516 {
00517 ExaltCodec exaltCodec;
00518 ENCODE_DECODE(encode);
00519 }
00520
00521 catch (ExaltContextNotInitializedException)
00522 {
00523 DBG("Use of uninitialized context!");
00524 }
00525 catch (ExaltException)
00526 {
00527 if (fileName)
00528 ERR("Failed to compress '" << fileName << "'!");
00529 else
00530 ERR("Failed to compress standard input!");
00531
00532 if (outputFileName)
00533 remove(outputFileName);
00534
00535 if (!force)
00536 exit(EXIT_FAILURE);
00537 }
00538
00539
00540 if (outputFileName)
00541 DELETE(outputFileName);
00542
00543 }
00544 break;
00545
00546 case Decompress:
00547 if (filesToProcess.isEmpty())
00548
00549 filesToProcess.append("-");
00550
00551 for (char *fileName = filesToProcess.first(); fileName; fileName = filesToProcess.next())
00552 {
00553 char *outputFileName = 0;
00554 int outputFileNameLength = 0;
00555
00556 if (!strcmp(fileName, "-"))
00557 {
00558 OUTPUTENL("Decompressing standard input to standard output.");
00559 fileName = 0;
00560 }
00561 else
00562 {
00563 if ((outputFileNameLength = testFileNameSuffix(fileName, DEFAULT_FILE_SUFFIX)) == -1)
00564 if (outputFileSuffix)
00565 outputFileNameLength = testFileNameSuffix(fileName, outputFileSuffix);
00566
00567 if (outputFileNameLength == -1)
00568 {
00569 ERR("Unknown suffix, ignoring.");
00570 }
00571 }
00572
00573
00574 if (useStdout)
00575 {
00576 if (fileName)
00577 {
00578 if (outputFileNameLength != -1)
00579 {
00580
00581 outputFileName = 0;
00582
00583 if (verbose)
00584 OUTPUTENL("Decompressing '" << fileName << "' to standard output.");
00585 }
00586 }
00587 }
00588 else
00589 {
00590 if (outputFileNameLength != -1)
00591 {
00592 if (fileName)
00593 {
00594 NEW(outputFileName, char[outputFileNameLength+1]);
00595 strncpy(outputFileName, fileName, outputFileNameLength);
00596 outputFileName[outputFileNameLength] = 0;
00597
00598 if (verbose)
00599 OUTPUTENL("Decoding '" << fileName << "' to '" << outputFileName << "'.");
00600 }
00601 }
00602 }
00603
00604
00605
00606 ExaltCodec exaltCodec;
00607
00608 try
00609 {
00610 ENCODE_DECODE(decode);
00611 }
00612
00613 catch (ExaltException)
00614 {
00615 if (fileName)
00616 ERR("Failed to decompress '" << fileName << "'!");
00617 else
00618 ERR("Failed to decompress standard input!");
00619
00620 if (outputFileName)
00621 remove(outputFileName);
00622
00623 if (!force)
00624 exit(EXIT_FAILURE);
00625 }
00626
00627 if (outputFileName)
00628 DELETE(outputFileName);
00629 }
00630
00631 break;
00632
00633 default:
00634 ERR("Don't know what to do!");
00635 return EXIT_FAILURE;
00636 }
00637
00638 return EXIT_SUCCESS;
00639 }