soma-io  5.0.5
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 
61 //----------------------------------------------------------------------------
62 
63 namespace soma
64 {
65  //==========================================================================
66  // C O N S T R U C T O R S
67  //==========================================================================
68  template<class T> Reader<T>::Reader()
69  : _datasourceinfo( new DataSourceInfo )
70  {
71  }
72 
74  : _datasourceinfo( new DataSourceInfo( ds ) )
75  {
76  }
77 
79  : _datasourceinfo( new DataSourceInfo( *dsi ) )
80  {
81  }
82 
83  template<class T> Reader<T>::Reader( const std::string& filename )
85  carto::rc_ptr<DataSource>( new FileDataSource( filename ) )
86  ) )
87  {
88  }
89 
90  template<class T> Reader<T>::Reader( std::istream & stream )
92  carto::rc_ptr<DataSource>( new IStreamDataSource( stream ) )
93  ) )
94  {
95  }
96 
97  template<class T> Reader<T>::~Reader()
98  {
99  }
100 
101  //==========================================================================
102  // A L L O C A T O R
103  //==========================================================================
104  template <typename T>
106  {
107  _alloccontext = ac;
108  }
109 
110  template <typename T>
112  {
113  return _alloccontext;
114  }
115 
116  //==========================================================================
117  // O P T I O N S
118  //==========================================================================
119  template<class T>
121  {
122  _options = options;
123  }
124 
125  template<class T>
127  {
128  return _options;
129  }
130 
131  template<class T>
133  {
134  return _options;
135  }
136 
137  //==========================================================================
138  // D A T A S O U R C E
139  //==========================================================================
140  template<class T>
142  {
143  if ( !_datasourceinfo->list().empty( "default" ) ) {
144  _datasourceinfo->list().dataSource() = ds;
145  } else {
146  _datasourceinfo->list().addDataSource( "default", ds );
147  }
148  }
149 
150  template<class T>
151  void Reader<T>::attach( const std::string & filename, offset_t offset )
152  {
153  if ( !_datasourceinfo->list().empty( "default" ) ) {
154  _datasourceinfo->list().dataSource()
155  = carto::rc_ptr<DataSource>( new FileDataSource( filename, offset ) );
156  } else {
157  _datasourceinfo->list().addDataSource( "default",
158  carto::rc_ptr<DataSource>( new FileDataSource( filename, offset ) ) );
159  }
160  }
161 
162  template<class T>
163  void Reader<T>::attach( std::istream & stream )
164  {
165  if ( !_datasourceinfo->list().empty( "default" ) ) {
166  _datasourceinfo->list().dataSource()
167  = carto::rc_ptr<DataSource>( new IStreamDataSource( stream ) );
168  } else {
169  _datasourceinfo->list().addDataSource( "default",
170  carto::rc_ptr<DataSource>( new IStreamDataSource( stream ) ) );
171  }
172  }
173 
174  template<class T>
176  {
177  if ( !_datasourceinfo->list().empty( "default" ) ) {
178  return _datasourceinfo->list().dataSource();
179  } else {
180  return DataSource::none();
181  }
182  }
183 
184  template<class T>
186  {
187  if ( !_datasourceinfo->list().empty() ) {
188  return _datasourceinfo->list().dataSource();
189  } else {
190  return DataSource::none();
191  }
192  }
193 
194  template <typename T>
196  {
197  if( _datasourceinfo->list().dataSource() )
198  _datasourceinfo->list().dataSource()->flush();
199  }
200 
201 
202  template <typename T>
204  {
205  if( _datasourceinfo->list().dataSource() )
206  _datasourceinfo->list().dataSource()->close();
207  }
208 
209  //==========================================================================
210  // R E A D M E T H O D S
211  //==========================================================================
212 
213  //--- useful typedef -------------------------------------------------------
214  typedef std::multimap<std::string,std::string> multi_S;
215  typedef std::set<std::string> set_S;
216  typedef std::pair<std::multimap<std::string, std::string>::const_iterator,
217  std::multimap<std::string, std::string>::const_iterator> pair_cit_S;
218  //--------------------------------------------------------------------------
219 
220  template<class T>
221  bool Reader<T>::read( T & obj, carto::Object header,
222  int passbegin, int passend )
223  {
224  localMsg( "<" + carto::DataTypeCode<T>::name() + "> "
225  + _datasourceinfo->url() );
226 
227  if( !header.isNone() )
228  _datasourceinfo->header() = header;
229 
230  if( !dataSource() )
231  throw std::runtime_error( "Reader with no source of data" );
232  if( !_options.get() )
234 
236  std::string uri = _datasourceinfo->list().dataSource()->url();
237  std::string filename = FileUtil::uriFilename( uri );
238  carto::Object urioptions = FileUtil::uriOptions( uri );
239  if( urioptions.get() ) {
240  _datasourceinfo->list().dataSource()
241  .reset( new FileDataSource( filename ) );
242  _options->copyProperties( urioptions );
243  }
244 
246  DataSourceInfoLoader dsil; // manages the case of a not-none header
247  DataSourceInfo dsi = dsil.check(
249  ( passbegin < 2 ? 1 : passbegin - 1 ), passend - 1 );
250  if( dsi.list().empty() )
251  dsil.launchException();
252  if( !dsi.header().get() )
253  dsil.launchException();
254  *_datasourceinfo = dsi;
255  try {
256  if( _options->getProperty( "partial_reading" )->getScalar() )
257  /* disable mmap here because partial reading on an already allocated
258  volume is not compatible with mmap */
259  _datasourceinfo->capabilities().setMemoryMapping( false );
260  } catch( ... ) {
261  }
263 
264  std::string format;
265  if( !_options->getProperty( "format", format )
266  && !_datasourceinfo->header()->getProperty( "format", format ) )
267  _datasourceinfo->header()->getProperty( "file_type", format );
268 
269  localMsg( "using format " + format + " for file: " + uri );
270 
272  set_S tried;
273  std::set<FormatReader<T> *> triedf;
274  FormatReader<T> * reader;
275  std::unique_ptr<FormatReader<T> > readerc;
276  set_S::iterator notyet = tried.end();
277  typename std::set<FormatReader<T> *>::iterator notyetf = triedf.end();
278  int excp = 0;
279  int exct = -1;
280  std::string excm;
281 
282  localMsg( "trying to find readers using pass range: [" + carto::toString(passbegin)
283  + "-" + carto::toString(passend) + "]" );
284 
285 #ifdef CARTO_DEBUG
286  std::set<std::string> read_formats = FormatDictionary<T>::readFormats();
287  std::set<std::string>::const_iterator fit, fie = read_formats.end();
288 
289  localMsg( "registered formats for <" + carto::DataTypeCode<T>::name() + ">:");
290  for(fit = read_formats.begin(); fit!=fie; ++fit)
291  localMsg(" - " + *fit);
292 #endif
293 
295  if( passbegin <= 1 && passend >=1 && !format.empty() )
296  {
297  localMsg( "1. try to find reader of " + format + " for file: " + uri );
298  reader = FormatDictionary<T>::readFormat( format );
299  localMsg( "1. reader found " + carto::toString(reader) );
300  if( reader )
301  {
302  try {
303  localMsg( "1. try reader " + format );
304  readerc.reset( reader->clone() );
305  readerc->setupAndRead( obj, _datasourceinfo,
307  localMsg( "1. " + format + " OK" );
308  return true;
309  }
310  catch( std::exception & e ) {
311  localMsg( "1. " + format + " failed" );
312  carto::io_error::keepExceptionPriority( e, excp, exct, excm, 5 );
313  }
314  tried.insert( format );
315  triedf.insert( reader );
316  }
317  }
318 
319  std::string ext = carto::FileUtil::extension( filename );
320  const multi_S & extensions = FormatDictionary<T>::readExtensions();
321  pair_cit_S iext;
322  multi_S::const_iterator ie, ee;
323 
325  if( passbegin <= 2 && passend >=2 )
326  {
327  localMsg( "2. try to find reader using extension " + ext + " for file: " + uri );
328  iext = extensions.equal_range( ext );
329  for( ie=iext.first, ee = iext.second; ie!=ee; ++ie ) {
330  if( tried.find( ie->second ) == notyet )
331  {
332  localMsg( "2. try to find reader of " + ie->second + " for file: " + uri );
333  reader = FormatDictionary<T>::readFormat( ie->second );
334  localMsg( "2. reader found " + carto::toString(reader) );
335  if( reader && triedf.find( reader ) == notyetf ) {
336  try {
337  localMsg( "2. try reader " + ie->second );
338  readerc.reset( reader->clone() );
339  readerc->setupAndRead( obj, _datasourceinfo,
341  localMsg( "2. " + ie->second + " OK" );
342  return true;
343  }
344  catch( std::exception & e ) {
345  localMsg( "2. " + ie->second + " failed" );
346  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
347  }
348  tried.insert( ie->second );
349  triedf.insert( reader );
350  }
351  }
352  }
353  }
354 
356  if( passbegin <= 3 && passend >= 3 && !ext.empty())
357  {
358  localMsg( "3. try to find reader using no extension for file: " + uri );
359  iext = extensions.equal_range( "" );
360  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
361  if( tried.find( ie->second ) == notyet ) {
362  localMsg( "3. try to find reader of " + ie->second + " for file: " + uri );
363  reader = FormatDictionary<T>::readFormat( ie->second );
364  localMsg( "3. reader found " + carto::toString(reader) );
365  if( reader && triedf.find( reader ) == notyetf )
366  {
367  try {
368  localMsg( "3. try reader " + ie->second );
369  readerc.reset( reader->clone() );
370  readerc->setupAndRead( obj, _datasourceinfo,
372  localMsg( "3. " + ie->second + " OK" );
373  return true;
374  }
375  catch( std::exception & e ) {
376  localMsg( "3. " + ie->second + " failed" );
377  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
378  }
379  tried.insert( ie->second );
380  triedf.insert( reader );
381  }
382  }
383  }
384  }
385 
387  if( passbegin <= 4 && passend >= 4 )
388  {
389  localMsg( "4. try every reader for file: " + uri );
390  iext.first = extensions.begin();
391  iext.second = extensions.end();
392  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
393  if( tried.find( ie->second ) == notyet ) {
394  localMsg( "4. try to find reader of " + ie->second + " for file: " + uri );
395  reader = FormatDictionary<T>::readFormat( ie->second );
396  localMsg( "4. reader found " + carto::toString(reader) );
397  if( reader && triedf.find( reader ) == notyetf )
398  {
399  try {
400  localMsg( "4. try reader " + ie->second );
401  readerc.reset( reader->clone() );
402  readerc->setupAndRead( obj, _datasourceinfo,
404  localMsg( "4. " + ie->second + " OK" );
405  return true;
406  }
407  catch( std::exception & e ) {
408  localMsg( "4. " + ie->second + " failed" );
409  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
410  }
411  tried.insert( ie->second );
412  triedf.insert( reader );
413  }
414  }
415  }
416  }
417 
419  carto::io_error::launchExcept( exct, excm,
420  filename + " : no matching format" );
421  return false;
422  }
423 
424  template<class T>
425  T* Reader<T>::read( carto::Object header, int passbegin, int passend )
426  {
427  localMsg( "<" + carto::DataTypeCode<T>::name() + "> "
428  + _datasourceinfo->url() );
429 
430  if( !header.isNone() )
431  _datasourceinfo->header() = header;
432 
433  if( !dataSource() )
434  throw std::runtime_error( "Reader with no source of data" );
435  if( !_options.get() )
437 
439  std::string uri = _datasourceinfo->list().dataSource()->url();
440  std::string filename = FileUtil::uriFilename( uri );
441  carto::Object urioptions = FileUtil::uriOptions( uri );
442  if( urioptions.get() ) {
443  _datasourceinfo->list().dataSource()
444  .reset( new FileDataSource( filename ) );
445  _options->copyProperties( urioptions );
446  }
447 
449  DataSourceInfoLoader dsil; // manages the case of a not-none header
451  if( dsi.list().empty() )
452  dsil.launchException();
453  if( dsi.header().get() )
454  dsil.launchException();
455  *_datasourceinfo = dsi;
457 
458  std::string format;
459  if( !_options->getProperty( "format", format )
460  && !_datasourceinfo->header()->getProperty( "format", format ) )
461  _datasourceinfo->header()->getProperty( "file_type", format );
462 
463  localMsg( "using format " + format + " for file: " + uri );
464 
466  set_S tried;
467  std::set<FormatReader<T> *> triedf;
468  FormatReader<T> * reader;
469  std::unique_ptr<FormatReader<T> > readerc;
470  set_S::iterator notyet = tried.end();
471  typename std::set<FormatReader<T> *>::iterator notyetf = triedf.end();
472  T * obj;
473  int excp = 0;
474  int exct = -1;
475  std::string excm;
476 
477  localMsg( "trying to find readers using pass range: [" + carto::toString(passbegin)
478  + "-" + carto::toString(passend) + "]" );
479 
480 #ifdef CARTO_DEBUG
481  std::set<std::string> read_formats = FormatDictionary<T>::readFormats();
482  std::set<std::string>::const_iterator fit, fie = read_formats.end();
483 
484  localMsg( "registered formats for <" + carto::DataTypeCode<T>::name() + ">:");
485  for(fit = read_formats.begin(); fit!=fie; ++fit)
486  localMsg(" - " + *fit);
487 #endif
488 
490  if( passbegin <= 1 && passend >= 1 && !format.empty() )
491  {
492  localMsg( "1. try to find reader of " + format + " for file: " + uri );
493  reader = FormatDictionary<T>::readFormat( format );
494  localMsg( "1. reader found " + carto::toString(reader) );
495  if( reader )
496  {
497  try
498  {
499  localMsg( "1. try reader " + format );
500  readerc.reset( reader->clone() );
501  obj = readerc->createAndRead( _datasourceinfo,
503  if( obj )
504  {
505  localMsg( "1. " + format + " OK" );
506  return obj;
507  }
508  }
509  catch( std::exception & e )
510  {
511  localMsg( "1. " + format + " failed" );
512  carto::io_error::keepExceptionPriority( e, excp, exct, excm, 5 );
513  }
514  tried.insert( format );
515  triedf.insert( reader );
516  }
517  }
518 
519  std::string ext = carto::FileUtil::extension( filename );
520 
521  const multi_S & extensions = FormatDictionary<T>::readExtensions();
522 
523  pair_cit_S iext;
524  multi_S::const_iterator ie, ee;
525 
527  if( passbegin <= 2 && passend >= 2 )
528  {
529  localMsg( "2. try to find reader using extension " + ext + " for file: " + uri );
530  iext = extensions.equal_range( ext );
531  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie )
532  {
533  if( tried.find( ie->second ) == notyet )
534  {
535  localMsg( "2. try to find reader of " + ie->second + " for file: " + uri );
536  reader = FormatDictionary<T>::readFormat( ie->second );
537  localMsg( "2. reader found " + carto::toString(reader) );
538  if( reader && triedf.find( reader ) == notyetf )
539  {
540  try
541  {
542  localMsg( "2. try reader " + ie->second );
543  readerc.reset( reader->clone() );
544  obj = readerc->createAndRead( _datasourceinfo,
546  if( obj )
547  {
548  localMsg( "2. " + ie->second + " OK" );
549  return obj;
550  }
551  }
552  catch( std::exception & e )
553  {
554  localMsg( "2. " + ie->second + " failed" );
555  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
556  }
557  tried.insert( ie->second );
558  triedf.insert( reader );
559  }
560  }
561  }
562  }
563 
565  if( passbegin <= 3 && passend >= 3 && !ext.empty() )
566  {
567  localMsg( "3. try to find reader using no extension for file: " + uri );
568  iext = extensions.equal_range( "" );
569  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
570  if( tried.find( ie->second ) == notyet ) {
571  localMsg( "3. try to find reader of " + ie->second + " for file: " + uri );
572  reader = FormatDictionary<T>::readFormat( ie->second );
573  localMsg( "3. reader found " + carto::toString(reader) );
574  if( reader && triedf.find( reader ) == notyetf )
575  {
576  try {
577  localMsg( "3. try reader " + ie->second );
578  readerc.reset( reader->clone() );
579  obj = readerc->createAndRead( _datasourceinfo,
581  if( obj ) {
582  localMsg( "3. " + ie->second + " OK" );
583  return obj;
584  }
585  } catch( std::exception & e ) {
586  localMsg( "3. " + ie->second + " failed" );
587  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
588  }
589  tried.insert( ie->second );
590  triedf.insert( reader );
591  }
592  }
593  }
594  }
595 
597  if( passbegin <= 4 && passend >= 4 )
598  {
599  localMsg( "4. try every reader for file: " + uri );
600  iext.first = extensions.begin();
601  iext.second = extensions.end();
602  for( ie=iext.first, ee=iext.second; ie!=ee; ++ie ) {
603  if( tried.find( ie->second ) == notyet ) {
604  localMsg( "4. try to find reader of " + ie->second + " for file: " + uri );
605  reader = FormatDictionary<T>::readFormat( ie->second );
606  localMsg( "4. reader found " + carto::toString(reader) );
607  if( reader && triedf.find( reader ) == notyetf )
608  {
609  try {
610  localMsg( "4. try reader " + ie->second );
611  readerc.reset( reader->clone() );
612  obj = readerc->createAndRead( _datasourceinfo,
614  if( obj ) {
615  localMsg( "4. " + ie->second + " OK" );
616  return obj;
617  }
618  } catch( std::exception & e ) {
619  localMsg( "4. " + ie->second + " failed" );
620  carto::io_error::keepExceptionPriority( e, excp, exct, excm );
621  }
622  tried.insert( ie->second );
623  triedf.insert( reader );
624  }
625  }
626  }
627  }
628 
630  carto::io_error::launchExcept( exct, excm,
631  filename + " : no matching format" );
632  return 0;
633  }
634 
635 }
636 
637 #undef localMsg
638 #endif
void flush()
Definition: reader_d.h:195
void close()
Definition: reader_d.h:203
Allocation context.
Definition: allocator.h:260
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 std::string extension(const std::string &)
static void keepExceptionPriority(std::exception &e, int &prio, int &type, std::string &message, int raiseprio=0)
AllocatorContext _alloccontext
Definition: reader.h:169
std::multimap< std::string, std::string > multi_S
Definition: reader_d.h:214
virtual ~Reader()
Definition: reader_d.h:97
bool empty() const
Returns true only if no keyword inserted.
const carto::rc_ptr< DataSource > dataSource() const
Definition: reader_d.h:175
carto::rc_ptr< DataSourceInfo > _datasourceinfo
Definition: reader.h:168
Abstraction layer for various data sources (file, buffer, socket...).
Definition: datasource.h:64
Definition: allocator.h:48
carto::Object _options
Definition: reader.h:170
static const std::multimap< std::string, std::string > & readExtensions()
carto::Object options() const
Definition: reader_d.h:126
bool isNone() const
DataSource on a std::istream (read-only stream)
static FormatReader< T > * readFormat(const std::string &format)
static std::set< std::string > readFormats()
void setAllocatorContext(const AllocatorContext &ac)
Definition: reader_d.h:105
Low-level object IO reader specialized for a specific format.
DataSourceInfo check(DataSourceInfo dsi, carto::Object options=carto::none(), int passbegin=1, int passend=3)
Finds the right format checker.
Generic information retreiver / checker for all data sources and file formats.
void setOptions(carto::Object options)
Definition: reader_d.h:120
void attach(carto::rc_ptr< DataSource > ds)
Definition: reader_d.h:141
void setDataSourceInfo(carto::rc_ptr< DataSourceInfo > dsi)
AllocatorContext becomes owner od datasourceinfo.
static Object value()
unsigned long long offset_t
Offsets are 64 bits if supported.
Definition: datasource.h:51
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:217
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:221
const AllocatorContext & allocatorContext() const
Definition: reader_d.h:111
GenericObject * get() const
static void launchExcept(int code, const std::string &msg, const std::string &defmsg="")
Informative object used by IO system.
virtual FormatReader< T > * clone() const =0
Duplicate the FormatReader.
std::set< std::string > set_S
Definition: reader_d.h:215
std::string toString(const T &object)
const carto::Object & header() const
#define localMsg(message)
Definition: reader_d.h:58
const DataSourceList & list() const