// balxml_utf8readerwrapper.h                                         -*-C++-*-
#ifndef INCLUDED_BALXML_UTF8READERWRAPPER
#define INCLUDED_BALXML_UTF8READERWRAPPER

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

//@PURPOSE: Provide wrapper for `Reader` to check input UTF-8 validity.
//
//@CLASSES:
//   balxml::Utf8ReaderWrapper: Wrap a `Reader`, check UTF-8 input.
//
//@SEE_ALSO: balxml_reader, balxml_errorinfo, bdlde_utf8streambufinputwrapper
//
//@DESCRIPTION: This component supplies a mechanism,
// `balxml::Utf8ReaderWrapper`, which holds another object of type
// `balxml::Reader` and forwards operations to the held object.  The held
// object is to operate on a `bsl::streambuf`, which is in fact a
// `bdlde::Utf8CheckingInStreamBufWrapper` contained in the object, which holds
// another `bsl::streambuf` and forward actions to that held `bsl::streambuf`.
//
// The `bdlde_Utf8StreamBufInputWrapper` detects invalid UTF-8.  If the input
// contains nothing but valid UTF-8, the `bdlde_Utf8StreamBufInputWrapper`
// simply forwards all operations to the `bsl::streambuf` it holds, and the
// wrapper has no influence on behavior.
//
// Similarly, if the input contains nothing but valid UTF-8, the reader wrapper
// simply forwards all operations to the held `Reader` and has no influence on
// behavior.
//
// If invalid UTF-8 occurs in the input, `errorInfo().message()` will reflect
// the nature of the UTF-8 error.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Routine Parsing:
/// - - - - - - - - - - - - -
// Utility function to skip past white space.
// ```
// int advancePastWhiteSpace(balxml::Reader& reader)
// {
//     static const char whiteSpace[] = "\n\r\t ";
//     const char *value = 0;
//     int         type = 0;
//     int         rc = 0;
//
//     do {
//         rc    = reader.advanceToNextNode();
//         value = reader.nodeValue();
//         type  = reader.nodeType();
//     } while ((0 == rc && type == balxml::Reader::e_NODE_TYPE_WHITESPACE) ||
//              (type == balxml::Reader::e_NODE_TYPE_TEXT &&
//               bsl::strlen(value) == bsl::strspn(value, whiteSpace)));
//
//     assert( reader.nodeType() != balxml::Reader::e_NODE_TYPE_WHITESPACE);
//
//     return rc;
// }
// ```
// Then, in `main`, we parse an XML string using the UTF-8 reader wrapper:
//
// The following string describes xml for a very simple user directory.  The
// top level element contains one xml namespace attribute, with one embedded
// entry describing a user.  The person's name contains some non-ascii UTF-8.
// ```
// static const char TEST_XML_STRING[] =
//    "<?xml version='1.0' encoding='UTF-8'?>\n"
//    "<directory-entry xmlns:dir='http://bloomberg.com/schemas/directory'>\n"
//    "    <name>John Smith\xe7\x8f\x8f</name>\n"
//    "    <phone dir:phonetype='cell'>212-318-2000</phone>\n"
//    "    <address/>\n"
//    "</directory-entry>\n";
// ```
// In order to read the XML, we first need to construct a
// `balxml::NamespaceRegistry` object, a `balxml::PrefixStack` object, and a
// `Utf8ReaderWrapper` object.
// ```
// balxml::NamespaceRegistry namespaces;
// balxml::PrefixStack prefixStack(&namespaces);
// balxml::MiniReader miniReader;
// balxml::Utf8ReaderWrapper reader(&miniReader);
//
// assert(!reader.isOpen());
// ```
// The reader uses a `balxml::PrefixStack` to manage namespace prefixes so we
// need to set it before we call open.
// ```
// reader.setPrefixStack(&prefixStack);
// assert(reader.prefixStack());
// assert(reader.prefixStack() == &prefixStack);
// ```
// Now we call the `open` method to setup the reader for parsing using the data
// contained in the in the XML string.
// ```
// reader.open(TEST_XML_STRING, sizeof(TEST_XML_STRING) -1, 0, "UTF-8");
// ```
// Confirm that the `bdem::Reader` has opened properly
// ```
// assert( reader.isOpen());
// assert(!bsl::strncmp(reader.documentEncoding(), "UTF-8", 5));
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_NONE);
// assert(!reader.nodeName());
// assert(!reader.nodeHasValue());
// assert(!reader.nodeValue());
// assert(!reader.nodeDepth());
// assert(!reader.numAttributes());
// assert(!reader.isEmptyElement());
// ```
// Advance through all the nodes and assert all information contained at each
// node is correct.
//
// Assert the next node's document type is xml.
// ```
// int rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() ==
//                           balxml::Reader::e_NODE_TYPE_XML_DECLARATION);
// assert(!bsl::strcmp(reader.nodeName(), "xml"));
// assert( reader.nodeHasValue());
// assert(!bsl::strcmp(reader.nodeValue(), "version='1.0' encoding='UTF-8'"));
// assert( reader.nodeDepth() == 1);
// assert(!reader.numAttributes());
// assert(!reader.isEmptyElement());
// assert( 0 == rc);
// assert( reader.nodeDepth() == 1);
// ```
// Advance to the top level element, which has one attribute, the xml
// namespace.  Assert the namespace information has been added correctly to the
// prefix stack.
// ```
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "directory-entry"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 1);
// assert( reader.numAttributes() == 1);
// assert(!reader.isEmptyElement());
//
// assert(!bsl::strcmp(prefixStack.lookupNamespacePrefix("dir"), "dir"));
// assert(prefixStack.lookupNamespaceId("dir") == 0);
// assert(!bsl::strcmp(prefixStack.lookupNamespaceUri("dir"),
//                     "http://bloomberg.com/schemas/directory"));
// ```
// The XML being read contains one entry describing a user, advance the users
// name name and assert all information can be read correctly.
// ```
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "name"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 2);
// assert( reader.numAttributes() == 0);
// assert(!reader.isEmptyElement());
//
// rc = reader.advanceToNextNode();
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_TEXT);
// assert( reader.nodeHasValue());
// assert(!bsl::strcmp(reader.nodeValue(), "John Smith\xe7\x8f\x8f"));
// assert( reader.nodeDepth() == 3);
// assert( reader.numAttributes() == 0);
// assert(!reader.isEmptyElement());
//
// rc = reader.advanceToNextNode();
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_END_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "name"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 2);
// assert( reader.numAttributes() == 0);
// assert(!reader.isEmptyElement());
// ```
// Advance to the user's phone number and assert all information can be read
// correctly.
// ```
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "phone"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 2);
// assert( reader.numAttributes() == 1);
// assert(!reader.isEmptyElement());
// ```
// The phone node has one attribute, look it up and assert the
// `balxml::ElementAttribute` contains valid information and that the prefix
// returns the correct namespace URI from the prefix stack.
// ```
// balxml::ElementAttribute elemAttr;
//
// rc = reader.lookupAttribute(&elemAttr, 0);
// assert( 0 == rc);
// assert(!elemAttr.isNull());
// assert(!bsl::strcmp(elemAttr.qualifiedName(), "dir:phonetype"));
// assert(!bsl::strcmp(elemAttr.value(), "cell"));
// assert(!bsl::strcmp(elemAttr.prefix(), "dir"));
// assert(!bsl::strcmp(elemAttr.localName(), "phonetype"));
// assert(!bsl::strcmp(elemAttr.namespaceUri(),
//                     "http://bloomberg.com/schemas/directory"));
// assert( elemAttr.namespaceId() == 0);
//
// assert(!bsl::strcmp(prefixStack.lookupNamespaceUri(elemAttr.prefix()),
//                     elemAttr.namespaceUri()));
//
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_TEXT);
// assert( reader.nodeHasValue());
// assert(!bsl::strcmp(reader.nodeValue(), "212-318-2000"));
// assert( reader.nodeDepth() == 3);
// assert( reader.numAttributes() == 0);
// assert(!reader.isEmptyElement());
//
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_END_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "phone"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 2);
// assert( reader.numAttributes() == 0);
// assert(!reader.isEmptyElement());
// ```
// Advance to the user's address and assert all information can be read
// correctly.
// ```
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "address"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 2);
// assert( reader.numAttributes() == 0);
// assert( reader.isEmptyElement());
// ```
// Advance to the end element.
// ```
// rc = advancePastWhiteSpace(reader);
// assert( 0 == rc);
// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_END_ELEMENT);
// assert(!bsl::strcmp(reader.nodeName(), "directory-entry"));
// assert(!reader.nodeHasValue());
// assert( reader.nodeDepth() == 1);
// assert( reader.numAttributes() == 0);
// assert(!reader.isEmptyElement());
// ```
// Close the reader.
// ```
// reader.close();
// assert(!reader.isOpen());
//
// return 0;
// ```

#include <balscm_version.h>

#include <balxml_errorinfo.h>
#include <balxml_reader.h>

#include <bdlde_utf8checkinginstreambufwrapper.h>
#include <bdlsb_fixedmeminstreambuf.h>

#include <bslmf_nestedtraitdeclaration.h>
#include <bsls_keyword.h>

#include <bsl_cstddef.h> // for size_t
#include <bsl_functional.h>
#include <bsl_fstream.h>
#include <bsl_streambuf.h>

namespace BloombergLP  {
namespace balxml {

class ElementAttribute;
class ErrorInfo;
class PrefixStack;

                            // =======================
                            // class Utf8ReaderWrapper
                            // =======================

/// This class "has a" pointer to a held and wrapped `Reader` object, and
/// operations on this object are passed to the held reader.  The held
/// reader is passed a `Utf8CheckingInStreamBufWrapper`, which holds and
/// wraps a normal `streambuf`.  The `Utf8CheckingInStreamBufWrapper` checks
/// input for invalid UTF-8, and if it detects any, makes the diagnosis of
/// the problem available through the `errorInfo` accessor.
class Utf8ReaderWrapper : public Reader {

    // DATA
    bdlde::Utf8CheckingInStreamBufWrapper d_utf8StreamBuf;
    bdlsb::FixedMemInStreamBuf            d_fixedStreamBuf;
    bsl::ifstream                         d_stream;
    Reader *                              d_reader_p;
    ErrorInfo                             d_errorInfo;
    bool                                  d_useHeldErrorInfo;

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

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(Utf8ReaderWrapper,
                                   bslma::UsesBslmaAllocator);

  private:
    // PRIVATE MANIPULATORS

    /// Open the held reader with `d_utf8StreamBuf`, as well as the
    /// specified `url` and `encoding`.  Note that all public `open`
    /// functions of this class prepare `d_utf8StreamBuf` and then delegate
    /// to this function as part of their implementation.
    int doOpen(const char *url, const char *encoding);

    /// Return a pointer providing modifiable access to the held `Reader`.
    Reader *heldReader();

    /// Called when a UTF-8 error is encountered, to make `d_errorInfo` into
    /// a combination of `heldReader()->errorInfo()` and the nature of the
    /// UTF-8 error as reported by the specified `utf8Rc`.  The behavior is
    /// undefined unless `utf8Rc < 0` and `utf8Rc` is one of the values
    /// enumerated by `Utf8Util::ErrorStatus`.
    void reportUtf8Error(int utf8Rc);

    // PRIVATE ACCESSORS

    /// Return a pointer providing non-modifiable access to the held
    /// `Reader`.
    const Reader *heldReader() const;

  public:
    // CREATORS

    /// Create a `Utf8ReaderWrapper` that holds the specified `reader`.
    /// Optionally specify a `basicAllocator` used to supply memory.  If
    /// `basicAllocator` is 0, the currently installed default allocator is
    /// used.  The behavior is undefined unless `reader` has never been
    /// opened or closed.
    explicit
    Utf8ReaderWrapper(Reader           *reader,
                      bslma::Allocator *basicAllocator = 0);

    /// Close the held reader and destroy this object.
    ~Utf8ReaderWrapper() BSLS_KEYWORD_OVERRIDE;

    // MANIPULATORS

                              // ** setup methods **

    /// Set the options of the held reader to the flags in the specified
    /// `flags`.  The options for the reader are persistent, i.e., the
    /// options are not reset by `close`.  The behavior is undefined if this
    /// method is called after calling `open` and before calling `close`;
    /// except that derived classes are permitted to specify valid behavior
    /// for calling this function for specific arguments while the reader is
    /// open.
    void setOptions(unsigned int flags) BSLS_KEYWORD_OVERRIDE;

    /// Set the prefix stack to the stack at the optionally specified
    /// `prefixes` address or disable prefix stack support if `prefixes` is
    /// null.  This stack is used to push and pop namespace prefixes as the
    /// parse progresses, so that, at any point, the stack will reflect the
    /// set of active prefixes for the current node.  It is legitimate to
    /// pass a stack that already contains prefixes, these prefixes shall be
    /// preserved when `close` is called, i.e., the prefix stack shall be
    /// returned to the stack depth it had when `setPrefixStack` was called.
    /// The behavior is undefined if this method is called after calling
    /// `open` and before calling `close`.
    void setPrefixStack(PrefixStack *prefixes) BSLS_KEYWORD_OVERRIDE;

    /// Set the external XML resource resolver to the specified `resolver`.
    /// The XML resource resolver is used by the `balxml_reader` to find and
    /// open an external resources (See the `XmlResolverFunctor` typedef for
    /// more details).  The XML resource resolver remains valid; it is not
    /// affected by a call to `close` and should be available until the
    /// reader is destroyed.  The behavior is undefined if this method is
    /// called after calling `open` and before calling `close`.
    void setResolver(XmlResolverFunctor resolver) BSLS_KEYWORD_OVERRIDE;

                            // ** open/close methods **

    /// Set up the reader for parsing using the data contained in the XML
    /// file described by the specified `filename`, and set the encoding
    /// value to the optionally specified `encoding` ("ASCII", "UTF-8",
    /// etc).  Returns 0 on success and non-zero otherwise.  The encoding
    /// passed to `Reader::open` will take effect only when there is no
    /// encoding information in the original document, i.e., the encoding
    /// information obtained from the XML file described by the `filename`
    /// trumps all.  If there is no encoding provided within the document
    /// and `encoding` is null or a blank string is passed, then set the
    /// encoding to the default "UTF-8".  It is an error to `open` a reader
    /// that is already open.  Note that the reader will not be on a valid
    /// node until `advanceToNextNode` is called.
    int open(const char *filename, const char *encoding = 0)
                                                         BSLS_KEYWORD_OVERRIDE;

    /// Set up the reader for parsing using the data contained in the
    /// specified (XML) `buffer` of the specified `size`, set the base URL
    /// to the optionally specified `url` and set the encoding value to the
    /// optionally specified `encoding` ("ASCII", "UTF-8", etc).  Return 0
    /// on success and non-zero otherwise.  If `url` is null or a blank
    /// string is passed, then base URL will be empty.  The encoding passed
    /// to `Reader::open` will take effect only when there is no encoding
    /// information in the original document, i.e., the encoding information
    /// obtained from the (XML) `buffer` trumps all.  If there is no
    /// encoding provided within the document and `encoding` is null or a
    /// blank string is passed, then set the encoding to the default
    /// "UTF-8".  It is an error to `open` a reader that is already open.
    /// Note that the reader will not be on a valid node until
    /// `advanceToNextNode` is called.
    int open(const char  *buffer,
             bsl::size_t  size,
             const char  *url = 0,
             const char  *encoding = 0) BSLS_KEYWORD_OVERRIDE;

    /// Set up the reader for parsing using the data contained in the
    /// specified (XML) `stream`, set the base URL to the optionally
    /// specified `url` and set the encoding value to the optionally
    /// specified `encoding` ("ASCII", "UTF-8", etc).  Return 0 on success
    /// and non-zero otherwise.  If `url` is null or a blank string is
    /// passed, then base URL will be empty.  The encoding passed to
    /// `Reader::open` will take effect only when there is no encoding
    /// information in the original document, i.e., the encoding information
    /// obtained from the (XML) `stream` trumps all.  If there is no
    /// encoding provided within the document and `encoding` is null or a
    /// blank string is passed, then set the encoding to the default
    /// "UTF-8".  It is an error to `open` a reader that is already open.
    /// Note that the reader will not be on a valid node until
    /// `advanceToNextNode` is called.
    int open(bsl::streambuf *stream,
             const char     *url = 0,
             const char     *encoding = 0) BSLS_KEYWORD_OVERRIDE;

    /// Close the reader.  Most, but not all state is reset.  Specifically,
    /// the XML resource resolver and the prefix stack remain.  The prefix
    /// stack shall be returned to the stack depth it had when
    /// `setPrefixStack` was called.  Call the method `open` to reuse the
    /// reader.  Note that `close` invalidates all strings and data
    /// structures obtained via `Reader` accessors.  E.g., the pointer
    /// returned from `nodeName` for this node will not be valid once
    /// `close` is called.
    void close() BSLS_KEYWORD_OVERRIDE;

                                // ** navigation method **

    /// Move to the next node in the data steam created by `open` thus
    /// allowing the node's properties to be queried via the `Reader`
    /// accessors.  Return 0 on successful read, 1 if there are no more
    /// nodes to read, and a negative number otherwise.  Note that each call
    /// to `advanceToNextNode` invalidates strings and data structures
    /// returned when `Reader` accessors where call for the "prior node".
    /// E.g., the pointer returned from `nodeName` for this node will not be
    /// valid once `advanceToNextNode` is called.  Note that the reader will
    /// not be on a valid node until the first call to `advanceToNextNode`
    /// after the reader is opened.
    int advanceToNextNode() BSLS_KEYWORD_OVERRIDE;

    // ACCESSORS

    /// Return the allocator used by this object to allocate memory.
    bslma::Allocator *allocator() const;

    /// Return the document encoding or NULL on error.  The returned poiner
    /// is owned by this object and must not be modified or deallocated by
    /// the caller.  The returned pointer becomes invalid when `close` is
    /// called or the reader is destroyed.
    const char *documentEncoding() const BSLS_KEYWORD_OVERRIDE;

    /// Return a reference to the non-modifiable error information for this
    /// reader.  The returned value becomes invalid when `close` is called
    /// or the reader is destroyed.
    const ErrorInfo& errorInfo() const BSLS_KEYWORD_OVERRIDE;

    /// Return the current column number within the input stream.  The
    /// current column number is the number of characters since the last
    /// newline was read by the reader plus one, i.e., the first column of
    /// each line is column number one.  Return 0 if not available.  Note
    /// that a derived-class implementation is not required to count
    /// columns and may just return 0.
    int getColumnNumber() const BSLS_KEYWORD_OVERRIDE;

    /// Return the current line number within the input stream.  The current
    /// line is the last line for which the reader has not yet seen a
    /// newline.  Lines are counted starting at one from the time a stream
    /// is provided to `open`.  Return 0 if not available.  Note that a
    /// derived-class implementation is not required to count lines and may
    /// just return 0.
    int getLineNumber() const BSLS_KEYWORD_OVERRIDE;

    /// Return true if the current node is an element (i.e., node type is
    /// `BAEXML_NODE_TYPE_ELEMENT`) that ends with `/>`; and false
    /// otherwise.  Note that `<a/>` will be considered empty but `<a></a>`
    /// will not.
    bool isEmptyElement() const BSLS_KEYWORD_OVERRIDE;

    /// Return true if `open` was called successfully and `close` has not
    /// yet been called and false otherwise.
    bool isOpen() const BSLS_KEYWORD_OVERRIDE;

    /// Find the attribute at the specified `index` in the current node, and
    /// fill in the specified `attribute` structure.  Return 0 on success, 1
    /// if no attribute is found at the `index`, and an a negative value
    /// otherwise.  The strings that were filled into the `attribute`
    /// structure are invalid upon the next `advanceToNextNode` or `close`
    /// is called.
    int lookupAttribute(ElementAttribute *attribute,
                        int               index) const BSLS_KEYWORD_OVERRIDE;

    /// Find the attribute with the specified `qname` (qualified name) in
    /// the current node, and fill in the specified `attribute` structure.
    /// Return 0 on success, 1 if there is no attribute found with `qname`,
    /// and a negative value otherwise.  The strings that were filled into
    /// the `attribute` structure are invalid upon the next
    /// `advanceToNextNode` or `close` is called.
    int lookupAttribute(ElementAttribute *attribute,
                        const char       *qname) const BSLS_KEYWORD_OVERRIDE;

    /// Find the attribute with the specified `localName` and specified
    /// `namespaceUri` in the current node, and fill in the specified
    /// `attribute` structure.  Return 0 on success, 1 if there is no
    /// attribute found with `localName` and `namespaceUri`, and a negative
    /// value otherwise.  If `namespaceUri` == 0 or a blank string is
    /// passed, then the document's default namespace will be used.  The
    /// strings that were filled into the `attribute` structure are invalid
    /// upon the next `advanceToNextNode` or `close` is called.
    int
    lookupAttribute(
                   ElementAttribute *attribute,
                   const char       *localName,
                   const char       *namespaceUri) const BSLS_KEYWORD_OVERRIDE;

    /// Find the attribute with the specified `localName` and specified
    /// `namespaceId` in the current node, and fill in the specified
    /// `attribute` structure.  Return 0 on success, 1 if there is no
    /// attribute found with `localName` and `namespaceId`, and a negative
    /// value otherwise.  If `namespaceId` == -1, then the document's
    /// default namespace will be used.  The strings that were filled into
    /// the `attribute` structure are invalid upon the next
    /// `advanceToNextNode` or `close` is called.
    int lookupAttribute(
                    ElementAttribute *attribute,
                    const char       *localName,
                    int               namespaceId) const BSLS_KEYWORD_OVERRIDE;

    /// Return the base URI name of the current node if the current node has
    /// a base URI and NULL otherwise.  The returned pointer is owned by
    /// this object and must not be modified or deallocated by the caller.
    /// The returned pointer becomes invalid upon the next
    /// `advanceToNextNode`, when `close` is called or the reader is
    /// destroyed.
    const char *nodeBaseUri() const BSLS_KEYWORD_OVERRIDE;

    /// Return the nesting depth of the current node in the XML document.
    /// The root node has depth 0.
    int nodeDepth() const BSLS_KEYWORD_OVERRIDE;

    /// Return the local name of the current node if the current node has a
    /// local name and NULL otherwise.  The returned pointer is owned by
    /// this object and must not be modified or deallocated by the caller.
    /// The returned pointer becomes invalid upon the next
    /// `advanceToNextNode`, when `close` is called or the reader is
    /// destroyed.
    const char *nodeLocalName() const BSLS_KEYWORD_OVERRIDE;

    /// Return true if the current node has a value and false otherwise.
    bool nodeHasValue() const BSLS_KEYWORD_OVERRIDE;

    /// Return the qualified name of the current node if the current node
    /// has a name and NULL otherwise.  The returned pointer is owned by
    /// this object and must not be modified or deallocated by the caller.
    /// The returned pointer becomes invalid upon the next
    /// `advanceToNextNode`, when `close` is called or the reader is
    /// destroyed.
    const char *nodeName() const BSLS_KEYWORD_OVERRIDE;

    /// Return the namespace ID of the current node if the current node has
    /// a namespace id and a negative number otherwise.
    int nodeNamespaceId() const BSLS_KEYWORD_OVERRIDE;

    /// Return the namespace URI name of the current node if the current
    /// node has a namespace URI and NULL otherwise.  The returned pointer
    /// is owned by this object and must not be modified or deallocated by
    /// the caller.  The returned pointer becomes invalid upon the next
    /// `advanceToNextNode`, when `close` is called or the reader is
    /// destroyed.
    const char *nodeNamespaceUri() const BSLS_KEYWORD_OVERRIDE;

    /// Return the prefix name of the current node if the correct node has a
    /// prefix name and NULL otherwise.  The returned pointer is owned by
    /// this object and must not be modified or deallocated by the caller.
    /// The returned pointer becomes invalid upon the next
    /// `advanceToNextNode`, when `close` is called or the reader is
    /// destroyed.
    const char *nodePrefix() const BSLS_KEYWORD_OVERRIDE;

    /// Return the node type of the current node if the reader `isOpen` and
    /// has not encounter an error and `Reader::NONE` otherwise.
    NodeType nodeType() const BSLS_KEYWORD_OVERRIDE;

    /// Return the value of the current node if the current node has a value
    /// and NULL otherwise.  The returned pointer is owned by this object
    /// and must not be modified or deallocated by the caller.  The returned
    /// pointer becomes invalid upon the next `advanceToNextNode`, when
    /// `close` is called or the reader is destroyed.
    const char *nodeValue() const BSLS_KEYWORD_OVERRIDE;

    /// Return the number of attributes for the current node if that node
    /// has attributes and 0 otherwise.
    int numAttributes() const BSLS_KEYWORD_OVERRIDE;

    /// Return the option flags.
    unsigned int options() const BSLS_KEYWORD_OVERRIDE;

    /// Return a pointer to the modifiable prefix stack that is used by this
    /// reader to manage namespace prefixes or 0 if namespace support is
    /// disabled.  The behavior is undefined if the returned prefix stack is
    /// augmented in any way after calling `open` and before calling
    /// `close`.
    PrefixStack *prefixStack() const BSLS_KEYWORD_OVERRIDE;

    /// Return the external XML resource resolver.
    XmlResolverFunctor resolver() const BSLS_KEYWORD_OVERRIDE;
};

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

                                // ------------
                                // class Reader
                                // ------------

// PRIVATE MANIPULATORS
inline
Reader *Utf8ReaderWrapper::heldReader()
{
    return d_reader_p;
}

// PRIVATE ACCESSORS
inline
const Reader *Utf8ReaderWrapper::heldReader() const
{
    return d_reader_p;
}

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

#endif // INCLUDED_BALXML_UTF8READERWRAPPER

// ----------------------------------------------------------------------------
// Copyright 2020 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 ----------------------------------
