Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <config_folders.h>
21 :
22 : #include "contentsink.hxx"
23 : #include "pdfparse.hxx"
24 : #include "pdfihelper.hxx"
25 : #include "wrapper.hxx"
26 :
27 : #include "osl/file.h"
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"
37 :
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"
52 :
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"
58 :
59 : #include <vcl/metric.hxx>
60 : #include <vcl/font.hxx>
61 : #include <vcl/virdev.hxx>
62 :
63 : #include <boost/scoped_ptr.hpp>
64 : #include <unordered_map>
65 : #include <string.h>
66 : #ifdef WNT
67 : #include <stdlib.h>
68 : #include <ctype.h>
69 : #endif
70 :
71 : #include "rtl/bootstrap.h"
72 :
73 : using namespace com::sun::star;
74 :
75 : namespace pdfi
76 : {
77 :
78 : namespace
79 : {
80 :
81 : // identifier of the strings coming from the out-of-process xpdf
82 : // converter
83 : enum parseKey {
84 : CLIPPATH,
85 : DRAWCHAR,
86 : DRAWIMAGE,
87 : DRAWLINK,
88 : DRAWMASK,
89 : DRAWMASKEDIMAGE,
90 : DRAWSOFTMASKEDIMAGE,
91 : ENDPAGE,
92 : ENDTEXTOBJECT,
93 : EOCLIPPATH,
94 : EOFILLPATH,
95 : FILLPATH,
96 : HYPERLINK,
97 : INTERSECTCLIP,
98 : INTERSECTEOCLIP,
99 : POPSTATE,
100 : PUSHSTATE,
101 : RESTORESTATE,
102 : SAVESTATE,
103 : SETBLENDMODE,
104 : SETFILLCOLOR,
105 : SETFONT,
106 : SETLINECAP,
107 : SETLINEDASH,
108 : SETLINEJOIN,
109 : SETLINEWIDTH,
110 : SETMITERLIMIT,
111 : SETPAGENUM,
112 : SETSTROKECOLOR,
113 : SETTEXTRENDERMODE,
114 : SETTRANSFORMATION,
115 : STARTPAGE,
116 : STROKEPATH,
117 : UPDATEBLENDMODE,
118 : UPDATECTM,
119 : UPDATEFILLCOLOR,
120 : UPDATEFILLOPACITY,
121 : UPDATEFLATNESS,
122 : UPDATEFONT,
123 : UPDATELINECAP,
124 : UPDATELINEDASH,
125 : UPDATELINEJOIN,
126 : UPDATELINEWIDTH,
127 : UPDATEMITERLIMIT,
128 : UPDATESTROKECOLOR,
129 : UPDATESTROKEOPACITY,
130 : NONE
131 : };
132 :
133 : #include "hash.cxx"
134 :
135 5 : class Parser
136 : {
137 : typedef std::unordered_map< sal_Int64,
138 : FontAttributes > FontMapType;
139 :
140 : const uno::Reference<uno::XComponentContext> m_xContext;
141 : const ContentSinkSharedPtr m_pSink;
142 : const oslFileHandle m_pErr;
143 : OString m_aLine;
144 : FontMapType m_aFontMap;
145 : sal_Int32 m_nNextToken;
146 : sal_Int32 m_nCharIndex;
147 :
148 :
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 );
154 : double readDouble();
155 : void readBinaryData( uno::Sequence<sal_Int8>& rBuf );
156 :
157 : uno::Reference<rendering::XPolyPolygon2D> readPath();
158 :
159 : void readChar();
160 : void readLineCap();
161 : void readLineDash();
162 : void readLineJoin();
163 : void readTransformation();
164 : rendering::ARGBColor readColor();
165 : static void parseFontFamilyName( FontAttributes& aResult );
166 : void readFont();
167 : uno::Sequence<beans::PropertyValue> readImageImpl();
168 :
169 : void readImage();
170 : void readMask();
171 : void readLink();
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);
179 :
180 : public:
181 5 : Parser( const ContentSinkSharedPtr& rSink,
182 : oslFileHandle pErr,
183 : const uno::Reference<uno::XComponentContext>& xContext ) :
184 : m_xContext(xContext),
185 : m_pSink(rSink),
186 : m_pErr(pErr),
187 : m_aLine(),
188 : m_aFontMap(101),
189 : m_nNextToken(-1),
190 5 : m_nCharIndex(-1)
191 5 : {}
192 :
193 : void parseLine( const OString& rLine );
194 : };
195 :
196 :
197 : namespace
198 : {
199 :
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'.
203 : */
204 428 : OString lcl_unescapeLineFeeds(const OString& i_rStr)
205 : {
206 428 : const size_t nOrigLen(sal::static_int_cast<size_t>(i_rStr.getLength()));
207 428 : const sal_Char* const pOrig(i_rStr.getStr());
208 428 : sal_Char* const pBuffer(new sal_Char[nOrigLen + 1]);
209 :
210 428 : const sal_Char* pRead(pOrig);
211 428 : sal_Char* pWrite(pBuffer);
212 428 : const sal_Char* pCur(pOrig);
213 856 : while ((pCur = strchr(pCur, '\\')) != 0)
214 : {
215 0 : const sal_Char cNext(pCur[1]);
216 0 : if (cNext == 'n' || cNext == 'r' || cNext == '\\')
217 : {
218 0 : const size_t nLen(pCur - pRead);
219 0 : strncpy(pWrite, pRead, nLen);
220 0 : pWrite += nLen;
221 0 : *pWrite = cNext == 'n' ? '\n' : (cNext == 'r' ? '\r' : '\\');
222 0 : ++pWrite;
223 0 : pCur = pRead = pCur + 2;
224 : }
225 : else
226 : {
227 : // Just continue on the next character. The current
228 : // block will be copied the next time it goes through the
229 : // 'if' branch.
230 0 : ++pCur;
231 : }
232 : }
233 : // maybe there are some data to copy yet
234 428 : if (sal::static_int_cast<size_t>(pRead - pOrig) < nOrigLen)
235 : {
236 428 : const size_t nLen(nOrigLen - (pRead - pOrig));
237 428 : strncpy(pWrite, pRead, nLen);
238 428 : pWrite += nLen;
239 : }
240 428 : *pWrite = '\0';
241 :
242 428 : OString aResult(pBuffer);
243 428 : delete[] pBuffer;
244 428 : return aResult;
245 : }
246 :
247 : }
248 :
249 :
250 5216 : OString Parser::readNextToken()
251 : {
252 : OSL_PRECOND(m_nCharIndex!=-1,"insufficient input");
253 5216 : return m_aLine.getToken(m_nNextToken,' ',m_nCharIndex);
254 : }
255 :
256 301 : void Parser::readInt32( sal_Int32& o_Value )
257 : {
258 301 : o_Value = readNextToken().toInt32();
259 301 : }
260 :
261 32 : sal_Int32 Parser::readInt32()
262 : {
263 32 : return readNextToken().toInt32();
264 : }
265 :
266 35 : void Parser::readInt64( sal_Int64& o_Value )
267 : {
268 35 : o_Value = readNextToken().toInt64();
269 35 : }
270 :
271 4045 : void Parser::readDouble( double& o_Value )
272 : {
273 4045 : o_Value = readNextToken().toDouble();
274 4045 : }
275 :
276 47 : double Parser::readDouble()
277 : {
278 47 : return readNextToken().toDouble();
279 : }
280 :
281 15 : void Parser::readBinaryData( uno::Sequence<sal_Int8>& rBuf )
282 : {
283 15 : sal_Int32 nFileLen( rBuf.getLength() );
284 15 : sal_Int8* pBuf( rBuf.getArray() );
285 15 : sal_uInt64 nBytesRead(0);
286 15 : oslFileError nRes=osl_File_E_None;
287 60 : while( nFileLen &&
288 15 : osl_File_E_None == (nRes=osl_readFile( m_pErr, pBuf, nFileLen, &nBytesRead )) )
289 : {
290 15 : pBuf += nBytesRead;
291 15 : nFileLen -= sal::static_int_cast<sal_Int32>(nBytesRead);
292 : }
293 :
294 : OSL_PRECOND(nRes==osl_File_E_None, "inconsistent data");
295 15 : }
296 :
297 18 : uno::Reference<rendering::XPolyPolygon2D> Parser::readPath()
298 : {
299 18 : const OString aSubPathMarker( "subpath" );
300 :
301 18 : if( readNextToken() != aSubPathMarker )
302 : OSL_PRECOND(false, "broken path");
303 :
304 36 : basegfx::B2DPolyPolygon aResult;
305 54 : while( m_nCharIndex != -1 )
306 : {
307 18 : basegfx::B2DPolygon aSubPath;
308 :
309 : sal_Int32 nClosedFlag;
310 18 : readInt32( nClosedFlag );
311 18 : aSubPath.setClosed( nClosedFlag != 0 );
312 :
313 18 : sal_Int32 nContiguousControlPoints(0);
314 18 : sal_Int32 nDummy=m_nCharIndex;
315 36 : OString aCurrToken( m_aLine.getToken(m_nNextToken,' ',nDummy) );
316 :
317 132 : while( m_nCharIndex != -1 && aCurrToken != aSubPathMarker )
318 : {
319 : sal_Int32 nCurveFlag;
320 : double nX, nY;
321 96 : readDouble( nX );
322 96 : readDouble( nY );
323 96 : readInt32( nCurveFlag );
324 :
325 96 : aSubPath.append(basegfx::B2DPoint(nX,nY));
326 96 : if( nCurveFlag )
327 : {
328 24 : ++nContiguousControlPoints;
329 : }
330 72 : else if( nContiguousControlPoints )
331 : {
332 : OSL_PRECOND(nContiguousControlPoints==2,"broken bezier path");
333 :
334 : // have two control points before us. the current one
335 : // is a normal point - thus, convert previous points
336 : // into bezier segment
337 12 : const sal_uInt32 nPoints( aSubPath.count() );
338 12 : const basegfx::B2DPoint aCtrlA( aSubPath.getB2DPoint(nPoints-3) );
339 24 : const basegfx::B2DPoint aCtrlB( aSubPath.getB2DPoint(nPoints-2) );
340 24 : const basegfx::B2DPoint aEnd( aSubPath.getB2DPoint(nPoints-1) );
341 12 : aSubPath.remove(nPoints-3, 3);
342 12 : aSubPath.appendBezierSegment(aCtrlA, aCtrlB, aEnd);
343 :
344 24 : nContiguousControlPoints=0;
345 : }
346 :
347 : // one token look-ahead (new subpath or more points?
348 96 : nDummy=m_nCharIndex;
349 96 : aCurrToken = m_aLine.getToken(m_nNextToken,' ',nDummy);
350 : }
351 :
352 18 : aResult.append( aSubPath );
353 18 : if( m_nCharIndex != -1 )
354 0 : readNextToken();
355 18 : }
356 :
357 : return static_cast<rendering::XLinePolyPolygon2D*>(
358 36 : new basegfx::unotools::UnoPolyPolygon(aResult));
359 : }
360 :
361 390 : void Parser::readChar()
362 : {
363 : double fontSize;
364 390 : geometry::Matrix2D aUnoMatrix;
365 390 : geometry::RealRectangle2D aRect;
366 :
367 390 : readDouble(aRect.X1);
368 390 : readDouble(aRect.Y1);
369 390 : readDouble(aRect.X2);
370 390 : readDouble(aRect.Y2);
371 390 : readDouble(aUnoMatrix.m00);
372 390 : readDouble(aUnoMatrix.m01);
373 390 : readDouble(aUnoMatrix.m10);
374 390 : readDouble(aUnoMatrix.m11);
375 390 : readDouble(fontSize);
376 :
377 390 : OString aChars;
378 :
379 390 : if (m_nCharIndex != -1)
380 390 : aChars = lcl_unescapeLineFeeds( m_aLine.copy( m_nCharIndex ) );
381 :
382 : // chars gobble up rest of line
383 390 : m_nCharIndex = -1;
384 :
385 390 : m_pSink->drawGlyphs(OStringToOUString(aChars, RTL_TEXTENCODING_UTF8),
386 390 : aRect, aUnoMatrix, fontSize);
387 390 : }
388 :
389 10 : void Parser::readLineCap()
390 : {
391 10 : sal_Int8 nCap(rendering::PathCapType::BUTT);
392 10 : switch( readInt32() )
393 : {
394 : default:
395 : // FALLTHROUGH intended
396 10 : case 0: nCap = rendering::PathCapType::BUTT; break;
397 0 : case 1: nCap = rendering::PathCapType::ROUND; break;
398 0 : case 2: nCap = rendering::PathCapType::SQUARE; break;
399 : }
400 10 : m_pSink->setLineCap(nCap);
401 10 : }
402 :
403 7 : void Parser::readLineDash()
404 : {
405 7 : if( m_nCharIndex == -1 )
406 : {
407 4 : m_pSink->setLineDash( uno::Sequence<double>(), 0.0 );
408 11 : return;
409 : }
410 :
411 3 : const double nOffset(readDouble());
412 3 : const sal_Int32 nLen(readInt32());
413 :
414 3 : uno::Sequence<double> aDashArray(nLen);
415 3 : double* pArray=aDashArray.getArray();
416 15 : for( sal_Int32 i=0; i<nLen; ++i )
417 12 : *pArray++ = readDouble();
418 :
419 3 : m_pSink->setLineDash( aDashArray, nOffset );
420 : }
421 :
422 10 : void Parser::readLineJoin()
423 : {
424 10 : sal_Int8 nJoin(rendering::PathJoinType::MITER);
425 10 : switch( readInt32() )
426 : {
427 : default:
428 : // FALLTHROUGH intended
429 4 : case 0: nJoin = rendering::PathJoinType::MITER; break;
430 6 : case 1: nJoin = rendering::PathJoinType::ROUND; break;
431 0 : case 2: nJoin = rendering::PathJoinType::BEVEL; break;
432 : }
433 10 : m_pSink->setLineJoin(nJoin);
434 10 : }
435 :
436 10 : void Parser::readTransformation()
437 : {
438 10 : geometry::AffineMatrix2D aMat;
439 10 : readDouble(aMat.m00);
440 10 : readDouble(aMat.m10);
441 10 : readDouble(aMat.m01);
442 10 : readDouble(aMat.m11);
443 10 : readDouble(aMat.m02);
444 10 : readDouble(aMat.m12);
445 10 : m_pSink->setTransformation( aMat );
446 10 : }
447 :
448 59 : rendering::ARGBColor Parser::readColor()
449 : {
450 59 : rendering::ARGBColor aRes;
451 59 : readDouble(aRes.Red);
452 59 : readDouble(aRes.Green);
453 59 : readDouble(aRes.Blue);
454 59 : readDouble(aRes.Alpha);
455 59 : return aRes;
456 : }
457 :
458 840 : 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)
462 : {
463 840 : if (nCopyLen < nAttribLen)
464 471 : return 0;
465 378 : for (sal_Int32 i = 0; i < nAttribLen; ++i)
466 378 : if (tolower(pCopy[i]) != pAttrib[i]
467 378 : && toupper(pCopy[i]) != pAttrib[i])
468 369 : return 0;
469 0 : rResult.isItalic |= bItalic;
470 0 : rResult.isBold |= bBold;
471 0 : return nAttribLen;
472 : }
473 :
474 210 : sal_Int32 Parser::parseFontRemoveSuffix(
475 : const sal_Unicode* pCopy, sal_Int32 nCopyLen,
476 : const char* pAttrib, sal_Int32 nAttribLen)
477 : {
478 210 : if (nCopyLen < nAttribLen)
479 44 : return 0;
480 166 : for (sal_Int32 i = 0; i < nAttribLen; ++i)
481 166 : if ( pCopy[nCopyLen - nAttribLen + i] != pAttrib[i] )
482 166 : return 0;
483 0 : return nAttribLen;
484 : }
485 :
486 11 : void Parser::parseFontFamilyName( FontAttributes& rResult )
487 : {
488 11 : OUStringBuffer aNewFamilyName( rResult.familyName.getLength() );
489 :
490 11 : const sal_Unicode* pCopy = rResult.familyName.getStr();
491 11 : sal_Int32 nLen = rResult.familyName.getLength();
492 : // parse out truetype subsets (e.g. BAAAAA+Thorndale)
493 11 : if( nLen > 8 && pCopy[6] == '+' )
494 : {
495 11 : pCopy += 7;
496 11 : nLen -= 7;
497 : }
498 :
499 : // TODO: Looks like this block needs to be refactored
500 127 : while( nLen )
501 : {
502 105 : if (parseFontRemoveSuffix(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("PSMT")))
503 : {
504 0 : nLen -= RTL_CONSTASCII_LENGTH("PSMT");
505 : }
506 105 : else if (parseFontRemoveSuffix(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("MT")))
507 : {
508 0 : nLen -= RTL_CONSTASCII_LENGTH("MT");
509 : }
510 :
511 105 : if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("Italic"), rResult, true, false))
512 : {
513 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("Italic");
514 0 : nLen -= nAttribLen;
515 0 : pCopy += nAttribLen;
516 : }
517 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("-Bold"), rResult, false, true))
518 : {
519 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("-Bold");
520 0 : nLen -= nAttribLen;
521 0 : pCopy += nAttribLen;
522 : }
523 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("Bold"), rResult, false, true))
524 : {
525 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("Bold");
526 0 : nLen -= nAttribLen;
527 0 : pCopy += nAttribLen;
528 : }
529 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("-Roman"), rResult, false, false))
530 : {
531 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("-Roman");
532 0 : nLen -= nAttribLen;
533 0 : pCopy += nAttribLen;
534 : }
535 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("-LightOblique"), rResult, true, false))
536 : {
537 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("-LightOblique");
538 0 : nLen -= nAttribLen;
539 0 : pCopy += nAttribLen;
540 : }
541 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("-BoldOblique"), rResult, true, true))
542 : {
543 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("-BoldOblique");
544 0 : nLen -= nAttribLen;
545 0 : pCopy += nAttribLen;
546 : }
547 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("-Light"), rResult, false, false))
548 : {
549 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("-Light");
550 0 : nLen -= nAttribLen;
551 0 : pCopy += nAttribLen;
552 : }
553 105 : else if (parseFontCheckForString(pCopy, nLen, RTL_CONSTASCII_STRINGPARAM("-Reg"), rResult, false, false))
554 : {
555 0 : sal_Int32 nAttribLen = RTL_CONSTASCII_LENGTH("-Reg");
556 0 : nLen -= nAttribLen;
557 0 : pCopy += nAttribLen;
558 : }
559 105 : else if(nLen > 0)
560 : {
561 105 : if( *pCopy != '-' )
562 105 : aNewFamilyName.append( *pCopy );
563 105 : pCopy++;
564 105 : nLen--;
565 : }
566 : }
567 11 : rResult.familyName = aNewFamilyName.makeStringAndClear();
568 11 : }
569 :
570 35 : void Parser::readFont()
571 : {
572 35 : OString aFontName;
573 : sal_Int64 nFontID;
574 : sal_Int32 nIsEmbedded, nIsBold, nIsItalic, nIsUnderline, nFileLen;
575 : double nSize;
576 :
577 35 : readInt64(nFontID);
578 35 : readInt32(nIsEmbedded);
579 35 : readInt32(nIsBold);
580 35 : readInt32(nIsItalic);
581 35 : readInt32(nIsUnderline);
582 35 : readDouble(nSize);
583 35 : readInt32(nFileLen);
584 :
585 35 : nSize = nSize < 0.0 ? -nSize : nSize;
586 35 : aFontName = lcl_unescapeLineFeeds( m_aLine.copy( m_nCharIndex ) );
587 :
588 : // name gobbles up rest of line
589 35 : m_nCharIndex = -1;
590 :
591 35 : FontMapType::const_iterator pFont( m_aFontMap.find(nFontID) );
592 35 : if( pFont != m_aFontMap.end() )
593 : {
594 : OSL_PRECOND(nFileLen==0,"font data for known font");
595 24 : FontAttributes aRes(pFont->second);
596 24 : aRes.size = nSize;
597 24 : m_pSink->setFont( aRes );
598 :
599 59 : return;
600 : }
601 :
602 : // yet unknown font - get info and add to map
603 : FontAttributes aResult( OStringToOUString( aFontName,
604 : RTL_TEXTENCODING_UTF8 ),
605 : nIsBold != 0,
606 : nIsItalic != 0,
607 : nIsUnderline != 0,
608 : false,
609 : nSize,
610 22 : 1.0);
611 :
612 : // extract textual attributes (bold, italic in the name, etc.)
613 11 : parseFontFamilyName(aResult);
614 : // need to read font file?
615 11 : if( nFileLen )
616 : {
617 11 : uno::Sequence<sal_Int8> aFontFile(nFileLen);
618 11 : readBinaryData( aFontFile );
619 :
620 22 : awt::FontDescriptor aFD;
621 22 : uno::Sequence< uno::Any > aArgs(1);
622 11 : aArgs[0] <<= aFontFile;
623 :
624 : try
625 : {
626 : uno::Reference< beans::XMaterialHolder > xMat(
627 22 : m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
628 : OUString( "com.sun.star.awt.FontIdentificator" ),
629 : aArgs,
630 11 : m_xContext ),
631 11 : uno::UNO_QUERY );
632 11 : if( xMat.is() )
633 : {
634 0 : uno::Any aRes( xMat->getMaterial() );
635 0 : if( aRes >>= aFD )
636 : {
637 0 : if (!aFD.Name.isEmpty())
638 : {
639 0 : aResult.familyName = aFD.Name;
640 0 : parseFontFamilyName(aResult);
641 : }
642 0 : aResult.isBold = (aFD.Weight > 100.0);
643 0 : aResult.isItalic = (aFD.Slant == awt::FontSlant_OBLIQUE ||
644 0 : aFD.Slant == awt::FontSlant_ITALIC );
645 0 : aResult.isUnderline = false;
646 0 : aResult.size = 0;
647 0 : }
648 11 : }
649 : }
650 0 : catch( uno::Exception& )
651 : {
652 : }
653 :
654 11 : if( aResult.familyName.isEmpty() )
655 : {
656 : // last fallback
657 0 : aResult.familyName = "Arial";
658 0 : aResult.isUnderline = false;
659 11 : }
660 :
661 : }
662 :
663 11 : static VclPtr<VirtualDevice> vDev;
664 11 : if (!vDev)
665 2 : vDev = VclPtr<VirtualDevice>::Create();
666 :
667 22 : vcl::Font font(aResult.familyName, Size(0, 1000));
668 11 : vDev->SetFont(font);
669 22 : FontMetric metric(vDev->GetFontMetric());
670 11 : aResult.ascent = metric.GetAscent() / 1000.0;
671 :
672 11 : m_aFontMap[nFontID] = aResult;
673 :
674 11 : aResult.size = nSize;
675 22 : m_pSink->setFont(aResult);
676 : }
677 :
678 4 : uno::Sequence<beans::PropertyValue> Parser::readImageImpl()
679 : {
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";
688 :
689 4 : OString aToken = readNextToken();
690 4 : const sal_Int32 nImageSize( readInt32() );
691 :
692 8 : OUString aFileName;
693 4 : if( aToken == aPngMarker )
694 1 : aFileName = aPngFile;
695 3 : else if( aToken == aJpegMarker )
696 3 : aFileName = aJpegFile;
697 0 : else if( aToken == aPbmMarker )
698 0 : aFileName = aPbmFile;
699 : else
700 : {
701 : SAL_WARN_IF(aToken != aPpmMarker,"sdext.pdfimport","Invalid bitmap format");
702 0 : aFileName = aPpmFile;
703 : }
704 :
705 8 : uno::Sequence<sal_Int8> aDataSequence(nImageSize);
706 4 : readBinaryData( aDataSequence );
707 :
708 8 : uno::Sequence< uno::Any > aStreamCreationArgs(1);
709 4 : aStreamCreationArgs[0] <<= aDataSequence;
710 :
711 8 : uno::Reference< uno::XComponentContext > xContext( m_xContext, uno::UNO_SET_THROW );
712 8 : uno::Reference< lang::XMultiComponentFactory > xFactory( xContext->getServiceManager(), uno::UNO_SET_THROW );
713 4 : uno::Reference< io::XInputStream > xDataStream( xFactory->createInstanceWithArgumentsAndContext(
714 : OUString( "com.sun.star.io.SequenceInputStream" ),
715 8 : aStreamCreationArgs, m_xContext ), uno::UNO_QUERY_THROW );
716 :
717 4 : uno::Sequence<beans::PropertyValue> aSequence(3);
718 8 : aSequence[0] = beans::PropertyValue( OUString("URL"),
719 : 0,
720 : uno::makeAny(aFileName),
721 4 : beans::PropertyState_DIRECT_VALUE );
722 8 : aSequence[1] = beans::PropertyValue( OUString("InputStream"),
723 : 0,
724 : uno::makeAny( xDataStream ),
725 4 : beans::PropertyState_DIRECT_VALUE );
726 8 : aSequence[2] = beans::PropertyValue( OUString("InputSequence"),
727 : 0,
728 : uno::makeAny(aDataSequence),
729 4 : beans::PropertyState_DIRECT_VALUE );
730 :
731 8 : return aSequence;
732 : }
733 :
734 4 : void Parser::readImage()
735 : {
736 : sal_Int32 nWidth, nHeight,nMaskColors;
737 4 : readInt32(nWidth);
738 4 : readInt32(nHeight);
739 4 : readInt32(nMaskColors);
740 :
741 4 : uno::Sequence<beans::PropertyValue> aImg( readImageImpl() );
742 :
743 4 : if( nMaskColors )
744 : {
745 0 : uno::Sequence<sal_Int8> aDataSequence(nMaskColors);
746 0 : readBinaryData( aDataSequence );
747 :
748 0 : uno::Sequence<uno::Any> aMaskRanges(2);
749 :
750 0 : uno::Sequence<double> aMinRange(nMaskColors/2);
751 0 : uno::Sequence<double> aMaxRange(nMaskColors/2);
752 0 : for( sal_Int32 i=0; i<nMaskColors/2; ++i )
753 : {
754 0 : aMinRange[i] = aDataSequence[i] / 255.0;
755 0 : aMaxRange[i] = aDataSequence[i+nMaskColors/2] / 255.0;
756 : }
757 :
758 0 : aMaskRanges[0] = uno::makeAny(aMinRange);
759 0 : aMaskRanges[1] = uno::makeAny(aMaxRange);
760 :
761 0 : m_pSink->drawColorMaskedImage( aImg, aMaskRanges );
762 : }
763 : else
764 4 : m_pSink->drawImage( aImg );
765 4 : }
766 :
767 0 : void Parser::readMask()
768 : {
769 : sal_Int32 nWidth, nHeight, nInvert;
770 0 : readInt32(nWidth);
771 0 : readInt32(nHeight);
772 0 : readInt32(nInvert);
773 :
774 0 : m_pSink->drawMask( readImageImpl(), nInvert );
775 0 : }
776 :
777 3 : void Parser::readLink()
778 : {
779 3 : geometry::RealRectangle2D aBounds;
780 3 : readDouble(aBounds.X1);
781 3 : readDouble(aBounds.Y1);
782 3 : readDouble(aBounds.X2);
783 3 : readDouble(aBounds.Y2);
784 :
785 3 : m_pSink->hyperLink( aBounds,
786 : OStringToOUString( lcl_unescapeLineFeeds(
787 : m_aLine.copy(m_nCharIndex) ),
788 3 : RTL_TEXTENCODING_UTF8 ) );
789 : // name gobbles up rest of line
790 3 : m_nCharIndex = -1;
791 3 : }
792 :
793 0 : void Parser::readMaskedImage()
794 : {
795 : sal_Int32 nWidth, nHeight, nMaskWidth, nMaskHeight, nMaskInvert;
796 0 : readInt32(nWidth);
797 0 : readInt32(nHeight);
798 0 : readInt32(nMaskWidth);
799 0 : readInt32(nMaskHeight);
800 0 : readInt32(nMaskInvert);
801 :
802 0 : const uno::Sequence<beans::PropertyValue> aImage( readImageImpl() );
803 0 : const uno::Sequence<beans::PropertyValue> aMask ( readImageImpl() );
804 0 : m_pSink->drawMaskedImage( aImage, aMask, nMaskInvert != 0 );
805 0 : }
806 :
807 0 : void Parser::readSoftMaskedImage()
808 : {
809 : sal_Int32 nWidth, nHeight, nMaskWidth, nMaskHeight;
810 0 : readInt32(nWidth);
811 0 : readInt32(nHeight);
812 0 : readInt32(nMaskWidth);
813 0 : readInt32(nMaskHeight);
814 :
815 0 : const uno::Sequence<beans::PropertyValue> aImage( readImageImpl() );
816 0 : const uno::Sequence<beans::PropertyValue> aMask ( readImageImpl() );
817 0 : m_pSink->drawAlphaMaskedImage( aImage, aMask );
818 0 : }
819 :
820 734 : void Parser::parseLine( const OString& rLine )
821 : {
822 : OSL_PRECOND( m_pSink, "Invalid sink" );
823 : OSL_PRECOND( m_pErr, "Invalid filehandle" );
824 : OSL_PRECOND( m_xContext.is(), "Invalid service factory" );
825 :
826 734 : m_nNextToken = 0; m_nCharIndex = 0; m_aLine = rLine;
827 734 : uno::Reference<rendering::XPolyPolygon2D> xPoly;
828 1468 : const OString& rCmd = readNextToken();
829 : const hash_entry* pEntry = PdfKeywordHash::in_word_set( rCmd.getStr(),
830 734 : rCmd.getLength() );
831 : OSL_ASSERT(pEntry);
832 734 : switch( pEntry->eKey )
833 : {
834 : case CLIPPATH:
835 4 : m_pSink->intersectClip(readPath()); break;
836 : case DRAWCHAR:
837 390 : readChar(); break;
838 : case DRAWIMAGE:
839 4 : readImage(); break;
840 : case DRAWLINK:
841 3 : readLink(); break;
842 : case DRAWMASK:
843 0 : readMask(); break;
844 : case DRAWMASKEDIMAGE:
845 0 : readMaskedImage(); break;
846 : case DRAWSOFTMASKEDIMAGE:
847 0 : readSoftMaskedImage(); break;
848 : case ENDPAGE:
849 5 : m_pSink->endPage(); break;
850 : case ENDTEXTOBJECT:
851 35 : m_pSink->endText(); break;
852 : case EOCLIPPATH:
853 5 : m_pSink->intersectEoClip(readPath()); break;
854 : case EOFILLPATH:
855 3 : m_pSink->eoFillPath(readPath()); break;
856 : case FILLPATH:
857 0 : m_pSink->fillPath(readPath()); break;
858 : case RESTORESTATE:
859 58 : m_pSink->popState(); break;
860 : case SAVESTATE:
861 58 : m_pSink->pushState(); break;
862 : case SETPAGENUM:
863 5 : m_pSink->setPageNum( readInt32() ); break;
864 : case STARTPAGE:
865 : {
866 5 : const double nWidth ( readDouble() );
867 5 : const double nHeight( readDouble() );
868 5 : m_pSink->startPage( geometry::RealSize2D( nWidth, nHeight ) );
869 5 : break;
870 : }
871 : case STROKEPATH:
872 6 : m_pSink->strokePath(readPath()); break;
873 : case UPDATECTM:
874 10 : readTransformation(); break;
875 : case UPDATEFILLCOLOR:
876 45 : m_pSink->setFillColor( readColor() ); break;
877 : case UPDATEFLATNESS:
878 4 : m_pSink->setFlatness( readDouble( ) ); break;
879 : case UPDATEFONT:
880 35 : readFont(); break;
881 : case UPDATELINECAP:
882 10 : readLineCap(); break;
883 : case UPDATELINEDASH:
884 7 : readLineDash(); break;
885 : case UPDATELINEJOIN:
886 10 : readLineJoin(); break;
887 : case UPDATELINEWIDTH:
888 14 : m_pSink->setLineWidth( readDouble() );break;
889 : case UPDATEMITERLIMIT:
890 4 : m_pSink->setMiterLimit( readDouble() ); break;
891 : case UPDATESTROKECOLOR:
892 14 : m_pSink->setStrokeColor( readColor() ); break;
893 : case UPDATESTROKEOPACITY:
894 0 : break;
895 : case SETTEXTRENDERMODE:
896 0 : m_pSink->setTextRenderMode( readInt32() ); break;
897 :
898 : case NONE:
899 : default:
900 : OSL_PRECOND(false,"Unknown input");
901 0 : break;
902 : }
903 :
904 : // all consumed?
905 734 : SAL_WARN_IF(m_nCharIndex!=-1, "sdext.pdfimport", "leftover scanner input");
906 734 : }
907 :
908 739 : oslFileError readLine( oslFileHandle pFile, OStringBuffer& line )
909 : {
910 : OSL_PRECOND( line.isEmpty(), "line buf not empty" );
911 :
912 : // TODO(P3): read larger chunks
913 739 : sal_Char aChar('\n');
914 : sal_uInt64 nBytesRead;
915 : oslFileError nRes;
916 :
917 : // skip garbage \r \n at start of line
918 2217 : while( osl_File_E_None == (nRes=osl_readFile(pFile, &aChar, 1, &nBytesRead)) &&
919 1473 : nBytesRead == 1 &&
920 1468 : (aChar == '\n' || aChar == '\r') ) ;
921 :
922 739 : if( aChar != '\n' && aChar != '\r' )
923 734 : line.append( aChar );
924 :
925 101369 : while( osl_File_E_None == (nRes=osl_readFile(pFile, &aChar, 1, &nBytesRead)) &&
926 100625 : nBytesRead == 1 && aChar != '\n' && aChar != '\r' )
927 : {
928 49576 : line.append( aChar );
929 : }
930 :
931 739 : return nRes;
932 : }
933 :
934 : } // namespace
935 :
936 5 : static bool checkEncryption( const OUString& i_rPath,
937 : const uno::Reference< task::XInteractionHandler >& i_xIHdl,
938 : OUString& io_rPwd,
939 : bool& o_rIsEncrypted,
940 : const OUString& i_rDocName
941 : )
942 : {
943 5 : bool bSuccess = false;
944 5 : OString aPDFFile;
945 5 : aPDFFile = OUStringToOString( i_rPath, osl_getThreadTextEncoding() );
946 :
947 10 : pdfparse::PDFReader aParser;
948 10 : boost::scoped_ptr<pdfparse::PDFEntry> pEntry( pdfparse::PDFReader::read( aPDFFile.getStr() ));
949 5 : if( pEntry )
950 : {
951 5 : pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get());
952 5 : if( pPDFFile )
953 : {
954 5 : o_rIsEncrypted = pPDFFile->isEncrypted();
955 5 : if( o_rIsEncrypted )
956 : {
957 0 : if( pPDFFile->usesSupportedEncryptionFormat() )
958 : {
959 0 : bool bAuthenticated = false;
960 0 : if( !io_rPwd.isEmpty() )
961 : {
962 : OString aIsoPwd = OUStringToOString( io_rPwd,
963 0 : RTL_TEXTENCODING_ISO_8859_1 );
964 0 : bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
965 : }
966 0 : if( bAuthenticated )
967 0 : bSuccess = true;
968 : else
969 : {
970 0 : if( i_xIHdl.is() )
971 : {
972 0 : bool bEntered = false;
973 0 : do
974 : {
975 0 : bEntered = getPassword( i_xIHdl, io_rPwd, ! bEntered, i_rDocName );
976 : OString aIsoPwd = OUStringToOString( io_rPwd,
977 0 : RTL_TEXTENCODING_ISO_8859_1 );
978 0 : bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
979 0 : } while( bEntered && ! bAuthenticated );
980 : }
981 :
982 : OSL_TRACE( "password: %s", bAuthenticated ? "matches" : "does not match" );
983 0 : bSuccess = bAuthenticated;
984 : }
985 0 : if( bAuthenticated )
986 : {
987 0 : OUStringBuffer aBuf( 128 );
988 0 : aBuf.appendAscii( "_OOO_pdfi_Credentials_" );
989 0 : aBuf.append( pPDFFile->getDecryptionKey() );
990 0 : io_rPwd = aBuf.makeStringAndClear();
991 : }
992 : }
993 0 : else if( i_xIHdl.is() )
994 : {
995 0 : 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
1001 : }
1002 : }
1003 : else
1004 5 : bSuccess = true;
1005 : }
1006 : }
1007 10 : return bSuccess;
1008 : }
1009 :
1010 5 : 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 )
1016 : {
1017 : OSL_ASSERT(rSink);
1018 :
1019 5 : OUString aSysUPath;
1020 5 : if( osl_getSystemPathFromFileURL( rURL.pData, &aSysUPath.pData ) != osl_File_E_None )
1021 : {
1022 : SAL_WARN(
1023 : "sdext.pdfimport",
1024 : "getSystemPathFromFileURL(" << rURL << ") failed");
1025 0 : return false;
1026 : }
1027 10 : OUString aDocName( rURL.copy( rURL.lastIndexOf( '/' )+1 ) );
1028 :
1029 : // check for encryption, if necessary get password
1030 10 : OUString aPwd( rPwd );
1031 5 : bool bIsEncrypted = false;
1032 5 : if( !checkEncryption( aSysUPath, xIHdl, aPwd, bIsEncrypted, aDocName ) )
1033 : {
1034 : SAL_INFO(
1035 : "sdext.pdfimport",
1036 : "checkEncryption(" << aSysUPath << ") failed");
1037 0 : return false;
1038 : }
1039 :
1040 : // Determine xpdfimport executable URL:
1041 10 : OUString converterURL("$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/xpdfimport");
1042 5 : rtl::Bootstrap::expandMacros(converterURL); //TODO: detect failure
1043 :
1044 : // Determine pathname of xpdfimport_err.pdf:
1045 10 : OUString errPathname("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/xpdfimport/xpdfimport_err.pdf");
1046 5 : rtl::Bootstrap::expandMacros(errPathname); //TODO: detect failure
1047 5 : if (osl::FileBase::getSystemPathFromFileURL(errPathname, errPathname)
1048 : != osl::FileBase::E_None)
1049 : {
1050 : SAL_WARN(
1051 : "sdext.pdfimport",
1052 : "getSystemPathFromFileURL(" << errPathname << ") failed");
1053 0 : return false;
1054 : }
1055 :
1056 : // spawn separate process to keep LGPL/GPL code apart.
1057 :
1058 10 : OUString aOptFlag("-o");
1059 : rtl_uString* args[] = { aSysUPath.pData, errPathname.pData,
1060 5 : aOptFlag.pData, rFilterOptions.pData };
1061 5 : sal_Int32 nArgs = rFilterOptions.isEmpty() ? 2 : 4;
1062 :
1063 : oslProcess aProcess;
1064 5 : oslFileHandle pIn = NULL;
1065 5 : oslFileHandle pOut = NULL;
1066 5 : oslFileHandle pErr = NULL;
1067 5 : oslSecurity pSecurity = osl_getCurrentSecurity ();
1068 : oslProcessError eErr =
1069 : osl_executeProcess_WithRedirectedIO(converterURL.pData,
1070 : args,
1071 : nArgs,
1072 : osl_Process_SEARCHPATH|osl_Process_HIDDEN,
1073 : pSecurity,
1074 : 0, 0, 0,
1075 5 : &aProcess, &pIn, &pOut, &pErr);
1076 5 : osl_freeSecurityHandle(pSecurity);
1077 :
1078 5 : bool bRet=true;
1079 : try
1080 : {
1081 5 : if( eErr!=osl_Process_E_None )
1082 : {
1083 : SAL_WARN(
1084 : "sdext.pdfimport",
1085 : "executeProcess of " << converterURL << " failed with "
1086 : << +eErr);
1087 0 : return false;
1088 : }
1089 :
1090 5 : if( pIn )
1091 : {
1092 5 : OStringBuffer aBuf(256);
1093 5 : if( bIsEncrypted )
1094 0 : aBuf.append( OUStringToOString( aPwd, RTL_TEXTENCODING_ISO_8859_1 ) );
1095 5 : aBuf.append( '\n' );
1096 :
1097 5 : sal_uInt64 nWritten = 0;
1098 5 : osl_writeFile( pIn, aBuf.getStr(), sal_uInt64(aBuf.getLength()), &nWritten );
1099 : }
1100 :
1101 5 : if( pOut && pErr )
1102 : {
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 5 : Parser aParser(rSink,pErr,xContext);
1107 10 : OStringBuffer line;
1108 744 : while( osl_File_E_None == readLine(pOut, line) && !line.isEmpty() )
1109 739 : aParser.parseLine(line.makeStringAndClear());
1110 : }
1111 : }
1112 0 : catch( uno::Exception& )
1113 : {
1114 : // crappy C file interface. need manual resource dealloc
1115 0 : bRet = false;
1116 : }
1117 :
1118 5 : if( pIn )
1119 5 : osl_closeFile(pIn);
1120 5 : if( pOut )
1121 5 : osl_closeFile(pOut);
1122 5 : if( pErr )
1123 5 : osl_closeFile(pErr);
1124 5 : eErr = osl_joinProcess(aProcess);
1125 5 : if (eErr == osl_Process_E_None)
1126 : {
1127 : oslProcessInfo info;
1128 5 : info.Size = sizeof info;
1129 5 : eErr = osl_getProcessInfo(aProcess, osl_Process_EXITCODE, &info);
1130 5 : if (eErr == osl_Process_E_None)
1131 : {
1132 5 : if (info.Code != 0)
1133 : {
1134 : SAL_WARN(
1135 : "sdext.pdfimport",
1136 : "getProcessInfo of " << converterURL
1137 : << " failed with exit code " << info.Code);
1138 0 : bRet = false;
1139 : }
1140 : }
1141 : else
1142 : {
1143 : SAL_WARN(
1144 : "sdext.pdfimport",
1145 : "getProcessInfo of " << converterURL << " failed with "
1146 : << +eErr);
1147 0 : bRet = false;
1148 : }
1149 : }
1150 : else
1151 : {
1152 : SAL_WARN(
1153 : "sdext.pdfimport",
1154 : "joinProcess of " << converterURL << " failed with " << +eErr);
1155 0 : bRet = false;
1156 : }
1157 5 : osl_freeProcessHandle(aProcess);
1158 10 : return bRet;
1159 : }
1160 :
1161 :
1162 2 : 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 )
1168 : {
1169 : OSL_ASSERT(xInput.is());
1170 : OSL_ASSERT(rSink);
1171 :
1172 : // convert XInputStream to local temp file
1173 2 : oslFileHandle aFile = NULL;
1174 2 : OUString aURL;
1175 2 : if( osl_createTempFile( NULL, &aFile, &aURL.pData ) != osl_File_E_None )
1176 0 : return false;
1177 :
1178 : // copy content, buffered...
1179 2 : const sal_uInt32 nBufSize = 4096;
1180 4 : uno::Sequence<sal_Int8> aBuf( nBufSize );
1181 2 : sal_uInt64 nBytes = 0;
1182 2 : sal_uInt64 nWritten = 0;
1183 2 : bool bSuccess = true;
1184 12 : do
1185 : {
1186 : try
1187 : {
1188 12 : nBytes = xInput->readBytes( aBuf, nBufSize );
1189 : }
1190 0 : catch( com::sun::star::uno::Exception& )
1191 : {
1192 0 : osl_closeFile( aFile );
1193 0 : throw;
1194 : }
1195 12 : if( nBytes > 0 )
1196 : {
1197 12 : osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
1198 12 : if( nWritten != nBytes )
1199 : {
1200 0 : bSuccess = false;
1201 0 : break;
1202 : }
1203 : }
1204 : }
1205 : while( nBytes == nBufSize );
1206 :
1207 2 : osl_closeFile( aFile );
1208 :
1209 2 : if ( bSuccess )
1210 2 : bSuccess = xpdf_ImportFromFile( aURL, rSink, xIHdl, rPwd, xContext, rFilterOptions );
1211 2 : osl_removeFile( aURL.pData );
1212 :
1213 4 : return bSuccess;
1214 : }
1215 :
1216 : }
1217 :
1218 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|