home *** CD-ROM | disk | FTP | other *** search
- /* Xceed Streaming Compression Library - Decomp Sample Application
- * Copyright (c) 2001 Xceed Software Inc.
- *
- * [Decomp.cpp]
- *
- * This console application shows how to decompress a file, using
- * different compression formats. It specifically demonstrates:
- * - The ReadFile and ProcessFile methods.
- * - The CompressionFormat property.
- *
- * This file is part of the Xceed Streaming Compression Library sample
- * applications. The source code in this file is only intended as
- * a supplement to Xceed Streaming Compression Library's documentation,
- * and is provided "as is", without warranty of any kind, either
- * expressed or implied.
- */
-
- #include "stdafx.h"
- #include <stdio.h>
- #include <string.h>
- #include <limits.h>
- #include "Decomp.h"
-
- //
- // Mapping between command-line and property values
- //
-
- static SCompressionFormat g_pxCompressionFormats[] =
- {
- { "=Std", cfStandard },
- { "=BZip2", cfBZip2 },
- { "=GZip", cfGZip },
- { "=Zip3", cfZip3 },
- { "=ZLib", cfZLib },
- { "=BWT", cfBWT },
- { "=Deflate", cfDeflate },
- { "=Store", cfStore },
- };
-
-
- //--------------------------------------------------------------------------
- // Entry point of the application
- //--------------------------------------------------------------------------
- int main(int argc, char* argv[])
- {
- // Initializes the COM library on the current thread following the STA model
- CoInitialize( NULL );
-
- try
- {
- // Create an instance of the XceedStreamingCompression coclass, and
- // use the "I" interface which manipulates byte arrays (instead of
- // Variants for the "D" interfaces).
- IXceedStreamingCompressionPtr piComp;
- piComp.CreateInstance( CLSID_XceedStreamingCompression );
-
- // Two BSTR variables that will contain the Input and Output file names.
- _bstr_t bstrInputFileName;
- _bstr_t bstrOutputFileName;
-
- // Extract the command line parameters and initialize the Compression
- // instance according to the user specification. After this call
- // the Compression instance piComp is ready to decompress.
- if( !ExtractParameters( argc, argv,
- piComp,
- bstrInputFileName,
- bstrOutputFileName ) )
- {
- ShowHelp();
- return 1;
- }
-
- if( bstrOutputFileName.length() == 0 )
- {
- // An output file name was not provided by the user.
- // Display the decompressed stream to the console.
-
- BYTE* pcDecomp = NULL;
- DWORD dwDecompSize = 0;
- DWORD dwBytesRead = 0;
-
- // Let's say we want to avoid using too much memory. We can keep calling
- // the ReadFile method, each time reading and decompressing chunks of 4k,
- // until we reach the end of the file.
- DWORD dwOffset = 0;
- bool bLoop = true;
-
- // We can't really call the ReadFile method until we get the
- // cerInvalidFileOffset error, since in this case, the potential footer
- // in the compressed stream wouldn't be processed. The rule of thumb is
- // to always have a final call to the processing method with the
- // bEndOfData set to TRUE.
-
- // The good way to do it is to initially get the file size, and loop
- // until our offset reaches this file size.
- WIN32_FIND_DATA xFindData = { 0 };
- FindClose( FindFirstFile( ( const char* )bstrInputFileName, &xFindData ) );
-
- DWORD dwFileSize = xFindData.nFileSizeLow;
-
- while( dwOffset < dwFileSize )
- {
- // Read and decompress 4k at the current offset, providing:
- // - The source filename, with the offset where to read, and the
- // number of bytes to read.
- // - The type of processing to perform, in this case cfpDecompress.
- // - Is this the last call, depending on the file offset we're up to.
- // - The address of a DWORD containing the number of bytes actually read.
- // - The address of a destination buffer and its size.
- piComp->ReadFile( bstrInputFileName, dwOffset, 4096,
- cfpDecompress, ( dwOffset + 4096 >= dwFileSize ),
- &dwBytesRead, &pcDecomp, &dwDecompSize );
-
- // Increment the offset based on number of bytes actually read.
- dwOffset += dwBytesRead;
-
- // Simply outout the buffer to the console and free it!
- fwrite( pcDecomp, sizeof( BYTE ), dwDecompSize, stdout );
-
- CoTaskMemFree( pcDecomp );
- }
- }
- else
- {
- // An output file name was provided by the user.
- // Send the decompressed stream to this file
-
- DWORD dwBytesWritten = 0;
- DWORD dwBytesRead = 0;
-
- // Decompress a source file directly into a destination file, providing:
- // - The source filename to decompress, without any offset or size.
- // - The type of processing to perform, in this case cfpDecompress.
- // - Since we decompress in a single call, bEndOfData is TRUE.
- // - The destination filename where to write the decompressed data,
- // overwriting it if it exists (bAppend is FALSE).
- // - Pointers to two DWORD that will respectively contain the number of
- // bytes read and written on return.
- piComp->ProcessFile( bstrInputFileName, 0, 0,
- cfpDecompress, TRUE,
- bstrOutputFileName, FALSE,
- &dwBytesRead, &dwBytesWritten );
-
- printf( "Successfully decompressed file %s to file %s\n",
- ( const char* )bstrInputFileName, ( const char* )bstrOutputFileName );
- }
- }
- catch( const _com_error& err )
- {
- // When using the "#import" directive, the compiler generates wrapper classes
- // around all interface types. These wrapper classes throw exceptions when
- // a method call returns an HRESULT which is a failure code.
- printf( "Error %08x: %s\n", err.Error(), ( const char* )err.Description() );
- }
- catch( ... )
- {
- // Catch any other exceptions
- printf( "An unknown error occured.\n" );
- }
-
- // Close the COM library for the current thread
- CoUninitialize();
-
- return 0;
- }
-
- //--------------------------------------------------------------------------
- // Display usage information
- //--------------------------------------------------------------------------
- void ShowHelp()
- {
- // "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
- printf( "Usage: DECOMP [options] input_file [output_file]\n\n"
- " input_file: the file to decompress\n"
- " output_file: the destination file\n\n"
- " options: /m=[Std | BZip2 | GZip | Zip3 | ZLib | BWT | Deflate | Store]\n"
- " This is the compression format of the source.\n"
- " The default is 'Std'\n"
- " /h or /? : Show this help\n" );
- }
-
- //--------------------------------------------------------------------------
- // Extract commands from the command line parameters
- //
- // In this function, we call the piComp interface and let exceptions
- // be caught by the caller.
- // This function returns false if an error occured parsing the command
- // line parameters or if the user requested help.
- //--------------------------------------------------------------------------
- bool ExtractParameters( int argc, char* argv[],
- IXceedStreamingCompressionPtr piComp,
- _bstr_t& bstrInputFileName,
- _bstr_t& bstrOutputFileName )
- {
- // We set pxFormat to the first compression format of the global
- //compression format array in case the user don't specify any.
- SCompressionFormat* pxFormat = g_pxCompressionFormats;
- bool bFound;
-
- int i = 0;
-
- // We parse each command line parameter
- while( ++i < argc )
- {
- if( argv[ i ][ 0 ] == '/' )
- {
- // The parameter starts with a /
- // Meaning it's an option parameter
- switch( argv[ i ][ 1 ] )
- {
- case 'm':
- case 'M':
- // The user wants to set the compression method
- bFound = false;
-
- // We go through all the compression methods in the
- // correspondence table, stopping when we find a
- // match.
- for( pxFormat = g_pxCompressionFormats;
- pxFormat->pszCommandLine != NULL;
- pxFormat++ )
- {
- if( lstrcmpi( argv[ i ] + 2, pxFormat->pszCommandLine ) == 0 )
- {
- bFound = true;
- break;
- }
- }
-
- if( !bFound )
- {
- printf( "Invalid compression format '%s'\n\n", argv[ i ] );
- return false;
- }
-
- break;
-
- default:
- printf( "Unknown command '%s'\n\n", argv[ i ] );
- // Continue
- case 'h':
- case 'H':
- case '?':
- return false;
- }
- }
- }
-
- if( argc < 2 || argv[ argc - 1 ][ 0 ] == '/' )
- {
- printf( "You did not specify an input filename\n\n" );
- return false;
- }
- else if( argc < 3 || argv[ argc - 2 ][ 0 ] == '/' )
- {
- // Only an input file was specified
- bstrInputFileName = argv[ argc - 1 ];
- }
- else
- {
- // Both input and output file were specified
- bstrInputFileName = argv[ argc - 2 ];
- bstrOutputFileName = argv[ argc - 1 ];
- }
-
- // Set the compression format property of the piComp.
- // - We create the corresponding format instance.
- // - We optionally set its properties (none in this sample).
- // - We assign it to the CompressionFormat property of the main
- // compression object. Since this property is of type
- // "IXceedCompressData*", we use the wrapper class to perform
- // a QueryInterface on our format instance.
-
- switch( pxFormat->eFormat )
- {
- case cfBZip2 :
- {
- IXceedBZip2CompressionFormatPtr piFormat;
-
- piFormat.CreateInstance( CLSID_XceedBZip2CompressionFormat );
- piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
- }
- break;
-
- case cfGZip :
- {
- IXceedGZipCompressionFormatPtr piFormat;
-
- piFormat.CreateInstance( CLSID_XceedGZipCompressionFormat );
- piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
- }
- break;
-
- case cfStandard :
- {
- IXceedStandardCompressionFormatPtr piFormat;
-
- piFormat.CreateInstance( CLSID_XceedStandardCompressionFormat );
- piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
- }
- break;
-
- case cfZip3 :
- {
- IXceedZip3CompressionFormatPtr piFormat;
-
- piFormat.CreateInstance( CLSID_XceedZip3CompressionFormat );
- piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
- }
- break;
-
- case cfZLib :
- {
- IXceedZLibCompressionFormatPtr piFormat;
-
- piFormat.CreateInstance( CLSID_XceedZLibCompressionFormat );
- piComp->CompressionFormat = IXceedCompressDataPtr( piFormat );
- }
- break;
-
- // The next three items are not compression formats. They are compression
- // methods. They still can be assigned to the CompressionFormat property
- // of the XceedStreamingCompression object. In this case, the resulting
- // compressed streams will have no formating (no header, footer, checksum, ...)
- case cfBWT :
- {
- IXceedBWTCompressionMethodPtr piMethod;
-
- piMethod.CreateInstance( CLSID_XceedBWTCompressionMethod );
- piComp->CompressionFormat = IXceedCompressDataPtr( piMethod );
- }
- break;
-
- case cfDeflate :
- {
- IXceedDeflateCompressionMethodPtr piMethod;
-
- piMethod.CreateInstance( CLSID_XceedDeflateCompressionMethod );
- piComp->CompressionFormat = IXceedCompressDataPtr( piMethod );
- }
- break;
-
- case cfStore :
- {
- // Using Store as the compression format will produce an output
- // decompressed stream identical to the compressed one!
- IXceedStoreCompressionMethodPtr piMethod;
-
- piMethod.CreateInstance( CLSID_XceedStoreCompressionMethod );
- piComp->CompressionFormat = IXceedCompressDataPtr( piMethod );
- }
- break;
- }
-
- return true;
- }
-
-
- //
- // END_OF_FILE
- //
-