1*c82f2877SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*c82f2877SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*c82f2877SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*c82f2877SAndrew Rist  * distributed with this work for additional information
6*c82f2877SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*c82f2877SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*c82f2877SAndrew Rist  * "License"); you may not use this file except in compliance
9*c82f2877SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*c82f2877SAndrew Rist  *
11*c82f2877SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*c82f2877SAndrew Rist  *
13*c82f2877SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*c82f2877SAndrew Rist  * software distributed under the License is distributed on an
15*c82f2877SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*c82f2877SAndrew Rist  * KIND, either express or implied.  See the License for the
17*c82f2877SAndrew Rist  * specific language governing permissions and limitations
18*c82f2877SAndrew Rist  * under the License.
19*c82f2877SAndrew Rist  *
20*c82f2877SAndrew Rist  *************************************************************/
21*c82f2877SAndrew Rist 
22*c82f2877SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <stdio.h>
28cdf0e10cSrcweir #include <sys/types.h>
29cdf0e10cSrcweir #include <sys/stat.h>
30cdf0e10cSrcweir #include <fcntl.h>
31cdf0e10cSrcweir #include <unistd.h>
32cdf0e10cSrcweir #include <pwd.h>
33cdf0e10cSrcweir 
34cdf0e10cSrcweir #include "psputil.hxx"
35cdf0e10cSrcweir #include "glyphset.hxx"
36cdf0e10cSrcweir 
37cdf0e10cSrcweir #include "printerjob.hxx"
38cdf0e10cSrcweir #include "printergfx.hxx"
39cdf0e10cSrcweir #include "vcl/ppdparser.hxx"
40cdf0e10cSrcweir #include "vcl/strhelper.hxx"
41cdf0e10cSrcweir #include "vcl/printerinfomanager.hxx"
42cdf0e10cSrcweir 
43cdf0e10cSrcweir #include "rtl/ustring.hxx"
44cdf0e10cSrcweir #include "rtl/strbuf.hxx"
45cdf0e10cSrcweir #include "rtl/ustrbuf.hxx"
46cdf0e10cSrcweir 
47cdf0e10cSrcweir #include "osl/thread.h"
48cdf0e10cSrcweir #include "sal/alloca.h"
49cdf0e10cSrcweir 
50cdf0e10cSrcweir #include <algorithm>
51cdf0e10cSrcweir #include <vector>
52cdf0e10cSrcweir 
53cdf0e10cSrcweir using namespace psp;
54cdf0e10cSrcweir using namespace rtl;
55cdf0e10cSrcweir 
56cdf0e10cSrcweir // forward declaration
57cdf0e10cSrcweir 
58cdf0e10cSrcweir #define nBLOCKSIZE 0x2000
59cdf0e10cSrcweir 
60cdf0e10cSrcweir namespace psp
61cdf0e10cSrcweir {
62cdf0e10cSrcweir 
63cdf0e10cSrcweir sal_Bool
64cdf0e10cSrcweir AppendPS (FILE* pDst, osl::File* pSrc, sal_uChar* pBuffer,
65cdf0e10cSrcweir           sal_uInt32 nBlockSize = nBLOCKSIZE)
66cdf0e10cSrcweir {
67cdf0e10cSrcweir     if ((pDst == NULL) || (pSrc == NULL))
68cdf0e10cSrcweir         return sal_False;
69cdf0e10cSrcweir 
70cdf0e10cSrcweir     if (nBlockSize == 0)
71cdf0e10cSrcweir         nBlockSize = nBLOCKSIZE;
72cdf0e10cSrcweir     if (pBuffer == NULL)
73cdf0e10cSrcweir         pBuffer = (sal_uChar*)alloca (nBlockSize);
74cdf0e10cSrcweir 
75cdf0e10cSrcweir     pSrc->setPos (osl_Pos_Absolut, 0);
76cdf0e10cSrcweir 
77cdf0e10cSrcweir     sal_uInt64 nIn = 0;
78cdf0e10cSrcweir     sal_uInt64 nOut = 0;
79cdf0e10cSrcweir     do
80cdf0e10cSrcweir     {
81cdf0e10cSrcweir         pSrc->read  (pBuffer, nBlockSize, nIn);
82cdf0e10cSrcweir         if (nIn > 0)
83cdf0e10cSrcweir             nOut = fwrite (pBuffer, 1, sal::static_int_cast<sal_uInt32>(nIn), pDst);
84cdf0e10cSrcweir     }
85cdf0e10cSrcweir     while ((nIn > 0) && (nIn == nOut));
86cdf0e10cSrcweir 
87cdf0e10cSrcweir     return sal_True;
88cdf0e10cSrcweir }
89cdf0e10cSrcweir 
90cdf0e10cSrcweir } // namespace psp
91cdf0e10cSrcweir 
92cdf0e10cSrcweir /*
93cdf0e10cSrcweir  * private convenience routines for file handling
94cdf0e10cSrcweir  */
95cdf0e10cSrcweir 
96cdf0e10cSrcweir osl::File*
97cdf0e10cSrcweir PrinterJob::CreateSpoolFile (const rtl::OUString& rName, const rtl::OUString& rExtension)
98cdf0e10cSrcweir {
99cdf0e10cSrcweir     osl::File::RC nError = osl::File::E_None;
100cdf0e10cSrcweir     osl::File*    pFile  = NULL;
101cdf0e10cSrcweir 
102cdf0e10cSrcweir     rtl::OUString aFile = rName + rExtension;
103cdf0e10cSrcweir     rtl::OUString aFileURL;
104cdf0e10cSrcweir 	nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL );
105cdf0e10cSrcweir     if (nError != osl::File::E_None)
106cdf0e10cSrcweir         return NULL;
107cdf0e10cSrcweir     aFileURL = maSpoolDirName + rtl::OUString::createFromAscii ("/") + aFileURL;
108cdf0e10cSrcweir 
109cdf0e10cSrcweir     pFile = new osl::File (aFileURL);
110cdf0e10cSrcweir     nError = pFile->open (OpenFlag_Read | OpenFlag_Write | OpenFlag_Create);
111cdf0e10cSrcweir     if (nError != osl::File::E_None)
112cdf0e10cSrcweir     {
113cdf0e10cSrcweir         delete pFile;
114cdf0e10cSrcweir         return NULL;
115cdf0e10cSrcweir     }
116cdf0e10cSrcweir 
117cdf0e10cSrcweir     pFile->setAttributes (aFileURL,
118cdf0e10cSrcweir                           osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnRead);
119cdf0e10cSrcweir     return pFile;
120cdf0e10cSrcweir }
121cdf0e10cSrcweir 
122cdf0e10cSrcweir /*
123cdf0e10cSrcweir  * public methods of PrinterJob: for use in PrinterGfx
124cdf0e10cSrcweir  */
125cdf0e10cSrcweir 
126cdf0e10cSrcweir void
127cdf0e10cSrcweir PrinterJob::GetScale (double &rXScale, double &rYScale) const
128cdf0e10cSrcweir {
129cdf0e10cSrcweir     rXScale = mfXScale;
130cdf0e10cSrcweir     rYScale = mfYScale;
131cdf0e10cSrcweir }
132cdf0e10cSrcweir 
133cdf0e10cSrcweir sal_uInt16
134cdf0e10cSrcweir PrinterJob::GetDepth () const
135cdf0e10cSrcweir {
136cdf0e10cSrcweir     sal_Int32 nLevel = GetPostscriptLevel();
137cdf0e10cSrcweir     sal_Bool  bColor = IsColorPrinter ();
138cdf0e10cSrcweir 
139cdf0e10cSrcweir     return nLevel > 1 && bColor ? 24 : 8;
140cdf0e10cSrcweir }
141cdf0e10cSrcweir 
142cdf0e10cSrcweir sal_uInt16
143cdf0e10cSrcweir PrinterJob::GetPostscriptLevel (const JobData *pJobData) const
144cdf0e10cSrcweir {
145cdf0e10cSrcweir     sal_uInt16 nPSLevel = 2;
146cdf0e10cSrcweir 
147cdf0e10cSrcweir     if( pJobData == NULL )
148cdf0e10cSrcweir         pJobData = &m_aLastJobData;
149cdf0e10cSrcweir 
150cdf0e10cSrcweir     if( pJobData->m_nPSLevel )
151cdf0e10cSrcweir         nPSLevel = pJobData->m_nPSLevel;
152cdf0e10cSrcweir     else
153cdf0e10cSrcweir         if( pJobData->m_pParser )
154cdf0e10cSrcweir             nPSLevel = pJobData->m_pParser->getLanguageLevel();
155cdf0e10cSrcweir 
156cdf0e10cSrcweir     return nPSLevel;
157cdf0e10cSrcweir }
158cdf0e10cSrcweir 
159cdf0e10cSrcweir sal_Bool
160cdf0e10cSrcweir PrinterJob::IsColorPrinter () const
161cdf0e10cSrcweir {
162cdf0e10cSrcweir     sal_Bool bColor = sal_False;
163cdf0e10cSrcweir 
164cdf0e10cSrcweir     if( m_aLastJobData.m_nColorDevice )
165cdf0e10cSrcweir         bColor = m_aLastJobData.m_nColorDevice == -1 ? sal_False : sal_True;
166cdf0e10cSrcweir     else if( m_aLastJobData.m_pParser )
167cdf0e10cSrcweir         bColor = m_aLastJobData.m_pParser->isColorDevice() ? sal_True : sal_False;
168cdf0e10cSrcweir 
169cdf0e10cSrcweir     return bColor;
170cdf0e10cSrcweir }
171cdf0e10cSrcweir 
172cdf0e10cSrcweir osl::File*
173cdf0e10cSrcweir PrinterJob::GetDocumentHeader ()
174cdf0e10cSrcweir {
175cdf0e10cSrcweir     return mpJobHeader;
176cdf0e10cSrcweir }
177cdf0e10cSrcweir 
178cdf0e10cSrcweir osl::File*
179cdf0e10cSrcweir PrinterJob::GetDocumentTrailer ()
180cdf0e10cSrcweir {
181cdf0e10cSrcweir     return mpJobTrailer;
182cdf0e10cSrcweir }
183cdf0e10cSrcweir 
184cdf0e10cSrcweir osl::File*
185cdf0e10cSrcweir PrinterJob::GetCurrentPageHeader ()
186cdf0e10cSrcweir {
187cdf0e10cSrcweir     return maHeaderList.back();
188cdf0e10cSrcweir }
189cdf0e10cSrcweir 
190cdf0e10cSrcweir osl::File*
191cdf0e10cSrcweir PrinterJob::GetCurrentPageBody ()
192cdf0e10cSrcweir {
193cdf0e10cSrcweir     return maPageList.back();
194cdf0e10cSrcweir }
195cdf0e10cSrcweir 
196cdf0e10cSrcweir /*
197cdf0e10cSrcweir  * public methods of PrinterJob: the actual job / spool handling
198cdf0e10cSrcweir  */
199cdf0e10cSrcweir 
200cdf0e10cSrcweir PrinterJob::PrinterJob () :
201cdf0e10cSrcweir         mpJobHeader( NULL ),
202cdf0e10cSrcweir         mpJobTrailer( NULL ),
203cdf0e10cSrcweir         m_bQuickJob( false )
204cdf0e10cSrcweir {
205cdf0e10cSrcweir }
206cdf0e10cSrcweir 
207cdf0e10cSrcweir namespace psp
208cdf0e10cSrcweir {
209cdf0e10cSrcweir 
210cdf0e10cSrcweir /* check whether the given name points to a directory which is
211cdf0e10cSrcweir    usable for the user */
212cdf0e10cSrcweir sal_Bool
213cdf0e10cSrcweir existsTmpDir (const char* pName)
214cdf0e10cSrcweir {
215cdf0e10cSrcweir     struct stat aFileStatus;
216cdf0e10cSrcweir 
217cdf0e10cSrcweir     if (pName == NULL)
218cdf0e10cSrcweir         return sal_False;
219cdf0e10cSrcweir     if (stat(pName, &aFileStatus) != 0)
220cdf0e10cSrcweir         return sal_False;
221cdf0e10cSrcweir     if (! S_ISDIR(aFileStatus.st_mode))
222cdf0e10cSrcweir         return sal_False;
223cdf0e10cSrcweir 
224cdf0e10cSrcweir     return access(pName, W_OK | R_OK) == 0 ? sal_True : sal_False;
225cdf0e10cSrcweir }
226cdf0e10cSrcweir 
227cdf0e10cSrcweir /* return the username in the given buffer */
228cdf0e10cSrcweir sal_Bool
229cdf0e10cSrcweir getUserName (char* pName, int nSize)
230cdf0e10cSrcweir {
231cdf0e10cSrcweir     struct passwd *pPWEntry;
232cdf0e10cSrcweir     struct passwd  aPWEntry;
233cdf0e10cSrcweir     sal_Char       pPWBuffer[256];
234cdf0e10cSrcweir 
235cdf0e10cSrcweir     sal_Bool bSuccess = sal_False;
236cdf0e10cSrcweir 
237cdf0e10cSrcweir #ifdef FREEBSD
238cdf0e10cSrcweir         pPWEntry = getpwuid( getuid());
239cdf0e10cSrcweir #else
240cdf0e10cSrcweir     if (getpwuid_r(getuid(), &aPWEntry, pPWBuffer, sizeof(pPWBuffer), &pPWEntry) != 0)
241cdf0e10cSrcweir         pPWEntry = NULL;
242cdf0e10cSrcweir #endif
243cdf0e10cSrcweir 
244cdf0e10cSrcweir     if (pPWEntry != NULL && pPWEntry->pw_name != NULL)
245cdf0e10cSrcweir     {
246cdf0e10cSrcweir         sal_Int32 nLen = strlen(pPWEntry->pw_name);
247cdf0e10cSrcweir         if (nLen > 0 && nLen < nSize)
248cdf0e10cSrcweir         {
249cdf0e10cSrcweir             memcpy (pName, pPWEntry->pw_name, nLen);
250cdf0e10cSrcweir             pName[nLen] = '\0';
251cdf0e10cSrcweir 
252cdf0e10cSrcweir             bSuccess = sal_True;
253cdf0e10cSrcweir         }
254cdf0e10cSrcweir     }
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     // wipe the passwd off the stack
257cdf0e10cSrcweir     memset (pPWBuffer, 0, sizeof(pPWBuffer));
258cdf0e10cSrcweir 
259cdf0e10cSrcweir     return bSuccess;
260cdf0e10cSrcweir }
261cdf0e10cSrcweir 
262cdf0e10cSrcweir /* remove all our temporary files, uses external program "rm", since
263cdf0e10cSrcweir    osl functionality is inadequate */
264cdf0e10cSrcweir void
265cdf0e10cSrcweir removeSpoolDir (const rtl::OUString& rSpoolDir)
266cdf0e10cSrcweir {
267cdf0e10cSrcweir     rtl::OUString aSysPath;
268cdf0e10cSrcweir 	if( osl::File::E_None != osl::File::getSystemPathFromFileURL( rSpoolDir, aSysPath ) )
269cdf0e10cSrcweir 	{
270cdf0e10cSrcweir 		// Conversion did not work, as this is quite a dangerous action,
271cdf0e10cSrcweir 		// we should abort here ....
272cdf0e10cSrcweir 		OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
273cdf0e10cSrcweir 		return;
274cdf0e10cSrcweir 	}
275cdf0e10cSrcweir     rtl::OString aSysPathByte =
276cdf0e10cSrcweir         rtl::OUStringToOString (aSysPath, osl_getThreadTextEncoding());
277cdf0e10cSrcweir     sal_Char  pSystem [128];
278cdf0e10cSrcweir     sal_Int32 nChar = 0;
279cdf0e10cSrcweir 
280cdf0e10cSrcweir     nChar  = psp::appendStr ("rm -rf ",     pSystem);
281cdf0e10cSrcweir     nChar += psp::appendStr (aSysPathByte.getStr(), pSystem + nChar);
282cdf0e10cSrcweir 
283cdf0e10cSrcweir     if (system (pSystem) == -1)
284cdf0e10cSrcweir         OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
285cdf0e10cSrcweir }
286cdf0e10cSrcweir 
287cdf0e10cSrcweir /* creates a spool directory with a "pidgin random" value based on
288cdf0e10cSrcweir    current system time */
289cdf0e10cSrcweir rtl::OUString
290cdf0e10cSrcweir createSpoolDir ()
291cdf0e10cSrcweir {
292cdf0e10cSrcweir     TimeValue aCur;
293cdf0e10cSrcweir     osl_getSystemTime( &aCur );
294cdf0e10cSrcweir     sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000);
295cdf0e10cSrcweir 
296cdf0e10cSrcweir     rtl::OUString aTmpDir;
297cdf0e10cSrcweir     osl_getTempDirURL( &aTmpDir.pData );
298cdf0e10cSrcweir 
299cdf0e10cSrcweir     do
300cdf0e10cSrcweir     {
301cdf0e10cSrcweir         rtl::OUStringBuffer aDir( aTmpDir.getLength() + 16 );
302cdf0e10cSrcweir         aDir.append( aTmpDir );
303cdf0e10cSrcweir         aDir.appendAscii( "/psp" );
304cdf0e10cSrcweir         aDir.append(nRand);
305cdf0e10cSrcweir         rtl::OUString aResult = aDir.makeStringAndClear();
306cdf0e10cSrcweir         if( osl::Directory::create( aResult ) == osl::FileBase::E_None )
307cdf0e10cSrcweir         {
308cdf0e10cSrcweir             osl::File::setAttributes( aResult,
309cdf0e10cSrcweir                                         osl_File_Attribute_OwnWrite
310cdf0e10cSrcweir                                       | osl_File_Attribute_OwnRead
311cdf0e10cSrcweir                                       | osl_File_Attribute_OwnExe );
312cdf0e10cSrcweir             return aResult;
313cdf0e10cSrcweir         }
314cdf0e10cSrcweir         nRand++;
315cdf0e10cSrcweir     } while( nRand );
316cdf0e10cSrcweir     return rtl::OUString();
317cdf0e10cSrcweir }
318cdf0e10cSrcweir 
319cdf0e10cSrcweir } // namespace psp
320cdf0e10cSrcweir 
321cdf0e10cSrcweir PrinterJob::~PrinterJob ()
322cdf0e10cSrcweir {
323cdf0e10cSrcweir     std::list< osl::File* >::iterator pPage;
324cdf0e10cSrcweir     for (pPage = maPageList.begin(); pPage != maPageList.end(); pPage++)
325cdf0e10cSrcweir     {
326cdf0e10cSrcweir         //(*pPage)->remove();
327cdf0e10cSrcweir         delete *pPage;
328cdf0e10cSrcweir     }
329cdf0e10cSrcweir     for (pPage = maHeaderList.begin(); pPage != maHeaderList.end(); pPage++)
330cdf0e10cSrcweir     {
331cdf0e10cSrcweir         //(*pPage)->remove();
332cdf0e10cSrcweir         delete *pPage;
333cdf0e10cSrcweir     }
334cdf0e10cSrcweir     // mpJobHeader->remove();
335cdf0e10cSrcweir     delete mpJobHeader;
336cdf0e10cSrcweir     // mpJobTrailer->remove();
337cdf0e10cSrcweir     delete mpJobTrailer;
338cdf0e10cSrcweir 
339cdf0e10cSrcweir     // XXX should really call osl::remove routines
340cdf0e10cSrcweir     if( maSpoolDirName.getLength() )
341cdf0e10cSrcweir         removeSpoolDir (maSpoolDirName);
342cdf0e10cSrcweir 
343cdf0e10cSrcweir     // osl::Directory::remove (maSpoolDirName);
344cdf0e10cSrcweir }
345cdf0e10cSrcweir 
346cdf0e10cSrcweir namespace psp
347cdf0e10cSrcweir {
348cdf0e10cSrcweir 
349cdf0e10cSrcweir // get locale invariant, 7bit clean current local time string
350cdf0e10cSrcweir sal_Char*
351cdf0e10cSrcweir getLocalTime(sal_Char* pBuffer)
352cdf0e10cSrcweir {
353cdf0e10cSrcweir     time_t nTime = time (NULL);
354cdf0e10cSrcweir     struct tm aTime;
355cdf0e10cSrcweir     struct tm *pLocalTime = localtime_r (&nTime, &aTime);
356cdf0e10cSrcweir 
357cdf0e10cSrcweir     return asctime_r(pLocalTime, pBuffer);
358cdf0e10cSrcweir }
359cdf0e10cSrcweir 
360cdf0e10cSrcweir }
361cdf0e10cSrcweir 
362cdf0e10cSrcweir static bool isAscii( const rtl::OUString& rStr )
363cdf0e10cSrcweir {
364cdf0e10cSrcweir     const sal_Unicode* pStr = rStr;
365cdf0e10cSrcweir     sal_Int32 nLen = rStr.getLength();
366cdf0e10cSrcweir     for( sal_Int32 i = 0; i < nLen; i++ )
367cdf0e10cSrcweir         if( pStr[i] > 127 )
368cdf0e10cSrcweir             return false;
369cdf0e10cSrcweir     return true;
370cdf0e10cSrcweir }
371cdf0e10cSrcweir 
372cdf0e10cSrcweir sal_Bool
373cdf0e10cSrcweir PrinterJob::StartJob (
374cdf0e10cSrcweir                       const rtl::OUString& rFileName,
375cdf0e10cSrcweir                       int nMode,
376cdf0e10cSrcweir                       const rtl::OUString& rJobName,
377cdf0e10cSrcweir                       const rtl::OUString& rAppName,
378cdf0e10cSrcweir                       const JobData& rSetupData,
379cdf0e10cSrcweir                       PrinterGfx* pGraphics,
380cdf0e10cSrcweir                       bool bIsQuickJob
381cdf0e10cSrcweir                       )
382cdf0e10cSrcweir {
383cdf0e10cSrcweir     m_bQuickJob = bIsQuickJob;
384cdf0e10cSrcweir     mnMaxWidthPt = mnMaxHeightPt = 0;
385cdf0e10cSrcweir     mnLandscapes = mnPortraits = 0;
386cdf0e10cSrcweir     m_pGraphics = pGraphics;
387cdf0e10cSrcweir     InitPaperSize (rSetupData);
388cdf0e10cSrcweir 
389cdf0e10cSrcweir     // create file container for document header and trailer
390cdf0e10cSrcweir     maFileName = rFileName;
391cdf0e10cSrcweir     mnFileMode = nMode;
392cdf0e10cSrcweir     maSpoolDirName = createSpoolDir ();
393cdf0e10cSrcweir     maJobTitle = rJobName;
394cdf0e10cSrcweir 
395cdf0e10cSrcweir     rtl::OUString aExt = rtl::OUString::createFromAscii (".ps");
396cdf0e10cSrcweir     mpJobHeader  = CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt);
397cdf0e10cSrcweir     mpJobTrailer = CreateSpoolFile (rtl::OUString::createFromAscii("psp_tail"), aExt);
398cdf0e10cSrcweir     if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor
399cdf0e10cSrcweir         return sal_False;
400cdf0e10cSrcweir 
401cdf0e10cSrcweir     // write document header according to Document Structuring Conventions (DSC)
402cdf0e10cSrcweir     WritePS (mpJobHeader,
403cdf0e10cSrcweir              "%!PS-Adobe-3.0\n"
404cdf0e10cSrcweir              "%%BoundingBox: (atend)\n" );
405cdf0e10cSrcweir 
406cdf0e10cSrcweir     rtl::OUString aFilterWS;
407cdf0e10cSrcweir 
408cdf0e10cSrcweir     // Creator (this application)
409cdf0e10cSrcweir     aFilterWS = WhitespaceToSpace( rAppName, sal_False );
410cdf0e10cSrcweir     WritePS (mpJobHeader, "%%Creator: (");
411cdf0e10cSrcweir     WritePS (mpJobHeader, aFilterWS);
412cdf0e10cSrcweir     WritePS (mpJobHeader, ")\n");
413cdf0e10cSrcweir 
414cdf0e10cSrcweir     // For (user name)
415cdf0e10cSrcweir     sal_Char pUserName[64];
416cdf0e10cSrcweir     if (getUserName(pUserName, sizeof(pUserName)))
417cdf0e10cSrcweir     {
418cdf0e10cSrcweir         WritePS (mpJobHeader, "%%For: (");
419cdf0e10cSrcweir         WritePS (mpJobHeader, pUserName);
420cdf0e10cSrcweir         WritePS (mpJobHeader, ")\n");
421cdf0e10cSrcweir     }
422cdf0e10cSrcweir 
423cdf0e10cSrcweir     // Creation Date (locale independent local time)
424cdf0e10cSrcweir     sal_Char pCreationDate [256];
425cdf0e10cSrcweir     WritePS (mpJobHeader, "%%CreationDate: (");
426cdf0e10cSrcweir     getLocalTime(pCreationDate);
427cdf0e10cSrcweir     for( unsigned int i = 0; i < sizeof(pCreationDate)/sizeof(pCreationDate[0]); i++ )
428cdf0e10cSrcweir     {
429cdf0e10cSrcweir         if( pCreationDate[i] == '\n' )
430cdf0e10cSrcweir         {
431cdf0e10cSrcweir             pCreationDate[i] = 0;
432cdf0e10cSrcweir             break;
433cdf0e10cSrcweir         }
434cdf0e10cSrcweir     }
435cdf0e10cSrcweir     WritePS (mpJobHeader, pCreationDate );
436cdf0e10cSrcweir     WritePS (mpJobHeader, ")\n");
437cdf0e10cSrcweir 
438cdf0e10cSrcweir     // Document Title
439cdf0e10cSrcweir     /* #i74335#
440cdf0e10cSrcweir     * The title should be clean ascii; rJobName however may
441cdf0e10cSrcweir     * contain any Unicode character. So implement the following
442cdf0e10cSrcweir     * algorithm:
443cdf0e10cSrcweir     * use rJobName, if it contains only ascii
444cdf0e10cSrcweir     * use the filename, if it contains only ascii
445cdf0e10cSrcweir     * else omit %%Title
446cdf0e10cSrcweir     */
447cdf0e10cSrcweir     aFilterWS = WhitespaceToSpace( rJobName, sal_False );
448cdf0e10cSrcweir     rtl::OUString aTitle( aFilterWS );
449cdf0e10cSrcweir     if( ! isAscii( aTitle ) )
450cdf0e10cSrcweir     {
451cdf0e10cSrcweir         sal_Int32 nIndex = 0;
452cdf0e10cSrcweir         while( nIndex != -1 )
453cdf0e10cSrcweir             aTitle = rFileName.getToken( 0, '/', nIndex );
454cdf0e10cSrcweir         aTitle = WhitespaceToSpace( aTitle, sal_False );
455cdf0e10cSrcweir         if( ! isAscii( aTitle ) )
456cdf0e10cSrcweir             aTitle = rtl::OUString();
457cdf0e10cSrcweir     }
458cdf0e10cSrcweir 
459cdf0e10cSrcweir     maJobTitle = aFilterWS;
460cdf0e10cSrcweir     if( aTitle.getLength() )
461cdf0e10cSrcweir     {
462cdf0e10cSrcweir         WritePS (mpJobHeader, "%%Title: (");
463cdf0e10cSrcweir         WritePS (mpJobHeader, aTitle);
464cdf0e10cSrcweir         WritePS (mpJobHeader, ")\n");
465cdf0e10cSrcweir     }
466cdf0e10cSrcweir 
467cdf0e10cSrcweir     // Language Level
468cdf0e10cSrcweir     sal_Char pLevel[16];
469cdf0e10cSrcweir     sal_Int32 nSz = getValueOf(GetPostscriptLevel(&rSetupData), pLevel);
470cdf0e10cSrcweir     pLevel[nSz++] = '\n';
471cdf0e10cSrcweir     pLevel[nSz  ] = '\0';
472cdf0e10cSrcweir     WritePS (mpJobHeader, "%%LanguageLevel: ");
473cdf0e10cSrcweir     WritePS (mpJobHeader, pLevel);
474cdf0e10cSrcweir 
475cdf0e10cSrcweir     // Other
476cdf0e10cSrcweir     WritePS (mpJobHeader, "%%DocumentData: Clean7Bit\n");
477cdf0e10cSrcweir     WritePS (mpJobHeader, "%%Pages: (atend)\n");
478cdf0e10cSrcweir     WritePS (mpJobHeader, "%%Orientation: (atend)\n");
479cdf0e10cSrcweir     WritePS (mpJobHeader, "%%PageOrder: Ascend\n");
480cdf0e10cSrcweir     WritePS (mpJobHeader, "%%EndComments\n");
481cdf0e10cSrcweir 
482cdf0e10cSrcweir     // write Prolog
483cdf0e10cSrcweir     writeProlog (mpJobHeader, rSetupData);
484cdf0e10cSrcweir 
485cdf0e10cSrcweir     // mark last job setup as not set
486cdf0e10cSrcweir     m_aLastJobData.m_pParser = NULL;
487cdf0e10cSrcweir     m_aLastJobData.m_aContext.setParser( NULL );
488cdf0e10cSrcweir 
489cdf0e10cSrcweir     return sal_True;
490cdf0e10cSrcweir }
491cdf0e10cSrcweir 
492cdf0e10cSrcweir sal_Bool
493cdf0e10cSrcweir PrinterJob::EndJob ()
494cdf0e10cSrcweir {
495cdf0e10cSrcweir     // no pages ? that really means no print job
496cdf0e10cSrcweir     if( maPageList.empty() )
497cdf0e10cSrcweir         return sal_False;
498cdf0e10cSrcweir 
499cdf0e10cSrcweir     // write document setup (done here because it
500cdf0e10cSrcweir     // includes the accumulated fonts
501cdf0e10cSrcweir     if( mpJobHeader )
502cdf0e10cSrcweir         writeSetup( mpJobHeader, m_aDocumentJobData );
503cdf0e10cSrcweir     m_pGraphics->OnEndJob();
504cdf0e10cSrcweir     if( ! (mpJobHeader && mpJobTrailer) )
505cdf0e10cSrcweir         return sal_False;
506cdf0e10cSrcweir 
507cdf0e10cSrcweir     // write document trailer according to Document Structuring Conventions (DSC)
508cdf0e10cSrcweir     rtl::OStringBuffer aTrailer(512);
509cdf0e10cSrcweir     aTrailer.append( "%%Trailer\n" );
510cdf0e10cSrcweir     aTrailer.append( "%%BoundingBox: 0 0 " );
511cdf0e10cSrcweir     aTrailer.append( (sal_Int32)mnMaxWidthPt );
512cdf0e10cSrcweir     aTrailer.append( " " );
513cdf0e10cSrcweir     aTrailer.append( (sal_Int32)mnMaxHeightPt );
514cdf0e10cSrcweir     if( mnLandscapes > mnPortraits )
515cdf0e10cSrcweir         aTrailer.append("\n%%Orientation: Landscape");
516cdf0e10cSrcweir     else
517cdf0e10cSrcweir         aTrailer.append("\n%%Orientation: Portrait");
518cdf0e10cSrcweir     aTrailer.append( "\n%%Pages: " );
519cdf0e10cSrcweir     aTrailer.append( (sal_Int32)maPageList.size() );
520cdf0e10cSrcweir     aTrailer.append( "\n%%EOF\n" );
521cdf0e10cSrcweir     WritePS (mpJobTrailer, aTrailer.getStr());
522cdf0e10cSrcweir 
523cdf0e10cSrcweir     /*
524cdf0e10cSrcweir      * spool the set of files to their final destination, this is U**X dependent
525cdf0e10cSrcweir      */
526cdf0e10cSrcweir 
527cdf0e10cSrcweir     FILE* pDestFILE = NULL;
528cdf0e10cSrcweir 
529cdf0e10cSrcweir     /* create a destination either as file or as a pipe */
530cdf0e10cSrcweir     sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False;
531cdf0e10cSrcweir     if (bSpoolToFile)
532cdf0e10cSrcweir     {
533cdf0e10cSrcweir         const rtl::OString aFileName = rtl::OUStringToOString (maFileName,
534cdf0e10cSrcweir                                                                osl_getThreadTextEncoding());
535cdf0e10cSrcweir         if( mnFileMode )
536cdf0e10cSrcweir         {
537cdf0e10cSrcweir             int nFile = open( aFileName.getStr(), O_CREAT | O_EXCL | O_RDWR, mnFileMode );
538cdf0e10cSrcweir             if( nFile != -1 )
539cdf0e10cSrcweir             {
540cdf0e10cSrcweir                 pDestFILE = fdopen( nFile, "w" );
541cdf0e10cSrcweir                 if( pDestFILE == NULL )
542cdf0e10cSrcweir                 {
543cdf0e10cSrcweir                     close( nFile );
544cdf0e10cSrcweir                     unlink( aFileName.getStr() );
545cdf0e10cSrcweir                     return sal_False;
546cdf0e10cSrcweir                 }
547cdf0e10cSrcweir             }
548cdf0e10cSrcweir             else
549cdf0e10cSrcweir                 chmod( aFileName.getStr(), mnFileMode );
550cdf0e10cSrcweir         }
551cdf0e10cSrcweir         if (pDestFILE == NULL)
552cdf0e10cSrcweir             pDestFILE = fopen (aFileName.getStr(), "w");
553cdf0e10cSrcweir 
554cdf0e10cSrcweir         if (pDestFILE == NULL)
555cdf0e10cSrcweir             return sal_False;
556cdf0e10cSrcweir     }
557cdf0e10cSrcweir     else
558cdf0e10cSrcweir     {
559cdf0e10cSrcweir         PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get ();
560cdf0e10cSrcweir         pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob );
561cdf0e10cSrcweir         if (pDestFILE == NULL)
562cdf0e10cSrcweir             return sal_False;
563cdf0e10cSrcweir     }
564cdf0e10cSrcweir 
565cdf0e10cSrcweir     /* spool the document parts to the destination */
566cdf0e10cSrcweir 
567cdf0e10cSrcweir     sal_uChar pBuffer[ nBLOCKSIZE ];
568cdf0e10cSrcweir 
569cdf0e10cSrcweir     AppendPS (pDestFILE, mpJobHeader, pBuffer);
570cdf0e10cSrcweir     mpJobHeader->close();
571cdf0e10cSrcweir 
572cdf0e10cSrcweir     sal_Bool bSuccess = sal_True;
573cdf0e10cSrcweir     std::list< osl::File* >::iterator pPageBody;
574cdf0e10cSrcweir     std::list< osl::File* >::iterator pPageHead;
575cdf0e10cSrcweir     for (pPageBody  = maPageList.begin(), pPageHead  = maHeaderList.begin();
576cdf0e10cSrcweir          pPageBody != maPageList.end() && pPageHead != maHeaderList.end();
577cdf0e10cSrcweir          pPageBody++, pPageHead++)
578cdf0e10cSrcweir     {
579cdf0e10cSrcweir         if( *pPageHead )
580cdf0e10cSrcweir         {
581cdf0e10cSrcweir             osl::File::RC nError = (*pPageHead)->open(OpenFlag_Read);
582cdf0e10cSrcweir             if (nError == osl::File::E_None)
583cdf0e10cSrcweir             {
584cdf0e10cSrcweir                 AppendPS (pDestFILE, *pPageHead, pBuffer);
585cdf0e10cSrcweir                 (*pPageHead)->close();
586cdf0e10cSrcweir             }
587cdf0e10cSrcweir         }
588cdf0e10cSrcweir         else
589cdf0e10cSrcweir             bSuccess = sal_False;
590cdf0e10cSrcweir         if( *pPageBody )
591cdf0e10cSrcweir         {
592cdf0e10cSrcweir             osl::File::RC nError = (*pPageBody)->open(OpenFlag_Read);
593cdf0e10cSrcweir             if (nError == osl::File::E_None)
594cdf0e10cSrcweir             {
595cdf0e10cSrcweir                 AppendPS (pDestFILE, *pPageBody, pBuffer);
596cdf0e10cSrcweir                 (*pPageBody)->close();
597cdf0e10cSrcweir             }
598cdf0e10cSrcweir         }
599cdf0e10cSrcweir         else
600cdf0e10cSrcweir             bSuccess = sal_False;
601cdf0e10cSrcweir     }
602cdf0e10cSrcweir 
603cdf0e10cSrcweir     AppendPS (pDestFILE, mpJobTrailer, pBuffer);
604cdf0e10cSrcweir     mpJobTrailer->close();
605cdf0e10cSrcweir 
606cdf0e10cSrcweir     /* well done */
607cdf0e10cSrcweir 
608cdf0e10cSrcweir     if (bSpoolToFile)
609cdf0e10cSrcweir         fclose (pDestFILE);
610cdf0e10cSrcweir     else
611cdf0e10cSrcweir     {
612cdf0e10cSrcweir         PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get();
613cdf0e10cSrcweir         if (0 == rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName,
614cdf0e10cSrcweir 			maJobTitle, pDestFILE, m_aDocumentJobData, true ))
615cdf0e10cSrcweir 		{
616cdf0e10cSrcweir 			bSuccess = sal_False;
617cdf0e10cSrcweir 		}
618cdf0e10cSrcweir     }
619cdf0e10cSrcweir 
620cdf0e10cSrcweir     return bSuccess;
621cdf0e10cSrcweir }
622cdf0e10cSrcweir 
623cdf0e10cSrcweir sal_Bool
624cdf0e10cSrcweir PrinterJob::AbortJob ()
625cdf0e10cSrcweir {
626cdf0e10cSrcweir     m_pGraphics->OnEndJob();
627cdf0e10cSrcweir     return sal_False;
628cdf0e10cSrcweir }
629cdf0e10cSrcweir 
630cdf0e10cSrcweir void
631cdf0e10cSrcweir PrinterJob::InitPaperSize (const JobData& rJobSetup)
632cdf0e10cSrcweir {
633cdf0e10cSrcweir     int nRes = rJobSetup.m_aContext.getRenderResolution ();
634cdf0e10cSrcweir 
635cdf0e10cSrcweir     String aPaper;
636cdf0e10cSrcweir     int nWidth, nHeight;
637cdf0e10cSrcweir     rJobSetup.m_aContext.getPageSize (aPaper, nWidth, nHeight);
638cdf0e10cSrcweir 
639cdf0e10cSrcweir     int nLeft = 0, nRight = 0, nUpper = 0, nLower = 0;
640cdf0e10cSrcweir     const PPDParser* pParser = rJobSetup.m_aContext.getParser();
641cdf0e10cSrcweir     if (pParser != NULL)
642cdf0e10cSrcweir         pParser->getMargins (aPaper, nLeft, nRight, nUpper, nLower);
643cdf0e10cSrcweir 
644cdf0e10cSrcweir     mnResolution	= nRes;
645cdf0e10cSrcweir 
646cdf0e10cSrcweir     mnWidthPt       = nWidth;
647cdf0e10cSrcweir     mnHeightPt      = nHeight;
648cdf0e10cSrcweir 
649cdf0e10cSrcweir     if( mnWidthPt > mnMaxWidthPt )
650cdf0e10cSrcweir         mnMaxWidthPt = mnWidthPt;
651cdf0e10cSrcweir     if( mnHeightPt > mnMaxHeightPt )
652cdf0e10cSrcweir         mnMaxHeightPt = mnHeightPt;
653cdf0e10cSrcweir 
654cdf0e10cSrcweir     mnLMarginPt     = nLeft;
655cdf0e10cSrcweir     mnRMarginPt     = nRight;
656cdf0e10cSrcweir     mnTMarginPt     = nUpper;
657cdf0e10cSrcweir     mnBMarginPt     = nLower;
658cdf0e10cSrcweir 
659cdf0e10cSrcweir     mfXScale        = (double)72.0 / (double)mnResolution;
660cdf0e10cSrcweir     mfYScale        = -1.0 * (double)72.0 / (double)mnResolution;
661cdf0e10cSrcweir }
662cdf0e10cSrcweir 
663cdf0e10cSrcweir 
664cdf0e10cSrcweir sal_Bool
665cdf0e10cSrcweir PrinterJob::StartPage (const JobData& rJobSetup)
666cdf0e10cSrcweir {
667cdf0e10cSrcweir     InitPaperSize (rJobSetup);
668cdf0e10cSrcweir 
669cdf0e10cSrcweir     rtl::OUString aPageNo = rtl::OUString::valueOf ((sal_Int32)maPageList.size()+1); // sequential page number must start with 1
670cdf0e10cSrcweir     rtl::OUString aExt    = aPageNo + rtl::OUString::createFromAscii (".ps");
671cdf0e10cSrcweir 
672cdf0e10cSrcweir     osl::File* pPageHeader = CreateSpoolFile (
673cdf0e10cSrcweir                                               rtl::OUString::createFromAscii("psp_pghead"), aExt);
674cdf0e10cSrcweir     osl::File* pPageBody   = CreateSpoolFile (
675cdf0e10cSrcweir                                               rtl::OUString::createFromAscii("psp_pgbody"), aExt);
676cdf0e10cSrcweir 
677cdf0e10cSrcweir     maHeaderList.push_back (pPageHeader);
678cdf0e10cSrcweir     maPageList.push_back (pPageBody);
679cdf0e10cSrcweir 
680cdf0e10cSrcweir     if( ! (pPageHeader && pPageBody) )
681cdf0e10cSrcweir         return sal_False;
682cdf0e10cSrcweir 
683cdf0e10cSrcweir     // write page header according to Document Structuring Conventions (DSC)
684cdf0e10cSrcweir     WritePS (pPageHeader, "%%Page: ");
685cdf0e10cSrcweir     WritePS (pPageHeader, aPageNo);
686cdf0e10cSrcweir     WritePS (pPageHeader, " ");
687cdf0e10cSrcweir     WritePS (pPageHeader, aPageNo);
688cdf0e10cSrcweir     WritePS (pPageHeader, "\n");
689cdf0e10cSrcweir 
690cdf0e10cSrcweir     if( rJobSetup.m_eOrientation == orientation::Landscape )
691cdf0e10cSrcweir     {
692cdf0e10cSrcweir         WritePS (pPageHeader, "%%PageOrientation: Landscape\n");
693cdf0e10cSrcweir         mnLandscapes++;
694cdf0e10cSrcweir     }
695cdf0e10cSrcweir     else
696cdf0e10cSrcweir     {
697cdf0e10cSrcweir         WritePS (pPageHeader, "%%PageOrientation: Portrait\n");
698cdf0e10cSrcweir         mnPortraits++;
699cdf0e10cSrcweir     }
700cdf0e10cSrcweir 
701cdf0e10cSrcweir     sal_Char  pBBox [256];
702cdf0e10cSrcweir     sal_Int32 nChar = 0;
703cdf0e10cSrcweir 
704cdf0e10cSrcweir     nChar  = psp::appendStr  ("%%PageBoundingBox: ",    pBBox);
705cdf0e10cSrcweir     nChar += psp::getValueOf (mnLMarginPt,              pBBox + nChar);
706cdf0e10cSrcweir     nChar += psp::appendStr  (" ",                      pBBox + nChar);
707cdf0e10cSrcweir     nChar += psp::getValueOf (mnBMarginPt,              pBBox + nChar);
708cdf0e10cSrcweir     nChar += psp::appendStr  (" ",                      pBBox + nChar);
709cdf0e10cSrcweir     nChar += psp::getValueOf (mnWidthPt  - mnRMarginPt, pBBox + nChar);
710cdf0e10cSrcweir     nChar += psp::appendStr  (" ",                      pBBox + nChar);
711cdf0e10cSrcweir     nChar += psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox + nChar);
712cdf0e10cSrcweir     nChar += psp::appendStr  ("\n",                     pBBox + nChar);
713cdf0e10cSrcweir 
714cdf0e10cSrcweir     WritePS (pPageHeader, pBBox);
715cdf0e10cSrcweir 
716cdf0e10cSrcweir     /* #i7262# #i65491# write setup only before first page
717cdf0e10cSrcweir      *  (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup)
718cdf0e10cSrcweir      *  don't do this in StartJob since the jobsetup there may be
719cdf0e10cSrcweir      *  different.
720cdf0e10cSrcweir      */
721cdf0e10cSrcweir     bool bWriteFeatures = true;
722cdf0e10cSrcweir     if( 1 == maPageList.size() )
723cdf0e10cSrcweir     {
724cdf0e10cSrcweir         m_aDocumentJobData = rJobSetup;
725cdf0e10cSrcweir         bWriteFeatures = false;
726cdf0e10cSrcweir     }
727cdf0e10cSrcweir 
728cdf0e10cSrcweir     if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) )
729cdf0e10cSrcweir     {
730cdf0e10cSrcweir         m_aLastJobData = rJobSetup;
731cdf0e10cSrcweir         return true;
732cdf0e10cSrcweir     }
733cdf0e10cSrcweir 
734cdf0e10cSrcweir     return false;
735cdf0e10cSrcweir }
736cdf0e10cSrcweir 
737cdf0e10cSrcweir sal_Bool
738cdf0e10cSrcweir PrinterJob::EndPage ()
739cdf0e10cSrcweir {
740cdf0e10cSrcweir     m_pGraphics->OnEndPage();
741cdf0e10cSrcweir 
742cdf0e10cSrcweir     osl::File* pPageHeader = maHeaderList.back();
743cdf0e10cSrcweir     osl::File* pPageBody   = maPageList.back();
744cdf0e10cSrcweir 
745cdf0e10cSrcweir     if( ! (pPageBody && pPageHeader) )
746cdf0e10cSrcweir         return sal_False;
747cdf0e10cSrcweir 
748cdf0e10cSrcweir     // copy page to paper and write page trailer according to DSC
749cdf0e10cSrcweir 
750cdf0e10cSrcweir     sal_Char pTrailer[256];
751cdf0e10cSrcweir     sal_Int32 nChar = 0;
752cdf0e10cSrcweir     nChar  = psp::appendStr ("grestore grestore\n", pTrailer);
753cdf0e10cSrcweir     nChar += psp::appendStr ("showpage\n",          pTrailer + nChar);
754cdf0e10cSrcweir     nChar += psp::appendStr ("%%PageTrailer\n\n",   pTrailer + nChar);
755cdf0e10cSrcweir     WritePS (pPageBody, pTrailer);
756cdf0e10cSrcweir 
757cdf0e10cSrcweir     // this page is done for now, close it to avoid having too many open fd's
758cdf0e10cSrcweir 
759cdf0e10cSrcweir     pPageHeader->close();
760cdf0e10cSrcweir     pPageBody->close();
761cdf0e10cSrcweir 
762cdf0e10cSrcweir     return sal_True;
763cdf0e10cSrcweir }
764cdf0e10cSrcweir 
765cdf0e10cSrcweir sal_uInt32
766cdf0e10cSrcweir PrinterJob::GetErrorCode ()
767cdf0e10cSrcweir {
768cdf0e10cSrcweir     /* TODO */
769cdf0e10cSrcweir     return 0;
770cdf0e10cSrcweir }
771cdf0e10cSrcweir 
772cdf0e10cSrcweir struct less_ppd_key : public ::std::binary_function<double, double, bool>
773cdf0e10cSrcweir {
774cdf0e10cSrcweir     bool operator()(const PPDKey* left, const PPDKey* right)
775cdf0e10cSrcweir     { return left->getOrderDependency() < right->getOrderDependency(); }
776cdf0e10cSrcweir };
777cdf0e10cSrcweir 
778cdf0e10cSrcweir static bool writeFeature( osl::File* pFile, const PPDKey* pKey, const PPDValue* pValue, bool bUseIncluseFeature )
779cdf0e10cSrcweir {
780cdf0e10cSrcweir     if( ! pKey || ! pValue )
781cdf0e10cSrcweir         return true;
782cdf0e10cSrcweir 
783cdf0e10cSrcweir     OStringBuffer aFeature(256);
784cdf0e10cSrcweir     aFeature.append( "[{\n" );
785cdf0e10cSrcweir     if( bUseIncluseFeature )
786cdf0e10cSrcweir         aFeature.append( "%%IncludeFeature:" );
787cdf0e10cSrcweir     else
788cdf0e10cSrcweir         aFeature.append( "%%BeginFeature:" );
789cdf0e10cSrcweir     aFeature.append( " *" );
790cdf0e10cSrcweir     aFeature.append( OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ) );
791cdf0e10cSrcweir     aFeature.append( ' ' );
792cdf0e10cSrcweir     aFeature.append( OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) );
793cdf0e10cSrcweir     if( !bUseIncluseFeature )
794cdf0e10cSrcweir     {
795cdf0e10cSrcweir         aFeature.append( '\n' );
796cdf0e10cSrcweir         aFeature.append( OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US ) );
797cdf0e10cSrcweir         aFeature.append( "\n%%EndFeature" );
798cdf0e10cSrcweir     }
799cdf0e10cSrcweir     aFeature.append( "\n} stopped cleartomark\n" );
800cdf0e10cSrcweir     sal_uInt64 nWritten = 0;
801cdf0e10cSrcweir     return pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten )
802cdf0e10cSrcweir         || nWritten != (sal_uInt64)aFeature.getLength() ? false : true;
803cdf0e10cSrcweir }
804cdf0e10cSrcweir 
805cdf0e10cSrcweir bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup )
806cdf0e10cSrcweir {
807cdf0e10cSrcweir     bool bSuccess = true;
808cdf0e10cSrcweir     int i;
809cdf0e10cSrcweir 
810cdf0e10cSrcweir     // emit features ordered to OrderDependency
811cdf0e10cSrcweir     // ignore features that are set to default
812cdf0e10cSrcweir 
813cdf0e10cSrcweir     // sanity check
814cdf0e10cSrcweir     if( rJob.m_pParser == rJob.m_aContext.getParser() &&
815cdf0e10cSrcweir         rJob.m_pParser &&
816cdf0e10cSrcweir         ( m_aLastJobData.m_pParser == rJob.m_pParser || m_aLastJobData.m_pParser == NULL )
817cdf0e10cSrcweir         )
818cdf0e10cSrcweir     {
819cdf0e10cSrcweir         int nKeys = rJob.m_aContext.countValuesModified();
820cdf0e10cSrcweir         ::std::vector< const PPDKey* > aKeys( nKeys );
821cdf0e10cSrcweir         for(  i = 0; i < nKeys; i++ )
822cdf0e10cSrcweir             aKeys[i] = rJob.m_aContext.getModifiedKey( i );
823cdf0e10cSrcweir         ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
824cdf0e10cSrcweir 
825cdf0e10cSrcweir         for( i = 0; i < nKeys && bSuccess; i++ )
826cdf0e10cSrcweir         {
827cdf0e10cSrcweir             const PPDKey* pKey = aKeys[i];
828cdf0e10cSrcweir             bool bEmit = false;
829cdf0e10cSrcweir             if( bDocumentSetup )
830cdf0e10cSrcweir             {
831cdf0e10cSrcweir                 if( pKey->getSetupType()    == PPDKey::DocumentSetup )
832cdf0e10cSrcweir                     bEmit = true;
833cdf0e10cSrcweir             }
834cdf0e10cSrcweir             if( pKey->getSetupType()    == PPDKey::PageSetup        ||
835cdf0e10cSrcweir                 pKey->getSetupType()    == PPDKey::AnySetup )
836cdf0e10cSrcweir                 bEmit = true;
837cdf0e10cSrcweir             if( bEmit )
838cdf0e10cSrcweir             {
839cdf0e10cSrcweir                 const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
840cdf0e10cSrcweir                 if( pValue
841cdf0e10cSrcweir                     && pValue->m_eType == eInvocation
842cdf0e10cSrcweir                     && ( m_aLastJobData.m_pParser == NULL
843cdf0e10cSrcweir                          || m_aLastJobData.m_aContext.getValue( pKey ) != pValue
844cdf0e10cSrcweir                          || bDocumentSetup
845cdf0e10cSrcweir                          )
846cdf0e10cSrcweir                    )
847cdf0e10cSrcweir                 {
848cdf0e10cSrcweir                     // try to avoid PS level 2 feature commands if level is set to 1
849cdf0e10cSrcweir                     if( GetPostscriptLevel( &rJob ) == 1 )
850cdf0e10cSrcweir                     {
851cdf0e10cSrcweir                         bool bHavePS2 =
852cdf0e10cSrcweir                             ( pValue->m_aValue.SearchAscii( "<<" ) != STRING_NOTFOUND )
853cdf0e10cSrcweir                             ||
854cdf0e10cSrcweir                             ( pValue->m_aValue.SearchAscii( ">>" ) != STRING_NOTFOUND );
855cdf0e10cSrcweir                         if( bHavePS2 )
856cdf0e10cSrcweir                             continue;
857cdf0e10cSrcweir                     }
858cdf0e10cSrcweir                     bSuccess = writeFeature( pFile, pKey, pValue, PrinterInfoManager::get().getUseIncludeFeature() );
859cdf0e10cSrcweir                 }
860cdf0e10cSrcweir             }
861cdf0e10cSrcweir         }
862cdf0e10cSrcweir     }
863cdf0e10cSrcweir     else
864cdf0e10cSrcweir         bSuccess = false;
865cdf0e10cSrcweir 
866cdf0e10cSrcweir     return bSuccess;
867cdf0e10cSrcweir }
868cdf0e10cSrcweir 
869cdf0e10cSrcweir bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob, bool bWriteFeatures )
870cdf0e10cSrcweir {
871cdf0e10cSrcweir     bool bSuccess = true;
872cdf0e10cSrcweir 
873cdf0e10cSrcweir     WritePS (pFile, "%%BeginPageSetup\n%\n");
874cdf0e10cSrcweir     if ( bWriteFeatures )
875cdf0e10cSrcweir         bSuccess = writeFeatureList( pFile, rJob, false );
876cdf0e10cSrcweir     WritePS (pFile, "%%EndPageSetup\n");
877cdf0e10cSrcweir 
878cdf0e10cSrcweir     sal_Char  pTranslate [128];
879cdf0e10cSrcweir     sal_Int32 nChar = 0;
880cdf0e10cSrcweir 
881cdf0e10cSrcweir     if( rJob.m_eOrientation == orientation::Portrait )
882cdf0e10cSrcweir     {
883cdf0e10cSrcweir         nChar  = psp::appendStr  ("gsave\n[",   pTranslate);
884cdf0e10cSrcweir         nChar += psp::getValueOfDouble (        pTranslate + nChar, mfXScale, 5);
885cdf0e10cSrcweir         nChar += psp::appendStr  (" 0 0 ",      pTranslate + nChar);
886cdf0e10cSrcweir         nChar += psp::getValueOfDouble (        pTranslate + nChar, mfYScale, 5);
887cdf0e10cSrcweir         nChar += psp::appendStr  (" ",          pTranslate + nChar);
888cdf0e10cSrcweir         nChar += psp::getValueOf (mnRMarginPt,  pTranslate + nChar);
889cdf0e10cSrcweir         nChar += psp::appendStr  (" ",          pTranslate + nChar);
890cdf0e10cSrcweir         nChar += psp::getValueOf (mnHeightPt-mnTMarginPt,
891cdf0e10cSrcweir                                   pTranslate + nChar);
892cdf0e10cSrcweir         nChar += psp::appendStr  ("] concat\ngsave\n",
893cdf0e10cSrcweir                                   pTranslate + nChar);
894cdf0e10cSrcweir     }
895cdf0e10cSrcweir     else
896cdf0e10cSrcweir     {
897cdf0e10cSrcweir         nChar  = psp::appendStr  ("gsave\n",    pTranslate);
898cdf0e10cSrcweir         nChar += psp::appendStr  ("[ 0 ",       pTranslate + nChar);
899cdf0e10cSrcweir         nChar += psp::getValueOfDouble (        pTranslate + nChar, -mfYScale, 5);
900cdf0e10cSrcweir         nChar += psp::appendStr  (" ",          pTranslate + nChar);
901cdf0e10cSrcweir         nChar += psp::getValueOfDouble (        pTranslate + nChar, mfXScale, 5);
902cdf0e10cSrcweir         nChar += psp::appendStr  (" 0 ",        pTranslate + nChar );
903cdf0e10cSrcweir         nChar += psp::getValueOfDouble (        pTranslate + nChar, mnLMarginPt, 5 );
904cdf0e10cSrcweir         nChar += psp::appendStr  (" ",          pTranslate + nChar);
905cdf0e10cSrcweir         nChar += psp::getValueOf (mnBMarginPt,  pTranslate + nChar );
906cdf0e10cSrcweir         nChar += psp::appendStr ("] concat\ngsave\n",
907cdf0e10cSrcweir                                  pTranslate + nChar);
908cdf0e10cSrcweir     }
909cdf0e10cSrcweir 
910cdf0e10cSrcweir     WritePS (pFile, pTranslate);
911cdf0e10cSrcweir 
912cdf0e10cSrcweir     return bSuccess;
913cdf0e10cSrcweir }
914cdf0e10cSrcweir 
915cdf0e10cSrcweir void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData )
916cdf0e10cSrcweir {
917cdf0e10cSrcweir     if( ! PrinterInfoManager::get().getUseJobPatch() )
918cdf0e10cSrcweir         return;
919cdf0e10cSrcweir 
920cdf0e10cSrcweir     const PPDKey* pKey = NULL;
921cdf0e10cSrcweir 
922cdf0e10cSrcweir     if( rJobData.m_pParser )
923cdf0e10cSrcweir         pKey = rJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "JobPatchFile" ) ) );
924cdf0e10cSrcweir     if( ! pKey )
925cdf0e10cSrcweir         return;
926cdf0e10cSrcweir 
927cdf0e10cSrcweir     // order the patch files
928cdf0e10cSrcweir     // according to PPD spec the JobPatchFile options must be int
929cdf0e10cSrcweir     // and should be emitted in order
930cdf0e10cSrcweir     std::list< sal_Int32 > patch_order;
931cdf0e10cSrcweir     int nValueCount = pKey->countValues();
932cdf0e10cSrcweir     for( int i = 0; i < nValueCount; i++ )
933cdf0e10cSrcweir     {
934cdf0e10cSrcweir         const PPDValue* pVal = pKey->getValue( i );
935cdf0e10cSrcweir         patch_order.push_back( pVal->m_aOption.ToInt32() );
936cdf0e10cSrcweir         if( patch_order.back() == 0 && ! pVal->m_aOption.EqualsAscii( "0" ) )
937cdf0e10cSrcweir         {
938cdf0e10cSrcweir             WritePS( pFile, "% Warning: left out JobPatchFile option \"" );
939cdf0e10cSrcweir             OString aOption = OUStringToOString( pVal->m_aOption, RTL_TEXTENCODING_ASCII_US );
940cdf0e10cSrcweir             WritePS( pFile, aOption.getStr() );
941cdf0e10cSrcweir             WritePS( pFile,
942cdf0e10cSrcweir                      "\"\n% as it violates the PPD spec;\n"
943cdf0e10cSrcweir                      "% JobPatchFile options need to be numbered for ordering.\n" );
944cdf0e10cSrcweir         }
945cdf0e10cSrcweir     }
946cdf0e10cSrcweir 
947cdf0e10cSrcweir     patch_order.sort();
948cdf0e10cSrcweir     patch_order.unique();
949cdf0e10cSrcweir 
950cdf0e10cSrcweir     while( patch_order.begin() != patch_order.end() )
951cdf0e10cSrcweir     {
952cdf0e10cSrcweir         // note: this discards patch files not adhering to the "int" scheme
953cdf0e10cSrcweir         // as there won't be a value for them
954cdf0e10cSrcweir         writeFeature( pFile, pKey, pKey->getValue( OUString::valueOf( patch_order.front() ) ), false );
955cdf0e10cSrcweir         patch_order.pop_front();
956cdf0e10cSrcweir     }
957cdf0e10cSrcweir }
958cdf0e10cSrcweir 
959cdf0e10cSrcweir bool PrinterJob::writeProlog (osl::File* pFile, const JobData& rJobData )
960cdf0e10cSrcweir {
961cdf0e10cSrcweir     WritePS( pFile, "%%BeginProlog\n" );
962cdf0e10cSrcweir 
963cdf0e10cSrcweir     // JobPatchFile feature needs to be emitted at begin of prolog
964cdf0e10cSrcweir     writeJobPatch( pFile, rJobData );
965cdf0e10cSrcweir 
966cdf0e10cSrcweir     static const sal_Char pProlog[] = {
967cdf0e10cSrcweir         "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
968cdf0e10cSrcweir         "/ISO1252Encoding [\n"
969cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
970cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
971cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
972cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
973cdf0e10cSrcweir         "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
974cdf0e10cSrcweir         "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
975cdf0e10cSrcweir         "/zero /one /two /three /four /five /six /seven\n"
976cdf0e10cSrcweir         "/eight /nine /colon /semicolon /less /equal /greater /question\n"
977cdf0e10cSrcweir         "/at /A /B /C /D /E /F /G\n"
978cdf0e10cSrcweir         "/H /I /J /K /L /M /N /O\n"
979cdf0e10cSrcweir         "/P /Q /R /S /T /U /V /W\n"
980cdf0e10cSrcweir         "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
981cdf0e10cSrcweir         "/grave /a /b /c /d /e /f /g\n"
982cdf0e10cSrcweir         "/h /i /j /k /l /m /n /o\n"
983cdf0e10cSrcweir         "/p /q /r /s /t /u /v /w\n"
984cdf0e10cSrcweir         "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
985cdf0e10cSrcweir         "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
986cdf0e10cSrcweir         "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
987cdf0e10cSrcweir         "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
988cdf0e10cSrcweir         "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
989cdf0e10cSrcweir         "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
990cdf0e10cSrcweir         "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
991cdf0e10cSrcweir         "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
992cdf0e10cSrcweir         "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
993cdf0e10cSrcweir         "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
994cdf0e10cSrcweir         "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
995cdf0e10cSrcweir         "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
996cdf0e10cSrcweir         "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
997cdf0e10cSrcweir         "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
998cdf0e10cSrcweir         "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
999cdf0e10cSrcweir         "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
1000cdf0e10cSrcweir         "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
1001cdf0e10cSrcweir         "\n"
1002cdf0e10cSrcweir         "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
1003cdf0e10cSrcweir         "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
1004cdf0e10cSrcweir         "currentdict end exch pop definefont pop } def\n"
1005cdf0e10cSrcweir         "\n"
1006cdf0e10cSrcweir         "/pathdict dup 8 dict def load begin\n"
1007cdf0e10cSrcweir         "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
1008cdf0e10cSrcweir         "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
1009cdf0e10cSrcweir         "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
1010cdf0e10cSrcweir         "eq 3 1 roll exch } def\n"
1011cdf0e10cSrcweir         "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
1012cdf0e10cSrcweir         "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
1013cdf0e10cSrcweir         "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
1014cdf0e10cSrcweir         "for 256 div exch pop exch { neg } if } def\n"
1015cdf0e10cSrcweir         "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
1016cdf0e10cSrcweir         "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
1017cdf0e10cSrcweir         "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
1018cdf0e10cSrcweir         "\n"
1019cdf0e10cSrcweir         "systemdict /languagelevel known not {\n"
1020cdf0e10cSrcweir         "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
1021cdf0e10cSrcweir         "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
1022cdf0e10cSrcweir         "roll show moveto 0 rmoveto } for pop pop } def\n"
1023cdf0e10cSrcweir         "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
1024cdf0e10cSrcweir         "rlineto closepath } def\n"
1025cdf0e10cSrcweir         "/rectfill { rectangle fill } def\n"
1026cdf0e10cSrcweir         "/rectstroke { rectangle stroke } def } if\n"
1027cdf0e10cSrcweir         "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
1028cdf0e10cSrcweir         "setlinewidth false charpath stroke setlinewidth } def\n"
1029cdf0e10cSrcweir         "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
1030cdf0e10cSrcweir         "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
1031cdf0e10cSrcweir         "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
1032cdf0e10cSrcweir         "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
1033cdf0e10cSrcweir         "\n"
1034cdf0e10cSrcweir 		"/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
1035cdf0e10cSrcweir 		"/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
1036cdf0e10cSrcweir 		"/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
1037cdf0e10cSrcweir 		"/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
1038cdf0e10cSrcweir 		"/psp_imagedict {\n"
1039cdf0e10cSrcweir 		"/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
1040cdf0e10cSrcweir 		"/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
1041cdf0e10cSrcweir 		"def 7 dict dup\n"
1042cdf0e10cSrcweir 		"/ImageType 1 put dup\n"
1043cdf0e10cSrcweir 		"/Width 7 -1 roll put dup\n"
1044cdf0e10cSrcweir 		"/Height 5 index put dup\n"
1045cdf0e10cSrcweir 		"/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
1046cdf0e10cSrcweir 		"/Decode 5 -1 roll psp_decodearray put dup\n"
1047cdf0e10cSrcweir 		"/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
1048cdf0e10cSrcweir 		"/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
1049cdf0e10cSrcweir         "} def\n"
1050cdf0e10cSrcweir         "%%EndResource\n"
1051cdf0e10cSrcweir         "%%EndProlog\n"
1052cdf0e10cSrcweir     };
1053cdf0e10cSrcweir     static const sal_Char pSO52CompatProlog[] = {
1054cdf0e10cSrcweir         "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
1055cdf0e10cSrcweir         "/ISO1252Encoding [\n"
1056cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1057cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1058cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1059cdf0e10cSrcweir         "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
1060cdf0e10cSrcweir         "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
1061cdf0e10cSrcweir         "/parenleft /parenright /asterisk /plus /comma /minus /period /slash\n"
1062cdf0e10cSrcweir         "/zero /one /two /three /four /five /six /seven\n"
1063cdf0e10cSrcweir         "/eight /nine /colon /semicolon /less /equal /greater /question\n"
1064cdf0e10cSrcweir         "/at /A /B /C /D /E /F /G\n"
1065cdf0e10cSrcweir         "/H /I /J /K /L /M /N /O\n"
1066cdf0e10cSrcweir         "/P /Q /R /S /T /U /V /W\n"
1067cdf0e10cSrcweir         "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
1068cdf0e10cSrcweir         "/grave /a /b /c /d /e /f /g\n"
1069cdf0e10cSrcweir         "/h /i /j /k /l /m /n /o\n"
1070cdf0e10cSrcweir         "/p /q /r /s /t /u /v /w\n"
1071cdf0e10cSrcweir         "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
1072cdf0e10cSrcweir         "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
1073cdf0e10cSrcweir         "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
1074cdf0e10cSrcweir         "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
1075cdf0e10cSrcweir         "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
1076cdf0e10cSrcweir         "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
1077cdf0e10cSrcweir         "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
1078cdf0e10cSrcweir         "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
1079cdf0e10cSrcweir         "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
1080cdf0e10cSrcweir         "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
1081cdf0e10cSrcweir         "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
1082cdf0e10cSrcweir         "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
1083cdf0e10cSrcweir         "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
1084cdf0e10cSrcweir         "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
1085cdf0e10cSrcweir         "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
1086cdf0e10cSrcweir         "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
1087cdf0e10cSrcweir         "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
1088cdf0e10cSrcweir         "\n"
1089cdf0e10cSrcweir         "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
1090cdf0e10cSrcweir         "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
1091cdf0e10cSrcweir         "currentdict end exch pop definefont pop } def\n"
1092cdf0e10cSrcweir         "\n"
1093cdf0e10cSrcweir         "/pathdict dup 8 dict def load begin\n"
1094cdf0e10cSrcweir         "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
1095cdf0e10cSrcweir         "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
1096cdf0e10cSrcweir         "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
1097cdf0e10cSrcweir         "eq 3 1 roll exch } def\n"
1098cdf0e10cSrcweir         "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
1099cdf0e10cSrcweir         "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
1100cdf0e10cSrcweir         "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
1101cdf0e10cSrcweir         "for 256 div exch pop exch { neg } if } def\n"
1102cdf0e10cSrcweir         "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
1103cdf0e10cSrcweir         "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
1104cdf0e10cSrcweir         "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
1105cdf0e10cSrcweir         "\n"
1106cdf0e10cSrcweir         "systemdict /languagelevel known not {\n"
1107cdf0e10cSrcweir         "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
1108cdf0e10cSrcweir         "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
1109cdf0e10cSrcweir         "roll show moveto 0 rmoveto } for pop pop } def\n"
1110cdf0e10cSrcweir         "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
1111cdf0e10cSrcweir         "rlineto closepath } def\n"
1112cdf0e10cSrcweir         "/rectfill { rectangle fill } def\n"
1113cdf0e10cSrcweir         "/rectstroke { rectangle stroke } def } if\n"
1114cdf0e10cSrcweir         "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
1115cdf0e10cSrcweir         "setlinewidth false charpath stroke setlinewidth } def\n"
1116cdf0e10cSrcweir         "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
1117cdf0e10cSrcweir         "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
1118cdf0e10cSrcweir         "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
1119cdf0e10cSrcweir         "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
1120cdf0e10cSrcweir         "\n"
1121cdf0e10cSrcweir 		"/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
1122cdf0e10cSrcweir 		"/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
1123cdf0e10cSrcweir 		"/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
1124cdf0e10cSrcweir 		"/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
1125cdf0e10cSrcweir 		"/psp_imagedict {\n"
1126cdf0e10cSrcweir 		"/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
1127cdf0e10cSrcweir 		"/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
1128cdf0e10cSrcweir 		"def 7 dict dup\n"
1129cdf0e10cSrcweir 		"/ImageType 1 put dup\n"
1130cdf0e10cSrcweir 		"/Width 7 -1 roll put dup\n"
1131cdf0e10cSrcweir 		"/Height 5 index put dup\n"
1132cdf0e10cSrcweir 		"/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
1133cdf0e10cSrcweir 		"/Decode 5 -1 roll psp_decodearray put dup\n"
1134cdf0e10cSrcweir 		"/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
1135cdf0e10cSrcweir 		"/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
1136cdf0e10cSrcweir         "} def\n"
1137cdf0e10cSrcweir         "%%EndResource\n"
1138cdf0e10cSrcweir         "%%EndProlog\n"
1139cdf0e10cSrcweir     };
1140cdf0e10cSrcweir     WritePS (pFile, m_pGraphics && m_pGraphics->getStrictSO52Compatibility() ? pSO52CompatProlog : pProlog);
1141cdf0e10cSrcweir 
1142cdf0e10cSrcweir     return true;
1143cdf0e10cSrcweir }
1144cdf0e10cSrcweir 
1145cdf0e10cSrcweir bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob )
1146cdf0e10cSrcweir {
1147cdf0e10cSrcweir     WritePS (pFile, "%%BeginSetup\n%\n");
1148cdf0e10cSrcweir 
1149cdf0e10cSrcweir     // download fonts
1150cdf0e10cSrcweir     std::list< rtl::OString > aFonts[2];
1151cdf0e10cSrcweir     m_pGraphics->writeResources( pFile, aFonts[0], aFonts[1] );
1152cdf0e10cSrcweir 
1153cdf0e10cSrcweir     for( int i = 0; i < 2; i++ )
1154cdf0e10cSrcweir     {
1155cdf0e10cSrcweir         if( !aFonts[i].empty() )
1156cdf0e10cSrcweir         {
1157cdf0e10cSrcweir             std::list< rtl::OString >::const_iterator it = aFonts[i].begin();
1158cdf0e10cSrcweir             rtl::OStringBuffer aLine( 256 );
1159cdf0e10cSrcweir             if( i == 0 )
1160cdf0e10cSrcweir                 aLine.append( "%%DocumentSuppliedResources: font " );
1161cdf0e10cSrcweir             else
1162cdf0e10cSrcweir                 aLine.append( "%%DocumentNeededResources: font " );
1163cdf0e10cSrcweir             aLine.append( *it );
1164cdf0e10cSrcweir             aLine.append( "\n" );
1165cdf0e10cSrcweir             WritePS ( pFile, aLine.getStr() );
1166cdf0e10cSrcweir             while( (++it) != aFonts[i].end() )
1167cdf0e10cSrcweir             {
1168cdf0e10cSrcweir                 aLine.setLength(0);
1169cdf0e10cSrcweir                 aLine.append( "%%+ font " );
1170cdf0e10cSrcweir                 aLine.append( *it );
1171cdf0e10cSrcweir                 aLine.append( "\n" );
1172cdf0e10cSrcweir                 WritePS ( pFile, aLine.getStr() );
1173cdf0e10cSrcweir             }
1174cdf0e10cSrcweir         }
1175cdf0e10cSrcweir     }
1176cdf0e10cSrcweir 
1177cdf0e10cSrcweir     bool bSuccess = true;
1178cdf0e10cSrcweir     // in case of external print dialog the number of copies is prepended
1179cdf0e10cSrcweir     // to the job, let us not complicate things by emitting our own copy count
1180cdf0e10cSrcweir     bool bExternalDialog = PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
1181cdf0e10cSrcweir     if( ! bExternalDialog && rJob.m_nCopies > 1 )
1182cdf0e10cSrcweir     {
1183cdf0e10cSrcweir         // setup code
1184cdf0e10cSrcweir         ByteString aLine( "/#copies " );
1185cdf0e10cSrcweir         aLine += ByteString::CreateFromInt32( rJob.m_nCopies );
1186cdf0e10cSrcweir         aLine +=  " def\n";
1187cdf0e10cSrcweir         sal_uInt64 nWritten = 0;
1188cdf0e10cSrcweir         bSuccess = pFile->write( aLine.GetBuffer(), aLine.Len(), nWritten )
1189cdf0e10cSrcweir             || nWritten != aLine.Len() ? false : true;
1190cdf0e10cSrcweir 
1191cdf0e10cSrcweir         if( bSuccess && GetPostscriptLevel( &rJob ) >= 2 )
1192cdf0e10cSrcweir             WritePS (pFile, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
1193cdf0e10cSrcweir     }
1194cdf0e10cSrcweir 
1195cdf0e10cSrcweir     bool bFeatureSuccess = writeFeatureList( pFile, rJob, true );
1196cdf0e10cSrcweir 
1197cdf0e10cSrcweir     WritePS (pFile, "%%EndSetup\n");
1198cdf0e10cSrcweir 
1199cdf0e10cSrcweir     return bSuccess && bFeatureSuccess;
1200cdf0e10cSrcweir }
1201