← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba

 

Paul J. Lucas has proposed merging lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba.

Requested reviews:
  Paul J. Lucas (paul-lucas)
Related bugs:
  Bug #1015580 in Zorba: "Add base64_streambuf / replace inefficient base64 code"
  https://bugs.launchpad.net/zorba/+bug/1015580

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/feature-base64_streambuf/+merge/111984

Added base64::streambuf class and replaced horribly inefficient base64 code.
-- 
https://code.launchpad.net/~zorba-coders/zorba/feature-base64_streambuf/+merge/111984
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog	2012-06-25 17:16:19 +0000
+++ ChangeLog	2012-06-26 01:20:25 +0000
@@ -18,7 +18,8 @@
   * Fixed bug #867357 (Improved parser error messages)
   * Fixed bug #932314 (non-comparable values must be treated as distinct by
     fn:distinct-values)
-  * Fixed bug #991088$ (raise XUST0001 in trycatch with mixed updating and simple clauses)
+  * Fixed bug #1015580 (Add base64_streambuf / replace inefficient base64 code)
+  * Fixed bug #9910884 (raise XUST0001 in trycatch with mixed updating and simple clauses)
   * Fixed bug #854506 (ugly type error messages) and partial fix for bug #867008
   * Fixed bug #1008082 (bug in transform expr when a copy var is not used anywhere)
   * Fixed bug #1003023$ (optimizer problems due to common subexpression after

=== modified file 'doc/cxx/examples/binary.cpp'
--- doc/cxx/examples/binary.cpp	2012-06-18 10:06:47 +0000
+++ doc/cxx/examples/binary.cpp	2012-06-26 01:20:25 +0000
@@ -25,35 +25,25 @@
 {
   String lString("Hello Zorba");
   String lEncoded = zorba::encoding::Base64::encode(lString);
-  String lExpectedResult("SGVsbG8gWm9yYmE=");
-  return lEncoded == lExpectedResult; 
+  return lEncoded == "SGVsbG8gWm9yYmE="; 
 }
 
 bool 
 decode_example()
 {
- String lEncoded("SGVsbG8gWm9yYmE=");
- String lDecoded = zorba::encoding::Base64::decode(lEncoded);
- return lDecoded == "Hello Zorba";
-
-}
-
-int 
-binary(int argc, char* argv[])
-{
-
-bool res = false;
-
-std::cout << "executing example 1 (Base64 encoding of String)" << std::endl;
-res = encode_example();
-if (!res) return 1;
-std::cout << std::endl;
-
-std::cout << "executing example 2 (decoding of Base64 encoded String)" << std::endl;
-res = decode_example();
-if (!res) return 1;
-std::cout << std::endl;
-
-return 0;
-
-}
+  String lEncoded("SGVsbG8gWm9yYmE=");
+  String lDecoded = zorba::encoding::Base64::decode(lEncoded);
+  return lDecoded == "Hello Zorba";
+}
+
+int binary(int argc, char* argv[]) {
+
+  std::cout << "executing example 1 (Base64 encoding of String)" << std::endl;
+  if (!encode_example()) return 1;
+
+  std::cout << "executing example 2 (decoding of Base64 encoded String)" << std::endl;
+  if (!decode_example()) return 1;
+
+  return 0;
+}
+/* vim:set et sw=2 ts=2: */

=== modified file 'include/zorba/base64.h'
--- include/zorba/base64.h	2012-06-18 10:06:47 +0000
+++ include/zorba/base64.h	2012-06-26 01:20:25 +0000
@@ -21,12 +21,11 @@
 #include <zorba/config.h>
 #include <zorba/zorba_string.h>
 
-namespace zorba { namespace encoding {
+namespace zorba {
+namespace encoding {
 
-  class ZORBA_DLL_PUBLIC Base64
+  struct ZORBA_DLL_PUBLIC Base64
   {
-    public:
-
       static String
       encode(const String& aString);
 
@@ -38,12 +37,10 @@
       
       static String
       decode(std::istream& aStream);  
-
   };
 
-} /* end namespace encoding */
-
-} /* end namespace zorba */
-
-#endif
+} // namespace encoding
+} // namespace zorba
+
+#endif /* ZORBA_BASE64_API_H */
 /* vim:set et sw=2 ts=2: */

=== added file 'include/zorba/base64_stream.h'
--- include/zorba/base64_stream.h	1970-01-01 00:00:00 +0000
+++ include/zorba/base64_stream.h	2012-06-26 01:20:25 +0000
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_BASE64_STREAM_API_H
+#define ZORBA_BASE64_STREAM_API_H
+
+#include <streambuf>
+
+#include <zorba/config.h>
+#include <zorba/internal/streambuf.h>
+
+namespace zorba {
+namespace base64 {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A %base64::streambuf is-a std::streambuf for encoding to and decoding from
+ * Base64 on-the-fly.
+ *
+ * To use it, replace a stream's streambuf:
+ * \code
+ *  istream is;
+ *  // ...
+ *  base64::streambuf b64buf( is.rdbuf() );
+ *  is.ios::rdbuf( &b64buf );
+ * \endcode
+ * Note that the %base64::streambuf must exist for as long as it's being used
+ * by the stream.  If you are replacing the streabuf for a stream you did not
+ * create, you should set it back to the original streambuf:
+ * \code
+ *  void f( ostream &os ) {
+ *    base64::streambuf b64buf( os.rdbuf() );
+ *    try {
+ *      os.ios::rdbuf( &b64buf );
+ *      // ...
+ *    }
+ *    catch ( ... ) {
+ *      os.ios::rdbuf( b64buf.orig_streambuf() );
+ *      throw;
+ *    }
+ *    os.ios::rdbuf( b64buf.orig_streambuf() );
+ *  }
+ * \endcode
+ * Alternatively, you may wish to use either \c attach(), \c auto_attach, or
+ * \c base64::stream instead.
+ *
+ * \b Note: due to the nature of Base64-encoding, when writing, you \e must
+ * ensure that the streambuf is flushed (by calling either \c pubsync() on the
+ * streambuf or \c flush() on the owning stream) when done.
+ *
+ * While %base64::streambuf does support seeking, the positions are relative
+ * to the original byte stream.
+ */
+class ZORBA_DLL_PUBLIC streambuf : public std::streambuf {
+public:
+  /**
+   * Constructs a %base64::streambuf.
+   *
+   * @param orig The original streambuf to read/write from/to.
+   * @throws std::invalid_argument if is not supported or \a orig is null.
+   */
+  streambuf( std::streambuf *orig );
+
+  /**
+   * Destructs a %base64::streambuf.
+   */
+  ~streambuf();
+
+  /**
+   * Gets the original streambuf.
+   *
+   * @return said streambuf.
+   */
+  std::streambuf* orig_streambuf() const {
+    return orig_buf_;
+  }
+
+protected:
+  void imbue( std::locale const& );
+  pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode );
+  pos_type seekpos( pos_type, std::ios_base::openmode );
+  std::streambuf* setbuf( char_type*, std::streamsize );
+  std::streamsize showmanyc();
+  int sync();
+  int_type overflow( int_type );
+  int_type pbackfail( int_type );
+  int_type underflow();
+  std::streamsize xsgetn( char_type*, std::streamsize );
+  std::streamsize xsputn( char_type const*, std::streamsize );
+
+private:
+  std::streambuf *orig_buf_;
+
+  char gbuf_[3];
+  char pbuf_[3];
+  int plen_;
+
+  void clear();
+  void resetg();
+  void resetp();
+  void writep();
+
+  // forbid
+  streambuf( streambuf const& );
+  streambuf& operator=( streambuf const& );
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace base64
+
+namespace internal {
+namespace base64 {
+
+ZORBA_DLL_PUBLIC
+std::streambuf* alloc_streambuf( std::streambuf *orig );
+
+ZORBA_DLL_PUBLIC
+int get_streambuf_index();
+
+} // namespace base64
+} // namespace internal
+
+namespace base64 {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Attaches a base64::streambuf to a stream.  Unlike using a
+ * base64::streambuf directly, this function will create the streambuf,
+ * attach it to the stream, and manage it for the lifetime of the stream
+ * automatically.
+ *
+ * @param ios The stream to attach the base64::streambuf to.  If the stream
+ * already has a base64::streambuf attached to it, this function does
+ * nothing.
+ */
+template<typename charT,typename Traits> inline
+void attach( std::basic_ios<charT,Traits> &ios ) {
+  int const index = internal::base64::get_streambuf_index();
+  void *&pword = ios.pword( index );
+  if ( !pword ) {
+    std::streambuf *const buf =
+      internal::base64::alloc_streambuf( ios.rdbuf() );
+    ios.rdbuf( buf );
+    pword = buf;
+    ios.register_callback( internal::stream_callback, index );
+  }
+}
+
+/**
+ * Detaches a previously attached base64::streambuf from a stream.  The
+ * streambuf is destroyed and the stream's original streambuf is restored.
+ *
+ * @param ios The stream to detach the base64::streambuf from.  If the
+ * stream doesn't have a base64::streambuf attached to it, this function
+ * does nothing.
+ */
+template<typename charT,typename Traits> inline
+void detach( std::basic_ios<charT,Traits> &ios ) {
+  int const index = internal::base64::get_streambuf_index();
+  if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {
+    ios.pword( index ) = 0;
+    ios.rdbuf( buf->orig_streambuf() );
+    internal::dealloc_streambuf( buf );
+  }
+}
+
+/**
+ * Checks whether the given stream has a base64::streambuf attached.
+ *
+ * @param ios The stream to check.
+ * @return \c true only if a base64::streambuf is attached.
+ */
+template<typename charT,typename Traits> inline
+bool is_attached( std::basic_ios<charT,Traits> &ios ) {
+  return !!ios.pword( internal::base64::get_streambuf_index() );
+}
+
+/**
+ * A %base64::auto_attach is a class that attaches a base64::streambuf to
+ * a stream and automatically detaches it when the %auto_attach object is
+ * destroyed.
+ * \code
+ *  void f( ostream &os ) {
+ *    base64::auto_attach<ostream> const raii( os, "ISO-8859-1" );
+ *    // ...
+ *  }
+ * \endcode
+ * A %base64::auto_attach is useful for streams not created by you.
+ *
+ * @see http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
+ */
+template<class StreamType>
+class auto_attach {
+public:
+  /**
+   * Constructs an %auto_attach object calling attach() on the given stream.
+   *
+   * @param stream The stream to attach the base64::streambuf to.  If the
+   * stream already has a base64::streambuf attached to it, this contructor
+   * does nothing.
+   */
+  auto_attach( StreamType &stream ) : stream_( stream ) {
+    attach( stream );
+  }
+
+  /**
+   * Destroys this %auto_attach object calling detach() on the previously
+   * attached stream.
+   */
+  ~auto_attach() {
+    detach( stream_ );
+  }
+
+private:
+  StreamType &stream_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A %base64::stream is used to wrap a C++ standard I/O stream with a
+ * base64::streambuf so that encoding/decoding and the management of the
+ * streambuf happens automatically.
+ *
+ * A %base64::stream is useful for streams created by you.
+ *
+ * @tparam StreamType The I/O stream class type to wrap. It must be a concrete
+ * stream class.
+ */
+template<class StreamType>
+class stream : public StreamType {
+public:
+  /**
+   * Constructs a %base64::stream.
+   */
+  stream() :
+#ifdef WIN32
+# pragma warning( push )
+# pragma warning( disable : 4355 )
+#endif /* WIN32 */
+    b64buf_( this->rdbuf() )
+#ifdef WIN32
+# pragma warning( pop )
+#endif /* WIN32 */
+  {
+    init();
+  }
+
+  /**
+   * Constructs a %stream.
+   *
+   * @tparam StreamArgType The type of the first argument of \a StreamType's
+   * constructor.
+   * @param stream_arg The argument to pass as the first argument to
+   * \a StreamType's constructor.
+   */
+  template<typename StreamArgType>
+  stream( StreamArgType stream_arg ) :
+    StreamType( stream_arg ),
+#ifdef WIN32
+# pragma warning( push )
+# pragma warning( disable : 4355 )
+#endif /* WIN32 */
+    b64buf_( this->rdbuf() )
+#ifdef WIN32
+# pragma warning( pop )
+#endif /* WIN32 */
+  {
+    init();
+  }
+
+  /**
+   * Constructs a %base64::stream.
+   *
+   * @tparam StreamArgType The type of the first argument of \a StreamType's
+   * constructor.
+   * @param stream_arg The argument to pass as the first argument to
+   * \a StreamType's constructor.
+   * @param mode The open-mode to pass to \a StreamType's constructor.
+   */
+  template<typename StreamArgType>
+  stream( StreamArgType stream_arg, std::ios_base::openmode mode ) :
+    StreamType( stream_arg, mode ),
+#ifdef WIN32
+# pragma warning( push )
+# pragma warning( disable : 4355 )
+#endif /* WIN32 */
+    b64buf_( this->rdbuf() )
+#ifdef WIN32
+# pragma warning( pop )
+#endif /* WIN32 */
+  {
+    init();
+  }
+
+private:
+  streambuf b64buf_;
+
+  void init() {
+    this->std::ios::rdbuf( &b64buf_ );
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace base64
+} // namespace zorba
+#endif  /* ZORBA_BASE64_STREAM_API_H */
+/* vim:set et sw=2 ts=2: */

=== modified file 'include/zorba/internal/diagnostic.h'
--- include/zorba/internal/diagnostic.h	2012-06-18 10:06:47 +0000
+++ include/zorba/internal/diagnostic.h	2012-06-26 01:20:25 +0000
@@ -42,7 +42,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * A %location hold the file location of an error.
+ * A %location holds the file location of an error.
  */
 class ZORBA_DLL_PUBLIC location {
 public:
@@ -71,21 +71,17 @@
    * Constructs a %location.
    *
    * @param file The name of the file where the error occurred.
-   * @param line The line number of the file where the expression that
-   *  raises the error begins.
+   * @param line The line number of the file where the expression that raises
+   * the error begins.
    * @param column The column number, if any, of the file where the expression
-   *  that raises the error begins.
-   * @param line_end The end line number, if any, of the file where the expression
-   *  causing the error ends.
-   * @param column_end The end column number, if any, of the file where 
-   *  the xpression causing the error ends.
+   * that raises the error begins.
+   * @param line_end The end line number, if any, of the file where the
+   * expression causing the error ends.
+   * @param column_end The end column number, if any, of the file where the
+   * xpression causing the error ends.
    */
-  location(
-      char const *file,
-      line_type line,
-      column_type column = 0,
-      line_type line_end = 0,
-      column_type column_end = 0) :
+  location( char const *file, line_type line, column_type column = 0,
+            line_type line_end = 0, column_type column_end = 0 ) :
     file_( file ), line_( line ), column_( column ),
     line_end_( line_end ), column_end_( column_end )
   {
@@ -97,19 +93,16 @@
    * @tparam StringType The string type for \a file.
    * @param file The name of the file where the error occurred.
    * @param line The line number of the file where the error occurred.
-   * @param column The column number, if any, of the file where the error occurred.
-   * @param line_end The end line number, if any, of the file where the expression
-   *  causing the error ends.
-   * @param column_end The end column number, if any, of the file where 
-   *  the xpression causing the error ends.
+   * @param column The column number, if any, of the file where the error
+   * occurred.
+   * @param line_end The end line number, if any, of the file where the
+   * expression causing the error ends.
+   * @param column_end The end column number, if any, of the file where the
+   * xpression causing the error ends.
    */
   template<class StringType>
-  location(
-      StringType const &file,
-      line_type line,
-      column_type column = 0,
-      line_type line_end = 0,
-      column_type column_end = 0) :
+  location( StringType const &file, line_type line, column_type column = 0,
+            line_type line_end = 0, column_type column_end = 0 ) :
     file_( file.c_str() ), line_( line ), column_( column ),
     line_end_( line_end ), column_end_( column_end )
   {
@@ -189,12 +182,8 @@
    * @param column_end The column number, if any, where the error ends.
    * occurred.
    */
-  void set(
-      char const *file,
-      line_type line,
-      column_type column = 0,
-      line_type line_end = 0,
-      column_type column_end = 0) {
+  void set( char const *file, line_type line, column_type column = 0,
+            line_type line_end = 0, column_type column_end = 0 ) {
     file_ = file;
     line_ = line;
     column_ = column;

=== added file 'include/zorba/internal/streambuf.h'
--- include/zorba/internal/streambuf.h	1970-01-01 00:00:00 +0000
+++ include/zorba/internal/streambuf.h	2012-06-26 01:20:25 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_INTERNAL_STREAMBUF_H
+#define ZORBA_INTERNAL_STREAMBUF_H
+
+#include <streambuf>
+
+#include <zorba/config.h>
+
+namespace zorba {
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+
+ZORBA_DLL_PUBLIC
+void dealloc_streambuf( std::streambuf* );
+
+ZORBA_DLL_PUBLIC
+void stream_callback( std::ios_base::event, std::ios_base&, int index );
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace internal
+} // namespace zorba
+#endif  /* ZORBA_INTERNAL_STREAMBUF_H */
+/* vim:set et sw=2 ts=2: */

=== modified file 'include/zorba/transcode_stream.h'
--- include/zorba/transcode_stream.h	2012-06-18 10:06:47 +0000
+++ include/zorba/transcode_stream.h	2012-06-26 01:20:25 +0000
@@ -19,10 +19,10 @@
 
 #include <stdexcept>
 #include <streambuf>
-#include <string>
 
 #include <zorba/config.h>
 #include <zorba/internal/proxy.h>
+#include <zorba/internal/streambuf.h>
 #include <zorba/internal/unique_ptr.h>
 
 namespace zorba {
@@ -120,20 +120,15 @@
 } // namespace transcode
 
 namespace internal {
-
-ZORBA_DLL_PUBLIC
-zorba::transcode::streambuf*
-alloc_streambuf( char const *charset, std::streambuf *orig );
-
-ZORBA_DLL_PUBLIC
-void dealloc_streambuf( zorba::transcode::streambuf* );
+namespace transcode {
+
+ZORBA_DLL_PUBLIC
+std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig );
 
 ZORBA_DLL_PUBLIC
 int get_streambuf_index();
 
-ZORBA_DLL_PUBLIC
-void stream_callback( std::ios_base::event, std::ios_base&, int index );
-
+} // transcode
 } // namespace internal
 
 namespace transcode {
@@ -153,10 +148,11 @@
  */
 template<typename charT,typename Traits> inline
 void attach( std::basic_ios<charT,Traits> &ios, char const *charset ) {
-  int const index = internal::get_streambuf_index();
+  int const index = internal::transcode::get_streambuf_index();
   void *&pword = ios.pword( index );
   if ( !pword ) {
-    streambuf *const buf = internal::alloc_streambuf( charset, ios.rdbuf() );
+    std::streambuf *const buf =
+      internal::transcode::alloc_streambuf( charset, ios.rdbuf() );
     ios.rdbuf( buf );
     pword = buf;
     ios.register_callback( internal::stream_callback, index );
@@ -173,7 +169,7 @@
  */
 template<typename charT,typename Traits> inline
 void detach( std::basic_ios<charT,Traits> &ios ) {
-  int const index = internal::get_streambuf_index();
+  int const index = internal::transcode::get_streambuf_index();
   if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {
     ios.pword( index ) = 0;
     ios.rdbuf( buf->orig_streambuf() );
@@ -189,7 +185,7 @@
  */
 template<typename charT,typename Traits> inline
 bool is_attached( std::basic_ios<charT,Traits> &ios ) {
-  return !!ios.pword( internal::get_streambuf_index() );
+  return !!ios.pword( internal::transcode::get_streambuf_index() );
 }
 
 /**

=== modified file 'src/api/CMakeLists.txt'
--- src/api/CMakeLists.txt	2012-06-18 10:06:47 +0000
+++ src/api/CMakeLists.txt	2012-06-26 01:20:25 +0000
@@ -49,6 +49,7 @@
     fileimpl.cpp
     serializerimpl.cpp
     base64impl.cpp
+    base64_streambuf.cpp
     uriimpl.cpp
     uriresolverimpl.cpp
     uri_resolver_wrappers.cpp
@@ -56,6 +57,7 @@
     zorba_functions.cpp
     annotationimpl.cpp
     auditimpl.cpp
+    streambuf.cpp
     transcode_streambuf.cpp
     )
 

=== added file 'src/api/base64_streambuf.cpp'
--- src/api/base64_streambuf.cpp	1970-01-01 00:00:00 +0000
+++ src/api/base64_streambuf.cpp	2012-06-26 01:20:25 +0000
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+
+#include <stdexcept>
+
+//#define ZORBA_DEBUG_BASE64_STREAMBUF
+#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
+# include <stdio.h>
+#endif
+
+#include <zorba/base64_stream.h>
+
+#include "util/base64_util.h"
+
+using namespace std;
+
+namespace zorba {
+namespace base64 {
+
+int const Large_External_Buf_Size = 4096; // must be a multiple of 4
+
+///////////////////////////////////////////////////////////////////////////////
+
+inline void streambuf::resetg() {
+  setg( gbuf_, gbuf_ + sizeof gbuf_, gbuf_ + sizeof gbuf_ );
+}
+
+inline void streambuf::resetp() {
+  plen_ = 0;
+}
+
+inline void streambuf::writep() {
+  char chunk[4];
+  orig_buf_->sputn( chunk, base64::encode( pbuf_, plen_, chunk ) );
+}
+
+streambuf::streambuf( std::streambuf *orig ) : orig_buf_( orig ) {
+  if ( !orig )
+    throw invalid_argument( "null streambuf" );
+  clear();
+}
+
+streambuf::~streambuf() {
+  if ( plen_ )
+    writep();
+}
+
+void streambuf::clear() {
+  resetg();
+  resetp();
+}
+
+void streambuf::imbue( std::locale const &loc ) {
+  orig_buf_->pubimbue( loc );
+}
+
+streambuf::pos_type streambuf::seekoff( off_type o, ios_base::seekdir d,
+                                        ios_base::openmode m ) {
+  clear();
+  return orig_buf_->pubseekoff( o, d, m );
+}
+
+streambuf::pos_type streambuf::seekpos( pos_type p, ios_base::openmode m ) {
+  clear();
+  return orig_buf_->pubseekpos( p, m );
+}
+
+std::streambuf* streambuf::setbuf( char_type *p, streamsize s ) {
+  orig_buf_->pubsetbuf( p, s );
+  return this;
+}
+
+streamsize streambuf::showmanyc() {
+  return orig_buf_->in_avail();
+}
+
+int streambuf::sync() {
+  if ( plen_ )
+    writep();
+  return orig_buf_->pubsync();
+}
+
+streambuf::int_type streambuf::overflow( int_type c ) {
+#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
+  printf( "overflow()\n" );
+#endif
+  bool const is_eof = traits_type::eq_int_type( c, traits_type::eof() );
+  if ( !is_eof )
+    pbuf_[ plen_++ ] = traits_type::to_char_type( c );
+  if ( plen_ == sizeof pbuf_ || (is_eof && plen_) ) {
+    writep();
+    resetp();
+  }
+  return c;
+}
+
+streambuf::int_type streambuf::pbackfail( int_type c ) {
+  if ( gptr() > eback() )
+    gbump( -1 );
+  return orig_buf_->sputbackc( traits_type::to_char_type( c ) );
+}
+
+streambuf::int_type streambuf::underflow() {
+#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
+  printf( "underflow()\n" );
+#endif
+  char chunk[4];
+  int chunk_len = 0;
+
+  while ( gptr() >= egptr() ) {
+    int_type const c = orig_buf_->sbumpc();
+    bool is_eof = false;
+    if ( traits_type::eq_int_type( c, traits_type::eof() ) ) {
+      if ( !chunk_len )
+        return traits_type::eof();
+      is_eof = true;
+    } else {
+      chunk[ chunk_len++ ] = traits_type::to_char_type( c );
+    }
+    if ( chunk_len == sizeof chunk || (is_eof && chunk_len) ) {
+      streamsize const n = base64::decode( chunk, chunk_len, eback() );
+      setg( gbuf_, gbuf_, gbuf_ + n );
+    }
+  }
+  return traits_type::to_int_type( *gptr() );
+}
+
+streamsize streambuf::xsgetn( char_type *to, streamsize size ) {
+#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
+  printf( "xsgetn()\n" );
+#endif
+  streamsize return_size = 0;
+
+  if ( streamsize const gsize = egptr() - gptr() ) {
+    //
+    // Get any chunk fragment pending the the get buffer first.
+    //
+    streamsize const n = min( gsize, size );
+    traits_type::copy( to, gptr(), n );
+    gbump( n );
+    to += n;
+    size -= n, return_size += n;
+  }
+
+  //
+  // Must get bytes in terms of encoded size.
+  //
+  size = base64::encoded_size( size );
+
+  while ( size ) {
+    char ebuf[ Large_External_Buf_Size ];
+    streamsize const get = min( (streamsize)(sizeof ebuf), size );
+    if ( streamsize got = orig_buf_->sgetn( ebuf, get ) ) {
+      streamsize const decoded = base64::decode( ebuf, got, to );
+      to += decoded;
+      size -= got, return_size += decoded;
+    } else
+      break;
+  }
+
+  return return_size;
+}
+
+streamsize streambuf::xsputn( char_type const *from, streamsize size ) {
+#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
+  printf( "xsputn()\n" );
+#endif
+  streamsize return_size = 0;
+
+  //
+  // Put any chunk fragment pending in the put buffer by completing it first.
+  //
+  while ( plen_ && size ) {
+    overflow( *from );
+    ++from, --size, ++return_size;
+  }
+
+  while ( size >= 3 ) {
+    char ebuf[ Large_External_Buf_Size ];
+    streamsize const put = min( (streamsize)(sizeof ebuf), size );
+    streamsize const encoded = base64::encode( from, put, ebuf );
+    orig_buf_->sputn( ebuf, encoded );
+    from += put, size -= put, return_size += put;
+  }
+
+  //
+  // Put any remaining chunk fragment into the put buffer.
+  //
+  if ( size ) {
+    traits_type::copy( pbuf_, from, size );
+    plen_ = size;
+  }
+
+  return return_size;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace base64
+
+namespace internal {
+namespace base64 {
+
+// Both new & delete are done inside Zorba rather than in the header to
+// guarantee that they're cross-DLL-boundary safe on Windows.
+
+std::streambuf* alloc_streambuf( std::streambuf *orig ) {
+  return new zorba::base64::streambuf( orig );
+}
+
+int get_streambuf_index() {
+  //
+  // This function is out-of-line because it has a static constant within it.
+  // It has a static constant within it to guarantee (1) initialization before
+  // use and (2) initialization happens exactly once.
+  //
+  // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and
+  // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section
+  // 3.3.1.1: "Initializing and Maintaining the iword/pword Index."
+  //
+  // See: "The C++ Programming Language," Bjarne Stroustrup, Addison-Wesley,
+  // 2000, section 10.4.8: "Local Static Store."
+  //
+  static int const index = ios_base::xalloc();
+  return index;
+}
+
+} // namespace base64
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/api/base64impl.cpp'
--- src/api/base64impl.cpp	2012-06-18 10:06:47 +0000
+++ src/api/base64impl.cpp	2012-06-26 01:20:25 +0000
@@ -17,45 +17,70 @@
 
 #include <sstream> 
 #include <zorba/base64.h>
+#include <zorba/diagnostic_list.h>
 
 #include <zorba/config.h>
 #include <zorba/zorba_string.h>
 
-#include "zorbatypes/binary.h"
+#include "diagnostics/dict.h"
+#include "diagnostics/xquery_exception.h"
+#include "util/base64_util.h"
 
+#define CATCH_BASE64_EXCEPTION()                                            \
+  catch ( base64::exception const &e ) {                                    \
+    throw XQUERY_EXCEPTION(                                                 \
+      err::FORG0001, ERROR_PARAMS( e.invalid_char(), ZED( Base64BadChar ) ) \
+    );                                                                      \
+  }                                                                         \
+  catch ( std::invalid_argument const& ) {                                  \
+    throw XQUERY_EXCEPTION(                                                 \
+      err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) )             \
+    );                                                                      \
+  }
 
 namespace zorba {
 namespace encoding {
 
 String Base64::encode(const String& aString) 
 {
-  std::stringstream lStream;
-  lStream << aString;
-
-  return encode(lStream);
+  String result;
+  base64::encode( aString.data(), aString.size(), &result );
+  return result;
 }
 
 
 String Base64::encode(std::istream& aStream) 
 {
-  return zorba::Base64::encode(aStream).str();
+  String result;
+  base64::encode( aStream, &result );
+  return result;
 }
 
 
 String Base64::decode(const String& aString)
 {
-  std::stringstream lStream;
-  lStream << aString;
-  return decode(lStream);
+  try {
+    String result;
+    base64::decode(
+      aString.data(), aString.size(), &result, base64::dopt_ignore_ws
+    );
+    return result;
+  }
+  CATCH_BASE64_EXCEPTION()
 }
 
 
 String Base64::decode(std::istream& aStream)
 {
-  return zorba::Base64::decode(aStream).str();
+  try {
+    String result;
+    base64::decode( aStream, &result, base64::dopt_ignore_ws );
+    return result;
+  }
+  CATCH_BASE64_EXCEPTION()
 }
 
 
-} /* end namespace encoding */
-} /* end namespace zorba */
+} // namespace encoding
+} // namespace zorba
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/api/serialization/serializer.cpp'
--- src/api/serialization/serializer.cpp	2012-06-18 10:06:47 +0000
+++ src/api/serialization/serializer.cpp	2012-06-26 01:20:25 +0000
@@ -2300,7 +2300,9 @@
     std::istream& stream = item->getStream();
     if (item->isEncoded())
     {
-      tr << Base64::decode(stream);
+      zstring decoded;
+      Base64::decode(stream, &decoded);
+      tr << decoded;
     }
     else
     {
@@ -2322,9 +2324,9 @@
 
       if (item->isEncoded())
       {
-        std::stringstream tmp;
-        tmp.write(value, len);
-        tr << Base64::decode(tmp);
+        zstring decoded;
+        Base64::decode(value, len, &decoded);
+        tr << decoded;
       }
       else
       {

=== added file 'src/api/streambuf.cpp'
--- src/api/streambuf.cpp	1970-01-01 00:00:00 +0000
+++ src/api/streambuf.cpp	2012-06-26 01:20:25 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+#include <zorba/internal/streambuf.h>
+
+using namespace std;
+
+namespace zorba {
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+
+// "delete" is done here inside Zorba rather than in the header to guarantee
+// that it's cross-DLL-boundary safe on Windows.
+
+void dealloc_streambuf( streambuf *buf ) {
+  delete buf;
+}
+
+void stream_callback( ios_base::event e, ios_base &ios, int index ) {
+  //
+  // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and
+  // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section
+  // 3.3.1.4: "Using Stream Callbacks for Memory Management."
+  //
+  if ( e == ios_base::erase_event )
+    delete static_cast<streambuf*>( ios.pword( index ) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace internal
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/api/transcode_streambuf.cpp'
--- src/api/transcode_streambuf.cpp	2012-06-18 10:06:47 +0000
+++ src/api/transcode_streambuf.cpp	2012-06-26 01:20:25 +0000
@@ -81,8 +81,7 @@
   return proxy_buf_->sgetn( to, size );
 }
 
-streamsize streambuf::xsputn( char_type const *from,
-                                       streamsize size ) {
+streamsize streambuf::xsputn( char_type const *from, streamsize size ) {
   return proxy_buf_->sputn( from, size );
 }
 
@@ -103,19 +102,15 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 namespace internal {
+namespace transcode {
 
 // Both new & delete are done here inside Zorba rather than in the header to
 // guarantee that they're cross-DLL-boundary safe on Windows.
 
-zorba::transcode::streambuf*
-alloc_streambuf( char const *charset, std::streambuf *orig ) {
+std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig ) {
   return new zorba::transcode::streambuf( charset, orig );
 }
 
-void dealloc_streambuf( zorba::transcode::streambuf *buf ) {
-  delete buf;
-}
-
 int get_streambuf_index() {
   //
   // This function is out-of-line because it has a static constant within it.
@@ -133,16 +128,7 @@
   return index;
 }
 
-void stream_callback( ios_base::event e, ios_base &ios, int index ) {
-  //
-  // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and
-  // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section
-  // 3.3.1.4: "Using Stream Callbacks for Memory Management."
-  //
-  if ( e == ios_base::erase_event )
-    delete static_cast<streambuf*>( ios.pword( index ) );
-}
-
+} // namespace transcode
 } // namespace internal
 
 ///////////////////////////////////////////////////////////////////////////////

=== modified file 'src/diagnostics/diagnostic_en.xml'
--- src/diagnostics/diagnostic_en.xml	2012-06-18 10:06:47 +0000
+++ src/diagnostics/diagnostic_en.xml	2012-06-26 01:20:25 +0000
@@ -2888,14 +2888,6 @@
       <value>invalid Base64 character</value>
     </entry>
 
-    <entry key="Base64Equals">
-      <value>in Base64, '=' must be at the end and followed by one of [AEIMQUYcgkosw048]</value>
-    </entry>
-
-    <entry key="Base64EqualsEquals">
-      <value>in Base64, "==" must be at the end and followed by one of [AQgw]</value>
-    </entry>
-
     <entry key="Base64Multiple4">
       <value>Base64 data must be a multiple of 4 characters</value>
     </entry>

=== modified file 'src/diagnostics/pregenerated/dict_en.cpp'
--- src/diagnostics/pregenerated/dict_en.cpp	2012-06-18 10:06:47 +0000
+++ src/diagnostics/pregenerated/dict_en.cpp	2012-06-26 01:20:25 +0000
@@ -546,8 +546,6 @@
   { "~BadXMLNoOpeningTag", "closing tag without matching opening tag" },
   { "~BadXQueryVersion", "unsupported XQuery version" },
   { "~Base64BadChar", "invalid Base64 character" },
-  { "~Base64Equals", "in Base64, '=' must be at the end and followed by one of [AEIMQUYcgkosw048]" },
-  { "~Base64EqualsEquals", "in Base64, \"==\" must be at the end and followed by one of [AQgw]" },
   { "~Base64Multiple4", "Base64 data must be a multiple of 4 characters" },
   { "~BaseURI", "base URI" },
   { "~BoxCondTooManyColumns", "box condition has more columns than index" },

=== modified file 'src/runtime/base64/base64_impl.cpp'
--- src/runtime/base64/base64_impl.cpp	2012-06-18 10:06:47 +0000
+++ src/runtime/base64/base64_impl.cpp	2012-06-26 01:20:25 +0000
@@ -66,7 +66,7 @@
   {
     if (lItem->isEncoded())
     {
-      lResultString = Base64::decode(lItem->getStream());
+      Base64::decode(lItem->getStream(), &lResultString);
     }
     else
     {
@@ -93,10 +93,7 @@
 
     if (lItem->isEncoded())
     {
-      std::vector<char> encoded(lContent, lContent+lSize);
-      std::vector<char> decoded;
-      Base64::decode(encoded, decoded);
-      lResultString.insert(0, &decoded[0], decoded.size());
+      Base64::decode( lContent, lSize, &lResultString );
     }
     else
     {
@@ -156,8 +153,8 @@
     // create a base64Binary item
     // the content is the non-encoded string
     GENV_ITEMFACTORY->createBase64Binary(
-          result, lTmpString.c_str(), lTmpString.size(), false
-        );
+      result, lTmpString.c_str(), lTmpString.size(), false
+    );
     STACK_PUSH (true, state);
   }
   STACK_END (state);

=== modified file 'src/unit_tests/CMakeLists.txt'
--- src/unit_tests/CMakeLists.txt	2012-06-18 10:06:47 +0000
+++ src/unit_tests/CMakeLists.txt	2012-06-26 01:20:25 +0000
@@ -13,6 +13,8 @@
 # limitations under the License.
 
 SET(UNIT_TEST_SRCS
+  test_base64.cpp
+  test_base64_streambuf.cpp
   string_instantiate.cpp
   string.cpp
   test_uri.cpp

=== added file 'src/unit_tests/test_base64.cpp'
--- src/unit_tests/test_base64.cpp	1970-01-01 00:00:00 +0000
+++ src/unit_tests/test_base64.cpp	2012-06-26 01:20:25 +0000
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include "util/base64_util.h"
+
+using namespace std;
+using namespace zorba;
+
+struct test {
+  char const *input;
+  char const *expected;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int failures;
+
+static bool assert_true( int no, char const *expr, int line, bool result ) {
+  if ( !result ) {
+    cout << '#' << no << " FAILED, line " << line << ": " << expr << endl;
+    ++failures;
+  }
+  return result;
+}
+
+static void print_exception( int no, char const *expr, int line,
+                             std::exception const &e ) {
+  assert_true( no, expr, line, false );
+  cout << "+ exception: " << e.what() << endl;
+}
+
+#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) )
+
+#define ASSERT_NO_EXCEPTION( NO, EXPR ) \
+  try { EXPR; } \
+  catch ( std::exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); } \
+  catch ( ... ) { assert_true( NO, #EXPR, __LINE__, false ); }
+
+#define ASSERT_EXCEPTION( NO, EXPR, EXCEPTION ) \
+  try { EXPR; assert_true( NO, #EXPR, __LINE__, false ); } \
+  catch ( EXCEPTION const& ) { }
+
+///////////////////////////////////////////////////////////////////////////////}
+
+static void test_decode_buf_to_buf( int no, string const &in,
+                                    string const &expected ) {
+  base64::size_type n;
+  char out[ 1024 ];
+  ASSERT_NO_EXCEPTION(
+    no, n = base64::decode( in.data(), in.size(), out, base64::dopt_any_len )
+  );
+  ASSERT_TRUE( no, n == expected.size() );
+  out[ n ] = '\0';
+  ASSERT_TRUE( no, out == expected );
+}
+
+static void test_decode_buf_to_string( int no, string const &in,
+                                       string const &expected ) {
+  base64::size_type n;
+  string out;
+  ASSERT_NO_EXCEPTION(
+    no,
+    n = base64::decode( in.data(), in.size(), &out, base64::dopt_any_len )
+  );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, out == expected );
+}
+
+static void test_decode_buf_to_vector( int no, string const &in,
+                                       string const &expected ) {
+  base64::size_type n;
+  vector<char> out;
+  ASSERT_NO_EXCEPTION(
+    no,
+    n = base64::decode( in.data(), in.size(), &out, base64::dopt_any_len )
+  );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
+}
+
+static void test_decode_stream_to_stream( int no, string const &in,
+                                          string const &expected ) {
+  base64::size_type n;
+  istringstream sin( in );
+  ostringstream sout;
+  ASSERT_NO_EXCEPTION(
+    no, n = base64::decode( sin, sout, base64::dopt_any_len )
+  );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, sout.str().size() == expected.size() );
+  ASSERT_TRUE( no, sout.str() == expected );
+}
+
+static void test_decode_stream_to_string( int no, string const &in,
+                                          string const &expected ) {
+  base64::size_type n;
+  istringstream sin( in );
+  string out;
+  ASSERT_NO_EXCEPTION(
+    no, n = base64::decode( sin, &out, base64::dopt_any_len )
+  );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, out == expected );
+}
+
+static void test_decode_stream_to_vector( int no, string const &in,
+                                          string const &expected ) {
+  base64::size_type n;
+  istringstream sin( in );
+  vector<char> out;
+  ASSERT_NO_EXCEPTION(
+    no, n = base64::decode( sin, &out, base64::dopt_any_len )
+  );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
+}
+
+static void test_decode_exception( int no, string const &in ) {
+  char out[ 1024 ];
+  ASSERT_EXCEPTION(
+    no, base64::decode( in.data(), in.size(), out ), invalid_argument
+  );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_encode_buf_to_buf( int no, string const &in,
+                                    string const &expected ) {
+  char out[ 1024 ];
+  base64::size_type const n = base64::encode( in.data(), in.size(), out );
+  ASSERT_TRUE( no, n == expected.size() );
+  out[ n ] = '\0';
+  ASSERT_TRUE( no, out == expected );
+}
+
+static void test_encode_buf_to_string( int no, string const &in,
+                                       string const &expected ) {
+  base64::size_type n;
+  string out;
+  ASSERT_NO_EXCEPTION( no, n = base64::encode( in.data(), in.size(), &out ) );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, out == expected );
+}
+
+static void test_encode_buf_to_vector( int no, string const &in,
+                                       string const &expected ) {
+  base64::size_type n;
+  vector<char> out;
+  ASSERT_NO_EXCEPTION( no, n = base64::encode( in.data(), in.size(), &out ) );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
+}
+
+static void test_encode_stream_to_stream( int no, string const &in,
+                                          string const &expected ) {
+  base64::size_type n;
+  istringstream sin( in );
+  ostringstream sout;
+  ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, sout ) );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, sout.str().size() == expected.size() );
+  ASSERT_TRUE( no, sout.str() == expected );
+}
+
+static void test_encode_stream_to_string( int no, string const &in,
+                                          string const &expected ) {
+  base64::size_type n;
+  istringstream sin( in );
+  string out;
+  ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, &out ) );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, out == expected );
+}
+
+static void test_encode_stream_to_vector( int no, string const &in,
+                                          string const &expected ) {
+  base64::size_type n;
+  istringstream sin( in );
+  vector<char> out;
+  ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, &out ) );
+  ASSERT_TRUE( no, n == expected.size() );
+  ASSERT_TRUE( no, out.size() == expected.size() );
+  ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static test const encode_tests[] = {
+  /* 0 */ { "Now is the time", "Tm93IGlzIHRoZSB0aW1l" },
+  /* 1 */ { "Now is the time.", "Tm93IGlzIHRoZSB0aW1lLg==" },
+  /* 2 */ { "Now is the time..", "Tm93IGlzIHRoZSB0aW1lLi4=" },
+
+  { 0, 0 }
+};
+
+static test const decode_tests[] = {
+  /* 3 */ { "Tm93IGlzIHRoZSB0aW1l", "Now is the time" },
+  /* 4 */ { "Tm93IGlzIHRoZSB0aW1lLg==", "Now is the time." },
+  /* 5 */ { "Tm93IGlzIHRoZSB0aW1lLi4=", "Now is the time.." },
+
+  // incomplete Base64 encodings
+  /* 6 */ { "Tm93IGlzIHRoZSB0aW1", "Now is the tim" },
+  /* 7 */ { "Tm93IGlzIHRoZSB0aW", "Now is the ti" },
+  /* 8 */ { "Tm93IGlzIHRoZSB0a", "Now is the t" },
+
+  { 0, 0 }
+};
+
+static char const *const decode_exception_tests[] = {
+  "=",
+  "_m93",
+  "T_93",
+  "Tm_3",
+  "Tm9_",
+  "=m93",
+  "T=93",
+  "Tm=3",
+  "Tm93=",
+  "ZmX=",
+  "ZX==",
+  "ZX===",
+  0
+};
+
+namespace zorba {
+namespace UnitTests {
+
+int test_base64( int, char*[] ) {
+  int test_no = 0;
+
+  for ( test const *t = encode_tests; t->input; ++t, ++test_no ) {
+    test_encode_buf_to_buf( test_no, t->input, t->expected );
+    test_encode_buf_to_string( test_no, t->input, t->expected );
+    test_encode_buf_to_vector( test_no, t->input, t->expected );
+    test_encode_stream_to_stream( test_no, t->input, t->expected );
+    test_encode_stream_to_string( test_no, t->input, t->expected );
+    test_encode_stream_to_vector( test_no, t->input, t->expected );
+  }
+
+  for ( test const *t = decode_tests; t->input; ++t, ++test_no ) {
+    test_decode_buf_to_buf( test_no, t->input, t->expected );
+    test_decode_buf_to_string( test_no, t->input, t->expected );
+    test_decode_buf_to_vector( test_no, t->input, t->expected );
+    test_decode_stream_to_stream( test_no, t->input, t->expected );
+    test_decode_stream_to_string( test_no, t->input, t->expected );
+    test_decode_stream_to_vector( test_no, t->input, t->expected );
+  }
+
+  for ( char const *const *t = decode_exception_tests; *t; ++t, ++test_no )
+    test_decode_exception( test_no, *t );
+
+  cout << failures << " test(s) failed\n";
+  return failures ? 1 : 0;
+}
+
+} // namespace UnitTests
+} // namespace zorba
+
+/* vim:set et sw=2 ts=2: */

=== added file 'src/unit_tests/test_base64_streambuf.cpp'
--- src/unit_tests/test_base64_streambuf.cpp	1970-01-01 00:00:00 +0000
+++ src/unit_tests/test_base64_streambuf.cpp	2012-06-26 01:20:25 +0000
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <zorba/base64_stream.h>
+
+using namespace std;
+using namespace zorba;
+
+struct test {
+  char const *raw_str;
+  char const *b64_str;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int failures;
+
+static bool assert_true( int no, char const *expr, int line, bool result ) {
+  if ( !result ) {
+    cout << '#' << no << " FAILED, line " << line << ": " << expr << endl;
+    ++failures;
+  }
+  return result;
+}
+
+static void print_exception( int no, char const *expr, int line,
+                             std::exception const &e ) {
+  assert_true( no, expr, line, false );
+  cout << "+ exception: " << e.what() << endl;
+}
+
+#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) )
+
+#define ASSERT_TRUE_AND_NO_EXCEPTION( NO, EXPR ) \
+  try { ASSERT_TRUE( NO, EXPR ); } \
+  catch ( std::exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); }
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool test_getline( test const *t ) {
+  string const b64_str( t->b64_str );
+  istringstream iss( b64_str );
+  base64::streambuf b64_sbuf( iss.rdbuf() );
+  iss.ios::rdbuf( &b64_sbuf );
+
+  char raw_buf[ 1024 ];
+  iss.getline( raw_buf, sizeof raw_buf );
+  if ( iss.gcount() ) {
+    string const raw_str( raw_buf );
+    return raw_str == t->raw_str;
+  }
+  return false;
+}
+
+static bool test_read( test const *t ) {
+  string const b64_str( t->b64_str );
+  istringstream iss( b64_str );
+  base64::streambuf b64_sbuf( iss.rdbuf() );
+  iss.ios::rdbuf( &b64_sbuf );
+
+  char raw_buf[ 1024 ];
+  iss.read( raw_buf, sizeof raw_buf );
+  if ( iss.gcount() ) {
+    string const raw_str( raw_buf, iss.gcount() );
+    return raw_str == t->raw_str;
+  }
+  return false;
+}
+
+static bool test_insertion( test const *t ) {
+  ostringstream oss;
+  base64::streambuf b64_sbuf( oss.rdbuf() );
+  oss.ios::rdbuf( &b64_sbuf );
+
+  oss << t->raw_str << flush;
+  string const b64_str( oss.str() );
+
+  string const expected_b64_str( t->b64_str );
+  return b64_str == expected_b64_str;
+}
+
+static bool test_put( test const *t ) {
+  ostringstream oss;
+  { // local scope
+  base64::auto_attach<ostringstream> const raii( oss );
+
+  for ( char const *c = t->raw_str; *c; ++c )
+    oss.put( *c );
+  } // local scope
+  string const b64_str( oss.str() );
+
+  string const expected_b64_str( t->b64_str );
+  return b64_str == expected_b64_str;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static test const tests[] = {
+  /* 0 */ { "Now ", "Tm93IA==" },
+  /* 1 */ { "Now is the time", "Tm93IGlzIHRoZSB0aW1l" },
+  /* 2 */ { "Now is the time.", "Tm93IGlzIHRoZSB0aW1lLg==" },
+  /* 3 */ { "Now is the time..", "Tm93IGlzIHRoZSB0aW1lLi4=" },
+  { 0, 0 }
+};
+
+namespace zorba {
+namespace UnitTests {
+
+int test_base64_streambuf( int, char*[] ) {
+  int test_no = 0;
+  for ( test const *t = tests; t->raw_str; ++t, ++test_no ) {
+    ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_getline( t ) );
+    ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_read( t ) );
+    ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_insertion( t ) );
+    ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_put( t ) );
+  }
+  cout << failures << " test(s) failed\n";
+  return failures ? 1 : 0;
+}
+
+} // namespace UnitTests
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/unit_tests/unit_test_list.h'
--- src/unit_tests/unit_test_list.h	2012-06-18 10:06:47 +0000
+++ src/unit_tests/unit_test_list.h	2012-06-26 01:20:25 +0000
@@ -21,24 +21,21 @@
 
 #include <zorba/config.h>
 
-namespace zorba 
-{
+namespace zorba {
+namespace UnitTests {
 
-namespace UnitTests 
-{
   int runUriTest(int argc, char* argv[]);
   int runDebuggerProtocolTest(int argc, char* argv[]);
+  int test_base64( int, char*[] );
+  int test_base64_streambuf( int, char*[] );
+  int test_fs_iterator( int, char*[] );
   int test_string( int, char*[] );
   int test_unique_ptr( int, char*[] );
-  int test_fs_iterator( int, char*[] );
 #ifndef ZORBA_NO_FULL_TEXT
   int test_stemmer( int, char*[] );
   int test_thesaurus( int, char*[] );
   int test_tokenizer( int, char*[] );
 #endif /* ZORBA_NO_FULL_TEXT */
-  /**
-   * ADD NEW UNIT TESTS HERE
-   */
 #ifndef ZORBA_NO_ICU
   int test_icu_streambuf( int, char*[] );
 #endif /* ZORBA_NO_ICU */
@@ -46,9 +43,7 @@
   
   void initializeTestList();
 
-
-};
-} /* namespace zorba */
-
+} // namespace UnitTests
+} // namespace zorba
 #endif /* ZORBA_UNIT_TEST_LIST_H */
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/unit_tests/unit_tests.cpp'
--- src/unit_tests/unit_tests.cpp	2012-06-18 10:06:47 +0000
+++ src/unit_tests/unit_tests.cpp	2012-06-26 01:20:25 +0000
@@ -28,9 +28,7 @@
 using namespace std;
 
 namespace zorba {
-
-namespace UnitTests 
-{
+namespace UnitTests {
 
 map<string,libunittestfunc> libunittests;
 
@@ -39,14 +37,16 @@
  */
 void initializeTestList() 
 {
+  libunittests["base64"] = test_base64;
+  libunittests["base64_streambuf"] = test_base64_streambuf;
+  libunittests["fs_iterator"] = test_fs_iterator;
+  libunittests["json_parser"] = json_parser;
   libunittests["string"] = test_string;
+  libunittests["unique_ptr"] = test_unique_ptr;
   libunittests["uri"] = runUriTest;
-  libunittests["fs_iterator"] = test_fs_iterator;
 #ifndef ZORBA_NO_ICU
   libunittests["icu_streambuf"] = test_icu_streambuf;
 #endif /* ZORBA_NO_ICU */
-  libunittests["json_parser"] = json_parser;
-  libunittests["unique_ptr"] = test_unique_ptr;
 #ifndef ZORBA_NO_FULL_TEXT
   libunittests["stemmer"] = test_stemmer;
   libunittests["thesaurus"] = test_thesaurus;
@@ -78,7 +78,6 @@
 }
 
 
-} /* namespace UnitTests */
-} /* namespace zorba */
-
+} // namespace UnitTests
+} // namespace zorba
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/util/CMakeLists.txt'
--- src/util/CMakeLists.txt	2012-06-18 10:06:47 +0000
+++ src/util/CMakeLists.txt	2012-06-26 01:20:25 +0000
@@ -14,6 +14,7 @@
 
 SET(UTIL_SRCS
   ascii_util.cpp
+  base64_util.cpp
   dynamic_bitset.cpp
   error_util.cpp
   file.cpp

=== modified file 'src/util/ascii_util.cpp'
--- src/util/ascii_util.cpp	2012-06-18 10:06:47 +0000
+++ src/util/ascii_util.cpp	2012-06-26 01:20:25 +0000
@@ -15,6 +15,8 @@
  */
 #include "stdafx.h"
 
+#include <cstring>
+
 #include "ascii_util.h"
 
 namespace zorba {
@@ -30,6 +32,38 @@
   return true;
 }
 
+size_type remove_chars( char *s, size_type s_len, char const *chars ) {
+  char *end = s + s_len;
+  char *c;
+
+  // remove trailing chars first
+  for ( c = end - 1; c >= s; --c )
+    if ( !std::strchr( chars, *c ) ) {
+      end = c + 1;
+      break;
+    }
+  if ( c < s )                          // it was all chars
+    return 0;
+
+  // remove all other chars
+  char *first_char = nullptr;
+  for ( c = s; c < end; ++c ) { 
+    if ( std::strchr( chars, *c ) ) { 
+      if ( !first_char ) 
+        first_char = c;
+    } else { 
+      if ( first_char ) { 
+        std::memmove( first_char, c, end - c );
+        end -= c - first_char;
+        c = first_char;
+        first_char = nullptr;
+      } 
+    } 
+  } 
+
+  return end - s;
+}
+
 char const* trim_start( char const *s, char const *chars ) {
   for ( ; *s; ++s ) {
     if ( !std::strchr( chars, *s ) )

=== modified file 'src/util/ascii_util.h'
--- src/util/ascii_util.h	2012-06-18 10:06:47 +0000
+++ src/util/ascii_util.h	2012-06-26 01:20:25 +0000
@@ -649,6 +649,29 @@
 }
 
 /**
+ * Removes all specified characters by shifting the contents of the buffer to
+ * the left.
+ *
+ * @param s The string.
+ * @param s_len The length of \a s.
+ * @param chars The characters to remove.
+ * @return Returns the new length of \a s with all \a chars removed.
+ */
+size_type remove_chars( char *s, size_type s_len, char const *chars );
+
+/**
+ * Removes all whitespace characters by shifting the contents of the buffer to
+ * the left.
+ *
+ * @param s The string.
+ * @param s_len The length of \a s.
+ * @return Returns the new length of \a s with all whitespace removed.
+ */
+inline size_type remove_whitespace( char *s, size_type s_len ) {
+  return remove_chars( s, s_len, whitespace );
+}
+
+/**
  * Removes all leading and trailing specified characters.
  *
  * @tparam InputStringType The input string type.

=== added file 'src/util/base64_util.cpp'
--- src/util/base64_util.cpp	1970-01-01 00:00:00 +0000
+++ src/util/base64_util.cpp	2012-06-26 01:20:25 +0000
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <cstring>
+
+#include "ascii_util.h"
+#include "base64_util.h"
+#include "string_util.h"
+
+using namespace std;
+
+namespace zorba {
+namespace base64 {
+
+///////////////////////////////////////////////////////////////////////////////
+
+static char const alphabet[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz"
+  "0123456789+/";
+
+/**
+ * Base64 decoding table.  A value of -1 means "invalid"; a value of -2 means
+ * "skip" (for newlines and carriage returns).
+ */
+static signed char const decode_table[] = {
+  /* 00-07 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 08-0F */ -1, -1, -2, -1, -1, -2, -1, -1, // . .\n . .\r . .
+  /* 10-17 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 18-1F */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 20-27 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 28-2F */ -1, -1, -1, 62, -1, -1, -1, 63, // . . . + . . . /
+  /* 30-37 */ 52, 53, 54, 55, 56, 57, 58, 59, // 0 1 2 3 4 5 6 7
+  /* 38-3F */ 60, 61, -1, -1, -1, -1, -1, -1, // 8 9 . . . . . .
+  /* 40-47 */ -1,  0,  1,  2,  3,  4,  5,  6, // . A B C D E F G
+  /* 48-4F */  7,  8,  9, 10, 11, 12, 13, 14, // H I J K L M N O
+  /* 50-57 */ 15, 16, 17, 18, 19, 20, 21, 22, // P Q R S T U V W
+  /* 58-5F */ 23, 24, 25, -1, -1, -1, -1, -1, // X Y Z . . . . .
+  /* 60-67 */ -1, 26, 27, 28, 29, 30, 31, 32, // . a b c d e f g
+  /* 68-6F */ 33, 34, 35, 36, 37, 38, 39, 40, // h i j k l m n o
+  /* 70-77 */ 41, 42, 43, 44, 45, 46, 47, 48, // p q r s t u v w
+  /* 78-7F */ 49, 50, 51, -1, -1, -1, -1, -1, // x y z . . . . .
+  /* 80-87 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 88-8F */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 90-97 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* 98-9F */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* A0-A7 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* A8-AF */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* B0-B7 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* B8-BF */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* C0-C7 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* C8-CF */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* D0-D7 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* D8-DF */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* E0-E7 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* E8-EF */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* F0-F7 */ -1, -1, -1, -1, -1, -1, -1, -1,
+  /* F8-FF */ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+inline void decode_chunk( char const *from, char *to ) {
+  //
+  //  | INPUT BYTES
+  //  +-----------+-----------+-----------+-----------+
+  //  |     0     |     1     |     2     |     3     |
+  //  +-----------+-----------+-----------+-----------+
+  //  |           |           |           |           |
+  //  | | | | | | | | | | | | | | | | | | | | | | | | |
+  //  |               |               |               |
+  //  +---------------+---------------+---------------+
+  //  |       0       |       1       |       2       |
+  //  +---------------+---------------+---------------+
+  //  | OUTPUT BYTES
+  //
+  unsigned char const *const u = reinterpret_cast<unsigned char const*>( from );
+  to[0] =  (u[0] << 2)         | (u[1] >> 4);
+  to[1] =  (u[1] << 4)         | (u[2] >> 2);
+  to[2] = ((u[2] << 6) & 0xC0) |  u[3]      ;
+}
+
+inline void encode_chunk( char const *from, char *to ) {
+  //
+  //  | INPUT BYTES
+  //  +---------------+---------------+---------------+
+  //  |       0       |       1       |       2       |
+  //  +---------------+---------------+---------------+
+  //  |               |               |               |
+  //  | | | | | | | | | | | | | | | | | | | | | | | | |
+  //  |           |           |           |           |
+  //  +-----------+-----------+-----------+-----------+
+  //  |     0     |     1     |     2     |     3     |
+  //  +-----------+-----------+-----------+-----------+
+  //  | OUTPUT BYTES
+  //
+  unsigned char const *const u = reinterpret_cast<unsigned char const*>( from );
+  to[0] = alphabet[   u[0]         >> 2                ];
+  to[1] = alphabet[ ((u[0] & 0x03) << 4) | (u[1] >> 4) ];
+  to[2] = alphabet[ ((u[1] & 0x0F) << 2) | (u[2] >> 6) ];
+  to[3] = alphabet[   u[2] & 0x3F                      ];
+}
+
+streamsize read_without_whitespace( istream &is, char *buf, streamsize n ) {
+  char const *const buf_orig = buf;
+  char const *const buf_end = buf + n;
+
+  while ( buf < buf_end ) {
+    is.read( buf, n );
+    if ( streamsize read = is.gcount() ) {
+      read = ascii::remove_whitespace( buf, read );
+      buf += read, n -= read;
+    } else
+      break;
+  }
+  return buf - buf_orig;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+size_type decode( char const *from, size_type from_len, char *to,
+                  int options ) {
+  char chunk[4];
+  int chunk_len = 0;
+  bool const ignore_ws = options & dopt_ignore_ws;
+  int pads = 0;
+  char const *const to_orig = to;
+
+  for ( size_type pos = 0; pos < from_len; ++pos, ++from ) {
+    char const c = *from;
+    signed char value;
+    if ( c == '=' ) {
+      switch ( pos % 4 ) {
+        //
+        // Ensure '=' occurs only in the 3rd or 4th bytes of a 4-byte chunk
+        // and that the byte preceding '=' is valid.
+        //
+        case 2:
+          if ( !strchr( "AQgw", from[-1] ) )
+            throw base64::exception(
+              c, pos, BUILD_STRING( '\'', c, "': invalid character before '='" )
+            );
+          break;
+        case 3:
+          if ( !strchr( "=048AEIMQUYcgkosw", from[-1] ) )
+            throw base64::exception(
+              c, pos, BUILD_STRING( '\'', c, "': invalid character before '='" )
+            );
+          break;
+        default:
+          throw base64::exception( c, pos, "'=' encountered unexpectedly" );
+      }
+      ++pads;
+      value = '\0';
+    } else {
+      if ( pads )
+        throw base64::exception(
+          c, pos, BUILD_STRING( '\'', c, "': invalid character after '='" )
+        );
+      value = decode_table[ static_cast<unsigned char>( c ) ];
+    }
+    switch ( value ) {
+      case -1:
+        if ( ascii::is_space( c ) && ignore_ws )
+          continue;
+        throw base64::exception(
+          c, pos, BUILD_STRING( '\'', c, "': invalid character" )
+        );
+      case -2: // \n or \r
+        continue;
+      default:
+        if ( chunk_len == 4 )
+          chunk_len = 0;
+        if ( to ) {
+          chunk[ chunk_len ] = value;
+          if ( ++chunk_len == 4 ) {
+            decode_chunk( chunk, to );
+            to += 3;
+          }
+        } else
+          ++chunk_len;
+    }
+  } // for
+
+  if ( (chunk_len % 4) && !(options & dopt_any_len) )
+    throw invalid_argument( "Base64 length is not a multiple of 4" );
+
+  if ( !to )
+    return 0;
+
+  if ( chunk_len > 1 && chunk_len < 4 ) {
+    //
+    // The number of non-whitespace bytes was not a multiple of 4, hence the
+    // Base64 encoding is incomplete: salvage 1 or 2 characters.
+    //
+    int const salvageable = chunk_len - 1;
+    chunk[3] = '\0';
+    if ( salvageable == 1 )
+      chunk[2] = '\0';
+    decode_chunk( chunk, to );
+    to += salvageable;
+  }
+
+  return to - to_orig - pads;
+}
+
+size_type decode( char const *from, size_type from_len, std::vector<char> *to,
+                  int options ) {
+  size_type total_decoded = 0;
+  if ( from_len ) {
+    std::vector<char>::size_type const orig_size = to->size();
+    to->resize( orig_size + decoded_size( from_len ) );
+    total_decoded = decode( from, from_len, &(*to)[ orig_size ], options );
+    to->resize( orig_size + total_decoded );
+  }
+  return total_decoded;
+}
+
+size_type decode( istream &from, ostream &to, int options ) {
+  size_type total_decoded = 0;
+  while ( !from.eof() ) {
+    char from_buf[ 1024 * 4 ], to_buf[ 1024 * 3 ];
+    streamsize gcount;
+    if ( options & dopt_ignore_ws )
+      gcount = read_without_whitespace( from, from_buf, sizeof from_buf );
+    else {
+      from.read( from_buf, sizeof from_buf );
+      gcount = from.gcount();
+    }
+    if ( gcount ) {
+      size_type const decoded = decode( from_buf, gcount, to_buf, options );
+      to.write( to_buf, decoded );
+      total_decoded += decoded;
+    } else
+      break;
+  }
+  return total_decoded;
+}
+
+size_type decode( istream &from, vector<char> *to, int options ) {
+  vector<char>::size_type const orig_size = to->size();
+  size_type total_decoded = 0;
+  while ( !from.eof() ) {
+    char from_buf[ 1024 * 4 ];
+    streamsize gcount;
+    if ( options & dopt_ignore_ws )
+      gcount = read_without_whitespace( from, from_buf, sizeof from_buf );
+    else {
+      from.read( from_buf, sizeof from_buf );
+      gcount = from.gcount();
+    }
+    if ( gcount ) {
+      to->resize( to->size() + decoded_size( gcount ) );
+      total_decoded +=
+        decode( from_buf, gcount, &(*to)[ total_decoded ], options );
+    } else
+      break;
+  }
+  to->resize( orig_size + total_decoded );
+  return total_decoded;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+size_type encode( char const *from, size_type from_len, char *to ) {
+  char const *const to_orig = to;
+  int chunk_len = 0;
+
+  while ( from_len-- ) {
+    if ( ++chunk_len == 3 ) {
+      encode_chunk( from, to );
+      from += 3, to += 4;
+      chunk_len = 0;
+    }
+  }
+
+  if ( chunk_len ) {                    // must be either 1 or 2
+    //
+    // Handle the special-case of from_len not being a multiple of 3.  First,
+    // copy what's left over from "from" to a temporary buffer that's 3 bytes
+    // long and encode that buffer so encode_chunk() remains special-case-free
+    // (and thus faster) for most of the encoding.
+    //
+    char from_temp[3];
+    from_temp[1] = from_temp[2] = '\0';
+    std::copy( from, from + chunk_len, from_temp );
+    encode_chunk( from_temp, to );
+    //
+    // Second, overwrite the trailing byte(s) with Base64 padding characters.
+    //
+    to[3] = '=';
+    if ( chunk_len == 1 )
+      to[2] = '=';
+    to += 4;
+  }
+
+  return to - to_orig;
+}
+
+size_type encode( char const *from, size_type from_len,
+                  std::vector<char> *to ) {
+  size_type encoded = 0;
+  if ( from_len ) {
+    std::vector<char>::size_type const orig_size = to->size();
+    to->resize( orig_size + encoded_size( from_len ) );
+    encoded = encode( from, from_len, &(*to)[ orig_size ] );
+    to->resize( orig_size + encoded );
+  }
+  return encoded;
+}
+
+size_type encode( istream &from, ostream &to ) {
+  size_type total_encoded = 0;
+  while ( !from.eof() ) {
+    char from_buf[ 1024 * 3 ], to_buf[ 1024 * 4 ];
+    from.read( from_buf, sizeof from_buf );
+    if ( streamsize const gcount = from.gcount() ) {
+      size_type const encoded = encode( from_buf, gcount, to_buf );
+      to.write( to_buf, encoded );
+      total_encoded += encoded;
+    } else
+      break;
+  }
+  return total_encoded;
+}
+
+size_type encode( istream &from, vector<char> *to ) {
+  vector<char>::size_type const orig_size = to->size();
+  size_type total_encoded = 0;
+  while ( !from.eof() ) {
+    char from_buf[ 1024 * 3 ];
+    from.read( from_buf, sizeof from_buf );
+    if ( streamsize const gcount = from.gcount() ) {
+      to->resize( to->size() + encoded_size( gcount ) );
+      total_encoded += encode( from_buf, gcount, &(*to)[ total_encoded ] );
+    } else
+      break;
+  }
+  to->resize( orig_size + total_encoded );
+  return total_encoded;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace base64
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== added file 'src/util/base64_util.h'
--- src/util/base64_util.h	1970-01-01 00:00:00 +0000
+++ src/util/base64_util.h	2012-06-26 01:20:25 +0000
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#ifndef ZORBA_BASE64_UTIL_H
+#define ZORBA_BASE64_UTIL_H
+
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+#include <sys/types.h>                  /* for size_t */
+#include <vector>
+
+#include "cxx_util.h"
+
+namespace zorba {
+namespace base64 {
+
+////////// Types //////////////////////////////////////////////////////////////
+
+typedef size_t size_type;
+
+/**
+ * Options to use for decoding.
+ */
+enum decode_options {
+  dopt_none       = 0x00, ///< No options.
+  dopt_any_len    = 0x01, ///< Input length may be non-multiple of 4.
+  dopt_ignore_ws  = 0x02, ///< Ignore all whitespace.
+};
+
+////////// Exception //////////////////////////////////////////////////////////
+
+/**
+ * A %base64::exception is-an invalid_argument that contains additional details
+ * about the exception such as the invalid character and its offset.
+ */
+class exception : public std::invalid_argument {
+public:
+  exception( char c, size_type offset, std::string const &msg ) :
+    std::invalid_argument( msg ), char_( c ), offset_( offset ) { }
+
+  char invalid_char() const {
+    return char_;
+  }
+
+  size_type char_offset() const {
+    return offset_;
+  }
+
+private:
+  char char_;
+  size_type offset_;
+};
+
+////////// Decoding ///////////////////////////////////////////////////////////
+
+/**
+ * \internal
+ * Reads from the given istream until \a n non-whitespace characters are read
+ * or until EOF is encountered.
+ *
+ * @param is The istream to read from.
+ * @param buf A pointer to the start of a buffer to read into.
+ * @param n The number of non-whitespace characters to read.
+ * @return Returns the number of non-whitespace characters read.
+ */
+std::streamsize read_without_whitespace( std::istream &is, char *buf,
+                                         std::streamsize n );
+
+/**
+ * Calculates the number of bytes required to decode \a n Base64-encoded bytes.
+ *
+ * @param n The number of bytes to decode.
+ * @return Returns the number of bytes needed for Base64 decoding.
+ */
+inline size_type decoded_size( size_type n ) {
+  return ((n / 4) + !!(n % 4)) * 3;
+}
+
+/**
+ * Decodes a Base64-encoded buffer.  Embedded newlines and carriage-returns are
+ * skipped.
+ *
+ * @param from A pointer to the Base64 buffer to be decoded.
+ * @param from_len The number of bytes to decode.
+ * @paran to A pointer to the buffer to receive the decoded bytes.  The buffer
+ * must be large enough to contain them.  Note that the buffer is \e not null
+ * terminated.
+ * @param options The decoding options to use.
+ * @return Returns the number of decoded bytes.
+ * @throws invalid_argument if \a options does not have the \c dtop_any_len bit
+ * set and \a from_len is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ * @see decoded_size()
+ */
+size_type decode( char const *from, size_type from_len, char *to,
+                  int options = dopt_none );
+
+/**
+ * Decodes a Base64-encoded buffer and appends the decoded bytes onto a
+ * vector&lt;char&gt;.  Embedded newlines and carriage-returns are skipped.
+ *
+ * @param from A pointer to the buffer to be encoded.
+ * @param from_len The number of bytes to encode.
+ * @param to A pointer to the vector to append the encoded bytes appended onto.
+ * The vector is made large enough to contain the additional bytes.
+ * @param options The decoding options to use.
+ * @return Returns the number of decoded bytes.
+ * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
+ * set and the number of Base64 bytes decoded is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ */
+size_type decode( char const *from, size_type from_len, std::vector<char> *to,
+                  int options = dopt_none );
+
+/**
+ * Decodes a Base64-encoded buffer and appends the decoded bytes onto a string.
+ * Embedded newlines and carriage-returns are skipped.
+ *
+ * @tparam ToStringType The string type.
+ * @param from A pointer to the Base64 buffer to be decoded.
+ * @param from_len The number of bytes to decode.
+ * @param to The string to append the decoded bytes to.
+ * @param options The options to use.
+ * @return Returns the number of decoded bytes.
+ * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
+ * set and the number of Base64 bytes decoded is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ */
+template<class ToStringType>
+size_type decode( char const *from, size_type from_len, ToStringType *to,
+                  int options = dopt_none ) {
+  size_type total_decoded = 0;
+  if ( from_len ) {
+    typename ToStringType::size_type const orig_size = to->size();
+    to->resize( orig_size + decoded_size( from_len ) );
+    total_decoded = decode( from, from_len, &to->at( orig_size ), options );
+    to->resize( orig_size + total_decoded );
+  }
+  return total_decoded;
+}
+
+/**
+ * Decodes a Base64-encoded istream.  Embedded newlines and carriage-returns
+ * are skipped.
+ *
+ * @param from The istream to read from until EOF is reached.
+ * @param to The ostream to write the decoded bytes to.
+ * @param options The options to use.
+ * 4 otherwise an exception is thrown; if \a false, missing trailing bytes are
+ * assumed to be padding.
+ * @return Returns the number of decoded bytes.
+ * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
+ * set and the number of Base64 bytes decoded is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ */
+size_type decode( std::istream &from, std::ostream &to,
+                  int options = dopt_none );
+
+/**
+ * Decodes a Base64-encoded istream and appends the decoded bytes to a string.
+ * Embedded newlines and carriage-returns are skipped.
+ *
+ * @tparam ToStringType The string type.
+ * @param from The istream to read from until EOF is reached.
+ * @param to The string to append the decoded bytes to.
+ * @param options The options to use.
+ * 4 otherwise an exception is thrown; if \a false, missing trailing bytes are
+ * assumed to be padding.
+ * @return Returns the number of decoded bytes.
+ * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
+ * set and the number of Base64 bytes decoded is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ */
+template<class ToStringType>
+size_type decode( std::istream &from, ToStringType *to,
+                  int options = dopt_none ) {
+  size_type total_decoded = 0;
+  while ( !from.eof() ) {
+    char from_buf[ 1024 * 4 ], to_buf[ 1024 * 3 ];
+    std::streamsize gcount;
+    if ( options & dopt_ignore_ws )
+      gcount = read_without_whitespace( from, from_buf, sizeof from_buf );
+    else {
+      from.read( from_buf, sizeof from_buf );
+      gcount = from.gcount();
+    }
+    if ( gcount ) {
+      size_type const decoded = decode( from_buf, gcount, to_buf, options );
+      to->append( to_buf, decoded );
+      total_decoded += decoded;
+    } else
+      break;
+  }
+  return total_decoded;
+}
+
+/**
+ * Decodes a Base64-encoded stream and appends the decoded bytes onto a
+ * vector&lt;char;&gt;.
+ *
+ * @param from The istream to read from until EOF is reached.
+ * @param to The string to append the decoded bytes to.
+ * @param options The options to use.
+ * @param Returns the number of decoded bytes.
+ * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
+ * set and the number of Base64 bytes decoded is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ */
+size_type decode( std::istream &from, std::vector<char> *to,
+                  int options = dopt_none );
+
+/**
+ * Validates a Base64-encoded buffer.  Embedded newlines and carriage-returns
+ * are skipped.
+ *
+ * @param buf A pointer to the Base64 buffer to be validated.
+ * @param buf_len The number of bytes to validate.
+ * @param options The options to use.
+ * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
+ * set and the number of Base64 bytes validated is not a multiple of 4.
+ * @throws base64::exception if an \c = is encountered unexpectedly or an
+ * invalid byte is encountered.
+ * @see decoded_size()
+ */
+inline void validate( char const *buf, size_type buf_len,
+                      int options = dopt_none ) {
+  decode( buf, buf_len, static_cast<char*>( nullptr ), options );
+}
+
+////////// Encoding ///////////////////////////////////////////////////////////
+
+/**
+ * Calculates the number of bytes required to Base64-encode \a n bytes.
+ *
+ * @param n The number of bytes to encode.
+ * @return Returns the number of bytes needed for Base64 encoding.
+ */
+inline size_type encoded_size( size_type n ) {
+  return (n + 2) / 3 * 4;
+}
+
+/**
+ * Base64-encodes a buffer.
+ *
+ * @param from A pointer to the buffer to be encoded.
+ * @param from_len The number of bytes to encode.
+ * @param to A pointer to the buffer to receive the encoded bytes.  The buffer
+ * must be large enough to contain them.  Note that the buffer is \e not null
+ * terminated.
+ * @return Returns the number of encoded bytes.
+ * @see encoded_size()
+ */
+size_type encode( char const *from, size_type from_len, char *to );
+
+/**
+ * Base64-encodes a buffer and appends the encoded bytes onto a
+ * vector&lt;char&gt;.
+ *
+ * @param from A pointer to the buffer to be encoded.
+ * @param from_len The number of bytes to encode.
+ * @param to A pointer to the vector to append the encoded bytes appended onto.
+ * The vector is made large enough to contain the additional bytes.
+ */
+size_type encode( char const *from, size_type from_len, std::vector<char> *to );
+
+/**
+ * Base64-encodes a buffer and appends the encoded bytes onto a string.
+ *
+ * @tparam ToStringType The string type.
+ * @param from A pointer to the Base64 buffer to be encoded.
+ * @param from_len The number of bytes to encode.
+ * @param to A pointer to the string to append the encoded bytes onto.
+ * @return Returns the number of encoded bytes.
+ */
+template<class ToStringType>
+size_type encode( char const *from, size_type from_len, ToStringType *to ) {
+  size_type total_encoded = 0;
+  if ( from_len ) {
+    typename ToStringType::size_type const orig_size = to->size();
+    to->resize( orig_size + encoded_size( from_len ) );
+    total_encoded = encode( from, from_len, &to->at( orig_size ) );
+    to->resize( orig_size + total_encoded );
+  }
+  return total_encoded;
+}
+
+/**
+ * Base64-encodes one stream and write the encoded bytes to another.
+ *
+ * @param from The istream to read from until EOF is reached.
+ * @param to The ostream to write the encoded bytes to.
+ */
+size_type encode( std::istream &from, std::ostream &to );
+
+/**
+ * Encodes a stream to Base64 and appends the encoded bytes to a string.
+ *
+ * @tparam ToStringType The string type.
+ * @param from The istream to read from until EOF is reached.
+ * @param to The string to append the encoded bytes to.
+ * @return Returns the number of encoded bytes.
+ */
+template<class ToStringType>
+size_type encode( std::istream &from, ToStringType *to ) {
+  size_type total_encoded = 0;
+  while ( !from.eof() ) {
+    char from_buf[ 1024 * 3 ], to_buf[ 1024 * 4 ];
+    from.read( from_buf, sizeof from_buf );
+    if ( std::streamsize const gcount = from.gcount() ) {
+      size_type const encoded = encode( from_buf, gcount, to_buf );
+      to->append( to_buf, encoded );
+      total_encoded += encoded;
+    } else
+      break;
+  }
+  return total_encoded;
+}
+
+/**
+ * Base64-encodes a stream and appends the encoded bytes onto a
+ * vector&lt;char;&gt;.
+ *
+ * @param from The istream to read from until EOF is reached.
+ * @param to The string to append the encoded bytes to.
+ * @param Returns the number of encoded bytes.
+ */
+size_type encode( std::istream &from, std::vector<char> *to );
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace base64
+} // namespace zorba
+
+#endif /* ZORBA_BASE64_UTIL_H */
+/*
+ * Local variables:
+ * mode: c++
+ * End:
+ */
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/util/icu_streambuf.cpp'
--- src/util/icu_streambuf.cpp	2012-06-18 10:06:47 +0000
+++ src/util/icu_streambuf.cpp	2012-06-26 01:20:25 +0000
@@ -15,8 +15,8 @@
  */
 
 #include "stdafx.h"
-#define ZORBA_DEBUG_ICU_STREAMBUF 0
 
+// #define ZORBA_DEBUG_ICU_STREAMBUF
 #ifdef ZORBA_DEBUG_ICU_STREAMBUF
 # include <stdio.h>
 #endif

=== modified file 'src/util/string/rstring.h'
--- src/util/string/rstring.h	2012-06-18 10:06:47 +0000
+++ src/util/string/rstring.h	2012-06-26 01:20:25 +0000
@@ -1884,7 +1884,7 @@
   }
 
   /**
-   * Attemts to pre-allocated enough memory to contain the given number of
+   * Attemts to pre-allocate enough memory to contain the given number of
    * bytes.
    *
    * @param n The number of bytes.

=== modified file 'src/zorbaserialization/serialize_template_types.h'
--- src/zorbaserialization/serialize_template_types.h	2012-06-25 09:22:44 +0000
+++ src/zorbaserialization/serialize_template_types.h	2012-06-26 01:20:25 +0000
@@ -65,6 +65,7 @@
 {
   if (ar.is_serializing_out())
   {
+#if 0
     bool is_ref = ar.add_compound_field(obj.get_serializer_type_code(),
                                         true,
                                         (SerializeBaseClass*)&obj, 
@@ -93,6 +94,7 @@
     obj.serialize_internal(ar);
 
     ar.read_end_current_level();
+#endif
   }
 }
 

=== modified file 'src/zorbatypes/binary.cpp'
--- src/zorbatypes/binary.cpp	2012-06-18 10:06:47 +0000
+++ src/zorbatypes/binary.cpp	2012-06-26 01:20:25 +0000
@@ -25,32 +25,44 @@
 #include "diagnostics/xquery_diagnostics.h"
 
 #include "util/ascii_util.h"
+#include "util/base64_util.h"
 #include "util/stl_util.h"
 
+#define CATCH_BASE64_EXCEPTION()                                            \
+  catch ( base64::exception const &e ) {                                    \
+    throw XQUERY_EXCEPTION(                                                 \
+      err::FORG0001, ERROR_PARAMS( e.invalid_char(), ZED( Base64BadChar ) ) \
+    );                                                                      \
+  }                                                                         \
+  catch ( std::invalid_argument const& ) {                                  \
+    throw XQUERY_EXCEPTION(                                                 \
+      err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) )             \
+    );                                                                      \
+  }
+
 using namespace std;
 
-namespace zorba 
-{
-
-
-static const string base64_chars = 
-             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-             "abcdefghijklmnopqrstuvwxyz"
-             "0123456789+/";
-
-
-inline bool is_base64(char c) 
-{
-  return (isalnum(c) || (c == '+') || (c == '/'));
+namespace zorba {
+
+static size_t copy_without_ws( char const *from, size_t len, char *to ) {
+  char const *const end = from + len;
+  char const *const to_orig = to;
+  for ( ; from < end; ++from )
+    if ( !ascii::is_space( *from ) )
+      *to++ = *from;
+  return to - to_orig;
 }
 
 
 bool Base64::parseString(const char* aString, size_t aLength,  Base64& aBase64)
 {
-  aBase64.theData.clear();
   try 
   {
-    aBase64.insertData(aString, aLength);
+    base64::validate( aString, aLength, base64::dopt_ignore_ws );
+    aBase64.theData.resize( aLength );
+    aBase64.theData.resize(
+      copy_without_ws( aString, aLength, &aBase64.theData[0] )
+    );
   }
   catch (...) 
   {
@@ -66,10 +78,13 @@
     Base64& aBase64, 
     string& lErrorMessage)
 {
-  aBase64.theData.clear();
   try 
   {
-    aBase64.insertData(aString, aLength);
+    base64::validate( aString, aLength, base64::dopt_ignore_ws );
+    aBase64.theData.resize( aLength );
+    aBase64.theData.resize(
+      copy_without_ws( aString, aLength, &aBase64.theData[0] )
+    );
   }
   catch (ZorbaException const& e) 
   {
@@ -82,102 +97,27 @@
 
 void Base64::encode(const zstring& aString, Base64& aResult)
 {
-  vector<char> source;
-  source.reserve(aString.size());
-  
-  FOR_EACH( zstring, i, aString )
-    source.push_back( *i );
-
-  aResult.theData.clear();
-  encode(source, aResult.theData);
+  base64::encode( aString.data(), aString.size(), &aResult.theData );
 }
 
 
 void Base64::encode(istream& aStream, Base64& aResult)
 {
-  vector<char> source;
-
-  char lC;
-  while (aStream.good()) 
-  {
-    aStream.get(lC);
-    if (!aStream.good()) 
-    {
-      break;
-    }
-    source.push_back(lC);
-  }
-
-  encode(source, aResult.theData);
+  base64::encode( aStream, &aResult.theData );
 }
 
 
 zstring Base64::encode(istream& aStream)
 {
-  vector<char> source;
-  vector<char> dest;
-
-  char buf[1024];
-  while (!aStream.eof()) 
-  {
-    aStream.read(buf, 1024);
-    source.insert(source.end(), buf, buf + aStream.gcount());
-  }
-
-  encode(source, dest);
-
   zstring result;
-  result.reserve(dest.size());
-
-  FOR_EACH( vector<char>, i, dest )
-    result.push_back( *i );
-
+  base64::encode( aStream, &result );
   return result;
 }
 
 
 void Base64::encode(const vector<char>& aSource, vector<char>& aResult)
 {
-  size_t in_len = aSource.size();
-  size_t lCurPos = 0;
-  int i = 0;
-  int j = 0;
-  char char_array_3[3] = {'\0','\0','\0'};
-  char char_array_4[4] = {'\0','\0','\0','\0'};
-
-  while (in_len--) 
-  {
-    char_array_3[i++] = aSource[lCurPos++];
-    if (i == 3) 
-    {
-      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
-      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
-      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
-      char_array_4[3] = char_array_3[2] & 0x3f;
-
-      for(i = 0; (i <4) ; i++)
-        aResult.push_back(base64_chars[char_array_4[i]]);
-      i = 0;
-    }
-  }
-
-  if (i)
-  {
-    for(j = i; j < 3; j++)
-      char_array_3[j] = '\0';
-
-    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
-    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
-    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
-    char_array_4[3] = char_array_3[2] & 0x3f;
-
-    for (j = 0; (j < i + 1); j++)
-      aResult.push_back(base64_chars[char_array_4[j]]);
-
-    while((i++ < 3))
-      aResult.push_back('=');
-
-  }  
+  base64::encode( &aSource[0], aSource.size(), &aResult );
 }
 
 
@@ -186,110 +126,38 @@
     unsigned int in_len,
     Base64& aResult)
 {
-  size_t lCurPos = 0;
-  int i = 0;
-  int j = 0;
-  char char_array_3[3] = {'\0','\0','\0'};
-  char char_array_4[4] = {'\0','\0','\0','\0'};
-
-  aResult.theData.reserve(in_len * 8 / 6  + 10);
-  while (in_len--) 
-  {
-    char_array_3[i++] = aSource[lCurPos++];
-    if (i == 3) 
-    {
-      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
-      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
-      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
-      char_array_4[3] = char_array_3[2] & 0x3f;
-
-      for(i = 0; (i <4) ; i++)
-        aResult.theData.push_back(base64_chars[char_array_4[i]]);
-      i = 0;
-    }
-  }
-
-  if (i)
-  {
-    for(j = i; j < 3; j++)
-      char_array_3[j] = '\0';
-
-    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
-    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
-    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
-    char_array_4[3] = char_array_3[2] & 0x3f;
-
-    for (j = 0; (j < i + 1); j++)
-      aResult.theData.push_back(base64_chars[char_array_4[j]]);
-
-    while((i++ < 3))
-      aResult.theData.push_back('=');
-
-  }  
+  base64::encode( (char*)aSource, in_len, &aResult.theData );
 }
 
 
-zstring Base64::decode(istream& aStream)
+void Base64::decode(istream& aStream, zstring *result)
 {
-  vector<char> source;
-  vector<char> dest;
-
-  char buf[1024];
-  while (!aStream.eof()) 
-  {
-    aStream.read(buf, 1024);
-    source.insert(source.end(), buf, buf + aStream.gcount());
+  try {
+    base64::decode(
+      aStream, result, base64::dopt_any_len | base64::dopt_ignore_ws
+    );
   }
-
-  decode(source, dest);
-
-  zstring result;
-  result.reserve(dest.size());
-
-  FOR_EACH( vector<char>, i, dest )
-    result.push_back( *i );
-
-  return result;
+  CATCH_BASE64_EXCEPTION()
 }
 
-
 void Base64::decode(const vector<char>& aSource, vector<char>& aResult)
 {
-  size_t in_len = aSource.size();
-  int i = 0;
-  int j = 0;
-  int in_ = 0;
-  char char_array_4[4], char_array_3[3];
-
-  while (in_len-- && ( aSource[in_] != '=') && is_base64(aSource[in_])) {
-    char_array_4[i++] = aSource[in_]; in_++;
-    if (i ==4) {
-      for (i = 0; i <4; i++)
-        char_array_4[i] = (char)base64_chars.find(char_array_4[i]);
-
-      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
-      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
-      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
-      for (i = 0; (i < 3); i++)
-        aResult.push_back(char_array_3[i]);
-      i = 0;
-    }
-  }
-
-  if (i) {
-    for (j = i; j <4; j++)
-      char_array_4[j] = 0;
-
-    for (j = 0; j <4; j++)
-      char_array_4[j] = (char)base64_chars.find(char_array_4[j]);
-
-    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
-    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
-    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
-    for (j = 0; (j < i - 1); j++) aResult.push_back(char_array_3[j]);
-  }
+  try {
+    base64::decode(
+      &aSource[0], aSource.size(), &aResult,
+      base64::dopt_any_len | base64::dopt_ignore_ws
+    );
+  }
+  CATCH_BASE64_EXCEPTION()
+}
+
+void Base64::decode( char const *from, size_t from_len, zstring *to ) {
+  try {
+    base64::decode(
+      from, from_len, to, base64::dopt_any_len | base64::dopt_ignore_ws
+    );
+  }
+  CATCH_BASE64_EXCEPTION()
 }
 
 
@@ -303,88 +171,12 @@
 
 Base64::Base64(const unsigned char *bin_data, size_t len)
 {
-  std::vector<char> tmp;
-  tmp.reserve(len);
-  tmp.insert(tmp.begin(), (const char*)bin_data, ((const char*)bin_data) + len);
-  theData.reserve(len);
-  encode(tmp, theData);
-}
-
-
-void Base64::insertData(const char* str, size_t len)
-{
-  ascii::size_type pos = 0;
-
-  ascii::skip_whitespace(str, len, &pos);
-
-  for (size_t i = pos; i < len; ++i)
-  {
-    char lChar = str[i];
-
-    if (lChar == ' ')
-    {
-      // do nothing
-    }
-    else if ((lChar >= 65 && lChar <= 90)  // A-Z
-         || (lChar >= 97 && lChar <= 122) // a-z
-         || (lChar >= 48 && lChar <= 57)  // 0-9
-         || (lChar == 43)                 // +
-         || (lChar == 47))                // /
-    {
-      theData.push_back(lChar);
-    }
-    else if (lChar == '=' && i > 0 && i == (len-2) && str[i+1] == '=' )
-    {
-      if (str[i-1] == 'A' ||
-          str[i-1] == 'Q' ||
-          str[i-1] == 'g' ||
-          str[i-1] == 'w')
-      {
-        theData.push_back('=');
-        theData.push_back('=');
-        ++i;
-      }
-      else
-      {
-        throw XQUERY_EXCEPTION(
-          err::FORG0001, ERROR_PARAMS( "==", ZED( Base64EqualsEquals ) )
-        );
-      }
-    }
-    else if (lChar == '=' && i > 0 && i == (len-1))
-    {
-      switch(str[i-1]) 
-      {
-      case 'A': case 'E': case 'I': case 'M': case 'Q': case 'U': case 'Y':
-      case 'c': case 'g': case 'k': case 'o': case 's': case 'w': case '0':
-      case '4': case '8':
-        theData.push_back('=');
-        break;
-      default:
-        throw XQUERY_EXCEPTION(
-          err::FORG0001, ERROR_PARAMS( '=', ZED( Base64Equals ) )
-        );
-      }
-    }
-    else if ( ascii::is_space(lChar) ) 
-    {
-      // ignore it
-    }
-    else
-    {
-      throw XQUERY_EXCEPTION(
-        err::FORG0001, ERROR_PARAMS( str[i], ZED( Base64BadChar ) )
-      );
-    }
-  }
-
-  if (theData.size() % 4 != 0) 
-  {
-    throw XQUERY_EXCEPTION(
-      err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) )
-    );
-  }
-}
+  try {
+    base64::encode( (char const*)bin_data, len, &theData );
+  }
+  CATCH_BASE64_EXCEPTION()
+}
+
 
 
 bool Base64::equal(const Base64& aBase64) const
@@ -396,7 +188,7 @@
   vector<char>::const_iterator lEnd0 = theData.end();
   vector<char>::const_iterator lIter1 = aBase64.theData.begin();
 
-  for (; lIter0 != lEnd0 ; )
+  while ( lIter0 != lEnd0 )
   {
     if (*lIter0 != *lIter1)
       return false;
@@ -408,31 +200,28 @@
 
 zstring Base64::str() const 
 {
-  stringstream lStream;
-  lStream << *this;
-  return zstring(lStream.str());
+  zstring result;
+  vector<char>::const_iterator lIter = theData.begin();
+  vector<char>::const_iterator lEnd = theData.end();
+  for( ; lIter != lEnd ; ++lIter)
+  {
+    result.push_back( *lIter );
+  }
+  return result;
 }
 
 
 zstring Base64::decode() const
 {
-  vector<char> lDecodedData;
-
-  Base64::decode(theData, lDecodedData);
-
   zstring result;
-  result.reserve( lDecodedData.size() );
-
-  FOR_EACH( vector<char>, i, lDecodedData )
-    result.push_back( *i );
-
+  base64::decode( &theData[0], theData.size(), &result );
   return result;
 }
 
 
 void Base64::decode(vector<char>& aResult)
 {
-  Base64::decode(theData, aResult);
+  base64::decode( &theData[0], theData.size(), &aResult );
 }
 
 
@@ -466,6 +255,7 @@
   return os;
 }
 
+///////////////////////////////////////////////////////////////////////////////
 
 const char* Base16::ENCODE_TABLE = "0123456789ABCDEF";
 
@@ -662,6 +452,7 @@
   return os;
 }
 
+///////////////////////////////////////////////////////////////////////////////
 
 } // namespace zorba
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/zorbatypes/binary.h'
--- src/zorbatypes/binary.h	2012-06-18 10:06:47 +0000
+++ src/zorbatypes/binary.h	2012-06-26 01:20:25 +0000
@@ -76,7 +76,9 @@
 
   static void decode(const std::vector<char>&, std::vector<char>&);
 
-  static zstring decode(std::istream& aStream);
+  static void decode(std::istream& aStream, zstring*);
+
+  static void decode(char const*, size_t, zstring*);
 
 public:
   Base64(const Base64& aBase64) 
@@ -90,8 +92,6 @@
 
   Base64() {}
 
-  virtual ~Base64() {}
-
   const std::vector<char>& getData() const { return theData; }
 
   size_t size() const { return theData.size(); }
@@ -105,9 +105,6 @@
   void decode(std::vector<char>&);
 
   uint32_t hash() const;
-
-private:
-  void insertData(const char* aCharStar, size_t len);
 };
 
 


Follow ups