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 <cppuhelper/factory.hxx>
25 #include <cppuhelper/servicefactory.hxx>
26 #include <cppuhelper/implbase1.hxx>
27 #include <cppuhelper/implbase2.hxx>
28 #include <cppuhelper/implbase3.hxx>
29 #include <cppuhelper/implbase.hxx>
30 
31 #include <com/sun/star/lang/XComponent.hpp>
32 
33 #include <com/sun/star/uno/Any.hxx>
34 #include <com/sun/star/uno/Type.hxx>
35 
36 #include <com/sun/star/beans/PropertyValue.hpp>
37 
38 #include <com/sun/star/xml/sax/XParser.hpp>
39 #include <com/sun/star/xml/sax/InputSource.hpp>
40 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
41 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
42 #include <com/sun/star/xml/sax/SAXException.hpp>
43 #include <com/sun/star/xml/XImportFilter.hpp>
44 #include <com/sun/star/xml/XExportFilter.hpp>
45 
46 #include <com/sun/star/io/XInputStream.hpp>
47 #include <com/sun/star/io/XOutputStream.hpp>
48 #include <com/sun/star/io/XActiveDataSource.hpp>
49 #include <com/sun/star/io/XSeekable.hpp>
50 
51 using namespace ::rtl;
52 using namespace ::cppu;
53 using namespace ::osl;
54 using namespace ::com::sun::star::beans;
55 using namespace ::com::sun::star::io;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::lang;
58 using namespace ::com::sun::star::registry;
59 using namespace ::com::sun::star::xml;
60 using namespace ::com::sun::star::xml::sax;
61 
62 namespace XFlatXml {
63 
64 class XFlatXml : public WeakImplHelper3< XImportFilter, XExportFilter, XDocumentHandler>
65 {
66 private:
67     // the UNO ServiceFactory
68     Reference< XMultiServiceFactory > m_rServiceFactory;
69 
70     // DocumentHandler interface of the css::xml::sax::Writer service
71     Reference < XExtendedDocumentHandler > m_rDocumentHandler;
72 
73     // controls pretty-printing
74     sal_Bool m_bPrettyPrint;
75 
76 public:
77 
78     // ctor...
XFlatXml(const Reference<XMultiServiceFactory> & r)79     XFlatXml( const Reference< XMultiServiceFactory > &r )
80         : m_rServiceFactory(r)
81         , m_bPrettyPrint(sal_True)
82 	{}
83 
84     // XImportFilter
85     virtual sal_Bool SAL_CALL importer(
86             const Sequence<PropertyValue>& aSourceData,
87             const Reference<XDocumentHandler>& xHandler,
88             const Sequence<OUString>& msUserData)
89         throw(RuntimeException);
90 
91     // XExportFilter
92     virtual sal_Bool SAL_CALL exporter(
93             const Sequence<PropertyValue>& aSourceData,
94             const Sequence<OUString>& msUserData)
95         throw(RuntimeException);
96 
97     // XDocumentHandler
98     virtual void SAL_CALL startDocument()
99         throw (SAXException,RuntimeException);
100     virtual void SAL_CALL endDocument()
101         throw (SAXException, RuntimeException);
102     virtual void SAL_CALL startElement(const OUString& str, const Reference<XAttributeList>& attriblist)
103         throw (SAXException,RuntimeException);
104     virtual void SAL_CALL endElement(const OUString& str)
105         throw (SAXException, RuntimeException);
106     virtual void SAL_CALL characters(const OUString& str)
107         throw (SAXException, RuntimeException);
108     virtual void SAL_CALL ignorableWhitespace(const OUString& str)
109         throw (SAXException, RuntimeException);
110     virtual void SAL_CALL processingInstruction(const OUString& str, const OUString& str2)
111         throw (com::sun::star::xml::sax::SAXException,RuntimeException);
112     virtual void SAL_CALL setDocumentLocator(const Reference<XLocator>& doclocator)
113         throw (SAXException,RuntimeException);
114 };
115 
importer(const Sequence<PropertyValue> & aSourceData,const Reference<XDocumentHandler> & xHandler,const Sequence<OUString> & msUserData)116 sal_Bool XFlatXml::importer(
117         const Sequence<PropertyValue>& aSourceData,
118         const Reference<XDocumentHandler>& xHandler,
119         const Sequence<OUString>& msUserData)
120     throw (RuntimeException)
121 {
122     // get information from media descriptor
123     // the input stream that represents the imported file
124     // is most important here since we need to supply it to
125     // the sax parser that drives the supplied document handler
126     sal_Int32 nLength = aSourceData.getLength();
127     OUString aName, aFileName, aURL;
128     Reference< XInputStream > xInputStream;
129     for ( sal_Int32 i = 0 ; i < nLength; i++)
130 	{
131         aName = aSourceData[i].Name;
132 	    if (aName.equalsAscii("InputStream"))
133             aSourceData[i].Value >>= xInputStream;
134 	    else if ( aName.equalsAscii("FileName"))
135 			aSourceData[i].Value >>= aFileName;
136 	    else if ( aName.equalsAscii("URL"))
137 			aSourceData[i].Value >>= aURL;
138 	}
139 
140     // we need an input stream
141     OSL_ASSERT(xInputStream.is());
142     if (!xInputStream.is()) return sal_False;
143 
144     // rewind seekable stream
145     Reference< XSeekable > xSeek(xInputStream, UNO_QUERY);
146     if (xSeek.is())
147         xSeek->seek(0);
148 
149 
150     // create SAX parser that will read the document file
151     // and provide events to xHandler passed to this call
152 	Reference < XParser > xSaxParser( m_rServiceFactory->createInstance(
153         OUString::createFromAscii("com.sun.star.xml.sax.Parser")), UNO_QUERY );
154     OSL_ASSERT(xSaxParser.is());
155 	if(!xSaxParser.is())return sal_False;
156 
157     // let the parser try to send the sax event to the document handler
158     try
159 	{
160 	    InputSource aInput;
161 	    aInput.sSystemId = aURL;
162         aInput.sPublicId = aURL;
163 	    aInput.aInputStream = xInputStream;
164 	    xSaxParser->setDocumentHandler(xHandler);
165 	    xSaxParser->parseStream(aInput);
166 	}
167 	catch( Exception &exc)
168 	{
169         // something went wrong
170         OSL_ENSURE(0, rtl::OUStringToOString(exc.Message,RTL_TEXTENCODING_UTF8).getStr());
171         return sal_False;
172 	}
173 
174     // done
175     return sal_True;
176 }
177 
exporter(const Sequence<PropertyValue> & aSourceData,const Sequence<OUString> & msUserData)178 sal_Bool XFlatXml::exporter(
179         const Sequence<PropertyValue>& aSourceData,
180         const Sequence<OUString>& msUserData)
181     throw (RuntimeException)
182 {
183 
184     // read source data
185     // we are especially interested in the output stream
186     // since that is where our xml-writer will push the data
187     // from its data-source interface
188     OUString aName, sURL;
189     Reference<XOutputStream> rOutputStream;
190     sal_Int32 nLength = aSourceData.getLength();
191     for ( sal_Int32 i = 0 ; i < nLength; i++)
192     {
193         aName = aSourceData[i].Name;
194         if ( aName.equalsAscii("OutputStream"))
195 	        aSourceData[i].Value >>= rOutputStream;
196         else if ( aName.equalsAscii("URL" ))
197             aSourceData[i].Value >>= sURL;
198     }
199 
200     if (!m_rDocumentHandler.is()) {
201         // get the document writer
202         m_rDocumentHandler = Reference<XExtendedDocumentHandler>(
203             m_rServiceFactory->createInstance(
204             OUString::createFromAscii("com.sun.star.xml.sax.Writer")),
205                 UNO_QUERY);
206         OSL_ASSERT(m_rDocumentHandler.is());
207         if (!m_rDocumentHandler.is()) return sal_False;
208     }
209     // get data source interface ...
210     Reference< XActiveDataSource > rDataSource(m_rDocumentHandler, UNO_QUERY);
211     OSL_ASSERT(rDataSource.is());
212     if (!rDataSource.is()) return sal_False;
213     OSL_ASSERT(rOutputStream.is());
214     if (!rOutputStream.is()) return sal_False;
215     // ... and set output stream
216     rDataSource->setOutputStream(rOutputStream);
217 
218     return sal_True;
219 }
220 
221 // for the DocumentHandler implementation, we just proxy the the
222 // events to the XML writer that we created upon the output stream
223 // that was provided by the XMLFilterAdapter
startDocument()224 void XFlatXml::startDocument() throw (SAXException,RuntimeException){
225     OSL_ASSERT(m_rDocumentHandler.is());
226     m_rDocumentHandler->startDocument();
227 }
228 
endDocument()229 void XFlatXml::endDocument() throw (SAXException,RuntimeException){
230     OSL_ASSERT(m_rDocumentHandler.is());
231     m_rDocumentHandler->endDocument();
232 }
233 
startElement(const OUString & str,const Reference<XAttributeList> & attriblist)234 void XFlatXml::startElement(const OUString& str, const Reference<XAttributeList>& attriblist)
235     throw (SAXException, RuntimeException)
236 {
237     OSL_ASSERT(m_rDocumentHandler.is());
238     m_rDocumentHandler->startElement(str, attriblist);
239 }
240 
endElement(const OUString & str)241 void XFlatXml::endElement(const OUString& str)
242     throw (SAXException, RuntimeException)
243 {
244     OSL_ASSERT(m_rDocumentHandler.is());
245     m_rDocumentHandler->endElement(str);
246 }
247 
characters(const OUString & str)248 void XFlatXml::characters(const OUString& str)
249     throw (SAXException, RuntimeException)
250 {
251     OSL_ASSERT(m_rDocumentHandler.is());
252     m_rDocumentHandler->characters(str);
253 }
254 
ignorableWhitespace(const OUString & str)255 void XFlatXml::ignorableWhitespace(const OUString& str)
256     throw (SAXException, RuntimeException)
257 {
258     OSL_ASSERT(m_rDocumentHandler.is());
259     if (!m_bPrettyPrint) return;
260     m_rDocumentHandler->ignorableWhitespace(str);
261 }
262 
processingInstruction(const OUString & str,const OUString & str2)263 void  XFlatXml::processingInstruction(const OUString& str, const OUString& str2)
264     throw (SAXException, RuntimeException)
265 {
266     OSL_ASSERT(m_rDocumentHandler.is());
267     m_rDocumentHandler->processingInstruction(str, str2);
268 }
269 
setDocumentLocator(const Reference<XLocator> & doclocator)270 void XFlatXml::setDocumentLocator(const Reference<XLocator>& doclocator)
271     throw (SAXException, RuntimeException)
272 {
273     OSL_ASSERT(m_rDocumentHandler.is());
274     m_rDocumentHandler->setDocumentLocator(doclocator);
275 }
276 
277 // --------------------------------------
278 // Component management
279 // --------------------------------------
CreateInstance(const Reference<XMultiServiceFactory> & r)280 Reference< XInterface > SAL_CALL CreateInstance( const Reference< XMultiServiceFactory > &r)
281 {
282     return Reference< XInterface >(( OWeakObject *)new XFlatXml(r));
283 }
284 
getSupportedServiceNames()285 Sequence< OUString > getSupportedServiceNames()
286 {
287 	static Sequence < OUString > *pNames = 0;
288 	if( ! pNames )
289 	{
290 		MutexGuard guard( Mutex::getGlobalMutex() );
291 		if( !pNames )
292 		{
293 			static Sequence< OUString > seqNames(1);
294 			seqNames.getArray()[0] = OUString::createFromAscii(
295     			"devguide.officedev.samples.filter.FlatXmlCpp");
296 			pNames = &seqNames;
297 		}
298 	}
299 	return *pNames;
300 }
301 
302 }
303 
304 using namespace XFlatXml;
305 #define IMPLEMENTATION_NAME "devguide.officedev.samples.filter.FlatXmlCpp"
306 
307 
308 extern "C"
309 {
component_getImplementationEnvironment(const sal_Char ** ppEnvTypeName,uno_Environment ** ppEnv)310 SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment(
311 	const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
312 {
313     *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
314 }
315 
316 // This method not longer necessary since OOo 3.4 where the component registration was
317 // was changed to passive component registration. For more details see
318 // https://wiki.openoffice.org/wiki/Passive_Component_Registration
319 //
320 // SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo(void * pServiceManager, void * pRegistryKey )
321 // {
322 //     if (pRegistryKey)
323 // 	{
324 //         try
325 //         {
326 //             Reference< XRegistryKey > xNewKey(
327 //                 reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey(
328 //                     OUString::createFromAscii( "/" IMPLEMENTATION_NAME "/UNO/SERVICES" ) ) );
329 
330 //             const Sequence< OUString > & rSNL = getSupportedServiceNames();
331 //             const OUString * pArray = rSNL.getConstArray();
332 //             for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
333 //                 xNewKey->createKey( pArray[nPos] );
334 
335 //             return sal_True;
336 //         }
337 //         catch (InvalidRegistryException &)
338 //         {
339 //             OSL_ENSURE( sal_False, "### InvalidRegistryException!" );
340 //         }
341 //     }
342 //     return sal_False;
343 // }
344 
component_getFactory(const sal_Char * pImplName,void * pServiceManager,void * pRegistryKey)345 SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(
346     const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
347 {
348     void * pRet = 0;
349 
350     if (pServiceManager && rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0)
351     {
352         Reference< XSingleServiceFactory > xFactory( createSingleFactory(
353             reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
354             OUString::createFromAscii( pImplName ),
355             CreateInstance, getSupportedServiceNames() ) );
356 
357         if (xFactory.is())
358         {
359             xFactory->acquire();
360             pRet = xFactory.get();
361         }
362     }
363     return pRet;
364 }
365 
366 } // extern "C"
367 
368