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 #include "filterdetect.hxx"
25 #include <osl/diagnose.h>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/io/XActiveDataSource.hpp>
28 #include <com/sun/star/io/XOutputStream.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/io/XSeekable.hpp>
31 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
32 #include <com/sun/star/xml/sax/InputSource.hpp>
33 #include <com/sun/star/xml/sax/XParser.hpp>
34 #include <com/sun/star/xml/XImportFilter.hpp>
35 #include <com/sun/star/xml/XExportFilter.hpp>
36 #include <com/sun/star/frame/XModel.hpp>
37 #include <com/sun/star/frame/XController.hpp>
38 #include <com/sun/star/task/XStatusIndicator.hpp>
39 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
40 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
41 #include <com/sun/star/style/XStyleLoader.hpp>
42 #include <com/sun/star/io/XInputStream.hpp>
43 #include <com/sun/star/document/XExtendedFilterDetection.hpp>
44 #include <com/sun/star/beans/PropertyState.hpp>
45 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 
48 
49 using namespace rtl;
50 using namespace com::sun::star::uno;
51 using namespace com::sun::star::document;
52 using namespace com::sun::star::lang;
53 using namespace com::sun::star::io;
54 using namespace com::sun::star::beans;
55 using namespace com::sun::star::xml::sax;
56 using namespace com::sun::star::xml;
57 using namespace com::sun::star::task;
58 using namespace com::sun::star::frame;
59 using namespace com::sun::star::container;
60 using namespace com::sun::star::ucb;
61 
62 
detect(Sequence<PropertyValue> & aArguments)63 OUString SAL_CALL FilterDetect::detect(Sequence< PropertyValue >& aArguments )
64     throw( RuntimeException )
65 {
66     // type name to return
67     OUString sOriginalTypeName;
68     OUString sTypeName;
69     OUString sURL;
70     // stream of the document to be detected
71     Reference< XInputStream > xInStream;
72     for ( sal_Int32 i = 0 ; i < aArguments.getLength(); i++)
73     {
74         OUString aName = aArguments[i].Name;
75         if (aName.equalsAscii("TypeName" ) )
76             aArguments[i].Value >>= sOriginalTypeName;
77         if (aName.equalsAscii("URL" ) )
78             aArguments[i].Value >>= sURL;
79         if (aName.equalsAscii("InputStream" ) )
80             aArguments[i].Value >>= xInStream;
81     }
82 
83     if (!xInStream.is())
84     {
85         // open the stream if it was not supplied by the framework
86         Reference< XSimpleFileAccess > xSFI(mxMSF->createInstance(
87             OUString::createFromAscii("com.sun.star.ucb.SimpleFileAccess" )), UNO_QUERY);
88         if (sURL.getLength() > 0 && xSFI.is())
89         {
90             try
91             {
92                 xInStream = xSFI->openFileRead( sURL);
93             }
94             catch( Exception& )
95             {
96                 return sTypeName;
97             }
98         } else {
99             // failed to access UCB
100             return sTypeName;
101         }
102     }
103 
104     // flatxml starts with an office:document element. this element
105     // contains a class="..." attribute by which we can deduct the
106     // type of document that is to be loaded
107     //
108     // WARNING:
109     // parsing the plain text of the document is an easy way to do this
110     // but not the purest solution, since namespaces and other xml details
111     // may lead to another syntactic expression of the same document.
112     // this example works for the way the office serializes it's XML stream
113     // but might need extension for other data sources...
114     static OString aDocToken("office:document");
115     // static OString aClassToken("office:class=\"");
116     static OString aMimeTypeToken("office:mimetype=\"");
117 
118     sal_Int32 nHeadSize = 4096;
119     Sequence< sal_Int8 > aHeadData(nHeadSize);
120 
121     // rewind seekable stream
122     Reference< XSeekable > xSeek(xInStream, UNO_QUERY);
123     if (xSeek.is())
124         xSeek->seek(0);
125 
126     long bytestRead = xInStream->readBytes(aHeadData, nHeadSize);
127 
128     OString aHead = OString((const sal_Char *)aHeadData.getConstArray(), bytestRead).toAsciiLowerCase();
129 
130     // check for document element of flatxml format
131     if (aHead.indexOf(aDocToken) >= 0)
132     {
133         // read document class
134         sal_Int32 n = aHead.indexOf(aMimeTypeToken);
135         if (n >= 0)
136         {
137             n += aMimeTypeToken.getLength();
138             OString aMimeType = aHead.copy(n, aHead.indexOf('\"', n) - n);
139             // return type for class found
140             if      (aMimeType.equals("application/x-vnd.oasis.opendocument.text") ||
141                        aMimeType.equals("application/vnd.oasis.opendocument.text"))
142                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_writer");
143             else if (aMimeType.equals("application/x-vnd.oasis.opendocument.text-master") ||
144                        aMimeType.equals("application/vnd.oasis.opendocument.text-master"))
145                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_master");
146            else if (aMimeType.equals("application/x-vnd.oasis.openoffice.text-global") ||
147                       aMimeType.equals("application/vnd.oasis.openoffice.text-global"))
148                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_master");
149            else if (aMimeType.equals("application/x-vnd.oasis.opendocument.spreadsheet") ||
150                        aMimeType.equals("application/vnd.oasis.opendocument.spreadsheet"))
151                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_calc");
152             else if (aMimeType.equals("application/x-vnd.oasis.opendocument.drawing") ||
153                        aMimeType.equals("application/vnd.oasis.opendocument.drawing"))
154                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_draw");
155             else if (aMimeType.equals("application/x-vnd.oasis.opendocument.presentation") ||
156                        aMimeType.equals("application/vnd.oasis.opendocument.presentation"))
157                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_impress");
158             else if (aMimeType.equals("application/x-vnd.oasis.opendocument.presentation") ||
159                        aMimeType.equals("application/vnd.oasis.opendocument.presentation"))
160                 sTypeName = OUString::createFromAscii("devguide_FlatXMLType_Cpp_impress");
161         }
162     }
163     return sTypeName;
164 }
165 
166 
167 // XInitialization
initialize(const Sequence<Any> & aArguments)168 void SAL_CALL FilterDetect::initialize( const Sequence< Any >& aArguments )
169 	throw (Exception, RuntimeException)
170 {
171 	Sequence < PropertyValue > aAnySeq;
172 	sal_Int32 nLength = aArguments.getLength();
173 	if ( nLength && ( aArguments[0] >>= aAnySeq ) )
174 	{
175 		const PropertyValue * pValue = aAnySeq.getConstArray();
176 		nLength = aAnySeq.getLength();
177 		for ( sal_Int32 i = 0 ; i < nLength; i++)
178 		{
179 			if ( pValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "Type" ) ) )
180 			{
181                 pValue[i].Value >>= msFilterName;
182 			}
183 			else if ( pValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "UserData" ) ) )
184 			{
185 				pValue[i].Value >>= msUserData;
186 			}
187 			else if ( pValue[i].Name.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "TemplateName" ) ) )
188 			{
189                 pValue[i].Value>>=msTemplateName;
190 			}
191 		}
192 	}
193 }
194 
FilterDetect_getImplementationName()195 OUString FilterDetect_getImplementationName ()
196 	throw (RuntimeException)
197 {
198 	return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "devguide.officedev.samples.filter.FlatXmlDetect" ) );
199 }
200 
201 #define SERVICE_NAME1 "com.sun.star.document.ExtendedTypeDetection"
202 
FilterDetect_supportsService(const OUString & ServiceName)203 sal_Bool SAL_CALL FilterDetect_supportsService( const OUString& ServiceName )
204 	throw (RuntimeException)
205 {
206     return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME1 ) );
207 }
208 
FilterDetect_getSupportedServiceNames()209 Sequence< OUString > SAL_CALL FilterDetect_getSupportedServiceNames(  )
210 	throw (RuntimeException)
211 {
212     Sequence < OUString > aRet(2);
213     OUString* pArray = aRet.getArray();
214     pArray[0] =  OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME1 ) );
215     return aRet;
216 }
217 #undef SERVICE_NAME1
218 #undef SERVICE_NAME2
219 
FilterDetect_createInstance(const Reference<XMultiServiceFactory> & rSMgr)220 Reference< XInterface > SAL_CALL FilterDetect_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
221 	throw( Exception )
222 {
223 	return (cppu::OWeakObject*) new FilterDetect( rSMgr );
224 }
225 
226 // XServiceInfo
getImplementationName()227 OUString SAL_CALL FilterDetect::getImplementationName(  )
228 	throw (RuntimeException)
229 {
230 	return FilterDetect_getImplementationName();
231 }
232 
supportsService(const OUString & rServiceName)233 sal_Bool SAL_CALL FilterDetect::supportsService( const OUString& rServiceName )
234 	throw (RuntimeException)
235 {
236     return FilterDetect_supportsService( rServiceName );
237 }
238 
getSupportedServiceNames()239 Sequence< OUString > SAL_CALL FilterDetect::getSupportedServiceNames(  )
240 	throw (RuntimeException)
241 {
242     return FilterDetect_getSupportedServiceNames();
243 }
244