zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #11342
[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<char>. 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<char;>.
+ *
+ * @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<char>.
+ *
+ * @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<char;>.
+ *
+ * @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
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: noreply, 2012-06-27
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Zorba Build Bot, 2012-06-27
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Zorba Build Bot, 2012-06-27
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Matthias Brantner, 2012-06-27
-
Re: [Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Matthias Brantner, 2012-06-27
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Zorba Build Bot, 2012-06-26
-
Re: [Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Zorba Build Bot, 2012-06-26
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Zorba Build Bot, 2012-06-26
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Zorba Build Bot, 2012-06-26
-
[Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Matthias Brantner, 2012-06-26
-
Re: [Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Matthias Brantner, 2012-06-26
-
Re: [Merge] lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
From: Paul J. Lucas, 2012-06-26