Logo Search packages:      
Sourcecode: helix-player version File versions

textprsr.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: textprsr.cpp,v 1.1.2.1 2004/07/09 01:50:20 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "hxtypes.h"
#include "hxassert.h"
#include <stdlib.h>
#include <string.h>

#include "rt_types.h" //for _CHAR, RED_GREEN_OR_BLUE, COLORTYPE

#include "hxslist.h" //for base class CHXSimpleList.
#include "hxstack.h" //for base class CHXStack.

#include "fontdefs.h"
#include "txtattrb.h" //for class TextAttributes
#include "txtcntnr.h" //for class TextContainer & class TextContainerList
#include "textline.h" //for class TextLine & TextLineList
#ifdef _WINDOWS
#ifdef _WIN16
#include <windows.h>
#endif /* _WIN16 */
#endif /* _WINDOWS */
#include "txtwindw.h" //for class TextWindow.
#include "parsing.h"  //for parsing helper functions.
#include "atocolor.h" //for string-to-COLORTYPE conversion functions.
#include "rt_string.h" //for stringCompare().
#include "atotime.h"
#include "fontinfo.h" //for GetCharacterWidth().
#include "hxstrutl.h" //for isspace()
#include "textprsr.h"

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE           
static char HX_THIS_FILE[] = __FILE__;
#endif


///////////////////////////////////////////////////////////////////////////// 
//  Returns 1 + (index of pData where the <WINDOW ..> tag's '>' char is).
//          returns dataLength if failure to find valid <WINDOW..> tag.
ULONG32 TextParser::ParseHeader(void* pData, ULONG32 dataLength,
      ULONG32 ulRTFileFormatMarkupParsingMajorVersion,
      ULONG32 ulRTFileFormatMarkupParsingMinorVersion)
{
    //Now parse pData:

#if !defined(_CHARsizeInBytesIs1)
#error this code needs to be updated...
#endif

    _CHAR* pData_CHAR = (_CHAR*)pData;

    if(!m_pTextWindow  ||  !m_pTextWindow->m_pTLList  ||
          !m_pTextWindow->m_pFontUndoTagList)
    {
      //can't do anything if a lack of memory meant that memory for
      // one or both of these objects  couldn't be allocated (which is
      // the only reason they should be NULL here):
      return dataLength;
    }
    
    //      Find the first '<' and then find the first '>' or end-of-data, and
    //  send the contents found to m_pTextWindow->parseHeaderTag():
    _CHAR* pHeaderTagBuf;
    LONG32 headerTagBufLen;

    LONG32 indexOfLeftBracket = -1;
    LONG32 indexOfRightBracket = -1;
    LONG32 indx;
    LONG32 len = LONG32(dataLength);
    for(indx=0; indx<len; indx++)
    {
/*XXXEH- for now, we have to assume that the first text encountered is not
  DBCS text; it and all text inside tags must be us-ascii charset:
      //added the following to handle DBCS chars:
      if((UCHAR)pData_CHAR[indx] >= DBCS_MIN_LEAD_BYTE_VAL)
      {
          indx++; //skip this and the following trail byte.
          continue;
      }
*/    
      if(pData_CHAR[indx] == '<')
      {
          indexOfLeftBracket = indx;
          break;
      }
    }
    if(indexOfLeftBracket != -1)
    {
      for(indx++; indx<len; indx++)
      {
/*XXXEH- for now, we have to assume that the first text encountered is not
  DBCS text; it and all text inside tags must be us-ascii charset:
          //added the following to handle DBCS chars:
          if((UCHAR)pData_CHAR[indx] >= DBCS_MIN_LEAD_BYTE_VAL)
          {
            indx++; //skip this and the following trail byte.
            continue;
          }
*/
          if(pData_CHAR[indx] == '>')
          {
            indexOfRightBracket = indx;
            break;
          } 
      }
    }
    if(-1 == indexOfLeftBracket  ||  -1 == indexOfRightBracket  ||
          ((indexOfRightBracket-indexOfLeftBracket)-1) <
          LONG32(int(strlen("WINDOW"))) )
    {
      //Added this to allow <HTML> to be the first tag:
      if( ((indexOfRightBracket-indexOfLeftBracket)-1) >=
            LONG32(int(strlen("HTML"))) )
      {
          if(('H' == pData_CHAR[indexOfLeftBracket]  ||
                'h' == pData_CHAR[indexOfLeftBracket])  &&
                ('T' == pData_CHAR[indexOfLeftBracket+1]  ||
                't' == pData_CHAR[indexOfLeftBracket+1])  &&
                ('M' == pData_CHAR[indexOfLeftBracket+2]  ||
                'm' == pData_CHAR[indexOfLeftBracket+2])  &&
                ('L' == pData_CHAR[indexOfLeftBracket+3]  ||
                'l' == pData_CHAR[indexOfLeftBracket+3])    )
          { //XXXEH- need to handle type=html in parseHeaderTag():
            m_pTextWindow->parseHeaderTag("WINDOW type=HTML", 16,
                  ulRTFileFormatMarkupParsingMajorVersion,
                  ulRTFileFormatMarkupParsingMinorVersion);
            if(-1 == indexOfRightBracket)
            {   //XXXEH- should dataLength be returned here?!:
                return 0L; //signals that no header tag was found (and
                        //that the text starts at byte zero of file).
            }
            else
            {
                return (indexOfRightBracket+1);
            }
          }
      }
      //Added this to allow files with no header tag:
      // No '<' was found (or no valid header tag was found),
      //Need to set default vals to type
      // generic's default vals here:
      //XXXEH- need to handle type=plaintext in parseHeaderTag():
        char szTmpBuff[255] = {"WINDOW type=plaintext"}; /* Flawfinder: ignore */
      m_pTextWindow->parseHeaderTag(szTmpBuff, 21,
            ulRTFileFormatMarkupParsingMajorVersion,
            ulRTFileFormatMarkupParsingMinorVersion);
      if(-1 == indexOfRightBracket)
      {     //XXXEH- should dataLength be returned here?!:
          return 0L; //this signals that no header tag was found (and
                  //that the text starts at byte zero of the file).
      }
      else
      {
          return (indexOfRightBracket+1);
      }
    }

    //      Next, parse the header's tag after copying it into pHeaderTagBuf:
    headerTagBufLen = indexOfRightBracket-indexOfLeftBracket-1;
    pHeaderTagBuf = new _CHAR[headerTagBufLen+1];//Add 1 for terminating '\0'
    HX_ASSERT_VALID_PTR(pHeaderTagBuf);
    if(NULL == pHeaderTagBuf)
    {
      return dataLength;  //return end-of-pData index to signal error.        
    }

    for(indx=0; indx<headerTagBufLen; indx++)
    {
      pHeaderTagBuf[indx] = pData_CHAR[indx+indexOfLeftBracket+1];
    }
    pHeaderTagBuf[headerTagBufLen] = '\0';

    //  Now parse the header to get the WINDOW tag, and, if it is
    //  found, get the "NAME=value" pairs and assign the TextWindow's
    //  appropriate objects' data to these requested values:
    if(!m_pTextWindow->parseHeaderTag(pHeaderTagBuf, headerTagBufLen,
          ulRTFileFormatMarkupParsingMajorVersion,
          ulRTFileFormatMarkupParsingMinorVersion))
    { //  Returned FALSE because of invalid header tag:
      delete [] pHeaderTagBuf;
      pHeaderTagBuf = NULL;
      return dataLength; //return end-of-pData index to signal error.                                       
    }

    delete [] pHeaderTagBuf;
    pHeaderTagBuf = NULL;

    //This kills a bug in a tickertape where
    // the packet starts with <TL> but the <POS .. Y0= >
    // before it causes the renderer to use the Y0=0 value
    // that the ff or encoder incorrectly calculated for TL
    // text because it thought the "visible" window height
    // was 0:
    m_pTextWindow->setVisibleWindowWidth(m_pTextWindow->getWidth());
    m_pTextWindow->setVisibleWindowHeight(m_pTextWindow->getHeight());

    return (indexOfRightBracket+1);
}



/////////////////////////////////////////////////////////////////////////////
// Method:
//  ULONG32 TextParser::ParseText(...)
// Purpose:
//  This function receives the latest raw data (in pData) and
//  inserts it into the m_pTextWindow::TextContainerList with the latest
//  render attribute in m_pTextWindow::TextAttributeStacks.
//
// bDataHasREQUIREDContents gets set by this function to TRUE if any of
//  the TextContainers created from pData have the REQUIRED attribute.
//
// ulEarliestTimeOfNewData gets set with the time which is the earliest
// time of the TextLines into which this data is parsed.
//
// Return value is HXR_OK if in-bound data was valid and no error occurred,
// otherwise it's HXR_NO_DATA if pData is NULL or empty,
// HXR_ELEMENT_NOT_FOUND if all that is in pData is spaces, tabs, and/or
// newline characters, and HXR_NOT_INITIALIZED if ulEarliestTimeOfNewData
// was not set.
//
HX_RESULT TextParser::ParseText(void* pData, ULONG32 dataLength,
      LONG32 lTimeOffset,
      ULONG32& ulEarliestTimeOfNewData,
      ULONG32& ulEndTimeOfPacket,
      BOOL& bRef_DataHasREQUIREDContents,
      BOOL bFileFormatIsCallingThis,
      ULONG32 ulByteOffsetIntoFile,
      TextLine** ppFirstTextLineInPkt
      )
{
    *ppFirstTextLineInPkt = NULL;
    ULONG32 ulStartByteOfFirstTL = 0L;
    BOOL bFirstTLwasFound = FALSE;

    //Look through the data for the first valid markup tag.  Any text found
    //      before that gets put in a new TextContainer object and is inserted
    //      into the TextContainerList part of the TextWindow object.  If that
    //      list is empty, a new TextContainer is added to it with the default
    //      characteristics for the text.  If a valid markup tag is found before
    //      the end of the pData is reached, the text that follows it, up to the
    //      next tag, goes into a new TextContainer object that is added to the
    //      list and has the text-rendering characteristic specified in that tag:
      
#if !defined(_CHARsizeInBytesIs1)
#error this code needs to be updated...
#endif
    _CHAR* pData_CHAR = (_CHAR*)pData;

    //Added this for when this is called by the file format
    ulEarliestTimeOfNewData = TIME_INVALID;
    BOOL bEarliestTimeOfNewDataIsValid = FALSE;

    //Added this for when this is called by the file format
    ulEndTimeOfPacket = TIME_INVALID;

    bRef_DataHasREQUIREDContents = FALSE;


    if(!pData_CHAR  ||  dataLength<1)
    {
      return HXR_NO_DATA; //there's nothing to do.
    }

    ULONG32 ulOriginalDataLength = dataLength;
    if('\0' == pData_CHAR[dataLength-1])
    {
      dataLength -= 1;
    }

    BOOL bIsLiveSource = m_pTextWindow->isLiveSource();

    TextContainer* pTC = NULL;

    //Added this for when this is called by the file format
    TextLine* pTL = NULL;

    //Find the first '<' or end-of-data, whichever comes first, and put
    //      any raw text found before it into the TextContainer list:

    LONG32 startIndex=0L;

    //Added the following which keep track of where
    // each TextLine starts/ends in the file (this is ignored if
    // bFileFormatIsCallingThis is FALSE):
    ULONG32 ulCurLineStartByteNumOfFile = ulByteOffsetIntoFile;
    ULONG32 ulCurLineEndByteNumOfFile = ulByteOffsetIntoFile;

    //Changed this to skip newlines only:
    //First, skip all newline characters at start of this string only
    // if this is the very first packet:
    IncrementCurrentPacketNum();
    if(GetCurrentPacketNum() <= 1L)
    {
      for(startIndex=0L; startIndex<(LONG32)dataLength; startIndex++)
      {
          if(pData_CHAR[startIndex] != '\n'  &&
                pData_CHAR[startIndex] != '\r')
          {
              break;
          }
      }
    }

    if((LONG32)dataLength == startIndex)
    { //All that were found were newline chars, so quit:
      return HXR_ELEMENT_NOT_FOUND;
    }

    //Reset the ptr and dataLength to where the first
    // non-newline is:
    dataLength = dataLength-startIndex;
    pData_CHAR = &(pData_CHAR[startIndex]);
    startIndex = 0L;

    LONG32 len = LONG32(dataLength);
    //Got rid of this and replaced with 
    // m_pTextWindow's functions to keep track of this because there
    // was a bug if a <BR> was the last thing in a packet, using just
    // the following local variable meant that this info got lost
    // when this function was done, so the next packet's data would
    // not end up with the proper number of line breaks before it:
    ///LONG32 numBreakTagsEncountered = 0L;
    
    BOOL bSomeCharsFoundSinceLastBreakTag = FALSE;

    //For bug #6906:
    BOOL bSomeCharsFoundSinceLastPosTag = FALSE;
    BOOL bUserPosTagFoundSinceLastTextContainer = FALSE;

    ULONG32 ulCurCharset;

    ULONG32 ulNumPREtagNewlineCharsFound = 0L;

    do //Now find the next '<', starting at pData_CHAR[startIndex]:
    {
      ulCurCharset = m_pTextWindow->peekAtCharsetStack();
      LONG32 indexOfLeftBracket = -1;
      LONG32 indexOfRightBracket = -1;
      BOOL bSlashFoundAtEndOfTag = FALSE;
      BOOL bIgnoringNewlineChars = FALSE;
      BOOL bDealingWithTabCharWithPre = FALSE;
      LONG32 indx;
      for(indx=startIndex; indx<len; indx++,
            bSomeCharsFoundSinceLastPosTag=TRUE,
            bSomeCharsFoundSinceLastBreakTag=TRUE)
      {
          _CHAR ch = pData_CHAR[indx];

          //added the following to handle DBCS chars:
          if((ulCurCharset & HX_DBCS_CHARSET)  &&
                (UCHAR)ch >= DBCS_MIN_LEAD_BYTE_VAL)
          {
            indx++; //skip this and the following trail byte.
            continue;
          }

          if('<' == ch)
          {
            indexOfLeftBracket = indx;
            bSomeCharsFoundSinceLastBreakTag=FALSE; //Fixes bug #6903.
            bSomeCharsFoundSinceLastPosTag=FALSE; //Helps fix bug #6906.
            break;
          }
          //Convert any tab chars outside a tag to spaces if we're not
          // currently between a <PRE> and a </PRE>, else leave '\t' alone
          // and let TextWindow::insertAtEndOfList() calculate where the
          // next tab stop is:
          BOOL bTabCharHandled = FALSE;
          if('\t' == ch  ||  '\v' == ch
                ||  '\0' == ch) //<--added this check for safety.
          {
            pData_CHAR[indx] = ' ';
            //treat tab char as a tab, not a space, inside PRE text:
            if(('\t' == ch)  &&  (m_pTextWindow->peekAtIsPreStack()) )
            {
                // pretend we've found the start and end of a tag so a
                // new TC will be created with this char and the
                // next will start just after this char.
                {
                  bTabCharHandled = TRUE;
                  indexOfLeftBracket = indx;
                  indexOfRightBracket = indexOfLeftBracket;
                  bDealingWithTabCharWithPre = TRUE;
                  bSomeCharsFoundSinceLastBreakTag = TRUE;
                  bSomeCharsFoundSinceLastPosTag = TRUE;
                  break; //indexOf[Left&Right]Bracket vars are set
                        // to act as a fake tag just after this '\t'.
                }
            }
          }
          //Reduce any string of newlines into either one or zero spaces,
          // one space if !bSomeCharsFoundSinceLastBreakTag, 0 otherwise:
          // UNLESS we're currently between a <PRE> and a </PRE>. in which
          // case leave them alone.
          // If we are ignoring extra spaces, then do this for spaces and
          // tab chars, too:
          else if(('\n' == ch  ||  '\r' == ch)  ||
                (m_pTextWindow->IgnoreExtraSpaces()  &&  
                  ((!bTabCharHandled && ('\t' == ch  ||  '\v' == ch))  ||
                  ' ' == ch
                  )
                )
               )
          {
            LONG32 firstNewlineIndex = indx;
            pData_CHAR[firstNewlineIndex] = ' ';
            indexOfLeftBracket = indx;
            if(indexOfLeftBracket+1==len)
            {
                //If we're at the end of the packet and it ends with a
                // space or tab char and we're ignoring extra spaces,
                // then we want to make sure NOT to ignore this last
                // space if it's solo:
                if('\n' != ch  &&  '\r' != ch  &&
                      m_pTextWindow->IgnoreExtraSpaces())
                {
                  indexOfLeftBracket++;
                }
            }
            LONG32 newLineCharCount=1L;
//XXXXXEH-19980918:
            BOOL bNonSpaceTabNewlineCharWasLastFound = FALSE;
            for(indx++; indx<len; indx++, newLineCharCount++)
            {
                _CHAR ch2 = pData_CHAR[indx];
                if('\n' == ch2  ||  '\r'== ch2)
                {
                  pData_CHAR[indx] = ' ';
                  if(m_pTextWindow->peekAtIsPreStack())
                  // pretend we've found the start and end of a tag so
                  // a new TC will be created with this char and the
                  // next will start just after this char:
                  {
                      //See if this is a PC "\r\n" newline:
                      if('\r' == pData_CHAR[indx-1]  &&  '\n' == ch2)
                      {
                        indx++;
                      }
                      ulNumPREtagNewlineCharsFound++;
                  }
                }
                else if(m_pTextWindow->IgnoreExtraSpaces()  &&
                      !m_pTextWindow->peekAtIsPreStack()  &&
                      (!bTabCharHandled && ('\t' == ch2  ||
                            '\v' == ch2)) )
                {
                  ;
                }
                else if(m_pTextWindow->IgnoreExtraSpaces()  &&
                      !m_pTextWindow->peekAtIsPreStack()  &&
                      ' ' == ch2)
                {
                  ;
                }
                else
                {
//XXXXXEH-19980918>>
                  //C_RTRNDR_DIFF>>
                  if(IsBeta1Player())
                  {
                      break;
                  }
                  //END C_RTRNDR_DIFF.
                  if('<'!=ch2)
                  {
                      bNonSpaceTabNewlineCharWasLastFound = TRUE;
                  }
//<<XXXXXEH-19980918.
                  break;
                }
            }
            indx--;      //back up one for outer for loop.

            if(bSomeCharsFoundSinceLastBreakTag)
            {
//XXXXXEH-is fix for bug 4881 here?!?  If UNIX uses '\n' instead of "\r\n",
// and we don't handle that count==1 here, what in the Wide Wide World Of
// Sports happens??  (Needs checking in same code in rtrender/c_rtrndr.cpp)
                //Doesn't follow a new line, so just reduce to 1 space:
                if(newLineCharCount >= 2L)
                {
                  indexOfRightBracket =
                        firstNewlineIndex + newLineCharCount - 1L;
                  indexOfLeftBracket = firstNewlineIndex + 1L;
                  bIgnoringNewlineChars = TRUE;
                  bSomeCharsFoundSinceLastBreakTag = TRUE;
                  break; //indexOf[Left&Right]Bracket vars are set
                        // to act as a fake tag after the first one.
                }
            }
            else 
            //we want to ignore all newline characters found
            // because they were preceded by a line break tag, so
            // pretend we've found the start and end of a tag so a new
            // TC will be created ending just before this char and the
            // next will start just after this char.
            {
                indexOfLeftBracket = firstNewlineIndex;
                indexOfRightBracket =
                      firstNewlineIndex + newLineCharCount - 1L;
                bIgnoringNewlineChars = TRUE;
//XXXXXEH-19980918>>
                //C_RTRNDR_DIFF>>
                if(IsBeta1Player())
                {
                  bSomeCharsFoundSinceLastPosTag = TRUE;
                  bSomeCharsFoundSinceLastBreakTag = TRUE;
                }
                else
                //<<END C_RTRNDR_DIFF.
                {
                  bSomeCharsFoundSinceLastBreakTag =
                        bSomeCharsFoundSinceLastPosTag = 
                        bNonSpaceTabNewlineCharWasLastFound;
                }
//<<XXXXXEH-19980918.
                break; //indexOf[Left&Right]Bracket vars are set.
                      // to act as a fake tag where newlines are..
            }
          }
      }

      if(-1L != indexOfLeftBracket  &&  -1L == indexOfRightBracket)
      {
          //Check if we're inside an HTML-style ("<!-- ... -->") comment,
          // and then ignore all '>'s until we see one preceeded by "--",
          // i.e., only "-->" ends a comment:
          if(len-indexOfLeftBracket >= 4)
          {
            if(!stringCompare(&pData_CHAR[indexOfLeftBracket], 4,
                  "<!--", 4))
            {
                m_pTextWindow->incrementCommentTagNestCount();
            }
          }

           //find the closing '>':
          for(indx++; indx<len; indx++)
          {
            _CHAR ch = pData_CHAR[indx];

/*XXXEH- for now, we have to assume that the text encountered is not
  DBCS text; all text inside tags must be us-ascii charset:
            //added the following to handle DBCS chars:
            if((UCHAR)ch >= DBCS_MIN_LEAD_BYTE_VAL)
            {
                indx++; //skip this and the following trail byte.
                continue;
            }
*/
            if('>' == ch)
            {
                //Check if we're inside an HTML-style ("<!-- ... -->")
                // comment, which could contain a '>' (which should be
                // ignored) before the closing "-->":
                if(m_pTextWindow->getCommentTagNestCount())
                {
                  if(indx-startIndex >= 2)
                  {
                      if(!stringCompare(&pData_CHAR[indx-2], 3,
                            "-->", 3))
                      {
                        if(m_pTextWindow->
                              decrementCommentTagNestCount() > 0L)
                        {
                            continue; //we're still inside a nested
                                    // comment.
                        }
                      }
                      else
                      {
                        continue;
                      }
                  }
                }

                indexOfRightBracket = indx;
                //Added this to make this XML-compatible:
                if(indexOfRightBracket>0)
                {
                  if(pData_CHAR[indexOfRightBracket-1] == '/')
                  {
                      bSlashFoundAtEndOfTag = TRUE;
                      pData_CHAR[indexOfRightBracket-1] = ' ';
                  }
                }
                break;
            }     
            else if('<' == ch  &&
                  m_pTextWindow->getCommentTagNestCount())
            {
                //Check if we're a comment nested inside another
                // ("<!-- ... -->") comment:
                if(len-indx >= 4)
                {
                  if(!stringCompare(&pData_CHAR[indx], 4,
                        "<!--", 4))
                  {
                      m_pTextWindow->incrementCommentTagNestCount();
                  }
                }
            }

            //Convert any newline or tab chars to spaces:
            if('\n' == ch  ||  '\r' == ch  ||
                        '\t' == ch  ||  '\v' == ch
                        ||  '\0' == ch)
            {
                pData_CHAR[indx] = ' ';    
                //Note: don't need to track #of conversions inside tag
            }
          }
          if(-1 == indexOfRightBracket)
          { //No valid end-of-tag found, so ignore all text from
            //  indexOfLeftBracket on; this is done by putting a '\0'
            //  at pData_CHAR[indexOfLeftBracket]:
            pData_CHAR[indexOfLeftBracket] = '\0';
            len = indexOfLeftBracket - startIndex;
          }
      }
      
      LONG32 tempLen;
      BOOL bPreTabOrNewlineCharOnly = FALSE;
      if(indexOfLeftBracket != -1)
      {
          tempLen = indexOfLeftBracket - startIndex;
          pData_CHAR[indexOfLeftBracket] = '\0';
          if(!tempLen)
          {
            //Special case where a tab char was the only text found
            // between tags, and, since we're faking like a PRE tab
            // is a tag, tempLen ended up 0 and the while loop, below,
            // was not getting entered:
            if(bDealingWithTabCharWithPre)
            {
                bPreTabOrNewlineCharOnly = TRUE;
            }
          }
      }
      else
      {
          tempLen = len - startIndex;
      }


      ulCurCharset = m_pTextWindow->peekAtCharsetStack();

      //Added the following "while" to allow for
      // word wrap; break the text up wherever there is a
      // space char.  (Also, Changed "if(tempLen.." to
      // "while(tempLen.."
      ULONG32 tmpStartIndex = startIndex;
      while(tempLen > 0  ||
            bPreTabOrNewlineCharOnly)
      {
          ULONG32 theFollowingSpaceCharIndex = tempLen;
          char savedChar = '\0';
          _CHAR* pCurText = &pData_CHAR[tmpStartIndex];

          //C_RTRNDRDIFF >>:
          //this needs to be reset prior to the creation of each T.C.:
          BOOL bCurLineHasREQUIREDContents = FALSE;
          //<< END C_RTRNDRDIFF.

          if(m_pTextWindow->usingWordwrap()  &&
                !m_pTextWindow->peekAtIsPreStack())
          {
            //Allow wordwrap to happen in DBCS/UNICODE between chars, not
            // just where spaces are, because each character represents
            // a "word" and they are rarely separated by spaces:
            //XXXEH- NOTE: I assume that UNICODE characters that have a
            // zero-valued first byte are really SBCS characters and
            // should not get wordwrapped (because they may be in the
            // middle of a SB word):
            if(ulCurCharset & HX_UNICODE_CHARSET  ||
                  ulCurCharset & HX_DBCS_CHARSET)
            {
                UINT16 sCharWidthInPixels = 0;
                UINT16 sChar = '\0';
                LONG32 lNumBytesOfChar = 1L;
                if(ulCurCharset & HX_UNICODE_CHARSET  ||
                      (ulCurCharset & HX_DBCS_CHARSET  &&
                      (UCHAR)(*pCurText)>= DBCS_MIN_LEAD_BYTE_VAL) )
                {
                  //Is a 2-byte character, so deal with it,
                  // making sure there's a trail byte
                  lNumBytesOfChar++;
                  HX_ASSERT(tempLen>=lNumBytesOfChar);
                  UCHAR tmp = *pCurText;
                  sChar = (((UINT16)tmp)<<8 | (UCHAR)pCurText[1]);
                }
                else
                {
                  sChar = (INT16)((UCHAR)(*pCurText));
                }

/*  XXXEH-need while loop on each char until we find which character
    exceeds the window's right edge and only then end the text blob...:
                sCharWidthInPixels = GetCharacterWidth(
                      sChar,
                      m_pTextWindow->peekAtFontFaceStack(),
                      m_pTextWindow->peekAtPointSizeStack(),
                      //XXXEH- isBold and isItalicized need peek..()
                      // functions written for them; assuming they are
                      // TRUE only means wordwrap will happen a few
                      // pixels early, if that:
                      TRUE, TRUE,
                      ulCurCharset);

                BOOL windowWidthExceeded = 
                      m_pTextWindow->getCurrentTextLineEndX() +
                      sCharWidthInPixels >
                      m_pTextWindow->getWidth();

    XXXEH- ...but for now, just make each (2-byte)DBCS/UNICODE character be in its
    own TextContainer, although this can be less efficient:
*/
                //If we are going from DB char to DB char or from DB char
                // to SB char, or from SB char to DB char, or SB char is
                // a space, newline, or tab, or is a UNICODE character
                // with a non-zero first byte, or is a UNICODE space, tab,
                // or newline, then we can do a wordwrap
                // after this char, otherwise we should not:
                BOOL bNextCharExists = tempLen>lNumBytesOfChar;
                //Initialize to opposite of what cur character is:
                BOOL bNextCharIsTwoByte = (lNumBytesOfChar==1);
                if(bNextCharExists)
                {
                  bNextCharIsTwoByte =
                        (ulCurCharset & HX_UNICODE_CHARSET  &&
                        ((UCHAR)(pCurText[lNumBytesOfChar])!=0))  ||
                      (ulCurCharset & HX_DBCS_CHARSET  &&
                      (UCHAR)(pCurText[lNumBytesOfChar])>=
                      DBCS_MIN_LEAD_BYTE_VAL);
                }
                BOOL bIsUNICODEcharThatCanBeWordwrapped = FALSE;
                if(ulCurCharset & HX_UNICODE_CHARSET)
                {
                  if(*pCurText!=0)
                  {
                      bIsUNICODEcharThatCanBeWordwrapped = TRUE;
                  }
                  else
                  {
                      UCHAR ch = pCurText[1]; 
                      if(' '==ch  ||  '\n'==ch  ||
                            '\r'==ch  ||  '\t'==ch)
                      {
                        bIsUNICODEcharThatCanBeWordwrapped = TRUE;
                      }
                  }
                }

                if((!(1==lNumBytesOfChar)  ||  bNextCharIsTwoByte)  ||
                      (1==lNumBytesOfChar  &&  (' '==*pCurText  ||
                      '\n'==*pCurText  ||  '\r'==*pCurText  ||
                      '\t'==*pCurText))  ||
                      bIsUNICODEcharThatCanBeWordwrapped )
                {
                  //End the text blob here so that wordwrap can occur
                  // if this character extends off the right edge
                  // of the window:
                  theFollowingSpaceCharIndex = lNumBytesOfChar-1;
                  savedChar = pCurText[theFollowingSpaceCharIndex+1];
                  pCurText[theFollowingSpaceCharIndex+1] = '\0';
                }
                //If we're in a bunch of single-byte DBCS chars, then we
                // need to find the end of them (or the first space, tab,
                // newline therein), and allow for wordwrap there:
                else if(1==lNumBytesOfChar  &&  tempLen)
                {
                  _CHAR* pTmpText = pCurText;
                  LONG32 lTmpTextLen = tempLen;
                  BOOL bSpaceTabOrNewlineFound=FALSE;
                  do
                  {
                      lNumBytesOfChar = (UCHAR)(*pTmpText)>=
                            DBCS_MIN_LEAD_BYTE_VAL? 2:1;
                      if(1==lNumBytesOfChar)
                      {
                        if(' '==*pTmpText  ||  '\n'==*pTmpText  ||
                              '\r'==*pTmpText  ||  '\t'==*pTmpText)
                        {
                            bSpaceTabOrNewlineFound = TRUE;
                            break;
                        }
                      }
                      else
                      {
                        lTmpTextLen++;
                        pTmpText--;
                        break;
                      }
                      pTmpText++;
                      lTmpTextLen--;
                  }while(lTmpTextLen);
                  if(lTmpTextLen)
                  {
                      //then we encountered a double-byte char or a
                      // space, tab, or newline char, so ok to wordwrap
                      // here:
                      theFollowingSpaceCharIndex = tempLen-lTmpTextLen;
                      savedChar=pCurText[theFollowingSpaceCharIndex+1];
                      pCurText[theFollowingSpaceCharIndex+1] = '\0';
                  }
                }
            }
            else //This is SBCS:
            {
                ULONG32 firstNonSpaceCharIndex =
                      skipSpacesTabsAndNewlineChars(
                      pCurText, tempLen, 0);
                ULONG32 dummyVar;
                if(firstNonSpaceCharIndex < (ULONG32)tempLen)
                {
                  theFollowingSpaceCharIndex =
                        findNextSpaceTabOrNewLineChar(
                        pCurText, tempLen,
                        firstNonSpaceCharIndex, dummyVar, ulCurCharset);
                  if(theFollowingSpaceCharIndex+1 < (ULONG32)tempLen)
                  {
                      savedChar = pCurText[theFollowingSpaceCharIndex+1];
                      pCurText[theFollowingSpaceCharIndex+1] = '\0';
                  }
                }
            }
          }


          //C_RTRNDRDIFF >>:
          //Added the following to keep track of where
          // in the buffer the TextContainer's data starts:
          ULONG32 ulTextContainerBufStartIndex = tmpStartIndex;
          //<< END C_RTRNDRDIFF.

          if(!bPreTabOrNewlineCharOnly)
          {
            //Now, look for "&lt;" or "&gt;" and, if found, end the
            // TextContainer at the end of the "&lt;" or "&gt;" & replace
            // it with '<' or '>'; also, look for "&#n;"
            // (where n>8 && n<=255) and translate into the ASCII char
            // with that value, and look for "&nbsp;" for ' ' and "&amp;"
            // for '&':
            ULONG32 ulIndexOfAmpersand = findNextChar('&',
                  pCurText,
                  theFollowingSpaceCharIndex,
                  0L,
                  ulCurCharset);
            ULONG32 ulIndexOfLastCharInTCsBuf=theFollowingSpaceCharIndex;
            ULONG32 theOriginalFollowingSpaceCharIndex =
                  theFollowingSpaceCharIndex;
            if(theFollowingSpaceCharIndex > ulIndexOfAmpersand  &&
                  theFollowingSpaceCharIndex - ulIndexOfAmpersand >= 4)
            {
                FindEscapeSequenceChar(pCurText,
                      ulIndexOfLastCharInTCsBuf,
                      theFollowingSpaceCharIndex, ulIndexOfAmpersand,
                      ulCurCharset);
            }

            //Create a new one and add it to the list:
            pTC = new TextContainer(pCurText,
                  ulIndexOfLastCharInTCsBuf+1>(ULONG32)tempLen?
                  (ULONG32)tempLen:ulIndexOfLastCharInTCsBuf+1);
            //First, restore pData_CHAR:
            if(theOriginalFollowingSpaceCharIndex+1 < (ULONG32)tempLen)
            {
                pCurText[theOriginalFollowingSpaceCharIndex+1] =
                      savedChar;
            }
            //then, reset tempLen and tmpStartIndex:
            {
                tempLen -= theFollowingSpaceCharIndex+1;
                tmpStartIndex += theFollowingSpaceCharIndex+1;
            }
          }
          else //is a tab char inside PRE so send a space char:
          {
            //Create a new one and add it to the list:
            pTC = new TextContainer(" ", 1);
            bPreTabOrNewlineCharOnly = FALSE; //so while loop will quit.
          }

          HX_ASSERT(pTC);
          if(!pTC)
          { //C_RTRNDRDIFF:  (different due to return type)
            return HXR_OUTOFMEMORY;//mem alloc error, so quit
          }
          pTC->setNumNewlinesAtStart(
                m_pTextWindow->getNumBreakTagsEncountered());
          m_pTextWindow->clearNumBreakTagsEncountered();

          //This has to be kept track of because insertAtEndOfList(),
          // below, resets m_bClearWasJustSent to FALSE:
          BOOL bClearWasJustSent = m_pTextWindow->m_bClearWasJustSent;

          BOOL bStopRenderingTimeIsMoreRecent =
                IsTimeAMoreRecentThanTimeB(
                m_pTextWindow->GetLatestSentTimeToStopRendering(),
                m_pTextWindow->GetLatestSentTimeToRender(),
                bIsLiveSource);

          //Reset the current endtime so all text
          // that follows a <CLEAR> has an endtime equal to that of
          // the end of the stream:
          if(bClearWasJustSent
                //This fixes a bug where the author wanted something
                // to end at a certain time after the <CLEAR> but
                // couldn't without a <time> tag after the <CLEAR>,
                // e.g., "<time start=10 end=20><CLEAR>foo" should
                // behave as follows: foo appears at 10 seconds and
                // goes away at 20; however:
                // "<time end=10>blah <time start=10><CLEAR>foo" should
                // have blah appear up to 10 seconds and foo appear from
                // 10 seconds until the end of the stream (or until the
                // next CLEAR tag's start time).
                &&  !bStopRenderingTimeIsMoreRecent)
          {
            //If liveSource, start time of stream may not be at time 0
            // and ULONG_MAX may be *earlier* than cur time (since time
            // val is ULONG32 and may wrap); we want to set this to
            // "infinity" (which is 0xfffffffe):
            m_pTextWindow->SetLatestSentTimeToStopRendering(
                  (ULONG32)ULONG_MAX);
            if(bIsLiveSource)
            {
                m_pTextWindow->SetLatestSentTimeToStopRendering(
                      TIME_INFINITY);
                if(TIME_INVALID == m_pTextWindow->
                      GetLatestSentTimeToStopRendering())
                {
                  m_pTextWindow->SetLatestSentTimeToStopRendering(1L);
                }
            }
          }

          //Set begin and end render times of this new TextContainer
          //  to the begin/end values of the most recent <TIME ..> tag:
          pTC->setBeginTime(
                m_pTextWindow->GetLatestSentTimeToRender()
                - lTimeOffset); //cz
          pTC->setEndTime(
                m_pTextWindow->GetLatestSentTimeToStopRendering()
                - lTimeOffset); //cz

          //C_RTRNDRDIFF >>
          //This is needed at the file format end because we need to keep
          // track of when the last <TIME ... end=t> was seen so we can
          // send it in the packet's opaque-data header:
          pTC->setMostRecentTimeTagEndTime(pTC->getEndTime());
          //<< END C_RTRNDRDIFF.

          if(m_pTextWindow->hasValidURL())
          {
            pTC->copyIntoHrefBuf(m_pTextWindow->getURL(),
                  m_pTextWindow->getLenURLbuf(),
                  m_pTextWindow->getTargetOfURL() );
            //C_RTRNDRDIFF >>
            ULONG32 ulNumOverrides = m_pTextWindow->
                  getNumberOfFontColorPushesInsideLinkText();
            if(ulNumOverrides > 0)
            {
                pTC->setNumLinkColorOverrides(ulNumOverrides);
            }
            //<< END C_RTRNDRDIFF.
          }

          m_pTextWindow->setTextAttributesToTopsOfStacksVals(*pTC);

          if(bDealingWithTabCharWithPre  &&
                !bSomeCharsFoundSinceLastBreakTag)
          {
            //If all we've got is a tab char in the TC, don't
            // paint any bg color:
            pTC->setTextBackgroundColor(DEFAULT_TEXT_BGCOLOR);
          }

          bUserPosTagFoundSinceLastTextContainer = FALSE;

          if(!m_pTextWindow->insertAtEndOfList(pTC,
                //C_RTRNDRDIFF:
                !bFileFormatIsCallingThis,
                bDealingWithTabCharWithPre))
          {
            delete pTC;
          }
          else
          {
            //C_RTRNDRDIFF >>
            if(pTC->isRequired())
            {
                bRef_DataHasREQUIREDContents =
                      bCurLineHasREQUIREDContents = TRUE;
            }
            //<< END C_RTRNDRDIFF.

            //Added this to adjust start & end times
            // based on visibility in window, e.g., the start time of
            // pTC might be 0 but it doesn't scroll into the window
            // until 4300msec, so this calculates and adjusts to that:
            BOOL bShouldNeverBeFalse =
                  pTC->adjustStartAndEndTimes(m_pTextWindow);
            HX_ASSERT(bShouldNeverBeFalse);

            if(m_pTextWindow->isLooping())
            {
                //We don't want to use the end time calculated in 
                // adjustStartAndEndTimes() above because looping means
                // the end time may be "infinite" since it could loop
                // "forever"; however, if there is an active <TIME end=t>
                // tag, use t instead of "infinity".
                // NOTE: as soon as another CLEAR tag is seen, this
                // T.C.'s endTime will be reset to time of the CLEAR:
                pTC->setEndTime(m_pTextWindow->
                      GetLatestSentTimeToStopRendering());
            }

            //C_RTRNDRDIFF >>
            if(TYPE_TELEPROMPTER == m_pTextWindow->getType())
            {
                //XXXEH-* need a better fix for this!:
                //We want to give each line a maximum lifetime of 90sec
                // so that, when a T.C. moves up and out of the window,
                // it doesn't persist as time-valid (and consequently
                // persist in the live packet-resend queue or in the
                // file format's list of what to send after a seek).
                // Setting its end time to the time this T.C. is "bumped"
                // out of the window is tricky and this 90second-duration
                // hack "solves" the problem for now but this needs to
                // be rivisited:
                if(pTC->getEndTime() - pTC->getStartTime() > 90000)
                {
                  pTC->setEndTime(pTC->getStartTime() + 90000);
                }
            }
            //<< END C_RTRNDRDIFF.

            if(bIsLiveSource  &&  TIME_INVALID == pTC->getEndTime())
            {
                //Make end time be "infinity":
                pTC->setEndTime(TIME_INFINITY);
            }

            //Moved this from below "CLEAR" parsing
            // code so that the adjustment would be made after the pTC's
            // official start time is known:
            if(bClearWasJustSent)
            {
                ULONG32 ulTmpStartTime = pTC->getStartTime();
                ULONG32 ulTmpEndTime = pTC->getEndTime();
                m_pTextWindow->SetLatestSentTimeToRender(ulTmpStartTime);

                //      is just after a <CLEAR> tag, so clear everything in
                //      TextContainerList whose m_endTime is greater
                //      than the latestSentTimeToRender:  
                m_pTextWindow->MarkAllForClear(  //(the T.C.List version)
                      bIsLiveSource);
                //Now, since pTC is already inserted in the T.C.List, its
                // endTime may have been adjusted in MarkAllForClear(),
                // so let's restore it:
                pTC->setStartTime(ulTmpStartTime);
                pTC->setEndTime(ulTmpEndTime);

                //C_RTRNDRDIFF >>:
                //Now call the T.L.List version of MarkAllForClear() and
                // make sure the TextLines all have the correct end times
                // otherwise a player Seek() may result in time-dead data
                // being sent over the wire and immediately discarded by
                // the renderer:
//#error:XXXXXEH- put bp here & see why not for renderer:
                m_pTextWindow->m_pTLList->MarkAllForClear(
                      m_pTextWindow->GetLatestSentTimeToRender(),
                      bIsLiveSource);
                //<< END C_RTRNDRDIFF.

                m_pTextWindow->setTimeOfLastClearTag();

                //follows a CLEAR tag but has no "newlines" before it,
                // so we can't set num newlines to non-zero, so this
                // tells us we've started a newline with no prior spacing
                pTC->isFakeNewLine(TRUE);
            }

            //C_RTRNDRDIFF >>:
            TextLine* pTL_prev = m_pTextWindow->m_pTLList->end();
            
            // Added the following code to create a new TextLine if pTC
            // is start of new line, or to update the latest TextLine in
            // the list if pTC is not the start of a new line:
            if(pTC->isStartOfNewLine()  ||
                  pTC->isFakeNewLine()  ||
                  //Added this because sometimes a TextLine gets split
                  // into two based on where the read() into the file
                  // ends and the next read() begins, so, if we haven't
                  // found a TL yet, make this the first one in the
                  // next packet (and don't append it to the existing
                  // pTL_prev even though it may be part of the same
                  // line):
                  !bFirstTLwasFound  ||
                  !pTL_prev)  //Bug #708 killer; the
                            // very first TextLine was not being
                            // created if it didn't start a newline.
            {
                ulCurLineStartByteNumOfFile = ulByteOffsetIntoFile +
                      ulTextContainerBufStartIndex;

                //if prev exsits, end it just before the new one starts:
                if(pTL_prev)
                {
                  pTL_prev->setEndByteInFile(
                        ulCurLineStartByteNumOfFile-1);
                }

                pTL = new TextLine((TextLine&)(*pTC));

                HX_ASSERT_VALID_PTR(pTL);
                if(NULL == pTL)
                {
                  break;  //Houston, We've had a problem.
                }
                
                //Do this so that the memcopied 
                // TextAttributes part of pTC did not copy the ptr to the
                // href buffer into pTL's TextAttributes part:
                pTL->clearWithoutDeletingHrefBuf();
                if(pTC->getHrefBuf()  &&  pTC->getHrefBufLen())
                {
                  pTL->copyIntoHrefBuf(pTC->getHrefBuf(),
                        pTC->getHrefBufLen(),
                        pTC->getTargetOfURL());
                }

                pTL->setLineNumOfFile(
                      m_pTextWindow->m_pTLList->nodeCount()+1);
                pTL->setStartByteInFile(ulCurLineStartByteNumOfFile);
                pTL->setEndByteInFile(0L);
                pTL->setTimeOfLastClear(
                      m_pTextWindow->getTimeOfLastClearTag());

                if(!m_pTextWindow->m_pTLList->insertAtEndOfList(pTL))
                {
                  delete pTL; //insert failed so kill it.
                }
                else //posible core dump without this else!!!
                if(pTL->getStartByteInFile() < ulStartByteOfFirstTL  ||
                      !bFirstTLwasFound)
                {
                  *ppFirstTextLineInPkt = pTL;
                  ulStartByteOfFirstTL = pTL->getStartByteInFile();
                  bFirstTLwasFound = TRUE;
                }
                //Make sure the current TextLine is considered
                // <REQUIRED> to be sent if any of it's text is
                // set as <REQUIRED>:
                if(bCurLineHasREQUIREDContents)
                {
                    pTL->isRequired(TRUE);
                }
            }
            else
            {
                //update the (current) TextLine's times because this
                // new pTC is part of the current TextLine (pTL_prev):
                if(pTL_prev)
                {
                  pTL_prev->updateStartAndEndTimes(pTC, bIsLiveSource);
                  //Make sure the current TextLine is considered
                  // <REQUIRED> to be sent if any of it's text is
                  // set as <REQUIRED>:
                  if(bCurLineHasREQUIREDContents)
                  {
                      pTL_prev->isRequired(TRUE);
                  }
                }
            }
            BOOL bEarliestTimeOfNewDataIsMoreRecent =
                  IsTimeAMoreRecentThanTimeB(
                  ulEarliestTimeOfNewData,
                  pTC->getStartTime(),
                  bIsLiveSource);
            //So ff can know next packet's time:
            if(bEarliestTimeOfNewDataIsMoreRecent  ||
                  !bEarliestTimeOfNewDataIsValid)
            {
                ulEarliestTimeOfNewData = pTC->getStartTime();
                bEarliestTimeOfNewDataIsValid = TRUE;
            }

            BOOL bGetEndTimeIsMoreRecent =
                  IsTimeAMoreRecentThanTimeB(
                  pTC->getEndTime(),
                  ulEndTimeOfPacket,
                  bIsLiveSource);
            if(TIME_INVALID == ulEndTimeOfPacket)
            {
                //(in)sanity check: Is the first time it's been used:
                HX_ASSERT(!bGetEndTimeIsMoreRecent);
            }

            //So ff can know next packet's end time
            // so it can decide whether it's too late to send the packet:
            if(bGetEndTimeIsMoreRecent
                  ||  (ULONG32)TIME_INVALID==ulEndTimeOfPacket)
            {
                ulEndTimeOfPacket = pTC->getEndTime();
            }
          }
          //<< END C_RTRNDRDIFF.

      } //end "while(tempLen > 0)".

      //Now, for PRE tag newlines found after pTC's text, increment
      // the num newlines to perform on the next TC:
      if(ulNumPREtagNewlineCharsFound)
      {
          for(ULONG32 ix=0L; ix<ulNumPREtagNewlineCharsFound; ix++)
          {
            m_pTextWindow->incrementNumBreakTagsEncountered();
          }
          ulNumPREtagNewlineCharsFound = 0L;
      }

      if(-1 == indexOfLeftBracket  ||  -1 == indexOfRightBracket)
      {
          break; //We're done with pData.
      }

      if(bIgnoringNewlineChars  ||  bDealingWithTabCharWithPre)
      {
          bIgnoringNewlineChars = bDealingWithTabCharWithPre = FALSE;
          startIndex = indexOfRightBracket+1;//where next tag-search starts
          if(startIndex >= len)
          {
            break;
          }
          continue;
      }

      pData_CHAR[indexOfLeftBracket] = '<'; //retore the char.


      //Now, find out what's in the markup tag, first temporarily
      // NULL-terminating it where the tag ends, then converting it
      // to uppercase:
      pData_CHAR[indexOfRightBracket] = '\0';
      _CHAR* pTagContents = &pData_CHAR[indexOfLeftBracket+1];
      ULONG32 tagContentsLen = indexOfRightBracket-indexOfLeftBracket-1;
      if(bSlashFoundAtEndOfTag) //XML-style end-of-tag "/" was found:
      {
          tagContentsLen--;
      }
      convertToUpperCase(pTagContents, tagContentsLen);
      switch(pTagContents[0])
      {
          case '/': //tag is the end of a binary tag, e.g. "</B>":
          {
            if(tagContentsLen > 1)
            {
                HandleEndTag(pTagContents, tagContentsLen,
                      bSomeCharsFoundSinceLastBreakTag,
                      bSomeCharsFoundSinceLastPosTag,
                      bUserPosTagFoundSinceLastTextContainer,
                      //C_RTRNDRDIFF >>
                      ulByteOffsetIntoFile,
                      indexOfLeftBracket,
                      indexOfRightBracket,
                      bFileFormatIsCallingThis);
                      //<< END C_RTRNDRDIFF.
            }//end "if(tagContentsLen > 1)".
          }//end "case '/':"
          break;

          case 'A':
            if(tagContentsLen > 2)
            {
                if(' '==pTagContents[1])
                {   
                  //we've found "A " so far...
                  _CHAR* pLval;
                  _CHAR* pRval;
                  _CHAR* pRestOfData = &pTagContents[2];
                  ULONG32 restOfDataLen = tagContentsLen-2;
                  ULONG32 nextTokenStartIndex, nextTokenEndIndex;
                  ULONG32 nextValStartIndex, nextValEndIndex;
                  do
                  {
                      if(GetNextTokenLvalueRvaluePair(pRestOfData, restOfDataLen,
                            nextTokenStartIndex, nextTokenEndIndex,
                            nextValStartIndex, nextValEndIndex) )
                      {
                        pLval = &pRestOfData[nextTokenStartIndex];
                        pRestOfData[nextTokenEndIndex]='\0';
                        pRval = &pRestOfData[nextValStartIndex];
                        pRestOfData[nextValEndIndex]='\0';
                      }
                      else
                      {
                        break;
                      }

                      if(!stringCompare(pLval, 
                            nextTokenEndIndex-nextTokenStartIndex, 
                            "HREF", 4)  &&  
                            nextValEndIndex-nextValStartIndex > 0L)
                      {
                        m_pTextWindow->setURL(pRval,
                              nextValEndIndex-nextValStartIndex);
/* C_RTRNDRDIFF:
          Don't do this at File Format side -- sending the <A > tag will
          be enough for the renderer to know the <U> and <FONT color=> 
          information it needs; (we don't want this duplicated in the
          packet header now that packet headers include <A > tags):
                      //Added the following to set
                      // the text that follows to the hyperlink color:
                      m_pTextWindow->pushTextColorStack(
                            m_pTextWindow->getLinkColor(), TRUE);
                      m_pTextWindow->setNumberOfFontColorPushesInsideLinkText(0L);
                      if(m_pTextWindow->usingUnderlineHyperlinks())
                      {
                        m_pTextWindow->pushIsUnderlinedStack(TRUE);
                      }
*/
                      }
                      else if(!stringCompare(pLval,
                            nextTokenEndIndex-nextTokenStartIndex,
                            "TARGET", 6))
                      {
                        //Redo this in case it was in quotes:
                        convertToUpperCase(pRval,
                              nextValEndIndex-nextValStartIndex);
                        if(!stringCompare(pRval,
                            nextValEndIndex-nextValStartIndex,
                            "_PLAYER", 7))
                        {
                            m_pTextWindow->setTargetOfURL(
                                  URL_TARGET_PLAYER);
                        }
                        else if(!stringCompare(pRval,
                            nextValEndIndex-nextValStartIndex,
                            "_BROWSER", 7))
                        {
                            m_pTextWindow->setTargetOfURL(
                                  URL_TARGET_BROWSER);
                        }
                        else
                        {
                            m_pTextWindow->setTargetOfURL(
                                  URL_TARGET_INVALID);
                        }
                      }

                      if(nextValEndIndex < restOfDataLen)
                      {
                        if(0L == nextValEndIndex)
                        {
                            break; //leave the do loop.
                        }
                        pRestOfData = &pRestOfData[nextValEndIndex+1];
                        restOfDataLen -= (nextValEndIndex+1);
                      }
                      else
                      {
                        restOfDataLen = 0L;
                      }

                  } while(restOfDataLen > 0L);
                }
            }
            break;

          case 'B':
            if(!stringCompare(pTagContents, tagContentsLen,
                  "B", 1)) //start of bold tag
            {
                m_pTextWindow->pushIsBoldStack(TRUE);
            }
            //or maybe a line break tag:
            else if(!stringCompare(pTagContents, tagContentsLen,
                  "BR", 2))
            {
                //If we got <pos ..>x<br/>, where "x" contains no
                // plain text (other than spaces, tabs, newlines),
                // then don't do a line break at all, but rather
                // update the NewPktStartYAtTimeZero() value:
                if(bUserPosTagFoundSinceLastTextContainer  &&
                      !bSomeCharsFoundSinceLastPosTag)
                {
                  LONG32 lCurY =  m_pTextWindow->
                        GetNewPktStartYAtTimeZero();
                  HX_ASSERT(INVALID_LONG32 != lCurY);
                  m_pTextWindow->
                        SetNewPktStartYAtTimeZero(
                        lCurY + DEFAULT_LINE_BREAK_SIZE);
                }
                else
                {
                  m_pTextWindow->incrementNumBreakTagsEncountered();
                }
                bSomeCharsFoundSinceLastBreakTag=0L;
            }
            break;

          case 'C':
            if (tagContentsLen>=5  &&  !stringCompare(pTagContents, 5,
                  "CLEAR", 5))
            {   
                // /ONLY do the following if it's live:
                if (bIsLiveSource)
                {
                  // /These are needed for seeking in non-live  case,
                  // but in live they just cause a memory build-up
                  // without any benefit.
                  ULONG32 numTextLinesDeleted =
                        m_pTextWindow->m_pTLList->flush();
                  // /These are needed up to the point where the clear
                  // tag's begin time is effective, and, in non-live,
                  // you can have a clear tag in the middle of a packet
                  // and we don't want to remove the text that precedes
                  // it if that text is valid now and if the clear has
                  // a begin time that is currently in the future.
                  ULONG32 numTextContainersDeleted =
                        m_pTextWindow->TextContainerList::flush();
                }
                m_pTextWindow->m_bClearWasJustSent = TRUE;
                //XXXEH- moved this out of txtwindw.cpp's
                // insertAtEndOfList() so, if "<BR/><CLEAR>foo" is seen,
                // the <BR/> will be ignored, but if <CLEAR><BR/>foo" is
                // seen, the <BR/> will be honored:
                m_pTextWindow->clearNumBreakTagsEncountered();
                m_pTextWindow->setTimeOfLastClearTag();
//#error:XXXXXEH- if isLiveSource, return and start a new pkt here!!
            }
            else if(!stringCompare(pTagContents, tagContentsLen,
                  "CENTER", 6))
            {   
                m_pTextWindow->pushIsCenteredStack(TRUE);
                //Do a line break, but only if 0 line breaks so far,
                // and not if there is no raw text yet, i.e., not if
                // this <CENTER> tag starts the data part of the file,
                // nor if a <CLEAR> tag was just sent:
                if(!m_pTextWindow->getNumBreakTagsEncountered()  &&
                      !m_pTextWindow->m_bClearWasJustSent  &&
                      m_pTextWindow->size()>0L)
                {
                  //If we got <pos ..>x<center>, where "x" contains no
                  // plain text (other than spaces, tabs, newlines),
                  // then don't do a line break at all:
                  if(bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag)
                  {
                      ;
                  }
                  else
                  {
                      m_pTextWindow->
                            incrementNumBreakTagsEncountered();
                  }
                  bSomeCharsFoundSinceLastBreakTag=0L;
                }
            }
            break;

          case 'F':
          {
            BOOL bIsFontTag = FALSE;
            if(tagContentsLen > 5)
            {
                if(pTagContents[1]=='O'  &&  pTagContents[2]=='N'  &&
                      pTagContents[3]=='T'  &&  pTagContents[4]==' ')
                {   //we've found "FONT " so far...
                  bIsFontTag = TRUE;
                  _CHAR* pLval;
                  _CHAR* pRval;
                  _CHAR* pRestOfData = &pTagContents[5];
                  ULONG32 restOfDataLen = tagContentsLen-5;
                  ULONG32 nextTokenStartIndex, nextTokenEndIndex;
                  ULONG32 nextValStartIndex, nextValEndIndex;

                  //Added the following variable to
                  // keep track of all attributes that get pushed in
                  // the following do loop so that the fontStack can
                  // tell us what to do with a subsequent </FONT> tag;
                  // E.g., "<FONT size=+2 color=red>" could get parsed
                  // below and we need to keep track of the fact that
                  // +2 and red were pushed on their respective stacks
                  // at the same time so that a subsequent </FONT> can
                  // force a pop of BOTH the size and the color stacks:
                  ULONG32 ulCurrentStacksPushed = 0L;
                  do
                  {
                      if(GetNextTokenLvalueRvaluePair(pRestOfData,
                            restOfDataLen,
                            nextTokenStartIndex, nextTokenEndIndex,
                            nextValStartIndex, nextValEndIndex) )
                      {
                        pLval = &pRestOfData[nextTokenStartIndex];
                        pRestOfData[nextTokenEndIndex]='\0';
                        pRval = &pRestOfData[nextValStartIndex];
                        pRestOfData[nextValEndIndex]='\0';
                      }
                      else
                      {
                        break;
                      }

                      _CHAR* tmpPtr = pRval;
                      ULONG32 tokenValLen =
                            nextValEndIndex-nextValStartIndex;

                      if(!stringCompare(pLval, 
                            nextTokenEndIndex-nextTokenStartIndex, 
                            "SIZE", 4)  &&
                            //Don't use if size already pushed:
                            !(ulCurrentStacksPushed & FONT_SIZE))
                      {
                        LONG32 lTmp = 0L;
                        if(1L == tokenValLen)
                        {
                            _CHAR ch = tmpPtr[0];
                            if(ch >= '0'  &&  ch <= '9')
                            {
                              lTmp = LONG32(ch - '0');
                              if(!lTmp)
                              {
                                  lTmp = 1L;
                              }
                              else if(lTmp > 7L)
                              {
                                  lTmp = 7L;
                              }
                            }
                        }
                        //"+0" exists so default val could be had
                        // without using </FONT> to get back to it:
                        if(lTmp==3L  ||  
                              !stringCompare(tmpPtr, tokenValLen,
                              "+0", 2))
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                  DEFAULT_FONT_PTSIZE, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(lTmp==4L  ||  
                              !stringCompare(tmpPtr, tokenValLen,
                              "+1", 2))
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                  FONT_SIZE_PLUS1, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(lTmp==5L  ||  
                              !stringCompare(tmpPtr, tokenValLen, 
                              "+2", 2))
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                        FONT_SIZE_PLUS2, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(lTmp==6L  ||  
                              !stringCompare(tmpPtr, tokenValLen,
                              "+3", 2))
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                        FONT_SIZE_PLUS3, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(lTmp==7L  ||  
                              !stringCompare(tmpPtr, tokenValLen,
                              "+4", 2))
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                        FONT_SIZE_PLUS4, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(lTmp==2L  ||  
                              !stringCompare(tmpPtr, tokenValLen,
                              "-1", 2))
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                        FONT_SIZE_MINUS1, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(lTmp==1L  ||  
                              !stringCompare(tmpPtr, tokenValLen,
                              "-2", 2)
                              )
                        {
                            m_pTextWindow->pushFontPointSizeStack(
                                        FONT_SIZE_MINUS2, FALSE);
                            ulCurrentStacksPushed |= FONT_SIZE;
                        }
                        else if(tokenValLen>=2)
                        {
                            INT32 i = atoi(tmpPtr);
                            if(i < -2)
                            {
                              m_pTextWindow->
                                    pushFontPointSizeStack(
                                    FONT_SIZE_MINUS2, FALSE);
                              ulCurrentStacksPushed |= FONT_SIZE;
                            }
                            else if(i > 4)
                            {
                              m_pTextWindow->
                                    pushFontPointSizeStack(
                                    FONT_SIZE_PLUS4, FALSE);
                              ulCurrentStacksPushed |= FONT_SIZE;
                            }
                            //this "else" should only get entered
                            // if "-0" was seen; we have to push
                            // something for each <FONT> tag so that
                            // the next </FONT> tag doesn't cause
                            // an erroneous pop of the prior <FONT>
                            // tag's push:
                            else
                            {
                              m_pTextWindow->
                                    pushFontPointSizeStack(
                                    DEFAULT_FONT_PTSIZE, FALSE);
                              ulCurrentStacksPushed |= FONT_SIZE;
                            }
                        }
                      } //end of "else if( ..."SIZE" ...)".

                      else if(!stringCompare(pLval, 
                            nextTokenEndIndex-nextTokenStartIndex, 
                            "COLOR", 5)  &&
                            //Don't use if color already pushed:
                            !(ulCurrentStacksPushed & FONT_COLOR))
                      {
                        COLORTYPE colortype_retVal;
                        BOOL isAValidColor = FALSE;
                        if(tokenValLen >= 1  &&  '#'==tmpPtr[0]  ||  
                              (tokenValLen>=2  &&
                              '\"'==tmpPtr[0]  &&  '#'==tmpPtr[1]) )
                        {
                            //Color was presented as "#RRGGBB" in hex:
                            isAValidColor = 
                                  convertColorValStringToCOLORTYPE(
                                  tmpPtr, tokenValLen,
                                  colortype_retVal);
                        }
                        //  Returns FALSE if colorName contains an
                        //  unrecognized color:
                        else
                        {     //Color was named, e.g., "darkblue":
                            isAValidColor = convertColorNameToCOLORTYPE(
                                  tmpPtr, tokenValLen, colortype_retVal);
                        }
                        if(isAValidColor)
                        {
                            //Is A legal color name, so push it on stack:
                            m_pTextWindow->pushTextColorStack(
                                  colortype_retVal, FALSE);
                            ulCurrentStacksPushed |= FONT_COLOR;
                            //Added the following to see
                            // if we're inside an <A> tag so that we can
                            // properly back out font colors after hyperlink
                            // text is done:
                            if(m_pTextWindow->hasValidURL())
                            {
                              m_pTextWindow->
                                      incrementNumberOfFontColorPushesInsideLinkText();
                            }
                        }
                        //else ignore the tag; is invalid color.
                      }  //end of "else if( ..."COLOR" ...)".

                      else if(!stringCompare(pLval, 
                            nextTokenEndIndex-nextTokenStartIndex, 
                            "BGCOLOR", 7)  &&
                            //Don't use if bgcolor already pushed:
                            !(ulCurrentStacksPushed & FONT_BGCOLOR))
                      {
                        COLORTYPE colortype_retVal;
                        BOOL isAValidColor = FALSE;
                        if(tokenValLen >= 1  &&  '#'==tmpPtr[0]  ||  
                              (tokenValLen>=2  &&
                              '\"'==tmpPtr[0]  &&  '#'==tmpPtr[1]) )
                        {
                            //Color was presented as "#RRGGBB" in hex:
                            isAValidColor = 
                                  convertColorValStringToCOLORTYPE(
                                  tmpPtr, tokenValLen,
                                  colortype_retVal);
                        }
                        //  Returns FALSE if colorName contains an
                        //  unrecognized color:
                        else
                        {     //Color was named, e.g., "darkblue":
                            isAValidColor = convertColorNameToCOLORTYPE(
                                  tmpPtr, tokenValLen, colortype_retVal);
                        }
                        if(isAValidColor)
                        {
                            //Is A legal color name, so push it on stack:
                            m_pTextWindow->pushTextBackgroundColorStack(
                                  colortype_retVal, FALSE);
                            ulCurrentStacksPushed |= FONT_BGCOLOR;
                        }
                        //else ignore the tag; is invalid color.
                      } //end of "else if( ..."BGCOLOR" ...)".

                      else if(!stringCompare(pLval, 
                            nextTokenEndIndex-nextTokenStartIndex, 
                            "CHARSET", 7)  &&  tokenValLen>1  &&
                            //Don't use if charset already pushed:
                            !(ulCurrentStacksPushed & FONT_CHARSET))
                      {
                        //  Returns FALSE if tmpPtr contains an 
                        //  unrecognized charset:
                        ULONG32 ulCharset_retVal = CHARSET__default;
                        if('\"' == tmpPtr[0])
                        {
                            tmpPtr=tmpPtr+1;
                            tokenValLen--;
                        }
                        if('\"' == tmpPtr[tokenValLen-1])
                        {
                            tokenValLen--;
                        }

                        if (HXR_OK ==
                              convertCharsetNameToCharsetULONG32(
                              tmpPtr, tokenValLen,
                              REALTEXT_MAX_CHARSET_LEVEL_SUPPORTED,
                              ulCharset_retVal))
                        {
                            //Is a legal charset name, so push it on stack:
                            m_pTextWindow->pushFontCharsetStack(
                                  ulCharset_retVal, FALSE);
                            ulCurrentStacksPushed |= FONT_CHARSET;
                        }
                        //else ignore the tag; is invalid charset.
                      } //end of "else if( ..."CHARSET" ...)".

                      //Added this else-if to handle
                      // font "faces", e.g., "helvetica":
                      else if( (!stringCompare(pLval, 
                            nextTokenEndIndex-nextTokenStartIndex, 
                            "FACE", 4)  ||
                              !stringCompare(pLval, 
                              nextTokenEndIndex-nextTokenStartIndex, 
                              "NAME", 4)
                            )  &&  tokenValLen>1  &&
                            //Don't use if face has already been pushed:
                            !(ulCurrentStacksPushed & FONT_FACE) )
                      {
                        //XXXEH- Replace the
                        // following hack with a function to do this:
                        {//hack start:
                            if('\"' == tmpPtr[0])
                            {
                              tmpPtr=tmpPtr+1;
                              tokenValLen--;
                            }
                            if('\"' == tmpPtr[tokenValLen-1])
                            {
                              tmpPtr[tokenValLen-1] = '\0'; 
                              tokenValLen--;
                            }
                            tmpPtr[tokenValLen] = '\0';
                            ///convertToUpperCase(tmpPtr, tokenValLen);
                            {
                              //Is an allowed font face name, so push it on
                              // the stack:
                              ULONG32 faceIndx =
                                    getFontFaceIndexFromString(
                                    tmpPtr, tokenValLen,
                                    m_pTextWindow->
                                        getMajorContentVersion(),
                                    m_pTextWindow->
                                        getMinorContentVersion()
                                    );
                              m_pTextWindow->pushFontFaceStack(
                                    faceIndx);
                              ulCurrentStacksPushed |= FONT_FACE;
                            }
                        }//hack end.
                      } //end of "else if( ..."FACE" ...)".

                      
                      if(nextValEndIndex < restOfDataLen)
                      {
                        if(0L == nextValEndIndex)
                        {
                            break; //leave the do loop.
                        }
                        pRestOfData = &pRestOfData[nextValEndIndex+1];
                        restOfDataLen -= (nextValEndIndex+1);
                      }
                      else
                      {
                        restOfDataLen = 0L;
                      }

                  } while(restOfDataLen > 0L);
                  //The following code sets up the
                  // font stack to keep track of ALL parameters
                  // pushed in the above do-while loop so that a
                  // subsequent </FONT> can pop all involoved stacks
                  // simultaneously:
                  if(0L != ulCurrentStacksPushed)
                  {
                      m_pTextWindow->pushFontStack(
                            ulCurrentStacksPushed);
                      //C_RTRNDRDIFF >>:
                      //Added this to keep track of location in file of
                      // every FONT tag so, when forming a packet, it
                      // can be determined where the matching <FONT>
                      // for each </FONT> is and, for each </FONT>
                      // whose matching <FONT> is in a prior packet,
                      // we can prepend an appropriate <FONT> tag in
                      // the packet's header:
                      m_pTextWindow->pushFontTagStartByteInFileStack(
                            ulByteOffsetIntoFile+indexOfLeftBracket);
                      //<< END C_RTRNDRDIFF.
                  }
                } //end of "if(pTagContents[1]==...) <==i.e., if "FONT".
            }
            //C_RTRNDRDIFF >>:
            // /Don't document this until it gets QA'd:
            // In non-live scenarios, you don't want to do most of these:
            // /This allows live-text author to blow away all state
            // information without having to use closing tags for
            // every yet-unclosed tag so far.  This allows a memory-
            // build-up problem to be controlled by the author in
            // the case where they've sent a lot of open tags but
            // haven't kept track of what needs closing.  Syntax
            // is flush="all" or flush="tags".  "tags" clears out all
            // font, bold, ...etc. stacks.  "all" does that and also
            // clears out other structures like savedPacketDataList:
            if (!bIsFontTag  &&  tagContentsLen >= 5  &&
                  !stringCompare(pTagContents, 5, "FLUSH", 5)  &&
                  /* bIsLiveSource  && */  isspace(pTagContents[5]))
            {
                UINT32 ui = tagContentsLen - 5;
                _CHAR* pFlushTarget = strstr(&pTagContents[6], "TARGET");
                if (pFlushTarget)
                {
                  _CHAR* pTmp = &pFlushTarget[6];
                  if (pTmp)
                  {
                      while (isspace(*pTmp))
                      {
                        pTmp++; ui--;
                      }
                      if ('=' == *pTmp)
                      {
                        *pTmp++; ui--;
                        while (isspace(*pTmp))
                        {
                            pTmp++; ui--;
                        }
                        if ('\"' == *pTmp)
                        {
                            pTmp++; ui--;
                            while (isspace(*pTmp))
                            {
                              pTmp++; ui--;
                            }
                            if (*pTmp)
                            {
                              // /Flags are:
                              // / 0x1 =font stacks
                              // / 0x2 =ticker stacks
                              // / 0x4 =bold, Italics,
                              // /  underlined, strikethrough
                              // / 0x8 =indent amount stacks
                              // / 0x10=TextContainerList
                              // / 0x20=TextLineList (m_pTLList)
                              ULONG32 ulFlags = 0x0;
                              ULONG32 ulTmpLen =
                                    (ULONG32)strlen(pTmp);
                              if (ui>=3 && !stringCompare(pTmp,
                                    3, "all", 3))
                              {
                                  m_pTextWindow->reset();
                                  ulFlags = 0xFFFFFFFF;
                              }
                              else if (ulTmpLen>=4  &&  *pTmp  &&
                                    !stringCompare(pTmp, 4,
                                    "tags", 4))
                              {
                                  ulFlags |= 0x00000007;
                              }

                              if ( (ulFlags & 0x00000001)  ||
                                    (ulTmpLen>=8  &&  *pTmp  &&
                                    !stringCompare(pTmp, 8,
                                    "fontTags", 8)) )
                              {
                                  m_pTextWindow->
                                        TextAttributeStacks::
                                        flushFontStacks();
                                  m_pTextWindow->
                                        m_pFontUndoTagList->
                                        flush();
                                  ulFlags |= 0x00000001;
                              }
                              if ( (ulFlags & 0x00000002)  ||
                                    (ulTmpLen>=10  &&  *pTmp  &&
                                    !stringCompare(pTmp, 10,
                                    "tickerTags", 10)) )
                              {
                                  m_pTextWindow->
                                        TextAttributeStacks::
                                        flushTickerStacks();
                                  ulFlags |= 0x00000002;
                              }
                              if ( (ulFlags & 0x0000004)  ||
                                    (ulTmpLen>=4  &&  *pTmp  &&
                                    !stringCompare(pTmp, 4,
                                    "bius", 4)) )
                              {
                                  m_pTextWindow->
                                        TextAttributeStacks::
                                        flushBIUSandBlinkStacks();
                                  ulFlags |= 0x00000004;
                              }
                              if ( (ulFlags & 0x00000008)  ||
                                    (ulTmpLen>=6  &&  *pTmp  &&
                                    !stringCompare(pTmp, 6,
                                    "indent", 6)) )
                              {
                                  m_pTextWindow->
                                        TextAttributeStacks::
                                        flushIndentAmtStack();
                                  ulFlags |= 0x00000008;
                              }
                              if ( (ulFlags & 0x00000010)  ||
                                    (ulTmpLen>=8  &&  *pTmp  &&
                                    !stringCompare(pTmp, 8,
                                    "wordList", 8)) )
                              {
                                  m_pTextWindow->
                                      TextContainerList::flush();
                                  ulFlags |= 0x00000010;
                              }
                              if ( (ulFlags & 0x00000020)  ||
                                    (ulTmpLen>=8  &&  *pTmp  &&
                                    !stringCompare(pTmp, 8,
                                    "lineList", 8)) )
                              {
                                  m_pTextWindow->m_pTLList->flush();
                                  ulFlags |= 0x00000020;
                              }
                            }
                        }
                      }
                  }
                }
            }
            //<< END C_RTRNDRDIFF.
            break;
          } // /End case 'F'.

          case 'H':
            //Added the following to allow better
            // handling of HTML text imported as RealText:
            //XXXEH- for now, treat as 2 line breaks, but in future,
            // also draw a line (horizontal rule):
            if(!stringCompare(pTagContents, tagContentsLen,
                  "HR", 2))
            {
                //Added the surrounding if() so that
                // this code doesn't get called if horizontal motion:
                if(m_pTextWindow->getCrawlRate() == 0  ||
                      m_pTextWindow->getScrollRate() != 0)
                {
                  //If we got <pos ..>x<hr/>, where "x" contains no
                  // plain text (other than spaces, tabs, newlines),
                  // then don't do a line break at all, but rather
                  // update the NewPktStartYAtTimeZero() value:
                  if(bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag)
                  {
                      LONG32 lCurY =  m_pTextWindow->
                            GetNewPktStartYAtTimeZero();
                      HX_ASSERT(INVALID_LONG32 != lCurY);
                      m_pTextWindow->
                            SetNewPktStartYAtTimeZero(
                            lCurY + (2*DEFAULT_LINE_BREAK_SIZE));
                  }
                  else
                  {
                     m_pTextWindow->incrementNumBreakTagsEncountered();
                     m_pTextWindow->incrementNumBreakTagsEncountered();
                  }
                  bSomeCharsFoundSinceLastBreakTag=0L;
                }
            }


          case 'I':
                if(!stringCompare(pTagContents, tagContentsLen,
                      "I", 1)) //start of italics tag
                {
                  m_pTextWindow->pushIsItalicizedStack(TRUE);
                }
                break;

          case 'L':
                if(!stringCompare(pTagContents, tagContentsLen,
                      "LOOP", 4))
                {
                  m_pTextWindow->loop(TRUE);
                }
                //Added the following to allow better
                // handling of HTML text imported as RealText:
                //XXXEH- for now, treat as line break tag, but in future,
                // add indent based on depth of nested ULs and OLs:
                else if(!stringCompare(pTagContents, tagContentsLen,
                      "LI", 2)) 
                {
                  //Added the surrounding if() so that
                  // this code doesn't get called if horizontal motion:
                  if(m_pTextWindow->getCrawlRate() == 0  ||
                        m_pTextWindow->getScrollRate() != 0)
                  {
                      //If we got <pos ..>x<center>, where "x" contains 
                      // no plain text (other than spaces, tabs,
                      // newlines), then don't do a line break at all:
                      if(bUserPosTagFoundSinceLastTextContainer  &&
                            !bSomeCharsFoundSinceLastPosTag)
                      {
                        ;
                      }
                      else
                      {
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                      }
                      bSomeCharsFoundSinceLastBreakTag=0L;
                  }
                }
                break;

          case 'O':
                //Added the following to allow better
                // handling of HTML text imported as RealText:
                //XXXEH- for now, treat as line break tag, but in future,
                // add indent based on depth of nested ULs and OLs:
                if(!stringCompare(pTagContents, tagContentsLen,
                      "OL", 2)) 
                {
                  UINT16 curIndentAmtInPixels =
                        m_pTextWindow->
                        peekAtLineIndentAmtInPixelsStack();
                  m_pTextWindow->pushLineIndentAmtInPixelsStack(
                        curIndentAmtInPixels +
                        ORDERED_LIST_INDENT_AMT);
                  //Added the surrounding if() so that
                  // this code doesn't get called if horizontal motion:
                  if(m_pTextWindow->getCrawlRate() == 0  ||
                        m_pTextWindow->getScrollRate() != 0)
                  {
                      BOOL bFollowsPosTag =
                            (bUserPosTagFoundSinceLastTextContainer
                            && !bSomeCharsFoundSinceLastPosTag);
                      //Do a line break, but only if 0 line breaks so
                      // far, and not if there is no raw text yet,
                      // i.e., not if this <OL> tag starts the data
                      // part of the file, nor if a <CLEAR> tag was
                      // just sent:
                      if(!m_pTextWindow->getNumBreakTagsEncountered()
                            &&
                            //C_RTRNDR_DIFF>>
                            (IsBeta1Player()  ||
                            //<<END C_RTRNDR_DIFF.
                            bFollowsPosTag  ||
                            (!m_pTextWindow->m_bClearWasJustSent  &&
                            m_pTextWindow->size()>0L)))
                      {
                        //If we got <pos ..>x<ol>, where "x" contains 
                        // no plain text (other than spaces, tabs,
                        // newlines), then don't do a line break at
                        // all, but DO add ORDERED_LIST_INDENT_AMT
                        // amount to the NewPktStartXAtTimeZero()
                        // value:
                        if(bFollowsPosTag  &&  !IsBeta1Player())
                        {
                            LONG32 lCurX = m_pTextWindow->
                                  GetNewPktStartXAtTimeZero();
                            HX_ASSERT(INVALID_LONG32 != lCurX);
                            m_pTextWindow->
                                  SetNewPktStartXAtTimeZero(
                                  lCurX +
                                  (ORDERED_LIST_INDENT_AMT));
                        }
                        else
                        {
                            m_pTextWindow->
                                incrementNumBreakTagsEncountered();
                        }
                        bSomeCharsFoundSinceLastBreakTag=0L;
                      }
                  }
                }
                break;

                      
          case 'P':
                if(!stringCompare(pTagContents, tagContentsLen,
                      "P", 1)) //start of paragraph tag
                {
                  //If we got <pos ..>x<p>, where "x" contains no
                  // plain text (other than spaces, tabs, newlines),
                  // then don't do a line break at all, but rather
                  // update the NewPktStartYAtTimeZero() value:
                  if(bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag)
                  {
                      LONG32 lCurY =  m_pTextWindow->
                            GetNewPktStartYAtTimeZero();
                      HX_ASSERT(INVALID_LONG32 != lCurY);
                      m_pTextWindow->
                            SetNewPktStartYAtTimeZero(
                            lCurY + (2*DEFAULT_LINE_BREAK_SIZE));
                  }
                  else
                  {
                      m_pTextWindow->
                            incrementNumBreakTagsEncountered();
                      m_pTextWindow->
                            incrementNumBreakTagsEncountered();
                  }
                  bSomeCharsFoundSinceLastBreakTag=0L;
                }
                else if(!stringCompare(pTagContents, tagContentsLen,
                      "PRE", 3)) //start of PRE tag
                {
                  m_pTextWindow->pushIsPreStack();

                  //Acts like a <P> tag as far as newlines go:
                  //Do a line break, but only if 0 line breaks so far,
                  // and not if there is no raw text yet, i.e., not if
                  // this <PRE> tag starts the data part of the file,
                  // nor if a <CLEAR> tag was just sent:
                  if(!m_pTextWindow->getNumBreakTagsEncountered()  &&
//XXXXXEH-19980918>>
                        //C_RTRNDR_DIFF>>
                        (IsBeta1Player()  ||
                        //<<END C_RTRNDR_DIFF.
                        (!m_pTextWindow->m_bClearWasJustSent  &&
                        m_pTextWindow->size()>0L)) )
//<<XXXXXEH-19980918.
                  {                 
                      //If we got <pos ..>x<pre>, where "x" contains
                      // no plain text (other than spaces, tabs,
                      // newlines), then don't do a line break at all:
                      if(bUserPosTagFoundSinceLastTextContainer  &&
                            !bSomeCharsFoundSinceLastPosTag)
                      {
                        ;
                      }
                      else
                      {
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                      }
                      bSomeCharsFoundSinceLastBreakTag=0L;
                  }

                  //Set cur font face to courier:
                  m_pTextWindow->pushFontFaceStack(
                        COURIERTT_FONT_FACE_INDX);
                  m_pTextWindow->pushFontStack(FONT_FACE);
                  //C_RTRNDRDIFF >>:
                  //Added this to keep track of location in file of
                  // every FONT tag so, when forming a packet, it
                  // can be determined where the matching <FONT>
                  // for each </FONT> is and, for each </FONT>
                  // whose matching <FONT> is in a prior packet,
                  // we can prepend an appropriate <FONT> tag in
                  // the packet's header:
                  m_pTextWindow->pushFontTagStartByteInFileStack(
                        ulByteOffsetIntoFile+indexOfLeftBracket);
                  //<< END C_RTRNDRDIFF.
                }
                else if(tagContentsLen >= 7) //7==min length (e.g.,
                                    // "POS X=8" is 7 chars long)
                {
                  if('O' == pTagContents[1]) 
                  {   //is possibly a <TIME > tag; min length for TIME
                      //  is 10: e.g., <TIME end=1> (10 chars)
                      if(pTagContents[2]=='S'  &&
                            pTagContents[3]==' ')
                      {   //we've found "POS " so far...
                        _CHAR* pLval;
                        _CHAR* pRval;
                        _CHAR* pRestOfData = &pTagContents[4];
                        ULONG32 restOfDataLen = tagContentsLen-4;
                        ULONG32 nextTokenStartIndex, 
                              nextTokenEndIndex;
                        ULONG32 nextValStartIndex, nextValEndIndex;
                        do
                        {
                            if(GetNextTokenLvalueRvaluePair(
                                  pRestOfData,
                                  restOfDataLen,
                                  nextTokenStartIndex,
                                  nextTokenEndIndex,
                                  nextValStartIndex, 
                                  nextValEndIndex) )
                            {
                              pLval = &pRestOfData[
                                    nextTokenStartIndex];
                              pRestOfData[nextTokenEndIndex]='\0';
                              pRval = &pRestOfData[
                                    nextValStartIndex];
                              pRestOfData[nextValEndIndex]='\0';
                            }
                            else
                            {
                              break;
                            }

                            _CHAR* tmpPtr = pRval;
                            ULONG32 tokenValLen =
                                  nextValEndIndex -
                                  nextValStartIndex;

                            BOOL bErr = FALSE;

                            BOOL bIsX0orY0 = TRUE;

                            if((bIsX0orY0 = !stringCompare(pLval, 
                                  nextTokenEndIndex -
                                  nextTokenStartIndex,
                                  "X0", 2))  ||
                                  //Only allow user to set POS X=n
                                  // if window has no motion to it:
                                  (!m_pTextWindow->getScrollRate()
                                  &&
                                  !m_pTextWindow->getCrawlRate()
                                  &&
                                  !stringCompare(pLval,
                                  nextTokenEndIndex -
                                  nextTokenStartIndex,
                                  "X", 1) ) )
                            {
                              //In case
                              //     <POS X0="15"/> <POS X="23">foo
                              // arrives at the start of a packet,
                              // make sure to clear the pkt start Y
                              // so the X="23" will be used instead
                              // of 15.  The problem was that the
                              // space char separating the 2 didn't
                              // become a TextContainer in the list
                              // and thus, when "foo" was inserted,
                              // the ...XAtTimeZero was still valid
                              // and was used as a result and the
                              // 23 was ignored:
                              if(!bIsX0orY0)
                              {
                                  m_pTextWindow->
                                        m_bUseXPOSVal = TRUE;
                              }
                              
                              ULONG32 ulXAtTimeZero = 0L;
                              //tmpPtr is always NULL-terminated
                              // at this pt:
                              ulXAtTimeZero =
                                  m_pTextWindow->
                                  string_to_ULONG32(tmpPtr, bErr);
                              if(!bErr)
                              {
                                  m_pTextWindow->
                                       SetNewPktStartXAtTimeZero(
                                       (LONG32)ulXAtTimeZero);
                                  //Fixes bug #6906; if
                                  // "<BR/><POS .../>foo" is seen,
                                  // the <BR/> will be ignored, but
                                  // if <POS ../><BR/>foo" is seen,
                                  // the <BR/> will be honored:
                                  m_pTextWindow->
                                    clearNumBreakTagsEncountered();
                            bUserPosTagFoundSinceLastTextContainer
                                        = !bIsX0orY0;
                                  bSomeCharsFoundSinceLastPosTag =
                                        FALSE;
                              }
                              //else ignore the tag; is invalid X
                            } //end of "if( ..."X0"...)".

                            else if((bIsX0orY0 =!stringCompare(pLval,
                                  nextTokenEndIndex -
                                  nextTokenStartIndex,
                                  "Y0", 2))  ||
                                  //Only allow user to set POS X=n
                                  // if window has no motion to it:
                                  (!m_pTextWindow->getScrollRate()
                                  &&
                                  !m_pTextWindow->getCrawlRate()
                                  &&
                                  !stringCompare(pLval,
                                  nextTokenEndIndex -
                                  nextTokenStartIndex,
                                  "Y", 1) ) )
                            {
                              //In case
                              //     <POS Y0="20"/> <POS Y="10">foo
                              // arrives at the start of a packet,
                              // make sure to clear the pkt start Y
                              // so the Y="10" will be used instead
                              // of 20.  The problem was that the
                              // space char separating the 2 didn't
                              // become a TextContainer in the list
                              // and thus, when "foo" was inserted,
                              // the ...YAtTimeZero was still valid
                              // and was used as a result and the
                              // 10 was ignored:
                              if(!bIsX0orY0)
                              {
                                  m_pTextWindow->
                                        m_bUseYPOSVal = TRUE;
                              }
                              
                              ULONG32 ulYAtTimeZero = 0L;
                              //tmpPtr is always NULL-terminated
                              // at this pt:
                              ulYAtTimeZero =
                                  m_pTextWindow->
                                  string_to_ULONG32(tmpPtr, bErr);
                              if(!bErr)
                              {
                                  m_pTextWindow->
                                       SetNewPktStartYAtTimeZero(
                                       (LONG32)ulYAtTimeZero);
                                  //Fixes bug #6906; if
                                  // "<BR/><POS .../>foo" is seen,
                                  // the <BR/> will be ignored, but
                                  // if <POS ../><BR/>foo" is seen,
                                  // the <BR/> will be honored:
                                  m_pTextWindow->
                                    clearNumBreakTagsEncountered();
                            bUserPosTagFoundSinceLastTextContainer
                                        = !bIsX0orY0;
                                  bSomeCharsFoundSinceLastPosTag =
                                        FALSE;
                              }
                              //else ignore the tag; is invalid Y
                            } //end of "else if( ..."Y0" ...)".

                            if(nextValEndIndex < restOfDataLen)
                            {
                              if(0L == nextValEndIndex)
                              {
                                  break; //leave the do loop.
                              }
                              pRestOfData = &pRestOfData[
                                    nextValEndIndex+1];
                              restOfDataLen -= (nextValEndIndex+1);
                            }
                            else
                            {
                              restOfDataLen = 0L;
                            }

                        } while(restOfDataLen > 0L);
                      } //end "POS " tag parsing.
                  }
                }
                break;

          case 'R':
                //added the following case so
                // that a forced deletion of all prior-streamed
                // data could be made (noting that <CLEAR> should
                // do this but doesn't until the FF is changed
                // to handle packet sending, and thus seeking,
                // at the expected time)  This is to remain
                // undocumented:
                if(!stringCompare(pTagContents, tagContentsLen,
                      "RESET", 5))
                {
                  //go through list and delete everything:
                  m_pTextWindow->deleteAllNoLongerVisible();
                }
                //C_RTRNDRDIFF >>:
                else if(!stringCompare(pTagContents, tagContentsLen,
                      "REQUIRED", 8))
                {
                  m_pTextWindow->pushIsRequiredStack();                 
                }
                // << END C_RTRNDRDIFF.
                break;


          case 'S':
                if(!stringCompare(pTagContents, tagContentsLen,
                      "S", 1)) //start of strike-out tag
                {
                  m_pTextWindow->pushIsStruckOutStack(TRUE);
                }
                break;

          case 'T':
            if(tagContentsLen >= 2)
            {
                BOOL isTUtag, isTLtag;
                isTUtag = isTLtag = FALSE;
                if('U' == pTagContents[1])
                { 
                  //changed this so, for example, 
                  //  <TUblah> won't work but <TU blah> will:
                  if(tagContentsLen > 2)
                  {
                      if(' ' ==  pTagContents[2]  ||
                            '\t'  == pTagContents[2]  ||
                            '\n'  == pTagContents[2]  ||
                            '\r'  == pTagContents[2]  )
                      {
                        //is <TU>, or "TextUpper" tag for tickertape:
                        isTUtag = TRUE;
                        m_pTextWindow->isTickerUpperText(isTUtag);
                      }
                  }
                  else  //tagContentsLen == 2, so is <TU>:
                  {
                      //is <TU>, or "TextUpper" tag for tickertape:
                      isTUtag = TRUE;
                      m_pTextWindow->isTickerUpperText(isTUtag);
                  }
                } 
                else if('L' == pTagContents[1]) 
                { 
                  //changed this so, for example, 
                  //  <TLblah> won't work but <TL blah> will:
                  if(tagContentsLen > 2)
                  {
                      if(' ' ==  pTagContents[2]  ||
                            '\t'  == pTagContents[2]  ||
                            '\n'  == pTagContents[2]  ||
                            '\r'  == pTagContents[2]  )
                      {
                        //is <TL>, or "TextLower" tag for tickertape:
                        isTLtag = TRUE;
                        m_pTextWindow->isTickerUpperText(!isTLtag);
                      }
                  }
                  else  //tagContentsLen == 2, so is <TL>:
                  {
                      //is <TL>, or "TextLower" tag for tickertape:
                      isTLtag = TRUE;
                      m_pTextWindow->isTickerUpperText(!isTLtag);
                  }
                }
                else if('I' == pTagContents[1]  &&  tagContentsLen >= 10) 
                { //is possibly a <TIME ..> tag; min length for TIME
                  //  is 10: e.g., <TIME end=1> (10 chars)
                  if(pTagContents[2]=='M'  &&  pTagContents[3]=='E'  &&
                        pTagContents[4]==' ')
                  {   //we've found "TIME " so far...
                      _CHAR* pLval;
                      _CHAR* pRval;
                      _CHAR* pRestOfData = &pTagContents[5];
                      ULONG32 restOfDataLen = tagContentsLen-5;
                      ULONG32 nextTokenStartIndex, nextTokenEndIndex;
                      ULONG32 nextValStartIndex, nextValEndIndex;
                      do
                      {
                        if(GetNextTokenLvalueRvaluePair(pRestOfData,
                              restOfDataLen,
                              nextTokenStartIndex,
                              nextTokenEndIndex,
                              nextValStartIndex, nextValEndIndex) )
                        {
                            pLval =&pRestOfData[nextTokenStartIndex];
                            pRestOfData[nextTokenEndIndex]='\0';
                            pRval = &pRestOfData[nextValStartIndex];
                            pRestOfData[nextValEndIndex]='\0';
                        }
                        else
                        {
                            break;
                        }

                        _CHAR* tmpPtr = pRval;
                        ULONG32 tokenValLen =
                              nextValEndIndex-nextValStartIndex;

                        if(!stringCompare(pLval, 
                              nextTokenEndIndex-nextTokenStartIndex, 
                              "BEGIN", 5)
                              //be consistent w/RA:
                              || !stringCompare(pLval, 
                              nextTokenEndIndex-nextTokenStartIndex, 
                              "START", 5)
                              )
                        {
                            ULONG32 timeValInMillisec = 0L;
                            if(convertTimeStringToULONG32(
                                  tmpPtr, tokenValLen, 
                                  timeValInMillisec))
                            {
                              m_pTextWindow->SetLatestSentTimeToRender(
                                    timeValInMillisec
                                    - lTimeOffset); //cz);
                            }
                            //else ignore the tag; is invalid BEGIN time.
                        } //end of "if( ..."BEGIN" ...||..."START"...)".

                        if(!stringCompare(pLval, 
                              nextTokenEndIndex-nextTokenStartIndex, 
                              "END", 3))
                        {
                            ULONG32 timeValInMillisec = 0L;
                            if(convertTimeStringToULONG32(
                                  tmpPtr, tokenValLen, 
                                  timeValInMillisec))
                            {
                              if(bIsLiveSource  &&
                                    TIME_INVALID ==
                                    timeValInMillisec)
                              {
                                  //Make end time be "infinity":
                                  timeValInMillisec =
                                        TIME_INFINITY;
                              }
                              m_pTextWindow->
                                    SetLatestSentTimeToStopRendering(
                                    timeValInMillisec
                                    - lTimeOffset);//cz);
                            }
                            //else ignore the tag; is invalid END time.
                        } //end of "else if( ..."END" ...)".

                        if(nextValEndIndex < restOfDataLen)
                        {
                            if(0L == nextValEndIndex)
                            {
                              break; //leave the do loop.
                            }
                            pRestOfData = &pRestOfData[nextValEndIndex+1];
                            restOfDataLen -= (nextValEndIndex+1);
                        }
                        else
                        {
                            restOfDataLen = 0L;
                        }

                      } while(restOfDataLen > 0L);
                  } //end "TIME " tag parsing.
                }
                //Added the following to allow better
                // handling of HTML text imported as RealText:
                //XXXEH- for now, just treat as line break tag, and
                //just look at first 2-3 chars (ignoring optional <TR>-tag
                //parameters like "align=") so "TR" or "TR " are valid:
                else if(!stringCompare(pTagContents, tagContentsLen,
                      "TR", 2)  ||
                      (tagContentsLen>=3  &&  
                      !stringCompare(pTagContents, 3, "TR ", 3)) )
                {
                  //Added the surrounding if() so that
                  // this code doesn't get called if horizontal motion:
                  if(m_pTextWindow->getCrawlRate() == 0  ||
                        m_pTextWindow->getScrollRate() != 0)
                  {
                      //If we got <pos ..>x<tr>, where "x" contains
                      // no plain text (other than spaces, tabs,
                      // newlines), then don't do a line break at all:
                      if(bUserPosTagFoundSinceLastTextContainer  &&
                            !bSomeCharsFoundSinceLastPosTag)
                      {
                        ;
                      }
                      else
                      {
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                      }
                      bSomeCharsFoundSinceLastBreakTag=0L;
                  }
                }

                //Now, see if there are any additional attributes for
                // ticker's upper/lower text:
                if(tagContentsLen > 2  &&  (isTUtag  ||  isTLtag))
                {
                  ULONG32 nameTokenStartIndex, nameTokenEndIndex,
                        indexOfEqualsSign;
                  ULONG32 valueTokenStartIndex, valueTokenEndIndex,
                        dummy;
                  _CHAR tmpChar1, tmpChar2;
                  ULONG32 nameTokenLen, valTokenLen;
                  nameTokenStartIndex =
                        skipSpacesTabsAndNewlineChars(
                        pTagContents, tagContentsLen,
                        2); //start at [2] and skip spaces.
                  if(nameTokenStartIndex == tagContentsLen)
                  {   //only spaces were found so rest of tag is empty:
                      break; 
                  }
                  nameTokenEndIndex = findNextSpaceTabOrNewLineChar(
                        pTagContents, tagContentsLen, 
                        nameTokenStartIndex, indexOfEqualsSign,
                        //In-tag text is always us-ascii:
                        CHARSET__us_ascii);
                  if(indexOfEqualsSign < tagContentsLen-1) 
                  {   //"(name)=(one or more chars)" was found:
                      if(nameTokenEndIndex == indexOfEqualsSign+1)
                      { /*  "(name)=(1 or more space chars)(val)" was
                         *  found:  */
                        valueTokenStartIndex = 
                              skipSpacesTabsAndNewlineChars(
                              pTagContents, tagContentsLen, 
                              nameTokenEndIndex);
                        if(valueTokenStartIndex == tagContentsLen)
                        {
                            break;
                        }
                      }
                      else //"(name)=(val)" was found:
                      {
                        nameTokenEndIndex = indexOfEqualsSign;
                        valueTokenStartIndex = indexOfEqualsSign+1;
                      }
                      valueTokenEndIndex = 
                            findNextSpaceTabOrNewLineChar(
                            pTagContents, tagContentsLen, 
                            valueTokenStartIndex, dummy,
                            //In-tag text is always us-ascii:
                            CHARSET__us_ascii);
                      //Put a '\0' at the character just past where
                      // the (name) part is:
                      tmpChar1 = pTagContents[nameTokenEndIndex];
                      pTagContents[nameTokenEndIndex] = '\0';
                      nameTokenLen = 
                            nameTokenEndIndex - nameTokenStartIndex;
                      if(!stringCompare(
                            &pTagContents[nameTokenStartIndex],
                            nameTokenLen,
                            "COLOR", 5))
                      {
                        COLORTYPE colortype_retVal;

                        tmpChar2 = pTagContents[valueTokenEndIndex];
                        pTagContents[valueTokenEndIndex] = '\0';
                        
                        //Added this so "#RRGGBB"
                        // works as well as "colorname" does:
                        BOOL isAValidColor = FALSE;
                        char* pTemp_Ptr =
                              &pTagContents[valueTokenStartIndex];
                        valTokenLen = valueTokenEndIndex - 
                              valueTokenStartIndex;
                        if(valTokenLen>=1  &&  '#'==pTemp_Ptr[0]  ||
                              (valTokenLen>=2  &&
                              '\"'==pTemp_Ptr[0]  && 
                              '#'==pTemp_Ptr[1])  )
                        {
                            //Color was presented as "#RRGGBB" in hex:
                            isAValidColor = 
                                  convertColorValStringToCOLORTYPE(
                                  pTemp_Ptr, valTokenLen, 
                                  colortype_retVal);
                        }
                        //  Returns FALSE if colorName contains an
                        //  unrecognized color:
                        else
                        {     //Color was named, e.g., "darkblue":
                            isAValidColor = convertColorNameToCOLORTYPE(
                                  pTemp_Ptr, valTokenLen, 
                                  colortype_retVal);
                        }
                        if(isAValidColor)
                        {
                            //  Is a legal color name, so push it on
                            //  the appropriate stack:
                            if(isTUtag)
                            {
                              m_pTextWindow->
                                    pushTickerUpperColorStack(
                                    colortype_retVal);
                            }
                            else
                            {
                              m_pTextWindow->
                                    pushTickerLowerColorStack(
                                    colortype_retVal);
                            }
                        }
                        //else ignore the tag; is invalid color.

                        //Restore the orig char:
                        pTagContents[valueTokenEndIndex] = tmpChar2; 
                      }
                      //Restore it from '\0':
                      pTagContents[nameTokenEndIndex] = tmpChar1; 
                  }
                  else
                  {
#if defined(SHOW_CODE_CHANGE_MESSAGES)
#pragma message("EH- in "__FILE__", \
\"(name)(SPACES)=(0 or more SPACES)(value)\"-parsing is not \
yet handled.")
#endif
                      ;
                  }
                }
            }
            break;

          case 'U':
            if(!stringCompare(pTagContents, tagContentsLen,
                  "U", 1)) //start of underlined tag
            {
                m_pTextWindow->pushIsUnderlinedStack(TRUE);
            }
            //Added the following to allow better
            // handling of HTML text imported as RealText:
            //XXXEH- for now, treat as line break tag, but in future,
            // add indent based on depth of nested ULs and OLs:
            else if(!stringCompare(pTagContents, tagContentsLen,
                  "UL", 2)) 
            {
                //added the following:
                UINT16 curIndentAmtInPixels =
                      m_pTextWindow->
                      peekAtLineIndentAmtInPixelsStack();
                m_pTextWindow->pushLineIndentAmtInPixelsStack(
                      curIndentAmtInPixels +
                      UNORDERED_LIST_INDENT_AMT);
                //Added the surrounding if() so that
                // this code doesn't get called if horizontal motion:
                if(m_pTextWindow->getCrawlRate() == 0  ||
                      m_pTextWindow->getScrollRate() != 0)
                {
                  BOOL bFollowsPosTag =
                        (bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag);
                  //Do a line break, but only if 0 line breaks so far,
                  // and not if there is no raw text yet, i.e., not if
                  // this <UL> tag starts the data part of the file,
                  // nor if a <CLEAR> tag was just sent:
                  if(!m_pTextWindow->getNumBreakTagsEncountered()  &&
//XXXXXEH-19980918>>
                        //C_RTRNDR_DIFF>>
                        (IsBeta1Player()  ||
                        //<<END C_RTRNDR_DIFF.
                        bFollowsPosTag  ||
                        (!m_pTextWindow->m_bClearWasJustSent  &&
                        m_pTextWindow->size()>0L)))
//<<XXXXXEH-19980918.
                  {
                      //If we got <pos ..>x<ul>, where "x" contains 
                      // no plain text (other than spaces, tabs,
                      // newlines), then don't do a line break at
                      // all, but DO add ORDERED_LIST_INDENT_AMT
                      // amount to the NewPktStartXAtTimeZero()
                      // value:
                      if(bFollowsPosTag  &&  !IsBeta1Player())
                      {
                        LONG32 lCurX = m_pTextWindow->
                              GetNewPktStartXAtTimeZero();
                        HX_ASSERT(INVALID_LONG32 != lCurX);
                        m_pTextWindow->
                              SetNewPktStartXAtTimeZero(
                              lCurX +
                              (UNORDERED_LIST_INDENT_AMT));
                      }
                      else
                      {
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                      }
                      bSomeCharsFoundSinceLastBreakTag=0L;
                  }
                }
            }
            break;


          default:
            break;
      }

      pData_CHAR[indexOfRightBracket] = '>'; //restore the char.
      
      startIndex = indexOfRightBracket+1; //where next tag-search starts.

    } while (startIndex < len);

    //C_RTRNDRDIFF >>:
    //Make sure we set the end byte of the last TextLine inserted (to the
    // last byte read in the file):
    TextLine* pTL_lastInserted = m_pTextWindow->m_pTLList->end();
    if(pTL_lastInserted)
    {
      pTL_lastInserted->
            setEndByteInFile(ulByteOffsetIntoFile+dataLength-1);
    }
    //<< END C_RTRNDRDIFF.
    
    
    return (bEarliestTimeOfNewDataIsValid ? HXR_OK:HXR_NOT_INITIALIZED);
} // end "TextParser::ParseText()".



// /If name isn't recognized, returns FALSE and charset_retVal is not valid:
HX_RESULT
TextParser::convertCharsetNameToCharsetULONG32(const char* pszCharsetName,
          ULONG32 ulCharsetNameLen,
          UINT16 uiMaxSupportedLevel,
          ULONG32& ulCharset_retVal /*OUT*/)
{
    HX_RESULT hxrslt = HXR_OK;

    ulCharset_retVal = CHARSET__default;

    if (!pszCharsetName  ||  ulCharsetNameLen < 1)
    {
      hxrslt = HXR_INVALID_PARAMETER;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen, 
          "us-ascii", 8) )
    {
      ulCharset_retVal = CHARSET__us_ascii;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-1", 10) )
    {
      ulCharset_retVal = CHARSET__us_ascii;
      if (uiMaxSupportedLevel > 0)
      {
          // /This is actually different from us-ascii in the upper-128
          // chars; us-ascii's upper-128 are undefined, and we handle these
          // 2 charsets better in level 1+ processing:
          ulCharset_retVal = CHARSET__iso_8859_1;
      }
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "mac-roman", 9) )
    {
      ulCharset_retVal = CHARSET__x_mac_roman;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-2022-jp", 11) )
    {
      ulCharset_retVal = CHARSET__iso_2022_jp;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "x-sjis", 6) )
    {
      ulCharset_retVal = CHARSET__x_sjis;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "euc-kr", 6) )
    {
      ulCharset_retVal = CHARSET__euc_kr;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "x-euc-jap", 9) )
    {
      ulCharset_retVal = CHARSET__x_euc_jap;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-2022-kr", 11) )
    {
      ulCharset_retVal = CHARSET__iso_2022_kr;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "big5", 4) )
    {
      ulCharset_retVal = CHARSET__big5;
    }
    else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "gb2312", 6) )
    {
      ulCharset_retVal = CHARSET__gb2312;
    }

    // /Extensions #1; only look for these if supported by the caller,
    // e.g., plain text in SMIL 2.0 supports these but RealText (1.6 and
    // earlier) does not.  Later versions of RT may or may not:
    else if (uiMaxSupportedLevel > 0)
    {
      if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-2", 10) )
      {
          ulCharset_retVal = CHARSET__iso_8859_2;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-5", 10) )
      {
          ulCharset_retVal = CHARSET__iso_8859_5;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-6", 10) )
      {
          ulCharset_retVal = CHARSET__iso_8859_6;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-7", 10) )
      {
          ulCharset_retVal = CHARSET__iso_8859_7;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-8", 10) )
      {
          ulCharset_retVal = CHARSET__iso_8859_8;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-9", 10) )
      {
          ulCharset_retVal = CHARSET__iso_8859_9;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-11", 11) )
      {
          ulCharset_retVal = CHARSET__iso_8859_11;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-8859-13", 11) )
      {
          ulCharset_retVal = CHARSET__iso_8859_13;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "windows-1251", 12) )
      {
          ulCharset_retVal = CHARSET__windows_1251;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "koi8-r", 6) )
      {
          ulCharset_retVal = CHARSET__koi8_r;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "iso-ir-166", 10) )
      {
          ulCharset_retVal = CHARSET__iso_ir_166;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "hangeul", 7) )
      {
          ulCharset_retVal = CHARSET__hangeul;
      }
      else if (!stringCompare(pszCharsetName, ulCharsetNameLen,
          "ksc5601", 7) )
      {
          ulCharset_retVal = CHARSET__ksc5601;
      }
      // /Here's where you'd add level 2, if new charsets are ever supported:
      else
      {
          hxrslt = HXR_FAILED;
      }
    }
    else
    {
      hxrslt = HXR_FAILED;
    }

    return hxrslt;
}

/////////////////////////////////////////////////////////////////////////////
// Method:
//  void TextParser::FindEscapeSequenceChar(...)
// Purpose:
//  This function searches for and handles HTML-style escape sequences that
//  start with '&' and end with ';', e.g., "&nbsp;" or "&#133;"
//
//  Looks for "&lt;" or "&gt;" and, if found, end the
//  TextContainer at the end of the "&lt;" or "&gt;" and replace
//  it with '<' or '>'; also, look for "&#n;"
//  (where n>8 && n<=255) and translate into the ASCII char
//  with that value, and look for "&nbsp;" for ' ' and "&amp;"
//  and replace with '&':
//
void TextParser::FindEscapeSequenceChar(_CHAR*& pCurText,
      ULONG32& ulIndexOfLastCharInTCsBuf,
      ULONG32& theFollowingSpaceCharIndex,
      ULONG32& ulIndexOfAmpersand,
      ULONG32& ulCurCharset)
{
    while(theFollowingSpaceCharIndex > ulIndexOfAmpersand  &&
          theFollowingSpaceCharIndex - ulIndexOfAmpersand >= 4)
    {                          //4 is strlen("&lt;") ^.
      _CHAR* pTmp= &pCurText[ulIndexOfAmpersand+1];
      ULONG32 ulStrlenSpecialChar = 1L;
      BOOL is_lt = FALSE;
      BOOL is_gt = FALSE;
      BOOL is_num = FALSE;
      BOOL is_amp = FALSE;
      BOOL is_nbsp = FALSE;
      _CHAR translatedChar = '\0';
      //Note from "http://www.ncsa.uiuc.edu/General/Internet/WWW/
      //  HTMLPrimerP2.html#ES":
      //  - "Unlike the rest of HTML, the escape sequences are case
      //     sensitive. You cannot, for instance, use &LT; instead
      //     of &lt;".
      // Thus we only need to check lower case possibilities:
      if((is_lt=('l'==*pTmp))  ||  (is_gt=('g'==*pTmp))  ||
            (is_num=('#'==*pTmp))  ||  (is_amp=('a'==*pTmp))  ||
            (is_nbsp=('n'==*pTmp)) )
      {
          pTmp++;
          ulStrlenSpecialChar++;
          INT32 num;
          if((is_lt  ||  is_gt)  &&  't'==*pTmp)
          {
            pTmp++;
            ulStrlenSpecialChar++;
            if(is_lt)
            {
                translatedChar = '<';
            }
            else if(is_gt)
            {
                translatedChar = '>';
            }
          }
          else if(is_amp  &&  'm'==*pTmp)
          {
            pTmp++;
            ulStrlenSpecialChar++;
            if('p' == *pTmp)
            {
                pTmp++;
                ulStrlenSpecialChar++;
                translatedChar = '&';
            }
          }
          else if(is_nbsp  &&  'b'==*pTmp)
          {
            pTmp++;
            ulStrlenSpecialChar++;
            if('s' == *pTmp)
            {
                pTmp++;
                ulStrlenSpecialChar++;
                if('p' == *pTmp)
                {
                  pTmp++;
                  ulStrlenSpecialChar++;
                  translatedChar = ' ';
                }
            }
          }
          else if(is_num  &&  
                (num = atoi(pTmp)) > 8) //#00 to #08 are unused.
          {
            //11, 12, 14-31, 127-159, and 256+ are also unused:
            if(num!=11  &&  num!=12  &&  !(num>=14  &&  num<=31)
                  &&  !(num>=127  && num<=159)  &&  num<=255)
            {
                INT32 numDigitsOf_num = 0;
                while(pTmp[numDigitsOf_num]>='0'  &&
                      pTmp[numDigitsOf_num]<='9')
                {
                  numDigitsOf_num++;
                }
                //Add the number of base-10 digits of num:
                pTmp += numDigitsOf_num; //XXXEH- DBCS-friendly??
                ulStrlenSpecialChar += (ULONG32)numDigitsOf_num;
                translatedChar = _CHAR(num);
            }
          }
          if(translatedChar)
          {
            if(';' == *pTmp)
            {
                ulStrlenSpecialChar++;

                pCurText[ulIndexOfAmpersand] = translatedChar;

                BOOL bWeHitEndOfBuff = FALSE;
                if(ulIndexOfLastCharInTCsBuf <=
                      ulStrlenSpecialChar + ulIndexOfAmpersand)
                {
                  bWeHitEndOfBuff = TRUE; //Fix for bug #6837.
                }

                ulIndexOfLastCharInTCsBuf = ulIndexOfAmpersand;

                //If space char ends the string, make sure it
                // still ends with space char:
                if(theFollowingSpaceCharIndex ==
                      ulIndexOfAmpersand + ulStrlenSpecialChar
                      //Fix for bug #6837:
                      &&  !bWeHitEndOfBuff)
                {
                  pCurText[ulIndexOfAmpersand+1] = ' ';
                  pCurText[ulIndexOfAmpersand+2] = '\0';
                  ulIndexOfLastCharInTCsBuf++;
                  ulStrlenSpecialChar++;
                }
                else
                {
                  pCurText[ulIndexOfAmpersand+1] = '\0';
                }
                theFollowingSpaceCharIndex =
                      ulIndexOfAmpersand+ulStrlenSpecialChar-1;
                break;
            }
          }
      }
      ulIndexOfAmpersand = findNextChar('&',
            pCurText,
            theFollowingSpaceCharIndex,
            //This is where in pCurText to
            // start searching for another '&':
            ulIndexOfAmpersand+ulStrlenSpecialChar,
            ulCurCharset);
    } //end "while(theFollowingSpaceCharIndex > ...)".
} // end "TextParser::FindEscapeSequenceChar()".




/////////////////////////////////////////////////////////////////////////////
// Method:
//  void TextParser::HandleEndTag(...)
// Purpose:
//  This function finds which, if any, valid end tag this is and handles the
//  "undoing" of the tag by popping the appropriate stack(s) and/or
//  resetting the appropriate state variables.
//
void TextParser::HandleEndTag(_CHAR* pTagContents, ULONG32 tagContentsLen,
      BOOL& bSomeCharsFoundSinceLastBreakTag,
      BOOL& bSomeCharsFoundSinceLastPosTag,
      BOOL& bUserPosTagFoundSinceLastTextContainer,
      ULONG32 ulByteOffsetIntoFile,
      LONG32 indexOfLeftBracket,
      LONG32 indexOfRightBracket,
      BOOL bFileFormatIsCallingThis)
{
    switch(pTagContents[1])
    {
      case 'A':   //is end of anchor tag:
          if(!stringCompare(pTagContents, tagContentsLen,
                "/A", 2)  &&
                //Don't do all the following unless this
                // was preceded by a valid <A HREF="foo">
                m_pTextWindow->hasValidURL())
          {
            m_pTextWindow->clearURL();
            if(bFileFormatIsCallingThis)
            {
                break;
            }
            //Don't do this @ File Format side; sending the <A > tag will
            //be enough for the renderer to know the <U> & <FONT color=> 
            //information it needs; (we don't want this duplicated in the
            //packet header now that packet headers include <A > tags):

            //Added the following to go
            // back to the pre-hyperlink text's font color:
            ////XXXEH- the following line was:
            //// popTextColorStack()
            ////but "<A ..><FONT size=+1>blah</FONT></A>"
            ////at the start of a packet would end up as:
            ////"<FONT size=+1><A ..>blah</FONT></A>" 
            ////(FONT and A get switched in the packet
            ////header) and the </FONT> ends up popping
            ////the color pushed by the <A > tag instead
            ////of popping the FONT size, and then the
            ////</A> pops the color again and all %#$!
            ////breaks loose.  This should be revisited!
            ////(See "BUGinHREFcolorDueTo...rtx"
            m_pTextWindow->popFontStack();
            if(m_pTextWindow->usingUnderlineHyperlinks())
            {
                m_pTextWindow->popIsUnderlinedStack();
            }
            //Added the following to
            // handle backing out after hyperlink text is done:
            ULONG32 numColorPushes = 
                  m_pTextWindow->
                  getNumberOfFontColorPushesInsideLinkText();
            for(; numColorPushes >0; numColorPushes--)
            {
                m_pTextWindow->popTextColorStack();
            }
            m_pTextWindow->
                  setNumberOfFontColorPushesInsideLinkText(0L);
          }
          break;

      case 'B':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/B", 2)) //end of bold tag
          {
            m_pTextWindow->popIsBoldStack();
          }
          break;

      case 'C':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/CENTER", 7))
          {   
            BOOL bSomethingWasPopped =
                  m_pTextWindow->popIsCenteredStack();
            //XXXEH- don't do this if() because we always want to do a
            // line break for a </CENTER> tag, even if it has no matching
            // <CENTER> tag, right?... (Fixes bug:
            // "BUG 2 at end-- unCENTER tag being ignored.rtx"):
            ///if(bSomethingWasPopped)
            {
                //Do a line break if this </CENTER> tag
                // has a matching (preceding) "<CENTER>",
                // but only if 0 line breaks so far:
                if(!m_pTextWindow->
                      getNumBreakTagsEncountered()  &&
                      !m_pTextWindow->m_bClearWasJustSent)
                {
                  //If we got <pos ..>x</center>, where "x" contains no
                  // plain text (other than spaces, tabs, newlines),
                  // then don't do a line break at all:
                  if(bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag)
                  {
                      ;
                  }
                  else
                  {
                      m_pTextWindow->
                            incrementNumBreakTagsEncountered();
                  }
                  bSomeCharsFoundSinceLastBreakTag=FALSE;
                }
            }
          }
          break;

      case 'F':
      {
          TextAttributes* pTA = NULL;
          if(bFileFormatIsCallingThis)
          {
            //pTA keeps track of what the
            // current font attributes are so that we can see
            // if this </FONT...> tag caused a change in any
            // of the font attribute values:
            pTA = new TextAttributes;
            HX_ASSERT_VALID_PTR(pTA);
            if(pTA)
            {
                pTA->setTextColor(m_pTextWindow->
                      peekAtTextColorStack());
                pTA->setTextBackgroundColor(m_pTextWindow->
                      peekAtTextBackgroundColorStack());
                pTA->setFontPointSize(m_pTextWindow->
                      peekAtPointSizeStack()); 
                pTA->setFontCharset(m_pTextWindow->
                      peekAtCharsetStack());
                pTA->setFontFace(m_pTextWindow->
                      peekAtFontFaceStack());
            }
          }

          if(!stringCompare(pTagContents, tagContentsLen,
                "/FONTSIZE", 9))
          {
            m_pTextWindow->popFontPointSizeStack();
          }
          else if(!stringCompare(pTagContents,
                tagContentsLen, "/FONTCOLOR", 10))
          {
            m_pTextWindow->popTextColorStack();
            //Added the following to see
            // if we're inside an <A> tag so that we can
            // properly back out font colors after hyperlink
            // text is done:
            if(m_pTextWindow->hasValidURL())
            {
                m_pTextWindow->
                      decrementNumberOfFontColorPushesInsideLinkText();
            }
          }
          else if(!stringCompare(pTagContents,
                tagContentsLen, "/FONTBGCOLOR", 12))
          {
            m_pTextWindow->popTextBackgroundColorStack();
          }
          else if(!stringCompare(pTagContents,
                tagContentsLen, "/FONTCHARSET", 12))
          {
            m_pTextWindow->popFontCharsetStack();
          }
          else if(!stringCompare(pTagContents,
                tagContentsLen, "/FONTFACE", 9))
          {
            m_pTextWindow->popFontFaceStack();
          }
          else if(!stringCompare(pTagContents,
                tagContentsLen, "/FONT", 5))
          {
            //pops the most recently-pushed value(s)
            // (size, color, ...etc):
            m_pTextWindow->popFontStack();
            //Added the following to
            // see if we're inside an <A> tag so that we
            // can properly back out font colors after
            // hyperlink text is done:
            if(m_pTextWindow->hasValidURL())
            {
                m_pTextWindow->
          decrementNumberOfFontColorPushesInsideLinkText();
            }
          }

          if(bFileFormatIsCallingThis)
          {
            //Now, see if any of the FONT attributes are diff
            // than they were before this "</FONT...>" tag,
            // and, if so, insert the changed-to values into
            // a new TextLine and insert that into the
            // m_pTextWindow->m_pFontUndoTagList:
            if(pTA  &&  m_pTextWindow->m_pFontUndoTagList)
            {
                //These are all "invalid" values that will
                // only be changed to "valid" ones if the
                // attribute changed as a result of the stack
                // "pop":
                ULONG32 ulFontPointSize = 0L;
                ULONG32 ulTextColor = BAD_RGB_COLOR;
                ULONG32 ulTextBGColor = BAD_RGB_COLOR;
                ULONG32 ulFontCharset = INVALID_CHARSET;
                ULONG32 ulFontFace = INVALID_FONT_INDEX;
                BOOL bSomethingChanged = FALSE;

    //XXXEH- Kludge: force all of them to be done for every </FONT>
    ulFontPointSize = m_pTextWindow->peekAtPointSizeStack();
    ulTextColor = m_pTextWindow->peekAtTextColorStack();
    ulTextBGColor = m_pTextWindow->peekAtTextBackgroundColorStack();
    ulFontCharset = m_pTextWindow->peekAtCharsetStack();
    ulFontFace = m_pTextWindow->peekAtFontFaceStack();

                if(pTA->getFontPointSize() != m_pTextWindow->
                      peekAtPointSizeStack()) 
                {
                  ulFontPointSize = m_pTextWindow->
                        peekAtPointSizeStack();
                  bSomethingChanged =TRUE;
                }
                if(pTA->getTextColor() != m_pTextWindow->
                      peekAtTextColorStack())
                {
                  ulTextColor = m_pTextWindow->
                        peekAtTextColorStack();
                  bSomethingChanged =TRUE;
                }
                if(pTA->getTextBackgroundColor() != 
                      m_pTextWindow->
                      peekAtTextBackgroundColorStack())
                {
                  ulTextBGColor = m_pTextWindow->
                        peekAtTextBackgroundColorStack();
                  bSomethingChanged =TRUE;
                }
                if(pTA->getFontCharset() != m_pTextWindow->
                      peekAtCharsetStack())
                {
                  ulFontCharset = m_pTextWindow->
                        peekAtCharsetStack();
                  bSomethingChanged =TRUE;
                }
                if(pTA->getFontFace() != m_pTextWindow->
                      peekAtFontFaceStack())
                {
                  ulFontFace = m_pTextWindow->
                        peekAtFontFaceStack();
                  bSomethingChanged =TRUE;
                }                   

                ///if(bSomethingChanged)
                {
                  TextLine* pTL = new TextLine(
                        ulByteOffsetIntoFile +
                              indexOfLeftBracket,
                        ulByteOffsetIntoFile +
                              indexOfRightBracket,
                        m_pTextWindow->
                        popFontTagStartByteInFileStack(),
                        ulFontPointSize,
                        ulTextColor,
                        ulTextBGColor,
                        ulFontCharset,
                        ulFontFace,
                        m_pTextWindow->getMajorContentVersion(),
                        m_pTextWindow->getMinorContentVersion());

                  HX_ASSERT_VALID_PTR(pTL);
                  if(NULL == pTL)
                  {
                      break;//Houston, We've had a problem.
                  }

                  pTL->setSomethingChanged(bSomethingChanged);

                  if(!m_pTextWindow->m_pFontUndoTagList->
                        insertAtEndOfList(pTL))
                  {
                      delete pTL;//insert failed: kill pTL.
                  }
                  else
                  {
                      // /Don't let the font undo stack grow beyond a
                      // certain size for live streams:
                      if (m_pTextWindow->isLiveSource()  &&
                            m_pTextWindow->m_pFontUndoTagList->
                            GetCount() >
                            MAX_LIVE_FONT_UNDO_STACK_DEPTH)
                      {
                        m_pTextWindow->m_pFontUndoTagList->RemoveHead();
                      }
                  }
                }
            }
            if(pTA)
            {
                delete pTA;
            }
          } //end "if(bFileFormatIsCallingThis)".
          break;
      }


      case 'I':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/I", 2)) //end of italics tag
          {
            m_pTextWindow->popIsItalicizedStack();
          }
          break;

      case 'L':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/LOOP", 5))
          {
            m_pTextWindow->loop(FALSE);
          }
          break;

      case 'O':
          //Added the following to allow better
          // handling of HTML text imported as RealText:
          //XXXEH- for now, treat as line break tag, but in future,
          // add indent based on depth of nested ULs and OLs:
          if(!stringCompare(pTagContents, tagContentsLen,
                "/OL", 3)) 
          {
            m_pTextWindow->popLineIndentAmtInPixelsStack();
            //Added the surrounding if() so that
            // this code doesn't get called if horizontal motion:
            if(m_pTextWindow->getCrawlRate() == 0  ||
                  m_pTextWindow->getScrollRate() != 0)
            {
                //only increment if 0 so far:
                if(!m_pTextWindow->getNumBreakTagsEncountered())
                {
                  //If we got <pos ..>x</ol>, where "x" contains no
                  // plain text (other than spaces, tabs, newlines),
                  // then don't do a line break at all:
                  if(bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag)
                  {
                      ;
                  }
                  else
                  {
                      m_pTextWindow->
                            incrementNumBreakTagsEncountered();
                  }
                  bSomeCharsFoundSinceLastBreakTag=FALSE;
                }
            }
          }
          break;

      
      case 'P':
          if(!stringCompare(pTagContents, tagContentsLen,
            "/P", 2)) //end of paragraph
          {
            //behaves same as <P>, namely 2 line breaks:

            //If we got <pos ..>x</p>, where "x" contains no
            // plain text (other than spaces, tabs, newlines),
            // then don't do a line break at all, but rather
            // update the NewPktStartYAtTimeZero() value:
            if(bUserPosTagFoundSinceLastTextContainer  &&
                  !bSomeCharsFoundSinceLastPosTag)
            {
                LONG32 lCurY =  m_pTextWindow->
                      GetNewPktStartYAtTimeZero();
                HX_ASSERT(INVALID_LONG32 != lCurY);
                m_pTextWindow->
                      SetNewPktStartYAtTimeZero(
                      lCurY + (2*DEFAULT_LINE_BREAK_SIZE));
            }
            else
            {
                m_pTextWindow->
                      incrementNumBreakTagsEncountered();
                m_pTextWindow->
                      incrementNumBreakTagsEncountered();
            }
            bSomeCharsFoundSinceLastBreakTag=FALSE;
          }
          else if(!stringCompare(pTagContents, tagContentsLen,
                "/PRE", 4)) //end of PRE-formatted text.
          {
            //Acts like a </P> tag as far as newlines go:

            //If we got <pos ..>x</pre>, where "x" contains no
            // plain text (other than spaces, tabs, newlines),
            // then don't do a line break at all:
            if(bUserPosTagFoundSinceLastTextContainer  &&
                  !bSomeCharsFoundSinceLastPosTag)
            {
                ;
            }
            else
            {
                m_pTextWindow->incrementNumBreakTagsEncountered();
                m_pTextWindow->incrementNumBreakTagsEncountered();
            }
            bSomeCharsFoundSinceLastBreakTag=FALSE;

            if(!m_pTextWindow->popIsPreStack())
            {
                break; //don't pop font, below, if has no matching <PRE>.
            }

            TextAttributes* pTA = NULL;
            if(bFileFormatIsCallingThis)
            {
                //pTA keeps track of what the
                // current font attributes are so that we can see
                // if this </FONT...> tag caused a change in any
                // of the font attribute values:
                pTA = new TextAttributes;
                HX_ASSERT_VALID_PTR(pTA);
                if(pTA)
                {
                  pTA->setTextColor(m_pTextWindow->
                        peekAtTextColorStack());
                  pTA->setTextBackgroundColor(m_pTextWindow->
                        peekAtTextBackgroundColorStack());
                  pTA->setFontPointSize(m_pTextWindow->
                        peekAtPointSizeStack()); 
                  pTA->setFontCharset(m_pTextWindow->
                        peekAtCharsetStack());
                  pTA->setFontFace(m_pTextWindow->
                        peekAtFontFaceStack());
                }
            }

            //pops the "courier" font-face that was pushed
            // onto the font stack when the matching <PRE> tag was
            // parsed UNLESS the author erroneously put some other
            // <FONT> tag in the text after the <PRE> and without a
            // matching </FONT>, in which case the following
            // will pop the most recently-pushed FONT tag's
            // value(s) (size, color, ...etc):
            m_pTextWindow->popFontStack();

            if(bFileFormatIsCallingThis)
            {
                //Now, see if any of the FONT attributes are diff
                // than they were before this "</FONT...>" tag,
                // and, if so, insert the changed-to values into
                // a new TextLine and insert that into the
                // m_pTextWindow->m_pFontUndoTagList:
                if(pTA  &&  m_pTextWindow->m_pFontUndoTagList)
                {
                  //These are all "invalid" values that will
                  // only be changed to "valid" ones if the
                  // attribute changed as a result of the stack
                  // "pop":
                  ULONG32 ulFontPointSize = 0L;
                  ULONG32 ulTextColor = BAD_RGB_COLOR;
                  ULONG32 ulTextBGColor = BAD_RGB_COLOR;
                  ULONG32 ulFontCharset = INVALID_CHARSET;
                  ULONG32 ulFontFace = INVALID_FONT_INDEX;
                  BOOL bSomethingChanged = FALSE;

      //XXXEH- Kludge: force all of them to be done for every </FONT>
      ulFontPointSize = m_pTextWindow->peekAtPointSizeStack();
      ulTextColor = m_pTextWindow->peekAtTextColorStack();
      ulTextBGColor = m_pTextWindow->peekAtTextBackgroundColorStack();
      ulFontCharset = m_pTextWindow->peekAtCharsetStack();
      ulFontFace = m_pTextWindow->peekAtFontFaceStack();

                  if(pTA->getFontPointSize() != m_pTextWindow->
                        peekAtPointSizeStack()) 
                  {
                      ulFontPointSize = m_pTextWindow->
                            peekAtPointSizeStack();
                      bSomethingChanged =TRUE;
                  }
                  if(pTA->getTextColor() != m_pTextWindow->
                        peekAtTextColorStack())
                  {
                      ulTextColor = m_pTextWindow->
                            peekAtTextColorStack();
                      bSomethingChanged =TRUE;
                  }
                  if(pTA->getTextBackgroundColor() != 
                        m_pTextWindow->
                        peekAtTextBackgroundColorStack())
                  {
                      ulTextBGColor = m_pTextWindow->
                            peekAtTextBackgroundColorStack();
                      bSomethingChanged =TRUE;
                  }
                  if(pTA->getFontCharset() != m_pTextWindow->
                        peekAtCharsetStack())
                  {
                      ulFontCharset = m_pTextWindow->
                            peekAtCharsetStack();
                      bSomethingChanged =TRUE;
                  }
                  if(pTA->getFontFace() != m_pTextWindow->
                        peekAtFontFaceStack())
                  {
                      ulFontFace = m_pTextWindow->
                            peekAtFontFaceStack();
                      bSomethingChanged =TRUE;
                  }                       

                  ///if(bSomethingChanged)
                  {
                      TextLine* pTL = new TextLine(
                            ulByteOffsetIntoFile +
                                  indexOfLeftBracket,
                            ulByteOffsetIntoFile +
                                  indexOfRightBracket,
                            m_pTextWindow->
                            popFontTagStartByteInFileStack(),
                            ulFontPointSize,
                            ulTextColor,
                            ulTextBGColor,
                            ulFontCharset,
                            ulFontFace,
                            m_pTextWindow->getMajorContentVersion(),
                            m_pTextWindow->getMinorContentVersion());

                      HX_ASSERT_VALID_PTR(pTL);
                      if(NULL == pTL)
                      {
                        break;//Houston, We've had a problem.
                      }

                      pTL->setSomethingChanged(bSomethingChanged);

                      if(!m_pTextWindow->m_pFontUndoTagList->
                            insertAtEndOfList(pTL))
                      {
                        delete pTL;//insert failed: kill pTL.
                      }
                      else
                      {
                        // /Don't let the font undo stack grow beyond a
                        // certain size for live streams:
                        if (m_pTextWindow->isLiveSource()  &&
                              m_pTextWindow->m_pFontUndoTagList->
                              GetCount() >
                              MAX_LIVE_FONT_UNDO_STACK_DEPTH)
                        {
                            m_pTextWindow->m_pFontUndoTagList->RemoveHead();
                        }
                      }
                  }
                }
                if(pTA)
                {
                  delete pTA;
                }
            } //end "if(bFileFormatIsCallingThis)".
          }
          break;

      case 'R':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/REQUIRED", 9))
          {
            m_pTextWindow->popIsRequiredStack();                  
          }
          break;
          
      case 'S':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/S", 2))//end of strike-out tag
          {
            m_pTextWindow->popIsStruckOutStack();
          }
          break;

      case 'T':
          //Added this to allow better
          // handling of HTML text imported as RealText:
          //XXXEH- for now, just treat as line break tag:
          if(!stringCompare(pTagContents, tagContentsLen,
                "/TABLE", 6)) 
          {
            //Added the surrounding
            // if() so that this code doesn't get
            // called if horizontal motion:
            if(m_pTextWindow->getCrawlRate() == 0  ||
                  m_pTextWindow->getScrollRate() != 0)
            {
                //If we got <pos ..>x</table>, where "x" contains no
                // plain text (other than spaces, tabs, newlines),
                // then don't do a line break at all:
                if(bUserPosTagFoundSinceLastTextContainer  &&
                      !bSomeCharsFoundSinceLastPosTag)
                {
                  ;
                }
                else
                {
                  m_pTextWindow->
                        incrementNumBreakTagsEncountered();
                }
                bSomeCharsFoundSinceLastBreakTag=FALSE;
            }
          }
          else if(!stringCompare(
                pTagContents, tagContentsLen,
                "/TU", 3) )
          {
            m_pTextWindow->isTickerUpperText(FALSE);
          }
          else if(!stringCompare(
                pTagContents, tagContentsLen,
                "/TL", 3) )
          {
            m_pTextWindow->isTickerUpperText(TRUE);
          }
          break;

      case 'U':
          if(!stringCompare(pTagContents, tagContentsLen,
                "/U", 2))//end of underlined tag
          {
            m_pTextWindow->popIsUnderlinedStack();
          }
          //Added the following to allow
          // better handling of HTML text imported as
          // RealText:
          //XXXEH- for now, treat as line break tag, but in
          // future, add indent based on depth of nested
          // ULs and OLs:
          if(!stringCompare(pTagContents, tagContentsLen,
                "/UL", 3)) 
          {
            m_pTextWindow->popLineIndentAmtInPixelsStack();
            //Added the surrounding if() so that
            // this code doesn't get called if horizontal motion:
            if(m_pTextWindow->getCrawlRate() == 0  ||
                  m_pTextWindow->getScrollRate() != 0)
            {
                //only increment if 0 so far:
                if(!m_pTextWindow->getNumBreakTagsEncountered())
                {
                  //If we got <pos ..>x</ul>, where "x" contains no
                  // plain text (other than spaces, tabs, newlines),
                  // then don't do a line break at all, but rather
                  // update the NewPktStartYAtTimeZero() value:
                  if(bUserPosTagFoundSinceLastTextContainer  &&
                        !bSomeCharsFoundSinceLastPosTag)
                  {
                      LONG32 lCurY =  m_pTextWindow->
                            GetNewPktStartYAtTimeZero();
                      HX_ASSERT(INVALID_LONG32 != lCurY);
                      m_pTextWindow->
                            SetNewPktStartYAtTimeZero(
                            lCurY + (DEFAULT_LINE_BREAK_SIZE));
                  }
                  else
                  {
                      //If we got <pos ..>x</table>, where "x" contains
                      // no plain text (other than spaces, tabs,
                      // newlines), then don't do a line break at all:
                      if(bUserPosTagFoundSinceLastTextContainer  &&
                            !bSomeCharsFoundSinceLastPosTag)
                      {
                        ;
                      }
                      else
                      {
                        m_pTextWindow->
                              incrementNumBreakTagsEncountered();
                      }
                  }
                  bSomeCharsFoundSinceLastBreakTag=FALSE;
                }
            }
          }
          break;

      default:
            break;
    } //end "switch(pTagContents[1])".
} //end TextParser::HandleEndTag().

Generated by  Doxygen 1.6.0   Back to index