00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #include <System/cmtkCompressedStream.h>
00034 
00035 #include <System/cmtkConsole.h>
00036 #include <System/cmtkMemory.h>
00037 
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <stdio.h>
00041 #include <limits.h>
00042 #include <errno.h>
00043 
00044 #ifdef HAVE_SYS_TYPES_H
00045 #  include <sys/types.h>
00046 #endif
00047 
00048 #ifdef _MSC_VER
00049 #  include <process.h>
00050 #endif
00051 
00052 namespace
00053 cmtk
00054 {
00055 
00058 
00059 const CompressedStream::ArchiveLookupEntry 
00060 CompressedStream::ArchiveLookup[] = {
00061 #ifdef _MSC_VER
00062   {".Z",    "gunzip -cd %s > %s"},
00063   {".gz",   "gzip -cd %s > %s"},
00064   {".bz",   "bzip -Q -cd %s > %s"},
00065   {".bz2",  "bzip2 -cd %s > %s"},
00066   {".lzma", "lzma -cd %s > %s"},
00067   {".xz",   "xz -cd %s > %s"},
00068 #else
00069   {".Z",    "gunzip -c %s"},
00070   {".gz",   "gzip -cd %s"},
00071   {".bz",   "bzip -Q -cd %s"},
00072   {".bz2",  "bzip2 -cd %s"},
00073   {".lzma", "lzma -cd %s"},
00074   {".xz",   "xz -cd %s"},
00075 #endif
00076   { NULL,   NULL} 
00077 };
00078 
00079 CompressedStream::CompressedStream ( const char *filename ) 
00080   : m_Reader( NULL ),
00081     m_Compressed( false )
00082 {
00083   this->Open( filename );
00084 }
00085 
00086 CompressedStream::~CompressedStream () 
00087 {
00088   this->Close();
00089 }
00090 
00091 bool
00092 CompressedStream::Open ( const char *filename ) 
00093 {
00094   this->Close();
00095 
00096   if ( Self::Stat( filename ) == 2 )
00097     {
00098     StdErr << "WARNING: file '" << filename << "' exists both compressed and uncompressed!\n";
00099     }
00100   
00101   const char *suffix = strrchr( filename, '.' );
00102   
00103   this->m_Compressed = false;
00104   
00105   if ( suffix )
00106     for ( int i=0; ArchiveLookup[i].suffix && !this->m_Compressed; ++i )
00107       this->m_Compressed = this->m_Compressed || ! strcmp( ArchiveLookup[i].suffix, suffix );
00108 
00109   try
00110     {
00111     if ( !this->m_Compressed )
00112       {
00113       this->m_Reader = ReaderBase::SmartPtr( new Self::File( filename ) );
00114       }
00115     }
00116   catch (...)
00117     {
00118     }
00119 
00120   try 
00121     {
00122     if ( ! this->m_Reader )
00123       {
00124       bool result = false;
00125       for ( int i=0; ArchiveLookup[i].suffix && !result; ++i )
00126         result = this->OpenDecompressionPipe( filename, suffix, ArchiveLookup[i].command, ArchiveLookup[i].suffix );
00127       this->m_Compressed = true;
00128       }
00129     }
00130   catch ( ... )
00131     {
00132     this->m_Reader = ReaderBase::SmartPtr( NULL );
00133     }
00134   
00135   return this->IsValid();
00136 }
00137 
00138 void
00139 CompressedStream::Close()
00140 {
00141   if ( this->m_Reader )
00142     {
00143     this->m_Reader->Close();
00144     this->m_Reader = ReaderBase::SmartPtr( NULL );
00145     }
00146 }
00147 
00148 bool
00149 CompressedStream::OpenDecompressionPipe
00150 ( const char* filename, const char* suffix, const char* command, const char* compressedSuffix )
00151 {
00152   char fname[PATH_MAX];
00153 
00154   strcpy( fname, filename );
00155   if ( !suffix || strcmp( compressedSuffix, suffix ) )
00156     strcat( fname, compressedSuffix );
00157 
00158 #ifdef _MSC_VER 
00159   for ( char *p=fname; *p; ++p )
00160     if ( *p == '/' ) *p = '\\';
00161 #endif
00162 
00163   struct stat buf;
00164   if ( (! stat( fname, &buf )) && ( (buf.st_mode & S_IFREG) == S_IFREG ) ) 
00165     {
00166     if ( !strcmp( compressedSuffix, ".gz" ) ) 
00167       {
00168       this->m_Reader = ReaderBase::SmartPtr( new Self::Zlib( fname ) );
00169       }
00170 #ifdef CMTK_USE_BZIP2
00171     else if ( !strcmp( compressedSuffix, ".bz2" ) ) 
00172       {
00173       this->m_Reader = ReaderBase::SmartPtr( new Self::BZip2( fname ) );
00174       }
00175 #endif
00176 #ifdef CMTK_USE_LZMA
00177     else if ( !strcmp( compressedSuffix, ".lzma" ) ) 
00178       {
00179       this->m_Reader = ReaderBase::SmartPtr( new Self::LZMA( fname ) );
00180       }
00181 #endif
00182     else
00183       {
00184       this->m_Reader = ReaderBase::SmartPtr( new Self::Pipe( fname, command ) );
00185       }
00186     }
00187   return this->IsValid();
00188 }
00189 
00190 std::string
00191 CompressedStream::GetBaseName( const std::string& path )
00192 {
00193   const size_t suffixPos = path.rfind( '.' );
00194   
00195   if ( suffixPos != std::string::npos ) 
00196     {
00197     for ( int i = 0; ArchiveLookup[i].suffix; ++i )
00198       {
00199       const size_t suffixLen = strlen( ArchiveLookup[i].suffix );
00200       if ( !path.compare( suffixPos, suffixLen, ArchiveLookup[i].suffix, suffixLen ) )
00201         {
00202         return path.substr( 0, suffixPos );
00203         }
00204       }
00205     }
00206   return path;
00207 }
00208 
00209 int 
00210 CompressedStream::Stat( const char *path, struct stat* buf )
00211 {
00212   std::string baseName = CompressedStream::GetBaseName( path );
00213 
00214   struct stat statbuf;
00215   if ( ! buf )
00216     buf = &statbuf;
00217 
00218   const bool existsUncompressed = ! stat( baseName.c_str(), buf );
00219   
00220   for ( int i = 0; ArchiveLookup[i].suffix; ++i ) 
00221     {
00222     const std::string cpath = baseName + std::string( ArchiveLookup[i].suffix );
00223     if ( ! stat( cpath.c_str(), buf ) ) 
00224       return existsUncompressed ? 2 : 1;
00225     }
00226   
00227   return existsUncompressed ? 0 : -1;
00228 }
00229 
00230 }