Fix default value of Emscripten --with-main-module
[LibreOffice.git] / sax / qa / cppunit / xmlimport.cxx
blob18f8c9a21112fe8ef25e5391cb42024b38cb0390
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/types.h>
22 #include <cppunit/extensions/HelperMacros.h>
23 #include <cppunit/plugin/TestPlugIn.h>
24 #include <test/bootstrapfixture.hxx>
25 #include <cppuhelper/implbase.hxx>
26 #include <com/sun/star/beans/Pair.hpp>
27 #include <com/sun/star/xml/sax/SAXException.hpp>
28 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
29 #include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
30 #include <comphelper/processfactory.hxx>
31 #include <com/sun/star/xml/sax/Parser.hpp>
32 #include <com/sun/star/xml/sax/XParser.hpp>
33 #include <com/sun/star/xml/sax/XLocator.hpp>
34 #include <com/sun/star/xml/sax/FastToken.hpp>
35 #include <com/sun/star/lang/XInitialization.hpp>
36 #include <osl/file.hxx>
37 #include <unotools/ucbstreamhelper.hxx>
38 #include <unotools/streamwrap.hxx>
39 #include <sax/fastattribs.hxx>
40 #include <stack>
41 #include <string_view>
42 #include <deque>
43 #include <rtl/ref.hxx>
46 namespace {
48 using namespace css;
49 using namespace uno;
50 using namespace io;
51 using namespace xml::sax;
52 using namespace ::osl;
53 using namespace sax_fastparser;
55 Reference< XInputStream > createStreamFromFile (
56 const OUString & filePath)
58 Reference< XInputStream > xInputStream;
59 OUString aInStr;
60 FileBase::getFileURLFromSystemPath(filePath, aInStr);
61 std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(aInStr, StreamMode::READ);
62 if(pStream == nullptr)
63 CPPUNIT_ASSERT(false);
64 Reference< XStream > xStream(new utl::OStreamWrapper(std::move(pStream)));
65 xInputStream.set(xStream, UNO_QUERY);
66 return xInputStream;
69 class TestDocumentHandler : public cppu::WeakImplHelper< XDocumentHandler >
71 private:
72 OUString m_aStr;
73 std::deque< std::pair<OUString,OUString> > m_aNamespaceStack;
74 std::stack<sal_uInt16> m_aCountStack;
76 OUString canonicalform(const OUString &sName, const OUString &sValue, bool isElement);
77 OUString getNamespace(std::u16string_view sName);
79 public:
80 TestDocumentHandler() {}
81 const OUString & getString() const { return m_aStr; }
83 // XDocumentHandler
84 virtual void SAL_CALL startDocument() override;
85 virtual void SAL_CALL endDocument() override;
86 virtual void SAL_CALL startElement( const OUString& aName, const Reference< XAttributeList >& xAttribs ) override;
87 virtual void SAL_CALL endElement( const OUString& aName ) override;
88 virtual void SAL_CALL characters( const OUString& aChars ) override;
89 virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override;
90 virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override;
91 virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) override;
94 OUString TestDocumentHandler::canonicalform(const OUString &sName, const OUString &sValue, bool isElement)
96 sal_Int16 nIndex = sName.indexOf(":");
97 if ( !isElement && sName.match( "xmlns" ) )
99 m_aCountStack.top() += 1;
100 if ( nIndex < 0 )
101 m_aNamespaceStack.emplace_back( u"default"_ustr, sValue );
102 else
103 m_aNamespaceStack.emplace_back( sName.copy( nIndex + 1 ), sValue );
105 else
107 if ( nIndex >= 0 )
109 OUString sNamespace = getNamespace( sName.subView( 0, nIndex ) );
110 return sNamespace + sName.subView(nIndex);
112 else
114 OUString sDefaultns = getNamespace( u"default" );
115 if ( !isElement || sDefaultns.isEmpty() )
116 return sName;
117 else
118 return sDefaultns + ":" + sName;
121 return OUString();
124 OUString TestDocumentHandler::getNamespace(std::u16string_view sName)
126 for (sal_Int16 i = m_aNamespaceStack.size() - 1; i>=0; i--)
128 std::pair<OUString, OUString> aPair = m_aNamespaceStack.at(i);
129 if (aPair.first == sName)
130 return aPair.second;
132 return OUString();
135 void SAL_CALL TestDocumentHandler::startDocument()
137 m_aStr.clear();
138 m_aNamespaceStack.clear();
139 m_aNamespaceStack.emplace_back( std::make_pair( u"default"_ustr, OUString() ) );
140 m_aCountStack = std::stack<sal_uInt16>();
141 m_aCountStack.emplace(0);
145 void SAL_CALL TestDocumentHandler::endDocument()
149 void SAL_CALL TestDocumentHandler::startElement( const OUString& aName, const Reference< XAttributeList >& xAttribs )
151 OUString sAttributes;
152 m_aCountStack.push(0);
153 sal_uInt16 len = xAttribs->getLength();
154 for (sal_uInt16 i=0; i<len; i++)
156 OUString sAttrValue = xAttribs->getValueByIndex(i);
157 OUString sAttrName = canonicalform(xAttribs->getNameByIndex(i), sAttrValue, false);
158 if (!sAttrName.isEmpty())
159 sAttributes += sAttrName + sAttrValue;
161 m_aStr += canonicalform(aName, u""_ustr, true) + sAttributes;
165 void SAL_CALL TestDocumentHandler::endElement( const OUString& aName )
167 m_aStr += canonicalform(aName, u""_ustr, true);
168 sal_uInt16 nPopQty = m_aCountStack.top();
169 for (sal_uInt16 i=0; i<nPopQty; i++)
170 m_aNamespaceStack.pop_back();
171 m_aCountStack.pop();
175 void SAL_CALL TestDocumentHandler::characters( const OUString& aChars )
177 m_aStr += aChars;
181 void SAL_CALL TestDocumentHandler::ignorableWhitespace( const OUString& aWhitespaces )
183 m_aStr += aWhitespaces;
187 void SAL_CALL TestDocumentHandler::processingInstruction( const OUString& aTarget, const OUString& aData )
189 m_aStr += aTarget + aData;
193 void SAL_CALL TestDocumentHandler::setDocumentLocator( const Reference< XLocator >& /*xLocator*/ )
197 class NSDocumentHandler : public cppu::WeakImplHelper< XDocumentHandler >
199 public:
200 NSDocumentHandler() {}
202 // XDocumentHandler
203 virtual void SAL_CALL startDocument() override {}
204 virtual void SAL_CALL endDocument() override {}
205 virtual void SAL_CALL startElement( const OUString& aName, const Reference< XAttributeList >& xAttribs ) override;
206 virtual void SAL_CALL endElement( const OUString& /* aName */ ) override {}
207 virtual void SAL_CALL characters( const OUString& /* aChars */ ) override {}
208 virtual void SAL_CALL ignorableWhitespace( const OUString& /* aWhitespaces */ ) override {}
209 virtual void SAL_CALL processingInstruction( const OUString& /* aTarget */, const OUString& /* aData */ ) override {}
210 virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& /* xLocator */ ) override {}
213 OUString getNamespaceValue( std::u16string_view rNamespacePrefix )
215 OUString aNamespaceURI;
216 if (rNamespacePrefix == u"office")
217 aNamespaceURI = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
218 else if (rNamespacePrefix == u"text")
219 aNamespaceURI = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
220 else if (rNamespacePrefix == u"note")
221 aNamespaceURI = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
222 return aNamespaceURI;
225 OUString resolveNamespace( const OUString& aName )
227 int index;
228 if (( index = aName.indexOf( ':' )) > 0 )
230 if ( aName.getLength() > index + 1 )
232 OUString aAttributeName = getNamespaceValue( aName.subView( 0, index ) ) +
233 ":" + aName.subView( index + 1 );
234 return aAttributeName;
237 return aName;
240 void SAL_CALL NSDocumentHandler::startElement( const OUString& aName, const Reference< XAttributeList >&/* xAttribs */ )
242 if (! (aName == "office:document" || aName == "office:body" || aName == "office:text" ||
243 aName == "text:p" || aName == "note:p") )
244 CPPUNIT_ASSERT(false);
246 OUString sResolvedName = resolveNamespace(aName);
247 if (! ( sResolvedName == "urn:oasis:names:tc:opendocument:xmlns:office:1.0:document" ||
248 sResolvedName == "urn:oasis:names:tc:opendocument:xmlns:office:1.0:body" ||
249 sResolvedName == "urn:oasis:names:tc:opendocument:xmlns:office:1.0:text" ||
250 sResolvedName == "urn:oasis:names:tc:opendocument:xmlns:text:1.0:p") )
251 CPPUNIT_ASSERT(false);
254 class DummyTokenHandler : public sax_fastparser::FastTokenHandlerBase
256 public:
257 const static std::string_view tokens[];
258 const static std::u16string_view namespaceURIs[];
259 const static std::string_view namespacePrefixes[];
261 // XFastTokenHandler
262 virtual Sequence< sal_Int8 > SAL_CALL getUTF8Identifier( sal_Int32 nToken ) override;
263 virtual sal_Int32 SAL_CALL getTokenFromUTF8( const css::uno::Sequence< sal_Int8 >& Identifier ) override;
264 //FastTokenHandlerBase
265 virtual sal_Int32 getTokenDirect(std::string_view sToken) const override;
268 const std::string_view DummyTokenHandler::tokens[] = {
269 "Signature", "CanonicalizationMethod",
270 "Algorithm", "Type",
271 "DigestMethod", "Reference",
272 "document", "spacing",
273 "Player", "Height" };
275 const std::u16string_view DummyTokenHandler::namespaceURIs[] = {
276 u"http://www.w3.org/2000/09/xmldsig#",
277 u"http://schemas.openxmlformats.org/wordprocessingml/2006/main/",
278 u"xyzsports.com/players/football/" };
280 const std::string_view DummyTokenHandler::namespacePrefixes[] = {
282 "w",
283 "Player" };
285 Sequence< sal_Int8 > DummyTokenHandler::getUTF8Identifier( sal_Int32 nToken )
287 std::string_view aUtf8Token;
288 if ( ( nToken & 0xffff0000 ) != 0 ) //namespace
290 sal_uInt32 nNamespaceToken = ( nToken >> 16 ) - 1;
291 if ( nNamespaceToken < std::size(namespacePrefixes) )
292 aUtf8Token = namespacePrefixes[ nNamespaceToken ];
294 else //element or attribute
296 size_t nElementToken = nToken & 0xffff;
297 if ( nElementToken < std::size(tokens) )
298 aUtf8Token = tokens[ nElementToken ];
300 Sequence< sal_Int8 > aSeq( reinterpret_cast< const sal_Int8* >(
301 aUtf8Token.data() ), aUtf8Token.size() );
302 return aSeq;
305 sal_Int32 DummyTokenHandler::getTokenFromUTF8( const uno::Sequence< sal_Int8 >& rIdentifier )
307 return getTokenDirect(std::string_view(
308 reinterpret_cast<const char*>(rIdentifier.getConstArray()), rIdentifier.getLength()));
311 sal_Int32 DummyTokenHandler::getTokenDirect(std::string_view sToken) const
313 for( size_t i = 0; i < std::size(tokens); i++ )
315 if ( tokens[i] == sToken )
316 return static_cast<sal_Int32>(i);
318 return FastToken::DONTKNOW;
322 class XMLImportTest : public test::BootstrapFixture
324 private:
325 OUString m_sDirPath;
326 rtl::Reference< TestDocumentHandler > m_xDocumentHandler;
327 Reference< XParser > m_xParser;
328 Reference< XParser > m_xLegacyFastParser;
330 public:
331 virtual void setUp() override;
333 XMLImportTest() : BootstrapFixture(true, false) {}
334 void parse();
335 void testMissingNamespaceDeclaration();
336 void testIllegalNamespaceUse();
338 CPPUNIT_TEST_SUITE( XMLImportTest );
339 CPPUNIT_TEST( parse );
340 CPPUNIT_TEST( testMissingNamespaceDeclaration );
341 CPPUNIT_TEST( testIllegalNamespaceUse );
342 CPPUNIT_TEST_SUITE_END();
345 void XMLImportTest::setUp()
347 test::BootstrapFixture::setUp();
348 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
349 m_xDocumentHandler.set( new TestDocumentHandler() );
350 m_xParser = Parser::create( xContext );
351 m_xParser->setDocumentHandler( m_xDocumentHandler );
352 m_xLegacyFastParser.set( xContext->getServiceManager()->createInstanceWithContext
353 ( u"com.sun.star.xml.sax.LegacyFastParser"_ustr, xContext ), UNO_QUERY );
354 m_xLegacyFastParser->setDocumentHandler( m_xDocumentHandler );
356 Reference< XFastTokenHandler > xTokenHandler;
357 xTokenHandler.set( new DummyTokenHandler );
358 uno::Reference<lang::XInitialization> const xInit(m_xLegacyFastParser,
359 uno::UNO_QUERY_THROW);
360 xInit->initialize({ uno::Any(xTokenHandler) });
362 sal_Int32 nNamespaceCount = SAL_N_ELEMENTS(DummyTokenHandler::namespaceURIs);
363 uno::Sequence<uno::Any> namespaceArgs( nNamespaceCount + 1 );
364 auto p_namespaceArgs = namespaceArgs.getArray();
365 p_namespaceArgs[0] <<= u"registerNamespaces"_ustr;
366 for (sal_Int32 i = 1; i <= nNamespaceCount; i++ )
368 css::beans::Pair<OUString, sal_Int32> rPair( OUString(DummyTokenHandler::namespaceURIs[i - 1]), i << 16 );
369 p_namespaceArgs[i] <<= rPair;
371 xInit->initialize( namespaceArgs );
373 m_sDirPath = m_directories.getPathFromSrc( u"/sax/qa/data/" );
376 void XMLImportTest::parse()
378 OUString fileNames[] = {u"simple.xml"_ustr, u"defaultns.xml"_ustr, u"inlinens.xml"_ustr,
379 u"multiplens.xml"_ustr, u"multiplepfx.xml"_ustr,
380 u"nstoattributes.xml"_ustr, u"nestedns.xml"_ustr, u"testthreading.xml"_ustr};
382 for (size_t i = 0; i < std::size( fileNames ); i++)
384 InputSource source;
385 source.sSystemId = "internal";
387 source.aInputStream = createStreamFromFile( m_sDirPath + fileNames[i] );
388 m_xParser->parseStream(source);
389 const OUString rParserStr = m_xDocumentHandler->getString();
391 source.aInputStream = createStreamFromFile( m_sDirPath + fileNames[i] );
392 m_xLegacyFastParser->parseStream(source);
393 const OUString rLegacyFastParserStr = m_xDocumentHandler->getString();
395 CPPUNIT_ASSERT_EQUAL( rParserStr, rLegacyFastParserStr );
396 // OString o = OUStringToOString( Str, RTL_TEXTENCODING_ASCII_US );
397 // CPPUNIT_ASSERT_MESSAGE( string(o.pData->buffer), false );
401 void XMLImportTest::testMissingNamespaceDeclaration()
403 OUString fileNames[] = { u"manifestwithnsdecl.xml"_ustr, u"manifestwithoutnsdecl.xml"_ustr };
405 uno::Reference<lang::XInitialization> const xInit(m_xLegacyFastParser,
406 uno::UNO_QUERY_THROW);
407 xInit->initialize({ uno::Any(u"IgnoreMissingNSDecl"_ustr) });
409 for (sal_uInt16 i = 0; i < std::size( fileNames ); i++)
413 InputSource source;
414 source.sSystemId = "internal";
416 source.aInputStream = createStreamFromFile( m_sDirPath + fileNames[i] );
417 m_xParser->parseStream(source);
418 const OUString rParserStr = m_xDocumentHandler->getString();
420 source.aInputStream = createStreamFromFile( m_sDirPath + fileNames[i] );
421 m_xLegacyFastParser->parseStream(source);
422 const OUString rLegacyFastParserStr = m_xDocumentHandler->getString();
424 CPPUNIT_ASSERT_EQUAL( rParserStr, rLegacyFastParserStr );
426 catch( const SAXException & )
432 void XMLImportTest::testIllegalNamespaceUse()
434 rtl::Reference< NSDocumentHandler > m_xNSDocumentHandler;
435 m_xNSDocumentHandler.set( new NSDocumentHandler() );
436 m_xParser->setDocumentHandler( m_xNSDocumentHandler );
437 InputSource source;
438 source.sSystemId = "internal";
440 source.aInputStream = createStreamFromFile( m_sDirPath + "multiplepfx.xml" );
441 m_xParser->parseStream(source);
443 m_xLegacyFastParser->setDocumentHandler( m_xNSDocumentHandler );
444 source.aInputStream = createStreamFromFile( m_sDirPath + "multiplepfx.xml" );
445 m_xLegacyFastParser->parseStream(source);
448 CPPUNIT_TEST_SUITE_REGISTRATION( XMLImportTest );
449 } //namespace
451 CPPUNIT_PLUGIN_IMPLEMENT();
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */