ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/DataStorage/io_interface.cpp

Go to the documentation of this file.
00001 #ifdef _MSC_VER
00002 #pragma warning(disable:4996)
00003 #endif
00004 
00005 #include <boost/foreach.hpp>
00006 #define BOOST_FILESYSTEM_VERSION 2 //@todo switch to 3 as soon as we drop support for boost < 1.44
00007 #include <boost/filesystem.hpp>
00008 #include <iomanip>
00009 #include <iostream>
00010 
00011 #include "../CoreUtils/log.hpp"
00012 #include "common.hpp"
00013 #include "io_interface.h"
00014 
00015 namespace isis
00016 {
00017 namespace image_io
00018 {
00019 API_EXCLUDE_BEGIN
00021 namespace _internal
00022 {
00023 bool moreCmp( const util::istring &a, const util::istring &b ) {return a.length() > b.length();}
00024 }
00026 API_EXCLUDE_END
00027 
00028 void FileFormat::write( const std::list< data::Image >& images, const std::string &filename, const util::istring &dialect, boost::shared_ptr< util::ProgressFeedback > progress ) throw( std::runtime_error & )
00029 {
00030     std::list<std::string> names = makeUniqueFilenames( images, filename );
00031     std::list<std::string>::const_iterator inames = names.begin();
00032     BOOST_FOREACH( std::list<data::Image>::const_reference ref, images ) {
00033         std::string uniquePath = *( inames++ );
00034 
00035         try {
00036             write( ref, uniquePath, dialect, progress );
00037             LOG( Runtime, notice )
00038                     << "Image of size " << ref.getSizeAsVector() << " written to " <<  uniquePath
00039                     << " using " <<  getName() << ( dialect.empty() ?
00040                                                     util::istring() :
00041                                                     util::istring( " and dialect " ) + dialect
00042                                                   );
00043         } catch ( std::runtime_error &e ) {
00044             LOG( Runtime, warning )
00045                     << "Failed to write image to " <<  uniquePath << " using " <<  getName() << " (" << e.what() << ")";
00046         }
00047     }
00048 }
00049 bool FileFormat::setGender( util::PropertyMap &object, const char *set, const char *entries )
00050 {
00051     util::Selection g( entries );
00052 
00053     if( g.set( set ) ) {
00054         object.setPropertyAs( "subjectGender", g );
00055         return true;
00056     }
00057 
00058     return false;
00059 }
00060 
00061 bool FileFormat::hasOrTell( const util::PropertyMap::KeyType &name, const util::PropertyMap &object, LogLevel level )
00062 {
00063     if ( object.hasProperty( name ) ) {
00064         return true;
00065     } else {
00066         LOG( Runtime, level ) << "Missing property " << name;
00067         return false;
00068     }
00069 }
00070 
00071 void FileFormat::throwGenericError( std::string desc )
00072 {
00073     throw( std::runtime_error( desc ) );
00074 }
00075 
00076 void FileFormat::throwSystemError( int err, std::string desc )
00077 {
00078     throw( boost::system::system_error( err, boost::system::get_system_category(), desc ) );
00079 }
00080 
00081 std::list< util::istring > FileFormat::getSuffixes( io_modes mode )const
00082 {
00083     std::list<util::istring> ret = util::stringToList<util::istring>( suffixes( mode ).c_str() );
00084     BOOST_FOREACH( util::istring & ref, ret ) {
00085         ref.erase( 0, ref.find_first_not_of( '.' ) ); // remove leading . if there are some
00086     }
00087     ret.sort( _internal::moreCmp ); //start with the longest suffix
00088     return ret;
00089 }
00090 
00091 std::pair< std::string, std::string > FileFormat::makeBasename( const std::string &filename )const
00092 {
00093     std::list<util::istring> supported_suffixes = getSuffixes();
00094     util::istring ifilename( filename.begin(), filename.end() );
00095     BOOST_FOREACH( const util::istring & suffix, supported_suffixes ) {
00096         util::istring check=ifilename.substr(ifilename.length()-suffix.length(),suffix.length());
00097         
00098         if(filename[filename.length()-suffix.length()-1]=='.' && check == suffix ) {
00099             return std::make_pair( filename.substr( 0, filename.length()-suffix.length()-1 ), filename.substr( filename.length()-suffix.length()-1 ) );
00100         }
00101     }
00102     return std::make_pair( filename, std::string() );
00103 }
00104 
00105 std::string FileFormat::makeFilename( const util::PropertyMap &props, std::string namePattern )
00106 {
00107     boost::regex reg( "\\{[^{}]+\\}" );
00108     boost::regex regFormatInt( "%d_" ); // add leading zeros to int values - always as much as possible
00109     //NOTE: can also be done for rounding floats, but at the moment not required so not done right now
00110 
00111     boost::match_results<std::string::iterator> what;
00112     std::string::iterator pos = namePattern.begin();
00113 
00114 
00115     while( boost::regex_search( pos, namePattern.end() , what, reg ) ) {
00116 
00117         bool isFormatUsed = false;
00118         boost::cmatch m;
00119         size_t mSize = 1;
00120 
00121         if ( boost::regex_match( what[0].str().substr( 1, regFormatInt.size() ).c_str(), m, regFormatInt ) ) {
00122             mSize += regFormatInt.size();
00123             isFormatUsed = true;
00124         }
00125 
00126         util::PropertyMap::KeyType prop( what[0].str().substr( mSize, what.length() - 1 - mSize ).c_str() );
00127         const std::string::iterator start = what[0].first, end = what[0].second;
00128 
00129         if( props.hasProperty( prop ) ) {
00130             std::string pstring;
00131 
00132             if ( true == isFormatUsed ) {
00133                 size_t overallDigits = 0;
00134                 unsigned short tID;
00135 
00136                 switch ( tID = ( *props.propertyValue( prop ) ).getTypeID() ) {
00137                 case util::Value<uint8_t>::staticID:
00138                     overallDigits = ceil( log10( std::numeric_limits<uint8_t>::max() ) );
00139                     break;
00140                 case util::Value<int8_t>::staticID:
00141                     overallDigits = ceil( log10( std::numeric_limits<int8_t>::max() ) );
00142                     break;
00143                 case util::Value<uint16_t>::staticID:
00144                     overallDigits = ceil( log10( std::numeric_limits<uint16_t>::max() ) );
00145                     break;
00146                 case util::Value<int16_t>::staticID:
00147                     overallDigits = ceil( log10( std::numeric_limits<int16_t>::max() ) );
00148                     break;
00149                 case util::Value<uint32_t>::staticID:
00150                     overallDigits = ceil( log10( std::numeric_limits<uint32_t>::max() ) );
00151                     break;
00152                 case util::Value<int32_t>::staticID:
00153                     overallDigits = ceil( log10( std::numeric_limits<int32_t>::max() ) );
00154                     break;
00155                 default:
00156                     break;
00157                 }
00158 
00159                 pstring =  boost::regex_replace( props.getPropertyAs<std::string>( prop ), boost::regex( "[[:space:]/\\\\]" ), "_" );
00160 
00161                 if ( 0 < overallDigits ) {
00162                     size_t zerosToFill = overallDigits - pstring.length();
00163                     pstring.insert( 0, zerosToFill, '0' );
00164                 }
00165             } else {
00166                 pstring =  boost::regex_replace( props.getPropertyAs<std::string>( prop ), boost::regex( "[[:space:]/\\\\]" ), "_" );
00167             }
00168 
00169             const size_t dist = start - namePattern.begin();
00170 
00171             namePattern.replace( start, end, pstring );
00172 
00173             pos = namePattern.begin() + dist + pstring.length();
00174 
00175             LOG( Debug, info )
00176                     << "Replacing " << util::PropertyMap::KeyType( "{" ) + prop + "}" << " by "   << props.getPropertyAs<std::string>( prop )
00177                     << " the string is now " << namePattern;
00178         } else {
00179             LOG( Runtime, warning ) << "The property " << util::MSubject( prop ) << " does not exist - ignoring it";
00180             namePattern.replace( start, end, "" ); // it must be removed, or it will match forever
00181         }
00182     }
00183 
00184     return namePattern;
00185 }
00186 
00187 std::list<std::string> FileFormat::makeUniqueFilenames( const std::list<data::Image> &images, const std::string &namePattern )const
00188 {
00189     std::list<std::string> ret;
00190     std::map<std::string, unsigned short> names, used_names;
00191     BOOST_FOREACH( std::list<data::Image>::const_reference ref, images ) {
00192         names[makeFilename( ref, namePattern )]++;
00193     }
00194 
00195     BOOST_FOREACH( std::list<data::Image>::const_reference ref, images ) {
00196         std::string name = makeFilename( ref, namePattern );
00197 
00198         if( names[name] > 1 ) {
00199             const unsigned short number = ++used_names[name];
00200             const unsigned short length = ( uint16_t )log10( ( float )names[name] ) - ( uint16_t )log10( ( float )number );
00201             const std::string snumber = std::string( length, '0' ) + boost::lexical_cast<std::string>( number );
00202             const std::pair<std::string, std::string> splitted = makeBasename( name );
00203             name = splitted.first + "_" + snumber + splitted.second;
00204         }
00205 
00206         ret.push_back( name );
00207     }
00208     return ret;
00209 }
00210 
00211 const float FileFormat::invalid_float = -std::numeric_limits<float>::infinity();
00212 }
00213 }