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