LCOV - code coverage report
Current view: top level - svtools/source/svhtml - parhtml.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 481 940 51.2 %
Date: 2015-06-13 12:38:46 Functions: 21 31 67.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <ctype.h>
      22             : #include <comphelper/string.hxx>
      23             : #include <o3tl/ptr_container.hxx>
      24             : #include <tools/stream.hxx>
      25             : #include <tools/debug.hxx>
      26             : #include <tools/color.hxx>
      27             : #include <rtl/ustrbuf.hxx>
      28             : #include <rtl/strbuf.hxx>
      29             : 
      30             : #include <tools/tenccvt.hxx>
      31             : #include <tools/datetime.hxx>
      32             : #include <svl/inettype.hxx>
      33             : #include <com/sun/star/beans/PropertyAttribute.hpp>
      34             : #include <com/sun/star/document/XDocumentProperties.hpp>
      35             : 
      36             : #include <svtools/parhtml.hxx>
      37             : #include <svtools/htmltokn.h>
      38             : #include <svtools/htmlkywd.hxx>
      39             : 
      40             : #include <memory>
      41             : #include <utility>
      42             : 
      43             : using namespace ::com::sun::star;
      44             : 
      45             : 
      46             : const sal_Int32 MAX_LEN( 1024L );
      47             : 
      48             : const sal_Int32 MAX_ENTITY_LEN( 8L );
      49             : 
      50             : 
      51             : // Tables to convert option values into strings
      52             : 
      53             : // <INPUT TYPE=xxx>
      54             : static HTMLOptionEnum const aInputTypeOptEnums[] =
      55             : {
      56             :     { OOO_STRING_SVTOOLS_HTML_IT_text,      HTML_IT_TEXT        },
      57             :     { OOO_STRING_SVTOOLS_HTML_IT_password,  HTML_IT_PASSWORD    },
      58             :     { OOO_STRING_SVTOOLS_HTML_IT_checkbox,  HTML_IT_CHECKBOX    },
      59             :     { OOO_STRING_SVTOOLS_HTML_IT_radio,     HTML_IT_RADIO       },
      60             :     { OOO_STRING_SVTOOLS_HTML_IT_range,     HTML_IT_RANGE       },
      61             :     { OOO_STRING_SVTOOLS_HTML_IT_scribble,  HTML_IT_SCRIBBLE    },
      62             :     { OOO_STRING_SVTOOLS_HTML_IT_file,      HTML_IT_FILE        },
      63             :     { OOO_STRING_SVTOOLS_HTML_IT_hidden,    HTML_IT_HIDDEN      },
      64             :     { OOO_STRING_SVTOOLS_HTML_IT_submit,    HTML_IT_SUBMIT      },
      65             :     { OOO_STRING_SVTOOLS_HTML_IT_image,     HTML_IT_IMAGE       },
      66             :     { OOO_STRING_SVTOOLS_HTML_IT_reset,     HTML_IT_RESET       },
      67             :     { OOO_STRING_SVTOOLS_HTML_IT_button,    HTML_IT_BUTTON      },
      68             :     { 0,                    0                   }
      69             : };
      70             : 
      71             : // <TABLE FRAME=xxx>
      72             : static HTMLOptionEnum const aTableFrameOptEnums[] =
      73             : {
      74             :     { OOO_STRING_SVTOOLS_HTML_TF_void,  HTML_TF_VOID    },
      75             :     { OOO_STRING_SVTOOLS_HTML_TF_above, HTML_TF_ABOVE   },
      76             :     { OOO_STRING_SVTOOLS_HTML_TF_below, HTML_TF_BELOW   },
      77             :     { OOO_STRING_SVTOOLS_HTML_TF_hsides,    HTML_TF_HSIDES  },
      78             :     { OOO_STRING_SVTOOLS_HTML_TF_lhs,       HTML_TF_LHS     },
      79             :     { OOO_STRING_SVTOOLS_HTML_TF_rhs,       HTML_TF_RHS     },
      80             :     { OOO_STRING_SVTOOLS_HTML_TF_vsides,    HTML_TF_VSIDES  },
      81             :     { OOO_STRING_SVTOOLS_HTML_TF_box,       HTML_TF_BOX     },
      82             :     { OOO_STRING_SVTOOLS_HTML_TF_border,    HTML_TF_BOX     },
      83             :     { 0,                0               }
      84             : };
      85             : 
      86             : // <TABLE RULES=xxx>
      87             : static HTMLOptionEnum const aTableRulesOptEnums[] =
      88             : {
      89             :     { OOO_STRING_SVTOOLS_HTML_TR_none,  HTML_TR_NONE    },
      90             :     { OOO_STRING_SVTOOLS_HTML_TR_groups,    HTML_TR_GROUPS  },
      91             :     { OOO_STRING_SVTOOLS_HTML_TR_rows,  HTML_TR_ROWS    },
      92             :     { OOO_STRING_SVTOOLS_HTML_TR_cols,  HTML_TR_COLS    },
      93             :     { OOO_STRING_SVTOOLS_HTML_TR_all,       HTML_TR_ALL     },
      94             :     { 0,                0               }
      95             : };
      96             : 
      97          63 : sal_uInt16 HTMLOption::GetEnum( const HTMLOptionEnum *pOptEnums, sal_uInt16 nDflt ) const
      98             : {
      99          63 :     sal_uInt16 nValue = nDflt;
     100             : 
     101         157 :     while( pOptEnums->pName )
     102          93 :         if( aValue.equalsIgnoreAsciiCaseAscii( pOptEnums->pName ) )
     103          62 :             break;
     104             :         else
     105          31 :             pOptEnums++;
     106             : 
     107          63 :     if( pOptEnums->pName )
     108          62 :         nValue = pOptEnums->nValue;
     109             : 
     110          63 :     return nValue;
     111             : }
     112             : 
     113          40 : bool HTMLOption::GetEnum( sal_uInt16 &rEnum, const HTMLOptionEnum *pOptEnums ) const
     114             : {
     115         310 :     while( pOptEnums->pName )
     116             :     {
     117         263 :         if( aValue.equalsIgnoreAsciiCaseAscii( pOptEnums->pName ) )
     118          33 :             break;
     119             :         else
     120         230 :             pOptEnums++;
     121             :     }
     122             : 
     123          40 :     const sal_Char *pName = pOptEnums->pName;
     124          40 :     if( pName )
     125          33 :         rEnum = pOptEnums->nValue;
     126             : 
     127          40 :     return (pName != 0);
     128             : }
     129             : 
     130        1455 : HTMLOption::HTMLOption( sal_uInt16 nTok, const OUString& rToken,
     131             :                         const OUString& rValue )
     132             :     : aValue(rValue)
     133             :     , aToken(rToken)
     134        1455 :     , nToken( nTok )
     135             : {
     136             :     DBG_ASSERT( nToken>=HTML_OPTION_START && nToken<HTML_OPTION_END,
     137             :         "HTMLOption: unknown token" );
     138        1455 : }
     139             : 
     140         319 : sal_uInt32 HTMLOption::GetNumber() const
     141             : {
     142             :     DBG_ASSERT( (nToken>=HTML_OPTION_NUMBER_START &&
     143             :                  nToken<HTML_OPTION_NUMBER_END) ||
     144             :                 (nToken>=HTML_OPTION_CONTEXT_START &&
     145             :                  nToken<HTML_OPTION_CONTEXT_END) ||
     146             :                 nToken==HTML_O_VALUE,
     147             :         "GetNumber: Option not numerical" );
     148         319 :     OUString aTmp(comphelper::string::stripStart(aValue, ' '));
     149         319 :     sal_Int32 nTmp = aTmp.toInt32();
     150         319 :     return nTmp >= 0 ? (sal_uInt32)nTmp : 0;
     151             : }
     152             : 
     153           0 : sal_Int32 HTMLOption::GetSNumber() const
     154             : {
     155             :     DBG_ASSERT( (nToken>=HTML_OPTION_NUMBER_START && nToken<HTML_OPTION_NUMBER_END) ||
     156             :                 (nToken>=HTML_OPTION_CONTEXT_START && nToken<HTML_OPTION_CONTEXT_END),
     157             :         "GetSNumber: Option not numerical" );
     158           0 :     OUString aTmp(comphelper::string::stripStart(aValue, ' '));
     159           0 :     return aTmp.toInt32();
     160             : }
     161             : 
     162           0 : void HTMLOption::GetNumbers( std::vector<sal_uInt32> &rNumbers, bool bSpaceDelim ) const
     163             : {
     164           0 :     rNumbers.clear();
     165             : 
     166           0 :     if( bSpaceDelim )
     167             :     {
     168             :         // This is a very simplified scanner: it only searches all
     169             :         // numerals in the string.
     170           0 :         bool bInNum = false;
     171           0 :         sal_uLong nNum = 0;
     172           0 :         for( sal_Int32 i=0; i<aValue.getLength(); i++ )
     173             :         {
     174           0 :             sal_Unicode c = aValue[ i ];
     175           0 :             if( c>='0' && c<='9' )
     176             :             {
     177           0 :                 nNum *= 10;
     178           0 :                 nNum += (c - '0');
     179           0 :                 bInNum = true;
     180             :             }
     181           0 :             else if( bInNum )
     182             :             {
     183           0 :                 rNumbers.push_back( nNum );
     184           0 :                 bInNum = false;
     185           0 :                 nNum = 0;
     186             :             }
     187             :         }
     188           0 :         if( bInNum )
     189             :         {
     190           0 :             rNumbers.push_back( nNum );
     191             :         }
     192             :     }
     193             :     else
     194             :     {
     195             :         // Check whether numbers are separated by ',' and
     196             :         // insert 0 if necessary
     197           0 :         sal_Int32 nPos = 0;
     198           0 :         while( nPos < aValue.getLength() )
     199             :         {
     200             :             sal_Unicode c;
     201           0 :             while( nPos < aValue.getLength() &&
     202           0 :                    ((c=aValue[nPos]) == ' ' || c == '\t' ||
     203           0 :                    c == '\n' || c== '\r' ) )
     204           0 :                 nPos++;
     205             : 
     206           0 :             if( nPos==aValue.getLength() )
     207           0 :                 rNumbers.push_back(0);
     208             :             else
     209             :             {
     210           0 :                 sal_Int32 nEnd = aValue.indexOf( (sal_Unicode)',', nPos );
     211           0 :                 if( -1 == nEnd )
     212             :                 {
     213           0 :                     sal_Int32 nTmp = aValue.copy(nPos).toInt32();
     214           0 :                     rNumbers.push_back( nTmp >= 0 ? (sal_uInt32)nTmp : 0 );
     215           0 :                     nPos = aValue.getLength();
     216             :                 }
     217             :                 else
     218             :                 {
     219           0 :                     sal_Int32 nTmp = aValue.copy(nPos,nEnd-nPos).toInt32();
     220           0 :                     rNumbers.push_back( nTmp >= 0 ? (sal_uInt32)nTmp : 0 );
     221           0 :                     nPos = nEnd+1;
     222             :                 }
     223             :             }
     224             :         }
     225             :     }
     226           0 : }
     227             : 
     228         277 : void HTMLOption::GetColor( Color& rColor ) const
     229             : {
     230             :     DBG_ASSERT( (nToken>=HTML_OPTION_COLOR_START && nToken<HTML_OPTION_COLOR_END) || nToken==HTML_O_SIZE,
     231             :         "GetColor: Option is not a color." );
     232             : 
     233         277 :     OUString aTmp(aValue.toAsciiLowerCase());
     234         277 :     sal_uInt32 nColor = SAL_MAX_UINT32;
     235         277 :     if (!aTmp.isEmpty() && aTmp[0] != '#')
     236           0 :         nColor = GetHTMLColor(aTmp);
     237             : 
     238         277 :     if( SAL_MAX_UINT32 == nColor )
     239             :     {
     240         277 :         nColor = 0;
     241         277 :         sal_Int32 nPos = 0;
     242        1939 :         for (sal_uInt32 i=0; i<6; ++i)
     243             :         {
     244             :             // Whatever Netscape does to get color values,
     245             :             // at maximum three characters < '0' are ignored.
     246        1662 :             sal_Unicode c = nPos<aTmp.getLength() ? aTmp[ nPos++ ] : '0';
     247        1662 :             if( c < '0' )
     248             :             {
     249         277 :                 c = nPos<aTmp.getLength() ? aTmp[nPos++] : '0';
     250         277 :                 if( c < '0' )
     251           0 :                     c = nPos<aTmp.getLength() ? aTmp[nPos++] : '0';
     252             :             }
     253        1662 :             nColor *= 16;
     254        1662 :             if( c >= '0' && c <= '9' )
     255         122 :                 nColor += (c - '0');
     256        1540 :             else if( c >= 'a' && c <= 'f' )
     257        1540 :                 nColor += (c + 0xa - 'a');
     258             :         }
     259             :     }
     260             : 
     261         277 :     rColor.SetRed(   (sal_uInt8)((nColor & 0x00ff0000) >> 16) );
     262         277 :     rColor.SetGreen( (sal_uInt8)((nColor & 0x0000ff00) >> 8));
     263         277 :     rColor.SetBlue(  (sal_uInt8)(nColor & 0x000000ff) );
     264         277 : }
     265             : 
     266           4 : HTMLInputType HTMLOption::GetInputType() const
     267             : {
     268             :     DBG_ASSERT( nToken==HTML_O_TYPE, "GetInputType: Option not TYPE" );
     269           4 :     return (HTMLInputType)GetEnum( aInputTypeOptEnums, HTML_IT_TEXT );
     270             : }
     271             : 
     272           0 : HTMLTableFrame HTMLOption::GetTableFrame() const
     273             : {
     274             :     DBG_ASSERT( nToken==HTML_O_FRAME, "GetTableFrame: Option not FRAME" );
     275           0 :     return (HTMLTableFrame)GetEnum( aTableFrameOptEnums, HTML_TF_VOID );
     276             : }
     277             : 
     278           0 : HTMLTableRules HTMLOption::GetTableRules() const
     279             : {
     280             :     DBG_ASSERT( nToken==HTML_O_RULES, "GetTableRules: Option not RULES" );
     281           0 :     return (HTMLTableRules)GetEnum( aTableRulesOptEnums, HTML_TR_NONE );
     282             : }
     283             : 
     284          17 : HTMLParser::HTMLParser( SvStream& rIn, bool bReadNewDoc ) :
     285             :     SvParser( rIn ),
     286             :     bNewDoc(bReadNewDoc),
     287             :     bIsInHeader(true),
     288             :     bIsInBody(false),
     289             :     bReadListing(false),
     290             :     bReadXMP(false),
     291             :     bReadPRE(false),
     292             :     bReadTextArea(false),
     293             :     bReadScript(false),
     294             :     bReadStyle(false),
     295             :     bEndTokenFound(false),
     296             :     bPre_IgnoreNewPara(false),
     297             :     bReadNextChar(false),
     298             :     bReadComment(false),
     299             :     nPre_LinePos(0),
     300          17 :     mnPendingOffToken(0)
     301             : {
     302             :     //#i76649, default to UTF-8 for HTML unless we know differently
     303          17 :     SetSrcEncoding(RTL_TEXTENCODING_UTF8);
     304          17 : }
     305             : 
     306          17 : HTMLParser::~HTMLParser()
     307             : {
     308          17 : }
     309             : 
     310          17 : SvParserState HTMLParser::CallParser()
     311             : {
     312          17 :     eState = SVPAR_WORKING;
     313          17 :     nNextCh = GetNextChar();
     314          17 :     SaveState( 0 );
     315             : 
     316          17 :     nPre_LinePos = 0;
     317          17 :     bPre_IgnoreNewPara = false;
     318             : 
     319          17 :     AddFirstRef();
     320          17 :     Continue( 0 );
     321          17 :     if( SVPAR_PENDING != eState )
     322          17 :         ReleaseRef();       // Parser not needed anymore
     323             : 
     324          17 :     return eState;
     325             : }
     326             : 
     327          17 : void HTMLParser::Continue( int nToken )
     328             : {
     329          17 :     if( !nToken )
     330          17 :         nToken = GetNextToken();
     331             : 
     332         744 :     while( IsParserWorking() )
     333             :     {
     334         710 :         SaveState( nToken );
     335         710 :         nToken = FilterToken( nToken );
     336             : 
     337         710 :         if( nToken )
     338         694 :             NextToken( nToken );
     339             : 
     340         710 :         if( IsParserWorking() )
     341         710 :             SaveState( 0 );         // continue with new token
     342             : 
     343         710 :         nToken = GetNextToken();
     344             :     }
     345          17 : }
     346             : 
     347        3496 : int HTMLParser::FilterToken( int nToken )
     348             : {
     349        3496 :     switch( nToken )
     350             :     {
     351             :     case sal_Unicode(EOF):
     352           0 :         nToken = 0;
     353           0 :         break;          // don't pass
     354             : 
     355             :     case HTML_HEAD_OFF:
     356          13 :         bIsInBody = true;
     357          13 :         bIsInHeader = false;
     358          13 :         break;
     359             : 
     360             :     case HTML_HEAD_ON:
     361          13 :         bIsInHeader = true;
     362          13 :         break;
     363             : 
     364             :     case HTML_BODY_ON:
     365          16 :         bIsInHeader = false;
     366          16 :         bIsInBody = true;
     367          16 :         break;
     368             : 
     369             :     case HTML_FRAMESET_ON:
     370           0 :         bIsInHeader = false;
     371           0 :         bIsInBody = false;
     372           0 :         break;
     373             : 
     374             :     case HTML_BODY_OFF:
     375          16 :         bIsInBody = bReadPRE = bReadListing = bReadXMP = false;
     376          16 :         break;
     377             : 
     378             :     case HTML_HTML_OFF:
     379          16 :         nToken = 0;
     380          16 :         bReadPRE = bReadListing = bReadXMP = false;
     381          16 :         break;      // HTML_ON hasn't been passed either !
     382             : 
     383             :     case HTML_PREFORMTXT_ON:
     384           0 :         StartPRE();
     385           0 :         break;
     386             : 
     387             :     case HTML_PREFORMTXT_OFF:
     388           0 :         FinishPRE();
     389           0 :         break;
     390             : 
     391             :     case HTML_LISTING_ON:
     392           0 :         StartListing();
     393           0 :         break;
     394             : 
     395             :     case HTML_LISTING_OFF:
     396           0 :         FinishListing();
     397           0 :         break;
     398             : 
     399             :     case HTML_XMP_ON:
     400           0 :         StartXMP();
     401           0 :         break;
     402             : 
     403             :     case HTML_XMP_OFF:
     404           0 :         FinishXMP();
     405           0 :         break;
     406             : 
     407             :     default:
     408        3422 :         if( bReadPRE )
     409           0 :             nToken = FilterPRE( nToken );
     410        3422 :         else if( bReadListing )
     411           0 :             nToken = FilterListing( nToken );
     412        3422 :         else if( bReadXMP )
     413           0 :             nToken = FilterXMP( nToken );
     414             : 
     415        3422 :         break;
     416             :     }
     417             : 
     418        3496 :     return nToken;
     419             : }
     420             : 
     421             : #define HTML_ISDIGIT( c ) comphelper::string::isdigitAscii(c)
     422             : #define HTML_ISALPHA( c ) comphelper::string::isalphaAscii(c)
     423             : #define HTML_ISALNUM( c ) comphelper::string::isalnumAscii(c)
     424             : #define HTML_ISSPACE( c ) ( ' ' == c || (c >= 0x09 && c <= 0x0d) )
     425             : #define HTML_ISPRINTABLE( c ) ( c >= 32 && c != 127)
     426             : #define HTML_ISHEXDIGIT( c ) comphelper::string::isxdigitAscii(c)
     427             : 
     428        2517 : int HTMLParser::ScanText( const sal_Unicode cBreak )
     429             : {
     430        2517 :     OUStringBuffer sTmpBuffer( MAX_LEN );
     431        2517 :     bool bContinue = true;
     432        2517 :     bool bEqSignFound = false;
     433        2517 :     sal_Unicode cQuote = 0U;
     434             : 
     435       30431 :     while( bContinue && IsParserWorking() )
     436             :     {
     437       25406 :         bool bNextCh = true;
     438       25406 :         switch( nNextCh )
     439             :         {
     440             :         case '&':
     441           0 :             bEqSignFound = false;
     442           0 :             if( bReadXMP )
     443           0 :                 sTmpBuffer.append( '&' );
     444             :             else
     445             :             {
     446           0 :                 sal_uLong nStreamPos = rInput.Tell();
     447           0 :                 sal_uLong nLinePos = GetLinePos();
     448             : 
     449           0 :                 sal_Unicode cChar = 0U;
     450           0 :                 if( '#' == (nNextCh = GetNextChar()) )
     451             :                 {
     452           0 :                     nNextCh = GetNextChar();
     453           0 :                     const bool bIsHex( 'x' == nNextCh );
     454           0 :                     const bool bIsDecOrHex( bIsHex || HTML_ISDIGIT(nNextCh) );
     455           0 :                     if ( bIsDecOrHex )
     456             :                     {
     457           0 :                         if ( bIsHex )
     458             :                         {
     459           0 :                             nNextCh = GetNextChar();
     460           0 :                             while ( HTML_ISHEXDIGIT(nNextCh) )
     461             :                             {
     462             :                                 cChar = cChar * 16U +
     463           0 :                                         ( nNextCh <= '9'
     464             :                                           ? sal_Unicode( nNextCh - '0' )
     465           0 :                                           : ( nNextCh <= 'F'
     466             :                                               ? sal_Unicode( nNextCh - 'A' + 10 )
     467           0 :                                               : sal_Unicode( nNextCh - 'a' + 10 ) ) );
     468           0 :                                 nNextCh = GetNextChar();
     469             :                             }
     470             :                         }
     471             :                         else
     472             :                         {
     473           0 :                             do
     474             :                             {
     475           0 :                                 cChar = cChar * 10U + sal_Unicode( nNextCh - '0');
     476           0 :                                 nNextCh = GetNextChar();
     477             :                             }
     478           0 :                             while( HTML_ISDIGIT(nNextCh) );
     479             :                         }
     480             : 
     481           0 :                         if( RTL_TEXTENCODING_DONTKNOW != eSrcEnc &&
     482           0 :                             RTL_TEXTENCODING_UCS2 != eSrcEnc &&
     483           0 :                             RTL_TEXTENCODING_UTF8 != eSrcEnc &&
     484             :                             cChar < 256 )
     485             :                         {
     486             :                             const sal_uInt32 convertFlags =
     487             :                                 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
     488             :                                 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
     489           0 :                                 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT;
     490             : 
     491           0 :                             sal_Char cEncodedChar = static_cast<sal_Char>(cChar);
     492           0 :                             cChar = OUString(&cEncodedChar, 1, eSrcEnc, convertFlags).toChar();
     493           0 :                             if( 0U == cChar )
     494             :                             {
     495             :                                 // If the character could not be
     496             :                                 // converted, because a conversion is not
     497             :                                 // available, do no conversion at all.
     498           0 :                                 cChar = cEncodedChar;
     499             :                             }
     500             :                         }
     501             :                     }
     502             :                     else
     503           0 :                         nNextCh = 0U;
     504             :                 }
     505           0 :                 else if( HTML_ISALPHA( nNextCh ) )
     506             :                 {
     507           0 :                     OUStringBuffer sEntityBuffer( MAX_ENTITY_LEN );
     508           0 :                     sal_Int32 nPos = 0L;
     509           0 :                     do
     510             :                     {
     511           0 :                         sEntityBuffer.append( nNextCh );
     512           0 :                         nPos++;
     513           0 :                         nNextCh = GetNextChar();
     514             :                     }
     515           0 :                     while( nPos < MAX_ENTITY_LEN && HTML_ISALNUM( nNextCh ) &&
     516           0 :                            !rInput.IsEof() );
     517             : 
     518           0 :                     if( IsParserWorking() && !rInput.IsEof() )
     519             :                     {
     520           0 :                         OUString sEntity(sEntityBuffer.getStr(), nPos);
     521           0 :                         cChar = GetHTMLCharName( sEntity );
     522             : 
     523             :                         // not found ( == 0 ): plain text
     524             :                         // or a character which is inserted as attribute
     525           0 :                         if( 0U == cChar && ';' != nNextCh )
     526             :                         {
     527             :                             DBG_ASSERT( rInput.Tell() - nStreamPos ==
     528             :                                         (sal_uLong)(nPos+1L)*GetCharSize(),
     529             :                                         "UTF-8 is failing here" );
     530           0 :                             for( sal_Int32 i = nPos-1; i>1; i-- )
     531             :                             {
     532           0 :                                 nNextCh = sEntityBuffer[i];
     533           0 :                                 sEntityBuffer.setLength( i );
     534           0 :                                 sEntity = OUString(sEntityBuffer.getStr(), i);
     535           0 :                                 cChar = GetHTMLCharName( sEntity );
     536           0 :                                 if( cChar )
     537             :                                 {
     538             :                                     rInput.SeekRel( -(long)
     539           0 :                                             ((nPos-i)*GetCharSize()) );
     540           0 :                                     nlLinePos -= sal_uInt32(nPos-i);
     541           0 :                                     nPos = i;
     542           0 :                                     ClearTxtConvContext();
     543           0 :                                     break;
     544             :                                 }
     545             :                             }
     546             :                         }
     547             : 
     548           0 :                         if( !cChar )        // unknown character?
     549             :                         {
     550             :                             // back in stream, insert '&'
     551             :                             // and restart with next character
     552           0 :                             sTmpBuffer.append( '&' );
     553             : 
     554             :                             DBG_ASSERT( rInput.Tell()-nStreamPos ==
     555             :                                         (sal_uLong)(nPos+1)*GetCharSize(),
     556             :                                         "Wrong stream position" );
     557             :                             DBG_ASSERT( nlLinePos-nLinePos ==
     558             :                                         (sal_uLong)(nPos+1),
     559             :                                         "Wrong line position" );
     560           0 :                             rInput.Seek( nStreamPos );
     561           0 :                             nlLinePos = nLinePos;
     562           0 :                             ClearTxtConvContext();
     563           0 :                             break;
     564             :                         }
     565             : 
     566             :                         assert(cChar != 0);
     567             : 
     568             :                         // 1 == Non Breaking Space
     569             :                         // 2 == SoftHyphen
     570             : 
     571           0 :                         if (cChar == 1 || cChar == 2)
     572             :                         {
     573           0 :                             if( '>' == cBreak )
     574             :                             {
     575             :                                 // When reading the content of a tag we have
     576             :                                 // to change it to ' ' or '-'
     577           0 :                                 if( 1U == cChar )
     578           0 :                                     cChar = ' ';
     579             :                                 else //2U
     580           0 :                                     cChar = '-';
     581             :                             }
     582             :                             else
     583             :                             {
     584             :                                 // If not scanning a tag return token
     585           0 :                                 aToken += sTmpBuffer.makeStringAndClear();
     586             : 
     587           0 :                                 if( !aToken.isEmpty() )
     588             :                                 {
     589             :                                     // restart with character
     590           0 :                                     nNextCh = '&';
     591             :                                     DBG_ASSERT( rInput.Tell()-nStreamPos ==
     592             :                                                 (sal_uLong)(nPos+1)*GetCharSize(),
     593             :                                                 "Wrong stream position" );
     594             :                                     DBG_ASSERT( nlLinePos-nLinePos ==
     595             :                                                 (sal_uLong)(nPos+1),
     596             :                                                 "Wrong line position" );
     597           0 :                                     rInput.Seek( nStreamPos );
     598           0 :                                     nlLinePos = nLinePos;
     599           0 :                                     ClearTxtConvContext();
     600           0 :                                     return HTML_TEXTTOKEN;
     601             :                                 }
     602             : 
     603             :                                 // Hack: _GetNextChar shall not read the
     604             :                                 // next character
     605           0 :                                 if( ';' != nNextCh )
     606           0 :                                     aToken += " ";
     607           0 :                                 if( 1U == cChar )
     608           0 :                                     return HTML_NONBREAKSPACE;
     609             :                                 else //2U
     610           0 :                                     return HTML_SOFTHYPH;
     611             :                             }
     612           0 :                         }
     613             :                     }
     614             :                     else
     615           0 :                         nNextCh = 0U;
     616             :                 }
     617             :                 // &{...};-JavaScript-Macros are not supported any longer.
     618           0 :                 else if( IsParserWorking() )
     619             :                 {
     620           0 :                     sTmpBuffer.append( '&' );
     621           0 :                     bNextCh = false;
     622           0 :                     break;
     623             :                 }
     624             : 
     625           0 :                 bNextCh = (';' == nNextCh);
     626           0 :                 if( cBreak=='>' && (cChar=='\\' || cChar=='\'' ||
     627           0 :                                     cChar=='\"' || cChar==' ') )
     628             :                 {
     629             :                     // ' and " have to be escaped within tags to separate
     630             :                     // them from ' and " enclosing options.
     631             :                     // \ has to be escaped as well.
     632             :                     // Space is protected because it's not a delimiter between
     633             :                     // options.
     634           0 :                     sTmpBuffer.append( '\\' );
     635           0 :                     if( MAX_LEN == sTmpBuffer.getLength() )
     636           0 :                         aToken += sTmpBuffer.makeStringAndClear();
     637             :                 }
     638           0 :                 if( IsParserWorking() )
     639             :                 {
     640           0 :                     if( cChar )
     641           0 :                         sTmpBuffer.append( cChar );
     642             :                 }
     643           0 :                 else if( SVPAR_PENDING==eState && '>'!=cBreak )
     644             :                 {
     645             :                     // Restart with '&', the remainder is returned as
     646             :                     // text token.
     647           0 :                     if( !aToken.isEmpty() || !sTmpBuffer.isEmpty() )
     648             :                     {
     649             :                         // _GetNextChar() returns the previous text and
     650             :                         // during the next execution a new character is read.
     651             :                         // Thus we have to position in front of the '&'.
     652           0 :                         nNextCh = 0U;
     653           0 :                         rInput.Seek( nStreamPos-(sal_uInt32)GetCharSize() );
     654           0 :                         nlLinePos = nLinePos-1;
     655           0 :                         ClearTxtConvContext();
     656           0 :                         bReadNextChar = true;
     657             :                     }
     658           0 :                     bNextCh = false;
     659             :                 }
     660             :             }
     661           0 :             break;
     662             :         case '=':
     663        1473 :             if( '>'==cBreak && !cQuote )
     664        1461 :                 bEqSignFound = true;
     665        1473 :             sTmpBuffer.append( nNextCh );
     666        1473 :             break;
     667             : 
     668             :         case '\\':
     669           0 :             if( '>'==cBreak )
     670             :             {
     671             :                 // Innerhalb von Tags kennzeichnen
     672           0 :                 sTmpBuffer.append( '\\' );
     673           0 :                 if( MAX_LEN == sTmpBuffer.getLength() )
     674           0 :                     aToken += sTmpBuffer.makeStringAndClear();
     675             :             }
     676           0 :             sTmpBuffer.append( '\\' );
     677           0 :             break;
     678             : 
     679             :         case '\"':
     680             :         case '\'':
     681        2941 :             if( '>'==cBreak )
     682             :             {
     683        2940 :                 if( bEqSignFound )
     684        1459 :                     cQuote = nNextCh;
     685        1481 :                 else if( cQuote && (cQuote==nNextCh ) )
     686        1459 :                     cQuote = 0U;
     687             :             }
     688        2941 :             sTmpBuffer.append( nNextCh );
     689        2941 :             bEqSignFound = false;
     690        2941 :             break;
     691             : 
     692             :         case sal_Unicode(EOF):
     693           0 :             if( rInput.IsEof() )
     694             :             {
     695           0 :                 bContinue = false;
     696             :             }
     697             :             else
     698             :             {
     699           0 :                 sTmpBuffer.append( nNextCh );
     700             :             }
     701           0 :             break;
     702             : 
     703             :         case '<':
     704        1493 :             bEqSignFound = false;
     705        1493 :             if( '>'==cBreak )
     706           0 :                 sTmpBuffer.append( nNextCh );
     707             :             else
     708        1493 :                 bContinue = false;      // break, String zusammen
     709        1493 :             break;
     710             : 
     711             :         case '\f':
     712           0 :             if( '>' == cBreak )
     713             :             {
     714             :                 // If scanning options treat it like a space, ...
     715           0 :                 sTmpBuffer.append( ' ' );
     716             :             }
     717             :             else
     718             :             {
     719             :                 // otherwise it's a separate token.
     720           0 :                 bContinue = false;
     721             :             }
     722           0 :             break;
     723             : 
     724             :         case '\r':
     725             :         case '\n':
     726        1465 :             if( '>'==cBreak )
     727             :             {
     728             :                 // cr/lf in tag is handled in _GetNextToken()
     729           4 :                 sTmpBuffer.append( nNextCh );
     730           4 :                 break;
     731             :             }
     732        1461 :             else if( bReadListing || bReadXMP || bReadPRE || bReadTextArea )
     733             :             {
     734           0 :                 bContinue = false;
     735           0 :                 break;
     736             :             }
     737             :             // Reduce sequence of CR/LF/BLANK/TAB to a single blank
     738             :             // no break!!
     739             :         case '\t':
     740        1474 :             if( '\t'==nNextCh && bReadPRE && '>'!=cBreak )
     741             :             {
     742             :                 // Pass Tabs up in <PRE>
     743           0 :                 bContinue = false;
     744           0 :                 break;
     745             :             }
     746             :             // no break
     747             :         case '\x0b':
     748        1474 :             if( '\x0b'==nNextCh && (bReadPRE || bReadXMP ||bReadListing) &&
     749             :                 '>'!=cBreak )
     750             :             {
     751           0 :                 break;
     752             :             }
     753        1474 :             nNextCh = ' ';
     754             :             // no break;
     755             :         case ' ':
     756        5339 :             sTmpBuffer.append( nNextCh );
     757        6837 :             if( '>'!=cBreak && (!bReadListing && !bReadXMP &&
     758        2996 :                                 !bReadPRE && !bReadTextArea) )
     759             :             {
     760             :                 // Reduce sequences of Blanks/Tabs/CR/LF to a single blank
     761        5346 :                 do {
     762        5364 :                     if( sal_Unicode(EOF) == (nNextCh = GetNextChar()) &&
     763           9 :                         rInput.IsEof() )
     764             :                     {
     765           9 :                         if( !aToken.isEmpty() || sTmpBuffer.getLength() > 1L )
     766             :                         {
     767             :                             // Have seen s.th. aside from blanks?
     768           0 :                             aToken += sTmpBuffer.makeStringAndClear();
     769           0 :                             return HTML_TEXTTOKEN;
     770             :                         }
     771             :                         else
     772             :                             // Only read blanks: no text must be returned
     773             :                             // and _GetNextToken has to read until EOF
     774           9 :                             return 0;
     775             :                     }
     776       11845 :                 } while ( ' ' == nNextCh || '\t' == nNextCh ||
     777        5041 :                           '\r' == nNextCh || '\n' == nNextCh ||
     778        1489 :                           '\x0b' == nNextCh );
     779        1489 :                 bNextCh = false;
     780             :             }
     781        5330 :             break;
     782             : 
     783             :         default:
     784       14156 :             bEqSignFound = false;
     785       14156 :             if (nNextCh == cBreak && !cQuote)
     786        1015 :                 bContinue = false;
     787             :             else
     788             :             {
     789       74019 :                 do {
     790             :                     // All remaining characters make their way into the text.
     791       74019 :                     sTmpBuffer.append( nNextCh );
     792       74019 :                     if( MAX_LEN == sTmpBuffer.getLength() )
     793             :                     {
     794          27 :                         aToken += sTmpBuffer.makeStringAndClear();
     795             :                     }
     796      222057 :                     if( ( sal_Unicode(EOF) == (nNextCh = GetNextChar()) &&
     797      222057 :                           rInput.IsEof() ) ||
     798       74019 :                         !IsParserWorking() )
     799             :                     {
     800           0 :                         if( !sTmpBuffer.isEmpty() )
     801           0 :                             aToken += sTmpBuffer.makeStringAndClear();
     802           0 :                         return HTML_TEXTTOKEN;
     803             :                     }
     804       74019 :                 } while( HTML_ISALPHA( nNextCh ) || HTML_ISDIGIT( nNextCh ) );
     805       13141 :                 bNextCh = false;
     806             :             }
     807             :         }
     808             : 
     809       25397 :         if( MAX_LEN == sTmpBuffer.getLength() )
     810           0 :             aToken += sTmpBuffer.makeStringAndClear();
     811             : 
     812       25397 :         if( bContinue && bNextCh )
     813        8259 :             nNextCh = GetNextChar();
     814             :     }
     815             : 
     816        2508 :     if( !sTmpBuffer.isEmpty() )
     817        2508 :         aToken += sTmpBuffer.makeStringAndClear();
     818             : 
     819        2508 :     return HTML_TEXTTOKEN;
     820             : }
     821             : 
     822         118 : int HTMLParser::_GetNextRawToken()
     823             : {
     824         118 :     OUStringBuffer sTmpBuffer( MAX_LEN );
     825             : 
     826         118 :     if( bEndTokenFound )
     827             :     {
     828             :         // During the last execution we already found the end token,
     829             :         // thus we don't have to search it again.
     830          12 :         bReadScript = false;
     831          12 :         bReadStyle = false;
     832          12 :         aEndToken.clear();
     833          12 :         bEndTokenFound = false;
     834             : 
     835          12 :         return 0;
     836             :     }
     837             : 
     838             :     // Default return value: HTML_RAWDATA
     839         106 :     bool bContinue = true;
     840         106 :     int nToken = HTML_RAWDATA;
     841         106 :     SaveState( 0 );
     842        2611 :     while( bContinue && IsParserWorking() )
     843             :     {
     844        2399 :         bool bNextCh = true;
     845        2399 :         switch( nNextCh )
     846             :         {
     847             :         case '<':
     848             :             {
     849             :                 // Maybe we've reached the end.
     850             : 
     851             :                 // Save what we have read previously...
     852          12 :                 aToken += sTmpBuffer.makeStringAndClear();
     853             : 
     854             :                 // and remember position in stream.
     855          12 :                 sal_uLong nStreamPos = rInput.Tell();
     856          12 :                 sal_uLong nLineNr = GetLineNr();
     857          12 :                 sal_uLong nLinePos = GetLinePos();
     858             : 
     859             :                 // Start of an end token?
     860          12 :                 bool bOffState = false;
     861          12 :                 if( '/' == (nNextCh = GetNextChar()) )
     862             :                 {
     863          12 :                     bOffState = true;
     864          12 :                     nNextCh = GetNextChar();
     865             :                 }
     866           0 :                 else if( '!' == nNextCh )
     867             :                 {
     868           0 :                     sTmpBuffer.append( nNextCh );
     869           0 :                     nNextCh = GetNextChar();
     870             :                 }
     871             : 
     872             :                 // Read following letters
     873         228 :                 while( (HTML_ISALPHA(nNextCh) || '-'==nNextCh) &&
     874         192 :                        IsParserWorking() && sTmpBuffer.getLength() < MAX_LEN )
     875             :                 {
     876          60 :                     sTmpBuffer.append( nNextCh );
     877          60 :                     nNextCh = GetNextChar();
     878             :                 }
     879             : 
     880          12 :                 OUString aTok( sTmpBuffer.toString() );
     881          12 :                 aTok = aTok.toAsciiLowerCase();
     882          12 :                 bool bDone = false;
     883          12 :                 if( bReadScript || !aEndToken.isEmpty() )
     884             :                 {
     885           0 :                     if( !bReadComment )
     886             :                     {
     887           0 :                         if( aTok.startsWith( OOO_STRING_SVTOOLS_HTML_comment ) )
     888             :                         {
     889           0 :                             bReadComment = true;
     890             :                         }
     891             :                         else
     892             :                         {
     893             :                             // A script has to end with "</SCRIPT>". But
     894             :                             // ">" is optional for security reasons
     895           0 :                             bDone = bOffState &&
     896             :                             ( bReadScript
     897           0 :                                 ? aTok == OOO_STRING_SVTOOLS_HTML_script
     898           0 :                                 : aTok.equals(aEndToken) );
     899             :                         }
     900             :                     }
     901           0 :                     if( bReadComment && '>'==nNextCh && aTok.endsWith( "--" ) )
     902             :                     {
     903             :                         // End of comment of style <!----->
     904           0 :                         bReadComment = false;
     905             :                     }
     906             :                 }
     907             :                 else
     908             :                 {
     909             :                     // Style sheets can be closed by </STYLE>, </HEAD> or <BODY>
     910          12 :                     if( bOffState )
     911          12 :                         bDone = aTok == OOO_STRING_SVTOOLS_HTML_style ||
     912          12 :                                 aTok == OOO_STRING_SVTOOLS_HTML_head;
     913             :                     else
     914           0 :                         bDone = aTok == OOO_STRING_SVTOOLS_HTML_body;
     915             :                 }
     916             : 
     917          12 :                 if( bDone )
     918             :                 {
     919             :                     // Done! Return the previously read string (if requested)
     920             :                     // and continue.
     921             : 
     922          12 :                     bContinue = false;
     923             : 
     924             :                     // nToken==0 means, _GetNextToken continues to read
     925          12 :                     if( aToken.isEmpty() && (bReadStyle || bReadScript) )
     926             :                     {
     927             :                         // Immediately close environment (or context?)
     928             :                         // and parse the end token
     929           0 :                         bReadScript = false;
     930           0 :                         bReadStyle = false;
     931           0 :                         aEndToken.clear();
     932           0 :                         nToken = 0;
     933             :                     }
     934             :                     else
     935             :                     {
     936             :                         // Keep bReadScript/bReadStyle alive
     937             :                         // and parse end token during next execution
     938          12 :                         bEndTokenFound = true;
     939             :                     }
     940             : 
     941             :                     // Move backwards in stream to '<'
     942          12 :                     rInput.Seek( nStreamPos );
     943          12 :                     SetLineNr( nLineNr );
     944          12 :                     SetLinePos( nLinePos );
     945          12 :                     ClearTxtConvContext();
     946          12 :                     nNextCh = '<';
     947             : 
     948             :                     // Don't append string to token.
     949          12 :                     sTmpBuffer.setLength( 0L );
     950             :                 }
     951             :                 else
     952             :                 {
     953             :                     // remember "</" , everything else we find in the buffer
     954           0 :                     aToken += "<";
     955           0 :                     if( bOffState )
     956           0 :                         aToken += "/";
     957             : 
     958           0 :                     bNextCh = false;
     959          12 :                 }
     960             :             }
     961          12 :             break;
     962             :         case '-':
     963          64 :             sTmpBuffer.append( nNextCh );
     964          64 :             if( bReadComment )
     965             :             {
     966           0 :                 bool bTwoMinus = false;
     967           0 :                 nNextCh = GetNextChar();
     968           0 :                 while( '-' == nNextCh && IsParserWorking() )
     969             :                 {
     970           0 :                     bTwoMinus = true;
     971             : 
     972           0 :                     if( MAX_LEN == sTmpBuffer.getLength() )
     973           0 :                         aToken += sTmpBuffer.makeStringAndClear();
     974           0 :                     sTmpBuffer.append( nNextCh );
     975           0 :                     nNextCh = GetNextChar();
     976             :                 }
     977             : 
     978           0 :                 if( '>' == nNextCh && IsParserWorking() && bTwoMinus )
     979           0 :                     bReadComment = false;
     980             : 
     981           0 :                 bNextCh = false;
     982             :             }
     983          64 :             break;
     984             : 
     985             :         case '\r':
     986             :             // \r\n? closes the current text token (even if it's empty)
     987           5 :             nNextCh = GetNextChar();
     988           5 :             if( nNextCh=='\n' )
     989           5 :                 nNextCh = GetNextChar();
     990           5 :             bContinue = false;
     991           5 :             break;
     992             :         case '\n':
     993             :             // \n closes the current text token (even if it's empty)
     994          89 :             nNextCh = GetNextChar();
     995          89 :             bContinue = false;
     996          89 :             break;
     997             :         case sal_Unicode(EOF):
     998             :             // eof closes the current text token and behaves like having read
     999             :             // an end token
    1000           0 :             if( rInput.IsEof() )
    1001             :             {
    1002           0 :                 bContinue = false;
    1003           0 :                 if( !aToken.isEmpty() || !sTmpBuffer.isEmpty() )
    1004             :                 {
    1005           0 :                     bEndTokenFound = true;
    1006             :                 }
    1007             :                 else
    1008             :                 {
    1009           0 :                     bReadScript = false;
    1010           0 :                     bReadStyle = false;
    1011           0 :                     aEndToken.clear();
    1012           0 :                     nToken = 0;
    1013             :                 }
    1014           0 :                 break;
    1015             :             }
    1016             :             // no break
    1017             :         default:
    1018             :             // all remaining characters are appended to the buffer
    1019        2229 :             sTmpBuffer.append( nNextCh );
    1020        2229 :             break;
    1021             :         }
    1022             : 
    1023        4720 :         if( (!bContinue && !sTmpBuffer.isEmpty()) ||
    1024        2321 :             MAX_LEN == sTmpBuffer.getLength() )
    1025          78 :             aToken += sTmpBuffer.makeStringAndClear();
    1026             : 
    1027        2399 :         if( bContinue && bNextCh )
    1028        2293 :             nNextCh = GetNextChar();
    1029             :     }
    1030             : 
    1031         106 :     if( IsParserWorking() )
    1032         106 :         SaveState( 0 );
    1033             :     else
    1034           0 :         nToken = 0;
    1035             : 
    1036         106 :     return nToken;
    1037             : }
    1038             : 
    1039             : // Scan next token
    1040        3493 : int HTMLParser::_GetNextToken()
    1041             : {
    1042        3493 :     int nRet = 0;
    1043        3493 :     sSaveToken.clear();
    1044             : 
    1045        3493 :     if (mnPendingOffToken)
    1046             :     {
    1047             :         // HTML_<TOKEN>_OFF generated for HTML_<TOKEN>_ON
    1048           1 :         nRet = mnPendingOffToken;
    1049           1 :         mnPendingOffToken = 0;
    1050           1 :         aToken.clear();
    1051           1 :         return nRet;
    1052             :     }
    1053             : 
    1054             :     // Delete options
    1055        3492 :     if (!maOptions.empty())
    1056         729 :         maOptions.clear();
    1057             : 
    1058        3492 :     if( !IsParserWorking() )        // Don't continue if already an error occurred
    1059           0 :         return 0;
    1060             : 
    1061        3492 :     bool bReadNextCharSave = bReadNextChar;
    1062        3492 :     if( bReadNextChar )
    1063             :     {
    1064             :         DBG_ASSERT( !bEndTokenFound,
    1065             :                     "Read a character despite </SCRIPT> was read?" );
    1066           0 :         nNextCh = GetNextChar();
    1067           0 :         if( !IsParserWorking() )        // Don't continue if already an error occurred
    1068           0 :             return 0;
    1069           0 :         bReadNextChar = false;
    1070             :     }
    1071             : 
    1072        3492 :     if( bReadScript || bReadStyle || !aEndToken.isEmpty() )
    1073             :     {
    1074         118 :         nRet = _GetNextRawToken();
    1075         118 :         if( nRet || !IsParserWorking() )
    1076         106 :             return nRet;
    1077             :     }
    1078             : 
    1079        3395 :     do {
    1080        3395 :         bool bNextCh = true;
    1081        3395 :         switch( nNextCh )
    1082             :         {
    1083             :         case '<':
    1084             :             {
    1085        1876 :                 sal_uLong nStreamPos = rInput.Tell();
    1086        1876 :                 sal_uLong nLineNr = GetLineNr();
    1087        1876 :                 sal_uLong nLinePos = GetLinePos();
    1088             : 
    1089        1876 :                 bool bOffState = false;
    1090        1876 :                 if( '/' == (nNextCh = GetNextChar()) )
    1091             :                 {
    1092         765 :                     bOffState = true;
    1093         765 :                     nNextCh = GetNextChar();
    1094             :                 }
    1095        1876 :                 if( HTML_ISALPHA( nNextCh ) || '!'==nNextCh )
    1096             :                 {
    1097        1876 :                     OUStringBuffer sTmpBuffer;
    1098        3914 :                     do {
    1099        3914 :                         sTmpBuffer.append( nNextCh );
    1100        3914 :                         if( MAX_LEN == sTmpBuffer.getLength() )
    1101           0 :                             aToken += sTmpBuffer.makeStringAndClear();
    1102        3914 :                         nNextCh = GetNextChar();
    1103        9006 :                     } while( '>' != nNextCh && '/' != nNextCh && !HTML_ISSPACE( nNextCh ) &&
    1104        7990 :                              IsParserWorking() && !rInput.IsEof() );
    1105             : 
    1106        1876 :                     if( !sTmpBuffer.isEmpty() )
    1107        1876 :                         aToken += sTmpBuffer.makeStringAndClear();
    1108             : 
    1109             :                     // Skip blanks
    1110        4500 :                     while( HTML_ISSPACE( nNextCh ) && IsParserWorking() )
    1111         748 :                         nNextCh = GetNextChar();
    1112             : 
    1113        1876 :                     if( !IsParserWorking() )
    1114             :                     {
    1115           0 :                         if( SVPAR_PENDING == eState )
    1116           0 :                             bReadNextChar = bReadNextCharSave;
    1117           0 :                         break;
    1118             :                     }
    1119             : 
    1120             :                     // Search token in table:
    1121        1876 :                     sSaveToken = aToken;
    1122        1876 :                     aToken = aToken.toAsciiLowerCase();
    1123        1876 :                     if( 0 == (nRet = GetHTMLToken( aToken )) )
    1124             :                         // Unknown control
    1125          27 :                         nRet = HTML_UNKNOWNCONTROL_ON;
    1126             : 
    1127             :                     // If it's a token which can be switched off...
    1128        1876 :                     if( bOffState )
    1129             :                     {
    1130         765 :                          if( HTML_TOKEN_ONOFF & nRet )
    1131             :                          {
    1132             :                             // and there is an off token, return off token instead
    1133         765 :                             ++nRet;
    1134             :                          }
    1135           0 :                          else if( HTML_LINEBREAK!=nRet )
    1136             :                          {
    1137             :                             // and there is no off token, return unknown token.
    1138             :                             // (except for </BR>, that is treated like <BR>)
    1139           0 :                             nRet = HTML_UNKNOWNCONTROL_OFF;
    1140             :                          }
    1141             :                     }
    1142             : 
    1143        1876 :                     if( nRet == HTML_COMMENT )
    1144             :                     {
    1145             :                         // fix: due to being case sensitive use sSaveToken as start of comment
    1146             :                         //      and append a blank.
    1147           1 :                         aToken = sSaveToken;
    1148           1 :                         if( '>'!=nNextCh )
    1149           1 :                             aToken += " ";
    1150           1 :                         sal_uLong nCStreamPos = 0;
    1151           1 :                         sal_uLong nCLineNr = 0;
    1152           1 :                         sal_uLong nCLinePos = 0;
    1153           1 :                         sal_Int32 nCStrLen = 0;
    1154             : 
    1155           1 :                         bool bDone = false;
    1156             :                         // Read until closing -->. If not found restart at first >
    1157       10600 :                         while( !bDone && !rInput.IsEof() && IsParserWorking() )
    1158             :                         {
    1159       10598 :                             if( '>'==nNextCh )
    1160             :                             {
    1161           5 :                                 if( !nCStreamPos )
    1162             :                                 {
    1163           1 :                                     nCStreamPos = rInput.Tell();
    1164           1 :                                     nCStrLen = aToken.getLength();
    1165           1 :                                     nCLineNr = GetLineNr();
    1166           1 :                                     nCLinePos = GetLinePos();
    1167             :                                 }
    1168           5 :                                 bDone = aToken.endsWith( "--" );
    1169           5 :                                 if( !bDone )
    1170           4 :                                 aToken += OUString(nNextCh);
    1171             :                             }
    1172             :                             else
    1173       10593 :                                 aToken += OUString(nNextCh);
    1174       10598 :                             if( !bDone )
    1175       10597 :                                 nNextCh = GetNextChar();
    1176             :                         }
    1177           1 :                         if( !bDone && IsParserWorking() && nCStreamPos )
    1178             :                         {
    1179           0 :                             rInput.Seek( nCStreamPos );
    1180           0 :                             SetLineNr( nCLineNr );
    1181           0 :                             SetLinePos( nCLinePos );
    1182           0 :                             ClearTxtConvContext();
    1183           0 :                             aToken = aToken.copy(0, nCStrLen);
    1184           0 :                             nNextCh = '>';
    1185             :                         }
    1186             :                     }
    1187             :                     else
    1188             :                     {
    1189             :                         // TokenString not needed anymore
    1190        1875 :                         aToken.clear();
    1191             :                     }
    1192             : 
    1193             :                     // Read until closing '>'
    1194        1876 :                     if( '>' != nNextCh && IsParserWorking() )
    1195             :                     {
    1196        1015 :                         ScanText( '>' );
    1197             : 
    1198             :                         // fdo#34666 fdo#36080 fdo#36390: closing "/>"?:
    1199             :                         // generate pending HTML_<TOKEN>_OFF for HTML_<TOKEN>_ON
    1200             :                         // Do not convert this to a single HTML_<TOKEN>_OFF
    1201             :                         // which lead to fdo#56772.
    1202        1015 :                         if ((HTML_TOKEN_ONOFF & nRet) && aToken.endsWith("/"))
    1203             :                         {
    1204           1 :                             mnPendingOffToken = nRet + 1;       // HTML_<TOKEN>_ON -> HTML_<TOKEN>_OFF
    1205           1 :                             aToken = aToken.replaceAt( aToken.getLength()-1, 1, "");   // remove trailing '/'
    1206             :                         }
    1207        1015 :                         if( sal_Unicode(EOF) == nNextCh && rInput.IsEof() )
    1208             :                         {
    1209             :                             // Move back in front of < and restart there.
    1210             :                             // Return < as text.
    1211           0 :                             rInput.Seek( nStreamPos );
    1212           0 :                             SetLineNr( nLineNr );
    1213           0 :                             SetLinePos( nLinePos );
    1214           0 :                             ClearTxtConvContext();
    1215             : 
    1216           0 :                             aToken = "<";
    1217           0 :                             nRet = HTML_TEXTTOKEN;
    1218           0 :                             nNextCh = GetNextChar();
    1219           0 :                             bNextCh = false;
    1220           0 :                             break;
    1221             :                         }
    1222             :                     }
    1223        1876 :                     if( SVPAR_PENDING == eState )
    1224           0 :                         bReadNextChar = bReadNextCharSave;
    1225             :                 }
    1226             :                 else
    1227             :                 {
    1228           0 :                     if( bOffState )
    1229             :                     {
    1230             :                         // einfach alles wegschmeissen
    1231           0 :                         ScanText( '>' );
    1232           0 :                         if( sal_Unicode(EOF) == nNextCh && rInput.IsEof() )
    1233             :                         {
    1234             :                             // Move back in front of < and restart there.
    1235             :                             // Return < as text.
    1236           0 :                             rInput.Seek( nStreamPos );
    1237           0 :                             SetLineNr( nLineNr );
    1238           0 :                             SetLinePos( nLinePos );
    1239           0 :                             ClearTxtConvContext();
    1240             : 
    1241           0 :                             aToken = "<";
    1242           0 :                             nRet = HTML_TEXTTOKEN;
    1243           0 :                             nNextCh = GetNextChar();
    1244           0 :                             bNextCh = false;
    1245           0 :                             break;
    1246             :                         }
    1247           0 :                         if( SVPAR_PENDING == eState )
    1248           0 :                             bReadNextChar = bReadNextCharSave;
    1249           0 :                         aToken.clear();
    1250             :                     }
    1251           0 :                     else if( '%' == nNextCh )
    1252             :                     {
    1253           0 :                         nRet = HTML_UNKNOWNCONTROL_ON;
    1254             : 
    1255           0 :                         sal_uLong nCStreamPos = rInput.Tell();
    1256           0 :                         sal_uLong nCLineNr = GetLineNr(), nCLinePos = GetLinePos();
    1257             : 
    1258           0 :                         bool bDone = false;
    1259             :                         // Read until closing %>. If not found restart at first >.
    1260           0 :                         while( !bDone && !rInput.IsEof() && IsParserWorking() )
    1261             :                         {
    1262           0 :                             bDone = '>'==nNextCh && aToken.endsWith("%");
    1263           0 :                             if( !bDone )
    1264             :                             {
    1265           0 :                                 aToken += OUString(nNextCh);
    1266           0 :                                 nNextCh = GetNextChar();
    1267             :                             }
    1268             :                         }
    1269           0 :                         if( !bDone && IsParserWorking() )
    1270             :                         {
    1271           0 :                             rInput.Seek( nCStreamPos );
    1272           0 :                             SetLineNr( nCLineNr );
    1273           0 :                             SetLinePos( nCLinePos );
    1274           0 :                             ClearTxtConvContext();
    1275           0 :                             aToken = "<%";
    1276           0 :                             nRet = HTML_TEXTTOKEN;
    1277           0 :                             break;
    1278             :                         }
    1279           0 :                         if( IsParserWorking() )
    1280             :                         {
    1281           0 :                             sSaveToken = aToken;
    1282           0 :                             aToken.clear();
    1283             :                         }
    1284             :                     }
    1285             :                     else
    1286             :                     {
    1287           0 :                         aToken = "<";
    1288           0 :                         nRet = HTML_TEXTTOKEN;
    1289           0 :                         bNextCh = false;
    1290           0 :                         break;
    1291             :                     }
    1292             :                 }
    1293             : 
    1294        1876 :                 if( IsParserWorking() )
    1295             :                 {
    1296        1876 :                     bNextCh = '>' == nNextCh;
    1297        1876 :                     switch( nRet )
    1298             :                     {
    1299             :                     case HTML_TEXTAREA_ON:
    1300           0 :                         bReadTextArea = true;
    1301           0 :                         break;
    1302             :                     case HTML_TEXTAREA_OFF:
    1303           0 :                         bReadTextArea = false;
    1304           0 :                         break;
    1305             :                     case HTML_SCRIPT_ON:
    1306           0 :                         if( !bReadTextArea )
    1307           0 :                             bReadScript = true;
    1308           0 :                         break;
    1309             :                     case HTML_SCRIPT_OFF:
    1310           0 :                         if( !bReadTextArea )
    1311             :                         {
    1312           0 :                             bReadScript = false;
    1313             :                             // JavaScript might modify the stream,
    1314             :                             // thus the last character has to be read again.
    1315           0 :                             bReadNextChar = true;
    1316           0 :                             bNextCh = false;
    1317             :                         }
    1318           0 :                         break;
    1319             : 
    1320             :                     case HTML_STYLE_ON:
    1321          12 :                         bReadStyle = true;
    1322          12 :                         break;
    1323             :                     case HTML_STYLE_OFF:
    1324          12 :                         bReadStyle = false;
    1325          12 :                         break;
    1326             :                     }
    1327             :                 }
    1328             :             }
    1329        1876 :             break;
    1330             : 
    1331             :         case sal_Unicode(EOF):
    1332          17 :             if( rInput.IsEof() )
    1333             :             {
    1334          17 :                 eState = SVPAR_ACCEPTED;
    1335          17 :                 nRet = nNextCh;
    1336             :             }
    1337             :             else
    1338             :             {
    1339             :                 // Read normal text.
    1340           0 :                 goto scan_text;
    1341             :             }
    1342          17 :             break;
    1343             : 
    1344             :         case '\f':
    1345             :             // form feeds are passed upwards separately
    1346           0 :             nRet = HTML_LINEFEEDCHAR; // !!! should be FORMFEEDCHAR
    1347           0 :             break;
    1348             : 
    1349             :         case '\n':
    1350             :         case '\r':
    1351        1458 :             if( bReadListing || bReadXMP || bReadPRE || bReadTextArea )
    1352             :             {
    1353           0 :                 sal_Unicode c = GetNextChar();
    1354           0 :                 if( ( '\n' != nNextCh || '\r' != c ) &&
    1355           0 :                     ( '\r' != nNextCh || '\n' != c ) )
    1356             :                 {
    1357           0 :                     bNextCh = false;
    1358           0 :                     nNextCh = c;
    1359             :                 }
    1360           0 :                 nRet = HTML_NEWPARA;
    1361           0 :                 break;
    1362             :             }
    1363             :             // no break !
    1364             :         case '\t':
    1365        1459 :             if( bReadPRE )
    1366             :             {
    1367           0 :                 nRet = HTML_TABCHAR;
    1368           0 :                 break;
    1369             :             }
    1370             :             // no break !
    1371             :         case ' ':
    1372             :             // no break !
    1373             :         default:
    1374             : 
    1375             : scan_text:
    1376             :             // "normal" text to come
    1377        1502 :             nRet = ScanText();
    1378        1502 :             bNextCh = 0 == aToken.getLength();
    1379             : 
    1380             :             // the text should be processed
    1381        1502 :             if( !bNextCh && eState == SVPAR_PENDING )
    1382             :             {
    1383           0 :                 eState = SVPAR_WORKING;
    1384           0 :                 bReadNextChar = true;
    1385             :             }
    1386             : 
    1387        1502 :             break;
    1388             :         }
    1389             : 
    1390        3395 :         if( bNextCh && SVPAR_WORKING == eState )
    1391             :         {
    1392        1885 :             nNextCh = GetNextChar();
    1393        1885 :             if( SVPAR_PENDING == eState && nRet && HTML_TEXTTOKEN != nRet )
    1394             :             {
    1395           0 :                 bReadNextChar = true;
    1396           0 :                 eState = SVPAR_WORKING;
    1397             :             }
    1398             :         }
    1399             : 
    1400           9 :     } while( !nRet && SVPAR_WORKING == eState );
    1401             : 
    1402        3386 :     if( SVPAR_PENDING == eState )
    1403           0 :         nRet = -1;      // s.th. invalid
    1404             : 
    1405        3386 :     return nRet;
    1406             : }
    1407             : 
    1408           0 : void HTMLParser::UnescapeToken()
    1409             : {
    1410           0 :     sal_Int32 nPos=0;
    1411             : 
    1412           0 :     bool bEscape = false;
    1413           0 :     while( nPos < aToken.getLength() )
    1414             :     {
    1415           0 :         bool bOldEscape = bEscape;
    1416           0 :         bEscape = false;
    1417           0 :         if( '\\'==aToken[nPos] && !bOldEscape )
    1418             :         {
    1419           0 :             aToken = aToken.replaceAt( nPos, 1, "" );
    1420           0 :             bEscape = true;
    1421             :         }
    1422             :         else
    1423             :         {
    1424           0 :             nPos++;
    1425             :         }
    1426             :     }
    1427           0 : }
    1428             : 
    1429        1106 : const HTMLOptions& HTMLParser::GetOptions( sal_uInt16 *pNoConvertToken )
    1430             : {
    1431             :     // If the options for the current token have already been returned,
    1432             :     // return them once again.
    1433        1106 :     if (!maOptions.empty())
    1434          32 :         return maOptions;
    1435             : 
    1436        1074 :     sal_Int32 nPos = 0;
    1437        4660 :     while( nPos < aToken.getLength() )
    1438             :     {
    1439             :         // A letter? Option beginning here.
    1440        2512 :         if( HTML_ISALPHA( aToken[nPos] ) )
    1441             :         {
    1442             :             int nToken;
    1443        1455 :             OUString aValue;
    1444        1455 :             sal_Int32 nStt = nPos;
    1445        1455 :             sal_Unicode cChar = 0;
    1446             : 
    1447             :             // Actually only certain characters allowed.
    1448             :             // Netscape only looks for "=" and white space (c.f.
    1449             :             // Mozilla: PA_FetchRequestedNameValues in lipparse/pa_mdl.c)
    1450       28923 :             while( nPos < aToken.getLength() && '=' != (cChar=aToken[nPos]) &&
    1451       16857 :                    HTML_ISPRINTABLE(cChar) && !HTML_ISSPACE(cChar) )
    1452        7701 :                 nPos++;
    1453             : 
    1454        2910 :             OUString sName( aToken.copy( nStt, nPos-nStt ) );
    1455             : 
    1456             :             // PlugIns require original token name. Convert to lower case only for searching.
    1457        1455 :             nToken = GetHTMLOption( sName.toAsciiLowerCase() ); // Name is ready
    1458             :             DBG_ASSERTWARNING( nToken!=HTML_O_UNKNOWN,
    1459             :                         "GetOption: unknown HTML option" );
    1460          18 :             bool bStripCRLF = (nToken < HTML_OPTION_SCRIPT_START ||
    1461        4322 :                                nToken >= HTML_OPTION_SCRIPT_END) &&
    1462        1554 :                               (!pNoConvertToken || nToken != *pNoConvertToken);
    1463             : 
    1464        4365 :             while( nPos < aToken.getLength() &&
    1465        2910 :                    ( !HTML_ISPRINTABLE( (cChar=aToken[nPos]) ) ||
    1466        1455 :                      HTML_ISSPACE(cChar) ) )
    1467           0 :                 nPos++;
    1468             : 
    1469             :             // Option with value?
    1470        1455 :             if( nPos!=aToken.getLength() && '='==cChar )
    1471             :             {
    1472        1455 :                 nPos++;
    1473             : 
    1474        4365 :                 while( nPos < aToken.getLength() &&
    1475        2910 :                         ( !HTML_ISPRINTABLE( (cChar=aToken[nPos]) ) ||
    1476        1455 :                           ' '==cChar || '\t'==cChar || '\r'==cChar || '\n'==cChar ) )
    1477           0 :                     nPos++;
    1478             : 
    1479        1455 :                 if( nPos != aToken.getLength() )
    1480             :                 {
    1481        1455 :                     sal_Int32 nLen = 0;
    1482        1455 :                     nStt = nPos;
    1483        1455 :                     if( ('"'==cChar) || ('\'')==cChar )
    1484             :                     {
    1485        1453 :                         sal_Unicode cEnd = cChar;
    1486        1453 :                         nPos++; nStt++;
    1487        1453 :                         bool bDone = false;
    1488        1453 :                         bool bEscape = false;
    1489       72526 :                         while( nPos < aToken.getLength() && !bDone )
    1490             :                         {
    1491       69620 :                             bool bOldEscape = bEscape;
    1492       69620 :                             bEscape = false;
    1493       69620 :                             cChar = aToken[nPos];
    1494       69620 :                             switch( cChar )
    1495             :                             {
    1496             :                             case '\r':
    1497             :                             case '\n':
    1498           0 :                                 if( bStripCRLF )
    1499           0 :                                     aToken = aToken.replaceAt( nPos, 1, "" );
    1500             :                                 else
    1501           0 :                                     nPos++, nLen++;
    1502           0 :                                 break;
    1503             :                             case '\\':
    1504           0 :                                 if( bOldEscape )
    1505             :                                 {
    1506           0 :                                     nPos++, nLen++;
    1507             :                                 }
    1508             :                                 else
    1509             :                                 {
    1510           0 :                                     aToken = aToken.replaceAt( nPos, 1, "" );
    1511           0 :                                     bEscape = true;
    1512             :                                 }
    1513           0 :                                 break;
    1514             :                             case '"':
    1515             :                             case '\'':
    1516        1453 :                                 bDone = !bOldEscape && cChar==cEnd;
    1517        1453 :                                 if( !bDone )
    1518           0 :                                     nPos++, nLen++;
    1519        1453 :                                 break;
    1520             :                             default:
    1521       68167 :                                 nPos++, nLen++;
    1522       68167 :                                 break;
    1523             :                             }
    1524             :                         }
    1525        1453 :                         if( nPos!=aToken.getLength() )
    1526        1453 :                             nPos++;
    1527             :                     }
    1528             :                     else
    1529             :                     {
    1530             :                         // More liberal than the standard: allow all printable characters
    1531           2 :                         bool bEscape = false;
    1532           2 :                         bool bDone = false;
    1533          26 :                         while( nPos < aToken.getLength() && !bDone )
    1534             :                         {
    1535          22 :                             bool bOldEscape = bEscape;
    1536          22 :                             bEscape = false;
    1537          22 :                             sal_Unicode c = aToken[nPos];
    1538          22 :                             switch( c )
    1539             :                             {
    1540             :                             case ' ':
    1541           2 :                                 bDone = !bOldEscape;
    1542           2 :                                 if( !bDone )
    1543           0 :                                     nPos++, nLen++;
    1544           2 :                                 break;
    1545             : 
    1546             :                             case '\t':
    1547             :                             case '\r':
    1548             :                             case '\n':
    1549           0 :                                 bDone = true;
    1550           0 :                                 break;
    1551             : 
    1552             :                             case '\\':
    1553           0 :                                 if( bOldEscape )
    1554             :                                 {
    1555           0 :                                     nPos++, nLen++;
    1556             :                                 }
    1557             :                                 else
    1558             :                                 {
    1559           0 :                                     aToken = aToken.replaceAt( nPos, 1, "" );
    1560           0 :                                     bEscape = true;
    1561             :                                 }
    1562           0 :                                 break;
    1563             : 
    1564             :                             default:
    1565          20 :                                 if( HTML_ISPRINTABLE( c ) )
    1566          20 :                                     nPos++, nLen++;
    1567             :                                 else
    1568           0 :                                     bDone = true;
    1569          20 :                                 break;
    1570             :                             }
    1571             :                         }
    1572             :                     }
    1573             : 
    1574        1455 :                     if( nLen )
    1575        1453 :                         aValue = aToken.copy( nStt, nLen );
    1576             :                 }
    1577             :             }
    1578             : 
    1579             :             // Token is known and can be saved
    1580             :             std::unique_ptr<HTMLOption> pOption(
    1581        1455 :                 new HTMLOption(sal::static_int_cast<sal_uInt16>(nToken), sName, aValue));
    1582             : 
    1583        2910 :             o3tl::ptr_container::push_back(maOptions, std::move(pOption));
    1584             :         }
    1585             :         else
    1586             :             // Ignore white space and unexpected characters
    1587        1057 :             nPos++;
    1588             :     }
    1589             : 
    1590        1074 :     return maOptions;
    1591             : }
    1592             : 
    1593           0 : int HTMLParser::FilterPRE( int nToken )
    1594             : {
    1595           0 :     switch( nToken )
    1596             :     {
    1597             :     // in Netscape they only have impact in not empty paragraphs
    1598             :     case HTML_PARABREAK_ON:
    1599           0 :         nToken = HTML_LINEBREAK;
    1600             :         //fall-through
    1601             :     case HTML_LINEBREAK:
    1602             :     case HTML_NEWPARA:
    1603           0 :         nPre_LinePos = 0;
    1604           0 :         if( bPre_IgnoreNewPara )
    1605           0 :             nToken = 0;
    1606           0 :         break;
    1607             : 
    1608             :     case HTML_TABCHAR:
    1609             :         {
    1610           0 :             sal_Int32 nSpaces = (8 - (nPre_LinePos % 8));
    1611             :             DBG_ASSERT( aToken.isEmpty(), "Why is the token not empty?" );
    1612           0 :             if (aToken.getLength() < nSpaces)
    1613             :             {
    1614             :                 using comphelper::string::padToLength;
    1615           0 :                 OUStringBuffer aBuf(aToken);
    1616           0 :                 aToken = padToLength(aBuf, nSpaces, ' ').makeStringAndClear();
    1617             :             }
    1618           0 :             nPre_LinePos += nSpaces;
    1619           0 :             nToken = HTML_TEXTTOKEN;
    1620             :         }
    1621           0 :         break;
    1622             :     // Keep those
    1623             :     case HTML_TEXTTOKEN:
    1624           0 :         nPre_LinePos += aToken.getLength();
    1625           0 :         break;
    1626             : 
    1627             :     case HTML_SELECT_ON:
    1628             :     case HTML_SELECT_OFF:
    1629             :     case HTML_BODY_ON:
    1630             :     case HTML_FORM_ON:
    1631             :     case HTML_FORM_OFF:
    1632             :     case HTML_INPUT:
    1633             :     case HTML_OPTION:
    1634             :     case HTML_TEXTAREA_ON:
    1635             :     case HTML_TEXTAREA_OFF:
    1636             : 
    1637             :     case HTML_IMAGE:
    1638             :     case HTML_APPLET_ON:
    1639             :     case HTML_APPLET_OFF:
    1640             :     case HTML_PARAM:
    1641             :     case HTML_EMBED:
    1642             : 
    1643             :     case HTML_HEAD1_ON:
    1644             :     case HTML_HEAD1_OFF:
    1645             :     case HTML_HEAD2_ON:
    1646             :     case HTML_HEAD2_OFF:
    1647             :     case HTML_HEAD3_ON:
    1648             :     case HTML_HEAD3_OFF:
    1649             :     case HTML_HEAD4_ON:
    1650             :     case HTML_HEAD4_OFF:
    1651             :     case HTML_HEAD5_ON:
    1652             :     case HTML_HEAD5_OFF:
    1653             :     case HTML_HEAD6_ON:
    1654             :     case HTML_HEAD6_OFF:
    1655             :     case HTML_BLOCKQUOTE_ON:
    1656             :     case HTML_BLOCKQUOTE_OFF:
    1657             :     case HTML_ADDRESS_ON:
    1658             :     case HTML_ADDRESS_OFF:
    1659             :     case HTML_HORZRULE:
    1660             : 
    1661             :     case HTML_CENTER_ON:
    1662             :     case HTML_CENTER_OFF:
    1663             :     case HTML_DIVISION_ON:
    1664             :     case HTML_DIVISION_OFF:
    1665             : 
    1666             :     case HTML_SCRIPT_ON:
    1667             :     case HTML_SCRIPT_OFF:
    1668             :     case HTML_RAWDATA:
    1669             : 
    1670             :     case HTML_TABLE_ON:
    1671             :     case HTML_TABLE_OFF:
    1672             :     case HTML_CAPTION_ON:
    1673             :     case HTML_CAPTION_OFF:
    1674             :     case HTML_COLGROUP_ON:
    1675             :     case HTML_COLGROUP_OFF:
    1676             :     case HTML_COL_ON:
    1677             :     case HTML_COL_OFF:
    1678             :     case HTML_THEAD_ON:
    1679             :     case HTML_THEAD_OFF:
    1680             :     case HTML_TFOOT_ON:
    1681             :     case HTML_TFOOT_OFF:
    1682             :     case HTML_TBODY_ON:
    1683             :     case HTML_TBODY_OFF:
    1684             :     case HTML_TABLEROW_ON:
    1685             :     case HTML_TABLEROW_OFF:
    1686             :     case HTML_TABLEDATA_ON:
    1687             :     case HTML_TABLEDATA_OFF:
    1688             :     case HTML_TABLEHEADER_ON:
    1689             :     case HTML_TABLEHEADER_OFF:
    1690             : 
    1691             :     case HTML_ANCHOR_ON:
    1692             :     case HTML_ANCHOR_OFF:
    1693             :     case HTML_BOLD_ON:
    1694             :     case HTML_BOLD_OFF:
    1695             :     case HTML_ITALIC_ON:
    1696             :     case HTML_ITALIC_OFF:
    1697             :     case HTML_STRIKE_ON:
    1698             :     case HTML_STRIKE_OFF:
    1699             :     case HTML_STRIKETHROUGH_ON:
    1700             :     case HTML_STRIKETHROUGH_OFF:
    1701             :     case HTML_UNDERLINE_ON:
    1702             :     case HTML_UNDERLINE_OFF:
    1703             :     case HTML_BASEFONT_ON:
    1704             :     case HTML_BASEFONT_OFF:
    1705             :     case HTML_FONT_ON:
    1706             :     case HTML_FONT_OFF:
    1707             :     case HTML_BLINK_ON:
    1708             :     case HTML_BLINK_OFF:
    1709             :     case HTML_SPAN_ON:
    1710             :     case HTML_SPAN_OFF:
    1711             :     case HTML_SUBSCRIPT_ON:
    1712             :     case HTML_SUBSCRIPT_OFF:
    1713             :     case HTML_SUPERSCRIPT_ON:
    1714             :     case HTML_SUPERSCRIPT_OFF:
    1715             :     case HTML_BIGPRINT_ON:
    1716             :     case HTML_BIGPRINT_OFF:
    1717             :     case HTML_SMALLPRINT_OFF:
    1718             :     case HTML_SMALLPRINT_ON:
    1719             : 
    1720             :     case HTML_EMPHASIS_ON:
    1721             :     case HTML_EMPHASIS_OFF:
    1722             :     case HTML_CITIATION_ON:
    1723             :     case HTML_CITIATION_OFF:
    1724             :     case HTML_STRONG_ON:
    1725             :     case HTML_STRONG_OFF:
    1726             :     case HTML_CODE_ON:
    1727             :     case HTML_CODE_OFF:
    1728             :     case HTML_SAMPLE_ON:
    1729             :     case HTML_SAMPLE_OFF:
    1730             :     case HTML_KEYBOARD_ON:
    1731             :     case HTML_KEYBOARD_OFF:
    1732             :     case HTML_VARIABLE_ON:
    1733             :     case HTML_VARIABLE_OFF:
    1734             :     case HTML_DEFINSTANCE_ON:
    1735             :     case HTML_DEFINSTANCE_OFF:
    1736             :     case HTML_SHORTQUOTE_ON:
    1737             :     case HTML_SHORTQUOTE_OFF:
    1738             :     case HTML_LANGUAGE_ON:
    1739             :     case HTML_LANGUAGE_OFF:
    1740             :     case HTML_AUTHOR_ON:
    1741             :     case HTML_AUTHOR_OFF:
    1742             :     case HTML_PERSON_ON:
    1743             :     case HTML_PERSON_OFF:
    1744             :     case HTML_ACRONYM_ON:
    1745             :     case HTML_ACRONYM_OFF:
    1746             :     case HTML_ABBREVIATION_ON:
    1747             :     case HTML_ABBREVIATION_OFF:
    1748             :     case HTML_INSERTEDTEXT_ON:
    1749             :     case HTML_INSERTEDTEXT_OFF:
    1750             :     case HTML_DELETEDTEXT_ON:
    1751             :     case HTML_DELETEDTEXT_OFF:
    1752             :     case HTML_TELETYPE_ON:
    1753             :     case HTML_TELETYPE_OFF:
    1754             : 
    1755           0 :         break;
    1756             : 
    1757             :     // The remainder is treated as an unknown token.
    1758             :     default:
    1759           0 :         if( nToken )
    1760             :         {
    1761             :             nToken =
    1762           0 :                 ( ((HTML_TOKEN_ONOFF & nToken) && (1 & nToken))
    1763             :                     ? HTML_UNKNOWNCONTROL_OFF
    1764           0 :                     : HTML_UNKNOWNCONTROL_ON );
    1765             :         }
    1766           0 :         break;
    1767             :     }
    1768             : 
    1769           0 :     bPre_IgnoreNewPara = false;
    1770             : 
    1771           0 :     return nToken;
    1772             : }
    1773             : 
    1774           0 : int HTMLParser::FilterXMP( int nToken )
    1775             : {
    1776           0 :     switch( nToken )
    1777             :     {
    1778             :     case HTML_NEWPARA:
    1779           0 :         if( bPre_IgnoreNewPara )
    1780           0 :             nToken = 0;
    1781             :     case HTML_TEXTTOKEN:
    1782             :     case HTML_NONBREAKSPACE:
    1783             :     case HTML_SOFTHYPH:
    1784           0 :         break;              // kept
    1785             : 
    1786             :     default:
    1787           0 :         if( nToken )
    1788             :         {
    1789           0 :             if( (HTML_TOKEN_ONOFF & nToken) && (1 & nToken) )
    1790             :             {
    1791           0 :                 sSaveToken = "</" + sSaveToken;
    1792             :             }
    1793             :             else
    1794           0 :                 sSaveToken = "<" + sSaveToken;
    1795           0 :             if( !aToken.isEmpty() )
    1796             :             {
    1797           0 :                 UnescapeToken();
    1798           0 :                 sSaveToken += " ";
    1799           0 :                 aToken = sSaveToken + aToken;
    1800             :             }
    1801             :             else
    1802           0 :                 aToken = sSaveToken;
    1803           0 :             aToken += ">";
    1804           0 :             nToken = HTML_TEXTTOKEN;
    1805             :         }
    1806           0 :         break;
    1807             :     }
    1808             : 
    1809           0 :     bPre_IgnoreNewPara = false;
    1810             : 
    1811           0 :     return nToken;
    1812             : }
    1813             : 
    1814           0 : int HTMLParser::FilterListing( int nToken )
    1815             : {
    1816           0 :     switch( nToken )
    1817             :     {
    1818             :     case HTML_NEWPARA:
    1819           0 :         if( bPre_IgnoreNewPara )
    1820           0 :             nToken = 0;
    1821             :     case HTML_TEXTTOKEN:
    1822             :     case HTML_NONBREAKSPACE:
    1823             :     case HTML_SOFTHYPH:
    1824           0 :         break;      // kept
    1825             : 
    1826             :     default:
    1827           0 :         if( nToken )
    1828             :         {
    1829             :             nToken =
    1830           0 :                 ( ((HTML_TOKEN_ONOFF & nToken) && (1 & nToken))
    1831             :                     ? HTML_UNKNOWNCONTROL_OFF
    1832           0 :                     : HTML_UNKNOWNCONTROL_ON );
    1833             :         }
    1834           0 :         break;
    1835             :     }
    1836             : 
    1837           0 :     bPre_IgnoreNewPara = false;
    1838             : 
    1839           0 :     return nToken;
    1840             : }
    1841             : 
    1842           4 : bool HTMLParser::InternalImgToPrivateURL( OUString& rURL )
    1843             : {
    1844           4 :     bool bFound = false;
    1845             : 
    1846           4 :     if( rURL.startsWith( OOO_STRING_SVTOOLS_HTML_internal_icon ) )
    1847             :     {
    1848           0 :         OUString aName( rURL.copy(14) );
    1849           0 :         switch( aName[0] )
    1850             :         {
    1851             :         case 'b':
    1852           0 :             bFound = aName == OOO_STRING_SVTOOLS_HTML_INT_ICON_baddata;
    1853           0 :             break;
    1854             :         case 'd':
    1855           0 :             bFound = aName == OOO_STRING_SVTOOLS_HTML_INT_ICON_delayed;
    1856           0 :             break;
    1857             :         case 'e':
    1858           0 :             bFound = aName == OOO_STRING_SVTOOLS_HTML_INT_ICON_embed;
    1859           0 :             break;
    1860             :         case 'i':
    1861           0 :             bFound = aName == OOO_STRING_SVTOOLS_HTML_INT_ICON_insecure;
    1862           0 :             break;
    1863             :         case 'n':
    1864           0 :             bFound = aName == OOO_STRING_SVTOOLS_HTML_INT_ICON_notfound;
    1865           0 :             break;
    1866           0 :         }
    1867             :     }
    1868           4 :     if( bFound )
    1869             :     {
    1870           0 :         OUString sTmp ( rURL );
    1871           0 :         rURL =  OOO_STRING_SVTOOLS_HTML_private_image;
    1872           0 :         rURL += sTmp;
    1873             :     }
    1874             : 
    1875           4 :     return bFound;
    1876             : }
    1877             : 
    1878             : enum eHtmlMetas {
    1879             :     HTML_META_NONE = 0,
    1880             :     HTML_META_AUTHOR,
    1881             :     HTML_META_DESCRIPTION,
    1882             :     HTML_META_KEYWORDS,
    1883             :     HTML_META_REFRESH,
    1884             :     HTML_META_CLASSIFICATION,
    1885             :     HTML_META_CREATED,
    1886             :     HTML_META_CHANGEDBY,
    1887             :     HTML_META_CHANGED,
    1888             :     HTML_META_GENERATOR,
    1889             :     HTML_META_SDFOOTNOTE,
    1890             :     HTML_META_SDENDNOTE,
    1891             :     HTML_META_CONTENT_TYPE
    1892             : };
    1893             : 
    1894             : // <META NAME=xxx>
    1895             : static HTMLOptionEnum const aHTMLMetaNameTable[] =
    1896             : {
    1897             :     { OOO_STRING_SVTOOLS_HTML_META_author,        HTML_META_AUTHOR        },
    1898             :     { OOO_STRING_SVTOOLS_HTML_META_changed,       HTML_META_CHANGED       },
    1899             :     { OOO_STRING_SVTOOLS_HTML_META_changedby,     HTML_META_CHANGEDBY     },
    1900             :     { OOO_STRING_SVTOOLS_HTML_META_classification,HTML_META_CLASSIFICATION},
    1901             :     { OOO_STRING_SVTOOLS_HTML_META_content_type,  HTML_META_CONTENT_TYPE  },
    1902             :     { OOO_STRING_SVTOOLS_HTML_META_created,       HTML_META_CREATED       },
    1903             :     { OOO_STRING_SVTOOLS_HTML_META_description,   HTML_META_DESCRIPTION   },
    1904             :     { OOO_STRING_SVTOOLS_HTML_META_keywords,      HTML_META_KEYWORDS      },
    1905             :     { OOO_STRING_SVTOOLS_HTML_META_generator,     HTML_META_GENERATOR     },
    1906             :     { OOO_STRING_SVTOOLS_HTML_META_refresh,       HTML_META_REFRESH       },
    1907             :     { OOO_STRING_SVTOOLS_HTML_META_sdendnote,     HTML_META_SDENDNOTE     },
    1908             :     { OOO_STRING_SVTOOLS_HTML_META_sdfootnote,    HTML_META_SDFOOTNOTE    },
    1909             :     { 0,                                          0                       }
    1910             : };
    1911             : 
    1912             : 
    1913           0 : void HTMLParser::AddMetaUserDefined( OUString const & )
    1914             : {
    1915           0 : }
    1916             : 
    1917          42 : bool HTMLParser::ParseMetaOptionsImpl(
    1918             :         const uno::Reference<document::XDocumentProperties> & i_xDocProps,
    1919             :         SvKeyValueIterator *i_pHTTPHeader,
    1920             :         const HTMLOptions& aOptions,
    1921             :         rtl_TextEncoding& o_rEnc )
    1922             : {
    1923          84 :     OUString aName, aContent;
    1924          42 :     sal_uInt16 nAction = HTML_META_NONE;
    1925          42 :     bool bHTTPEquiv = false, bChanged = false;
    1926             : 
    1927         166 :     for ( size_t i = aOptions.size(); i; )
    1928             :     {
    1929          82 :         const HTMLOption& aOption = aOptions[--i];
    1930          82 :         switch ( aOption.GetToken() )
    1931             :         {
    1932             :             case HTML_O_NAME:
    1933          29 :                 aName = aOption.GetString();
    1934          29 :                 if ( HTML_META_NONE==nAction )
    1935             :                 {
    1936          29 :                     aOption.GetEnum( nAction, aHTMLMetaNameTable );
    1937             :                 }
    1938          29 :                 break;
    1939             :             case HTML_O_HTTPEQUIV:
    1940          11 :                 aName = aOption.GetString();
    1941          11 :                 aOption.GetEnum( nAction, aHTMLMetaNameTable );
    1942          11 :                 bHTTPEquiv = true;
    1943          11 :                 break;
    1944             :             case HTML_O_CONTENT:
    1945          40 :                 aContent = aOption.GetString();
    1946          40 :                 break;
    1947             :         }
    1948             :     }
    1949             : 
    1950          42 :     if ( bHTTPEquiv || HTML_META_DESCRIPTION != nAction )
    1951             :     {
    1952             :         // if it is not a Description, remove CRs and LFs from CONTENT
    1953          42 :         aContent = comphelper::string::remove(aContent, '\r');
    1954          42 :         aContent = comphelper::string::remove(aContent, '\n');
    1955             :     }
    1956             :     else
    1957             :     {
    1958             :         // convert line endings for Description
    1959           0 :         aContent = convertLineEnd(aContent, GetSystemLineEnd());
    1960             :     }
    1961             : 
    1962             : 
    1963          42 :     if ( bHTTPEquiv && i_pHTTPHeader )
    1964             :     {
    1965             :         // Netscape seems to just ignore a closing ", so we do too
    1966          11 :         if ( aContent.endsWith("\"") )
    1967             :         {
    1968           0 :             aContent = aContent.copy( 0, aContent.getLength() - 1 );
    1969             :         }
    1970          11 :         SvKeyValue aKeyValue( aName, aContent );
    1971          11 :         i_pHTTPHeader->Append( aKeyValue );
    1972             :     }
    1973             : 
    1974          42 :     switch ( nAction )
    1975             :     {
    1976             :         case HTML_META_AUTHOR:
    1977           1 :             if (i_xDocProps.is()) {
    1978           1 :                 i_xDocProps->setAuthor( aContent );
    1979           1 :                 bChanged = true;
    1980             :             }
    1981           1 :             break;
    1982             :         case HTML_META_DESCRIPTION:
    1983           0 :             if (i_xDocProps.is()) {
    1984           0 :                 i_xDocProps->setDescription( aContent );
    1985           0 :                 bChanged = true;
    1986             :             }
    1987           0 :             break;
    1988             :         case HTML_META_KEYWORDS:
    1989           0 :             if (i_xDocProps.is()) {
    1990           0 :                 i_xDocProps->setKeywords(
    1991           0 :                     ::comphelper::string::convertCommaSeparated(aContent));
    1992           0 :                 bChanged = true;
    1993             :             }
    1994           0 :             break;
    1995             :         case HTML_META_CLASSIFICATION:
    1996           0 :             if (i_xDocProps.is()) {
    1997           0 :                 i_xDocProps->setSubject( aContent );
    1998           0 :                 bChanged = true;
    1999             :             }
    2000           0 :             break;
    2001             : 
    2002             :         case HTML_META_CHANGEDBY:
    2003           1 :             if (i_xDocProps.is()) {
    2004           1 :                 i_xDocProps->setModifiedBy( aContent );
    2005             :             }
    2006           1 :             break;
    2007             : 
    2008             :         case HTML_META_CREATED:
    2009             :         case HTML_META_CHANGED:
    2010          24 :             if ( i_xDocProps.is() && !aContent.isEmpty() &&
    2011          12 :                  comphelper::string::getTokenCount(aContent, ';') == 2 )
    2012             :             {
    2013           0 :                 Date aDate( (sal_uLong)aContent.getToken(0, ';').toInt32() );
    2014           0 :                 tools::Time aTime( (sal_uLong)aContent.getToken(1, ';').toInt32() );
    2015           0 :                 DateTime aDateTime( aDate, aTime );
    2016           0 :                 ::util::DateTime uDT = aDateTime.GetUNODateTime();
    2017           0 :                 if ( HTML_META_CREATED==nAction )
    2018           0 :                     i_xDocProps->setCreationDate( uDT );
    2019             :                 else
    2020           0 :                     i_xDocProps->setModificationDate( uDT );
    2021           0 :                 bChanged = true;
    2022             :             }
    2023          12 :             break;
    2024             : 
    2025             :         case HTML_META_REFRESH:
    2026             :             DBG_ASSERT( !bHTTPEquiv || i_pHTTPHeader,
    2027             :         "Reload-URL aufgrund unterlassener MUSS-Aenderung verlorengegangen" );
    2028           0 :             break;
    2029             : 
    2030             :         case HTML_META_CONTENT_TYPE:
    2031          11 :             if ( !aContent.isEmpty() )
    2032             :             {
    2033          11 :                 o_rEnc = GetEncodingByMIME( aContent );
    2034             :             }
    2035          11 :             break;
    2036             : 
    2037             :         case HTML_META_NONE:
    2038           9 :             if ( !bHTTPEquiv )
    2039             :             {
    2040           9 :                 if (i_xDocProps.is())
    2041             :                 {
    2042             :                     uno::Reference<beans::XPropertyContainer> xUDProps
    2043           9 :                         = i_xDocProps->getUserDefinedProperties();
    2044             :                     try {
    2045           9 :                         xUDProps->addProperty(aName,
    2046             :                             beans::PropertyAttribute::REMOVABLE,
    2047           9 :                             uno::makeAny(OUString(aContent)));
    2048           9 :                         AddMetaUserDefined(aName);
    2049           9 :                         bChanged = true;
    2050           0 :                     } catch (uno::Exception &) {
    2051             :                         // ignore
    2052           9 :                     }
    2053             :                 }
    2054             :             }
    2055           9 :             break;
    2056             :         default:
    2057           8 :             break;
    2058             :     }
    2059             : 
    2060          84 :     return bChanged;
    2061             : }
    2062             : 
    2063          42 : bool HTMLParser::ParseMetaOptions(
    2064             :         const uno::Reference<document::XDocumentProperties> & i_xDocProps,
    2065             :         SvKeyValueIterator *i_pHeader )
    2066             : {
    2067          42 :     sal_uInt16 nContentOption = HTML_O_CONTENT;
    2068          42 :     rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW;
    2069             : 
    2070             :     bool bRet = ParseMetaOptionsImpl( i_xDocProps, i_pHeader,
    2071          42 :                       GetOptions(&nContentOption),
    2072          42 :                       eEnc );
    2073             : 
    2074             :     // If the encoding is set by a META tag, it may only overwrite the
    2075             :     // current encoding if both, the current and the new encoding, are 1-sal_uInt8
    2076             :     // encodings. Everything else cannot lead to reasonable results.
    2077          95 :     if (RTL_TEXTENCODING_DONTKNOW != eEnc &&
    2078          53 :         rtl_isOctetTextEncoding( eEnc ) &&
    2079          11 :         rtl_isOctetTextEncoding( GetSrcEncoding() ) )
    2080             :     {
    2081          11 :         eEnc = GetExtendedCompatibilityTextEncoding( eEnc );
    2082          11 :         SetSrcEncoding( eEnc );
    2083             :     }
    2084             : 
    2085          42 :     return bRet;
    2086             : }
    2087             : 
    2088          11 : rtl_TextEncoding HTMLParser::GetEncodingByMIME( const OUString& rMime )
    2089             : {
    2090          11 :     OUString sType;
    2091          22 :     OUString sSubType;
    2092          22 :     INetContentTypeParameterList aParameters;
    2093          11 :     if (INetContentTypes::parse(rMime, sType, sSubType, &aParameters))
    2094             :     {
    2095          11 :         const INetContentTypeParameter * pCharset = aParameters.find("charset");
    2096          11 :         if (pCharset != 0)
    2097             :         {
    2098          11 :             OString sValue(OUStringToOString(pCharset->m_sValue, RTL_TEXTENCODING_ASCII_US));
    2099          11 :             return GetExtendedCompatibilityTextEncoding( rtl_getTextEncodingFromMimeCharset( sValue.getStr() ) );
    2100             :         }
    2101             :     }
    2102          11 :     return RTL_TEXTENCODING_DONTKNOW;
    2103             : }
    2104             : 
    2105          17 : rtl_TextEncoding HTMLParser::GetEncodingByHttpHeader( SvKeyValueIterator *pHTTPHeader )
    2106             : {
    2107          17 :     rtl_TextEncoding eRet = RTL_TEXTENCODING_DONTKNOW;
    2108          17 :     if( pHTTPHeader )
    2109             :     {
    2110          17 :         SvKeyValue aKV;
    2111          34 :         for( bool bCont = pHTTPHeader->GetFirst( aKV ); bCont;
    2112          17 :              bCont = pHTTPHeader->GetNext( aKV ) )
    2113             :         {
    2114          17 :             if( aKV.GetKey().equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_content_type ) )
    2115             :             {
    2116          17 :                 if( !aKV.GetValue().isEmpty() )
    2117             :                 {
    2118           0 :                     eRet = HTMLParser::GetEncodingByMIME( aKV.GetValue() );
    2119             :                 }
    2120             :             }
    2121          17 :         }
    2122             :     }
    2123          17 :     return eRet;
    2124             : }
    2125             : 
    2126          17 : bool HTMLParser::SetEncodingByHTTPHeader( SvKeyValueIterator *pHTTPHeader )
    2127             : {
    2128          17 :     bool bRet = false;
    2129          17 :     rtl_TextEncoding eEnc = HTMLParser::GetEncodingByHttpHeader( pHTTPHeader );
    2130          17 :     if(RTL_TEXTENCODING_DONTKNOW != eEnc)
    2131             :     {
    2132           0 :         SetSrcEncoding( eEnc );
    2133           0 :         bRet = true;
    2134             :     }
    2135          17 :     return bRet;
    2136             : }
    2137             : 
    2138             : 
    2139             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11