core/vsl/vsl_binary_io.h
Go to the documentation of this file.
00001 // This is core/vsl/vsl_binary_io.h
00002 #ifndef vsl_binary_io_h_
00003 #define vsl_binary_io_h_
00004 //:
00005 // \file
00006 // \brief Set of functions, and objects to perform binary IO
00007 // \author Ian Scott, Tim Cootes (Manchester) March 2001
00008 //
00009 // You should include this file if you want to do binary_io
00010 //
00011 // Also included are a set of functions
00012 // vsl_print_summary(vcl_ostream& os, bool b)
00013 // for basic types to ensure that templated classes
00014 // vsl_print_summaries can work with all types
00015 
00016 #include <vcl_iosfwd.h>
00017 #include <vcl_string.h>
00018 #include <vcl_fstream.h>
00019 #include <vcl_map.h>
00020 #include <vcl_utility.h>
00021 #include <vxl_config.h>
00022 
00023 //: A binary output adaptor for any vcl_ostream
00024 // Currently the main use of this is to encourage streams to be opened
00025 // in binary mode (ie. without CR/LF conversion)
00026 //
00027 // This class also provide basic support for serialisation. This allows an
00028 // object which has multiple pointers to it to be saved only once. During
00029 // reloading, the pointers can be all set up again to point to the single
00030 // object. vsl_b_ostream does not do the serialisation itself, but instead
00031 // keeps records of unique identifiers to allow the user's code to perform
00032 // serialisation safely. For instance, a smart pointer type object will have
00033 // to know how to safely save whatever it is pointing to.
00034 class vsl_b_ostream
00035 {
00036  public:
00037   //: Create this adaptor using an existing stream
00038   // The stream (os) must be open (i.e. ready to receive insertions)
00039   // so that the
00040   // IO version and magic number can be written by this constructor.
00041   // User is responsible for deleting os after deleting the adaptor
00042   vsl_b_ostream(vcl_ostream *os);
00043 
00044   //: A reference to the adaptor's stream
00045   vcl_ostream& os() const;
00046 
00047   //: Virtual destructor.
00048   virtual ~vsl_b_ostream() {}
00049 
00050   //: Returns true if the underlying stream has its fail bit set.
00051   bool operator!() const;
00052 
00053   //: Clear the stream's record of any serialisation operations
00054   // Calling this function while outputting serialisable things to stream,
00055   // will mean
00056   // that a second copy of an object may get stored to the stream.
00057   virtual void clear_serialisation_records();
00058 
00059 
00060   //: Adds an object pointer to the serialisation records.
00061   // Returns a unique identifier for the object.
00062   //
00063   // \a pointer must be non-null, so you should handle null pointers separately.
00064   //
00065   // You can optionally add some user-defined integer with each record
00066   // If error checking is on, and the object pointer is null or already in the records,
00067   // this function will abort()
00068   virtual unsigned long add_serialisation_record(void *pointer, int other_data = 0);
00069 
00070   //: Returns a unique identifier for the object.
00071   // Returns 0 if there is no record of the object.
00072   virtual unsigned long get_serial_number(void *pointer) const;
00073 
00074   //: Set the user-defined data associated with the object
00075   // If there is no record of the object, this function will return 0.
00076   // However a retval of 0 does not necessarily imply that the object is
00077   // unrecorded.
00078   virtual int get_serialisation_other_data(void *pointer) const;
00079 
00080   //: Modify the user-defined data associated with the object
00081   // If there is no record of the object, this function will abort.
00082   virtual int set_serialisation_other_data(void *pointer, int other_data);
00083 
00084   //: The length of the b_stream header.
00085   // You can move to this offset from the start of the file to get to
00086   // the first real data item.
00087   static const vcl_streamoff header_length;
00088 
00089  protected:
00090   //: The member stream
00091   vcl_ostream *os_;
00092 
00093   // Design notes: IMS
00094   // I used to think that a pointer and class name were needed to identify an
00095   // object. This is true if class your_class{my_class A}; your_class B;
00096   // then &B = &(B.A).
00097   // However this case doesn't arise in serialisation situations, because you
00098   // can't have shared ownership of A.
00099 
00100   // I could have used the pointer itself as the unique identifier, but it is
00101   // unreasonable to expect this to work cross-platform when the platforms have
00102   // different pointer sizes.
00103 
00104   //: The type of the serialisation records
00105   typedef vcl_map<void *, vcl_pair<unsigned long, int>, vcl_less<void *> >
00106     serialisation_records_type;
00107 
00108   //: The serialisation records
00109   // Records a pointer, a unique identifier, and an integer
00110   // (user_defined data.)
00111   serialisation_records_type serialisation_records_;
00112 
00113   //: The version number of the IO scheme.
00114   static const unsigned short version_no_;
00115 };
00116 
00117 
00118 //: An adapter for a vcl_ofstream to make it suitable for binary IO
00119 class vsl_b_ofstream: public vsl_b_ostream
00120 {
00121  public:
00122   //: Create this adaptor from a file.
00123   // The adapter will delete the internal stream automatically on destruction.
00124   vsl_b_ofstream(const vcl_string &filename,
00125                  vcl_ios_openmode mode = vcl_ios_out | vcl_ios_trunc):
00126     vsl_b_ostream(new vcl_ofstream(filename.c_str(), mode | vcl_ios_binary)) {}
00127 
00128   //: Create this adaptor from a file.
00129   // The adapter will delete the internal stream automatically on destruction.
00130   vsl_b_ofstream(const char *filename,
00131                  vcl_ios_openmode mode = vcl_ios_out | vcl_ios_trunc) :
00132     vsl_b_ostream(new vcl_ofstream(filename, mode | vcl_ios_binary)) {}
00133 
00134   //: Virtual destructor.
00135   virtual ~vsl_b_ofstream();
00136 
00137 
00138   //: Close the stream
00139   void close();
00140 };
00141 
00142 
00143 
00144 
00145 //: Test to see if a stream really is a binary vsl file.
00146 // \return false if we can't find magic numbers and correct version number.
00147 // The file pointer is reset to the beginning on leaving this function.
00148 bool vsl_b_istream_test(vcl_istream &is);
00149 
00150 //: An adaptor for any vcl_istream to make it suitable for binary input
00151 // Currently the main use of this is to encourage file streams to be opened
00152 // in binary mode (ie. without CR/LF conversion)
00153 //
00154 // This class also provide basic support for serialisation. During loading,
00155 // multiple pointers to one object can be all set up again to point to the
00156 // single object. vsl_b_ostream does not do the serialisation itself, but
00157 // instead keeps records of unique identifiers to allow the user's code to
00158 // perform serialisation safely. For instance, a smart pointer type object will
00159 // have to know how to safely save whatever it is pointing to.
00160 class vsl_b_istream
00161 {
00162  public:
00163   //: Create this adaptor using an existing stream.
00164   // The stream (is) must be open (i.e. ready to be read from) so that the
00165   // IO version and magic number can be read by this constructor.
00166   // User is responsible for deleting is after deleting the adaptor
00167   vsl_b_istream(vcl_istream *is);
00168 
00169   //: A reference to the adaptor's stream
00170   vcl_istream & is() const;
00171 
00172   //: Virtual destructor.so that it can be overloaded
00173   virtual ~vsl_b_istream() {}
00174 
00175   //: Returns true if the underlying stream has its fail bit set.
00176   bool operator!() const;
00177 
00178   //: Clear the stream's record of any serialisation operations
00179   // Calling this function while inputting serialisable things from a stream,
00180   // could cause errors during loading unless the records were cleared at a
00181   // similar point during output.
00182   virtual void clear_serialisation_records();
00183 
00184   //: Adds record of object's unique serial number, and location in memory.
00185   // \a pointer must be non-null, so you should handle null pointers separately.
00186   //
00187   // Adding a null pointer or one that already exists will cause the function to abort(),
00188   // if debugging is turned on;
00189   //
00190   // You can also store a single integer as other data.
00191   // Interpretation of this data is entirely up to the client code.
00192   virtual void add_serialisation_record(unsigned long serial_number,
00193                                         void *pointer, int other_data = 0);
00194 
00195   //: Returns the pointer to the object identified by the unique serial number.
00196   // Returns 0 if no record has been added.
00197   virtual void * get_serialisation_pointer(unsigned long serial_number) const;
00198 
00199   //: Returns the user defined data associated with the unique serial number
00200   // Returns 0 if no record has been added.
00201   virtual int get_serialisation_other_data(unsigned long serial_number) const;
00202 
00203   //: Modify the user-defined data associated with the unique serial number
00204   // If there is no record of the object, this function will abort.
00205   virtual int set_serialisation_other_data(unsigned long serial_number,
00206                                            int other_data);
00207 
00208 
00209   //: Return the version number of the IO format of the file being read.
00210   unsigned short version_no() const;
00211 
00212  protected:
00213   //: The member stream
00214   vcl_istream *is_;
00215 
00216   //: The type of the serialisation records.
00217   typedef vcl_map<unsigned long, vcl_pair<void *, int>, vcl_less<unsigned long> >
00218     serialisation_records_type;
00219 
00220   //: The serialisation records,
00221   // The record takes a unique identifier of the object (which would be
00222   // stored on the stream) and returns the pointer to the object, and
00223   // an other_data integer.
00224   serialisation_records_type serialisation_records_;
00225 
00226   // The version number of the IO format of the file being read.
00227   unsigned short version_no_;
00228 };
00229 
00230 
00231 //: An adapter for a vcl_ifstream to make it suitable for binary IO
00232 class vsl_b_ifstream: public vsl_b_istream
00233 {
00234  public:
00235   //: Create this adaptor from a file.
00236   // The adapter will delete the stream automatically on destruction.
00237   vsl_b_ifstream(const vcl_string &filename, vcl_ios_openmode mode = vcl_ios_in):
00238     vsl_b_istream(new vcl_ifstream(filename.c_str(),
00239     mode | vcl_ios_binary)) {}
00240 
00241   //: Create this adaptor from a file.
00242   // The adapter will delete the stream automatically on destruction.
00243   vsl_b_ifstream(const char *filename, vcl_ios_openmode mode = vcl_ios_in):
00244     vsl_b_istream(new vcl_ifstream(filename, mode | vcl_ios_binary)) {}
00245 
00246   //: Virtual destructor.so that it can be overloaded
00247   virtual ~vsl_b_ifstream();
00248 
00249   //: Close the stream
00250   void close();
00251 };
00252 
00253 //: Write bool to vsl_b_ostream
00254 void vsl_b_write(vsl_b_ostream& os,bool b);
00255 //: Read bool from vsl_b_istream
00256 void vsl_b_read(vsl_b_istream& is,bool& b);
00257 //: Print to a stream
00258 inline void vsl_print_summary(vcl_ostream& os, bool b )
00259 {  os << b; }
00260 
00261 //: Write char to vsl_b_ostream
00262 void vsl_b_write(vsl_b_ostream& os,char n );
00263 //: Read char from vsl_b_istream
00264 void vsl_b_read(vsl_b_istream& is,char& n );
00265 //: Print to a stream
00266 inline void vsl_print_summary(vcl_ostream& os, char n )
00267 {  os << n; }
00268 
00269 //: Write signed char to vsl_b_ostream
00270 void vsl_b_write(vsl_b_ostream& os,signed char n );
00271 //: Read  signed char from vsl_b_istream
00272 void vsl_b_read(vsl_b_istream& is,signed char& n );
00273 //: Print to a stream
00274 inline void vsl_print_summary(vcl_ostream& os, signed char n )
00275 {  os << n; }
00276 
00277 //: Write  to vsl_b_ostream
00278 void vsl_b_write(vsl_b_ostream& os,unsigned char n );
00279 //: Read  from vsl_b_istream
00280 void vsl_b_read(vsl_b_istream& is,unsigned char& n );
00281 //: Print to a stream
00282 inline void vsl_print_summary(vcl_ostream& os, unsigned char n )
00283 {  os << n; }
00284 
00285 //: Write  to vsl_b_ostream
00286 void vsl_b_write(vsl_b_ostream& os,const vcl_string& n );
00287 //: Read  from vsl_b_istream
00288 void vsl_b_read(vsl_b_istream& is,vcl_string& n );
00289 //: Print to a stream
00290 inline void vsl_print_summary(vcl_ostream& os, const vcl_string& n )
00291 {  os << n; }
00292 
00293 //: Write  to vsl_b_ostream
00294 // \deprecated in favour of vcl_string version.
00295 void vsl_b_write(vsl_b_ostream& os,const char* s );
00296 //: Read  from vsl_b_istream
00297 // \deprecated in favour of vcl_string version.
00298 // \note You must preallocate enough space at \p s for expected length of string.
00299 // This function is easy to crash mith a malformed data file.
00300 void vsl_b_read(vsl_b_istream& is,char* s );
00301 //: Print to a stream
00302 inline void vsl_print_summary(vcl_ostream& os, const char* s )
00303 {  os << s; }
00304 
00305 
00306 // Visual Studio .NET on a 32-bit platform can check for 64-bit
00307 // portability issues. When these warnings (/Wp64) are turn on,
00308 // passing a ptrdiff_t as an int triggers a warning. The __w64
00309 // keyword suppresses that warning here, because it's not a problem.
00310 // On a real 64-bit platform, there will presumably be an overloaded
00311 // vsl_b_write for the 64-bit integral type. We don't want to suppress
00312 // the warning (C4244) completely, because it is a useful warning.
00313 // 08/20/2003: Added macro that defines whether or not attribute needs
00314 //             to be used. A new version of MS .NET compiler required this change.
00315 //             Add compilers as needed. This could be moved to vcl_compiler.h. 
00316 //             [Nils Krahnstoever]
00317 #ifdef VCL_VC_DOTNET
00318 # define VCL_64BIT_ATTR __w64
00319 #else
00320 # define VCL_64BIT_ATTR /* */
00321 #endif
00322 
00323 //: Write  to vsl_b_ostream
00324 void vsl_b_write(vsl_b_ostream& os, int VCL_64BIT_ATTR n );
00325 //: Read  from vsl_b_istream
00326 void vsl_b_read(vsl_b_istream& is, int VCL_64BIT_ATTR &n );
00327 //: Print to a stream
00328 inline void vsl_print_summary(vcl_ostream& os, int VCL_64BIT_ATTR n )
00329 {  os << int(n); }
00330 
00331 #undef VCL_64BIT_ATTR
00332 
00333 //: Write  to vsl_b_ostream
00334 void vsl_b_write(vsl_b_ostream& os,unsigned int n );
00335 //: Read  from vsl_b_istream
00336 void vsl_b_read(vsl_b_istream& is,unsigned int& n );
00337 //: Print to a stream
00338 inline void vsl_print_summary(vcl_ostream& os, unsigned int n )
00339 {  os << n; }
00340 
00341 //: Write  to vsl_b_ostream
00342 void vsl_b_write(vsl_b_ostream& os,short n );
00343 //: Read  from vsl_b_istream
00344 void vsl_b_read(vsl_b_istream& is,short& n );
00345 //: Print to a stream
00346 inline void vsl_print_summary(vcl_ostream& os, short n )
00347 {  os << n; }
00348 
00349 //: Write  to vsl_b_ostream
00350 void vsl_b_write(vsl_b_ostream& os,unsigned short n );
00351 //: Read  from vsl_b_istream
00352 void vsl_b_read(vsl_b_istream& is,unsigned short& n );
00353 //: Print to a stream
00354 inline void vsl_print_summary(vcl_ostream& os, unsigned short n )
00355 {  os << n; }
00356 
00357 //: Write  to vsl_b_ostream
00358 void vsl_b_write(vsl_b_ostream& os,long n );
00359 //: Read  from vsl_b_istream
00360 void vsl_b_read(vsl_b_istream& is,long& n );
00361 //: Print to a stream
00362 inline void vsl_print_summary(vcl_ostream& os, long n )
00363 {  os << n; }
00364 
00365 //: Write  to vsl_b_ostream
00366 void vsl_b_write(vsl_b_ostream& os,unsigned long n );
00367 //: Read  from vsl_b_istream
00368 void vsl_b_read(vsl_b_istream& is,unsigned long& n );
00369 //: Print to a stream
00370 inline void vsl_print_summary(vcl_ostream& os, unsigned long n )
00371 {  os << n; }
00372 
00373 #if VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG
00374 
00375 //: Write  to vsl_b_ostream
00376 void vsl_b_write(vsl_b_ostream& os,vxl_int_64 n );
00377 //: Read  from vsl_b_istream
00378 void vsl_b_read(vsl_b_istream& is,vxl_int_64& n );
00379 //: Print to a stream
00380 inline void vsl_print_summary(vcl_ostream& os, vxl_int_64 n )
00381 {
00382 #if defined(VCL_VC_6)  // IMS. This Hack could be replaced by code which
00383   os << "****";        // splits the 64bit int and doesn the right thing.
00384 #else
00385   os << n;
00386 #endif
00387 }
00388 
00389 //: Write  to vsl_b_ostream
00390 void vsl_b_write(vsl_b_ostream& os,vxl_uint_64 n );
00391 //: Read  from vsl_b_istream
00392 void vsl_b_read(vsl_b_istream& is,vxl_uint_64& n );
00393 //: Print to a stream
00394 inline void vsl_print_summary(vcl_ostream& os, vxl_uint_64 n )
00395 {
00396 #if defined(VCL_VC_6)  // IMS. This Hack could be replaced by code which
00397   os << "****";        // splits the 64bit int and doesn the right thing.
00398 #else
00399   os << n;
00400 #endif
00401 }
00402 
00403 #endif // VXL_HAS_INT_64
00404 
00405 //: Write  to vsl_b_ostream
00406 // Number is saved with ANSI/IEEE Standard 754-1985 single precision.
00407 void vsl_b_write(vsl_b_ostream& os,float n );
00408 //: Read  from vsl_b_istream
00409 void vsl_b_read(vsl_b_istream& is,float& n );
00410 //: Print to a stream
00411 inline void vsl_print_summary(vcl_ostream& os, float n )
00412 {  os << n; }
00413 
00414 //: Write  to vsl_b_ostream
00415 // Number is saved with ANSI/IEEE Standard 754-1985 double precision.
00416 void vsl_b_write(vsl_b_ostream& os,double n );
00417 //: Read  from vsl_b_istream
00418 void vsl_b_read(vsl_b_istream& is,double& n );
00419 //: Print to a stream
00420 inline void vsl_print_summary(vcl_ostream& os, double n )
00421 { os << n; }
00422 
00423 
00424 #endif // vsl_binary_io_h_