summaryrefslogtreecommitdiff
path: root/svtools/source/svhtml/parhtml.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/svhtml/parhtml.cxx')
-rw-r--r--svtools/source/svhtml/parhtml.cxx2371
1 files changed, 2371 insertions, 0 deletions
diff --git a/svtools/source/svhtml/parhtml.cxx b/svtools/source/svhtml/parhtml.cxx
new file mode 100644
index 000000000000..ade58688dc55
--- /dev/null
+++ b/svtools/source/svhtml/parhtml.cxx
@@ -0,0 +1,2371 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#include <tools/color.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/strbuf.hxx>
+#ifndef _SVSTDARR_HXX
+#define _SVSTDARR_ULONGS
+#include <svl/svstdarr.hxx>
+#endif
+
+#include <tools/tenccvt.hxx>
+#include <tools/datetime.hxx>
+#include <svl/inettype.hxx>
+#include <comphelper/string.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <svtools/parhtml.hxx>
+#include "htmltokn.h"
+#include "htmlkywd.hxx"
+
+
+using namespace ::com::sun::star;
+
+
+const sal_Int32 MAX_LEN( 1024L );
+//static sal_Unicode sTmpBuffer[ MAX_LEN+1 ];
+const sal_Int32 MAX_MACRO_LEN( 1024 );
+
+const sal_Int32 MAX_ENTITY_LEN( 8L );
+
+/* */
+
+// Tabellen zum Umwandeln von Options-Werten in Strings
+
+// <INPUT TYPE=xxx>
+static HTMLOptionEnum __READONLY_DATA aInputTypeOptEnums[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_IT_text, HTML_IT_TEXT },
+ { OOO_STRING_SVTOOLS_HTML_IT_password, HTML_IT_PASSWORD },
+ { OOO_STRING_SVTOOLS_HTML_IT_checkbox, HTML_IT_CHECKBOX },
+ { OOO_STRING_SVTOOLS_HTML_IT_radio, HTML_IT_RADIO },
+ { OOO_STRING_SVTOOLS_HTML_IT_range, HTML_IT_RANGE },
+ { OOO_STRING_SVTOOLS_HTML_IT_scribble, HTML_IT_SCRIBBLE },
+ { OOO_STRING_SVTOOLS_HTML_IT_file, HTML_IT_FILE },
+ { OOO_STRING_SVTOOLS_HTML_IT_hidden, HTML_IT_HIDDEN },
+ { OOO_STRING_SVTOOLS_HTML_IT_submit, HTML_IT_SUBMIT },
+ { OOO_STRING_SVTOOLS_HTML_IT_image, HTML_IT_IMAGE },
+ { OOO_STRING_SVTOOLS_HTML_IT_reset, HTML_IT_RESET },
+ { OOO_STRING_SVTOOLS_HTML_IT_button, HTML_IT_BUTTON },
+ { 0, 0 }
+};
+
+// <TABLE FRAME=xxx>
+static HTMLOptionEnum __READONLY_DATA aTableFrameOptEnums[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_TF_void, HTML_TF_VOID },
+ { OOO_STRING_SVTOOLS_HTML_TF_above, HTML_TF_ABOVE },
+ { OOO_STRING_SVTOOLS_HTML_TF_below, HTML_TF_BELOW },
+ { OOO_STRING_SVTOOLS_HTML_TF_hsides, HTML_TF_HSIDES },
+ { OOO_STRING_SVTOOLS_HTML_TF_lhs, HTML_TF_LHS },
+ { OOO_STRING_SVTOOLS_HTML_TF_rhs, HTML_TF_RHS },
+ { OOO_STRING_SVTOOLS_HTML_TF_vsides, HTML_TF_VSIDES },
+ { OOO_STRING_SVTOOLS_HTML_TF_box, HTML_TF_BOX },
+ { OOO_STRING_SVTOOLS_HTML_TF_border, HTML_TF_BOX },
+ { 0, 0 }
+};
+
+// <TABLE RULES=xxx>
+static HTMLOptionEnum __READONLY_DATA aTableRulesOptEnums[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_TR_none, HTML_TR_NONE },
+ { OOO_STRING_SVTOOLS_HTML_TR_groups, HTML_TR_GROUPS },
+ { OOO_STRING_SVTOOLS_HTML_TR_rows, HTML_TR_ROWS },
+ { OOO_STRING_SVTOOLS_HTML_TR_cols, HTML_TR_COLS },
+ { OOO_STRING_SVTOOLS_HTML_TR_all, HTML_TR_ALL },
+ { 0, 0 }
+};
+
+
+SV_IMPL_PTRARR(HTMLOptions,HTMLOptionPtr)
+
+/* */
+
+USHORT HTMLOption::GetEnum( const HTMLOptionEnum *pOptEnums, USHORT nDflt ) const
+{
+ USHORT nValue = nDflt;
+
+ while( pOptEnums->pName )
+ if( aValue.EqualsIgnoreCaseAscii( pOptEnums->pName ) )
+ break;
+ else
+ pOptEnums++;
+
+ if( pOptEnums->pName )
+ nValue = pOptEnums->nValue;
+
+ return nValue;
+}
+
+BOOL HTMLOption::GetEnum( USHORT &rEnum, const HTMLOptionEnum *pOptEnums ) const
+{
+ while( pOptEnums->pName )
+ {
+ if( aValue.EqualsIgnoreCaseAscii( pOptEnums->pName ) )
+ break;
+ else
+ pOptEnums++;
+ }
+
+ const sal_Char *pName = pOptEnums->pName;
+ if( pName )
+ rEnum = pOptEnums->nValue;
+
+ return (pName != 0);
+}
+
+HTMLOption::HTMLOption( USHORT nTok, const String& rToken,
+ const String& rValue )
+ : aValue(rValue)
+ , aToken(rToken)
+ , nToken( nTok )
+{
+ DBG_ASSERT( nToken>=HTML_OPTION_START && nToken<HTML_OPTION_END,
+ "HTMLOption: unbekanntes Token" );
+}
+
+sal_uInt32 HTMLOption::GetNumber() const
+{
+ DBG_ASSERT( (nToken>=HTML_OPTION_NUMBER_START &&
+ nToken<HTML_OPTION_NUMBER_END) ||
+ (nToken>=HTML_OPTION_CONTEXT_START &&
+ nToken<HTML_OPTION_CONTEXT_END) ||
+ nToken==HTML_O_VALUE,
+ "GetNumber: Option ist nicht numerisch" );
+ String aTmp( aValue );
+ aTmp.EraseLeadingChars();
+ sal_Int32 nTmp = aTmp.ToInt32();
+ return nTmp >= 0 ? (sal_uInt32)nTmp : 0;
+}
+
+INT32 HTMLOption::GetSNumber() const
+{
+ DBG_ASSERT( (nToken>=HTML_OPTION_NUMBER_START && nToken<HTML_OPTION_NUMBER_END) ||
+ (nToken>=HTML_OPTION_CONTEXT_START && nToken<HTML_OPTION_CONTEXT_END),
+ "GetSNumber: Option ist nicht numerisch" );
+ String aTmp( aValue );
+ aTmp.EraseLeadingChars();
+ return aTmp.ToInt32();
+}
+
+void HTMLOption::GetNumbers( SvULongs &rLongs, BOOL bSpaceDelim ) const
+{
+ if( rLongs.Count() )
+ rLongs.Remove( 0, rLongs.Count() );
+
+ if( bSpaceDelim )
+ {
+ // das ist ein sehr stark vereinfachter Scanner. Er sucht einfach
+ // alle Tiffern aus dem String
+ BOOL bInNum = FALSE;
+ ULONG nNum = 0;
+ for( xub_StrLen i=0; i<aValue.Len(); i++ )
+ {
+ register sal_Unicode c = aValue.GetChar( i );
+ if( c>='0' && c<='9' )
+ {
+ nNum *= 10;
+ nNum += (c - '0');
+ bInNum = TRUE;
+ }
+ else if( bInNum )
+ {
+ rLongs.Insert( nNum, rLongs.Count() );
+ bInNum = FALSE;
+ nNum = 0;
+ }
+ }
+ if( bInNum )
+ {
+ rLongs.Insert( nNum, rLongs.Count() );
+ }
+ }
+ else
+ {
+ // hier wird auf die korrekte Trennung der Zahlen durch ',' geachtet
+ // und auch mal eine 0 eingefuegt
+ xub_StrLen nPos = 0;
+ while( nPos < aValue.Len() )
+ {
+ register sal_Unicode c;
+ while( nPos < aValue.Len() &&
+ ((c=aValue.GetChar(nPos)) == ' ' || c == '\t' ||
+ c == '\n' || c== '\r' ) )
+ nPos++;
+
+ if( nPos==aValue.Len() )
+ rLongs.Insert( ULONG(0), rLongs.Count() );
+ else
+ {
+ xub_StrLen nEnd = aValue.Search( (sal_Unicode)',', nPos );
+ if( STRING_NOTFOUND==nEnd )
+ {
+ sal_Int32 nTmp = aValue.Copy(nPos).ToInt32();
+ rLongs.Insert( nTmp >= 0 ? (sal_uInt32)nTmp : 0,
+ rLongs.Count() );
+ nPos = aValue.Len();
+ }
+ else
+ {
+ sal_Int32 nTmp =
+ aValue.Copy(nPos,nEnd-nPos).ToInt32();
+ rLongs.Insert( nTmp >= 0 ? (sal_uInt32)nTmp : 0,
+ rLongs.Count() );
+ nPos = nEnd+1;
+ }
+ }
+ }
+ }
+}
+
+void HTMLOption::GetColor( Color& rColor ) const
+{
+ DBG_ASSERT( (nToken>=HTML_OPTION_COLOR_START && nToken<HTML_OPTION_COLOR_END) || nToken==HTML_O_SIZE,
+ "GetColor: Option spezifiziert keine Farbe" );
+
+ String aTmp( aValue );
+ aTmp.ToUpperAscii();
+ ULONG nColor = ULONG_MAX;
+ if( '#'!=aTmp.GetChar( 0 ) )
+ nColor = GetHTMLColor( aTmp );
+
+ if( ULONG_MAX == nColor )
+ {
+ nColor = 0;
+ xub_StrLen nPos = 0;
+ for( sal_uInt32 i=0; i<6; i++ )
+ {
+ // MIB 26.06.97: Wie auch immer Netscape Farbwerte ermittelt,
+ // maximal drei Zeichen, die kleiner als '0' sind werden
+ // ignoriert. Bug #40901# stimmt damit. Mal schauen, was sich
+ // irgendwelche HTML-Autoren noch so einfallen lassen...
+ register sal_Unicode c = nPos<aTmp.Len() ? aTmp.GetChar( nPos++ )
+ : '0';
+ if( c < '0' )
+ {
+ c = nPos<aTmp.Len() ? aTmp.GetChar(nPos++) : '0';
+ if( c < '0' )
+ c = nPos<aTmp.Len() ? aTmp.GetChar(nPos++) : '0';
+ }
+ nColor *= 16;
+ if( c >= '0' && c <= '9' )
+ nColor += (c - 48);
+ else if( c >= 'A' && c <= 'F' )
+ nColor += (c - 55);
+ }
+ }
+
+ rColor.SetRed( (BYTE)((nColor & 0x00ff0000) >> 16) );
+ rColor.SetGreen( (BYTE)((nColor & 0x0000ff00) >> 8));
+ rColor.SetBlue( (BYTE)(nColor & 0x000000ff) );
+}
+
+HTMLInputType HTMLOption::GetInputType() const
+{
+ DBG_ASSERT( nToken==HTML_O_TYPE, "GetInputType: Option nicht TYPE" );
+ return (HTMLInputType)GetEnum( aInputTypeOptEnums, HTML_IT_TEXT );
+}
+
+HTMLTableFrame HTMLOption::GetTableFrame() const
+{
+ DBG_ASSERT( nToken==HTML_O_FRAME, "GetTableFrame: Option nicht FRAME" );
+ return (HTMLTableFrame)GetEnum( aTableFrameOptEnums, HTML_TF_VOID );
+}
+
+HTMLTableRules HTMLOption::GetTableRules() const
+{
+ DBG_ASSERT( nToken==HTML_O_RULES, "GetTableRules: Option nicht RULES" );
+ return (HTMLTableRules)GetEnum( aTableRulesOptEnums, HTML_TR_NONE );
+}
+
+/* */
+
+HTMLParser::HTMLParser( SvStream& rIn, int bReadNewDoc )
+ : SvParser( rIn )
+{
+ bNewDoc = bReadNewDoc;
+ bReadListing = bReadXMP = bReadPRE = bReadTextArea =
+ bReadScript = bReadStyle =
+ bEndTokenFound = bIsInBody = bReadNextChar =
+ bReadComment = FALSE;
+ bIsInHeader = TRUE;
+ pOptions = new HTMLOptions;
+}
+
+HTMLParser::~HTMLParser()
+{
+ if( pOptions && pOptions->Count() )
+ pOptions->DeleteAndDestroy( 0, pOptions->Count() );
+ delete pOptions;
+}
+
+SvParserState __EXPORT HTMLParser::CallParser()
+{
+ eState = SVPAR_WORKING;
+ nNextCh = GetNextChar();
+ SaveState( 0 );
+
+ nPre_LinePos = 0;
+ bPre_IgnoreNewPara = FALSE;
+
+ AddRef();
+ Continue( 0 );
+ if( SVPAR_PENDING != eState )
+ ReleaseRef(); // dann brauchen wir den Parser nicht mehr!
+
+ return eState;
+}
+
+void HTMLParser::Continue( int nToken )
+{
+ if( !nToken )
+ nToken = GetNextToken();
+
+ while( IsParserWorking() )
+ {
+ SaveState( nToken );
+ nToken = FilterToken( nToken );
+
+ if( nToken )
+ NextToken( nToken );
+
+ if( IsParserWorking() )
+ SaveState( 0 ); // bis hierhin abgearbeitet,
+ // weiter mit neuem Token!
+ nToken = GetNextToken();
+ }
+}
+
+int HTMLParser::FilterToken( int nToken )
+{
+ switch( nToken )
+ {
+ case sal_Unicode(EOF):
+ nToken = 0;
+ break; // nicht verschicken
+
+ case HTML_HEAD_OFF:
+ bIsInBody = TRUE;
+ case HTML_HEAD_ON:
+ bIsInHeader = HTML_HEAD_ON == nToken;
+ break;
+
+ case HTML_BODY_ON:
+ case HTML_FRAMESET_ON:
+ bIsInHeader = FALSE;
+ bIsInBody = HTML_BODY_ON == nToken;
+ break;
+
+ case HTML_BODY_OFF:
+ bIsInBody = bReadPRE = bReadListing = bReadXMP = FALSE;
+ break;
+
+ case HTML_HTML_OFF:
+ nToken = 0;
+ bReadPRE = bReadListing = bReadXMP = FALSE;
+ break; // HTML_ON wurde auch nicht verschickt !
+
+ case HTML_PREFORMTXT_ON:
+ StartPRE();
+ break;
+
+ case HTML_PREFORMTXT_OFF:
+ FinishPRE();
+ break;
+
+ case HTML_LISTING_ON:
+ StartListing();
+ break;
+
+ case HTML_LISTING_OFF:
+ FinishListing();
+ break;
+
+ case HTML_XMP_ON:
+ StartXMP();
+ break;
+
+ case HTML_XMP_OFF:
+ FinishXMP();
+ break;
+
+ default:
+ if( bReadPRE )
+ nToken = FilterPRE( nToken );
+ else if( bReadListing )
+ nToken = FilterListing( nToken );
+ else if( bReadXMP )
+ nToken = FilterXMP( nToken );
+
+ break;
+ }
+
+ return nToken;
+}
+
+#define HTML_ISDIGIT( c ) (c >= '0' && c <= '9')
+#define HTML_ISALPHA( c ) ( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') )
+#define HTML_ISALNUM( c ) ( HTML_ISALPHA(c) || HTML_ISDIGIT(c) )
+#define HTML_ISSPACE( c ) ( ' ' == c || (c >= 0x09 && c <= 0x0d) )
+#define HTML_ISPRINTABLE( c ) ( c >= 32 && c != 127)
+// --> OD 2006-07-26 #138464#
+#define HTML_ISHEXDIGIT( c ) ( HTML_ISDIGIT(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') )
+// <--
+
+int HTMLParser::ScanText( const sal_Unicode cBreak )
+{
+ ::rtl::OUStringBuffer sTmpBuffer( MAX_LEN );
+ int bWeiter = TRUE;
+ int bEqSignFound = FALSE;
+ sal_Unicode cQuote = 0U;
+
+ while( bWeiter && IsParserWorking() )
+ {
+ int bNextCh = TRUE;
+ switch( nNextCh )
+ {
+ case '&':
+ bEqSignFound = FALSE;
+ if( bReadXMP )
+ sTmpBuffer.append( (sal_Unicode)'&' );
+ else
+ {
+ ULONG nStreamPos = rInput.Tell();
+ ULONG nLinePos = GetLinePos();
+
+ sal_Unicode cChar = 0U;
+ if( '#' == (nNextCh = GetNextChar()) )
+ {
+ nNextCh = GetNextChar();
+ // --> OD 2006-07-26 #138464#
+ // consider hexadecimal digits
+ const sal_Bool bIsHex( 'x' == nNextCh );
+ const sal_Bool bIsDecOrHex( bIsHex || HTML_ISDIGIT(nNextCh) );
+ if ( bIsDecOrHex )
+ {
+ if ( bIsHex )
+ {
+ nNextCh = GetNextChar();
+ while ( HTML_ISHEXDIGIT(nNextCh) )
+ {
+ cChar = cChar * 16U +
+ ( nNextCh <= '9'
+ ? sal_Unicode( nNextCh - '0' )
+ : ( nNextCh <= 'F'
+ ? sal_Unicode( nNextCh - 'A' + 10 )
+ : sal_Unicode( nNextCh - 'a' + 10 ) ) );
+ nNextCh = GetNextChar();
+ }
+ }
+ else
+ {
+ do
+ {
+ cChar = cChar * 10U + sal_Unicode( nNextCh - '0');
+ nNextCh = GetNextChar();
+ }
+ while( HTML_ISDIGIT(nNextCh) );
+ }
+
+ if( RTL_TEXTENCODING_DONTKNOW != eSrcEnc &&
+ RTL_TEXTENCODING_UCS2 != eSrcEnc &&
+ RTL_TEXTENCODING_UTF8 != eSrcEnc &&
+ cChar < 256 )
+ {
+ sal_Unicode cOrig = cChar;
+ cChar = ByteString::ConvertToUnicode(
+ (sal_Char)cChar, eSrcEnc );
+ if( 0U == cChar )
+ {
+ // #73398#: If the character could not be
+ // converted, because a conversion is not
+ // available, do no conversion at all.
+ cChar = cOrig;
+ }
+ }
+ }
+ // <--
+ else
+ nNextCh = 0U;
+ }
+ else if( HTML_ISALPHA( nNextCh ) )
+ {
+ ::rtl::OUStringBuffer sEntityBuffer( MAX_ENTITY_LEN );
+ xub_StrLen nPos = 0L;
+ do
+ {
+ sEntityBuffer.append( nNextCh );
+ nPos++;
+ nNextCh = GetNextChar();
+ }
+ while( nPos < MAX_ENTITY_LEN && HTML_ISALNUM( nNextCh ) &&
+ !rInput.IsEof() );
+
+ if( IsParserWorking() && !rInput.IsEof() )
+ {
+ String sEntity( sEntityBuffer.getStr(), nPos );
+ cChar = GetHTMLCharName( sEntity );
+
+ // nicht gefunden ( == 0 ), dann Klartext
+ // oder ein Zeichen das als Attribut eingefuegt
+ // wird
+ if( 0U == cChar && ';' != nNextCh )
+ {
+ DBG_ASSERT( rInput.Tell() - nStreamPos ==
+ (ULONG)(nPos+1L)*GetCharSize(),
+ "UTF-8 geht hier schief" );
+ for( xub_StrLen i=nPos-1L; i>1L; i-- )
+ {
+ nNextCh = sEntityBuffer[i];
+ sEntityBuffer.setLength( i );
+ sEntity.Assign( sEntityBuffer.getStr(), i );
+ cChar = GetHTMLCharName( sEntity );
+ if( cChar )
+ {
+ rInput.SeekRel( -(long)
+ ((nPos-i)*GetCharSize()) );
+ nlLinePos -= sal_uInt32(nPos-i);
+ nPos = i;
+ ClearTxtConvContext();
+ break;
+ }
+ }
+ }
+
+ if( !cChar ) // unbekanntes Zeichen?
+ {
+ // dann im Stream zurueck, das '&' als Zeichen
+ // einfuegen und mit dem nachfolgenden Zeichen
+ // wieder aufsetzen
+ sTmpBuffer.append( (sal_Unicode)'&' );
+
+// rInput.SeekRel( -(long)(++nPos*GetCharSize()) );
+// nlLinePos -= nPos;
+ DBG_ASSERT( rInput.Tell()-nStreamPos ==
+ (ULONG)(nPos+1)*GetCharSize(),
+ "Falsche Stream-Position" );
+ DBG_ASSERT( nlLinePos-nLinePos ==
+ (ULONG)(nPos+1),
+ "Falsche Zeilen-Position" );
+ rInput.Seek( nStreamPos );
+ nlLinePos = nLinePos;
+ ClearTxtConvContext();
+ break;
+ }
+
+ // 1 == Non Breaking Space
+ // 2 == SoftHyphen
+
+ if( cChar < 3U )
+ {
+ if( '>' == cBreak )
+ {
+ // Wenn der Inhalt eines Tags gelesen wird,
+ // muessen wir ein Space bzw. - daraus machen
+ switch( cChar )
+ {
+ case 1U: cChar = ' '; break;
+ case 2U: cChar = '-'; break;
+ default:
+ DBG_ASSERT( cChar==1U,
+ "\0x00 sollte doch schon laengt abgefangen sein!" );
+ break;
+ }
+ }
+ else
+ {
+ // Wenn kein Tag gescannt wird, enstprechendes
+ // Token zurueckgeben
+ aToken +=
+ String( sTmpBuffer.makeStringAndClear() );
+ if( cChar )
+ {
+ if( aToken.Len() )
+ {
+ // mit dem Zeichen wieder aufsetzen
+ nNextCh = '&';
+// rInput.SeekRel( -(long)(++nPos*GetCharSize()) );
+// nlLinePos -= nPos;
+ DBG_ASSERT( rInput.Tell()-nStreamPos ==
+ (ULONG)(nPos+1)*GetCharSize(),
+ "Falsche Stream-Position" );
+ DBG_ASSERT( nlLinePos-nLinePos ==
+ (ULONG)(nPos+1),
+ "Falsche Zeilen-Position" );
+ rInput.Seek( nStreamPos );
+ nlLinePos = nLinePos;
+ ClearTxtConvContext();
+ return HTML_TEXTTOKEN;
+ }
+
+ // Hack: _GetNextChar soll nicht das
+ // naechste Zeichen lesen
+ if( ';' != nNextCh )
+ aToken += ' ';
+ if( 1U == cChar )
+ return HTML_NONBREAKSPACE;
+ if( 2U == cChar )
+ return HTML_SOFTHYPH;
+ }
+ aToken += (sal_Unicode)'&';
+ aToken +=
+ String(sEntityBuffer.makeStringAndClear());
+ break;
+ }
+ }
+ }
+ else
+ nNextCh = 0U;
+ }
+ // MIB 03/02/2000: &{...};-JavaScript-Macros are not
+ // supported any longer.
+ else if( IsParserWorking() )
+ {
+ sTmpBuffer.append( (sal_Unicode)'&' );
+ bNextCh = FALSE;
+ break;
+ }
+
+ bNextCh = (';' == nNextCh);
+ if( cBreak=='>' && (cChar=='\\' || cChar=='\'' ||
+ cChar=='\"' || cChar==' ') )
+ {
+ // ' und " mussen innerhalb von Tags mit einem
+ // gekennzeichnet werden, um sie von ' und " als Klammern
+ // um Optionen zu unterscheiden. Logischerweise muss
+ // deshalb auch ein \ gekeenzeichnet werden. Ausserdem
+ // schuetzen wir ein Space, weil es kein Trennzeichen
+ // zwischen Optionen ist.
+ sTmpBuffer.append( (sal_Unicode)'\\' );
+ if( MAX_LEN == sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ }
+ if( IsParserWorking() )
+ {
+ if( cChar )
+ sTmpBuffer.append( cChar );
+ }
+ else if( SVPAR_PENDING==eState && '>'!=cBreak )
+ {
+ // Mit dem '&' Zeichen wieder aufsetzen, der Rest
+ // wird als Texttoken zurueckgegeben.
+ if( aToken.Len() || sTmpBuffer.getLength() )
+ {
+ // Der bisherige Text wird von _GetNextChar()
+ // zurueckgegeben und beim naechsten Aufruf wird
+ // ein neues Zeichen gelesen. Also muessen wir uns
+ // noch vor das & stellen.
+ nNextCh = 0U;
+ rInput.Seek( nStreamPos-(sal_uInt32)GetCharSize() );
+ nlLinePos = nLinePos-1;
+ ClearTxtConvContext();
+ bReadNextChar = TRUE;
+ }
+ bNextCh = FALSE;
+ }
+ }
+ break;
+ case '=':
+ if( '>'==cBreak && !cQuote )
+ bEqSignFound = TRUE;
+ sTmpBuffer.append( nNextCh );
+ break;
+
+ case '\\':
+ if( '>'==cBreak )
+ {
+ // Innerhalb von Tags kennzeichnen
+ sTmpBuffer.append( (sal_Unicode)'\\' );
+ if( MAX_LEN == sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ }
+ sTmpBuffer.append( (sal_Unicode)'\\' );
+ break;
+
+ case '\"':
+ case '\'':
+ if( '>'==cBreak )
+ {
+ if( bEqSignFound )
+ cQuote = nNextCh;
+ else if( cQuote && (cQuote==nNextCh ) )
+ cQuote = 0U;
+ }
+ sTmpBuffer.append( nNextCh );
+ bEqSignFound = FALSE;
+ break;
+
+ case sal_Unicode(EOF):
+ if( rInput.IsEof() )
+ {
+// MIB 20.11.98: Das macht hier keinen Sinn, oder doch: Zumindest wird
+// abc&auml;<EOF> nicht angezeigt, also lassen wir das in Zukunft.
+// if( '>' != cBreak )
+// eState = SVPAR_ACCEPTED;
+ bWeiter = FALSE;
+ }
+ else
+ {
+ sTmpBuffer.append( nNextCh );
+ }
+ break;
+
+ case '<':
+ bEqSignFound = FALSE;
+ if( '>'==cBreak )
+ sTmpBuffer.append( nNextCh );
+ else
+ bWeiter = FALSE; // Abbrechen, String zusammen
+ break;
+
+ case '\f':
+ if( '>' == cBreak )
+ {
+ // Beim Scannen von Optionen wie ein Space behandeln
+ sTmpBuffer.append( (sal_Unicode)' ' );
+ }
+ else
+ {
+ // sonst wird es ein eigenes Token
+ bWeiter = FALSE;
+ }
+ break;
+
+ case '\r':
+ case '\n':
+ if( '>'==cBreak )
+ {
+ // #26979# cr/lf in Tag wird in _GetNextToken() behandeln
+ sTmpBuffer.append( nNextCh );
+ break;
+ }
+ else if( bReadListing || bReadXMP || bReadPRE || bReadTextArea )
+ {
+ bWeiter = FALSE;
+ break;
+ }
+ // Bug 18984: CR-LF -> Blank
+ // Folge von CR/LF/BLANK/TAB nur in ein Blank wandeln
+ // kein break!!
+ case '\t':
+ if( '\t'==nNextCh && bReadPRE && '>'!=cBreak )
+ {
+ // In <PRE>: Tabs nach oben durchreichen
+ bWeiter = FALSE;
+ break;
+ }
+ // kein break
+ case '\x0b':
+ if( '\x0b'==nNextCh && (bReadPRE || bReadXMP ||bReadListing) &&
+ '>'!=cBreak )
+ {
+ break;
+ }
+ nNextCh = ' ';
+ // kein break;
+ case ' ':
+ sTmpBuffer.append( nNextCh );
+ if( '>'!=cBreak && (!bReadListing && !bReadXMP &&
+ !bReadPRE && !bReadTextArea) )
+ {
+ // alle Folgen von Blanks/Tabs/CR/LF zu einem Blank umwandeln
+ do {
+ if( sal_Unicode(EOF) == (nNextCh = GetNextChar()) &&
+ rInput.IsEof() )
+ {
+ if( aToken.Len() || sTmpBuffer.getLength() > 1L )
+ {
+ // ausser den Blanks wurde noch etwas geselen
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ return HTML_TEXTTOKEN;
+ }
+ else
+ // nur Blanks gelesen: dann darf kein Text
+ // mehr zurueckgegeben werden und _GetNextToken
+ // muss auf EOF laufen
+ return 0;
+ }
+ } while ( ' ' == nNextCh || '\t' == nNextCh ||
+ '\r' == nNextCh || '\n' == nNextCh ||
+ '\x0b' == nNextCh );
+ bNextCh = FALSE;
+ }
+ break;
+
+ default:
+ bEqSignFound = FALSE;
+ if( (nNextCh==cBreak && !cQuote) ||
+ (ULONG(aToken.Len()) + MAX_LEN) > ULONG(STRING_MAXLEN & ~1 ))
+ bWeiter = FALSE;
+ else
+ {
+ do {
+ // alle anderen Zeichen kommen in den Text
+ sTmpBuffer.append( nNextCh );
+ if( MAX_LEN == sTmpBuffer.getLength() )
+ {
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ if( (ULONG(aToken.Len()) + MAX_LEN) >
+ ULONG(STRING_MAXLEN & ~1 ) )
+ {
+ nNextCh = GetNextChar();
+ return HTML_TEXTTOKEN;
+ }
+ }
+ if( ( sal_Unicode(EOF) == (nNextCh = GetNextChar()) &&
+ rInput.IsEof() ) ||
+ !IsParserWorking() )
+ {
+ if( sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ return HTML_TEXTTOKEN;
+ }
+ } while( HTML_ISALPHA( nNextCh ) || HTML_ISDIGIT( nNextCh ) );
+ bNextCh = FALSE;
+ }
+ }
+
+ if( MAX_LEN == sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+
+ if( bWeiter && bNextCh )
+ nNextCh = GetNextChar();
+ }
+
+ if( sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+
+ return HTML_TEXTTOKEN;
+}
+
+int HTMLParser::_GetNextRawToken()
+{
+ ::rtl::OUStringBuffer sTmpBuffer( MAX_LEN );
+
+ if( bEndTokenFound )
+ {
+ // beim letzten Aufruf haben wir das End-Token bereits gefunden,
+ // deshalb muessen wir es nicht noch einmal suchen
+ bReadScript = FALSE;
+ bReadStyle = FALSE;
+ aEndToken.Erase();
+ bEndTokenFound = FALSE;
+
+ return 0;
+ }
+
+ // per default geben wir HTML_RAWDATA zurueck
+ int bWeiter = TRUE;
+ int nToken = HTML_RAWDATA;
+ SaveState( 0 );
+ while( bWeiter && IsParserWorking() )
+ {
+ int bNextCh = TRUE;
+ switch( nNextCh )
+ {
+ case '<':
+ {
+ // Vielleicht haben wir das Ende erreicht
+
+ // das bisher gelesene erstmal retten
+ aToken += String(sTmpBuffer.makeStringAndClear());
+
+ // und die Position im Stream merken
+ ULONG nStreamPos = rInput.Tell();
+ ULONG nLineNr = GetLineNr();
+ ULONG nLinePos = GetLinePos();
+
+ // Start eines End-Token?
+ int bOffState = FALSE;
+ if( '/' == (nNextCh = GetNextChar()) )
+ {
+ bOffState = TRUE;
+ nNextCh = GetNextChar();
+ }
+ else if( '!' == nNextCh )
+ {
+ sTmpBuffer.append( nNextCh );
+ nNextCh = GetNextChar();
+ }
+
+ // jetzt die Buchstaben danach lesen
+ while( (HTML_ISALPHA(nNextCh) || '-'==nNextCh) &&
+ IsParserWorking() && sTmpBuffer.getLength() < MAX_LEN )
+ {
+ sTmpBuffer.append( nNextCh );
+ nNextCh = GetNextChar();
+ }
+
+ String aTok( sTmpBuffer.getStr(),
+ sal::static_int_cast< xub_StrLen >(
+ sTmpBuffer.getLength()) );
+ aTok.ToUpperAscii();
+ BOOL bDone = FALSE;
+ if( bReadScript || aEndToken.Len() )
+ {
+ if( !bReadComment )
+ {
+ if( aTok.CompareToAscii( OOO_STRING_SVTOOLS_HTML_comment, 3 )
+ == COMPARE_EQUAL )
+ {
+ bReadComment = TRUE;
+ }
+ else
+ {
+ // ein Script muss mit "</SCRIPT>" aufhoehren, wobei
+ // wir es mit dem ">" aus sicherheitsgruenden
+ // erstmal nicht so genau nehmen
+ bDone = bOffState && // '>'==nNextCh &&
+ COMPARE_EQUAL == ( bReadScript
+ ? aTok.CompareToAscii(OOO_STRING_SVTOOLS_HTML_script)
+ : aTok.CompareTo(aEndToken) );
+ }
+ }
+ if( bReadComment && '>'==nNextCh && aTok.Len() >= 2 &&
+ aTok.Copy( aTok.Len()-2 ).EqualsAscii( "--" ) )
+ {
+ // hier ist ein Kommentar der Art <!-----> zuende
+ bReadComment = FALSE;
+ }
+ }
+ else
+ {
+ // ein Style-Sheet kann mit </STYLE>, </HEAD> oder
+ // <BODY> aughoehren
+ if( bOffState )
+ bDone = aTok.CompareToAscii(OOO_STRING_SVTOOLS_HTML_style)
+ == COMPARE_EQUAL ||
+ aTok.CompareToAscii(OOO_STRING_SVTOOLS_HTML_head)
+ == COMPARE_EQUAL;
+ else
+ bDone =
+ aTok.CompareToAscii(OOO_STRING_SVTOOLS_HTML_body) == COMPARE_EQUAL;
+ }
+
+ if( bDone )
+ {
+ // das war's, jetzt muessen wir gegebenenfalls den
+ // bisher gelesenen String zurueckgeben und dnach normal
+ // weitermachen
+
+ bWeiter = FALSE;
+
+ // nToken==0 heisst, dass _GetNextToken gleich weiterliest
+ if( !aToken.Len() && (bReadStyle || bReadScript) )
+ {
+ // wir koennen sofort die Umgebung beeden und
+ // das End-Token parsen
+ bReadScript = FALSE;
+ bReadStyle = FALSE;
+ aEndToken.Erase();
+ nToken = 0;
+ }
+ else
+ {
+ // wir muessen bReadScript/bReadStyle noch am
+ // Leben lassen und koennen erst beim naechsten
+ // mal das End-Token Parsen
+ bEndTokenFound = TRUE;
+ }
+
+ // jetzt fahren wir im Stream auf das '<' zurueck
+ rInput.Seek( nStreamPos );
+ SetLineNr( nLineNr );
+ SetLinePos( nLinePos );
+ ClearTxtConvContext();
+ nNextCh = '<';
+
+ // den String wollen wir nicht an das Token haengen
+ sTmpBuffer.setLength( 0L );
+ }
+ else
+ {
+ // "</" merken, alles andere steht noch im buffer
+ aToken += (sal_Unicode)'<';
+ if( bOffState )
+ aToken += (sal_Unicode)'/';
+
+ bNextCh = FALSE;
+ }
+ }
+ break;
+ case '-':
+ sTmpBuffer.append( nNextCh );
+ if( bReadComment )
+ {
+ BOOL bTwoMinus = FALSE;
+ nNextCh = GetNextChar();
+ while( '-' == nNextCh && IsParserWorking() )
+ {
+ bTwoMinus = TRUE;
+
+ if( MAX_LEN == sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ sTmpBuffer.append( nNextCh );
+ nNextCh = GetNextChar();
+ }
+
+ if( '>' == nNextCh && IsParserWorking() && bTwoMinus )
+ bReadComment = FALSE;
+
+ bNextCh = FALSE;
+ }
+ break;
+
+ case '\r':
+ // \r\n? beendet das aktuelle Text-Token (auch wenn es leer ist)
+ nNextCh = GetNextChar();
+ if( nNextCh=='\n' )
+ nNextCh = GetNextChar();
+ bWeiter = FALSE;
+ break;
+ case '\n':
+ // \n beendet das aktuelle Text-Token (auch wenn es leer ist)
+ nNextCh = GetNextChar();
+ bWeiter = FALSE;
+ break;
+ case sal_Unicode(EOF):
+ // eof beendet das aktuelle Text-Token und tut so, als ob
+ // ein End-Token gelesen wurde
+ if( rInput.IsEof() )
+ {
+ bWeiter = FALSE;
+ if( aToken.Len() || sTmpBuffer.getLength() )
+ {
+ bEndTokenFound = TRUE;
+ }
+ else
+ {
+ bReadScript = FALSE;
+ bReadStyle = FALSE;
+ aEndToken.Erase();
+ nToken = 0;
+ }
+ break;
+ }
+ // kein break
+ default:
+ // alle anderen Zeichen landen im Buffer
+ sTmpBuffer.append( nNextCh );
+ break;
+ }
+
+ if( (!bWeiter && sTmpBuffer.getLength() > 0L) ||
+ MAX_LEN == sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+
+ if( bWeiter && bNextCh )
+ nNextCh = GetNextChar();
+ }
+
+ if( IsParserWorking() )
+ SaveState( 0 );
+ else
+ nToken = 0;
+
+ return nToken;
+}
+
+// scanne das naechste Token,
+int __EXPORT HTMLParser::_GetNextToken()
+{
+ int nRet = 0;
+ sSaveToken.Erase();
+
+ // die Optionen loeschen
+ if( pOptions->Count() )
+ pOptions->DeleteAndDestroy( 0, pOptions->Count() );
+
+ if( !IsParserWorking() ) // wenn schon Fehler, dann nicht weiter!
+ return 0;
+
+ BOOL bReadNextCharSave = bReadNextChar;
+ if( bReadNextChar )
+ {
+ DBG_ASSERT( !bEndTokenFound,
+ "</SCRIPT> gelesen und trotzdem noch ein Zeichen lesen?" );
+ nNextCh = GetNextChar();
+ if( !IsParserWorking() ) // wenn schon Fehler, dann nicht weiter!
+ return 0;
+ bReadNextChar = FALSE;
+ }
+
+ if( bReadScript || bReadStyle || aEndToken.Len() )
+ {
+ nRet = _GetNextRawToken();
+ if( nRet || !IsParserWorking() )
+ return nRet;
+ }
+
+ do {
+ int bNextCh = TRUE;
+ switch( nNextCh )
+ {
+ case '<':
+ {
+ ULONG nStreamPos = rInput.Tell();
+ ULONG nLineNr = GetLineNr();
+ ULONG nLinePos = GetLinePos();
+
+ int bOffState = FALSE;
+ if( '/' == (nNextCh = GetNextChar()) )
+ {
+ bOffState = TRUE;
+ nNextCh = GetNextChar();
+ }
+ if( HTML_ISALPHA( nNextCh ) || '!'==nNextCh ) // fix #26984#
+ {
+ ::rtl::OUStringBuffer sTmpBuffer;
+ do {
+ sTmpBuffer.append( nNextCh );
+ if( MAX_LEN == sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+ nNextCh = GetNextChar();
+ } while( '>' != nNextCh && !HTML_ISSPACE( nNextCh ) &&
+ IsParserWorking() && !rInput.IsEof() );
+
+ if( sTmpBuffer.getLength() )
+ aToken += String(sTmpBuffer.makeStringAndClear());
+
+ // Blanks ueberlesen
+ while( HTML_ISSPACE( nNextCh ) && IsParserWorking() )
+ nNextCh = GetNextChar();
+
+ if( !IsParserWorking() )
+ {
+ if( SVPAR_PENDING == eState )
+ bReadNextChar = bReadNextCharSave;
+ break;
+ }
+
+ // suche das Token in der Tabelle:
+ sSaveToken = aToken;
+ aToken.ToUpperAscii();
+ if( 0 == (nRet = GetHTMLToken( aToken )) )
+ // Unknown Control
+ nRet = HTML_UNKNOWNCONTROL_ON;
+
+ // Wenn es ein Token zum ausschalten ist ...
+ if( bOffState )
+ {
+ if( HTML_TOKEN_ONOFF & nRet )
+ {
+ // und es ein Off-Token gibt, das daraus machen
+ ++nRet;
+ }
+ else if( HTML_LINEBREAK!=nRet )
+ {
+ // und es kein Off-Token gibt, ein unbekanntes
+ // Token daraus machen (ausser </BR>, das wird
+ // wie <BR> behandelt
+ nRet = HTML_UNKNOWNCONTROL_OFF;
+ }
+ }
+
+ if( nRet == HTML_COMMENT )
+ {
+ // fix: sSaveToken wegen Gross-/Kleinschreibung
+ // als Anfang des Kommentars benutzen und ein
+ // Space anhaengen.
+ aToken = sSaveToken;
+ if( '>'!=nNextCh )
+ aToken += (sal_Unicode)' ';
+ ULONG nCStreamPos = 0;
+ ULONG nCLineNr = 0;
+ ULONG nCLinePos = 0;
+ xub_StrLen nCStrLen = 0;
+
+ BOOL bDone = FALSE;
+ // bis zum schliessenden --> lesen. wenn keins gefunden
+ // wurde beim der ersten > wieder aufsetzen
+ while( !bDone && !rInput.IsEof() && IsParserWorking() )
+ {
+ if( '>'==nNextCh )
+ {
+ if( !nCStreamPos )
+ {
+ nCStreamPos = rInput.Tell();
+ nCStrLen = aToken.Len();
+ nCLineNr = GetLineNr();
+ nCLinePos = GetLinePos();
+ }
+ bDone = aToken.Len() >= 2 &&
+ aToken.Copy(aToken.Len()-2,2).
+ EqualsAscii( "--" );
+ if( !bDone )
+ aToken += nNextCh;
+ }
+ else
+ aToken += nNextCh;
+ if( !bDone )
+ nNextCh = GetNextChar();
+ }
+ if( !bDone && IsParserWorking() && nCStreamPos )
+ {
+ rInput.Seek( nCStreamPos );
+ SetLineNr( nCLineNr );
+ SetLinePos( nCLinePos );
+ ClearTxtConvContext();
+ aToken.Erase( nCStrLen );
+ nNextCh = '>';
+ }
+ }
+ else
+ {
+ // den TokenString koennen wir jetzt verwerfen
+ aToken.Erase();
+ }
+
+ // dann lesen wir mal alles bis zur schliessenden '>'
+ if( '>' != nNextCh && IsParserWorking() )
+ {
+ ScanText( '>' );
+ if( sal_Unicode(EOF) == nNextCh && rInput.IsEof() )
+ {
+ // zurueck hinter die < gehen und dort neu
+ // aufsetzen, das < als Text zurueckgeben
+ rInput.Seek( nStreamPos );
+ SetLineNr( nLineNr );
+ SetLinePos( nLinePos );
+ ClearTxtConvContext();
+
+ aToken = '<';
+ nRet = HTML_TEXTTOKEN;
+ nNextCh = GetNextChar();
+ bNextCh = FALSE;
+ break;
+ }
+ }
+ if( SVPAR_PENDING == eState )
+ bReadNextChar = bReadNextCharSave;
+ }
+ else
+ {
+ if( bOffState )
+ {
+ // einfach alles wegschmeissen
+ ScanText( '>' );
+ if( sal_Unicode(EOF) == nNextCh && rInput.IsEof() )
+ {
+ // zurueck hinter die < gehen und dort neu
+ // aufsetzen, das < als Text zurueckgeben
+ rInput.Seek( nStreamPos );
+ SetLineNr( nLineNr );
+ SetLinePos( nLinePos );
+ ClearTxtConvContext();
+
+ aToken = '<';
+ nRet = HTML_TEXTTOKEN;
+ nNextCh = GetNextChar();
+ bNextCh = FALSE;
+ break;
+ }
+ if( SVPAR_PENDING == eState )
+ bReadNextChar = bReadNextCharSave;
+ aToken.Erase();
+ }
+ else if( '%' == nNextCh )
+ {
+ nRet = HTML_UNKNOWNCONTROL_ON;
+
+ ULONG nCStreamPos = rInput.Tell();
+ ULONG nCLineNr = GetLineNr(), nCLinePos = GetLinePos();
+
+ BOOL bDone = FALSE;
+ // bis zum schliessenden %> lesen. wenn keins gefunden
+ // wurde beim der ersten > wieder aufsetzen
+ while( !bDone && !rInput.IsEof() && IsParserWorking() )
+ {
+ bDone = '>'==nNextCh && aToken.Len() >= 1 &&
+ '%' == aToken.GetChar( aToken.Len()-1 );
+ if( !bDone )
+ {
+ aToken += nNextCh;
+ nNextCh = GetNextChar();
+ }
+ }
+ if( !bDone && IsParserWorking() )
+ {
+ rInput.Seek( nCStreamPos );
+ SetLineNr( nCLineNr );
+ SetLinePos( nCLinePos );
+ ClearTxtConvContext();
+ aToken.AssignAscii( "<%", 2 );
+ nRet = HTML_TEXTTOKEN;
+ break;
+ }
+ if( IsParserWorking() )
+ {
+ sSaveToken = aToken;
+ aToken.Erase();
+ }
+ }
+ else
+ {
+ aToken = '<';
+ nRet = HTML_TEXTTOKEN;
+ bNextCh = FALSE;
+ break;
+ }
+ }
+
+ if( IsParserWorking() )
+ {
+ bNextCh = '>' == nNextCh;
+ switch( nRet )
+ {
+ case HTML_TEXTAREA_ON:
+ bReadTextArea = TRUE;
+ break;
+ case HTML_TEXTAREA_OFF:
+ bReadTextArea = FALSE;
+ break;
+ case HTML_SCRIPT_ON:
+ if( !bReadTextArea )
+ bReadScript = TRUE;
+ break;
+ case HTML_SCRIPT_OFF:
+ if( !bReadTextArea )
+ {
+ bReadScript = FALSE;
+ // JavaScript kann den Stream veraendern
+ // also muss das letzte Zeichen nochmals
+ // gelesen werden
+ bReadNextChar = TRUE;
+ bNextCh = FALSE;
+ }
+ break;
+
+ case HTML_STYLE_ON:
+ bReadStyle = TRUE;
+ break;
+ case HTML_STYLE_OFF:
+ bReadStyle = FALSE;
+ break;
+ }
+
+ }
+ }
+ break;
+
+ case sal_Unicode(EOF):
+ if( rInput.IsEof() )
+ {
+ eState = SVPAR_ACCEPTED;
+ nRet = nNextCh;
+ }
+ else
+ {
+ // normalen Text lesen
+ goto scan_text;
+ }
+ break;
+
+ case '\f':
+ // Form-Feeds werden jetzt extra nach oben gereicht
+ nRet = HTML_LINEFEEDCHAR; // !!! eigentlich FORMFEEDCHAR
+ break;
+
+ case '\n':
+ case '\r':
+ if( bReadListing || bReadXMP || bReadPRE || bReadTextArea )
+ {
+ sal_Unicode c = GetNextChar();
+ if( ( '\n' != nNextCh || '\r' != c ) &&
+ ( '\r' != nNextCh || '\n' != c ) )
+ {
+ bNextCh = FALSE;
+ nNextCh = c;
+ }
+ nRet = HTML_NEWPARA;
+ break;
+ }
+ // kein break !
+ case '\t':
+ if( bReadPRE )
+ {
+ nRet = HTML_TABCHAR;
+ break;
+ }
+ // kein break !
+ case ' ':
+ // kein break !
+ default:
+
+scan_text:
+ // es folgt "normaler" Text
+ nRet = ScanText();
+ bNextCh = 0 == aToken.Len();
+
+ // der Text sollte noch verarbeitet werden
+ if( !bNextCh && eState == SVPAR_PENDING )
+ {
+ eState = SVPAR_WORKING;
+ bReadNextChar = TRUE;
+ }
+
+ break;
+ }
+
+ if( bNextCh && SVPAR_WORKING == eState )
+ {
+ nNextCh = GetNextChar();
+ if( SVPAR_PENDING == eState && nRet && HTML_TEXTTOKEN != nRet )
+ {
+ bReadNextChar = TRUE;
+ eState = SVPAR_WORKING;
+ }
+ }
+
+ } while( !nRet && SVPAR_WORKING == eState );
+
+ if( SVPAR_PENDING == eState )
+ nRet = -1; // irgendwas ungueltiges
+
+ return nRet;
+}
+
+void HTMLParser::UnescapeToken()
+{
+ xub_StrLen nPos=0;
+
+ BOOL bEscape = FALSE;
+ while( nPos < aToken.Len() )
+ {
+ BOOL bOldEscape = bEscape;
+ bEscape = FALSE;
+ if( '\\'==aToken.GetChar(nPos) && !bOldEscape )
+ {
+ aToken.Erase( nPos, 1 );
+ bEscape = TRUE;
+ }
+ else
+ {
+ nPos++;
+ }
+ }
+}
+
+// hole die Optionen
+const HTMLOptions *HTMLParser::GetOptions( USHORT *pNoConvertToken ) const
+{
+ // wenn die Option fuer das aktuelle Token schon einmal
+ // geholt wurden, geben wir sie noch einmal zurueck
+ if( pOptions->Count() )
+ return pOptions;
+
+ xub_StrLen nPos = 0;
+ while( nPos < aToken.Len() )
+ {
+ // ein Zeichen ? Dann faengt hier eine Option an
+ if( HTML_ISALPHA( aToken.GetChar(nPos) ) )
+ {
+ int nToken;
+ String aValue;
+ xub_StrLen nStt = nPos;
+ sal_Unicode cChar = 0;
+
+ // Eigentlich sind hier nur ganz bestimmte Zeichen erlaubt.
+ // Netscape achtet aber nur auf "=" und Leerzeichen (siehe
+ // Mozilla: PA_FetchRequestedNameValues in
+ // lipparse/pa_mdl.c
+// while( nPos < aToken.Len() &&
+// ( '-'==(c=aToken[nPos]) || isalnum(c) || '.'==c || '_'==c) )
+ while( nPos < aToken.Len() && '=' != (cChar=aToken.GetChar(nPos)) &&
+ HTML_ISPRINTABLE(cChar) && !HTML_ISSPACE(cChar) )
+ nPos++;
+
+ String sName( aToken.Copy( nStt, nPos-nStt ) );
+
+//JP 23.03.97: die PlugIns wollen die TokenName im "Original" haben
+// also nur fuers Suchen in UpperCase wandeln
+ String sNameUpperCase( sName );
+ sNameUpperCase.ToUpperAscii();
+
+ nToken = GetHTMLOption( sNameUpperCase ); // der Name ist fertig
+ DBG_ASSERTWARNING( nToken!=HTML_O_UNKNOWN,
+ "GetOption: unbekannte HTML-Option" );
+ BOOL bStripCRLF = (nToken < HTML_OPTION_SCRIPT_START ||
+ nToken >= HTML_OPTION_SCRIPT_END) &&
+ (!pNoConvertToken || nToken != *pNoConvertToken);
+
+ while( nPos < aToken.Len() &&
+ ( !HTML_ISPRINTABLE( (cChar=aToken.GetChar(nPos)) ) ||
+ HTML_ISSPACE(cChar) ) )
+ nPos++;
+
+ // hat die Option auch einen Wert?
+ if( nPos!=aToken.Len() && '='==cChar )
+ {
+ nPos++;
+
+ while( nPos < aToken.Len() &&
+ ( !HTML_ISPRINTABLE( (cChar=aToken.GetChar(nPos)) ) ||
+ ' '==cChar || '\t'==cChar || '\r'==cChar || '\n'==cChar ) )
+ nPos++;
+
+ if( nPos != aToken.Len() )
+ {
+ xub_StrLen nLen = 0;
+ nStt = nPos;
+ if( ('"'==cChar) || ('\'')==cChar )
+ {
+ sal_Unicode cEnd = cChar;
+ nPos++; nStt++;
+ BOOL bDone = FALSE;
+ BOOL bEscape = FALSE;
+ while( nPos < aToken.Len() && !bDone )
+ {
+ BOOL bOldEscape = bEscape;
+ bEscape = FALSE;
+ cChar = aToken.GetChar(nPos);
+ switch( cChar )
+ {
+ case '\r':
+ case '\n':
+ if( bStripCRLF )
+ ((String &)aToken).Erase( nPos, 1 );
+ else
+ nPos++, nLen++;
+ break;
+ case '\\':
+ if( bOldEscape )
+ {
+ nPos++, nLen++;
+ }
+ else
+ {
+ ((String &)aToken).Erase( nPos, 1 );
+ bEscape = TRUE;
+ }
+ break;
+ case '"':
+ case '\'':
+ bDone = !bOldEscape && cChar==cEnd;
+ if( !bDone )
+ nPos++, nLen++;
+ break;
+ default:
+ nPos++, nLen++;
+ break;
+ }
+ }
+ if( nPos!=aToken.Len() )
+ nPos++;
+ }
+ else
+ {
+ // hier sind wir etwas laxer als der
+ // Standard und erlauben alles druckbare
+ BOOL bEscape = FALSE;
+ BOOL bDone = FALSE;
+ while( nPos < aToken.Len() && !bDone )
+ {
+ BOOL bOldEscape = bEscape;
+ bEscape = FALSE;
+ sal_Unicode c = aToken.GetChar(nPos);
+ switch( c )
+ {
+ case ' ':
+ bDone = !bOldEscape;
+ if( !bDone )
+ nPos++, nLen++;
+ break;
+
+ case '\t':
+ case '\r':
+ case '\n':
+ bDone = TRUE;
+ break;
+
+ case '\\':
+ if( bOldEscape )
+ {
+ nPos++, nLen++;
+ }
+ else
+ {
+ ((String &)aToken).Erase( nPos, 1 );
+ bEscape = TRUE;
+ }
+ break;
+
+ default:
+ if( HTML_ISPRINTABLE( c ) )
+ nPos++, nLen++;
+ else
+ bDone = TRUE;
+ break;
+ }
+ }
+ }
+
+ if( nLen )
+ aValue = aToken.Copy( nStt, nLen );
+ }
+ }
+
+ // Wir kennen das Token und koennen es Speichern
+ HTMLOption *pOption =
+ new HTMLOption(
+ sal::static_int_cast< sal_uInt16 >(nToken), sName, aValue );
+
+ pOptions->Insert( pOption, pOptions->Count() );
+
+ }
+ else
+ // white space un unerwartete Zeichen ignorieren wie
+ nPos++;
+ }
+
+ return pOptions;
+}
+
+int HTMLParser::FilterPRE( int nToken )
+{
+ switch( nToken )
+ {
+#ifdef HTML_BEHAVIOUR
+ // diese werden laut Definition zu LFs
+ case HTML_PARABREAK_ON:
+ case HTML_LINEBREAK:
+ nToken = HTML_NEWPARA;
+#else
+ // in Netscape zeigen sie aber nur in nicht-leeren Absaetzen Wirkung
+ case HTML_PARABREAK_ON:
+ nToken = HTML_LINEBREAK;
+ case HTML_LINEBREAK:
+#endif
+ case HTML_NEWPARA:
+ nPre_LinePos = 0;
+ if( bPre_IgnoreNewPara )
+ nToken = 0;
+ break;
+
+ case HTML_TABCHAR:
+ {
+ xub_StrLen nSpaces = sal::static_int_cast< xub_StrLen >(
+ 8 - (nPre_LinePos % 8));
+ DBG_ASSERT( !aToken.Len(), "Wieso ist das Token nicht leer?" );
+ aToken.Expand( nSpaces, ' ' );
+ nPre_LinePos += nSpaces;
+ nToken = HTML_TEXTTOKEN;
+ }
+ break;
+ // diese bleiben erhalten
+ case HTML_TEXTTOKEN:
+ nPre_LinePos += aToken.Len();
+ break;
+
+ case HTML_SELECT_ON:
+ case HTML_SELECT_OFF:
+ case HTML_BODY_ON:
+ case HTML_FORM_ON:
+ case HTML_FORM_OFF:
+ case HTML_INPUT:
+ case HTML_OPTION:
+ case HTML_TEXTAREA_ON:
+ case HTML_TEXTAREA_OFF:
+
+ case HTML_IMAGE:
+ case HTML_APPLET_ON:
+ case HTML_APPLET_OFF:
+ case HTML_PARAM:
+ case HTML_EMBED:
+
+ case HTML_HEAD1_ON:
+ case HTML_HEAD1_OFF:
+ case HTML_HEAD2_ON:
+ case HTML_HEAD2_OFF:
+ case HTML_HEAD3_ON:
+ case HTML_HEAD3_OFF:
+ case HTML_HEAD4_ON:
+ case HTML_HEAD4_OFF:
+ case HTML_HEAD5_ON:
+ case HTML_HEAD5_OFF:
+ case HTML_HEAD6_ON:
+ case HTML_HEAD6_OFF:
+ case HTML_BLOCKQUOTE_ON:
+ case HTML_BLOCKQUOTE_OFF:
+ case HTML_ADDRESS_ON:
+ case HTML_ADDRESS_OFF:
+ case HTML_HORZRULE:
+
+ case HTML_CENTER_ON:
+ case HTML_CENTER_OFF:
+ case HTML_DIVISION_ON:
+ case HTML_DIVISION_OFF:
+
+ case HTML_SCRIPT_ON:
+ case HTML_SCRIPT_OFF:
+ case HTML_RAWDATA:
+
+ case HTML_TABLE_ON:
+ case HTML_TABLE_OFF:
+ case HTML_CAPTION_ON:
+ case HTML_CAPTION_OFF:
+ case HTML_COLGROUP_ON:
+ case HTML_COLGROUP_OFF:
+ case HTML_COL_ON:
+ case HTML_COL_OFF:
+ case HTML_THEAD_ON:
+ case HTML_THEAD_OFF:
+ case HTML_TFOOT_ON:
+ case HTML_TFOOT_OFF:
+ case HTML_TBODY_ON:
+ case HTML_TBODY_OFF:
+ case HTML_TABLEROW_ON:
+ case HTML_TABLEROW_OFF:
+ case HTML_TABLEDATA_ON:
+ case HTML_TABLEDATA_OFF:
+ case HTML_TABLEHEADER_ON:
+ case HTML_TABLEHEADER_OFF:
+
+ case HTML_ANCHOR_ON:
+ case HTML_ANCHOR_OFF:
+ case HTML_BOLD_ON:
+ case HTML_BOLD_OFF:
+ case HTML_ITALIC_ON:
+ case HTML_ITALIC_OFF:
+ case HTML_STRIKE_ON:
+ case HTML_STRIKE_OFF:
+ case HTML_STRIKETHROUGH_ON:
+ case HTML_STRIKETHROUGH_OFF:
+ case HTML_UNDERLINE_ON:
+ case HTML_UNDERLINE_OFF:
+ case HTML_BASEFONT_ON:
+ case HTML_BASEFONT_OFF:
+ case HTML_FONT_ON:
+ case HTML_FONT_OFF:
+ case HTML_BLINK_ON:
+ case HTML_BLINK_OFF:
+ case HTML_SPAN_ON:
+ case HTML_SPAN_OFF:
+ case HTML_SUBSCRIPT_ON:
+ case HTML_SUBSCRIPT_OFF:
+ case HTML_SUPERSCRIPT_ON:
+ case HTML_SUPERSCRIPT_OFF:
+ case HTML_BIGPRINT_ON:
+ case HTML_BIGPRINT_OFF:
+ case HTML_SMALLPRINT_OFF:
+ case HTML_SMALLPRINT_ON:
+
+ case HTML_EMPHASIS_ON:
+ case HTML_EMPHASIS_OFF:
+ case HTML_CITIATION_ON:
+ case HTML_CITIATION_OFF:
+ case HTML_STRONG_ON:
+ case HTML_STRONG_OFF:
+ case HTML_CODE_ON:
+ case HTML_CODE_OFF:
+ case HTML_SAMPLE_ON:
+ case HTML_SAMPLE_OFF:
+ case HTML_KEYBOARD_ON:
+ case HTML_KEYBOARD_OFF:
+ case HTML_VARIABLE_ON:
+ case HTML_VARIABLE_OFF:
+ case HTML_DEFINSTANCE_ON:
+ case HTML_DEFINSTANCE_OFF:
+ case HTML_SHORTQUOTE_ON:
+ case HTML_SHORTQUOTE_OFF:
+ case HTML_LANGUAGE_ON:
+ case HTML_LANGUAGE_OFF:
+ case HTML_AUTHOR_ON:
+ case HTML_AUTHOR_OFF:
+ case HTML_PERSON_ON:
+ case HTML_PERSON_OFF:
+ case HTML_ACRONYM_ON:
+ case HTML_ACRONYM_OFF:
+ case HTML_ABBREVIATION_ON:
+ case HTML_ABBREVIATION_OFF:
+ case HTML_INSERTEDTEXT_ON:
+ case HTML_INSERTEDTEXT_OFF:
+ case HTML_DELETEDTEXT_ON:
+ case HTML_DELETEDTEXT_OFF:
+ case HTML_TELETYPE_ON:
+ case HTML_TELETYPE_OFF:
+
+ break;
+
+ // der Rest wird als unbekanntes Token behandelt
+ default:
+ if( nToken )
+ {
+ nToken =
+ ( ((HTML_TOKEN_ONOFF & nToken) && (1 & nToken))
+ ? HTML_UNKNOWNCONTROL_OFF
+ : HTML_UNKNOWNCONTROL_ON );
+ }
+ break;
+ }
+
+ bPre_IgnoreNewPara = FALSE;
+
+ return nToken;
+}
+
+int HTMLParser::FilterXMP( int nToken )
+{
+ switch( nToken )
+ {
+ case HTML_NEWPARA:
+ if( bPre_IgnoreNewPara )
+ nToken = 0;
+ case HTML_TEXTTOKEN:
+ case HTML_NONBREAKSPACE:
+ case HTML_SOFTHYPH:
+ break; // bleiben erhalten
+
+ default:
+ if( nToken )
+ {
+ if( (HTML_TOKEN_ONOFF & nToken) && (1 & nToken) )
+ {
+ sSaveToken.Insert( '<', 0 );
+ sSaveToken.Insert( '/', 1 );
+ }
+ else
+ sSaveToken.Insert( '<', 0 );
+ if( aToken.Len() )
+ {
+ UnescapeToken();
+ sSaveToken += (sal_Unicode)' ';
+ aToken.Insert( sSaveToken, 0 );
+ }
+ else
+ aToken = sSaveToken;
+ aToken += (sal_Unicode)'>';
+ nToken = HTML_TEXTTOKEN;
+ }
+ break;
+ }
+
+ bPre_IgnoreNewPara = FALSE;
+
+ return nToken;
+}
+
+int HTMLParser::FilterListing( int nToken )
+{
+ switch( nToken )
+ {
+ case HTML_NEWPARA:
+ if( bPre_IgnoreNewPara )
+ nToken = 0;
+ case HTML_TEXTTOKEN:
+ case HTML_NONBREAKSPACE:
+ case HTML_SOFTHYPH:
+ break; // bleiben erhalten
+
+ default:
+ if( nToken )
+ {
+ nToken =
+ ( ((HTML_TOKEN_ONOFF & nToken) && (1 & nToken))
+ ? HTML_UNKNOWNCONTROL_OFF
+ : HTML_UNKNOWNCONTROL_ON );
+ }
+ break;
+ }
+
+ bPre_IgnoreNewPara = FALSE;
+
+ return nToken;
+}
+
+FASTBOOL HTMLParser::IsHTMLFormat( const sal_Char* pHeader,
+ BOOL bSwitchToUCS2,
+ rtl_TextEncoding eEnc )
+{
+ // Einer der folgenden regulaeren Ausdrucke muss sich auf den String
+ // anwenden lassen, damit das Dok ein HTML-Dokument ist.
+ //
+ // ^[^<]*<[^ \t]*[> \t]
+ // -------
+ // ^<!
+ //
+ // wobei der unterstrichene Teilausdruck einem HTML-Token
+ // ensprechen muss
+
+ ByteString sCmp;
+ BOOL bUCS2B = FALSE;
+ if( bSwitchToUCS2 )
+ {
+ if( 0xfeU == (sal_uChar)pHeader[0] &&
+ 0xffU == (sal_uChar)pHeader[1] )
+ {
+ eEnc = RTL_TEXTENCODING_UCS2;
+ bUCS2B = TRUE;
+ }
+ else if( 0xffU == (sal_uChar)pHeader[0] &&
+ 0xfeU == (sal_uChar)pHeader[1] )
+ {
+ eEnc = RTL_TEXTENCODING_UCS2;
+ }
+ }
+ if
+ (
+ RTL_TEXTENCODING_UCS2 == eEnc &&
+ (
+ (0xfe == (sal_uChar)pHeader[0] && 0xff == (sal_uChar)pHeader[1]) ||
+ (0xff == (sal_uChar)pHeader[0] && 0xfe == (sal_uChar)pHeader[1])
+ )
+ )
+ {
+ if( 0xfe == (sal_uChar)pHeader[0] )
+ bUCS2B = TRUE;
+
+ xub_StrLen nLen;
+ for( nLen = 2;
+ pHeader[nLen] != 0 || pHeader[nLen+1] != 0;
+ nLen+=2 )
+ ;
+
+ ::rtl::OStringBuffer sTmp( (nLen - 2)/2 );
+ for( xub_StrLen nPos = 2; nPos < nLen; nPos += 2 )
+ {
+ sal_Unicode cUC;
+ if( bUCS2B )
+ cUC = (sal_Unicode(pHeader[nPos]) << 8) | pHeader[nPos+1];
+ else
+ cUC = (sal_Unicode(pHeader[nPos+1]) << 8) | pHeader[nPos];
+ if( 0U == cUC )
+ break;
+
+ sTmp.append( cUC < 256U ? (sal_Char)cUC : '.' );
+ }
+ sCmp = ByteString( sTmp.makeStringAndClear() );
+ }
+ else
+ {
+ sCmp = (sal_Char *)pHeader;
+ }
+
+ sCmp.ToUpperAscii();
+
+ // Ein HTML-Dokument muss in der ersten Zeile ein '<' besitzen
+ xub_StrLen nStart = sCmp.Search( '<' );
+ if( STRING_NOTFOUND == nStart )
+ return FALSE;
+ nStart++;
+
+ // danach duerfen beliebige andere Zeichen bis zu einem blank oder
+ // '>' kommen
+ sal_Char c;
+ xub_StrLen nPos;
+ for( nPos = nStart; nPos<sCmp.Len(); nPos++ )
+ {
+ if( '>'==(c=sCmp.GetChar(nPos)) || HTML_ISSPACE(c) )
+ break;
+ }
+
+ // wenn das Dokeument hinter dem < aufhoert ist es wohl kein HTML
+ if( nPos==nStart )
+ return FALSE;
+
+ // die Zeichenkette nach dem '<' muss ausserdem ein bekanntes
+ // HTML Token sein. Damit die Ausgabe eines DOS-dir-Befehls nicht
+ // als HTML interpretiert wird, wird ein <DIR> jedoch nicht als HTML
+ // interpretiert.
+ String sTest( sCmp.Copy( nStart, nPos-nStart ), RTL_TEXTENCODING_ASCII_US );
+ int nTok = GetHTMLToken( sTest );
+ if( 0 != nTok && HTML_DIRLIST_ON != nTok )
+ return TRUE;
+
+ // oder es handelt sich um ein "<!" ganz am Anfang der Datei (fix #27092#)
+ if( nStart == 1 && '!' == sCmp.GetChar( 1 ) )
+ return TRUE;
+
+ // oder wir finden irgendwo ein <HTML> in den ersten 80 Zeichen
+ nStart = sCmp.Search( OOO_STRING_SVTOOLS_HTML_html );
+ if( nStart!=STRING_NOTFOUND &&
+ nStart>0 && '<'==sCmp.GetChar(nStart-1) &&
+ nStart+4 < sCmp.Len() && '>'==sCmp.GetChar(nStart+4) )
+ return TRUE;
+
+ // sonst ist es wohl doch eher kein HTML-Dokument
+ return FALSE;
+}
+
+BOOL HTMLParser::InternalImgToPrivateURL( String& rURL )
+{
+ if( rURL.Len() < 19 || 'i' != rURL.GetChar(0) ||
+ rURL.CompareToAscii( OOO_STRING_SVTOOLS_HTML_internal_gopher, 9 ) != COMPARE_EQUAL )
+ return FALSE;
+
+ BOOL bFound = FALSE;
+
+ if( rURL.CompareToAscii( OOO_STRING_SVTOOLS_HTML_internal_gopher,16) == COMPARE_EQUAL )
+ {
+ String aName( rURL.Copy(16) );
+ switch( aName.GetChar(0) )
+ {
+ case 'b':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_binary );
+ break;
+ case 'i':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_image ) ||
+ aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_index );
+ break;
+ case 'm':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_menu ) ||
+ aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_movie );
+ break;
+ case 's':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_sound );
+ break;
+ case 't':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_telnet ) ||
+ aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_text );
+ break;
+ case 'u':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_unknown );
+ break;
+ }
+ }
+ else if( rURL.CompareToAscii( OOO_STRING_SVTOOLS_HTML_internal_icon,14) == COMPARE_EQUAL )
+ {
+ String aName( rURL.Copy(14) );
+ switch( aName.GetChar(0) )
+ {
+ case 'b':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_baddata );
+ break;
+ case 'd':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_delayed );
+ break;
+ case 'e':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_embed );
+ break;
+ case 'i':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_insecure );
+ break;
+ case 'n':
+ bFound = aName.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_notfound );
+ break;
+ }
+ }
+ if( bFound )
+ {
+ String sTmp ( rURL );
+ rURL.AssignAscii( OOO_STRING_SVTOOLS_HTML_private_image );
+ rURL.Append( sTmp );
+ }
+
+ return bFound;
+}
+
+#ifdef USED
+void HTMLParser::SaveState( int nToken )
+{
+ SvParser::SaveState( nToken );
+}
+
+void HTMLParser::RestoreState()
+{
+ SvParser::RestoreState();
+}
+#endif
+
+
+enum eHtmlMetas {
+ HTML_META_NONE = 0,
+ HTML_META_AUTHOR,
+ HTML_META_DESCRIPTION,
+ HTML_META_KEYWORDS,
+ HTML_META_REFRESH,
+ HTML_META_CLASSIFICATION,
+ HTML_META_CREATED,
+ HTML_META_CHANGEDBY,
+ HTML_META_CHANGED,
+ HTML_META_GENERATOR,
+ HTML_META_SDFOOTNOTE,
+ HTML_META_SDENDNOTE,
+ HTML_META_CONTENT_TYPE
+};
+
+// <META NAME=xxx>
+static HTMLOptionEnum __READONLY_DATA aHTMLMetaNameTable[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_META_author, HTML_META_AUTHOR },
+ { OOO_STRING_SVTOOLS_HTML_META_changed, HTML_META_CHANGED },
+ { OOO_STRING_SVTOOLS_HTML_META_changedby, HTML_META_CHANGEDBY },
+ { OOO_STRING_SVTOOLS_HTML_META_classification,HTML_META_CLASSIFICATION},
+ { OOO_STRING_SVTOOLS_HTML_META_content_type, HTML_META_CONTENT_TYPE },
+ { OOO_STRING_SVTOOLS_HTML_META_created, HTML_META_CREATED },
+ { OOO_STRING_SVTOOLS_HTML_META_description, HTML_META_DESCRIPTION },
+ { OOO_STRING_SVTOOLS_HTML_META_keywords, HTML_META_KEYWORDS },
+ { OOO_STRING_SVTOOLS_HTML_META_generator, HTML_META_GENERATOR },
+ { OOO_STRING_SVTOOLS_HTML_META_refresh, HTML_META_REFRESH },
+ { OOO_STRING_SVTOOLS_HTML_META_sdendnote, HTML_META_SDENDNOTE },
+ { OOO_STRING_SVTOOLS_HTML_META_sdfootnote, HTML_META_SDFOOTNOTE },
+ { 0, 0 }
+};
+
+
+void HTMLParser::AddMetaUserDefined( ::rtl::OUString const & )
+{
+}
+
+bool HTMLParser::ParseMetaOptionsImpl(
+ const uno::Reference<document::XDocumentProperties> & i_xDocProps,
+ SvKeyValueIterator *i_pHTTPHeader,
+ const HTMLOptions *i_pOptions,
+ rtl_TextEncoding& o_rEnc )
+{
+ String aName, aContent;
+ USHORT nAction = HTML_META_NONE;
+ bool bHTTPEquiv = false, bChanged = false;
+
+ for ( USHORT i = i_pOptions->Count(); i; )
+ {
+ const HTMLOption *pOption = (*i_pOptions)[ --i ];
+ switch ( pOption->GetToken() )
+ {
+ case HTML_O_NAME:
+ aName = pOption->GetString();
+ if ( HTML_META_NONE==nAction )
+ {
+ pOption->GetEnum( nAction, aHTMLMetaNameTable );
+ }
+ break;
+ case HTML_O_HTTPEQUIV:
+ aName = pOption->GetString();
+ pOption->GetEnum( nAction, aHTMLMetaNameTable );
+ bHTTPEquiv = true;
+ break;
+ case HTML_O_CONTENT:
+ aContent = pOption->GetString();
+ break;
+ }
+ }
+
+ if ( bHTTPEquiv || HTML_META_DESCRIPTION != nAction )
+ {
+ // if it is not a Description, remove CRs and LFs from CONTENT
+ aContent.EraseAllChars( _CR );
+ aContent.EraseAllChars( _LF );
+ }
+ else
+ {
+ // convert line endings for Description
+ aContent.ConvertLineEnd();
+ }
+
+
+ if ( bHTTPEquiv && i_pHTTPHeader )
+ {
+ // #57232#: Netscape seems to just ignore a closing ", so we do too
+ if ( aContent.Len() && '"' == aContent.GetChar( aContent.Len()-1 ) )
+ {
+ aContent.Erase( aContent.Len() - 1 );
+ }
+ SvKeyValue aKeyValue( aName, aContent );
+ i_pHTTPHeader->Append( aKeyValue );
+ }
+
+ switch ( nAction )
+ {
+ case HTML_META_AUTHOR:
+ if (i_xDocProps.is()) {
+ i_xDocProps->setAuthor( aContent );
+ bChanged = true;
+ }
+ break;
+ case HTML_META_DESCRIPTION:
+ if (i_xDocProps.is()) {
+ i_xDocProps->setDescription( aContent );
+ bChanged = true;
+ }
+ break;
+ case HTML_META_KEYWORDS:
+ if (i_xDocProps.is()) {
+ i_xDocProps->setKeywords(
+ ::comphelper::string::convertCommaSeparated(aContent));
+ bChanged = true;
+ }
+ break;
+ case HTML_META_CLASSIFICATION:
+ if (i_xDocProps.is()) {
+ i_xDocProps->setSubject( aContent );
+ bChanged = true;
+ }
+ break;
+
+ case HTML_META_CHANGEDBY:
+ if (i_xDocProps.is()) {
+ i_xDocProps->setModifiedBy( aContent );
+ }
+ break;
+
+ case HTML_META_CREATED:
+ case HTML_META_CHANGED:
+ if ( i_xDocProps.is() && aContent.Len() &&
+ aContent.GetTokenCount() == 2 )
+ {
+ Date aDate( (ULONG)aContent.GetToken(0).ToInt32() );
+ Time aTime( (ULONG)aContent.GetToken(1).ToInt32() );
+ DateTime aDateTime( aDate, aTime );
+ ::util::DateTime uDT(aDateTime.Get100Sec(),
+ aDateTime.GetSec(), aDateTime.GetMin(),
+ aDateTime.GetHour(), aDateTime.GetDay(),
+ aDateTime.GetMonth(), aDateTime.GetYear());
+ if ( HTML_META_CREATED==nAction )
+ i_xDocProps->setCreationDate( uDT );
+ else
+ i_xDocProps->setModificationDate( uDT );
+ bChanged = true;
+ }
+ break;
+
+ case HTML_META_REFRESH:
+ DBG_ASSERT( !bHTTPEquiv || i_pHTTPHeader,
+ "Reload-URL aufgrund unterlassener MUSS-Aenderung verlorengegangen" );
+ break;
+
+ case HTML_META_CONTENT_TYPE:
+ if ( aContent.Len() )
+ {
+ o_rEnc = GetEncodingByMIME( aContent );
+ }
+ break;
+
+ case HTML_META_NONE:
+ if ( !bHTTPEquiv )
+ {
+ if (i_xDocProps.is())
+ {
+ uno::Reference<beans::XPropertyContainer> xUDProps
+ = i_xDocProps->getUserDefinedProperties();
+ try {
+ xUDProps->addProperty(aName,
+ beans::PropertyAttribute::REMOVEABLE,
+ uno::makeAny(::rtl::OUString(aContent)));
+ AddMetaUserDefined(aName);
+ bChanged = true;
+ } catch (uno::Exception &) {
+ // ignore
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return bChanged;
+}
+
+bool HTMLParser::ParseMetaOptions(
+ const uno::Reference<document::XDocumentProperties> & i_xDocProps,
+ SvKeyValueIterator *i_pHeader )
+{
+ USHORT nContentOption = HTML_O_CONTENT;
+ rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW;
+
+ bool bRet = ParseMetaOptionsImpl( i_xDocProps, i_pHeader,
+ GetOptions(&nContentOption),
+ eEnc );
+
+ // If the encoding is set by a META tag, it may only overwrite the
+ // current encoding if both, the current and the new encoding, are 1-BYTE
+ // encodings. Everything else cannot lead to reasonable results.
+ if (RTL_TEXTENCODING_DONTKNOW != eEnc &&
+ rtl_isOctetTextEncoding( eEnc ) &&
+ rtl_isOctetTextEncoding( GetSrcEncoding() ) )
+ {
+ eEnc = GetExtendedCompatibilityTextEncoding( eEnc ); // #89973#
+ SetSrcEncoding( eEnc );
+ }
+
+ return bRet;
+}
+
+rtl_TextEncoding HTMLParser::GetEncodingByMIME( const String& rMime )
+{
+ ByteString sType;
+ ByteString sSubType;
+ INetContentTypeParameterList aParameters;
+ ByteString sMime( rMime, RTL_TEXTENCODING_ASCII_US );
+ if (INetContentTypes::parse(sMime, sType, sSubType, &aParameters))
+ {
+ const INetContentTypeParameter * pCharset
+ = aParameters.find("charset");
+ if (pCharset != 0)
+ {
+ ByteString sValue( pCharset->m_sValue, RTL_TEXTENCODING_ASCII_US );
+ return GetExtendedCompatibilityTextEncoding(
+ rtl_getTextEncodingFromMimeCharset( sValue.GetBuffer() ) );
+ }
+ }
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+rtl_TextEncoding HTMLParser::GetEncodingByHttpHeader( SvKeyValueIterator *pHTTPHeader )
+{
+ rtl_TextEncoding eRet = RTL_TEXTENCODING_DONTKNOW;
+ if( pHTTPHeader )
+ {
+ SvKeyValue aKV;
+ for( BOOL bCont = pHTTPHeader->GetFirst( aKV ); bCont;
+ bCont = pHTTPHeader->GetNext( aKV ) )
+ {
+ if( aKV.GetKey().EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_type ) )
+ {
+ if( aKV.GetValue().Len() )
+ {
+ eRet = HTMLParser::GetEncodingByMIME( aKV.GetValue() );
+ }
+ }
+ }
+ }
+ return eRet;
+}
+
+BOOL HTMLParser::SetEncodingByHTTPHeader(
+ SvKeyValueIterator *pHTTPHeader )
+{
+ BOOL bRet = FALSE;
+ rtl_TextEncoding eEnc = HTMLParser::GetEncodingByHttpHeader( pHTTPHeader );
+ if(RTL_TEXTENCODING_DONTKNOW != eEnc)
+ {
+ SetSrcEncoding( eEnc );
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+