xref: /trunk/main/sc/source/filter/rtf/rtfparse.cxx (revision b77af630)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_scfilt.hxx"
26 
27 
28 
29 //------------------------------------------------------------------------
30 
31 #include "scitems.hxx"
32 #include <editeng/eeitem.hxx>
33 
34 
35 #include <editeng/editeng.hxx>
36 #include <editeng/fhgtitem.hxx>
37 #include <editeng/svxrtf.hxx>
38 #include <vcl/outdev.hxx>
39 #include <svtools/rtftoken.h>
40 
41 #define SC_RTFPARSE_CXX
42 #include "rtfparse.hxx"
43 #include "global.hxx"
44 #include "document.hxx"
45 #include "docpool.hxx"
46 
47 #define SC_RTFTWIPTOL 10		// 10 Twips Toleranz bei Spaltenbestimmung
48 
49 
50 
51 SV_IMPL_VARARR_SORT( ScRTFColTwips, sal_uLong );
52 
53 
54 
ScRTFParser(EditEngine * pEditP)55 ScRTFParser::ScRTFParser( EditEngine* pEditP ) :
56 		ScEEParser( pEditP ),
57 		pDefaultList( new ScRTFDefaultList ),
58 		pColTwips( new ScRTFColTwips ),
59 		pActDefault( NULL ),
60 		pDefMerge( NULL ),
61 		nStartAdjust( (sal_uLong)~0 ),
62 		nLastWidth(0),
63 		bNewDef( sal_False )
64 {
65 	// RTF default FontSize 12Pt
66 	long nMM = OutputDevice::LogicToLogic( 12, MAP_POINT, MAP_100TH_MM );
67 	pPool->SetPoolDefaultItem( SvxFontHeightItem( nMM, 100, EE_CHAR_FONTHEIGHT ) );
68 	// freifliegender pInsDefault
69 	pInsDefault = new ScRTFCellDefault( pPool );
70 }
71 
72 
~ScRTFParser()73 ScRTFParser::~ScRTFParser()
74 {
75 	delete pInsDefault;
76 	delete pColTwips;
77 	for ( ScRTFCellDefault* pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
78 		delete pD;
79 	delete pDefaultList;
80 }
81 
82 
Read(SvStream & rStream,const String & rBaseURL)83 sal_uLong ScRTFParser::Read( SvStream& rStream, const String& rBaseURL )
84 {
85 	Link aOldLink = pEdit->GetImportHdl();
86 	pEdit->SetImportHdl( LINK( this, ScRTFParser, RTFImportHdl ) );
87     sal_uLong nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_RTF );
88 	if ( nLastToken == RTF_PAR )
89 	{
90 		ScEEParseEntry* pE = pList->Last();
91 		if ( pE
92 				// komplett leer
93 			&& (( pE->aSel.nStartPara == pE->aSel.nEndPara
94 					&& pE->aSel.nStartPos == pE->aSel.nEndPos)
95 				// leerer Paragraph
96 				|| ( pE->aSel.nStartPara + 1 == pE->aSel.nEndPara
97 					&& pE->aSel.nStartPos == pEdit->GetTextLen( pE->aSel.nStartPara )
98 					&& pE->aSel.nEndPos == 0 )) )
99 		{	// den letzten leeren Absatz nicht uebernehmen
100 			pList->Remove();
101 			delete pE;
102 		}
103 	}
104 	ColAdjust();
105 	pEdit->SetImportHdl( aOldLink );
106 	return nErr;
107 }
108 
109 
EntryEnd(ScEEParseEntry * pE,const ESelection & aSel)110 void ScRTFParser::EntryEnd( ScEEParseEntry* pE, const ESelection& aSel )
111 {
112 	// Paragraph -2 stript den angehaengten leeren Paragraph
113 	pE->aSel.nEndPara = aSel.nEndPara - 2;
114 	// obwohl das nEndPos heisst, ist das letzte Position + 1
115 	pE->aSel.nEndPos = pEdit->GetTextLen( aSel.nEndPara - 1 );
116 }
117 
118 
NextRow()119 inline void ScRTFParser::NextRow()
120 {
121 	if ( nRowMax < ++nRowCnt )
122 		nRowMax = nRowCnt;
123 }
124 
125 
SeekTwips(sal_uInt16 nTwips,SCCOL * pCol)126 sal_Bool ScRTFParser::SeekTwips( sal_uInt16 nTwips, SCCOL* pCol )
127 {
128     sal_uInt16 nPos;
129     sal_Bool bFound = pColTwips->Seek_Entry( nTwips, &nPos );
130     *pCol = static_cast<SCCOL>(nPos);
131 	if ( bFound )
132 		return sal_True;
133 	sal_uInt16 nCount = pColTwips->Count();
134 	if ( !nCount )
135 		return sal_False;
136 	SCCOL nCol = *pCol;
137 	// nCol ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
138 	if ( nCol < static_cast<SCCOL>(nCount) && (((*pColTwips)[nCol] - SC_RTFTWIPTOL) <= nTwips) )
139 		return sal_True;
140 	// nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
141 	else if ( nCol != 0 && (((*pColTwips)[nCol-1] + SC_RTFTWIPTOL) >= nTwips) )
142 	{
143 		(*pCol)--;
144 		return sal_True;
145 	}
146 	return sal_False;
147 }
148 
149 
ColAdjust()150 void ScRTFParser::ColAdjust()
151 {
152 	if ( nStartAdjust != (sal_uLong)~0 )
153 	{
154 		SCCOL nCol = 0;
155 		ScEEParseEntry* pE;
156 		pE = pList->Seek( nStartAdjust );
157 		while ( pE )
158 		{
159 			if ( pE->nCol == 0 )
160 				nCol = 0;
161 			pE->nCol = nCol;
162 			if ( pE->nColOverlap > 1 )
163                 nCol = nCol + pE->nColOverlap;       // merged cells mit \clmrg
164 			else
165 			{
166 				SeekTwips( pE->nTwips, &nCol );
167 				if ( ++nCol <= pE->nCol )
168 					nCol = pE->nCol + 1;		// verschobene Zell-X
169 				pE->nColOverlap = nCol - pE->nCol;		// merged cells ohne \clmrg
170 			}
171 			if ( nCol > nColMax )
172 				nColMax = nCol;
173 			pE = pList->Next();
174 		}
175 		nStartAdjust = (sal_uLong)~0;
176 		pColTwips->Remove( (sal_uInt16)0, pColTwips->Count() );
177 	}
178 }
179 
180 
IMPL_LINK(ScRTFParser,RTFImportHdl,ImportInfo *,pInfo)181 IMPL_LINK( ScRTFParser, RTFImportHdl, ImportInfo*, pInfo )
182 {
183 	switch ( pInfo->eState )
184 	{
185 		case RTFIMP_NEXTTOKEN:
186 			ProcToken( pInfo );
187 			break;
188 		case RTFIMP_UNKNOWNATTR:
189 			ProcToken( pInfo );
190 			break;
191 		case RTFIMP_START:
192 		{
193 			SvxRTFParser* pParser = (SvxRTFParser*) pInfo->pParser;
194 			pParser->SetAttrPool( pPool );
195 			RTFPardAttrMapIds& rMap = pParser->GetPardMap();
196 			rMap.nBrush = ATTR_BACKGROUND;
197 			rMap.nBox = ATTR_BORDER;
198 			rMap.nShadow = ATTR_SHADOW;
199 		}
200 			break;
201 		case RTFIMP_END:
202 			if ( pInfo->aSelection.nEndPos )
203 			{	// falls noch Text: letzten Absatz erzeugen
204 				pActDefault = NULL;
205 				pInfo->nToken = RTF_PAR;
206 				// EditEngine hat keinen leeren Paragraph mehr angehaengt
207 				// den EntryEnd strippen koennte
208 				pInfo->aSelection.nEndPara++;
209 				ProcToken( pInfo );
210 			}
211 			break;
212 		case RTFIMP_SETATTR:
213 			break;
214 		case RTFIMP_INSERTTEXT:
215 			break;
216 		case RTFIMP_INSERTPARA:
217 			break;
218 		default:
219 			DBG_ERRORFILE("unknown ImportInfo.eState");
220 	}
221 	return 0;
222 }
223 
224 
225 // bei RTF_INTBL bzw. am Anfang von erstem RTF_CELL nach RTF_CELLX wenn es
226 // kein RTF_INTBL gab, bad behavior
NewCellRow(ImportInfo *)227 void ScRTFParser::NewCellRow( ImportInfo* /*pInfo*/ )
228 {
229 	if ( bNewDef )
230 	{
231 		ScRTFCellDefault* pD;
232 		bNewDef = sal_False;
233 		// rechts nicht buendig? => neue Tabelle
234 		if ( nLastWidth
235           && ((pD = pDefaultList->Last()) != 0) && pD->nTwips != nLastWidth )
236 		{
237 			SCCOL n1, n2;
238 			if ( !( SeekTwips( nLastWidth, &n1 )
239 				&& SeekTwips( pD->nTwips, &n2 ) && n1 == n2) )
240 				ColAdjust();
241 		}
242 		// TwipCols aufbauen, erst nach nLastWidth Vergleich!
243 		for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
244 		{
245 			SCCOL n;
246 			if ( !SeekTwips( pD->nTwips, &n ) )
247 				pColTwips->Insert( pD->nTwips );
248 		}
249 	}
250 	pDefMerge = NULL;
251 	pActDefault = pDefaultList->First();
252 	DBG_ASSERT( pActDefault, "NewCellRow: pActDefault==0" );
253 }
254 
255 
256 /*
257 	SW:
258 	~~~
259 	[\par]
260 	\trowd \cellx \cellx ...
261 	\intbl \cell \cell ...
262 	\row
263 	[\par]
264 	[\trowd \cellx \cellx ...]
265 	\intbl \cell \cell ...
266 	\row
267 	[\par]
268 
269 	M$-Word:
270 	~~~~~~~~
271 	[\par]
272 	\trowd \cellx \cellx ...
273 	\intbl \cell \cell ...
274 	\intbl \row
275 	[\par]
276 	[\trowd \cellx \cellx ...]
277 	\intbl \cell \cell ...
278 	\intbl \row
279 	[\par]
280 
281  */
282 
ProcToken(ImportInfo * pInfo)283 void ScRTFParser::ProcToken( ImportInfo* pInfo )
284 {
285 	ScRTFCellDefault* pD;
286 	ScEEParseEntry* pE;
287 	switch ( pInfo->nToken )
288 	{
289 		case RTF_TROWD:			// denotes table row defauls, before RTF_CELLX
290 		{
291             if ( (pD = pDefaultList->Last()) != 0 )
292 				nLastWidth = pD->nTwips;
293 			nColCnt = 0;
294 			for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
295 				delete pD;
296 			pDefaultList->Clear();
297 			pDefMerge = NULL;
298 			nLastToken = pInfo->nToken;
299 		}
300 		break;
301 		case RTF_CLMGF:			// The first cell of cells to be merged
302 		{
303 			pDefMerge = pInsDefault;
304 			nLastToken = pInfo->nToken;
305 		}
306 		break;
307 		case RTF_CLMRG:			// A cell to be merged with the preceding cell
308 		{
309 			if ( !pDefMerge )
310 				pDefMerge = pDefaultList->Last();
311 			DBG_ASSERT( pDefMerge, "RTF_CLMRG: pDefMerge==0" );
312 			if ( pDefMerge )		// sonst rottes RTF
313 				pDefMerge->nColOverlap++;	// mehrere nacheinander moeglich
314 			pInsDefault->nColOverlap = 0;	// Flag: ignoriere diese
315 			nLastToken = pInfo->nToken;
316 		}
317 		break;
318 		case RTF_CELLX:			// closes cell default
319 		{
320 			bNewDef = sal_True;
321 			pInsDefault->nCol = nColCnt;
322 			pInsDefault->nTwips = pInfo->nTokenValue;	// rechter Zellenrand
323 			pDefaultList->Insert( pInsDefault, LIST_APPEND );
324 			// neuer freifliegender pInsDefault
325 			pInsDefault = new ScRTFCellDefault( pPool );
326 			if ( ++nColCnt > nColMax )
327 				nColMax = nColCnt;
328 			nLastToken = pInfo->nToken;
329 		}
330 		break;
331 		case RTF_INTBL:			// before the first RTF_CELL
332 		{
333 			// einmal ueber NextToken und einmal ueber UnknownAttrToken
334 			// oder z.B. \intbl ... \cell \pard \intbl ... \cell
335 			if ( nLastToken != RTF_INTBL && nLastToken != RTF_CELL && nLastToken != RTF_PAR )
336 			{
337 				NewCellRow( pInfo );
338 				nLastToken = pInfo->nToken;
339 			}
340 		}
341 		break;
342 		case RTF_CELL:			// denotes the end of a cell.
343 		{
344 			DBG_ASSERT( pActDefault, "RTF_CELL: pActDefault==0" );
345 			if ( bNewDef || !pActDefault )
346 				NewCellRow( pInfo );	// davor war kein \intbl, bad behavior
347 			// rottes RTF? retten was zu retten ist
348 			if ( !pActDefault )
349 				pActDefault = pInsDefault;
350 			if ( pActDefault->nColOverlap > 0 )
351 			{	// nicht merged mit vorheriger
352 				pActEntry->nCol = pActDefault->nCol;
353 				pActEntry->nColOverlap = pActDefault->nColOverlap;
354 				pActEntry->nTwips = pActDefault->nTwips;
355 				pActEntry->nRow = nRowCnt;
356 				pActEntry->aItemSet.Set( pActDefault->aItemSet );
357 				EntryEnd( pActEntry, pInfo->aSelection );
358 
359 				if ( nStartAdjust == (sal_uLong)~0 )
360 					nStartAdjust = pList->Count();
361 				pList->Insert( pActEntry, LIST_APPEND );
362 				NewActEntry( pActEntry );	// neuer freifliegender pActEntry
363 			}
364 			else
365 			{	// aktuelle Twips der MergeCell zuweisen
366                 if ( (pE = pList->Last()) != 0 )
367 					pE->nTwips = pActDefault->nTwips;
368 				// Selection des freifliegenden pActEntry anpassen
369 				// Paragraph -1 wg. Textaufbruch in EditEngine waehrend Parse
370 				pActEntry->aSel.nStartPara = pInfo->aSelection.nEndPara - 1;
371 			}
372 			pActDefault = pDefaultList->Next();
373 			nLastToken = pInfo->nToken;
374 		}
375 		break;
376 		case RTF_ROW:			// means the end of a row
377 		{
378 			NextRow();
379 			nLastToken = pInfo->nToken;
380 		}
381 		break;
382 		case RTF_PAR:			// Paragraph
383 		{
384 			if ( !pActDefault )
385 			{	// text not in table
386 				ColAdjust();	// close the processing table
387 				pActEntry->nCol = 0;
388 				pActEntry->nRow = nRowCnt;
389 				EntryEnd( pActEntry, pInfo->aSelection );
390 				pList->Insert( pActEntry, LIST_APPEND );
391 				NewActEntry( pActEntry );	// new pActEntry
392 				NextRow();
393 			}
394 			nLastToken = pInfo->nToken;
395 		}
396 		break;
397 		default:
398 		{	// do not set nLastToken
399 			switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
400 			{
401 				case RTF_SHADINGDEF:
402 					((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(
403 						pInfo->nToken, pInsDefault->aItemSet, sal_True );
404 				break;
405 				case RTF_BRDRDEF:
406 					((SvxRTFParser*)pInfo->pParser)->ReadBorderAttr(
407 						pInfo->nToken, pInsDefault->aItemSet, sal_True );
408 				break;
409 			}
410 		}
411 	}
412 }
413 
414 
415 
416 
417