BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlde_base64decoder.h
Go to the documentation of this file.
1/// @file bdlde_base64decoder.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlde_base64decoder.h -*-C++-*-
8#ifndef INCLUDED_BDLDE_BASE64DECODER
9#define INCLUDED_BDLDE_BASE64DECODER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlde_base64decoder bdlde_base64decoder
15/// @brief Provide automata for converting to and from Base64 encodings.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlde
19/// @{
20/// @addtogroup bdlde_base64decoder
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlde_base64decoder-purpose"> Purpose</a>
25/// * <a href="#bdlde_base64decoder-classes"> Classes </a>
26/// * <a href="#bdlde_base64decoder-description"> Description </a>
27/// * <a href="#bdlde_base64decoder-base-64-encoding"> Base 64 Encoding </a>
28/// * <a href="#bdlde_base64decoder-base-64-encoding-with-url-and-filename-safe-alphabet"> Base 64 Encoding with URL and Filename Safe Alphabet </a>
29/// * <a href="#bdlde_base64decoder-base-64-decoding"> Base 64 Decoding </a>
30/// * <a href="#bdlde_base64decoder-usage"> Usage </a>
31/// * <a href="#bdlde_base64decoder-example-1-basic-usage"> Example 1: Basic Usage </a>
32///
33/// # Purpose {#bdlde_base64decoder-purpose}
34/// Provide automata for converting to and from Base64 encodings.
35///
36/// # Classes {#bdlde_base64decoder-classes}
37///
38/// - bdlde::Base64Decoder: automata performing Base64 decoding operations
39///
40/// @see bdlde_base64encoder
41///
42/// # Description {#bdlde_base64decoder-description}
43/// This component a `class`, `bdlde::Base64Decoder`, which
44/// provides a pair of template functions (each parameterized separately on both
45/// input and output iterators) that can be used respectively to encode and to
46/// decode byte sequences of arbitrary length into and from the printable Base64
47/// representation described in Section 6.8 "Base64 Content Transfer Encoding"
48/// of RFC 2045, "Multipurpose Internet Mail Extensions (MIME) Part One: Format
49/// of Internet Message Bodies."
50///
51/// The `bdlde::Base64Encoder` and `bdlde::Base64Decoder` support the standard
52/// "base64" encoding (described in https://tools.ietf.org/html/rfc4648) as well
53/// as the "Base 64 Encoding with URL and Filename Safe Alphabet", or
54/// "base64url", encoding. The "base64url" encoding is very similar to "base64"
55/// but substitutes a couple characters in the encoded alphabet to avoid
56/// characters that conflict with special characters in URL syntax or filename
57/// descriptions (replacing `+` for `-`. and `/` for `_`). See
58/// {Base 64 Encoding with URL and Filename Safe Alphabet} for more information.
59///
60/// Each instance of either the encoder or decoder retains the state of the
61/// conversion from one supplied input to the next, enabling the processing of
62/// segmented input -- i.e., processing resumes where it left off with the next
63/// invocation on new input. Instance methods are provided for both the
64/// encoder and decoder to (1) assert the end of input, (2) determine whether
65/// the input so far is currently acceptable, and (3) indicate whether a
66/// non-recoverable error has occurred.
67///
68/// ## Base 64 Encoding {#bdlde_base64decoder-base-64-encoding}
69///
70///
71/// The data stream is processed three bytes at a time from left to right (a
72/// final quantum consisting of one or two bytes, as discussed below, is handled
73/// specially). Each sequence of three 8-bit quantities
74/// @code
75/// 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
76/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77/// | | | |
78/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79/// `------v------' `------v------' `------v------'
80/// Byte2 Byte1 Byte0
81/// @endcode
82/// is segmented into four intermediate 6-bit quantities.
83/// @code
84/// 5 4 3 2 1 0 5 4 3 2 1 0 5 4 3 2 1 0 5 4 3 2 1 0
85/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86/// | | | | |
87/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88/// `----v----' `----v----' `----v----' `----v----'
89/// char3 char2 char1 char0
90/// @endcode
91/// Each 6-bit quantity is in turn used as an index into the following character
92/// table to generate an 8-bit character. The four resulting characters hence
93/// form the encoding for the original 3-byte sequence.
94/// @code
95/// ======================================================================
96/// * The Basic BASE-64 Alphabet *
97/// ----------------------------------------------------------------------
98/// Val Enc Val Enc Val Enc Val Enc Val Enc Val Enc Val Enc Val Enc
99/// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
100/// 0 'A' 8 'I' 16 'Q' 24 'Y' 32 'g' 40 'o' 48 'w' 56 '4'
101/// 1 'B' 9 'J' 17 'R' 25 'Z' 33 'h' 41 'p' 49 'x' 57 '5'
102/// 2 'C' 10 'K' 18 'S' 26 'a' 34 'i' 42 'q' 50 'y' 58 '6'
103/// 3 'D' 11 'L' 19 'T' 27 'b' 35 'j' 43 'r' 51 'z' 59 '7'
104/// 4 'E' 12 'M' 20 'U' 28 'c' 36 'k' 44 's' 52 '0' 60 '8'
105/// 5 'F' 13 'N' 21 'V' 29 'd' 37 'l' 45 't' 53 '1' 61 '9'
106/// 6 'G' 14 'O' 22 'W' 30 'e' 38 'm' 46 'u' 54 '2' 62 '+'
107/// 7 'H' 15 'P' 23 'X' 31 'f' 39 'n' 47 'v' 55 '3' 63 '/'
108/// ======================================================================
109/// @endcode
110/// This component also supports a slightly different alphabet, "base64url",
111/// that is more appropriate if the encoded representation would be used in a
112/// file name or URL (see
113/// {Base 64 Encoding with URL and Filename Safe Alphabet}).
114///
115/// The 3-byte grouping of the input is only a design of convenience and not a
116/// requirement. When the number of bytes in the input stream is not divisible
117/// by 3, sufficient 0 bits are padded on the right to achieve an integral
118/// number of 6-bit character indices. Then one of two special cases will apply
119/// for the final processing step:
120///
121/// I) There is a single byte of data, in which case there will be two Base64
122/// encoding characters (the second of which will be one of [AQgw]) followed by
123/// two equal (`=`) signs.
124///
125/// II) There are exactly two bytes of data, in which case there will be
126/// three Base64 encoding characters (the third of which will be one of
127/// [AEIMQUYcgkosw048] followed by a single equal (`=`) sign.
128///
129/// The MIME standard requires that the maximum line length of emitted text not
130/// exceed 76 characters exclusive of CRLF. The caller may override this
131/// default if desired.
132///
133/// Input values of increasing length along with their corresponding Base64
134/// encodings are illustrated below:
135/// @code
136/// Data: /* nothing */
137/// Encoding: /* nothing */
138///
139/// Data: 0x01
140/// Encoding: AQ==
141///
142/// Data: 0x01 0x02
143/// Encoding: AQI=
144///
145/// Data: 0x01 0x02 0x03
146/// Encoding: AQID
147///
148/// Data: 0x01 0x02 0x03 0x04
149/// Encoding: AQIDBA==
150/// @endcode
151/// In order for a Base64 encoding to be valid, the input data must be either of
152/// length a multiple of three (constituting maximal input), or have been
153/// terminated explicitly by the `endConvert` method (initiating bit padding
154/// when necessary).
155///
156/// ## Base 64 Encoding with URL and Filename Safe Alphabet {#bdlde_base64decoder-base-64-encoding-with-url-and-filename-safe-alphabet}
157///
158///
159/// The encoder and decoder in this component also support the "base64url"
160/// encoding, which is the same as standard "base64" but substitutes (a couple)
161/// characters in the alphabet that are treated as special characters when used
162/// in a URL or in a file system. The following table is technically identical
163/// to the table presented in {Base 64 Encoding}, except for the 62:nd and 63:rd
164/// alphabet character, that indicates `-` and `_` respectively.
165/// @code
166/// ======================================================================
167/// * The "URL and Filename Safe" BASE-64 Alphabet *
168/// ----------------------------------------------------------------------
169/// Val Enc Val Enc Val Enc Val Enc Val Enc Val Enc Val Enc Val Enc
170/// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
171/// 0 'A' 8 'I' 16 'Q' 24 'Y' 32 'g' 40 'o' 48 'w' 56 '4'
172/// 1 'B' 9 'J' 17 'R' 25 'Z' 33 'h' 41 'p' 49 'x' 57 '5'
173/// 2 'C' 10 'K' 18 'S' 26 'a' 34 'i' 42 'q' 50 'y' 58 '6'
174/// 3 'D' 11 'L' 19 'T' 27 'b' 35 'j' 43 'r' 51 'z' 59 '7'
175/// 4 'E' 12 'M' 20 'U' 28 'c' 36 'k' 44 's' 52 '0' 60 '8'
176/// 5 'F' 13 'N' 21 'V' 29 'd' 37 'l' 45 't' 53 '1' 61 '9'
177/// 6 'G' 14 'O' 22 'W' 30 'e' 38 'm' 46 'u' 54 '2' 62 '-'
178/// 7 'H' 15 'P' 23 'X' 31 'f' 39 'n' 47 'v' 55 '3' 63 '_'
179/// ======================================================================
180/// @endcode
181/// ## Base 64 Decoding {#bdlde_base64decoder-base-64-decoding}
182///
183///
184/// The degree to which decoding detects errors can significantly affect
185/// performance. The standard permits all non-Base64 characters to be treated
186/// as whitespace. One variant mode of this decoder does just that; the other
187/// reports an error if a bad (i.e., non-whitespace) character is detected. The
188/// mode of the instance is configurable. The standard imposes a maximum of 76
189/// characters exclusive of CRLF; however, the decoder implemented in this
190/// component will handle lines of arbitrary length.
191///
192/// The following kinds of errors can occur during decoding and are reported
193/// with the following priority:
194/// @code
195/// BAD DATA: A character (other than whitespace) that is not a member of the
196/// Base64 character set (including '='). Note that this error
197/// is detected only if the 'decoder' is explicitly configured (at
198/// construction) to do so.
199///
200/// BAD FORMAT: An '=' character precedes a valid numeric Base64 character,
201/// more than two '=' characters appear (possibly separated by
202/// non-Base64 characters), a numeric Base64 character other than
203/// [AEIMQUYcgkosw048] precedes a single terminal '=' character,
204/// or a character other than [AQgw] precedes a terminal pair of
205/// consecutive '=' characters.
206/// @endcode
207/// The `isError` method is used to detect such anomalies, and the `numIn`
208/// output parameter (indicating the number of input characters consumed)
209/// or possibly the iterator itself (for iterators with reference-semantics)
210/// identifies the offending character.
211///
212/// Note that the existence of an `=` can be used to reliably indicate the end
213/// of the valid data, but no such assurance is possible when the length (in
214/// bytes) of the initial input data sequence before encoding was evenly
215/// divisible by 3.
216///
217/// ## Usage {#bdlde_base64decoder-usage}
218///
219///
220/// This section illustrates intended use of this component.
221///
222/// ### Example 1: Basic Usage {#bdlde_base64decoder-example-1-basic-usage}
223///
224///
225/// The following example shows how to use a `bdlde::Base64Decoder` object to
226/// implement a function, `streamconverter`, that reads text from a
227/// `bsl::istream`, decodes that text from base 64 representation, and writes
228/// the decoded text to a `bsl::ostream`. `streamconverter` returns 0 on
229/// success and a negative value if the input data could not be successfully
230/// decoded or if there is an I/O error.
231///
232/// streamdecoder.cpp -*-C++-*-
233///
234/// #include <streamdecoder.h>
235///
236/// #include <bdlde_base64decoder.h>
237///
238/// @code
239/// /// Read the entire contents of the specified input stream `is`, convert
240/// /// the input base-64 encoding into plain text, and write the decoded text
241/// /// to the specified output stream `os`. Return 0 on success, and a
242/// /// negative value otherwise.
243/// int streamDecoder(bsl::ostream& os, bsl::istream& is)
244/// {
245/// enum {
246/// SUCCESS = 0,
247/// DECODE_ERROR = -1,
248/// IO_ERROR = -2
249/// };
250/// @endcode
251/// We declare a `bdlde::Base64Decoder` object `converter`, which will decode
252/// the input data. Note that various internal buffers and cursors are used as
253/// needed without further comment. We read as much data as is available from
254/// the user-supplied input stream `is` *or* as much as will fit in
255/// `inputBuffer` before beginning conversion. To obtain unobstructedly the
256/// output that results from decoding the entire input stream (even in the case
257/// of errors), the base64 decoder is configured not to detect errors.
258/// @code
259/// bdlde::Base64Decoder converter(
260/// bdlde::Base64DecoderOptions::standard());
261///
262/// const int INBUFFER_SIZE = 1 << 10;
263/// const int OUTBUFFER_SIZE = 1 << 10;
264/// @endcode
265/// We will use fixed-sized input and output buffers in the implementation, but,
266/// because of the flexibility of `bsl::istream` and the output-buffer
267/// monitoring functionality of `bdlde::Base64Decoder`, the fixed buffer sizes
268/// do *not* limit the quantity of data that can be read, decoded, or written to
269/// the output stream. The implementation file is as follows.
270/// @code
271/// char inputBuffer[INBUFFER_SIZE];
272/// char outputBuffer[OUTBUFFER_SIZE];
273///
274/// char *output = outputBuffer;
275/// char *outputEnd = outputBuffer + sizeof outputBuffer;
276///
277/// while (is.good()) { // input stream not exhausted
278///
279/// is.read(inputBuffer, sizeof inputBuffer);
280/// @endcode
281/// With `inputBuffer` now populated, we'll use `converter` in an inner `while`
282/// loop to decode the input and write the decoded data to `outputBuffer` (via
283/// the `output` cursor'). Note that if the call to `converter.convert` fails,
284/// our function terminates with a negative status.
285/// @code
286/// const char *input = inputBuffer;
287/// const char *inputEnd = input + is.gcount();
288///
289/// while (input < inputEnd) { // input encoding not complete
290///
291/// int numOut;
292/// int numIn;
293///
294/// int status = converter.convert(
295/// output,
296/// &numOut,
297/// &numIn,
298/// input,
299/// inputEnd,
300/// static_cast<int>(outputEnd - output));
301/// if (status < 0) {
302/// return DECODE_ERROR; // RETURN
303/// }
304/// @endcode
305/// If the call to `converter.convert` returns successfully, we'll see if the
306/// output buffer is full, and if so, write its contents to the user-supplied
307/// output stream `os`. Note how we use the values of `numOut` and `numIn`
308/// generated by `convert` to update the relevant cursors.
309/// @code
310/// output += numOut;
311/// input += numIn;
312///
313/// if (output == outputEnd) { // output buffer full; write data
314/// os.write(outputBuffer, sizeof outputBuffer);
315/// if (os.fail()) {
316/// return IO_ERROR; // RETURN
317/// }
318/// output = outputBuffer;
319/// }
320/// }
321/// }
322/// @endcode
323/// We have now exited both the input and the "decode" loops. `converter` may
324/// still hold decoded output characters, and so we call `converter.endConvert`
325/// to emit any retained output. To guarantee correct behavior, we call this
326/// method in an infinite loop, because it is possible that the retained output
327/// can fill the output buffer. In that case, we solve the problem by writing
328/// the contents of the output buffer to `os` within the loop. The most likely
329/// case, however, is that `endConvert` will return 0, in which case we exit the
330/// loop and write any data remaining in `outputBuffer` to `os`. As above, if
331/// `endConvert` fails, we exit the function with a negative return status.
332/// @code
333/// while (1) {
334///
335/// int numOut;
336///
337/// int more = converter.endConvert(
338/// output,
339/// &numOut,
340/// static_cast<int>(outputEnd - output));
341/// if (more < 0) {
342/// return DECODE_ERROR; // RETURN
343/// }
344///
345/// output += numOut;
346///
347/// if (!more) { // no more output
348/// break;
349/// }
350///
351/// assert(output == outputEnd); // output buffer is full
352///
353/// os.write (outputBuffer, sizeof outputBuffer); // write buffer
354/// if (os.fail()) {
355/// return IO_ERROR; // RETURN
356/// }
357/// output = outputBuffer;
358/// }
359///
360/// if (output > outputBuffer) {
361/// os.write (outputBuffer, output - outputBuffer);
362/// }
363///
364/// return is.eof() && os.good() ? SUCCESS : IO_ERROR;
365/// }
366/// @endcode
367/// @}
368/** @} */
369/** @} */
370
371/** @addtogroup bdl
372 * @{
373 */
374/** @addtogroup bdlde
375 * @{
376 */
377/** @addtogroup bdlde_base64decoder
378 * @{
379 */
380
381#include <bdlscm_version.h>
382
383#include <bdlde_base64alphabet.h>
386
387#include <bslmf_assert.h>
388
389#include <bsls_alignedbuffer.h>
390#include <bsls_assert.h>
392#include <bsls_performancehint.h>
393#include <bsls_review.h>
394#include <bsls_types.h>
395
396#include <bsl_cstring.h>
397#include <bsl_cstdint.h>
398#include <bsl_iostream.h>
399
400#ifdef __SSE4_2__
401#include <emmintrin.h>
402#include <smmintrin.h>
403#include <tmmintrin.h>
404#endif
405
406
407namespace bdlde {
408
409 // ===================
410 // class Base64Decoder
411 // ===================
412
413/// This class implements a mechanism capable of converting data of
414/// arbitrary length from its corresponding Base64 representation.
415///
416/// See @ref bdlde_base64decoder
418
419 public:
420 // PUBLIC TYPES
422
423 // PUBLIC CONSTANTS
426
427 private:
428 // PRIVATE TYPES
431
432 enum State {
433 // Symbolic state values.
434
435 e_ERROR_STATE = -1, // input is irreparably invalid
436 e_INPUT_STATE = 0, // general input state
437 e_NEED_EQUAL_STATE = 1, // need an '='
438 e_SOFT_DONE_STATE = 2, // only ignorable input and 'endConvert'
439 e_DONE_STATE = 3 // any additional input is an error
440 };
441
442 // INSTANCE DATA
443 int d_outputLength; // total number of output
444 // characters
445
446 const char *const d_alphabet_p; // selected alphabet based on
447 // specified alphabet type
448
449 const bool *const d_ignorable_p; // selected table of ignorable
450 // characters based on specified
451 // error-reporting mode
452
453 unsigned d_stack; // word containing 6-bit chunks of
454 // data to be assembled into bytes
455
456 int d_bitsInStack; // number of bits in 'd_stack'
457
458 State d_state; // state of this object as defined
459 // by the 'State' enum.
460
461 const Alphabet d_alphabet; // 'e_BASIC' or 'e_URL'.
462
463 const IgnoreMode::Enum d_ignoreMode; // 'e_IGNORE_NONE',
464 // 'e_IGNORE_WHITESPACE', or
465 // 'e_IGNORE_UNRECOGNIZED'
466
467 const bool d_isPadded; // 'true' means '=' padding is
468 // required, 'false' means '=' is
469 // an error
470
471 private:
472 // NOT IMPLEMENTED
474 Base64Decoder& operator=(const Base64Decoder&);
475
476 // PRIVATE ACCESSORS
477
478 /// Return the number bits of output there are (either already done or
479 /// to be done) since the end of the last 4-bytes of input.
480 ///
481 /// \note Note that input to this decoder, other than ignored whitespace or garbage,
482 /// comes in 4 byte quads, each of which results in 3 bytes of output,
483 /// and this accessor is particularly useful in calculating output for
484 /// the last partial quad of input.
485 int residualBits(int bytesOutputSoFar) const;
486
487 public:
488 // CLASS METHODS
489
490 /// Return the maximum number of decoded bytes that could result from an
491 /// input byte sequence of the specified `inputLength` provided to the
492 /// `convert` and `endConvert` methods of this decoder.
493 ///
494 /// \pre The behavior is undefined unless `0 <= inputLength`.
495 /// \note Note that the result is
496 /// independent of which options are provided to the decoder.
497 static int maxDecodedLength(int inputLength);
498
499 // CREATORS
500
501 /// Create a Base64 decoder with options determined by the specfied
502 /// `options`.
503 explicit
505
506 /// Create a decoder expecting padded encoding.
507 ///
508 /// @deprecated Use the overload that takes `options` instead, for example
509 /// @code
510 /// Base64Decoder(Base64DecoderOptions::custom(
511 /// unrecognizedNonWhitespaceIsErrorFlag
512 /// ? e_IGNORE_WHITESPACE,
513 /// : e_IGNORE_UNRECOGNIZED,
514 /// alphabet,
515 /// true));
516 /// @endcode
517 BSLS_DEPRECATE_FEATURE("bdl", "Base64Decoder", "use options c'tor")
518 explicit
519 Base64Decoder(bool unrecognizedNonWhitespaceIsErrorFlag,
521
522 /// Destroy this object.
524
525 // MANIPULATORS
526
527 /// Decode the sequence of input characters starting at the specified
528 /// `begin` position up to, but not including, the specified `end`
529 /// position, writing any resulting output characters to the specified
530 /// `out` buffer. Optionally specify the `maxNumOut` limit on the
531 /// number of bytes to output; if `maxNumOut` is negative, no limit is
532 /// imposed. If the `maxNumOut` limit is reached, no further input will
533 /// be consumed. Load into the (optionally) specified `numOut` and
534 /// `numIn` the number of output bytes produced and input bytes
535 /// consumed, respectively. Return a non-negative value on success, -1
536 /// on an input error, and -2 if the `endConvert` method has already
537 /// been called without an intervening `resetState` call. A return
538 /// status of -1 indicates that the data at `begin` + `numIn`
539 /// constitutes an irrecoverably undecodable input sequence (i.e., the
540 /// data cannot be extended to form any valid encoding). A positive
541 /// return status indicates the number of valid processed output bytes
542 /// retained by this decoder and not written to `out` because
543 /// `maxNumOut` has been reached; these bytes are available for output if this method is called with appropriate input.
544 ///
545 /// \note Note that it is
546 /// recommended that after all calls to `convert` are finished, the
547 /// `endConvert` method be called to complete the encoding of any
548 /// unprocessed input characters that do not complete a 3-byte sequence.
549 template <class OUTPUT_ITERATOR, class INPUT_ITERATOR>
550 int convert(OUTPUT_ITERATOR out,
551 INPUT_ITERATOR begin,
552 INPUT_ITERATOR end);
553 template <class OUTPUT_ITERATOR, class INPUT_ITERATOR>
554 int convert(OUTPUT_ITERATOR out,
555 int *numOut,
556 int *numIn,
557 INPUT_ITERATOR begin,
558 INPUT_ITERATOR end,
559 int maxNumOut = -1);
560
561 /// Terminate decoding for this decoder; write any retained output
562 /// (e.g., from a previous call to `convert` with a non-zero optionally
563 /// specified `maxNumOut` argument) to the specified `out` buffer;
564 /// encode any unprocessed input characters that do not complete a
565 /// 3-byte sequence. The argument `maxNumOut` is the limit on the
566 /// number of bytes to output; if `maxNumOut` is negative, no limit is
567 /// imposed. Load into the (optionally) specified `numOut` the number
568 /// of output bytes produced. Return 0 on success, the positive number
569 /// of bytes *still* retained by this decoder if the `maxNumOut` limit
570 /// was reached, and a negative value otherwise. Any retained bytes are
571 /// available on a subsequent call to `endConvert`. Once this method is
572 /// called, no additional input may be supplied without an intervening
573 /// call to `resetState`; once this method returns a zero status, a
574 /// subsequent call will place this decoder in the error state, and
575 /// return an error status.
576 template <class OUTPUT_ITERATOR>
577 int endConvert(OUTPUT_ITERATOR out);
578 template <class OUTPUT_ITERATOR>
579 int endConvert(OUTPUT_ITERATOR out,
580 int *numOut,
581 int maxNumOut = -1);
582
583 /// Reset this instance to its initial state (i.e., as if no input had
584 /// been consumed).
585 void resetState();
586
587 // ACCESSORS
588
589 /// Return the alphabet supplied at construction of this object.
590 Alphabet alphabet() const;
591
592 /// Return the `ignoreMode` state of this decoder.
593 IgnoreMode::Enum ignoreMode() const;
594
595 /// Return `true` if the input read so far is considered syntactically complete, and `false` otherwise.
596 ///
597 /// \note Note that the number of relevant
598 /// input characters must be divisible by 4.
599 bool isAcceptable() const;
600
601 /// Return `true` if the current input is acceptable and any additional
602 /// input (including `endConvert`) would be an error, and `false` otherwise.
603 ///
604 /// \note Note that if this decoder `isDone` then all resulting
605 /// output has been emitted to `out`.
606 bool isDone() const;
607
608 /// Return `true` if there is no possibility of achieving an
609 /// "acceptable" result, and `false` otherwise.
610 bool isError() const;
611
612 /// Return `true` if this instance is in the initial state (i.e., as
613 /// if no input had been consumed), and `false` otherwise.
614 bool isInitialState() const;
615
616 /// Return `true` if the current input is acceptable and any additional
617 /// input (other than `endConvert`) would be an error, and `false`
618 /// otherwise.
619 bool isMaximal() const;
620
621 /// Return `true` if this object is configured for padded input and
622 /// `false` otherwise.
623 bool isPadded() const;
624
625 /// Return `true` if this mechanism is currently configured to report an
626 /// error when an unrecognized character (i.e., a character other than
627 /// one of the 64 "numeric" base-64 characters, `=`, or whitespace) is
628 /// encountered, and `false` otherwise.
629 ///
630 /// @deprecated use the `ignoreMode` accessor instead.
632 bool isUnrecognizedAnError() const;
633
634 /// Return a `Base64DecoderOptions` object representing the
635 /// configuration of this decoder.
636 DecoderOptions options() const;
637
638 /// Return the total length of the output emitted thus far.
639 int outputLength() const;
640};
641
642// ============================================================================
643// INLINE DEFINITIONS
644// ============================================================================
645
646 // -------------------
647 // class Base64Decoder
648 // -------------------
649
650// PRIVATE CLASS METHODS
651inline
652int Base64Decoder::residualBits(int bytesOutputSoFar) const
653{
654 BSLS_ASSERT(0 <= bytesOutputSoFar);
655 BSLS_ASSERT(0 <= d_bitsInStack);
656
657 // If one byte has been read since that last completed quad of input, the
658 // result will be 6, and it will be an error if no more input is available.
659 //
660 // If two bytes have been read since the last complete quad of input, the
661 // result will be 12, and if input is done:
662 //: o If all output has been done, 'd_stack == 0'
663 //:
664 //: o If a byte of output remains to be done, the low-order 4 bytes of
665 //: 'd_stack' should be 0.
666 //
667 // If three bytes have been read since the last complete quad of input, the
668 // result will be 18, and if input is done,
669 //: o If the last 2 bytes of output have been done, the low-order 2 bytes
670 //: of 'd_stack' should be 0.
671 //:
672 //: o If one of the last 2 bytes of output have been done, there will be 10
673 //: bits in the stack, the low-order 2 bits of which should be 0.
674 //:
675 //: o If none of the last 2 bytes of output to be done, there will be 18
676 //: bits in the stack, the low-order 2 bits of which will be 0.
677
678 int ret = ((bytesOutputSoFar % 3) * 8 + d_bitsInStack) % 24;
679 BSLS_ASSERT(e_INPUT_STATE != d_state || 0 == ret % 6);
680 return ret;
681}
682
683// CLASS METHODS
684inline
686{
687 BSLS_ASSERT(0 <= inputLength);
688
689 return (inputLength + 3) / 4 * 3;
690}
691
692// MANIPULATORS
693template <class OUTPUT_ITERATOR, class INPUT_ITERATOR>
694int Base64Decoder::convert(OUTPUT_ITERATOR out,
695 INPUT_ITERATOR begin,
696 INPUT_ITERATOR end)
697{
698 int dummyNumOut;
699 int dummyNumIn;
700
701 return convert(out, &dummyNumOut, &dummyNumIn, begin, end, -1);
702}
703
704template <class OUTPUT_ITERATOR, class INPUT_ITERATOR>
705int Base64Decoder::convert(OUTPUT_ITERATOR out,
706 int *numOut,
707 int *numIn,
708 INPUT_ITERATOR begin,
709 INPUT_ITERATOR end,
710 int maxNumOut)
711{
712 BSLS_ASSERT(numOut);
713 BSLS_ASSERT(numIn);
714
715 if (e_ERROR_STATE == d_state || e_DONE_STATE == d_state) {
716 int rv = e_DONE_STATE == d_state ? -2 : -1;
717 d_state = e_ERROR_STATE;
718 *numOut = 0;
719 *numIn = 0;
720 return rv; // RETURN
721 }
722
723 int numEmitted = 0;
724
725 // Emit as many output bytes as possible.
726
727 while (8 <= d_bitsInStack && numEmitted != maxNumOut) {
728 d_bitsInStack -= 8;
729 *out = static_cast<char>((d_stack >> d_bitsInStack) & 0xff);
730 ++out;
731 ++numEmitted;
732 }
733
734 // Consume as many input bytes as possible.
735
736 *numIn = 0;
737
738 if (e_INPUT_STATE == d_state) {
739 while (18 >= d_bitsInStack && begin != end) {
740 const unsigned char byte = static_cast<unsigned char>(*begin);
741
742 ++begin;
743 ++*numIn;
744
745 unsigned char converted = static_cast<unsigned char>(
746 d_alphabet_p[byte]);
747
748 if (converted < 64) {
749 d_stack = (d_stack << 6) | converted;
750 d_bitsInStack += 6;
751 if (8 <= d_bitsInStack && numEmitted != maxNumOut) {
752 d_bitsInStack -= 8;
753 *out = static_cast<char>(
754 (d_stack >> d_bitsInStack) & 0xff);
755 ++out;
756 ++numEmitted;
757 }
758 }
759 else if (!d_ignorable_p[byte]) {
760 if ('=' == byte && d_isPadded) {
761 const int residual = residualBits(
762 d_outputLength + numEmitted);
763 // 'residual' is 0, 6, 12, or 18.
764 //: o If it's 0, that's an error since no '=' should be
765 //: needed.
766 //:
767 //: o If it's 6, that's an error because an incomplete
768 //: byte has been input.
769 //:
770 //: o 12 means 2 bytes have been read, meaning we have to
771 //: do 1 byte of output (which we may have already done).
772 //: The low-order 4 bits of stack should either be
773 //: 0 or the stack should be empty.
774 //:
775 //: o 18 means 3 bytes have been read, meaning we have to
776 //: do 2 bytes of output (some or all of which we may
777 //: have already done). The low-order 2 bits of stack
778 //: should either be 0 or the stack should be empty.
779
780 const int leftOver = residual % 8;
781 d_state = 0 != (d_stack & ((1 << leftOver) - 1))
782 ? e_ERROR_STATE
783 : 12 == residual
784 ? e_NEED_EQUAL_STATE
785 : 18 == residual
786 ? e_SOFT_DONE_STATE
787 : e_ERROR_STATE;
788 d_stack >>= leftOver;
789 d_bitsInStack -= leftOver;
790 }
791 else {
792 d_state = e_ERROR_STATE;
793 }
794 break;
795 }
796 }
797 }
798
799 if (e_NEED_EQUAL_STATE == d_state) {
800 BSLS_ASSERT(d_isPadded);
801
802 while (begin != end) {
803 const unsigned char byte = static_cast<unsigned char>(*begin);
804
805 ++begin;
806 ++*numIn;
807
808 if (!d_ignorable_p[byte]) {
809 if ('=' == byte) {
810 d_state = e_SOFT_DONE_STATE;
811 }
812 else {
813 d_state = e_ERROR_STATE;
814 }
815 break;
816 }
817 }
818 }
819 if (e_SOFT_DONE_STATE == d_state) {
820 while (begin != end) {
821 const unsigned char byte = static_cast<unsigned char>(*begin);
822
823 ++begin;
824 ++*numIn;
825
826 if (!d_ignorable_p[byte]) {
827 d_state = e_ERROR_STATE;
828 break;
829 }
830 }
831 }
832
833 *numOut = numEmitted;
834 d_outputLength += numEmitted;
835
836 return e_ERROR_STATE == d_state ? -1 : d_bitsInStack / 8;
837}
838
839template<>
840inline
841int Base64Decoder::convert<char *, const char *>(
842 char *out,
843 int *numOut,
844 int *numIn,
845 const char *begin,
846 const char *end,
847 int maxNumOut)
848{
849 BSLS_ASSERT(numOut);
850 BSLS_ASSERT(numIn);
851
853 e_ERROR_STATE == d_state || e_DONE_STATE == d_state)) {
854 int rv = e_DONE_STATE == d_state ? -2 : -1;
855 d_state = e_ERROR_STATE;
856 *numOut = 0;
857 *numIn = 0;
858 return rv; // RETURN
859 }
860
861 int numEmitted = 0;
862
863 // Emit as many output bytes as possible.
864
865 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(8 <= d_bitsInStack)) {
866 while (8 <= d_bitsInStack && numEmitted != maxNumOut) {
867 d_bitsInStack -= 8;
868 *out = static_cast<char>((d_stack >> d_bitsInStack) & 0xff);
869 ++out;
870 ++numEmitted;
871 }
872 }
873
874 // Consume as many input bytes as possible.
875
876 const char *originalBegin = begin;
877
878 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(e_INPUT_STATE == d_state)) {
879 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(d_bitsInStack == 0)) {
880 // Optimize for common case
881#ifdef __SSE4_2__
882 // Load 16-byte slices of LUT. Note that the entire 256-byte LUT
883 // is *not* loaded, but only the middle slices that are non-ff.
884 const __m128i *alphabetSlices =
885 reinterpret_cast<const __m128i *>(d_alphabet_p);
886 __m128i lut5 = _mm_loadu_si128(alphabetSlices + 7);
887 __m128i lut4 = _mm_loadu_si128(alphabetSlices + 6);
888 __m128i lut3 = _mm_loadu_si128(alphabetSlices + 5);
889 __m128i lut2 = _mm_loadu_si128(alphabetSlices + 4);
890 __m128i lut1 = _mm_loadu_si128(alphabetSlices + 3);
891 __m128i lut0 = _mm_loadu_si128(alphabetSlices + 2);
892
893 // Heavily inspired by techniques outlined in
894 // http://0x80.pl/notesen/2016-01-17-sse-base64-decoding.html
895
896 // xor LUT fragments together for pshufb-xor chaining below.
897 lut5 = _mm_xor_si128(lut5, lut4);
898 lut4 = _mm_xor_si128(lut4, lut3);
899 lut3 = _mm_xor_si128(lut3, lut2);
900 lut2 = _mm_xor_si128(lut2, lut1);
901 lut1 = _mm_xor_si128(lut1, lut0);
902
903 while (end - begin >= 16 && static_cast<unsigned>(numEmitted + 12)
904 <= static_cast<unsigned>(maxNumOut)) {
905 // Load 16 base64 characters (will eventually be transformed
906 // into 12 bytes)
907 __m128i x = _mm_loadu_si128(
908 reinterpret_cast<const __m128i *>(begin));
909
910 // Offset indexes to match first LUT slice at offset 0x20
911 x = _mm_subs_epi8(x, _mm_set1_epi8(0x20));
912
913 // If indexes were < 0x20, 'x' will contain negative values
914 // which we will check for later (minimum bounds check)
915 __m128i tooSmall = x;
916
917 // Using the characters as indexes, look up the corresponding
918 // values from the LUT. If an index is non-negative, only its
919 // low 4 bits are considered. If an index is negative, 0 is
920 // returned for its lookup value.
921 __m128i decoded = _mm_shuffle_epi8(lut0, x);
922
923 // Advance to the next LUT slice. Note that if the previous
924 // slice was the correct one for a given index, the index will
925 // become negative after this, resulting in subsequent lookups
926 // simply xor-ing 0 (harmless no-ops).
927 x = _mm_subs_epi8(x, _mm_set1_epi8(0x10));
928
929 // Perform the next lookup using the same low 4 bits of each
930 // non-negative index. The result is then xor-ed with the
931 // previous lookup result. For negative indices, this is a
932 // no-op, while for non-negative indices, the xor with the
933 // previous LUT slice value cancels out the xor-ing done to the
934 // LUT slices above the loop, leaving the original value from
935 // this LUT slice.
936 decoded = _mm_xor_si128(decoded, _mm_shuffle_epi8(lut1, x));
937
938 // Continue to advance to each LUT slice
939 x = _mm_subs_epi8(x, _mm_set1_epi8(0x10));
940 decoded = _mm_xor_si128(decoded, _mm_shuffle_epi8(lut2, x));
941 x = _mm_subs_epi8(x, _mm_set1_epi8(0x10));
942 decoded = _mm_xor_si128(decoded, _mm_shuffle_epi8(lut3, x));
943 x = _mm_subs_epi8(x, _mm_set1_epi8(0x10));
944 decoded = _mm_xor_si128(decoded, _mm_shuffle_epi8(lut4, x));
945 x = _mm_subs_epi8(x, _mm_set1_epi8(0x10));
946 decoded = _mm_xor_si128(decoded, _mm_shuffle_epi8(lut5, x));
947 x = _mm_subs_epi8(x, _mm_set1_epi8(0x10));
948
949 // At this point, the indexes in 'x' should be negative, as
950 // we've exhausted all populated LUT slices. If any are not,
951 // that indicates the maximum bounds check failed.
952
953 // Check the minimum and maximum bounds were respected, as well
954 // as for any 'ff' values loaded from LUT slices themselves.
956 !_mm_testz_si128(tooSmall | decoded | ~x,
957 _mm_set1_epi8(static_cast<char>(0x80))))) {
958 // Unknown char; could be error or could be a character to
959 // ignore; either way fall back to regular decoding
960 break;
961 }
962
963 // 'decoded' currently contains dwords layed out like
964 // |00aaaaaa|00bbbbbb|00cccccc|00dddddd|. Convert to
965 // |0000aaaa aabbbbbb|0000cccc ccdddddd| with a multiply-add.
966 decoded = _mm_maddubs_epi16(decoded, _mm_set1_epi16(0x0140));
967
968 // Convert to final form of
969 // |00000000 aaaaaabb bbbbcccc ccdddddd| with another multiply-
970 // add. Note that each triplet of values is aligned to a byte
971 // boundary following this operation.
972 decoded = _mm_madd_epi16(decoded, _mm_set1_epi32(0x00011000));
973
974 // Take care of endianness and last four one-byte gaps by
975 // explicitly selecting each byte we want in order.
976 __m128i selection = _mm_set_epi64(
977 reinterpret_cast<__m64>(0xffffffff0c0d0e08ull),
978 reinterpret_cast<__m64>(0x090a040506000102ull));
979 decoded = _mm_shuffle_epi8(decoded, selection);
980
981 // Store the result
982 memcpy(out, &decoded, 12);
983
984 begin += 16;
985 numEmitted += 12;
986 out += 12;
987 }
988#endif
989 while (end - begin >= 4 && static_cast<unsigned>(numEmitted + 3)
990 <= static_cast<unsigned>(maxNumOut)) {
992 uint8_t *in = reinterpret_cast<uint8_t *>(inBuffer.buffer());
993 memcpy(in, begin, 4);
994
995 uint8_t x[4];
996 x[0] = static_cast<uint8_t>(d_alphabet_p[in[0]]);
997 x[1] = static_cast<uint8_t>(d_alphabet_p[in[1]]);
998 x[2] = static_cast<uint8_t>(d_alphabet_p[in[2]]);
999 x[3] = static_cast<uint8_t>(d_alphabet_p[in[3]]);
1000
1001 uint32_t x4;
1002 memcpy(&x4, x, sizeof(x4));
1003 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(x4 & 0x80808080u)) {
1004 // Unknown char; could be error or could be a character to
1005 // ignore; either way fall back to char-by-char decoding
1006 break;
1007 }
1008
1009 out[0] = static_cast<char>((x[0] << 2) | (x[1] >> 4));
1010 out[1] = static_cast<char>((x[1] << 4) | (x[2] >> 2));
1011 out[2] = static_cast<char>((x[2] << 6) | (x[3] >> 0));
1012
1013 begin += 4;
1014 numEmitted += 3;
1015 out += 3;
1016 }
1017 }
1018
1019 while (18 >= d_bitsInStack && begin != end) {
1020 const unsigned char byte = static_cast<unsigned char>(*begin);
1021
1022 ++begin;
1023
1024 unsigned char converted = static_cast<unsigned char>(
1025 d_alphabet_p[byte]);
1026
1027 if (converted < 64) {
1028 d_stack = (d_stack << 6) | converted;
1029 d_bitsInStack += 6;
1030 if (8 <= d_bitsInStack && numEmitted != maxNumOut) {
1031 d_bitsInStack -= 8;
1032 *out = static_cast<char>(
1033 (d_stack >> d_bitsInStack) & 0xff);
1034 ++out;
1035 ++numEmitted;
1036 }
1037 }
1038 else if (!d_ignorable_p[byte]) {
1039 if ('=' == byte && d_isPadded) {
1040 const int residual = residualBits(
1041 d_outputLength + numEmitted);
1042 // 'residual' is 0, 6, 12, or 18.
1043 //: o If it's 0, that's an error since no '=' should be
1044 //: needed.
1045 //:
1046 //: o If it's 6, that's an error because an incomplete
1047 //: byte has been input.
1048 //:
1049 //: o 12 means 2 bytes have been read, meaning we have to
1050 //: do 1 byte of output (which we may have already done).
1051 //: The low-order 4 bits of stack should either be
1052 //: 0 or the stack should be empty.
1053 //:
1054 //: o 18 means 3 bytes have been read, meaning we have to
1055 //: do 2 bytes of output (some or all of which we may
1056 //: have already done). The low-order 2 bits of stack
1057 //: should either be 0 or the stack should be empty.
1058
1059 const int leftOver = residual % 8;
1060 d_state = 0 != (d_stack & ((1 << leftOver) - 1))
1061 ? e_ERROR_STATE
1062 : 12 == residual
1063 ? e_NEED_EQUAL_STATE
1064 : 18 == residual
1065 ? e_SOFT_DONE_STATE
1066 : e_ERROR_STATE;
1067 d_stack >>= leftOver;
1068 d_bitsInStack -= leftOver;
1069 }
1070 else {
1071 d_state = e_ERROR_STATE;
1072 }
1073 break;
1074 }
1075 }
1076 }
1077
1078 if (e_NEED_EQUAL_STATE == d_state) {
1079 BSLS_ASSERT(d_isPadded);
1080
1081 while (begin != end) {
1082 const unsigned char byte = static_cast<unsigned char>(*begin);
1083
1084 ++begin;
1085
1086 if (!d_ignorable_p[byte]) {
1087 if ('=' == byte) {
1088 d_state = e_SOFT_DONE_STATE;
1089 }
1090 else {
1091 d_state = e_ERROR_STATE;
1092 }
1093 break;
1094 }
1095 }
1096 }
1097 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(e_SOFT_DONE_STATE == d_state
1098 && begin != end)) {
1099 do {
1100 const unsigned char byte = static_cast<unsigned char>(*begin);
1101
1102 ++begin;
1103
1104 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!d_ignorable_p[byte])) {
1105 d_state = e_ERROR_STATE;
1106 break;
1107 }
1108 } while (begin != end);
1109 }
1110
1111 *numIn = static_cast<int>(begin - originalBegin);
1112 *numOut = numEmitted;
1113 d_outputLength += numEmitted;
1114
1115 return e_ERROR_STATE == d_state ? -1 : d_bitsInStack / 8;
1116}
1117
1118template<>
1119inline
1120int Base64Decoder::convert<unsigned char *, const unsigned char *>(
1121 unsigned char *out,
1122 int *numOut,
1123 int *numIn,
1124 const unsigned char *begin,
1125 const unsigned char *end,
1126 int maxNumOut)
1127{
1128 return convert(reinterpret_cast<char *>(out),
1129 numOut,
1130 numIn,
1131 reinterpret_cast<const char *>(begin),
1132 reinterpret_cast<const char *>(end),
1133 maxNumOut);
1134}
1135
1136
1137template <class OUTPUT_ITERATOR>
1138int Base64Decoder::endConvert(OUTPUT_ITERATOR out)
1139{
1140 int dummyNumOut;
1141
1142 return endConvert(out, &dummyNumOut, -1);
1143}
1144
1145template <class OUTPUT_ITERATOR>
1146int Base64Decoder::endConvert(OUTPUT_ITERATOR out,
1147 int *numOut,
1148 int maxNumOut)
1149{
1150 BSLS_ASSERT(numOut);
1151
1152 if (!d_isPadded && e_INPUT_STATE == d_state) {
1153 const int residual = residualBits(d_outputLength);
1154 const int leftOver = residual % 8;
1155 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(6 == residual ||
1156 0 != (d_stack & ((1 << leftOver) - 1)))) {
1157 d_state = e_ERROR_STATE;
1158 *numOut = 0;
1159 return -1; // RETURN
1160 }
1161 else {
1162 d_stack >>= leftOver;
1163 d_bitsInStack -= leftOver;
1164 }
1165 }
1166
1167 if (e_ERROR_STATE == d_state || e_NEED_EQUAL_STATE == d_state ||
1168 (e_DONE_STATE == d_state && 0 == d_bitsInStack) ||
1169 (d_isPadded && e_INPUT_STATE == d_state &&
1170 0 != residualBits(d_outputLength))) {
1171 d_state = e_ERROR_STATE;
1172 *numOut = 0;
1173 return -1; // RETURN
1174 }
1175
1176 BSLS_ASSERT(0 == d_bitsInStack % 8);
1177
1178 d_state = e_DONE_STATE;
1179
1180 int numEmitted;
1181 for (numEmitted = 0; 8 <= d_bitsInStack && numEmitted != maxNumOut;
1182 ++numEmitted) {
1183 d_bitsInStack -= 8;
1184 *out++ = static_cast<char>((d_stack >> d_bitsInStack) & 0xff);
1185 }
1186
1187 *numOut = numEmitted;
1188 d_outputLength += numEmitted;
1189
1190 return d_bitsInStack / 8;
1191}
1192
1193inline
1195{
1196 d_state = e_INPUT_STATE;
1197 d_outputLength = 0;
1198 d_bitsInStack = 0;
1199}
1200
1201// ACCESSORS
1202inline
1204{
1205 return d_alphabet;
1206}
1207
1208inline
1210{
1211 return d_ignoreMode;
1212}
1213
1214inline
1216{
1217 const int residual = residualBits(d_outputLength);
1218 return (0 == residual && e_INPUT_STATE == d_state) ||
1219 e_SOFT_DONE_STATE == d_state || e_DONE_STATE == d_state;
1220}
1221
1222inline
1224{
1225 return !d_bitsInStack && e_DONE_STATE == d_state;
1226}
1227
1228inline
1230{
1231 return e_ERROR_STATE == d_state;
1232}
1233
1234inline
1236{
1237 return e_INPUT_STATE == d_state
1238 && 0 == d_bitsInStack
1239 && 0 == d_outputLength;
1240}
1241
1242inline
1244{
1245 return e_SOFT_DONE_STATE == d_state
1246 || (d_bitsInStack && e_DONE_STATE == d_state);
1247}
1248
1249inline
1251{
1252 return d_isPadded;
1253}
1254
1255inline
1260
1261inline
1266
1267inline
1269{
1270 return d_outputLength;
1271}
1272
1273} // close package namespace
1274
1275
1276#endif
1277
1278// ----------------------------------------------------------------------------
1279// Copyright 2015 Bloomberg Finance L.P.
1280//
1281// Licensed under the Apache License, Version 2.0 (the "License");
1282// you may not use this file except in compliance with the License.
1283// You may obtain a copy of the License at
1284//
1285// http://www.apache.org/licenses/LICENSE-2.0
1286//
1287// Unless required by applicable law or agreed to in writing, software
1288// distributed under the License is distributed on an "AS IS" BASIS,
1289// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1290// See the License for the specific language governing permissions and
1291// limitations under the License.
1292// ----------------------------- END-OF-FILE ----------------------------------
1293
1294/** @} */
1295/** @} */
1296/** @} */
Definition bdlde_base64decoderoptions.h:322
static Base64DecoderOptions custom(IgnoreMode::Enum ignoreMode, Base64Alphabet::Enum alphabet, bool padded)
Definition bdlde_base64decoderoptions.h:501
Definition bdlde_base64decoder.h:417
bool isInitialState() const
Definition bdlde_base64decoder.h:1235
static int maxDecodedLength(int inputLength)
Definition bdlde_base64decoder.h:685
bool isError() const
Definition bdlde_base64decoder.h:1229
bool isDone() const
Definition bdlde_base64decoder.h:1223
Base64Alphabet::Enum Alphabet
Definition bdlde_base64decoder.h:421
int convert(OUTPUT_ITERATOR out, INPUT_ITERATOR begin, INPUT_ITERATOR end)
Definition bdlde_base64decoder.h:694
Alphabet alphabet() const
Return the alphabet supplied at construction of this object.
Definition bdlde_base64decoder.h:1203
bool isAcceptable() const
Definition bdlde_base64decoder.h:1215
IgnoreMode::Enum ignoreMode() const
Return the ignoreMode state of this decoder.
Definition bdlde_base64decoder.h:1209
int outputLength() const
Return the total length of the output emitted thus far.
Definition bdlde_base64decoder.h:1268
Base64Decoder(const Base64DecoderOptions &options)
int endConvert(OUTPUT_ITERATOR out)
Definition bdlde_base64decoder.h:1138
static const Alphabet e_BASIC
Definition bdlde_base64decoder.h:424
void resetState()
Definition bdlde_base64decoder.h:1194
bool isUnrecognizedAnError() const
Definition bdlde_base64decoder.h:1256
bool isMaximal() const
Definition bdlde_base64decoder.h:1243
DecoderOptions options() const
Definition bdlde_base64decoder.h:1262
bool isPadded() const
Definition bdlde_base64decoder.h:1250
static const Alphabet e_URL
Definition bdlde_base64decoder.h:425
Definition bsls_alignedbuffer.h:262
char * buffer()
Definition bsls_alignedbuffer.h:295
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_DEPRECATE_FEATURE(UOR, FEATURE, MESSAGE)
Definition bsls_deprecatefeature.h:387
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition bdlde_base64alphabet.h:118
Enum
Definition bdlde_base64alphabet.h:137
@ e_URL
Definition bdlde_base64alphabet.h:139
@ e_BASIC
Definition bdlde_base64alphabet.h:138
Definition bdlde_base64ignoremode.h:135
Enum
Definition bdlde_base64ignoremode.h:138
@ e_IGNORE_UNRECOGNIZED
Definition bdlde_base64ignoremode.h:144