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 //: An adaptor for any vcl_istream to make it suitable for binary input
00144 // Currently the main use of this is to encourage file streams to be opened
00145 // in binary mode (ie. without CR/LF conversion)
00146 //
00147 // This class also provide basic support for serialisation. During loading,
00148 // multiple pointers to one object can be all set up again to point to the
00149 // single object. vsl_b_ostream does not do the serialisation itself, but
00150 // instead keeps records of unique identifiers to allow the user's code to
00151 // perform serialisation safely. For instance, a smart pointer type object will
00152 // have to know how to safely save whatever it is pointing to.
00153 class vsl_b_istream
00154 {
00155  public:
00156   //: Create this adaptor using an existing stream.
00157   // The stream (is) must be open (i.e. ready to be read from) so that the
00158   // IO version and magic number can be read by this constructor.
00159   // User is responsible for deleting is after deleting the adaptor
00160   vsl_b_istream(vcl_istream *is);
00161 
00162   //: A reference to the adaptor's stream
00163   vcl_istream & is() const;
00164 
00165   //: Virtual destructor.so that it can be overloaded
00166   virtual ~vsl_b_istream() {}
00167 
00168   //: Returns true if the underlying stream has its fail bit set.
00169   bool operator!() const;
00170 
00171   //: Clear the stream's record of any serialisation operations
00172   // Calling this function while inputting serialisable things from a stream,
00173   // could cause errors during loading unless the records were cleared at a
00174   // similar point during output.
00175   virtual void clear_serialisation_records();
00176 
00177   //: Adds record of object's unique serial number, and location in memory.
00178   // \a pointer must be non-null, so you should handle null pointers separately.
00179   //
00180   // Adding a null pointer or one that already exists will cause the function to abort(),
00181   // if debugging is turned on;
00182   //
00183   // You can also store a single integer as other data.
00184   // Interpretation of this data is entirely up to the client code.
00185   virtual void add_serialisation_record(unsigned long serial_number,
00186                                         void *pointer, int other_data = 0);
00187 
00188   //: Returns the pointer to the object identified by the unique serial number.
00189   // Returns 0 if no record has been added.
00190   virtual void * get_serialisation_pointer(unsigned long serial_number) const;
00191 
00192   //: Returns the user defined data associated with the unique serial number
00193   // Returns 0 if no record has been added.
00194   virtual int get_serialisation_other_data(unsigned long serial_number) const;
00195 
00196   //: Modify the user-defined data associated with the unique serial number
00197   // If there is no record of the object, this function will abort.
00198   virtual int set_serialisation_other_data(unsigned long serial_number,
00199                                            int other_data);
00200 
00201 
00202   //: Return the version number of the IO format of the file being read.
00203   unsigned short version_no() const;
00204 
00205  protected:
00206   //: The member stream
00207   vcl_istream *is_;
00208 
00209   //: The type of the serialisation records.
00210   typedef vcl_map<unsigned long, vcl_pair<void *, int>, vcl_less<unsigned long> >
00211     serialisation_records_type;
00212 
00213   //: The serialisation records,
00214   // The record takes a unique identifier of the object (which would be
00215   // stored on the stream) and returns the pointer to the object, and
00216   // an other_data integer.
00217   serialisation_records_type serialisation_records_;
00218 
00219   // The version number of the IO format of the file being read.
00220   unsigned short version_no_;
00221 };
00222 
00223 
00224 //: An adapter for a vcl_ifstream to make it suitable for binary IO
00225 class vsl_b_ifstream: public vsl_b_istream
00226 {
00227  public:
00228   //: Create this adaptor from a file.
00229   // The adapter will delete the stream automatically on destruction.
00230   vsl_b_ifstream(const vcl_string &filename, vcl_ios_openmode mode = vcl_ios_in):
00231     vsl_b_istream(new vcl_ifstream(filename.c_str(),
00232     mode | vcl_ios_binary)) {}
00233 
00234   //: Create this adaptor from a file.
00235   // The adapter will delete the stream automatically on destruction.
00236   vsl_b_ifstream(const char *filename, vcl_ios_openmode mode = vcl_ios_in):
00237     vsl_b_istream(new vcl_ifstream(filename, mode | vcl_ios_binary)) {}
00238 
00239   //: Virtual destructor.so that it can be overloaded
00240   virtual ~vsl_b_ifstream();
00241 
00242   //: Close the stream
00243   void close();
00244 };
00245 
00246 //: Write bool to vsl_b_ostream
00247 void vsl_b_write(vsl_b_ostream& os,bool b);
00248 //: Read bool from vsl_b_istream
00249 void vsl_b_read(vsl_b_istream& is,bool& b);
00250 //: Print to a stream
00251 inline void vsl_print_summary(vcl_ostream& os, bool b )
00252 {  os << b; }
00253 
00254 //: Write char to vsl_b_ostream
00255 void vsl_b_write(vsl_b_ostream& os,char n );
00256 //: Read char from vsl_b_istream
00257 void vsl_b_read(vsl_b_istream& is,char& n );
00258 //: Print to a stream
00259 inline void vsl_print_summary(vcl_ostream& os, char n )
00260 {  os << n; }
00261 
00262 //: Write signed char to vsl_b_ostream
00263 void vsl_b_write(vsl_b_ostream& os,signed char n );
00264 //: Read  signed char from vsl_b_istream
00265 void vsl_b_read(vsl_b_istream& is,signed char& n );
00266 //: Print to a stream
00267 inline void vsl_print_summary(vcl_ostream& os, signed char n )
00268 {  os << n; }
00269 
00270 //: Write  to vsl_b_ostream
00271 void vsl_b_write(vsl_b_ostream& os,unsigned char n );
00272 //: Read  from vsl_b_istream
00273 void vsl_b_read(vsl_b_istream& is,unsigned char& n );
00274 //: Print to a stream
00275 inline void vsl_print_summary(vcl_ostream& os, unsigned char n )
00276 {  os << n; }
00277 
00278 //: Write  to vsl_b_ostream
00279 void vsl_b_write(vsl_b_ostream& os,const vcl_string& n );
00280 //: Read  from vsl_b_istream
00281 void vsl_b_read(vsl_b_istream& is,vcl_string& n );
00282 //: Print to a stream
00283 inline void vsl_print_summary(vcl_ostream& os, const vcl_string& n )
00284 {  os << n; }
00285 
00286 //: Write  to vsl_b_ostream
00287 // \deprecated in favour of vcl_string version.
00288 void vsl_b_write(vsl_b_ostream& os,const char* s );
00289 //: Read  from vsl_b_istream
00290 // \deprecated in favour of vcl_string version.
00291 // \note You must preallocate enough space at \p s for expected length of string.
00292 // This function is easy to crash mith a malformed data file.
00293 void vsl_b_read(vsl_b_istream& is,char* s );
00294 //: Print to a stream
00295 inline void vsl_print_summary(vcl_ostream& os, const char* s )
00296 {  os << s; }
00297 
00298 
00299 // Visual Studio .NET on a 32-bit platform can check for 64-bit
00300 // portability issues. When these warnings (/Wp64) are turn on,
00301 // passing a ptrdiff_t as an int triggers a warning. The __w64
00302 // keyword suppresses that warning here, because it's not a problem.
00303 // On a real 64-bit platform, there will presumably be an overloaded
00304 // vsl_b_write for the 64-bit integral type. We don't want to suppress
00305 // the warning (C4244) completely, because it is a useful warning.
00306 // 08/20/2003: Added macro that defines whether or not attribute needs
00307 //             to be used. A new version of MS .NET compiler required this change.
00308 //             Add compilers as needed. This could be moved to vcl_compiler.h. 
00309 //             [Nils Krahnstoever]
00310 #ifdef VCL_VC_DOTNET
00311 # define VCL_64BIT_ATTR __w64
00312 #else
00313 # define VCL_64BIT_ATTR /* */
00314 #endif
00315 
00316 //: Write  to vsl_b_ostream
00317 void vsl_b_write(vsl_b_ostream& os, int VCL_64BIT_ATTR n );
00318 //: Read  from vsl_b_istream
00319 void vsl_b_read(vsl_b_istream& is, int VCL_64BIT_ATTR &n );
00320 //: Print to a stream
00321 inline void vsl_print_summary(vcl_ostream& os, int VCL_64BIT_ATTR n )
00322 {  os << int(n); }
00323 
00324 #undef VCL_64BIT_ATTR
00325 
00326 //: Write  to vsl_b_ostream
00327 void vsl_b_write(vsl_b_ostream& os,unsigned int n );
00328 //: Read  from vsl_b_istream
00329 void vsl_b_read(vsl_b_istream& is,unsigned int& n );
00330 //: Print to a stream
00331 inline void vsl_print_summary(vcl_ostream& os, unsigned int n )
00332 {  os << n; }
00333 
00334 //: Write  to vsl_b_ostream
00335 void vsl_b_write(vsl_b_ostream& os,short n );
00336 //: Read  from vsl_b_istream
00337 void vsl_b_read(vsl_b_istream& is,short& n );
00338 //: Print to a stream
00339 inline void vsl_print_summary(vcl_ostream& os, short n )
00340 {  os << n; }
00341 
00342 //: Write  to vsl_b_ostream
00343 void vsl_b_write(vsl_b_ostream& os,unsigned short n );
00344 //: Read  from vsl_b_istream
00345 void vsl_b_read(vsl_b_istream& is,unsigned short& n );
00346 //: Print to a stream
00347 inline void vsl_print_summary(vcl_ostream& os, unsigned short n )
00348 {  os << n; }
00349 
00350 //: Write  to vsl_b_ostream
00351 void vsl_b_write(vsl_b_ostream& os,long n );
00352 //: Read  from vsl_b_istream
00353 void vsl_b_read(vsl_b_istream& is,long& n );
00354 //: Print to a stream
00355 inline void vsl_print_summary(vcl_ostream& os, long n )
00356 {  os << n; }
00357 
00358 //: Write  to vsl_b_ostream
00359 void vsl_b_write(vsl_b_ostream& os,unsigned long n );
00360 //: Read  from vsl_b_istream
00361 void vsl_b_read(vsl_b_istream& is,unsigned long& n );
00362 //: Print to a stream
00363 inline void vsl_print_summary(vcl_ostream& os, unsigned long n )
00364 {  os << n; }
00365 
00366 #if VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG
00367 
00368 //: Write  to vsl_b_ostream
00369 void vsl_b_write(vsl_b_ostream& os,vxl_int_64 n );
00370 //: Read  from vsl_b_istream
00371 void vsl_b_read(vsl_b_istream& is,vxl_int_64& n );
00372 //: Print to a stream
00373 inline void vsl_print_summary(vcl_ostream& os, vxl_int_64 n )
00374 {
00375 #if defined(VCL_VC_6)  // IMS. This Hack could be replaced by code which
00376   os << "****";        // splits the 64bit int and doesn the right thing.
00377 #else
00378   os << n;
00379 #endif
00380 }
00381 
00382 //: Write  to vsl_b_ostream
00383 void vsl_b_write(vsl_b_ostream& os,vxl_uint_64 n );
00384 //: Read  from vsl_b_istream
00385 void vsl_b_read(vsl_b_istream& is,vxl_uint_64& n );
00386 //: Print to a stream
00387 inline void vsl_print_summary(vcl_ostream& os, vxl_uint_64 n )
00388 {
00389 #if defined(VCL_VC_6)  // IMS. This Hack could be replaced by code which
00390   os << "****";        // splits the 64bit int and doesn the right thing.
00391 #else
00392   os << n;
00393 #endif
00394 }
00395 
00396 #endif // VXL_HAS_INT_64
00397 
00398 //: Write  to vsl_b_ostream
00399 // Number is saved with ANSI/IEEE Standard 754-1985 single precision.
00400 void vsl_b_write(vsl_b_ostream& os,float n );
00401 //: Read  from vsl_b_istream
00402 void vsl_b_read(vsl_b_istream& is,float& n );
00403 //: Print to a stream
00404 inline void vsl_print_summary(vcl_ostream& os, float n )
00405 {  os << n; }
00406 
00407 //: Write  to vsl_b_ostream
00408 // Number is saved with ANSI/IEEE Standard 754-1985 double precision.
00409 void vsl_b_write(vsl_b_ostream& os,double n );
00410 //: Read  from vsl_b_istream
00411 void vsl_b_read(vsl_b_istream& is,double& n );
00412 //: Print to a stream
00413 inline void vsl_print_summary(vcl_ostream& os, double n )
00414 { os << n; }
00415 
00416 
00417 #endif // vsl_binary_io_h_