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