// balxml_base64parser.h                                              -*-C++-*-
#ifndef INCLUDED_BALXML_BASE64PARSER
#define INCLUDED_BALXML_BASE64PARSER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide push parser for Base64 types.
//
//@DEPRECATED: Use bdlde_base64decoder instead.
//
//@CLASSES:
//  balxml::Base64Parser: push parser for Base64 types
//
//@DESCRIPTION: The `balxml::Base64Parser` class template provided by this
// component can be used to parse Base64 characters into one of the supported
// Base64 types, which are `bsl::vector<char>` and `bsl::string`.  The `TYPE`
// parameter can be one of these two types.
//
// This class template is a model of the `PushParser` concept, which contains
// the following methods:
// ```
// int beginParse(TYPE *object);
//     // Prepare the parser to start parsing a new value and associate the
//     // specified 'object' with the parser.  Return 0 if successful and
//     // non-zero otherwise.
//
// int endParse();
//     // Ends the parse operation and store the value parsed from the pushed
//     // characters into the associated object.  Return 0 if successful and
//     // non-zero otherwise.  The behavior is undefined unless an object is
//     // associated with this parser.  Upon successful completion, the parser
//     // will be disassociated with the object.
//
// template <typename INPUT_ITERATOR>
// int pushCharacters(INPUT_ITERATOR begin, INPUT_ITERATOR end);
//     // Push the characters ranging from the specified 'begin' up to (but
//     // not including) the specified 'end' into this parser.  Return 0 if
//     // successful and non-zero otherwise.  The parameterized
//     // 'INPUT_ITERATOR' must be dereferenceable to a 'char' value.  The
//     // behavior is undefined unless an object is associated with this
//     // parser.
// ```
//
///Usage
///-----
// The following snippets of code illustrate the usage of this component.
// Suppose you had an input stream that contained Base64 data.  The following
// `loadFromBase64Stream` function loads this data into an `bsl::vector<char>`
// blob:
// ```
// #include <balxml_base64parser.h>
//
// #include <istream>
// #include <iterator>
// #include <vector>
//
// using namespace BloombergLP;
//
// int loadFromBase64Stream(bsl::vector<char> *result, bsl::istream& stream)
// {
//     enum { FAILURE = -1 };
//
//     balxml::Base64Parser<bsl::vector<char> > parser;
//
//     if (0 != parser.beginParse(result)) {
//         return FAILURE;
//     }
//
//     if (0 != parser.pushCharacters(bsl::istreambuf_iterator<char>(stream),
//                                    bsl::istreambuf_iterator<char>())) {
//         return FAILURE;
//     }
//
//     return parser.endParse();
// }
// ```
// The following function demonstrates the `loadFromBase64Stream` function:
// ```
// #include <sstream>
//
// void usageExample()
// {
//     const char INPUT[] = "YWJjZA==";  // "abcd" in Base64
//
//     bsl::vector<char>  vec;
//     bsl::istringstream iss(INPUT);
//
//     int result = loadFromBase64Stream(&vec, iss);
//
//     assert(0   == result);
//     assert(4   == vec.size());
//     assert('a' == vec[0]);
//     assert('b' == vec[1]);
//     assert('c' == vec[2]);
//     assert('d' == vec[3]);
// }
// ```

#include <balscm_version.h>

#include <bdlde_base64decoder.h>

#include <bdlat_valuetypefunctions.h>

#include <bsl_iterator.h>

#include <bsls_assert.h>
#include <bsls_review.h>

namespace BloombergLP {
namespace balxml {

                          // ========================
                          // class Base64Parser<TYPE>
                          // ========================

/// This is a push parser for supported Base64 types (`bsl::vector<char>` or
/// `bsl::string`).
template <class TYPE>
class Base64Parser {

    // PRIVATE DATA MEMBERS
    bdlde::Base64Decoder  d_base64Decoder;   // decoder
    TYPE                 *d_object_p;        // associated object

  private:
    // NOT IMPLEMENTED
    Base64Parser(const Base64Parser&);
    Base64Parser& operator=(const Base64Parser&);

  public:
    // CREATORS

    /// Create a parser for parsing Base64 types.
    Base64Parser();

#ifdef DOXYGEN    // Generated by compiler:

    ~Base64Parser();
        // Destroy this parser object.
#endif

    // MANIPULATORS

    /// Prepare the parser to start parsing a new value and associate the
    /// specified `object` with the parser.  Return 0 if successful and
    /// non-zero otherwise.
    int beginParse(TYPE *object);

    /// Ends the parse operation and store the value parsed from the pushed
    /// characters into the associated object.  Return 0 if successful and
    /// non-zero otherwise.  The behavior is undefined unless an object is
    /// associated with this parser.  Upon successful completion, the parser
    /// will be disassociated with the object.
    int endParse();

    /// Push the characters ranging from the specified `begin` up to (but
    /// not including) the specified `end` into this parser.  Return 0 if
    /// successful and non-zero otherwise.  The parameterized
    /// `INPUT_ITERATOR` must be dereferenceable to a `char` value.  The
    /// behavior is undefined unless an object is associated with this
    /// parser.
    template <class INPUT_ITERATOR>
    int pushCharacters(INPUT_ITERATOR begin, INPUT_ITERATOR end);
};

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                          // ------------------------
                          // class Base64Parser<TYPE>
                          // ------------------------

// CREATORS
template <class TYPE>
Base64Parser<TYPE>::Base64Parser()
: d_base64Decoder(true)  // 'true' indicates report errors
, d_object_p(0)
{
}

// MANIPULATORS
template <class TYPE>
int Base64Parser<TYPE>::beginParse(TYPE *object)
{
    BSLS_ASSERT(object);

    enum { k_SUCCESS = 0 };

    d_base64Decoder.resetState();
    d_object_p = object;

    bdlat_ValueTypeFunctions::reset(d_object_p);

    return k_SUCCESS;
}

template <class TYPE>
int Base64Parser<TYPE>::endParse()
{
    BSLS_ASSERT(d_object_p);

    enum { k_SUCCESS = 0, k_FAILURE = -1 };

    bsl::back_insert_iterator<TYPE> outputIterator(*d_object_p);

    int status = d_base64Decoder.endConvert(outputIterator);

    if (0 > status) {
        return k_FAILURE;                                             // RETURN
    }

    BSLS_ASSERT(0 == status);  // nothing should be retained by decoder

    d_object_p = 0;

    return k_SUCCESS;
}

template <class TYPE>
template <class INPUT_ITERATOR>
int Base64Parser<TYPE>::pushCharacters(INPUT_ITERATOR begin,
                                       INPUT_ITERATOR end)
{
    BSLS_ASSERT(d_object_p);

    enum { k_SUCCESS = 0, k_FAILURE = -1 };

    bsl::back_insert_iterator<TYPE> outputIterator(*d_object_p);

    int status = d_base64Decoder.convert(outputIterator, begin, end);

    if (0 > status) {
        return k_FAILURE;                                             // RETURN
    }

    BSLS_ASSERT(0 == status);  // nothing should be retained by decoder

    return k_SUCCESS;
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
