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