xref: /trunk/main/oox/source/xls/ooxformulaparser.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/ooxformulaparser.hxx"
29 
30 #include <com/sun/star/uno/XComponentContext.hpp>
31 #include "oox/xls/formulaparser.hxx"
32 
33 namespace oox {
34 namespace xls {
35 
36 // ============================================================================
37 
38 using namespace ::com::sun::star::lang;
39 using namespace ::com::sun::star::sheet;
40 using namespace ::com::sun::star::table;
41 using namespace ::com::sun::star::uno;
42 
43 using ::rtl::OUString;
44 
45 // ============================================================================
46 
47 class OOXMLFormulaParserImpl : private FormulaFinalizer
48 {
49 public:
50     explicit            OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxModelFactory );
51 
52     Sequence< FormulaToken > parseFormula( const OUString& rFormula, const CellAddress& rReferencePos );
53 
54 protected:
55     virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
56 
57 private:
58     ApiParserWrapper    maApiParser;
59 };
60 
61 // ----------------------------------------------------------------------------
62 
63 OOXMLFormulaParserImpl::OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxModelFactory ) :
64     FormulaFinalizer( OpCodeProvider( rxModelFactory, FILTER_OOXML, BIFF_UNKNOWN, true ) ),
65     maApiParser( rxModelFactory, *this )
66 {
67 }
68 
69 Sequence< FormulaToken > OOXMLFormulaParserImpl::parseFormula( const OUString& rFormula, const CellAddress& rReferencePos )
70 {
71     return finalizeTokenArray( maApiParser.parseFormula( rFormula, rReferencePos ) );
72 }
73 
74 const FunctionInfo* OOXMLFormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
75 {
76     /*  Try to parse calls to library functions. The format of such a function
77         call is assumed to be
78             "'<path-to-office-install>\Library\<libname>'!<funcname>". */
79 
80     // the string has to start with an apostroph (followed by the library URL)
81     if( (rTokenData.getLength() >= 6) && (rTokenData[ 0 ] == '\'') )
82     {
83         // library URL and function name are separated by an exclamation mark
84         sal_Int32 nExclamPos = rTokenData.lastIndexOf( '!' );
85         if( (1 < nExclamPos) && (nExclamPos + 1 < rTokenData.getLength()) && (rTokenData[ nExclamPos - 1 ] == '\'') )
86         {
87             // find the last backslash that separates library path and name
88             sal_Int32 nFileSep = rTokenData.lastIndexOf( '\\', nExclamPos - 2 );
89             if( nFileSep > 1 )
90             {
91                 // find preceding backslash that separates the last directory name
92                 sal_Int32 nDirSep = rTokenData.lastIndexOf( '\\', nFileSep - 1 );
93                 // function library is located in a directory called 'library'
94                 if( (nDirSep > 0) && rTokenData.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "\\LIBRARY\\" ), nDirSep ) )
95                 {
96                     // try to find a function info for the function name
97                     OUString aFuncName = rTokenData.copy( nExclamPos + 1 ).toAsciiUpperCase();
98                     const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName );
99                     if( pFuncInfo && (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) )
100                     {
101                         // check that the name of the library matches
102                         OUString aLibName = rTokenData.copy( nFileSep + 1, nExclamPos - nFileSep - 2 );
103                         if( pFuncInfo->meFuncLibType == getFuncLibTypeFromLibraryName( aLibName ) )
104                             return pFuncInfo;
105                     }
106                 }
107             }
108         }
109     }
110     return 0;
111 }
112 
113 // ============================================================================
114 
115 class OOXMLFormulaPrinterImpl : public OpCodeProvider
116 {
117 public:
118     explicit            OOXMLFormulaPrinterImpl( const Reference< XMultiServiceFactory >& rxModelFactory );
119 
120 private:
121     ApiParserWrapper    maApiParser;
122 };
123 
124 // ----------------------------------------------------------------------------
125 
126 OOXMLFormulaPrinterImpl::OOXMLFormulaPrinterImpl( const Reference< XMultiServiceFactory >& rxModelFactory ) :
127     OpCodeProvider( rxModelFactory, FILTER_OOXML, BIFF_UNKNOWN, false ),
128     maApiParser( rxModelFactory, *this )
129 {
130 }
131 
132 // ============================================================================
133 
134 Sequence< OUString > OOXMLFormulaParser_getSupportedServiceNames()
135 {
136     Sequence< OUString > aServiceNames( 1 );
137     aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.sheet.FilterFormulaParser" );
138     return aServiceNames;
139 }
140 
141 OUString OOXMLFormulaParser_getImplementationName()
142 {
143     return CREATE_OUSTRING( "com.sun.star.comp.oox.xls.FormulaParser" );
144 }
145 
146 Reference< XInterface > SAL_CALL OOXMLFormulaParser_createInstance( const Reference< XComponentContext >& ) throw( Exception )
147 {
148     return static_cast< ::cppu::OWeakObject* >( new OOXMLFormulaParser );
149 }
150 
151 // ============================================================================
152 
153 OOXMLFormulaParser::OOXMLFormulaParser()
154 {
155 }
156 
157 OOXMLFormulaParser::~OOXMLFormulaParser()
158 {
159 }
160 
161 // com.sun.star.lang.XServiceInfo interface -----------------------------------
162 
163 OUString SAL_CALL OOXMLFormulaParser::getImplementationName() throw( RuntimeException )
164 {
165     return OOXMLFormulaParser_getImplementationName();
166 }
167 
168 sal_Bool SAL_CALL OOXMLFormulaParser::supportsService( const OUString& rService ) throw( RuntimeException )
169 {
170     const Sequence< OUString > aServices( OOXMLFormulaParser_getSupportedServiceNames() );
171     const OUString* pArray = aServices.getConstArray();
172     const OUString* pArrayEnd = pArray + aServices.getLength();
173     return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
174 }
175 
176 Sequence< OUString > SAL_CALL OOXMLFormulaParser::getSupportedServiceNames() throw( RuntimeException )
177 {
178     return OOXMLFormulaParser_getSupportedServiceNames();
179 }
180 
181 // com.sun.star.lang.XInitialization interface --------------------------------
182 
183 void SAL_CALL OOXMLFormulaParser::initialize( const Sequence< Any >& rArgs ) throw( Exception, RuntimeException )
184 {
185     OSL_ENSURE( rArgs.hasElements(), "OOXMLFormulaParser::initialize - missing arguments" );
186     if( !rArgs.hasElements() )
187         throw RuntimeException();
188     mxComponent.set( rArgs[ 0 ], UNO_QUERY_THROW );
189 }
190 
191 // com.sun.star.sheet.XFilterFormulaParser interface --------------------------
192 
193 OUString SAL_CALL OOXMLFormulaParser::getSupportedNamespace() throw( RuntimeException )
194 {
195     return CREATE_OUSTRING( "http://schemas.microsoft.com/office/excel/formula" );
196 }
197 
198 // com.sun.star.sheet.XFormulaParser interface --------------------------------
199 
200 Sequence< FormulaToken > SAL_CALL OOXMLFormulaParser::parseFormula(
201         const OUString& rFormula, const CellAddress& rReferencePos ) throw( RuntimeException )
202 {
203     if( !mxParserImpl )
204     {
205         Reference< XMultiServiceFactory > xModelFactory( mxComponent, UNO_QUERY_THROW );
206         mxParserImpl.reset( new OOXMLFormulaParserImpl( xModelFactory ) );
207     }
208     return mxParserImpl->parseFormula( rFormula, rReferencePos );
209 }
210 
211 OUString SAL_CALL OOXMLFormulaParser::printFormula(
212         const Sequence< FormulaToken >& /*rTokens*/, const CellAddress& /*rReferencePos*/ ) throw( RuntimeException )
213 {
214     // not implemented
215     throw RuntimeException();
216 }
217 
218 // ============================================================================
219 
220 } // namespace xls
221 } // namespace oox
222