00001 //# AipsIO.h: AipsIO is the object persistency mechanism of Casacore 00002 //# Copyright (C) 1993,1994,1995,1996,1998,2000,2001 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id$ 00027 00028 #ifndef CASA_AIPSIO_H 00029 #define CASA_AIPSIO_H 00030 00031 00032 //# Includes 00033 #include <casacore/casa/aips.h> 00034 #include <casacore/casa/Containers/Block.h> 00035 #include <casacore/casa/BasicSL/String.h> 00036 #include <casacore/casa/BasicSL/Complex.h> 00037 #include <casacore/casa/IO/ByteIO.h> 00038 #include <casacore/casa/vector.h> 00039 00040 namespace casacore { //# NAMESPACE CASACORE - BEGIN 00041 00042 //# Forward Declarations 00043 class TypeIO; 00044 class ByteIO; 00045 class RegularFileIO; 00046 class MultiFileBase; 00047 00048 00049 // <summary> 00050 // AipsIO is the object persistency mechanism of Casacore 00051 // </summary> 00052 00053 // <use visibility=export> 00054 00055 // <reviewed reviewer="ghunt" date="95Feb21" tests="" demos=""> 00056 00057 // <etymology> 00058 // AipsIO is simply the conventional shorthand for "AIPS++ input/output". 00059 // Note that Casacore is the successor of the old AIPS++ project. 00060 // </etymology> 00061 00062 // <synopsis> 00063 // AipsIO is a class designed to do I/O for objects. 00064 // It reads/writes the data using a class derived from 00065 // <linkto class=TypeIO>TypeIO</linkto>. For instance, class 00066 // <linkto class=CanonicalIO>CanonicalIO</linkto> can be used 00067 // to read/write the data in canonical format. 00068 // <p> 00069 // The TypeIO class in its turn uses a class derived from 00070 // <linkto class=ByteIO>ByteIO</linkto> to determine where the data 00071 // has to be written. 00072 // <p> 00073 // An object is written by writing all its data members. It will be 00074 // preceeded by a header containing type and version. 00075 // The I/O can be done via de overloaded << and >> operators to write or 00076 // read a single item (e.g., an int or an object). These operators are 00077 // already defined for all built-in data types and for Complex, DComplex, 00078 // String, and Bool. 00079 // Since each enumeration is a specific type, it is hard to handle them. 00080 // Casting to Bool (which is also an enumerated type) is a possibility, 00081 // but that assumes that each enumerated type has the same size (which 00082 // is probably true for all compilers). 00083 // Another possibility is to store it in an int when writing. Reading 00084 // can be done the opposite way, although the ARM says that an int 00085 // cannot be assigned to an enumerated type. 00086 // <p> 00087 // There are also functions put, get and getnew to write or read an 00088 // array of values. These functions are defined for the same data types 00089 // as << and >> (so one can write, for example, an array of Strings). 00090 // AipsIO.put (nr, arr) writes nr values from the given array. 00091 // AipsIO.get (nr, arr) reads nr values into the given user-supplied array. 00092 // AipsIO.getnew (&nr, &arr) reads the number of values written into 00093 // a new array allocated on the heap. It returns the nr of values read 00094 // and a pointer to the array. 00095 // The data must be read back in the same order as it was written. 00096 // <p> 00097 // The functions <src>putstart(type,version)</src> 00098 // and <src>putend()</src> must be called 00099 // before resp. after writing all values of the object. 00100 // It stores the given type and version of the object. 00101 // Similarly <src>getstart(type)</src> and <src>getend()</src> must be called. 00102 // getstart checks the type and returns the version. By using the version 00103 // the read function of the object can convert older versions of the 00104 // object (which may still reside on disk) to the latest version. 00105 // The function getNextType is available to get the type of the next 00106 // object stored. This can be used to check the type or to open (i.e. 00107 // issue a getstart) in the correct way. 00108 // <p> 00109 // When implementing a class, one should also define the operators << and >> 00110 // for the class to allow users to write or read an object in this 00111 // simple way (e.g., as io >> obj; to read an object). 00112 // One has to define the friend functions: 00113 // <srcblock> 00114 // friend AipsIO& operator<< (AipsIO&, const YourClass&); 00115 // friend AipsIO& operator>> (AipsIO&, YourClass&); 00116 // </srcblock> 00117 // since they cannot be stored in the class itself. 00118 // The type of an object is usually passed as the class name. 00119 // <srcblock> 00120 // AipsIO& operator<< (AipsIO& ios, const YourClass& object) { 00121 // ios.putstart ("YourClass", version); 00122 // ios << ....; 00123 // ios.putend (); 00124 // } 00125 // </srcblock> 00126 // 00127 // The functions getpos() and setpos(offset) can be used to get and set 00128 // the offset in the file to a given point. They can be used to point 00129 // to a position in the file where an object must be written or read. 00130 // Obviously these functions are to be used by a storage manager and 00131 // are not for public use. Someday they should be made private with 00132 // a friend defined. 00133 // </synopsis> 00134 00135 // <example> 00136 // <srcblock> 00137 // MyClass myObject(...); // some object 00138 // AipsIO ios("file.name", ByteIO::New); // create new file 00139 // ios << myObject; // write object 00140 // MyClass myObject2; 00141 // ios >> myObject2; // read it back 00142 // </srcblock> 00143 // This example creates an object, writes it to AipsIO and reads it 00144 // back into another object. 00145 // The shift functions for MyClass could be defined as follows: 00146 // <srcblock> 00147 // AipsIO& operator<< (AipsIO& ios, const MyClass& myObject) 00148 // { 00149 // ios.putstart ("MyClass", 1); // MyClass version 1 00150 // ios << ...; // write all data members 00151 // ios.putend(); 00152 // } 00153 // AipsIO& operator>> (AipsIO& ios, const MyClass& myObject) 00154 // { 00155 // // If needed, delete current data members first. 00156 // // Now read in the object. 00157 // uInt version = ios.getstart ("MyClass"); 00158 // ios >> ...; // read all data members 00159 // ios.getend(); 00160 // } 00161 // </srcblock> 00162 // In this example the version is not used. In more complex objects 00163 // it will probably be used when data members get added or changed 00164 // in future versions of a software system. 00165 // </example> 00166 00167 00168 class AipsIO 00169 { 00170 public: 00171 // No file attached yet 00172 AipsIO(); 00173 00174 // Construct and open/create a file with the given name. 00175 // The actual IO is done via a CanonicalIO object on a regular file 00176 // using buffered IO with a buffer of the given size. 00177 // <br>If the MultiFileBase pointer is not null, a virtual file in the 00178 // MultiFileBase will be used instead of a regular file. 00179 explicit AipsIO (const String& fileName, 00180 ByteIO::OpenOption = ByteIO::Old, 00181 uInt filebufSize=65536, 00183 MultiFileBase* mfile=0); 00184 00185 // Construct from a stream object derived from ByteIO. 00186 // This can for instance by used to use AipsIO on a file descriptor 00187 // for which a <linkto class=FilebufIO>FilebufIO</linkto> 00188 // object has been created. 00189 // The actual IO is done via a CanonicalIO object on top of it. 00190 explicit AipsIO (ByteIO*); 00191 00192 // Construct from a stream object derived from TypeIO, thus from 00193 // a stream on top of ByteIOn doing the possible conversions. 00194 explicit AipsIO (TypeIO*); 00195 00196 // Close if not done yet 00197 ~AipsIO(); 00198 00199 // Open/create file (either a regular file or a MultiFileBase virtual file). 00200 // An exception is thrown if the object contains an already open file. 00201 void open (const String& fileName, ByteIO::OpenOption = ByteIO::Old, 00202 uInt filebufSize=65536, MultiFileBase* mfile=0); 00203 00204 // Open by connecting to the given byte stream. 00205 // This can for instance by used to use AipsIO on a file descriptor 00206 // for which a <linkto class=FilebufIO>FilebufIO</linkto> 00207 // object has been created. 00208 // The actual IO is done via a CanonicalIO object on top of it. 00209 // An exception is thrown if the object contains an already open file. 00210 void open (ByteIO*); 00211 00212 // Open by connecting to the given typed byte stream. 00213 // An exception is thrown if the object contains an already open file. 00214 void open (TypeIO*); 00215 00216 // Close file opened 00217 void close(); 00218 00219 // Return the file option. 00220 ByteIO::OpenOption fileOption() const; 00221 00222 // Start putting an object. 00223 // This writes the object type and version. When reading back getstart 00224 // calls have to be done in the same way. Getstart 00225 // checks the type and returns the version. The user can use that to 00226 // correctly read back objects with different versions. 00227 // <br> 00228 // Data in the outermost object cannot be put before a putstart is done. 00229 // Data in nested objects can be put without an intermediate putstart. 00230 // However, for complex objects it is recommended to do a putstart 00231 // to have a better checking. 00232 // <br> 00233 // After all values (inclusing nested objects) of the object have 00234 // been put, a call to putend has to be done. 00235 // <group> 00236 uInt putstart (const String& objectType, uInt objectVersion); 00237 uInt putstart (const Char* objectType, uInt objectVersion); 00238 // </group> 00239 00240 // Put a single value. 00241 // <group> 00242 AipsIO& operator<< (const Bool& value); 00243 AipsIO& operator<< (const Char& value); 00244 AipsIO& operator<< (const uChar& value); 00245 AipsIO& operator<< (const short& value); 00246 AipsIO& operator<< (const unsigned short& value); 00247 AipsIO& operator<< (const int& value); 00248 AipsIO& operator<< (const unsigned int& value); 00249 AipsIO& operator<< (const Int64& value); 00250 AipsIO& operator<< (const uInt64& value); 00251 AipsIO& operator<< (const float& value); 00252 AipsIO& operator<< (const double& value); 00253 AipsIO& operator<< (const Complex& value); 00254 AipsIO& operator<< (const DComplex& value); 00255 AipsIO& operator<< (const String& value); 00256 AipsIO& operator<< (const Char* value); 00257 // </group> 00258 00259 // Put an array of values with the given number of values. 00260 // If the flag putNr is set, the number of values is put first. 00261 // <group> 00262 AipsIO& put (uInt nrval, const Bool* values, Bool putNR = True); 00263 AipsIO& put (uInt nrval, const Char* values, Bool putNR = True); 00264 AipsIO& put (uInt nrval, const uChar* values, Bool putNR = True); 00265 AipsIO& put (uInt nrval, const short* values, Bool putNR = True); 00266 AipsIO& put (uInt nrval, const unsigned short* values, Bool putNR = True); 00267 AipsIO& put (uInt nrval, const int* values, Bool putNR = True); 00268 AipsIO& put (uInt nrval, const unsigned int* values, Bool putNR = True); 00269 AipsIO& put (uInt nrval, const Int64* values, Bool putNR = True); 00270 AipsIO& put (uInt nrval, const uInt64* values, Bool putNR = True); 00271 AipsIO& put (uInt nrval, const float* values, Bool putNR = True); 00272 AipsIO& put (uInt nrval, const double* values, Bool putNR = True); 00273 AipsIO& put (uInt nrval, const Complex* values, Bool putNR = True); 00274 AipsIO& put (uInt nrval, const DComplex* values, Bool putNR = True); 00275 AipsIO& put (uInt nrval, const String* values, Bool putNR = True); 00276 // </group> 00277 00278 // Put a vector as an array of values 00279 // For standard types it has the same result as put with putNR=True. 00280 template<typename T> 00281 AipsIO& put (const vector<T>& vec) 00282 { *this << uInt(vec.size()); 00283 for (typename vector<T>::const_iterator iter=vec.begin(); 00284 iter!=vec.end(); ++iter) { 00285 *this << *iter; 00286 } 00287 return *this; 00288 } 00289 //# Possibly specialize for standard types to make it faster. 00290 //# Specialize for a bool vector. 00291 AipsIO& put (const vector<Bool>& vec); 00292 00293 00294 // End putting an object. It returns the object length (including 00295 // possible nested objects). 00296 uInt putend(); 00297 00298 // Get and set file-offset. 00299 // <group> 00300 Int64 getpos (); 00301 Int64 setpos (Int64 offset); 00302 // </group> 00303 00304 // Get the type of the next object stored. 00305 // This is not possible if a put is in progress. 00306 const String& getNextType(); 00307 00308 // Start reading an object. It will check if the given type matches 00309 // the one stored by putstart. It returns the object version which 00310 // can be used to read in older version of the object correctly. 00311 // <br> 00312 // After all values (inclusing nested objects) of the object have 00313 // been read, a call to getend has to be done. 00314 // <group> 00315 uInt getstart (const String& objectType); 00316 uInt getstart (const Char* objectType); 00317 // </group> 00318 00319 // Get a single value. 00320 // <group> 00321 AipsIO& operator>> (Bool& value); 00322 AipsIO& operator>> (Char& value); 00323 AipsIO& operator>> (uChar& value); 00324 AipsIO& operator>> (short& value); 00325 AipsIO& operator>> (unsigned short& value); 00326 AipsIO& operator>> (int& value); 00327 AipsIO& operator>> (unsigned int& value); 00328 AipsIO& operator>> (Int64& value); 00329 AipsIO& operator>> (uInt64& value); 00330 AipsIO& operator>> (float& value); 00331 AipsIO& operator>> (double& value); 00332 AipsIO& operator>> (Complex& value); 00333 AipsIO& operator>> (DComplex& value); 00334 AipsIO& operator>> (String& value); 00335 // </group> 00336 00337 // Read in nrval values into the user-supplied values buffer. 00338 // The buffer must be long enough. 00339 // <group> 00340 AipsIO& get (uInt nrval, Bool* values); 00341 AipsIO& get (uInt nrval, Char* values); 00342 AipsIO& get (uInt nrval, uChar* values); 00343 AipsIO& get (uInt nrval, short* values); 00344 AipsIO& get (uInt nrval, unsigned short* values); 00345 AipsIO& get (uInt nrval, int* values); 00346 AipsIO& get (uInt nrval, unsigned int* values); 00347 AipsIO& get (uInt nrval, Int64* values); 00348 AipsIO& get (uInt nrval, uInt64* values); 00349 AipsIO& get (uInt nrval, float* values); 00350 AipsIO& get (uInt nrval, double* values); 00351 AipsIO& get (uInt nrval, Complex* values); 00352 AipsIO& get (uInt nrval, DComplex* values); 00353 AipsIO& get (uInt nrval, String* values); 00354 // </group> 00355 00356 // Get a vector as an array of values (similar to getnew). 00357 // It resizes the vector as needed. 00358 template<typename T> 00359 AipsIO& get (vector<T>& vec) 00360 { uInt sz; 00361 *this >> sz; 00362 vec.resize(sz); 00363 for (typename vector<T>::iterator iter=vec.begin(); 00364 iter!=vec.end(); ++iter) { 00365 *this >> *iter; 00366 } 00367 return *this; 00368 } 00369 //# Specialize for a bool vector. 00370 AipsIO& get (vector<Bool>& vec); 00371 00372 00373 // Read in values as written by the function put. 00374 // It will read the number of values (into nrval), allocate a 00375 // values buffer of that length and read the values into that buffer. 00376 // A pointer to the buffer is returned into values. 00377 // <warn=caution> Although the buffer is allocated by this function, 00378 // the user has to delete it (using <src>delete [] values;</src>). 00379 // <group> 00380 AipsIO& getnew (uInt& nrval, Bool*& values); 00381 AipsIO& getnew (uInt& nrval, Char*& values); 00382 AipsIO& getnew (uInt& nrval, uChar*& values); 00383 AipsIO& getnew (uInt& nrval, short*& values); 00384 AipsIO& getnew (uInt& nrval, unsigned short*& values); 00385 AipsIO& getnew (uInt& nrval, int*& values); 00386 AipsIO& getnew (uInt& nrval, unsigned int*& values); 00387 AipsIO& getnew (uInt& nrval, Int64*& values); 00388 AipsIO& getnew (uInt& nrval, uInt64*& values); 00389 AipsIO& getnew (uInt& nrval, float*& values); 00390 AipsIO& getnew (uInt& nrval, double*& values); 00391 AipsIO& getnew (uInt& nrval, Complex*& values); 00392 AipsIO& getnew (uInt& nrval, DComplex*& values); 00393 AipsIO& getnew (uInt& nrval, String*& values); 00394 // </group> 00395 00396 // End reading an object. It returns the object length (including 00397 // possible nested objects). 00398 // It checks if the entire object has been read (to keep the data 00399 // stream in sync). If not, an exception is thrown. 00400 uInt getend(); 00401 00402 private: 00403 // Initialize everything for the open. 00404 // It checks if there is no outstanding open file. 00405 void openInit (ByteIO::OpenOption); 00406 00407 // Test if put is possible (throw exception if not). 00408 void testput(); 00409 00410 // Test if get is possible (throw exception if not). 00411 void testget(); 00412 00413 // Test if get did not exceed object. 00414 void testgetLength(); 00415 00416 // Throw exception for testput 00417 void testputerr(); 00418 00419 // Throw exception for testget 00420 void testgeterr(); 00421 00422 // Throw exception for testgetLength 00423 void testgeterrLength(); 00424 00425 00426 // 1 = file was opened by AipsIO 00427 // 0 = file not opened 00428 // -1 = file opened by user (=fd passed) 00429 Int opened_p; 00430 // File open option 00431 ByteIO::OpenOption fopt_p; 00432 // <0 = not opened for put 00433 // 0 = no putstart done 00434 // >0 = put is possible 00435 int swput_p; 00436 // <0 = not opened for get 00437 // 0 = no getstart done 00438 // >0 = get is possible 00439 int swget_p; 00440 // Nested object level 00441 uInt level_p; 00442 // Current size of objlen and objptr 00443 uInt maxlev_p; 00444 // Object length at each level 00445 Block<uInt> objlen_p; 00446 // Object length to be read at each level 00447 Block<uInt> objtln_p; 00448 // Offset of length at each level 00449 Block<Int64> objptr_p; 00450 // True = the object type has already been read 00451 Bool hasCachedType_p; 00452 // The cached object type. 00453 String objectType_p; 00454 // The file object. 00455 ByteIO* file_p; 00456 // The actual IO object. 00457 TypeIO* io_p; 00458 // Is the file is seekable? 00459 Bool seekable_p; 00460 // magic value to check sync. 00461 static const uInt magicval_p; 00462 }; 00463 00464 00465 00466 // Return the file option. 00467 inline ByteIO::OpenOption AipsIO::fileOption() const 00468 { return fopt_p; } 00469 00470 00471 // testput tests if a put can be done; ie. if putstart has been done. 00472 // It throws an exception if not. 00473 // testget is similar to test if a get can be done. 00474 inline void AipsIO::testput() 00475 { 00476 if (swput_p <= 0) { 00477 testputerr(); 00478 } 00479 } 00480 inline void AipsIO::testget() 00481 { 00482 if (swget_p <= 0) { 00483 testgeterr(); 00484 } 00485 } 00486 inline void AipsIO::testgetLength() 00487 { 00488 if (objlen_p[level_p] > objtln_p[level_p]) { 00489 testgeterrLength(); 00490 } 00491 } 00492 00493 00494 00495 } //# NAMESPACE CASACORE - END 00496 00497 #endif