Synesis Software STLSoft - ... Robust, Lightweight, Cross-platform, Template Software ...

b64/b64.hpp

Go to the documentation of this file.
00001 /* /////////////////////////////////////////////////////////////////////////
00002  * File:        b64/b64.hpp
00003  *
00004  * Purpose:     Header file for the b64 C++-API.
00005  *
00006  * Created:     18th October 2004
00007  * Updated:     4th February 2012
00008  *
00009  * Home:        http://synesis.com.au/software/
00010  *
00011  * Copyright 2004-2012, Matthew Wilson and Synesis Software
00012  * All rights reserved.
00013  *
00014  * Redistribution and use in source and binary forms, with or without 
00015  * modification, are permitted provided that the following conditions are met:
00016  *
00017  * - Redistributions of source code must retain the above copyright notice, this
00018  *   list of conditions and the following disclaimer. 
00019  * - Redistributions in binary form must reproduce the above copyright notice,
00020  *   this list of conditions and the following disclaimer in the documentation
00021  *   and/or other materials provided with the distribution.
00022  * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
00023  *   any contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00036  * POSSIBILITY OF SUCH DAMAGE.
00037  *
00038  * ////////////////////////////////////////////////////////////////////// */
00039 
00040 
00057 #ifndef B64_INCL_B64_HPP_B64
00058 #define B64_INCL_B64_HPP_B64
00059 
00060 /* /////////////////////////////////////////////////////////////////////////
00061  * Version information
00062  */
00063 
00064 #ifndef B64_DOCUMENTATION_SKIP_SECTION
00065 # define B64_VER_B64_HPP_B64_MAJOR      2
00066 # define B64_VER_B64_HPP_B64_MINOR      1
00067 # define B64_VER_B64_HPP_B64_REVISION   12
00068 # define B64_VER_B64_HPP_B64_EDIT       38
00069 #endif /* !B64_DOCUMENTATION_SKIP_SECTION */
00070 
00071 /* /////////////////////////////////////////////////////////////////////////
00072  * Includes
00073  */
00074 
00075 #ifndef B64_INCL_B64_H_B64
00076 # include <b64/b64.h>
00077 #endif /* !B64_INCL_B64_H_B64 */
00078 
00079 /* If the compiler cannot find the following include, you may have not
00080  * upgraded to the latest version of STLSoft: 1.9.1. Go to
00081  *  http://stlsoft.org/ and download this version or later.
00082  */
00083 #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
00084 # include <stlsoft/stlsoft.h>
00085 #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
00086 
00087 #if !defined(_STLSOFT_VER) || \
00088     _STLSOFT_VER < 0x01096fff
00089 # error Requires STLSoft 1.9.111, or later. (www.stlsoft.org/downloads.html)
00090 #endif /* STLSoft version */
00091 
00092 #ifdef STLSOFT_CF_std_NAMESPACE
00093 
00094 # if defined(B64_USE_CUSTOM_STRING)
00095 #  include B64_CUSTOM_STRING_INCLUDE
00096 # else /* B64_USE_CUSTOM_STRING */
00097 #  include <string>
00098 # endif /* !B64_USE_CUSTOM_STRING */
00099 
00100 # if defined(B64_USE_CUSTOM_VECTOR)
00101 #  include B64_CUSTOM_VECTOR_INCLUDE
00102 # else /* B64_USE_CUSTOM_VECTOR */
00103 #  include <vector>
00104 # endif /* !B64_USE_CUSTOM_VECTOR */
00105 
00106  /* We'll now have a go at checking whether the string type is 
00107   * known to be contiguous
00108   */
00109 # ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_LIBRARY_DISCRIMINATOR
00110 #  include <stlsoft/util/std/library_discriminator.hpp>
00111 # endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_LIBRARY_DISCRIMINATOR */
00112 # ifdef STLSOFT_CF_STD_LIBRARY_IS_DINKUMWARE_VC
00113 #  if STLSOFT_CF_STD_LIBRARY_DINKUMWARE_VC_VERSION <= STLSOFT_CF_DINKUMWARE_VC_VERSION_7_1
00114 #   define B64_STRING_TYPE_IS_CONTIGUOUS
00115 #  endif /* STLSOFT_CF_STD_LIBRARY_DINKUMWARE_VC_VERSION */
00116 # endif /* STLSOFT_CF_STD_LIBRARY_IS_DINKUMWARE_VC */
00117 
00118 #else /* ? STLSOFT_CF_std_NAMESPACE */
00119 
00120 # if defined(STLSOFT_COMPILER_IS_WATCOM)
00121 #  include <string.hpp>
00122 #  include <wcvector.h>
00123 #  define   B64_USE_CUSTOM_STRING
00124 #  define   B64_CUSTOM_STRING_TYPE      watcom_string_for_b64
00125 #  define   B64_USE_CUSTOM_VECTOR
00126 #  define   B64_CUSTOM_BLOB_TYPE        watcom_vector_for_b64
00127 #  define   B64_STRING_TYPE_IS_CONTIGUOUS
00128 # else /* ? compiler */
00129 #  error No other non-std compiler is known
00130 # endif /* ? compiler */
00131 
00132 #endif /* STLSOFT_CF_std_NAMESPACE */
00133 
00134 #ifdef B64_NO_CONTIGUOUS_STRING_TYPE
00135 # ifdef B64_STRING_TYPE_IS_CONTIGUOUS
00136 #  undef B64_STRING_TYPE_IS_CONTIGUOUS
00137 # endif /* B64_STRING_TYPE_IS_CONTIGUOUS */
00138 #endif /* B64_NO_CONTIGUOUS_STRING_TYPE */
00139 
00140 #if !defined(B64_STRING_TYPE_IS_CONTIGUOUS)
00141 # ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
00142 #  include <stlsoft/memory/auto_buffer.hpp>
00143 # endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
00144 #endif /* !B64_STRING_TYPE_IS_CONTIGUOUS */
00145 
00146 #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
00147 # include <stlsoft/shims/access/string.hpp>
00148 #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
00149 
00150 /* #ifdef B64_ */
00151 
00152 #define B64_DECLARE_SHIM_PAIR_()        stlsoft_ns_using(c_str_data_a); stlsoft_ns_using(c_str_len_a)
00153 #define B64_INVOKE_SHIM_data_(s)        c_str_data_a(s)
00154 #define B64_INVOKE_SHIM_len_(s)         c_str_len_a(s)
00155 
00156 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00157 # if defined(STLSOFT_COMPILER_IS_WATCOM)
00158 #  include <stdexcep.h>
00159 # else /* ? compiler */
00160 #  include <stdexcept>
00161 # endif /* compiler */
00162 #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
00163 
00164 /* /////////////////////////////////////////////////////////////////////////
00165  * Namespace
00166  */
00167 
00168 #ifndef B64_NO_NAMESPACE
00169 namespace B64_NAMESPACE
00170 {
00171 #endif /* !B64_NO_NAMESPACE */
00172 
00173 /* /////////////////////////////////////////////////////////////////////////
00174  * Classes
00175  */
00176 
00177 #if defined(STLSOFT_COMPILER_IS_WATCOM)
00178 class watcom_vector_for_b64
00179     : public WCValVector<unsigned char>
00180 {
00181 private:
00182     typedef WCValVector<unsigned char>  parent_class_type;
00183     typedef watcom_vector_for_b64       class_type;
00184 public:
00185     watcom_vector_for_b64()
00186     {}
00187     watcom_vector_for_b64(size_t n)
00188         : parent_class_type(n)
00189     {}
00190     watcom_vector_for_b64(class_type const &rhs)
00191         : parent_class_type(rhs)
00192     {}
00193 
00194 public:
00195     size_t size() const
00196     {
00197         return parent_class_type::length();
00198     }
00199 };
00200 
00201 class watcom_string_for_b64
00202     : public String
00203 {
00204 public:
00205     watcom_string_for_b64(size_t n, char ch)
00206         : String(ch, n)
00207     {}
00208 
00209 public:
00210     void resize(size_t n)
00211     {
00212         String& this_ = *this;
00213 
00214         this_ = String(*this, n);
00215     }
00216 };
00217 #endif /* STLSOFT_COMPILER_IS_WATCOM */
00218 
00219 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00220 
00222 class coding_exception
00223     : public stlsoft_ns_qual_std(runtime_error)
00224 {
00225 public:
00226     typedef stlsoft_ns_qual_std(runtime_error)  parent_class_type;
00227     typedef coding_exception                    class_type;
00228 private:
00229 #if defined(B64_USE_CUSTOM_STRING)
00230     typedef B64_CUSTOM_STRING_TYPE              string_type;
00231 #else /* B64_USE_CUSTOM_STRING */
00232     typedef std::string                         string_type;
00233 #endif /* !B64_USE_CUSTOM_STRING */
00234 
00235 public:
00237     coding_exception(B64_RC rc, char const* badChar)
00238         : parent_class_type(make_message_(rc))
00239         , m_rc(rc)
00240         , m_badChar(badChar)
00241     {}
00242 
00243 public:
00245     B64_RC get_rc() const
00246     {
00247         return m_rc;
00248     }
00253     char const* get_badChar() const
00254     {
00255         return m_badChar;
00256     }
00257 
00258 private:
00259     static string_type make_message_(B64_RC rc)
00260     {
00261         return string_type("Decoding error: ") + b64_getStatusCodeString(rc);
00262     }
00263 
00264 private:
00265     B64_RC      m_rc;
00266     char const* m_badChar;
00267 };
00268 #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
00269 
00270 /* /////////////////////////////////////////////////////////////////////////
00271  * Typedefs
00272  */
00273 
00295 #if defined(B64_USE_CUSTOM_STRING)
00296 typedef B64_CUSTOM_STRING_TYPE          string_t;
00297 #else /* B64_USE_CUSTOM_STRING */
00298 typedef std::string                     string_t;
00299 #endif /* !B64_USE_CUSTOM_STRING */
00300 
00323 #if defined(B64_USE_CUSTOM_VECTOR)
00324 typedef B64_CUSTOM_BLOB_TYPE            blob_t;
00325 #else /* B64_USE_CUSTOM_VECTOR */
00326 # ifndef B64_DOCUMENTATION_SKIP_SECTION
00327 typedef ::stlsoft::byte_t               byte_t_;
00328 typedef std::vector<byte_t_>            blob_t;
00329 # else /* !B64_DOCUMENTATION_SKIP_SECTION */
00330 typedef std::vector< ::stlsoft::byte_t> blob_t;
00331 # endif /* !B64_DOCUMENTATION_SKIP_SECTION */
00332 #endif /* !B64_USE_CUSTOM_VECTOR */
00333 
00334 /* /////////////////////////////////////////////////////////////////////////
00335  * Functions
00336  */
00337 
00368 inline string_t encode(void const* src, size_t srcSize, int flags, int lineLen = 0, B64_RC* rc = NULL)
00369 {
00370     B64_RC  rc_;
00371 
00372     // Make sure rc is non-NULL, since we will need to get the RC in order to
00373     // throw exception later.
00374     if(NULL == rc)
00375     {
00376         rc = &rc_;
00377     }
00378 
00379     size_t      n   =   B64_NAMESPACE_QUALIFIER::b64_encode2(src, srcSize, NULL, 0u, static_cast<unsigned>(flags), lineLen, rc);
00380 
00381 #ifdef B64_STRING_TYPE_IS_CONTIGUOUS
00382 
00383     // If the string type is known to have contiguous storage we can avoid
00384     // any intermediate memory, and decode directly into its internal
00385     // buffer.
00386 
00387     string_t    s(n, '~'); // ~ is used for an invalid / eyecatcher
00388 
00389     STLSOFT_MESSAGE_ASSERT("assumed contiguous string type is not so. Please report this error. To effect fix now, #define B64_NO_CONTIGUOUS_STRING_TYPE", 0 == n || &s[n - 1] == &s[0] + (n - 1));
00390 
00391     size_t      n2  =   B64_NAMESPACE_QUALIFIER::b64_encode2(src, srcSize, &s[0], s.length(), static_cast<unsigned>(flags), lineLen, rc);
00392 
00393     s.resize(n2);
00394 
00395 #else /* ? B64_STRING_TYPE_IS_CONTIGUOUS */
00396 
00397     // If the string type is not known to be contiguous, then we must use
00398     // intermediate storage. Here we use a 1KB auto_buffer, so that only
00399     // data in excess of that will incur an additional (over the string's)
00400     // heap allocation.
00401 
00402     typedef stlsoft::auto_buffer<b64_char_t, 1024>  buffer_t;
00403 
00404     buffer_t    buffer(n);
00405     size_t      n2  =   B64_NAMESPACE_QUALIFIER::b64_encode2(src, srcSize, &buffer[0], buffer.size(), static_cast<unsigned>(flags), lineLen, rc);
00406 
00407     string_t    s(&buffer[0], n2);
00408 #endif /* B64_STRING_TYPE_IS_CONTIGUOUS */
00409 
00410 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00411     if( 0 != srcSize &&
00412         0 == n2 &&
00413         rc == &rc_)
00414     {
00415         throw coding_exception(*rc, NULL);
00416     }
00417 #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
00418 
00419     return s;
00420 }
00421 
00445 inline string_t encode(void const* src, size_t srcSize)
00446 {
00447     return encode(src, srcSize, 0, 0, NULL);
00448 }
00449 
00450 #ifdef STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT
00451 
00473 template <typename T, size_t N>
00474 inline string_t encode(T (&ar)[N])
00475 {
00476     return encode(&ar[0], sizeof(T) * N);
00477 }
00478 #endif /* STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT */
00479 
00497 inline string_t encode(blob_t const &blob)
00498 {
00499     return encode(blob.empty() ? NULL : &blob[0], blob.size());
00500 }
00501 
00526 inline string_t encode(blob_t const &blob, int flags, int lineLen = 0, B64_RC* rc = NULL)
00527 {
00528     return encode(blob.empty() ? NULL : &blob[0], blob.size(), flags, lineLen, rc);
00529 }
00530 
00557 inline blob_t decode(b64_char_t const* src, size_t srcLen, int flags, b64_char_t const** badChar = NULL, B64_RC* rc = NULL)
00558 {
00559 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00560     B64_RC              rc_;
00561     b64_char_t const*   badChar_;
00562 
00563     if(NULL == rc)
00564     {
00565         rc = &rc_;
00566     }
00567     if(NULL == badChar)
00568     {
00569         badChar = &badChar_;
00570     }
00571 #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
00572 
00573     size_t  n   =   B64_NAMESPACE_QUALIFIER::b64_decode2(src, srcLen, NULL, 0, static_cast<unsigned>(flags), badChar, rc);
00574     blob_t  v(n);
00575     size_t  n2  =   v.empty() ? 0 : B64_NAMESPACE_QUALIFIER::b64_decode2(src, srcLen, &v[0], v.size(), static_cast<unsigned>(flags), badChar, rc);
00576 
00577     v.resize(n2);
00578 
00579 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00580     if( 0 != srcLen &&
00581         0 == n2 &&
00582         rc == &rc_)
00583     {
00584         if(B64_RC_OK == *rc)
00585         {
00586             *rc = B64_RC_TRUNCATED_INPUT;
00587         }
00588 
00589         throw coding_exception(*rc, (badChar == &badChar_) ? *badChar : NULL);
00590     }
00591 #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
00592 
00593     return v;
00594 }
00595 
00614 inline blob_t decode(b64_char_t const* src, size_t srcLen)
00615 {
00616     return decode(src, srcLen, B64_F_STOP_ON_BAD_CHAR, NULL, NULL);
00617 }
00618 
00619 #ifndef B64_DOCUMENTATION_SKIP_SECTION
00620 STLSOFT_OPEN_WORKER_NS_(impl)
00621 
00622 
00640 template <class S>
00641 inline blob_t b64_impl_decode_(int flags, S const &str)
00642 {
00643     B64_DECLARE_SHIM_PAIR_();
00644 
00645     b64_char_t const* dummy; // Cannot rely on badChar being available in str
00646 
00647     return decode(
00648         B64_INVOKE_SHIM_data_(str)
00649     ,   B64_INVOKE_SHIM_len_(str)
00650     ,   static_cast<B64_FLAGS>(flags)
00651     ,   &dummy
00652     ,   NULL
00653     );
00654 }
00655 
00656 STLSOFT_CLOSE_WORKER_NS_(ns)
00657 #endif /* !B64_DOCUMENTATION_SKIP_SECTION */
00658 
00659 
00677 template <class S>
00678 inline blob_t decode(S const &str)
00679 {
00680     return STLSOFT_WORKER_NS_QUAL_(impl, b64_impl_decode_)(B64_F_STOP_ON_BAD_CHAR, str);
00681 }
00682 
00701 template <class S>
00702 inline blob_t decode(int flags, S const &str) // NOTE: This has to be overloaded, rather than use default arguments, otherwise VC has a spit
00703 {
00704     return STLSOFT_WORKER_NS_QUAL_(impl, b64_impl_decode_)(flags, str);
00705 }
00706 
00727 inline blob_t decode(string_t const &str, int flags = B64_F_STOP_ON_BAD_CHAR)
00728 {
00729     B64_DECLARE_SHIM_PAIR_();
00730 
00731     return decode(
00732         B64_INVOKE_SHIM_data_(str)
00733     ,   B64_INVOKE_SHIM_len_(str)
00734     ,   flags
00735     ,   NULL
00736     ,   NULL
00737     );
00738 }
00739 
00765 inline blob_t decode(string_t const &str, int flags, b64_char_t const** badChar, B64_RC* rc = NULL)
00766 {
00767     B64_DECLARE_SHIM_PAIR_();
00768 
00769     return decode(
00770         B64_INVOKE_SHIM_data_(str)
00771     ,   B64_INVOKE_SHIM_len_(str)
00772     ,   flags
00773     ,   badChar
00774     ,   rc
00775     );
00776 }
00777 
00778 /* /////////////////////////////////////////////////////////////////////////
00779  * Namespace
00780  */
00781 
00790 namespace cpp
00791 {
00792 
00793     using B64_NAMESPACE::coding_exception;
00794 
00795     using B64_NAMESPACE::blob_t;
00796     using B64_NAMESPACE::string_t;
00797 
00798     using B64_NAMESPACE::decode;
00799     using B64_NAMESPACE::encode;
00800 
00801 } /* namespace cpp */
00802 
00803 #ifndef B64_NO_NAMESPACE
00804 } /* namespace B64_NAMESPACE */
00805 #endif /* !B64_NO_NAMESPACE */
00806 
00807 /* ////////////////////////////////////////////////////////////////////// */
00808 
00809 #endif /* B64_INCL_B64_HPP_B64 */
00810 
00811 /* ///////////////////////////// end of file //////////////////////////// */

b64 Library documentation © Synesis Software Pty Ltd, 2004-2012