There are 3 different layers of IO in Aims for virtually all objects:
- low-level readers / writers for each specific file format
- mid-level IO encapsulate all formats supported by Aims for a given object / data type (ie read an AimsData<short> whatever the disk file format): aims::Reader and aims::Writer template classes
- the highest level readers allow to switch to different pieces of code dealing with each object and data type (ie read an AimsData<short> or a BucketMap<Void>): the aims::Process class
Normal programs perform IO at mid or high level, never at low-level: the lower layer is reserved to the specific usage of the mid-layer Reader and Writer classes for their internal purpose
Mid-level IO: What to do to read a volume of short data ?
High-level IO: My program has to read a file but doesn't know what's in it
Adding new IO formats
Mid-level IO: What to do to read a volume of short data ?
#include <cstdlib>
#include <stdexcept>
try
{
r.read( data );
}
catch( exception & e )
{
cerr << e.what() << endl;
}
You may use an aims::Finder to read the file header and help you determine what's in the file:
Finder f;
if( f.check( "filename" ) )
{
if( f.objectType() == "Volume" )
{
if( f.dataType() == "S16" )
{
}
else
...
}
else
...
}
High-level IO: My program has to read a file but doesn't know what's in it
Use a aims::Process class, you will avoid using a Finder by yourself and testing all possible types by hand: Process does it for you.
#include <stdexcept>
void myAimsData_short_function(
Process &,
const string &filename,
Finder & )
{
r.read( data );
}
void myBucket_void_function(
Process &,
const string &filename,
Finder & )
{
r.read( data );
}
int main( int argc, char** argv )
{
string filename = argv[1];
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
It's possible to use template functions as callbacks: see aims::Process documentation for details
Adding new IO formats
It's the most complex part since there are several operations to perform. Here you have to know a little more of the mechanisms of Aims IO systems:
- A header system is responsible for reading the beginning of the file (or the header file): this is the aims::Finder part, which purpose is to determine what's in the input file: object type (volume, bucket, mesh etc), data type (short: "S16", float: "FLOAT"...) and other information which may depend on the objet/data type and/or the format.
- A reader system (aims::Reader) which actually reads the file and fills an object with it. To do so the object must be already existing, ie you must know its type.
- Finder
- Reader / Writer
- Operations to add an IO format
Finder
A aims::Finder object checks a file header. It uses a list of header reader classes and tries them one after another until a header reader succeeds in reading the file header. There is one header reader for each file format: aims::FinderFormat classes which may in turn use a lower level Header class. This Header object may contain dynamic attributes (see aims::PythonHeader) and is accessible via the Finder after it has been read
Reader / Writer
aims::Reader is a template for each object/data type. Its role is to read a data file into an object in a format-independant way. To do so, Reader has a list of specific format readers which can be tried one after another until one of them "understands" the file and is able to read it. These readers/writers are subclasses of aims::FileFormat and are generally template classes (because there must be one for each data type). These FileFormat objects are stored in a aims::FileFormatDictionary object and shared wy both Reader and Writer classes. There is one FileFormatDictionary for each object/data type (it's a template like Reader and Writer)
Operations to add an IO format
In the most general case these operations are:
- Finder (header) part:
- Reader (body) part:
But:
- if you're adding a new format for already supported objects (ie your own volume format to be read as AimsData), aims::Reader, aims::Writer and aims::FileFormatDictionary classes are already compiled on the needed types:
- write a header class with read the file header
- wrap it in a aims::FinderFormat inherited class
- register the FinderFormat in the Finder class
- define the specific format reader and writer classes
- wrap them in a (a set of) aims::FileFormat inherited class(es)
- register them in already defined (and compiled) aims::FileFormatDictionary instances: don't specialize the registerBaseFormats() function (because it's already compiled in the library), but use the static registerFormat() function
- if you want to compile and use existing IO formats for new data types:
- (nothing to do for the Finder part)
- specialize the aims::FinderFormatDictionary::registerBaseFormats() functions and compile them
- compile (instantiate) the specific aims::Reader and aims::Writer on your type(s)
todo: code examples...