xref: /AOO41X/main/sc/source/filter/rtf/rtfparse.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
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_sc.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