Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

LoadSave.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_LoadSave_h
00003 #define INCLUDED_LoadSave_h
00004 
00005 #include <string>
00006 #include <sys/param.h>
00007 #include <stdexcept>
00008 #include <stdarg.h>
00009 #include "attributes.h"
00010 
00011 #ifdef PLATFORM_APERIOS
00012 //! prototype declared only on PLATFORM_APERIOS; system provides an implementation, but apparently no API declaration
00013 int vasprintf(char** ret, const char* format, va_list al);
00014 #endif
00015 
00016 /*! @def LOADSAVE_SWAPBYTES
00017  *  @brief Set to 0 on platforms which don't actually need to swap bytes, 1 otherwise.  If not set externally, will attempt to auto-detect.
00018  *  Swapping is performed to standardize on little-endian byte order.  Mainly because this is what we used on the Aibo, which
00019  *  was the most processor-starved platform.  If running embedded on other platforms, you may want to reverse the logic
00020  *  for determining whether byte swapping will be performed! */
00021 #ifndef LOADSAVE_SWAPBYTES
00022 
00023 #ifdef BYTE_ORDER
00024 #  if BYTE_ORDER == BIG_ENDIAN
00025 #    define LOADSAVE_SWAPBYTES 1
00026 #  elif BYTE_ORDER == LITTLE_ENDIAN
00027 #    define LOADSAVE_SWAPBYTES 0
00028 #  else
00029 #    warning unknown byte ordering for current platform, assuming no swap
00030 #    define LOADSAVE_SWAPBYTES 0
00031 #  endif
00032 #else
00033 //aperios distribution doesn't actually define BYTE_ORDER :(
00034 //just as well, since we're using that byte order anyway
00035 #  ifdef PLATFORM_APERIOS
00036 //!On PLATFORM_APERIOS, we avoid swapping bytes, since it's likely to be the most CPU constrained platform
00037 #    define LOADSAVE_SWAPBYTES 0
00038 #  else
00039 #    warning unknown byte ordering for current platform, assuming no swap
00040 #    define LOADSAVE_SWAPBYTES 0
00041 #  endif
00042 #endif
00043 
00044 #endif
00045 
00046 //! Intended as an interface to allow easy and portable serialization operations
00047 /*! Generally, for triggering serialization of a LoadSave subclass, all you need to know is to call saveFile() /
00048     saveBuffer() in order to have the class serialize itself, and loadFile() /
00049     loadBuffer() in order to reload the data.
00050     
00051     When saveFile() is called, it checks that it can open the specified file, and then calls
00052     saveFileStream() with the open file.  This will then check getBinSize(), create a buffer of that
00053     size, and call saveBuffer() to do the actual work of serialization into that buffer.  If
00054     saveBuffer is successful, saveFileStream() copies the buffer out to the file, and then finally,
00055     saveFile() will close the file.
00056     
00057     This means when writing a class which requires serialization, you need only define 3 functions:
00058     loadBuffer(), saveBuffer(), and getBinSize().  If you are saving directly into a file and need
00059     the highest possible performance, overriding loadFileStream and saveFileStream and
00060     reimplementing the serialization operations into the file stream can save a buffer copy.
00061     Usually this is not a performance issue, but the interface is there if you need it.
00062     
00063     The recommended style for using LoadSave in classes with multiple levels of inheritance is to
00064     have each subclass first call the superclass's implementation (e.g. of loadBuffer/saveBuffer),
00065     and then save their own data afterward.  This compartmentalizes the data access and makes it
00066     easy to maintain - the code that serializes is right in with the code that defines the
00067     structure.  If you change one, it's easy to see where to change the other.  And protection
00068     between levels of inheritance is retained.  (This is why I say it's highly
00069     flexible/maintainable, but poor readability since the serialization is all broken up.)
00070     
00071     I also recommend putting a little string header at the beginning of each class's info via saveCreator() and checkCreator().  This
00072     will allow polymorphism when loading files (you can look at the string and create the
00073     appropriate type) but also is handy for checking field alignment... it's a lot easier to tell
00074     how much you're offset within a string than to do the same with a stream of binary values.
00075     Further, you can use the string as version information if you want to be backward compatible in
00076     future versions of your code.
00077   
00078     LoadSave provides a series of encode() and decode() functions for all the primitive types.  This
00079     will handle copying the value into the buffer or file, and can provide platform independence
00080     through byte swapping if needed (there's a compiler flag you can set for platforms that have the
00081     opposite byte order, although this should be autodetected from the system headers).
00082     Most of these are pretty straightfoward - an int is just 4 bytes and so on.
00083   
00084     However, there's one caveat that I want to make sure to point out if you have to write parsing
00085     code in say, Java.  Strings are encoded by first storing an int to hold the string's length,
00086     then the string itself, and then a null character.  This adds 5 bytes to the length of any
00087     string, but makes loading the files much easier/faster - you can call string library functions
00088     directly on the buffer if it's already in memory since the string is null terminated, or can
00089     allocate memory to hold the string with one pass from a file because you'll know the
00090     size of the string before you get to it.
00091   
00092     Of course, the string serialization format is transparent if you just stick to using LoadSave's
00093     encode/decode functions to parse it.
00094 */
00095 class LoadSave {
00096  public:
00097   //! This is the amount of extra space needed to store a string (int for len of string plus 1 for @code '\0' @endcode termination)
00098   static const unsigned int stringpad=sizeof(unsigned int)+1;
00099 
00100   //!@name Constructors/Destructors
00101   /*! @brief constructor */
00102   LoadSave() {}
00103   virtual ~LoadSave(); //!< destructor
00104   //@}
00105 
00106   /*! @brief These are useful for sending the data across a network as well as to a file.\n
00107    *  These three functions (getBinSize(), loadBuffer(), saveBuffer() ) are the only ones that MUST be
00108    *  overridden, as the file stream versions can be based on calling these.  However, you can override
00109    *  the file stream versions as well if speed or temp. memory is tight. */
00110   //!@name Buffer Operations
00111   
00112   //! Calculates space needed to save - if you can't precisely add up the size, just make sure to overestimate and things will still work.
00113   /*! getBinSize is used for reserving buffers during serialization, but does not necessarily determine
00114    *  the actual size of what is written -- the return value of saveBuffer() specifies that after the data
00115    *  actually has been written.  If getBinSize overestimates, the extra memory allocation is only
00116    *  temporary, no extra filler bytes are actually stored.
00117    *  @return number of bytes read/written, 0 if error (or empty) */
00118   virtual unsigned int getBinSize() const =0;
00119   //! Load from a saved buffer in memory
00120   /*! @param buf pointer to the memory where you should begin loading
00121    *  @param len length of @a buf available (this isn't necessarily all yours, there might be other things following your data)
00122    *  @return the number of bytes actually used */
00123   virtual unsigned int loadBuffer(const char buf[], unsigned int len)=0;
00124   //! Save to a given buffer in memory
00125   /*! @param buf pointer to the memory where you should begin writing
00126    *  @param len length of @a buf available.  (this isn't necessarily all yours, constrain yourself to what you returned in getBinSize() )
00127    *  @return the number of bytes actually used */
00128   virtual unsigned int saveBuffer(char buf[], unsigned int len) const =0;
00129   //@}
00130 
00131   //!These are called to load and save to files
00132   //!@name File Operations
00133   /*!@brief initiate opening of the specified file and loading/saving of all appropriate information.
00134    * @param filename the file to load/save @return number of bytes read/written, 0 if error (or empty)*/
00135   virtual unsigned int loadFile(const char* filename);
00136   virtual unsigned int saveFile(const char* filename) const;
00137   
00138   //!Used recursively on member objects once a file is already open - DON'T CLOSE the file in your overridden functions
00139   /*! @param f a pointer to the file to load
00140    *  @return number of bytes read, 0 if error (or empty) */
00141   virtual unsigned int loadFileStream(FILE* f);
00142   //!Used recursively on member objects once a file is already open - DON'T CLOSE the file in your overridden functions
00143   /*! @param f a pointer to the file to save
00144    *  @return number of bytes written, 0 if error (or empty) */
00145   virtual unsigned int saveFileStream(FILE* f) const;
00146 
00147   //! deprecated, use loadFile() instead (refactored to standardize capitalization style)
00148   virtual unsigned int LoadFile(const char* filename) ATTR_deprecated;
00149   //! deprecated, use saveFile() instead (refactored to standardize capitalization style)
00150   virtual unsigned int SaveFile(const char* filename) const ATTR_deprecated;
00151   //@}
00152 
00153   //! Handy for checking results from functions which manipulate a buffer (see also encodeInc()/decodeInc() )  If res is 0, returns false
00154   /*! Doesn't have to be used with encode/decode, also handy with snprintf, sscanf type operations using %n
00155    *  @param res number of bytes used, or 0 if error
00156    *  @param buf pointer to current position in buffer, will be incremented by @a res bytes
00157    *  @param len number of bytes remain between current place and end of buffer, will be decremented by @a res bytes
00158    *  @return true if everything worked, false otherwise */
00159   static inline bool checkInc(int res, const char*& buf, unsigned int& len) throw();
00160   
00161   //! Handy for checking results from functions which manipulate a buffer (see also encodeInc()/decodeInc() )  If res is 0, displays the specified message on stderr and returns false.
00162   /*! Doesn't have to be used with encode/decode, also handy with snprintf, sscanf type operations using %n
00163    *  @param res number of bytes used, or 0 if error
00164    *  @param buf pointer to current position in buffer, will be incremented by @a res bytes
00165    *  @param len number of bytes remain between current place and end of buffer, will be decremented by @a res bytes
00166    *  @param msg Error to display if res is less than or equal to zero
00167    *  @return true if everything worked, false otherwise */
00168   static inline bool checkInc(int res, const char*& buf, unsigned int& len, const char* msg, ...) throw() __attribute__((format(printf,4,5)));
00169   
00170   //! Handy for checking results from functions which manipulate a buffer (see also encodeInc()/decodeInc() ).  If res is 0, returns false
00171   /*! Doesn't have to be used with encode/decode, also handy with snprintf, sscanf type operations using %n
00172    *  @param res number of bytes used, or 0 if error
00173    *  @param buf pointer to current position in buffer, will be incremented by @a res bytes
00174    *  @param len number of bytes remain between current place and end of buffer, will be decremented by @a res bytes
00175    *  @return true if everything worked, false otherwise */
00176   static inline bool checkInc(int res, char*& buf, unsigned int& len) throw();
00177   
00178   //! Handy for checking results from functions which manipulate a buffer (see also encodeInc()/decodeInc() ).  If res is 0, displays the specified message on stderr and returns false.
00179   /*! Doesn't have to be used with encode/decode, also handy with snprintf, sscanf type operations using %n
00180    *  @param res number of bytes used, or 0 if error
00181    *  @param buf pointer to current position in buffer, will be incremented by @a res bytes
00182    *  @param len number of bytes remain between current place and end of buffer, will be decremented by @a res bytes
00183    *  @param msg Error to display if res is less than or equal to zero
00184    *  @return true if everything worked, false otherwise */
00185   static inline bool checkInc(int res, char*& buf, unsigned int& len, const char* msg, ...) throw() __attribute__((format(printf,4,5)));
00186   
00187   //! Handy for checking results from functions which manipulate a buffer (see also encodeInc()/decodeInc() )  If res is 0, throws a std::length_error with the specified message.
00188   /*! Doesn't have to be used with encode/decode, also handy with snprintf, sscanf type operations using %n
00189    *  @param res number of bytes used, or 0 if error
00190    *  @param buf pointer to current position in buffer, will be incremented by @a res bytes
00191    *  @param len number of bytes remain between current place and end of buffer, will be decremented by @a res bytes
00192    *  @param msg Error message to throw in the std::length_error if res is less than or equal to zero */
00193   static inline void checkIncT(int res, const char*& buf, unsigned int& len, const char* msg="LoadSave::check underflow", ...) throw(std::length_error) __attribute__((format(printf,4,5)));
00194   
00195   //! Handy for checking results from functions which manipulate a buffer (see also encodeInc()/decodeInc() ).  If res is 0, throws a std::length_error with the specified message.
00196   /*! Doesn't have to be used with encode/decode, also handy with snprintf, sscanf type operations using %n
00197    *  @param res number of bytes used, or 0 if error
00198    *  @param buf pointer to current position in buffer, will be incremented by @a res bytes
00199    *  @param len number of bytes remain between current place and end of buffer, will be decremented by @a res bytes
00200    *  @param msg Error message to throw in the std::length_error if res is less than or equal to zero */
00201   static inline void checkIncT(int res, char*& buf, unsigned int& len, const char* msg="LoadSave::check underflow", ...) throw(std::length_error) __attribute__((format(printf,4,5)));
00202   
00203   //! Encodes @a value into the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, returns false
00204   /*! @param value the value to encode, must be a primitive or a LoadSave subclass (i.e. a value for which encode() is defined)
00205    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00206    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00207    *  @return true if everything worked, false otherwise */
00208   template <class T> static inline bool encodeInc(const T& value, char*& buf, unsigned int& cap) throw();
00209 
00210   //! Encodes @a value into the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, displays the specified message on stderr and returns false.
00211   /*! @param value the value to encode, must be a primitive or a LoadSave subclass (i.e. a value for which encode() is defined)
00212    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00213    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00214    *  @param msg Error to display if @a buf did not have enough capacity
00215    *  @return true if everything worked, false otherwise */
00216   template <class T> static inline bool encodeInc(const T& value, char*& buf, unsigned int& cap, const char* msg, ...) throw() __attribute__((format(printf,4,5)));
00217 
00218   //! Decodes @a value from the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, returns false
00219   /*! @param value the value to decode into, must be a primitive or a LoadSave subclass (i.e. a value for which decode() is defined)
00220    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00221    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00222    *  @return true if everything worked, false otherwise */
00223   template <class T> static inline bool decodeInc(T& value, const char*& buf, unsigned int& cap) throw();
00224   
00225   //! Decodes @a value from the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, displays the specified message on stderr and returns false.
00226   /*! @param value the value to decode into, must be a primitive or a LoadSave subclass (i.e. a value for which decode() is defined)
00227    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00228    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00229    *  @param msg Error to display if @a buf did not have enough capacity
00230    *  @return true if everything worked, false otherwise */
00231   template <class T> static inline bool decodeInc(T& value, const char*& buf, unsigned int& cap, const char* msg, ...) throw() __attribute__((format(printf,4,5)));
00232   
00233   //! Decodes @a value from the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, returns false.
00234   /*! @param value the value to decode into, must be a primitive or a LoadSave subclass (i.e. a value for which decode() is defined)
00235    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00236    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00237    *  @return true if everything worked, false otherwise */
00238   template <class T> static inline bool decodeInc(T& value, char*& buf, unsigned int& cap) throw();
00239   
00240   //! Decodes @a value from the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, displays the specified message on stderr and returns false.
00241   /*! @param value the value to decode into, must be a primitive or a LoadSave subclass (i.e. a value for which decode() is defined)
00242    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00243    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00244    *  @param msg Error to display if @a buf did not have enough capacity
00245    *  @return true if everything worked, false otherwise */
00246   template <class T> static inline bool decodeInc(T& value, char*& buf, unsigned int& cap, const char* msg, ...) throw() __attribute__((format(printf,4,5)));
00247   
00248   //! Encodes @a value into the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, throws a std::length_error with the specified message.
00249   /*! @param value the value to encode, must be a primitive or a LoadSave subclass (i.e. a value for which encode() is defined)
00250    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00251    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00252    *  @param msg Error to display if @a buf did not have enough capacity */
00253   template <class T> static inline void encodeIncT(const T& value, char*& buf, unsigned int& cap, const char* msg="LoadSave::encode overflow", ...) throw(std::length_error) __attribute__((format(printf,4,5)));
00254 
00255   //! Decodes @a value from the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, throws a std::length_error with the specified message.
00256   /*! @param value the value to decode into, must be a primitive or a LoadSave subclass (i.e. a value for which decode() is defined)
00257    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00258    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00259    *  @param msg Error to display if @a buf did not have enough capacity */
00260   template <class T> static inline void decodeIncT(T& value, const char*& buf, unsigned int& cap, const char* msg="LoadSave::decode underflow", ...) throw(std::length_error) __attribute__((format(printf,4,5)));
00261   
00262   //! Decodes @a value from the buffer and if successful, increments the the buffer position and decrements the capacity.  If unsuccessful, throws a std::length_error with the specified message.
00263   /*! @param value the value to decode into, must be a primitive or a LoadSave subclass (i.e. a value for which decode() is defined)
00264    *  @param buf pointer to current position in buffer, will be incremented by the serialized size of @a value
00265    *  @param cap number of bytes remain between current place and end of buffer, will be decremented by the serialized size of @a value
00266    *  @param msg Error to display if @a buf did not have enough capacity */
00267   template <class T> static inline void decodeIncT(T& value, char*& buf, unsigned int& cap, const char* msg="LoadSave::decode underflow", ...) throw(std::length_error) __attribute__((format(printf,4,5)));
00268   
00269   //! deprecated, use checkInc() instead (provides less error-prone interface (NULL not allowed), mixes better with other new *Inc varients)
00270   static bool chkAdvance(int res, const char** buf, unsigned int* len, const char* msg, ...) ATTR_deprecated __attribute__((format(printf,4,5)));
00271 
00272   /*! @brief These are expected to be called from within your own getBinSize implementation in order to add up the size of all the member fields.
00273    *  Use these instead of sizeof() because this allows proper handling of some oddball conditions (bool isn't 1 byte on some platforms, use strlen on char*, etc.) */
00274   //! @name Methods to detect the size member fields
00275   /*! @brief returns the serialized size of the argument */
00276   inline static unsigned int getSerializedSize(const LoadSave& x) throw() { return x.getBinSize(); }
00277   inline static unsigned int getSerializedSize(const std::string& x) throw() { return x.size()+stringpad; }
00278   inline static unsigned int getSerializedSize(const char* x) throw() { unsigned int sz=strlen(x); return sz+stringpad; }
00279   inline static unsigned int getSerializedSize(const void*) throw() { return sizeof(unsigned long long); }
00280   inline static unsigned int getSerializedSize(const bool&) throw() { return sizeof(char); }
00281   template <class T> inline static unsigned int getSerializedSize(const T& x) throw() { return sizeof(x); }
00282   //! this version lets you get the theoretical size of a type, but beware it will throw invalid_argument if you pass a string type! (can't tell the size of the string without an actual instance...)
00283   template <class T> inline static unsigned int getSerializedSize() throw() { throw std::invalid_argument("The template argument passed to getSerializedSize() is not supported by LoadSave"); }
00284   //@}
00285   
00286   
00287   /*! @brief These are for putting creator codes (a uniquely identifying string, e.g. the name of the class) at the beginning of your data -- 
00288    *  doing so is a good idea to allow polymorphism, version detection (backward compatability), or just a sanity check */
00289   //!@name Creator Utilities
00290 
00291   /*!@brief Returns size of the creator code
00292    * @param creator a string to use for the creator
00293    * @return the size to leave for the creator code */
00294   virtual unsigned int creatorSize(const char creator[]) const { return strlen(creator)+stringpad; }
00295   //! Compares the creator code in the buffer to the one given
00296   /*!@param creator what the creator should be
00297    * @param buf the buffer to check
00298    * @param len the size remaining in the buffer
00299    * @param isLoading set this to true if you want to output a warning if it doesn't match
00300    * @return the number of bytes used by the creator, or 0 if it didn't match */
00301   virtual unsigned int checkCreator(const char* creator, const char buf[], unsigned int len, bool isLoading=true) const throw();
00302   //! Compares the creator code in the buffer to the one given, increments buf and decrements len if it matches
00303   /*!@param creator what the creator should be
00304    * @param buf the buffer to check
00305    * @param len the size remaining in the buffer
00306    * @param isLoading set this to true if you want to output a warning if it doesn't match
00307    * @return true if it matched, false otherwise */
00308   virtual bool checkCreatorInc(const char* creator, const char*& buf, unsigned int& len, bool isLoading=true) const throw();
00309   //! Compares the creator code in the buffer to the one given, increments buf and decrements len if it matches, throws std::runtime_error if it doesn't match
00310   /*!@param creator what the creator should be
00311    * @param buf the buffer to check
00312    * @param len the size remaining in the buffer
00313    * @param isLoading set this to true if you want to output a warning if it doesn't match */
00314   virtual void checkCreatorIncT(const char* creator, const char*& buf, unsigned int& len, bool isLoading=true) const throw(std::runtime_error);
00315   //! Compares the creator code in the file to the one given, will attempt to reset the file position if fails (so you can check for one of several types)
00316   /*!@param creator what the creator should be
00317    * @param f the file pointer to check
00318    * @param isLoading set this to true if you want to output a warning if it doesn't match
00319    * @return the number of bytes consumed by the creator code, or 0 if it didn't match */
00320   virtual unsigned int checkCreator(const char* creator, FILE* f, bool isLoading=true) const throw();
00321   //! Saves a creator code to a buffer
00322   /*!@param creator the string to use for the creator code
00323    * @param buf the buffer to save the code into
00324    * @param len the space available in the buffer
00325    * @return the number of bytes consumed */
00326   virtual unsigned int saveCreator(const char* creator, char buf[], unsigned int len) const throw();
00327   //! Saves a creator code to a buffer, increments buf and decrements len by the amount used
00328   /*!@param creator the string to use for the creator code
00329    * @param buf the buffer to save the code into
00330    * @param len the space available in the buffer
00331    * @return true if successful, false otherwise */
00332   virtual bool saveCreatorInc(const char* creator, char*& buf, unsigned int& len) const throw();
00333   //! Saves a creator code to a buffer, increments buf and decrements len by the amount used
00334   /*!@param creator the string to use for the creator code
00335    * @param buf the buffer to save the code into
00336    * @param len the space available in the buffer */
00337   virtual void saveCreatorIncT(const char* creator, char*& buf, unsigned int& len) const throw(std::runtime_error);
00338   //! Saves a creator code directly to a file
00339   /*!@param creator the string to use for the creator code
00340    * @param f the file to save the code into
00341    * @return the number of bytes consumed */
00342   virtual unsigned int saveCreator(const char* creator, FILE* f) const throw();
00343   //@}
00344 
00345   /* //if you want to have a default behavior template like this (look up template specialization) (i thought i needed this, nevermind)
00346     template<class T> inline static unsigned int encode(const T x, char buf[], unsigned int cap) { cout << "*** WARNING attempted to encode non-primitive and non-LoadSave" << endl; return 0; }
00347     template<class T> inline static unsigned int decode(T& x, const char buf[], unsigned int cap) { cout << "*** WARNING attempted to decode non-primitive and non-LoadSave" << endl; return 0; }
00348     template<class T> inline static unsigned int encode(const T x, FILE* f) { cout << "*** WARNING attempted to encode non-primitive and non-LoadSave" << endl; return 0; }
00349     template<class T> inline static unsigned int decode(T& x, FILE* f) { cout << "*** WARNING attempted to decode non-primitive and non-LoadSave" << endl; return 0; }
00350   */
00351 
00352   //!encode/decode cross-platform compatable (byte order consistancy)
00353   //!@name Encode/Decode Utils
00354   /*!@brief encode or decode with byte order consistancy*/
00355   inline static unsigned int encode(const LoadSave& x, char buf[], unsigned int cap) { return x.saveBuffer(buf,cap); }
00356   inline static unsigned int decode(LoadSave& x, const char buf[], unsigned int cap) { return x.loadBuffer(buf,cap); }
00357   inline static unsigned int encode(const LoadSave& x, FILE* f)                 { return x.saveFileStream(f); }
00358   inline static unsigned int decode(LoadSave& x, FILE* f)                       { return x.loadFileStream(f); }
00359   
00360 #if LOADSAVE_SWAPBYTES
00361   
00362   inline static unsigned int encode(const double x, char buf[], unsigned int cap) throw()         { if(cap<sizeof(x)) return 0; byteswap(*(double*)buf,x); return sizeof(x); }
00363   inline static unsigned int decode(double& x, const char buf[], unsigned int cap) throw()        { if(cap<sizeof(x)) return 0; byteswap(x,*(const double*)buf); return sizeof(x);}
00364   inline static unsigned int encode(const double x, FILE* f) throw()                         { double t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00365   inline static unsigned int decode(double& x, FILE* f) throw()                              { double t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00366   
00367   inline static unsigned int encode(const float x, char buf[], unsigned int cap) throw()          { if(cap<sizeof(x)) return 0; byteswap(*(float*)buf,x); return sizeof(x); }
00368   inline static unsigned int decode(float& x, const char buf[], unsigned int cap) throw()         { if(cap<sizeof(x)) return 0; byteswap(x,*(const float*)buf); return sizeof(x);}
00369   inline static unsigned int encode(const float x, FILE* f) throw()                          { float t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00370   inline static unsigned int decode(float& x, FILE* f) throw()                               { float t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00371   
00372   inline static unsigned int encode(const long long x, char buf[], unsigned int cap) throw()           { if(cap<sizeof(x)) return 0; byteswap(*(long long*)buf,x); return sizeof(x); }
00373   inline static unsigned int decode(long long& x, const char buf[], unsigned int cap) throw()          { if(cap<sizeof(x)) return 0; byteswap(x,*(const long long*)buf); return sizeof(x);}
00374   inline static unsigned int encode(const long long x, FILE* f) throw()                           { long long t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00375   inline static unsigned int decode(long long& x, FILE* f) throw()                                { long long t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00376   inline static unsigned int encode(const unsigned long long x, char buf[], unsigned int cap) throw()  { if(cap<sizeof(x)) return 0; byteswap(*(unsigned long long*)buf,x); return sizeof(x); }
00377   inline static unsigned int decode(unsigned long long& x, const char buf[], unsigned int cap) throw() { if(cap<sizeof(x)) return 0; byteswap(x,*(const unsigned long long*)buf); return sizeof(x);}
00378   inline static unsigned int encode(const unsigned long long x, FILE* f) throw()                  { unsigned long long t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00379   inline static unsigned int decode(unsigned long long& x, FILE* f) throw()                       { unsigned long long t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00380   
00381   inline static unsigned int encode(const long x, char buf[], unsigned int cap) throw()           { if(cap<sizeof(x)) return 0; byteswap(*(long*)buf,x); return sizeof(x); }
00382   inline static unsigned int decode(long& x, const char buf[], unsigned int cap) throw()          { if(cap<sizeof(x)) return 0; byteswap(x,*(const long*)buf); return sizeof(x);}
00383   inline static unsigned int encode(const long x, FILE* f) throw()                           { long t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00384   inline static unsigned int decode(long& x, FILE* f) throw()                                { long t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00385   inline static unsigned int encode(const unsigned long x, char buf[], unsigned int cap) throw()  { if(cap<sizeof(x)) return 0; byteswap(*(unsigned long*)buf,x); return sizeof(x); }
00386   inline static unsigned int decode(unsigned long& x, const char buf[], unsigned int cap) throw() { if(cap<sizeof(x)) return 0; byteswap(x,*(const unsigned long*)buf); return sizeof(x);}
00387   inline static unsigned int encode(const unsigned long x, FILE* f) throw()                  { unsigned long t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00388   inline static unsigned int decode(unsigned long& x, FILE* f) throw()                       { unsigned long t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00389   
00390   inline static unsigned int encode(const int x, char buf[], unsigned int cap) throw()            { if(cap<sizeof(x)) return 0; byteswap(*(int*)buf,x); return sizeof(x); }
00391   inline static unsigned int decode(int& x, const char buf[], unsigned int cap) throw()           { if(cap<sizeof(x)) return 0; byteswap(x,*(const int*)buf); return sizeof(x);}
00392   inline static unsigned int encode(const int x, FILE* f) throw()                            { int t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00393   inline static unsigned int decode(int& x, FILE* f) throw()                                 { int t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00394   inline static unsigned int encode(const unsigned int x, char buf[], unsigned int cap) throw()   { if(cap<sizeof(x)) return 0; byteswap(*(unsigned int*)buf,x); return sizeof(x); }
00395   inline static unsigned int decode(unsigned int& x, const char buf[], unsigned int cap) throw()  { if(cap<sizeof(x)) return 0; byteswap(x,*(const unsigned int*)buf); return sizeof(x);}
00396   inline static unsigned int encode(const unsigned int x, FILE* f) throw()                   { unsigned int t=0; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00397   inline static unsigned int decode(unsigned int& x, FILE* f) throw()                        { unsigned int t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00398   
00399   inline static unsigned int encode(const short x, char buf[], unsigned int cap) throw()          { if(cap<sizeof(x)) return 0; byteswap(*(short*)buf,x); return sizeof(x); }
00400   inline static unsigned int decode(short& x, const char buf[], unsigned int cap) throw()         { if(cap<sizeof(x)) return 0; byteswap(x,*(const short*)buf); return sizeof(x);}
00401   inline static unsigned int encode(const short x, FILE* f) throw()                          { short t; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00402   inline static unsigned int decode(short& x, FILE* f) throw()                               { short t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00403   inline static unsigned int encode(const unsigned short x, char buf[], unsigned int cap) throw() { if(cap<sizeof(x)) return 0; byteswap(*(unsigned short*)buf,x); return sizeof(x); }
00404   inline static unsigned int decode(unsigned short& x, const char buf[], unsigned int cap) throw(){ if(cap<sizeof(x)) return 0; byteswap(x,*(const unsigned short*)buf); return sizeof(x);}
00405   inline static unsigned int encode(const unsigned short x, FILE* f) throw()                 { unsigned short t; byteswap(t,x); return sizeof(x)*fwrite(&t,sizeof(x),1,f); }
00406   inline static unsigned int decode(unsigned short& x, FILE* f) throw()                      { unsigned short t=0; if(fread(&t,sizeof(x),1,f)==0) return 0; byteswap(x,t); return sizeof(x);}
00407 
00408 #else
00409   
00410   inline static unsigned int encode(const double x, char buf[], unsigned int cap) throw()        { if(cap<sizeof(x)) return 0; memcpy(buf,&x,sizeof(x)); return sizeof(x); }
00411   inline static unsigned int decode(double& x, const char buf[], unsigned int cap) throw()       { if(cap<sizeof(x)) return 0; memcpy(&x,buf,sizeof(x)); return sizeof(x); }
00412   inline static unsigned int encode(const double x, FILE* f) throw()                        { return sizeof(x)*fwrite(&x,sizeof(x),1,f); }
00413   inline static unsigned int decode(double& x, FILE* f) throw()                             { return sizeof(x)*fread(&x,sizeof(x),1,f); }
00414   
00415   inline static unsigned int encode(const float x, char buf[], unsigned int cap) throw()         { if(cap<sizeof(x)) return 0; memcpy(buf,&x,sizeof(x)); return sizeof(x); }
00416   inline static unsigned int decode(float& x, const char buf[], unsigned int cap) throw()        { if(cap<sizeof(x)) return 0; memcpy(&x,buf,sizeof(x)); return sizeof(x); }
00417   inline static unsigned int encode(const float x, FILE* f) throw()                         { return sizeof(x)*fwrite(&x,sizeof(x),1,f); }
00418   inline static unsigned int decode(float& x, FILE* f) throw()                              { return sizeof(x)*fread(&x,sizeof(x),1,f); }
00419 
00420   inline static unsigned int encode(const long long x, char buf[], unsigned int cap) throw()          { if(cap<sizeof(x)) return 0; memcpy(buf,&x,sizeof(x)); return sizeof(x); }
00421   inline static unsigned int decode(long long& x, const char buf[], unsigned int cap) throw()         { if(cap<sizeof(x)) return 0; memcpy(&x,buf,sizeof(x)); return sizeof(x); }
00422   inline static unsigned int encode(const long long x, FILE* f) throw()                          { return sizeof(x)*fwrite(&x,sizeof(x),1,f); }
00423   inline static unsigned int decode(long long& x, FILE* f) throw()                               { return sizeof(x)*fread(&x,sizeof(x),1,f); }
00424   inline static unsigned int encode(const unsigned long long x, char buf[], unsigned int cap) throw() { if(cap<sizeof(x)) return 0; memcpy(buf,&x,sizeof(x)); return sizeof(x); }
00425   inline static unsigned int decode(unsigned long long& x, const char buf[], unsigned int cap) throw(){ if(cap<sizeof(x)) return 0; memcpy(&x,buf,sizeof(x)); return sizeof(x); }
00426   inline static unsigned int encode(const unsigned long long x, FILE* f) throw()                 { return sizeof(x)*fwrite(&x,sizeof(x),1,f); }