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