soma-io  5.1.2
reader_d.h
Go to the documentation of this file.
1 /* This software and supporting documentation are distributed by
2  * Institut Federatif de Recherche 49
3  * CEA/NeuroSpin, Batiment 145,
4  * 91191 Gif-sur-Yvette cedex
5  * France
6  *
7  * This software is governed by the CeCILL-B license under
8  * French law and abiding by the rules of distribution of free software.
9  * You can use, modify and/or redistribute the software under the
10  * terms of the CeCILL-B license as circulated by CEA, CNRS
11  * and INRIA at the following URL "http://www.cecill.info".
12  *
13  * As a counterpart to the access to the source code and rights to copy,
14  * modify and redistribute granted by the license, users are provided only
15  * with a limited warranty and the software's author, the holder of the
16  * economic rights, and the successive licensors have only limited
17  * liability.
18  *
19  * In this respect, the user's attention is drawn to the risks associated
20  * with loading, using, modifying and/or developing or reproducing the
21  * software by the user in light of its specific status of free software,
22  * that may mean that it is complicated to manipulate, and that also
23  * therefore means that it is reserved for developers and experienced
24  * professionals having in-depth computer knowledge. Users are therefore
25  * encouraged to load and test the software's suitability as regards their
26  * requirements in conditions enabling the security of their systems and/or
27  * data to be ensured and, more generally, to use and operate it in the
28  * same conditions as regards security.
29  *
30  * The fact that you are presently reading this means that you have had
31  * knowledge of the CeCILL-B license and that you accept its terms.
32  */
33 
34 #ifndef SOMAIO_IO_READER_D_H
35 #define SOMAIO_IO_READER_D_H
36 //--- soma-io ----------------------------------------------------------------
38 #include <soma-io/datasourceinfo/datasourceinfo.h> // format info
39 #include <soma-io/datasourceinfo/datasourceinfoloader.h> // format check
40 #include <soma-io/datasource/datasourcelist.h> // member
41 #include <soma-io/datasource/datasource.h> // useful for none() pointer
42 #include <soma-io/datasource/filedatasource.h> // used by constructor
43 #include <soma-io/datasource/streamdatasource.h> // used by constructor
44 #include <soma-io/io/formatdictionary.h> // used by read() method
45 #include <soma-io/io/reader.h> // class declaration
46 #include <soma-io/reader/formatreader.h> // used by read() method
47 #include <soma-io/allocator/allocator.h> // allocator management
48 //--- cartobase --------------------------------------------------------------
49 #include <cartobase/exception/ioexcept.h> // launch exception
50 #include <cartobase/object/object.h> // header & options
51 #include <cartobase/object/property.h> // header & options
52 #include <cartobase/stream/fileutil.h> // finding file extension
53 //--- system -----------------------------------------------------------------
54 #include <set>
55 #include <map>
56 //--- debug ------------------------------------------------------------------
58 #define localMsg( message ) cartoCondMsg( 4, message, "READER" )
59 // localMsg must be undef at end of file
60 // #undef localMsg
61 // #define localMsg( message ) std::cerr << (message) << std::endl;
62 
63 //----------------------------------------------------------------------------
64 
65 namespace soma
66 {
67  //==========================================================================
68  // C O N S T R U C T O R S
69  //==========================================================================
70  template<class T> Reader<T>::Reader()
71  : _datasourceinfo( new DataSourceInfo )
72  {
73  }
74 
76  : _datasourceinfo( new DataSourceInfo( ds ) )
77  {
78  }
79 
81  : _datasourceinfo( new DataSourceInfo( *dsi ) )
82  {
83  }
84 
85  template<class T> Reader<T>::Reader( const std::string& filename )
86  : _datasourceinfo( new DataSourceInfo(
87  carto::rc_ptr<DataSource>( new FileDataSource( filename ) )
88  ) )
89  {
90  }
91 
92  template<class T> Reader<T>::Reader( std::istream & stream )
93  : _datasourceinfo( new DataSourceInfo(
94  carto::rc_ptr<DataSource>( new IStreamDataSource( stream ) )
95  ) )
96  {
97  }
98 
99  template<class T> Reader<T>::~Reader()
100  {
101  }
102 
103  //==========================================================================
104  // A L L O C A T O R
105  //==========================================================================
106  template <typename T>
108  {
109  _alloccontext = ac;
110  }
111 
112  template <typename T>
114  {
115  return _alloccontext;
116  }
117 
118  //==========================================================================
119  // O P T I O N S
120  //==========================================================================
121  template<class T>
123  {
124  _options = options;
125  }
126 
127  template<class T>
129  {
130  return _options;
131  }
132 
133  template<class T>
135  {
136  return _options;
137  }
138 
139  //==========================================================================
140  // D A T A S O U R C E
141  //==========================================================================
142  template<class T>
144  {
145  if ( !_datasourceinfo->list().empty( "default" ) ) {
146  _datasourceinfo->list().dataSource() = ds;
147  } else {
148  _datasourceinfo->list().addDataSource( "default", ds );
149  }
150  }
151 
152  template<class T>
153  void Reader<T>::attach( const std::string & filename, offset_t offset )
154  {
155  if ( !_datasourceinfo->list().empty( "default" ) ) {
156  _datasourceinfo->list().dataSource()
157  = carto::rc_ptr<DataSource>( new FileDataSource( filename, offset ) );
158  } else {
159  _datasourceinfo->list().addDataSource( "default",
160  carto::rc_ptr<DataSource>( new FileDataSource( filename, offset ) ) );
161  }
162  }
163 
164  template<class T>
165  void Reader<T>::attach( std::istream & stream )
166  {
167  if ( !_datasourceinfo->list().empty( "default" ) ) {
168  _datasourceinfo->list().dataSource()
169  = carto::rc_ptr<DataSource>( new IStreamDataSource( stream ) );
170  } else {
171  _datasourceinfo->list().addDataSource( "default",
172  carto::rc_ptr<DataSource>( new IStreamDataSource( stream ) ) );
173  }
174  }
175 
176  template<class T>
178  {
179  if ( !_datasourceinfo->list().empty( "default" ) ) {
180  return _datasourceinfo->list().dataSource();
181  } else {
182  return DataSource::none();
183  }
184  }
185 
186  template<class T>
188  {
189  if ( !_datasourceinfo->list().empty() ) {
190  return _datasourceinfo->list().dataSource();
191  } else {
192  return DataSource::none();
193  }
194  }
195 
196  template <typename T>
198  {
199  if( _datasourceinfo->list().dataSource() )
200  _datasourceinfo->list().dataSource()->flush();
201  }
202 
203 
204  template <typename T>
206  {
207  if( _datasourceinfo->list().dataSource() )
208  _datasourceinfo->list().dataSource()->close();
209  }
210 
211  //==========================================================================
212  // R E A D M E T H O D S
213  //==========================================================================
214 
215  //--- useful typedef -------------------------------------------------------
216  typedef std::multimap<std::string,std::string> multi_S;
217  typedef std::set<std::string> set_S;
218  typedef std::pair<std::multimap<std::string, std::string>::const_iterator,
219  std::multimap<std::string, std::string>::const_iterator> pair_cit_S;
220  //--------------------------------------------------------------------------
221 
222  template<class T>
223  bool Reader<T>::read( T & obj, carto::Object header,
224  int passbegin, int passend )
225  {
226  localMsg( "<" + carto::DataTypeCode<T>::name() + "> "
227  + _datasourceinfo->url() + " reading existing object" );
228 
229  if( !header.isNone() )
230  _datasourceinfo->header() = header;
231 
232  if( !dataSource() )
233  throw std::runtime_error( "Reader with no source of data" );
234  if( !_options.get() )
236 
238  std::string uri = _datasourceinfo->list().dataSource()->url();
239  std::string filename = FileUtil::uriFilename( uri );
240  carto::Object urioptions = FileUtil::uriOptions( uri );
241  if( urioptions.get() ) {
242  _datasourceinfo->list().dataSource()
243  .reset( new FileDataSource( filename ) );
244  _options->copyProperties( urioptions );
245  }
246 
248  DataSourceInfoLoader dsil; // manages the case of a not-none header
249  DataSourceInfo dsi = dsil.check(
250  *_datasourceinfo, _options,
251  ( passbegin < 2 ? 1 : passbegin - 1 ), passend - 1 );
252  if( dsi.list().empty() )
253  dsil.launchException();
254  if( !dsi.header().get() )
255  dsil.launchException();
256  *_datasourceinfo = dsi;
257  try {
258  if( _options->getProperty( "partial_reading" )->getScalar() )
259  /* disable mmap here because partial reading on an already allocated
260  volume is not compatible with mmap */
261  _datasourceinfo->capabilities().setMemoryMapping( false );
262  } catch( ... ) {
263  }
264  _alloccontext.setDataSourceInfo( _datasourceinfo );
265 
266  std::string format;
267  if( !_options->getProperty( "format", format )
268  && !_datasourceinfo->header()->getProperty( "format", format ) )
269  _datasourceinfo->header()->getProperty( "file_type", format );
270 
271  localMsg( "using format " + format + " for file: " + uri );
272 
274  set_S tried;
275  std::set<FormatReader<T> *> triedf;
276  FormatReader<T> * reader;
277  std::unique_ptr<FormatReader<T> > readerc;
278  set_S::iterator notyet = tried.end();
279  typename std::set<FormatReader<T> *>::iterator notyetf = triedf.end();
280  int excp = 0;
281  int exct = -1;
282  std::string excm;
283 
284  localMsg( "trying to find readers using pass range: [" + carto::toString(passbegin)
285  + "-" + carto::toString(passend) + "]" );
286 
287 #ifdef CARTO_DEBUG
288  std::set<std::string> read_formats = FormatDictionary<T>::readFormats();
289  std::set<std::string>::const_iterator fit, fie = read_formats.end();
290 
291  localMsg( "registered formats for <" + carto::DataTypeCode<T>::name() + ">:");
292  for(fit = read_formats.begin(); fit!=fie; ++fit)
293  localMsg(" - " + *fit);
294 #endif
295 
297  if( passbegin <= 1 && passend >=1 && !format.empty() )
298  {
299  localMsg( "1. try to find reader of " + format + " for file: " + uri );
300  reader = FormatDictionary<T>::readFormat( format );
301  localMsg( "1. reader found " + carto::toString(reader) );
302  if( reader )
303  {
304  try {
305  localMsg( "1. try reader " + format );
306  readerc.reset( reader->clone() );
307  readerc->setupAndRead( obj, _datasourceinfo,
308  _alloccontext, _options );
309  localMsg( "1. " + format + " OK" );
310  return true;
311  }
312  catch( std::exception & e ) {
313  localMsg( "1. " + format + " failed" );
314  carto::io_error::keepExceptionPriority( e, excp, exct, excm, 5 );
315  }
316  tried.insert( format );
317  triedf.insert( reader );
318  }
319  }
320 
321  std::string ext = carto::FileUtil::extension( filename );
322  const multi_S & extensions = FormatDictionary<T>::readExtensions();
323  pair_cit_S iext;
324  multi_S::const_iterator ie, ee;
325 
327  if( passbegin <= 2 && passend >=2 )
328  {
329  localMsg( "2. try to find reader using extension " + ext + " for file: " + uri );
330  iext = extensions.equal_range( ext );
331  for( ie=iext.first, ee = iext.second; ie!=ee; ++ie ) {
332  if( tried.find( ie->second ) == notyet )
333  {
334  localMsg( "2. try to find reader of " + ie->second + " for file: " + uri );
335  reader = FormatDictionary<T>::readFormat( ie->second );
336  localMsg( "2. reader found " + carto::toString(reader) );
337  if( reader && triedf.find( reader ) == notyetf ) {
338  try {
339  localMsg( "2. try reader " + ie->second );
340  readerc.reset( reader->clone() );
341  readerc->setupAndRead( obj, _datasourceinfo,
342  _alloccontext, _options );
343  localMsg( "2. " + ie->second + " OK" );
344  return true;
345  }
346  catch( std::exception & e ) {
347  localMsg( "2. " + ie->second + " failed" );
348  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
349  }
350  tried.insert( ie->second );
351  triedf.insert( reader );
352  }
353  }
354  }
355  }
356 
358  if( passbegin <= 3 && passend >= 3 && !ext.empty())
359  {
360  localMsg( "3. try to find reader using no extension for file: " + uri );
361  iext = extensions.equal_range( "" );
362  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
363  if( tried.find( ie->second ) == notyet ) {
364  localMsg( "3. try to find reader of " + ie->second + " for file: " + uri );
365  reader = FormatDictionary<T>::readFormat( ie->second );
366  localMsg( "3. reader found " + carto::toString(reader) );
367  if( reader && triedf.find( reader ) == notyetf )
368  {
369  try {
370  localMsg( "3. try reader " + ie->second );
371  readerc.reset( reader->clone() );
372  readerc->setupAndRead( obj, _datasourceinfo,
373  _alloccontext, _options );
374  localMsg( "3. " + ie->second + " OK" );
375  return true;
376  }
377  catch( std::exception & e ) {
378  localMsg( "3. " + ie->second + " failed" );
379  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
380  }
381  tried.insert( ie->second );
382  triedf.insert( reader );
383  }
384  }
385  }
386  }
387 
389  if( passbegin <= 4 && passend >= 4 )
390  {
391  localMsg( "4. try every reader for file: " + uri );
392  iext.first = extensions.begin();
393  iext.second = extensions.end();
394  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
395  if( tried.find( ie->second ) == notyet ) {
396  localMsg( "4. try to find reader of " + ie->second + " for file: " + uri );
397  reader = FormatDictionary<T>::readFormat( ie->second );
398  localMsg( "4. reader found " + carto::toString(reader) );
399  if( reader && triedf.find( reader ) == notyetf )
400  {
401  try {
402  localMsg( "4. try reader " + ie->second );
403  readerc.reset( reader->clone() );
404  readerc->setupAndRead( obj, _datasourceinfo,
405  _alloccontext, _options );
406  localMsg( "4. " + ie->second + " OK" );
407  return true;
408  }
409  catch( std::exception & e ) {
410  localMsg( "4. " + ie->second + " failed" );
411  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
412  }
413  tried.insert( ie->second );
414  triedf.insert( reader );
415  }
416  }
417  }
418  }
419 
421  carto::io_error::launchExcept( exct, excm,
422  filename + " : no matching format" );
423  return false;
424  }
425 
426  template<class T>
427  T* Reader<T>::read( carto::Object header, int passbegin, int passend )
428  {
429  localMsg( "<" + carto::DataTypeCode<T>::name() + "> "
430  + _datasourceinfo->url() );
431 
432  if( !header.isNone() )
433  _datasourceinfo->header() = header;
434 
435  if( !dataSource() )
436  throw std::runtime_error( "Reader with no source of data" );
437  if( !_options.get() )
439 
441  std::string uri = _datasourceinfo->list().dataSource()->url();
442  std::string filename = FileUtil::uriFilename( uri );
443  carto::Object urioptions = FileUtil::uriOptions( uri );
444  if( urioptions.get() ) {
445  _datasourceinfo->list().dataSource()
446  .reset( new FileDataSource( filename ) );
447  _options->copyProperties( urioptions );
448  }
449 
451  DataSourceInfoLoader dsil; // manages the case of a not-none header
452  DataSourceInfo dsi = dsil.check( *_datasourceinfo, _options );
453  if( dsi.list().empty() )
454  dsil.launchException();
455  if( dsi.header().get() )
456  dsil.launchException();
457  *_datasourceinfo = dsi;
458  _alloccontext.setDataSourceInfo( _datasourceinfo );
459 
460  std::string format;
461  if( !_options->getProperty( "format", format )
462  && !_datasourceinfo->header()->getProperty( "format", format ) )
463  _datasourceinfo->header()->getProperty( "file_type", format );
464 
465  localMsg( "using format " + format + " for file: " + uri );
466 
468  set_S tried;
469  std::set<FormatReader<T> *> triedf;
470  FormatReader<T> * reader;
471  std::unique_ptr<FormatReader<T> > readerc;
472  set_S::iterator notyet = tried.end();
473  typename std::set<FormatReader<T> *>::iterator notyetf = triedf.end();
474  T * obj;
475  int excp = 0;
476  int exct = -1;
477  std::string excm;
478 
479  localMsg( "trying to find readers using pass range: [" + carto::toString(passbegin)
480  + "-" + carto::toString(passend) + "]" );
481 
482 #ifdef CARTO_DEBUG
483  std::set<std::string> read_formats = FormatDictionary<T>::readFormats();
484  std::set<std::string>::const_iterator fit, fie = read_formats.end();
485 
486  localMsg( "registered formats for <" + carto::DataTypeCode<T>::name() + ">:");
487  for(fit = read_formats.begin(); fit!=fie; ++fit)
488  localMsg(" - " + *fit);
489 #endif
490 
492  if( passbegin <= 1 && passend >= 1 && !format.empty() )
493  {
494  localMsg( "1. try to find reader of " + format + " for file: " + uri );
495  reader = FormatDictionary<T>::readFormat( format );
496  localMsg( "1. reader found " + carto::toString(reader) );
497  if( reader )
498  {
499  try
500  {
501  localMsg( "1. try reader " + format );
502  readerc.reset( reader->clone() );
503  obj = readerc->createAndRead( _datasourceinfo,
504  _alloccontext, _options );
505  if( obj )
506  {
507  localMsg( "1. " + format + " OK" );
508  return obj;
509  }
510  }
511  catch( std::exception & e )
512  {
513  localMsg( "1. " + format + " failed" );
514  carto::io_error::keepExceptionPriority( e, excp, exct, excm, 5 );
515  }
516  tried.insert( format );
517  triedf.insert( reader );
518  }
519  }
520 
521  std::string ext = carto::FileUtil::extension( filename );
522 
523  const multi_S & extensions = FormatDictionary<T>::readExtensions();
524 
525  pair_cit_S iext;
526  multi_S::const_iterator ie, ee;
527 
529  if( passbegin <= 2 && passend >= 2 )
530  {
531  localMsg( "2. try to find reader using extension " + ext + " for file: " + uri );
532  iext = extensions.equal_range( ext );
533  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie )
534  {
535  if( tried.find( ie->second ) == notyet )
536  {
537  localMsg( "2. try to find reader of " + ie->second + " for file: " + uri );
538  reader = FormatDictionary<T>::readFormat( ie->second );
539  localMsg( "2. reader found " + carto::toString(reader) );
540  if( reader && triedf.find( reader ) == notyetf )
541  {
542  try
543  {
544  localMsg( "2. try reader " + ie->second );
545  readerc.reset( reader->clone() );
546  obj = readerc->createAndRead( _datasourceinfo,
547  _alloccontext, _options );
548  if( obj )
549  {
550  localMsg( "2. " + ie->second + " OK" );
551  return obj;
552  }
553  }
554  catch( std::exception & e )
555  {
556  localMsg( "2. " + ie->second + " failed" );
557  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
558  }
559  tried.insert( ie->second );
560  triedf.insert( reader );
561  }
562  }
563  }
564  }
565 
567  if( passbegin <= 3 && passend >= 3 && !ext.empty() )
568  {
569  localMsg( "3. try to find reader using no extension for file: " + uri );
570  iext = extensions.equal_range( "" );
571  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
572  if( tried.find( ie->second ) == notyet ) {
573  localMsg( "3. try to find reader of " + ie->second + " for file: " + uri );
574  reader = FormatDictionary<T>::readFormat( ie->second );
575  localMsg( "3. reader found " + carto::toString(reader) );
576  if( reader && triedf.find( reader ) == notyetf )
577  {
578  try {
579  localMsg( "3. try reader " + ie->second );
580  readerc.reset( reader->clone() );
581  obj = readerc->createAndRead( _datasourceinfo,
582  _alloccontext, _options );
583  if( obj ) {
584  localMsg( "3. " + ie->second + " OK" );
585  return obj;
586  }
587  } catch( std::exception & e ) {
588  localMsg( "3. " + ie->second + " failed" );
589  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
590  }
591  tried.insert( ie->second );
592  triedf.insert( reader );
593  }
594  }
595  }
596  }
597 
599  if( passbegin <= 4 && passend >= 4 )
600  {
601  localMsg( "4. try every reader for file: " + uri );
602  iext.first = extensions.begin();
603  iext.second = extensions.end();
604  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
605  if( tried.find( ie->second ) == notyet ) {
606  localMsg( "4. try to find reader of " + ie->second + " for file: " + uri );
607  reader = FormatDictionary<T>::readFormat( ie->second );
608  localMsg( "4. reader found " + carto::toString(reader) );
609  if( reader && triedf.find( reader ) == notyetf )
610  {
611  try {
612  localMsg( "4. try reader " + ie->second );
613  readerc.reset( reader->clone() );
614  obj = readerc->createAndRead( _datasourceinfo,
615  _alloccontext, _options );
616  if( obj ) {
617  localMsg( "4. " + ie->second + " OK" );
618  return obj;
619  }
620  } catch( std::exception & e ) {
621  localMsg( "4. " + ie->second + " failed" );
622  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
623  }
624  tried.insert( ie->second );
625  triedf.insert( reader );
626  }
627  }
628  }
629  }
630 
632  carto::io_error::launchExcept( exct, excm,
633  filename + " : no matching format" );
634  return 0;
635  }
636 
637 }
638 
639 #undef localMsg
640 #endif
static std::string extension(const std::string &)
static Object value()
bool isNone() const
static void keepExceptionPriority(std::exception &e, int &prio, int &type, std::string &message, int raiseprio=0)
static void launchExcept(int code, const std::string &msg, const std::string &defmsg="")
GenericObject * get() const
Allocation context.
Definition: allocator.h:261
void setMemoryMapping(const bool &boo=true)
Generic information retreiver / checker for all data sources and file formats.
DataSourceInfo check(DataSourceInfo dsi, carto::Object options=carto::none(), int passbegin=1, int passend=3)
Finds the right format checker.
Informative object used by IO system.
const DataSourceList & list() const
const DataSourceCapabilities & capabilities() const
const carto::Object & header() const
bool empty() const
Returns true only if no keyword inserted.
Abstraction layer for various data sources (file, buffer, socket...).
Definition: datasource.h:65
static const carto::rc_ptr< DataSource > none()
An empty ref-counter that is more convenient than calling a constructor of rc_ptr<DataSource> (useful...
static const std::multimap< std::string, std::string > & readExtensions()
static std::set< std::string > readFormats()
static FormatReader< T > * readFormat(const std::string &format)
Low-level object IO reader specialized for a specific format.
Definition: formatreader.h:85
virtual FormatReader< T > * clone() const =0
Duplicate the FormatReader.
DataSource on a std::istream (read-only stream)
void close()
Definition: reader_d.h:205
void setAllocatorContext(const AllocatorContext &ac)
Definition: reader_d.h:107
const carto::rc_ptr< DataSource > dataSource() const
Definition: reader_d.h:177
carto::Object options() const
Definition: reader_d.h:128
virtual bool read(T &obj, carto::Object header=carto::none(), int passbegin=1, int passend=4)
Finds the correct format and reads the object.
Definition: reader_d.h:223
void flush()
Definition: reader_d.h:197
const AllocatorContext & allocatorContext() const
Definition: reader_d.h:113
virtual ~Reader()
Definition: reader_d.h:99
void setOptions(carto::Object options)
Definition: reader_d.h:122
void attach(carto::rc_ptr< DataSource > ds)
Definition: reader_d.h:143
std::string toString(const T &object)
Definition: allocator.h:49
std::pair< std::multimap< std::string, std::string >::const_iterator, std::multimap< std::string, std::string >::const_iterator > pair_cit_S
Definition: reader_d.h:219
std::set< std::string > set_S
Definition: reader_d.h:217
std::multimap< std::string, std::string > multi_S
Definition: reader_d.h:216
unsigned long long offset_t
Offsets are 64 bits if supported.
Definition: datasource.h:51
#define localMsg(message)
Definition: reader_d.h:58