1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ppdparser.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
39 #include "vcl/ppdparser.hxx"
40 #include "vcl/strhelper.hxx"
41 #include "vcl/helper.hxx"
42 #include "cupsmgr.hxx"
43 #include "tools/debug.hxx"
44 #include "tools/urlobj.hxx"
45 #include "tools/stream.hxx"
46 #include "tools/zcodec.hxx"
47 #include "osl/mutex.hxx"
48 #include "osl/file.hxx"
49 #include "osl/process.h"
50 #include "osl/thread.h"
51 #include "rtl/strbuf.hxx"
52 #include "rtl/ustrbuf.hxx"
58 #if defined DBG_UTIL || (OSL_DEBUG_LEVEL > 1)
59 #define BSTRING(x) ByteString( x, osl_getThreadTextEncoding() )
60 #define DBG_ASSERT( x, y ) { if( ! (x) ) fprintf( stderr, (y) ); }
62 #define DBG_ASSERT( x, y )
65 std::list
< PPDParser
* > PPDParser::aAllParsers
;
66 std::hash_map
< OUString
, OUString
, OUStringHash
>* PPDParser::pAllPPDFiles
= NULL
;
67 static String aEmptyString
;
69 class PPDDecompressStream
71 SvFileStream
* mpFileStream
;
72 SvMemoryStream
* mpMemStream
;
73 rtl::OUString maFileName
;
76 PPDDecompressStream( const PPDDecompressStream
& );
77 PPDDecompressStream
& operator=(const PPDDecompressStream
& );
80 PPDDecompressStream( const rtl::OUString
& rFile
);
81 ~PPDDecompressStream();
85 void ReadLine( ByteString
& o_rLine
);
86 void Open( const rtl::OUString
& i_rFile
);
88 const rtl::OUString
& GetFileName() const { return maFileName
; }
91 PPDDecompressStream::PPDDecompressStream( const rtl::OUString
& i_rFile
) :
98 PPDDecompressStream::~PPDDecompressStream()
103 void PPDDecompressStream::Open( const rtl::OUString
& i_rFile
)
107 mpFileStream
= new SvFileStream( i_rFile
, STREAM_READ
);
108 maFileName
= mpFileStream
->GetFileName();
110 if( ! mpFileStream
->IsOpen() )
117 mpFileStream
->ReadLine( aLine
);
118 mpFileStream
->Seek( 0 );
120 // check for compress'ed or gzip'ed file
121 ULONG nCompressMethod
= 0;
122 if( aLine
.Len() > 1 && static_cast<unsigned char>(aLine
.GetChar( 0 )) == 0x1f )
124 if( static_cast<unsigned char>(aLine
.GetChar( 1 )) == 0x8b ) // check for gzip
125 nCompressMethod
= ZCODEC_DEFAULT
| ZCODEC_GZ_LIB
;
128 if( nCompressMethod
!= 0 )
130 // so let's try to decompress the stream
131 mpMemStream
= new SvMemoryStream( 4096, 4096 );
133 aCodec
.BeginCompression( nCompressMethod
);
134 long nComp
= aCodec
.Decompress( *mpFileStream
, *mpMemStream
);
135 aCodec
.EndCompression();
138 // decompression failed, must be an uncompressed stream after all
139 delete mpMemStream
, mpMemStream
= NULL
;
140 mpFileStream
->Seek( 0 );
144 // compression successfull, can get rid of file stream
145 delete mpFileStream
, mpFileStream
= NULL
;
146 mpMemStream
->Seek( 0 );
151 void PPDDecompressStream::Close()
153 delete mpMemStream
, mpMemStream
= NULL
;
154 delete mpFileStream
, mpFileStream
= NULL
;
157 bool PPDDecompressStream::IsOpen() const
159 return (mpMemStream
|| (mpFileStream
&& mpFileStream
->IsOpen()));
162 bool PPDDecompressStream::IsEof() const
164 return ( mpMemStream
? mpMemStream
->IsEof() : ( mpFileStream
? mpFileStream
->IsEof() : true ) );
167 void PPDDecompressStream::ReadLine( ByteString
& o_rLine
)
170 mpMemStream
->ReadLine( o_rLine
);
171 else if( mpFileStream
)
172 mpFileStream
->ReadLine( o_rLine
);
175 static osl::FileBase::RC
resolveLink( const rtl::OUString
& i_rURL
, rtl::OUString
& o_rResolvedURL
, rtl::OUString
& o_rBaseName
, osl::FileStatus::Type
& o_rType
, int nLinkLevel
= 10 )
177 osl::DirectoryItem aLinkItem
;
178 osl::FileBase::RC aRet
= osl::FileBase::E_None
;
180 if( ( aRet
= osl::DirectoryItem::get( i_rURL
, aLinkItem
) ) == osl::FileBase::E_None
)
182 osl::FileStatus
aStatus( FileStatusMask_FileName
| FileStatusMask_Type
| FileStatusMask_LinkTargetURL
);
183 if( ( aRet
= aLinkItem
.getFileStatus( aStatus
) ) == osl::FileBase::E_None
)
185 if( aStatus
.getFileType() == osl::FileStatus::Link
)
188 aRet
= resolveLink( aStatus
.getLinkTargetURL(), o_rResolvedURL
, o_rBaseName
, o_rType
, nLinkLevel
-1 );
190 aRet
= osl::FileBase::E_MULTIHOP
;
194 o_rResolvedURL
= i_rURL
;
195 o_rBaseName
= aStatus
.getFileName();
196 o_rType
= aStatus
.getFileType();
203 void PPDParser::scanPPDDir( const String
& rDir
)
205 static struct suffix_t
207 const sal_Char
* pSuffix
;
208 const sal_Int32 nSuffixLen
;
209 } const pSuffixes
[] =
210 { { ".PS", 3 }, { ".PPD", 4 }, { ".PS.GZ", 6 }, { ".PPD.GZ", 7 } };
212 const int nSuffixes
= sizeof(pSuffixes
)/sizeof(pSuffixes
[0]);
214 osl::Directory
aDir( rDir
);
216 osl::DirectoryItem aItem
;
218 INetURLObject
aPPDDir(rDir
);
219 while( aDir
.getNextItem( aItem
) == osl::FileBase::E_None
)
221 osl::FileStatus
aStatus( FileStatusMask_FileName
);
222 if( aItem
.getFileStatus( aStatus
) == osl::FileBase::E_None
)
224 rtl::OUStringBuffer
aURLBuf( rDir
.Len() + 64 );
225 aURLBuf
.append( rDir
);
226 aURLBuf
.append( sal_Unicode( '/' ) );
227 aURLBuf
.append( aStatus
.getFileName() );
229 rtl::OUString aFileURL
, aFileName
;
230 osl::FileStatus::Type eType
= osl::FileStatus::Unknown
;
232 if( resolveLink( aURLBuf
.makeStringAndClear(), aFileURL
, aFileName
, eType
) == osl::FileBase::E_None
)
234 if( eType
== osl::FileStatus::Regular
)
236 INetURLObject aPPDFile
= aPPDDir
;
237 aPPDFile
.Append( aFileName
);
240 for( int nSuffix
= 0; nSuffix
< nSuffixes
; nSuffix
++ )
242 if( aFileName
.getLength() > pSuffixes
[nSuffix
].nSuffixLen
)
244 if( aFileName
.endsWithIgnoreAsciiCaseAsciiL( pSuffixes
[nSuffix
].pSuffix
, pSuffixes
[nSuffix
].nSuffixLen
) )
246 (*pAllPPDFiles
)[ aFileName
.copy( 0, aFileName
.getLength() - pSuffixes
[nSuffix
].nSuffixLen
) ] = aPPDFile
.PathToFileName();
252 else if( eType
== osl::FileStatus::Directory
)
254 scanPPDDir( aFileURL
);
262 void PPDParser::initPPDFiles()
267 pAllPPDFiles
= new std::hash_map
< OUString
, OUString
, OUStringHash
>();
269 // check installation directories
270 std::list
< OUString
> aPathList
;
271 psp::getPrinterPathList( aPathList
, PRINTER_PPDDIR
);
272 for( std::list
< OUString
>::const_iterator ppd_it
= aPathList
.begin(); ppd_it
!= aPathList
.end(); ++ppd_it
)
274 INetURLObject
aPPDDir( *ppd_it
, INET_PROT_FILE
, INetURLObject::ENCODE_ALL
);
275 scanPPDDir( aPPDDir
.GetMainURL( INetURLObject::NO_DECODE
) );
277 if( pAllPPDFiles
->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles
->end() )
279 // last try: search in directory of executable (mainly for setup)
281 if( osl_getExecutableFile( &aExe
.pData
) == osl_Process_E_None
)
283 INetURLObject
aDir( aExe
);
284 aDir
.removeSegment();
286 fprintf( stderr
, "scanning last chance dir: %s\n", OUStringToOString( aDir
.GetMainURL( INetURLObject::NO_DECODE
), osl_getThreadTextEncoding() ).getStr() );
288 scanPPDDir( aDir
.GetMainURL( INetURLObject::NO_DECODE
) );
290 fprintf( stderr
, "SGENPRT %s\n", pAllPPDFiles
->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles
->end() ? "not found" : "found" );
296 void PPDParser::getKnownPPDDrivers( std::list
< rtl::OUString
>& o_rDrivers
, bool bRefresh
)
307 std::hash_map
< OUString
, OUString
, OUStringHash
>::const_iterator it
;
308 for( it
= pAllPPDFiles
->begin(); it
!= pAllPPDFiles
->end(); ++it
)
309 o_rDrivers
.push_back( it
->first
);
312 String
PPDParser::getPPDFile( const String
& rFile
)
314 INetURLObject
aPPD( rFile
, INET_PROT_FILE
, INetURLObject::ENCODE_ALL
);
315 // someone might enter a full qualified name here
316 PPDDecompressStream
aStream( aPPD
.PathToFileName() );
317 if( ! aStream
.IsOpen() )
319 std::hash_map
< OUString
, OUString
, OUStringHash
>::const_iterator it
;
325 // some PPD files contain dots beside the extension, so try name first
326 // and cut of points after that
327 rtl::OUString
aBase( rFile
);
328 sal_Int32 nLastIndex
= aBase
.lastIndexOf( sal_Unicode( '/' ) );
329 if( nLastIndex
>= 0 )
330 aBase
= aBase
.copy( nLastIndex
+1 );
333 it
= pAllPPDFiles
->find( aBase
);
334 nLastIndex
= aBase
.lastIndexOf( sal_Unicode( '.' ) );
336 aBase
= aBase
.copy( 0, nLastIndex
);
337 } while( it
== pAllPPDFiles
->end() && nLastIndex
> 0 );
339 if( it
== pAllPPDFiles
->end() && bRetry
)
341 // a new file ? rehash
342 delete pAllPPDFiles
; pAllPPDFiles
= NULL
;
344 // note this is optimized for office start where
345 // no new files occur and initPPDFiles is called only once
347 } while( ! pAllPPDFiles
);
349 if( it
!= pAllPPDFiles
->end() )
350 aStream
.Open( it
->second
);
354 if( aStream
.IsOpen() )
357 aStream
.ReadLine( aLine
);
358 if( aLine
.Search( "*PPD-Adobe" ) == 0 )
359 aRet
= aStream
.GetFileName();
362 // our *Include hack does usually not begin
363 // with *PPD-Adobe, so try some lines for *Include
365 while( aLine
.Search( "*Include" ) != 0 && --nLines
)
366 aStream
.ReadLine( aLine
);
368 aRet
= aStream
.GetFileName();
375 String
PPDParser::getPPDPrinterName( const String
& rFile
)
377 String aPath
= getPPDFile( rFile
);
381 PPDDecompressStream
aStream( aPath
);
382 if( aStream
.IsOpen() )
385 while( ! aStream
.IsEof() && aStream
.IsOpen() )
387 ByteString aByteLine
;
388 aStream
.ReadLine( aByteLine
);
389 aCurLine
= String( aByteLine
, RTL_TEXTENCODING_MS_1252
);
390 if( aCurLine
.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL
)
392 aCurLine
.Erase( 0, 9 );
393 aCurLine
.EraseLeadingChars( ' ' );
394 aCurLine
.EraseTrailingChars( ' ' );
395 aCurLine
.EraseLeadingChars( '\t' );
396 aCurLine
.EraseTrailingChars( '\t' );
397 aCurLine
.EraseTrailingChars( '\r' );
398 aCurLine
.EraseTrailingChars( '\n' );
399 aCurLine
.EraseLeadingChars( '"' );
400 aCurLine
.EraseTrailingChars( '"' );
402 aStream
.Open( getPPDFile( aCurLine
) );
405 if( aCurLine
.CompareToAscii( "*ModelName:", 11 ) == COMPARE_EQUAL
)
407 aName
= aCurLine
.GetToken( 1, '"' );
410 else if( aCurLine
.CompareToAscii( "*NickName:", 10 ) == COMPARE_EQUAL
)
411 aName
= aCurLine
.GetToken( 1, '"' );
417 const PPDParser
* PPDParser::getParser( const String
& rFile
)
419 static ::osl::Mutex aMutex
;
420 ::osl::Guard
< ::osl::Mutex
> aGuard( aMutex
);
422 String aFile
= rFile
;
423 if( rFile
.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL
)
424 aFile
= getPPDFile( rFile
);
427 #if OSL_DEBUG_LEVEL > 1
428 fprintf( stderr
, "Could not get printer PPD file \"%s\" !\n", OUStringToOString( rFile
, osl_getThreadTextEncoding() ).getStr() );
433 for( ::std::list
< PPDParser
* >::const_iterator it
= aAllParsers
.begin(); it
!= aAllParsers
.end(); ++it
)
434 if( (*it
)->m_aFile
== aFile
)
437 PPDParser
* pNewParser
= NULL
;
438 if( aFile
.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL
)
439 pNewParser
= new PPDParser( aFile
);
442 PrinterInfoManager
& rMgr
= PrinterInfoManager::get();
443 if( rMgr
.getType() == PrinterInfoManager::CUPS
)
445 pNewParser
= const_cast<PPDParser
*>(static_cast<CUPSManager
&>(rMgr
).createCUPSParser( aFile
));
450 // this may actually be the SGENPRT parser,
451 // so ensure uniquness here
452 aAllParsers
.remove( pNewParser
);
453 // insert new parser to list
454 aAllParsers
.push_front( pNewParser
);
459 void PPDParser::freeAll()
461 while( aAllParsers
.begin() != aAllParsers
.end() )
463 delete aAllParsers
.front();
464 aAllParsers
.pop_front();
470 PPDParser::PPDParser( const String
& rFile
) :
472 m_bType42Capable( false ),
473 m_aFileEncoding( RTL_TEXTENCODING_MS_1252
),
474 m_pDefaultImageableArea( NULL
),
475 m_pImageableAreas( NULL
),
476 m_pDefaultPaperDimension( NULL
),
477 m_pPaperDimensions( NULL
),
478 m_pDefaultInputSlot( NULL
),
479 m_pInputSlots( NULL
),
480 m_pDefaultResolution( NULL
),
481 m_pResolutions( NULL
),
482 m_pDefaultDuplexType( NULL
),
483 m_pDuplexTypes( NULL
),
487 std::list
< ByteString
> aLines
;
488 PPDDecompressStream
aStream( m_aFile
);
489 bool bLanguageEncoding
= false;
490 if( aStream
.IsOpen() )
493 while( ! aStream
.IsEof() )
495 aStream
.ReadLine( aCurLine
);
496 if( aCurLine
.GetChar( 0 ) == '*' )
498 if( aCurLine
.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL
)
500 aCurLine
.Erase( 0, 9 );
501 aCurLine
.EraseLeadingChars( ' ' );
502 aCurLine
.EraseTrailingChars( ' ' );
503 aCurLine
.EraseLeadingChars( '\t' );
504 aCurLine
.EraseTrailingChars( '\t' );
505 aCurLine
.EraseTrailingChars( '\r' );
506 aCurLine
.EraseTrailingChars( '\n' );
507 aCurLine
.EraseLeadingChars( '"' );
508 aCurLine
.EraseTrailingChars( '"' );
510 aStream
.Open( getPPDFile( String( aCurLine
, m_aFileEncoding
) ) );
513 else if( ! bLanguageEncoding
&&
514 aCurLine
.CompareIgnoreCaseToAscii( "*languageencoding", 17 ) == COMPARE_EQUAL
)
516 bLanguageEncoding
= true; // generally only the first one counts
517 ByteString aLower
= aCurLine
;
518 aLower
.ToLowerAscii();
519 if( aLower
.Search( "isolatin1", 17 ) != STRING_NOTFOUND
||
520 aLower
.Search( "windowsansi", 17 ) != STRING_NOTFOUND
)
521 m_aFileEncoding
= RTL_TEXTENCODING_MS_1252
;
522 else if( aLower
.Search( "isolatin2", 17 ) != STRING_NOTFOUND
)
523 m_aFileEncoding
= RTL_TEXTENCODING_ISO_8859_2
;
524 else if( aLower
.Search( "isolatin5", 17 ) != STRING_NOTFOUND
)
525 m_aFileEncoding
= RTL_TEXTENCODING_ISO_8859_5
;
526 else if( aLower
.Search( "jis83-rksj", 17 ) != STRING_NOTFOUND
)
527 m_aFileEncoding
= RTL_TEXTENCODING_SHIFT_JIS
;
528 else if( aLower
.Search( "macstandard", 17 ) != STRING_NOTFOUND
)
529 m_aFileEncoding
= RTL_TEXTENCODING_APPLE_ROMAN
;
530 else if( aLower
.Search( "utf-8", 17 ) != STRING_NOTFOUND
)
531 m_aFileEncoding
= RTL_TEXTENCODING_UTF8
;
534 aLines
.push_back( aCurLine
);
539 // now get the Values
541 #if OSL_DEBUG_LEVEL > 2
542 fprintf( stderr
, "acquired %d Keys from PPD %s:\n", m_aKeys
.size(), BSTRING( m_aFile
).GetBuffer() );
543 for( PPDParser::hash_type::const_iterator it
= m_aKeys
.begin(); it
!= m_aKeys
.end(); ++it
)
545 const PPDKey
* pKey
= it
->second
;
546 char* pSetupType
= "<unknown>";
547 switch( pKey
->m_eSetupType
)
549 case PPDKey::ExitServer
: pSetupType
= "ExitServer";break;
550 case PPDKey::Prolog
: pSetupType
= "Prolog";break;
551 case PPDKey::DocumentSetup
: pSetupType
= "DocumentSetup";break;
552 case PPDKey::PageSetup
: pSetupType
= "PageSetup";break;
553 case PPDKey::JCLSetup
: pSetupType
= "JCLSetup";break;
554 case PPDKey::AnySetup
: pSetupType
= "AnySetup";break;
557 fprintf( stderr
, "\t\"%s\" (\"%s\") (%d values) OrderDependency: %d %s\n",
558 BSTRING( pKey
->getKey() ).GetBuffer(),
559 BSTRING( pKey
->m_aUITranslation
).GetBuffer(),
561 pKey
->m_nOrderDependency
,
563 for( int j
= 0; j
< pKey
->countValues(); j
++ )
565 fprintf( stderr
, "\t\t" );
566 const PPDValue
* pValue
= pKey
->getValue( j
);
567 if( pValue
== pKey
->m_pDefaultValue
)
568 fprintf( stderr
, "(Default:) " );
569 char* pVType
= "<unknown>";
570 switch( pValue
->m_eType
)
572 case eInvocation
: pVType
= "invocation";break;
573 case eQuoted
: pVType
= "quoted";break;
574 case eString
: pVType
= "string";break;
575 case eSymbol
: pVType
= "symbol";break;
576 case eNo
: pVType
= "no";break;
579 fprintf( stderr
, "option: \"%s\" (\"%s\"), value: type %s \"%s\" (\"%s\")\n",
580 BSTRING( pValue
->m_aOption
).GetBuffer(),
581 BSTRING( pValue
->m_aOptionTranslation
).GetBuffer(),
583 BSTRING( pValue
->m_aValue
).GetBuffer(),
584 BSTRING( pValue
->m_aValueTranslation
).GetBuffer() );
587 fprintf( stderr
, "constraints: (%d found)\n", m_aConstraints
.size() );
588 for( std::list
< PPDConstraint
>::const_iterator cit
= m_aConstraints
.begin(); cit
!= m_aConstraints
.end(); ++cit
)
590 fprintf( stderr
, "*\"%s\" \"%s\" *\"%s\" \"%s\"\n",
591 BSTRING( cit
->m_pKey1
->getKey() ).GetBuffer(),
592 cit
->m_pOption1
? BSTRING( cit
->m_pOption1
->m_aOption
).GetBuffer() : "<nil>",
593 BSTRING( cit
->m_pKey2
->getKey() ).GetBuffer(),
594 cit
->m_pOption2
? BSTRING( cit
->m_pOption2
->m_aOption
).GetBuffer() : "<nil>"
602 m_pImageableAreas
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ImageableArea" ) ) );
603 if( m_pImageableAreas
)
604 m_pDefaultImageableArea
= m_pImageableAreas
->getDefaultValue();
605 DBG_ASSERT( m_pImageableAreas
, "Warning: no ImageableArea in PPD\n" );
606 DBG_ASSERT( m_pDefaultImageableArea
, "Warning: no DefaultImageableArea in PPD\n" );
608 m_pPaperDimensions
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PaperDimension" ) ) );
609 if( m_pPaperDimensions
)
610 m_pDefaultPaperDimension
= m_pPaperDimensions
->getDefaultValue();
611 DBG_ASSERT( m_pPaperDimensions
, "Warning: no PaperDimension in PPD\n" );
612 DBG_ASSERT( m_pDefaultPaperDimension
, "Warning: no DefaultPaperDimension in PPD\n" );
614 m_pResolutions
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
616 m_pDefaultResolution
= m_pResolutions
->getDefaultValue();
617 DBG_ASSERT( m_pResolutions
, "Warning: no Resolution in PPD\n" );
618 DBG_ASSERT( m_pDefaultResolution
, "Warning: no DefaultResolution in PPD\n" );
620 m_pInputSlots
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
622 m_pDefaultInputSlot
= m_pInputSlots
->getDefaultValue();
623 DBG_ASSERT( m_pPaperDimensions
, "Warning: no InputSlot in PPD\n" );
624 DBG_ASSERT( m_pDefaultPaperDimension
, "Warning: no DefaultInputSlot in PPD\n" );
626 m_pDuplexTypes
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
628 m_pDefaultDuplexType
= m_pDuplexTypes
->getDefaultValue();
630 m_pFontList
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Font" ) ) );
631 DBG_ASSERT( m_pFontList
, "Warning: no Font in PPD\n" );
633 // fill in direct values
634 if( (pKey
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ModelName" ) ) )) )
635 m_aPrinterName
= pKey
->getValue( 0 )->m_aValue
;
636 if( (pKey
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "NickName" ) ) )) )
637 m_aNickName
= pKey
->getValue( 0 )->m_aValue
;
638 if( (pKey
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ColorDevice" ) ) )) )
639 m_bColorDevice
= pKey
->getValue( 0 )->m_aValue
.CompareIgnoreCaseToAscii( "true", 4 ) == COMPARE_EQUAL
? true : false;
641 if( (pKey
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "LanguageLevel" ) ) )) )
642 m_nLanguageLevel
= pKey
->getValue( 0 )->m_aValue
.ToInt32();
643 if( (pKey
= getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) )) )
644 m_bType42Capable
= pKey
->getValue( 0 )->m_aValue
.EqualsIgnoreCaseAscii( "Type42" ) ? true : false;
647 PPDParser::~PPDParser()
649 for( PPDParser::hash_type::iterator it
= m_aKeys
.begin(); it
!= m_aKeys
.end(); ++it
)
653 void PPDParser::insertKey( const String
& rKey
, PPDKey
* pKey
)
655 m_aKeys
[ rKey
] = pKey
;
656 m_aOrderedKeys
.push_back( pKey
);
659 const PPDKey
* PPDParser::getKey( int n
) const
661 return ((unsigned int)n
< m_aOrderedKeys
.size() && n
>= 0) ? m_aOrderedKeys
[n
] : NULL
;
664 const PPDKey
* PPDParser::getKey( const String
& rKey
) const
666 PPDParser::hash_type::const_iterator it
= m_aKeys
.find( rKey
);
667 return it
!= m_aKeys
.end() ? it
->second
: NULL
;
670 bool PPDParser::hasKey( const PPDKey
* pKey
) const
674 ( m_aKeys
.find( pKey
->getKey() ) != m_aKeys
.end() ? true : false ) :
678 static sal_uInt8
getNibble( sal_Char cChar
)
681 if( cChar
>= '0' && cChar
<= '9' )
682 nRet
= sal_uInt8( cChar
- '0' );
683 else if( cChar
>= 'A' && cChar
<= 'F' )
684 nRet
= 10 + sal_uInt8( cChar
- 'A' );
685 else if( cChar
>= 'a' && cChar
<= 'f' )
686 nRet
= 10 + sal_uInt8( cChar
- 'a' );
690 String
PPDParser::handleTranslation( const ByteString
& rString
)
692 int nOrigLen
= rString
.Len();
693 OStringBuffer
aTrans( nOrigLen
);
694 const sal_Char
* pStr
= rString
.GetBuffer();
695 const sal_Char
* pEnd
= pStr
+ nOrigLen
;
702 while( *pStr
!= '>' && pStr
< pEnd
-1 )
704 cChar
= getNibble( *pStr
++ ) << 4;
705 cChar
|= getNibble( *pStr
++ );
706 aTrans
.append( cChar
);
711 aTrans
.append( *pStr
++ );
713 return OStringToOUString( aTrans
.makeStringAndClear(), m_aFileEncoding
);
716 void PPDParser::parse( ::std::list
< ByteString
>& rLines
)
718 PPDValue
* pValue
= NULL
;
721 std::list
< ByteString
>::iterator line
= rLines
.begin();
722 PPDParser::hash_type::const_iterator keyit
;
723 while( line
!= rLines
.end() )
725 ByteString
aCurrentLine( *line
);
727 if( aCurrentLine
.GetChar(0) != '*' )
729 if( aCurrentLine
.GetChar(1) == '%' )
732 ByteString aKey
= GetCommandLineToken( 0, aCurrentLine
.GetToken( 0, ':' ) );
733 int nPos
= aKey
.Search( '/' );
734 if( nPos
!= STRING_NOTFOUND
)
736 aKey
.Erase( 0, 1 ); // remove the '*'
738 if( aKey
.Equals( "CloseUI" ) || aKey
.Equals( "OpenGroup" ) || aKey
.Equals( "CloseGroup" ) || aKey
.Equals( "End" ) || aKey
.Equals( "OpenSubGroup" ) || aKey
.Equals( "CloseSubGroup" ) )
741 if( aKey
.Equals( "OpenUI" ) )
743 parseOpenUI( aCurrentLine
);
746 else if( aKey
.Equals( "OrderDependency" ) )
748 parseOrderDependency( aCurrentLine
);
751 else if( aKey
.Equals( "UIConstraints" ) || aKey
.Equals( "NonUIConstraints" ) )
752 continue; // parsed in pass 2
753 else if( aKey
.Equals( "CustomPageSize" ) ) // currently not handled
756 // default values are parsed in pass 2
757 if( aKey
.CompareTo( "Default", 7 ) == COMPARE_EQUAL
)
761 if( aKey
.GetChar( 0 ) == '?' )
767 String
aUniKey( aKey
, RTL_TEXTENCODING_MS_1252
);
768 keyit
= m_aKeys
.find( aUniKey
);
769 if( keyit
== m_aKeys
.end() )
771 pKey
= new PPDKey( aUniKey
);
772 insertKey( aUniKey
, pKey
);
775 pKey
= keyit
->second
;
778 nPos
= aCurrentLine
.Search( ':' );
779 if( nPos
!= STRING_NOTFOUND
)
781 aOption
= String( aCurrentLine
.Copy( 1, nPos
-1 ), RTL_TEXTENCODING_MS_1252
);
782 aOption
= GetCommandLineToken( 1, aOption
);
783 int nTransPos
= aOption
.Search( '/' );
784 if( nTransPos
!= STRING_NOTFOUND
)
785 aOption
.Erase( nTransPos
);
787 pValue
= pKey
->insertValue( aOption
);
791 if( nPos
== STRING_NOTFOUND
)
793 // have a single main keyword
794 pValue
->m_eType
= eNo
;
796 pKey
->eraseValue( aOption
);
800 // found a colon, there may be an option
801 ByteString aLine
= aCurrentLine
.Copy( 1, nPos
-1 );
802 aLine
= WhitespaceToSpace( aLine
);
803 int nTransPos
= aLine
.Search( '/' );
804 if( nTransPos
!= STRING_NOTFOUND
)
805 pValue
->m_aOptionTranslation
= handleTranslation( aLine
.Copy( nTransPos
+1 ) );
807 // read in more lines if necessary for multiline values
808 aLine
= aCurrentLine
.Copy( nPos
+1 );
809 while( ! ( aLine
.GetTokenCount( '"' ) & 1 ) &&
810 line
!= rLines
.end() )
811 // while there is an even number of tokens; that m_eans
812 // an odd number of doubleqoutes
814 // copy the newlines also
819 aLine
= WhitespaceToSpace( aLine
);
821 // check for invocation or quoted value
822 if( aLine
.GetChar(0) == '"' )
825 nTransPos
= aLine
.Search( '"' );
826 pValue
->m_aValue
= String( aLine
.Copy( 0, nTransPos
), RTL_TEXTENCODING_MS_1252
);
827 // after the second doublequote can follow a / and a translation
828 pValue
->m_aValueTranslation
= handleTranslation( aLine
.Copy( nTransPos
+2 ) );
829 // check for quoted value
830 if( pValue
->m_aOption
.Len() &&
831 aKey
.CompareTo( "JCL", 3 ) != COMPARE_EQUAL
)
832 pValue
->m_eType
= eInvocation
;
834 pValue
->m_eType
= eQuoted
;
836 // check for symbol value
837 else if( aLine
.GetChar(0) == '^' )
840 pValue
->m_aValue
= String( aLine
, RTL_TEXTENCODING_MS_1252
);
841 pValue
->m_eType
= eSymbol
;
845 // must be a string value then
846 // strictly this is false because string values
847 // can contain any whitespace which is reduced
848 // to one space by now
850 nTransPos
= aLine
.Search( '/' );
851 if( nTransPos
== STRING_NOTFOUND
)
852 nTransPos
= aLine
.Len();
853 pValue
->m_aValue
= String( aLine
.Copy( 0, nTransPos
), RTL_TEXTENCODING_MS_1252
);
854 pValue
->m_aValueTranslation
= handleTranslation( aLine
.Copy( nTransPos
+1 ) );
855 pValue
->m_eType
= eString
;
858 // eventually update query and remove from option list
859 if( bQuery
&& pKey
->m_bQueryValue
== FALSE
)
861 pKey
->m_aQueryValue
= *pValue
;
862 pKey
->m_bQueryValue
= true;
863 pKey
->eraseValue( pValue
->m_aOption
);
867 // second pass: fill in defaults
868 for( line
= rLines
.begin(); line
!= rLines
.end(); ++line
)
870 ByteString
aLine( *line
);
871 if( aLine
.CompareTo( "*Default", 8 ) == COMPARE_EQUAL
)
873 String
aKey( aLine
.Copy( 8 ), RTL_TEXTENCODING_MS_1252
);
874 USHORT nPos
= aKey
.Search( ':' );
875 if( nPos
!= STRING_NOTFOUND
)
878 String
aOption( WhitespaceToSpace( aLine
.Copy( nPos
+9 ) ), RTL_TEXTENCODING_MS_1252
);
879 keyit
= m_aKeys
.find( aKey
);
880 if( keyit
!= m_aKeys
.end() )
882 pKey
= keyit
->second
;
883 const PPDValue
* pDefValue
= pKey
->getValue( aOption
);
884 if( pKey
->m_pDefaultValue
== NULL
)
885 pKey
->m_pDefaultValue
= pDefValue
;
889 // some PPDs contain defaults for keys that
890 // do not exist otherwise
891 // (example: DefaultResolution)
892 // so invent that key here and have a default value
893 pKey
= new PPDKey( aKey
);
894 PPDValue
* pNewValue
= pKey
->insertValue( aOption
);
895 pNewValue
->m_eType
= eInvocation
; // or what ?
896 insertKey( aKey
, pKey
);
900 else if( aLine
.CompareTo( "*UIConstraints", 14 ) == COMPARE_EQUAL
||
901 aLine
.CompareTo( "*NonUIConstraints", 17 ) == COMPARE_EQUAL
)
902 parseConstraint( aLine
);
907 void PPDParser::parseOpenUI( const ByteString
& rLine
)
910 ByteString aKey
= rLine
;
912 int nPos
= aKey
.Search( ':' );
913 if( nPos
!= STRING_NOTFOUND
)
915 nPos
= aKey
.Search( '/' );
916 if( nPos
!= STRING_NOTFOUND
)
918 aTranslation
= handleTranslation( aKey
.Copy( nPos
+ 1 ) );
921 aKey
= GetCommandLineToken( 1, aKey
);
924 String
aUniKey( aKey
, RTL_TEXTENCODING_MS_1252
);
925 PPDParser::hash_type::const_iterator keyit
= m_aKeys
.find( aUniKey
);
927 if( keyit
== m_aKeys
.end() )
929 pKey
= new PPDKey( aUniKey
);
930 insertKey( aUniKey
, pKey
);
933 pKey
= keyit
->second
;
935 pKey
->m_bUIOption
= true;
936 pKey
->m_aUITranslation
= aTranslation
;
938 ByteString aValue
= WhitespaceToSpace( rLine
.GetToken( 1, ':' ) );
939 if( aValue
.CompareIgnoreCaseToAscii( "boolean" ) == COMPARE_EQUAL
)
940 pKey
->m_eUIType
= PPDKey::Boolean
;
941 else if( aValue
.CompareIgnoreCaseToAscii( "pickmany" ) == COMPARE_EQUAL
)
942 pKey
->m_eUIType
= PPDKey::PickMany
;
944 pKey
->m_eUIType
= PPDKey::PickOne
;
947 void PPDParser::parseOrderDependency( const ByteString
& rLine
)
949 ByteString
aLine( rLine
);
950 int nPos
= aLine
.Search( ':' );
951 if( nPos
!= STRING_NOTFOUND
)
952 aLine
.Erase( 0, nPos
+1 );
954 int nOrder
= GetCommandLineToken( 0, aLine
).ToInt32();
955 ByteString aSetup
= GetCommandLineToken( 1, aLine
);
956 String
aKey( GetCommandLineToken( 2, aLine
), RTL_TEXTENCODING_MS_1252
);
957 if( aKey
.GetChar( 0 ) != '*' )
958 return; // invalid order depency
962 PPDParser::hash_type::const_iterator keyit
= m_aKeys
.find( aKey
);
963 if( keyit
== m_aKeys
.end() )
965 pKey
= new PPDKey( aKey
);
966 insertKey( aKey
, pKey
);
969 pKey
= keyit
->second
;
971 pKey
->m_nOrderDependency
= nOrder
;
972 if( aSetup
.Equals( "ExitServer" ) )
973 pKey
->m_eSetupType
= PPDKey::ExitServer
;
974 else if( aSetup
.Equals( "Prolog" ) )
975 pKey
->m_eSetupType
= PPDKey::Prolog
;
976 else if( aSetup
.Equals( "DocumentSetup" ) )
977 pKey
->m_eSetupType
= PPDKey::DocumentSetup
;
978 else if( aSetup
.Equals( "PageSetup" ) )
979 pKey
->m_eSetupType
= PPDKey::PageSetup
;
980 else if( aSetup
.Equals( "JCLSetup" ) )
981 pKey
->m_eSetupType
= PPDKey::JCLSetup
;
983 pKey
->m_eSetupType
= PPDKey::AnySetup
;
986 void PPDParser::parseConstraint( const ByteString
& rLine
)
988 bool bFailed
= false;
990 String
aLine( rLine
, RTL_TEXTENCODING_MS_1252
);
991 aLine
.Erase( 0, rLine
.Search( ':' )+1 );
992 PPDConstraint aConstraint
;
993 int nTokens
= GetCommandLineTokenCount( aLine
);
994 for( int i
= 0; i
< nTokens
; i
++ )
996 String aToken
= GetCommandLineToken( i
, aLine
);
997 if( aToken
.GetChar( 0 ) == '*' )
999 aToken
.Erase( 0, 1 );
1000 if( aConstraint
.m_pKey1
)
1001 aConstraint
.m_pKey2
= getKey( aToken
);
1003 aConstraint
.m_pKey1
= getKey( aToken
);
1007 if( aConstraint
.m_pKey2
)
1009 if( ! ( aConstraint
.m_pOption2
= aConstraint
.m_pKey2
->getValue( aToken
) ) )
1012 else if( aConstraint
.m_pKey1
)
1014 if( ! ( aConstraint
.m_pOption1
= aConstraint
.m_pKey1
->getValue( aToken
) ) )
1018 // constraint for nonexistent keys; this happens
1019 // e.g. in HP4PLUS3 (#75636#)
1023 // there must be two keywords
1024 if( ! aConstraint
.m_pKey1
|| ! aConstraint
.m_pKey2
|| bFailed
)
1027 fprintf( stderr
, "Warning: constraint \"%s\" is invalid\n", rLine
.GetStr() );
1031 m_aConstraints
.push_back( aConstraint
);
1034 const String
& PPDParser::getDefaultPaperDimension() const
1036 if( m_pDefaultPaperDimension
)
1037 return m_pDefaultPaperDimension
->m_aOption
;
1039 return aEmptyString
;
1042 bool PPDParser::getMargins(
1043 const String
& rPaperName
,
1044 int& rLeft
, int& rRight
,
1045 int& rUpper
, int& rLower
) const
1047 if( ! m_pImageableAreas
|| ! m_pPaperDimensions
)
1050 int nPDim
=-1, nImArea
=-1, i
;
1051 for( i
= 0; i
< m_pImageableAreas
->countValues(); i
++ )
1052 if( rPaperName
== m_pImageableAreas
->getValue( i
)->m_aOption
)
1054 for( i
= 0; i
< m_pPaperDimensions
->countValues(); i
++ )
1055 if( rPaperName
== m_pPaperDimensions
->getValue( i
)->m_aOption
)
1057 if( nPDim
== -1 || nImArea
== -1 )
1060 double ImLLx
, ImLLy
, ImURx
, ImURy
;
1061 double PDWidth
, PDHeight
;
1062 String aArea
= m_pImageableAreas
->getValue( nImArea
)->m_aValue
;
1063 ImLLx
= StringToDouble( GetCommandLineToken( 0, aArea
) );
1064 ImLLy
= StringToDouble( GetCommandLineToken( 1, aArea
) );
1065 ImURx
= StringToDouble( GetCommandLineToken( 2, aArea
) );
1066 ImURy
= StringToDouble( GetCommandLineToken( 3, aArea
) );
1067 // sscanf( m_pImageableAreas->getValue( nImArea )->m_aValue.GetStr(),
1068 // "%lg%lg%lg%lg", &ImLLx, &ImLLy, &ImURx, &ImURy );
1069 aArea
= m_pPaperDimensions
->getValue( nPDim
)->m_aValue
;
1070 PDWidth
= StringToDouble( GetCommandLineToken( 0, aArea
) );
1071 PDHeight
= StringToDouble( GetCommandLineToken( 1, aArea
) );
1072 // sscanf( m_pPaperDimensions->getValue( nPDim )->m_aValue.GetStr(),
1073 // "%lg%lg", &PDWidth, &PDHeight );
1074 rLeft
= (int)(ImLLx
+ 0.5);
1075 rLower
= (int)(ImLLy
+ 0.5);
1076 rUpper
= (int)(PDHeight
- ImURy
+ 0.5);
1077 rRight
= (int)(PDWidth
- ImURx
+ 0.5);
1082 bool PPDParser::getPaperDimension(
1083 const String
& rPaperName
,
1084 int& rWidth
, int& rHeight
) const
1086 if( ! m_pPaperDimensions
)
1090 for( int i
= 0; i
< m_pPaperDimensions
->countValues(); i
++ )
1091 if( rPaperName
== m_pPaperDimensions
->getValue( i
)->m_aOption
)
1096 double PDWidth
, PDHeight
;
1097 String aArea
= m_pPaperDimensions
->getValue( nPDim
)->m_aValue
;
1098 PDWidth
= StringToDouble( GetCommandLineToken( 0, aArea
) );
1099 PDHeight
= StringToDouble( GetCommandLineToken( 1, aArea
) );
1100 rHeight
= (int)(PDHeight
+ 0.5);
1101 rWidth
= (int)(PDWidth
+ 0.5);
1106 const String
& PPDParser::matchPaper( int nWidth
, int nHeight
) const
1108 if( ! m_pPaperDimensions
)
1109 return aEmptyString
;
1112 double PDWidth
, PDHeight
;
1113 double fSort
= 2e36
, fNewSort
;
1115 for( int i
= 0; i
< m_pPaperDimensions
->countValues(); i
++ )
1117 String aArea
= m_pPaperDimensions
->getValue( i
)->m_aValue
;
1118 PDWidth
= StringToDouble( GetCommandLineToken( 0, aArea
) );
1119 PDHeight
= StringToDouble( GetCommandLineToken( 1, aArea
) );
1120 PDWidth
/= (double)nWidth
;
1121 PDHeight
/= (double)nHeight
;
1122 if( PDWidth
>= 0.9 && PDWidth
<= 1.1 &&
1123 PDHeight
>= 0.9 && PDHeight
<= 1.1 )
1126 (1.0-PDWidth
)*(1.0-PDWidth
) + (1.0-PDHeight
)*(1.0-PDHeight
);
1127 if( fNewSort
== 0.0 ) // perfect match
1128 return m_pPaperDimensions
->getValue( i
)->m_aOption
;
1130 if( fNewSort
< fSort
)
1138 static bool bDontSwap
= false;
1139 if( nPDim
== -1 && ! bDontSwap
)
1141 // swap portrait/landscape and try again
1143 const String
& rRet
= matchPaper( nHeight
, nWidth
);
1148 return nPDim
!= -1 ? m_pPaperDimensions
->getValue( nPDim
)->m_aOption
: aEmptyString
;
1151 const String
& PPDParser::getDefaultInputSlot() const
1153 if( m_pDefaultInputSlot
)
1154 return m_pDefaultInputSlot
->m_aValue
;
1155 return aEmptyString
;
1158 const String
& PPDParser::getSlot( int nSlot
) const
1160 if( ! m_pInputSlots
)
1161 return aEmptyString
;
1163 if( nSlot
> 0 && nSlot
< m_pInputSlots
->countValues() )
1164 return m_pInputSlots
->getValue( nSlot
)->m_aOption
;
1165 else if( m_pInputSlots
->countValues() > 0 )
1166 return m_pInputSlots
->getValue( (ULONG
)0 )->m_aOption
;
1168 return aEmptyString
;
1171 const String
& PPDParser::getSlotCommand( int nSlot
) const
1173 if( ! m_pInputSlots
)
1174 return aEmptyString
;
1176 if( nSlot
> 0 && nSlot
< m_pInputSlots
->countValues() )
1177 return m_pInputSlots
->getValue( nSlot
)->m_aValue
;
1178 else if( m_pInputSlots
->countValues() > 0 )
1179 return m_pInputSlots
->getValue( (ULONG
)0 )->m_aValue
;
1181 return aEmptyString
;
1184 const String
& PPDParser::getSlotCommand( const String
& rSlot
) const
1186 if( ! m_pInputSlots
)
1187 return aEmptyString
;
1189 for( int i
=0; i
< m_pInputSlots
->countValues(); i
++ )
1191 const PPDValue
* pValue
= m_pInputSlots
->getValue( i
);
1192 if( pValue
->m_aOption
== rSlot
)
1193 return pValue
->m_aValue
;
1195 return aEmptyString
;
1198 const String
& PPDParser::getPaperDimension( int nPaperDimension
) const
1200 if( ! m_pPaperDimensions
)
1201 return aEmptyString
;
1203 if( nPaperDimension
> 0 && nPaperDimension
< m_pPaperDimensions
->countValues() )
1204 return m_pPaperDimensions
->getValue( nPaperDimension
)->m_aOption
;
1205 else if( m_pPaperDimensions
->countValues() > 0 )
1206 return m_pPaperDimensions
->getValue( (ULONG
)0 )->m_aOption
;
1208 return aEmptyString
;
1211 const String
& PPDParser::getPaperDimensionCommand( int nPaperDimension
) const
1213 if( ! m_pPaperDimensions
)
1214 return aEmptyString
;
1216 if( nPaperDimension
> 0 && nPaperDimension
< m_pPaperDimensions
->countValues() )
1217 return m_pPaperDimensions
->getValue( nPaperDimension
)->m_aValue
;
1218 else if( m_pPaperDimensions
->countValues() > 0 )
1219 return m_pPaperDimensions
->getValue( (ULONG
)0 )->m_aValue
;
1221 return aEmptyString
;
1224 const String
& PPDParser::getPaperDimensionCommand( const String
& rPaperDimension
) const
1226 if( ! m_pPaperDimensions
)
1227 return aEmptyString
;
1229 for( int i
=0; i
< m_pPaperDimensions
->countValues(); i
++ )
1231 const PPDValue
* pValue
= m_pPaperDimensions
->getValue( i
);
1232 if( pValue
->m_aOption
== rPaperDimension
)
1233 return pValue
->m_aValue
;
1235 return aEmptyString
;
1238 void PPDParser::getResolutionFromString(
1239 const String
& rString
,
1240 int& rXRes
, int& rYRes
) const
1242 int nPos
= 0, nDPIPos
;
1244 rXRes
= rYRes
= 300;
1246 nDPIPos
= rString
.SearchAscii( "dpi" );
1247 if( nDPIPos
!= STRING_NOTFOUND
)
1249 if( ( nPos
= rString
.Search( 'x' ) ) != STRING_NOTFOUND
)
1251 rXRes
= rString
.Copy( 0, nPos
).ToInt32();
1252 rYRes
= rString
.GetToken( 1, 'x' ).Erase( nDPIPos
- nPos
- 1 ).ToInt32();
1255 rXRes
= rYRes
= rString
.Copy( 0, nDPIPos
).ToInt32();
1259 void PPDParser::getDefaultResolution( int& rXRes
, int& rYRes
) const
1261 if( m_pDefaultResolution
)
1263 getResolutionFromString( m_pDefaultResolution
->m_aValue
, rXRes
, rYRes
);
1271 int PPDParser::getResolutions() const
1273 if( ( ! m_pResolutions
|| m_pResolutions
->countValues() == 0 ) &&
1274 m_pDefaultResolution
)
1276 return m_pResolutions
? m_pResolutions
->countValues() : 0;
1279 void PPDParser::getResolution( int nNr
, int& rXRes
, int& rYRes
) const
1281 if( ( ! m_pResolutions
|| m_pResolutions
->countValues() == 0 ) && m_pDefaultResolution
&& nNr
== 0 )
1283 getDefaultResolution( rXRes
, rYRes
);
1286 if( ! m_pResolutions
)
1289 getResolutionFromString( m_pResolutions
->getValue( nNr
)->m_aOption
,
1293 const String
& PPDParser::getResolutionCommand( int nXRes
, int nYRes
) const
1295 if( ( ! m_pResolutions
|| m_pResolutions
->countValues() == 0 ) && m_pDefaultResolution
)
1296 return m_pDefaultResolution
->m_aValue
;
1298 if( ! m_pResolutions
)
1299 return aEmptyString
;
1302 for( int i
= 0; i
< m_pResolutions
->countValues(); i
++ )
1304 getResolutionFromString( m_pResolutions
->getValue( i
)->m_aOption
,
1306 if( nX
== nXRes
&& nY
== nYRes
)
1307 return m_pResolutions
->getValue( i
)->m_aValue
;
1309 return aEmptyString
;
1312 const String
& PPDParser::getDefaultDuplexType() const
1314 if( m_pDefaultDuplexType
)
1315 return m_pDefaultDuplexType
->m_aValue
;
1316 return aEmptyString
;
1319 const String
& PPDParser::getDuplex( int nDuplex
) const
1321 if( ! m_pDuplexTypes
)
1322 return aEmptyString
;
1324 if( nDuplex
> 0 && nDuplex
< m_pDuplexTypes
->countValues() )
1325 return m_pDuplexTypes
->getValue( nDuplex
)->m_aOption
;
1326 else if( m_pDuplexTypes
->countValues() > 0 )
1327 return m_pDuplexTypes
->getValue( (ULONG
)0 )->m_aOption
;
1329 return aEmptyString
;
1332 const String
& PPDParser::getDuplexCommand( int nDuplex
) const
1334 if( ! m_pDuplexTypes
)
1335 return aEmptyString
;
1337 if( nDuplex
> 0 && nDuplex
< m_pDuplexTypes
->countValues() )
1338 return m_pDuplexTypes
->getValue( nDuplex
)->m_aValue
;
1339 else if( m_pDuplexTypes
->countValues() > 0 )
1340 return m_pDuplexTypes
->getValue( (ULONG
)0 )->m_aValue
;
1342 return aEmptyString
;
1345 const String
& PPDParser::getDuplexCommand( const String
& rDuplex
) const
1347 if( ! m_pDuplexTypes
)
1348 return aEmptyString
;
1350 for( int i
=0; i
< m_pDuplexTypes
->countValues(); i
++ )
1352 const PPDValue
* pValue
= m_pDuplexTypes
->getValue( i
);
1353 if( pValue
->m_aOption
== rDuplex
)
1354 return pValue
->m_aValue
;
1356 return aEmptyString
;
1359 void PPDParser::getFontAttributes(
1362 String
& rCharset
) const
1364 if( m_pFontList
&& nFont
>= 0 && nFont
< m_pFontList
->countValues() )
1367 WhitespaceToSpace( m_pFontList
->getValue( nFont
)->m_aValue
);
1368 rEncoding
= GetCommandLineToken( 0, aAttribs
);
1369 rCharset
= GetCommandLineToken( 2, aAttribs
);
1373 void PPDParser::getFontAttributes(
1374 const String
& rFont
,
1376 String
& rCharset
) const
1380 for( int i
= 0; i
< m_pFontList
->countValues(); i
++ )
1381 if( m_pFontList
->getValue( i
)->m_aOption
== rFont
)
1382 getFontAttributes( i
, rEncoding
, rCharset
);
1386 const String
& PPDParser::getFont( int nFont
) const
1389 return aEmptyString
;
1391 if( nFont
>=0 && nFont
< m_pFontList
->countValues() )
1392 return m_pFontList
->getValue( nFont
)->m_aOption
;
1393 return aEmptyString
;
1400 PPDKey::PPDKey( const String
& rKey
) :
1402 m_pDefaultValue( NULL
),
1403 m_bQueryValue( false ),
1404 m_bUIOption( false ),
1405 m_eUIType( PickOne
),
1406 m_nOrderDependency( 100 ),
1407 m_eSetupType( AnySetup
)
1411 // -------------------------------------------------------------------
1417 // -------------------------------------------------------------------
1419 const PPDValue
* PPDKey::getValue( int n
) const
1421 return ((unsigned int)n
< m_aOrderedValues
.size() && n
>= 0) ? m_aOrderedValues
[n
] : NULL
;
1424 // -------------------------------------------------------------------
1426 const PPDValue
* PPDKey::getValue( const String
& rOption
) const
1428 PPDKey::hash_type::const_iterator it
= m_aValues
.find( rOption
);
1429 return it
!= m_aValues
.end() ? &it
->second
: NULL
;
1432 // -------------------------------------------------------------------
1434 const PPDValue
* PPDKey::getValueCaseInsensitive( const String
& rOption
) const
1436 const PPDValue
* pValue
= getValue( rOption
);
1439 for( size_t n
= 0; n
< m_aOrderedValues
.size() && ! pValue
; n
++ )
1440 if( m_aOrderedValues
[n
]->m_aOption
.EqualsIgnoreCaseAscii( rOption
) )
1441 pValue
= m_aOrderedValues
[n
];
1447 // -------------------------------------------------------------------
1449 void PPDKey::eraseValue( const String
& rOption
)
1451 PPDKey::hash_type::iterator it
= m_aValues
.find( rOption
);
1452 if( it
== m_aValues
.end() )
1455 for( PPDKey::value_type::iterator vit
= m_aOrderedValues
.begin(); vit
!= m_aOrderedValues
.end(); ++vit
)
1457 if( *vit
== &(it
->second
) )
1459 m_aOrderedValues
.erase( vit
);
1463 m_aValues
.erase( it
);
1466 // -------------------------------------------------------------------
1468 PPDValue
* PPDKey::insertValue( const String
& rOption
)
1470 if( m_aValues
.find( rOption
) != m_aValues
.end() )
1474 aValue
.m_aOption
= rOption
;
1475 m_aValues
[ rOption
] = aValue
;
1476 PPDValue
* pValue
= &m_aValues
[rOption
];
1477 m_aOrderedValues
.push_back( pValue
);
1481 // -------------------------------------------------------------------
1487 PPDContext::PPDContext( const PPDParser
* pParser
) :
1488 m_pParser( pParser
)
1492 // -------------------------------------------------------------------
1494 PPDContext
& PPDContext::operator=( const PPDContext
& rCopy
)
1496 m_pParser
= rCopy
.m_pParser
;
1497 m_aCurrentValues
= rCopy
.m_aCurrentValues
;
1501 // -------------------------------------------------------------------
1503 PPDContext::~PPDContext()
1507 // -------------------------------------------------------------------
1509 const PPDKey
* PPDContext::getModifiedKey( int n
) const
1511 hash_type::const_iterator it
;
1512 for( it
= m_aCurrentValues
.begin(); it
!= m_aCurrentValues
.end() && n
--; ++it
)
1514 return it
!= m_aCurrentValues
.end() ? it
->first
: NULL
;
1517 // -------------------------------------------------------------------
1519 void PPDContext::setParser( const PPDParser
* pParser
)
1521 if( pParser
!= m_pParser
)
1523 m_aCurrentValues
.clear();
1524 m_pParser
= pParser
;
1528 // -------------------------------------------------------------------
1530 const PPDValue
* PPDContext::getValue( const PPDKey
* pKey
) const
1535 hash_type::const_iterator it
;
1536 it
= m_aCurrentValues
.find( pKey
);
1537 if( it
!= m_aCurrentValues
.end() )
1540 if( ! m_pParser
->hasKey( pKey
) )
1543 const PPDValue
* pValue
= pKey
->getDefaultValue();
1545 pValue
= pKey
->getValue( 0 );
1550 // -------------------------------------------------------------------
1552 const PPDValue
* PPDContext::setValue( const PPDKey
* pKey
, const PPDValue
* pValue
, bool bDontCareForConstraints
)
1554 if( ! m_pParser
|| ! pKey
)
1557 // pValue can be NULL - it means ignore this option
1559 if( ! m_pParser
->hasKey( pKey
) )
1562 // check constraints
1565 if( bDontCareForConstraints
)
1567 m_aCurrentValues
[ pKey
] = pValue
;
1569 else if( checkConstraints( pKey
, pValue
, true ) )
1571 m_aCurrentValues
[ pKey
] = pValue
;
1573 // after setting this value, check all constraints !
1574 hash_type::iterator it
= m_aCurrentValues
.begin();
1575 while( it
!= m_aCurrentValues
.end() )
1577 if( it
->first
!= pKey
&&
1578 ! checkConstraints( it
->first
, it
->second
, false ) )
1581 fprintf( stderr
, "PPDContext::setValue: option %s (%s) is constrained after setting %s to %s\n",
1582 it
->first
->getKey().GetStr(),
1583 it
->second
->m_aOption
.GetStr(),
1584 pKey
->getKey().GetStr(),
1585 pValue
->m_aOption
.GetStr() );
1587 resetValue( it
->first
, true );
1588 it
= m_aCurrentValues
.begin();
1596 m_aCurrentValues
[ pKey
] = NULL
;
1601 // -------------------------------------------------------------------
1603 bool PPDContext::checkConstraints( const PPDKey
* pKey
, const PPDValue
* pValue
)
1605 if( ! m_pParser
|| ! pKey
|| ! pValue
)
1608 // ensure that this key is already in the list if it exists at all
1609 if( m_aCurrentValues
.find( pKey
) != m_aCurrentValues
.end() )
1610 return checkConstraints( pKey
, pValue
, false );
1612 // it is not in the list, insert it temporarily
1614 if( m_pParser
->hasKey( pKey
) )
1616 const PPDValue
* pDefValue
= pKey
->getDefaultValue();
1617 m_aCurrentValues
[ pKey
] = pDefValue
;
1618 bRet
= checkConstraints( pKey
, pValue
, false );
1619 m_aCurrentValues
.erase( pKey
);
1625 // -------------------------------------------------------------------
1627 bool PPDContext::resetValue( const PPDKey
* pKey
, bool bDefaultable
)
1629 if( ! pKey
|| ! m_pParser
|| ! m_pParser
->hasKey( pKey
) )
1632 const PPDValue
* pResetValue
= pKey
->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
1634 pResetValue
= pKey
->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) );
1635 if( ! pResetValue
&& bDefaultable
)
1636 pResetValue
= pKey
->getDefaultValue();
1638 bool bRet
= pResetValue
? ( setValue( pKey
, pResetValue
) == pResetValue
? true : false ) : false;
1643 // -------------------------------------------------------------------
1645 bool PPDContext::checkConstraints( const PPDKey
* pKey
, const PPDValue
* pNewValue
, bool bDoReset
)
1654 if( pKey
->getValue( pNewValue
->m_aOption
) != pNewValue
)
1657 // None / False and the default can always be set, but be careful !
1658 // setting them might influence constrained values
1659 if( pNewValue
->m_aOption
.EqualsAscii( "None" ) || pNewValue
->m_aOption
.EqualsAscii( "False" ) ||
1660 pNewValue
== pKey
->getDefaultValue() )
1663 const ::std::list
< PPDParser::PPDConstraint
>& rConstraints( m_pParser
->getConstraints() );
1664 for( ::std::list
< PPDParser::PPDConstraint
>::const_iterator it
= rConstraints
.begin(); it
!= rConstraints
.end(); ++it
)
1666 const PPDKey
* pLeft
= it
->m_pKey1
;
1667 const PPDKey
* pRight
= it
->m_pKey2
;
1668 if( ! pLeft
|| ! pRight
|| ( pKey
!= pLeft
&& pKey
!= pRight
) )
1671 const PPDKey
* pOtherKey
= pKey
== pLeft
? pRight
: pLeft
;
1672 const PPDValue
* pOtherKeyOption
= pKey
== pLeft
? it
->m_pOption2
: it
->m_pOption1
;
1673 const PPDValue
* pKeyOption
= pKey
== pLeft
? it
->m_pOption1
: it
->m_pOption2
;
1675 // syntax *Key1 option1 *Key2 option2
1676 if( pKeyOption
&& pOtherKeyOption
)
1678 if( pNewValue
!= pKeyOption
)
1680 if( pOtherKeyOption
== getValue( pOtherKey
) )
1685 // syntax *Key1 option *Key2 or *Key1 *Key2 option
1686 else if( pOtherKeyOption
|| pKeyOption
)
1690 if( ! ( pOtherKeyOption
= getValue( pOtherKey
) ) )
1691 continue; // this should not happen, PPD broken
1693 if( pKeyOption
== pNewValue
&&
1694 ! pOtherKeyOption
->m_aOption
.EqualsAscii( "None" ) &&
1695 ! pOtherKeyOption
->m_aOption
.EqualsAscii( "False" ) )
1697 // check if the other value can be reset and
1698 // do so if possible
1699 if( bDoReset
&& resetValue( pOtherKey
) )
1705 else if( pOtherKeyOption
)
1707 if( getValue( pOtherKey
) == pOtherKeyOption
&&
1708 ! pNewValue
->m_aOption
.EqualsAscii( "None" ) &&
1709 ! pNewValue
->m_aOption
.EqualsAscii( "False" ) )
1714 // this should not happen, PPD is broken
1717 // syntax *Key1 *Key2
1720 const PPDValue
* pOtherValue
= getValue( pOtherKey
);
1721 if( ! pOtherValue
->m_aOption
.EqualsAscii( "None" ) &&
1722 ! pOtherValue
->m_aOption
.EqualsAscii( "False" ) &&
1723 ! pNewValue
->m_aOption
.EqualsAscii( "None" ) &&
1724 ! pNewValue
->m_aOption
.EqualsAscii( "False" ) )
1731 // -------------------------------------------------------------------
1733 void PPDContext::getUnconstrainedValues( const PPDKey
* pKey
, ::std::list
< const PPDValue
* >& rValues
)
1737 if( ! m_pParser
|| ! pKey
|| ! m_pParser
->hasKey( pKey
) )
1740 int nValues
= pKey
->countValues();
1741 for( int i
= 0; i
< nValues
; i
++ )
1743 const PPDValue
* pValue
= pKey
->getValue( i
);
1744 if( checkConstraints( pKey
, pValue
) )
1745 rValues
.push_back( pValue
);
1750 // -------------------------------------------------------------------
1752 void* PPDContext::getStreamableBuffer( ULONG
& rBytes
) const
1755 if( ! m_aCurrentValues
.size() )
1757 hash_type::const_iterator it
;
1758 for( it
= m_aCurrentValues
.begin(); it
!= m_aCurrentValues
.end(); ++it
)
1760 ByteString
aCopy( it
->first
->getKey(), RTL_TEXTENCODING_MS_1252
);
1761 rBytes
+= aCopy
.Len();
1762 rBytes
+= 1; // for ':'
1765 aCopy
= ByteString( it
->second
->m_aOption
, RTL_TEXTENCODING_MS_1252
);
1766 rBytes
+= aCopy
.Len();
1770 rBytes
+= 1; // for '\0'
1773 void* pBuffer
= new char[ rBytes
];
1774 memset( pBuffer
, 0, rBytes
);
1775 char* pRun
= (char*)pBuffer
;
1776 for( it
= m_aCurrentValues
.begin(); it
!= m_aCurrentValues
.end(); ++it
)
1778 ByteString
aCopy( it
->first
->getKey(), RTL_TEXTENCODING_MS_1252
);
1779 int nBytes
= aCopy
.Len();
1780 memcpy( pRun
, aCopy
.GetBuffer(), nBytes
);
1784 aCopy
= ByteString( it
->second
->m_aOption
, RTL_TEXTENCODING_MS_1252
);
1787 nBytes
= aCopy
.Len();
1788 memcpy( pRun
, aCopy
.GetBuffer(), nBytes
);
1796 // -------------------------------------------------------------------
1798 void PPDContext::rebuildFromStreamBuffer( void* pBuffer
, ULONG nBytes
)
1803 m_aCurrentValues
.clear();
1805 char* pRun
= (char*)pBuffer
;
1806 while( nBytes
&& *pRun
)
1808 ByteString
aLine( pRun
);
1809 int nPos
= aLine
.Search( ':' );
1810 if( nPos
!= STRING_NOTFOUND
)
1812 const PPDKey
* pKey
= m_pParser
->getKey( String( aLine
.Copy( 0, nPos
), RTL_TEXTENCODING_MS_1252
) );
1815 const PPDValue
* pValue
= NULL
;
1816 String
aOption( aLine
.Copy( nPos
+1 ), RTL_TEXTENCODING_MS_1252
);
1817 if( ! aOption
.EqualsAscii( "*nil" ) )
1818 pValue
= pKey
->getValue( aOption
);
1819 m_aCurrentValues
[ pKey
] = pValue
;
1821 fprintf( stderr
, "PPDContext::rebuildFromStreamBuffer: read PPDKeyValue { %s, %s }\n", pKV
->m_pKey
->getKey().GetStr(), pKV
->m_pCurrentValue
? pKV
->m_pCurrentValue
->m_aOption
.GetStr() : "<nil>" );
1825 nBytes
-= aLine
.Len()+1;
1826 pRun
+= aLine
.Len()+1;
1830 // -------------------------------------------------------------------
1832 int PPDContext::getRenderResolution() const
1834 // initialize to reasonable default, if parser is not set
1838 int nDPIx
= 300, nDPIy
= 300;
1839 const PPDKey
* pKey
= m_pParser
->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
1842 const PPDValue
* pValue
= getValue( pKey
);
1844 m_pParser
->getResolutionFromString( pValue
->m_aOption
, nDPIx
, nDPIy
);
1846 m_pParser
->getDefaultResolution( nDPIx
, nDPIy
);
1849 m_pParser
->getDefaultResolution( nDPIx
, nDPIy
);
1851 nDPI
= (nDPIx
> nDPIy
) ? nDPIx
: nDPIy
;
1856 // -------------------------------------------------------------------
1858 void PPDContext::getPageSize( String
& rPaper
, int& rWidth
, int& rHeight
) const
1860 // initialize to reasonable default, if parser is not set
1861 rPaper
= String( RTL_CONSTASCII_USTRINGPARAM( "A4" ) );
1866 const PPDKey
* pKey
= m_pParser
->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
1869 const PPDValue
* pValue
= getValue( pKey
);
1872 rPaper
= pValue
->m_aOption
;
1873 m_pParser
->getPaperDimension( rPaper
, rWidth
, rHeight
);
1877 rPaper
= m_pParser
->getDefaultPaperDimension();
1878 m_pParser
->getDefaultPaperDimension( rWidth
, rHeight
);