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