merge the formfield patch from ooo-build
[ooovba.git] / sdext / source / pdfimport / wrapper / wrapper.cxx
blobc4f906250d09942941441440bbaa35842d3e1f13
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: wrapper.cxx,v $
11 * $Revision: 1.2.4.1 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_sdext.hxx"
35 #include "contentsink.hxx"
36 #include "pdfparse.hxx"
37 #include "pdfihelper.hxx"
39 #include "osl/file.h"
40 #include "osl/thread.h"
41 #include "osl/process.h"
42 #include "osl/diagnose.h"
43 #include "rtl/ustring.hxx"
44 #include "rtl/ustrbuf.hxx"
45 #include "rtl/strbuf.hxx"
46 #include "rtl/byteseq.hxx"
48 #include "cppuhelper/exc_hlp.hxx"
49 #include "com/sun/star/io/XInputStream.hpp"
50 #include "com/sun/star/uno/XComponentContext.hpp"
51 #include "com/sun/star/awt/FontDescriptor.hpp"
52 #include "com/sun/star/deployment/XPackageInformationProvider.hpp"
53 #include "com/sun/star/beans/XMaterialHolder.hpp"
54 #include "com/sun/star/rendering/PathCapType.hpp"
55 #include "com/sun/star/rendering/PathJoinType.hpp"
56 #include "com/sun/star/rendering/XColorSpace.hpp"
57 #include "com/sun/star/rendering/XPolyPolygon2D.hpp"
58 #include "com/sun/star/rendering/XBitmap.hpp"
59 #include "com/sun/star/geometry/Matrix2D.hpp"
60 #include "com/sun/star/geometry/AffineMatrix2D.hpp"
61 #include "com/sun/star/geometry/RealRectangle2D.hpp"
62 #include "com/sun/star/task/XInteractionHandler.hpp"
64 #include "basegfx/point/b2dpoint.hxx"
65 #include "basegfx/polygon/b2dpolypolygon.hxx"
66 #include "basegfx/polygon/b2dpolygon.hxx"
67 #include "basegfx/tools/canvastools.hxx"
68 #include "basegfx/tools/unopolypolygon.hxx"
70 #include <boost/bind.hpp>
71 #include <boost/preprocessor/stringize.hpp>
72 #include <boost/scoped_ptr.hpp>
73 #include <boost/scoped_array.hpp>
75 #include <hash_map>
76 #include <string.h>
78 #include "rtl/bootstrap.h"
80 #include <string.h> // memcmp
82 #ifndef PDFI_IMPL_IDENTIFIER
83 # error define implementation name for pdfi extension, please!
84 #endif
86 using namespace com::sun::star;
88 namespace pdfi
91 namespace
94 // identifier of the strings coming from the out-of-process xpdf
95 // converter
96 enum parseKey {
97 CLIPPATH,
98 DRAWCHAR,
99 DRAWIMAGE,
100 DRAWLINK,
101 DRAWMASK,
102 DRAWMASKEDIMAGE,
103 DRAWSOFTMASKEDIMAGE,
104 ENDPAGE,
105 ENDTEXTOBJECT,
106 EOCLIPPATH,
107 EOFILLPATH,
108 FILLPATH,
109 HYPERLINK,
110 INTERSECTCLIP,
111 INTERSECTEOCLIP,
112 POPSTATE,
113 PUSHSTATE,
114 RESTORESTATE,
115 SAVESTATE,
116 SETBLENDMODE,
117 SETFILLCOLOR,
118 SETFONT,
119 SETLINECAP,
120 SETLINEDASH,
121 SETLINEJOIN,
122 SETLINEWIDTH,
123 SETMITERLIMIT,
124 SETPAGENUM,
125 SETSTROKECOLOR,
126 SETTEXTRENDERMODE,
127 SETTRANSFORMATION,
128 STARTPAGE,
129 STROKEPATH,
130 UPDATEBLENDMODE,
131 UPDATECTM,
132 UPDATEFILLCOLOR,
133 UPDATEFILLOPACITY,
134 UPDATEFLATNESS,
135 UPDATEFONT,
136 UPDATELINECAP,
137 UPDATELINEDASH,
138 UPDATELINEJOIN,
139 UPDATELINEWIDTH,
140 UPDATEMITERLIMIT,
141 UPDATESTROKECOLOR,
142 UPDATESTROKEOPACITY,
143 NONE
146 #include "hash.cxx"
148 class Parser
150 typedef std::hash_map< sal_Int64,
151 FontAttributes > FontMapType;
153 const uno::Reference<uno::XComponentContext> m_xContext;
154 const ContentSinkSharedPtr m_pSink;
155 const oslFileHandle m_pErr;
156 ::rtl::OString m_aLine;
157 FontMapType m_aFontMap;
158 sal_Int32 m_nNextToken;
159 sal_Int32 m_nCharIndex;
162 ::rtl::OString readNextToken();
163 void readInt32( sal_Int32& o_Value );
164 sal_Int32 readInt32();
165 void readInt64( sal_Int64& o_Value );
166 void readDouble( double& o_Value );
167 double readDouble();
168 void readBinaryData( uno::Sequence<sal_Int8>& rBuf );
170 uno::Reference<rendering::XPolyPolygon2D> readPath();
172 void readChar();
173 void readLineCap();
174 void readLineDash();
175 void readLineJoin();
176 void readTransformation();
177 rendering::ARGBColor readColor();
178 void parseFontFamilyName( FontAttributes& aResult );
179 void readFont();
180 uno::Sequence<beans::PropertyValue> readImageImpl();
182 void readImage();
183 void readMask();
184 void readLink();
185 void readMaskedImage();
186 void readSoftMaskedImage();
188 public:
189 Parser( const ContentSinkSharedPtr& rSink,
190 oslFileHandle pErr,
191 const uno::Reference<uno::XComponentContext>& xContext ) :
192 m_xContext(xContext),
193 m_pSink(rSink),
194 m_pErr(pErr),
195 m_aLine(),
196 m_aFontMap(101),
197 m_nNextToken(-1),
198 m_nCharIndex(-1)
201 void parseLine( const ::rtl::OString& rLine );
204 ::rtl::OString Parser::readNextToken()
206 OSL_PRECOND(m_nCharIndex!=-1,"insufficient input");
207 return m_aLine.getToken(m_nNextToken,' ',m_nCharIndex);
210 void Parser::readInt32( sal_Int32& o_Value )
212 o_Value = readNextToken().toInt32();
215 sal_Int32 Parser::readInt32()
217 return readNextToken().toInt32();
220 void Parser::readInt64( sal_Int64& o_Value )
222 o_Value = readNextToken().toInt64();
225 void Parser::readDouble( double& o_Value )
227 o_Value = readNextToken().toDouble();
230 double Parser::readDouble()
232 return readNextToken().toDouble();
235 void Parser::readBinaryData( uno::Sequence<sal_Int8>& rBuf )
237 sal_Int32 nFileLen( rBuf.getLength() );
238 sal_Int8* pBuf( rBuf.getArray() );
239 sal_uInt64 nBytesRead(0);
240 oslFileError nRes=osl_File_E_None;
241 while( nFileLen &&
242 osl_File_E_None == (nRes=osl_readFile( m_pErr, pBuf, nFileLen, &nBytesRead )) )
244 pBuf += nBytesRead;
245 nFileLen -= sal::static_int_cast<sal_Int32>(nBytesRead);
248 OSL_PRECOND(nRes==osl_File_E_None, "inconsistent data");
251 uno::Reference<rendering::XPolyPolygon2D> Parser::readPath()
253 const rtl::OString aSubPathMarker( "subpath" );
255 if( 0 != readNextToken().compareTo( aSubPathMarker ) )
256 OSL_PRECOND(false, "broken path");
258 basegfx::B2DPolyPolygon aResult;
259 while( m_nCharIndex != -1 )
261 basegfx::B2DPolygon aSubPath;
263 sal_Int32 nClosedFlag;
264 readInt32( nClosedFlag );
265 aSubPath.setClosed( nClosedFlag != 0 );
267 sal_Int32 nContiguousControlPoints(0);
268 sal_Int32 nDummy=m_nCharIndex;
269 rtl::OString aCurrToken( m_aLine.getToken(m_nNextToken,' ',nDummy) );
271 while( m_nCharIndex != -1 && 0 != aCurrToken.compareTo(aSubPathMarker) )
273 sal_Int32 nCurveFlag;
274 double nX, nY;
275 readDouble( nX );
276 readDouble( nY );
277 readInt32( nCurveFlag );
279 aSubPath.append(basegfx::B2DPoint(nX,nY));
280 if( nCurveFlag )
282 ++nContiguousControlPoints;
284 else if( nContiguousControlPoints )
286 OSL_PRECOND(nContiguousControlPoints==2,"broken bezier path");
288 // have two control points before us. the current one
289 // is a normal point - thus, convert previous points
290 // into bezier segment
291 const sal_uInt32 nPoints( aSubPath.count() );
292 const basegfx::B2DPoint aCtrlA( aSubPath.getB2DPoint(nPoints-3) );
293 const basegfx::B2DPoint aCtrlB( aSubPath.getB2DPoint(nPoints-2) );
294 const basegfx::B2DPoint aEnd( aSubPath.getB2DPoint(nPoints-1) );
295 aSubPath.remove(nPoints-3, 3);
296 aSubPath.appendBezierSegment(aCtrlA, aCtrlB, aEnd);
298 nContiguousControlPoints=0;
301 // one token look-ahead (new subpath or more points?
302 nDummy=m_nCharIndex;
303 aCurrToken = m_aLine.getToken(m_nNextToken,' ',nDummy);
306 aResult.append( aSubPath );
307 if( m_nCharIndex != -1 )
308 readNextToken();
311 return static_cast<rendering::XLinePolyPolygon2D*>(
312 new basegfx::unotools::UnoPolyPolygon(aResult));
315 void Parser::readChar()
317 geometry::Matrix2D aUnoMatrix;
318 geometry::RealRectangle2D aRect;
320 readDouble(aRect.X1);
321 readDouble(aRect.Y1);
322 readDouble(aRect.X2);
323 readDouble(aRect.Y2);
324 readDouble(aUnoMatrix.m00);
325 readDouble(aUnoMatrix.m01);
326 readDouble(aUnoMatrix.m10);
327 readDouble(aUnoMatrix.m11);
329 rtl::OString aChars = m_aLine.copy( m_nCharIndex );
331 // chars gobble up rest of line
332 m_nCharIndex = -1;
334 m_pSink->drawGlyphs( rtl::OStringToOUString( aChars,
335 RTL_TEXTENCODING_UTF8 ),
336 aRect, aUnoMatrix );
339 void Parser::readLineCap()
341 sal_Int8 nCap(rendering::PathCapType::BUTT);
342 switch( readInt32() )
344 default:
345 // FALLTHROUGH intended
346 case 0: nCap = rendering::PathCapType::BUTT; break;
347 case 1: nCap = rendering::PathCapType::ROUND; break;
348 case 2: nCap = rendering::PathCapType::SQUARE; break;
350 m_pSink->setLineCap(nCap);
353 void Parser::readLineDash()
355 if( m_nCharIndex == -1 )
357 m_pSink->setLineDash( uno::Sequence<double>(), 0.0 );
358 return;
361 const double nOffset(readDouble());
362 const sal_Int32 nLen(readInt32());
364 uno::Sequence<double> aDashArray(nLen);
365 double* pArray=aDashArray.getArray();
366 for( sal_Int32 i=0; i<nLen; ++i )
367 *pArray++ = readDouble();
369 m_pSink->setLineDash( aDashArray, nOffset );
372 void Parser::readLineJoin()
374 sal_Int8 nJoin(rendering::PathJoinType::MITER);
375 switch( readInt32() )
377 default:
378 // FALLTHROUGH intended
379 case 0: nJoin = rendering::PathJoinType::MITER; break;
380 case 1: nJoin = rendering::PathJoinType::ROUND; break;
381 case 2: nJoin = rendering::PathJoinType::BEVEL; break;
383 m_pSink->setLineJoin(nJoin);
386 void Parser::readTransformation()
388 geometry::AffineMatrix2D aMat;
389 readDouble(aMat.m00);
390 readDouble(aMat.m10);
391 readDouble(aMat.m01);
392 readDouble(aMat.m11);
393 readDouble(aMat.m02);
394 readDouble(aMat.m12);
395 m_pSink->setTransformation( aMat );
398 rendering::ARGBColor Parser::readColor()
400 rendering::ARGBColor aRes;
401 readDouble(aRes.Red);
402 readDouble(aRes.Green);
403 readDouble(aRes.Blue);
404 readDouble(aRes.Alpha);
405 return aRes;
408 void Parser::parseFontFamilyName( FontAttributes& aResult )
410 rtl::OUStringBuffer aNewFamilyName( aResult.familyName.getLength() );
412 const sal_Unicode* pCopy = aResult.familyName.getStr();
413 sal_Int32 nLen = aResult.familyName.getLength();
414 // parse out truetype subsets (e.g. BAAAAA+Thorndale)
415 if( nLen > 8 && pCopy[6] == sal_Unicode('+') )
417 pCopy += 7;
418 nLen -= 7;
421 while( nLen )
423 if( nLen > 5 &&
424 ( *pCopy == 'i' || *pCopy == 'I' ) &&
425 pCopy[1] == 't' &&
426 pCopy[2] == 'a' &&
427 pCopy[3] == 'l' &&
428 pCopy[4] == 'i' &&
429 pCopy[5] == 'c' )
431 aResult.isItalic = true;
432 nLen -=6;
433 pCopy += 6;
435 else if( nLen > 3 &&
436 ( *pCopy == 'B' || *pCopy == 'b' ) &&
437 pCopy[1] == 'o' &&
438 pCopy[2] == 'l' &&
439 pCopy[3] == 'd' )
441 aResult.isBold = true;
442 nLen -=4;
443 pCopy += 4;
445 else if( nLen > 5 &&
446 *pCopy == '-' &&
447 ( pCopy[1] == 'R' || pCopy[1] == 'r' ) &&
448 pCopy[2] == 'o' &&
449 pCopy[3] == 'm' &&
450 pCopy[4] == 'a' &&
451 pCopy[5] == 'n' )
453 nLen -= 6;
454 pCopy += 6;
456 else
458 if( *pCopy != '-' )
459 aNewFamilyName.append( *pCopy );
460 pCopy++;
461 nLen--;
464 aResult.familyName = aNewFamilyName.makeStringAndClear();
467 void Parser::readFont()
469 ::rtl::OString aFontName;
470 sal_Int64 nFontID;
471 sal_Int32 nIsEmbedded, nIsBold, nIsItalic, nIsUnderline, nFileLen;
472 double nSize;
474 readInt64(nFontID);
475 readInt32(nIsEmbedded);
476 readInt32(nIsBold);
477 readInt32(nIsItalic);
478 readInt32(nIsUnderline);
479 readDouble(nSize);
480 readInt32(nFileLen);
482 nSize = nSize < 0.0 ? -nSize : nSize;
483 aFontName = m_aLine.copy( m_nCharIndex );
485 // name gobbles up rest of line
486 m_nCharIndex = -1;
488 FontMapType::const_iterator pFont( m_aFontMap.find(nFontID) );
489 if( pFont != m_aFontMap.end() )
491 OSL_PRECOND(nFileLen==0,"font data for known font");
492 FontAttributes aRes(pFont->second);
493 aRes.size = nSize;
494 m_pSink->setFont( aRes );
496 return;
499 // yet unknown font - get info and add to map
500 FontAttributes aResult( rtl::OStringToOUString( aFontName,
501 RTL_TEXTENCODING_UTF8 ),
502 nIsBold != 0,
503 nIsItalic != 0,
504 nIsUnderline != 0,
505 false,
506 nSize );
508 // extract textual attributes (bold, italic in the name, etc.)
509 parseFontFamilyName(aResult);
511 // need to read font file?
512 if( nFileLen )
514 uno::Sequence<sal_Int8> aFontFile(nFileLen);
515 readBinaryData( aFontFile );
517 awt::FontDescriptor aFD;
518 uno::Sequence< uno::Any > aArgs(1);
519 aArgs[0] <<= aFontFile;
523 uno::Reference< beans::XMaterialHolder > xMat(
524 m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
525 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.FontIdentificator" ) ),
526 aArgs,
527 m_xContext ),
528 uno::UNO_QUERY );
529 if( xMat.is() )
531 uno::Any aRes( xMat->getMaterial() );
532 if( aRes >>= aFD )
534 aResult.familyName = aFD.Name;
535 aResult.isBold = (aFD.Weight > 100.0);
536 aResult.isItalic = (aFD.Slant == awt::FontSlant_OBLIQUE ||
537 aFD.Slant == awt::FontSlant_ITALIC );
538 aResult.isUnderline = false;
539 aResult.size = 0;
543 catch( uno::Exception& )
547 if( !aResult.familyName.getLength() )
549 // last fallback
550 aResult.familyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Arial" ) );
551 aResult.isUnderline = false;
556 m_aFontMap[nFontID] = aResult;
558 aResult.size = nSize;
559 m_pSink->setFont(aResult);
562 uno::Sequence<beans::PropertyValue> Parser::readImageImpl()
564 static const rtl::OString aJpegMarker( "JPEG" );
565 static const rtl::OString aPbmMarker( "PBM" );
566 static const rtl::OString aPpmMarker( "PPM" );
567 static const rtl::OString aPngMarker( "PNG" );
568 static const rtl::OUString aJpegFile(
569 RTL_CONSTASCII_USTRINGPARAM( "DUMMY.JPEG" ));
570 static const rtl::OUString aPbmFile(
571 RTL_CONSTASCII_USTRINGPARAM( "DUMMY.PBM" ));
572 static const rtl::OUString aPpmFile(
573 RTL_CONSTASCII_USTRINGPARAM( "DUMMY.PPM" ));
574 static const rtl::OUString aPngFile(
575 RTL_CONSTASCII_USTRINGPARAM( "DUMMY.PNG" ));
577 rtl::OString aToken = readNextToken();
578 const sal_Int32 nImageSize( readInt32() );
580 rtl::OUString aFileName;
581 if( aToken.compareTo( aPngMarker ) == 0 )
582 aFileName = aPngFile;
583 else if( aToken.compareTo( aJpegMarker ) == 0 )
584 aFileName = aJpegFile;
585 else if( aToken.compareTo( aPbmMarker ) == 0 )
586 aFileName = aPbmFile;
587 else
589 OSL_PRECOND( aToken.compareTo( aPpmMarker ) == 0,
590 "Invalid bitmap format" );
591 aFileName = aPpmFile;
594 uno::Sequence<sal_Int8> aDataSequence(nImageSize);
595 readBinaryData( aDataSequence );
597 uno::Sequence< uno::Any > aStreamCreationArgs(1);
598 aStreamCreationArgs[0] <<= aDataSequence;
600 uno::Reference< uno::XComponentContext > xContext( m_xContext, uno::UNO_SET_THROW );
601 uno::Reference< lang::XMultiComponentFactory > xFactory( xContext->getServiceManager(), uno::UNO_SET_THROW );
602 uno::Reference< io::XInputStream > xDataStream( xFactory->createInstanceWithArgumentsAndContext(
603 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.SequenceInputStream" ) ),
604 aStreamCreationArgs, m_xContext ), uno::UNO_QUERY_THROW );
606 uno::Sequence<beans::PropertyValue> aSequence(3);
607 aSequence[0] = beans::PropertyValue( ::rtl::OUString::createFromAscii("URL"),
609 uno::makeAny(aFileName),
610 beans::PropertyState_DIRECT_VALUE );
611 aSequence[1] = beans::PropertyValue( ::rtl::OUString::createFromAscii("InputStream"),
613 uno::makeAny( xDataStream ),
614 beans::PropertyState_DIRECT_VALUE );
615 aSequence[2] = beans::PropertyValue( ::rtl::OUString::createFromAscii("InputSequence"),
617 uno::makeAny(aDataSequence),
618 beans::PropertyState_DIRECT_VALUE );
620 return aSequence;
623 void Parser::readImage()
625 sal_Int32 nWidth, nHeight,nMaskColors;
626 readInt32(nWidth);
627 readInt32(nHeight);
628 readInt32(nMaskColors);
630 uno::Sequence<beans::PropertyValue> aImg( readImageImpl() );
632 if( nMaskColors )
634 uno::Sequence<sal_Int8> aDataSequence(nMaskColors);
635 readBinaryData( aDataSequence );
637 uno::Sequence<uno::Any> aMaskRanges(2);
639 uno::Sequence<double> aMinRange(nMaskColors/2);
640 uno::Sequence<double> aMaxRange(nMaskColors/2);
641 for( sal_Int32 i=0; i<nMaskColors/2; ++i )
643 aMinRange[i] = aDataSequence[i] / 255.0;
644 aMaxRange[i] = aDataSequence[i+nMaskColors/2] / 255.0;
647 aMaskRanges[0] = uno::makeAny(aMinRange);
648 aMaskRanges[1] = uno::makeAny(aMaxRange);
650 m_pSink->drawColorMaskedImage( aImg, aMaskRanges );
652 else
653 m_pSink->drawImage( aImg );
656 void Parser::readMask()
658 sal_Int32 nWidth, nHeight, nInvert;
659 readInt32(nWidth);
660 readInt32(nHeight);
661 readInt32(nInvert);
663 m_pSink->drawMask( readImageImpl(), nInvert );
666 void Parser::readLink()
668 geometry::RealRectangle2D aBounds;
669 readDouble(aBounds.X1);
670 readDouble(aBounds.Y1);
671 readDouble(aBounds.X2);
672 readDouble(aBounds.Y2);
674 m_pSink->hyperLink( aBounds,
675 rtl::OStringToOUString( m_aLine.copy(m_nCharIndex),
676 RTL_TEXTENCODING_UTF8 ));
677 // name gobbles up rest of line
678 m_nCharIndex = -1;
681 void Parser::readMaskedImage()
683 sal_Int32 nWidth, nHeight, nMaskWidth, nMaskHeight, nMaskInvert;
684 readInt32(nWidth);
685 readInt32(nHeight);
686 readInt32(nMaskWidth);
687 readInt32(nMaskHeight);
688 readInt32(nMaskInvert);
690 const uno::Sequence<beans::PropertyValue> aImage( readImageImpl() );
691 const uno::Sequence<beans::PropertyValue> aMask ( readImageImpl() );
692 m_pSink->drawMaskedImage( aImage, aMask, nMaskInvert != 0 );
695 void Parser::readSoftMaskedImage()
697 sal_Int32 nWidth, nHeight, nMaskWidth, nMaskHeight;
698 readInt32(nWidth);
699 readInt32(nHeight);
700 readInt32(nMaskWidth);
701 readInt32(nMaskHeight);
703 const uno::Sequence<beans::PropertyValue> aImage( readImageImpl() );
704 const uno::Sequence<beans::PropertyValue> aMask ( readImageImpl() );
705 m_pSink->drawAlphaMaskedImage( aImage, aMask );
708 void Parser::parseLine( const ::rtl::OString& rLine )
710 OSL_PRECOND( m_pSink, "Invalid sink" );
711 OSL_PRECOND( m_pErr, "Invalid filehandle" );
712 OSL_PRECOND( m_xContext.is(), "Invalid service factory" );
714 m_nNextToken = 0; m_nCharIndex = 0; m_aLine = rLine;
715 uno::Reference<rendering::XPolyPolygon2D> xPoly;
716 const ::rtl::OString& rCmd = readNextToken();
717 const hash_entry* pEntry = PdfKeywordHash::in_word_set( rCmd.getStr(),
718 rCmd.getLength() );
719 OSL_ASSERT(pEntry);
720 switch( pEntry->eKey )
722 case CLIPPATH:
723 m_pSink->intersectClip(readPath()); break;
724 case DRAWCHAR:
725 readChar(); break;
726 case DRAWIMAGE:
727 readImage(); break;
728 case DRAWLINK:
729 readLink(); break;
730 case DRAWMASK:
731 readMask(); break;
732 case DRAWMASKEDIMAGE:
733 readMaskedImage(); break;
734 case DRAWSOFTMASKEDIMAGE:
735 readSoftMaskedImage(); break;
736 case ENDPAGE:
737 m_pSink->endPage(); break;
738 case ENDTEXTOBJECT:
739 m_pSink->endText(); break;
740 case EOCLIPPATH:
741 m_pSink->intersectEoClip(readPath()); break;
742 case EOFILLPATH:
743 m_pSink->eoFillPath(readPath()); break;
744 case FILLPATH:
745 m_pSink->fillPath(readPath()); break;
746 case RESTORESTATE:
747 m_pSink->popState(); break;
748 case SAVESTATE:
749 m_pSink->pushState(); break;
750 case SETPAGENUM:
751 m_pSink->setPageNum( readInt32() ); break;
752 case STARTPAGE:
754 const double nWidth ( readDouble() );
755 const double nHeight( readDouble() );
756 m_pSink->startPage( geometry::RealSize2D( nWidth, nHeight ) );
757 break;
759 case STROKEPATH:
760 m_pSink->strokePath(readPath()); break;
761 case UPDATECTM:
762 readTransformation(); break;
763 case UPDATEFILLCOLOR:
764 m_pSink->setFillColor( readColor() ); break;
765 case UPDATEFLATNESS:
766 m_pSink->setFlatness( readDouble( ) ); break;
767 case UPDATEFONT:
768 readFont(); break;
769 case UPDATELINECAP:
770 readLineCap(); break;
771 case UPDATELINEDASH:
772 readLineDash(); break;
773 case UPDATELINEJOIN:
774 readLineJoin(); break;
775 case UPDATELINEWIDTH:
776 m_pSink->setLineWidth( readDouble() );break;
777 case UPDATEMITERLIMIT:
778 m_pSink->setMiterLimit( readDouble() ); break;
779 case UPDATESTROKECOLOR:
780 m_pSink->setStrokeColor( readColor() ); break;
781 case UPDATESTROKEOPACITY:
782 break;
783 case SETTEXTRENDERMODE:
784 m_pSink->setTextRenderMode( readInt32() ); break;
786 case NONE:
787 default:
788 OSL_PRECOND(false,"Unknown input");
789 break;
792 // all consumed?
793 OSL_POSTCOND(m_nCharIndex==-1,"leftover scanner input");
796 oslFileError readLine( oslFileHandle pFile, ::rtl::OStringBuffer& line )
798 OSL_PRECOND( line.getLength() == 0, "line buf not empty" );
800 // TODO(P3): read larger chunks
801 sal_Char aChar('\n');
802 sal_uInt64 nBytesRead;
803 oslFileError nRes;
805 // skip garbage \r \n at start of line
806 while( osl_File_E_None == (nRes=osl_readFile(pFile, &aChar, 1, &nBytesRead)) &&
807 nBytesRead == 1 &&
808 (aChar == '\n' || aChar == '\r') ) ;
810 if( aChar != '\n' && aChar != '\r' )
811 line.append( aChar );
813 while( osl_File_E_None == (nRes=osl_readFile(pFile, &aChar, 1, &nBytesRead)) &&
814 nBytesRead == 1 && aChar != '\n' && aChar != '\r' )
816 line.append( aChar );
819 return nRes;
822 } // namespace
824 static bool checkEncryption( const rtl::OUString& i_rPath,
825 const uno::Reference< task::XInteractionHandler >& i_xIHdl,
826 rtl::OUString& io_rPwd,
827 bool& o_rIsEncrypted
830 bool bSuccess = false;
831 rtl::OString aPDFFile;
832 aPDFFile = rtl::OUStringToOString( i_rPath, osl_getThreadTextEncoding() );
834 pdfparse::PDFReader aParser;
835 boost::scoped_ptr<pdfparse::PDFEntry> pEntry( aParser.read( aPDFFile.getStr() ));
836 if( pEntry )
838 pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get());
839 if( pPDFFile )
841 o_rIsEncrypted = pPDFFile->isEncrypted();
842 if( o_rIsEncrypted )
844 bool bAuthenticated = false;
845 if( io_rPwd.getLength() )
847 rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
848 RTL_TEXTENCODING_ISO_8859_1 );
849 bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
851 if( bAuthenticated )
852 bSuccess = true;
853 else
855 if( i_xIHdl.is() )
857 bool bEntered = false;
860 bEntered = getPassword( i_xIHdl, io_rPwd, ! bEntered );
861 rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
862 RTL_TEXTENCODING_ISO_8859_1 );
863 bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
864 } while( bEntered && ! bAuthenticated );
867 OSL_TRACE( "password: %s\n", bAuthenticated ? "matches" : "does not match" );
868 bSuccess = bAuthenticated;
871 else
872 bSuccess = true;
875 return bSuccess;
878 bool xpdf_ImportFromFile( const ::rtl::OUString& rURL,
879 const ContentSinkSharedPtr& rSink,
880 const uno::Reference< task::XInteractionHandler >& xIHdl,
881 const rtl::OUString& rPwd,
882 const uno::Reference< uno::XComponentContext >& xContext )
884 OSL_ASSERT(rSink);
886 ::rtl::OUString aSysUPath;
887 if( osl_getSystemPathFromFileURL( rURL.pData, &aSysUPath.pData ) != osl_File_E_None )
888 return false;
890 // check for encryption, if necessary get password
891 rtl::OUString aPwd( rPwd );
892 bool bIsEncrypted = false;
893 if( checkEncryption( aSysUPath, xIHdl, aPwd, bIsEncrypted ) == false )
894 return false;
896 rtl::OUStringBuffer converterURL = rtl::OUString::createFromAscii("xpdfimport");
898 // retrieve package location url (xpdfimport executable is located there)
899 // ---------------------------------------------------
900 uno::Reference<deployment::XPackageInformationProvider> xProvider(
901 xContext->getValueByName(
902 rtl::OUString::createFromAscii("/singletons/com.sun.star.deployment.PackageInformationProvider" )),
903 uno::UNO_QUERY);
904 if( xProvider.is() )
906 converterURL.insert(
908 rtl::OUString::createFromAscii("/"));
909 converterURL.insert(
911 xProvider->getPackageLocation(
912 rtl::OUString::createFromAscii(
913 BOOST_PP_STRINGIZE(PDFI_IMPL_IDENTIFIER))));
916 // spawn separate process to keep LGPL/GPL code apart.
917 // ---------------------------------------------------
918 rtl_uString** ppEnv = NULL;
919 sal_uInt32 nEnv = 0;
921 #if defined UNX && ! defined MACOSX
922 rtl::OUString aStr( RTL_CONSTASCII_USTRINGPARAM( "$URE_LIB_DIR" ) );
923 rtl_bootstrap_expandMacros( &aStr.pData );
924 rtl::OUString aSysPath;
925 osl_getSystemPathFromFileURL( aStr.pData, &aSysPath.pData );
926 rtl::OUStringBuffer aEnvBuf( aStr.getLength() + 20 );
927 aEnvBuf.appendAscii( "LD_LIBRARY_PATH=" );
928 aEnvBuf.append( aSysPath );
929 aStr = aEnvBuf.makeStringAndClear();
930 ppEnv = &aStr.pData;
931 nEnv = 1;
932 #endif
934 rtl_uString* args[] = { aSysUPath.pData };
935 sal_Int32 nArgs = 1;
937 oslProcess aProcess;
938 oslFileHandle pIn = NULL;
939 oslFileHandle pOut = NULL;
940 oslFileHandle pErr = NULL;
941 const oslProcessError eErr =
942 osl_executeProcess_WithRedirectedIO(converterURL.makeStringAndClear().pData,
943 args,
944 nArgs,
945 osl_Process_SEARCHPATH|osl_Process_HIDDEN,
946 osl_getCurrentSecurity(),
947 0, ppEnv, nEnv,
948 &aProcess, &pIn, &pOut, &pErr);
950 bool bRet=true;
953 if( eErr!=osl_Process_E_None )
954 return false;
956 if( pIn )
958 rtl::OStringBuffer aBuf(256);
959 if( bIsEncrypted )
960 aBuf.append( rtl::OUStringToOString( aPwd, RTL_TEXTENCODING_ISO_8859_1 ) );
961 aBuf.append( '\n' );
963 sal_uInt64 nWritten = 0;
964 osl_writeFile( pIn, aBuf.getStr(), sal_uInt64(aBuf.getLength()), &nWritten );
967 if( pOut && pErr )
969 // read results of PDF parser. One line - one call to
970 // OutputDev. stderr is used for alternate streams, like
971 // embedded fonts and bitmaps
972 Parser aParser(rSink,pErr,xContext);
973 ::rtl::OStringBuffer line;
974 while( osl_File_E_None == readLine(pOut, line) && line.getLength() )
975 aParser.parseLine(line.makeStringAndClear());
978 catch( uno::Exception& )
980 // crappy C file interface. need manual resource dealloc
981 bRet = false;
984 if( pIn )
985 osl_closeFile(pIn);
986 if( pOut )
987 osl_closeFile(pOut);
988 if( pErr )
989 osl_closeFile(pErr);
990 osl_freeProcessHandle(aProcess);
991 return bRet;
995 bool xpdf_ImportFromStream( const uno::Reference< io::XInputStream >& xInput,
996 const ContentSinkSharedPtr& rSink,
997 const uno::Reference<task::XInteractionHandler >& xIHdl,
998 const rtl::OUString& rPwd,
999 const uno::Reference< uno::XComponentContext >& xContext )
1001 OSL_ASSERT(xInput.is());
1002 OSL_ASSERT(rSink);
1004 // convert XInputStream to local temp file
1005 oslFileHandle aFile = NULL;
1006 rtl::OUString aURL;
1007 if( osl_createTempFile( NULL, &aFile, &aURL.pData ) != osl_File_E_None )
1008 return false;
1010 // copy content, buffered...
1011 const sal_uInt32 nBufSize = 4096;
1012 uno::Sequence<sal_Int8> aBuf( nBufSize );
1013 sal_uInt64 nBytes = 0;
1014 sal_uInt64 nWritten = 0;
1015 bool bSuccess = true;
1020 nBytes = xInput->readBytes( aBuf, nBufSize );
1022 catch( com::sun::star::uno::Exception& )
1024 osl_closeFile( aFile );
1025 throw;
1027 if( nBytes > 0 )
1029 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
1030 if( nWritten != nBytes )
1032 bSuccess = false;
1033 break;
1037 while( nBytes == nBufSize );
1039 osl_closeFile( aFile );
1041 return bSuccess && xpdf_ImportFromFile( aURL, rSink, xIHdl, rPwd, xContext );