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

Proposed by Paul J. Lucas
Status: Merged
Approved by: Matthias Brantner
Approved revision: 10894
Merged at revision: 10894
Proposed branch: lp:~zorba-coders/zorba/feature-base64_streambuf
Merge into: lp:zorba
Diff against target: 3118 lines (+2077/-451)
30 files modified
ChangeLog (+2/-1)
doc/cxx/examples/binary.cpp (+17/-27)
include/zorba/base64.h (+7/-10)
include/zorba/base64_stream.h (+325/-0)
include/zorba/internal/diagnostic.h (+20/-31)
include/zorba/internal/streambuf.h (+40/-0)
include/zorba/transcode_stream.h (+11/-15)
src/api/CMakeLists.txt (+2/-0)
src/api/base64_streambuf.cpp (+249/-0)
src/api/base64impl.cpp (+37/-12)
src/api/serialization/serializer.cpp (+6/-4)
src/api/streambuf.cpp (+48/-0)
src/api/transcode_streambuf.cpp (+4/-18)
src/diagnostics/diagnostic_en.xml (+0/-8)
src/diagnostics/pregenerated/dict_en.cpp (+0/-2)
src/runtime/base64/base64_impl.cpp (+4/-7)
src/unit_tests/CMakeLists.txt (+2/-0)
src/unit_tests/test_base64.cpp (+286/-0)
src/unit_tests/test_base64_streambuf.cpp (+141/-0)
src/unit_tests/unit_test_list.h (+7/-12)
src/unit_tests/unit_tests.cpp (+8/-9)
src/util/CMakeLists.txt (+1/-0)
src/util/ascii_util.cpp (+34/-0)
src/util/ascii_util.h (+23/-0)
src/util/base64_util.cpp (+359/-0)
src/util/base64_util.h (+361/-0)
src/util/icu_streambuf.cpp (+1/-1)
src/util/string/rstring.h (+1/-1)
src/zorbatypes/binary.cpp (+78/-287)
src/zorbatypes/binary.h (+3/-6)
To merge this branch: bzr merge lp:~zorba-coders/zorba/feature-base64_streambuf
Reviewer Review Type Date Requested Status
Matthias Brantner Approve
Paul J. Lucas Approve
Review via email: mp+111984@code.launchpad.net

Commit message

Added base64::streambuf class and replaced horribly inefficient base64 code.

Description of the change

Added base64::streambuf class and replaced horribly inefficient base64 code.

To post a comment you must log in.
Revision history for this message
Paul J. Lucas (paul-lucas) :
review: Approve
Revision history for this message
Matthias Brantner (matthias-brantner) wrote :

Did the streambuf api (already released in 2.5) change?

review: Needs Information
Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

> Did the streambuf api (already released in 2.5) change?

No.

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job feature-base64_streambuf-2012-06-26T18-40-25.173Z is finished. The final status was:

All tests succeeded!

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Voting does not meet specified criteria. Required: Approve > 1, Disapprove < 1, Needs Fixing < 1, Pending < 1. Got: 1 Approve, 1 Needs Information.

Revision history for this message
Matthias Brantner (matthias-brantner) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job feature-base64_streambuf-2012-06-27T00-07-01.759Z is finished. The final status was:

All tests succeeded!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog'
--- ChangeLog 2012-06-25 17:16:19 +0000
+++ ChangeLog 2012-06-26 01:34:26 +0000
@@ -18,7 +18,8 @@
18 * Fixed bug #867357 (Improved parser error messages)18 * Fixed bug #867357 (Improved parser error messages)
19 * Fixed bug #932314 (non-comparable values must be treated as distinct by19 * Fixed bug #932314 (non-comparable values must be treated as distinct by
20 fn:distinct-values)20 fn:distinct-values)
21 * Fixed bug #991088$ (raise XUST0001 in trycatch with mixed updating and simple clauses)21 * Fixed bug #1015580 (Add base64_streambuf / replace inefficient base64 code)
22 * Fixed bug #9910884 (raise XUST0001 in trycatch with mixed updating and simple clauses)
22 * Fixed bug #854506 (ugly type error messages) and partial fix for bug #86700823 * Fixed bug #854506 (ugly type error messages) and partial fix for bug #867008
23 * Fixed bug #1008082 (bug in transform expr when a copy var is not used anywhere)24 * Fixed bug #1008082 (bug in transform expr when a copy var is not used anywhere)
24 * Fixed bug #1003023$ (optimizer problems due to common subexpression after25 * Fixed bug #1003023$ (optimizer problems due to common subexpression after
2526
=== 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:34:26 +0000
@@ -25,35 +25,25 @@
25{25{
26 String lString("Hello Zorba");26 String lString("Hello Zorba");
27 String lEncoded = zorba::encoding::Base64::encode(lString);27 String lEncoded = zorba::encoding::Base64::encode(lString);
28 String lExpectedResult("SGVsbG8gWm9yYmE=");28 return lEncoded == "SGVsbG8gWm9yYmE=";
29 return lEncoded == lExpectedResult;
30}29}
3130
32bool 31bool
33decode_example()32decode_example()
34{33{
35 String lEncoded("SGVsbG8gWm9yYmE=");34 String lEncoded("SGVsbG8gWm9yYmE=");
36 String lDecoded = zorba::encoding::Base64::decode(lEncoded);35 String lDecoded = zorba::encoding::Base64::decode(lEncoded);
37 return lDecoded == "Hello Zorba";36 return lDecoded == "Hello Zorba";
3837}
39}38
4039int binary(int argc, char* argv[]) {
41int 40
42binary(int argc, char* argv[])41 std::cout << "executing example 1 (Base64 encoding of String)" << std::endl;
43{42 if (!encode_example()) return 1;
4443
45bool res = false;44 std::cout << "executing example 2 (decoding of Base64 encoded String)" << std::endl;
4645 if (!decode_example()) return 1;
47std::cout << "executing example 1 (Base64 encoding of String)" << std::endl;46
48res = encode_example();47 return 0;
49if (!res) return 1;48}
50std::cout << std::endl;49/* vim:set et sw=2 ts=2: */
51
52std::cout << "executing example 2 (decoding of Base64 encoded String)" << std::endl;
53res = decode_example();
54if (!res) return 1;
55std::cout << std::endl;
56
57return 0;
58
59}
6050
=== 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:34:26 +0000
@@ -21,12 +21,11 @@
21#include <zorba/config.h>21#include <zorba/config.h>
22#include <zorba/zorba_string.h>22#include <zorba/zorba_string.h>
2323
24namespace zorba { namespace encoding {24namespace zorba {
25namespace encoding {
2526
26 class ZORBA_DLL_PUBLIC Base6427 struct ZORBA_DLL_PUBLIC Base64
27 {28 {
28 public:
29
30 static String29 static String
31 encode(const String& aString);30 encode(const String& aString);
3231
@@ -38,12 +37,10 @@
38 37
39 static String38 static String
40 decode(std::istream& aStream); 39 decode(std::istream& aStream);
41
42 };40 };
4341
44} /* end namespace encoding */42} // namespace encoding
4543} // namespace zorba
46} /* end namespace zorba */44
4745#endif /* ZORBA_BASE64_API_H */
48#endif
49/* vim:set et sw=2 ts=2: */46/* vim:set et sw=2 ts=2: */
5047
=== 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:34:26 +0000
@@ -0,0 +1,325 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ZORBA_BASE64_STREAM_API_H
18#define ZORBA_BASE64_STREAM_API_H
19
20#include <streambuf>
21
22#include <zorba/config.h>
23#include <zorba/internal/streambuf.h>
24
25namespace zorba {
26namespace base64 {
27
28///////////////////////////////////////////////////////////////////////////////
29
30/**
31 * A %base64::streambuf is-a std::streambuf for encoding to and decoding from
32 * Base64 on-the-fly.
33 *
34 * To use it, replace a stream's streambuf:
35 * \code
36 * istream is;
37 * // ...
38 * base64::streambuf b64buf( is.rdbuf() );
39 * is.ios::rdbuf( &b64buf );
40 * \endcode
41 * Note that the %base64::streambuf must exist for as long as it's being used
42 * by the stream. If you are replacing the streabuf for a stream you did not
43 * create, you should set it back to the original streambuf:
44 * \code
45 * void f( ostream &os ) {
46 * base64::streambuf b64buf( os.rdbuf() );
47 * try {
48 * os.ios::rdbuf( &b64buf );
49 * // ...
50 * }
51 * catch ( ... ) {
52 * os.ios::rdbuf( b64buf.orig_streambuf() );
53 * throw;
54 * }
55 * os.ios::rdbuf( b64buf.orig_streambuf() );
56 * }
57 * \endcode
58 * Alternatively, you may wish to use either \c attach(), \c auto_attach, or
59 * \c base64::stream instead.
60 *
61 * \b Note: due to the nature of Base64-encoding, when writing, you \e must
62 * ensure that the streambuf is flushed (by calling either \c pubsync() on the
63 * streambuf or \c flush() on the owning stream) when done.
64 *
65 * While %base64::streambuf does support seeking, the positions are relative
66 * to the original byte stream.
67 */
68class ZORBA_DLL_PUBLIC streambuf : public std::streambuf {
69public:
70 /**
71 * Constructs a %base64::streambuf.
72 *
73 * @param orig The original streambuf to read/write from/to.
74 * @throws std::invalid_argument if is not supported or \a orig is null.
75 */
76 streambuf( std::streambuf *orig );
77
78 /**
79 * Destructs a %base64::streambuf.
80 */
81 ~streambuf();
82
83 /**
84 * Gets the original streambuf.
85 *
86 * @return said streambuf.
87 */
88 std::streambuf* orig_streambuf() const {
89 return orig_buf_;
90 }
91
92protected:
93 void imbue( std::locale const& );
94 pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode );
95 pos_type seekpos( pos_type, std::ios_base::openmode );
96 std::streambuf* setbuf( char_type*, std::streamsize );
97 std::streamsize showmanyc();
98 int sync();
99 int_type overflow( int_type );
100 int_type pbackfail( int_type );
101 int_type underflow();
102 std::streamsize xsgetn( char_type*, std::streamsize );
103 std::streamsize xsputn( char_type const*, std::streamsize );
104
105private:
106 std::streambuf *orig_buf_;
107
108 char gbuf_[3];
109 char pbuf_[3];
110 int plen_;
111
112 void clear();
113 void resetg();
114 void resetp();
115 void writep();
116
117 // forbid
118 streambuf( streambuf const& );
119 streambuf& operator=( streambuf const& );
120};
121
122///////////////////////////////////////////////////////////////////////////////
123
124} // namespace base64
125
126namespace internal {
127namespace base64 {
128
129ZORBA_DLL_PUBLIC
130std::streambuf* alloc_streambuf( std::streambuf *orig );
131
132ZORBA_DLL_PUBLIC
133int get_streambuf_index();
134
135} // namespace base64
136} // namespace internal
137
138namespace base64 {
139
140///////////////////////////////////////////////////////////////////////////////
141
142/**
143 * Attaches a base64::streambuf to a stream. Unlike using a
144 * base64::streambuf directly, this function will create the streambuf,
145 * attach it to the stream, and manage it for the lifetime of the stream
146 * automatically.
147 *
148 * @param ios The stream to attach the base64::streambuf to. If the stream
149 * already has a base64::streambuf attached to it, this function does
150 * nothing.
151 */
152template<typename charT,typename Traits> inline
153void attach( std::basic_ios<charT,Traits> &ios ) {
154 int const index = internal::base64::get_streambuf_index();
155 void *&pword = ios.pword( index );
156 if ( !pword ) {
157 std::streambuf *const buf =
158 internal::base64::alloc_streambuf( ios.rdbuf() );
159 ios.rdbuf( buf );
160 pword = buf;
161 ios.register_callback( internal::stream_callback, index );
162 }
163}
164
165/**
166 * Detaches a previously attached base64::streambuf from a stream. The
167 * streambuf is destroyed and the stream's original streambuf is restored.
168 *
169 * @param ios The stream to detach the base64::streambuf from. If the
170 * stream doesn't have a base64::streambuf attached to it, this function
171 * does nothing.
172 */
173template<typename charT,typename Traits> inline
174void detach( std::basic_ios<charT,Traits> &ios ) {
175 int const index = internal::base64::get_streambuf_index();
176 if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {
177 ios.pword( index ) = 0;
178 ios.rdbuf( buf->orig_streambuf() );
179 internal::dealloc_streambuf( buf );
180 }
181}
182
183/**
184 * Checks whether the given stream has a base64::streambuf attached.
185 *
186 * @param ios The stream to check.
187 * @return \c true only if a base64::streambuf is attached.
188 */
189template<typename charT,typename Traits> inline
190bool is_attached( std::basic_ios<charT,Traits> &ios ) {
191 return !!ios.pword( internal::base64::get_streambuf_index() );
192}
193
194/**
195 * A %base64::auto_attach is a class that attaches a base64::streambuf to
196 * a stream and automatically detaches it when the %auto_attach object is
197 * destroyed.
198 * \code
199 * void f( ostream &os ) {
200 * base64::auto_attach<ostream> const raii( os, "ISO-8859-1" );
201 * // ...
202 * }
203 * \endcode
204 * A %base64::auto_attach is useful for streams not created by you.
205 *
206 * @see http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
207 */
208template<class StreamType>
209class auto_attach {
210public:
211 /**
212 * Constructs an %auto_attach object calling attach() on the given stream.
213 *
214 * @param stream The stream to attach the base64::streambuf to. If the
215 * stream already has a base64::streambuf attached to it, this contructor
216 * does nothing.
217 */
218 auto_attach( StreamType &stream ) : stream_( stream ) {
219 attach( stream );
220 }
221
222 /**
223 * Destroys this %auto_attach object calling detach() on the previously
224 * attached stream.
225 */
226 ~auto_attach() {
227 detach( stream_ );
228 }
229
230private:
231 StreamType &stream_;
232};
233
234///////////////////////////////////////////////////////////////////////////////
235
236/**
237 * A %base64::stream is used to wrap a C++ standard I/O stream with a
238 * base64::streambuf so that encoding/decoding and the management of the
239 * streambuf happens automatically.
240 *
241 * A %base64::stream is useful for streams created by you.
242 *
243 * @tparam StreamType The I/O stream class type to wrap. It must be a concrete
244 * stream class.
245 */
246template<class StreamType>
247class stream : public StreamType {
248public:
249 /**
250 * Constructs a %base64::stream.
251 */
252 stream() :
253#ifdef WIN32
254# pragma warning( push )
255# pragma warning( disable : 4355 )
256#endif /* WIN32 */
257 b64buf_( this->rdbuf() )
258#ifdef WIN32
259# pragma warning( pop )
260#endif /* WIN32 */
261 {
262 init();
263 }
264
265 /**
266 * Constructs a %stream.
267 *
268 * @tparam StreamArgType The type of the first argument of \a StreamType's
269 * constructor.
270 * @param stream_arg The argument to pass as the first argument to
271 * \a StreamType's constructor.
272 */
273 template<typename StreamArgType>
274 stream( StreamArgType stream_arg ) :
275 StreamType( stream_arg ),
276#ifdef WIN32
277# pragma warning( push )
278# pragma warning( disable : 4355 )
279#endif /* WIN32 */
280 b64buf_( this->rdbuf() )
281#ifdef WIN32
282# pragma warning( pop )
283#endif /* WIN32 */
284 {
285 init();
286 }
287
288 /**
289 * Constructs a %base64::stream.
290 *
291 * @tparam StreamArgType The type of the first argument of \a StreamType's
292 * constructor.
293 * @param stream_arg The argument to pass as the first argument to
294 * \a StreamType's constructor.
295 * @param mode The open-mode to pass to \a StreamType's constructor.
296 */
297 template<typename StreamArgType>
298 stream( StreamArgType stream_arg, std::ios_base::openmode mode ) :
299 StreamType( stream_arg, mode ),
300#ifdef WIN32
301# pragma warning( push )
302# pragma warning( disable : 4355 )
303#endif /* WIN32 */
304 b64buf_( this->rdbuf() )
305#ifdef WIN32
306# pragma warning( pop )
307#endif /* WIN32 */
308 {
309 init();
310 }
311
312private:
313 streambuf b64buf_;
314
315 void init() {
316 this->std::ios::rdbuf( &b64buf_ );
317 }
318};
319
320///////////////////////////////////////////////////////////////////////////////
321
322} // namespace base64
323} // namespace zorba
324#endif /* ZORBA_BASE64_STREAM_API_H */
325/* vim:set et sw=2 ts=2: */
0326
=== 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:34:26 +0000
@@ -42,7 +42,7 @@
42///////////////////////////////////////////////////////////////////////////////42///////////////////////////////////////////////////////////////////////////////
4343
44/**44/**
45 * A %location hold the file location of an error.45 * A %location holds the file location of an error.
46 */46 */
47class ZORBA_DLL_PUBLIC location {47class ZORBA_DLL_PUBLIC location {
48public:48public:
@@ -71,21 +71,17 @@
71 * Constructs a %location.71 * Constructs a %location.
72 *72 *
73 * @param file The name of the file where the error occurred.73 * @param file The name of the file where the error occurred.
74 * @param line The line number of the file where the expression that74 * @param line The line number of the file where the expression that raises
75 * raises the error begins.75 * the error begins.
76 * @param column The column number, if any, of the file where the expression76 * @param column The column number, if any, of the file where the expression
77 * that raises the error begins.77 * that raises the error begins.
78 * @param line_end The end line number, if any, of the file where the expression78 * @param line_end The end line number, if any, of the file where the
79 * causing the error ends.79 * expression causing the error ends.
80 * @param column_end The end column number, if any, of the file where 80 * @param column_end The end column number, if any, of the file where the
81 * the xpression causing the error ends.81 * xpression causing the error ends.
82 */82 */
83 location(83 location( char const *file, line_type line, column_type column = 0,
84 char const *file,84 line_type line_end = 0, column_type column_end = 0 ) :
85 line_type line,
86 column_type column = 0,
87 line_type line_end = 0,
88 column_type column_end = 0) :
89 file_( file ), line_( line ), column_( column ),85 file_( file ), line_( line ), column_( column ),
90 line_end_( line_end ), column_end_( column_end )86 line_end_( line_end ), column_end_( column_end )
91 {87 {
@@ -97,19 +93,16 @@
97 * @tparam StringType The string type for \a file.93 * @tparam StringType The string type for \a file.
98 * @param file The name of the file where the error occurred.94 * @param file The name of the file where the error occurred.
99 * @param line The line number of the file where the error occurred.95 * @param line The line number of the file where the error occurred.
100 * @param column The column number, if any, of the file where the error occurred.96 * @param column The column number, if any, of the file where the error
101 * @param line_end The end line number, if any, of the file where the expression97 * occurred.
102 * causing the error ends.98 * @param line_end The end line number, if any, of the file where the
103 * @param column_end The end column number, if any, of the file where 99 * expression causing the error ends.
104 * the xpression causing the error ends.100 * @param column_end The end column number, if any, of the file where the
101 * xpression causing the error ends.
105 */102 */
106 template<class StringType>103 template<class StringType>
107 location(104 location( StringType const &file, line_type line, column_type column = 0,
108 StringType const &file,105 line_type line_end = 0, column_type column_end = 0 ) :
109 line_type line,
110 column_type column = 0,
111 line_type line_end = 0,
112 column_type column_end = 0) :
113 file_( file.c_str() ), line_( line ), column_( column ),106 file_( file.c_str() ), line_( line ), column_( column ),
114 line_end_( line_end ), column_end_( column_end )107 line_end_( line_end ), column_end_( column_end )
115 {108 {
@@ -189,12 +182,8 @@
189 * @param column_end The column number, if any, where the error ends.182 * @param column_end The column number, if any, where the error ends.
190 * occurred.183 * occurred.
191 */184 */
192 void set(185 void set( char const *file, line_type line, column_type column = 0,
193 char const *file,186 line_type line_end = 0, column_type column_end = 0 ) {
194 line_type line,
195 column_type column = 0,
196 line_type line_end = 0,
197 column_type column_end = 0) {
198 file_ = file;187 file_ = file;
199 line_ = line;188 line_ = line;
200 column_ = column;189 column_ = column;
201190
=== 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:34:26 +0000
@@ -0,0 +1,40 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ZORBA_INTERNAL_STREAMBUF_H
18#define ZORBA_INTERNAL_STREAMBUF_H
19
20#include <streambuf>
21
22#include <zorba/config.h>
23
24namespace zorba {
25namespace internal {
26
27///////////////////////////////////////////////////////////////////////////////
28
29ZORBA_DLL_PUBLIC
30void dealloc_streambuf( std::streambuf* );
31
32ZORBA_DLL_PUBLIC
33void stream_callback( std::ios_base::event, std::ios_base&, int index );
34
35///////////////////////////////////////////////////////////////////////////////
36
37} // namespace internal
38} // namespace zorba
39#endif /* ZORBA_INTERNAL_STREAMBUF_H */
40/* vim:set et sw=2 ts=2: */
041
=== 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:34:26 +0000
@@ -19,10 +19,10 @@
1919
20#include <stdexcept>20#include <stdexcept>
21#include <streambuf>21#include <streambuf>
22#include <string>
2322
24#include <zorba/config.h>23#include <zorba/config.h>
25#include <zorba/internal/proxy.h>24#include <zorba/internal/proxy.h>
25#include <zorba/internal/streambuf.h>
26#include <zorba/internal/unique_ptr.h>26#include <zorba/internal/unique_ptr.h>
2727
28namespace zorba {28namespace zorba {
@@ -120,20 +120,15 @@
120} // namespace transcode120} // namespace transcode
121121
122namespace internal {122namespace internal {
123123namespace transcode {
124ZORBA_DLL_PUBLIC124
125zorba::transcode::streambuf*125ZORBA_DLL_PUBLIC
126alloc_streambuf( char const *charset, std::streambuf *orig );126std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig );
127
128ZORBA_DLL_PUBLIC
129void dealloc_streambuf( zorba::transcode::streambuf* );
130127
131ZORBA_DLL_PUBLIC128ZORBA_DLL_PUBLIC
132int get_streambuf_index();129int get_streambuf_index();
133130
134ZORBA_DLL_PUBLIC131} // transcode
135void stream_callback( std::ios_base::event, std::ios_base&, int index );
136
137} // namespace internal132} // namespace internal
138133
139namespace transcode {134namespace transcode {
@@ -153,10 +148,11 @@
153 */148 */
154template<typename charT,typename Traits> inline149template<typename charT,typename Traits> inline
155void attach( std::basic_ios<charT,Traits> &ios, char const *charset ) {150void attach( std::basic_ios<charT,Traits> &ios, char const *charset ) {
156 int const index = internal::get_streambuf_index();151 int const index = internal::transcode::get_streambuf_index();
157 void *&pword = ios.pword( index );152 void *&pword = ios.pword( index );
158 if ( !pword ) {153 if ( !pword ) {
159 streambuf *const buf = internal::alloc_streambuf( charset, ios.rdbuf() );154 std::streambuf *const buf =
155 internal::transcode::alloc_streambuf( charset, ios.rdbuf() );
160 ios.rdbuf( buf );156 ios.rdbuf( buf );
161 pword = buf;157 pword = buf;
162 ios.register_callback( internal::stream_callback, index );158 ios.register_callback( internal::stream_callback, index );
@@ -173,7 +169,7 @@
173 */169 */
174template<typename charT,typename Traits> inline170template<typename charT,typename Traits> inline
175void detach( std::basic_ios<charT,Traits> &ios ) {171void detach( std::basic_ios<charT,Traits> &ios ) {
176 int const index = internal::get_streambuf_index();172 int const index = internal::transcode::get_streambuf_index();
177 if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {173 if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {
178 ios.pword( index ) = 0;174 ios.pword( index ) = 0;
179 ios.rdbuf( buf->orig_streambuf() );175 ios.rdbuf( buf->orig_streambuf() );
@@ -189,7 +185,7 @@
189 */185 */
190template<typename charT,typename Traits> inline186template<typename charT,typename Traits> inline
191bool is_attached( std::basic_ios<charT,Traits> &ios ) {187bool is_attached( std::basic_ios<charT,Traits> &ios ) {
192 return !!ios.pword( internal::get_streambuf_index() );188 return !!ios.pword( internal::transcode::get_streambuf_index() );
193}189}
194190
195/**191/**
196192
=== 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:34:26 +0000
@@ -49,6 +49,7 @@
49 fileimpl.cpp49 fileimpl.cpp
50 serializerimpl.cpp50 serializerimpl.cpp
51 base64impl.cpp51 base64impl.cpp
52 base64_streambuf.cpp
52 uriimpl.cpp53 uriimpl.cpp
53 uriresolverimpl.cpp54 uriresolverimpl.cpp
54 uri_resolver_wrappers.cpp55 uri_resolver_wrappers.cpp
@@ -56,6 +57,7 @@
56 zorba_functions.cpp57 zorba_functions.cpp
57 annotationimpl.cpp58 annotationimpl.cpp
58 auditimpl.cpp59 auditimpl.cpp
60 streambuf.cpp
59 transcode_streambuf.cpp61 transcode_streambuf.cpp
60 )62 )
6163
6264
=== 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:34:26 +0000
@@ -0,0 +1,249 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stdafx.h"
18
19#include <stdexcept>
20
21//#define ZORBA_DEBUG_BASE64_STREAMBUF
22#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
23# include <stdio.h>
24#endif
25
26#include <zorba/base64_stream.h>
27
28#include "util/base64_util.h"
29
30using namespace std;
31
32namespace zorba {
33namespace base64 {
34
35int const Large_External_Buf_Size = 4096; // must be a multiple of 4
36
37///////////////////////////////////////////////////////////////////////////////
38
39inline void streambuf::resetg() {
40 setg( gbuf_, gbuf_ + sizeof gbuf_, gbuf_ + sizeof gbuf_ );
41}
42
43inline void streambuf::resetp() {
44 plen_ = 0;
45}
46
47inline void streambuf::writep() {
48 char chunk[4];
49 orig_buf_->sputn( chunk, base64::encode( pbuf_, plen_, chunk ) );
50}
51
52streambuf::streambuf( std::streambuf *orig ) : orig_buf_( orig ) {
53 if ( !orig )
54 throw invalid_argument( "null streambuf" );
55 clear();
56}
57
58streambuf::~streambuf() {
59 if ( plen_ )
60 writep();
61}
62
63void streambuf::clear() {
64 resetg();
65 resetp();
66}
67
68void streambuf::imbue( std::locale const &loc ) {
69 orig_buf_->pubimbue( loc );
70}
71
72streambuf::pos_type streambuf::seekoff( off_type o, ios_base::seekdir d,
73 ios_base::openmode m ) {
74 clear();
75 return orig_buf_->pubseekoff( o, d, m );
76}
77
78streambuf::pos_type streambuf::seekpos( pos_type p, ios_base::openmode m ) {
79 clear();
80 return orig_buf_->pubseekpos( p, m );
81}
82
83std::streambuf* streambuf::setbuf( char_type *p, streamsize s ) {
84 orig_buf_->pubsetbuf( p, s );
85 return this;
86}
87
88streamsize streambuf::showmanyc() {
89 return orig_buf_->in_avail();
90}
91
92int streambuf::sync() {
93 if ( plen_ )
94 writep();
95 return orig_buf_->pubsync();
96}
97
98streambuf::int_type streambuf::overflow( int_type c ) {
99#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
100 printf( "overflow()\n" );
101#endif
102 bool const is_eof = traits_type::eq_int_type( c, traits_type::eof() );
103 if ( !is_eof )
104 pbuf_[ plen_++ ] = traits_type::to_char_type( c );
105 if ( plen_ == sizeof pbuf_ || (is_eof && plen_) ) {
106 writep();
107 resetp();
108 }
109 return c;
110}
111
112streambuf::int_type streambuf::pbackfail( int_type c ) {
113 if ( gptr() > eback() )
114 gbump( -1 );
115 return orig_buf_->sputbackc( traits_type::to_char_type( c ) );
116}
117
118streambuf::int_type streambuf::underflow() {
119#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
120 printf( "underflow()\n" );
121#endif
122 char chunk[4];
123 int chunk_len = 0;
124
125 while ( gptr() >= egptr() ) {
126 int_type const c = orig_buf_->sbumpc();
127 bool is_eof = false;
128 if ( traits_type::eq_int_type( c, traits_type::eof() ) ) {
129 if ( !chunk_len )
130 return traits_type::eof();
131 is_eof = true;
132 } else {
133 chunk[ chunk_len++ ] = traits_type::to_char_type( c );
134 }
135 if ( chunk_len == sizeof chunk || (is_eof && chunk_len) ) {
136 streamsize const n = base64::decode( chunk, chunk_len, eback() );
137 setg( gbuf_, gbuf_, gbuf_ + n );
138 }
139 }
140 return traits_type::to_int_type( *gptr() );
141}
142
143streamsize streambuf::xsgetn( char_type *to, streamsize size ) {
144#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
145 printf( "xsgetn()\n" );
146#endif
147 streamsize return_size = 0;
148
149 if ( streamsize const gsize = egptr() - gptr() ) {
150 //
151 // Get any chunk fragment pending the the get buffer first.
152 //
153 streamsize const n = min( gsize, size );
154 traits_type::copy( to, gptr(), n );
155 gbump( n );
156 to += n;
157 size -= n, return_size += n;
158 }
159
160 //
161 // Must get bytes in terms of encoded size.
162 //
163 size = base64::encoded_size( size );
164
165 while ( size ) {
166 char ebuf[ Large_External_Buf_Size ];
167 streamsize const get = min( (streamsize)(sizeof ebuf), size );
168 if ( streamsize got = orig_buf_->sgetn( ebuf, get ) ) {
169 streamsize const decoded = base64::decode( ebuf, got, to );
170 to += decoded;
171 size -= got, return_size += decoded;
172 } else
173 break;
174 }
175
176 return return_size;
177}
178
179streamsize streambuf::xsputn( char_type const *from, streamsize size ) {
180#ifdef ZORBA_DEBUG_BASE64_STREAMBUF
181 printf( "xsputn()\n" );
182#endif
183 streamsize return_size = 0;
184
185 //
186 // Put any chunk fragment pending in the put buffer by completing it first.
187 //
188 while ( plen_ && size ) {
189 overflow( *from );
190 ++from, --size, ++return_size;
191 }
192
193 while ( size >= 3 ) {
194 char ebuf[ Large_External_Buf_Size ];
195 streamsize const put = min( (streamsize)(sizeof ebuf), size );
196 streamsize const encoded = base64::encode( from, put, ebuf );
197 orig_buf_->sputn( ebuf, encoded );
198 from += put, size -= put, return_size += put;
199 }
200
201 //
202 // Put any remaining chunk fragment into the put buffer.
203 //
204 if ( size ) {
205 traits_type::copy( pbuf_, from, size );
206 plen_ = size;
207 }
208
209 return return_size;
210}
211
212///////////////////////////////////////////////////////////////////////////////
213
214} // namespace base64
215
216namespace internal {
217namespace base64 {
218
219// Both new & delete are done inside Zorba rather than in the header to
220// guarantee that they're cross-DLL-boundary safe on Windows.
221
222std::streambuf* alloc_streambuf( std::streambuf *orig ) {
223 return new zorba::base64::streambuf( orig );
224}
225
226int get_streambuf_index() {
227 //
228 // This function is out-of-line because it has a static constant within it.
229 // It has a static constant within it to guarantee (1) initialization before
230 // use and (2) initialization happens exactly once.
231 //
232 // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and
233 // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section
234 // 3.3.1.1: "Initializing and Maintaining the iword/pword Index."
235 //
236 // See: "The C++ Programming Language," Bjarne Stroustrup, Addison-Wesley,
237 // 2000, section 10.4.8: "Local Static Store."
238 //
239 static int const index = ios_base::xalloc();
240 return index;
241}
242
243} // namespace base64
244} // namespace internal
245
246///////////////////////////////////////////////////////////////////////////////
247
248} // namespace zorba
249/* vim:set et sw=2 ts=2: */
0250
=== 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:34:26 +0000
@@ -17,45 +17,70 @@
1717
18#include <sstream> 18#include <sstream>
19#include <zorba/base64.h>19#include <zorba/base64.h>
20#include <zorba/diagnostic_list.h>
2021
21#include <zorba/config.h>22#include <zorba/config.h>
22#include <zorba/zorba_string.h>23#include <zorba/zorba_string.h>
2324
24#include "zorbatypes/binary.h"25#include "diagnostics/dict.h"
26#include "diagnostics/xquery_exception.h"
27#include "util/base64_util.h"
2528
29#define CATCH_BASE64_EXCEPTION() \
30 catch ( base64::exception const &e ) { \
31 throw XQUERY_EXCEPTION( \
32 err::FORG0001, ERROR_PARAMS( e.invalid_char(), ZED( Base64BadChar ) ) \
33 ); \
34 } \
35 catch ( std::invalid_argument const& ) { \
36 throw XQUERY_EXCEPTION( \
37 err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) ) \
38 ); \
39 }
2640
27namespace zorba {41namespace zorba {
28namespace encoding {42namespace encoding {
2943
30String Base64::encode(const String& aString) 44String Base64::encode(const String& aString)
31{45{
32 std::stringstream lStream;46 String result;
33 lStream << aString;47 base64::encode( aString.data(), aString.size(), &result );
3448 return result;
35 return encode(lStream);
36}49}
3750
3851
39String Base64::encode(std::istream& aStream) 52String Base64::encode(std::istream& aStream)
40{53{
41 return zorba::Base64::encode(aStream).str();54 String result;
55 base64::encode( aStream, &result );
56 return result;
42}57}
4358
4459
45String Base64::decode(const String& aString)60String Base64::decode(const String& aString)
46{61{
47 std::stringstream lStream;62 try {
48 lStream << aString;63 String result;
49 return decode(lStream);64 base64::decode(
65 aString.data(), aString.size(), &result, base64::dopt_ignore_ws
66 );
67 return result;
68 }
69 CATCH_BASE64_EXCEPTION()
50}70}
5171
5272
53String Base64::decode(std::istream& aStream)73String Base64::decode(std::istream& aStream)
54{74{
55 return zorba::Base64::decode(aStream).str();75 try {
76 String result;
77 base64::decode( aStream, &result, base64::dopt_ignore_ws );
78 return result;
79 }
80 CATCH_BASE64_EXCEPTION()
56}81}
5782
5883
59} /* end namespace encoding */84} // namespace encoding
60} /* end namespace zorba */85} // namespace zorba
61/* vim:set et sw=2 ts=2: */86/* vim:set et sw=2 ts=2: */
6287
=== 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:34:26 +0000
@@ -2300,7 +2300,9 @@
2300 std::istream& stream = item->getStream();2300 std::istream& stream = item->getStream();
2301 if (item->isEncoded())2301 if (item->isEncoded())
2302 {2302 {
2303 tr << Base64::decode(stream);2303 zstring decoded;
2304 Base64::decode(stream, &decoded);
2305 tr << decoded;
2304 }2306 }
2305 else2307 else
2306 {2308 {
@@ -2322,9 +2324,9 @@
23222324
2323 if (item->isEncoded())2325 if (item->isEncoded())
2324 {2326 {
2325 std::stringstream tmp;2327 zstring decoded;
2326 tmp.write(value, len);2328 Base64::decode(value, len, &decoded);
2327 tr << Base64::decode(tmp);2329 tr << decoded;
2328 }2330 }
2329 else2331 else
2330 {2332 {
23312333
=== 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:34:26 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stdafx.h"
18#include <zorba/internal/streambuf.h>
19
20using namespace std;
21
22namespace zorba {
23namespace internal {
24
25///////////////////////////////////////////////////////////////////////////////
26
27// "delete" is done here inside Zorba rather than in the header to guarantee
28// that it's cross-DLL-boundary safe on Windows.
29
30void dealloc_streambuf( streambuf *buf ) {
31 delete buf;
32}
33
34void stream_callback( ios_base::event e, ios_base &ios, int index ) {
35 //
36 // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and
37 // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section
38 // 3.3.1.4: "Using Stream Callbacks for Memory Management."
39 //
40 if ( e == ios_base::erase_event )
41 delete static_cast<streambuf*>( ios.pword( index ) );
42}
43
44///////////////////////////////////////////////////////////////////////////////
45
46} // namespace internal
47} // namespace zorba
48/* vim:set et sw=2 ts=2: */
049
=== 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:34:26 +0000
@@ -81,8 +81,7 @@
81 return proxy_buf_->sgetn( to, size );81 return proxy_buf_->sgetn( to, size );
82}82}
8383
84streamsize streambuf::xsputn( char_type const *from,84streamsize streambuf::xsputn( char_type const *from, streamsize size ) {
85 streamsize size ) {
86 return proxy_buf_->sputn( from, size );85 return proxy_buf_->sputn( from, size );
87}86}
8887
@@ -103,19 +102,15 @@
103///////////////////////////////////////////////////////////////////////////////102///////////////////////////////////////////////////////////////////////////////
104103
105namespace internal {104namespace internal {
105namespace transcode {
106106
107// Both new & delete are done here inside Zorba rather than in the header to107// Both new & delete are done here inside Zorba rather than in the header to
108// guarantee that they're cross-DLL-boundary safe on Windows.108// guarantee that they're cross-DLL-boundary safe on Windows.
109109
110zorba::transcode::streambuf*110std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig ) {
111alloc_streambuf( char const *charset, std::streambuf *orig ) {
112 return new zorba::transcode::streambuf( charset, orig );111 return new zorba::transcode::streambuf( charset, orig );
113}112}
114113
115void dealloc_streambuf( zorba::transcode::streambuf *buf ) {
116 delete buf;
117}
118
119int get_streambuf_index() {114int get_streambuf_index() {
120 //115 //
121 // This function is out-of-line because it has a static constant within it.116 // This function is out-of-line because it has a static constant within it.
@@ -133,16 +128,7 @@
133 return index;128 return index;
134}129}
135130
136void stream_callback( ios_base::event e, ios_base &ios, int index ) {131} // namespace transcode
137 //
138 // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and
139 // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section
140 // 3.3.1.4: "Using Stream Callbacks for Memory Management."
141 //
142 if ( e == ios_base::erase_event )
143 delete static_cast<streambuf*>( ios.pword( index ) );
144}
145
146} // namespace internal132} // namespace internal
147133
148///////////////////////////////////////////////////////////////////////////////134///////////////////////////////////////////////////////////////////////////////
149135
=== 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:34:26 +0000
@@ -2888,14 +2888,6 @@
2888 <value>invalid Base64 character</value>2888 <value>invalid Base64 character</value>
2889 </entry>2889 </entry>
28902890
2891 <entry key="Base64Equals">
2892 <value>in Base64, '=' must be at the end and followed by one of [AEIMQUYcgkosw048]</value>
2893 </entry>
2894
2895 <entry key="Base64EqualsEquals">
2896 <value>in Base64, "==" must be at the end and followed by one of [AQgw]</value>
2897 </entry>
2898
2899 <entry key="Base64Multiple4">2891 <entry key="Base64Multiple4">
2900 <value>Base64 data must be a multiple of 4 characters</value>2892 <value>Base64 data must be a multiple of 4 characters</value>
2901 </entry>2893 </entry>
29022894
=== 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:34:26 +0000
@@ -546,8 +546,6 @@
546 { "~BadXMLNoOpeningTag", "closing tag without matching opening tag" },546 { "~BadXMLNoOpeningTag", "closing tag without matching opening tag" },
547 { "~BadXQueryVersion", "unsupported XQuery version" },547 { "~BadXQueryVersion", "unsupported XQuery version" },
548 { "~Base64BadChar", "invalid Base64 character" },548 { "~Base64BadChar", "invalid Base64 character" },
549 { "~Base64Equals", "in Base64, '=' must be at the end and followed by one of [AEIMQUYcgkosw048]" },
550 { "~Base64EqualsEquals", "in Base64, \"==\" must be at the end and followed by one of [AQgw]" },
551 { "~Base64Multiple4", "Base64 data must be a multiple of 4 characters" },549 { "~Base64Multiple4", "Base64 data must be a multiple of 4 characters" },
552 { "~BaseURI", "base URI" },550 { "~BaseURI", "base URI" },
553 { "~BoxCondTooManyColumns", "box condition has more columns than index" },551 { "~BoxCondTooManyColumns", "box condition has more columns than index" },
554552
=== 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:34:26 +0000
@@ -66,7 +66,7 @@
66 {66 {
67 if (lItem->isEncoded())67 if (lItem->isEncoded())
68 {68 {
69 lResultString = Base64::decode(lItem->getStream());69 Base64::decode(lItem->getStream(), &lResultString);
70 }70 }
71 else71 else
72 {72 {
@@ -93,10 +93,7 @@
9393
94 if (lItem->isEncoded())94 if (lItem->isEncoded())
95 {95 {
96 std::vector<char> encoded(lContent, lContent+lSize);96 Base64::decode( lContent, lSize, &lResultString );
97 std::vector<char> decoded;
98 Base64::decode(encoded, decoded);
99 lResultString.insert(0, &decoded[0], decoded.size());
100 }97 }
101 else98 else
102 {99 {
@@ -156,8 +153,8 @@
156 // create a base64Binary item153 // create a base64Binary item
157 // the content is the non-encoded string154 // the content is the non-encoded string
158 GENV_ITEMFACTORY->createBase64Binary(155 GENV_ITEMFACTORY->createBase64Binary(
159 result, lTmpString.c_str(), lTmpString.size(), false156 result, lTmpString.c_str(), lTmpString.size(), false
160 );157 );
161 STACK_PUSH (true, state);158 STACK_PUSH (true, state);
162 }159 }
163 STACK_END (state);160 STACK_END (state);
164161
=== 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:34:26 +0000
@@ -13,6 +13,8 @@
13# limitations under the License.13# limitations under the License.
1414
15SET(UNIT_TEST_SRCS15SET(UNIT_TEST_SRCS
16 test_base64.cpp
17 test_base64_streambuf.cpp
16 string_instantiate.cpp18 string_instantiate.cpp
17 string.cpp19 string.cpp
18 test_uri.cpp20 test_uri.cpp
1921
=== 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:34:26 +0000
@@ -0,0 +1,286 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stdafx.h"
18#include <cstring>
19#include <iostream>
20#include <sstream>
21#include <stdexcept>
22#include <string>
23
24#include "util/base64_util.h"
25
26using namespace std;
27using namespace zorba;
28
29struct test {
30 char const *input;
31 char const *expected;
32};
33
34///////////////////////////////////////////////////////////////////////////////
35
36static int failures;
37
38static bool assert_true( int no, char const *expr, int line, bool result ) {
39 if ( !result ) {
40 cout << '#' << no << " FAILED, line " << line << ": " << expr << endl;
41 ++failures;
42 }
43 return result;
44}
45
46static void print_exception( int no, char const *expr, int line,
47 std::exception const &e ) {
48 assert_true( no, expr, line, false );
49 cout << "+ exception: " << e.what() << endl;
50}
51
52#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) )
53
54#define ASSERT_NO_EXCEPTION( NO, EXPR ) \
55 try { EXPR; } \
56 catch ( std::exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); } \
57 catch ( ... ) { assert_true( NO, #EXPR, __LINE__, false ); }
58
59#define ASSERT_EXCEPTION( NO, EXPR, EXCEPTION ) \
60 try { EXPR; assert_true( NO, #EXPR, __LINE__, false ); } \
61 catch ( EXCEPTION const& ) { }
62
63///////////////////////////////////////////////////////////////////////////////}
64
65static void test_decode_buf_to_buf( int no, string const &in,
66 string const &expected ) {
67 base64::size_type n;
68 char out[ 1024 ];
69 ASSERT_NO_EXCEPTION(
70 no, n = base64::decode( in.data(), in.size(), out, base64::dopt_any_len )
71 );
72 ASSERT_TRUE( no, n == expected.size() );
73 out[ n ] = '\0';
74 ASSERT_TRUE( no, out == expected );
75}
76
77static void test_decode_buf_to_string( int no, string const &in,
78 string const &expected ) {
79 base64::size_type n;
80 string out;
81 ASSERT_NO_EXCEPTION(
82 no,
83 n = base64::decode( in.data(), in.size(), &out, base64::dopt_any_len )
84 );
85 ASSERT_TRUE( no, n == expected.size() );
86 ASSERT_TRUE( no, out.size() == expected.size() );
87 ASSERT_TRUE( no, out == expected );
88}
89
90static void test_decode_buf_to_vector( int no, string const &in,
91 string const &expected ) {
92 base64::size_type n;
93 vector<char> out;
94 ASSERT_NO_EXCEPTION(
95 no,
96 n = base64::decode( in.data(), in.size(), &out, base64::dopt_any_len )
97 );
98 ASSERT_TRUE( no, n == expected.size() );
99 ASSERT_TRUE( no, out.size() == expected.size() );
100 ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
101}
102
103static void test_decode_stream_to_stream( int no, string const &in,
104 string const &expected ) {
105 base64::size_type n;
106 istringstream sin( in );
107 ostringstream sout;
108 ASSERT_NO_EXCEPTION(
109 no, n = base64::decode( sin, sout, base64::dopt_any_len )
110 );
111 ASSERT_TRUE( no, n == expected.size() );
112 ASSERT_TRUE( no, sout.str().size() == expected.size() );
113 ASSERT_TRUE( no, sout.str() == expected );
114}
115
116static void test_decode_stream_to_string( int no, string const &in,
117 string const &expected ) {
118 base64::size_type n;
119 istringstream sin( in );
120 string out;
121 ASSERT_NO_EXCEPTION(
122 no, n = base64::decode( sin, &out, base64::dopt_any_len )
123 );
124 ASSERT_TRUE( no, n == expected.size() );
125 ASSERT_TRUE( no, out.size() == expected.size() );
126 ASSERT_TRUE( no, out == expected );
127}
128
129static void test_decode_stream_to_vector( int no, string const &in,
130 string const &expected ) {
131 base64::size_type n;
132 istringstream sin( in );
133 vector<char> out;
134 ASSERT_NO_EXCEPTION(
135 no, n = base64::decode( sin, &out, base64::dopt_any_len )
136 );
137 ASSERT_TRUE( no, n == expected.size() );
138 ASSERT_TRUE( no, out.size() == expected.size() );
139 ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
140}
141
142static void test_decode_exception( int no, string const &in ) {
143 char out[ 1024 ];
144 ASSERT_EXCEPTION(
145 no, base64::decode( in.data(), in.size(), out ), invalid_argument
146 );
147}
148
149///////////////////////////////////////////////////////////////////////////////
150
151static void test_encode_buf_to_buf( int no, string const &in,
152 string const &expected ) {
153 char out[ 1024 ];
154 base64::size_type const n = base64::encode( in.data(), in.size(), out );
155 ASSERT_TRUE( no, n == expected.size() );
156 out[ n ] = '\0';
157 ASSERT_TRUE( no, out == expected );
158}
159
160static void test_encode_buf_to_string( int no, string const &in,
161 string const &expected ) {
162 base64::size_type n;
163 string out;
164 ASSERT_NO_EXCEPTION( no, n = base64::encode( in.data(), in.size(), &out ) );
165 ASSERT_TRUE( no, n == expected.size() );
166 ASSERT_TRUE( no, out.size() == expected.size() );
167 ASSERT_TRUE( no, out == expected );
168}
169
170static void test_encode_buf_to_vector( int no, string const &in,
171 string const &expected ) {
172 base64::size_type n;
173 vector<char> out;
174 ASSERT_NO_EXCEPTION( no, n = base64::encode( in.data(), in.size(), &out ) );
175 ASSERT_TRUE( no, n == expected.size() );
176 ASSERT_TRUE( no, out.size() == expected.size() );
177 ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
178}
179
180static void test_encode_stream_to_stream( int no, string const &in,
181 string const &expected ) {
182 base64::size_type n;
183 istringstream sin( in );
184 ostringstream sout;
185 ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, sout ) );
186 ASSERT_TRUE( no, n == expected.size() );
187 ASSERT_TRUE( no, sout.str().size() == expected.size() );
188 ASSERT_TRUE( no, sout.str() == expected );
189}
190
191static void test_encode_stream_to_string( int no, string const &in,
192 string const &expected ) {
193 base64::size_type n;
194 istringstream sin( in );
195 string out;
196 ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, &out ) );
197 ASSERT_TRUE( no, n == expected.size() );
198 ASSERT_TRUE( no, out.size() == expected.size() );
199 ASSERT_TRUE( no, out == expected );
200}
201
202static void test_encode_stream_to_vector( int no, string const &in,
203 string const &expected ) {
204 base64::size_type n;
205 istringstream sin( in );
206 vector<char> out;
207 ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, &out ) );
208 ASSERT_TRUE( no, n == expected.size() );
209 ASSERT_TRUE( no, out.size() == expected.size() );
210 ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) );
211}
212
213///////////////////////////////////////////////////////////////////////////////
214
215static test const encode_tests[] = {
216 /* 0 */ { "Now is the time", "Tm93IGlzIHRoZSB0aW1l" },
217 /* 1 */ { "Now is the time.", "Tm93IGlzIHRoZSB0aW1lLg==" },
218 /* 2 */ { "Now is the time..", "Tm93IGlzIHRoZSB0aW1lLi4=" },
219
220 { 0, 0 }
221};
222
223static test const decode_tests[] = {
224 /* 3 */ { "Tm93IGlzIHRoZSB0aW1l", "Now is the time" },
225 /* 4 */ { "Tm93IGlzIHRoZSB0aW1lLg==", "Now is the time." },
226 /* 5 */ { "Tm93IGlzIHRoZSB0aW1lLi4=", "Now is the time.." },
227
228 // incomplete Base64 encodings
229 /* 6 */ { "Tm93IGlzIHRoZSB0aW1", "Now is the tim" },
230 /* 7 */ { "Tm93IGlzIHRoZSB0aW", "Now is the ti" },
231 /* 8 */ { "Tm93IGlzIHRoZSB0a", "Now is the t" },
232
233 { 0, 0 }
234};
235
236static char const *const decode_exception_tests[] = {
237 "=",
238 "_m93",
239 "T_93",
240 "Tm_3",
241 "Tm9_",
242 "=m93",
243 "T=93",
244 "Tm=3",
245 "Tm93=",
246 "ZmX=",
247 "ZX==",
248 "ZX===",
249 0
250};
251
252namespace zorba {
253namespace UnitTests {
254
255int test_base64( int, char*[] ) {
256 int test_no = 0;
257
258 for ( test const *t = encode_tests; t->input; ++t, ++test_no ) {
259 test_encode_buf_to_buf( test_no, t->input, t->expected );
260 test_encode_buf_to_string( test_no, t->input, t->expected );
261 test_encode_buf_to_vector( test_no, t->input, t->expected );
262 test_encode_stream_to_stream( test_no, t->input, t->expected );
263 test_encode_stream_to_string( test_no, t->input, t->expected );
264 test_encode_stream_to_vector( test_no, t->input, t->expected );
265 }
266
267 for ( test const *t = decode_tests; t->input; ++t, ++test_no ) {
268 test_decode_buf_to_buf( test_no, t->input, t->expected );
269 test_decode_buf_to_string( test_no, t->input, t->expected );
270 test_decode_buf_to_vector( test_no, t->input, t->expected );
271 test_decode_stream_to_stream( test_no, t->input, t->expected );
272 test_decode_stream_to_string( test_no, t->input, t->expected );
273 test_decode_stream_to_vector( test_no, t->input, t->expected );
274 }
275
276 for ( char const *const *t = decode_exception_tests; *t; ++t, ++test_no )
277 test_decode_exception( test_no, *t );
278
279 cout << failures << " test(s) failed\n";
280 return failures ? 1 : 0;
281}
282
283} // namespace UnitTests
284} // namespace zorba
285
286/* vim:set et sw=2 ts=2: */
0287
=== 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:34:26 +0000
@@ -0,0 +1,141 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stdafx.h"
18#include <fstream>
19#include <iostream>
20#include <sstream>
21
22#include <zorba/base64_stream.h>
23
24using namespace std;
25using namespace zorba;
26
27struct test {
28 char const *raw_str;
29 char const *b64_str;
30};
31
32///////////////////////////////////////////////////////////////////////////////
33
34static int failures;
35
36static bool assert_true( int no, char const *expr, int line, bool result ) {
37 if ( !result ) {
38 cout << '#' << no << " FAILED, line " << line << ": " << expr << endl;
39 ++failures;
40 }
41 return result;
42}
43
44static void print_exception( int no, char const *expr, int line,
45 std::exception const &e ) {
46 assert_true( no, expr, line, false );
47 cout << "+ exception: " << e.what() << endl;
48}
49
50#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) )
51
52#define ASSERT_TRUE_AND_NO_EXCEPTION( NO, EXPR ) \
53 try { ASSERT_TRUE( NO, EXPR ); } \
54 catch ( std::exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); }
55
56///////////////////////////////////////////////////////////////////////////////
57
58static bool test_getline( test const *t ) {
59 string const b64_str( t->b64_str );
60 istringstream iss( b64_str );
61 base64::streambuf b64_sbuf( iss.rdbuf() );
62 iss.ios::rdbuf( &b64_sbuf );
63
64 char raw_buf[ 1024 ];
65 iss.getline( raw_buf, sizeof raw_buf );
66 if ( iss.gcount() ) {
67 string const raw_str( raw_buf );
68 return raw_str == t->raw_str;
69 }
70 return false;
71}
72
73static bool test_read( test const *t ) {
74 string const b64_str( t->b64_str );
75 istringstream iss( b64_str );
76 base64::streambuf b64_sbuf( iss.rdbuf() );
77 iss.ios::rdbuf( &b64_sbuf );
78
79 char raw_buf[ 1024 ];
80 iss.read( raw_buf, sizeof raw_buf );
81 if ( iss.gcount() ) {
82 string const raw_str( raw_buf, iss.gcount() );
83 return raw_str == t->raw_str;
84 }
85 return false;
86}
87
88static bool test_insertion( test const *t ) {
89 ostringstream oss;
90 base64::streambuf b64_sbuf( oss.rdbuf() );
91 oss.ios::rdbuf( &b64_sbuf );
92
93 oss << t->raw_str << flush;
94 string const b64_str( oss.str() );
95
96 string const expected_b64_str( t->b64_str );
97 return b64_str == expected_b64_str;
98}
99
100static bool test_put( test const *t ) {
101 ostringstream oss;
102 { // local scope
103 base64::auto_attach<ostringstream> const raii( oss );
104
105 for ( char const *c = t->raw_str; *c; ++c )
106 oss.put( *c );
107 } // local scope
108 string const b64_str( oss.str() );
109
110 string const expected_b64_str( t->b64_str );
111 return b64_str == expected_b64_str;
112}
113
114///////////////////////////////////////////////////////////////////////////////
115
116static test const tests[] = {
117 /* 0 */ { "Now ", "Tm93IA==" },
118 /* 1 */ { "Now is the time", "Tm93IGlzIHRoZSB0aW1l" },
119 /* 2 */ { "Now is the time.", "Tm93IGlzIHRoZSB0aW1lLg==" },
120 /* 3 */ { "Now is the time..", "Tm93IGlzIHRoZSB0aW1lLi4=" },
121 { 0, 0 }
122};
123
124namespace zorba {
125namespace UnitTests {
126
127int test_base64_streambuf( int, char*[] ) {
128 int test_no = 0;
129 for ( test const *t = tests; t->raw_str; ++t, ++test_no ) {
130 ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_getline( t ) );
131 ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_read( t ) );
132 ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_insertion( t ) );
133 ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_put( t ) );
134 }
135 cout << failures << " test(s) failed\n";
136 return failures ? 1 : 0;
137}
138
139} // namespace UnitTests
140} // namespace zorba
141/* vim:set et sw=2 ts=2: */
0142
=== 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:34:26 +0000
@@ -21,24 +21,21 @@
2121
22#include <zorba/config.h>22#include <zorba/config.h>
2323
24namespace zorba 24namespace zorba {
25{25namespace UnitTests {
2626
27namespace UnitTests
28{
29 int runUriTest(int argc, char* argv[]);27 int runUriTest(int argc, char* argv[]);
30 int runDebuggerProtocolTest(int argc, char* argv[]);28 int runDebuggerProtocolTest(int argc, char* argv[]);
29 int test_base64( int, char*[] );
30 int test_base64_streambuf( int, char*[] );
31 int test_fs_iterator( int, char*[] );
31 int test_string( int, char*[] );32 int test_string( int, char*[] );
32 int test_unique_ptr( int, char*[] );33 int test_unique_ptr( int, char*[] );
33 int test_fs_iterator( int, char*[] );
34#ifndef ZORBA_NO_FULL_TEXT34#ifndef ZORBA_NO_FULL_TEXT
35 int test_stemmer( int, char*[] );35 int test_stemmer( int, char*[] );
36 int test_thesaurus( int, char*[] );36 int test_thesaurus( int, char*[] );
37 int test_tokenizer( int, char*[] );37 int test_tokenizer( int, char*[] );
38#endif /* ZORBA_NO_FULL_TEXT */38#endif /* ZORBA_NO_FULL_TEXT */
39 /**
40 * ADD NEW UNIT TESTS HERE
41 */
42#ifndef ZORBA_NO_ICU39#ifndef ZORBA_NO_ICU
43 int test_icu_streambuf( int, char*[] );40 int test_icu_streambuf( int, char*[] );
44#endif /* ZORBA_NO_ICU */41#endif /* ZORBA_NO_ICU */
@@ -46,9 +43,7 @@
46 43
47 void initializeTestList();44 void initializeTestList();
4845
4946} // namespace UnitTests
50};47} // namespace zorba
51} /* namespace zorba */
52
53#endif /* ZORBA_UNIT_TEST_LIST_H */48#endif /* ZORBA_UNIT_TEST_LIST_H */
54/* vim:set et sw=2 ts=2: */49/* vim:set et sw=2 ts=2: */
5550
=== 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:34:26 +0000
@@ -28,9 +28,7 @@
28using namespace std;28using namespace std;
2929
30namespace zorba {30namespace zorba {
3131namespace UnitTests {
32namespace UnitTests
33{
3432
35map<string,libunittestfunc> libunittests;33map<string,libunittestfunc> libunittests;
3634
@@ -39,14 +37,16 @@
39 */37 */
40void initializeTestList() 38void initializeTestList()
41{39{
40 libunittests["base64"] = test_base64;
41 libunittests["base64_streambuf"] = test_base64_streambuf;
42 libunittests["fs_iterator"] = test_fs_iterator;
43 libunittests["json_parser"] = json_parser;
42 libunittests["string"] = test_string;44 libunittests["string"] = test_string;
45 libunittests["unique_ptr"] = test_unique_ptr;
43 libunittests["uri"] = runUriTest;46 libunittests["uri"] = runUriTest;
44 libunittests["fs_iterator"] = test_fs_iterator;
45#ifndef ZORBA_NO_ICU47#ifndef ZORBA_NO_ICU
46 libunittests["icu_streambuf"] = test_icu_streambuf;48 libunittests["icu_streambuf"] = test_icu_streambuf;
47#endif /* ZORBA_NO_ICU */49#endif /* ZORBA_NO_ICU */
48 libunittests["json_parser"] = json_parser;
49 libunittests["unique_ptr"] = test_unique_ptr;
50#ifndef ZORBA_NO_FULL_TEXT50#ifndef ZORBA_NO_FULL_TEXT
51 libunittests["stemmer"] = test_stemmer;51 libunittests["stemmer"] = test_stemmer;
52 libunittests["thesaurus"] = test_thesaurus;52 libunittests["thesaurus"] = test_thesaurus;
@@ -78,7 +78,6 @@
78}78}
7979
8080
81} /* namespace UnitTests */81} // namespace UnitTests
82} /* namespace zorba */82} // namespace zorba
83
84/* vim:set et sw=2 ts=2: */83/* vim:set et sw=2 ts=2: */
8584
=== 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:34:26 +0000
@@ -14,6 +14,7 @@
1414
15SET(UTIL_SRCS15SET(UTIL_SRCS
16 ascii_util.cpp16 ascii_util.cpp
17 base64_util.cpp
17 dynamic_bitset.cpp18 dynamic_bitset.cpp
18 error_util.cpp19 error_util.cpp
19 file.cpp20 file.cpp
2021
=== 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:34:26 +0000
@@ -15,6 +15,8 @@
15 */15 */
16#include "stdafx.h"16#include "stdafx.h"
1717
18#include <cstring>
19
18#include "ascii_util.h"20#include "ascii_util.h"
1921
20namespace zorba {22namespace zorba {
@@ -30,6 +32,38 @@
30 return true;32 return true;
31}33}
3234
35size_type remove_chars( char *s, size_type s_len, char const *chars ) {
36 char *end = s + s_len;
37 char *c;
38
39 // remove trailing chars first
40 for ( c = end - 1; c >= s; --c )
41 if ( !std::strchr( chars, *c ) ) {
42 end = c + 1;
43 break;
44 }
45 if ( c < s ) // it was all chars
46 return 0;
47
48 // remove all other chars
49 char *first_char = nullptr;
50 for ( c = s; c < end; ++c ) {
51 if ( std::strchr( chars, *c ) ) {
52 if ( !first_char )
53 first_char = c;
54 } else {
55 if ( first_char ) {
56 std::memmove( first_char, c, end - c );
57 end -= c - first_char;
58 c = first_char;
59 first_char = nullptr;
60 }
61 }
62 }
63
64 return end - s;
65}
66
33char const* trim_start( char const *s, char const *chars ) {67char const* trim_start( char const *s, char const *chars ) {
34 for ( ; *s; ++s ) {68 for ( ; *s; ++s ) {
35 if ( !std::strchr( chars, *s ) )69 if ( !std::strchr( chars, *s ) )
3670
=== 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:34:26 +0000
@@ -649,6 +649,29 @@
649}649}
650650
651/**651/**
652 * Removes all specified characters by shifting the contents of the buffer to
653 * the left.
654 *
655 * @param s The string.
656 * @param s_len The length of \a s.
657 * @param chars The characters to remove.
658 * @return Returns the new length of \a s with all \a chars removed.
659 */
660size_type remove_chars( char *s, size_type s_len, char const *chars );
661
662/**
663 * Removes all whitespace characters by shifting the contents of the buffer to
664 * the left.
665 *
666 * @param s The string.
667 * @param s_len The length of \a s.
668 * @return Returns the new length of \a s with all whitespace removed.
669 */
670inline size_type remove_whitespace( char *s, size_type s_len ) {
671 return remove_chars( s, s_len, whitespace );
672}
673
674/**
652 * Removes all leading and trailing specified characters.675 * Removes all leading and trailing specified characters.
653 *676 *
654 * @tparam InputStringType The input string type.677 * @tparam InputStringType The input string type.
655678
=== 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:34:26 +0000
@@ -0,0 +1,359 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18#include <cstring>
19
20#include "ascii_util.h"
21#include "base64_util.h"
22#include "string_util.h"
23
24using namespace std;
25
26namespace zorba {
27namespace base64 {
28
29///////////////////////////////////////////////////////////////////////////////
30
31static char const alphabet[] =
32 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
33 "abcdefghijklmnopqrstuvwxyz"
34 "0123456789+/";
35
36/**
37 * Base64 decoding table. A value of -1 means "invalid"; a value of -2 means
38 * "skip" (for newlines and carriage returns).
39 */
40static signed char const decode_table[] = {
41 /* 00-07 */ -1, -1, -1, -1, -1, -1, -1, -1,
42 /* 08-0F */ -1, -1, -2, -1, -1, -2, -1, -1, // . .\n . .\r . .
43 /* 10-17 */ -1, -1, -1, -1, -1, -1, -1, -1,
44 /* 18-1F */ -1, -1, -1, -1, -1, -1, -1, -1,
45 /* 20-27 */ -1, -1, -1, -1, -1, -1, -1, -1,
46 /* 28-2F */ -1, -1, -1, 62, -1, -1, -1, 63, // . . . + . . . /
47 /* 30-37 */ 52, 53, 54, 55, 56, 57, 58, 59, // 0 1 2 3 4 5 6 7
48 /* 38-3F */ 60, 61, -1, -1, -1, -1, -1, -1, // 8 9 . . . . . .
49 /* 40-47 */ -1, 0, 1, 2, 3, 4, 5, 6, // . A B C D E F G
50 /* 48-4F */ 7, 8, 9, 10, 11, 12, 13, 14, // H I J K L M N O
51 /* 50-57 */ 15, 16, 17, 18, 19, 20, 21, 22, // P Q R S T U V W
52 /* 58-5F */ 23, 24, 25, -1, -1, -1, -1, -1, // X Y Z . . . . .
53 /* 60-67 */ -1, 26, 27, 28, 29, 30, 31, 32, // . a b c d e f g
54 /* 68-6F */ 33, 34, 35, 36, 37, 38, 39, 40, // h i j k l m n o
55 /* 70-77 */ 41, 42, 43, 44, 45, 46, 47, 48, // p q r s t u v w
56 /* 78-7F */ 49, 50, 51, -1, -1, -1, -1, -1, // x y z . . . . .
57 /* 80-87 */ -1, -1, -1, -1, -1, -1, -1, -1,
58 /* 88-8F */ -1, -1, -1, -1, -1, -1, -1, -1,
59 /* 90-97 */ -1, -1, -1, -1, -1, -1, -1, -1,
60 /* 98-9F */ -1, -1, -1, -1, -1, -1, -1, -1,
61 /* A0-A7 */ -1, -1, -1, -1, -1, -1, -1, -1,
62 /* A8-AF */ -1, -1, -1, -1, -1, -1, -1, -1,
63 /* B0-B7 */ -1, -1, -1, -1, -1, -1, -1, -1,
64 /* B8-BF */ -1, -1, -1, -1, -1, -1, -1, -1,
65 /* C0-C7 */ -1, -1, -1, -1, -1, -1, -1, -1,
66 /* C8-CF */ -1, -1, -1, -1, -1, -1, -1, -1,
67 /* D0-D7 */ -1, -1, -1, -1, -1, -1, -1, -1,
68 /* D8-DF */ -1, -1, -1, -1, -1, -1, -1, -1,
69 /* E0-E7 */ -1, -1, -1, -1, -1, -1, -1, -1,
70 /* E8-EF */ -1, -1, -1, -1, -1, -1, -1, -1,
71 /* F0-F7 */ -1, -1, -1, -1, -1, -1, -1, -1,
72 /* F8-FF */ -1, -1, -1, -1, -1, -1, -1, -1,
73};
74
75inline void decode_chunk( char const *from, char *to ) {
76 //
77 // | INPUT BYTES
78 // +-----------+-----------+-----------+-----------+
79 // | 0 | 1 | 2 | 3 |
80 // +-----------+-----------+-----------+-----------+
81 // | | | | |
82 // | | | | | | | | | | | | | | | | | | | | | | | | |
83 // | | | |
84 // +---------------+---------------+---------------+
85 // | 0 | 1 | 2 |
86 // +---------------+---------------+---------------+
87 // | OUTPUT BYTES
88 //
89 unsigned char const *const u = reinterpret_cast<unsigned char const*>( from );
90 to[0] = (u[0] << 2) | (u[1] >> 4);
91 to[1] = (u[1] << 4) | (u[2] >> 2);
92 to[2] = ((u[2] << 6) & 0xC0) | u[3] ;
93}
94
95inline void encode_chunk( char const *from, char *to ) {
96 //
97 // | INPUT BYTES
98 // +---------------+---------------+---------------+
99 // | 0 | 1 | 2 |
100 // +---------------+---------------+---------------+
101 // | | | |
102 // | | | | | | | | | | | | | | | | | | | | | | | | |
103 // | | | | |
104 // +-----------+-----------+-----------+-----------+
105 // | 0 | 1 | 2 | 3 |
106 // +-----------+-----------+-----------+-----------+
107 // | OUTPUT BYTES
108 //
109 unsigned char const *const u = reinterpret_cast<unsigned char const*>( from );
110 to[0] = alphabet[ u[0] >> 2 ];
111 to[1] = alphabet[ ((u[0] & 0x03) << 4) | (u[1] >> 4) ];
112 to[2] = alphabet[ ((u[1] & 0x0F) << 2) | (u[2] >> 6) ];
113 to[3] = alphabet[ u[2] & 0x3F ];
114}
115
116streamsize read_without_whitespace( istream &is, char *buf, streamsize n ) {
117 char const *const buf_orig = buf;
118 char const *const buf_end = buf + n;
119
120 while ( buf < buf_end ) {
121 is.read( buf, n );
122 if ( streamsize read = is.gcount() ) {
123 read = ascii::remove_whitespace( buf, read );
124 buf += read, n -= read;
125 } else
126 break;
127 }
128 return buf - buf_orig;
129}
130
131///////////////////////////////////////////////////////////////////////////////
132
133size_type decode( char const *from, size_type from_len, char *to,
134 int options ) {
135 char chunk[4];
136 int chunk_len = 0;
137 bool const ignore_ws = options & dopt_ignore_ws;
138 int pads = 0;
139 char const *const to_orig = to;
140
141 for ( size_type pos = 0; pos < from_len; ++pos, ++from ) {
142 char const c = *from;
143 signed char value;
144 if ( c == '=' ) {
145 switch ( pos % 4 ) {
146 //
147 // Ensure '=' occurs only in the 3rd or 4th bytes of a 4-byte chunk
148 // and that the byte preceding '=' is valid.
149 //
150 case 2:
151 if ( !strchr( "AQgw", from[-1] ) )
152 throw base64::exception(
153 c, pos, BUILD_STRING( '\'', c, "': invalid character before '='" )
154 );
155 break;
156 case 3:
157 if ( !strchr( "=048AEIMQUYcgkosw", from[-1] ) )
158 throw base64::exception(
159 c, pos, BUILD_STRING( '\'', c, "': invalid character before '='" )
160 );
161 break;
162 default:
163 throw base64::exception( c, pos, "'=' encountered unexpectedly" );
164 }
165 ++pads;
166 value = '\0';
167 } else {
168 if ( pads )
169 throw base64::exception(
170 c, pos, BUILD_STRING( '\'', c, "': invalid character after '='" )
171 );
172 value = decode_table[ static_cast<unsigned char>( c ) ];
173 }
174 switch ( value ) {
175 case -1:
176 if ( ascii::is_space( c ) && ignore_ws )
177 continue;
178 throw base64::exception(
179 c, pos, BUILD_STRING( '\'', c, "': invalid character" )
180 );
181 case -2: // \n or \r
182 continue;
183 default:
184 if ( chunk_len == 4 )
185 chunk_len = 0;
186 if ( to ) {
187 chunk[ chunk_len ] = value;
188 if ( ++chunk_len == 4 ) {
189 decode_chunk( chunk, to );
190 to += 3;
191 }
192 } else
193 ++chunk_len;
194 }
195 } // for
196
197 if ( (chunk_len % 4) && !(options & dopt_any_len) )
198 throw invalid_argument( "Base64 length is not a multiple of 4" );
199
200 if ( !to )
201 return 0;
202
203 if ( chunk_len > 1 && chunk_len < 4 ) {
204 //
205 // The number of non-whitespace bytes was not a multiple of 4, hence the
206 // Base64 encoding is incomplete: salvage 1 or 2 characters.
207 //
208 int const salvageable = chunk_len - 1;
209 chunk[3] = '\0';
210 if ( salvageable == 1 )
211 chunk[2] = '\0';
212 decode_chunk( chunk, to );
213 to += salvageable;
214 }
215
216 return to - to_orig - pads;
217}
218
219size_type decode( char const *from, size_type from_len, std::vector<char> *to,
220 int options ) {
221 size_type total_decoded = 0;
222 if ( from_len ) {
223 std::vector<char>::size_type const orig_size = to->size();
224 to->resize( orig_size + decoded_size( from_len ) );
225 total_decoded = decode( from, from_len, &(*to)[ orig_size ], options );
226 to->resize( orig_size + total_decoded );
227 }
228 return total_decoded;
229}
230
231size_type decode( istream &from, ostream &to, int options ) {
232 size_type total_decoded = 0;
233 while ( !from.eof() ) {
234 char from_buf[ 1024 * 4 ], to_buf[ 1024 * 3 ];
235 streamsize gcount;
236 if ( options & dopt_ignore_ws )
237 gcount = read_without_whitespace( from, from_buf, sizeof from_buf );
238 else {
239 from.read( from_buf, sizeof from_buf );
240 gcount = from.gcount();
241 }
242 if ( gcount ) {
243 size_type const decoded = decode( from_buf, gcount, to_buf, options );
244 to.write( to_buf, decoded );
245 total_decoded += decoded;
246 } else
247 break;
248 }
249 return total_decoded;
250}
251
252size_type decode( istream &from, vector<char> *to, int options ) {
253 vector<char>::size_type const orig_size = to->size();
254 size_type total_decoded = 0;
255 while ( !from.eof() ) {
256 char from_buf[ 1024 * 4 ];
257 streamsize gcount;
258 if ( options & dopt_ignore_ws )
259 gcount = read_without_whitespace( from, from_buf, sizeof from_buf );
260 else {
261 from.read( from_buf, sizeof from_buf );
262 gcount = from.gcount();
263 }
264 if ( gcount ) {
265 to->resize( to->size() + decoded_size( gcount ) );
266 total_decoded +=
267 decode( from_buf, gcount, &(*to)[ total_decoded ], options );
268 } else
269 break;
270 }
271 to->resize( orig_size + total_decoded );
272 return total_decoded;
273}
274
275///////////////////////////////////////////////////////////////////////////////
276
277size_type encode( char const *from, size_type from_len, char *to ) {
278 char const *const to_orig = to;
279 int chunk_len = 0;
280
281 while ( from_len-- ) {
282 if ( ++chunk_len == 3 ) {
283 encode_chunk( from, to );
284 from += 3, to += 4;
285 chunk_len = 0;
286 }
287 }
288
289 if ( chunk_len ) { // must be either 1 or 2
290 //
291 // Handle the special-case of from_len not being a multiple of 3. First,
292 // copy what's left over from "from" to a temporary buffer that's 3 bytes
293 // long and encode that buffer so encode_chunk() remains special-case-free
294 // (and thus faster) for most of the encoding.
295 //
296 char from_temp[3];
297 from_temp[1] = from_temp[2] = '\0';
298 std::copy( from, from + chunk_len, from_temp );
299 encode_chunk( from_temp, to );
300 //
301 // Second, overwrite the trailing byte(s) with Base64 padding characters.
302 //
303 to[3] = '=';
304 if ( chunk_len == 1 )
305 to[2] = '=';
306 to += 4;
307 }
308
309 return to - to_orig;
310}
311
312size_type encode( char const *from, size_type from_len,
313 std::vector<char> *to ) {
314 size_type encoded = 0;
315 if ( from_len ) {
316 std::vector<char>::size_type const orig_size = to->size();
317 to->resize( orig_size + encoded_size( from_len ) );
318 encoded = encode( from, from_len, &(*to)[ orig_size ] );
319 to->resize( orig_size + encoded );
320 }
321 return encoded;
322}
323
324size_type encode( istream &from, ostream &to ) {
325 size_type total_encoded = 0;
326 while ( !from.eof() ) {
327 char from_buf[ 1024 * 3 ], to_buf[ 1024 * 4 ];
328 from.read( from_buf, sizeof from_buf );
329 if ( streamsize const gcount = from.gcount() ) {
330 size_type const encoded = encode( from_buf, gcount, to_buf );
331 to.write( to_buf, encoded );
332 total_encoded += encoded;
333 } else
334 break;
335 }
336 return total_encoded;
337}
338
339size_type encode( istream &from, vector<char> *to ) {
340 vector<char>::size_type const orig_size = to->size();
341 size_type total_encoded = 0;
342 while ( !from.eof() ) {
343 char from_buf[ 1024 * 3 ];
344 from.read( from_buf, sizeof from_buf );
345 if ( streamsize const gcount = from.gcount() ) {
346 to->resize( to->size() + encoded_size( gcount ) );
347 total_encoded += encode( from_buf, gcount, &(*to)[ total_encoded ] );
348 } else
349 break;
350 }
351 to->resize( orig_size + total_encoded );
352 return total_encoded;
353}
354
355///////////////////////////////////////////////////////////////////////////////
356
357} // namespace base64
358} // namespace zorba
359/* vim:set et sw=2 ts=2: */
0360
=== 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:34:26 +0000
@@ -0,0 +1,361 @@
1/*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18#ifndef ZORBA_BASE64_UTIL_H
19#define ZORBA_BASE64_UTIL_H
20
21#include <algorithm>
22#include <iostream>
23#include <stdexcept>
24#include <sys/types.h> /* for size_t */
25#include <vector>
26
27#include "cxx_util.h"
28
29namespace zorba {
30namespace base64 {
31
32////////// Types //////////////////////////////////////////////////////////////
33
34typedef size_t size_type;
35
36/**
37 * Options to use for decoding.
38 */
39enum decode_options {
40 dopt_none = 0x00, ///< No options.
41 dopt_any_len = 0x01, ///< Input length may be non-multiple of 4.
42 dopt_ignore_ws = 0x02, ///< Ignore all whitespace.
43};
44
45////////// Exception //////////////////////////////////////////////////////////
46
47/**
48 * A %base64::exception is-an invalid_argument that contains additional details
49 * about the exception such as the invalid character and its offset.
50 */
51class exception : public std::invalid_argument {
52public:
53 exception( char c, size_type offset, std::string const &msg ) :
54 std::invalid_argument( msg ), char_( c ), offset_( offset ) { }
55
56 char invalid_char() const {
57 return char_;
58 }
59
60 size_type char_offset() const {
61 return offset_;
62 }
63
64private:
65 char char_;
66 size_type offset_;
67};
68
69////////// Decoding ///////////////////////////////////////////////////////////
70
71/**
72 * \internal
73 * Reads from the given istream until \a n non-whitespace characters are read
74 * or until EOF is encountered.
75 *
76 * @param is The istream to read from.
77 * @param buf A pointer to the start of a buffer to read into.
78 * @param n The number of non-whitespace characters to read.
79 * @return Returns the number of non-whitespace characters read.
80 */
81std::streamsize read_without_whitespace( std::istream &is, char *buf,
82 std::streamsize n );
83
84/**
85 * Calculates the number of bytes required to decode \a n Base64-encoded bytes.
86 *
87 * @param n The number of bytes to decode.
88 * @return Returns the number of bytes needed for Base64 decoding.
89 */
90inline size_type decoded_size( size_type n ) {
91 return ((n / 4) + !!(n % 4)) * 3;
92}
93
94/**
95 * Decodes a Base64-encoded buffer. Embedded newlines and carriage-returns are
96 * skipped.
97 *
98 * @param from A pointer to the Base64 buffer to be decoded.
99 * @param from_len The number of bytes to decode.
100 * @paran to A pointer to the buffer to receive the decoded bytes. The buffer
101 * must be large enough to contain them. Note that the buffer is \e not null
102 * terminated.
103 * @param options The decoding options to use.
104 * @return Returns the number of decoded bytes.
105 * @throws invalid_argument if \a options does not have the \c dtop_any_len bit
106 * set and \a from_len is not a multiple of 4.
107 * @throws base64::exception if an \c = is encountered unexpectedly or an
108 * invalid byte is encountered.
109 * @see decoded_size()
110 */
111size_type decode( char const *from, size_type from_len, char *to,
112 int options = dopt_none );
113
114/**
115 * Decodes a Base64-encoded buffer and appends the decoded bytes onto a
116 * vector&lt;char&gt;. Embedded newlines and carriage-returns are skipped.
117 *
118 * @param from A pointer to the buffer to be encoded.
119 * @param from_len The number of bytes to encode.
120 * @param to A pointer to the vector to append the encoded bytes appended onto.
121 * The vector is made large enough to contain the additional bytes.
122 * @param options The decoding options to use.
123 * @return Returns the number of decoded bytes.
124 * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
125 * set and the number of Base64 bytes decoded is not a multiple of 4.
126 * @throws base64::exception if an \c = is encountered unexpectedly or an
127 * invalid byte is encountered.
128 */
129size_type decode( char const *from, size_type from_len, std::vector<char> *to,
130 int options = dopt_none );
131
132/**
133 * Decodes a Base64-encoded buffer and appends the decoded bytes onto a string.
134 * Embedded newlines and carriage-returns are skipped.
135 *
136 * @tparam ToStringType The string type.
137 * @param from A pointer to the Base64 buffer to be decoded.
138 * @param from_len The number of bytes to decode.
139 * @param to The string to append the decoded bytes to.
140 * @param options The options to use.
141 * @return Returns the number of decoded bytes.
142 * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
143 * set and the number of Base64 bytes decoded is not a multiple of 4.
144 * @throws base64::exception if an \c = is encountered unexpectedly or an
145 * invalid byte is encountered.
146 */
147template<class ToStringType>
148size_type decode( char const *from, size_type from_len, ToStringType *to,
149 int options = dopt_none ) {
150 size_type total_decoded = 0;
151 if ( from_len ) {
152 typename ToStringType::size_type const orig_size = to->size();
153 to->resize( orig_size + decoded_size( from_len ) );
154 total_decoded = decode( from, from_len, &to->at( orig_size ), options );
155 to->resize( orig_size + total_decoded );
156 }
157 return total_decoded;
158}
159
160/**
161 * Decodes a Base64-encoded istream. Embedded newlines and carriage-returns
162 * are skipped.
163 *
164 * @param from The istream to read from until EOF is reached.
165 * @param to The ostream to write the decoded bytes to.
166 * @param options The options to use.
167 * 4 otherwise an exception is thrown; if \a false, missing trailing bytes are
168 * assumed to be padding.
169 * @return Returns the number of decoded bytes.
170 * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
171 * set and the number of Base64 bytes decoded is not a multiple of 4.
172 * @throws base64::exception if an \c = is encountered unexpectedly or an
173 * invalid byte is encountered.
174 */
175size_type decode( std::istream &from, std::ostream &to,
176 int options = dopt_none );
177
178/**
179 * Decodes a Base64-encoded istream and appends the decoded bytes to a string.
180 * Embedded newlines and carriage-returns are skipped.
181 *
182 * @tparam ToStringType The string type.
183 * @param from The istream to read from until EOF is reached.
184 * @param to The string to append the decoded bytes to.
185 * @param options The options to use.
186 * 4 otherwise an exception is thrown; if \a false, missing trailing bytes are
187 * assumed to be padding.
188 * @return Returns the number of decoded bytes.
189 * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
190 * set and the number of Base64 bytes decoded is not a multiple of 4.
191 * @throws base64::exception if an \c = is encountered unexpectedly or an
192 * invalid byte is encountered.
193 */
194template<class ToStringType>
195size_type decode( std::istream &from, ToStringType *to,
196 int options = dopt_none ) {
197 size_type total_decoded = 0;
198 while ( !from.eof() ) {
199 char from_buf[ 1024 * 4 ], to_buf[ 1024 * 3 ];
200 std::streamsize gcount;
201 if ( options & dopt_ignore_ws )
202 gcount = read_without_whitespace( from, from_buf, sizeof from_buf );
203 else {
204 from.read( from_buf, sizeof from_buf );
205 gcount = from.gcount();
206 }
207 if ( gcount ) {
208 size_type const decoded = decode( from_buf, gcount, to_buf, options );
209 to->append( to_buf, decoded );
210 total_decoded += decoded;
211 } else
212 break;
213 }
214 return total_decoded;
215}
216
217/**
218 * Decodes a Base64-encoded stream and appends the decoded bytes onto a
219 * vector&lt;char;&gt;.
220 *
221 * @param from The istream to read from until EOF is reached.
222 * @param to The string to append the decoded bytes to.
223 * @param options The options to use.
224 * @param Returns the number of decoded bytes.
225 * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
226 * set and the number of Base64 bytes decoded is not a multiple of 4.
227 * @throws base64::exception if an \c = is encountered unexpectedly or an
228 * invalid byte is encountered.
229 */
230size_type decode( std::istream &from, std::vector<char> *to,
231 int options = dopt_none );
232
233/**
234 * Validates a Base64-encoded buffer. Embedded newlines and carriage-returns
235 * are skipped.
236 *
237 * @param buf A pointer to the Base64 buffer to be validated.
238 * @param buf_len The number of bytes to validate.
239 * @param options The options to use.
240 * @throws invalid_argument if \a options does not have the \c dopt_any_len bit
241 * set and the number of Base64 bytes validated is not a multiple of 4.
242 * @throws base64::exception if an \c = is encountered unexpectedly or an
243 * invalid byte is encountered.
244 * @see decoded_size()
245 */
246inline void validate( char const *buf, size_type buf_len,
247 int options = dopt_none ) {
248 decode( buf, buf_len, static_cast<char*>( nullptr ), options );
249}
250
251////////// Encoding ///////////////////////////////////////////////////////////
252
253/**
254 * Calculates the number of bytes required to Base64-encode \a n bytes.
255 *
256 * @param n The number of bytes to encode.
257 * @return Returns the number of bytes needed for Base64 encoding.
258 */
259inline size_type encoded_size( size_type n ) {
260 return (n + 2) / 3 * 4;
261}
262
263/**
264 * Base64-encodes a buffer.
265 *
266 * @param from A pointer to the buffer to be encoded.
267 * @param from_len The number of bytes to encode.
268 * @param to A pointer to the buffer to receive the encoded bytes. The buffer
269 * must be large enough to contain them. Note that the buffer is \e not null
270 * terminated.
271 * @return Returns the number of encoded bytes.
272 * @see encoded_size()
273 */
274size_type encode( char const *from, size_type from_len, char *to );
275
276/**
277 * Base64-encodes a buffer and appends the encoded bytes onto a
278 * vector&lt;char&gt;.
279 *
280 * @param from A pointer to the buffer to be encoded.
281 * @param from_len The number of bytes to encode.
282 * @param to A pointer to the vector to append the encoded bytes appended onto.
283 * The vector is made large enough to contain the additional bytes.
284 */
285size_type encode( char const *from, size_type from_len, std::vector<char> *to );
286
287/**
288 * Base64-encodes a buffer and appends the encoded bytes onto a string.
289 *
290 * @tparam ToStringType The string type.
291 * @param from A pointer to the Base64 buffer to be encoded.
292 * @param from_len The number of bytes to encode.
293 * @param to A pointer to the string to append the encoded bytes onto.
294 * @return Returns the number of encoded bytes.
295 */
296template<class ToStringType>
297size_type encode( char const *from, size_type from_len, ToStringType *to ) {
298 size_type total_encoded = 0;
299 if ( from_len ) {
300 typename ToStringType::size_type const orig_size = to->size();
301 to->resize( orig_size + encoded_size( from_len ) );
302 total_encoded = encode( from, from_len, &to->at( orig_size ) );
303 to->resize( orig_size + total_encoded );
304 }
305 return total_encoded;
306}
307
308/**
309 * Base64-encodes one stream and write the encoded bytes to another.
310 *
311 * @param from The istream to read from until EOF is reached.
312 * @param to The ostream to write the encoded bytes to.
313 */
314size_type encode( std::istream &from, std::ostream &to );
315
316/**
317 * Encodes a stream to Base64 and appends the encoded bytes to a string.
318 *
319 * @tparam ToStringType The string type.
320 * @param from The istream to read from until EOF is reached.
321 * @param to The string to append the encoded bytes to.
322 * @return Returns the number of encoded bytes.
323 */
324template<class ToStringType>
325size_type encode( std::istream &from, ToStringType *to ) {
326 size_type total_encoded = 0;
327 while ( !from.eof() ) {
328 char from_buf[ 1024 * 3 ], to_buf[ 1024 * 4 ];
329 from.read( from_buf, sizeof from_buf );
330 if ( std::streamsize const gcount = from.gcount() ) {
331 size_type const encoded = encode( from_buf, gcount, to_buf );
332 to->append( to_buf, encoded );
333 total_encoded += encoded;
334 } else
335 break;
336 }
337 return total_encoded;
338}
339
340/**
341 * Base64-encodes a stream and appends the encoded bytes onto a
342 * vector&lt;char;&gt;.
343 *
344 * @param from The istream to read from until EOF is reached.
345 * @param to The string to append the encoded bytes to.
346 * @param Returns the number of encoded bytes.
347 */
348size_type encode( std::istream &from, std::vector<char> *to );
349
350///////////////////////////////////////////////////////////////////////////////
351
352} // namespace base64
353} // namespace zorba
354
355#endif /* ZORBA_BASE64_UTIL_H */
356/*
357 * Local variables:
358 * mode: c++
359 * End:
360 */
361/* vim:set et sw=2 ts=2: */
0362
=== 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:34:26 +0000
@@ -15,8 +15,8 @@
15 */15 */
1616
17#include "stdafx.h"17#include "stdafx.h"
18#define ZORBA_DEBUG_ICU_STREAMBUF 0
1918
19// #define ZORBA_DEBUG_ICU_STREAMBUF
20#ifdef ZORBA_DEBUG_ICU_STREAMBUF20#ifdef ZORBA_DEBUG_ICU_STREAMBUF
21# include <stdio.h>21# include <stdio.h>
22#endif22#endif
2323
=== 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:34:26 +0000
@@ -1884,7 +1884,7 @@
1884 }1884 }
18851885
1886 /**1886 /**
1887 * Attemts to pre-allocated enough memory to contain the given number of1887 * Attemts to pre-allocate enough memory to contain the given number of
1888 * bytes.1888 * bytes.
1889 *1889 *
1890 * @param n The number of bytes.1890 * @param n The number of bytes.
18911891
=== 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:34:26 +0000
@@ -25,32 +25,44 @@
25#include "diagnostics/xquery_diagnostics.h"25#include "diagnostics/xquery_diagnostics.h"
2626
27#include "util/ascii_util.h"27#include "util/ascii_util.h"
28#include "util/base64_util.h"
28#include "util/stl_util.h"29#include "util/stl_util.h"
2930
31#define CATCH_BASE64_EXCEPTION() \
32 catch ( base64::exception const &e ) { \
33 throw XQUERY_EXCEPTION( \
34 err::FORG0001, ERROR_PARAMS( e.invalid_char(), ZED( Base64BadChar ) ) \
35 ); \
36 } \
37 catch ( std::invalid_argument const& ) { \
38 throw XQUERY_EXCEPTION( \
39 err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) ) \
40 ); \
41 }
42
30using namespace std;43using namespace std;
3144
32namespace zorba 45namespace zorba {
33{46
3447static size_t copy_without_ws( char const *from, size_t len, char *to ) {
3548 char const *const end = from + len;
36static const string base64_chars = 49 char const *const to_orig = to;
37 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"50 for ( ; from < end; ++from )
38 "abcdefghijklmnopqrstuvwxyz"51 if ( !ascii::is_space( *from ) )
39 "0123456789+/";52 *to++ = *from;
4053 return to - to_orig;
41
42inline bool is_base64(char c)
43{
44 return (isalnum(c) || (c == '+') || (c == '/'));
45}54}
4655
4756
48bool Base64::parseString(const char* aString, size_t aLength, Base64& aBase64)57bool Base64::parseString(const char* aString, size_t aLength, Base64& aBase64)
49{58{
50 aBase64.theData.clear();
51 try 59 try
52 {60 {
53 aBase64.insertData(aString, aLength);61 base64::validate( aString, aLength, base64::dopt_ignore_ws );
62 aBase64.theData.resize( aLength );
63 aBase64.theData.resize(
64 copy_without_ws( aString, aLength, &aBase64.theData[0] )
65 );
54 }66 }
55 catch (...) 67 catch (...)
56 {68 {
@@ -66,10 +78,13 @@
66 Base64& aBase64, 78 Base64& aBase64,
67 string& lErrorMessage)79 string& lErrorMessage)
68{80{
69 aBase64.theData.clear();
70 try 81 try
71 {82 {
72 aBase64.insertData(aString, aLength);83 base64::validate( aString, aLength, base64::dopt_ignore_ws );
84 aBase64.theData.resize( aLength );
85 aBase64.theData.resize(
86 copy_without_ws( aString, aLength, &aBase64.theData[0] )
87 );
73 }88 }
74 catch (ZorbaException const& e) 89 catch (ZorbaException const& e)
75 {90 {
@@ -82,102 +97,27 @@
8297
83void Base64::encode(const zstring& aString, Base64& aResult)98void Base64::encode(const zstring& aString, Base64& aResult)
84{99{
85 vector<char> source;100 base64::encode( aString.data(), aString.size(), &aResult.theData );
86 source.reserve(aString.size());
87
88 FOR_EACH( zstring, i, aString )
89 source.push_back( *i );
90
91 aResult.theData.clear();
92 encode(source, aResult.theData);
93}101}
94102
95103
96void Base64::encode(istream& aStream, Base64& aResult)104void Base64::encode(istream& aStream, Base64& aResult)
97{105{
98 vector<char> source;106 base64::encode( aStream, &aResult.theData );
99
100 char lC;
101 while (aStream.good())
102 {
103 aStream.get(lC);
104 if (!aStream.good())
105 {
106 break;
107 }
108 source.push_back(lC);
109 }
110
111 encode(source, aResult.theData);
112}107}
113108
114109
115zstring Base64::encode(istream& aStream)110zstring Base64::encode(istream& aStream)
116{111{
117 vector<char> source;
118 vector<char> dest;
119
120 char buf[1024];
121 while (!aStream.eof())
122 {
123 aStream.read(buf, 1024);
124 source.insert(source.end(), buf, buf + aStream.gcount());
125 }
126
127 encode(source, dest);
128
129 zstring result;112 zstring result;
130 result.reserve(dest.size());113 base64::encode( aStream, &result );
131
132 FOR_EACH( vector<char>, i, dest )
133 result.push_back( *i );
134
135 return result;114 return result;
136}115}
137116
138117
139void Base64::encode(const vector<char>& aSource, vector<char>& aResult)118void Base64::encode(const vector<char>& aSource, vector<char>& aResult)
140{119{
141 size_t in_len = aSource.size();120 base64::encode( &aSource[0], aSource.size(), &aResult );
142 size_t lCurPos = 0;
143 int i = 0;
144 int j = 0;
145 char char_array_3[3] = {'\0','\0','\0'};
146 char char_array_4[4] = {'\0','\0','\0','\0'};
147
148 while (in_len--)
149 {
150 char_array_3[i++] = aSource[lCurPos++];
151 if (i == 3)
152 {
153 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
154 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
155 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
156 char_array_4[3] = char_array_3[2] & 0x3f;
157
158 for(i = 0; (i <4) ; i++)
159 aResult.push_back(base64_chars[char_array_4[i]]);
160 i = 0;
161 }
162 }
163
164 if (i)
165 {
166 for(j = i; j < 3; j++)
167 char_array_3[j] = '\0';
168
169 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
170 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
171 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
172 char_array_4[3] = char_array_3[2] & 0x3f;
173
174 for (j = 0; (j < i + 1); j++)
175 aResult.push_back(base64_chars[char_array_4[j]]);
176
177 while((i++ < 3))
178 aResult.push_back('=');
179
180 }
181}121}
182122
183123
@@ -186,110 +126,38 @@
186 unsigned int in_len,126 unsigned int in_len,
187 Base64& aResult)127 Base64& aResult)
188{128{
189 size_t lCurPos = 0;129 base64::encode( (char*)aSource, in_len, &aResult.theData );
190 int i = 0;
191 int j = 0;
192 char char_array_3[3] = {'\0','\0','\0'};
193 char char_array_4[4] = {'\0','\0','\0','\0'};
194
195 aResult.theData.reserve(in_len * 8 / 6 + 10);
196 while (in_len--)
197 {
198 char_array_3[i++] = aSource[lCurPos++];
199 if (i == 3)
200 {
201 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
202 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
203 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
204 char_array_4[3] = char_array_3[2] & 0x3f;
205
206 for(i = 0; (i <4) ; i++)
207 aResult.theData.push_back(base64_chars[char_array_4[i]]);
208 i = 0;
209 }
210 }
211
212 if (i)
213 {
214 for(j = i; j < 3; j++)
215 char_array_3[j] = '\0';
216
217 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
218 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
219 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
220 char_array_4[3] = char_array_3[2] & 0x3f;
221
222 for (j = 0; (j < i + 1); j++)
223 aResult.theData.push_back(base64_chars[char_array_4[j]]);
224
225 while((i++ < 3))
226 aResult.theData.push_back('=');
227
228 }
229}130}
230131
231132
232zstring Base64::decode(istream& aStream)133void Base64::decode(istream& aStream, zstring *result)
233{134{
234 vector<char> source;135 try {
235 vector<char> dest;136 base64::decode(
236137 aStream, result, base64::dopt_any_len | base64::dopt_ignore_ws
237 char buf[1024];138 );
238 while (!aStream.eof())
239 {
240 aStream.read(buf, 1024);
241 source.insert(source.end(), buf, buf + aStream.gcount());
242 }139 }
243140 CATCH_BASE64_EXCEPTION()
244 decode(source, dest);
245
246 zstring result;
247 result.reserve(dest.size());
248
249 FOR_EACH( vector<char>, i, dest )
250 result.push_back( *i );
251
252 return result;
253}141}
254142
255
256void Base64::decode(const vector<char>& aSource, vector<char>& aResult)143void Base64::decode(const vector<char>& aSource, vector<char>& aResult)
257{144{
258 size_t in_len = aSource.size();145 try {
259 int i = 0;146 base64::decode(
260 int j = 0;147 &aSource[0], aSource.size(), &aResult,
261 int in_ = 0;148 base64::dopt_any_len | base64::dopt_ignore_ws
262 char char_array_4[4], char_array_3[3];149 );
263150 }
264 while (in_len-- && ( aSource[in_] != '=') && is_base64(aSource[in_])) {151 CATCH_BASE64_EXCEPTION()
265 char_array_4[i++] = aSource[in_]; in_++;152}
266 if (i ==4) {153
267 for (i = 0; i <4; i++)154void Base64::decode( char const *from, size_t from_len, zstring *to ) {
268 char_array_4[i] = (char)base64_chars.find(char_array_4[i]);155 try {
269156 base64::decode(
270 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);157 from, from_len, to, base64::dopt_any_len | base64::dopt_ignore_ws
271 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);158 );
272 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];159 }
273160 CATCH_BASE64_EXCEPTION()
274 for (i = 0; (i < 3); i++)
275 aResult.push_back(char_array_3[i]);
276 i = 0;
277 }
278 }
279
280 if (i) {
281 for (j = i; j <4; j++)
282 char_array_4[j] = 0;
283
284 for (j = 0; j <4; j++)
285 char_array_4[j] = (char)base64_chars.find(char_array_4[j]);
286
287 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
288 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
289 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
290
291 for (j = 0; (j < i - 1); j++) aResult.push_back(char_array_3[j]);
292 }
293}161}
294162
295163
@@ -303,88 +171,12 @@
303171
304Base64::Base64(const unsigned char *bin_data, size_t len)172Base64::Base64(const unsigned char *bin_data, size_t len)
305{173{
306 std::vector<char> tmp;174 try {
307 tmp.reserve(len);175 base64::encode( (char const*)bin_data, len, &theData );
308 tmp.insert(tmp.begin(), (const char*)bin_data, ((const char*)bin_data) + len);176 }
309 theData.reserve(len);177 CATCH_BASE64_EXCEPTION()
310 encode(tmp, theData);178}
311}179
312
313
314void Base64::insertData(const char* str, size_t len)
315{
316 ascii::size_type pos = 0;
317
318 ascii::skip_whitespace(str, len, &pos);
319
320 for (size_t i = pos; i < len; ++i)
321 {
322 char lChar = str[i];
323
324 if (lChar == ' ')
325 {
326 // do nothing
327 }
328 else if ((lChar >= 65 && lChar <= 90) // A-Z
329 || (lChar >= 97 && lChar <= 122) // a-z
330 || (lChar >= 48 && lChar <= 57) // 0-9
331 || (lChar == 43) // +
332 || (lChar == 47)) // /
333 {
334 theData.push_back(lChar);
335 }
336 else if (lChar == '=' && i > 0 && i == (len-2) && str[i+1] == '=' )
337 {
338 if (str[i-1] == 'A' ||
339 str[i-1] == 'Q' ||
340 str[i-1] == 'g' ||
341 str[i-1] == 'w')
342 {
343 theData.push_back('=');
344 theData.push_back('=');
345 ++i;
346 }
347 else
348 {
349 throw XQUERY_EXCEPTION(
350 err::FORG0001, ERROR_PARAMS( "==", ZED( Base64EqualsEquals ) )
351 );
352 }
353 }
354 else if (lChar == '=' && i > 0 && i == (len-1))
355 {
356 switch(str[i-1])
357 {
358 case 'A': case 'E': case 'I': case 'M': case 'Q': case 'U': case 'Y':
359 case 'c': case 'g': case 'k': case 'o': case 's': case 'w': case '0':
360 case '4': case '8':
361 theData.push_back('=');
362 break;
363 default:
364 throw XQUERY_EXCEPTION(
365 err::FORG0001, ERROR_PARAMS( '=', ZED( Base64Equals ) )
366 );
367 }
368 }
369 else if ( ascii::is_space(lChar) )
370 {
371 // ignore it
372 }
373 else
374 {
375 throw XQUERY_EXCEPTION(
376 err::FORG0001, ERROR_PARAMS( str[i], ZED( Base64BadChar ) )
377 );
378 }
379 }
380
381 if (theData.size() % 4 != 0)
382 {
383 throw XQUERY_EXCEPTION(
384 err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) )
385 );
386 }
387}
388180
389181
390bool Base64::equal(const Base64& aBase64) const182bool Base64::equal(const Base64& aBase64) const
@@ -396,7 +188,7 @@
396 vector<char>::const_iterator lEnd0 = theData.end();188 vector<char>::const_iterator lEnd0 = theData.end();
397 vector<char>::const_iterator lIter1 = aBase64.theData.begin();189 vector<char>::const_iterator lIter1 = aBase64.theData.begin();
398190
399 for (; lIter0 != lEnd0 ; )191 while ( lIter0 != lEnd0 )
400 {192 {
401 if (*lIter0 != *lIter1)193 if (*lIter0 != *lIter1)
402 return false;194 return false;
@@ -408,31 +200,28 @@
408200
409zstring Base64::str() const 201zstring Base64::str() const
410{202{
411 stringstream lStream;203 zstring result;
412 lStream << *this;204 vector<char>::const_iterator lIter = theData.begin();
413 return zstring(lStream.str());205 vector<char>::const_iterator lEnd = theData.end();
206 for( ; lIter != lEnd ; ++lIter)
207 {
208 result.push_back( *lIter );
209 }
210 return result;
414}211}
415212
416213
417zstring Base64::decode() const214zstring Base64::decode() const
418{215{
419 vector<char> lDecodedData;
420
421 Base64::decode(theData, lDecodedData);
422
423 zstring result;216 zstring result;
424 result.reserve( lDecodedData.size() );217 base64::decode( &theData[0], theData.size(), &result );
425
426 FOR_EACH( vector<char>, i, lDecodedData )
427 result.push_back( *i );
428
429 return result;218 return result;
430}219}
431220
432221
433void Base64::decode(vector<char>& aResult)222void Base64::decode(vector<char>& aResult)
434{223{
435 Base64::decode(theData, aResult);224 base64::decode( &theData[0], theData.size(), &aResult );
436}225}
437226
438227
@@ -466,6 +255,7 @@
466 return os;255 return os;
467}256}
468257
258///////////////////////////////////////////////////////////////////////////////
469259
470const char* Base16::ENCODE_TABLE = "0123456789ABCDEF";260const char* Base16::ENCODE_TABLE = "0123456789ABCDEF";
471261
@@ -662,6 +452,7 @@
662 return os;452 return os;
663}453}
664454
455///////////////////////////////////////////////////////////////////////////////
665456
666} // namespace zorba457} // namespace zorba
667/* vim:set et sw=2 ts=2: */458/* vim:set et sw=2 ts=2: */
668459
=== 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:34:26 +0000
@@ -76,7 +76,9 @@
7676
77 static void decode(const std::vector<char>&, std::vector<char>&);77 static void decode(const std::vector<char>&, std::vector<char>&);
7878
79 static zstring decode(std::istream& aStream);79 static void decode(std::istream& aStream, zstring*);
80
81 static void decode(char const*, size_t, zstring*);
8082
81public:83public:
82 Base64(const Base64& aBase64) 84 Base64(const Base64& aBase64)
@@ -90,8 +92,6 @@
9092
91 Base64() {}93 Base64() {}
9294
93 virtual ~Base64() {}
94
95 const std::vector<char>& getData() const { return theData; }95 const std::vector<char>& getData() const { return theData; }
9696
97 size_t size() const { return theData.size(); }97 size_t size() const { return theData.size(); }
@@ -105,9 +105,6 @@
105 void decode(std::vector<char>&);105 void decode(std::vector<char>&);
106106
107 uint32_t hash() const;107 uint32_t hash() const;
108
109private:
110 void insertData(const char* aCharStar, size_t len);
111};108};
112109
113110

Subscribers

People subscribed via source and target branches