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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sdext.hxx"
30 
31 #ifdef SYSTEM_ZLIB
32 #include "zlib.h"
33 #else
34 #include <zlib/zlib.h>
35 #endif
36 
37 #include "outputwrap.hxx"
38 #include "contentsink.hxx"
39 #include "pdfihelper.hxx"
40 #include "wrapper.hxx"
41 #include "pdfparse.hxx"
42 #include "../pdfiadaptor.hxx"
43 
44 #include <rtl/math.hxx>
45 #include <osl/file.hxx>
46 #include <osl/process.h>
47 #include <testshl/simpleheader.hxx>
48 #include <cppuhelper/compbase1.hxx>
49 #include <cppuhelper/bootstrap.hxx>
50 #include <cppuhelper/basemutex.hxx>
51 #include <comphelper/sequence.hxx>
52 
53 
54 #include <com/sun/star/rendering/XCanvas.hpp>
55 #include <com/sun/star/rendering/XColorSpace.hpp>
56 #include <com/sun/star/rendering/PathJoinType.hpp>
57 #include <com/sun/star/rendering/PathCapType.hpp>
58 #include <com/sun/star/rendering/BlendMode.hpp>
59 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
60 #include <com/sun/star/lang/XInitialization.hpp>
61 #include <com/sun/star/registry/XSimpleRegistry.hpp>
62 
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 #include <basegfx/tools/canvastools.hxx>
65 #include <basegfx/polygon/b2dpolygon.hxx>
66 #include <basegfx/polygon/b2dpolypolygon.hxx>
67 #include <basegfx/polygon/b2dpolypolygontools.hxx>
68 #include <basegfx/polygon/b2dpolygonclipper.hxx>
69 
70 #include <vector>
71 #include <hash_map>
72 
73 
74 using namespace ::pdfparse;
75 using namespace ::pdfi;
76 using namespace ::com::sun::star;
77 
78 namespace
79 {
80     class TestSink : public ContentSink
81     {
82     public:
83         TestSink() :
84             m_nNextFontId( 1 ),
85             m_aIdToFont(),
86             m_aFontToId(),
87             m_aGCStack(1),
88             m_aPageSize(),
89             m_aHyperlinkBounds(),
90             m_aURI(),
91             m_aTextOut(),
92             m_nNumPages(0),
93             m_bPageEnded(false),
94             m_bRedCircleSeen(false),
95             m_bGreenStrokeSeen(false),
96             m_bDashedLineSeen(false)
97         {}
98 
99         ~TestSink()
100         {
101             CPPUNIT_ASSERT_MESSAGE( "A4 page size (in 100th of points)",
102                                     m_aPageSize.Width == 79400 && m_aPageSize.Height == 59500 );
103             CPPUNIT_ASSERT_MESSAGE( "endPage() called", m_bPageEnded );
104             CPPUNIT_ASSERT_MESSAGE( "Num pages equal one", m_nNumPages == 1 );
105             CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
106                                     rtl::math::approxEqual(m_aHyperlinkBounds.X1,34.7 ) &&
107                                     rtl::math::approxEqual(m_aHyperlinkBounds.Y1,386.0) &&
108                                     rtl::math::approxEqual(m_aHyperlinkBounds.X2,166.7) &&
109                                     rtl::math::approxEqual(m_aHyperlinkBounds.Y2,406.2) );
110             CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink URI",
111                                     m_aURI == ::rtl::OUString::createFromAscii( "http://download.openoffice.org/" ) );
112 
113             const char* sText = " \n \nThis is a testtext\nNew paragraph,\nnew line\n"
114                 "Hyperlink, this is\n?\nThis is more text\noutline mode\n?\nNew paragraph\n";
115             ::rtl::OString aTmp;
116             m_aTextOut.makeStringAndClear().convertToString( &aTmp,
117                                                              RTL_TEXTENCODING_ASCII_US,
118                                                              OUSTRING_TO_OSTRING_CVTFLAGS );
119             CPPUNIT_ASSERT_MESSAGE( "Imported text is \"This is a testtext New paragraph, new line"
120                                     " Hyperlink, this is * This is more text outline mode * New paragraph\"",
121                                     sText == aTmp );
122 
123             CPPUNIT_ASSERT_MESSAGE( "red circle seen in input", m_bRedCircleSeen );
124             CPPUNIT_ASSERT_MESSAGE( "green stroke seen in input", m_bGreenStrokeSeen );
125             CPPUNIT_ASSERT_MESSAGE( "dashed line seen in input", m_bDashedLineSeen );
126         }
127 
128     private:
129         GraphicsContext& getCurrentContext() { return m_aGCStack.back(); }
130 
131         // ContentSink interface implementation
132         virtual void setPageNum( sal_Int32 nNumPages )
133         {
134             m_nNumPages = nNumPages;
135         }
136 
137         virtual void startPage( const geometry::RealSize2D& rSize )
138         {
139             m_aPageSize = rSize;
140         }
141 
142         virtual void endPage()
143         {
144             m_bPageEnded = true;
145         }
146 
147         virtual void hyperLink( const geometry::RealRectangle2D& rBounds,
148                                 const ::rtl::OUString&             rURI )
149         {
150             m_aHyperlinkBounds = rBounds;
151             m_aURI = rURI;
152         }
153 
154         virtual void pushState()
155         {
156             m_aGCStack.push_back( m_aGCStack.back() );
157         }
158 
159         virtual void popState()
160         {
161             m_aGCStack.pop_back();
162         }
163 
164         virtual void setTransformation( const geometry::AffineMatrix2D& rMatrix )
165         {
166             basegfx::unotools::homMatrixFromAffineMatrix(
167                 getCurrentContext().Transformation,
168                 rMatrix );
169         }
170 
171         virtual void setLineDash( const uno::Sequence<double>& dashes,
172                                   double                       start )
173         {
174             GraphicsContext& rContext( getCurrentContext() );
175             if( dashes.getLength() )
176                 comphelper::sequenceToContainer(rContext.DashArray,dashes);
177             CPPUNIT_ASSERT_MESSAGE( "line dashing start offset", start == 0.0 );
178         }
179 
180         virtual void setFlatness( double nFlatness )
181         {
182             getCurrentContext().Flatness = nFlatness;
183         }
184 
185         virtual void setLineJoin(sal_Int8 nJoin)
186         {
187             getCurrentContext().LineJoin = nJoin;
188         }
189 
190         virtual void setLineCap(sal_Int8 nCap)
191         {
192             getCurrentContext().LineCap = nCap;
193         }
194 
195         virtual void setMiterLimit(double nVal)
196         {
197             getCurrentContext().MiterLimit = nVal;
198         }
199 
200         virtual void setLineWidth(double nVal)
201         {
202             getCurrentContext().LineWidth = nVal;
203         }
204 
205         virtual void setFillColor( const rendering::ARGBColor& rColor )
206         {
207             getCurrentContext().FillColor = rColor;
208         }
209 
210         virtual void setStrokeColor( const rendering::ARGBColor& rColor )
211         {
212             getCurrentContext().LineColor = rColor;
213         }
214 
215         virtual void setBlendMode(sal_Int8 nMode)
216         {
217             getCurrentContext().BlendMode = nMode;
218         }
219 
220         virtual void setFont( const FontAttributes& rFont )
221         {
222             FontToIdMap::const_iterator it = m_aFontToId.find( rFont );
223             if( it != m_aFontToId.end() )
224                 getCurrentContext().FontId = it->second;
225             else
226             {
227                 m_aFontToId[ rFont ] = m_nNextFontId;
228                 m_aIdToFont[ m_nNextFontId ] = rFont;
229                 getCurrentContext().FontId = m_nNextFontId;
230                 m_nNextFontId++;
231             }
232         }
233 
234         virtual void strokePath( const uno::Reference<rendering::XPolyPolygon2D>& rPath )
235         {
236             GraphicsContext& rContext( getCurrentContext() );
237             basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
238             aPath.transform( rContext.Transformation );
239 
240             if( rContext.DashArray.empty() )
241             {
242                 CPPUNIT_ASSERT_MESSAGE( "Line color is green",
243                                         rContext.LineColor.Alpha == 1.0 &&
244                                         rContext.LineColor.Red == 0.0 &&
245                                         rContext.LineColor.Green == 1.0 &&
246                                         rContext.LineColor.Blue == 0.0 );
247 
248                 CPPUNIT_ASSERT_MESSAGE( "Line width is 0",
249                                         rtl::math::approxEqual(rContext.LineWidth, 28.3) );
250 
251                 const char* sExportString = "m53570 7650-35430 24100";
252                 CPPUNIT_ASSERT_MESSAGE( "Stroke is m535.7 518.5-354.3-241",
253                                         basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 );
254 
255                 m_bGreenStrokeSeen = true;
256             }
257             else
258             {
259                 CPPUNIT_ASSERT_MESSAGE( "Dash array cons  ists of four entries",
260                                         rContext.DashArray.size() == 4 &&
261                                         rtl::math::approxEqual(rContext.DashArray[0],14.3764) &&
262                                         rContext.DashArray[0] == rContext.DashArray[1] &&
263                                         rContext.DashArray[1] == rContext.DashArray[2] &&
264                                         rContext.DashArray[2] == rContext.DashArray[3] );
265 
266                 CPPUNIT_ASSERT_MESSAGE( "Line color is black",
267                                         rContext.LineColor.Alpha == 1.0 &&
268                                         rContext.LineColor.Red == 0.0 &&
269                                         rContext.LineColor.Green == 0.0 &&
270                                         rContext.LineColor.Blue == 0.0 );
271 
272                 CPPUNIT_ASSERT_MESSAGE( "Line width is 0",
273                                         rContext.LineWidth == 0 );
274 
275                 const char* sExportString = "m49890 5670.00000000001-35430 24090";
276                 CPPUNIT_ASSERT_MESSAGE( "Stroke is m49890 5670.00000000001-35430 24090",
277                                         basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 );
278 
279                 m_bDashedLineSeen = true;
280             }
281             CPPUNIT_ASSERT_MESSAGE( "Blend mode is normal",
282                                     rContext.BlendMode == rendering::BlendMode::NORMAL );
283             CPPUNIT_ASSERT_MESSAGE( "Join type is round",
284                                     rContext.LineJoin == rendering::PathJoinType::ROUND );
285             CPPUNIT_ASSERT_MESSAGE( "Cap type is butt",
286                                     rContext.LineCap == rendering::PathCapType::BUTT );
287             CPPUNIT_ASSERT_MESSAGE( "Line miter limit is 10",
288                                     rContext.MiterLimit == 10 );
289             CPPUNIT_ASSERT_MESSAGE( "Flatness is 0",
290                                     rContext.Flatness == 1 );
291             CPPUNIT_ASSERT_MESSAGE( "Font id is 0",
292                                     rContext.FontId == 0 );
293         }
294 
295         virtual void fillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath )
296         {
297             GraphicsContext& rContext( getCurrentContext() );
298             basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
299             aPath.transform( rContext.Transformation );
300 
301             CPPUNIT_ASSERT_MESSAGE( "Fill color is black",
302                                     rContext.FillColor.Alpha == 1.0 &&
303                                     rContext.FillColor.Red == 0.0 &&
304                                     rContext.FillColor.Green == 0.0 &&
305                                     rContext.FillColor.Blue == 0.0 );
306             CPPUNIT_ASSERT_MESSAGE( "Blend mode is normal",
307                                     rContext.BlendMode == rendering::BlendMode::NORMAL );
308             CPPUNIT_ASSERT_MESSAGE( "Flatness is 10",
309                                     rContext.Flatness == 10 );
310             CPPUNIT_ASSERT_MESSAGE( "Font id is 0",
311                                     rContext.FontId == 0 );
312         }
313 
314         virtual void eoFillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath )
315         {
316             GraphicsContext& rContext( getCurrentContext() );
317             basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
318             aPath.transform( rContext.Transformation );
319 
320             CPPUNIT_ASSERT_MESSAGE( "Fill color is black",
321                                     rContext.FillColor.Alpha == 1.0 &&
322                                     rContext.FillColor.Red == 1.0 &&
323                                     rContext.FillColor.Green == 0.0 &&
324                                     rContext.FillColor.Blue == 0.0 );
325             CPPUNIT_ASSERT_MESSAGE( "Blend mode is normal",
326                                     rContext.BlendMode == rendering::BlendMode::NORMAL );
327             CPPUNIT_ASSERT_MESSAGE( "Flatness is 0",
328                                     rContext.Flatness == 1 );
329             CPPUNIT_ASSERT_MESSAGE( "Font id is 0",
330                                     rContext.FontId == 0 );
331 
332             const char* sExportString = "m12050 49610c-4310 0-7800-3490-7800-7800 0-4300 "
333                 "3490-7790 7800-7790 4300 0 7790 3490 7790 7790 0 4310-3490 7800-7790 7800z";
334             CPPUNIT_ASSERT_MESSAGE( "Stroke is a 4-bezier circle",
335                                     basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 );
336 
337             m_bRedCircleSeen = true;
338         }
339 
340         virtual void intersectClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath)
341         {
342             basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
343             basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
344 
345             if( aCurClip.count() )  // #i92985# adapted API from (..., false, false) to (..., true, false)
346                 aNewClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
347 
348             getCurrentContext().Clip = aNewClip;
349         }
350 
351         virtual void intersectEoClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath)
352         {
353             basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
354             basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
355 
356             if( aCurClip.count() )  // #i92985# adapted API from (..., false, false) to (..., true, false)
357                 aNewClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
358 
359             getCurrentContext().Clip = aNewClip;
360         }
361 
362         virtual void drawGlyphs( const rtl::OUString&             rGlyphs,
363                                  const geometry::RealRectangle2D& /*rRect*/,
364                                  const geometry::Matrix2D&        /*rFontMatrix*/ )
365         {
366             m_aTextOut.append(rGlyphs);
367         }
368 
369         virtual void endText()
370         {
371             m_aTextOut.append( ::rtl::OUString::createFromAscii("\n") );
372         }
373 
374         virtual void drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap,
375                               bool                                       /*bInvert*/ )
376         {
377             CPPUNIT_ASSERT_MESSAGE( "drawMask received two properties",
378                                     xBitmap.getLength()==3 );
379             CPPUNIT_ASSERT_MESSAGE( "drawMask got URL param",
380                                     xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
381             CPPUNIT_ASSERT_MESSAGE( "drawMask got InputStream param",
382                                     xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
383         }
384 
385         virtual void drawImage(const uno::Sequence<beans::PropertyValue>& xBitmap )
386         {
387             CPPUNIT_ASSERT_MESSAGE( "drawImage received two properties",
388                                     xBitmap.getLength()==3 );
389             CPPUNIT_ASSERT_MESSAGE( "drawImage got URL param",
390                                     xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
391             CPPUNIT_ASSERT_MESSAGE( "drawImage got InputStream param",
392                                     xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
393         }
394 
395         virtual void drawColorMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
396                                           const uno::Sequence<uno::Any>&             /*xMaskColors*/ )
397         {
398             CPPUNIT_ASSERT_MESSAGE( "drawColorMaskedImage received two properties",
399                                     xBitmap.getLength()==3 );
400             CPPUNIT_ASSERT_MESSAGE( "drawColorMaskedImage got URL param",
401                                     xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
402             CPPUNIT_ASSERT_MESSAGE( "drawColorMaskedImage got InputStream param",
403                                     xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
404         }
405 
406         virtual void drawMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
407                                      const uno::Sequence<beans::PropertyValue>& xMask,
408                                      bool                                       /*bInvertMask*/)
409         {
410             CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage received two properties #1",
411                                     xBitmap.getLength()==3 );
412             CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got URL param #1",
413                                     xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
414             CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got InputStream param #1",
415                                     xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
416 
417             CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage received two properties #2",
418                                     xMask.getLength()==3 );
419             CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got URL param #2",
420                                     xMask[0].Name.compareToAscii( "URL" ) == 0 );
421             CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got InputStream param #2",
422                                     xMask[1].Name.compareToAscii( "InputStream" ) == 0 );
423         }
424 
425         virtual void drawAlphaMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
426                                           const uno::Sequence<beans::PropertyValue>& xMask)
427         {
428             CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage received two properties #1",
429                                     xBitmap.getLength()==3 );
430             CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got URL param #1",
431                                     xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
432             CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got InputStream param #1",
433                                     xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
434 
435             CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage received two properties #2",
436                                     xMask.getLength()==3 );
437             CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got URL param #2",
438                                     xMask[0].Name.compareToAscii( "URL" ) == 0 );
439             CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got InputStream param #2",
440                                     xMask[1].Name.compareToAscii( "InputStream" ) == 0 );
441         }
442 
443         virtual void setTextRenderMode( sal_Int32 )
444         {
445         }
446 
447         typedef std::hash_map<sal_Int32,FontAttributes> IdToFontMap;
448         typedef std::hash_map<FontAttributes,sal_Int32,FontAttrHash> FontToIdMap;
449 
450         typedef std::hash_map<sal_Int32,GraphicsContext> IdToGCMap;
451         typedef std::hash_map<GraphicsContext,sal_Int32,GraphicsContextHash> GCToIdMap;
452 
453         typedef std::vector<GraphicsContext> GraphicsContextStack;
454 
455         sal_Int32                 m_nNextFontId;
456         IdToFontMap               m_aIdToFont;
457         FontToIdMap               m_aFontToId;
458 
459         GraphicsContextStack      m_aGCStack;
460         geometry::RealSize2D      m_aPageSize;
461         geometry::RealRectangle2D m_aHyperlinkBounds;
462         ::rtl::OUString           m_aURI;
463         ::rtl::OUStringBuffer     m_aTextOut;
464         sal_Int32                 m_nNumPages;
465         bool                      m_bPageEnded;
466         bool                      m_bRedCircleSeen;
467         bool                      m_bGreenStrokeSeen;
468         bool                      m_bDashedLineSeen;
469     };
470 
471     class PDFITest : public CppUnit::TestFixture
472     {
473         uno::Reference<uno::XComponentContext> mxCtx;
474         rtl::OUString                          msBaseDir;
475         bool                                   mbUnoInitialized;
476 
477     public:
478         PDFITest() : mxCtx(),msBaseDir(),mbUnoInitialized(false)
479         {}
480 
481         void setUp()
482         {
483             if( !mbUnoInitialized )
484             {
485                 const char* pArgs( getForwardString() );
486                 CPPUNIT_ASSERT_MESSAGE("Test file parameter", pArgs);
487 
488                 msBaseDir = rtl::OUString::createFromAscii(pArgs);
489 
490                 // bootstrap UNO
491                 try
492                 {
493                     ::rtl::OUString aIniUrl;
494                     CPPUNIT_ASSERT_MESSAGE(
495                         "Converting ini file to URL",
496                         osl_getFileURLFromSystemPath(
497                             (msBaseDir+rtl::OUString::createFromAscii("pdfi_unittest_test.ini")).pData,
498                             &aIniUrl.pData ) == osl_File_E_None );
499 
500                     mxCtx = ::cppu::defaultBootstrap_InitialComponentContext(aIniUrl);
501                     CPPUNIT_ASSERT_MESSAGE("Getting component context", mxCtx.is());
502                 }
503                 catch( uno::Exception& )
504                 {
505                     CPPUNIT_ASSERT_MESSAGE("Bootstrapping UNO", false);
506                 }
507 
508                 mbUnoInitialized = true;
509             }
510         }
511         void tearDown()
512         {
513         }
514 
515         void testXPDFParser()
516         {
517             pdfi::ContentSinkSharedPtr pSink( new TestSink() );
518             pdfi::xpdf_ImportFromFile( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"),
519                                        pSink,
520                                        uno::Reference< task::XInteractionHandler >(),
521                                        rtl::OUString(),
522                                        mxCtx );
523 
524             // make destruction explicit, a bunch of things are
525             // checked in the destructor
526             pSink.reset();
527         }
528 
529         void testOdfDrawExport()
530         {
531             pdfi::PDFIRawAdaptor aAdaptor( mxCtx );
532             aAdaptor.setTreeVisitorFactory( createDrawTreeVisitorFactory() );
533 
534             ::rtl::OUString aURL, aAbsURL, aBaseURL;
535             osl_getFileURLFromSystemPath( (msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_draw.xml")).pData,
536                                           &aURL.pData );
537             osl_getProcessWorkingDir(&aBaseURL.pData);
538             osl_getAbsoluteFileURL(aBaseURL.pData,aURL.pData,&aAbsURL.pData);
539             CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
540                                    aAdaptor.odfConvert( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"),
541                                                         new OutputWrap(aAbsURL),
542                                                         NULL ));
543         }
544 
545         void testOdfWriterExport()
546         {
547             pdfi::PDFIRawAdaptor aAdaptor( mxCtx );
548             aAdaptor.setTreeVisitorFactory( createWriterTreeVisitorFactory() );
549 
550             ::rtl::OUString aURL, aAbsURL, aBaseURL;
551             osl_getFileURLFromSystemPath( (msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_writer.xml")).pData,
552                                           &aURL.pData );
553             osl_getProcessWorkingDir(&aBaseURL.pData);
554             osl_getAbsoluteFileURL(aBaseURL.pData,aURL.pData,&aAbsURL.pData);
555             CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
556                                    aAdaptor.odfConvert( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"),
557                                                         new OutputWrap(aAbsURL),
558                                                         NULL ));
559         }
560 
561         CPPUNIT_TEST_SUITE(PDFITest);
562         CPPUNIT_TEST(testXPDFParser);
563         CPPUNIT_TEST(testOdfWriterExport);
564         CPPUNIT_TEST(testOdfDrawExport);
565         CPPUNIT_TEST_SUITE_END();
566     };
567 
568 }
569 
570 // =======================================================================
571 
572 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(PDFITest, "PDFITest");
573 
574 
575 // -----------------------------------------------------------------------------
576 
577 // this macro creates an empty function, which will called by the RegisterAllFunctions()
578 // to let the user the possibility to also register some functions by hand.
579 NOADDITIONAL;
580