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