base64.hpp

Go to the documentation of this file.
00001 #ifndef s11n_BIN64_H_INCLUDED
00002 #define s11n_BIN64_H_INCLUDED 1
00003 ////////////////////////////////////////////////////////////////////////
00004 // s11n.hpp:
00005 // Author: stephan beal <stephan@s11n.net>
00006 // License: Public Domain
00007 ////////////////////////////////////////////////////////////////////////
00008 
00009 #include <s11n.net/s11n/base64enc.hpp>
00010 #include <s11n.net/s11n/base64dec.hpp>
00011 
00012 namespace s11n {
00013 /**
00014    The base64 namespace encapsulates code for de/serializing binary
00015    data using base64 encoding/decoding.
00016 
00017    Added in version 1.3.1.
00018 */
00019 namespace base64 {
00020 
00021     /**
00022        This is a helper for serializing binary data.  It is a Serializable
00023        type, but does not meet all requirements for Serializables (namely,
00024        it is not DefaultConstructable). It is to be initialized with a
00025        pointer to some binary data (which is limited to a (char const *))
00026        and the length of that data.
00027 
00028        The intended usage goes something like this:
00029 
00030        \code
00031        bindata_ser bin( myPtr, lengthOfMyPtr );
00032        serialize( anS11nNode, bin );
00033        \endcode
00034 
00035        To deserialize it, use bindata_deser.
00036 
00037        IMPORTANT WARNINGS:
00038 
00039        Serializing binary data this way is not terribly efficient, due
00040        to the whole encoding/decoding process. Also most s11n data
00041        formats do some sort of entity translation when setting
00042        properties, and may peform very poorly when given huge
00043        inputs. Some formats may not like newlines in properties
00044        (simplexml_serializer comes to mind). Base64-encoded data is
00045        also larger than the original binary data. Thus the following
00046        recommendations:
00047 
00048        - When serializing binary data using s11n, be nice to your CPU
00049        and restrict it to data of reasonable sizes (no 2GB blobs).
00050 
00051        - Try the compact_serializer as your output format. It does not
00052        character translation and thus should perform much better than
00053        the other serializers on encoded data.
00054     */
00055     struct bindata_ser
00056     {
00057     typedef std::string::value_type char_type;
00058     /** The binary data we want to serialize. */
00059     char_type const * data;
00060     /** The length of this->data. */
00061     size_t length;
00062 
00063     /**
00064        Sets this object to point to begin, which is required to be
00065        at least n bytes long.
00066     */
00067     bindata_ser( char_type const * begin, size_t n )
00068         : data(begin), length(n)
00069     {}
00070 
00071     /**
00072        Stores this->length and the base64-encoded form of this->data.
00073     */
00074     template <typename NodeT>
00075     bool operator()( NodeT & dest ) const
00076     {
00077         if( ! this->length ) return false;
00078         typedef s11n::node_traits<NodeT> NTR;
00079         NTR::class_name( dest, "bindata_ser" );
00080         std::ostringstream obuf;
00081         {
00082         std::istringstream ibuf( std::string( this->data, this->data + this->length ) );
00083         s11n::base64::encoder E;
00084         E.encode( ibuf, obuf );
00085         }
00086         NTR::set( dest, "base64", obuf.str() );
00087         NTR::set( dest, "length", this->length );
00088         return true;
00089     }
00090     };
00091 
00092 
00093     /**
00094        bindata_deser is a helper to deserialize base64-encoded
00095        binary data to a (char *). It is intended to be used
00096        in conjunction with bindata_ser.
00097 
00098        The intended usage goes something like this:
00099 
00100        \code
00101        bindata_deser bin;
00102        deserialize( anS11nNode, bin );
00103        // ... either take over bin.data or deallocate it ...
00104        \endcode
00105 
00106     */
00107     struct bindata_deser
00108     {
00109     typedef std::string::value_type char_type;
00110     /**
00111        The raw binary data. It is set by the deserialize
00112        operator.
00113     */
00114     char_type * data;
00115     /**
00116        The length of the raw binary data. It is set by the deserialize
00117        operator.
00118     */
00119     size_t length;
00120     bindata_deser()
00121         : data(0), length(0)
00122     {}
00123 
00124     /**
00125        Uses malloc() to allocate count bytes. Returns 0 on error, at
00126        least theoretically (depends on the OS's allocator - some
00127        always return non-0 with the assumption that memory will become
00128        free at some point).
00129     */
00130     static char * allocate( size_t count )
00131     {
00132         return static_cast<char *>( malloc( count ) );
00133     }
00134 
00135     /**
00136        Deallocates tgt.data using free() and sets
00137        tgt's values to 0.
00138     */
00139     static void deallocate( bindata_deser & tgt )
00140     {
00141         free( tgt.data );
00142         tgt.data = 0;
00143         tgt.length = 0;
00144     }
00145 
00146     /**
00147        Decodes base64-encoded data from src and sets this->data to
00148        that data, and this->length to the length of that data. It
00149        allocates the memory using malloc(). The caller owns the
00150        deserialized data and must deallocate it at some point using
00151        free() or deallocate(thisObject).
00152 
00153        If src does not appear to contain any data, false is
00154        returned.  If it contains data but does not appear to be
00155        consistent (e.g.  decoded data length does not match
00156        recorded length) or we cannot allocate enough memory to
00157        deserialize then an s11n_exception is thrown.
00158 
00159        This is not a terribly efficient routine, requiring several
00160        copies of the binary data. Thus it should not be used with
00161        very large data sets.
00162     */
00163     template <typename NodeT>
00164     bool operator()( NodeT const & src )
00165     {
00166         typedef s11n::node_traits<NodeT> NTR;
00167         this->data = 0;
00168         this->length = NTR::get( src, "length", 0 );
00169         if( !length ) return false;
00170         std::string cdata( NTR::get( src, "base64", std::string() ) );
00171         if( cdata.empty() ) return false;
00172 
00173         {
00174         std::ostringstream obuf;
00175         std::istringstream ibuf( cdata );
00176         s11n::base64::decoder D;
00177         D.decode( ibuf, obuf );
00178         cdata = obuf.str();
00179         }
00180 
00181         if( this->length != cdata.size() )
00182         {
00183         throw s11n::s11n_exception( S11N_SOURCEINFO,
00184                         "bindata_deser::deserialize: 'length' property [%u] does not correspond to actual data length [%u].",
00185                         this->length,
00186                         cdata.size() );
00187         }
00188         // We could do the allocation before decoding, but then we'd take up yet another copy.
00189         this->data = allocate( this->length );
00190         if( ! this->data )
00191         {
00192         throw s11n::s11n_exception( S11N_SOURCEINFO,
00193                         "bindata_deser::deserialize: could not allocate [%u] bytes for binary data.",
00194                         this->length );
00195         }
00196         memcpy( this->data, cdata.c_str(), this->length );
00197         return true;
00198     }
00199     };
00200 
00201 
00202 }}
00203 
00204 #endif // s11n_BIN64_H_INCLUDED

Generated on Wed Jun 4 21:44:19 2008 for libs11n by  doxygen 1.5.3