1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <config_folders.h>
22 #include "contentsink.hxx"
23 #include "pdfparse.hxx"
24 #include "pdfihelper.hxx"
25 #include "wrapper.hxx"
28 #include "osl/file.hxx"
29 #include "osl/thread.h"
30 #include "osl/process.h"
31 #include "osl/diagnose.h"
32 #include "rtl/bootstrap.hxx"
33 #include "rtl/ustring.hxx"
34 #include "rtl/ustrbuf.hxx"
35 #include "rtl/strbuf.hxx"
36 #include "rtl/byteseq.hxx"
38 #include "cppuhelper/exc_hlp.hxx"
39 #include "com/sun/star/io/XInputStream.hpp"
40 #include "com/sun/star/uno/XComponentContext.hpp"
41 #include "com/sun/star/awt/FontDescriptor.hpp"
42 #include "com/sun/star/beans/XMaterialHolder.hpp"
43 #include "com/sun/star/rendering/PathCapType.hpp"
44 #include "com/sun/star/rendering/PathJoinType.hpp"
45 #include "com/sun/star/rendering/XColorSpace.hpp"
46 #include "com/sun/star/rendering/XPolyPolygon2D.hpp"
47 #include "com/sun/star/rendering/XBitmap.hpp"
48 #include "com/sun/star/geometry/Matrix2D.hpp"
49 #include "com/sun/star/geometry/AffineMatrix2D.hpp"
50 #include "com/sun/star/geometry/RealRectangle2D.hpp"
51 #include "com/sun/star/task/XInteractionHandler.hpp"
53 #include "basegfx/point/b2dpoint.hxx"
54 #include "basegfx/polygon/b2dpolypolygon.hxx"
55 #include "basegfx/polygon/b2dpolygon.hxx"
56 #include "basegfx/tools/canvastools.hxx"
57 #include "basegfx/tools/unopolypolygon.hxx"
59 #include <vcl/metric.hxx>
60 #include <vcl/font.hxx>
61 #include <vcl/virdev.hxx>
63 #include <boost/scoped_ptr.hpp>
64 #include <unordered_map>
71 #include "rtl/bootstrap.h"
73 using namespace com::sun::star
;
81 // identifier of the strings coming from the out-of-process xpdf
137 typedef std::unordered_map
< sal_Int64
,
138 FontAttributes
> FontMapType
;
140 const uno::Reference
<uno::XComponentContext
> m_xContext
;
141 const ContentSinkSharedPtr m_pSink
;
142 const oslFileHandle m_pErr
;
144 FontMapType m_aFontMap
;
145 sal_Int32 m_nNextToken
;
146 sal_Int32 m_nCharIndex
;
149 OString
readNextToken();
150 void readInt32( sal_Int32
& o_Value
);
151 sal_Int32
readInt32();
152 void readInt64( sal_Int64
& o_Value
);
153 void readDouble( double& o_Value
);
155 void readBinaryData( uno::Sequence
<sal_Int8
>& rBuf
);
157 uno::Reference
<rendering::XPolyPolygon2D
> readPath();
163 void readTransformation();
164 rendering::ARGBColor
readColor();
165 static void parseFontFamilyName( FontAttributes
& aResult
);
167 uno::Sequence
<beans::PropertyValue
> readImageImpl();
172 void readMaskedImage();
173 void readSoftMaskedImage();
174 static sal_Int32
parseFontCheckForString(const sal_Unicode
* pCopy
, sal_Int32 nCopyLen
,
175 const char* pAttrib
, sal_Int32 nAttribLen
,
176 FontAttributes
& rResult
, bool bItalic
, bool bBold
);
177 static sal_Int32
parseFontRemoveSuffix(const sal_Unicode
* pCopy
, sal_Int32 nCopyLen
,
178 const char* pAttrib
, sal_Int32 nAttribLen
);
181 Parser( const ContentSinkSharedPtr
& rSink
,
183 const uno::Reference
<uno::XComponentContext
>& xContext
) :
184 m_xContext(xContext
),
193 void parseLine( const OString
& rLine
);
200 /** Unescapes line-ending characters in input string. These
201 characters are encoded as pairs of characters: '\\' 'n', resp.
202 '\\' 'r'. This function converts them back to '\n', resp. '\r'.
204 OString
lcl_unescapeLineFeeds(const OString
& i_rStr
)
206 const size_t nOrigLen(sal::static_int_cast
<size_t>(i_rStr
.getLength()));
207 const sal_Char
* const pOrig(i_rStr
.getStr());
208 sal_Char
* const pBuffer(new sal_Char
[nOrigLen
+ 1]);
210 const sal_Char
* pRead(pOrig
);
211 sal_Char
* pWrite(pBuffer
);
212 const sal_Char
* pCur(pOrig
);
213 while ((pCur
= strchr(pCur
, '\\')) != 0)
215 const sal_Char
cNext(pCur
[1]);
216 if (cNext
== 'n' || cNext
== 'r' || cNext
== '\\')
218 const size_t nLen(pCur
- pRead
);
219 strncpy(pWrite
, pRead
, nLen
);
221 *pWrite
= cNext
== 'n' ? '\n' : (cNext
== 'r' ? '\r' : '\\');
223 pCur
= pRead
= pCur
+ 2;
227 // Just continue on the next character. The current
228 // block will be copied the next time it goes through the
233 // maybe there are some data to copy yet
234 if (sal::static_int_cast
<size_t>(pRead
- pOrig
) < nOrigLen
)
236 const size_t nLen(nOrigLen
- (pRead
- pOrig
));
237 strncpy(pWrite
, pRead
, nLen
);
242 OString
aResult(pBuffer
);
250 OString
Parser::readNextToken()
252 OSL_PRECOND(m_nCharIndex
!=-1,"insufficient input");
253 return m_aLine
.getToken(m_nNextToken
,' ',m_nCharIndex
);
256 void Parser::readInt32( sal_Int32
& o_Value
)
258 o_Value
= readNextToken().toInt32();
261 sal_Int32
Parser::readInt32()
263 return readNextToken().toInt32();
266 void Parser::readInt64( sal_Int64
& o_Value
)
268 o_Value
= readNextToken().toInt64();
271 void Parser::readDouble( double& o_Value
)
273 o_Value
= readNextToken().toDouble();
276 double Parser::readDouble()
278 return readNextToken().toDouble();
281 void Parser::readBinaryData( uno::Sequence
<sal_Int8
>& rBuf
)
283 sal_Int32
nFileLen( rBuf
.getLength() );
284 sal_Int8
* pBuf( rBuf
.getArray() );
285 sal_uInt64
nBytesRead(0);
286 oslFileError nRes
=osl_File_E_None
;
288 osl_File_E_None
== (nRes
=osl_readFile( m_pErr
, pBuf
, nFileLen
, &nBytesRead
)) )
291 nFileLen
-= sal::static_int_cast
<sal_Int32
>(nBytesRead
);
294 OSL_PRECOND(nRes
==osl_File_E_None
, "inconsistent data");
297 uno::Reference
<rendering::XPolyPolygon2D
> Parser::readPath()
299 const OString
aSubPathMarker( "subpath" );
301 if( readNextToken() != aSubPathMarker
)
302 OSL_PRECOND(false, "broken path");
304 basegfx::B2DPolyPolygon aResult
;
305 while( m_nCharIndex
!= -1 )
307 basegfx::B2DPolygon aSubPath
;
309 sal_Int32 nClosedFlag
;
310 readInt32( nClosedFlag
);
311 aSubPath
.setClosed( nClosedFlag
!= 0 );
313 sal_Int32
nContiguousControlPoints(0);
314 sal_Int32 nDummy
=m_nCharIndex
;
315 OString
aCurrToken( m_aLine
.getToken(m_nNextToken
,' ',nDummy
) );
317 while( m_nCharIndex
!= -1 && aCurrToken
!= aSubPathMarker
)
319 sal_Int32 nCurveFlag
;
323 readInt32( nCurveFlag
);
325 aSubPath
.append(basegfx::B2DPoint(nX
,nY
));
328 ++nContiguousControlPoints
;
330 else if( nContiguousControlPoints
)
332 OSL_PRECOND(nContiguousControlPoints
==2,"broken bezier path");
334 // have two control points before us. the current one
335 // is a normal point - thus, convert previous points
336 // into bezier segment
337 const sal_uInt32
nPoints( aSubPath
.count() );
338 const basegfx::B2DPoint
aCtrlA( aSubPath
.getB2DPoint(nPoints
-3) );
339 const basegfx::B2DPoint
aCtrlB( aSubPath
.getB2DPoint(nPoints
-2) );
340 const basegfx::B2DPoint
aEnd( aSubPath
.getB2DPoint(nPoints
-1) );
341 aSubPath
.remove(nPoints
-3, 3);
342 aSubPath
.appendBezierSegment(aCtrlA
, aCtrlB
, aEnd
);
344 nContiguousControlPoints
=0;
347 // one token look-ahead (new subpath or more points?
349 aCurrToken
= m_aLine
.getToken(m_nNextToken
,' ',nDummy
);
352 aResult
.append( aSubPath
);
353 if( m_nCharIndex
!= -1 )
357 return static_cast<rendering::XLinePolyPolygon2D
*>(
358 new basegfx::unotools::UnoPolyPolygon(aResult
));
361 void Parser::readChar()
364 geometry::Matrix2D aUnoMatrix
;
365 geometry::RealRectangle2D aRect
;
367 readDouble(aRect
.X1
);
368 readDouble(aRect
.Y1
);
369 readDouble(aRect
.X2
);
370 readDouble(aRect
.Y2
);
371 readDouble(aUnoMatrix
.m00
);
372 readDouble(aUnoMatrix
.m01
);
373 readDouble(aUnoMatrix
.m10
);
374 readDouble(aUnoMatrix
.m11
);
375 readDouble(fontSize
);
379 if (m_nCharIndex
!= -1)
380 aChars
= lcl_unescapeLineFeeds( m_aLine
.copy( m_nCharIndex
) );
382 // chars gobble up rest of line
385 m_pSink
->drawGlyphs(OStringToOUString(aChars
, RTL_TEXTENCODING_UTF8
),
386 aRect
, aUnoMatrix
, fontSize
);
389 void Parser::readLineCap()
391 sal_Int8
nCap(rendering::PathCapType::BUTT
);
392 switch( readInt32() )
395 // FALLTHROUGH intended
396 case 0: nCap
= rendering::PathCapType::BUTT
; break;
397 case 1: nCap
= rendering::PathCapType::ROUND
; break;
398 case 2: nCap
= rendering::PathCapType::SQUARE
; break;
400 m_pSink
->setLineCap(nCap
);
403 void Parser::readLineDash()
405 if( m_nCharIndex
== -1 )
407 m_pSink
->setLineDash( uno::Sequence
<double>(), 0.0 );
411 const double nOffset(readDouble());
412 const sal_Int32
nLen(readInt32());
414 uno::Sequence
<double> aDashArray(nLen
);
415 double* pArray
=aDashArray
.getArray();
416 for( sal_Int32 i
=0; i
<nLen
; ++i
)
417 *pArray
++ = readDouble();
419 m_pSink
->setLineDash( aDashArray
, nOffset
);
422 void Parser::readLineJoin()
424 sal_Int8
nJoin(rendering::PathJoinType::MITER
);
425 switch( readInt32() )
428 // FALLTHROUGH intended
429 case 0: nJoin
= rendering::PathJoinType::MITER
; break;
430 case 1: nJoin
= rendering::PathJoinType::ROUND
; break;
431 case 2: nJoin
= rendering::PathJoinType::BEVEL
; break;
433 m_pSink
->setLineJoin(nJoin
);
436 void Parser::readTransformation()
438 geometry::AffineMatrix2D aMat
;
439 readDouble(aMat
.m00
);
440 readDouble(aMat
.m10
);
441 readDouble(aMat
.m01
);
442 readDouble(aMat
.m11
);
443 readDouble(aMat
.m02
);
444 readDouble(aMat
.m12
);
445 m_pSink
->setTransformation( aMat
);
448 rendering::ARGBColor
Parser::readColor()
450 rendering::ARGBColor aRes
;
451 readDouble(aRes
.Red
);
452 readDouble(aRes
.Green
);
453 readDouble(aRes
.Blue
);
454 readDouble(aRes
.Alpha
);
458 sal_Int32
Parser::parseFontCheckForString(
459 const sal_Unicode
* pCopy
, sal_Int32 nCopyLen
,
460 const char* pAttrib
, sal_Int32 nAttribLen
,
461 FontAttributes
& rResult
, bool bItalic
, bool bBold
)
463 if (nCopyLen
< nAttribLen
)
465 for (sal_Int32 i
= 0; i
< nAttribLen
; ++i
)
466 if (tolower(pCopy
[i
]) != pAttrib
[i
]
467 && toupper(pCopy
[i
]) != pAttrib
[i
])
469 rResult
.isItalic
|= bItalic
;
470 rResult
.isBold
|= bBold
;
474 sal_Int32
Parser::parseFontRemoveSuffix(
475 const sal_Unicode
* pCopy
, sal_Int32 nCopyLen
,
476 const char* pAttrib
, sal_Int32 nAttribLen
)
478 if (nCopyLen
< nAttribLen
)
480 for (sal_Int32 i
= 0; i
< nAttribLen
; ++i
)
481 if ( pCopy
[nCopyLen
- nAttribLen
+ i
] != pAttrib
[i
] )
486 void Parser::parseFontFamilyName( FontAttributes
& rResult
)
488 OUStringBuffer
aNewFamilyName( rResult
.familyName
.getLength() );
490 const sal_Unicode
* pCopy
= rResult
.familyName
.getStr();
491 sal_Int32 nLen
= rResult
.familyName
.getLength();
492 // parse out truetype subsets (e.g. BAAAAA+Thorndale)
493 if( nLen
> 8 && pCopy
[6] == '+' )
499 // TODO: Looks like this block needs to be refactored
502 if (parseFontRemoveSuffix(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("PSMT")))
504 nLen
-= RTL_CONSTASCII_LENGTH("PSMT");
506 else if (parseFontRemoveSuffix(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("MT")))
508 nLen
-= RTL_CONSTASCII_LENGTH("MT");
511 if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("Italic"), rResult
, true, false))
513 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("Italic");
517 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("-Bold"), rResult
, false, true))
519 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("-Bold");
523 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("Bold"), rResult
, false, true))
525 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("Bold");
529 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("-Roman"), rResult
, false, false))
531 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("-Roman");
535 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("-LightOblique"), rResult
, true, false))
537 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("-LightOblique");
541 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("-BoldOblique"), rResult
, true, true))
543 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("-BoldOblique");
547 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("-Light"), rResult
, false, false))
549 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("-Light");
553 else if (parseFontCheckForString(pCopy
, nLen
, RTL_CONSTASCII_STRINGPARAM("-Reg"), rResult
, false, false))
555 sal_Int32 nAttribLen
= RTL_CONSTASCII_LENGTH("-Reg");
562 aNewFamilyName
.append( *pCopy
);
567 rResult
.familyName
= aNewFamilyName
.makeStringAndClear();
570 void Parser::readFont()
574 sal_Int32 nIsEmbedded
, nIsBold
, nIsItalic
, nIsUnderline
, nFileLen
;
578 readInt32(nIsEmbedded
);
580 readInt32(nIsItalic
);
581 readInt32(nIsUnderline
);
585 nSize
= nSize
< 0.0 ? -nSize
: nSize
;
586 aFontName
= lcl_unescapeLineFeeds( m_aLine
.copy( m_nCharIndex
) );
588 // name gobbles up rest of line
591 FontMapType::const_iterator
pFont( m_aFontMap
.find(nFontID
) );
592 if( pFont
!= m_aFontMap
.end() )
594 OSL_PRECOND(nFileLen
==0,"font data for known font");
595 FontAttributes
aRes(pFont
->second
);
597 m_pSink
->setFont( aRes
);
602 // yet unknown font - get info and add to map
603 FontAttributes
aResult( OStringToOUString( aFontName
,
604 RTL_TEXTENCODING_UTF8
),
612 // extract textual attributes (bold, italic in the name, etc.)
613 parseFontFamilyName(aResult
);
614 // need to read font file?
617 uno::Sequence
<sal_Int8
> aFontFile(nFileLen
);
618 readBinaryData( aFontFile
);
620 awt::FontDescriptor aFD
;
621 uno::Sequence
< uno::Any
> aArgs(1);
622 aArgs
[0] <<= aFontFile
;
626 uno::Reference
< beans::XMaterialHolder
> xMat(
627 m_xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
628 OUString( "com.sun.star.awt.FontIdentificator" ),
634 uno::Any
aRes( xMat
->getMaterial() );
637 if (!aFD
.Name
.isEmpty())
639 aResult
.familyName
= aFD
.Name
;
640 parseFontFamilyName(aResult
);
642 aResult
.isBold
= (aFD
.Weight
> 100.0);
643 aResult
.isItalic
= (aFD
.Slant
== awt::FontSlant_OBLIQUE
||
644 aFD
.Slant
== awt::FontSlant_ITALIC
);
645 aResult
.isUnderline
= false;
650 catch( uno::Exception
& )
654 if( aResult
.familyName
.isEmpty() )
657 aResult
.familyName
= "Arial";
658 aResult
.isUnderline
= false;
663 static VclPtr
<VirtualDevice
> vDev
;
665 vDev
= VclPtr
<VirtualDevice
>::Create();
667 vcl::Font
font(aResult
.familyName
, Size(0, 1000));
669 FontMetric
metric(vDev
->GetFontMetric());
670 aResult
.ascent
= metric
.GetAscent() / 1000.0;
672 m_aFontMap
[nFontID
] = aResult
;
674 aResult
.size
= nSize
;
675 m_pSink
->setFont(aResult
);
678 uno::Sequence
<beans::PropertyValue
> Parser::readImageImpl()
680 static const char aJpegMarker
[] = "JPEG";
681 static const char aPbmMarker
[] = "PBM";
682 static const char aPpmMarker
[] = "PPM";
683 static const char aPngMarker
[] = "PNG";
684 static const char aJpegFile
[] = "DUMMY.JPEG";
685 static const char aPbmFile
[] = "DUMMY.PBM";
686 static const char aPpmFile
[] = "DUMMY.PPM";
687 static const char aPngFile
[] = "DUMMY.PNG";
689 OString aToken
= readNextToken();
690 const sal_Int32
nImageSize( readInt32() );
693 if( aToken
== aPngMarker
)
694 aFileName
= aPngFile
;
695 else if( aToken
== aJpegMarker
)
696 aFileName
= aJpegFile
;
697 else if( aToken
== aPbmMarker
)
698 aFileName
= aPbmFile
;
701 SAL_WARN_IF(aToken
!= aPpmMarker
,"sdext.pdfimport","Invalid bitmap format");
702 aFileName
= aPpmFile
;
705 uno::Sequence
<sal_Int8
> aDataSequence(nImageSize
);
706 readBinaryData( aDataSequence
);
708 uno::Sequence
< uno::Any
> aStreamCreationArgs(1);
709 aStreamCreationArgs
[0] <<= aDataSequence
;
711 uno::Reference
< uno::XComponentContext
> xContext( m_xContext
, uno::UNO_SET_THROW
);
712 uno::Reference
< lang::XMultiComponentFactory
> xFactory( xContext
->getServiceManager(), uno::UNO_SET_THROW
);
713 uno::Reference
< io::XInputStream
> xDataStream( xFactory
->createInstanceWithArgumentsAndContext(
714 OUString( "com.sun.star.io.SequenceInputStream" ),
715 aStreamCreationArgs
, m_xContext
), uno::UNO_QUERY_THROW
);
717 uno::Sequence
<beans::PropertyValue
> aSequence(3);
718 aSequence
[0] = beans::PropertyValue( OUString("URL"),
720 uno::makeAny(aFileName
),
721 beans::PropertyState_DIRECT_VALUE
);
722 aSequence
[1] = beans::PropertyValue( OUString("InputStream"),
724 uno::makeAny( xDataStream
),
725 beans::PropertyState_DIRECT_VALUE
);
726 aSequence
[2] = beans::PropertyValue( OUString("InputSequence"),
728 uno::makeAny(aDataSequence
),
729 beans::PropertyState_DIRECT_VALUE
);
734 void Parser::readImage()
736 sal_Int32 nWidth
, nHeight
,nMaskColors
;
739 readInt32(nMaskColors
);
741 uno::Sequence
<beans::PropertyValue
> aImg( readImageImpl() );
745 uno::Sequence
<sal_Int8
> aDataSequence(nMaskColors
);
746 readBinaryData( aDataSequence
);
748 uno::Sequence
<uno::Any
> aMaskRanges(2);
750 uno::Sequence
<double> aMinRange(nMaskColors
/2);
751 uno::Sequence
<double> aMaxRange(nMaskColors
/2);
752 for( sal_Int32 i
=0; i
<nMaskColors
/2; ++i
)
754 aMinRange
[i
] = aDataSequence
[i
] / 255.0;
755 aMaxRange
[i
] = aDataSequence
[i
+nMaskColors
/2] / 255.0;
758 aMaskRanges
[0] = uno::makeAny(aMinRange
);
759 aMaskRanges
[1] = uno::makeAny(aMaxRange
);
761 m_pSink
->drawColorMaskedImage( aImg
, aMaskRanges
);
764 m_pSink
->drawImage( aImg
);
767 void Parser::readMask()
769 sal_Int32 nWidth
, nHeight
, nInvert
;
774 m_pSink
->drawMask( readImageImpl(), nInvert
);
777 void Parser::readLink()
779 geometry::RealRectangle2D aBounds
;
780 readDouble(aBounds
.X1
);
781 readDouble(aBounds
.Y1
);
782 readDouble(aBounds
.X2
);
783 readDouble(aBounds
.Y2
);
785 m_pSink
->hyperLink( aBounds
,
786 OStringToOUString( lcl_unescapeLineFeeds(
787 m_aLine
.copy(m_nCharIndex
) ),
788 RTL_TEXTENCODING_UTF8
) );
789 // name gobbles up rest of line
793 void Parser::readMaskedImage()
795 sal_Int32 nWidth
, nHeight
, nMaskWidth
, nMaskHeight
, nMaskInvert
;
798 readInt32(nMaskWidth
);
799 readInt32(nMaskHeight
);
800 readInt32(nMaskInvert
);
802 const uno::Sequence
<beans::PropertyValue
> aImage( readImageImpl() );
803 const uno::Sequence
<beans::PropertyValue
> aMask ( readImageImpl() );
804 m_pSink
->drawMaskedImage( aImage
, aMask
, nMaskInvert
!= 0 );
807 void Parser::readSoftMaskedImage()
809 sal_Int32 nWidth
, nHeight
, nMaskWidth
, nMaskHeight
;
812 readInt32(nMaskWidth
);
813 readInt32(nMaskHeight
);
815 const uno::Sequence
<beans::PropertyValue
> aImage( readImageImpl() );
816 const uno::Sequence
<beans::PropertyValue
> aMask ( readImageImpl() );
817 m_pSink
->drawAlphaMaskedImage( aImage
, aMask
);
820 void Parser::parseLine( const OString
& rLine
)
822 OSL_PRECOND( m_pSink
, "Invalid sink" );
823 OSL_PRECOND( m_pErr
, "Invalid filehandle" );
824 OSL_PRECOND( m_xContext
.is(), "Invalid service factory" );
826 m_nNextToken
= 0; m_nCharIndex
= 0; m_aLine
= rLine
;
827 uno::Reference
<rendering::XPolyPolygon2D
> xPoly
;
828 const OString
& rCmd
= readNextToken();
829 const hash_entry
* pEntry
= PdfKeywordHash::in_word_set( rCmd
.getStr(),
832 switch( pEntry
->eKey
)
835 m_pSink
->intersectClip(readPath()); break;
844 case DRAWMASKEDIMAGE
:
845 readMaskedImage(); break;
846 case DRAWSOFTMASKEDIMAGE
:
847 readSoftMaskedImage(); break;
849 m_pSink
->endPage(); break;
851 m_pSink
->endText(); break;
853 m_pSink
->intersectEoClip(readPath()); break;
855 m_pSink
->eoFillPath(readPath()); break;
857 m_pSink
->fillPath(readPath()); break;
859 m_pSink
->popState(); break;
861 m_pSink
->pushState(); break;
863 m_pSink
->setPageNum( readInt32() ); break;
866 const double nWidth ( readDouble() );
867 const double nHeight( readDouble() );
868 m_pSink
->startPage( geometry::RealSize2D( nWidth
, nHeight
) );
872 m_pSink
->strokePath(readPath()); break;
874 readTransformation(); break;
875 case UPDATEFILLCOLOR
:
876 m_pSink
->setFillColor( readColor() ); break;
878 m_pSink
->setFlatness( readDouble( ) ); break;
882 readLineCap(); break;
884 readLineDash(); break;
886 readLineJoin(); break;
887 case UPDATELINEWIDTH
:
888 m_pSink
->setLineWidth( readDouble() );break;
889 case UPDATEMITERLIMIT
:
890 m_pSink
->setMiterLimit( readDouble() ); break;
891 case UPDATESTROKECOLOR
:
892 m_pSink
->setStrokeColor( readColor() ); break;
893 case UPDATESTROKEOPACITY
:
895 case SETTEXTRENDERMODE
:
896 m_pSink
->setTextRenderMode( readInt32() ); break;
900 OSL_PRECOND(false,"Unknown input");
905 SAL_WARN_IF(m_nCharIndex
!=-1, "sdext.pdfimport", "leftover scanner input");
908 oslFileError
readLine( oslFileHandle pFile
, OStringBuffer
& line
)
910 OSL_PRECOND( line
.isEmpty(), "line buf not empty" );
912 // TODO(P3): read larger chunks
913 sal_Char
aChar('\n');
914 sal_uInt64 nBytesRead
;
917 // skip garbage \r \n at start of line
918 while( osl_File_E_None
== (nRes
=osl_readFile(pFile
, &aChar
, 1, &nBytesRead
)) &&
920 (aChar
== '\n' || aChar
== '\r') ) ;
922 if( aChar
!= '\n' && aChar
!= '\r' )
923 line
.append( aChar
);
925 while( osl_File_E_None
== (nRes
=osl_readFile(pFile
, &aChar
, 1, &nBytesRead
)) &&
926 nBytesRead
== 1 && aChar
!= '\n' && aChar
!= '\r' )
928 line
.append( aChar
);
936 static bool checkEncryption( const OUString
& i_rPath
,
937 const uno::Reference
< task::XInteractionHandler
>& i_xIHdl
,
939 bool& o_rIsEncrypted
,
940 const OUString
& i_rDocName
943 bool bSuccess
= false;
945 aPDFFile
= OUStringToOString( i_rPath
, osl_getThreadTextEncoding() );
947 pdfparse::PDFReader aParser
;
948 boost::scoped_ptr
<pdfparse::PDFEntry
> pEntry( pdfparse::PDFReader::read( aPDFFile
.getStr() ));
951 pdfparse::PDFFile
* pPDFFile
= dynamic_cast<pdfparse::PDFFile
*>(pEntry
.get());
954 o_rIsEncrypted
= pPDFFile
->isEncrypted();
957 if( pPDFFile
->usesSupportedEncryptionFormat() )
959 bool bAuthenticated
= false;
960 if( !io_rPwd
.isEmpty() )
962 OString aIsoPwd
= OUStringToOString( io_rPwd
,
963 RTL_TEXTENCODING_ISO_8859_1
);
964 bAuthenticated
= pPDFFile
->setupDecryptionData( aIsoPwd
.getStr() );
972 bool bEntered
= false;
975 bEntered
= getPassword( i_xIHdl
, io_rPwd
, ! bEntered
, i_rDocName
);
976 OString aIsoPwd
= OUStringToOString( io_rPwd
,
977 RTL_TEXTENCODING_ISO_8859_1
);
978 bAuthenticated
= pPDFFile
->setupDecryptionData( aIsoPwd
.getStr() );
979 } while( bEntered
&& ! bAuthenticated
);
982 OSL_TRACE( "password: %s", bAuthenticated
? "matches" : "does not match" );
983 bSuccess
= bAuthenticated
;
987 OUStringBuffer
aBuf( 128 );
988 aBuf
.appendAscii( "_OOO_pdfi_Credentials_" );
989 aBuf
.append( pPDFFile
->getDecryptionKey() );
990 io_rPwd
= aBuf
.makeStringAndClear();
993 else if( i_xIHdl
.is() )
995 reportUnsupportedEncryptionFormat( i_xIHdl
);
996 //TODO: this should either be handled further down the
997 // call stack, or else information that this has already
998 // been handled should be passed down the call stack, so
999 // that SfxBaseModel::load does not show an additional
1000 // "General Error" message box
1010 bool xpdf_ImportFromFile( const OUString
& rURL
,
1011 const ContentSinkSharedPtr
& rSink
,
1012 const uno::Reference
< task::XInteractionHandler
>& xIHdl
,
1013 const OUString
& rPwd
,
1014 const uno::Reference
< uno::XComponentContext
>& xContext
,
1015 const OUString
& rFilterOptions
)
1020 if( osl_getSystemPathFromFileURL( rURL
.pData
, &aSysUPath
.pData
) != osl_File_E_None
)
1024 "getSystemPathFromFileURL(" << rURL
<< ") failed");
1027 OUString
aDocName( rURL
.copy( rURL
.lastIndexOf( '/' )+1 ) );
1029 // check for encryption, if necessary get password
1030 OUString
aPwd( rPwd
);
1031 bool bIsEncrypted
= false;
1032 if( !checkEncryption( aSysUPath
, xIHdl
, aPwd
, bIsEncrypted
, aDocName
) )
1036 "checkEncryption(" << aSysUPath
<< ") failed");
1040 // Determine xpdfimport executable URL:
1041 OUString
converterURL("$BRAND_BASE_DIR/" LIBO_BIN_FOLDER
"/xpdfimport");
1042 rtl::Bootstrap::expandMacros(converterURL
); //TODO: detect failure
1044 // Determine pathname of xpdfimport_err.pdf:
1045 OUString
errPathname("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
"/xpdfimport/xpdfimport_err.pdf");
1046 rtl::Bootstrap::expandMacros(errPathname
); //TODO: detect failure
1047 if (osl::FileBase::getSystemPathFromFileURL(errPathname
, errPathname
)
1048 != osl::FileBase::E_None
)
1052 "getSystemPathFromFileURL(" << errPathname
<< ") failed");
1056 // spawn separate process to keep LGPL/GPL code apart.
1058 OUString
aOptFlag("-o");
1059 rtl_uString
* args
[] = { aSysUPath
.pData
, errPathname
.pData
,
1060 aOptFlag
.pData
, rFilterOptions
.pData
};
1061 sal_Int32 nArgs
= rFilterOptions
.isEmpty() ? 2 : 4;
1063 oslProcess aProcess
;
1064 oslFileHandle pIn
= NULL
;
1065 oslFileHandle pOut
= NULL
;
1066 oslFileHandle pErr
= NULL
;
1067 oslSecurity pSecurity
= osl_getCurrentSecurity ();
1068 oslProcessError eErr
=
1069 osl_executeProcess_WithRedirectedIO(converterURL
.pData
,
1072 osl_Process_SEARCHPATH
|osl_Process_HIDDEN
,
1075 &aProcess
, &pIn
, &pOut
, &pErr
);
1076 osl_freeSecurityHandle(pSecurity
);
1081 if( eErr
!=osl_Process_E_None
)
1085 "executeProcess of " << converterURL
<< " failed with "
1092 OStringBuffer
aBuf(256);
1094 aBuf
.append( OUStringToOString( aPwd
, RTL_TEXTENCODING_ISO_8859_1
) );
1095 aBuf
.append( '\n' );
1097 sal_uInt64 nWritten
= 0;
1098 osl_writeFile( pIn
, aBuf
.getStr(), sal_uInt64(aBuf
.getLength()), &nWritten
);
1103 // read results of PDF parser. One line - one call to
1104 // OutputDev. stderr is used for alternate streams, like
1105 // embedded fonts and bitmaps
1106 Parser
aParser(rSink
,pErr
,xContext
);
1108 while( osl_File_E_None
== readLine(pOut
, line
) && !line
.isEmpty() )
1109 aParser
.parseLine(line
.makeStringAndClear());
1112 catch( uno::Exception
& )
1114 // crappy C file interface. need manual resource dealloc
1121 osl_closeFile(pOut
);
1123 osl_closeFile(pErr
);
1124 eErr
= osl_joinProcess(aProcess
);
1125 if (eErr
== osl_Process_E_None
)
1127 oslProcessInfo info
;
1128 info
.Size
= sizeof info
;
1129 eErr
= osl_getProcessInfo(aProcess
, osl_Process_EXITCODE
, &info
);
1130 if (eErr
== osl_Process_E_None
)
1136 "getProcessInfo of " << converterURL
1137 << " failed with exit code " << info
.Code
);
1145 "getProcessInfo of " << converterURL
<< " failed with "
1154 "joinProcess of " << converterURL
<< " failed with " << +eErr
);
1157 osl_freeProcessHandle(aProcess
);
1162 bool xpdf_ImportFromStream( const uno::Reference
< io::XInputStream
>& xInput
,
1163 const ContentSinkSharedPtr
& rSink
,
1164 const uno::Reference
<task::XInteractionHandler
>& xIHdl
,
1165 const OUString
& rPwd
,
1166 const uno::Reference
< uno::XComponentContext
>& xContext
,
1167 const OUString
& rFilterOptions
)
1169 OSL_ASSERT(xInput
.is());
1172 // convert XInputStream to local temp file
1173 oslFileHandle aFile
= NULL
;
1175 if( osl_createTempFile( NULL
, &aFile
, &aURL
.pData
) != osl_File_E_None
)
1178 // copy content, buffered...
1179 const sal_uInt32 nBufSize
= 4096;
1180 uno::Sequence
<sal_Int8
> aBuf( nBufSize
);
1181 sal_uInt64 nBytes
= 0;
1182 sal_uInt64 nWritten
= 0;
1183 bool bSuccess
= true;
1188 nBytes
= xInput
->readBytes( aBuf
, nBufSize
);
1190 catch( com::sun::star::uno::Exception
& )
1192 osl_closeFile( aFile
);
1197 osl_writeFile( aFile
, aBuf
.getConstArray(), nBytes
, &nWritten
);
1198 if( nWritten
!= nBytes
)
1205 while( nBytes
== nBufSize
);
1207 osl_closeFile( aFile
);
1210 bSuccess
= xpdf_ImportFromFile( aURL
, rSink
, xIHdl
, rPwd
, xContext
, rFilterOptions
);
1211 osl_removeFile( aURL
.pData
);
1218 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */