home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / vbasic / Data / Utils / XZipComp.exe / XceedCompression.Cab / F112862_Decomp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-05-11  |  12.2 KB  |  362 lines

  1. /* Xceed Streaming Compression Library - Decomp Sample Application
  2.  * Copyright (c) 2001 Xceed Software Inc.
  3.  *
  4.  * [Decomp.cpp]
  5.  *
  6.  * This console application shows how to decompress a file, using 
  7.  * different compression formats. It specifically demonstrates:
  8.  *  - The ReadFile and ProcessFile methods.
  9.  *  - The CompressionFormat property.
  10.  *
  11.  * This file is part of the Xceed Streaming Compression Library sample 
  12.  * applications. The source code in this file is only intended as 
  13.  * a supplement to Xceed Streaming Compression Library's documentation, 
  14.  * and is provided "as is", without warranty of any kind, either 
  15.  * expressed or implied. 
  16.  */
  17.  
  18. #include "stdafx.h"
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <limits.h>
  22. #include "Decomp.h"
  23.  
  24. //
  25. // Mapping between command-line and property values
  26. //
  27.  
  28. static SCompressionFormat g_pxCompressionFormats[] = 
  29. {
  30.   { "=Std",     cfStandard },
  31.   { "=BZip2",   cfBZip2 },
  32.   { "=GZip",    cfGZip },
  33.   { "=Zip3",    cfZip3 },
  34.   { "=ZLib",    cfZLib },
  35.   { "=BWT",     cfBWT },
  36.   { "=Deflate", cfDeflate },
  37.   { "=Store",   cfStore },
  38. };
  39.  
  40.  
  41. //--------------------------------------------------------------------------
  42. // Entry point of the application
  43. //--------------------------------------------------------------------------
  44. int main(int argc, char* argv[])
  45. {
  46.   // Initializes the COM library on the current thread following the STA model
  47.   CoInitialize( NULL );
  48.  
  49.   try
  50.   {
  51.     // Create an instance of the XceedStreamingCompression coclass, and
  52.     // use the "I" interface which manipulates byte arrays (instead of
  53.     // Variants for the "D" interfaces).
  54.     IXceedStreamingCompressionPtr piComp;
  55.     piComp.CreateInstance( CLSID_XceedStreamingCompression );
  56.  
  57.     // Two BSTR variables that will contain the Input and Output file names.
  58.     _bstr_t bstrInputFileName;
  59.     _bstr_t bstrOutputFileName;
  60.  
  61.     // Extract the command line parameters and initialize the Compression
  62.     // instance according to the user specification. After this call
  63.     // the Compression instance piComp is ready to decompress.
  64.     if( !ExtractParameters( argc, argv, 
  65.                             piComp,
  66.                             bstrInputFileName, 
  67.                             bstrOutputFileName ) )
  68.     {
  69.       ShowHelp();
  70.       return 1;
  71.     }
  72.  
  73.     if( bstrOutputFileName.length() == 0 )
  74.     {
  75.       // An output file name was not provided by the user.
  76.       // Display the decompressed stream to the console.
  77.  
  78.       BYTE* pcDecomp      = NULL;
  79.       DWORD dwDecompSize  = 0;
  80.       DWORD dwBytesRead   = 0;
  81.  
  82.       // Let's say we want to avoid using too much memory. We can keep calling
  83.       // the ReadFile method, each time reading and decompressing chunks of 4k, 
  84.       // until we reach the end of the file.
  85.       DWORD dwOffset  = 0;
  86.       bool  bLoop = true;
  87.  
  88.       // We can't really call the ReadFile method until we get the 
  89.       // cerInvalidFileOffset error, since in this case, the potential footer
  90.       // in the compressed stream wouldn't be processed. The rule of thumb is
  91.       // to always have a final call to the processing method with the
  92.       // bEndOfData set to TRUE.
  93.  
  94.       // The good way to do it is to initially get the file size, and loop
  95.       // until our offset reaches this file size.
  96.       WIN32_FIND_DATA xFindData = { 0 };
  97.       FindClose( FindFirstFile( ( const char* )bstrInputFileName, &xFindData ) );
  98.  
  99.       DWORD dwFileSize = xFindData.nFileSizeLow;
  100.       
  101.       while( dwOffset < dwFileSize )
  102.       {
  103.         // Read and decompress 4k at the current offset, providing:
  104.         //  - The source filename, with the offset where to read, and the
  105.         //    number of bytes to read.
  106.         //  - The type of processing to perform, in this case cfpDecompress.
  107.         //  - Is this the last call, depending on the file offset we're up to.
  108.         //  - The address of a DWORD containing the number of bytes actually read.
  109.         //  - The address of a destination buffer and its size.
  110.         piComp->ReadFile( bstrInputFileName, dwOffset, 4096, 
  111.                           cfpDecompress, ( dwOffset + 4096 >= dwFileSize ), 
  112.                           &dwBytesRead, &pcDecomp, &dwDecompSize );
  113.  
  114.         // Increment the offset based on number of bytes actually read.
  115.         dwOffset  += dwBytesRead;
  116.  
  117.         // Simply outout the buffer to the console and free it!
  118.         fwrite( pcDecomp, sizeof( BYTE ), dwDecompSize, stdout );
  119.  
  120.         CoTaskMemFree( pcDecomp );
  121.       }
  122.     }
  123.     else
  124.     {
  125.       // An output file name was provided by the user.
  126.       // Send the decompressed stream to this file
  127.  
  128.       DWORD dwBytesWritten  = 0;
  129.       DWORD dwBytesRead     = 0;
  130.  
  131.       // Decompress a source file directly into a destination file, providing:
  132.       //  - The source filename to decompress, without any offset or size.
  133.       //  - The type of processing to perform, in this case cfpDecompress.
  134.       //  - Since we decompress in a single call, bEndOfData is TRUE.
  135.       //  - The destination filename where to write the decompressed data,
  136.       //    overwriting it if it exists (bAppend is FALSE).
  137.       //  - Pointers to two DWORD that will respectively contain the number of 
  138.       //    bytes read and written on return.
  139.       piComp->ProcessFile( bstrInputFileName, 0, 0, 
  140.                            cfpDecompress, TRUE, 
  141.                            bstrOutputFileName, FALSE, 
  142.                            &dwBytesRead, &dwBytesWritten );
  143.  
  144.       printf( "Successfully decompressed file %s to file %s\n", 
  145.               ( const char* )bstrInputFileName, ( const char* )bstrOutputFileName );
  146.     }
  147.   }
  148.   catch( const _com_error& err )
  149.   {
  150.     // When using the "#import" directive, the compiler generates wrapper classes
  151.     // around all interface types. These wrapper classes throw exceptions when
  152.     // a method call returns an HRESULT which is a failure code.
  153.     printf( "Error %08x: %s\n", err.Error(), ( const char* )err.Description() );
  154.   }
  155.   catch( ... )
  156.   {
  157.     // Catch any other exceptions
  158.     printf( "An unknown error occured.\n" );
  159.   }
  160.  
  161.   // Close the COM library for the current thread
  162.   CoUninitialize();
  163.  
  164.   return 0;
  165. }
  166.  
  167. //--------------------------------------------------------------------------
  168. // Display usage information
  169. //--------------------------------------------------------------------------
  170. void ShowHelp()
  171. {
  172.   //      "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
  173.   printf( "Usage: DECOMP [options] input_file [output_file]\n\n"
  174.           "  input_file: the file to decompress\n"
  175.           "  output_file: the destination file\n\n"
  176.           "  options: /m=[Std | BZip2 | GZip | Zip3 | ZLib | BWT | Deflate | Store]\n"
  177.           "              This is the compression format of the source.\n"
  178.           "              The default is 'Std'\n"
  179.           "           /h or /? : Show this help\n" );
  180. }
  181.  
  182. //--------------------------------------------------------------------------
  183. // Extract commands from the command line parameters
  184. //
  185. // In this function, we call the piComp interface and let exceptions
  186. // be caught by the caller.
  187. // This function returns false if an error occured parsing the command
  188. // line parameters or if the user requested help.
  189. //--------------------------------------------------------------------------
  190. bool ExtractParameters( int argc, char* argv[],
  191.                         IXceedStreamingCompressionPtr piComp, 
  192.                         _bstr_t& bstrInputFileName,
  193.                         _bstr_t& bstrOutputFileName )
  194. {
  195.   // We set pxFormat to the first compression format of the global 
  196.   //compression format array in case the user don't specify any.
  197.   SCompressionFormat*  pxFormat = g_pxCompressionFormats;
  198.   bool bFound;
  199.  
  200.   int   i = 0;
  201.  
  202.   // We parse each command line parameter
  203.   while( ++i < argc )
  204.   {
  205.     if( argv[ i ][ 0 ] == '/' )
  206.     {
  207.       // The parameter starts with a /
  208.       // Meaning it's an option parameter
  209.       switch( argv[ i ][ 1 ] )
  210.       {
  211.         case 'm':
  212.         case 'M':
  213.           // The user wants to set the compression method
  214.           bFound = false;
  215.  
  216.           // We go through all the compression methods in the 
  217.           // correspondence table, stopping when we find a 
  218.           // match.
  219.           for( pxFormat = g_pxCompressionFormats;
  220.                pxFormat->pszCommandLine != NULL;
  221.                pxFormat++ )
  222.           {
  223.             if( lstrcmpi( argv[ i ] + 2, pxFormat->pszCommandLine ) == 0 )
  224.             {
  225.               bFound = true;
  226.               break;
  227.             }
  228.           }
  229.  
  230.           if( !bFound )
  231.           {
  232.             printf( "Invalid compression format '%s'\n\n", argv[ i ] );
  233.             return false;
  234.           }
  235.  
  236.           break;
  237.  
  238.         default:
  239.           printf( "Unknown command '%s'\n\n", argv[ i ] );
  240.           // Continue
  241.         case 'h':
  242.         case 'H':
  243.         case '?':
  244.           return false;
  245.       }
  246.     }
  247.   }
  248.  
  249.   if( argc < 2 || argv[ argc - 1 ][ 0 ] == '/' )
  250.   {
  251.     printf( "You did not specify an input filename\n\n" );
  252.     return false;
  253.   }
  254.   else if( argc < 3 || argv[ argc - 2 ][ 0 ] == '/' )
  255.   {
  256.     // Only an input file was specified
  257.     bstrInputFileName = argv[ argc - 1 ];
  258.   }
  259.   else
  260.   {
  261.     // Both input and output file were specified
  262.     bstrInputFileName   = argv[ argc - 2 ];
  263.     bstrOutputFileName  = argv[ argc - 1 ];
  264.   }
  265.  
  266.   // Set the compression format property of the piComp.
  267.   //  - We create the corresponding format instance.
  268.   //  - We optionally set its properties (none in this sample).
  269.   //  - We assign it to the CompressionFormat property of the main
  270.   //    compression object. Since this property is of type
  271.   //    "IXceedCompressData*", we use the wrapper class to perform
  272.   //    a QueryInterface on our format instance.
  273.  
  274.   switch( pxFormat->eFormat )
  275.   {
  276.     case cfBZip2 :
  277.     {
  278.       IXceedBZip2CompressionFormatPtr piFormat;
  279.       
  280.       piFormat.CreateInstance( CLSID_XceedBZip2CompressionFormat );
  281.       piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
  282.     }
  283.     break;
  284.  
  285.     case cfGZip :
  286.     {
  287.       IXceedGZipCompressionFormatPtr piFormat;
  288.       
  289.       piFormat.CreateInstance( CLSID_XceedGZipCompressionFormat );
  290.       piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
  291.     }
  292.     break;
  293.  
  294.     case cfStandard :
  295.     {
  296.       IXceedStandardCompressionFormatPtr piFormat;
  297.       
  298.       piFormat.CreateInstance( CLSID_XceedStandardCompressionFormat );
  299.       piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
  300.     }
  301.     break;
  302.  
  303.     case cfZip3 :
  304.     {
  305.       IXceedZip3CompressionFormatPtr piFormat;
  306.       
  307.       piFormat.CreateInstance( CLSID_XceedZip3CompressionFormat );
  308.       piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
  309.     }
  310.     break;
  311.  
  312.     case cfZLib :
  313.     {
  314.       IXceedZLibCompressionFormatPtr piFormat;
  315.       
  316.       piFormat.CreateInstance( CLSID_XceedZLibCompressionFormat );
  317.       piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
  318.     }
  319.     break;
  320.  
  321.     // The next three items are not compression formats. They are compression
  322.     // methods. They still can be assigned to the CompressionFormat property 
  323.     // of the XceedStreamingCompression object. In this case, the resulting
  324.     // compressed streams will have no formating (no header, footer, checksum, ...)
  325.     case cfBWT :
  326.     {
  327.       IXceedBWTCompressionMethodPtr piMethod;
  328.       
  329.       piMethod.CreateInstance( CLSID_XceedBWTCompressionMethod );
  330.       piComp->CompressionFormat = IXceedCompressDataPtr( piMethod );
  331.     }
  332.     break;
  333.  
  334.     case cfDeflate :
  335.     {
  336.       IXceedDeflateCompressionMethodPtr piMethod;
  337.       
  338.       piMethod.CreateInstance( CLSID_XceedDeflateCompressionMethod );
  339.       piComp->CompressionFormat = IXceedCompressDataPtr( piMethod );
  340.     }
  341.     break;
  342.  
  343.     case cfStore :
  344.     {
  345.       // Using Store as the compression format will produce an output
  346.       // decompressed stream identical to the compressed one!
  347.       IXceedStoreCompressionMethodPtr piMethod;
  348.       
  349.       piMethod.CreateInstance( CLSID_XceedStoreCompressionMethod );
  350.       piComp->CompressionFormat = IXceedCompressDataPtr( piMethod );
  351.     }
  352.     break;
  353.   }
  354.  
  355.   return true;
  356. }
  357.  
  358.  
  359. //
  360. // END_OF_FILE
  361. //
  362.