/*
* 
* Copyright (c) 1998,1999 Microsoft Corporation. All rights reserved.
* EXEMPT: copyright change only, no build required
* 
*/
#include "stdinc.h"
#include "core.hxx"
#pragma hdrstop

#include "xmlhelper.hxx"
#include "xmlstream.hxx"
#include "bufferedstream.hxx"
#include "xmlparser.hxx"

const long BLOCK_SIZE = 512;
const long STACK_INCREMENT = 10;

// macros used in this file
#define INTERNALERROR       return XML_E_INTERNALERROR;
#define checkeof(a,b)       if (_fEOF) return b;
#define ADVANCE             hr = _pInput->nextChar(&_chLookahead, &_fEOF); if (hr != S_OK) return hr;
#define ADVANCETO(a)        hr = AdvanceTo(a);  if (hr != S_OK) return hr;
#define ISWHITESPACE(ch)    _pInput->isWhiteSpace(ch) 
#define STATE(state)        { _sSubState = state; return S_OK; }
#define GOTOSTART(state)    { _sSubState = state; goto Start; }
#define DELAYMARK(hr)       (hr == S_OK || (hr >= XML_E_TOKEN_ERROR && hr < XML_E_LASTERROR))
#define XML_E_FOUNDPEREF    0x8000e5ff


// The tokenizer has special handling for the following attribute types.
// These values are derived from the XML_AT_XXXX types provided in SetType
// and are also calculated during parsing of an ATTLIST for parsing of
// default values.
typedef enum 
{
    XMLTYPE_CDATA,       // the default.
    XMLTYPE_NAME,
    XMLTYPE_NAMES,
    XMLTYPE_NMTOKEN,
    XMLTYPE_NMTOKENS,
} XML_ATTRIBUTE_TYPE;

//==============================================================================
// xiaoyu : a simplified table : only deal with comments, not include DOCTYPE, NotationDecl, EntityDecl and ElementDecl.
// Parse an <!^xxxxxxxx Declaration.
const StateEntry g_DeclarationTable[] =
{
// 0    '<' ^ '!' 
    { OP_CHAR, L"!", 1, (DWORD)XML_E_INTERNALERROR,  },                    
// 1    '<!' ^ '-'
    { OP_PEEK, L"-", 2, 4, 0 },                    
// 2    '<!-'
    { OP_COMMENT,  NULL, 3,   },                 
// 3    done !!
    { OP_POP,  NULL, 0, 0 },

// 4    '<!' ^ '['
    { OP_PEEK, L"[", 5, (DWORD)XML_E_BADDECLNAME, 0 }, //xiaoyu : we do not consider others <!XXX, which is a DTD subset
// 5    '<![...'
    { OP_CONDSECT,  NULL, 3,   }
 
};

//==============================================================================
// Parse an <?xml or <?xml:namespace declaration.
const StateEntry g_XMLDeclarationTable[] =
{
// 0    must be xml declaration - and not xml namespace declaration        
    { OP_TOKEN, NULL, 1, XML_XMLDECL, 0 },
// 1    '<?xml' ^ S version="1.0" ...
    { OP_OWS, NULL, 2 },
// 2    '<?xml' S ^ version="1.0" ...
    { OP_SNCHAR, NULL, 3, (DWORD)XML_E_XMLDECLSYNTAX },	
// 3    '<?xml' S ^ version="1.0" ...
    { OP_NAME, NULL, 4, },
// 4    '<?xml' S version^="1.0" ...
    { OP_STRCMP, L"version", 5, 12, XML_VERSION },
// 5
    { OP_EQUALS, NULL, 6 },
// 6    '<?xml' S version = ^ "1.0" ...
    { OP_ATTRVAL, NULL, 32, 0},
// 7    '<?xml' S version '=' value ^ 
    { OP_TOKEN, NULL, 8, XML_PCDATA, -1 },
// 8    ^ are we done ?
    { OP_CHARWS, L"?", 28, 9 },    // must be '?' or whitespace.
// 9    ^ S? [encoding|standalone] '?>'
    { OP_OWS, NULL, 10 },
// 10
    { OP_CHAR, L"?", 28, 33 },    // may have '?' after skipping whitespace.
// 11    ^ [encoding|standalone] '?>'
    { OP_NAME, NULL, 12, },
// 12
    { OP_STRCMP, L"standalone", 23, 13, XML_STANDALONE },
// 13
    { OP_STRCMP, L"encoding", 14, (DWORD)XML_E_UNEXPECTED_ATTRIBUTE, XML_ENCODING },
// 14
    { OP_EQUALS, NULL, 15 },
// 15   
    { OP_ATTRVAL, NULL, 16, 0 },
// 16
    { OP_ENCODING, NULL, 17, 0, -1 },
// 17
    { OP_TOKEN, NULL, 18, XML_PCDATA, -1 },

// 18    ^ are we done ?
    { OP_CHARWS, L"?", 28, 19 },    // must be '?' or whitespace.
// 19    ^ S? standalone '?>'
    { OP_OWS, NULL, 20 },
// 20
    { OP_CHAR, L"?", 28, 34 },    // may have '?' after skipping whitespace.
// 21    ^ standalone '?>'
    { OP_NAME, NULL, 22, },
// 22 
    { OP_STRCMP, L"standalone", 23, (DWORD)XML_E_UNEXPECTED_ATTRIBUTE, 
XML_STANDALONE },
// 23
    { OP_EQUALS, NULL, 24 },
// 24
    { OP_ATTRVAL, NULL, 25, 0 },
// 25   
    { OP_STRCMP, L"yes", 31, 30, -1  },

// 26    <?xml ....... ^ '?>'   -- now expecting just the closing '?>' chars
    { OP_OWS, NULL, 27 },
// 27    
    { OP_CHAR, L"?", 28, (DWORD)XML_E_XMLDECLSYNTAX, 0 },
// 28   
    { OP_CHAR, L">", 29, (DWORD)XML_E_XMLDECLSYNTAX, 0 },
// 29    done !!
    { OP_POP,  NULL, 0, XMLStream::XML_ENDXMLDECL },

//----------------------- check standalone values  "yes" or "no"
// 30
    { OP_STRCMP, L"no", 31, (DWORD)XML_E_INVALID_STANDALONE, -1  },
// 31
    { OP_TOKEN, NULL, 26, XML_PCDATA, -1 },
    
//----------------------- check version = "1.0"
// 32
    { OP_STRCMP, L"1.0", 7, (DWORD)XML_E_INVALID_VERSION, -1 },
// 33 
    { OP_SNCHAR, NULL, 11, (DWORD)XML_E_XMLDECLSYNTAX },   
// 34 
    { OP_SNCHAR, NULL, 21, (DWORD)XML_E_XMLDECLSYNTAX },  
};

static const WCHAR* g_pstrCDATA = L"CDATA";
////////////////////////////////////////////////////////////////////////
XMLStream::XMLStream(XMLParser * pXMLParser)
:   _pStack(1), _pStreams(1)
{   
    // precondition: 'func' is never NULL
    _fnState = &XMLStream::init;
    _pInput = NULL;
    _pchBuffer = NULL;
    _fDTD = false;
	//_fInternalSubset = false;
    _cStreamDepth = 0;
    _pXMLParser = pXMLParser;

    _init();
    SetFlags(0);
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::init()
{
    HRESULT hr = S_OK;

    if (_pInput == NULL) 
	{
		//haven' called put-stream yet
        return XML_E_ENDOFINPUT;
	}
    
    _init();
#ifdef FUSION_USE_OLD_XML_PARSER_SOURCE
    if (_fDTD)
    {
        _fnState = &XMLStream::parseDTDContent;
    }
    else
#endif
    {
        _fnState =  &XMLStream::parseContent;
    }

    checkhr2(push(&XMLStream::firstAdvance,0));

    return hr;
}
////////////////////////////////////////////////////////////////////////
void
XMLStream::_init()
{
    _fEOF = false;
    //_fEOPE = false;
    _chLookahead	= 0;
    _nToken			= XML_PENDING;
    _chTerminator	= 0;
    _lLengthDelta	= 0;
	_lNslen = _lNssep = 0;
    _sSubState		= 0;
    _lMarkDelta		= 0;
	//_nAttrType = XMLTYPE_CDATA;
    _fUsingBuffer	= false;
    _lBufLen		= 0;
    delete[] _pchBuffer;
    _pchBuffer		= NULL;
    _lBufSize		= 0;
    _fDelayMark		= false;
    _fFoundWhitespace = false;
    _fFoundNonWhitespace = false;
	//_fFoundPEREf = false;
    _fWasUsingBuffer = false;
    _chNextLookahead = 0;
    //_lParseStringLevel = 0;
    //_cConditionalSection = 0;
    //_cIgnoreSectLevel = 0;
    //_fWasDTD = false;

	_fParsingAttDef = false;
    _fFoundFirstElement = false;
    _fReturnAttributeValue = true;
	//_fHandlePE = true;

    _pTable = NULL;
    //_lEOFError = 0;
}
////////////////////////////////////////////////////////////////////////
XMLStream::~XMLStream()
{
    delete _pInput;
    delete[] _pchBuffer;

    InputInfo* pi = _pStreams.peek();
    while (pi != NULL)
    {
        // Previous stream is finished also, so
        // pop it and continue on.
        delete pi->_pInput;
        pi = _pStreams.pop();
    }
}
////////////////////////////////////////////////////////////////////////
HRESULT  
XMLStream::AppendData( 
    /* [in] */ const BYTE  *buffer,
    /* [in] */ long  length,
    /* [in] */ BOOL  last)
{
    if (_pInput == NULL)
    {
        _pInput = NEW (BufferedStream(this));
        if (_pInput == NULL)
            return E_OUTOFMEMORY;
        init();
    }

    HRESULT hr = _pInput->AppendData(buffer, length, last);

    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT  
XMLStream::Reset( void)
{
    init();
    delete _pInput;
    _pInput = NULL;

    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT  
XMLStream::PushStream( 
        /* [unique][in] */ EncodingStream  *p,
        /* [in] */ bool fExternalPE)
{
	UNUSED(fExternalPE);

    if (_pStreams.used() == 0 && _pInput == NULL)
        init();

    _cStreamDepth++;

    if (_fDelayMark && _pInput != NULL)
    {
        mark(_lMarkDelta);
        _lMarkDelta = 0;
        _fDelayMark = false;
    }

    // Save current input stream.
    if (_pInput != NULL)
    {
        InputInfo* pi = _pStreams.push();
        if (pi == NULL)
            return E_OUTOFMEMORY;
 
        pi->_pInput = _pInput;
        pi->_chLookahead = _chLookahead;
        //pi->_fPE = true; // assume this is a parameter entity.
        //pi->_fExternalPE = fExternalPE;
        //pi->_fInternalSubset = _fInternalSubset;
        if (&XMLStream::skipWhiteSpace == _fnState  && _pStack.used() > 0) {
            StateInfo* pSI = _pStack.peek();
            pi->_fnState = pSI->_fnState;
        }
        else
            pi->_fnState = _fnState;
        

        // and prepend pe text with space as per xml spec.
        _chLookahead = L' ';
        _chNextLookahead = _chLookahead;
        _pInput = NULL;
    }

    _pInput = NEW (BufferedStream(this));
    if (_pInput == NULL)
        return E_OUTOFMEMORY;

    if (p != NULL)
        _pInput->Load(p);
    
    if (_chLookahead == L' ')
        _pInput->setWhiteSpace(); // _pInput didn't see this space char.
    
	return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::PopStream()
{
    // This method has to pop all streams until it finds a stream that
    // can deliver the next _chLookahead character.

    HRESULT hr = S_OK;

    InputInfo* pi = NULL;

    pi = _pStreams.peek();
    if (pi == NULL) return S_FALSE;

    _chLookahead = pi->_chLookahead;

    // Found previous stream, so we can continue.
    _fEOF = false;

    // Ok, so we actually got the next character, so
    // we can now safely throw away the previous 
    // lookahead character and return the next
    // non-whitespace character from the previous stream.
    delete _pInput;

    _pInput = pi->_pInput;
    if (_chLookahead == L' ')
        _pInput->setWhiteSpace();

    // BUGBUG: we need to clear this so that the parser does not
    // try and pop a download in the internalPE case (when handling XML_E_ENDOFINPUT in run())
    // but this means that internal PEs never get XMLNF_ENDENTITY notifications generated.
    // The DTDNodeFactory requires this behaviour currently (incorrectly)
    _pStreams.pop();

    _cStreamDepth--;

    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT  
XMLStream::GetNextToken( 
        /* [out] */ DWORD  *t,
        /* [out] */ const WCHAR  **text,
        /* [out] */ long  *length,
        /* [out] */ long  *nslen)
{
    HRESULT hr;

    if (_fDTD)
        return E_UNEXPECTED;

    if (_fDelayMark)
    {
        mark(_lMarkDelta);
        _lMarkDelta = 0;
        _fDelayMark = false;
    }

    hr = (this->*_fnState)();
    while (hr == S_OK && _nToken == XML_PENDING)
        hr = (this->*_fnState)();
    
    if (hr == S_OK)
        *t = _nToken;
    else if (hr == E_PENDING) {
        *t = XML_PENDING;
        *length = *nslen = 0;
        *text = NULL;
        goto CleanUp;
    }
    else
        *t = XML_PENDING;
    
    // At this point hr == S_OK or it is some error.  So we
    // want to return the text of the current token, since this
    // is useful in both cases.

    if (! _fUsingBuffer)
    {
        getToken(text,length);
        if (_lLengthDelta != 0)
        { // xiaoyu : IF STOP WITHIN, HAVE A CAREFUL LOOK : in ParsingAttributeValue, we have to read ahead of one char '"'
            *length += _lLengthDelta;
            _lLengthDelta = 0;
        }
// This can only happen in the context of a DTD.
//        if (_fWasUsingBuffer)
//        {
//            _fUsingBuffer = _fWasUsingBuffer;
//            _fWasUsingBuffer = false;
//        }
    }
    else
    { // xiaoyu : IF STOP WITHIN, HAVE A CAREFUL LOOK
        *text = _pchBuffer;
        *length = _lBufLen;
        _fUsingBuffer = false;
        _fFoundWhitespace = false;
        _lBufLen = 0;
        _lLengthDelta = 0;
    }
    
    if (DELAYMARK(hr))
    {
        // Mark next time around so that error information points to the
        // beginning of this token.
        _fDelayMark = true;
    }
    else 
    {  // xiaoyu : IF STOP WITHIN, HAVE A CAREFUL LOOK
        // otherwise mark this spot right away so we point to the exact
        // source of the error.
        mark(_lMarkDelta);
        _lMarkDelta = 0;
    }
    
    _nToken = XML_PENDING;
    *nslen = _lNslen;
    _lNslen = _lNssep = 0;

CleanUp:
    return hr;
}
////////////////////////////////////////////////////////////////////////
ULONG  
XMLStream::GetLine()    
{
    BufferedStream* input = getCurrentStream();
    if (input != NULL)
        return input->getLine();
    return 0;
}
////////////////////////////////////////////////////////////////////////
ULONG  
XMLStream::GetLinePosition( )
{
    BufferedStream* input = getCurrentStream();
    if (input != NULL)
        return input->getLinePos();
    return 0;
}
////////////////////////////////////////////////////////////////////////
ULONG  
XMLStream::GetInputPosition( )
{
    BufferedStream* input = getCurrentStream();
    if (input != NULL)
        return input->getInputPos();
    return 0;
}
////////////////////////////////////////////////////////////////////////
HRESULT  
XMLStream::GetLineBuffer( 
    /* [out] */ const WCHAR  * *buf, ULONG* len, ULONG* startpos)
{
    if (buf == NULL || len == NULL)
        return E_INVALIDARG;

    *buf = NULL;
    BufferedStream* input = getCurrentStream();
    if (input)
        *buf = input->getLineBuf(len, startpos);
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
BufferedStream* 
XMLStream::getCurrentStream()
{
    // Return the most recent stream that
    // actually has somthing to return.
    BufferedStream* input = _pInput;
    if (!_pInput)
    {
        return NULL;
    }
    int i = _pStreams.used()-1;    
    do 
    {
        ULONG len = 0, pos = 0;
//      const WCHAR* buf = input->getLineBuf(&len, &pos); // generates C4189: 'buf' local variable is initialized but not referenced
        (void) input->getLineBuf(&len, &pos);
        if (len > 0)
            return input;

        if (i >= 0)
            input = _pStreams[i--]->_pInput;
        else
            break;
    }
    while (input != NULL);
    return NULL;
}
////////////////////////////////////////////////////////////////////////
void 
XMLStream::SetFlags( unsigned short usFlags)
{
    _usFlags = usFlags;
    // And break out the flags for performance reasons.
    //_fFloatingAmp = (usFlags & XMLFLAG_FLOATINGAMP) != 0;
    _fShortEndTags = (usFlags & XMLFLAG_SHORTENDTAGS) != 0;
    _fCaseInsensitive = (usFlags & XMLFLAG_CASEINSENSITIVE) != 0;
    _fNoNamespaces = (usFlags & XMLFLAG_NONAMESPACES) != 0;
    //_fNoWhitespaceNodes = false; // this is now bogus.  (usFlags & XMLFLAG_NOWHITESPACE) != 0;
    //_fIE4Quirks = (_usFlags & XMLFLAG_IE4QUIRKS) != 0;
    //_fNoDTDNodes = (_usFlags & XMLFLAG_NODTDNODES) != 0;
}
////////////////////////////////////////////////////////////////////////
unsigned short 
XMLStream::GetFlags()
{
    return _usFlags;
}
////////////////////////////////////////////////////////////////////////


//======================================================================
// Real Implementation
HRESULT 
XMLStream::firstAdvance()
{
    HRESULT hr;

    ADVANCE;
    checkhr2(pop(false));

    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseContent()
{
    HRESULT hr = S_OK;

    if (_fEOF)
        return XML_E_ENDOFINPUT;

    switch (_chLookahead){
    case L'<':
        ADVANCE;
        checkeof(_chLookahead, XML_E_UNCLOSEDDECL);
        switch (_chLookahead)
        {
        case L'!':
            checkhr2(_pInput->Freeze()); // stop shifting data until '>'
            return pushTable( 0, g_DeclarationTable, (DWORD)XML_E_UNCLOSEDDECL);
        case L'?':
            checkhr2(push( &XMLStream::parsePI ));
            return parsePI();
        case L'/':
            checkhr2(push(&XMLStream::parseEndTag));
            return parseEndTag();
        default:
            checkhr2(push( &XMLStream::parseElement )); // push ParseContent, and _fnState = parseElement
            if (_fFoundFirstElement)
            {
                return parseElement();
            }
            else
            {
                // Return special end prolog token and then continue with 
                // with parseElement.
                _fFoundFirstElement = true;
                _nToken = XML_ENDPROLOG;
            }
        }
        break;

    default:
        checkhr2(push(&XMLStream::parsePCData));
        return parsePCData();
        break;
    }
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::skipWhiteSpace()
{
    HRESULT hr = S_OK;

    while (ISWHITESPACE(_chLookahead) && ! _fEOF)
    {
        ADVANCE;        
    }
    checkhr2(pop(false));
    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseElement()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        checkhr2(_pInput->Freeze()); // stop shifting data until '>'
        checkhr2(push( &XMLStream::parseName, 1));
        checkhr2(parseName());
        _sSubState = 1;
        // fall through
    case 1:
        checkeof(_chLookahead, XML_E_UNCLOSEDSTARTTAG);
        _nToken = XML_ELEMENT;
        // and then try and parse the attributes, and return
        // to state 2 to finish up.  With an optimization
        // for the case where there are no attributes.
        if (_chLookahead == L'/' || _chLookahead == L'>')
        {
            _sSubState = 2;
        }
		else {
			if (!ISWHITESPACE(_chLookahead))
			{
				return XML_E_BADNAMECHAR;
			}
			
			_chEndChar = L'/'; // for empty tags. //xiaoyu : used to match ENDTAG
			checkhr2(push(&XMLStream::parseAttributes,2));
		}	
        
        return S_OK;
        break;

    case 2: // finish up with start tag.
        mark(); // only return '>' or '/>' in _nToken text
        if (_chLookahead == L'/')
        {
            // must be empty tag sequence '/>'.
            ADVANCE;
            _nToken = XML_EMPTYTAGEND;
        } 
        else if (_chLookahead == L'>')
        {
            _nToken = XML_TAGEND;
        }
        else if (ISWHITESPACE(_chLookahead))
        {
            return XML_E_UNEXPECTED_WHITESPACE;
        }
        else
            return XML_E_EXPECTINGTAGEND;

        _sSubState = 3;
        // fall through
    case 3:
        checkeof(_chLookahead, XML_E_UNCLOSEDSTARTTAG);
        if (_chLookahead != L'>')
        {
            if (ISWHITESPACE(_chLookahead))
                return XML_E_UNEXPECTED_WHITESPACE;
            else 
                return XML_E_EXPECTINGTAGEND;
        }
        ADVANCE; 
        mark();
        checkhr2(pop());// return to parseContent.

        return _pInput->UnFreeze(); 
        break;

    case 4: // swollow up bad tag
        // Allow the weird CDF madness <PRECACHE="YES"/>
        // For total compatibility we fake out the parser by returning
        // XML_EMPTYTAGEND, this way the rest of the tag becomes PCDATA.
        // YUK -- but it works.
        _nToken = XML_EMPTYTAGEND;
        mark();
        checkhr2(pop());// return to parseContent.
        return _pInput->UnFreeze(); 
        break;

    default:
        INTERNALERROR;
    }
    //return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseEndTag()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        ADVANCE; // soak up the '/'
        mark(); 
        // SHORT END TAG SUPPORT, IE4 Compatibility Mode only.
        if (! _fShortEndTags || _chLookahead != L'>') 
        {
            checkhr2(push( &XMLStream::parseName, 1));
            checkhr2(parseName());
        }
        _sSubState = 1;
        // fall through
        
    case 1: // finish parsing end tag
        checkeof(_chLookahead, XML_E_UNCLOSEDENDTAG);
        _nToken = XML_ENDTAG;
        checkhr2(push(&XMLStream::skipWhiteSpace, 2));
        return S_OK;

    case 2:
        checkeof(_chLookahead, XML_E_UNCLOSEDENDTAG);
        if (_chLookahead != L'>')
        {
            return XML_E_BADNAMECHAR;
        }
        ADVANCE;
        mark();
        checkhr2(pop());// return to parseContent.
        break;

    default:
        INTERNALERROR;
    }
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parsePI()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        //_fWasDTD = _fDTD; // as far as Advance is concerned, the contents
        //_fHandlePE = false;    // of a PI are not special.
        ADVANCE;
        checkhr2(_pInput->Freeze()); // stop shifting data until '?>'
        mark(); // don't include '?' in tag name.
        if (_chLookahead == L'x' || _chLookahead == L'X')
        {
            // perhaps this is the magic <?xml version="1.0"?> declaration.
            STATE(7);  // jump to state 7.
        }
        // fall through
        _sSubState = 1;
    case 1:
        checkhr2(push( &XMLStream::parseName, 2));
        checkhr2(parseName()); 
        _sSubState = 2;
        // fall through
    case 2:
        checkeof(_chLookahead, XML_E_UNCLOSEDPI);
        if (_chLookahead != L'?' && ! ISWHITESPACE(_chLookahead))
        { 
            return XML_E_BADNAMECHAR;
        }
        _nToken = XML_PI;
        STATE(3);   // found startpi _nToken and return to _sSubState 3
        break;

    case 3: // finish with rest of PI
        if (_chLookahead == L'?')
        {
            ADVANCE;
            if (_chLookahead == L'>')
            {
                STATE(6);
            }
            else
            {
                return XML_E_EXPECTINGTAGEND;
            }
        }

        checkhr2(push(&XMLStream::skipWhiteSpace, 4));
        checkhr2( skipWhiteSpace() );
        _sSubState = 4;
        // fall through

    case 4: // support for normalized whitespace
        mark(); // strip whitespace from beginning of PI data, since this is
                // just the separator between the PI target name and the PI  data.
        _sSubState = 5;
        // fallthrough

    case 5:
        while (! _fEOF )
        {
            if (_chLookahead == L'?')
            {
                ADVANCE;
                break;
            }
            if (! isCharData(_chLookahead))
                return XML_E_PIDECLSYNTAX;
            ADVANCE;
        }
        _sSubState = 6; // go to next state
        // fall through.
    case 6:
        checkeof(_chLookahead, XML_E_UNCLOSEDPI);
        if (_chLookahead == L'>')
        {
            ADVANCE;
            _lLengthDelta = -2; // don't include '?>' in PI CDATA.
        }
        else
        {
            // Hmmm.  Must be  a lone '?' so go back to state 5.
            STATE(5);
        }
        _nToken = XML_ENDPI;
        //_fHandlePE = true;
        checkhr2(pop());
        return _pInput->UnFreeze();
        break;      

    case 7: // recognize 'm' in '<?xml' declaration
        ADVANCE;
        if (_chLookahead != L'm' && _chLookahead != L'M')
        {
            STATE(11); // not 'xml' so jump to state 11 to parse name
        }
        _sSubState = 8;
        // fall through                

    case 8: // recognize L'l' in '<?xml' declaration
        ADVANCE;
        if (_chLookahead != L'l' && _chLookahead != L'L')
        {
            STATE(11); // not 'xml' so jump to state 11 to parse name
        }
        _sSubState = 9;
        // fall through                

    case 9: // now need whitespace or ':' or '?' to terminate name.
        ADVANCE;
        if (ISWHITESPACE(_chLookahead))
        {
            if (! _fCaseInsensitive)
            {
                const WCHAR* t = NULL;
                long len =0; // for prefix bug : xiaoyuw@08/28/00
                getToken(&t,&len);
                //if (! StringEquals(L"xml",t,3,false)) // case sensitive
                if (::FusionpCompareStrings(L"xml", 3, t, 3, false)!=0) // not equal 
                    return XML_E_BADXMLCASE;
            }
            return pushTable(10, g_XMLDeclarationTable, (DWORD)XML_E_UNCLOSEDPI);
        }
        if (isNameChar(_chLookahead) || _chLookahead == ':')  
        {
            STATE(11); // Hmmm.  Must be something else then so continue parsing name
        }
        else
        {
            return XML_E_XMLDECLSYNTAX;
        }
        break;

    case 10:
        //_fHandlePE = true;
        checkhr2(pop());
        return _pInput->UnFreeze();
        break;

    case 11:
        if (_chLookahead == ':')
            ADVANCE;
        _sSubState = 12;
        // fall through
    case 12:
        if (isNameChar(_chLookahead))
        {
            checkhr2(push( &XMLStream::parseName, 2));
            _sSubState = 1; // but skip IsStartNameChar test
            checkhr2(parseName());
            return S_OK;
        } 
        else
        {
            STATE(2);
        }
        break;

    default:
        INTERNALERROR;
    }

    //return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseComment()
{
    // ok, so '<!-' has been parsed so far
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        //_fWasDTD = _fDTD; // as far as the DTD is concerned, the contents
        //_fHandlePE = false;    // of a COMMENT are not special.
        ADVANCE; // soak up first '-'
        checkeof(_chLookahead, XML_E_UNCLOSEDCOMMENT);
        if (_chLookahead != L'-')
        {
            return XML_E_COMMENTSYNTAX;
        }
        _sSubState = 1;
        // fall through
    case 1:
        ADVANCE; // soak up second '-'
        mark(); // don't include '<!--' in comment text
        _sSubState = 2;
        // fall through;
    case 2:
        while (! _fEOF)
        {
            if (_chLookahead == L'-')
            {
                ADVANCE; // soak up first closing L'-'                
                break;
            }
            if (! isCharData(_chLookahead))
                return XML_E_BADCHARDATA;
            ADVANCE;
        }
        checkeof(_chLookahead, XML_E_UNCLOSEDCOMMENT);
        _sSubState = 3; // advance to next state        
        // fall through.
    case 3:
        if (_chLookahead != L'-')
        {
            // Hmmm, must have been a floating L'-' so go back to state 2
            STATE(2);
        }
        ADVANCE; // soak up second closing L'-'
        _sSubState = 4; 
        // fall through
    case 4:
        checkeof(_chLookahead, XML_E_UNCLOSEDCOMMENT);
        //if (_chLookahead != L'>' && ! _fIE4Quirks)
		if (_chLookahead != L'>')
        {
            // cannot have floating L'--' unless we are in compatibility mode.
            return XML_E_COMMENTSYNTAX;
        }
        ADVANCE; // soak up closing L'>'
        _lLengthDelta = -3; // don't include L'-->' in PI CDATA.
        _nToken = XML_COMMENT;
        checkhr2(pop());
        //_fHandlePE = true;
        break;

    default:
        INTERNALERROR;
    }    
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseName()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        if (! isStartNameChar(_chLookahead))
        {
            if (ISWHITESPACE(_chLookahead))
                hr = XML_E_UNEXPECTED_WHITESPACE;
            else
                hr = XML_E_BADSTARTNAMECHAR;
            goto CleanUp;
        }
        mark(); 
        _sSubState = 1;
        // fall through

    case 1:
		_lNslen = _lNssep = 0;
        while (isNameChar(_chLookahead) && !_fEOF)
        {
            ADVANCE;
        }
        hr = pop(false); // return to the previous state
        break;

    default:
        INTERNALERROR;
    }

CleanUp:
    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseAttributes()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        //_nAttrType = XMLTYPE_CDATA;
        _fCheckAttribute = false;
        checkhr2(push(&XMLStream::skipWhiteSpace, 1));
        checkhr2( skipWhiteSpace() );
        _sSubState = 1;
        // fall through
    case 1:
        if (_chLookahead == _chEndChar || _chLookahead == L'>' )
        {
            checkhr2(pop()); // no attributes.
            return S_OK;
        }
        checkhr2( push( &XMLStream::parseName, 2 ) );
        checkhr2( parseName() );

        if (!ISWHITESPACE(_chLookahead) && _chLookahead != L'=')
        {
            return XML_E_BADNAMECHAR;
        }
        _sSubState = 2;
        // fall through
    case 2:
        if (ISWHITESPACE(_chLookahead))
        {
            // Eq ::= S? '=' S?
            STATE(7);
        }

        checkeof(_chLookahead, XML_E_UNCLOSEDSTARTTAG);
        _nToken = XML_ATTRIBUTE;    
        _sSubState = 3;
        return S_OK;
        break;

    case 3:
        if (ISWHITESPACE(_chLookahead))
            return XML_E_UNEXPECTED_WHITESPACE;
        _fWhitespace = false;
        _sSubState = 4;
        // fall through

    case 4:
        if (_chLookahead != L'=')
        {
            return XML_E_MISSINGEQUALS;
        }
        ADVANCE;
        if (ISWHITESPACE(_chLookahead))
        {
            // allow whitespace between '=' and attribute value.
            checkhr2(push(&XMLStream::skipWhiteSpace, 5));
            checkhr2( skipWhiteSpace() );            
        }
        _sSubState = 5;
        // fall through

    case 5:
        if (ISWHITESPACE(_chLookahead))
            return XML_E_UNEXPECTED_WHITESPACE;
        if (_chLookahead != L'"' && _chLookahead != L'\'')
        {
            return XML_E_MISSINGQUOTE;
        }
        _chTerminator = _chLookahead;
        ADVANCE;
        mark(); 
        return push(&XMLStream::parseAttrValue, 6);
        //_sSubState = 6;
    // fall through;

    case 6:
        checkeof(_chLookahead, XML_E_UNCLOSEDSTARTTAG);
        if (_chLookahead == _chEndChar || _chLookahead == L'>')
        {
            checkhr2(pop());
            return S_OK;
        }
        if (! ISWHITESPACE(_chLookahead) )
        {
            return XML_E_MISSINGWHITESPACE;
        }
        STATE(0); // go back to state 0
        break;

    case 7:
        // allow whitespace between attribute and '='
        _lLengthDelta = _pInput->getTokenLength();
        checkhr2(push(&XMLStream::skipWhiteSpace, 8));
        checkhr2( skipWhiteSpace() );       
        _sSubState = 8;
        // fall through

    case 8:
        checkeof(_chLookahead, XML_E_UNCLOSEDSTARTTAG);
        _lLengthDelta -= _pInput->getTokenLength();
        STATE(2);
        break;

    default:
        INTERNALERROR;
    }
    //return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT XMLStream::parseAttrValue()
{
    HRESULT hr = S_OK;

    switch (_sSubState)
    {
    case 0: 
        _fParsingAttDef = true;        
        // mark beginning of attribute data           
        _sSubState =  2;
        // fall through;

    case 2:
        while ( _chLookahead != _chTerminator && 
                _chLookahead != L'<' &&
                ! _fEOF  ) 
        {
            if (_chLookahead == L'&')
            {
                // then parse entity ref and then return
                // to state 2 to continue with PCDATA.
                return push(&XMLStream::parseEntityRef,2);
            }
            hr = _pInput->scanPCData(&_chLookahead, &_fWhitespace);
            if (FAILED(hr))
            {
                if (hr == E_PENDING)
                {
                    hr = S_OK;
                    ADVANCE;
                }
                return hr;
            }
        }
        _sSubState = 3;
        // fall through
    case 3:
        checkeof(_chLookahead, XML_E_UNCLOSEDSTRING);
        if (_chLookahead == _chTerminator)
        {
            ADVANCE;
            if (_fReturnAttributeValue)
            {
                // return what we have so far - if anything.
                if ((_fUsingBuffer && _lBufLen > 0) ||
                    _pInput->getTokenLength() > 1)
                {
                    _lLengthDelta = -1; // don't include string _chTerminator.
                    _nToken = XML_PCDATA;
                }
            }
            else
            {
                _fReturnAttributeValue = true; // reset to default value.
            }
            _fParsingAttDef = false;
            checkhr2(pop());
            return S_OK;
        } 
        else
        {
            return XML_E_BADCHARINSTRING;
        }        
        break;

    default:
        INTERNALERROR;
    }
    //return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::ScanHexDigits()
{
    HRESULT hr = S_OK;
    while (! _fEOF && _chLookahead != L';')
    {
        if (! isHexDigit(_chLookahead))
        {
            return ISWHITESPACE(_chLookahead) ? XML_E_UNEXPECTED_WHITESPACE : XML_E_BADCHARINENTREF;
        }
        ADVANCE;
    }
    checkeof(_chLookahead, XML_E_UNEXPECTEDEOF);
    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::ScanDecimalDigits()
{
    HRESULT hr = S_OK;
    while (! _fEOF && _chLookahead != L';')
    {
        if (! isDigit(_chLookahead))
        {
            return ISWHITESPACE(_chLookahead) ? XML_E_UNEXPECTED_WHITESPACE : XML_E_BADCHARINENTREF;
        }
        ADVANCE;
    }
    checkeof(_chLookahead, XML_E_UNEXPECTEDEOF);
    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parsePCData()
{
    HRESULT hr = S_OK;

    switch (_sSubState)
    {
    case 0:
        _fWhitespace = true;
        _sSubState = 1;
        // fall through;

    case 1:
        // This state is used when we are not normalizing white space.  This
        // is a separate state for performance reasons.  
        // Normalizing whitespace is about 11% slower.
        while (_chLookahead != L'<' && ! _fEOF )
        {
             if (_chLookahead == L'&')
            {
                // then parse entity ref and then return
                // to state 1 to continue with PCDATA.
                return push(&XMLStream::parseEntityRef,1);
            }

            if (_chLookahead == L'>')
            {
                WCHAR* pText = NULL;
                long len = 0;
                _pInput->getToken((const WCHAR**)&pText, &len);
                //if (len >= 2 && StrCmpN(L"]]", pText + len - 2, 2) == 0)
                if ((len >= 2) && (::FusionpCompareStrings(L"]]", 2, pText + len - 2, 2, false)==0))
		             return XML_E_INVALID_CDATACLOSINGTAG;               
            }
// This slows us down too much.
//            else if (! isCharData(_chLookahead))
//            {
//                return XML_E_BADCHARDATA;
//            }

            hr = _pInput->scanPCData(&_chLookahead, &_fWhitespace);
            if (FAILED(hr))
            {
                if (hr == E_PENDING)
                {
                    hr = S_OK;
                    ADVANCE;
                }
                return hr;
            }
            checkhr2(hr);
        }
        _sSubState = 2;
        // fall through

    case 2:
        if (_pInput->getTokenLength() > 0 || _fUsingBuffer)
        {
            _nToken = _fWhitespace ? XML_WHITESPACE : XML_PCDATA;
        }
        checkhr2(pop());
        break;

    default:
        INTERNALERROR;
    }   
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseEntityRef()
{
    HRESULT hr = S_OK;
    long entityLen = 0, lLen = 1;
    const WCHAR* t = NULL; 
    long len = 0;

Start:
    switch (_sSubState)
    {
    case 0: // ^ ( '&#' [0-9]+ ) | ('&#X' [0-9a-fA-F]+) | ('&' Name) ';'
        _nPreToken = XML_PENDING;
        _lEntityPos = _pInput->getTokenLength(); // record entity position.
        _fPCDataPending = (_lEntityPos > 0);

        if (PreEntityText())
        {
            // remember the pending text before parsing the entity.
            _nPreToken = _nToken;
            _nToken = XML_PENDING;
        }
        _sSubState = 1;
        // fall through
    case 1:
        ADVANCE; // soak up the '&'
        _sSubState = 2;
        // fall through
    case 2:
        checkeof(_chLookahead, XML_E_UNEXPECTEDEOF);
        if (_chLookahead == L'#')
        {
            ADVANCE;
            _sSubState = 3;
            // fall through
        }
        else
        {
            // Loose entity parsing allows "...&6..."
            if (! isStartNameChar(_chLookahead))
            {
				/*
                if (_fFloatingAmp)
                {
                    // then it isn't an entity reference, so go back to PCDATA
                    if (_fUsingBuffer)
                    {
                        // this in case we are normalizing white space.
                        PushChar(L'&');
                    }
                    _fWhitespace = false;
                    checkhr2(pop());
                    return S_OK;
                }
                else */
				if (ISWHITESPACE(_chLookahead))
                    return XML_E_UNEXPECTED_WHITESPACE;
                else
                    return XML_E_BADSTARTNAMECHAR;
            }
            checkhr2(push(&XMLStream::parseName, 6));
            _sSubState = 1; // avoid doing a mark() so we can return PCDATA if necessary.
            return parseName();
        }
        break;

        // ------------- Numeric entity references --------------------
    case 3:
        checkeof(_chLookahead, XML_E_UNEXPECTEDEOF);
        if (_chLookahead == L'x')
        {
            // hex character reference.
            ADVANCE;
            STATE(5); // go to state 5
        }
        _sSubState = 4;
        // fall through

    case 4: // '&#' ^ [0-9]+ ';'
        checkhr2(ScanDecimalDigits());
        if (_chLookahead != L';')
        {
            STATE(9);
        }

        entityLen = _pInput->getTokenLength() - _lEntityPos;
        getToken(&t, &len);
        checkhr2(DecimalToUnicode(t + _lEntityPos + 2, entityLen - 2, _wcEntityValue));
        lLen = 2;
        _nToken = XML_NUMENTITYREF;
        GOTOSTART(10); // have to use GOTOSTART() because we want to use the values of t and len
        break;

    case 5: // '&#X' ^ [0-9a-fA-F]+
        checkhr2(ScanHexDigits());
        if (_chLookahead != L';')
        {
            STATE(9);
        }

        entityLen = _pInput->getTokenLength() - _lEntityPos;
        getToken(&t, &len);
        checkhr2(HexToUnicode(t + _lEntityPos + 3, entityLen - 3, _wcEntityValue));
        lLen = 3;
        _nToken = XML_HEXENTITYREF;
        GOTOSTART(10);  // have to use GOTOSTART() because we want to use the values of t and len
        break;
        
        // ------------- Named Entity References --------------------
    case 6: // '&' Name ^ ';'
        checkeof(_chLookahead, XML_E_UNEXPECTEDEOF);
        if (_chLookahead != L';')
        {
            STATE(9);
        }

        // If parseName found a namespace then we need to calculate the
        // real nslen taking the pending PC data and '&' into account
        // and remember this in case we have to return the PCDATA.
        _nEntityNSLen = (_lNslen > 0) ? _lNslen - _lEntityPos - 1 : 0;
        _fUsingBuffer = false;

        entityLen = _pInput->getTokenLength() - _lEntityPos;
        getToken(&t, &len);

        if (0 != (_wcEntityValue = BuiltinEntity(t + _lEntityPos + 1, entityLen - 1))) //||
            //(_fIE4Quirks && 0xFFFF != (_wcEntityValue = LookupBuiltinEntity(t + _lEntityPos + 1, entityLen - 1))))
        {
            lLen = 1;
            _nToken = XML_BUILTINENTITYREF;
            GOTOSTART(10);  // have to use GOTOSTART() because we want to use the values of t and len
        }
        else //xiaoyu : Fusion XML Parser does not support external ref, 
			 // so, if it is not a builtIn ref, we would return error
			return XML_E_MISSINGSEMICOLON;
		break; 
		//xiaoyu : Fusion XML Parser does not support external ref
		/*
			if (_nPreToken != XML_PENDING)
        {
            // Return previous token (XML_PCDATA or XML_WHITESPACE)
            _lLengthDelta = -entityLen;
            _lMarkDelta = entityLen - 1; // don't include '&' in _nToken.
            _nToken = _nPreToken;
            STATE(7);
        }

        mark(entityLen-1); // don't include '&' in _nToken.
        _sSubState = 7;
        // fall through

    case 7:
        ADVANCE; // soak up the ';'
        _nToken = XML_ENTITYREF;
        _lNslen = _nEntityNSLen;
        _lLengthDelta = -1; // don't include the ';'
        STATE(8); // return token and resume in state 8.
        break;
    */
    case 8:
        mark();
        checkhr2(pop());
        return S_OK;
	/*
    case 9:
        // Soft entity handling - we just continue with PCDATA in 
        // this case.
		
        if (_fFloatingAmp)
        {
            if (_fUsingBuffer)
            {
                // this in case we are normalizing white space.  In this case
                // we have to copy what we have so far to the normalized buffer.
                long endpos = _pInput->getTokenLength();
                const WCHAR* t; long len;
                getToken(&t, &len);
                for (long i = _lEntityPos; i < endpos; i++)
                    PushChar(t[i]);
            }
            _fWhitespace = false;
            checkhr2(pop());
            return S_OK;
        }
        else
		
            return XML_E_MISSINGSEMICOLON;
        break;
	*/

    case 10:
        // Return the text before builtin or char entityref as XML_PCDATA
        if (_nPreToken)
        {
            _nPreToken = _nToken;
            _nToken = XML_PCDATA;
            _lLengthDelta = -entityLen;
            _lMarkDelta = entityLen - lLen; // don't include '&' in _nToken.
            STATE(11);  // return token and resume in state 12.
        }
        else
        {
            _nPreToken = _nToken;
            mark(entityLen - lLen);
            GOTOSTART(11);
        }
        break;

    case 11:
        // push the builtin entity
        _fUsingBuffer = true;
        PushChar(_wcEntityValue);
        _nToken = _nPreToken;
        STATE(12); // return token and resume in state 12.
        break;

    case 12:
        ADVANCE; // soak up the ';'
        STATE(8); // resume in state 8.
        break;

    default:
        INTERNALERROR;
    }   
    return S_OK;      
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::pushTable(short substate, const StateEntry* table, DWORD le)
{
    HRESULT hr = S_OK;

    checkhr2(push(&XMLStream::parseTable, substate));
	_pTable = table;
	UNUSED(le);
    //_lEOFError = le;
    return hr;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::push(StateFunc f, short s)
{
    StateInfo* pSI = _pStack.push();
    if (pSI == NULL)
        return E_OUTOFMEMORY;

    pSI->_sSubState = s;
    pSI->_fnState = _fnState;
	pSI->_pTable = _pTable;
	pSI->_cStreamDepth = _cStreamDepth;


    _sSubState = 0;
    _fnState = f;

    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT
XMLStream::pop(bool boundary)
{
    StateInfo* pSI = _pStack.peek();

    // prefix bug fix : xiaoyuw@08/29/00
    ASSERT_NTC(pSI != NULL);

    if (_fDTD && 
        ! (_fParsingAttDef) && boundary && _cStreamDepth != pSI->_cStreamDepth) // _fParsingNames || 
    {
        // If we are in a PE and we are popping out to a state that is NOT in a PE
        // and this is a pop where we need to check this condition, then return an error.
        // For example, the following is not well formed because the parameter entity
        // pops us out of the ContentModel state in which the PE was found:
        // <!DOCTYPE foo [
        //      <!ENTITY % foo "a)">
        //      <!ELEMENT bar ( %foo; >
        //  ]>...
        return XML_E_PE_NESTING;
    }

    _fnState	= pSI->_fnState;
    _sSubState	= pSI->_sSubState;
    _pTable		= pSI->_pTable;
    //_lEOFError	= pSI->_lEOFError;
    _pStack.pop();

    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::switchTo(StateFunc f)
{
    HRESULT hr;

    // Make sure we keep the old stream depth.
    StateInfo* pSI = _pStack.peek();

    // prefix bug fix : xiaoyuw@08/29/00
    ASSERT_NTC(pSI != NULL);
    int currentDepth = _cStreamDepth;
    _cStreamDepth = pSI->_cStreamDepth;

    checkhr2(pop(false));
    checkhr2(push(f,_sSubState)); // keep return to _sSubState the same

    _cStreamDepth = currentDepth;

    return (this->*f)();
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseCondSect()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        ADVANCE; // soak up the '[' character
        //if (_fFoundPEREf) return S_OK;
        _sSubState = 1;
        // fall through
    case 1: // now match magic '[CDATA[' sequence.     
        checkeof(_chLookahead, XML_E_UNCLOSEDMARKUPDECL);
        if (_chLookahead == L'C')
        {
            _pchCDataState = g_pstrCDATA;
            STATE(5); // goto state 5
        }
        _sSubState = 2;   // must be IGNORE, INCLUDE or %pe;
        // fall through

    case 2: // must be DTD markup declaration
        // '<![' ^ S? ('INCLUDE' | 'IGNORE' | %pe;) S? [...]]> or 
        // skip optional whitespace
        //if (_fInternalSubset)
        //    return XML_E_CONDSECTINSUBSET;
        checkeof(_chLookahead, XML_E_EXPECTINGOPENBRACKET);
        checkhr2(push(&XMLStream::skipWhiteSpace, 3));
        return skipWhiteSpace(); // must return because of %pe;

    case 3:
        checkeof(_chLookahead, XML_E_UNCLOSEDMARKUPDECL);
        checkhr2(push(&XMLStream::parseName,4));
        return parseName();

    case 4: // scanned 'INCLUDE' or 'IGNORE'
        {
            const WCHAR* t = NULL;
            long len = 0;
            getToken(&t,&len); 
            //if (StringEquals(L"IGNORE",t,len,false))
            //{
            //    return switchTo(&XMLStream::parseIgnoreSect);
            //}
            //else if (StringEquals(L"INCLUDE",t,len,false))
            //{
            //    return switchTo(&XMLStream::parseIncludeSect);
            //}
            //else
                return XML_E_BADENDCONDSECT;
        }
        break;

    case 5: // parse CDATA name
        while (*_pchCDataState != 0 && _chLookahead == *_pchCDataState && ! _fEOF)
        {
            ADVANCE;            // advance first, before incrementing _pchCDataState
            _pchCDataState++;   // so that this state is re-entrant in the E_PENDING case.
            checkeof(_chLookahead, XML_E_UNCLOSEDMARKUPDECL);
        }
        if (*_pchCDataState != 0)
        {
            // must be INCLUDE or IGNORE section so go to state 2.
            _sSubState = 2;
        } 
        else if (_chLookahead != L'[')
        {
            return XML_E_EXPECTINGOPENBRACKET;
        }
        else if (_fDTD)
            return XML_E_CDATAINVALID;
        else
            return switchTo(&XMLStream::parseCData);

        return S_OK;
        break;        

    default:
        INTERNALERROR;
    }
    return S_OK;
}

////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseCData()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0:
        ADVANCE; // soak up the '[' character.
        mark(); // don't include 'CDATA[' in CDATA text
        _sSubState = 1;
        // fall through
    case 1:
        while (_chLookahead != L']' && ! _fEOF)
        {
            // scanPCData will stop when it sees a ']' character.
            hr = _pInput->scanPCData(&_chLookahead, &_fWhitespace);
            if (FAILED(hr))
            {
                if (hr == E_PENDING)
                {
                    hr = S_OK;
                    ADVANCE;
                }
                return hr;
            }
        }
        checkeof(_chLookahead, XML_E_UNCLOSEDCDATA);
        _sSubState = 2;
        // fall through
    case 2:
        ADVANCE; // soak up first L']' character.
        checkeof(_chLookahead, XML_E_UNCLOSEDCDATA);
        if (_chLookahead != L']')
        {
            // must have been floating ']' character, so
            // return to state 1.
            STATE(1); 
        }
        _sSubState = 3;
        // fall through
    case 3:
        ADVANCE; // soak up second ']' character.
        checkeof(_chLookahead, XML_E_UNCLOSEDCDATA);
        if (_chLookahead == L']')
        {
            // Ah, an extra ']' character, tricky !!  
            // In this case we stay in state 3 until we find a non ']' character
            // so you can terminate a CDATA section with ']]]]]]]]]]]]]]]]>'
            // and everying except the final ']]>' is treated as CDATA.
            STATE(3);
        }
        else if (_chLookahead != L'>')
        {
            // must have been floating "]]" pair, so
            // return to state 1.
            STATE(1);
        }
        _sSubState = 4;
        // fall through
    case 4:
        ADVANCE; // soak up the '>'
        _nToken = XML_CDATA;
        _lLengthDelta = -3; // don't include terminating ']]>' in text.
        checkhr2(pop()); // return to parseContent.
        return S_OK;
        break;

    default:
        INTERNALERROR;
    }
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT
XMLStream::parseEquals()
{
    HRESULT hr = S_OK;
    switch (_sSubState)
    {
    case 0: // Eq ::= S? '=' S? 
        if (ISWHITESPACE(_chLookahead))
        {
            // allow whitespace between attribute and '='
            checkhr2(push(&XMLStream::skipWhiteSpace, 1));
            checkhr2( skipWhiteSpace() );            
        }
        _sSubState = 1;
        // fall through

    case 1:
        if (_chLookahead != L'=')
        {
            return XML_E_MISSINGEQUALS;
        }
        ADVANCE;
        if (ISWHITESPACE(_chLookahead))
        {
            // allow whitespace between '=' and attribute value.
            checkhr2(push(&XMLStream::skipWhiteSpace, 2));
            checkhr2( skipWhiteSpace() );            
        }
        _sSubState = 2;
        // fall through

    case 2:
        checkhr2(pop(false));
        break;

    default:
        INTERNALERROR;

    }
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::parseTable()
{
    HRESULT hr = S_OK;

    while (hr == S_OK && _nToken == XML_PENDING)
    {
        const StateEntry* pSE = &_pTable[_sSubState];

        DWORD newState = pSE->_sGoto;

        switch (pSE->_sOp)
        {
        case OP_WS:
            //checkeof(_chLookahead, _lEOFError);
            if (! ISWHITESPACE(_chLookahead))
                return XML_E_MISSINGWHITESPACE;
            // fall through
        case OP_OWS:
            //checkeof(_chLookahead, _lEOFError);
            checkhr2(push(&XMLStream::skipWhiteSpace, (short)newState));
            checkhr2(skipWhiteSpace());
            //if (_fFoundPEREf) return XML_E_FOUNDPEREF;
            break;
        case OP_CHARWS:
            //if (_fFoundPEREf) return S_OK;
            mark();
            //checkeof(_chLookahead, _lEOFError);
            if (_chLookahead == pSE->_pch[0])
            {
                ADVANCE;
                newState = pSE->_sGoto;
                _nToken = pSE->_lDelta;
            }
            else if (! ISWHITESPACE(_chLookahead))
            {
                return XML_E_WHITESPACEORQUESTIONMARK;
            }
            else
                newState = pSE->_sArg1;
            break;
        case OP_CHAR:
            //if (_fFoundPEREf) return S_OK;
            mark();
        case OP_CHAR2:
            //if (_fFoundPEREf) return S_OK;
            //checkeof(_chLookahead, _lEOFError);
            if (_chLookahead == pSE->_pch[0])
            {
                ADVANCE;
                newState = pSE->_sGoto;
                _nToken = pSE->_lDelta;
                //if (_nToken == XML_GROUP)
                    //_nAttrType = XMLTYPE_NMTOKEN;
            }
            else
            {
                newState = pSE->_sArg1;
                if (newState >= XML_E_PARSEERRORBASE &&
                    ISWHITESPACE(_chLookahead))
                    return XML_E_UNEXPECTED_WHITESPACE;
            }
            break;
        case OP_PEEK:
            //if (_fFoundPEREf) return S_OK;
            //checkeof(_chLookahead, _lEOFError);
            if (_chLookahead == pSE->_pch[0])
            {
                newState = pSE->_sGoto;
            }
            else
                newState = pSE->_sArg1;
            break;

        case OP_NAME:
            //if (_fFoundPEREf) return S_OK;
            //checkeof(_chLookahead, _lEOFError);
            checkhr2(push(&XMLStream::parseName, (short)newState));
            checkhr2(parseName());
            break;
        case OP_TOKEN:
            _nToken = pSE->_sArg1;
            _lLengthDelta = pSE->_lDelta;  
            break;
        case OP_POP:
            _lLengthDelta = pSE->_lDelta;
            if (_lLengthDelta == 0) mark();
            // The _lDelta field contains a boolean flag to tell us whether this
            // pop needs to check for parameter entity boundary or not.
            checkhr2(pop(pSE->_lDelta == 0)); // we're done !
            _nToken = pSE->_sArg1;
            //_nAttrType = XMLTYPE_CDATA;
            return S_OK;
        case OP_STRCMP:
            {
                const WCHAR* t = NULL;
                long len = 0;
                getToken(&t,&len);
                long delta = (pSE->_lDelta < 0) ? pSE->_lDelta : 0;
                //if (StringEquals(pSE->_pch,t,len+delta,_fCaseInsensitive))
                if (::FusionpCompareStrings(pSE->_pch, len+delta, t, len+delta, _fCaseInsensitive)==0)
                {
                    if (pSE->_lDelta > 0) 
                    {
                        _nToken = pSE->_lDelta;
                        _lLengthDelta = 0;
                    }

					newState = pSE->_sGoto;
                }
                else
                    newState = pSE->_sArg1;
             }
             break;

        case OP_COMMENT:
            return push(&XMLStream::parseComment, (short)newState);
            break;

        case OP_CONDSECT:
            //if (_fFoundPEREf) return S_OK;
            // parse <![CDATA[...]]> or <![IGNORE[...]]>
            return push(&XMLStream::parseCondSect, (short)newState);

        case OP_SNCHAR:
            //checkeof(_chLookahead, _lEOFError);
            if (isStartNameChar(_chLookahead))
            {
                newState = pSE->_sGoto;
            }
            else
                newState = pSE->_sArg1;
            break;
        case OP_EQUALS:
            //if (_fFoundPEREf) return S_OK;
            //checkeof(_chLookahead, _lEOFError);
            checkhr2(push(&XMLStream::parseEquals, (short)newState));
            checkhr2(parseEquals());
            break;
        case OP_ENCODING:
            {
                const WCHAR* t = NULL; // prefix bug fix, xiaoyuw@08/29/00
                long len = 0; // prefix bug fix, xiaoyuw@08/29/00
                _pInput->getToken(&t,&len);
                hr =  _pInput->switchEncoding(t, len+pSE->_lDelta);
            }
            break;

        case OP_ATTRVAL:
            //if (_fFoundPEREf) return S_OK;
            if (_chLookahead != L'"' && _chLookahead != L'\'')
            {
                return XML_E_MISSINGQUOTE;
            }  
            _chTerminator = _chLookahead;
            ADVANCE; 
            mark();
            _fReturnAttributeValue = (pSE->_sArg1 == 1);
            //checkeof(_chLookahead, _lEOFError);
            return push(&XMLStream::parseAttrValue, (short)newState);
            break;

        } // end of switch
        if (_fnState != &XMLStream::parseTable)
            return S_OK;

        if (newState >= XML_E_PARSEERRORBASE)
            return (HRESULT)newState;
        else
            _sSubState = (short)newState;
    } // end of while

    if (_nToken == XMLStream::XML_ENDDECL)
    {
        return _pInput->UnFreeze();
    }
    return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT    
XMLStream::_PushChar(WCHAR ch) 
{
    // buffer needs to grow.
    long   newsize =  (_lBufSize+512)*2 ;
    WCHAR* newbuf = NEW ( WCHAR[newsize]);
    if (newbuf == NULL)
        return E_OUTOFMEMORY;

    if (_pchBuffer != NULL){
        ::memcpy(newbuf, _pchBuffer, sizeof(WCHAR)*_lBufLen);
        delete[] _pchBuffer;
    }

    _lBufSize = newsize;
    _pchBuffer = newbuf;   
    _pchBuffer[_lBufLen++] = ch;
    
	return S_OK;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::AdvanceTo(short substate)
{
    // This method combines and advance with a state switch in one
    // atomic operation that handles the E_PENDING case properly.

    _sSubState = substate;

    //HRESULT hr = (!_fDTD) ? _pInput->nextChar(&_chLookahead, &_fEOF) : DTDAdvance(); 
	HRESULT hr = _pInput->nextChar(&_chLookahead, &_fEOF) ; 
    if (hr != S_OK && (hr == E_PENDING || hr == E_DATA_AVAILABLE || hr == E_DATA_REALLOCATE || hr == XML_E_FOUNDPEREF))
    {
        // Then we must do an advance next time around before continuing
        // with previous state.  Push will save the _sSubState and return
        // to it.
        push(&XMLStream::firstAdvance,substate);
    }    
    return hr;
}
////////////////////////////////////////////////////////////////////////
bool
XMLStream::PreEntityText()
{
    // This is a helper function that calculates whether or not to
    // return some PCDATA or WHITEPACE before an entity reference.
    if (_fPCDataPending)
    {
        // return what we have so far.
        //if (_fWhitespace && ! _fIE4Quirks) // in IE4 mode we do not have WHITESPACE nodes
                                           // and entities are always resolved, so return
                                           // the leading whitespace as PCDATA.
		if (_fWhitespace )
            _nToken = XML_WHITESPACE;                                
        else                               
            _nToken = XML_PCDATA;

        long entityLen = _pInput->getTokenLength() - _lEntityPos;
        _lLengthDelta = -entityLen;
        _lMarkDelta = entityLen;
        _fPCDataPending = false;
        _fWhitespace = true;
        return true;
    }

    return false;
}
////////////////////////////////////////////////////////////////////////
HRESULT 
XMLStream::ErrorCallback(HRESULT hr)
{
    if (hr == E_DATA_AVAILABLE)
        hr = XML_DATAAVAILABLE;
    else if (hr == E_DATA_REALLOCATE)
        hr = XML_DATAREALLOCATE;
    return _pXMLParser->ErrorCallback(hr);
}