Merge lp:~zorba-coders/zorba/feature-base64_streambuf into lp:zorba
- feature-base64_streambuf
- Merge into trunk
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 |
Related bugs: |
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.
Paul J. Lucas (paul-lucas) : | # |
Matthias Brantner (matthias-brantner) wrote : | # |
Paul J. Lucas (paul-lucas) wrote : | # |
> Did the streambuf api (already released in 2.5) change?
No.
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue starting for merge proposal.
Log at: http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue job feature-
All tests succeeded!
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.
Matthias Brantner (matthias-brantner) : | # |
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue starting for merge proposal.
Log at: http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue job feature-
All tests succeeded!
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2012-06-25 17:16:19 +0000 |
3 | +++ ChangeLog 2012-06-26 01:34:26 +0000 |
4 | @@ -18,7 +18,8 @@ |
5 | * Fixed bug #867357 (Improved parser error messages) |
6 | * Fixed bug #932314 (non-comparable values must be treated as distinct by |
7 | fn:distinct-values) |
8 | - * Fixed bug #991088$ (raise XUST0001 in trycatch with mixed updating and simple clauses) |
9 | + * Fixed bug #1015580 (Add base64_streambuf / replace inefficient base64 code) |
10 | + * Fixed bug #9910884 (raise XUST0001 in trycatch with mixed updating and simple clauses) |
11 | * Fixed bug #854506 (ugly type error messages) and partial fix for bug #867008 |
12 | * Fixed bug #1008082 (bug in transform expr when a copy var is not used anywhere) |
13 | * Fixed bug #1003023$ (optimizer problems due to common subexpression after |
14 | |
15 | === modified file 'doc/cxx/examples/binary.cpp' |
16 | --- doc/cxx/examples/binary.cpp 2012-06-18 10:06:47 +0000 |
17 | +++ doc/cxx/examples/binary.cpp 2012-06-26 01:34:26 +0000 |
18 | @@ -25,35 +25,25 @@ |
19 | { |
20 | String lString("Hello Zorba"); |
21 | String lEncoded = zorba::encoding::Base64::encode(lString); |
22 | - String lExpectedResult("SGVsbG8gWm9yYmE="); |
23 | - return lEncoded == lExpectedResult; |
24 | + return lEncoded == "SGVsbG8gWm9yYmE="; |
25 | } |
26 | |
27 | bool |
28 | decode_example() |
29 | { |
30 | - String lEncoded("SGVsbG8gWm9yYmE="); |
31 | - String lDecoded = zorba::encoding::Base64::decode(lEncoded); |
32 | - return lDecoded == "Hello Zorba"; |
33 | - |
34 | -} |
35 | - |
36 | -int |
37 | -binary(int argc, char* argv[]) |
38 | -{ |
39 | - |
40 | -bool res = false; |
41 | - |
42 | -std::cout << "executing example 1 (Base64 encoding of String)" << std::endl; |
43 | -res = encode_example(); |
44 | -if (!res) return 1; |
45 | -std::cout << std::endl; |
46 | - |
47 | -std::cout << "executing example 2 (decoding of Base64 encoded String)" << std::endl; |
48 | -res = decode_example(); |
49 | -if (!res) return 1; |
50 | -std::cout << std::endl; |
51 | - |
52 | -return 0; |
53 | - |
54 | -} |
55 | + String lEncoded("SGVsbG8gWm9yYmE="); |
56 | + String lDecoded = zorba::encoding::Base64::decode(lEncoded); |
57 | + return lDecoded == "Hello Zorba"; |
58 | +} |
59 | + |
60 | +int binary(int argc, char* argv[]) { |
61 | + |
62 | + std::cout << "executing example 1 (Base64 encoding of String)" << std::endl; |
63 | + if (!encode_example()) return 1; |
64 | + |
65 | + std::cout << "executing example 2 (decoding of Base64 encoded String)" << std::endl; |
66 | + if (!decode_example()) return 1; |
67 | + |
68 | + return 0; |
69 | +} |
70 | +/* vim:set et sw=2 ts=2: */ |
71 | |
72 | === modified file 'include/zorba/base64.h' |
73 | --- include/zorba/base64.h 2012-06-18 10:06:47 +0000 |
74 | +++ include/zorba/base64.h 2012-06-26 01:34:26 +0000 |
75 | @@ -21,12 +21,11 @@ |
76 | #include <zorba/config.h> |
77 | #include <zorba/zorba_string.h> |
78 | |
79 | -namespace zorba { namespace encoding { |
80 | +namespace zorba { |
81 | +namespace encoding { |
82 | |
83 | - class ZORBA_DLL_PUBLIC Base64 |
84 | + struct ZORBA_DLL_PUBLIC Base64 |
85 | { |
86 | - public: |
87 | - |
88 | static String |
89 | encode(const String& aString); |
90 | |
91 | @@ -38,12 +37,10 @@ |
92 | |
93 | static String |
94 | decode(std::istream& aStream); |
95 | - |
96 | }; |
97 | |
98 | -} /* end namespace encoding */ |
99 | - |
100 | -} /* end namespace zorba */ |
101 | - |
102 | -#endif |
103 | +} // namespace encoding |
104 | +} // namespace zorba |
105 | + |
106 | +#endif /* ZORBA_BASE64_API_H */ |
107 | /* vim:set et sw=2 ts=2: */ |
108 | |
109 | === added file 'include/zorba/base64_stream.h' |
110 | --- include/zorba/base64_stream.h 1970-01-01 00:00:00 +0000 |
111 | +++ include/zorba/base64_stream.h 2012-06-26 01:34:26 +0000 |
112 | @@ -0,0 +1,325 @@ |
113 | +/* |
114 | + * Copyright 2006-2008 The FLWOR Foundation. |
115 | + * |
116 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
117 | + * you may not use this file except in compliance with the License. |
118 | + * You may obtain a copy of the License at |
119 | + * |
120 | + * http://www.apache.org/licenses/LICENSE-2.0 |
121 | + * |
122 | + * Unless required by applicable law or agreed to in writing, software |
123 | + * distributed under the License is distributed on an "AS IS" BASIS, |
124 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
125 | + * See the License for the specific language governing permissions and |
126 | + * limitations under the License. |
127 | + */ |
128 | + |
129 | +#ifndef ZORBA_BASE64_STREAM_API_H |
130 | +#define ZORBA_BASE64_STREAM_API_H |
131 | + |
132 | +#include <streambuf> |
133 | + |
134 | +#include <zorba/config.h> |
135 | +#include <zorba/internal/streambuf.h> |
136 | + |
137 | +namespace zorba { |
138 | +namespace base64 { |
139 | + |
140 | +/////////////////////////////////////////////////////////////////////////////// |
141 | + |
142 | +/** |
143 | + * A %base64::streambuf is-a std::streambuf for encoding to and decoding from |
144 | + * Base64 on-the-fly. |
145 | + * |
146 | + * To use it, replace a stream's streambuf: |
147 | + * \code |
148 | + * istream is; |
149 | + * // ... |
150 | + * base64::streambuf b64buf( is.rdbuf() ); |
151 | + * is.ios::rdbuf( &b64buf ); |
152 | + * \endcode |
153 | + * Note that the %base64::streambuf must exist for as long as it's being used |
154 | + * by the stream. If you are replacing the streabuf for a stream you did not |
155 | + * create, you should set it back to the original streambuf: |
156 | + * \code |
157 | + * void f( ostream &os ) { |
158 | + * base64::streambuf b64buf( os.rdbuf() ); |
159 | + * try { |
160 | + * os.ios::rdbuf( &b64buf ); |
161 | + * // ... |
162 | + * } |
163 | + * catch ( ... ) { |
164 | + * os.ios::rdbuf( b64buf.orig_streambuf() ); |
165 | + * throw; |
166 | + * } |
167 | + * os.ios::rdbuf( b64buf.orig_streambuf() ); |
168 | + * } |
169 | + * \endcode |
170 | + * Alternatively, you may wish to use either \c attach(), \c auto_attach, or |
171 | + * \c base64::stream instead. |
172 | + * |
173 | + * \b Note: due to the nature of Base64-encoding, when writing, you \e must |
174 | + * ensure that the streambuf is flushed (by calling either \c pubsync() on the |
175 | + * streambuf or \c flush() on the owning stream) when done. |
176 | + * |
177 | + * While %base64::streambuf does support seeking, the positions are relative |
178 | + * to the original byte stream. |
179 | + */ |
180 | +class ZORBA_DLL_PUBLIC streambuf : public std::streambuf { |
181 | +public: |
182 | + /** |
183 | + * Constructs a %base64::streambuf. |
184 | + * |
185 | + * @param orig The original streambuf to read/write from/to. |
186 | + * @throws std::invalid_argument if is not supported or \a orig is null. |
187 | + */ |
188 | + streambuf( std::streambuf *orig ); |
189 | + |
190 | + /** |
191 | + * Destructs a %base64::streambuf. |
192 | + */ |
193 | + ~streambuf(); |
194 | + |
195 | + /** |
196 | + * Gets the original streambuf. |
197 | + * |
198 | + * @return said streambuf. |
199 | + */ |
200 | + std::streambuf* orig_streambuf() const { |
201 | + return orig_buf_; |
202 | + } |
203 | + |
204 | +protected: |
205 | + void imbue( std::locale const& ); |
206 | + pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode ); |
207 | + pos_type seekpos( pos_type, std::ios_base::openmode ); |
208 | + std::streambuf* setbuf( char_type*, std::streamsize ); |
209 | + std::streamsize showmanyc(); |
210 | + int sync(); |
211 | + int_type overflow( int_type ); |
212 | + int_type pbackfail( int_type ); |
213 | + int_type underflow(); |
214 | + std::streamsize xsgetn( char_type*, std::streamsize ); |
215 | + std::streamsize xsputn( char_type const*, std::streamsize ); |
216 | + |
217 | +private: |
218 | + std::streambuf *orig_buf_; |
219 | + |
220 | + char gbuf_[3]; |
221 | + char pbuf_[3]; |
222 | + int plen_; |
223 | + |
224 | + void clear(); |
225 | + void resetg(); |
226 | + void resetp(); |
227 | + void writep(); |
228 | + |
229 | + // forbid |
230 | + streambuf( streambuf const& ); |
231 | + streambuf& operator=( streambuf const& ); |
232 | +}; |
233 | + |
234 | +/////////////////////////////////////////////////////////////////////////////// |
235 | + |
236 | +} // namespace base64 |
237 | + |
238 | +namespace internal { |
239 | +namespace base64 { |
240 | + |
241 | +ZORBA_DLL_PUBLIC |
242 | +std::streambuf* alloc_streambuf( std::streambuf *orig ); |
243 | + |
244 | +ZORBA_DLL_PUBLIC |
245 | +int get_streambuf_index(); |
246 | + |
247 | +} // namespace base64 |
248 | +} // namespace internal |
249 | + |
250 | +namespace base64 { |
251 | + |
252 | +/////////////////////////////////////////////////////////////////////////////// |
253 | + |
254 | +/** |
255 | + * Attaches a base64::streambuf to a stream. Unlike using a |
256 | + * base64::streambuf directly, this function will create the streambuf, |
257 | + * attach it to the stream, and manage it for the lifetime of the stream |
258 | + * automatically. |
259 | + * |
260 | + * @param ios The stream to attach the base64::streambuf to. If the stream |
261 | + * already has a base64::streambuf attached to it, this function does |
262 | + * nothing. |
263 | + */ |
264 | +template<typename charT,typename Traits> inline |
265 | +void attach( std::basic_ios<charT,Traits> &ios ) { |
266 | + int const index = internal::base64::get_streambuf_index(); |
267 | + void *&pword = ios.pword( index ); |
268 | + if ( !pword ) { |
269 | + std::streambuf *const buf = |
270 | + internal::base64::alloc_streambuf( ios.rdbuf() ); |
271 | + ios.rdbuf( buf ); |
272 | + pword = buf; |
273 | + ios.register_callback( internal::stream_callback, index ); |
274 | + } |
275 | +} |
276 | + |
277 | +/** |
278 | + * Detaches a previously attached base64::streambuf from a stream. The |
279 | + * streambuf is destroyed and the stream's original streambuf is restored. |
280 | + * |
281 | + * @param ios The stream to detach the base64::streambuf from. If the |
282 | + * stream doesn't have a base64::streambuf attached to it, this function |
283 | + * does nothing. |
284 | + */ |
285 | +template<typename charT,typename Traits> inline |
286 | +void detach( std::basic_ios<charT,Traits> &ios ) { |
287 | + int const index = internal::base64::get_streambuf_index(); |
288 | + if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) { |
289 | + ios.pword( index ) = 0; |
290 | + ios.rdbuf( buf->orig_streambuf() ); |
291 | + internal::dealloc_streambuf( buf ); |
292 | + } |
293 | +} |
294 | + |
295 | +/** |
296 | + * Checks whether the given stream has a base64::streambuf attached. |
297 | + * |
298 | + * @param ios The stream to check. |
299 | + * @return \c true only if a base64::streambuf is attached. |
300 | + */ |
301 | +template<typename charT,typename Traits> inline |
302 | +bool is_attached( std::basic_ios<charT,Traits> &ios ) { |
303 | + return !!ios.pword( internal::base64::get_streambuf_index() ); |
304 | +} |
305 | + |
306 | +/** |
307 | + * A %base64::auto_attach is a class that attaches a base64::streambuf to |
308 | + * a stream and automatically detaches it when the %auto_attach object is |
309 | + * destroyed. |
310 | + * \code |
311 | + * void f( ostream &os ) { |
312 | + * base64::auto_attach<ostream> const raii( os, "ISO-8859-1" ); |
313 | + * // ... |
314 | + * } |
315 | + * \endcode |
316 | + * A %base64::auto_attach is useful for streams not created by you. |
317 | + * |
318 | + * @see http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization |
319 | + */ |
320 | +template<class StreamType> |
321 | +class auto_attach { |
322 | +public: |
323 | + /** |
324 | + * Constructs an %auto_attach object calling attach() on the given stream. |
325 | + * |
326 | + * @param stream The stream to attach the base64::streambuf to. If the |
327 | + * stream already has a base64::streambuf attached to it, this contructor |
328 | + * does nothing. |
329 | + */ |
330 | + auto_attach( StreamType &stream ) : stream_( stream ) { |
331 | + attach( stream ); |
332 | + } |
333 | + |
334 | + /** |
335 | + * Destroys this %auto_attach object calling detach() on the previously |
336 | + * attached stream. |
337 | + */ |
338 | + ~auto_attach() { |
339 | + detach( stream_ ); |
340 | + } |
341 | + |
342 | +private: |
343 | + StreamType &stream_; |
344 | +}; |
345 | + |
346 | +/////////////////////////////////////////////////////////////////////////////// |
347 | + |
348 | +/** |
349 | + * A %base64::stream is used to wrap a C++ standard I/O stream with a |
350 | + * base64::streambuf so that encoding/decoding and the management of the |
351 | + * streambuf happens automatically. |
352 | + * |
353 | + * A %base64::stream is useful for streams created by you. |
354 | + * |
355 | + * @tparam StreamType The I/O stream class type to wrap. It must be a concrete |
356 | + * stream class. |
357 | + */ |
358 | +template<class StreamType> |
359 | +class stream : public StreamType { |
360 | +public: |
361 | + /** |
362 | + * Constructs a %base64::stream. |
363 | + */ |
364 | + stream() : |
365 | +#ifdef WIN32 |
366 | +# pragma warning( push ) |
367 | +# pragma warning( disable : 4355 ) |
368 | +#endif /* WIN32 */ |
369 | + b64buf_( this->rdbuf() ) |
370 | +#ifdef WIN32 |
371 | +# pragma warning( pop ) |
372 | +#endif /* WIN32 */ |
373 | + { |
374 | + init(); |
375 | + } |
376 | + |
377 | + /** |
378 | + * Constructs a %stream. |
379 | + * |
380 | + * @tparam StreamArgType The type of the first argument of \a StreamType's |
381 | + * constructor. |
382 | + * @param stream_arg The argument to pass as the first argument to |
383 | + * \a StreamType's constructor. |
384 | + */ |
385 | + template<typename StreamArgType> |
386 | + stream( StreamArgType stream_arg ) : |
387 | + StreamType( stream_arg ), |
388 | +#ifdef WIN32 |
389 | +# pragma warning( push ) |
390 | +# pragma warning( disable : 4355 ) |
391 | +#endif /* WIN32 */ |
392 | + b64buf_( this->rdbuf() ) |
393 | +#ifdef WIN32 |
394 | +# pragma warning( pop ) |
395 | +#endif /* WIN32 */ |
396 | + { |
397 | + init(); |
398 | + } |
399 | + |
400 | + /** |
401 | + * Constructs a %base64::stream. |
402 | + * |
403 | + * @tparam StreamArgType The type of the first argument of \a StreamType's |
404 | + * constructor. |
405 | + * @param stream_arg The argument to pass as the first argument to |
406 | + * \a StreamType's constructor. |
407 | + * @param mode The open-mode to pass to \a StreamType's constructor. |
408 | + */ |
409 | + template<typename StreamArgType> |
410 | + stream( StreamArgType stream_arg, std::ios_base::openmode mode ) : |
411 | + StreamType( stream_arg, mode ), |
412 | +#ifdef WIN32 |
413 | +# pragma warning( push ) |
414 | +# pragma warning( disable : 4355 ) |
415 | +#endif /* WIN32 */ |
416 | + b64buf_( this->rdbuf() ) |
417 | +#ifdef WIN32 |
418 | +# pragma warning( pop ) |
419 | +#endif /* WIN32 */ |
420 | + { |
421 | + init(); |
422 | + } |
423 | + |
424 | +private: |
425 | + streambuf b64buf_; |
426 | + |
427 | + void init() { |
428 | + this->std::ios::rdbuf( &b64buf_ ); |
429 | + } |
430 | +}; |
431 | + |
432 | +/////////////////////////////////////////////////////////////////////////////// |
433 | + |
434 | +} // namespace base64 |
435 | +} // namespace zorba |
436 | +#endif /* ZORBA_BASE64_STREAM_API_H */ |
437 | +/* vim:set et sw=2 ts=2: */ |
438 | |
439 | === modified file 'include/zorba/internal/diagnostic.h' |
440 | --- include/zorba/internal/diagnostic.h 2012-06-18 10:06:47 +0000 |
441 | +++ include/zorba/internal/diagnostic.h 2012-06-26 01:34:26 +0000 |
442 | @@ -42,7 +42,7 @@ |
443 | /////////////////////////////////////////////////////////////////////////////// |
444 | |
445 | /** |
446 | - * A %location hold the file location of an error. |
447 | + * A %location holds the file location of an error. |
448 | */ |
449 | class ZORBA_DLL_PUBLIC location { |
450 | public: |
451 | @@ -71,21 +71,17 @@ |
452 | * Constructs a %location. |
453 | * |
454 | * @param file The name of the file where the error occurred. |
455 | - * @param line The line number of the file where the expression that |
456 | - * raises the error begins. |
457 | + * @param line The line number of the file where the expression that raises |
458 | + * the error begins. |
459 | * @param column The column number, if any, of the file where the expression |
460 | - * that raises the error begins. |
461 | - * @param line_end The end line number, if any, of the file where the expression |
462 | - * causing the error ends. |
463 | - * @param column_end The end column number, if any, of the file where |
464 | - * the xpression causing the error ends. |
465 | + * that raises the error begins. |
466 | + * @param line_end The end line number, if any, of the file where the |
467 | + * expression causing the error ends. |
468 | + * @param column_end The end column number, if any, of the file where the |
469 | + * xpression causing the error ends. |
470 | */ |
471 | - location( |
472 | - char const *file, |
473 | - line_type line, |
474 | - column_type column = 0, |
475 | - line_type line_end = 0, |
476 | - column_type column_end = 0) : |
477 | + location( char const *file, line_type line, column_type column = 0, |
478 | + line_type line_end = 0, column_type column_end = 0 ) : |
479 | file_( file ), line_( line ), column_( column ), |
480 | line_end_( line_end ), column_end_( column_end ) |
481 | { |
482 | @@ -97,19 +93,16 @@ |
483 | * @tparam StringType The string type for \a file. |
484 | * @param file The name of the file where the error occurred. |
485 | * @param line The line number of the file where the error occurred. |
486 | - * @param column The column number, if any, of the file where the error occurred. |
487 | - * @param line_end The end line number, if any, of the file where the expression |
488 | - * causing the error ends. |
489 | - * @param column_end The end column number, if any, of the file where |
490 | - * the xpression causing the error ends. |
491 | + * @param column The column number, if any, of the file where the error |
492 | + * occurred. |
493 | + * @param line_end The end line number, if any, of the file where the |
494 | + * expression causing the error ends. |
495 | + * @param column_end The end column number, if any, of the file where the |
496 | + * xpression causing the error ends. |
497 | */ |
498 | template<class StringType> |
499 | - location( |
500 | - StringType const &file, |
501 | - line_type line, |
502 | - column_type column = 0, |
503 | - line_type line_end = 0, |
504 | - column_type column_end = 0) : |
505 | + location( StringType const &file, line_type line, column_type column = 0, |
506 | + line_type line_end = 0, column_type column_end = 0 ) : |
507 | file_( file.c_str() ), line_( line ), column_( column ), |
508 | line_end_( line_end ), column_end_( column_end ) |
509 | { |
510 | @@ -189,12 +182,8 @@ |
511 | * @param column_end The column number, if any, where the error ends. |
512 | * occurred. |
513 | */ |
514 | - void set( |
515 | - char const *file, |
516 | - line_type line, |
517 | - column_type column = 0, |
518 | - line_type line_end = 0, |
519 | - column_type column_end = 0) { |
520 | + void set( char const *file, line_type line, column_type column = 0, |
521 | + line_type line_end = 0, column_type column_end = 0 ) { |
522 | file_ = file; |
523 | line_ = line; |
524 | column_ = column; |
525 | |
526 | === added file 'include/zorba/internal/streambuf.h' |
527 | --- include/zorba/internal/streambuf.h 1970-01-01 00:00:00 +0000 |
528 | +++ include/zorba/internal/streambuf.h 2012-06-26 01:34:26 +0000 |
529 | @@ -0,0 +1,40 @@ |
530 | +/* |
531 | + * Copyright 2006-2008 The FLWOR Foundation. |
532 | + * |
533 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
534 | + * you may not use this file except in compliance with the License. |
535 | + * You may obtain a copy of the License at |
536 | + * |
537 | + * http://www.apache.org/licenses/LICENSE-2.0 |
538 | + * |
539 | + * Unless required by applicable law or agreed to in writing, software |
540 | + * distributed under the License is distributed on an "AS IS" BASIS, |
541 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
542 | + * See the License for the specific language governing permissions and |
543 | + * limitations under the License. |
544 | + */ |
545 | + |
546 | +#ifndef ZORBA_INTERNAL_STREAMBUF_H |
547 | +#define ZORBA_INTERNAL_STREAMBUF_H |
548 | + |
549 | +#include <streambuf> |
550 | + |
551 | +#include <zorba/config.h> |
552 | + |
553 | +namespace zorba { |
554 | +namespace internal { |
555 | + |
556 | +/////////////////////////////////////////////////////////////////////////////// |
557 | + |
558 | +ZORBA_DLL_PUBLIC |
559 | +void dealloc_streambuf( std::streambuf* ); |
560 | + |
561 | +ZORBA_DLL_PUBLIC |
562 | +void stream_callback( std::ios_base::event, std::ios_base&, int index ); |
563 | + |
564 | +/////////////////////////////////////////////////////////////////////////////// |
565 | + |
566 | +} // namespace internal |
567 | +} // namespace zorba |
568 | +#endif /* ZORBA_INTERNAL_STREAMBUF_H */ |
569 | +/* vim:set et sw=2 ts=2: */ |
570 | |
571 | === modified file 'include/zorba/transcode_stream.h' |
572 | --- include/zorba/transcode_stream.h 2012-06-18 10:06:47 +0000 |
573 | +++ include/zorba/transcode_stream.h 2012-06-26 01:34:26 +0000 |
574 | @@ -19,10 +19,10 @@ |
575 | |
576 | #include <stdexcept> |
577 | #include <streambuf> |
578 | -#include <string> |
579 | |
580 | #include <zorba/config.h> |
581 | #include <zorba/internal/proxy.h> |
582 | +#include <zorba/internal/streambuf.h> |
583 | #include <zorba/internal/unique_ptr.h> |
584 | |
585 | namespace zorba { |
586 | @@ -120,20 +120,15 @@ |
587 | } // namespace transcode |
588 | |
589 | namespace internal { |
590 | - |
591 | -ZORBA_DLL_PUBLIC |
592 | -zorba::transcode::streambuf* |
593 | -alloc_streambuf( char const *charset, std::streambuf *orig ); |
594 | - |
595 | -ZORBA_DLL_PUBLIC |
596 | -void dealloc_streambuf( zorba::transcode::streambuf* ); |
597 | +namespace transcode { |
598 | + |
599 | +ZORBA_DLL_PUBLIC |
600 | +std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig ); |
601 | |
602 | ZORBA_DLL_PUBLIC |
603 | int get_streambuf_index(); |
604 | |
605 | -ZORBA_DLL_PUBLIC |
606 | -void stream_callback( std::ios_base::event, std::ios_base&, int index ); |
607 | - |
608 | +} // transcode |
609 | } // namespace internal |
610 | |
611 | namespace transcode { |
612 | @@ -153,10 +148,11 @@ |
613 | */ |
614 | template<typename charT,typename Traits> inline |
615 | void attach( std::basic_ios<charT,Traits> &ios, char const *charset ) { |
616 | - int const index = internal::get_streambuf_index(); |
617 | + int const index = internal::transcode::get_streambuf_index(); |
618 | void *&pword = ios.pword( index ); |
619 | if ( !pword ) { |
620 | - streambuf *const buf = internal::alloc_streambuf( charset, ios.rdbuf() ); |
621 | + std::streambuf *const buf = |
622 | + internal::transcode::alloc_streambuf( charset, ios.rdbuf() ); |
623 | ios.rdbuf( buf ); |
624 | pword = buf; |
625 | ios.register_callback( internal::stream_callback, index ); |
626 | @@ -173,7 +169,7 @@ |
627 | */ |
628 | template<typename charT,typename Traits> inline |
629 | void detach( std::basic_ios<charT,Traits> &ios ) { |
630 | - int const index = internal::get_streambuf_index(); |
631 | + int const index = internal::transcode::get_streambuf_index(); |
632 | if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) { |
633 | ios.pword( index ) = 0; |
634 | ios.rdbuf( buf->orig_streambuf() ); |
635 | @@ -189,7 +185,7 @@ |
636 | */ |
637 | template<typename charT,typename Traits> inline |
638 | bool is_attached( std::basic_ios<charT,Traits> &ios ) { |
639 | - return !!ios.pword( internal::get_streambuf_index() ); |
640 | + return !!ios.pword( internal::transcode::get_streambuf_index() ); |
641 | } |
642 | |
643 | /** |
644 | |
645 | === modified file 'src/api/CMakeLists.txt' |
646 | --- src/api/CMakeLists.txt 2012-06-18 10:06:47 +0000 |
647 | +++ src/api/CMakeLists.txt 2012-06-26 01:34:26 +0000 |
648 | @@ -49,6 +49,7 @@ |
649 | fileimpl.cpp |
650 | serializerimpl.cpp |
651 | base64impl.cpp |
652 | + base64_streambuf.cpp |
653 | uriimpl.cpp |
654 | uriresolverimpl.cpp |
655 | uri_resolver_wrappers.cpp |
656 | @@ -56,6 +57,7 @@ |
657 | zorba_functions.cpp |
658 | annotationimpl.cpp |
659 | auditimpl.cpp |
660 | + streambuf.cpp |
661 | transcode_streambuf.cpp |
662 | ) |
663 | |
664 | |
665 | === added file 'src/api/base64_streambuf.cpp' |
666 | --- src/api/base64_streambuf.cpp 1970-01-01 00:00:00 +0000 |
667 | +++ src/api/base64_streambuf.cpp 2012-06-26 01:34:26 +0000 |
668 | @@ -0,0 +1,249 @@ |
669 | +/* |
670 | + * Copyright 2006-2008 The FLWOR Foundation. |
671 | + * |
672 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
673 | + * you may not use this file except in compliance with the License. |
674 | + * You may obtain a copy of the License at |
675 | + * |
676 | + * http://www.apache.org/licenses/LICENSE-2.0 |
677 | + * |
678 | + * Unless required by applicable law or agreed to in writing, software |
679 | + * distributed under the License is distributed on an "AS IS" BASIS, |
680 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
681 | + * See the License for the specific language governing permissions and |
682 | + * limitations under the License. |
683 | + */ |
684 | + |
685 | +#include "stdafx.h" |
686 | + |
687 | +#include <stdexcept> |
688 | + |
689 | +//#define ZORBA_DEBUG_BASE64_STREAMBUF |
690 | +#ifdef ZORBA_DEBUG_BASE64_STREAMBUF |
691 | +# include <stdio.h> |
692 | +#endif |
693 | + |
694 | +#include <zorba/base64_stream.h> |
695 | + |
696 | +#include "util/base64_util.h" |
697 | + |
698 | +using namespace std; |
699 | + |
700 | +namespace zorba { |
701 | +namespace base64 { |
702 | + |
703 | +int const Large_External_Buf_Size = 4096; // must be a multiple of 4 |
704 | + |
705 | +/////////////////////////////////////////////////////////////////////////////// |
706 | + |
707 | +inline void streambuf::resetg() { |
708 | + setg( gbuf_, gbuf_ + sizeof gbuf_, gbuf_ + sizeof gbuf_ ); |
709 | +} |
710 | + |
711 | +inline void streambuf::resetp() { |
712 | + plen_ = 0; |
713 | +} |
714 | + |
715 | +inline void streambuf::writep() { |
716 | + char chunk[4]; |
717 | + orig_buf_->sputn( chunk, base64::encode( pbuf_, plen_, chunk ) ); |
718 | +} |
719 | + |
720 | +streambuf::streambuf( std::streambuf *orig ) : orig_buf_( orig ) { |
721 | + if ( !orig ) |
722 | + throw invalid_argument( "null streambuf" ); |
723 | + clear(); |
724 | +} |
725 | + |
726 | +streambuf::~streambuf() { |
727 | + if ( plen_ ) |
728 | + writep(); |
729 | +} |
730 | + |
731 | +void streambuf::clear() { |
732 | + resetg(); |
733 | + resetp(); |
734 | +} |
735 | + |
736 | +void streambuf::imbue( std::locale const &loc ) { |
737 | + orig_buf_->pubimbue( loc ); |
738 | +} |
739 | + |
740 | +streambuf::pos_type streambuf::seekoff( off_type o, ios_base::seekdir d, |
741 | + ios_base::openmode m ) { |
742 | + clear(); |
743 | + return orig_buf_->pubseekoff( o, d, m ); |
744 | +} |
745 | + |
746 | +streambuf::pos_type streambuf::seekpos( pos_type p, ios_base::openmode m ) { |
747 | + clear(); |
748 | + return orig_buf_->pubseekpos( p, m ); |
749 | +} |
750 | + |
751 | +std::streambuf* streambuf::setbuf( char_type *p, streamsize s ) { |
752 | + orig_buf_->pubsetbuf( p, s ); |
753 | + return this; |
754 | +} |
755 | + |
756 | +streamsize streambuf::showmanyc() { |
757 | + return orig_buf_->in_avail(); |
758 | +} |
759 | + |
760 | +int streambuf::sync() { |
761 | + if ( plen_ ) |
762 | + writep(); |
763 | + return orig_buf_->pubsync(); |
764 | +} |
765 | + |
766 | +streambuf::int_type streambuf::overflow( int_type c ) { |
767 | +#ifdef ZORBA_DEBUG_BASE64_STREAMBUF |
768 | + printf( "overflow()\n" ); |
769 | +#endif |
770 | + bool const is_eof = traits_type::eq_int_type( c, traits_type::eof() ); |
771 | + if ( !is_eof ) |
772 | + pbuf_[ plen_++ ] = traits_type::to_char_type( c ); |
773 | + if ( plen_ == sizeof pbuf_ || (is_eof && plen_) ) { |
774 | + writep(); |
775 | + resetp(); |
776 | + } |
777 | + return c; |
778 | +} |
779 | + |
780 | +streambuf::int_type streambuf::pbackfail( int_type c ) { |
781 | + if ( gptr() > eback() ) |
782 | + gbump( -1 ); |
783 | + return orig_buf_->sputbackc( traits_type::to_char_type( c ) ); |
784 | +} |
785 | + |
786 | +streambuf::int_type streambuf::underflow() { |
787 | +#ifdef ZORBA_DEBUG_BASE64_STREAMBUF |
788 | + printf( "underflow()\n" ); |
789 | +#endif |
790 | + char chunk[4]; |
791 | + int chunk_len = 0; |
792 | + |
793 | + while ( gptr() >= egptr() ) { |
794 | + int_type const c = orig_buf_->sbumpc(); |
795 | + bool is_eof = false; |
796 | + if ( traits_type::eq_int_type( c, traits_type::eof() ) ) { |
797 | + if ( !chunk_len ) |
798 | + return traits_type::eof(); |
799 | + is_eof = true; |
800 | + } else { |
801 | + chunk[ chunk_len++ ] = traits_type::to_char_type( c ); |
802 | + } |
803 | + if ( chunk_len == sizeof chunk || (is_eof && chunk_len) ) { |
804 | + streamsize const n = base64::decode( chunk, chunk_len, eback() ); |
805 | + setg( gbuf_, gbuf_, gbuf_ + n ); |
806 | + } |
807 | + } |
808 | + return traits_type::to_int_type( *gptr() ); |
809 | +} |
810 | + |
811 | +streamsize streambuf::xsgetn( char_type *to, streamsize size ) { |
812 | +#ifdef ZORBA_DEBUG_BASE64_STREAMBUF |
813 | + printf( "xsgetn()\n" ); |
814 | +#endif |
815 | + streamsize return_size = 0; |
816 | + |
817 | + if ( streamsize const gsize = egptr() - gptr() ) { |
818 | + // |
819 | + // Get any chunk fragment pending the the get buffer first. |
820 | + // |
821 | + streamsize const n = min( gsize, size ); |
822 | + traits_type::copy( to, gptr(), n ); |
823 | + gbump( n ); |
824 | + to += n; |
825 | + size -= n, return_size += n; |
826 | + } |
827 | + |
828 | + // |
829 | + // Must get bytes in terms of encoded size. |
830 | + // |
831 | + size = base64::encoded_size( size ); |
832 | + |
833 | + while ( size ) { |
834 | + char ebuf[ Large_External_Buf_Size ]; |
835 | + streamsize const get = min( (streamsize)(sizeof ebuf), size ); |
836 | + if ( streamsize got = orig_buf_->sgetn( ebuf, get ) ) { |
837 | + streamsize const decoded = base64::decode( ebuf, got, to ); |
838 | + to += decoded; |
839 | + size -= got, return_size += decoded; |
840 | + } else |
841 | + break; |
842 | + } |
843 | + |
844 | + return return_size; |
845 | +} |
846 | + |
847 | +streamsize streambuf::xsputn( char_type const *from, streamsize size ) { |
848 | +#ifdef ZORBA_DEBUG_BASE64_STREAMBUF |
849 | + printf( "xsputn()\n" ); |
850 | +#endif |
851 | + streamsize return_size = 0; |
852 | + |
853 | + // |
854 | + // Put any chunk fragment pending in the put buffer by completing it first. |
855 | + // |
856 | + while ( plen_ && size ) { |
857 | + overflow( *from ); |
858 | + ++from, --size, ++return_size; |
859 | + } |
860 | + |
861 | + while ( size >= 3 ) { |
862 | + char ebuf[ Large_External_Buf_Size ]; |
863 | + streamsize const put = min( (streamsize)(sizeof ebuf), size ); |
864 | + streamsize const encoded = base64::encode( from, put, ebuf ); |
865 | + orig_buf_->sputn( ebuf, encoded ); |
866 | + from += put, size -= put, return_size += put; |
867 | + } |
868 | + |
869 | + // |
870 | + // Put any remaining chunk fragment into the put buffer. |
871 | + // |
872 | + if ( size ) { |
873 | + traits_type::copy( pbuf_, from, size ); |
874 | + plen_ = size; |
875 | + } |
876 | + |
877 | + return return_size; |
878 | +} |
879 | + |
880 | +/////////////////////////////////////////////////////////////////////////////// |
881 | + |
882 | +} // namespace base64 |
883 | + |
884 | +namespace internal { |
885 | +namespace base64 { |
886 | + |
887 | +// Both new & delete are done inside Zorba rather than in the header to |
888 | +// guarantee that they're cross-DLL-boundary safe on Windows. |
889 | + |
890 | +std::streambuf* alloc_streambuf( std::streambuf *orig ) { |
891 | + return new zorba::base64::streambuf( orig ); |
892 | +} |
893 | + |
894 | +int get_streambuf_index() { |
895 | + // |
896 | + // This function is out-of-line because it has a static constant within it. |
897 | + // It has a static constant within it to guarantee (1) initialization before |
898 | + // use and (2) initialization happens exactly once. |
899 | + // |
900 | + // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and |
901 | + // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section |
902 | + // 3.3.1.1: "Initializing and Maintaining the iword/pword Index." |
903 | + // |
904 | + // See: "The C++ Programming Language," Bjarne Stroustrup, Addison-Wesley, |
905 | + // 2000, section 10.4.8: "Local Static Store." |
906 | + // |
907 | + static int const index = ios_base::xalloc(); |
908 | + return index; |
909 | +} |
910 | + |
911 | +} // namespace base64 |
912 | +} // namespace internal |
913 | + |
914 | +/////////////////////////////////////////////////////////////////////////////// |
915 | + |
916 | +} // namespace zorba |
917 | +/* vim:set et sw=2 ts=2: */ |
918 | |
919 | === modified file 'src/api/base64impl.cpp' |
920 | --- src/api/base64impl.cpp 2012-06-18 10:06:47 +0000 |
921 | +++ src/api/base64impl.cpp 2012-06-26 01:34:26 +0000 |
922 | @@ -17,45 +17,70 @@ |
923 | |
924 | #include <sstream> |
925 | #include <zorba/base64.h> |
926 | +#include <zorba/diagnostic_list.h> |
927 | |
928 | #include <zorba/config.h> |
929 | #include <zorba/zorba_string.h> |
930 | |
931 | -#include "zorbatypes/binary.h" |
932 | +#include "diagnostics/dict.h" |
933 | +#include "diagnostics/xquery_exception.h" |
934 | +#include "util/base64_util.h" |
935 | |
936 | +#define CATCH_BASE64_EXCEPTION() \ |
937 | + catch ( base64::exception const &e ) { \ |
938 | + throw XQUERY_EXCEPTION( \ |
939 | + err::FORG0001, ERROR_PARAMS( e.invalid_char(), ZED( Base64BadChar ) ) \ |
940 | + ); \ |
941 | + } \ |
942 | + catch ( std::invalid_argument const& ) { \ |
943 | + throw XQUERY_EXCEPTION( \ |
944 | + err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) ) \ |
945 | + ); \ |
946 | + } |
947 | |
948 | namespace zorba { |
949 | namespace encoding { |
950 | |
951 | String Base64::encode(const String& aString) |
952 | { |
953 | - std::stringstream lStream; |
954 | - lStream << aString; |
955 | - |
956 | - return encode(lStream); |
957 | + String result; |
958 | + base64::encode( aString.data(), aString.size(), &result ); |
959 | + return result; |
960 | } |
961 | |
962 | |
963 | String Base64::encode(std::istream& aStream) |
964 | { |
965 | - return zorba::Base64::encode(aStream).str(); |
966 | + String result; |
967 | + base64::encode( aStream, &result ); |
968 | + return result; |
969 | } |
970 | |
971 | |
972 | String Base64::decode(const String& aString) |
973 | { |
974 | - std::stringstream lStream; |
975 | - lStream << aString; |
976 | - return decode(lStream); |
977 | + try { |
978 | + String result; |
979 | + base64::decode( |
980 | + aString.data(), aString.size(), &result, base64::dopt_ignore_ws |
981 | + ); |
982 | + return result; |
983 | + } |
984 | + CATCH_BASE64_EXCEPTION() |
985 | } |
986 | |
987 | |
988 | String Base64::decode(std::istream& aStream) |
989 | { |
990 | - return zorba::Base64::decode(aStream).str(); |
991 | + try { |
992 | + String result; |
993 | + base64::decode( aStream, &result, base64::dopt_ignore_ws ); |
994 | + return result; |
995 | + } |
996 | + CATCH_BASE64_EXCEPTION() |
997 | } |
998 | |
999 | |
1000 | -} /* end namespace encoding */ |
1001 | -} /* end namespace zorba */ |
1002 | +} // namespace encoding |
1003 | +} // namespace zorba |
1004 | /* vim:set et sw=2 ts=2: */ |
1005 | |
1006 | === modified file 'src/api/serialization/serializer.cpp' |
1007 | --- src/api/serialization/serializer.cpp 2012-06-18 10:06:47 +0000 |
1008 | +++ src/api/serialization/serializer.cpp 2012-06-26 01:34:26 +0000 |
1009 | @@ -2300,7 +2300,9 @@ |
1010 | std::istream& stream = item->getStream(); |
1011 | if (item->isEncoded()) |
1012 | { |
1013 | - tr << Base64::decode(stream); |
1014 | + zstring decoded; |
1015 | + Base64::decode(stream, &decoded); |
1016 | + tr << decoded; |
1017 | } |
1018 | else |
1019 | { |
1020 | @@ -2322,9 +2324,9 @@ |
1021 | |
1022 | if (item->isEncoded()) |
1023 | { |
1024 | - std::stringstream tmp; |
1025 | - tmp.write(value, len); |
1026 | - tr << Base64::decode(tmp); |
1027 | + zstring decoded; |
1028 | + Base64::decode(value, len, &decoded); |
1029 | + tr << decoded; |
1030 | } |
1031 | else |
1032 | { |
1033 | |
1034 | === added file 'src/api/streambuf.cpp' |
1035 | --- src/api/streambuf.cpp 1970-01-01 00:00:00 +0000 |
1036 | +++ src/api/streambuf.cpp 2012-06-26 01:34:26 +0000 |
1037 | @@ -0,0 +1,48 @@ |
1038 | +/* |
1039 | + * Copyright 2006-2008 The FLWOR Foundation. |
1040 | + * |
1041 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
1042 | + * you may not use this file except in compliance with the License. |
1043 | + * You may obtain a copy of the License at |
1044 | + * |
1045 | + * http://www.apache.org/licenses/LICENSE-2.0 |
1046 | + * |
1047 | + * Unless required by applicable law or agreed to in writing, software |
1048 | + * distributed under the License is distributed on an "AS IS" BASIS, |
1049 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1050 | + * See the License for the specific language governing permissions and |
1051 | + * limitations under the License. |
1052 | + */ |
1053 | + |
1054 | +#include "stdafx.h" |
1055 | +#include <zorba/internal/streambuf.h> |
1056 | + |
1057 | +using namespace std; |
1058 | + |
1059 | +namespace zorba { |
1060 | +namespace internal { |
1061 | + |
1062 | +/////////////////////////////////////////////////////////////////////////////// |
1063 | + |
1064 | +// "delete" is done here inside Zorba rather than in the header to guarantee |
1065 | +// that it's cross-DLL-boundary safe on Windows. |
1066 | + |
1067 | +void dealloc_streambuf( streambuf *buf ) { |
1068 | + delete buf; |
1069 | +} |
1070 | + |
1071 | +void stream_callback( ios_base::event e, ios_base &ios, int index ) { |
1072 | + // |
1073 | + // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and |
1074 | + // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section |
1075 | + // 3.3.1.4: "Using Stream Callbacks for Memory Management." |
1076 | + // |
1077 | + if ( e == ios_base::erase_event ) |
1078 | + delete static_cast<streambuf*>( ios.pword( index ) ); |
1079 | +} |
1080 | + |
1081 | +/////////////////////////////////////////////////////////////////////////////// |
1082 | + |
1083 | +} // namespace internal |
1084 | +} // namespace zorba |
1085 | +/* vim:set et sw=2 ts=2: */ |
1086 | |
1087 | === modified file 'src/api/transcode_streambuf.cpp' |
1088 | --- src/api/transcode_streambuf.cpp 2012-06-18 10:06:47 +0000 |
1089 | +++ src/api/transcode_streambuf.cpp 2012-06-26 01:34:26 +0000 |
1090 | @@ -81,8 +81,7 @@ |
1091 | return proxy_buf_->sgetn( to, size ); |
1092 | } |
1093 | |
1094 | -streamsize streambuf::xsputn( char_type const *from, |
1095 | - streamsize size ) { |
1096 | +streamsize streambuf::xsputn( char_type const *from, streamsize size ) { |
1097 | return proxy_buf_->sputn( from, size ); |
1098 | } |
1099 | |
1100 | @@ -103,19 +102,15 @@ |
1101 | /////////////////////////////////////////////////////////////////////////////// |
1102 | |
1103 | namespace internal { |
1104 | +namespace transcode { |
1105 | |
1106 | // Both new & delete are done here inside Zorba rather than in the header to |
1107 | // guarantee that they're cross-DLL-boundary safe on Windows. |
1108 | |
1109 | -zorba::transcode::streambuf* |
1110 | -alloc_streambuf( char const *charset, std::streambuf *orig ) { |
1111 | +std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig ) { |
1112 | return new zorba::transcode::streambuf( charset, orig ); |
1113 | } |
1114 | |
1115 | -void dealloc_streambuf( zorba::transcode::streambuf *buf ) { |
1116 | - delete buf; |
1117 | -} |
1118 | - |
1119 | int get_streambuf_index() { |
1120 | // |
1121 | // This function is out-of-line because it has a static constant within it. |
1122 | @@ -133,16 +128,7 @@ |
1123 | return index; |
1124 | } |
1125 | |
1126 | -void stream_callback( ios_base::event e, ios_base &ios, int index ) { |
1127 | - // |
1128 | - // See: "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and |
1129 | - // Reference," Angelika Langer and Klaus Kreft, Addison-Wesley, 2000, section |
1130 | - // 3.3.1.4: "Using Stream Callbacks for Memory Management." |
1131 | - // |
1132 | - if ( e == ios_base::erase_event ) |
1133 | - delete static_cast<streambuf*>( ios.pword( index ) ); |
1134 | -} |
1135 | - |
1136 | +} // namespace transcode |
1137 | } // namespace internal |
1138 | |
1139 | /////////////////////////////////////////////////////////////////////////////// |
1140 | |
1141 | === modified file 'src/diagnostics/diagnostic_en.xml' |
1142 | --- src/diagnostics/diagnostic_en.xml 2012-06-18 10:06:47 +0000 |
1143 | +++ src/diagnostics/diagnostic_en.xml 2012-06-26 01:34:26 +0000 |
1144 | @@ -2888,14 +2888,6 @@ |
1145 | <value>invalid Base64 character</value> |
1146 | </entry> |
1147 | |
1148 | - <entry key="Base64Equals"> |
1149 | - <value>in Base64, '=' must be at the end and followed by one of [AEIMQUYcgkosw048]</value> |
1150 | - </entry> |
1151 | - |
1152 | - <entry key="Base64EqualsEquals"> |
1153 | - <value>in Base64, "==" must be at the end and followed by one of [AQgw]</value> |
1154 | - </entry> |
1155 | - |
1156 | <entry key="Base64Multiple4"> |
1157 | <value>Base64 data must be a multiple of 4 characters</value> |
1158 | </entry> |
1159 | |
1160 | === modified file 'src/diagnostics/pregenerated/dict_en.cpp' |
1161 | --- src/diagnostics/pregenerated/dict_en.cpp 2012-06-18 10:06:47 +0000 |
1162 | +++ src/diagnostics/pregenerated/dict_en.cpp 2012-06-26 01:34:26 +0000 |
1163 | @@ -546,8 +546,6 @@ |
1164 | { "~BadXMLNoOpeningTag", "closing tag without matching opening tag" }, |
1165 | { "~BadXQueryVersion", "unsupported XQuery version" }, |
1166 | { "~Base64BadChar", "invalid Base64 character" }, |
1167 | - { "~Base64Equals", "in Base64, '=' must be at the end and followed by one of [AEIMQUYcgkosw048]" }, |
1168 | - { "~Base64EqualsEquals", "in Base64, \"==\" must be at the end and followed by one of [AQgw]" }, |
1169 | { "~Base64Multiple4", "Base64 data must be a multiple of 4 characters" }, |
1170 | { "~BaseURI", "base URI" }, |
1171 | { "~BoxCondTooManyColumns", "box condition has more columns than index" }, |
1172 | |
1173 | === modified file 'src/runtime/base64/base64_impl.cpp' |
1174 | --- src/runtime/base64/base64_impl.cpp 2012-06-18 10:06:47 +0000 |
1175 | +++ src/runtime/base64/base64_impl.cpp 2012-06-26 01:34:26 +0000 |
1176 | @@ -66,7 +66,7 @@ |
1177 | { |
1178 | if (lItem->isEncoded()) |
1179 | { |
1180 | - lResultString = Base64::decode(lItem->getStream()); |
1181 | + Base64::decode(lItem->getStream(), &lResultString); |
1182 | } |
1183 | else |
1184 | { |
1185 | @@ -93,10 +93,7 @@ |
1186 | |
1187 | if (lItem->isEncoded()) |
1188 | { |
1189 | - std::vector<char> encoded(lContent, lContent+lSize); |
1190 | - std::vector<char> decoded; |
1191 | - Base64::decode(encoded, decoded); |
1192 | - lResultString.insert(0, &decoded[0], decoded.size()); |
1193 | + Base64::decode( lContent, lSize, &lResultString ); |
1194 | } |
1195 | else |
1196 | { |
1197 | @@ -156,8 +153,8 @@ |
1198 | // create a base64Binary item |
1199 | // the content is the non-encoded string |
1200 | GENV_ITEMFACTORY->createBase64Binary( |
1201 | - result, lTmpString.c_str(), lTmpString.size(), false |
1202 | - ); |
1203 | + result, lTmpString.c_str(), lTmpString.size(), false |
1204 | + ); |
1205 | STACK_PUSH (true, state); |
1206 | } |
1207 | STACK_END (state); |
1208 | |
1209 | === modified file 'src/unit_tests/CMakeLists.txt' |
1210 | --- src/unit_tests/CMakeLists.txt 2012-06-18 10:06:47 +0000 |
1211 | +++ src/unit_tests/CMakeLists.txt 2012-06-26 01:34:26 +0000 |
1212 | @@ -13,6 +13,8 @@ |
1213 | # limitations under the License. |
1214 | |
1215 | SET(UNIT_TEST_SRCS |
1216 | + test_base64.cpp |
1217 | + test_base64_streambuf.cpp |
1218 | string_instantiate.cpp |
1219 | string.cpp |
1220 | test_uri.cpp |
1221 | |
1222 | === added file 'src/unit_tests/test_base64.cpp' |
1223 | --- src/unit_tests/test_base64.cpp 1970-01-01 00:00:00 +0000 |
1224 | +++ src/unit_tests/test_base64.cpp 2012-06-26 01:34:26 +0000 |
1225 | @@ -0,0 +1,286 @@ |
1226 | +/* |
1227 | + * Copyright 2006-2008 The FLWOR Foundation. |
1228 | + * |
1229 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
1230 | + * you may not use this file except in compliance with the License. |
1231 | + * You may obtain a copy of the License at |
1232 | + * |
1233 | + * http://www.apache.org/licenses/LICENSE-2.0 |
1234 | + * |
1235 | + * Unless required by applicable law or agreed to in writing, software |
1236 | + * distributed under the License is distributed on an "AS IS" BASIS, |
1237 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1238 | + * See the License for the specific language governing permissions and |
1239 | + * limitations under the License. |
1240 | + */ |
1241 | + |
1242 | +#include "stdafx.h" |
1243 | +#include <cstring> |
1244 | +#include <iostream> |
1245 | +#include <sstream> |
1246 | +#include <stdexcept> |
1247 | +#include <string> |
1248 | + |
1249 | +#include "util/base64_util.h" |
1250 | + |
1251 | +using namespace std; |
1252 | +using namespace zorba; |
1253 | + |
1254 | +struct test { |
1255 | + char const *input; |
1256 | + char const *expected; |
1257 | +}; |
1258 | + |
1259 | +/////////////////////////////////////////////////////////////////////////////// |
1260 | + |
1261 | +static int failures; |
1262 | + |
1263 | +static bool assert_true( int no, char const *expr, int line, bool result ) { |
1264 | + if ( !result ) { |
1265 | + cout << '#' << no << " FAILED, line " << line << ": " << expr << endl; |
1266 | + ++failures; |
1267 | + } |
1268 | + return result; |
1269 | +} |
1270 | + |
1271 | +static void print_exception( int no, char const *expr, int line, |
1272 | + std::exception const &e ) { |
1273 | + assert_true( no, expr, line, false ); |
1274 | + cout << "+ exception: " << e.what() << endl; |
1275 | +} |
1276 | + |
1277 | +#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) ) |
1278 | + |
1279 | +#define ASSERT_NO_EXCEPTION( NO, EXPR ) \ |
1280 | + try { EXPR; } \ |
1281 | + catch ( std::exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); } \ |
1282 | + catch ( ... ) { assert_true( NO, #EXPR, __LINE__, false ); } |
1283 | + |
1284 | +#define ASSERT_EXCEPTION( NO, EXPR, EXCEPTION ) \ |
1285 | + try { EXPR; assert_true( NO, #EXPR, __LINE__, false ); } \ |
1286 | + catch ( EXCEPTION const& ) { } |
1287 | + |
1288 | +///////////////////////////////////////////////////////////////////////////////} |
1289 | + |
1290 | +static void test_decode_buf_to_buf( int no, string const &in, |
1291 | + string const &expected ) { |
1292 | + base64::size_type n; |
1293 | + char out[ 1024 ]; |
1294 | + ASSERT_NO_EXCEPTION( |
1295 | + no, n = base64::decode( in.data(), in.size(), out, base64::dopt_any_len ) |
1296 | + ); |
1297 | + ASSERT_TRUE( no, n == expected.size() ); |
1298 | + out[ n ] = '\0'; |
1299 | + ASSERT_TRUE( no, out == expected ); |
1300 | +} |
1301 | + |
1302 | +static void test_decode_buf_to_string( int no, string const &in, |
1303 | + string const &expected ) { |
1304 | + base64::size_type n; |
1305 | + string out; |
1306 | + ASSERT_NO_EXCEPTION( |
1307 | + no, |
1308 | + n = base64::decode( in.data(), in.size(), &out, base64::dopt_any_len ) |
1309 | + ); |
1310 | + ASSERT_TRUE( no, n == expected.size() ); |
1311 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1312 | + ASSERT_TRUE( no, out == expected ); |
1313 | +} |
1314 | + |
1315 | +static void test_decode_buf_to_vector( int no, string const &in, |
1316 | + string const &expected ) { |
1317 | + base64::size_type n; |
1318 | + vector<char> out; |
1319 | + ASSERT_NO_EXCEPTION( |
1320 | + no, |
1321 | + n = base64::decode( in.data(), in.size(), &out, base64::dopt_any_len ) |
1322 | + ); |
1323 | + ASSERT_TRUE( no, n == expected.size() ); |
1324 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1325 | + ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) ); |
1326 | +} |
1327 | + |
1328 | +static void test_decode_stream_to_stream( int no, string const &in, |
1329 | + string const &expected ) { |
1330 | + base64::size_type n; |
1331 | + istringstream sin( in ); |
1332 | + ostringstream sout; |
1333 | + ASSERT_NO_EXCEPTION( |
1334 | + no, n = base64::decode( sin, sout, base64::dopt_any_len ) |
1335 | + ); |
1336 | + ASSERT_TRUE( no, n == expected.size() ); |
1337 | + ASSERT_TRUE( no, sout.str().size() == expected.size() ); |
1338 | + ASSERT_TRUE( no, sout.str() == expected ); |
1339 | +} |
1340 | + |
1341 | +static void test_decode_stream_to_string( int no, string const &in, |
1342 | + string const &expected ) { |
1343 | + base64::size_type n; |
1344 | + istringstream sin( in ); |
1345 | + string out; |
1346 | + ASSERT_NO_EXCEPTION( |
1347 | + no, n = base64::decode( sin, &out, base64::dopt_any_len ) |
1348 | + ); |
1349 | + ASSERT_TRUE( no, n == expected.size() ); |
1350 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1351 | + ASSERT_TRUE( no, out == expected ); |
1352 | +} |
1353 | + |
1354 | +static void test_decode_stream_to_vector( int no, string const &in, |
1355 | + string const &expected ) { |
1356 | + base64::size_type n; |
1357 | + istringstream sin( in ); |
1358 | + vector<char> out; |
1359 | + ASSERT_NO_EXCEPTION( |
1360 | + no, n = base64::decode( sin, &out, base64::dopt_any_len ) |
1361 | + ); |
1362 | + ASSERT_TRUE( no, n == expected.size() ); |
1363 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1364 | + ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) ); |
1365 | +} |
1366 | + |
1367 | +static void test_decode_exception( int no, string const &in ) { |
1368 | + char out[ 1024 ]; |
1369 | + ASSERT_EXCEPTION( |
1370 | + no, base64::decode( in.data(), in.size(), out ), invalid_argument |
1371 | + ); |
1372 | +} |
1373 | + |
1374 | +/////////////////////////////////////////////////////////////////////////////// |
1375 | + |
1376 | +static void test_encode_buf_to_buf( int no, string const &in, |
1377 | + string const &expected ) { |
1378 | + char out[ 1024 ]; |
1379 | + base64::size_type const n = base64::encode( in.data(), in.size(), out ); |
1380 | + ASSERT_TRUE( no, n == expected.size() ); |
1381 | + out[ n ] = '\0'; |
1382 | + ASSERT_TRUE( no, out == expected ); |
1383 | +} |
1384 | + |
1385 | +static void test_encode_buf_to_string( int no, string const &in, |
1386 | + string const &expected ) { |
1387 | + base64::size_type n; |
1388 | + string out; |
1389 | + ASSERT_NO_EXCEPTION( no, n = base64::encode( in.data(), in.size(), &out ) ); |
1390 | + ASSERT_TRUE( no, n == expected.size() ); |
1391 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1392 | + ASSERT_TRUE( no, out == expected ); |
1393 | +} |
1394 | + |
1395 | +static void test_encode_buf_to_vector( int no, string const &in, |
1396 | + string const &expected ) { |
1397 | + base64::size_type n; |
1398 | + vector<char> out; |
1399 | + ASSERT_NO_EXCEPTION( no, n = base64::encode( in.data(), in.size(), &out ) ); |
1400 | + ASSERT_TRUE( no, n == expected.size() ); |
1401 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1402 | + ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) ); |
1403 | +} |
1404 | + |
1405 | +static void test_encode_stream_to_stream( int no, string const &in, |
1406 | + string const &expected ) { |
1407 | + base64::size_type n; |
1408 | + istringstream sin( in ); |
1409 | + ostringstream sout; |
1410 | + ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, sout ) ); |
1411 | + ASSERT_TRUE( no, n == expected.size() ); |
1412 | + ASSERT_TRUE( no, sout.str().size() == expected.size() ); |
1413 | + ASSERT_TRUE( no, sout.str() == expected ); |
1414 | +} |
1415 | + |
1416 | +static void test_encode_stream_to_string( int no, string const &in, |
1417 | + string const &expected ) { |
1418 | + base64::size_type n; |
1419 | + istringstream sin( in ); |
1420 | + string out; |
1421 | + ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, &out ) ); |
1422 | + ASSERT_TRUE( no, n == expected.size() ); |
1423 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1424 | + ASSERT_TRUE( no, out == expected ); |
1425 | +} |
1426 | + |
1427 | +static void test_encode_stream_to_vector( int no, string const &in, |
1428 | + string const &expected ) { |
1429 | + base64::size_type n; |
1430 | + istringstream sin( in ); |
1431 | + vector<char> out; |
1432 | + ASSERT_NO_EXCEPTION( no, n = base64::encode( sin, &out ) ); |
1433 | + ASSERT_TRUE( no, n == expected.size() ); |
1434 | + ASSERT_TRUE( no, out.size() == expected.size() ); |
1435 | + ASSERT_TRUE( no, !strncmp( &out[0], expected.data(), expected.size() ) ); |
1436 | +} |
1437 | + |
1438 | +/////////////////////////////////////////////////////////////////////////////// |
1439 | + |
1440 | +static test const encode_tests[] = { |
1441 | + /* 0 */ { "Now is the time", "Tm93IGlzIHRoZSB0aW1l" }, |
1442 | + /* 1 */ { "Now is the time.", "Tm93IGlzIHRoZSB0aW1lLg==" }, |
1443 | + /* 2 */ { "Now is the time..", "Tm93IGlzIHRoZSB0aW1lLi4=" }, |
1444 | + |
1445 | + { 0, 0 } |
1446 | +}; |
1447 | + |
1448 | +static test const decode_tests[] = { |
1449 | + /* 3 */ { "Tm93IGlzIHRoZSB0aW1l", "Now is the time" }, |
1450 | + /* 4 */ { "Tm93IGlzIHRoZSB0aW1lLg==", "Now is the time." }, |
1451 | + /* 5 */ { "Tm93IGlzIHRoZSB0aW1lLi4=", "Now is the time.." }, |
1452 | + |
1453 | + // incomplete Base64 encodings |
1454 | + /* 6 */ { "Tm93IGlzIHRoZSB0aW1", "Now is the tim" }, |
1455 | + /* 7 */ { "Tm93IGlzIHRoZSB0aW", "Now is the ti" }, |
1456 | + /* 8 */ { "Tm93IGlzIHRoZSB0a", "Now is the t" }, |
1457 | + |
1458 | + { 0, 0 } |
1459 | +}; |
1460 | + |
1461 | +static char const *const decode_exception_tests[] = { |
1462 | + "=", |
1463 | + "_m93", |
1464 | + "T_93", |
1465 | + "Tm_3", |
1466 | + "Tm9_", |
1467 | + "=m93", |
1468 | + "T=93", |
1469 | + "Tm=3", |
1470 | + "Tm93=", |
1471 | + "ZmX=", |
1472 | + "ZX==", |
1473 | + "ZX===", |
1474 | + 0 |
1475 | +}; |
1476 | + |
1477 | +namespace zorba { |
1478 | +namespace UnitTests { |
1479 | + |
1480 | +int test_base64( int, char*[] ) { |
1481 | + int test_no = 0; |
1482 | + |
1483 | + for ( test const *t = encode_tests; t->input; ++t, ++test_no ) { |
1484 | + test_encode_buf_to_buf( test_no, t->input, t->expected ); |
1485 | + test_encode_buf_to_string( test_no, t->input, t->expected ); |
1486 | + test_encode_buf_to_vector( test_no, t->input, t->expected ); |
1487 | + test_encode_stream_to_stream( test_no, t->input, t->expected ); |
1488 | + test_encode_stream_to_string( test_no, t->input, t->expected ); |
1489 | + test_encode_stream_to_vector( test_no, t->input, t->expected ); |
1490 | + } |
1491 | + |
1492 | + for ( test const *t = decode_tests; t->input; ++t, ++test_no ) { |
1493 | + test_decode_buf_to_buf( test_no, t->input, t->expected ); |
1494 | + test_decode_buf_to_string( test_no, t->input, t->expected ); |
1495 | + test_decode_buf_to_vector( test_no, t->input, t->expected ); |
1496 | + test_decode_stream_to_stream( test_no, t->input, t->expected ); |
1497 | + test_decode_stream_to_string( test_no, t->input, t->expected ); |
1498 | + test_decode_stream_to_vector( test_no, t->input, t->expected ); |
1499 | + } |
1500 | + |
1501 | + for ( char const *const *t = decode_exception_tests; *t; ++t, ++test_no ) |
1502 | + test_decode_exception( test_no, *t ); |
1503 | + |
1504 | + cout << failures << " test(s) failed\n"; |
1505 | + return failures ? 1 : 0; |
1506 | +} |
1507 | + |
1508 | +} // namespace UnitTests |
1509 | +} // namespace zorba |
1510 | + |
1511 | +/* vim:set et sw=2 ts=2: */ |
1512 | |
1513 | === added file 'src/unit_tests/test_base64_streambuf.cpp' |
1514 | --- src/unit_tests/test_base64_streambuf.cpp 1970-01-01 00:00:00 +0000 |
1515 | +++ src/unit_tests/test_base64_streambuf.cpp 2012-06-26 01:34:26 +0000 |
1516 | @@ -0,0 +1,141 @@ |
1517 | +/* |
1518 | + * Copyright 2006-2008 The FLWOR Foundation. |
1519 | + * |
1520 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
1521 | + * you may not use this file except in compliance with the License. |
1522 | + * You may obtain a copy of the License at |
1523 | + * |
1524 | + * http://www.apache.org/licenses/LICENSE-2.0 |
1525 | + * |
1526 | + * Unless required by applicable law or agreed to in writing, software |
1527 | + * distributed under the License is distributed on an "AS IS" BASIS, |
1528 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1529 | + * See the License for the specific language governing permissions and |
1530 | + * limitations under the License. |
1531 | + */ |
1532 | + |
1533 | +#include "stdafx.h" |
1534 | +#include <fstream> |
1535 | +#include <iostream> |
1536 | +#include <sstream> |
1537 | + |
1538 | +#include <zorba/base64_stream.h> |
1539 | + |
1540 | +using namespace std; |
1541 | +using namespace zorba; |
1542 | + |
1543 | +struct test { |
1544 | + char const *raw_str; |
1545 | + char const *b64_str; |
1546 | +}; |
1547 | + |
1548 | +/////////////////////////////////////////////////////////////////////////////// |
1549 | + |
1550 | +static int failures; |
1551 | + |
1552 | +static bool assert_true( int no, char const *expr, int line, bool result ) { |
1553 | + if ( !result ) { |
1554 | + cout << '#' << no << " FAILED, line " << line << ": " << expr << endl; |
1555 | + ++failures; |
1556 | + } |
1557 | + return result; |
1558 | +} |
1559 | + |
1560 | +static void print_exception( int no, char const *expr, int line, |
1561 | + std::exception const &e ) { |
1562 | + assert_true( no, expr, line, false ); |
1563 | + cout << "+ exception: " << e.what() << endl; |
1564 | +} |
1565 | + |
1566 | +#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) ) |
1567 | + |
1568 | +#define ASSERT_TRUE_AND_NO_EXCEPTION( NO, EXPR ) \ |
1569 | + try { ASSERT_TRUE( NO, EXPR ); } \ |
1570 | + catch ( std::exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); } |
1571 | + |
1572 | +/////////////////////////////////////////////////////////////////////////////// |
1573 | + |
1574 | +static bool test_getline( test const *t ) { |
1575 | + string const b64_str( t->b64_str ); |
1576 | + istringstream iss( b64_str ); |
1577 | + base64::streambuf b64_sbuf( iss.rdbuf() ); |
1578 | + iss.ios::rdbuf( &b64_sbuf ); |
1579 | + |
1580 | + char raw_buf[ 1024 ]; |
1581 | + iss.getline( raw_buf, sizeof raw_buf ); |
1582 | + if ( iss.gcount() ) { |
1583 | + string const raw_str( raw_buf ); |
1584 | + return raw_str == t->raw_str; |
1585 | + } |
1586 | + return false; |
1587 | +} |
1588 | + |
1589 | +static bool test_read( test const *t ) { |
1590 | + string const b64_str( t->b64_str ); |
1591 | + istringstream iss( b64_str ); |
1592 | + base64::streambuf b64_sbuf( iss.rdbuf() ); |
1593 | + iss.ios::rdbuf( &b64_sbuf ); |
1594 | + |
1595 | + char raw_buf[ 1024 ]; |
1596 | + iss.read( raw_buf, sizeof raw_buf ); |
1597 | + if ( iss.gcount() ) { |
1598 | + string const raw_str( raw_buf, iss.gcount() ); |
1599 | + return raw_str == t->raw_str; |
1600 | + } |
1601 | + return false; |
1602 | +} |
1603 | + |
1604 | +static bool test_insertion( test const *t ) { |
1605 | + ostringstream oss; |
1606 | + base64::streambuf b64_sbuf( oss.rdbuf() ); |
1607 | + oss.ios::rdbuf( &b64_sbuf ); |
1608 | + |
1609 | + oss << t->raw_str << flush; |
1610 | + string const b64_str( oss.str() ); |
1611 | + |
1612 | + string const expected_b64_str( t->b64_str ); |
1613 | + return b64_str == expected_b64_str; |
1614 | +} |
1615 | + |
1616 | +static bool test_put( test const *t ) { |
1617 | + ostringstream oss; |
1618 | + { // local scope |
1619 | + base64::auto_attach<ostringstream> const raii( oss ); |
1620 | + |
1621 | + for ( char const *c = t->raw_str; *c; ++c ) |
1622 | + oss.put( *c ); |
1623 | + } // local scope |
1624 | + string const b64_str( oss.str() ); |
1625 | + |
1626 | + string const expected_b64_str( t->b64_str ); |
1627 | + return b64_str == expected_b64_str; |
1628 | +} |
1629 | + |
1630 | +/////////////////////////////////////////////////////////////////////////////// |
1631 | + |
1632 | +static test const tests[] = { |
1633 | + /* 0 */ { "Now ", "Tm93IA==" }, |
1634 | + /* 1 */ { "Now is the time", "Tm93IGlzIHRoZSB0aW1l" }, |
1635 | + /* 2 */ { "Now is the time.", "Tm93IGlzIHRoZSB0aW1lLg==" }, |
1636 | + /* 3 */ { "Now is the time..", "Tm93IGlzIHRoZSB0aW1lLi4=" }, |
1637 | + { 0, 0 } |
1638 | +}; |
1639 | + |
1640 | +namespace zorba { |
1641 | +namespace UnitTests { |
1642 | + |
1643 | +int test_base64_streambuf( int, char*[] ) { |
1644 | + int test_no = 0; |
1645 | + for ( test const *t = tests; t->raw_str; ++t, ++test_no ) { |
1646 | + ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_getline( t ) ); |
1647 | + ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_read( t ) ); |
1648 | + ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_insertion( t ) ); |
1649 | + ASSERT_TRUE_AND_NO_EXCEPTION( test_no, test_put( t ) ); |
1650 | + } |
1651 | + cout << failures << " test(s) failed\n"; |
1652 | + return failures ? 1 : 0; |
1653 | +} |
1654 | + |
1655 | +} // namespace UnitTests |
1656 | +} // namespace zorba |
1657 | +/* vim:set et sw=2 ts=2: */ |
1658 | |
1659 | === modified file 'src/unit_tests/unit_test_list.h' |
1660 | --- src/unit_tests/unit_test_list.h 2012-06-18 10:06:47 +0000 |
1661 | +++ src/unit_tests/unit_test_list.h 2012-06-26 01:34:26 +0000 |
1662 | @@ -21,24 +21,21 @@ |
1663 | |
1664 | #include <zorba/config.h> |
1665 | |
1666 | -namespace zorba |
1667 | -{ |
1668 | +namespace zorba { |
1669 | +namespace UnitTests { |
1670 | |
1671 | -namespace UnitTests |
1672 | -{ |
1673 | int runUriTest(int argc, char* argv[]); |
1674 | int runDebuggerProtocolTest(int argc, char* argv[]); |
1675 | + int test_base64( int, char*[] ); |
1676 | + int test_base64_streambuf( int, char*[] ); |
1677 | + int test_fs_iterator( int, char*[] ); |
1678 | int test_string( int, char*[] ); |
1679 | int test_unique_ptr( int, char*[] ); |
1680 | - int test_fs_iterator( int, char*[] ); |
1681 | #ifndef ZORBA_NO_FULL_TEXT |
1682 | int test_stemmer( int, char*[] ); |
1683 | int test_thesaurus( int, char*[] ); |
1684 | int test_tokenizer( int, char*[] ); |
1685 | #endif /* ZORBA_NO_FULL_TEXT */ |
1686 | - /** |
1687 | - * ADD NEW UNIT TESTS HERE |
1688 | - */ |
1689 | #ifndef ZORBA_NO_ICU |
1690 | int test_icu_streambuf( int, char*[] ); |
1691 | #endif /* ZORBA_NO_ICU */ |
1692 | @@ -46,9 +43,7 @@ |
1693 | |
1694 | void initializeTestList(); |
1695 | |
1696 | - |
1697 | -}; |
1698 | -} /* namespace zorba */ |
1699 | - |
1700 | +} // namespace UnitTests |
1701 | +} // namespace zorba |
1702 | #endif /* ZORBA_UNIT_TEST_LIST_H */ |
1703 | /* vim:set et sw=2 ts=2: */ |
1704 | |
1705 | === modified file 'src/unit_tests/unit_tests.cpp' |
1706 | --- src/unit_tests/unit_tests.cpp 2012-06-18 10:06:47 +0000 |
1707 | +++ src/unit_tests/unit_tests.cpp 2012-06-26 01:34:26 +0000 |
1708 | @@ -28,9 +28,7 @@ |
1709 | using namespace std; |
1710 | |
1711 | namespace zorba { |
1712 | - |
1713 | -namespace UnitTests |
1714 | -{ |
1715 | +namespace UnitTests { |
1716 | |
1717 | map<string,libunittestfunc> libunittests; |
1718 | |
1719 | @@ -39,14 +37,16 @@ |
1720 | */ |
1721 | void initializeTestList() |
1722 | { |
1723 | + libunittests["base64"] = test_base64; |
1724 | + libunittests["base64_streambuf"] = test_base64_streambuf; |
1725 | + libunittests["fs_iterator"] = test_fs_iterator; |
1726 | + libunittests["json_parser"] = json_parser; |
1727 | libunittests["string"] = test_string; |
1728 | + libunittests["unique_ptr"] = test_unique_ptr; |
1729 | libunittests["uri"] = runUriTest; |
1730 | - libunittests["fs_iterator"] = test_fs_iterator; |
1731 | #ifndef ZORBA_NO_ICU |
1732 | libunittests["icu_streambuf"] = test_icu_streambuf; |
1733 | #endif /* ZORBA_NO_ICU */ |
1734 | - libunittests["json_parser"] = json_parser; |
1735 | - libunittests["unique_ptr"] = test_unique_ptr; |
1736 | #ifndef ZORBA_NO_FULL_TEXT |
1737 | libunittests["stemmer"] = test_stemmer; |
1738 | libunittests["thesaurus"] = test_thesaurus; |
1739 | @@ -78,7 +78,6 @@ |
1740 | } |
1741 | |
1742 | |
1743 | -} /* namespace UnitTests */ |
1744 | -} /* namespace zorba */ |
1745 | - |
1746 | +} // namespace UnitTests |
1747 | +} // namespace zorba |
1748 | /* vim:set et sw=2 ts=2: */ |
1749 | |
1750 | === modified file 'src/util/CMakeLists.txt' |
1751 | --- src/util/CMakeLists.txt 2012-06-18 10:06:47 +0000 |
1752 | +++ src/util/CMakeLists.txt 2012-06-26 01:34:26 +0000 |
1753 | @@ -14,6 +14,7 @@ |
1754 | |
1755 | SET(UTIL_SRCS |
1756 | ascii_util.cpp |
1757 | + base64_util.cpp |
1758 | dynamic_bitset.cpp |
1759 | error_util.cpp |
1760 | file.cpp |
1761 | |
1762 | === modified file 'src/util/ascii_util.cpp' |
1763 | --- src/util/ascii_util.cpp 2012-06-18 10:06:47 +0000 |
1764 | +++ src/util/ascii_util.cpp 2012-06-26 01:34:26 +0000 |
1765 | @@ -15,6 +15,8 @@ |
1766 | */ |
1767 | #include "stdafx.h" |
1768 | |
1769 | +#include <cstring> |
1770 | + |
1771 | #include "ascii_util.h" |
1772 | |
1773 | namespace zorba { |
1774 | @@ -30,6 +32,38 @@ |
1775 | return true; |
1776 | } |
1777 | |
1778 | +size_type remove_chars( char *s, size_type s_len, char const *chars ) { |
1779 | + char *end = s + s_len; |
1780 | + char *c; |
1781 | + |
1782 | + // remove trailing chars first |
1783 | + for ( c = end - 1; c >= s; --c ) |
1784 | + if ( !std::strchr( chars, *c ) ) { |
1785 | + end = c + 1; |
1786 | + break; |
1787 | + } |
1788 | + if ( c < s ) // it was all chars |
1789 | + return 0; |
1790 | + |
1791 | + // remove all other chars |
1792 | + char *first_char = nullptr; |
1793 | + for ( c = s; c < end; ++c ) { |
1794 | + if ( std::strchr( chars, *c ) ) { |
1795 | + if ( !first_char ) |
1796 | + first_char = c; |
1797 | + } else { |
1798 | + if ( first_char ) { |
1799 | + std::memmove( first_char, c, end - c ); |
1800 | + end -= c - first_char; |
1801 | + c = first_char; |
1802 | + first_char = nullptr; |
1803 | + } |
1804 | + } |
1805 | + } |
1806 | + |
1807 | + return end - s; |
1808 | +} |
1809 | + |
1810 | char const* trim_start( char const *s, char const *chars ) { |
1811 | for ( ; *s; ++s ) { |
1812 | if ( !std::strchr( chars, *s ) ) |
1813 | |
1814 | === modified file 'src/util/ascii_util.h' |
1815 | --- src/util/ascii_util.h 2012-06-18 10:06:47 +0000 |
1816 | +++ src/util/ascii_util.h 2012-06-26 01:34:26 +0000 |
1817 | @@ -649,6 +649,29 @@ |
1818 | } |
1819 | |
1820 | /** |
1821 | + * Removes all specified characters by shifting the contents of the buffer to |
1822 | + * the left. |
1823 | + * |
1824 | + * @param s The string. |
1825 | + * @param s_len The length of \a s. |
1826 | + * @param chars The characters to remove. |
1827 | + * @return Returns the new length of \a s with all \a chars removed. |
1828 | + */ |
1829 | +size_type remove_chars( char *s, size_type s_len, char const *chars ); |
1830 | + |
1831 | +/** |
1832 | + * Removes all whitespace characters by shifting the contents of the buffer to |
1833 | + * the left. |
1834 | + * |
1835 | + * @param s The string. |
1836 | + * @param s_len The length of \a s. |
1837 | + * @return Returns the new length of \a s with all whitespace removed. |
1838 | + */ |
1839 | +inline size_type remove_whitespace( char *s, size_type s_len ) { |
1840 | + return remove_chars( s, s_len, whitespace ); |
1841 | +} |
1842 | + |
1843 | +/** |
1844 | * Removes all leading and trailing specified characters. |
1845 | * |
1846 | * @tparam InputStringType The input string type. |
1847 | |
1848 | === added file 'src/util/base64_util.cpp' |
1849 | --- src/util/base64_util.cpp 1970-01-01 00:00:00 +0000 |
1850 | +++ src/util/base64_util.cpp 2012-06-26 01:34:26 +0000 |
1851 | @@ -0,0 +1,359 @@ |
1852 | +/* |
1853 | + * Copyright 2006-2008 The FLWOR Foundation. |
1854 | + * |
1855 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
1856 | + * you may not use this file except in compliance with the License. |
1857 | + * You may obtain a copy of the License at |
1858 | + * |
1859 | + * http://www.apache.org/licenses/LICENSE-2.0 |
1860 | + * |
1861 | + * Unless required by applicable law or agreed to in writing, software |
1862 | + * distributed under the License is distributed on an "AS IS" BASIS, |
1863 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1864 | + * See the License for the specific language governing permissions and |
1865 | + * limitations under the License. |
1866 | + */ |
1867 | + |
1868 | +#include <algorithm> |
1869 | +#include <cstring> |
1870 | + |
1871 | +#include "ascii_util.h" |
1872 | +#include "base64_util.h" |
1873 | +#include "string_util.h" |
1874 | + |
1875 | +using namespace std; |
1876 | + |
1877 | +namespace zorba { |
1878 | +namespace base64 { |
1879 | + |
1880 | +/////////////////////////////////////////////////////////////////////////////// |
1881 | + |
1882 | +static char const alphabet[] = |
1883 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
1884 | + "abcdefghijklmnopqrstuvwxyz" |
1885 | + "0123456789+/"; |
1886 | + |
1887 | +/** |
1888 | + * Base64 decoding table. A value of -1 means "invalid"; a value of -2 means |
1889 | + * "skip" (for newlines and carriage returns). |
1890 | + */ |
1891 | +static signed char const decode_table[] = { |
1892 | + /* 00-07 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1893 | + /* 08-0F */ -1, -1, -2, -1, -1, -2, -1, -1, // . .\n . .\r . . |
1894 | + /* 10-17 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1895 | + /* 18-1F */ -1, -1, -1, -1, -1, -1, -1, -1, |
1896 | + /* 20-27 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1897 | + /* 28-2F */ -1, -1, -1, 62, -1, -1, -1, 63, // . . . + . . . / |
1898 | + /* 30-37 */ 52, 53, 54, 55, 56, 57, 58, 59, // 0 1 2 3 4 5 6 7 |
1899 | + /* 38-3F */ 60, 61, -1, -1, -1, -1, -1, -1, // 8 9 . . . . . . |
1900 | + /* 40-47 */ -1, 0, 1, 2, 3, 4, 5, 6, // . A B C D E F G |
1901 | + /* 48-4F */ 7, 8, 9, 10, 11, 12, 13, 14, // H I J K L M N O |
1902 | + /* 50-57 */ 15, 16, 17, 18, 19, 20, 21, 22, // P Q R S T U V W |
1903 | + /* 58-5F */ 23, 24, 25, -1, -1, -1, -1, -1, // X Y Z . . . . . |
1904 | + /* 60-67 */ -1, 26, 27, 28, 29, 30, 31, 32, // . a b c d e f g |
1905 | + /* 68-6F */ 33, 34, 35, 36, 37, 38, 39, 40, // h i j k l m n o |
1906 | + /* 70-77 */ 41, 42, 43, 44, 45, 46, 47, 48, // p q r s t u v w |
1907 | + /* 78-7F */ 49, 50, 51, -1, -1, -1, -1, -1, // x y z . . . . . |
1908 | + /* 80-87 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1909 | + /* 88-8F */ -1, -1, -1, -1, -1, -1, -1, -1, |
1910 | + /* 90-97 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1911 | + /* 98-9F */ -1, -1, -1, -1, -1, -1, -1, -1, |
1912 | + /* A0-A7 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1913 | + /* A8-AF */ -1, -1, -1, -1, -1, -1, -1, -1, |
1914 | + /* B0-B7 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1915 | + /* B8-BF */ -1, -1, -1, -1, -1, -1, -1, -1, |
1916 | + /* C0-C7 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1917 | + /* C8-CF */ -1, -1, -1, -1, -1, -1, -1, -1, |
1918 | + /* D0-D7 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1919 | + /* D8-DF */ -1, -1, -1, -1, -1, -1, -1, -1, |
1920 | + /* E0-E7 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1921 | + /* E8-EF */ -1, -1, -1, -1, -1, -1, -1, -1, |
1922 | + /* F0-F7 */ -1, -1, -1, -1, -1, -1, -1, -1, |
1923 | + /* F8-FF */ -1, -1, -1, -1, -1, -1, -1, -1, |
1924 | +}; |
1925 | + |
1926 | +inline void decode_chunk( char const *from, char *to ) { |
1927 | + // |
1928 | + // | INPUT BYTES |
1929 | + // +-----------+-----------+-----------+-----------+ |
1930 | + // | 0 | 1 | 2 | 3 | |
1931 | + // +-----------+-----------+-----------+-----------+ |
1932 | + // | | | | | |
1933 | + // | | | | | | | | | | | | | | | | | | | | | | | | | |
1934 | + // | | | | |
1935 | + // +---------------+---------------+---------------+ |
1936 | + // | 0 | 1 | 2 | |
1937 | + // +---------------+---------------+---------------+ |
1938 | + // | OUTPUT BYTES |
1939 | + // |
1940 | + unsigned char const *const u = reinterpret_cast<unsigned char const*>( from ); |
1941 | + to[0] = (u[0] << 2) | (u[1] >> 4); |
1942 | + to[1] = (u[1] << 4) | (u[2] >> 2); |
1943 | + to[2] = ((u[2] << 6) & 0xC0) | u[3] ; |
1944 | +} |
1945 | + |
1946 | +inline void encode_chunk( char const *from, char *to ) { |
1947 | + // |
1948 | + // | INPUT BYTES |
1949 | + // +---------------+---------------+---------------+ |
1950 | + // | 0 | 1 | 2 | |
1951 | + // +---------------+---------------+---------------+ |
1952 | + // | | | | |
1953 | + // | | | | | | | | | | | | | | | | | | | | | | | | | |
1954 | + // | | | | | |
1955 | + // +-----------+-----------+-----------+-----------+ |
1956 | + // | 0 | 1 | 2 | 3 | |
1957 | + // +-----------+-----------+-----------+-----------+ |
1958 | + // | OUTPUT BYTES |
1959 | + // |
1960 | + unsigned char const *const u = reinterpret_cast<unsigned char const*>( from ); |
1961 | + to[0] = alphabet[ u[0] >> 2 ]; |
1962 | + to[1] = alphabet[ ((u[0] & 0x03) << 4) | (u[1] >> 4) ]; |
1963 | + to[2] = alphabet[ ((u[1] & 0x0F) << 2) | (u[2] >> 6) ]; |
1964 | + to[3] = alphabet[ u[2] & 0x3F ]; |
1965 | +} |
1966 | + |
1967 | +streamsize read_without_whitespace( istream &is, char *buf, streamsize n ) { |
1968 | + char const *const buf_orig = buf; |
1969 | + char const *const buf_end = buf + n; |
1970 | + |
1971 | + while ( buf < buf_end ) { |
1972 | + is.read( buf, n ); |
1973 | + if ( streamsize read = is.gcount() ) { |
1974 | + read = ascii::remove_whitespace( buf, read ); |
1975 | + buf += read, n -= read; |
1976 | + } else |
1977 | + break; |
1978 | + } |
1979 | + return buf - buf_orig; |
1980 | +} |
1981 | + |
1982 | +/////////////////////////////////////////////////////////////////////////////// |
1983 | + |
1984 | +size_type decode( char const *from, size_type from_len, char *to, |
1985 | + int options ) { |
1986 | + char chunk[4]; |
1987 | + int chunk_len = 0; |
1988 | + bool const ignore_ws = options & dopt_ignore_ws; |
1989 | + int pads = 0; |
1990 | + char const *const to_orig = to; |
1991 | + |
1992 | + for ( size_type pos = 0; pos < from_len; ++pos, ++from ) { |
1993 | + char const c = *from; |
1994 | + signed char value; |
1995 | + if ( c == '=' ) { |
1996 | + switch ( pos % 4 ) { |
1997 | + // |
1998 | + // Ensure '=' occurs only in the 3rd or 4th bytes of a 4-byte chunk |
1999 | + // and that the byte preceding '=' is valid. |
2000 | + // |
2001 | + case 2: |
2002 | + if ( !strchr( "AQgw", from[-1] ) ) |
2003 | + throw base64::exception( |
2004 | + c, pos, BUILD_STRING( '\'', c, "': invalid character before '='" ) |
2005 | + ); |
2006 | + break; |
2007 | + case 3: |
2008 | + if ( !strchr( "=048AEIMQUYcgkosw", from[-1] ) ) |
2009 | + throw base64::exception( |
2010 | + c, pos, BUILD_STRING( '\'', c, "': invalid character before '='" ) |
2011 | + ); |
2012 | + break; |
2013 | + default: |
2014 | + throw base64::exception( c, pos, "'=' encountered unexpectedly" ); |
2015 | + } |
2016 | + ++pads; |
2017 | + value = '\0'; |
2018 | + } else { |
2019 | + if ( pads ) |
2020 | + throw base64::exception( |
2021 | + c, pos, BUILD_STRING( '\'', c, "': invalid character after '='" ) |
2022 | + ); |
2023 | + value = decode_table[ static_cast<unsigned char>( c ) ]; |
2024 | + } |
2025 | + switch ( value ) { |
2026 | + case -1: |
2027 | + if ( ascii::is_space( c ) && ignore_ws ) |
2028 | + continue; |
2029 | + throw base64::exception( |
2030 | + c, pos, BUILD_STRING( '\'', c, "': invalid character" ) |
2031 | + ); |
2032 | + case -2: // \n or \r |
2033 | + continue; |
2034 | + default: |
2035 | + if ( chunk_len == 4 ) |
2036 | + chunk_len = 0; |
2037 | + if ( to ) { |
2038 | + chunk[ chunk_len ] = value; |
2039 | + if ( ++chunk_len == 4 ) { |
2040 | + decode_chunk( chunk, to ); |
2041 | + to += 3; |
2042 | + } |
2043 | + } else |
2044 | + ++chunk_len; |
2045 | + } |
2046 | + } // for |
2047 | + |
2048 | + if ( (chunk_len % 4) && !(options & dopt_any_len) ) |
2049 | + throw invalid_argument( "Base64 length is not a multiple of 4" ); |
2050 | + |
2051 | + if ( !to ) |
2052 | + return 0; |
2053 | + |
2054 | + if ( chunk_len > 1 && chunk_len < 4 ) { |
2055 | + // |
2056 | + // The number of non-whitespace bytes was not a multiple of 4, hence the |
2057 | + // Base64 encoding is incomplete: salvage 1 or 2 characters. |
2058 | + // |
2059 | + int const salvageable = chunk_len - 1; |
2060 | + chunk[3] = '\0'; |
2061 | + if ( salvageable == 1 ) |
2062 | + chunk[2] = '\0'; |
2063 | + decode_chunk( chunk, to ); |
2064 | + to += salvageable; |
2065 | + } |
2066 | + |
2067 | + return to - to_orig - pads; |
2068 | +} |
2069 | + |
2070 | +size_type decode( char const *from, size_type from_len, std::vector<char> *to, |
2071 | + int options ) { |
2072 | + size_type total_decoded = 0; |
2073 | + if ( from_len ) { |
2074 | + std::vector<char>::size_type const orig_size = to->size(); |
2075 | + to->resize( orig_size + decoded_size( from_len ) ); |
2076 | + total_decoded = decode( from, from_len, &(*to)[ orig_size ], options ); |
2077 | + to->resize( orig_size + total_decoded ); |
2078 | + } |
2079 | + return total_decoded; |
2080 | +} |
2081 | + |
2082 | +size_type decode( istream &from, ostream &to, int options ) { |
2083 | + size_type total_decoded = 0; |
2084 | + while ( !from.eof() ) { |
2085 | + char from_buf[ 1024 * 4 ], to_buf[ 1024 * 3 ]; |
2086 | + streamsize gcount; |
2087 | + if ( options & dopt_ignore_ws ) |
2088 | + gcount = read_without_whitespace( from, from_buf, sizeof from_buf ); |
2089 | + else { |
2090 | + from.read( from_buf, sizeof from_buf ); |
2091 | + gcount = from.gcount(); |
2092 | + } |
2093 | + if ( gcount ) { |
2094 | + size_type const decoded = decode( from_buf, gcount, to_buf, options ); |
2095 | + to.write( to_buf, decoded ); |
2096 | + total_decoded += decoded; |
2097 | + } else |
2098 | + break; |
2099 | + } |
2100 | + return total_decoded; |
2101 | +} |
2102 | + |
2103 | +size_type decode( istream &from, vector<char> *to, int options ) { |
2104 | + vector<char>::size_type const orig_size = to->size(); |
2105 | + size_type total_decoded = 0; |
2106 | + while ( !from.eof() ) { |
2107 | + char from_buf[ 1024 * 4 ]; |
2108 | + streamsize gcount; |
2109 | + if ( options & dopt_ignore_ws ) |
2110 | + gcount = read_without_whitespace( from, from_buf, sizeof from_buf ); |
2111 | + else { |
2112 | + from.read( from_buf, sizeof from_buf ); |
2113 | + gcount = from.gcount(); |
2114 | + } |
2115 | + if ( gcount ) { |
2116 | + to->resize( to->size() + decoded_size( gcount ) ); |
2117 | + total_decoded += |
2118 | + decode( from_buf, gcount, &(*to)[ total_decoded ], options ); |
2119 | + } else |
2120 | + break; |
2121 | + } |
2122 | + to->resize( orig_size + total_decoded ); |
2123 | + return total_decoded; |
2124 | +} |
2125 | + |
2126 | +/////////////////////////////////////////////////////////////////////////////// |
2127 | + |
2128 | +size_type encode( char const *from, size_type from_len, char *to ) { |
2129 | + char const *const to_orig = to; |
2130 | + int chunk_len = 0; |
2131 | + |
2132 | + while ( from_len-- ) { |
2133 | + if ( ++chunk_len == 3 ) { |
2134 | + encode_chunk( from, to ); |
2135 | + from += 3, to += 4; |
2136 | + chunk_len = 0; |
2137 | + } |
2138 | + } |
2139 | + |
2140 | + if ( chunk_len ) { // must be either 1 or 2 |
2141 | + // |
2142 | + // Handle the special-case of from_len not being a multiple of 3. First, |
2143 | + // copy what's left over from "from" to a temporary buffer that's 3 bytes |
2144 | + // long and encode that buffer so encode_chunk() remains special-case-free |
2145 | + // (and thus faster) for most of the encoding. |
2146 | + // |
2147 | + char from_temp[3]; |
2148 | + from_temp[1] = from_temp[2] = '\0'; |
2149 | + std::copy( from, from + chunk_len, from_temp ); |
2150 | + encode_chunk( from_temp, to ); |
2151 | + // |
2152 | + // Second, overwrite the trailing byte(s) with Base64 padding characters. |
2153 | + // |
2154 | + to[3] = '='; |
2155 | + if ( chunk_len == 1 ) |
2156 | + to[2] = '='; |
2157 | + to += 4; |
2158 | + } |
2159 | + |
2160 | + return to - to_orig; |
2161 | +} |
2162 | + |
2163 | +size_type encode( char const *from, size_type from_len, |
2164 | + std::vector<char> *to ) { |
2165 | + size_type encoded = 0; |
2166 | + if ( from_len ) { |
2167 | + std::vector<char>::size_type const orig_size = to->size(); |
2168 | + to->resize( orig_size + encoded_size( from_len ) ); |
2169 | + encoded = encode( from, from_len, &(*to)[ orig_size ] ); |
2170 | + to->resize( orig_size + encoded ); |
2171 | + } |
2172 | + return encoded; |
2173 | +} |
2174 | + |
2175 | +size_type encode( istream &from, ostream &to ) { |
2176 | + size_type total_encoded = 0; |
2177 | + while ( !from.eof() ) { |
2178 | + char from_buf[ 1024 * 3 ], to_buf[ 1024 * 4 ]; |
2179 | + from.read( from_buf, sizeof from_buf ); |
2180 | + if ( streamsize const gcount = from.gcount() ) { |
2181 | + size_type const encoded = encode( from_buf, gcount, to_buf ); |
2182 | + to.write( to_buf, encoded ); |
2183 | + total_encoded += encoded; |
2184 | + } else |
2185 | + break; |
2186 | + } |
2187 | + return total_encoded; |
2188 | +} |
2189 | + |
2190 | +size_type encode( istream &from, vector<char> *to ) { |
2191 | + vector<char>::size_type const orig_size = to->size(); |
2192 | + size_type total_encoded = 0; |
2193 | + while ( !from.eof() ) { |
2194 | + char from_buf[ 1024 * 3 ]; |
2195 | + from.read( from_buf, sizeof from_buf ); |
2196 | + if ( streamsize const gcount = from.gcount() ) { |
2197 | + to->resize( to->size() + encoded_size( gcount ) ); |
2198 | + total_encoded += encode( from_buf, gcount, &(*to)[ total_encoded ] ); |
2199 | + } else |
2200 | + break; |
2201 | + } |
2202 | + to->resize( orig_size + total_encoded ); |
2203 | + return total_encoded; |
2204 | +} |
2205 | + |
2206 | +/////////////////////////////////////////////////////////////////////////////// |
2207 | + |
2208 | +} // namespace base64 |
2209 | +} // namespace zorba |
2210 | +/* vim:set et sw=2 ts=2: */ |
2211 | |
2212 | === added file 'src/util/base64_util.h' |
2213 | --- src/util/base64_util.h 1970-01-01 00:00:00 +0000 |
2214 | +++ src/util/base64_util.h 2012-06-26 01:34:26 +0000 |
2215 | @@ -0,0 +1,361 @@ |
2216 | +/* |
2217 | + * Copyright 2006-2008 The FLWOR Foundation. |
2218 | + * |
2219 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
2220 | + * you may not use this file except in compliance with the License. |
2221 | + * You may obtain a copy of the License at |
2222 | + * |
2223 | + * http://www.apache.org/licenses/LICENSE-2.0 |
2224 | + * |
2225 | + * Unless required by applicable law or agreed to in writing, software |
2226 | + * distributed under the License is distributed on an "AS IS" BASIS, |
2227 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
2228 | + * See the License for the specific language governing permissions and |
2229 | + * limitations under the License. |
2230 | + */ |
2231 | + |
2232 | +#pragma once |
2233 | +#ifndef ZORBA_BASE64_UTIL_H |
2234 | +#define ZORBA_BASE64_UTIL_H |
2235 | + |
2236 | +#include <algorithm> |
2237 | +#include <iostream> |
2238 | +#include <stdexcept> |
2239 | +#include <sys/types.h> /* for size_t */ |
2240 | +#include <vector> |
2241 | + |
2242 | +#include "cxx_util.h" |
2243 | + |
2244 | +namespace zorba { |
2245 | +namespace base64 { |
2246 | + |
2247 | +////////// Types ////////////////////////////////////////////////////////////// |
2248 | + |
2249 | +typedef size_t size_type; |
2250 | + |
2251 | +/** |
2252 | + * Options to use for decoding. |
2253 | + */ |
2254 | +enum decode_options { |
2255 | + dopt_none = 0x00, ///< No options. |
2256 | + dopt_any_len = 0x01, ///< Input length may be non-multiple of 4. |
2257 | + dopt_ignore_ws = 0x02, ///< Ignore all whitespace. |
2258 | +}; |
2259 | + |
2260 | +////////// Exception ////////////////////////////////////////////////////////// |
2261 | + |
2262 | +/** |
2263 | + * A %base64::exception is-an invalid_argument that contains additional details |
2264 | + * about the exception such as the invalid character and its offset. |
2265 | + */ |
2266 | +class exception : public std::invalid_argument { |
2267 | +public: |
2268 | + exception( char c, size_type offset, std::string const &msg ) : |
2269 | + std::invalid_argument( msg ), char_( c ), offset_( offset ) { } |
2270 | + |
2271 | + char invalid_char() const { |
2272 | + return char_; |
2273 | + } |
2274 | + |
2275 | + size_type char_offset() const { |
2276 | + return offset_; |
2277 | + } |
2278 | + |
2279 | +private: |
2280 | + char char_; |
2281 | + size_type offset_; |
2282 | +}; |
2283 | + |
2284 | +////////// Decoding /////////////////////////////////////////////////////////// |
2285 | + |
2286 | +/** |
2287 | + * \internal |
2288 | + * Reads from the given istream until \a n non-whitespace characters are read |
2289 | + * or until EOF is encountered. |
2290 | + * |
2291 | + * @param is The istream to read from. |
2292 | + * @param buf A pointer to the start of a buffer to read into. |
2293 | + * @param n The number of non-whitespace characters to read. |
2294 | + * @return Returns the number of non-whitespace characters read. |
2295 | + */ |
2296 | +std::streamsize read_without_whitespace( std::istream &is, char *buf, |
2297 | + std::streamsize n ); |
2298 | + |
2299 | +/** |
2300 | + * Calculates the number of bytes required to decode \a n Base64-encoded bytes. |
2301 | + * |
2302 | + * @param n The number of bytes to decode. |
2303 | + * @return Returns the number of bytes needed for Base64 decoding. |
2304 | + */ |
2305 | +inline size_type decoded_size( size_type n ) { |
2306 | + return ((n / 4) + !!(n % 4)) * 3; |
2307 | +} |
2308 | + |
2309 | +/** |
2310 | + * Decodes a Base64-encoded buffer. Embedded newlines and carriage-returns are |
2311 | + * skipped. |
2312 | + * |
2313 | + * @param from A pointer to the Base64 buffer to be decoded. |
2314 | + * @param from_len The number of bytes to decode. |
2315 | + * @paran to A pointer to the buffer to receive the decoded bytes. The buffer |
2316 | + * must be large enough to contain them. Note that the buffer is \e not null |
2317 | + * terminated. |
2318 | + * @param options The decoding options to use. |
2319 | + * @return Returns the number of decoded bytes. |
2320 | + * @throws invalid_argument if \a options does not have the \c dtop_any_len bit |
2321 | + * set and \a from_len is not a multiple of 4. |
2322 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2323 | + * invalid byte is encountered. |
2324 | + * @see decoded_size() |
2325 | + */ |
2326 | +size_type decode( char const *from, size_type from_len, char *to, |
2327 | + int options = dopt_none ); |
2328 | + |
2329 | +/** |
2330 | + * Decodes a Base64-encoded buffer and appends the decoded bytes onto a |
2331 | + * vector<char>. Embedded newlines and carriage-returns are skipped. |
2332 | + * |
2333 | + * @param from A pointer to the buffer to be encoded. |
2334 | + * @param from_len The number of bytes to encode. |
2335 | + * @param to A pointer to the vector to append the encoded bytes appended onto. |
2336 | + * The vector is made large enough to contain the additional bytes. |
2337 | + * @param options The decoding options to use. |
2338 | + * @return Returns the number of decoded bytes. |
2339 | + * @throws invalid_argument if \a options does not have the \c dopt_any_len bit |
2340 | + * set and the number of Base64 bytes decoded is not a multiple of 4. |
2341 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2342 | + * invalid byte is encountered. |
2343 | + */ |
2344 | +size_type decode( char const *from, size_type from_len, std::vector<char> *to, |
2345 | + int options = dopt_none ); |
2346 | + |
2347 | +/** |
2348 | + * Decodes a Base64-encoded buffer and appends the decoded bytes onto a string. |
2349 | + * Embedded newlines and carriage-returns are skipped. |
2350 | + * |
2351 | + * @tparam ToStringType The string type. |
2352 | + * @param from A pointer to the Base64 buffer to be decoded. |
2353 | + * @param from_len The number of bytes to decode. |
2354 | + * @param to The string to append the decoded bytes to. |
2355 | + * @param options The options to use. |
2356 | + * @return Returns the number of decoded bytes. |
2357 | + * @throws invalid_argument if \a options does not have the \c dopt_any_len bit |
2358 | + * set and the number of Base64 bytes decoded is not a multiple of 4. |
2359 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2360 | + * invalid byte is encountered. |
2361 | + */ |
2362 | +template<class ToStringType> |
2363 | +size_type decode( char const *from, size_type from_len, ToStringType *to, |
2364 | + int options = dopt_none ) { |
2365 | + size_type total_decoded = 0; |
2366 | + if ( from_len ) { |
2367 | + typename ToStringType::size_type const orig_size = to->size(); |
2368 | + to->resize( orig_size + decoded_size( from_len ) ); |
2369 | + total_decoded = decode( from, from_len, &to->at( orig_size ), options ); |
2370 | + to->resize( orig_size + total_decoded ); |
2371 | + } |
2372 | + return total_decoded; |
2373 | +} |
2374 | + |
2375 | +/** |
2376 | + * Decodes a Base64-encoded istream. Embedded newlines and carriage-returns |
2377 | + * are skipped. |
2378 | + * |
2379 | + * @param from The istream to read from until EOF is reached. |
2380 | + * @param to The ostream to write the decoded bytes to. |
2381 | + * @param options The options to use. |
2382 | + * 4 otherwise an exception is thrown; if \a false, missing trailing bytes are |
2383 | + * assumed to be padding. |
2384 | + * @return Returns the number of decoded bytes. |
2385 | + * @throws invalid_argument if \a options does not have the \c dopt_any_len bit |
2386 | + * set and the number of Base64 bytes decoded is not a multiple of 4. |
2387 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2388 | + * invalid byte is encountered. |
2389 | + */ |
2390 | +size_type decode( std::istream &from, std::ostream &to, |
2391 | + int options = dopt_none ); |
2392 | + |
2393 | +/** |
2394 | + * Decodes a Base64-encoded istream and appends the decoded bytes to a string. |
2395 | + * Embedded newlines and carriage-returns are skipped. |
2396 | + * |
2397 | + * @tparam ToStringType The string type. |
2398 | + * @param from The istream to read from until EOF is reached. |
2399 | + * @param to The string to append the decoded bytes to. |
2400 | + * @param options The options to use. |
2401 | + * 4 otherwise an exception is thrown; if \a false, missing trailing bytes are |
2402 | + * assumed to be padding. |
2403 | + * @return Returns the number of decoded bytes. |
2404 | + * @throws invalid_argument if \a options does not have the \c dopt_any_len bit |
2405 | + * set and the number of Base64 bytes decoded is not a multiple of 4. |
2406 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2407 | + * invalid byte is encountered. |
2408 | + */ |
2409 | +template<class ToStringType> |
2410 | +size_type decode( std::istream &from, ToStringType *to, |
2411 | + int options = dopt_none ) { |
2412 | + size_type total_decoded = 0; |
2413 | + while ( !from.eof() ) { |
2414 | + char from_buf[ 1024 * 4 ], to_buf[ 1024 * 3 ]; |
2415 | + std::streamsize gcount; |
2416 | + if ( options & dopt_ignore_ws ) |
2417 | + gcount = read_without_whitespace( from, from_buf, sizeof from_buf ); |
2418 | + else { |
2419 | + from.read( from_buf, sizeof from_buf ); |
2420 | + gcount = from.gcount(); |
2421 | + } |
2422 | + if ( gcount ) { |
2423 | + size_type const decoded = decode( from_buf, gcount, to_buf, options ); |
2424 | + to->append( to_buf, decoded ); |
2425 | + total_decoded += decoded; |
2426 | + } else |
2427 | + break; |
2428 | + } |
2429 | + return total_decoded; |
2430 | +} |
2431 | + |
2432 | +/** |
2433 | + * Decodes a Base64-encoded stream and appends the decoded bytes onto a |
2434 | + * vector<char;>. |
2435 | + * |
2436 | + * @param from The istream to read from until EOF is reached. |
2437 | + * @param to The string to append the decoded bytes to. |
2438 | + * @param options The options to use. |
2439 | + * @param Returns the number of decoded bytes. |
2440 | + * @throws invalid_argument if \a options does not have the \c dopt_any_len bit |
2441 | + * set and the number of Base64 bytes decoded is not a multiple of 4. |
2442 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2443 | + * invalid byte is encountered. |
2444 | + */ |
2445 | +size_type decode( std::istream &from, std::vector<char> *to, |
2446 | + int options = dopt_none ); |
2447 | + |
2448 | +/** |
2449 | + * Validates a Base64-encoded buffer. Embedded newlines and carriage-returns |
2450 | + * are skipped. |
2451 | + * |
2452 | + * @param buf A pointer to the Base64 buffer to be validated. |
2453 | + * @param buf_len The number of bytes to validate. |
2454 | + * @param options The options to use. |
2455 | + * @throws invalid_argument if \a options does not have the \c dopt_any_len bit |
2456 | + * set and the number of Base64 bytes validated is not a multiple of 4. |
2457 | + * @throws base64::exception if an \c = is encountered unexpectedly or an |
2458 | + * invalid byte is encountered. |
2459 | + * @see decoded_size() |
2460 | + */ |
2461 | +inline void validate( char const *buf, size_type buf_len, |
2462 | + int options = dopt_none ) { |
2463 | + decode( buf, buf_len, static_cast<char*>( nullptr ), options ); |
2464 | +} |
2465 | + |
2466 | +////////// Encoding /////////////////////////////////////////////////////////// |
2467 | + |
2468 | +/** |
2469 | + * Calculates the number of bytes required to Base64-encode \a n bytes. |
2470 | + * |
2471 | + * @param n The number of bytes to encode. |
2472 | + * @return Returns the number of bytes needed for Base64 encoding. |
2473 | + */ |
2474 | +inline size_type encoded_size( size_type n ) { |
2475 | + return (n + 2) / 3 * 4; |
2476 | +} |
2477 | + |
2478 | +/** |
2479 | + * Base64-encodes a buffer. |
2480 | + * |
2481 | + * @param from A pointer to the buffer to be encoded. |
2482 | + * @param from_len The number of bytes to encode. |
2483 | + * @param to A pointer to the buffer to receive the encoded bytes. The buffer |
2484 | + * must be large enough to contain them. Note that the buffer is \e not null |
2485 | + * terminated. |
2486 | + * @return Returns the number of encoded bytes. |
2487 | + * @see encoded_size() |
2488 | + */ |
2489 | +size_type encode( char const *from, size_type from_len, char *to ); |
2490 | + |
2491 | +/** |
2492 | + * Base64-encodes a buffer and appends the encoded bytes onto a |
2493 | + * vector<char>. |
2494 | + * |
2495 | + * @param from A pointer to the buffer to be encoded. |
2496 | + * @param from_len The number of bytes to encode. |
2497 | + * @param to A pointer to the vector to append the encoded bytes appended onto. |
2498 | + * The vector is made large enough to contain the additional bytes. |
2499 | + */ |
2500 | +size_type encode( char const *from, size_type from_len, std::vector<char> *to ); |
2501 | + |
2502 | +/** |
2503 | + * Base64-encodes a buffer and appends the encoded bytes onto a string. |
2504 | + * |
2505 | + * @tparam ToStringType The string type. |
2506 | + * @param from A pointer to the Base64 buffer to be encoded. |
2507 | + * @param from_len The number of bytes to encode. |
2508 | + * @param to A pointer to the string to append the encoded bytes onto. |
2509 | + * @return Returns the number of encoded bytes. |
2510 | + */ |
2511 | +template<class ToStringType> |
2512 | +size_type encode( char const *from, size_type from_len, ToStringType *to ) { |
2513 | + size_type total_encoded = 0; |
2514 | + if ( from_len ) { |
2515 | + typename ToStringType::size_type const orig_size = to->size(); |
2516 | + to->resize( orig_size + encoded_size( from_len ) ); |
2517 | + total_encoded = encode( from, from_len, &to->at( orig_size ) ); |
2518 | + to->resize( orig_size + total_encoded ); |
2519 | + } |
2520 | + return total_encoded; |
2521 | +} |
2522 | + |
2523 | +/** |
2524 | + * Base64-encodes one stream and write the encoded bytes to another. |
2525 | + * |
2526 | + * @param from The istream to read from until EOF is reached. |
2527 | + * @param to The ostream to write the encoded bytes to. |
2528 | + */ |
2529 | +size_type encode( std::istream &from, std::ostream &to ); |
2530 | + |
2531 | +/** |
2532 | + * Encodes a stream to Base64 and appends the encoded bytes to a string. |
2533 | + * |
2534 | + * @tparam ToStringType The string type. |
2535 | + * @param from The istream to read from until EOF is reached. |
2536 | + * @param to The string to append the encoded bytes to. |
2537 | + * @return Returns the number of encoded bytes. |
2538 | + */ |
2539 | +template<class ToStringType> |
2540 | +size_type encode( std::istream &from, ToStringType *to ) { |
2541 | + size_type total_encoded = 0; |
2542 | + while ( !from.eof() ) { |
2543 | + char from_buf[ 1024 * 3 ], to_buf[ 1024 * 4 ]; |
2544 | + from.read( from_buf, sizeof from_buf ); |
2545 | + if ( std::streamsize const gcount = from.gcount() ) { |
2546 | + size_type const encoded = encode( from_buf, gcount, to_buf ); |
2547 | + to->append( to_buf, encoded ); |
2548 | + total_encoded += encoded; |
2549 | + } else |
2550 | + break; |
2551 | + } |
2552 | + return total_encoded; |
2553 | +} |
2554 | + |
2555 | +/** |
2556 | + * Base64-encodes a stream and appends the encoded bytes onto a |
2557 | + * vector<char;>. |
2558 | + * |
2559 | + * @param from The istream to read from until EOF is reached. |
2560 | + * @param to The string to append the encoded bytes to. |
2561 | + * @param Returns the number of encoded bytes. |
2562 | + */ |
2563 | +size_type encode( std::istream &from, std::vector<char> *to ); |
2564 | + |
2565 | +/////////////////////////////////////////////////////////////////////////////// |
2566 | + |
2567 | +} // namespace base64 |
2568 | +} // namespace zorba |
2569 | + |
2570 | +#endif /* ZORBA_BASE64_UTIL_H */ |
2571 | +/* |
2572 | + * Local variables: |
2573 | + * mode: c++ |
2574 | + * End: |
2575 | + */ |
2576 | +/* vim:set et sw=2 ts=2: */ |
2577 | |
2578 | === modified file 'src/util/icu_streambuf.cpp' |
2579 | --- src/util/icu_streambuf.cpp 2012-06-18 10:06:47 +0000 |
2580 | +++ src/util/icu_streambuf.cpp 2012-06-26 01:34:26 +0000 |
2581 | @@ -15,8 +15,8 @@ |
2582 | */ |
2583 | |
2584 | #include "stdafx.h" |
2585 | -#define ZORBA_DEBUG_ICU_STREAMBUF 0 |
2586 | |
2587 | +// #define ZORBA_DEBUG_ICU_STREAMBUF |
2588 | #ifdef ZORBA_DEBUG_ICU_STREAMBUF |
2589 | # include <stdio.h> |
2590 | #endif |
2591 | |
2592 | === modified file 'src/util/string/rstring.h' |
2593 | --- src/util/string/rstring.h 2012-06-18 10:06:47 +0000 |
2594 | +++ src/util/string/rstring.h 2012-06-26 01:34:26 +0000 |
2595 | @@ -1884,7 +1884,7 @@ |
2596 | } |
2597 | |
2598 | /** |
2599 | - * Attemts to pre-allocated enough memory to contain the given number of |
2600 | + * Attemts to pre-allocate enough memory to contain the given number of |
2601 | * bytes. |
2602 | * |
2603 | * @param n The number of bytes. |
2604 | |
2605 | === modified file 'src/zorbatypes/binary.cpp' |
2606 | --- src/zorbatypes/binary.cpp 2012-06-18 10:06:47 +0000 |
2607 | +++ src/zorbatypes/binary.cpp 2012-06-26 01:34:26 +0000 |
2608 | @@ -25,32 +25,44 @@ |
2609 | #include "diagnostics/xquery_diagnostics.h" |
2610 | |
2611 | #include "util/ascii_util.h" |
2612 | +#include "util/base64_util.h" |
2613 | #include "util/stl_util.h" |
2614 | |
2615 | +#define CATCH_BASE64_EXCEPTION() \ |
2616 | + catch ( base64::exception const &e ) { \ |
2617 | + throw XQUERY_EXCEPTION( \ |
2618 | + err::FORG0001, ERROR_PARAMS( e.invalid_char(), ZED( Base64BadChar ) ) \ |
2619 | + ); \ |
2620 | + } \ |
2621 | + catch ( std::invalid_argument const& ) { \ |
2622 | + throw XQUERY_EXCEPTION( \ |
2623 | + err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) ) \ |
2624 | + ); \ |
2625 | + } |
2626 | + |
2627 | using namespace std; |
2628 | |
2629 | -namespace zorba |
2630 | -{ |
2631 | - |
2632 | - |
2633 | -static const string base64_chars = |
2634 | - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
2635 | - "abcdefghijklmnopqrstuvwxyz" |
2636 | - "0123456789+/"; |
2637 | - |
2638 | - |
2639 | -inline bool is_base64(char c) |
2640 | -{ |
2641 | - return (isalnum(c) || (c == '+') || (c == '/')); |
2642 | +namespace zorba { |
2643 | + |
2644 | +static size_t copy_without_ws( char const *from, size_t len, char *to ) { |
2645 | + char const *const end = from + len; |
2646 | + char const *const to_orig = to; |
2647 | + for ( ; from < end; ++from ) |
2648 | + if ( !ascii::is_space( *from ) ) |
2649 | + *to++ = *from; |
2650 | + return to - to_orig; |
2651 | } |
2652 | |
2653 | |
2654 | bool Base64::parseString(const char* aString, size_t aLength, Base64& aBase64) |
2655 | { |
2656 | - aBase64.theData.clear(); |
2657 | try |
2658 | { |
2659 | - aBase64.insertData(aString, aLength); |
2660 | + base64::validate( aString, aLength, base64::dopt_ignore_ws ); |
2661 | + aBase64.theData.resize( aLength ); |
2662 | + aBase64.theData.resize( |
2663 | + copy_without_ws( aString, aLength, &aBase64.theData[0] ) |
2664 | + ); |
2665 | } |
2666 | catch (...) |
2667 | { |
2668 | @@ -66,10 +78,13 @@ |
2669 | Base64& aBase64, |
2670 | string& lErrorMessage) |
2671 | { |
2672 | - aBase64.theData.clear(); |
2673 | try |
2674 | { |
2675 | - aBase64.insertData(aString, aLength); |
2676 | + base64::validate( aString, aLength, base64::dopt_ignore_ws ); |
2677 | + aBase64.theData.resize( aLength ); |
2678 | + aBase64.theData.resize( |
2679 | + copy_without_ws( aString, aLength, &aBase64.theData[0] ) |
2680 | + ); |
2681 | } |
2682 | catch (ZorbaException const& e) |
2683 | { |
2684 | @@ -82,102 +97,27 @@ |
2685 | |
2686 | void Base64::encode(const zstring& aString, Base64& aResult) |
2687 | { |
2688 | - vector<char> source; |
2689 | - source.reserve(aString.size()); |
2690 | - |
2691 | - FOR_EACH( zstring, i, aString ) |
2692 | - source.push_back( *i ); |
2693 | - |
2694 | - aResult.theData.clear(); |
2695 | - encode(source, aResult.theData); |
2696 | + base64::encode( aString.data(), aString.size(), &aResult.theData ); |
2697 | } |
2698 | |
2699 | |
2700 | void Base64::encode(istream& aStream, Base64& aResult) |
2701 | { |
2702 | - vector<char> source; |
2703 | - |
2704 | - char lC; |
2705 | - while (aStream.good()) |
2706 | - { |
2707 | - aStream.get(lC); |
2708 | - if (!aStream.good()) |
2709 | - { |
2710 | - break; |
2711 | - } |
2712 | - source.push_back(lC); |
2713 | - } |
2714 | - |
2715 | - encode(source, aResult.theData); |
2716 | + base64::encode( aStream, &aResult.theData ); |
2717 | } |
2718 | |
2719 | |
2720 | zstring Base64::encode(istream& aStream) |
2721 | { |
2722 | - vector<char> source; |
2723 | - vector<char> dest; |
2724 | - |
2725 | - char buf[1024]; |
2726 | - while (!aStream.eof()) |
2727 | - { |
2728 | - aStream.read(buf, 1024); |
2729 | - source.insert(source.end(), buf, buf + aStream.gcount()); |
2730 | - } |
2731 | - |
2732 | - encode(source, dest); |
2733 | - |
2734 | zstring result; |
2735 | - result.reserve(dest.size()); |
2736 | - |
2737 | - FOR_EACH( vector<char>, i, dest ) |
2738 | - result.push_back( *i ); |
2739 | - |
2740 | + base64::encode( aStream, &result ); |
2741 | return result; |
2742 | } |
2743 | |
2744 | |
2745 | void Base64::encode(const vector<char>& aSource, vector<char>& aResult) |
2746 | { |
2747 | - size_t in_len = aSource.size(); |
2748 | - size_t lCurPos = 0; |
2749 | - int i = 0; |
2750 | - int j = 0; |
2751 | - char char_array_3[3] = {'\0','\0','\0'}; |
2752 | - char char_array_4[4] = {'\0','\0','\0','\0'}; |
2753 | - |
2754 | - while (in_len--) |
2755 | - { |
2756 | - char_array_3[i++] = aSource[lCurPos++]; |
2757 | - if (i == 3) |
2758 | - { |
2759 | - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; |
2760 | - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); |
2761 | - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); |
2762 | - char_array_4[3] = char_array_3[2] & 0x3f; |
2763 | - |
2764 | - for(i = 0; (i <4) ; i++) |
2765 | - aResult.push_back(base64_chars[char_array_4[i]]); |
2766 | - i = 0; |
2767 | - } |
2768 | - } |
2769 | - |
2770 | - if (i) |
2771 | - { |
2772 | - for(j = i; j < 3; j++) |
2773 | - char_array_3[j] = '\0'; |
2774 | - |
2775 | - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; |
2776 | - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); |
2777 | - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); |
2778 | - char_array_4[3] = char_array_3[2] & 0x3f; |
2779 | - |
2780 | - for (j = 0; (j < i + 1); j++) |
2781 | - aResult.push_back(base64_chars[char_array_4[j]]); |
2782 | - |
2783 | - while((i++ < 3)) |
2784 | - aResult.push_back('='); |
2785 | - |
2786 | - } |
2787 | + base64::encode( &aSource[0], aSource.size(), &aResult ); |
2788 | } |
2789 | |
2790 | |
2791 | @@ -186,110 +126,38 @@ |
2792 | unsigned int in_len, |
2793 | Base64& aResult) |
2794 | { |
2795 | - size_t lCurPos = 0; |
2796 | - int i = 0; |
2797 | - int j = 0; |
2798 | - char char_array_3[3] = {'\0','\0','\0'}; |
2799 | - char char_array_4[4] = {'\0','\0','\0','\0'}; |
2800 | - |
2801 | - aResult.theData.reserve(in_len * 8 / 6 + 10); |
2802 | - while (in_len--) |
2803 | - { |
2804 | - char_array_3[i++] = aSource[lCurPos++]; |
2805 | - if (i == 3) |
2806 | - { |
2807 | - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; |
2808 | - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); |
2809 | - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); |
2810 | - char_array_4[3] = char_array_3[2] & 0x3f; |
2811 | - |
2812 | - for(i = 0; (i <4) ; i++) |
2813 | - aResult.theData.push_back(base64_chars[char_array_4[i]]); |
2814 | - i = 0; |
2815 | - } |
2816 | - } |
2817 | - |
2818 | - if (i) |
2819 | - { |
2820 | - for(j = i; j < 3; j++) |
2821 | - char_array_3[j] = '\0'; |
2822 | - |
2823 | - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; |
2824 | - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); |
2825 | - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); |
2826 | - char_array_4[3] = char_array_3[2] & 0x3f; |
2827 | - |
2828 | - for (j = 0; (j < i + 1); j++) |
2829 | - aResult.theData.push_back(base64_chars[char_array_4[j]]); |
2830 | - |
2831 | - while((i++ < 3)) |
2832 | - aResult.theData.push_back('='); |
2833 | - |
2834 | - } |
2835 | + base64::encode( (char*)aSource, in_len, &aResult.theData ); |
2836 | } |
2837 | |
2838 | |
2839 | -zstring Base64::decode(istream& aStream) |
2840 | +void Base64::decode(istream& aStream, zstring *result) |
2841 | { |
2842 | - vector<char> source; |
2843 | - vector<char> dest; |
2844 | - |
2845 | - char buf[1024]; |
2846 | - while (!aStream.eof()) |
2847 | - { |
2848 | - aStream.read(buf, 1024); |
2849 | - source.insert(source.end(), buf, buf + aStream.gcount()); |
2850 | + try { |
2851 | + base64::decode( |
2852 | + aStream, result, base64::dopt_any_len | base64::dopt_ignore_ws |
2853 | + ); |
2854 | } |
2855 | - |
2856 | - decode(source, dest); |
2857 | - |
2858 | - zstring result; |
2859 | - result.reserve(dest.size()); |
2860 | - |
2861 | - FOR_EACH( vector<char>, i, dest ) |
2862 | - result.push_back( *i ); |
2863 | - |
2864 | - return result; |
2865 | + CATCH_BASE64_EXCEPTION() |
2866 | } |
2867 | |
2868 | - |
2869 | void Base64::decode(const vector<char>& aSource, vector<char>& aResult) |
2870 | { |
2871 | - size_t in_len = aSource.size(); |
2872 | - int i = 0; |
2873 | - int j = 0; |
2874 | - int in_ = 0; |
2875 | - char char_array_4[4], char_array_3[3]; |
2876 | - |
2877 | - while (in_len-- && ( aSource[in_] != '=') && is_base64(aSource[in_])) { |
2878 | - char_array_4[i++] = aSource[in_]; in_++; |
2879 | - if (i ==4) { |
2880 | - for (i = 0; i <4; i++) |
2881 | - char_array_4[i] = (char)base64_chars.find(char_array_4[i]); |
2882 | - |
2883 | - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); |
2884 | - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); |
2885 | - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; |
2886 | - |
2887 | - for (i = 0; (i < 3); i++) |
2888 | - aResult.push_back(char_array_3[i]); |
2889 | - i = 0; |
2890 | - } |
2891 | - } |
2892 | - |
2893 | - if (i) { |
2894 | - for (j = i; j <4; j++) |
2895 | - char_array_4[j] = 0; |
2896 | - |
2897 | - for (j = 0; j <4; j++) |
2898 | - char_array_4[j] = (char)base64_chars.find(char_array_4[j]); |
2899 | - |
2900 | - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); |
2901 | - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); |
2902 | - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; |
2903 | - |
2904 | - for (j = 0; (j < i - 1); j++) aResult.push_back(char_array_3[j]); |
2905 | - } |
2906 | + try { |
2907 | + base64::decode( |
2908 | + &aSource[0], aSource.size(), &aResult, |
2909 | + base64::dopt_any_len | base64::dopt_ignore_ws |
2910 | + ); |
2911 | + } |
2912 | + CATCH_BASE64_EXCEPTION() |
2913 | +} |
2914 | + |
2915 | +void Base64::decode( char const *from, size_t from_len, zstring *to ) { |
2916 | + try { |
2917 | + base64::decode( |
2918 | + from, from_len, to, base64::dopt_any_len | base64::dopt_ignore_ws |
2919 | + ); |
2920 | + } |
2921 | + CATCH_BASE64_EXCEPTION() |
2922 | } |
2923 | |
2924 | |
2925 | @@ -303,88 +171,12 @@ |
2926 | |
2927 | Base64::Base64(const unsigned char *bin_data, size_t len) |
2928 | { |
2929 | - std::vector<char> tmp; |
2930 | - tmp.reserve(len); |
2931 | - tmp.insert(tmp.begin(), (const char*)bin_data, ((const char*)bin_data) + len); |
2932 | - theData.reserve(len); |
2933 | - encode(tmp, theData); |
2934 | -} |
2935 | - |
2936 | - |
2937 | -void Base64::insertData(const char* str, size_t len) |
2938 | -{ |
2939 | - ascii::size_type pos = 0; |
2940 | - |
2941 | - ascii::skip_whitespace(str, len, &pos); |
2942 | - |
2943 | - for (size_t i = pos; i < len; ++i) |
2944 | - { |
2945 | - char lChar = str[i]; |
2946 | - |
2947 | - if (lChar == ' ') |
2948 | - { |
2949 | - // do nothing |
2950 | - } |
2951 | - else if ((lChar >= 65 && lChar <= 90) // A-Z |
2952 | - || (lChar >= 97 && lChar <= 122) // a-z |
2953 | - || (lChar >= 48 && lChar <= 57) // 0-9 |
2954 | - || (lChar == 43) // + |
2955 | - || (lChar == 47)) // / |
2956 | - { |
2957 | - theData.push_back(lChar); |
2958 | - } |
2959 | - else if (lChar == '=' && i > 0 && i == (len-2) && str[i+1] == '=' ) |
2960 | - { |
2961 | - if (str[i-1] == 'A' || |
2962 | - str[i-1] == 'Q' || |
2963 | - str[i-1] == 'g' || |
2964 | - str[i-1] == 'w') |
2965 | - { |
2966 | - theData.push_back('='); |
2967 | - theData.push_back('='); |
2968 | - ++i; |
2969 | - } |
2970 | - else |
2971 | - { |
2972 | - throw XQUERY_EXCEPTION( |
2973 | - err::FORG0001, ERROR_PARAMS( "==", ZED( Base64EqualsEquals ) ) |
2974 | - ); |
2975 | - } |
2976 | - } |
2977 | - else if (lChar == '=' && i > 0 && i == (len-1)) |
2978 | - { |
2979 | - switch(str[i-1]) |
2980 | - { |
2981 | - case 'A': case 'E': case 'I': case 'M': case 'Q': case 'U': case 'Y': |
2982 | - case 'c': case 'g': case 'k': case 'o': case 's': case 'w': case '0': |
2983 | - case '4': case '8': |
2984 | - theData.push_back('='); |
2985 | - break; |
2986 | - default: |
2987 | - throw XQUERY_EXCEPTION( |
2988 | - err::FORG0001, ERROR_PARAMS( '=', ZED( Base64Equals ) ) |
2989 | - ); |
2990 | - } |
2991 | - } |
2992 | - else if ( ascii::is_space(lChar) ) |
2993 | - { |
2994 | - // ignore it |
2995 | - } |
2996 | - else |
2997 | - { |
2998 | - throw XQUERY_EXCEPTION( |
2999 | - err::FORG0001, ERROR_PARAMS( str[i], ZED( Base64BadChar ) ) |
3000 | - ); |
3001 | - } |
3002 | - } |
3003 | - |
3004 | - if (theData.size() % 4 != 0) |
3005 | - { |
3006 | - throw XQUERY_EXCEPTION( |
3007 | - err::FORG0001, ERROR_PARAMS( "", ZED( Base64Multiple4 ) ) |
3008 | - ); |
3009 | - } |
3010 | -} |
3011 | + try { |
3012 | + base64::encode( (char const*)bin_data, len, &theData ); |
3013 | + } |
3014 | + CATCH_BASE64_EXCEPTION() |
3015 | +} |
3016 | + |
3017 | |
3018 | |
3019 | bool Base64::equal(const Base64& aBase64) const |
3020 | @@ -396,7 +188,7 @@ |
3021 | vector<char>::const_iterator lEnd0 = theData.end(); |
3022 | vector<char>::const_iterator lIter1 = aBase64.theData.begin(); |
3023 | |
3024 | - for (; lIter0 != lEnd0 ; ) |
3025 | + while ( lIter0 != lEnd0 ) |
3026 | { |
3027 | if (*lIter0 != *lIter1) |
3028 | return false; |
3029 | @@ -408,31 +200,28 @@ |
3030 | |
3031 | zstring Base64::str() const |
3032 | { |
3033 | - stringstream lStream; |
3034 | - lStream << *this; |
3035 | - return zstring(lStream.str()); |
3036 | + zstring result; |
3037 | + vector<char>::const_iterator lIter = theData.begin(); |
3038 | + vector<char>::const_iterator lEnd = theData.end(); |
3039 | + for( ; lIter != lEnd ; ++lIter) |
3040 | + { |
3041 | + result.push_back( *lIter ); |
3042 | + } |
3043 | + return result; |
3044 | } |
3045 | |
3046 | |
3047 | zstring Base64::decode() const |
3048 | { |
3049 | - vector<char> lDecodedData; |
3050 | - |
3051 | - Base64::decode(theData, lDecodedData); |
3052 | - |
3053 | zstring result; |
3054 | - result.reserve( lDecodedData.size() ); |
3055 | - |
3056 | - FOR_EACH( vector<char>, i, lDecodedData ) |
3057 | - result.push_back( *i ); |
3058 | - |
3059 | + base64::decode( &theData[0], theData.size(), &result ); |
3060 | return result; |
3061 | } |
3062 | |
3063 | |
3064 | void Base64::decode(vector<char>& aResult) |
3065 | { |
3066 | - Base64::decode(theData, aResult); |
3067 | + base64::decode( &theData[0], theData.size(), &aResult ); |
3068 | } |
3069 | |
3070 | |
3071 | @@ -466,6 +255,7 @@ |
3072 | return os; |
3073 | } |
3074 | |
3075 | +/////////////////////////////////////////////////////////////////////////////// |
3076 | |
3077 | const char* Base16::ENCODE_TABLE = "0123456789ABCDEF"; |
3078 | |
3079 | @@ -662,6 +452,7 @@ |
3080 | return os; |
3081 | } |
3082 | |
3083 | +/////////////////////////////////////////////////////////////////////////////// |
3084 | |
3085 | } // namespace zorba |
3086 | /* vim:set et sw=2 ts=2: */ |
3087 | |
3088 | === modified file 'src/zorbatypes/binary.h' |
3089 | --- src/zorbatypes/binary.h 2012-06-18 10:06:47 +0000 |
3090 | +++ src/zorbatypes/binary.h 2012-06-26 01:34:26 +0000 |
3091 | @@ -76,7 +76,9 @@ |
3092 | |
3093 | static void decode(const std::vector<char>&, std::vector<char>&); |
3094 | |
3095 | - static zstring decode(std::istream& aStream); |
3096 | + static void decode(std::istream& aStream, zstring*); |
3097 | + |
3098 | + static void decode(char const*, size_t, zstring*); |
3099 | |
3100 | public: |
3101 | Base64(const Base64& aBase64) |
3102 | @@ -90,8 +92,6 @@ |
3103 | |
3104 | Base64() {} |
3105 | |
3106 | - virtual ~Base64() {} |
3107 | - |
3108 | const std::vector<char>& getData() const { return theData; } |
3109 | |
3110 | size_t size() const { return theData.size(); } |
3111 | @@ -105,9 +105,6 @@ |
3112 | void decode(std::vector<char>&); |
3113 | |
3114 | uint32_t hash() const; |
3115 | - |
3116 | -private: |
3117 | - void insertData(const char* aCharStar, size_t len); |
3118 | }; |
3119 | |
3120 |
Did the streambuf api (already released in 2.5) change?