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_