1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svtools/svparser.hxx>
22 #include <tools/stream.hxx>
23 #include <tools/debug.hxx>
24 #include <rtl/textcvt.h>
25 #include <rtl/tencinfo.h>
27 // Struktur, um sich die akt. Daten zumerken
30 String aToken
; // gescanntes Token
31 sal_uLong nFilePos
; // akt. Position im Stream
32 sal_uLong nlLineNr
; // akt. Zeilen Nummer
33 sal_uLong nlLinePos
; // akt. Spalten Nummer
34 long nTokenValue
; // zusaetzlicher Wert (RTF)
35 sal_Bool bTokenHasValue
; // indicates whether nTokenValue is valid
36 int nToken
; // akt. Token
37 sal_Unicode nNextCh
; // akt. Zeichen
39 int nSaveToken
; // das Token vom Continue
41 rtl_TextToUnicodeConverter hConv
;
42 rtl_TextToUnicodeContext hContext
;
45 nSaveToken(0), hConv( 0 ), hContext( (rtl_TextToUnicodeContext
)1 )
54 SvParser::SvParser( SvStream
& rIn
, sal_uInt8 nStackSize
)
60 , bTokenHasValue( false )
61 , eState( SVPAR_NOTSTARTED
)
62 , eSrcEnc( RTL_TEXTENCODING_DONTKNOW
)
63 , bDownloadingFile( sal_False
)
64 , nTokenStackSize( nStackSize
)
67 bUCS2BSrcEnc
= bSwitchToUCS2
= sal_False
;
68 eState
= SVPAR_NOTSTARTED
;
69 if( nTokenStackSize
< 3 )
71 pTokenStack
= new TokenStackType
[ nTokenStackSize
];
72 pTokenStackPos
= pTokenStack
;
77 if( pImplData
&& pImplData
->hConv
)
79 rtl_destroyTextToUnicodeContext( pImplData
->hConv
,
80 pImplData
->hContext
);
81 rtl_destroyTextToUnicodeConverter( pImplData
->hConv
);
86 delete [] pTokenStack
;
89 void SvParser::ClearTxtConvContext()
91 if( pImplData
&& pImplData
->hConv
)
92 rtl_resetTextToUnicodeContext( pImplData
->hConv
, pImplData
->hContext
);
95 void SvParser::SetSrcEncoding( rtl_TextEncoding eEnc
)
100 if( pImplData
&& pImplData
->hConv
)
102 rtl_destroyTextToUnicodeContext( pImplData
->hConv
,
103 pImplData
->hContext
);
104 rtl_destroyTextToUnicodeConverter( pImplData
->hConv
);
105 pImplData
->hConv
= 0;
106 pImplData
->hContext
= (rtl_TextToUnicodeContext
)1;
109 if( rtl_isOctetTextEncoding(eEnc
) ||
110 RTL_TEXTENCODING_UCS2
== eEnc
)
114 pImplData
= new SvParser_Impl
;
115 pImplData
->hConv
= rtl_createTextToUnicodeConverter( eSrcEnc
);
116 DBG_ASSERT( pImplData
->hConv
,
117 "SvParser::SetSrcEncoding: no converter for source encoding" );
118 if( !pImplData
->hConv
)
119 eSrcEnc
= RTL_TEXTENCODING_DONTKNOW
;
121 pImplData
->hContext
=
122 rtl_createTextToUnicodeContext( pImplData
->hConv
);
127 "SvParser::SetSrcEncoding: invalid source encoding" );
128 eSrcEnc
= RTL_TEXTENCODING_DONTKNOW
;
133 void SvParser::RereadLookahead()
135 rInput
.Seek(nNextChPos
);
136 nNextCh
= GetNextChar();
139 sal_Unicode
SvParser::GetNextChar()
143 // When reading muliple bytes, we don't have to care about the file
144 // position when we run inti the pending state. The file position is
145 // maintained by SaveState/RestoreState.
147 if( bSwitchToUCS2
&& 0 == rInput
.Tell() )
150 sal_Bool bSeekBack
= sal_True
;
153 bErr
= rInput
.IsEof() || rInput
.GetError();
156 if( 0xff == c1
|| 0xfe == c1
)
159 bErr
= rInput
.IsEof() || rInput
.GetError();
162 if( 0xfe == c1
&& 0xff == c2
)
164 eSrcEnc
= RTL_TEXTENCODING_UCS2
;
165 bUCS2BSrcEnc
= sal_True
;
166 bSeekBack
= sal_False
;
168 else if( 0xff == c1
&& 0xfe == c2
)
170 eSrcEnc
= RTL_TEXTENCODING_UCS2
;
171 bUCS2BSrcEnc
= sal_False
;
172 bSeekBack
= sal_False
;
180 bSwitchToUCS2
= sal_False
;
183 nNextChPos
= rInput
.Tell();
185 if( RTL_TEXTENCODING_UCS2
== eSrcEnc
)
187 sal_Unicode cUC
= USHRT_MAX
;
191 if( 2 == rInput
.Tell() &&
192 !(rInput
.IsEof() || rInput
.GetError()) &&
193 ( (bUCS2BSrcEnc
&& 0xfe == c1
&& 0xff == c2
) ||
194 (!bUCS2BSrcEnc
&& 0xff == c1
&& 0xfe == c2
) ) )
197 bErr
= rInput
.IsEof() || rInput
.GetError();
201 cUC
= (sal_Unicode(c1
) << 8) | c2
;
203 cUC
= (sal_Unicode(c2
) << 8) | c1
;
216 sal_Char c1
; // signed, that's the text converter expects
218 bErr
= rInput
.IsEof() || rInput
.GetError();
222 RTL_TEXTENCODING_DONTKNOW
== eSrcEnc
||
223 RTL_TEXTENCODING_SYMBOL
== eSrcEnc
226 // no convserion shall take place
232 DBG_ASSERT( pImplData
&& pImplData
->hConv
,
233 "no text converter!" );
236 sal_uInt32 nInfo
= 0;
238 nChars
= rtl_convertTextToUnicode(
239 pImplData
->hConv
, pImplData
->hContext
,
241 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
242 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
243 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
,
245 if( (nInfo
&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
) != 0 )
247 // The conversion wasn't successful because we haven't
248 // read enough characters.
249 if( pImplData
->hContext
!= (rtl_TextToUnicodeContext
)1 )
251 while( (nInfo
&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
) != 0 )
254 bErr
= rInput
.IsEof() || rInput
.GetError();
258 nChars
= rtl_convertTextToUnicode(
259 pImplData
->hConv
, pImplData
->hContext
,
261 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
262 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
263 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
,
268 if( 1 == nChars
&& 0 == nInfo
)
272 else if( 0 != nChars
|| 0 != nInfo
)
274 DBG_ASSERT( (nInfo
&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
) == 0,
275 "source buffer is to small" );
276 DBG_ASSERT( (nInfo
&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
)) == 0,
277 "there is a conversion error" );
278 DBG_ASSERT( 0 == nChars
,
279 "there is a converted character, but an error" );
280 // There are still errors, but nothing we can
282 c
= (sal_Unicode
)'?';
289 sal_Char sBuffer
[10];
292 while( (nInfo
&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
) != 0 &&
296 bErr
= rInput
.IsEof() || rInput
.GetError();
300 sBuffer
[nLen
++] = c1
;
301 nChars
= rtl_convertTextToUnicode(
302 pImplData
->hConv
, 0, sBuffer
, nLen
, &cUC
, 1,
303 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
304 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
305 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
,
310 if( 1 == nChars
&& 0 == nInfo
)
312 DBG_ASSERT( nCvtBytes
== nLen
,
313 "no all bytes have been converted!" );
318 DBG_ASSERT( (nInfo
&RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
) == 0,
319 "source buffer is to small" );
320 DBG_ASSERT( (nInfo
&~(RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
)) == 0,
321 "there is a conversion error" );
322 DBG_ASSERT( 0 == nChars
,
323 "there is a converted character, but an error" );
325 // There are still errors, so we use the first
326 // character and restart after that.
327 c
= (sal_Unicode
)sBuffer
[0];
328 rInput
.SeekRel( -(nLen
-1) );
334 else if( 1 == nChars
&& 0 == nInfo
)
336 // The conversion was successful
337 DBG_ASSERT( nCvtBytes
== 1,
338 "no all bytes have been converted!" );
341 else if( 0 != nChars
|| 0 != nInfo
)
343 DBG_ASSERT( 0 == nChars
,
344 "there is a converted character, but an error" );
345 DBG_ASSERT( 0 != nInfo
,
346 "there is no converted character and no error" );
347 // #73398#: If the character could not be converted,
348 // because a conversion is not available, do no conversion at all.
356 while( 0 == nChars
&& !bErr
);
360 if( ERRCODE_IO_PENDING
== rInput
.GetError() )
362 eState
= SVPAR_PENDING
;
366 return sal_Unicode(EOF
);
379 int SvParser::GetNextToken()
383 if( !nTokenStackPos
)
385 aToken
.Erase(); // Token-Buffer loeschen
386 nTokenValue
= -1; // Kennzeichen fuer kein Value gelesen
387 bTokenHasValue
= false;
389 nRet
= _GetNextToken();
390 if( SVPAR_PENDING
== eState
)
395 if( pTokenStackPos
== pTokenStack
+ nTokenStackSize
)
396 pTokenStackPos
= pTokenStack
;
398 // vom Stack holen ??
402 nTokenValue
= pTokenStackPos
->nTokenValue
;
403 bTokenHasValue
= pTokenStackPos
->bTokenHasValue
;
404 aToken
= pTokenStackPos
->sToken
;
405 nRet
= pTokenStackPos
->nTokenId
;
407 // nein, dann das aktuelle auf den Stack
408 else if( SVPAR_WORKING
== eState
)
410 pTokenStackPos
->sToken
= aToken
;
411 pTokenStackPos
->nTokenValue
= nTokenValue
;
412 pTokenStackPos
->bTokenHasValue
= bTokenHasValue
;
413 pTokenStackPos
->nTokenId
= nRet
;
415 else if( SVPAR_ACCEPTED
!= eState
&& SVPAR_PENDING
!= eState
)
416 eState
= SVPAR_ERROR
; // irgend ein Fehler
421 int SvParser::SkipToken( short nCnt
) // n Tokens zurueck "skippen"
423 pTokenStackPos
= GetStackPtr( nCnt
);
424 short nTmp
= nTokenStackPos
- nCnt
;
427 else if( nTmp
> nTokenStackSize
)
428 nTmp
= nTokenStackSize
;
429 nTokenStackPos
= sal_uInt8(nTmp
);
431 // und die Werte zurueck
432 aToken
= pTokenStackPos
->sToken
;
433 nTokenValue
= pTokenStackPos
->nTokenValue
;
434 bTokenHasValue
= pTokenStackPos
->bTokenHasValue
;
436 return pTokenStackPos
->nTokenId
;
439 SvParser::TokenStackType
* SvParser::GetStackPtr( short nCnt
)
441 sal_uInt8 nAktPos
= sal_uInt8(pTokenStackPos
- pTokenStack
);
444 if( nCnt
>= nTokenStackSize
)
445 nCnt
= (nTokenStackSize
-1);
446 if( nAktPos
+ nCnt
< nTokenStackSize
)
447 nAktPos
= sal::static_int_cast
< sal_uInt8
>(nAktPos
+ nCnt
);
449 nAktPos
= sal::static_int_cast
< sal_uInt8
>(
450 nAktPos
+ (nCnt
- nTokenStackSize
));
454 if( -nCnt
>= nTokenStackSize
)
455 nCnt
= -nTokenStackSize
+1;
456 if( -nCnt
<= nAktPos
)
457 nAktPos
= sal::static_int_cast
< sal_uInt8
>(nAktPos
+ nCnt
);
459 nAktPos
= sal::static_int_cast
< sal_uInt8
>(
460 nAktPos
+ (nCnt
+ nTokenStackSize
));
462 return pTokenStack
+ nAktPos
;
465 // wird fuer jedes Token gerufen, das in CallParser erkannt wird
466 void SvParser::NextToken( int )
471 // fuers asynchrone lesen aus dem SvStream
473 int SvParser::GetSaveToken() const
475 return pImplData
? pImplData
->nSaveToken
: 0;
478 void SvParser::SaveState( int nToken
)
480 // aktuellen Status merken
483 pImplData
= new SvParser_Impl
;
484 pImplData
->nSaveToken
= 0;
487 pImplData
->nFilePos
= rInput
.Tell();
488 pImplData
->nToken
= nToken
;
490 pImplData
->aToken
= aToken
;
491 pImplData
->nlLineNr
= nlLineNr
;
492 pImplData
->nlLinePos
= nlLinePos
;
493 pImplData
->nTokenValue
= nTokenValue
;
494 pImplData
->bTokenHasValue
= bTokenHasValue
;
495 pImplData
->nNextCh
= nNextCh
;
498 void SvParser::RestoreState()
500 // alten Status wieder zurueck setzen
503 if( ERRCODE_IO_PENDING
== rInput
.GetError() )
505 aToken
= pImplData
->aToken
;
506 nlLineNr
= pImplData
->nlLineNr
;
507 nlLinePos
= pImplData
->nlLinePos
;
508 nTokenValue
= pImplData
->nTokenValue
;
509 bTokenHasValue
=pImplData
->bTokenHasValue
;
510 nNextCh
= pImplData
->nNextCh
;
512 pImplData
->nSaveToken
= pImplData
->nToken
;
514 rInput
.Seek( pImplData
->nFilePos
);
518 void SvParser::Continue( int )
522 void SvParser::BuildWhichTbl( std::vector
<sal_uInt16
> &rWhichMap
,
523 sal_uInt16
*pWhichIds
,
524 sal_uInt16 nWhichIds
)
526 sal_uInt16 aNewRange
[2];
528 for( sal_uInt16 nCnt
= 0; nCnt
< nWhichIds
; ++nCnt
, ++pWhichIds
)
531 aNewRange
[0] = aNewRange
[1] = *pWhichIds
;
532 sal_Bool bIns
= sal_True
;
535 for ( sal_uInt16 nOfs
= 0; rWhichMap
[nOfs
]; nOfs
+= 2 )
537 if( *pWhichIds
< rWhichMap
[nOfs
] - 1 )
540 rWhichMap
.insert( rWhichMap
.begin() + nOfs
, aNewRange
, aNewRange
+ 2 );
544 else if( *pWhichIds
== rWhichMap
[nOfs
] - 1 )
546 // diesen Range nach unten erweitern
547 rWhichMap
[nOfs
] = *pWhichIds
;
551 else if( *pWhichIds
== rWhichMap
[nOfs
+1] + 1 )
553 if( rWhichMap
[nOfs
+2] != 0 && rWhichMap
[nOfs
+2] == *pWhichIds
+ 1 )
555 // mit dem naechsten Bereich mergen
556 rWhichMap
[nOfs
+1] = rWhichMap
[nOfs
+3];
557 rWhichMap
.erase( rWhichMap
.begin() + nOfs
+ 2,
558 rWhichMap
.begin() + nOfs
+ 4 );
561 // diesen Range nach oben erweitern
562 rWhichMap
[nOfs
+1] = *pWhichIds
;
568 // einen Range hinten anhaengen
571 rWhichMap
.insert( rWhichMap
.begin() + rWhichMap
.size() - 1,
572 aNewRange
, aNewRange
+ 2 );
578 IMPL_STATIC_LINK( SvParser
, NewDataRead
, void*, EMPTYARG
)
580 switch( pThis
->eState
)
583 // Wenn gerade ein File geladen wird duerfen wir nicht weiterlaufen,
584 // sondern muessen den Aufruf ignorieren.
585 if( pThis
->IsDownloadingFile() )
588 pThis
->eState
= SVPAR_WORKING
;
589 pThis
->RestoreState();
591 pThis
->Continue( pThis
->pImplData
->nToken
);
593 if( ERRCODE_IO_PENDING
== pThis
->rInput
.GetError() )
594 pThis
->rInput
.ResetError();
596 if( SVPAR_PENDING
!= pThis
->eState
)
597 pThis
->ReleaseRef(); // ansonsten sind wir fertig!
600 case SVPAR_WAITFORDATA
:
601 pThis
->eState
= SVPAR_WORKING
;
604 case SVPAR_NOTSTARTED
:
609 pThis
->ReleaseRef(); // ansonsten sind wir fertig!
616 /*========================================================================
618 * SvKeyValueIterator.
620 *======================================================================*/
623 * SvKeyValueIterator.
625 SvKeyValueIterator::SvKeyValueIterator (void)
626 : m_pList (new SvKeyValueList_Impl
),
632 * ~SvKeyValueIterator.
634 SvKeyValueIterator::~SvKeyValueIterator (void)
642 sal_Bool
SvKeyValueIterator::GetFirst (SvKeyValue
&rKeyVal
)
644 m_nPos
= m_pList
->size();
645 return GetNext (rKeyVal
);
651 sal_Bool
SvKeyValueIterator::GetNext (SvKeyValue
&rKeyVal
)
655 rKeyVal
= (*m_pList
)[--m_nPos
];
668 void SvKeyValueIterator::Append (const SvKeyValue
&rKeyVal
)
670 m_pList
->push_back(new SvKeyValue(rKeyVal
));
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */