1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: printerjob.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
35 #include <sys/types.h>
41 #include "psputil.hxx"
42 #include "glyphset.hxx"
44 #include "vcl/printerjob.hxx"
45 #include "vcl/ppdparser.hxx"
46 #include "vcl/strhelper.hxx"
47 #include "vcl/printerinfomanager.hxx"
48 #include "vcl/printergfx.hxx"
50 #include "rtl/ustring.hxx"
51 #include "rtl/strbuf.hxx"
52 #include "rtl/ustrbuf.hxx"
54 #include "osl/thread.h"
55 #include "sal/alloca.h"
63 // forward declaration
65 #define nBLOCKSIZE 0x2000
71 AppendPS (FILE* pDst
, osl::File
* pSrc
, sal_uChar
* pBuffer
,
72 sal_uInt32 nBlockSize
= nBLOCKSIZE
)
74 if ((pDst
== NULL
) || (pSrc
== NULL
))
78 nBlockSize
= nBLOCKSIZE
;
80 pBuffer
= (sal_uChar
*)alloca (nBlockSize
);
82 pSrc
->setPos (osl_Pos_Absolut
, 0);
88 pSrc
->read (pBuffer
, nBlockSize
, nIn
);
90 nOut
= fwrite (pBuffer
, 1, sal::static_int_cast
<sal_uInt32
>(nIn
), pDst
);
92 while ((nIn
> 0) && (nIn
== nOut
));
100 * private convenience routines for file handling
104 PrinterJob::CreateSpoolFile (const rtl::OUString
& rName
, const rtl::OUString
& rExtension
)
106 osl::File::RC nError
= osl::File::E_None
;
107 osl::File
* pFile
= NULL
;
109 rtl::OUString aFile
= rName
+ rExtension
;
110 rtl::OUString aFileURL
;
111 nError
= osl::File::getFileURLFromSystemPath( aFile
, aFileURL
);
112 if (nError
!= osl::File::E_None
)
114 aFileURL
= maSpoolDirName
+ rtl::OUString::createFromAscii ("/") + aFileURL
;
116 pFile
= new osl::File (aFileURL
);
117 nError
= pFile
->open (OpenFlag_Read
| OpenFlag_Write
| OpenFlag_Create
);
118 if (nError
!= osl::File::E_None
)
124 pFile
->setAttributes (aFileURL
,
125 osl_File_Attribute_OwnWrite
| osl_File_Attribute_OwnRead
);
130 * public methods of PrinterJob: for use in PrinterGfx
134 PrinterJob::GetScale (double &rXScale
, double &rYScale
) const
141 PrinterJob::GetDepth () const
143 sal_Int32 nLevel
= GetPostscriptLevel();
144 sal_Bool bColor
= IsColorPrinter ();
146 return nLevel
> 1 && bColor
? 24 : 8;
150 PrinterJob::GetPostscriptLevel (const JobData
*pJobData
) const
152 sal_uInt16 nPSLevel
= 2;
154 if( pJobData
== NULL
)
155 pJobData
= &m_aLastJobData
;
157 if( pJobData
->m_nPSLevel
)
158 nPSLevel
= pJobData
->m_nPSLevel
;
160 if( pJobData
->m_pParser
)
161 nPSLevel
= pJobData
->m_pParser
->getLanguageLevel();
167 PrinterJob::IsColorPrinter () const
169 sal_Bool bColor
= sal_False
;
171 if( m_aLastJobData
.m_nColorDevice
)
172 bColor
= m_aLastJobData
.m_nColorDevice
== -1 ? sal_False
: sal_True
;
173 else if( m_aLastJobData
.m_pParser
)
174 bColor
= m_aLastJobData
.m_pParser
->isColorDevice() ? sal_True
: sal_False
;
180 PrinterJob::GetDocumentHeader ()
186 PrinterJob::GetDocumentTrailer ()
192 PrinterJob::GetCurrentPageHeader ()
194 return maHeaderList
.back();
198 PrinterJob::GetCurrentPageBody ()
200 return maPageList
.back();
204 * public methods of PrinterJob: the actual job / spool handling
207 PrinterJob::PrinterJob () :
209 mpJobTrailer( NULL
),
217 /* check whether the given name points to a directory which is
218 usable for the user */
220 existsTmpDir (const char* pName
)
222 struct stat aFileStatus
;
226 if (stat(pName
, &aFileStatus
) != 0)
228 if (! S_ISDIR(aFileStatus
.st_mode
))
231 return access(pName
, W_OK
| R_OK
) == 0 ? sal_True
: sal_False
;
234 /* return the username in the given buffer */
236 getUserName (char* pName
, int nSize
)
238 struct passwd
*pPWEntry
;
239 struct passwd aPWEntry
;
240 sal_Char pPWBuffer
[256];
242 sal_Bool bSuccess
= sal_False
;
245 pPWEntry
= getpwuid( getuid());
247 if (getpwuid_r(getuid(), &aPWEntry
, pPWBuffer
, sizeof(pPWBuffer
), &pPWEntry
) != 0)
251 if (pPWEntry
!= NULL
&& pPWEntry
->pw_name
!= NULL
)
253 sal_Int32 nLen
= strlen(pPWEntry
->pw_name
);
254 if (nLen
> 0 && nLen
< nSize
)
256 memcpy (pName
, pPWEntry
->pw_name
, nLen
);
263 // wipe the passwd off the stack
264 memset (pPWBuffer
, 0, sizeof(pPWBuffer
));
269 /* remove all our temporary files, uses external program "rm", since
270 osl functionality is inadequate */
272 removeSpoolDir (const rtl::OUString
& rSpoolDir
)
274 rtl::OUString aSysPath
;
275 if( osl::File::E_None
!= osl::File::getSystemPathFromFileURL( rSpoolDir
, aSysPath
) )
277 // Conversion did not work, as this is quite a dangerous action,
278 // we should abort here ....
279 OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
282 rtl::OString aSysPathByte
=
283 rtl::OUStringToOString (aSysPath
, osl_getThreadTextEncoding());
284 sal_Char pSystem
[128];
287 nChar
= psp::appendStr ("rm -rf ", pSystem
);
288 nChar
+= psp::appendStr (aSysPathByte
.getStr(), pSystem
+ nChar
);
293 /* creates a spool directory with a "pidgin random" value based on
294 current system time */
299 osl_getSystemTime( &aCur
);
300 sal_Int32 nRand
= aCur
.Seconds
^ (aCur
.Nanosec
/1000);
302 rtl::OUString aTmpDir
;
303 osl_getTempDirURL( &aTmpDir
.pData
);
307 rtl::OUStringBuffer
aDir( aTmpDir
.getLength() + 16 );
308 aDir
.append( aTmpDir
);
309 aDir
.appendAscii( "/psp" );
311 rtl::OUString aResult
= aDir
.makeStringAndClear();
312 if( osl::Directory::create( aResult
) == osl::FileBase::E_None
)
314 osl::File::setAttributes( aResult
,
315 osl_File_Attribute_OwnWrite
316 | osl_File_Attribute_OwnRead
317 | osl_File_Attribute_OwnExe
);
322 return rtl::OUString();
327 PrinterJob::~PrinterJob ()
329 std::list
< osl::File
* >::iterator pPage
;
330 for (pPage
= maPageList
.begin(); pPage
!= maPageList
.end(); pPage
++)
332 //(*pPage)->remove();
335 for (pPage
= maHeaderList
.begin(); pPage
!= maHeaderList
.end(); pPage
++)
337 //(*pPage)->remove();
340 // mpJobHeader->remove();
342 // mpJobTrailer->remove();
345 // XXX should really call osl::remove routines
346 removeSpoolDir (maSpoolDirName
);
348 // osl::Directory::remove (maSpoolDirName);
354 // get locale invariant, 7bit clean current local time string
356 getLocalTime(sal_Char
* pBuffer
)
358 time_t nTime
= time (NULL
);
360 struct tm
*pLocalTime
= localtime_r (&nTime
, &aTime
);
362 return asctime_r(pLocalTime
, pBuffer
);
367 static bool isAscii( const rtl::OUString
& rStr
)
369 const sal_Unicode
* pStr
= rStr
;
370 sal_Int32 nLen
= rStr
.getLength();
371 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
378 PrinterJob::StartJob (
379 const rtl::OUString
& rFileName
,
381 const rtl::OUString
& rJobName
,
382 const rtl::OUString
& rAppName
,
383 const JobData
& rSetupData
,
384 PrinterGfx
* pGraphics
,
388 m_bQuickJob
= bIsQuickJob
;
389 mnMaxWidthPt
= mnMaxHeightPt
= 0;
390 mnLandscapes
= mnPortraits
= 0;
391 m_pGraphics
= pGraphics
;
392 InitPaperSize (rSetupData
);
394 // create file container for document header and trailer
395 maFileName
= rFileName
;
397 maSpoolDirName
= createSpoolDir ();
398 maJobTitle
= rJobName
;
400 rtl::OUString aExt
= rtl::OUString::createFromAscii (".ps");
401 mpJobHeader
= CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt
);
402 mpJobTrailer
= CreateSpoolFile (rtl::OUString::createFromAscii("psp_tail"), aExt
);
403 if( ! (mpJobHeader
&& mpJobTrailer
) ) // existing files are removed in destructor
406 // write document header according to Document Structuring Conventions (DSC)
407 WritePS (mpJobHeader
,
409 "%%BoundingBox: (atend)\n" );
411 rtl::OUString aFilterWS
;
413 // Creator (this application)
414 aFilterWS
= WhitespaceToSpace( rAppName
, FALSE
);
415 WritePS (mpJobHeader
, "%%Creator: (");
416 WritePS (mpJobHeader
, aFilterWS
);
417 WritePS (mpJobHeader
, ")\n");
420 sal_Char pUserName
[64];
421 if (getUserName(pUserName
, sizeof(pUserName
)))
423 WritePS (mpJobHeader
, "%%For: (");
424 WritePS (mpJobHeader
, pUserName
);
425 WritePS (mpJobHeader
, ")\n");
428 // Creation Date (locale independent local time)
429 sal_Char pCreationDate
[256];
430 WritePS (mpJobHeader
, "%%CreationDate: (");
431 getLocalTime(pCreationDate
);
432 for( unsigned int i
= 0; i
< sizeof(pCreationDate
)/sizeof(pCreationDate
[0]); i
++ )
434 if( pCreationDate
[i
] == '\n' )
436 pCreationDate
[i
] = 0;
440 WritePS (mpJobHeader
, pCreationDate
);
441 WritePS (mpJobHeader
, ")\n");
445 * The title should be clean ascii; rJobName however may
446 * contain any Unicode character. So implement the following
448 * use rJobName, if it contains only ascii
449 * use the filename, if it contains only ascii
452 aFilterWS
= WhitespaceToSpace( rJobName
, FALSE
);
453 rtl::OUString
aTitle( aFilterWS
);
454 if( ! isAscii( aTitle
) )
456 sal_Int32 nIndex
= 0;
457 while( nIndex
!= -1 )
458 aTitle
= rFileName
.getToken( 0, '/', nIndex
);
459 aTitle
= WhitespaceToSpace( aTitle
, FALSE
);
460 if( ! isAscii( aTitle
) )
461 aTitle
= rtl::OUString();
464 maJobTitle
= aFilterWS
;
465 if( aTitle
.getLength() )
467 WritePS (mpJobHeader
, "%%Title: (");
468 WritePS (mpJobHeader
, aTitle
);
469 WritePS (mpJobHeader
, ")\n");
474 sal_Int32 nSz
= getValueOf(GetPostscriptLevel(&rSetupData
), pLevel
);
475 pLevel
[nSz
++] = '\n';
477 WritePS (mpJobHeader
, "%%LanguageLevel: ");
478 WritePS (mpJobHeader
, pLevel
);
481 WritePS (mpJobHeader
, "%%DocumentData: Clean7Bit\n");
482 WritePS (mpJobHeader
, "%%Pages: (atend)\n");
483 WritePS (mpJobHeader
, "%%Orientation: (atend)\n");
484 WritePS (mpJobHeader
, "%%PageOrder: Ascend\n");
485 WritePS (mpJobHeader
, "%%EndComments\n");
488 writeProlog (mpJobHeader
, rSetupData
);
490 // mark last job setup as not set
491 m_aLastJobData
.m_pParser
= NULL
;
492 m_aLastJobData
.m_aContext
.setParser( NULL
);
498 PrinterJob::EndJob ()
500 // write document setup (done here because it
501 // includes the accumulated fonts
503 writeSetup( mpJobHeader
, m_aDocumentJobData
);
504 m_pGraphics
->OnEndJob();
505 if( ! (mpJobHeader
&& mpJobTrailer
) )
508 // write document trailer according to Document Structuring Conventions (DSC)
509 rtl::OStringBuffer
aTrailer(512);
510 aTrailer
.append( "%%Trailer\n" );
511 aTrailer
.append( "%%BoundingBox: 0 0 " );
512 aTrailer
.append( (sal_Int32
)mnMaxWidthPt
);
513 aTrailer
.append( " " );
514 aTrailer
.append( (sal_Int32
)mnMaxHeightPt
);
515 if( mnLandscapes
> mnPortraits
)
516 aTrailer
.append("\n%%Orientation: Landscape");
518 aTrailer
.append("\n%%Orientation: Portrait");
519 aTrailer
.append( "\n%%Pages: " );
520 aTrailer
.append( (sal_Int32
)maPageList
.size() );
521 aTrailer
.append( "\n%%EOF\n" );
522 WritePS (mpJobTrailer
, aTrailer
.getStr());
525 * spool the set of files to their final destination, this is U**X dependent
528 FILE* pDestFILE
= NULL
;
530 /* create a destination either as file or as a pipe */
531 sal_Bool bSpoolToFile
= maFileName
.getLength() > 0 ? sal_True
: sal_False
;
534 const rtl::OString aFileName
= rtl::OUStringToOString (maFileName
,
535 osl_getThreadTextEncoding());
538 int nFile
= open( aFileName
.getStr(), O_CREAT
| O_EXCL
| O_RDWR
, mnFileMode
);
541 pDestFILE
= fdopen( nFile
, "w" );
542 if( pDestFILE
== NULL
)
545 unlink( aFileName
.getStr() );
550 chmod( aFileName
.getStr(), mnFileMode
);
552 if (pDestFILE
== NULL
)
553 pDestFILE
= fopen (aFileName
.getStr(), "w");
555 if (pDestFILE
== NULL
)
560 PrinterInfoManager
& rPrinterInfoManager
= PrinterInfoManager::get ();
561 pDestFILE
= rPrinterInfoManager
.startSpool( m_aLastJobData
.m_aPrinterName
, m_bQuickJob
);
562 if (pDestFILE
== NULL
)
566 /* spool the document parts to the destination */
568 sal_uChar pBuffer
[ nBLOCKSIZE
];
570 AppendPS (pDestFILE
, mpJobHeader
, pBuffer
);
571 mpJobHeader
->close();
573 sal_Bool bSuccess
= sal_True
;
574 std::list
< osl::File
* >::iterator pPageBody
;
575 std::list
< osl::File
* >::iterator pPageHead
;
576 for (pPageBody
= maPageList
.begin(), pPageHead
= maHeaderList
.begin();
577 pPageBody
!= maPageList
.end() && pPageHead
!= maHeaderList
.end();
578 pPageBody
++, pPageHead
++)
582 osl::File::RC nError
= (*pPageHead
)->open(OpenFlag_Read
);
583 if (nError
== osl::File::E_None
)
585 AppendPS (pDestFILE
, *pPageHead
, pBuffer
);
586 (*pPageHead
)->close();
590 bSuccess
= sal_False
;
593 osl::File::RC nError
= (*pPageBody
)->open(OpenFlag_Read
);
594 if (nError
== osl::File::E_None
)
596 AppendPS (pDestFILE
, *pPageBody
, pBuffer
);
597 (*pPageBody
)->close();
601 bSuccess
= sal_False
;
604 AppendPS (pDestFILE
, mpJobTrailer
, pBuffer
);
605 mpJobTrailer
->close();
613 PrinterInfoManager
& rPrinterInfoManager
= PrinterInfoManager::get();
614 if (0 == rPrinterInfoManager
.endSpool( m_aLastJobData
.m_aPrinterName
,
615 maJobTitle
, pDestFILE
, m_aDocumentJobData
))
617 bSuccess
= sal_False
;
625 PrinterJob::AbortJob ()
627 m_pGraphics
->OnEndJob();
632 PrinterJob::InitPaperSize (const JobData
& rJobSetup
)
634 int nRes
= rJobSetup
.m_aContext
.getRenderResolution ();
638 rJobSetup
.m_aContext
.getPageSize (aPaper
, nWidth
, nHeight
);
640 int nLeft
= 0, nRight
= 0, nUpper
= 0, nLower
= 0;
641 const PPDParser
* pParser
= rJobSetup
.m_aContext
.getParser();
643 pParser
->getMargins (aPaper
, nLeft
, nRight
, nUpper
, nLower
);
648 mnHeightPt
= nHeight
;
650 if( mnWidthPt
> mnMaxWidthPt
)
651 mnMaxWidthPt
= mnWidthPt
;
652 if( mnHeightPt
> mnMaxHeightPt
)
653 mnMaxHeightPt
= mnHeightPt
;
656 mnRMarginPt
= nRight
;
657 mnTMarginPt
= nUpper
;
658 mnBMarginPt
= nLower
;
660 mfXScale
= (double)72.0 / (double)mnResolution
;
661 mfYScale
= -1.0 * (double)72.0 / (double)mnResolution
;
666 PrinterJob::StartPage (const JobData
& rJobSetup
)
668 InitPaperSize (rJobSetup
);
670 rtl::OUString aPageNo
= rtl::OUString::valueOf ((sal_Int32
)maPageList
.size()+1); // sequential page number must start with 1
671 rtl::OUString aExt
= aPageNo
+ rtl::OUString::createFromAscii (".ps");
673 osl::File
* pPageHeader
= CreateSpoolFile (
674 rtl::OUString::createFromAscii("psp_pghead"), aExt
);
675 osl::File
* pPageBody
= CreateSpoolFile (
676 rtl::OUString::createFromAscii("psp_pgbody"), aExt
);
678 maHeaderList
.push_back (pPageHeader
);
679 maPageList
.push_back (pPageBody
);
681 if( ! (pPageHeader
&& pPageBody
) )
684 // write page header according to Document Structuring Conventions (DSC)
685 WritePS (pPageHeader
, "%%Page: ");
686 WritePS (pPageHeader
, aPageNo
);
687 WritePS (pPageHeader
, " ");
688 WritePS (pPageHeader
, aPageNo
);
689 WritePS (pPageHeader
, "\n");
691 if( rJobSetup
.m_eOrientation
== orientation::Landscape
)
693 WritePS (pPageHeader
, "%%PageOrientation: Landscape\n");
698 WritePS (pPageHeader
, "%%PageOrientation: Portrait\n");
702 sal_Char pBBox
[256];
705 nChar
= psp::appendStr ("%%PageBoundingBox: ", pBBox
);
706 nChar
+= psp::getValueOf (mnLMarginPt
, pBBox
+ nChar
);
707 nChar
+= psp::appendStr (" ", pBBox
+ nChar
);
708 nChar
+= psp::getValueOf (mnBMarginPt
, pBBox
+ nChar
);
709 nChar
+= psp::appendStr (" ", pBBox
+ nChar
);
710 nChar
+= psp::getValueOf (mnWidthPt
- mnRMarginPt
, pBBox
+ nChar
);
711 nChar
+= psp::appendStr (" ", pBBox
+ nChar
);
712 nChar
+= psp::getValueOf (mnHeightPt
- mnTMarginPt
, pBBox
+ nChar
);
713 nChar
+= psp::appendStr ("\n", pBBox
+ nChar
);
715 WritePS (pPageHeader
, pBBox
);
717 /* #i7262# #i65491# write setup only before first page
718 * (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup)
719 * don't do this in StartJob since the jobsetup there may be
722 bool bWriteFeatures
= true;
723 if( 1 == maPageList
.size() )
725 m_aDocumentJobData
= rJobSetup
;
726 bWriteFeatures
= false;
729 if ( writePageSetup( pPageHeader
, rJobSetup
, bWriteFeatures
) )
731 m_aLastJobData
= rJobSetup
;
739 PrinterJob::EndPage ()
741 m_pGraphics
->OnEndPage();
743 osl::File
* pPageHeader
= maHeaderList
.back();
744 osl::File
* pPageBody
= maPageList
.back();
746 if( ! (pPageBody
&& pPageHeader
) )
749 // copy page to paper and write page trailer according to DSC
751 sal_Char pTrailer
[256];
753 nChar
= psp::appendStr ("grestore grestore\n", pTrailer
);
754 nChar
+= psp::appendStr ("showpage\n", pTrailer
+ nChar
);
755 nChar
+= psp::appendStr ("%%PageTrailer\n\n", pTrailer
+ nChar
);
756 WritePS (pPageBody
, pTrailer
);
758 // this page is done for now, close it to avoid having too many open fd's
760 pPageHeader
->close();
767 PrinterJob::GetErrorCode ()
773 struct less_ppd_key
: public ::std::binary_function
<double, double, bool>
775 bool operator()(const PPDKey
* left
, const PPDKey
* right
)
776 { return left
->getOrderDependency() < right
->getOrderDependency(); }
779 static bool writeFeature( osl::File
* pFile
, const PPDKey
* pKey
, const PPDValue
* pValue
, bool bUseIncluseFeature
)
781 if( ! pKey
|| ! pValue
)
784 OStringBuffer
aFeature(256);
785 aFeature
.append( "[{\n" );
786 if( bUseIncluseFeature
)
787 aFeature
.append( "%%IncludeFeature:" );
789 aFeature
.append( "%%BeginFeature:" );
790 aFeature
.append( " *" );
791 aFeature
.append( OUStringToOString( pKey
->getKey(), RTL_TEXTENCODING_ASCII_US
) );
792 aFeature
.append( ' ' );
793 aFeature
.append( OUStringToOString( pValue
->m_aOption
, RTL_TEXTENCODING_ASCII_US
) );
794 if( !bUseIncluseFeature
)
796 aFeature
.append( '\n' );
797 aFeature
.append( OUStringToOString( pValue
->m_aValue
, RTL_TEXTENCODING_ASCII_US
) );
798 aFeature
.append( "\n%%EndFeature" );
800 aFeature
.append( "\n} stopped cleartomark\n" );
801 sal_uInt64 nWritten
= 0;
802 return pFile
->write( aFeature
.getStr(), aFeature
.getLength(), nWritten
)
803 || nWritten
!= (sal_uInt64
)aFeature
.getLength() ? false : true;
806 bool PrinterJob::writeFeatureList( osl::File
* pFile
, const JobData
& rJob
, bool bDocumentSetup
)
808 bool bSuccess
= true;
811 // emit features ordered to OrderDependency
812 // ignore features that are set to default
815 if( rJob
.m_pParser
== rJob
.m_aContext
.getParser() &&
817 ( m_aLastJobData
.m_pParser
== rJob
.m_pParser
|| m_aLastJobData
.m_pParser
== NULL
)
820 int nKeys
= rJob
.m_aContext
.countValuesModified();
821 ::std::vector
< const PPDKey
* > aKeys( nKeys
);
822 for( i
= 0; i
< nKeys
; i
++ )
823 aKeys
[i
] = rJob
.m_aContext
.getModifiedKey( i
);
824 ::std::sort( aKeys
.begin(), aKeys
.end(), less_ppd_key() );
826 for( i
= 0; i
< nKeys
&& bSuccess
; i
++ )
828 const PPDKey
* pKey
= aKeys
[i
];
832 if( pKey
->getSetupType() == PPDKey::DocumentSetup
)
835 if( pKey
->getSetupType() == PPDKey::PageSetup
||
836 pKey
->getSetupType() == PPDKey::AnySetup
)
840 const PPDValue
* pValue
= rJob
.m_aContext
.getValue( pKey
);
842 && pValue
->m_eType
== eInvocation
843 && ( m_aLastJobData
.m_pParser
== NULL
844 || m_aLastJobData
.m_aContext
.getValue( pKey
) != pValue
849 // try to avoid PS level 2 feature commands if level is set to 1
850 if( GetPostscriptLevel( &rJob
) == 1 )
853 ( pValue
->m_aValue
.SearchAscii( "<<" ) != STRING_NOTFOUND
)
855 ( pValue
->m_aValue
.SearchAscii( ">>" ) != STRING_NOTFOUND
);
859 bSuccess
= writeFeature( pFile
, pKey
, pValue
, PrinterInfoManager::get().getUseIncludeFeature() );
870 bool PrinterJob::writePageSetup( osl::File
* pFile
, const JobData
& rJob
, bool bWriteFeatures
)
872 bool bSuccess
= true;
874 WritePS (pFile
, "%%BeginPageSetup\n%\n");
875 if ( bWriteFeatures
)
876 bSuccess
= writeFeatureList( pFile
, rJob
, false );
877 WritePS (pFile
, "%%EndPageSetup\n");
879 sal_Char pTranslate
[128];
882 if( rJob
.m_eOrientation
== orientation::Portrait
)
884 nChar
= psp::appendStr ("gsave\n[", pTranslate
);
885 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mfXScale
, 5);
886 nChar
+= psp::appendStr (" 0 0 ", pTranslate
+ nChar
);
887 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mfYScale
, 5);
888 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
889 nChar
+= psp::getValueOf (mnRMarginPt
, pTranslate
+ nChar
);
890 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
891 nChar
+= psp::getValueOf (mnHeightPt
-mnTMarginPt
,
893 nChar
+= psp::appendStr ("] concat\ngsave\n",
898 nChar
= psp::appendStr ("gsave\n", pTranslate
);
899 nChar
+= psp::appendStr ("[ 0 ", pTranslate
+ nChar
);
900 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, -mfYScale
, 5);
901 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
902 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mfXScale
, 5);
903 nChar
+= psp::appendStr (" 0 ", pTranslate
+ nChar
);
904 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mnLMarginPt
, 5 );
905 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
906 nChar
+= psp::getValueOf (mnBMarginPt
, pTranslate
+ nChar
);
907 nChar
+= psp::appendStr ("] concat\ngsave\n",
911 WritePS (pFile
, pTranslate
);
916 void PrinterJob::writeJobPatch( osl::File
* pFile
, const JobData
& rJobData
)
918 const PPDKey
* pKey
= NULL
;
920 if( rJobData
.m_pParser
)
921 pKey
= rJobData
.m_pParser
->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "JobPatchFile" ) ) );
925 // order the patch files
926 // according to PPD spec the JobPatchFile options must be int
927 // and should be emitted in order
928 std::list
< sal_Int32
> patch_order
;
929 int nValueCount
= pKey
->countValues();
930 for( int i
= 0; i
< nValueCount
; i
++ )
932 const PPDValue
* pVal
= pKey
->getValue( i
);
933 patch_order
.push_back( pVal
->m_aOption
.ToInt32() );
934 if( patch_order
.back() == 0 && ! pVal
->m_aOption
.EqualsAscii( "0" ) )
936 WritePS( pFile
, "% Warning: left out JobPatchFile option \"" );
937 OString aOption
= OUStringToOString( pVal
->m_aOption
, RTL_TEXTENCODING_ASCII_US
);
938 WritePS( pFile
, aOption
.getStr() );
940 "\"\n% as it violates the PPD spec;\n"
941 "% JobPatchFile options need to be numbered for ordering.\n" );
946 patch_order
.unique();
948 while( patch_order
.begin() != patch_order
.end() )
950 // note: this discards patch files not adhering to the "int" scheme
951 // as there won't be a value for them
952 writeFeature( pFile
, pKey
, pKey
->getValue( OUString::valueOf( patch_order
.front() ) ), false );
953 patch_order
.pop_front();
957 bool PrinterJob::writeProlog (osl::File
* pFile
, const JobData
& rJobData
)
959 WritePS( pFile
, "%%BeginProlog\n" );
961 // JobPatchFile feature needs to be emitted at begin of prolog
962 writeJobPatch( pFile
, rJobData
);
964 static const sal_Char pProlog
[] = {
965 "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
966 "/ISO1252Encoding [\n"
967 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
968 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
969 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
970 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
971 "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
972 "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
973 "/zero /one /two /three /four /five /six /seven\n"
974 "/eight /nine /colon /semicolon /less /equal /greater /question\n"
975 "/at /A /B /C /D /E /F /G\n"
976 "/H /I /J /K /L /M /N /O\n"
977 "/P /Q /R /S /T /U /V /W\n"
978 "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
979 "/grave /a /b /c /d /e /f /g\n"
980 "/h /i /j /k /l /m /n /o\n"
981 "/p /q /r /s /t /u /v /w\n"
982 "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
983 "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
984 "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
985 "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
986 "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
987 "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
988 "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
989 "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
990 "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
991 "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
992 "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
993 "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
994 "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
995 "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
996 "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
997 "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
998 "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
1000 "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
1001 "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
1002 "currentdict end exch pop definefont pop } def\n"
1004 "/pathdict dup 8 dict def load begin\n"
1005 "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
1006 "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
1007 "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
1008 "eq 3 1 roll exch } def\n"
1009 "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
1010 "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
1011 "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
1012 "for 256 div exch pop exch { neg } if } def\n"
1013 "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
1014 "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
1015 "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
1017 "systemdict /languagelevel known not {\n"
1018 "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
1019 "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
1020 "roll show moveto 0 rmoveto } for pop pop } def\n"
1021 "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
1022 "rlineto closepath } def\n"
1023 "/rectfill { rectangle fill } def\n"
1024 "/rectstroke { rectangle stroke } def } if\n"
1025 "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
1026 "setlinewidth false charpath stroke setlinewidth } def\n"
1027 "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
1028 "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
1029 "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
1030 "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
1032 "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
1033 "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
1034 "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
1035 "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
1036 "/psp_imagedict {\n"
1037 "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
1038 "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
1040 "/ImageType 1 put dup\n"
1041 "/Width 7 -1 roll put dup\n"
1042 "/Height 5 index put dup\n"
1043 "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
1044 "/Decode 5 -1 roll psp_decodearray put dup\n"
1045 "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
1046 "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
1051 static const sal_Char pSO52CompatProlog
[] = {
1052 "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
1053 "/ISO1252Encoding [\n"
1054 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1055 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1056 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1057 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1058 "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
1059 "/parenleft /parenright /asterisk /plus /comma /minus /period /slash\n"
1060 "/zero /one /two /three /four /five /six /seven\n"
1061 "/eight /nine /colon /semicolon /less /equal /greater /question\n"
1062 "/at /A /B /C /D /E /F /G\n"
1063 "/H /I /J /K /L /M /N /O\n"
1064 "/P /Q /R /S /T /U /V /W\n"
1065 "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
1066 "/grave /a /b /c /d /e /f /g\n"
1067 "/h /i /j /k /l /m /n /o\n"
1068 "/p /q /r /s /t /u /v /w\n"
1069 "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
1070 "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
1071 "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
1072 "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
1073 "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
1074 "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
1075 "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
1076 "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
1077 "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
1078 "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
1079 "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
1080 "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
1081 "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
1082 "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
1083 "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
1084 "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
1085 "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
1087 "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
1088 "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
1089 "currentdict end exch pop definefont pop } def\n"
1091 "/pathdict dup 8 dict def load begin\n"
1092 "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
1093 "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
1094 "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
1095 "eq 3 1 roll exch } def\n"
1096 "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
1097 "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
1098 "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
1099 "for 256 div exch pop exch { neg } if } def\n"
1100 "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
1101 "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
1102 "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
1104 "systemdict /languagelevel known not {\n"
1105 "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
1106 "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
1107 "roll show moveto 0 rmoveto } for pop pop } def\n"
1108 "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
1109 "rlineto closepath } def\n"
1110 "/rectfill { rectangle fill } def\n"
1111 "/rectstroke { rectangle stroke } def } if\n"
1112 "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
1113 "setlinewidth false charpath stroke setlinewidth } def\n"
1114 "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
1115 "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
1116 "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
1117 "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
1119 "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
1120 "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
1121 "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
1122 "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
1123 "/psp_imagedict {\n"
1124 "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
1125 "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
1127 "/ImageType 1 put dup\n"
1128 "/Width 7 -1 roll put dup\n"
1129 "/Height 5 index put dup\n"
1130 "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
1131 "/Decode 5 -1 roll psp_decodearray put dup\n"
1132 "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
1133 "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
1138 WritePS (pFile
, m_pGraphics
&& m_pGraphics
->getStrictSO52Compatibility() ? pSO52CompatProlog
: pProlog
);
1143 bool PrinterJob::writeSetup( osl::File
* pFile
, const JobData
& rJob
)
1145 WritePS (pFile
, "%%BeginSetup\n%\n");
1148 std::list
< rtl::OString
> aFonts
[2];
1149 m_pGraphics
->writeResources( pFile
, aFonts
[0], aFonts
[1] );
1151 for( int i
= 0; i
< 2; i
++ )
1153 if( !aFonts
[i
].empty() )
1155 std::list
< rtl::OString
>::const_iterator it
= aFonts
[i
].begin();
1156 rtl::OStringBuffer
aLine( 256 );
1158 aLine
.append( "%%DocumentSuppliedResources: font " );
1160 aLine
.append( "%%DocumentNeededResources: font " );
1161 aLine
.append( *it
);
1162 aLine
.append( "\n" );
1163 WritePS ( pFile
, aLine
.getStr() );
1164 while( (++it
) != aFonts
[i
].end() )
1167 aLine
.append( "%%+ font " );
1168 aLine
.append( *it
);
1169 aLine
.append( "\n" );
1170 WritePS ( pFile
, aLine
.getStr() );
1175 bool bSuccess
= true;
1176 // in case of external print dialog the number of copies is prepended
1177 // to the job, let us not complicate things by emitting our own copy count
1178 bool bExternalDialog
= PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
1179 if( ! bExternalDialog
&& rJob
.m_nCopies
> 1 )
1182 ByteString
aLine( "/#copies " );
1183 aLine
+= ByteString::CreateFromInt32( rJob
.m_nCopies
);
1185 sal_uInt64 nWritten
= 0;
1186 bSuccess
= pFile
->write( aLine
.GetBuffer(), aLine
.Len(), nWritten
)
1187 || nWritten
!= aLine
.Len() ? false : true;
1189 if( bSuccess
&& GetPostscriptLevel( &rJob
) >= 2 )
1190 WritePS (pFile
, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
1193 bool bFeatureSuccess
= writeFeatureList( pFile
, rJob
, true );
1195 WritePS (pFile
, "%%EndSetup\n");
1197 return bSuccess
&& bFeatureSuccess
;