1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: parhtml.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
36 #include <tools/stream.hxx>
37 #include <tools/debug.hxx>
38 #include <tools/color.hxx>
39 #include <rtl/ustrbuf.hxx>
40 #include <rtl/strbuf.hxx>
42 #define _SVSTDARR_ULONGS
43 #include <svtools/svstdarr.hxx>
46 #include <tools/tenccvt.hxx>
47 #include <tools/datetime.hxx>
48 #include <svtools/inettype.hxx>
49 #include <comphelper/string.hxx>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/document/XDocumentProperties.hpp>
53 #include <svtools/parhtml.hxx>
55 #include "htmlkywd.hxx"
58 using namespace ::com::sun::star
;
61 const sal_Int32
MAX_LEN( 1024L );
62 //static sal_Unicode sTmpBuffer[ MAX_LEN+1 ];
63 const sal_Int32
MAX_MACRO_LEN( 1024 );
65 const sal_Int32
MAX_ENTITY_LEN( 8L );
69 // Tabellen zum Umwandeln von Options-Werten in Strings
72 static HTMLOptionEnum __READONLY_DATA aInputTypeOptEnums
[] =
74 { OOO_STRING_SVTOOLS_HTML_IT_text
, HTML_IT_TEXT
},
75 { OOO_STRING_SVTOOLS_HTML_IT_password
, HTML_IT_PASSWORD
},
76 { OOO_STRING_SVTOOLS_HTML_IT_checkbox
, HTML_IT_CHECKBOX
},
77 { OOO_STRING_SVTOOLS_HTML_IT_radio
, HTML_IT_RADIO
},
78 { OOO_STRING_SVTOOLS_HTML_IT_range
, HTML_IT_RANGE
},
79 { OOO_STRING_SVTOOLS_HTML_IT_scribble
, HTML_IT_SCRIBBLE
},
80 { OOO_STRING_SVTOOLS_HTML_IT_file
, HTML_IT_FILE
},
81 { OOO_STRING_SVTOOLS_HTML_IT_hidden
, HTML_IT_HIDDEN
},
82 { OOO_STRING_SVTOOLS_HTML_IT_submit
, HTML_IT_SUBMIT
},
83 { OOO_STRING_SVTOOLS_HTML_IT_image
, HTML_IT_IMAGE
},
84 { OOO_STRING_SVTOOLS_HTML_IT_reset
, HTML_IT_RESET
},
85 { OOO_STRING_SVTOOLS_HTML_IT_button
, HTML_IT_BUTTON
},
90 static HTMLOptionEnum __READONLY_DATA aTableFrameOptEnums
[] =
92 { OOO_STRING_SVTOOLS_HTML_TF_void
, HTML_TF_VOID
},
93 { OOO_STRING_SVTOOLS_HTML_TF_above
, HTML_TF_ABOVE
},
94 { OOO_STRING_SVTOOLS_HTML_TF_below
, HTML_TF_BELOW
},
95 { OOO_STRING_SVTOOLS_HTML_TF_hsides
, HTML_TF_HSIDES
},
96 { OOO_STRING_SVTOOLS_HTML_TF_lhs
, HTML_TF_LHS
},
97 { OOO_STRING_SVTOOLS_HTML_TF_rhs
, HTML_TF_RHS
},
98 { OOO_STRING_SVTOOLS_HTML_TF_vsides
, HTML_TF_VSIDES
},
99 { OOO_STRING_SVTOOLS_HTML_TF_box
, HTML_TF_BOX
},
100 { OOO_STRING_SVTOOLS_HTML_TF_border
, HTML_TF_BOX
},
105 static HTMLOptionEnum __READONLY_DATA aTableRulesOptEnums
[] =
107 { OOO_STRING_SVTOOLS_HTML_TR_none
, HTML_TR_NONE
},
108 { OOO_STRING_SVTOOLS_HTML_TR_groups
, HTML_TR_GROUPS
},
109 { OOO_STRING_SVTOOLS_HTML_TR_rows
, HTML_TR_ROWS
},
110 { OOO_STRING_SVTOOLS_HTML_TR_cols
, HTML_TR_COLS
},
111 { OOO_STRING_SVTOOLS_HTML_TR_all
, HTML_TR_ALL
},
116 SV_IMPL_PTRARR(HTMLOptions
,HTMLOptionPtr
)
120 USHORT
HTMLOption::GetEnum( const HTMLOptionEnum
*pOptEnums
, USHORT nDflt
) const
122 USHORT nValue
= nDflt
;
124 while( pOptEnums
->pName
)
125 if( aValue
.EqualsIgnoreCaseAscii( pOptEnums
->pName
) )
130 if( pOptEnums
->pName
)
131 nValue
= pOptEnums
->nValue
;
136 BOOL
HTMLOption::GetEnum( USHORT
&rEnum
, const HTMLOptionEnum
*pOptEnums
) const
138 while( pOptEnums
->pName
)
140 if( aValue
.EqualsIgnoreCaseAscii( pOptEnums
->pName
) )
146 const sal_Char
*pName
= pOptEnums
->pName
;
148 rEnum
= pOptEnums
->nValue
;
153 HTMLOption::HTMLOption( USHORT nTok
, const String
& rToken
,
154 const String
& rValue
)
159 DBG_ASSERT( nToken
>=HTML_OPTION_START
&& nToken
<HTML_OPTION_END
,
160 "HTMLOption: unbekanntes Token" );
163 sal_uInt32
HTMLOption::GetNumber() const
165 DBG_ASSERT( (nToken
>=HTML_OPTION_NUMBER_START
&&
166 nToken
<HTML_OPTION_NUMBER_END
) ||
167 (nToken
>=HTML_OPTION_CONTEXT_START
&&
168 nToken
<HTML_OPTION_CONTEXT_END
) ||
169 nToken
==HTML_O_VALUE
,
170 "GetNumber: Option ist nicht numerisch" );
171 String
aTmp( aValue
);
172 aTmp
.EraseLeadingChars();
173 sal_Int32 nTmp
= aTmp
.ToInt32();
174 return nTmp
>= 0 ? (sal_uInt32
)nTmp
: 0;
177 INT32
HTMLOption::GetSNumber() const
179 DBG_ASSERT( (nToken
>=HTML_OPTION_NUMBER_START
&& nToken
<HTML_OPTION_NUMBER_END
) ||
180 (nToken
>=HTML_OPTION_CONTEXT_START
&& nToken
<HTML_OPTION_CONTEXT_END
),
181 "GetSNumber: Option ist nicht numerisch" );
182 String
aTmp( aValue
);
183 aTmp
.EraseLeadingChars();
184 return aTmp
.ToInt32();
187 void HTMLOption::GetNumbers( SvULongs
&rLongs
, BOOL bSpaceDelim
) const
190 rLongs
.Remove( 0, rLongs
.Count() );
194 // das ist ein sehr stark vereinfachter Scanner. Er sucht einfach
195 // alle Tiffern aus dem String
198 for( xub_StrLen i
=0; i
<aValue
.Len(); i
++ )
200 register sal_Unicode c
= aValue
.GetChar( i
);
201 if( c
>='0' && c
<='9' )
209 rLongs
.Insert( nNum
, rLongs
.Count() );
216 rLongs
.Insert( nNum
, rLongs
.Count() );
221 // hier wird auf die korrekte Trennung der Zahlen durch ',' geachtet
222 // und auch mal eine 0 eingefuegt
224 while( nPos
< aValue
.Len() )
226 register sal_Unicode c
;
227 while( nPos
< aValue
.Len() &&
228 ((c
=aValue
.GetChar(nPos
)) == ' ' || c
== '\t' ||
229 c
== '\n' || c
== '\r' ) )
232 if( nPos
==aValue
.Len() )
233 rLongs
.Insert( ULONG(0), rLongs
.Count() );
236 xub_StrLen nEnd
= aValue
.Search( (sal_Unicode
)',', nPos
);
237 if( STRING_NOTFOUND
==nEnd
)
239 sal_Int32 nTmp
= aValue
.Copy(nPos
).ToInt32();
240 rLongs
.Insert( nTmp
>= 0 ? (sal_uInt32
)nTmp
: 0,
247 aValue
.Copy(nPos
,nEnd
-nPos
).ToInt32();
248 rLongs
.Insert( nTmp
>= 0 ? (sal_uInt32
)nTmp
: 0,
257 void HTMLOption::GetColor( Color
& rColor
) const
259 DBG_ASSERT( (nToken
>=HTML_OPTION_COLOR_START
&& nToken
<HTML_OPTION_COLOR_END
) || nToken
==HTML_O_SIZE
,
260 "GetColor: Option spezifiziert keine Farbe" );
262 String
aTmp( aValue
);
264 ULONG nColor
= ULONG_MAX
;
265 if( '#'!=aTmp
.GetChar( 0 ) )
266 nColor
= GetHTMLColor( aTmp
);
268 if( ULONG_MAX
== nColor
)
272 for( sal_uInt32 i
=0; i
<6; i
++ )
274 // MIB 26.06.97: Wie auch immer Netscape Farbwerte ermittelt,
275 // maximal drei Zeichen, die kleiner als '0' sind werden
276 // ignoriert. Bug #40901# stimmt damit. Mal schauen, was sich
277 // irgendwelche HTML-Autoren noch so einfallen lassen...
278 register sal_Unicode c
= nPos
<aTmp
.Len() ? aTmp
.GetChar( nPos
++ )
282 c
= nPos
<aTmp
.Len() ? aTmp
.GetChar(nPos
++) : '0';
284 c
= nPos
<aTmp
.Len() ? aTmp
.GetChar(nPos
++) : '0';
287 if( c
>= '0' && c
<= '9' )
289 else if( c
>= 'A' && c
<= 'F' )
294 rColor
.SetRed( (BYTE
)((nColor
& 0x00ff0000) >> 16) );
295 rColor
.SetGreen( (BYTE
)((nColor
& 0x0000ff00) >> 8));
296 rColor
.SetBlue( (BYTE
)(nColor
& 0x000000ff) );
299 HTMLInputType
HTMLOption::GetInputType() const
301 DBG_ASSERT( nToken
==HTML_O_TYPE
, "GetInputType: Option nicht TYPE" );
302 return (HTMLInputType
)GetEnum( aInputTypeOptEnums
, HTML_IT_TEXT
);
305 HTMLTableFrame
HTMLOption::GetTableFrame() const
307 DBG_ASSERT( nToken
==HTML_O_FRAME
, "GetTableFrame: Option nicht FRAME" );
308 return (HTMLTableFrame
)GetEnum( aTableFrameOptEnums
, HTML_TF_VOID
);
311 HTMLTableRules
HTMLOption::GetTableRules() const
313 DBG_ASSERT( nToken
==HTML_O_RULES
, "GetTableRules: Option nicht RULES" );
314 return (HTMLTableRules
)GetEnum( aTableRulesOptEnums
, HTML_TR_NONE
);
319 HTMLParser::HTMLParser( SvStream
& rIn
, int bReadNewDoc
)
322 bNewDoc
= bReadNewDoc
;
323 bReadListing
= bReadXMP
= bReadPRE
= bReadTextArea
=
324 bReadScript
= bReadStyle
=
325 bEndTokenFound
= bIsInBody
= bReadNextChar
=
326 bReadComment
= FALSE
;
328 pOptions
= new HTMLOptions
;
331 HTMLParser::~HTMLParser()
333 if( pOptions
&& pOptions
->Count() )
334 pOptions
->DeleteAndDestroy( 0, pOptions
->Count() );
338 SvParserState __EXPORT
HTMLParser::CallParser()
340 eState
= SVPAR_WORKING
;
341 nNextCh
= GetNextChar();
345 bPre_IgnoreNewPara
= FALSE
;
349 if( SVPAR_PENDING
!= eState
)
350 ReleaseRef(); // dann brauchen wir den Parser nicht mehr!
355 void HTMLParser::Continue( int nToken
)
358 nToken
= GetNextToken();
360 while( IsParserWorking() )
363 nToken
= FilterToken( nToken
);
368 if( IsParserWorking() )
369 SaveState( 0 ); // bis hierhin abgearbeitet,
370 // weiter mit neuem Token!
371 nToken
= GetNextToken();
375 int HTMLParser::FilterToken( int nToken
)
379 case sal_Unicode(EOF
):
381 break; // nicht verschicken
386 bIsInHeader
= HTML_HEAD_ON
== nToken
;
390 case HTML_FRAMESET_ON
:
392 bIsInBody
= HTML_BODY_ON
== nToken
;
396 bIsInBody
= bReadPRE
= bReadListing
= bReadXMP
= FALSE
;
401 bReadPRE
= bReadListing
= bReadXMP
= FALSE
;
402 break; // HTML_ON wurde auch nicht verschickt !
404 case HTML_PREFORMTXT_ON
:
408 case HTML_PREFORMTXT_OFF
:
412 case HTML_LISTING_ON
:
416 case HTML_LISTING_OFF
:
430 nToken
= FilterPRE( nToken
);
431 else if( bReadListing
)
432 nToken
= FilterListing( nToken
);
434 nToken
= FilterXMP( nToken
);
442 #define HTML_ISDIGIT( c ) (c >= '0' && c <= '9')
443 #define HTML_ISALPHA( c ) ( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') )
444 #define HTML_ISALNUM( c ) ( HTML_ISALPHA(c) || HTML_ISDIGIT(c) )
445 #define HTML_ISSPACE( c ) ( ' ' == c || (c >= 0x09 && c <= 0x0d) )
446 #define HTML_ISPRINTABLE( c ) ( c >= 32 && c != 127)
447 // --> OD 2006-07-26 #138464#
448 #define HTML_ISHEXDIGIT( c ) ( HTML_ISDIGIT(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') )
451 int HTMLParser::ScanText( const sal_Unicode cBreak
)
453 ::rtl::OUStringBuffer
sTmpBuffer( MAX_LEN
);
455 int bEqSignFound
= FALSE
;
456 sal_Unicode cQuote
= 0U;
458 while( bWeiter
&& IsParserWorking() )
464 bEqSignFound
= FALSE
;
466 sTmpBuffer
.append( (sal_Unicode
)'&' );
469 ULONG nStreamPos
= rInput
.Tell();
470 ULONG nLinePos
= GetLinePos();
472 sal_Unicode cChar
= 0U;
473 if( '#' == (nNextCh
= GetNextChar()) )
475 nNextCh
= GetNextChar();
476 // --> OD 2006-07-26 #138464#
477 // consider hexadecimal digits
478 const sal_Bool
bIsHex( 'x' == nNextCh
);
479 const sal_Bool
bIsDecOrHex( bIsHex
|| HTML_ISDIGIT(nNextCh
) );
484 nNextCh
= GetNextChar();
485 while ( HTML_ISHEXDIGIT(nNextCh
) )
487 cChar
= cChar
* 16U +
489 ? sal_Unicode( nNextCh
- '0' )
491 ? sal_Unicode( nNextCh
- 'A' + 10 )
492 : sal_Unicode( nNextCh
- 'a' + 10 ) ) );
493 nNextCh
= GetNextChar();
500 cChar
= cChar
* 10U + sal_Unicode( nNextCh
- '0');
501 nNextCh
= GetNextChar();
503 while( HTML_ISDIGIT(nNextCh
) );
506 if( RTL_TEXTENCODING_DONTKNOW
!= eSrcEnc
&&
507 RTL_TEXTENCODING_UCS2
!= eSrcEnc
&&
508 RTL_TEXTENCODING_UTF8
!= eSrcEnc
&&
511 sal_Unicode cOrig
= cChar
;
512 cChar
= ByteString::ConvertToUnicode(
513 (sal_Char
)cChar
, eSrcEnc
);
516 // #73398#: If the character could not be
517 // converted, because a conversion is not
518 // available, do no conversion at all.
527 else if( HTML_ISALPHA( nNextCh
) )
529 ::rtl::OUStringBuffer
sEntityBuffer( MAX_ENTITY_LEN
);
530 xub_StrLen nPos
= 0L;
533 sEntityBuffer
.append( nNextCh
);
535 nNextCh
= GetNextChar();
537 while( nPos
< MAX_ENTITY_LEN
&& HTML_ISALNUM( nNextCh
) &&
540 if( IsParserWorking() && !rInput
.IsEof() )
542 String
sEntity( sEntityBuffer
.getStr(), nPos
);
543 cChar
= GetHTMLCharName( sEntity
);
545 // nicht gefunden ( == 0 ), dann Klartext
546 // oder ein Zeichen das als Attribut eingefuegt
548 if( 0U == cChar
&& ';' != nNextCh
)
550 DBG_ASSERT( rInput
.Tell() - nStreamPos
==
551 (ULONG
)(nPos
+1L)*GetCharSize(),
552 "UTF-8 geht hier schief" );
553 for( xub_StrLen i
=nPos
-1L; i
>1L; i
-- )
555 nNextCh
= sEntityBuffer
[i
];
556 sEntityBuffer
.setLength( i
);
557 sEntity
.Assign( sEntityBuffer
.getStr(), i
);
558 cChar
= GetHTMLCharName( sEntity
);
561 rInput
.SeekRel( -(long)
562 ((nPos
-i
)*GetCharSize()) );
563 nlLinePos
-= sal_uInt32(nPos
-i
);
565 ClearTxtConvContext();
571 if( !cChar
) // unbekanntes Zeichen?
573 // dann im Stream zurueck, das '&' als Zeichen
574 // einfuegen und mit dem nachfolgenden Zeichen
576 sTmpBuffer
.append( (sal_Unicode
)'&' );
578 // rInput.SeekRel( -(long)(++nPos*GetCharSize()) );
579 // nlLinePos -= nPos;
580 DBG_ASSERT( rInput
.Tell()-nStreamPos
==
581 (ULONG
)(nPos
+1)*GetCharSize(),
582 "Falsche Stream-Position" );
583 DBG_ASSERT( nlLinePos
-nLinePos
==
585 "Falsche Zeilen-Position" );
586 rInput
.Seek( nStreamPos
);
587 nlLinePos
= nLinePos
;
588 ClearTxtConvContext();
592 // 1 == Non Breaking Space
599 // Wenn der Inhalt eines Tags gelesen wird,
600 // muessen wir ein Space bzw. - daraus machen
603 case 1U: cChar
= ' '; break;
604 case 2U: cChar
= '-'; break;
606 DBG_ASSERT( cChar
==1U,
607 "\0x00 sollte doch schon laengt abgefangen sein!" );
613 // Wenn kein Tag gescannt wird, enstprechendes
614 // Token zurueckgeben
616 String( sTmpBuffer
.makeStringAndClear() );
621 // mit dem Zeichen wieder aufsetzen
623 // rInput.SeekRel( -(long)(++nPos*GetCharSize()) );
624 // nlLinePos -= nPos;
625 DBG_ASSERT( rInput
.Tell()-nStreamPos
==
626 (ULONG
)(nPos
+1)*GetCharSize(),
627 "Falsche Stream-Position" );
628 DBG_ASSERT( nlLinePos
-nLinePos
==
630 "Falsche Zeilen-Position" );
631 rInput
.Seek( nStreamPos
);
632 nlLinePos
= nLinePos
;
633 ClearTxtConvContext();
634 return HTML_TEXTTOKEN
;
637 // Hack: _GetNextChar soll nicht das
638 // naechste Zeichen lesen
642 return HTML_NONBREAKSPACE
;
644 return HTML_SOFTHYPH
;
646 aToken
+= (sal_Unicode
)'&';
648 String(sEntityBuffer
.makeStringAndClear());
656 // MIB 03/02/2000: &{...};-JavaScript-Macros are not
657 // supported any longer.
658 else if( IsParserWorking() )
660 sTmpBuffer
.append( (sal_Unicode
)'&' );
665 bNextCh
= (';' == nNextCh
);
666 if( cBreak
=='>' && (cChar
=='\\' || cChar
=='\'' ||
667 cChar
=='\"' || cChar
==' ') )
669 // ' und " mussen innerhalb von Tags mit einem
670 // gekennzeichnet werden, um sie von ' und " als Klammern
671 // um Optionen zu unterscheiden. Logischerweise muss
672 // deshalb auch ein \ gekeenzeichnet werden. Ausserdem
673 // schuetzen wir ein Space, weil es kein Trennzeichen
674 // zwischen Optionen ist.
675 sTmpBuffer
.append( (sal_Unicode
)'\\' );
676 if( MAX_LEN
== sTmpBuffer
.getLength() )
677 aToken
+= String(sTmpBuffer
.makeStringAndClear());
679 if( IsParserWorking() )
682 sTmpBuffer
.append( cChar
);
684 else if( SVPAR_PENDING
==eState
&& '>'!=cBreak
)
686 // Mit dem '&' Zeichen wieder aufsetzen, der Rest
687 // wird als Texttoken zurueckgegeben.
688 if( aToken
.Len() || sTmpBuffer
.getLength() )
690 // Der bisherige Text wird von _GetNextChar()
691 // zurueckgegeben und beim naechsten Aufruf wird
692 // ein neues Zeichen gelesen. Also muessen wir uns
693 // noch vor das & stellen.
695 rInput
.Seek( nStreamPos
-(sal_uInt32
)GetCharSize() );
696 nlLinePos
= nLinePos
-1;
697 ClearTxtConvContext();
698 bReadNextChar
= TRUE
;
705 if( '>'==cBreak
&& !cQuote
)
707 sTmpBuffer
.append( nNextCh
);
713 // Innerhalb von Tags kennzeichnen
714 sTmpBuffer
.append( (sal_Unicode
)'\\' );
715 if( MAX_LEN
== sTmpBuffer
.getLength() )
716 aToken
+= String(sTmpBuffer
.makeStringAndClear());
718 sTmpBuffer
.append( (sal_Unicode
)'\\' );
727 else if( cQuote
&& (cQuote
==nNextCh
) )
730 sTmpBuffer
.append( nNextCh
);
731 bEqSignFound
= FALSE
;
734 case sal_Unicode(EOF
):
737 // MIB 20.11.98: Das macht hier keinen Sinn, oder doch: Zumindest wird
738 // abcä<EOF> nicht angezeigt, also lassen wir das in Zukunft.
739 // if( '>' != cBreak )
740 // eState = SVPAR_ACCEPTED;
745 sTmpBuffer
.append( nNextCh
);
750 bEqSignFound
= FALSE
;
752 sTmpBuffer
.append( nNextCh
);
754 bWeiter
= FALSE
; // Abbrechen, String zusammen
760 // Beim Scannen von Optionen wie ein Space behandeln
761 sTmpBuffer
.append( (sal_Unicode
)' ' );
765 // sonst wird es ein eigenes Token
774 // #26979# cr/lf in Tag wird in _GetNextToken() behandeln
775 sTmpBuffer
.append( nNextCh
);
778 else if( bReadListing
|| bReadXMP
|| bReadPRE
|| bReadTextArea
)
783 // Bug 18984: CR-LF -> Blank
784 // Folge von CR/LF/BLANK/TAB nur in ein Blank wandeln
787 if( '\t'==nNextCh
&& bReadPRE
&& '>'!=cBreak
)
789 // In <PRE>: Tabs nach oben durchreichen
795 if( '\x0b'==nNextCh
&& (bReadPRE
|| bReadXMP
||bReadListing
) &&
803 sTmpBuffer
.append( nNextCh
);
804 if( '>'!=cBreak
&& (!bReadListing
&& !bReadXMP
&&
805 !bReadPRE
&& !bReadTextArea
) )
807 // alle Folgen von Blanks/Tabs/CR/LF zu einem Blank umwandeln
809 if( sal_Unicode(EOF
) == (nNextCh
= GetNextChar()) &&
812 if( aToken
.Len() || sTmpBuffer
.getLength() > 1L )
814 // ausser den Blanks wurde noch etwas geselen
815 aToken
+= String(sTmpBuffer
.makeStringAndClear());
816 return HTML_TEXTTOKEN
;
819 // nur Blanks gelesen: dann darf kein Text
820 // mehr zurueckgegeben werden und _GetNextToken
821 // muss auf EOF laufen
824 } while ( ' ' == nNextCh
|| '\t' == nNextCh
||
825 '\r' == nNextCh
|| '\n' == nNextCh
||
832 bEqSignFound
= FALSE
;
833 if( (nNextCh
==cBreak
&& !cQuote
) ||
834 (ULONG(aToken
.Len()) + MAX_LEN
) > ULONG(STRING_MAXLEN
& ~1 ))
839 // alle anderen Zeichen kommen in den Text
840 sTmpBuffer
.append( nNextCh
);
841 if( MAX_LEN
== sTmpBuffer
.getLength() )
843 aToken
+= String(sTmpBuffer
.makeStringAndClear());
844 if( (ULONG(aToken
.Len()) + MAX_LEN
) >
845 ULONG(STRING_MAXLEN
& ~1 ) )
847 nNextCh
= GetNextChar();
848 return HTML_TEXTTOKEN
;
851 if( ( sal_Unicode(EOF
) == (nNextCh
= GetNextChar()) &&
855 if( sTmpBuffer
.getLength() )
856 aToken
+= String(sTmpBuffer
.makeStringAndClear());
857 return HTML_TEXTTOKEN
;
859 } while( HTML_ISALPHA( nNextCh
) || HTML_ISDIGIT( nNextCh
) );
864 if( MAX_LEN
== sTmpBuffer
.getLength() )
865 aToken
+= String(sTmpBuffer
.makeStringAndClear());
867 if( bWeiter
&& bNextCh
)
868 nNextCh
= GetNextChar();
871 if( sTmpBuffer
.getLength() )
872 aToken
+= String(sTmpBuffer
.makeStringAndClear());
874 return HTML_TEXTTOKEN
;
877 int HTMLParser::_GetNextRawToken()
879 ::rtl::OUStringBuffer
sTmpBuffer( MAX_LEN
);
883 // beim letzten Aufruf haben wir das End-Token bereits gefunden,
884 // deshalb muessen wir es nicht noch einmal suchen
888 bEndTokenFound
= FALSE
;
893 // per default geben wir HTML_RAWDATA zurueck
895 int nToken
= HTML_RAWDATA
;
897 while( bWeiter
&& IsParserWorking() )
904 // Vielleicht haben wir das Ende erreicht
906 // das bisher gelesene erstmal retten
907 aToken
+= String(sTmpBuffer
.makeStringAndClear());
909 // und die Position im Stream merken
910 ULONG nStreamPos
= rInput
.Tell();
911 ULONG nLineNr
= GetLineNr();
912 ULONG nLinePos
= GetLinePos();
914 // Start eines End-Token?
915 int bOffState
= FALSE
;
916 if( '/' == (nNextCh
= GetNextChar()) )
919 nNextCh
= GetNextChar();
921 else if( '!' == nNextCh
)
923 sTmpBuffer
.append( nNextCh
);
924 nNextCh
= GetNextChar();
927 // jetzt die Buchstaben danach lesen
928 while( (HTML_ISALPHA(nNextCh
) || '-'==nNextCh
) &&
929 IsParserWorking() && sTmpBuffer
.getLength() < MAX_LEN
)
931 sTmpBuffer
.append( nNextCh
);
932 nNextCh
= GetNextChar();
935 String
aTok( sTmpBuffer
.getStr(),
936 sal::static_int_cast
< xub_StrLen
>(
937 sTmpBuffer
.getLength()) );
940 if( bReadScript
|| aEndToken
.Len() )
944 if( aTok
.CompareToAscii( OOO_STRING_SVTOOLS_HTML_comment
, 3 )
951 // ein Script muss mit "</SCRIPT>" aufhoehren, wobei
952 // wir es mit dem ">" aus sicherheitsgruenden
953 // erstmal nicht so genau nehmen
954 bDone
= bOffState
&& // '>'==nNextCh &&
955 COMPARE_EQUAL
== ( bReadScript
956 ? aTok
.CompareToAscii(OOO_STRING_SVTOOLS_HTML_script
)
957 : aTok
.CompareTo(aEndToken
) );
960 if( bReadComment
&& '>'==nNextCh
&& aTok
.Len() >= 2 &&
961 aTok
.Copy( aTok
.Len()-2 ).EqualsAscii( "--" ) )
963 // hier ist ein Kommentar der Art <!-----> zuende
964 bReadComment
= FALSE
;
969 // ein Style-Sheet kann mit </STYLE>, </HEAD> oder
972 bDone
= aTok
.CompareToAscii(OOO_STRING_SVTOOLS_HTML_style
)
974 aTok
.CompareToAscii(OOO_STRING_SVTOOLS_HTML_head
)
978 aTok
.CompareToAscii(OOO_STRING_SVTOOLS_HTML_body
) == COMPARE_EQUAL
;
983 // das war's, jetzt muessen wir gegebenenfalls den
984 // bisher gelesenen String zurueckgeben und dnach normal
989 // nToken==0 heisst, dass _GetNextToken gleich weiterliest
990 if( !aToken
.Len() && (bReadStyle
|| bReadScript
) )
992 // wir koennen sofort die Umgebung beeden und
993 // das End-Token parsen
1001 // wir muessen bReadScript/bReadStyle noch am
1002 // Leben lassen und koennen erst beim naechsten
1003 // mal das End-Token Parsen
1004 bEndTokenFound
= TRUE
;
1007 // jetzt fahren wir im Stream auf das '<' zurueck
1008 rInput
.Seek( nStreamPos
);
1009 SetLineNr( nLineNr
);
1010 SetLinePos( nLinePos
);
1011 ClearTxtConvContext();
1014 // den String wollen wir nicht an das Token haengen
1015 sTmpBuffer
.setLength( 0L );
1019 // "</" merken, alles andere steht noch im buffer
1020 aToken
+= (sal_Unicode
)'<';
1022 aToken
+= (sal_Unicode
)'/';
1029 sTmpBuffer
.append( nNextCh
);
1032 BOOL bTwoMinus
= FALSE
;
1033 nNextCh
= GetNextChar();
1034 while( '-' == nNextCh
&& IsParserWorking() )
1038 if( MAX_LEN
== sTmpBuffer
.getLength() )
1039 aToken
+= String(sTmpBuffer
.makeStringAndClear());
1040 sTmpBuffer
.append( nNextCh
);
1041 nNextCh
= GetNextChar();
1044 if( '>' == nNextCh
&& IsParserWorking() && bTwoMinus
)
1045 bReadComment
= FALSE
;
1052 // \r\n? beendet das aktuelle Text-Token (auch wenn es leer ist)
1053 nNextCh
= GetNextChar();
1055 nNextCh
= GetNextChar();
1059 // \n beendet das aktuelle Text-Token (auch wenn es leer ist)
1060 nNextCh
= GetNextChar();
1063 case sal_Unicode(EOF
):
1064 // eof beendet das aktuelle Text-Token und tut so, als ob
1065 // ein End-Token gelesen wurde
1066 if( rInput
.IsEof() )
1069 if( aToken
.Len() || sTmpBuffer
.getLength() )
1071 bEndTokenFound
= TRUE
;
1075 bReadScript
= FALSE
;
1084 // alle anderen Zeichen landen im Buffer
1085 sTmpBuffer
.append( nNextCh
);
1089 if( (!bWeiter
&& sTmpBuffer
.getLength() > 0L) ||
1090 MAX_LEN
== sTmpBuffer
.getLength() )
1091 aToken
+= String(sTmpBuffer
.makeStringAndClear());
1093 if( bWeiter
&& bNextCh
)
1094 nNextCh
= GetNextChar();
1097 if( IsParserWorking() )
1105 // scanne das naechste Token,
1106 int __EXPORT
HTMLParser::_GetNextToken()
1111 // die Optionen loeschen
1112 if( pOptions
->Count() )
1113 pOptions
->DeleteAndDestroy( 0, pOptions
->Count() );
1115 if( !IsParserWorking() ) // wenn schon Fehler, dann nicht weiter!
1118 BOOL bReadNextCharSave
= bReadNextChar
;
1121 DBG_ASSERT( !bEndTokenFound
,
1122 "</SCRIPT> gelesen und trotzdem noch ein Zeichen lesen?" );
1123 nNextCh
= GetNextChar();
1124 if( !IsParserWorking() ) // wenn schon Fehler, dann nicht weiter!
1126 bReadNextChar
= FALSE
;
1129 if( bReadScript
|| bReadStyle
|| aEndToken
.Len() )
1131 nRet
= _GetNextRawToken();
1132 if( nRet
|| !IsParserWorking() )
1142 ULONG nStreamPos
= rInput
.Tell();
1143 ULONG nLineNr
= GetLineNr();
1144 ULONG nLinePos
= GetLinePos();
1146 int bOffState
= FALSE
;
1147 if( '/' == (nNextCh
= GetNextChar()) )
1150 nNextCh
= GetNextChar();
1152 if( HTML_ISALPHA( nNextCh
) || '!'==nNextCh
) // fix #26984#
1154 ::rtl::OUStringBuffer sTmpBuffer
;
1156 sTmpBuffer
.append( nNextCh
);
1157 if( MAX_LEN
== sTmpBuffer
.getLength() )
1158 aToken
+= String(sTmpBuffer
.makeStringAndClear());
1159 nNextCh
= GetNextChar();
1160 } while( '>' != nNextCh
&& !HTML_ISSPACE( nNextCh
) &&
1161 IsParserWorking() && !rInput
.IsEof() );
1163 if( sTmpBuffer
.getLength() )
1164 aToken
+= String(sTmpBuffer
.makeStringAndClear());
1166 // Blanks ueberlesen
1167 while( HTML_ISSPACE( nNextCh
) && IsParserWorking() )
1168 nNextCh
= GetNextChar();
1170 if( !IsParserWorking() )
1172 if( SVPAR_PENDING
== eState
)
1173 bReadNextChar
= bReadNextCharSave
;
1177 // suche das Token in der Tabelle:
1178 sSaveToken
= aToken
;
1179 aToken
.ToUpperAscii();
1180 if( 0 == (nRet
= GetHTMLToken( aToken
)) )
1182 nRet
= HTML_UNKNOWNCONTROL_ON
;
1184 // Wenn es ein Token zum ausschalten ist ...
1187 if( HTML_TOKEN_ONOFF
& nRet
)
1189 // und es ein Off-Token gibt, das daraus machen
1192 else if( HTML_LINEBREAK
!=nRet
)
1194 // und es kein Off-Token gibt, ein unbekanntes
1195 // Token daraus machen (ausser </BR>, das wird
1196 // wie <BR> behandelt
1197 nRet
= HTML_UNKNOWNCONTROL_OFF
;
1201 if( nRet
== HTML_COMMENT
)
1203 // fix: sSaveToken wegen Gross-/Kleinschreibung
1204 // als Anfang des Kommentars benutzen und ein
1206 aToken
= sSaveToken
;
1208 aToken
+= (sal_Unicode
)' ';
1209 ULONG nCStreamPos
= 0;
1211 ULONG nCLinePos
= 0;
1212 xub_StrLen nCStrLen
= 0;
1215 // bis zum schliessenden --> lesen. wenn keins gefunden
1216 // wurde beim der ersten > wieder aufsetzen
1217 while( !bDone
&& !rInput
.IsEof() && IsParserWorking() )
1223 nCStreamPos
= rInput
.Tell();
1224 nCStrLen
= aToken
.Len();
1225 nCLineNr
= GetLineNr();
1226 nCLinePos
= GetLinePos();
1228 bDone
= aToken
.Len() >= 2 &&
1229 aToken
.Copy(aToken
.Len()-2,2).
1230 EqualsAscii( "--" );
1237 nNextCh
= GetNextChar();
1239 if( !bDone
&& IsParserWorking() && nCStreamPos
)
1241 rInput
.Seek( nCStreamPos
);
1242 SetLineNr( nCLineNr
);
1243 SetLinePos( nCLinePos
);
1244 ClearTxtConvContext();
1245 aToken
.Erase( nCStrLen
);
1251 // den TokenString koennen wir jetzt verwerfen
1255 // dann lesen wir mal alles bis zur schliessenden '>'
1256 if( '>' != nNextCh
&& IsParserWorking() )
1259 if( sal_Unicode(EOF
) == nNextCh
&& rInput
.IsEof() )
1261 // zurueck hinter die < gehen und dort neu
1262 // aufsetzen, das < als Text zurueckgeben
1263 rInput
.Seek( nStreamPos
);
1264 SetLineNr( nLineNr
);
1265 SetLinePos( nLinePos
);
1266 ClearTxtConvContext();
1269 nRet
= HTML_TEXTTOKEN
;
1270 nNextCh
= GetNextChar();
1275 if( SVPAR_PENDING
== eState
)
1276 bReadNextChar
= bReadNextCharSave
;
1282 // einfach alles wegschmeissen
1284 if( sal_Unicode(EOF
) == nNextCh
&& rInput
.IsEof() )
1286 // zurueck hinter die < gehen und dort neu
1287 // aufsetzen, das < als Text zurueckgeben
1288 rInput
.Seek( nStreamPos
);
1289 SetLineNr( nLineNr
);
1290 SetLinePos( nLinePos
);
1291 ClearTxtConvContext();
1294 nRet
= HTML_TEXTTOKEN
;
1295 nNextCh
= GetNextChar();
1299 if( SVPAR_PENDING
== eState
)
1300 bReadNextChar
= bReadNextCharSave
;
1303 else if( '%' == nNextCh
)
1305 nRet
= HTML_UNKNOWNCONTROL_ON
;
1307 ULONG nCStreamPos
= rInput
.Tell();
1308 ULONG nCLineNr
= GetLineNr(), nCLinePos
= GetLinePos();
1311 // bis zum schliessenden %> lesen. wenn keins gefunden
1312 // wurde beim der ersten > wieder aufsetzen
1313 while( !bDone
&& !rInput
.IsEof() && IsParserWorking() )
1315 bDone
= '>'==nNextCh
&& aToken
.Len() >= 1 &&
1316 '%' == aToken
.GetChar( aToken
.Len()-1 );
1320 nNextCh
= GetNextChar();
1323 if( !bDone
&& IsParserWorking() )
1325 rInput
.Seek( nCStreamPos
);
1326 SetLineNr( nCLineNr
);
1327 SetLinePos( nCLinePos
);
1328 ClearTxtConvContext();
1329 aToken
.AssignAscii( "<%", 2 );
1330 nRet
= HTML_TEXTTOKEN
;
1333 if( IsParserWorking() )
1335 sSaveToken
= aToken
;
1342 nRet
= HTML_TEXTTOKEN
;
1348 if( IsParserWorking() )
1350 bNextCh
= '>' == nNextCh
;
1353 case HTML_TEXTAREA_ON
:
1354 bReadTextArea
= TRUE
;
1356 case HTML_TEXTAREA_OFF
:
1357 bReadTextArea
= FALSE
;
1359 case HTML_SCRIPT_ON
:
1360 if( !bReadTextArea
)
1363 case HTML_SCRIPT_OFF
:
1364 if( !bReadTextArea
)
1366 bReadScript
= FALSE
;
1367 // JavaScript kann den Stream veraendern
1368 // also muss das letzte Zeichen nochmals
1370 bReadNextChar
= TRUE
;
1378 case HTML_STYLE_OFF
:
1387 case sal_Unicode(EOF
):
1388 if( rInput
.IsEof() )
1390 eState
= SVPAR_ACCEPTED
;
1395 // normalen Text lesen
1401 // Form-Feeds werden jetzt extra nach oben gereicht
1402 nRet
= HTML_LINEFEEDCHAR
; // !!! eigentlich FORMFEEDCHAR
1407 if( bReadListing
|| bReadXMP
|| bReadPRE
|| bReadTextArea
)
1409 sal_Unicode c
= GetNextChar();
1410 if( ( '\n' != nNextCh
|| '\r' != c
) &&
1411 ( '\r' != nNextCh
|| '\n' != c
) )
1416 nRet
= HTML_NEWPARA
;
1423 nRet
= HTML_TABCHAR
;
1432 // es folgt "normaler" Text
1434 bNextCh
= 0 == aToken
.Len();
1436 // der Text sollte noch verarbeitet werden
1437 if( !bNextCh
&& eState
== SVPAR_PENDING
)
1439 eState
= SVPAR_WORKING
;
1440 bReadNextChar
= TRUE
;
1446 if( bNextCh
&& SVPAR_WORKING
== eState
)
1448 nNextCh
= GetNextChar();
1449 if( SVPAR_PENDING
== eState
&& nRet
&& HTML_TEXTTOKEN
!= nRet
)
1451 bReadNextChar
= TRUE
;
1452 eState
= SVPAR_WORKING
;
1456 } while( !nRet
&& SVPAR_WORKING
== eState
);
1458 if( SVPAR_PENDING
== eState
)
1459 nRet
= -1; // irgendwas ungueltiges
1464 void HTMLParser::UnescapeToken()
1468 BOOL bEscape
= FALSE
;
1469 while( nPos
< aToken
.Len() )
1471 BOOL bOldEscape
= bEscape
;
1473 if( '\\'==aToken
.GetChar(nPos
) && !bOldEscape
)
1475 aToken
.Erase( nPos
, 1 );
1485 // hole die Optionen
1486 const HTMLOptions
*HTMLParser::GetOptions( USHORT
*pNoConvertToken
) const
1488 // wenn die Option fuer das aktuelle Token schon einmal
1489 // geholt wurden, geben wir sie noch einmal zurueck
1490 if( pOptions
->Count() )
1493 xub_StrLen nPos
= 0;
1494 while( nPos
< aToken
.Len() )
1496 // ein Zeichen ? Dann faengt hier eine Option an
1497 if( HTML_ISALPHA( aToken
.GetChar(nPos
) ) )
1501 xub_StrLen nStt
= nPos
;
1502 sal_Unicode cChar
= 0;
1504 // Eigentlich sind hier nur ganz bestimmte Zeichen erlaubt.
1505 // Netscape achtet aber nur auf "=" und Leerzeichen (siehe
1506 // Mozilla: PA_FetchRequestedNameValues in
1507 // lipparse/pa_mdl.c
1508 // while( nPos < aToken.Len() &&
1509 // ( '-'==(c=aToken[nPos]) || isalnum(c) || '.'==c || '_'==c) )
1510 while( nPos
< aToken
.Len() && '=' != (cChar
=aToken
.GetChar(nPos
)) &&
1511 HTML_ISPRINTABLE(cChar
) && !HTML_ISSPACE(cChar
) )
1514 String
sName( aToken
.Copy( nStt
, nPos
-nStt
) );
1516 //JP 23.03.97: die PlugIns wollen die TokenName im "Original" haben
1517 // also nur fuers Suchen in UpperCase wandeln
1518 String
sNameUpperCase( sName
);
1519 sNameUpperCase
.ToUpperAscii();
1521 nToken
= GetHTMLOption( sNameUpperCase
); // der Name ist fertig
1522 DBG_ASSERTWARNING( nToken
!=HTML_O_UNKNOWN
,
1523 "GetOption: unbekannte HTML-Option" );
1524 BOOL bStripCRLF
= (nToken
< HTML_OPTION_SCRIPT_START
||
1525 nToken
>= HTML_OPTION_SCRIPT_END
) &&
1526 (!pNoConvertToken
|| nToken
!= *pNoConvertToken
);
1528 while( nPos
< aToken
.Len() &&
1529 ( !HTML_ISPRINTABLE( (cChar
=aToken
.GetChar(nPos
)) ) ||
1530 HTML_ISSPACE(cChar
) ) )
1533 // hat die Option auch einen Wert?
1534 if( nPos
!=aToken
.Len() && '='==cChar
)
1538 while( nPos
< aToken
.Len() &&
1539 ( !HTML_ISPRINTABLE( (cChar
=aToken
.GetChar(nPos
)) ) ||
1540 ' '==cChar
|| '\t'==cChar
|| '\r'==cChar
|| '\n'==cChar
) )
1543 if( nPos
!= aToken
.Len() )
1545 xub_StrLen nLen
= 0;
1547 if( ('"'==cChar
) || ('\'')==cChar
)
1549 sal_Unicode cEnd
= cChar
;
1552 BOOL bEscape
= FALSE
;
1553 while( nPos
< aToken
.Len() && !bDone
)
1555 BOOL bOldEscape
= bEscape
;
1557 cChar
= aToken
.GetChar(nPos
);
1563 ((String
&)aToken
).Erase( nPos
, 1 );
1574 ((String
&)aToken
).Erase( nPos
, 1 );
1580 bDone
= !bOldEscape
&& cChar
==cEnd
;
1589 if( nPos
!=aToken
.Len() )
1594 // hier sind wir etwas laxer als der
1595 // Standard und erlauben alles druckbare
1596 BOOL bEscape
= FALSE
;
1598 while( nPos
< aToken
.Len() && !bDone
)
1600 BOOL bOldEscape
= bEscape
;
1602 sal_Unicode c
= aToken
.GetChar(nPos
);
1606 bDone
= !bOldEscape
;
1624 ((String
&)aToken
).Erase( nPos
, 1 );
1630 if( HTML_ISPRINTABLE( c
) )
1640 aValue
= aToken
.Copy( nStt
, nLen
);
1644 // Wir kennen das Token und koennen es Speichern
1645 HTMLOption
*pOption
=
1647 sal::static_int_cast
< sal_uInt16
>(nToken
), sName
, aValue
);
1649 pOptions
->Insert( pOption
, pOptions
->Count() );
1653 // white space un unerwartete Zeichen ignorieren wie
1660 int HTMLParser::FilterPRE( int nToken
)
1664 #ifdef HTML_BEHAVIOUR
1665 // diese werden laut Definition zu LFs
1666 case HTML_PARABREAK_ON
:
1667 case HTML_LINEBREAK
:
1668 nToken
= HTML_NEWPARA
;
1670 // in Netscape zeigen sie aber nur in nicht-leeren Absaetzen Wirkung
1671 case HTML_PARABREAK_ON
:
1672 nToken
= HTML_LINEBREAK
;
1673 case HTML_LINEBREAK
:
1677 if( bPre_IgnoreNewPara
)
1683 xub_StrLen nSpaces
= sal::static_int_cast
< xub_StrLen
>(
1684 8 - (nPre_LinePos
% 8));
1685 DBG_ASSERT( !aToken
.Len(), "Wieso ist das Token nicht leer?" );
1686 aToken
.Expand( nSpaces
, ' ' );
1687 nPre_LinePos
+= nSpaces
;
1688 nToken
= HTML_TEXTTOKEN
;
1691 // diese bleiben erhalten
1692 case HTML_TEXTTOKEN
:
1693 nPre_LinePos
+= aToken
.Len();
1696 case HTML_SELECT_ON
:
1697 case HTML_SELECT_OFF
:
1703 case HTML_TEXTAREA_ON
:
1704 case HTML_TEXTAREA_OFF
:
1707 case HTML_APPLET_ON
:
1708 case HTML_APPLET_OFF
:
1713 case HTML_HEAD1_OFF
:
1715 case HTML_HEAD2_OFF
:
1717 case HTML_HEAD3_OFF
:
1719 case HTML_HEAD4_OFF
:
1721 case HTML_HEAD5_OFF
:
1723 case HTML_HEAD6_OFF
:
1724 case HTML_BLOCKQUOTE_ON
:
1725 case HTML_BLOCKQUOTE_OFF
:
1726 case HTML_ADDRESS_ON
:
1727 case HTML_ADDRESS_OFF
:
1730 case HTML_CENTER_ON
:
1731 case HTML_CENTER_OFF
:
1732 case HTML_DIVISION_ON
:
1733 case HTML_DIVISION_OFF
:
1735 case HTML_SCRIPT_ON
:
1736 case HTML_SCRIPT_OFF
:
1740 case HTML_TABLE_OFF
:
1741 case HTML_CAPTION_ON
:
1742 case HTML_CAPTION_OFF
:
1743 case HTML_COLGROUP_ON
:
1744 case HTML_COLGROUP_OFF
:
1748 case HTML_THEAD_OFF
:
1750 case HTML_TFOOT_OFF
:
1752 case HTML_TBODY_OFF
:
1753 case HTML_TABLEROW_ON
:
1754 case HTML_TABLEROW_OFF
:
1755 case HTML_TABLEDATA_ON
:
1756 case HTML_TABLEDATA_OFF
:
1757 case HTML_TABLEHEADER_ON
:
1758 case HTML_TABLEHEADER_OFF
:
1760 case HTML_ANCHOR_ON
:
1761 case HTML_ANCHOR_OFF
:
1764 case HTML_ITALIC_ON
:
1765 case HTML_ITALIC_OFF
:
1766 case HTML_STRIKE_ON
:
1767 case HTML_STRIKE_OFF
:
1768 case HTML_STRIKETHROUGH_ON
:
1769 case HTML_STRIKETHROUGH_OFF
:
1770 case HTML_UNDERLINE_ON
:
1771 case HTML_UNDERLINE_OFF
:
1772 case HTML_BASEFONT_ON
:
1773 case HTML_BASEFONT_OFF
:
1777 case HTML_BLINK_OFF
:
1780 case HTML_SUBSCRIPT_ON
:
1781 case HTML_SUBSCRIPT_OFF
:
1782 case HTML_SUPERSCRIPT_ON
:
1783 case HTML_SUPERSCRIPT_OFF
:
1784 case HTML_BIGPRINT_ON
:
1785 case HTML_BIGPRINT_OFF
:
1786 case HTML_SMALLPRINT_OFF
:
1787 case HTML_SMALLPRINT_ON
:
1789 case HTML_EMPHASIS_ON
:
1790 case HTML_EMPHASIS_OFF
:
1791 case HTML_CITIATION_ON
:
1792 case HTML_CITIATION_OFF
:
1793 case HTML_STRONG_ON
:
1794 case HTML_STRONG_OFF
:
1797 case HTML_SAMPLE_ON
:
1798 case HTML_SAMPLE_OFF
:
1799 case HTML_KEYBOARD_ON
:
1800 case HTML_KEYBOARD_OFF
:
1801 case HTML_VARIABLE_ON
:
1802 case HTML_VARIABLE_OFF
:
1803 case HTML_DEFINSTANCE_ON
:
1804 case HTML_DEFINSTANCE_OFF
:
1805 case HTML_SHORTQUOTE_ON
:
1806 case HTML_SHORTQUOTE_OFF
:
1807 case HTML_LANGUAGE_ON
:
1808 case HTML_LANGUAGE_OFF
:
1809 case HTML_AUTHOR_ON
:
1810 case HTML_AUTHOR_OFF
:
1811 case HTML_PERSON_ON
:
1812 case HTML_PERSON_OFF
:
1813 case HTML_ACRONYM_ON
:
1814 case HTML_ACRONYM_OFF
:
1815 case HTML_ABBREVIATION_ON
:
1816 case HTML_ABBREVIATION_OFF
:
1817 case HTML_INSERTEDTEXT_ON
:
1818 case HTML_INSERTEDTEXT_OFF
:
1819 case HTML_DELETEDTEXT_ON
:
1820 case HTML_DELETEDTEXT_OFF
:
1821 case HTML_TELETYPE_ON
:
1822 case HTML_TELETYPE_OFF
:
1826 // der Rest wird als unbekanntes Token behandelt
1831 ( ((HTML_TOKEN_ONOFF
& nToken
) && (1 & nToken
))
1832 ? HTML_UNKNOWNCONTROL_OFF
1833 : HTML_UNKNOWNCONTROL_ON
);
1838 bPre_IgnoreNewPara
= FALSE
;
1843 int HTMLParser::FilterXMP( int nToken
)
1848 if( bPre_IgnoreNewPara
)
1850 case HTML_TEXTTOKEN
:
1851 case HTML_NONBREAKSPACE
:
1853 break; // bleiben erhalten
1858 if( (HTML_TOKEN_ONOFF
& nToken
) && (1 & nToken
) )
1860 sSaveToken
.Insert( '<', 0 );
1861 sSaveToken
.Insert( '/', 1 );
1864 sSaveToken
.Insert( '<', 0 );
1868 sSaveToken
+= (sal_Unicode
)' ';
1869 aToken
.Insert( sSaveToken
, 0 );
1872 aToken
= sSaveToken
;
1873 aToken
+= (sal_Unicode
)'>';
1874 nToken
= HTML_TEXTTOKEN
;
1879 bPre_IgnoreNewPara
= FALSE
;
1884 int HTMLParser::FilterListing( int nToken
)
1889 if( bPre_IgnoreNewPara
)
1891 case HTML_TEXTTOKEN
:
1892 case HTML_NONBREAKSPACE
:
1894 break; // bleiben erhalten
1900 ( ((HTML_TOKEN_ONOFF
& nToken
) && (1 & nToken
))
1901 ? HTML_UNKNOWNCONTROL_OFF
1902 : HTML_UNKNOWNCONTROL_ON
);
1907 bPre_IgnoreNewPara
= FALSE
;
1912 FASTBOOL
HTMLParser::IsHTMLFormat( const sal_Char
* pHeader
,
1914 rtl_TextEncoding eEnc
)
1916 // Einer der folgenden regulaeren Ausdrucke muss sich auf den String
1917 // anwenden lassen, damit das Dok ein HTML-Dokument ist.
1919 // ^[^<]*<[^ \t]*[> \t]
1923 // wobei der unterstrichene Teilausdruck einem HTML-Token
1927 BOOL bUCS2B
= FALSE
;
1930 if( 0xfeU
== (sal_uChar
)pHeader
[0] &&
1931 0xffU
== (sal_uChar
)pHeader
[1] )
1933 eEnc
= RTL_TEXTENCODING_UCS2
;
1936 else if( 0xffU
== (sal_uChar
)pHeader
[0] &&
1937 0xfeU
== (sal_uChar
)pHeader
[1] )
1939 eEnc
= RTL_TEXTENCODING_UCS2
;
1944 RTL_TEXTENCODING_UCS2
== eEnc
&&
1946 (0xfe == (sal_uChar
)pHeader
[0] && 0xff == (sal_uChar
)pHeader
[1]) ||
1947 (0xff == (sal_uChar
)pHeader
[0] && 0xfe == (sal_uChar
)pHeader
[1])
1951 if( 0xfe == (sal_uChar
)pHeader
[0] )
1956 pHeader
[nLen
] != 0 || pHeader
[nLen
+1] != 0;
1960 ::rtl::OStringBuffer
sTmp( (nLen
- 2)/2 );
1961 for( xub_StrLen nPos
= 2; nPos
< nLen
; nPos
+= 2 )
1965 cUC
= (sal_Unicode(pHeader
[nPos
]) << 8) | pHeader
[nPos
+1];
1967 cUC
= (sal_Unicode(pHeader
[nPos
+1]) << 8) | pHeader
[nPos
];
1971 sTmp
.append( cUC
< 256U ? (sal_Char
)cUC
: '.' );
1973 sCmp
= ByteString( sTmp
.makeStringAndClear() );
1977 sCmp
= (sal_Char
*)pHeader
;
1980 sCmp
.ToUpperAscii();
1982 // Ein HTML-Dokument muss in der ersten Zeile ein '<' besitzen
1983 xub_StrLen nStart
= sCmp
.Search( '<' );
1984 if( STRING_NOTFOUND
== nStart
)
1988 // danach duerfen beliebige andere Zeichen bis zu einem blank oder
1992 for( nPos
= nStart
; nPos
<sCmp
.Len(); nPos
++ )
1994 if( '>'==(c
=sCmp
.GetChar(nPos
)) || HTML_ISSPACE(c
) )
1998 // wenn das Dokeument hinter dem < aufhoert ist es wohl kein HTML
2002 // die Zeichenkette nach dem '<' muss ausserdem ein bekanntes
2003 // HTML Token sein. Damit die Ausgabe eines DOS-dir-Befehls nicht
2004 // als HTML interpretiert wird, wird ein <DIR> jedoch nicht als HTML
2006 String
sTest( sCmp
.Copy( nStart
, nPos
-nStart
), RTL_TEXTENCODING_ASCII_US
);
2007 int nTok
= GetHTMLToken( sTest
);
2008 if( 0 != nTok
&& HTML_DIRLIST_ON
!= nTok
)
2011 // oder es handelt sich um ein "<!" ganz am Anfang der Datei (fix #27092#)
2012 if( nStart
== 1 && '!' == sCmp
.GetChar( 1 ) )
2015 // oder wir finden irgendwo ein <HTML> in den ersten 80 Zeichen
2016 nStart
= sCmp
.Search( OOO_STRING_SVTOOLS_HTML_html
);
2017 if( nStart
!=STRING_NOTFOUND
&&
2018 nStart
>0 && '<'==sCmp
.GetChar(nStart
-1) &&
2019 nStart
+4 < sCmp
.Len() && '>'==sCmp
.GetChar(nStart
+4) )
2022 // sonst ist es wohl doch eher kein HTML-Dokument
2026 BOOL
HTMLParser::InternalImgToPrivateURL( String
& rURL
)
2028 if( rURL
.Len() < 19 || 'i' != rURL
.GetChar(0) ||
2029 rURL
.CompareToAscii( OOO_STRING_SVTOOLS_HTML_internal_gopher
, 9 ) != COMPARE_EQUAL
)
2032 BOOL bFound
= FALSE
;
2034 if( rURL
.CompareToAscii( OOO_STRING_SVTOOLS_HTML_internal_gopher
,16) == COMPARE_EQUAL
)
2036 String
aName( rURL
.Copy(16) );
2037 switch( aName
.GetChar(0) )
2040 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_binary
);
2043 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_image
) ||
2044 aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_index
);
2047 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_menu
) ||
2048 aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_movie
);
2051 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_sound
);
2054 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_telnet
) ||
2055 aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_text
);
2058 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_GOPHER_unknown
);
2062 else if( rURL
.CompareToAscii( OOO_STRING_SVTOOLS_HTML_internal_icon
,14) == COMPARE_EQUAL
)
2064 String
aName( rURL
.Copy(14) );
2065 switch( aName
.GetChar(0) )
2068 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_baddata
);
2071 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_delayed
);
2074 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_embed
);
2077 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_insecure
);
2080 bFound
= aName
.EqualsAscii( OOO_STRING_SVTOOLS_HTML_INT_ICON_notfound
);
2086 String
sTmp ( rURL
);
2087 rURL
.AssignAscii( OOO_STRING_SVTOOLS_HTML_private_image
);
2088 rURL
.Append( sTmp
);
2095 void HTMLParser::SaveState( int nToken
)
2097 SvParser::SaveState( nToken
);
2100 void HTMLParser::RestoreState()
2102 SvParser::RestoreState();
2110 HTML_META_DESCRIPTION
,
2113 HTML_META_CLASSIFICATION
,
2115 HTML_META_CHANGEDBY
,
2117 HTML_META_GENERATOR
,
2118 HTML_META_SDFOOTNOTE
,
2119 HTML_META_SDENDNOTE
,
2120 HTML_META_CONTENT_TYPE
2124 #ifdef __MINGW32__ // for runtime pseudo reloc
2125 static HTMLOptionEnum aHTMLMetaNameTable
[] =
2127 static HTMLOptionEnum __READONLY_DATA aHTMLMetaNameTable
[] =
2130 { OOO_STRING_SVTOOLS_HTML_META_author
, HTML_META_AUTHOR
},
2131 { OOO_STRING_SVTOOLS_HTML_META_changed
, HTML_META_CHANGED
},
2132 { OOO_STRING_SVTOOLS_HTML_META_changedby
, HTML_META_CHANGEDBY
},
2133 { OOO_STRING_SVTOOLS_HTML_META_classification
,HTML_META_CLASSIFICATION
},
2134 { OOO_STRING_SVTOOLS_HTML_META_content_type
, HTML_META_CONTENT_TYPE
},
2135 { OOO_STRING_SVTOOLS_HTML_META_created
, HTML_META_CREATED
},
2136 { OOO_STRING_SVTOOLS_HTML_META_description
, HTML_META_DESCRIPTION
},
2137 { OOO_STRING_SVTOOLS_HTML_META_keywords
, HTML_META_KEYWORDS
},
2138 { OOO_STRING_SVTOOLS_HTML_META_generator
, HTML_META_GENERATOR
},
2139 { OOO_STRING_SVTOOLS_HTML_META_refresh
, HTML_META_REFRESH
},
2140 { OOO_STRING_SVTOOLS_HTML_META_sdendnote
, HTML_META_SDENDNOTE
},
2141 { OOO_STRING_SVTOOLS_HTML_META_sdfootnote
, HTML_META_SDFOOTNOTE
},
2146 void HTMLParser::AddMetaUserDefined( ::rtl::OUString
const & )
2150 bool HTMLParser::ParseMetaOptionsImpl(
2151 const uno::Reference
<document::XDocumentProperties
> & i_xDocProps
,
2152 SvKeyValueIterator
*i_pHTTPHeader
,
2153 const HTMLOptions
*i_pOptions
,
2154 rtl_TextEncoding
& o_rEnc
)
2156 String aName
, aContent
;
2157 USHORT nAction
= HTML_META_NONE
;
2158 bool bHTTPEquiv
= false, bChanged
= false;
2160 for ( USHORT i
= i_pOptions
->Count(); i
; )
2162 const HTMLOption
*pOption
= (*i_pOptions
)[ --i
];
2163 switch ( pOption
->GetToken() )
2166 aName
= pOption
->GetString();
2167 if ( HTML_META_NONE
==nAction
)
2169 pOption
->GetEnum( nAction
, aHTMLMetaNameTable
);
2172 case HTML_O_HTTPEQUIV
:
2173 aName
= pOption
->GetString();
2174 pOption
->GetEnum( nAction
, aHTMLMetaNameTable
);
2177 case HTML_O_CONTENT
:
2178 aContent
= pOption
->GetString();
2183 if ( bHTTPEquiv
|| HTML_META_DESCRIPTION
!= nAction
)
2185 // if it is not a Description, remove CRs and LFs from CONTENT
2186 aContent
.EraseAllChars( _CR
);
2187 aContent
.EraseAllChars( _LF
);
2191 // convert line endings for Description
2192 aContent
.ConvertLineEnd();
2196 if ( bHTTPEquiv
&& i_pHTTPHeader
)
2198 // #57232#: Netscape seems to just ignore a closing ", so we do too
2199 if ( aContent
.Len() && '"' == aContent
.GetChar( aContent
.Len()-1 ) )
2201 aContent
.Erase( aContent
.Len() - 1 );
2203 SvKeyValue
aKeyValue( aName
, aContent
);
2204 i_pHTTPHeader
->Append( aKeyValue
);
2209 case HTML_META_AUTHOR
:
2210 if (i_xDocProps
.is()) {
2211 i_xDocProps
->setAuthor( aContent
);
2215 case HTML_META_DESCRIPTION
:
2216 if (i_xDocProps
.is()) {
2217 i_xDocProps
->setDescription( aContent
);
2221 case HTML_META_KEYWORDS
:
2222 if (i_xDocProps
.is()) {
2223 i_xDocProps
->setKeywords(
2224 ::comphelper::string::convertCommaSeparated(aContent
));
2228 case HTML_META_CLASSIFICATION
:
2229 if (i_xDocProps
.is()) {
2230 i_xDocProps
->setSubject( aContent
);
2235 case HTML_META_CHANGEDBY
:
2236 if (i_xDocProps
.is()) {
2237 i_xDocProps
->setModifiedBy( aContent
);
2241 case HTML_META_CREATED
:
2242 case HTML_META_CHANGED
:
2243 if ( i_xDocProps
.is() && aContent
.Len() &&
2244 aContent
.GetTokenCount() == 2 )
2246 Date
aDate( (ULONG
)aContent
.GetToken(0).ToInt32() );
2247 Time
aTime( (ULONG
)aContent
.GetToken(1).ToInt32() );
2248 DateTime
aDateTime( aDate
, aTime
);
2249 ::util::DateTime
uDT(aDateTime
.Get100Sec(),
2250 aDateTime
.GetSec(), aDateTime
.GetMin(),
2251 aDateTime
.GetHour(), aDateTime
.GetDay(),
2252 aDateTime
.GetMonth(), aDateTime
.GetYear());
2253 if ( HTML_META_CREATED
==nAction
)
2254 i_xDocProps
->setCreationDate( uDT
);
2256 i_xDocProps
->setModificationDate( uDT
);
2261 case HTML_META_REFRESH
:
2262 DBG_ASSERT( !bHTTPEquiv
|| i_pHTTPHeader
,
2263 "Reload-URL aufgrund unterlassener MUSS-Aenderung verlorengegangen" );
2266 case HTML_META_CONTENT_TYPE
:
2267 if ( aContent
.Len() )
2269 o_rEnc
= GetEncodingByMIME( aContent
);
2273 case HTML_META_NONE
:
2276 if (i_xDocProps
.is())
2278 uno::Reference
<beans::XPropertyContainer
> xUDProps
2279 = i_xDocProps
->getUserDefinedProperties();
2281 xUDProps
->addProperty(aName
,
2282 beans::PropertyAttribute::REMOVEABLE
,
2283 uno::makeAny(::rtl::OUString(aContent
)));
2284 AddMetaUserDefined(aName
);
2286 } catch (uno::Exception
&) {
2299 bool HTMLParser::ParseMetaOptions(
2300 const uno::Reference
<document::XDocumentProperties
> & i_xDocProps
,
2301 SvKeyValueIterator
*i_pHeader
)
2303 USHORT nContentOption
= HTML_O_CONTENT
;
2304 rtl_TextEncoding eEnc
= RTL_TEXTENCODING_DONTKNOW
;
2306 bool bRet
= ParseMetaOptionsImpl( i_xDocProps
, i_pHeader
,
2307 GetOptions(&nContentOption
),
2310 // If the encoding is set by a META tag, it may only overwrite the
2311 // current encoding if both, the current and the new encoding, are 1-BYTE
2312 // encodings. Everything else cannot lead to reasonable results.
2313 if (RTL_TEXTENCODING_DONTKNOW
!= eEnc
&&
2314 rtl_isOctetTextEncoding( eEnc
) &&
2315 rtl_isOctetTextEncoding( GetSrcEncoding() ) )
2317 eEnc
= GetExtendedCompatibilityTextEncoding( eEnc
); // #89973#
2318 SetSrcEncoding( eEnc
);
2324 rtl_TextEncoding
HTMLParser::GetEncodingByMIME( const String
& rMime
)
2327 ByteString sSubType
;
2328 INetContentTypeParameterList aParameters
;
2329 ByteString
sMime( rMime
, RTL_TEXTENCODING_ASCII_US
);
2330 if (INetContentTypes::parse(sMime
, sType
, sSubType
, &aParameters
))
2332 const INetContentTypeParameter
* pCharset
2333 = aParameters
.find("charset");
2336 ByteString
sValue( pCharset
->m_sValue
, RTL_TEXTENCODING_ASCII_US
);
2337 return GetExtendedCompatibilityTextEncoding(
2338 rtl_getTextEncodingFromMimeCharset( sValue
.GetBuffer() ) );
2341 return RTL_TEXTENCODING_DONTKNOW
;