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 "cmtkFileFormat.h"
00034
00035 #include <Base/cmtkTypes.h>
00036 #include <System/cmtkCompressedStream.h>
00037
00038 #ifdef HAVE_SYS_TYPES_H
00039 # include <sys/types.h>
00040 #endif
00041
00042 #ifdef HAVE_SYS_STAT_H
00043 # include <sys/stat.h>
00044 #endif
00045
00046 #include <stdio.h>
00047 #include <string.h>
00048 #include <limits.h>
00049
00050 namespace
00051 cmtk
00052 {
00053
00056
00058 typedef
00059 struct
00060 {
00062 unsigned short offset;
00064 const char *magicString;
00066 const size_t magicStringLength;
00067 } FileFormatMagic;
00068
00070 const FileFormatMagic FileFormatMagicNumbers[] = {
00071 { 0, NULL, 0 },
00072 { 0, NULL, 0 },
00073 { 0, NULL, 0 },
00074 { 0, NULL, 0 },
00075 { 0, "! TYPEDSTREAM", 13 },
00076 { 0, "P5", 2 },
00077 { 128, "DICM", 4 },
00078 { 0, "Modality :=", 11 },
00079 { 0, "# AmiraMesh 3D", 14 },
00080 { 0, NULL, 0 },
00081 { 0, NULL, 0 },
00082 { 54, "\x39\x30", 2 },
00083 { 344, "ni1\x00", 4 },
00084 { 344, "n+1\x00", 4 },
00085 { 0, "AVW_ImageFile", 13 },
00086 { 0, NULL, 0 },
00087 { 0, "NRRD", 4 },
00088 { 0, "\x5C\x01\x00\x00", 4 },
00089 { 0, "\x00\x00\x01\x5C", 4 },
00090 { 0, "#Insight Transform File V1.0", 28 },
00091 { 0, NULL, 0 }
00092 };
00093
00094 const char* FileFormatName[] =
00095 {
00097 "",
00099 "COMPRESSED-ARCHIVE",
00101 "STUDY",
00103 "STUDYLIST",
00105 "TYPEDSTREAM",
00107 "PGM",
00109 "DICOM",
00111 "VANDERBILT",
00113 "AMIRA",
00115 "RAW-DATA",
00117 "RAW3D",
00119 "BIORAD",
00121 "NIFTI-DETACHED-HEADER",
00123 "NIFTI-SINGLE-FILE",
00125 "ANALYZE-AVW",
00127 "METAIMAGE",
00129 "NRRD",
00131 "ANALYZE-HDR-LITTLEENDIAN",
00133 "ANALYZE-HDR-BIGENDIAN",
00137 NULL
00138 };
00139
00140 FileFormatID
00141 FileFormat::Identify( const char* path, const bool decompress )
00142 {
00143 struct stat buf;
00144 if ( CompressedStream::Stat( path, &buf ) < 0 )
00145 return FILEFORMAT_NEXIST;
00146
00147 if ( buf.st_mode & S_IFDIR )
00148 return FileFormat::IdentifyDirectory( path );
00149 else if ( buf.st_mode & S_IFREG )
00150 return FileFormat::IdentifyFile( path, decompress );
00151
00152 return FILEFORMAT_NEXIST;
00153 }
00154
00155 FileFormatID
00156 FileFormat::GetID( const char* name )
00157 {
00158 if ( name )
00159 {
00160 for ( unsigned int idx = 0; FileFormatName[idx]; ++idx )
00161 {
00162 if ( ! strcmp( FileFormatName[idx], name ) )
00163 return static_cast<FileFormatID>( idx );
00164 }
00165 }
00166 return FILEFORMAT_UNKNOWN;
00167 }
00168
00169 const char*
00170 FileFormat::Describe( const FileFormatID id )
00171 {
00172 switch ( id )
00173 {
00174 case FILEFORMAT_NEXIST:
00175 return "File or directory does not exist.";
00176 case FILEFORMAT_STUDY:
00177 return "Typedstream study archive [Directory].";
00178 case FILEFORMAT_STUDYLIST:
00179 return "Typedstream studylist archive [Directory].";
00180 case FILEFORMAT_PGM:
00181 return "PGM image file [File].";
00182 case FILEFORMAT_DICOM:
00183 return "DICOM image file [File].";
00184 case FILEFORMAT_VANDERBILT:
00185 return "Vanderbilt header/image file combination [File].";
00186 case FILEFORMAT_AMIRA:
00187 return "AmiraMesh image file [File].";
00188 case FILEFORMAT_BIORAD:
00189 return "BioRad image file [File].";
00190 case FILEFORMAT_NIFTI_DETACHED:
00191 return "NIFTI detached header+image [File]";
00192 case FILEFORMAT_NIFTI_SINGLEFILE:
00193 return "NIFTI single file [File]";
00194 case FILEFORMAT_ANALYZE_HDR:
00195 return "Analyze 7.5 file [Header+Binary File/Little Endian].";
00196 case FILEFORMAT_ANALYZE_HDR_BIGENDIAN:
00197 return "Analyze 7.5 file [Header+Binary File/Big Endian].";
00198 case FILEFORMAT_ANALYZE_AVW:
00199 return "Analyze AVW file [File].";
00200 case FILEFORMAT_RAW:
00201 return "RAW image file [File].";
00202 case FILEFORMAT_NRRD:
00203 return "Nrrd image file [File].";
00204 case FILEFORMAT_UNKNOWN:
00205 default:
00206 return "Unknown format.";
00207 }
00208 return "ILLEGAL ID tag in FileFormat::Describe().";
00209 }
00210
00211 FileFormatID
00212 FileFormat::IdentifyDirectory( const char* path )
00213 {
00214 char filename[PATH_MAX];
00215 struct stat buf;
00216
00217 snprintf( filename, sizeof( filename ), "%s/images", path );
00218 if ( (!stat( filename, &buf )) && ( buf.st_mode & S_IFREG ) )
00219 return FILEFORMAT_STUDY;
00220
00221 snprintf( filename, sizeof( filename ), "%s/images.gz", path );
00222 if ( (!stat( filename, &buf )) && ( buf.st_mode & S_IFREG ) )
00223 return FILEFORMAT_STUDY;
00224
00225 snprintf( filename, sizeof( filename ), "%s/studylist", path );
00226 if ( (!stat( filename, &buf )) && ( buf.st_mode & S_IFREG ) )
00227 return FILEFORMAT_STUDYLIST;
00228
00229 snprintf( filename, sizeof( filename ), "%s/studylist.gz", path );
00230 if ( (!stat( filename, &buf )) && ( buf.st_mode & S_IFREG ) )
00231 return FILEFORMAT_STUDYLIST;
00232
00233 return FILEFORMAT_UNKNOWN;
00234 }
00235
00236 FileFormatID
00237 FileFormat::IdentifyFile( const char* path, const bool decompress )
00238 {
00239 CompressedStream stream( path );
00240 if ( ! stream.IsValid() )
00241 return FILEFORMAT_NEXIST;
00242
00243 if ( stream.IsCompressed() && !decompress )
00244 return FILEFORMAT_COMPRESSED_ARCHIVE;
00245
00246 char buffer[348];
00247 memset( buffer, 0, sizeof( buffer ) );
00248 stream.Read( buffer, 1, 348 );
00249
00250 FileFormatID id = FILEFORMAT_NEXIST;
00251 while ( id != FILEFORMAT_UNKNOWN )
00252 {
00253 if ( FileFormatMagicNumbers[id].magicString )
00254 {
00255 if ( !memcmp( buffer+FileFormatMagicNumbers[id].offset, FileFormatMagicNumbers[id].magicString, FileFormatMagicNumbers[id].magicStringLength ) )
00256 return id;
00257 }
00258 char cid = static_cast<char>( id );
00259 id = static_cast<FileFormatID>( ++cid );
00260 }
00261
00262 return FILEFORMAT_UNKNOWN;
00263 }
00264
00265 }