1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <stdlib.h> 32 #include <stdio.h> 33 34 #include <hash_map> 35 36 #include "vcl/ppdparser.hxx" 37 #include "vcl/strhelper.hxx" 38 #include "vcl/helper.hxx" 39 #include "vcl/svapp.hxx" 40 #include "cupsmgr.hxx" 41 #include "tools/debug.hxx" 42 #include "tools/urlobj.hxx" 43 #include "tools/stream.hxx" 44 #include "tools/zcodec.hxx" 45 #include "osl/mutex.hxx" 46 #include "osl/file.hxx" 47 #include "osl/process.h" 48 #include "osl/thread.h" 49 #include "rtl/strbuf.hxx" 50 #include "rtl/ustrbuf.hxx" 51 52 #include "com/sun/star/lang/Locale.hpp" 53 54 namespace psp 55 { 56 class PPDTranslator 57 { 58 struct LocaleEqual 59 { 60 bool operator()(const com::sun::star::lang::Locale& i_rLeft, 61 const com::sun::star::lang::Locale& i_rRight) const 62 { 63 return i_rLeft.Language.equals( i_rRight.Language ) && 64 i_rLeft.Country.equals( i_rRight.Country ) && 65 i_rLeft.Variant.equals( i_rRight.Variant ); 66 } 67 }; 68 69 struct LocaleHash 70 { 71 size_t operator()(const com::sun::star::lang::Locale& rLocale) const 72 { return 73 (size_t)rLocale.Language.hashCode() 74 ^ (size_t)rLocale.Country.hashCode() 75 ^ (size_t)rLocale.Variant.hashCode() 76 ; 77 } 78 }; 79 80 typedef std::hash_map< com::sun::star::lang::Locale, rtl::OUString, LocaleHash, LocaleEqual > translation_map; 81 typedef std::hash_map< rtl::OUString, translation_map, rtl::OUStringHash > key_translation_map; 82 83 key_translation_map m_aTranslations; 84 public: 85 PPDTranslator() {} 86 ~PPDTranslator() {} 87 88 89 void insertValue( 90 const rtl::OUString& i_rKey, 91 const rtl::OUString& i_rOption, 92 const rtl::OUString& i_rValue, 93 const rtl::OUString& i_rTranslation, 94 const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() 95 ); 96 97 void insertOption( const rtl::OUString& i_rKey, 98 const rtl::OUString& i_rOption, 99 const rtl::OUString& i_rTranslation, 100 const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) 101 { 102 insertValue( i_rKey, i_rOption, rtl::OUString(), i_rTranslation, i_rLocale ); 103 } 104 105 void insertKey( const rtl::OUString& i_rKey, 106 const rtl::OUString& i_rTranslation, 107 const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) 108 { 109 insertValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rTranslation, i_rLocale ); 110 } 111 112 rtl::OUString translateValue( 113 const rtl::OUString& i_rKey, 114 const rtl::OUString& i_rOption, 115 const rtl::OUString& i_rValue, 116 const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() 117 ) const; 118 119 rtl::OUString translateOption( const rtl::OUString& i_rKey, 120 const rtl::OUString& i_rOption, 121 const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const 122 { 123 return translateValue( i_rKey, i_rOption, rtl::OUString(), i_rLocale ); 124 } 125 126 rtl::OUString translateKey( const rtl::OUString& i_rKey, 127 const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const 128 { 129 return translateValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rLocale ); 130 } 131 }; 132 133 static com::sun::star::lang::Locale normalizeInputLocale( 134 const com::sun::star::lang::Locale& i_rLocale, 135 bool bInsertDefault = false 136 ) 137 { 138 com::sun::star::lang::Locale aLoc( i_rLocale ); 139 if( bInsertDefault && aLoc.Language.getLength() == 0 ) 140 { 141 // empty locale requested, fill in application UI locale 142 aLoc = Application::GetSettings().GetUILocale(); 143 144 #if OSL_DEBUG_LEVEL > 1 145 static const char* pEnvLocale = getenv( "SAL_PPDPARSER_LOCALE" ); 146 if( pEnvLocale && *pEnvLocale ) 147 { 148 rtl::OString aStr( pEnvLocale ); 149 sal_Int32 nLen = aStr.getLength(); 150 aLoc.Language = rtl::OStringToOUString( aStr.copy( 0, nLen > 2 ? 2 : nLen ), RTL_TEXTENCODING_MS_1252 ); 151 if( nLen >=5 && aStr.getStr()[2] == '_' ) 152 aLoc.Country = rtl::OStringToOUString( aStr.copy( 3, 2 ), RTL_TEXTENCODING_MS_1252 ); 153 else 154 aLoc.Country = rtl::OUString(); 155 aLoc.Variant = rtl::OUString(); 156 } 157 #endif 158 } 159 aLoc.Language = aLoc.Language.toAsciiLowerCase(); 160 aLoc.Country = aLoc.Country.toAsciiUpperCase(); 161 aLoc.Variant = aLoc.Variant.toAsciiUpperCase(); 162 163 return aLoc; 164 } 165 166 void PPDTranslator::insertValue( 167 const rtl::OUString& i_rKey, 168 const rtl::OUString& i_rOption, 169 const rtl::OUString& i_rValue, 170 const rtl::OUString& i_rTranslation, 171 const com::sun::star::lang::Locale& i_rLocale 172 ) 173 { 174 rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 ); 175 aKey.append( i_rKey ); 176 if( i_rOption.getLength() || i_rValue.getLength() ) 177 { 178 aKey.append( sal_Unicode( ':' ) ); 179 aKey.append( i_rOption ); 180 } 181 if( i_rValue.getLength() ) 182 { 183 aKey.append( sal_Unicode( ':' ) ); 184 aKey.append( i_rValue ); 185 } 186 if( aKey.getLength() && i_rTranslation.getLength() ) 187 { 188 rtl::OUString aK( aKey.makeStringAndClear() ); 189 com::sun::star::lang::Locale aLoc; 190 aLoc.Language = i_rLocale.Language.toAsciiLowerCase(); 191 aLoc.Country = i_rLocale.Country.toAsciiUpperCase(); 192 aLoc.Variant = i_rLocale.Variant.toAsciiUpperCase(); 193 m_aTranslations[ aK ][ aLoc ] = i_rTranslation; 194 } 195 } 196 197 rtl::OUString PPDTranslator::translateValue( 198 const rtl::OUString& i_rKey, 199 const rtl::OUString& i_rOption, 200 const rtl::OUString& i_rValue, 201 const com::sun::star::lang::Locale& i_rLocale 202 ) const 203 { 204 rtl::OUString aResult; 205 206 rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 ); 207 aKey.append( i_rKey ); 208 if( i_rOption.getLength() || i_rValue.getLength() ) 209 { 210 aKey.append( sal_Unicode( ':' ) ); 211 aKey.append( i_rOption ); 212 } 213 if( i_rValue.getLength() ) 214 { 215 aKey.append( sal_Unicode( ':' ) ); 216 aKey.append( i_rValue ); 217 } 218 if( aKey.getLength() ) 219 { 220 rtl::OUString aK( aKey.makeStringAndClear() ); 221 key_translation_map::const_iterator it = m_aTranslations.find( aK ); 222 if( it != m_aTranslations.end() ) 223 { 224 const translation_map& rMap( it->second ); 225 226 com::sun::star::lang::Locale aLoc( normalizeInputLocale( i_rLocale, true ) ); 227 for( int nTry = 0; nTry < 4; nTry++ ) 228 { 229 translation_map::const_iterator tr = rMap.find( aLoc ); 230 if( tr != rMap.end() ) 231 { 232 aResult = tr->second; 233 break; 234 } 235 switch( nTry ) 236 { 237 case 0: aLoc.Variant = rtl::OUString();break; 238 case 1: aLoc.Country = rtl::OUString();break; 239 case 2: aLoc.Language = rtl::OUString();break; 240 } 241 } 242 } 243 } 244 return aResult; 245 } 246 } 247 248 using namespace psp; 249 using namespace rtl; 250 251 #undef DBG_ASSERT 252 #if defined DBG_UTIL || (OSL_DEBUG_LEVEL > 1) 253 #define BSTRING(x) ByteString( x, osl_getThreadTextEncoding() ) 254 #define DBG_ASSERT( x, y ) { if( ! (x) ) fprintf( stderr, (y) ); } 255 #else 256 #define DBG_ASSERT( x, y ) 257 #endif 258 259 std::list< PPDParser* > PPDParser::aAllParsers; 260 std::hash_map< OUString, OUString, OUStringHash >* PPDParser::pAllPPDFiles = NULL; 261 262 class PPDDecompressStream 263 { 264 SvFileStream* mpFileStream; 265 SvMemoryStream* mpMemStream; 266 rtl::OUString maFileName; 267 268 // forbid copying 269 PPDDecompressStream( const PPDDecompressStream& ); 270 PPDDecompressStream& operator=(const PPDDecompressStream& ); 271 272 public: 273 PPDDecompressStream( const rtl::OUString& rFile ); 274 ~PPDDecompressStream(); 275 276 bool IsOpen() const; 277 bool IsEof() const; 278 void ReadLine( ByteString& o_rLine); 279 void Open( const rtl::OUString& i_rFile ); 280 void Close(); 281 const rtl::OUString& GetFileName() const { return maFileName; } 282 }; 283 284 PPDDecompressStream::PPDDecompressStream( const rtl::OUString& i_rFile ) : 285 mpFileStream( NULL ), 286 mpMemStream( NULL ) 287 { 288 Open( i_rFile ); 289 } 290 291 PPDDecompressStream::~PPDDecompressStream() 292 { 293 Close(); 294 } 295 296 void PPDDecompressStream::Open( const rtl::OUString& i_rFile ) 297 { 298 Close(); 299 300 mpFileStream = new SvFileStream( i_rFile, STREAM_READ ); 301 maFileName = mpFileStream->GetFileName(); 302 303 if( ! mpFileStream->IsOpen() ) 304 { 305 Close(); 306 return; 307 } 308 309 ByteString aLine; 310 mpFileStream->ReadLine( aLine ); 311 mpFileStream->Seek( 0 ); 312 313 // check for compress'ed or gzip'ed file 314 sal_uLong nCompressMethod = 0; 315 if( aLine.Len() > 1 && static_cast<unsigned char>(aLine.GetChar( 0 )) == 0x1f ) 316 { 317 if( static_cast<unsigned char>(aLine.GetChar( 1 )) == 0x8b ) // check for gzip 318 nCompressMethod = ZCODEC_DEFAULT | ZCODEC_GZ_LIB; 319 } 320 321 if( nCompressMethod != 0 ) 322 { 323 // so let's try to decompress the stream 324 mpMemStream = new SvMemoryStream( 4096, 4096 ); 325 ZCodec aCodec; 326 aCodec.BeginCompression( nCompressMethod ); 327 long nComp = aCodec.Decompress( *mpFileStream, *mpMemStream ); 328 aCodec.EndCompression(); 329 if( nComp < 0 ) 330 { 331 // decompression failed, must be an uncompressed stream after all 332 delete mpMemStream, mpMemStream = NULL; 333 mpFileStream->Seek( 0 ); 334 } 335 else 336 { 337 // compression successfull, can get rid of file stream 338 delete mpFileStream, mpFileStream = NULL; 339 mpMemStream->Seek( 0 ); 340 } 341 } 342 } 343 344 void PPDDecompressStream::Close() 345 { 346 delete mpMemStream, mpMemStream = NULL; 347 delete mpFileStream, mpFileStream = NULL; 348 } 349 350 bool PPDDecompressStream::IsOpen() const 351 { 352 return (mpMemStream || (mpFileStream && mpFileStream->IsOpen())); 353 } 354 355 bool PPDDecompressStream::IsEof() const 356 { 357 return ( mpMemStream ? mpMemStream->IsEof() : ( mpFileStream ? mpFileStream->IsEof() : true ) ); 358 } 359 360 void PPDDecompressStream::ReadLine( ByteString& o_rLine ) 361 { 362 if( mpMemStream ) 363 mpMemStream->ReadLine( o_rLine ); 364 else if( mpFileStream ) 365 mpFileStream->ReadLine( o_rLine ); 366 } 367 368 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 ) 369 { 370 osl::DirectoryItem aLinkItem; 371 osl::FileBase::RC aRet = osl::FileBase::E_None; 372 373 if( ( aRet = osl::DirectoryItem::get( i_rURL, aLinkItem ) ) == osl::FileBase::E_None ) 374 { 375 osl::FileStatus aStatus( FileStatusMask_FileName | FileStatusMask_Type | FileStatusMask_LinkTargetURL ); 376 if( ( aRet = aLinkItem.getFileStatus( aStatus ) ) == osl::FileBase::E_None ) 377 { 378 if( aStatus.getFileType() == osl::FileStatus::Link ) 379 { 380 if( nLinkLevel > 0 ) 381 aRet = resolveLink( aStatus.getLinkTargetURL(), o_rResolvedURL, o_rBaseName, o_rType, nLinkLevel-1 ); 382 else 383 aRet = osl::FileBase::E_MULTIHOP; 384 } 385 else 386 { 387 o_rResolvedURL = i_rURL; 388 o_rBaseName = aStatus.getFileName(); 389 o_rType = aStatus.getFileType(); 390 } 391 } 392 } 393 return aRet; 394 } 395 396 void PPDParser::scanPPDDir( const String& rDir ) 397 { 398 static struct suffix_t 399 { 400 const sal_Char* pSuffix; 401 const sal_Int32 nSuffixLen; 402 } const pSuffixes[] = 403 { { ".PS", 3 }, { ".PPD", 4 }, { ".PS.GZ", 6 }, { ".PPD.GZ", 7 } }; 404 405 const int nSuffixes = sizeof(pSuffixes)/sizeof(pSuffixes[0]); 406 407 osl::Directory aDir( rDir ); 408 if ( aDir.open() == osl::FileBase::E_None ) 409 { 410 osl::DirectoryItem aItem; 411 412 INetURLObject aPPDDir(rDir); 413 while( aDir.getNextItem( aItem ) == osl::FileBase::E_None ) 414 { 415 osl::FileStatus aStatus( FileStatusMask_FileName ); 416 if( aItem.getFileStatus( aStatus ) == osl::FileBase::E_None ) 417 { 418 rtl::OUStringBuffer aURLBuf( rDir.Len() + 64 ); 419 aURLBuf.append( rDir ); 420 aURLBuf.append( sal_Unicode( '/' ) ); 421 aURLBuf.append( aStatus.getFileName() ); 422 423 rtl::OUString aFileURL, aFileName; 424 osl::FileStatus::Type eType = osl::FileStatus::Unknown; 425 426 if( resolveLink( aURLBuf.makeStringAndClear(), aFileURL, aFileName, eType ) == osl::FileBase::E_None ) 427 { 428 if( eType == osl::FileStatus::Regular ) 429 { 430 INetURLObject aPPDFile = aPPDDir; 431 aPPDFile.Append( aFileName ); 432 433 // match extension 434 for( int nSuffix = 0; nSuffix < nSuffixes; nSuffix++ ) 435 { 436 if( aFileName.getLength() > pSuffixes[nSuffix].nSuffixLen ) 437 { 438 if( aFileName.endsWithIgnoreAsciiCaseAsciiL( pSuffixes[nSuffix].pSuffix, pSuffixes[nSuffix].nSuffixLen ) ) 439 { 440 (*pAllPPDFiles)[ aFileName.copy( 0, aFileName.getLength() - pSuffixes[nSuffix].nSuffixLen ) ] = aPPDFile.PathToFileName(); 441 break; 442 } 443 } 444 } 445 } 446 else if( eType == osl::FileStatus::Directory ) 447 { 448 scanPPDDir( aFileURL ); 449 } 450 } 451 } 452 } 453 aDir.close(); 454 } 455 } 456 457 void PPDParser::initPPDFiles() 458 { 459 if( pAllPPDFiles ) 460 return; 461 462 pAllPPDFiles = new std::hash_map< OUString, OUString, OUStringHash >(); 463 464 // check installation directories 465 std::list< OUString > aPathList; 466 psp::getPrinterPathList( aPathList, PRINTER_PPDDIR ); 467 for( std::list< OUString >::const_iterator ppd_it = aPathList.begin(); ppd_it != aPathList.end(); ++ppd_it ) 468 { 469 INetURLObject aPPDDir( *ppd_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); 470 scanPPDDir( aPPDDir.GetMainURL( INetURLObject::NO_DECODE ) ); 471 } 472 if( pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() ) 473 { 474 // last try: search in directory of executable (mainly for setup) 475 OUString aExe; 476 if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None ) 477 { 478 INetURLObject aDir( aExe ); 479 aDir.removeSegment(); 480 #ifdef DEBUG 481 fprintf( stderr, "scanning last chance dir: %s\n", OUStringToOString( aDir.GetMainURL( INetURLObject::NO_DECODE ), osl_getThreadTextEncoding() ).getStr() ); 482 #endif 483 scanPPDDir( aDir.GetMainURL( INetURLObject::NO_DECODE ) ); 484 #ifdef DEBUG 485 fprintf( stderr, "SGENPRT %s\n", pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() ? "not found" : "found" ); 486 #endif 487 } 488 } 489 } 490 491 void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh ) 492 { 493 if( bRefresh ) 494 { 495 delete pAllPPDFiles; 496 pAllPPDFiles = NULL; 497 } 498 499 initPPDFiles(); 500 o_rDrivers.clear(); 501 502 std::hash_map< OUString, OUString, OUStringHash >::const_iterator it; 503 for( it = pAllPPDFiles->begin(); it != pAllPPDFiles->end(); ++it ) 504 o_rDrivers.push_back( it->first ); 505 } 506 507 String PPDParser::getPPDFile( const String& rFile ) 508 { 509 INetURLObject aPPD( rFile, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); 510 // someone might enter a full qualified name here 511 PPDDecompressStream aStream( aPPD.PathToFileName() ); 512 if( ! aStream.IsOpen() ) 513 { 514 std::hash_map< OUString, OUString, OUStringHash >::const_iterator it; 515 516 bool bRetry = true; 517 do 518 { 519 initPPDFiles(); 520 // some PPD files contain dots beside the extension, so try name first 521 // and cut of points after that 522 rtl::OUString aBase( rFile ); 523 sal_Int32 nLastIndex = aBase.lastIndexOf( sal_Unicode( '/' ) ); 524 if( nLastIndex >= 0 ) 525 aBase = aBase.copy( nLastIndex+1 ); 526 do 527 { 528 it = pAllPPDFiles->find( aBase ); 529 nLastIndex = aBase.lastIndexOf( sal_Unicode( '.' ) ); 530 if( nLastIndex > 0 ) 531 aBase = aBase.copy( 0, nLastIndex ); 532 } while( it == pAllPPDFiles->end() && nLastIndex > 0 ); 533 534 if( it == pAllPPDFiles->end() && bRetry ) 535 { 536 // a new file ? rehash 537 delete pAllPPDFiles; pAllPPDFiles = NULL; 538 bRetry = false; 539 // note this is optimized for office start where 540 // no new files occur and initPPDFiles is called only once 541 } 542 } while( ! pAllPPDFiles ); 543 544 if( it != pAllPPDFiles->end() ) 545 aStream.Open( it->second ); 546 } 547 548 String aRet; 549 if( aStream.IsOpen() ) 550 { 551 ByteString aLine; 552 aStream.ReadLine( aLine ); 553 if( aLine.Search( "*PPD-Adobe" ) == 0 ) 554 aRet = aStream.GetFileName(); 555 else 556 { 557 // our *Include hack does usually not begin 558 // with *PPD-Adobe, so try some lines for *Include 559 int nLines = 10; 560 while( aLine.Search( "*Include" ) != 0 && --nLines ) 561 aStream.ReadLine( aLine ); 562 if( nLines ) 563 aRet = aStream.GetFileName(); 564 } 565 } 566 567 return aRet; 568 } 569 570 String PPDParser::getPPDPrinterName( const String& rFile ) 571 { 572 String aPath = getPPDFile( rFile ); 573 String aName; 574 575 // read in the file 576 PPDDecompressStream aStream( aPath ); 577 if( aStream.IsOpen() ) 578 { 579 String aCurLine; 580 while( ! aStream.IsEof() && aStream.IsOpen() ) 581 { 582 ByteString aByteLine; 583 aStream.ReadLine( aByteLine ); 584 aCurLine = String( aByteLine, RTL_TEXTENCODING_MS_1252 ); 585 if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL ) 586 { 587 aCurLine.Erase( 0, 9 ); 588 aCurLine.EraseLeadingChars( ' ' ); 589 aCurLine.EraseTrailingChars( ' ' ); 590 aCurLine.EraseLeadingChars( '\t' ); 591 aCurLine.EraseTrailingChars( '\t' ); 592 aCurLine.EraseTrailingChars( '\r' ); 593 aCurLine.EraseTrailingChars( '\n' ); 594 aCurLine.EraseLeadingChars( '"' ); 595 aCurLine.EraseTrailingChars( '"' ); 596 aStream.Close(); 597 aStream.Open( getPPDFile( aCurLine ) ); 598 continue; 599 } 600 if( aCurLine.CompareToAscii( "*ModelName:", 11 ) == COMPARE_EQUAL ) 601 { 602 aName = aCurLine.GetToken( 1, '"' ); 603 break; 604 } 605 else if( aCurLine.CompareToAscii( "*NickName:", 10 ) == COMPARE_EQUAL ) 606 aName = aCurLine.GetToken( 1, '"' ); 607 } 608 } 609 return aName; 610 } 611 612 const PPDParser* PPDParser::getParser( const String& rFile ) 613 { 614 static ::osl::Mutex aMutex; 615 ::osl::Guard< ::osl::Mutex > aGuard( aMutex ); 616 617 String aFile = rFile; 618 if( rFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL ) 619 aFile = getPPDFile( rFile ); 620 if( ! aFile.Len() ) 621 { 622 #if OSL_DEBUG_LEVEL > 1 623 fprintf( stderr, "Could not get printer PPD file \"%s\" !\n", OUStringToOString( rFile, osl_getThreadTextEncoding() ).getStr() ); 624 #endif 625 return NULL; 626 } 627 628 for( ::std::list< PPDParser* >::const_iterator it = aAllParsers.begin(); it != aAllParsers.end(); ++it ) 629 if( (*it)->m_aFile == aFile ) 630 return *it; 631 632 PPDParser* pNewParser = NULL; 633 if( aFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL ) 634 pNewParser = new PPDParser( aFile ); 635 else 636 { 637 PrinterInfoManager& rMgr = PrinterInfoManager::get(); 638 if( rMgr.getType() == PrinterInfoManager::CUPS ) 639 { 640 pNewParser = const_cast<PPDParser*>(static_cast<CUPSManager&>(rMgr).createCUPSParser( aFile )); 641 } 642 } 643 if( pNewParser ) 644 { 645 // this may actually be the SGENPRT parser, 646 // so ensure uniquness here 647 aAllParsers.remove( pNewParser ); 648 // insert new parser to list 649 aAllParsers.push_front( pNewParser ); 650 } 651 return pNewParser; 652 } 653 654 void PPDParser::freeAll() 655 { 656 while( aAllParsers.begin() != aAllParsers.end() ) 657 { 658 delete aAllParsers.front(); 659 aAllParsers.pop_front(); 660 } 661 delete pAllPPDFiles; 662 pAllPPDFiles = NULL; 663 } 664 665 PPDParser::PPDParser( const String& rFile ) : 666 m_aFile( rFile ), 667 m_bType42Capable( false ), 668 m_aFileEncoding( RTL_TEXTENCODING_MS_1252 ), 669 m_pDefaultImageableArea( NULL ), 670 m_pImageableAreas( NULL ), 671 m_pDefaultPaperDimension( NULL ), 672 m_pPaperDimensions( NULL ), 673 m_pDefaultInputSlot( NULL ), 674 m_pInputSlots( NULL ), 675 m_pDefaultResolution( NULL ), 676 m_pResolutions( NULL ), 677 m_pDefaultDuplexType( NULL ), 678 m_pDuplexTypes( NULL ), 679 m_pFontList( NULL ), 680 m_pTranslator( new PPDTranslator() ) 681 { 682 // read in the file 683 std::list< ByteString > aLines; 684 PPDDecompressStream aStream( m_aFile ); 685 bool bLanguageEncoding = false; 686 if( aStream.IsOpen() ) 687 { 688 ByteString aCurLine; 689 while( ! aStream.IsEof() ) 690 { 691 aStream.ReadLine( aCurLine ); 692 if( aCurLine.GetChar( 0 ) == '*' ) 693 { 694 if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL ) 695 { 696 aCurLine.Erase( 0, 9 ); 697 aCurLine.EraseLeadingChars( ' ' ); 698 aCurLine.EraseTrailingChars( ' ' ); 699 aCurLine.EraseLeadingChars( '\t' ); 700 aCurLine.EraseTrailingChars( '\t' ); 701 aCurLine.EraseTrailingChars( '\r' ); 702 aCurLine.EraseTrailingChars( '\n' ); 703 aCurLine.EraseLeadingChars( '"' ); 704 aCurLine.EraseTrailingChars( '"' ); 705 aStream.Close(); 706 aStream.Open( getPPDFile( String( aCurLine, m_aFileEncoding ) ) ); 707 continue; 708 } 709 else if( ! bLanguageEncoding && 710 aCurLine.CompareIgnoreCaseToAscii( "*languageencoding", 17 ) == COMPARE_EQUAL ) 711 { 712 bLanguageEncoding = true; // generally only the first one counts 713 ByteString aLower = aCurLine; 714 aLower.ToLowerAscii(); 715 if( aLower.Search( "isolatin1", 17 ) != STRING_NOTFOUND || 716 aLower.Search( "windowsansi", 17 ) != STRING_NOTFOUND ) 717 m_aFileEncoding = RTL_TEXTENCODING_MS_1252; 718 else if( aLower.Search( "isolatin2", 17 ) != STRING_NOTFOUND ) 719 m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_2; 720 else if( aLower.Search( "isolatin5", 17 ) != STRING_NOTFOUND ) 721 m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_5; 722 else if( aLower.Search( "jis83-rksj", 17 ) != STRING_NOTFOUND ) 723 m_aFileEncoding = RTL_TEXTENCODING_SHIFT_JIS; 724 else if( aLower.Search( "macstandard", 17 ) != STRING_NOTFOUND ) 725 m_aFileEncoding = RTL_TEXTENCODING_APPLE_ROMAN; 726 else if( aLower.Search( "utf-8", 17 ) != STRING_NOTFOUND ) 727 m_aFileEncoding = RTL_TEXTENCODING_UTF8; 728 } 729 } 730 aLines.push_back( aCurLine ); 731 } 732 } 733 aStream.Close(); 734 735 // now get the Values 736 parse( aLines ); 737 #if OSL_DEBUG_LEVEL > 2 738 fprintf( stderr, "acquired %d Keys from PPD %s:\n", m_aKeys.size(), BSTRING( m_aFile ).GetBuffer() ); 739 for( PPDParser::hash_type::const_iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it ) 740 { 741 const PPDKey* pKey = it->second; 742 char* pSetupType = "<unknown>"; 743 switch( pKey->m_eSetupType ) 744 { 745 case PPDKey::ExitServer: pSetupType = "ExitServer";break; 746 case PPDKey::Prolog: pSetupType = "Prolog";break; 747 case PPDKey::DocumentSetup: pSetupType = "DocumentSetup";break; 748 case PPDKey::PageSetup: pSetupType = "PageSetup";break; 749 case PPDKey::JCLSetup: pSetupType = "JCLSetup";break; 750 case PPDKey::AnySetup: pSetupType = "AnySetup";break; 751 default: break; 752 }; 753 fprintf( stderr, "\t\"%s\" (\"%s\") (%d values) OrderDependency: %d %s\n", 754 BSTRING( pKey->getKey() ).GetBuffer(), 755 BSTRING( pKey->m_aUITranslation ).GetBuffer(), 756 pKey->countValues(), 757 pKey->m_nOrderDependency, 758 pSetupType ); 759 for( int j = 0; j < pKey->countValues(); j++ ) 760 { 761 fprintf( stderr, "\t\t" ); 762 const PPDValue* pValue = pKey->getValue( j ); 763 if( pValue == pKey->m_pDefaultValue ) 764 fprintf( stderr, "(Default:) " ); 765 char* pVType = "<unknown>"; 766 switch( pValue->m_eType ) 767 { 768 case eInvocation: pVType = "invocation";break; 769 case eQuoted: pVType = "quoted";break; 770 case eString: pVType = "string";break; 771 case eSymbol: pVType = "symbol";break; 772 case eNo: pVType = "no";break; 773 default: break; 774 }; 775 fprintf( stderr, "option: \"%s\" (\"%s\"), value: type %s \"%s\" (\"%s\")\n", 776 BSTRING( pValue->m_aOption ).GetBuffer(), 777 BSTRING( pValue->m_aOptionTranslation ).GetBuffer(), 778 pVType, 779 BSTRING( pValue->m_aValue ).GetBuffer(), 780 BSTRING( pValue->m_aValueTranslation ).GetBuffer() ); 781 } 782 } 783 fprintf( stderr, "constraints: (%d found)\n", m_aConstraints.size() ); 784 for( std::list< PPDConstraint >::const_iterator cit = m_aConstraints.begin(); cit != m_aConstraints.end(); ++cit ) 785 { 786 fprintf( stderr, "*\"%s\" \"%s\" *\"%s\" \"%s\"\n", 787 BSTRING( cit->m_pKey1->getKey() ).GetBuffer(), 788 cit->m_pOption1 ? BSTRING( cit->m_pOption1->m_aOption ).GetBuffer() : "<nil>", 789 BSTRING( cit->m_pKey2->getKey() ).GetBuffer(), 790 cit->m_pOption2 ? BSTRING( cit->m_pOption2->m_aOption ).GetBuffer() : "<nil>" 791 ); 792 } 793 #endif 794 795 // fill in shortcuts 796 const PPDKey* pKey; 797 798 m_pImageableAreas = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ImageableArea" ) ) ); 799 if( m_pImageableAreas ) 800 m_pDefaultImageableArea = m_pImageableAreas->getDefaultValue(); 801 DBG_ASSERT( m_pImageableAreas, "Warning: no ImageableArea in PPD\n" ); 802 DBG_ASSERT( m_pDefaultImageableArea, "Warning: no DefaultImageableArea in PPD\n" ); 803 804 m_pPaperDimensions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PaperDimension" ) ) ); 805 if( m_pPaperDimensions ) 806 m_pDefaultPaperDimension = m_pPaperDimensions->getDefaultValue(); 807 DBG_ASSERT( m_pPaperDimensions, "Warning: no PaperDimension in PPD\n" ); 808 DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultPaperDimension in PPD\n" ); 809 810 m_pResolutions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) ); 811 if( m_pResolutions ) 812 m_pDefaultResolution = m_pResolutions->getDefaultValue(); 813 DBG_ASSERT( m_pResolutions, "Warning: no Resolution in PPD\n" ); 814 DBG_ASSERT( m_pDefaultResolution, "Warning: no DefaultResolution in PPD\n" ); 815 816 m_pInputSlots = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 817 if( m_pInputSlots ) 818 m_pDefaultInputSlot = m_pInputSlots->getDefaultValue(); 819 DBG_ASSERT( m_pPaperDimensions, "Warning: no InputSlot in PPD\n" ); 820 DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultInputSlot in PPD\n" ); 821 822 m_pDuplexTypes = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 823 if( m_pDuplexTypes ) 824 m_pDefaultDuplexType = m_pDuplexTypes->getDefaultValue(); 825 826 m_pFontList = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Font" ) ) ); 827 DBG_ASSERT( m_pFontList, "Warning: no Font in PPD\n" ); 828 829 // fill in direct values 830 if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ModelName" ) ) )) ) 831 m_aPrinterName = pKey->getValue( 0 )->m_aValue; 832 if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "NickName" ) ) )) ) 833 m_aNickName = pKey->getValue( 0 )->m_aValue; 834 if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ColorDevice" ) ) )) ) 835 m_bColorDevice = pKey->getValue( 0 )->m_aValue.CompareIgnoreCaseToAscii( "true", 4 ) == COMPARE_EQUAL ? true : false; 836 837 if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "LanguageLevel" ) ) )) ) 838 m_nLanguageLevel = pKey->getValue( 0 )->m_aValue.ToInt32(); 839 if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) )) ) 840 m_bType42Capable = pKey->getValue( 0 )->m_aValue.EqualsIgnoreCaseAscii( "Type42" ) ? true : false; 841 } 842 843 PPDParser::~PPDParser() 844 { 845 for( PPDParser::hash_type::iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it ) 846 delete it->second; 847 delete m_pTranslator; 848 } 849 850 void PPDParser::insertKey( const String& rKey, PPDKey* pKey ) 851 { 852 m_aKeys[ rKey ] = pKey; 853 m_aOrderedKeys.push_back( pKey ); 854 } 855 856 const PPDKey* PPDParser::getKey( int n ) const 857 { 858 return ((unsigned int)n < m_aOrderedKeys.size() && n >= 0) ? m_aOrderedKeys[n] : NULL; 859 } 860 861 const PPDKey* PPDParser::getKey( const String& rKey ) const 862 { 863 PPDParser::hash_type::const_iterator it = m_aKeys.find( rKey ); 864 return it != m_aKeys.end() ? it->second : NULL; 865 } 866 867 bool PPDParser::hasKey( const PPDKey* pKey ) const 868 { 869 return 870 pKey ? 871 ( m_aKeys.find( pKey->getKey() ) != m_aKeys.end() ? true : false ) : 872 false; 873 } 874 875 static sal_uInt8 getNibble( sal_Char cChar ) 876 { 877 sal_uInt8 nRet = 0; 878 if( cChar >= '0' && cChar <= '9' ) 879 nRet = sal_uInt8( cChar - '0' ); 880 else if( cChar >= 'A' && cChar <= 'F' ) 881 nRet = 10 + sal_uInt8( cChar - 'A' ); 882 else if( cChar >= 'a' && cChar <= 'f' ) 883 nRet = 10 + sal_uInt8( cChar - 'a' ); 884 return nRet; 885 } 886 887 String PPDParser::handleTranslation( const ByteString& i_rString, bool bIsGlobalized ) 888 { 889 int nOrigLen = i_rString.Len(); 890 OStringBuffer aTrans( nOrigLen ); 891 const sal_Char* pStr = i_rString.GetBuffer(); 892 const sal_Char* pEnd = pStr + nOrigLen; 893 while( pStr < pEnd ) 894 { 895 if( *pStr == '<' ) 896 { 897 pStr++; 898 sal_Char cChar; 899 while( *pStr != '>' && pStr < pEnd-1 ) 900 { 901 cChar = getNibble( *pStr++ ) << 4; 902 cChar |= getNibble( *pStr++ ); 903 aTrans.append( cChar ); 904 } 905 pStr++; 906 } 907 else 908 aTrans.append( *pStr++ ); 909 } 910 return OStringToOUString( aTrans.makeStringAndClear(), bIsGlobalized ? RTL_TEXTENCODING_UTF8 : m_aFileEncoding ); 911 } 912 913 void PPDParser::parse( ::std::list< ByteString >& rLines ) 914 { 915 std::list< ByteString >::iterator line = rLines.begin(); 916 PPDParser::hash_type::const_iterator keyit; 917 while( line != rLines.end() ) 918 { 919 ByteString aCurrentLine( *line ); 920 ++line; 921 if( aCurrentLine.GetChar(0) != '*' ) 922 continue; 923 if( aCurrentLine.GetChar(1) == '%' ) 924 continue; 925 926 ByteString aKey = GetCommandLineToken( 0, aCurrentLine.GetToken( 0, ':' ) ); 927 int nPos = aKey.Search( '/' ); 928 if( nPos != STRING_NOTFOUND ) 929 aKey.Erase( nPos ); 930 aKey.Erase( 0, 1 ); // remove the '*' 931 932 if( aKey.Equals( "CloseUI" ) || aKey.Equals( "OpenGroup" ) || aKey.Equals( "CloseGroup" ) || aKey.Equals( "End" ) || aKey.Equals( "OpenSubGroup" ) || aKey.Equals( "CloseSubGroup" ) ) 933 continue; 934 935 if( aKey.Equals( "OpenUI" ) ) 936 { 937 parseOpenUI( aCurrentLine ); 938 continue; 939 } 940 else if( aKey.Equals( "OrderDependency" ) ) 941 { 942 parseOrderDependency( aCurrentLine ); 943 continue; 944 } 945 else if( aKey.Equals( "UIConstraints" ) || aKey.Equals( "NonUIConstraints" ) ) 946 continue; // parsed in pass 2 947 else if( aKey.Equals( "CustomPageSize" ) ) // currently not handled 948 continue; 949 950 // default values are parsed in pass 2 951 if( aKey.CompareTo( "Default", 7 ) == COMPARE_EQUAL ) 952 continue; 953 954 bool bQuery = false; 955 if( aKey.GetChar( 0 ) == '?' ) 956 { 957 aKey.Erase( 0, 1 ); 958 bQuery = true; 959 } 960 961 String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 ); 962 // handle CUPS extension for globalized PPDs 963 bool bIsGlobalizedLine = false; 964 com::sun::star::lang::Locale aTransLocale; 965 if( ( aUniKey.Len() > 3 && aUniKey.GetChar( 2 ) == '.' ) || 966 ( aUniKey.Len() > 5 && aUniKey.GetChar( 2 ) == '_' && aUniKey.GetChar( 5 ) == '.' ) ) 967 { 968 if( aUniKey.GetChar( 2 ) == '.' ) 969 { 970 aTransLocale.Language = aUniKey.Copy( 0, 2 ); 971 aUniKey = aUniKey.Copy( 3 ); 972 } 973 else 974 { 975 aTransLocale.Language = aUniKey.Copy( 0, 2 ); 976 aTransLocale.Country = aUniKey.Copy( 3, 2 ); 977 aUniKey = aUniKey.Copy( 6 ); 978 } 979 bIsGlobalizedLine = true; 980 } 981 982 String aOption; 983 nPos = aCurrentLine.Search( ':' ); 984 if( nPos != STRING_NOTFOUND ) 985 { 986 aOption = String( aCurrentLine.Copy( 1, nPos-1 ), RTL_TEXTENCODING_MS_1252 ); 987 aOption = GetCommandLineToken( 1, aOption ); 988 int nTransPos = aOption.Search( '/' ); 989 if( nTransPos != STRING_NOTFOUND ) 990 aOption.Erase( nTransPos ); 991 } 992 993 PPDValueType eType = eNo; 994 String aValue; 995 rtl::OUString aOptionTranslation; 996 rtl::OUString aValueTranslation; 997 if( nPos != STRING_NOTFOUND ) 998 { 999 // found a colon, there may be an option 1000 ByteString aLine = aCurrentLine.Copy( 1, nPos-1 ); 1001 aLine = WhitespaceToSpace( aLine ); 1002 int nTransPos = aLine.Search( '/' ); 1003 if( nTransPos != STRING_NOTFOUND ) 1004 aOptionTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine ); 1005 1006 // read in more lines if necessary for multiline values 1007 aLine = aCurrentLine.Copy( nPos+1 ); 1008 if( aLine.Len() ) 1009 { 1010 while( ! ( aLine.GetTokenCount( '"' ) & 1 ) && 1011 line != rLines.end() ) 1012 // while there is an even number of tokens; that means 1013 // an odd number of doubleqoutes 1014 { 1015 // copy the newlines also 1016 aLine += '\n'; 1017 aLine += *line; 1018 ++line; 1019 } 1020 } 1021 aLine = WhitespaceToSpace( aLine ); 1022 1023 // #i100644# handle a missing value (actually a broken PPD) 1024 if( ! aLine.Len() ) 1025 { 1026 if( aOption.Len() && 1027 aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL ) 1028 eType = eInvocation; 1029 else 1030 eType = eQuoted; 1031 } 1032 // check for invocation or quoted value 1033 else if( aLine.GetChar(0) == '"' ) 1034 { 1035 aLine.Erase( 0, 1 ); 1036 nTransPos = aLine.Search( '"' ); 1037 aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 ); 1038 // after the second doublequote can follow a / and a translation 1039 aValueTranslation = handleTranslation( aLine.Copy( nTransPos+2 ), bIsGlobalizedLine ); 1040 // check for quoted value 1041 if( aOption.Len() && 1042 aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL ) 1043 eType = eInvocation; 1044 else 1045 eType = eQuoted; 1046 } 1047 // check for symbol value 1048 else if( aLine.GetChar(0) == '^' ) 1049 { 1050 aLine.Erase( 0, 1 ); 1051 aValue = String( aLine, RTL_TEXTENCODING_MS_1252 ); 1052 eType = eSymbol; 1053 } 1054 else 1055 { 1056 // must be a string value then 1057 // strictly this is false because string values 1058 // can contain any whitespace which is reduced 1059 // to one space by now 1060 // who cares ... 1061 nTransPos = aLine.Search( '/' ); 1062 if( nTransPos == STRING_NOTFOUND ) 1063 nTransPos = aLine.Len(); 1064 aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 ); 1065 aValueTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine ); 1066 eType = eString; 1067 } 1068 } 1069 1070 // handle globalized PPD entries 1071 if( bIsGlobalizedLine ) 1072 { 1073 // handle main key translations of form: 1074 // *ll_CC.Translation MainKeyword/translated text: "" 1075 if( aUniKey.EqualsAscii( "Translation" ) ) 1076 { 1077 m_pTranslator->insertKey( aOption, aOptionTranslation, aTransLocale ); 1078 } 1079 // handle options translations of for: 1080 // *ll_CC.MainKeyword OptionKeyword/translated text: "" 1081 else 1082 { 1083 m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale ); 1084 } 1085 continue; 1086 } 1087 1088 PPDKey* pKey = NULL; 1089 keyit = m_aKeys.find( aUniKey ); 1090 if( keyit == m_aKeys.end() ) 1091 { 1092 pKey = new PPDKey( aUniKey ); 1093 insertKey( aUniKey, pKey ); 1094 } 1095 else 1096 pKey = keyit->second; 1097 1098 if( eType == eNo && bQuery ) 1099 continue; 1100 1101 PPDValue* pValue = pKey->insertValue( aOption ); 1102 if( ! pValue ) 1103 continue; 1104 pValue->m_eType = eType; 1105 pValue->m_aValue = aValue; 1106 1107 if( aOptionTranslation.getLength() ) 1108 m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale ); 1109 if( aValueTranslation.getLength() ) 1110 m_pTranslator->insertValue( aUniKey, aOption, aValue, aValueTranslation, aTransLocale ); 1111 1112 // eventually update query and remove from option list 1113 if( bQuery && pKey->m_bQueryValue == sal_False ) 1114 { 1115 pKey->m_aQueryValue = *pValue; 1116 pKey->m_bQueryValue = true; 1117 pKey->eraseValue( pValue->m_aOption ); 1118 } 1119 } 1120 1121 // second pass: fill in defaults 1122 for( line = rLines.begin(); line != rLines.end(); ++line ) 1123 { 1124 ByteString aLine( *line ); 1125 if( aLine.CompareTo( "*Default", 8 ) == COMPARE_EQUAL ) 1126 { 1127 String aKey( aLine.Copy( 8 ), RTL_TEXTENCODING_MS_1252 ); 1128 sal_uInt16 nPos = aKey.Search( ':' ); 1129 if( nPos != STRING_NOTFOUND ) 1130 { 1131 aKey.Erase( nPos ); 1132 String aOption( WhitespaceToSpace( aLine.Copy( nPos+9 ) ), RTL_TEXTENCODING_MS_1252 ); 1133 keyit = m_aKeys.find( aKey ); 1134 if( keyit != m_aKeys.end() ) 1135 { 1136 PPDKey* pKey = keyit->second; 1137 const PPDValue* pDefValue = pKey->getValue( aOption ); 1138 if( pKey->m_pDefaultValue == NULL ) 1139 pKey->m_pDefaultValue = pDefValue; 1140 } 1141 else 1142 { 1143 // some PPDs contain defaults for keys that 1144 // do not exist otherwise 1145 // (example: DefaultResolution) 1146 // so invent that key here and have a default value 1147 PPDKey* pKey = new PPDKey( aKey ); 1148 PPDValue* pNewValue = pKey->insertValue( aOption ); 1149 pNewValue->m_eType = eInvocation; // or what ? 1150 insertKey( aKey, pKey ); 1151 } 1152 } 1153 } 1154 else if( aLine.CompareTo( "*UIConstraints", 14 ) == COMPARE_EQUAL || 1155 aLine.CompareTo( "*NonUIConstraints", 17 ) == COMPARE_EQUAL ) 1156 parseConstraint( aLine ); 1157 1158 } 1159 } 1160 1161 void PPDParser::parseOpenUI( const ByteString& rLine ) 1162 { 1163 String aTranslation; 1164 ByteString aKey = rLine; 1165 1166 int nPos = aKey.Search( ':' ); 1167 if( nPos != STRING_NOTFOUND ) 1168 aKey.Erase( nPos ); 1169 nPos = aKey.Search( '/' ); 1170 if( nPos != STRING_NOTFOUND ) 1171 { 1172 aTranslation = handleTranslation( aKey.Copy( nPos + 1 ), false ); 1173 aKey.Erase( nPos ); 1174 } 1175 aKey = GetCommandLineToken( 1, aKey ); 1176 aKey.Erase( 0, 1 ); 1177 1178 String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 ); 1179 PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aUniKey ); 1180 PPDKey* pKey; 1181 if( keyit == m_aKeys.end() ) 1182 { 1183 pKey = new PPDKey( aUniKey ); 1184 insertKey( aUniKey, pKey ); 1185 } 1186 else 1187 pKey = keyit->second; 1188 1189 pKey->m_bUIOption = true; 1190 m_pTranslator->insertKey( pKey->getKey(), aTranslation ); 1191 1192 ByteString aValue = WhitespaceToSpace( rLine.GetToken( 1, ':' ) ); 1193 if( aValue.CompareIgnoreCaseToAscii( "boolean" ) == COMPARE_EQUAL ) 1194 pKey->m_eUIType = PPDKey::Boolean; 1195 else if( aValue.CompareIgnoreCaseToAscii( "pickmany" ) == COMPARE_EQUAL ) 1196 pKey->m_eUIType = PPDKey::PickMany; 1197 else 1198 pKey->m_eUIType = PPDKey::PickOne; 1199 } 1200 1201 void PPDParser::parseOrderDependency( const ByteString& rLine ) 1202 { 1203 ByteString aLine( rLine ); 1204 int nPos = aLine.Search( ':' ); 1205 if( nPos != STRING_NOTFOUND ) 1206 aLine.Erase( 0, nPos+1 ); 1207 1208 int nOrder = GetCommandLineToken( 0, aLine ).ToInt32(); 1209 ByteString aSetup = GetCommandLineToken( 1, aLine ); 1210 String aKey( GetCommandLineToken( 2, aLine ), RTL_TEXTENCODING_MS_1252 ); 1211 if( aKey.GetChar( 0 ) != '*' ) 1212 return; // invalid order depency 1213 aKey.Erase( 0, 1 ); 1214 1215 PPDKey* pKey; 1216 PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aKey ); 1217 if( keyit == m_aKeys.end() ) 1218 { 1219 pKey = new PPDKey( aKey ); 1220 insertKey( aKey, pKey ); 1221 } 1222 else 1223 pKey = keyit->second; 1224 1225 pKey->m_nOrderDependency = nOrder; 1226 if( aSetup.Equals( "ExitServer" ) ) 1227 pKey->m_eSetupType = PPDKey::ExitServer; 1228 else if( aSetup.Equals( "Prolog" ) ) 1229 pKey->m_eSetupType = PPDKey::Prolog; 1230 else if( aSetup.Equals( "DocumentSetup" ) ) 1231 pKey->m_eSetupType = PPDKey::DocumentSetup; 1232 else if( aSetup.Equals( "PageSetup" ) ) 1233 pKey->m_eSetupType = PPDKey::PageSetup; 1234 else if( aSetup.Equals( "JCLSetup" ) ) 1235 pKey->m_eSetupType = PPDKey::JCLSetup; 1236 else 1237 pKey->m_eSetupType = PPDKey::AnySetup; 1238 } 1239 1240 void PPDParser::parseConstraint( const ByteString& rLine ) 1241 { 1242 bool bFailed = false; 1243 1244 String aLine( rLine, RTL_TEXTENCODING_MS_1252 ); 1245 aLine.Erase( 0, rLine.Search( ':' )+1 ); 1246 PPDConstraint aConstraint; 1247 int nTokens = GetCommandLineTokenCount( aLine ); 1248 for( int i = 0; i < nTokens; i++ ) 1249 { 1250 String aToken = GetCommandLineToken( i, aLine ); 1251 if( aToken.GetChar( 0 ) == '*' ) 1252 { 1253 aToken.Erase( 0, 1 ); 1254 if( aConstraint.m_pKey1 ) 1255 aConstraint.m_pKey2 = getKey( aToken ); 1256 else 1257 aConstraint.m_pKey1 = getKey( aToken ); 1258 } 1259 else 1260 { 1261 if( aConstraint.m_pKey2 ) 1262 { 1263 if( ! ( aConstraint.m_pOption2 = aConstraint.m_pKey2->getValue( aToken ) ) ) 1264 bFailed = true; 1265 } 1266 else if( aConstraint.m_pKey1 ) 1267 { 1268 if( ! ( aConstraint.m_pOption1 = aConstraint.m_pKey1->getValue( aToken ) ) ) 1269 bFailed = true; 1270 } 1271 else 1272 // constraint for nonexistent keys; this happens 1273 // e.g. in HP4PLUS3 (#75636#) 1274 bFailed = true; 1275 } 1276 } 1277 // there must be two keywords 1278 if( ! aConstraint.m_pKey1 || ! aConstraint.m_pKey2 || bFailed ) 1279 { 1280 #ifdef __DEBUG 1281 fprintf( stderr, "Warning: constraint \"%s\" is invalid\n", rLine.GetStr() ); 1282 #endif 1283 } 1284 else 1285 m_aConstraints.push_back( aConstraint ); 1286 } 1287 1288 String PPDParser::getDefaultPaperDimension() const 1289 { 1290 if( m_pDefaultPaperDimension ) 1291 return m_pDefaultPaperDimension->m_aOption; 1292 1293 return String(); 1294 } 1295 1296 bool PPDParser::getMargins( 1297 const String& rPaperName, 1298 int& rLeft, int& rRight, 1299 int& rUpper, int& rLower ) const 1300 { 1301 if( ! m_pImageableAreas || ! m_pPaperDimensions ) 1302 return false; 1303 1304 int nPDim=-1, nImArea=-1, i; 1305 for( i = 0; i < m_pImageableAreas->countValues(); i++ ) 1306 if( rPaperName == m_pImageableAreas->getValue( i )->m_aOption ) 1307 nImArea = i; 1308 for( i = 0; i < m_pPaperDimensions->countValues(); i++ ) 1309 if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption ) 1310 nPDim = i; 1311 if( nPDim == -1 || nImArea == -1 ) 1312 return false; 1313 1314 double ImLLx, ImLLy, ImURx, ImURy; 1315 double PDWidth, PDHeight; 1316 String aArea = m_pImageableAreas->getValue( nImArea )->m_aValue; 1317 ImLLx = StringToDouble( GetCommandLineToken( 0, aArea ) ); 1318 ImLLy = StringToDouble( GetCommandLineToken( 1, aArea ) ); 1319 ImURx = StringToDouble( GetCommandLineToken( 2, aArea ) ); 1320 ImURy = StringToDouble( GetCommandLineToken( 3, aArea ) ); 1321 // sscanf( m_pImageableAreas->getValue( nImArea )->m_aValue.GetStr(), 1322 // "%lg%lg%lg%lg", &ImLLx, &ImLLy, &ImURx, &ImURy ); 1323 aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue; 1324 PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) ); 1325 PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) ); 1326 // sscanf( m_pPaperDimensions->getValue( nPDim )->m_aValue.GetStr(), 1327 // "%lg%lg", &PDWidth, &PDHeight ); 1328 rLeft = (int)(ImLLx + 0.5); 1329 rLower = (int)(ImLLy + 0.5); 1330 rUpper = (int)(PDHeight - ImURy + 0.5); 1331 rRight = (int)(PDWidth - ImURx + 0.5); 1332 1333 return true; 1334 } 1335 1336 bool PPDParser::getPaperDimension( 1337 const String& rPaperName, 1338 int& rWidth, int& rHeight ) const 1339 { 1340 if( ! m_pPaperDimensions ) 1341 return false; 1342 1343 int nPDim=-1; 1344 for( int i = 0; i < m_pPaperDimensions->countValues(); i++ ) 1345 if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption ) 1346 nPDim = i; 1347 if( nPDim == -1 ) 1348 return false; 1349 1350 double PDWidth, PDHeight; 1351 String aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue; 1352 PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) ); 1353 PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) ); 1354 rHeight = (int)(PDHeight + 0.5); 1355 rWidth = (int)(PDWidth + 0.5); 1356 1357 return true; 1358 } 1359 1360 String PPDParser::matchPaper( int nWidth, int nHeight ) const 1361 { 1362 if( ! m_pPaperDimensions ) 1363 return String(); 1364 1365 int nPDim = -1; 1366 double PDWidth, PDHeight; 1367 double fSort = 2e36, fNewSort; 1368 1369 for( int i = 0; i < m_pPaperDimensions->countValues(); i++ ) 1370 { 1371 String aArea = m_pPaperDimensions->getValue( i )->m_aValue; 1372 PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) ); 1373 PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) ); 1374 PDWidth /= (double)nWidth; 1375 PDHeight /= (double)nHeight; 1376 if( PDWidth >= 0.9 && PDWidth <= 1.1 && 1377 PDHeight >= 0.9 && PDHeight <= 1.1 ) 1378 { 1379 fNewSort = 1380 (1.0-PDWidth)*(1.0-PDWidth) + (1.0-PDHeight)*(1.0-PDHeight); 1381 if( fNewSort == 0.0 ) // perfect match 1382 return m_pPaperDimensions->getValue( i )->m_aOption; 1383 1384 if( fNewSort < fSort ) 1385 { 1386 fSort = fNewSort; 1387 nPDim = i; 1388 } 1389 } 1390 } 1391 1392 static bool bDontSwap = false; 1393 if( nPDim == -1 && ! bDontSwap ) 1394 { 1395 // swap portrait/landscape and try again 1396 bDontSwap = true; 1397 String rRet = matchPaper( nHeight, nWidth ); 1398 bDontSwap = false; 1399 return rRet; 1400 } 1401 1402 return nPDim != -1 ? m_pPaperDimensions->getValue( nPDim )->m_aOption : String(); 1403 } 1404 1405 String PPDParser::getDefaultInputSlot() const 1406 { 1407 if( m_pDefaultInputSlot ) 1408 return m_pDefaultInputSlot->m_aValue; 1409 return String(); 1410 } 1411 1412 String PPDParser::getSlot( int nSlot ) const 1413 { 1414 if( ! m_pInputSlots ) 1415 return String(); 1416 1417 if( nSlot > 0 && nSlot < m_pInputSlots->countValues() ) 1418 return m_pInputSlots->getValue( nSlot )->m_aOption; 1419 else if( m_pInputSlots->countValues() > 0 ) 1420 return m_pInputSlots->getValue( (sal_uLong)0 )->m_aOption; 1421 1422 return String(); 1423 } 1424 1425 String PPDParser::getSlotCommand( int nSlot ) const 1426 { 1427 if( ! m_pInputSlots ) 1428 return String(); 1429 1430 if( nSlot > 0 && nSlot < m_pInputSlots->countValues() ) 1431 return m_pInputSlots->getValue( nSlot )->m_aValue; 1432 else if( m_pInputSlots->countValues() > 0 ) 1433 return m_pInputSlots->getValue( (sal_uLong)0 )->m_aValue; 1434 1435 return String(); 1436 } 1437 1438 String PPDParser::getSlotCommand( const String& rSlot ) const 1439 { 1440 if( ! m_pInputSlots ) 1441 return String(); 1442 1443 for( int i=0; i < m_pInputSlots->countValues(); i++ ) 1444 { 1445 const PPDValue* pValue = m_pInputSlots->getValue( i ); 1446 if( pValue->m_aOption == rSlot ) 1447 return pValue->m_aValue; 1448 } 1449 return String(); 1450 } 1451 1452 String PPDParser::getPaperDimension( int nPaperDimension ) const 1453 { 1454 if( ! m_pPaperDimensions ) 1455 return String(); 1456 1457 if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() ) 1458 return m_pPaperDimensions->getValue( nPaperDimension )->m_aOption; 1459 else if( m_pPaperDimensions->countValues() > 0 ) 1460 return m_pPaperDimensions->getValue( (sal_uLong)0 )->m_aOption; 1461 1462 return String(); 1463 } 1464 1465 String PPDParser::getPaperDimensionCommand( int nPaperDimension ) const 1466 { 1467 if( ! m_pPaperDimensions ) 1468 return String(); 1469 1470 if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() ) 1471 return m_pPaperDimensions->getValue( nPaperDimension )->m_aValue; 1472 else if( m_pPaperDimensions->countValues() > 0 ) 1473 return m_pPaperDimensions->getValue( (sal_uLong)0 )->m_aValue; 1474 1475 return String(); 1476 } 1477 1478 String PPDParser::getPaperDimensionCommand( const String& rPaperDimension ) const 1479 { 1480 if( ! m_pPaperDimensions ) 1481 return String(); 1482 1483 for( int i=0; i < m_pPaperDimensions->countValues(); i++ ) 1484 { 1485 const PPDValue* pValue = m_pPaperDimensions->getValue( i ); 1486 if( pValue->m_aOption == rPaperDimension ) 1487 return pValue->m_aValue; 1488 } 1489 return String(); 1490 } 1491 1492 void PPDParser::getResolutionFromString( 1493 const String& rString, 1494 int& rXRes, int& rYRes ) const 1495 { 1496 int nPos = 0, nDPIPos; 1497 1498 rXRes = rYRes = 300; 1499 1500 nDPIPos = rString.SearchAscii( "dpi" ); 1501 if( nDPIPos != STRING_NOTFOUND ) 1502 { 1503 if( ( nPos = rString.Search( 'x' ) ) != STRING_NOTFOUND ) 1504 { 1505 rXRes = rString.Copy( 0, nPos ).ToInt32(); 1506 rYRes = rString.GetToken( 1, 'x' ).Erase( nDPIPos - nPos - 1 ).ToInt32(); 1507 } 1508 else 1509 rXRes = rYRes = rString.Copy( 0, nDPIPos ).ToInt32(); 1510 } 1511 } 1512 1513 void PPDParser::getDefaultResolution( int& rXRes, int& rYRes ) const 1514 { 1515 if( m_pDefaultResolution ) 1516 { 1517 getResolutionFromString( m_pDefaultResolution->m_aValue, rXRes, rYRes ); 1518 return; 1519 } 1520 1521 rXRes = 300; 1522 rYRes = 300; 1523 } 1524 1525 int PPDParser::getResolutions() const 1526 { 1527 if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && 1528 m_pDefaultResolution ) 1529 return 1; 1530 return m_pResolutions ? m_pResolutions->countValues() : 0; 1531 } 1532 1533 void PPDParser::getResolution( int nNr, int& rXRes, int& rYRes ) const 1534 { 1535 if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution && nNr == 0 ) 1536 { 1537 getDefaultResolution( rXRes, rYRes ); 1538 return; 1539 } 1540 if( ! m_pResolutions ) 1541 return; 1542 1543 getResolutionFromString( m_pResolutions->getValue( nNr )->m_aOption, 1544 rXRes, rYRes ); 1545 } 1546 1547 String PPDParser::getResolutionCommand( int nXRes, int nYRes ) const 1548 { 1549 if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution ) 1550 return m_pDefaultResolution->m_aValue; 1551 1552 if( ! m_pResolutions ) 1553 return String(); 1554 1555 int nX, nY; 1556 for( int i = 0; i < m_pResolutions->countValues(); i++ ) 1557 { 1558 getResolutionFromString( m_pResolutions->getValue( i )->m_aOption, 1559 nX, nY ); 1560 if( nX == nXRes && nY == nYRes ) 1561 return m_pResolutions->getValue( i )->m_aValue; 1562 } 1563 return String(); 1564 } 1565 1566 String PPDParser::getDefaultDuplexType() const 1567 { 1568 if( m_pDefaultDuplexType ) 1569 return m_pDefaultDuplexType->m_aValue; 1570 return String(); 1571 } 1572 1573 String PPDParser::getDuplex( int nDuplex ) const 1574 { 1575 if( ! m_pDuplexTypes ) 1576 return String(); 1577 1578 if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() ) 1579 return m_pDuplexTypes->getValue( nDuplex )->m_aOption; 1580 else if( m_pDuplexTypes->countValues() > 0 ) 1581 return m_pDuplexTypes->getValue( (sal_uLong)0 )->m_aOption; 1582 1583 return String(); 1584 } 1585 1586 String PPDParser::getDuplexCommand( int nDuplex ) const 1587 { 1588 if( ! m_pDuplexTypes ) 1589 return String(); 1590 1591 if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() ) 1592 return m_pDuplexTypes->getValue( nDuplex )->m_aValue; 1593 else if( m_pDuplexTypes->countValues() > 0 ) 1594 return m_pDuplexTypes->getValue( (sal_uLong)0 )->m_aValue; 1595 1596 return String(); 1597 } 1598 1599 String PPDParser::getDuplexCommand( const String& rDuplex ) const 1600 { 1601 if( ! m_pDuplexTypes ) 1602 return String(); 1603 1604 for( int i=0; i < m_pDuplexTypes->countValues(); i++ ) 1605 { 1606 const PPDValue* pValue = m_pDuplexTypes->getValue( i ); 1607 if( pValue->m_aOption == rDuplex ) 1608 return pValue->m_aValue; 1609 } 1610 return String(); 1611 } 1612 1613 void PPDParser::getFontAttributes( 1614 int nFont, 1615 String& rEncoding, 1616 String& rCharset ) const 1617 { 1618 if( m_pFontList && nFont >= 0 && nFont < m_pFontList->countValues() ) 1619 { 1620 String aAttribs = 1621 WhitespaceToSpace( m_pFontList->getValue( nFont )->m_aValue ); 1622 rEncoding = GetCommandLineToken( 0, aAttribs ); 1623 rCharset = GetCommandLineToken( 2, aAttribs ); 1624 } 1625 } 1626 1627 void PPDParser::getFontAttributes( 1628 const String& rFont, 1629 String& rEncoding, 1630 String& rCharset ) const 1631 { 1632 if( m_pFontList ) 1633 { 1634 for( int i = 0; i < m_pFontList->countValues(); i++ ) 1635 if( m_pFontList->getValue( i )->m_aOption == rFont ) 1636 getFontAttributes( i, rEncoding, rCharset ); 1637 } 1638 } 1639 1640 String PPDParser::getFont( int nFont ) const 1641 { 1642 if( ! m_pFontList ) 1643 return String(); 1644 1645 if( nFont >=0 && nFont < m_pFontList->countValues() ) 1646 return m_pFontList->getValue( nFont )->m_aOption; 1647 return String(); 1648 } 1649 1650 rtl::OUString PPDParser::translateKey( const rtl::OUString& i_rKey, 1651 const com::sun::star::lang::Locale& i_rLocale ) const 1652 { 1653 rtl::OUString aResult( m_pTranslator->translateKey( i_rKey, i_rLocale ) ); 1654 if( aResult.getLength() == 0 ) 1655 aResult = i_rKey; 1656 return aResult; 1657 } 1658 1659 rtl::OUString PPDParser::translateOption( const rtl::OUString& i_rKey, 1660 const rtl::OUString& i_rOption, 1661 const com::sun::star::lang::Locale& i_rLocale ) const 1662 { 1663 rtl::OUString aResult( m_pTranslator->translateOption( i_rKey, i_rOption, i_rLocale ) ); 1664 if( aResult.getLength() == 0 ) 1665 aResult = i_rOption; 1666 return aResult; 1667 } 1668 1669 rtl::OUString PPDParser::translateValue( const rtl::OUString& i_rKey, 1670 const rtl::OUString& i_rOption, 1671 const rtl::OUString& i_rValue, 1672 const com::sun::star::lang::Locale& i_rLocale ) const 1673 { 1674 rtl::OUString aResult( m_pTranslator->translateValue( i_rKey, i_rOption, i_rValue, i_rLocale ) ); 1675 if( aResult.getLength() == 0 ) 1676 aResult = i_rValue; 1677 return aResult; 1678 } 1679 1680 /* 1681 * PPDKey 1682 */ 1683 1684 PPDKey::PPDKey( const String& rKey ) : 1685 m_aKey( rKey ), 1686 m_pDefaultValue( NULL ), 1687 m_bQueryValue( false ), 1688 m_bUIOption( false ), 1689 m_eUIType( PickOne ), 1690 m_nOrderDependency( 100 ), 1691 m_eSetupType( AnySetup ) 1692 { 1693 } 1694 1695 // ------------------------------------------------------------------- 1696 1697 PPDKey::~PPDKey() 1698 { 1699 } 1700 1701 // ------------------------------------------------------------------- 1702 1703 const PPDValue* PPDKey::getValue( int n ) const 1704 { 1705 return ((unsigned int)n < m_aOrderedValues.size() && n >= 0) ? m_aOrderedValues[n] : NULL; 1706 } 1707 1708 // ------------------------------------------------------------------- 1709 1710 const PPDValue* PPDKey::getValue( const String& rOption ) const 1711 { 1712 PPDKey::hash_type::const_iterator it = m_aValues.find( rOption ); 1713 return it != m_aValues.end() ? &it->second : NULL; 1714 } 1715 1716 // ------------------------------------------------------------------- 1717 1718 const PPDValue* PPDKey::getValueCaseInsensitive( const String& rOption ) const 1719 { 1720 const PPDValue* pValue = getValue( rOption ); 1721 if( ! pValue ) 1722 { 1723 for( size_t n = 0; n < m_aOrderedValues.size() && ! pValue; n++ ) 1724 if( m_aOrderedValues[n]->m_aOption.EqualsIgnoreCaseAscii( rOption ) ) 1725 pValue = m_aOrderedValues[n]; 1726 } 1727 1728 return pValue; 1729 } 1730 1731 // ------------------------------------------------------------------- 1732 1733 void PPDKey::eraseValue( const String& rOption ) 1734 { 1735 PPDKey::hash_type::iterator it = m_aValues.find( rOption ); 1736 if( it == m_aValues.end() ) 1737 return; 1738 1739 for( PPDKey::value_type::iterator vit = m_aOrderedValues.begin(); vit != m_aOrderedValues.end(); ++vit ) 1740 { 1741 if( *vit == &(it->second ) ) 1742 { 1743 m_aOrderedValues.erase( vit ); 1744 break; 1745 } 1746 } 1747 m_aValues.erase( it ); 1748 } 1749 1750 // ------------------------------------------------------------------- 1751 1752 PPDValue* PPDKey::insertValue( const String& rOption ) 1753 { 1754 if( m_aValues.find( rOption ) != m_aValues.end() ) 1755 return NULL; 1756 1757 PPDValue aValue; 1758 aValue.m_aOption = rOption; 1759 m_aValues[ rOption ] = aValue; 1760 PPDValue* pValue = &m_aValues[rOption]; 1761 m_aOrderedValues.push_back( pValue ); 1762 return pValue; 1763 } 1764 1765 // ------------------------------------------------------------------- 1766 1767 /* 1768 * PPDContext 1769 */ 1770 1771 PPDContext::PPDContext( const PPDParser* pParser ) : 1772 m_pParser( pParser ) 1773 { 1774 } 1775 1776 // ------------------------------------------------------------------- 1777 1778 PPDContext& PPDContext::operator=( const PPDContext& rCopy ) 1779 { 1780 m_pParser = rCopy.m_pParser; 1781 m_aCurrentValues = rCopy.m_aCurrentValues; 1782 return *this; 1783 } 1784 1785 // ------------------------------------------------------------------- 1786 1787 PPDContext::~PPDContext() 1788 { 1789 } 1790 1791 // ------------------------------------------------------------------- 1792 1793 const PPDKey* PPDContext::getModifiedKey( int n ) const 1794 { 1795 hash_type::const_iterator it; 1796 for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end() && n--; ++it ) 1797 ; 1798 return it != m_aCurrentValues.end() ? it->first : NULL; 1799 } 1800 1801 // ------------------------------------------------------------------- 1802 1803 void PPDContext::setParser( const PPDParser* pParser ) 1804 { 1805 if( pParser != m_pParser ) 1806 { 1807 m_aCurrentValues.clear(); 1808 m_pParser = pParser; 1809 } 1810 } 1811 1812 // ------------------------------------------------------------------- 1813 1814 const PPDValue* PPDContext::getValue( const PPDKey* pKey ) const 1815 { 1816 if( ! m_pParser ) 1817 return NULL; 1818 1819 hash_type::const_iterator it; 1820 it = m_aCurrentValues.find( pKey ); 1821 if( it != m_aCurrentValues.end() ) 1822 return it->second; 1823 1824 if( ! m_pParser->hasKey( pKey ) ) 1825 return NULL; 1826 1827 const PPDValue* pValue = pKey->getDefaultValue(); 1828 if( ! pValue ) 1829 pValue = pKey->getValue( 0 ); 1830 1831 return pValue; 1832 } 1833 1834 // ------------------------------------------------------------------- 1835 1836 const PPDValue* PPDContext::setValue( const PPDKey* pKey, const PPDValue* pValue, bool bDontCareForConstraints ) 1837 { 1838 if( ! m_pParser || ! pKey ) 1839 return NULL; 1840 1841 // pValue can be NULL - it means ignore this option 1842 1843 if( ! m_pParser->hasKey( pKey ) ) 1844 return NULL; 1845 1846 // check constraints 1847 if( pValue ) 1848 { 1849 if( bDontCareForConstraints ) 1850 { 1851 m_aCurrentValues[ pKey ] = pValue; 1852 } 1853 else if( checkConstraints( pKey, pValue, true ) ) 1854 { 1855 m_aCurrentValues[ pKey ] = pValue; 1856 1857 // after setting this value, check all constraints ! 1858 hash_type::iterator it = m_aCurrentValues.begin(); 1859 while( it != m_aCurrentValues.end() ) 1860 { 1861 if( it->first != pKey && 1862 ! checkConstraints( it->first, it->second, false ) ) 1863 { 1864 #ifdef __DEBUG 1865 fprintf( stderr, "PPDContext::setValue: option %s (%s) is constrained after setting %s to %s\n", 1866 it->first->getKey().GetStr(), 1867 it->second->m_aOption.GetStr(), 1868 pKey->getKey().GetStr(), 1869 pValue->m_aOption.GetStr() ); 1870 #endif 1871 resetValue( it->first, true ); 1872 it = m_aCurrentValues.begin(); 1873 } 1874 else 1875 ++it; 1876 } 1877 } 1878 } 1879 else 1880 m_aCurrentValues[ pKey ] = NULL; 1881 1882 return pValue; 1883 } 1884 1885 // ------------------------------------------------------------------- 1886 1887 bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pValue ) 1888 { 1889 if( ! m_pParser || ! pKey || ! pValue ) 1890 return false; 1891 1892 // ensure that this key is already in the list if it exists at all 1893 if( m_aCurrentValues.find( pKey ) != m_aCurrentValues.end() ) 1894 return checkConstraints( pKey, pValue, false ); 1895 1896 // it is not in the list, insert it temporarily 1897 bool bRet = false; 1898 if( m_pParser->hasKey( pKey ) ) 1899 { 1900 const PPDValue* pDefValue = pKey->getDefaultValue(); 1901 m_aCurrentValues[ pKey ] = pDefValue; 1902 bRet = checkConstraints( pKey, pValue, false ); 1903 m_aCurrentValues.erase( pKey ); 1904 } 1905 1906 return bRet; 1907 } 1908 1909 // ------------------------------------------------------------------- 1910 1911 bool PPDContext::resetValue( const PPDKey* pKey, bool bDefaultable ) 1912 { 1913 if( ! pKey || ! m_pParser || ! m_pParser->hasKey( pKey ) ) 1914 return false; 1915 1916 const PPDValue* pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); 1917 if( ! pResetValue ) 1918 pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) ); 1919 if( ! pResetValue && bDefaultable ) 1920 pResetValue = pKey->getDefaultValue(); 1921 1922 bool bRet = pResetValue ? ( setValue( pKey, pResetValue ) == pResetValue ? true : false ) : false; 1923 1924 return bRet; 1925 } 1926 1927 // ------------------------------------------------------------------- 1928 1929 bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pNewValue, bool bDoReset ) 1930 { 1931 if( ! pNewValue ) 1932 return true; 1933 1934 // sanity checks 1935 if( ! m_pParser ) 1936 return false; 1937 1938 if( pKey->getValue( pNewValue->m_aOption ) != pNewValue ) 1939 return false; 1940 1941 // None / False and the default can always be set, but be careful ! 1942 // setting them might influence constrained values 1943 if( pNewValue->m_aOption.EqualsAscii( "None" ) || pNewValue->m_aOption.EqualsAscii( "False" ) || 1944 pNewValue == pKey->getDefaultValue() ) 1945 return true; 1946 1947 const ::std::list< PPDParser::PPDConstraint >& rConstraints( m_pParser->getConstraints() ); 1948 for( ::std::list< PPDParser::PPDConstraint >::const_iterator it = rConstraints.begin(); it != rConstraints.end(); ++it ) 1949 { 1950 const PPDKey* pLeft = it->m_pKey1; 1951 const PPDKey* pRight = it->m_pKey2; 1952 if( ! pLeft || ! pRight || ( pKey != pLeft && pKey != pRight ) ) 1953 continue; 1954 1955 const PPDKey* pOtherKey = pKey == pLeft ? pRight : pLeft; 1956 const PPDValue* pOtherKeyOption = pKey == pLeft ? it->m_pOption2 : it->m_pOption1; 1957 const PPDValue* pKeyOption = pKey == pLeft ? it->m_pOption1 : it->m_pOption2; 1958 1959 // syntax *Key1 option1 *Key2 option2 1960 if( pKeyOption && pOtherKeyOption ) 1961 { 1962 if( pNewValue != pKeyOption ) 1963 continue; 1964 if( pOtherKeyOption == getValue( pOtherKey ) ) 1965 { 1966 return false; 1967 } 1968 } 1969 // syntax *Key1 option *Key2 or *Key1 *Key2 option 1970 else if( pOtherKeyOption || pKeyOption ) 1971 { 1972 if( pKeyOption ) 1973 { 1974 if( ! ( pOtherKeyOption = getValue( pOtherKey ) ) ) 1975 continue; // this should not happen, PPD broken 1976 1977 if( pKeyOption == pNewValue && 1978 ! pOtherKeyOption->m_aOption.EqualsAscii( "None" ) && 1979 ! pOtherKeyOption->m_aOption.EqualsAscii( "False" ) ) 1980 { 1981 // check if the other value can be reset and 1982 // do so if possible 1983 if( bDoReset && resetValue( pOtherKey ) ) 1984 continue; 1985 1986 return false; 1987 } 1988 } 1989 else if( pOtherKeyOption ) 1990 { 1991 if( getValue( pOtherKey ) == pOtherKeyOption && 1992 ! pNewValue->m_aOption.EqualsAscii( "None" ) && 1993 ! pNewValue->m_aOption.EqualsAscii( "False" ) ) 1994 return false; 1995 } 1996 else 1997 { 1998 // this should not happen, PPD is broken 1999 } 2000 } 2001 // syntax *Key1 *Key2 2002 else 2003 { 2004 const PPDValue* pOtherValue = getValue( pOtherKey ); 2005 if( ! pOtherValue->m_aOption.EqualsAscii( "None" ) && 2006 ! pOtherValue->m_aOption.EqualsAscii( "False" ) && 2007 ! pNewValue->m_aOption.EqualsAscii( "None" ) && 2008 ! pNewValue->m_aOption.EqualsAscii( "False" ) ) 2009 return false; 2010 } 2011 } 2012 return true; 2013 } 2014 2015 // ------------------------------------------------------------------- 2016 2017 void PPDContext::getUnconstrainedValues( const PPDKey* pKey, ::std::list< const PPDValue* >& rValues ) 2018 { 2019 rValues.clear(); 2020 2021 if( ! m_pParser || ! pKey || ! m_pParser->hasKey( pKey ) ) 2022 return; 2023 2024 int nValues = pKey->countValues(); 2025 for( int i = 0; i < nValues; i++ ) 2026 { 2027 const PPDValue* pValue = pKey->getValue( i ); 2028 if( checkConstraints( pKey, pValue ) ) 2029 rValues.push_back( pValue ); 2030 } 2031 } 2032 2033 2034 // ------------------------------------------------------------------- 2035 2036 void* PPDContext::getStreamableBuffer( sal_uLong& rBytes ) const 2037 { 2038 rBytes = 0; 2039 if( ! m_aCurrentValues.size() ) 2040 return NULL; 2041 hash_type::const_iterator it; 2042 for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it ) 2043 { 2044 ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 ); 2045 rBytes += aCopy.Len(); 2046 rBytes += 1; // for ':' 2047 if( it->second ) 2048 { 2049 aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 ); 2050 rBytes += aCopy.Len(); 2051 } 2052 else 2053 rBytes += 4; 2054 rBytes += 1; // for '\0' 2055 } 2056 rBytes += 1; 2057 void* pBuffer = new char[ rBytes ]; 2058 memset( pBuffer, 0, rBytes ); 2059 char* pRun = (char*)pBuffer; 2060 for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it ) 2061 { 2062 ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 ); 2063 int nBytes = aCopy.Len(); 2064 memcpy( pRun, aCopy.GetBuffer(), nBytes ); 2065 pRun += nBytes; 2066 *pRun++ = ':'; 2067 if( it->second ) 2068 aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 ); 2069 else 2070 aCopy = "*nil"; 2071 nBytes = aCopy.Len(); 2072 memcpy( pRun, aCopy.GetBuffer(), nBytes ); 2073 pRun += nBytes; 2074 2075 *pRun++ = 0; 2076 } 2077 return pBuffer; 2078 } 2079 2080 // ------------------------------------------------------------------- 2081 2082 void PPDContext::rebuildFromStreamBuffer( void* pBuffer, sal_uLong nBytes ) 2083 { 2084 if( ! m_pParser ) 2085 return; 2086 2087 m_aCurrentValues.clear(); 2088 2089 char* pRun = (char*)pBuffer; 2090 while( nBytes && *pRun ) 2091 { 2092 ByteString aLine( pRun ); 2093 int nPos = aLine.Search( ':' ); 2094 if( nPos != STRING_NOTFOUND ) 2095 { 2096 const PPDKey* pKey = m_pParser->getKey( String( aLine.Copy( 0, nPos ), RTL_TEXTENCODING_MS_1252 ) ); 2097 if( pKey ) 2098 { 2099 const PPDValue* pValue = NULL; 2100 String aOption( aLine.Copy( nPos+1 ), RTL_TEXTENCODING_MS_1252 ); 2101 if( ! aOption.EqualsAscii( "*nil" ) ) 2102 pValue = pKey->getValue( aOption ); 2103 m_aCurrentValues[ pKey ] = pValue; 2104 #ifdef __DEBUG 2105 fprintf( stderr, "PPDContext::rebuildFromStreamBuffer: read PPDKeyValue { %s, %s }\n", pKV->m_pKey->getKey().GetStr(), pKV->m_pCurrentValue ? pKV->m_pCurrentValue->m_aOption.GetStr() : "<nil>" ); 2106 #endif 2107 } 2108 } 2109 nBytes -= aLine.Len()+1; 2110 pRun += aLine.Len()+1; 2111 } 2112 } 2113 2114 // ------------------------------------------------------------------- 2115 2116 int PPDContext::getRenderResolution() const 2117 { 2118 // initialize to reasonable default, if parser is not set 2119 int nDPI = 300; 2120 if( m_pParser ) 2121 { 2122 int nDPIx = 300, nDPIy = 300; 2123 const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) ); 2124 if( pKey ) 2125 { 2126 const PPDValue* pValue = getValue( pKey ); 2127 if( pValue ) 2128 m_pParser->getResolutionFromString( pValue->m_aOption, nDPIx, nDPIy ); 2129 else 2130 m_pParser->getDefaultResolution( nDPIx, nDPIy ); 2131 } 2132 else 2133 m_pParser->getDefaultResolution( nDPIx, nDPIy ); 2134 2135 nDPI = (nDPIx > nDPIy) ? nDPIx : nDPIy; 2136 } 2137 return nDPI; 2138 } 2139 2140 // ------------------------------------------------------------------- 2141 2142 void PPDContext::getPageSize( String& rPaper, int& rWidth, int& rHeight ) const 2143 { 2144 // initialize to reasonable default, if parser is not set 2145 rPaper = String( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ); 2146 rWidth = 595; 2147 rHeight = 842; 2148 if( m_pParser ) 2149 { 2150 const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 2151 if( pKey ) 2152 { 2153 const PPDValue* pValue = getValue( pKey ); 2154 if( pValue ) 2155 { 2156 rPaper = pValue->m_aOption; 2157 m_pParser->getPaperDimension( rPaper, rWidth, rHeight ); 2158 } 2159 else 2160 { 2161 rPaper = m_pParser->getDefaultPaperDimension(); 2162 m_pParser->getDefaultPaperDimension( rWidth, rHeight ); 2163 } 2164 } 2165 } 2166 } 2167