LCOV - code coverage report
Current view: top level - vcl/unx/generic/printer - ppdparser.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 643 963 66.8 %
Date: 2014-11-03 Functions: 55 71 77.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10