| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| #include <hash_map> |
| |
| #include "vcl/ppdparser.hxx" |
| #include "vcl/strhelper.hxx" |
| #include "vcl/helper.hxx" |
| #include "vcl/svapp.hxx" |
| #include "cupsmgr.hxx" |
| #include "tools/debug.hxx" |
| #include "tools/urlobj.hxx" |
| #include "tools/stream.hxx" |
| #include "tools/zcodec.hxx" |
| #include "osl/mutex.hxx" |
| #include "osl/file.hxx" |
| #include "osl/process.h" |
| #include "osl/thread.h" |
| #include "rtl/strbuf.hxx" |
| #include "rtl/ustrbuf.hxx" |
| |
| #include "com/sun/star/lang/Locale.hpp" |
| |
| namespace psp |
| { |
| class PPDTranslator |
| { |
| struct LocaleEqual |
| { |
| bool operator()(const com::sun::star::lang::Locale& i_rLeft, |
| const com::sun::star::lang::Locale& i_rRight) const |
| { |
| return i_rLeft.Language.equals( i_rRight.Language ) && |
| i_rLeft.Country.equals( i_rRight.Country ) && |
| i_rLeft.Variant.equals( i_rRight.Variant ); |
| } |
| }; |
| |
| struct LocaleHash |
| { |
| size_t operator()(const com::sun::star::lang::Locale& rLocale) const |
| { return |
| (size_t)rLocale.Language.hashCode() |
| ^ (size_t)rLocale.Country.hashCode() |
| ^ (size_t)rLocale.Variant.hashCode() |
| ; |
| } |
| }; |
| |
| typedef std::hash_map< com::sun::star::lang::Locale, rtl::OUString, LocaleHash, LocaleEqual > translation_map; |
| typedef std::hash_map< rtl::OUString, translation_map, rtl::OUStringHash > key_translation_map; |
| |
| key_translation_map m_aTranslations; |
| public: |
| PPDTranslator() {} |
| ~PPDTranslator() {} |
| |
| |
| void insertValue( |
| const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const rtl::OUString& i_rValue, |
| const rtl::OUString& i_rTranslation, |
| const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() |
| ); |
| |
| void insertOption( const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const rtl::OUString& i_rTranslation, |
| const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) |
| { |
| insertValue( i_rKey, i_rOption, rtl::OUString(), i_rTranslation, i_rLocale ); |
| } |
| |
| void insertKey( const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rTranslation, |
| const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) |
| { |
| insertValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rTranslation, i_rLocale ); |
| } |
| |
| rtl::OUString translateValue( |
| const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const rtl::OUString& i_rValue, |
| const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() |
| ) const; |
| |
| rtl::OUString translateOption( const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const |
| { |
| return translateValue( i_rKey, i_rOption, rtl::OUString(), i_rLocale ); |
| } |
| |
| rtl::OUString translateKey( const rtl::OUString& i_rKey, |
| const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const |
| { |
| return translateValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rLocale ); |
| } |
| }; |
| |
| static com::sun::star::lang::Locale normalizeInputLocale( |
| const com::sun::star::lang::Locale& i_rLocale, |
| bool bInsertDefault = false |
| ) |
| { |
| com::sun::star::lang::Locale aLoc( i_rLocale ); |
| if( bInsertDefault && aLoc.Language.getLength() == 0 ) |
| { |
| // empty locale requested, fill in application UI locale |
| aLoc = Application::GetSettings().GetUILocale(); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| static const char* pEnvLocale = getenv( "SAL_PPDPARSER_LOCALE" ); |
| if( pEnvLocale && *pEnvLocale ) |
| { |
| rtl::OString aStr( pEnvLocale ); |
| sal_Int32 nLen = aStr.getLength(); |
| aLoc.Language = rtl::OStringToOUString( aStr.copy( 0, nLen > 2 ? 2 : nLen ), RTL_TEXTENCODING_MS_1252 ); |
| if( nLen >=5 && aStr.getStr()[2] == '_' ) |
| aLoc.Country = rtl::OStringToOUString( aStr.copy( 3, 2 ), RTL_TEXTENCODING_MS_1252 ); |
| else |
| aLoc.Country = rtl::OUString(); |
| aLoc.Variant = rtl::OUString(); |
| } |
| #endif |
| } |
| aLoc.Language = aLoc.Language.toAsciiLowerCase(); |
| aLoc.Country = aLoc.Country.toAsciiUpperCase(); |
| aLoc.Variant = aLoc.Variant.toAsciiUpperCase(); |
| |
| return aLoc; |
| } |
| |
| void PPDTranslator::insertValue( |
| const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const rtl::OUString& i_rValue, |
| const rtl::OUString& i_rTranslation, |
| const com::sun::star::lang::Locale& i_rLocale |
| ) |
| { |
| rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 ); |
| aKey.append( i_rKey ); |
| if( i_rOption.getLength() || i_rValue.getLength() ) |
| { |
| aKey.append( sal_Unicode( ':' ) ); |
| aKey.append( i_rOption ); |
| } |
| if( i_rValue.getLength() ) |
| { |
| aKey.append( sal_Unicode( ':' ) ); |
| aKey.append( i_rValue ); |
| } |
| if( aKey.getLength() && i_rTranslation.getLength() ) |
| { |
| rtl::OUString aK( aKey.makeStringAndClear() ); |
| com::sun::star::lang::Locale aLoc; |
| aLoc.Language = i_rLocale.Language.toAsciiLowerCase(); |
| aLoc.Country = i_rLocale.Country.toAsciiUpperCase(); |
| aLoc.Variant = i_rLocale.Variant.toAsciiUpperCase(); |
| m_aTranslations[ aK ][ aLoc ] = i_rTranslation; |
| } |
| } |
| |
| rtl::OUString PPDTranslator::translateValue( |
| const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const rtl::OUString& i_rValue, |
| const com::sun::star::lang::Locale& i_rLocale |
| ) const |
| { |
| rtl::OUString aResult; |
| |
| rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 ); |
| aKey.append( i_rKey ); |
| if( i_rOption.getLength() || i_rValue.getLength() ) |
| { |
| aKey.append( sal_Unicode( ':' ) ); |
| aKey.append( i_rOption ); |
| } |
| if( i_rValue.getLength() ) |
| { |
| aKey.append( sal_Unicode( ':' ) ); |
| aKey.append( i_rValue ); |
| } |
| if( aKey.getLength() ) |
| { |
| rtl::OUString aK( aKey.makeStringAndClear() ); |
| key_translation_map::const_iterator it = m_aTranslations.find( aK ); |
| if( it != m_aTranslations.end() ) |
| { |
| const translation_map& rMap( it->second ); |
| |
| com::sun::star::lang::Locale aLoc( normalizeInputLocale( i_rLocale, true ) ); |
| for( int nTry = 0; nTry < 4; nTry++ ) |
| { |
| translation_map::const_iterator tr = rMap.find( aLoc ); |
| if( tr != rMap.end() ) |
| { |
| aResult = tr->second; |
| break; |
| } |
| switch( nTry ) |
| { |
| case 0: aLoc.Variant = rtl::OUString();break; |
| case 1: aLoc.Country = rtl::OUString();break; |
| case 2: aLoc.Language = rtl::OUString();break; |
| } |
| } |
| } |
| } |
| return aResult; |
| } |
| } |
| |
| using namespace psp; |
| using namespace rtl; |
| |
| #undef DBG_ASSERT |
| #if defined DBG_UTIL || (OSL_DEBUG_LEVEL > 1) |
| #define BSTRING(x) ByteString( x, osl_getThreadTextEncoding() ) |
| #define DBG_ASSERT( x, y ) { if( ! (x) ) fprintf( stderr, (y) ); } |
| #else |
| #define DBG_ASSERT( x, y ) |
| #endif |
| |
| std::list< PPDParser* > PPDParser::aAllParsers; |
| std::hash_map< OUString, OUString, OUStringHash >* PPDParser::pAllPPDFiles = NULL; |
| |
| class PPDDecompressStream |
| { |
| SvFileStream* mpFileStream; |
| SvMemoryStream* mpMemStream; |
| rtl::OUString maFileName; |
| |
| // forbid copying |
| PPDDecompressStream( const PPDDecompressStream& ); |
| PPDDecompressStream& operator=(const PPDDecompressStream& ); |
| |
| public: |
| PPDDecompressStream( const rtl::OUString& rFile ); |
| ~PPDDecompressStream(); |
| |
| bool IsOpen() const; |
| bool IsEof() const; |
| void ReadLine( ByteString& o_rLine); |
| void Open( const rtl::OUString& i_rFile ); |
| void Close(); |
| const rtl::OUString& GetFileName() const { return maFileName; } |
| }; |
| |
| PPDDecompressStream::PPDDecompressStream( const rtl::OUString& i_rFile ) : |
| mpFileStream( NULL ), |
| mpMemStream( NULL ) |
| { |
| Open( i_rFile ); |
| } |
| |
| PPDDecompressStream::~PPDDecompressStream() |
| { |
| Close(); |
| } |
| |
| void PPDDecompressStream::Open( const rtl::OUString& i_rFile ) |
| { |
| Close(); |
| |
| mpFileStream = new SvFileStream( i_rFile, STREAM_READ ); |
| maFileName = mpFileStream->GetFileName(); |
| |
| if( ! mpFileStream->IsOpen() ) |
| { |
| Close(); |
| return; |
| } |
| |
| ByteString aLine; |
| mpFileStream->ReadLine( aLine ); |
| mpFileStream->Seek( 0 ); |
| |
| // check for compress'ed or gzip'ed file |
| sal_uLong nCompressMethod = 0; |
| if( aLine.Len() > 1 && static_cast<unsigned char>(aLine.GetChar( 0 )) == 0x1f ) |
| { |
| if( static_cast<unsigned char>(aLine.GetChar( 1 )) == 0x8b ) // check for gzip |
| nCompressMethod = ZCODEC_DEFAULT | ZCODEC_GZ_LIB; |
| } |
| |
| if( nCompressMethod != 0 ) |
| { |
| // so let's try to decompress the stream |
| mpMemStream = new SvMemoryStream( 4096, 4096 ); |
| ZCodec aCodec; |
| aCodec.BeginCompression( nCompressMethod ); |
| long nComp = aCodec.Decompress( *mpFileStream, *mpMemStream ); |
| aCodec.EndCompression(); |
| if( nComp < 0 ) |
| { |
| // decompression failed, must be an uncompressed stream after all |
| delete mpMemStream, mpMemStream = NULL; |
| mpFileStream->Seek( 0 ); |
| } |
| else |
| { |
| // compression successfull, can get rid of file stream |
| delete mpFileStream, mpFileStream = NULL; |
| mpMemStream->Seek( 0 ); |
| } |
| } |
| } |
| |
| void PPDDecompressStream::Close() |
| { |
| delete mpMemStream, mpMemStream = NULL; |
| delete mpFileStream, mpFileStream = NULL; |
| } |
| |
| bool PPDDecompressStream::IsOpen() const |
| { |
| return (mpMemStream || (mpFileStream && mpFileStream->IsOpen())); |
| } |
| |
| bool PPDDecompressStream::IsEof() const |
| { |
| return ( mpMemStream ? mpMemStream->IsEof() : ( mpFileStream ? mpFileStream->IsEof() : true ) ); |
| } |
| |
| void PPDDecompressStream::ReadLine( ByteString& o_rLine ) |
| { |
| if( mpMemStream ) |
| mpMemStream->ReadLine( o_rLine ); |
| else if( mpFileStream ) |
| mpFileStream->ReadLine( o_rLine ); |
| } |
| |
| static osl::FileBase::RC resolveLink( const rtl::OUString& i_rURL, rtl::OUString& o_rResolvedURL, rtl::OUString& o_rBaseName, osl::FileStatus::Type& o_rType, int nLinkLevel = 10 ) |
| { |
| osl::DirectoryItem aLinkItem; |
| osl::FileBase::RC aRet = osl::FileBase::E_None; |
| |
| if( ( aRet = osl::DirectoryItem::get( i_rURL, aLinkItem ) ) == osl::FileBase::E_None ) |
| { |
| osl::FileStatus aStatus( FileStatusMask_FileName | FileStatusMask_Type | FileStatusMask_LinkTargetURL ); |
| if( ( aRet = aLinkItem.getFileStatus( aStatus ) ) == osl::FileBase::E_None ) |
| { |
| if( aStatus.getFileType() == osl::FileStatus::Link ) |
| { |
| if( nLinkLevel > 0 ) |
| aRet = resolveLink( aStatus.getLinkTargetURL(), o_rResolvedURL, o_rBaseName, o_rType, nLinkLevel-1 ); |
| else |
| aRet = osl::FileBase::E_MULTIHOP; |
| } |
| else |
| { |
| o_rResolvedURL = i_rURL; |
| o_rBaseName = aStatus.getFileName(); |
| o_rType = aStatus.getFileType(); |
| } |
| } |
| } |
| return aRet; |
| } |
| |
| void PPDParser::scanPPDDir( const String& rDir ) |
| { |
| static struct suffix_t |
| { |
| const sal_Char* pSuffix; |
| const sal_Int32 nSuffixLen; |
| } const pSuffixes[] = |
| { { ".PS", 3 }, { ".PPD", 4 }, { ".PS.GZ", 6 }, { ".PPD.GZ", 7 } }; |
| |
| const int nSuffixes = sizeof(pSuffixes)/sizeof(pSuffixes[0]); |
| |
| osl::Directory aDir( rDir ); |
| if ( aDir.open() == osl::FileBase::E_None ) |
| { |
| osl::DirectoryItem aItem; |
| |
| INetURLObject aPPDDir(rDir); |
| while( aDir.getNextItem( aItem ) == osl::FileBase::E_None ) |
| { |
| osl::FileStatus aStatus( FileStatusMask_FileName ); |
| if( aItem.getFileStatus( aStatus ) == osl::FileBase::E_None ) |
| { |
| rtl::OUStringBuffer aURLBuf( rDir.Len() + 64 ); |
| aURLBuf.append( rDir ); |
| aURLBuf.append( sal_Unicode( '/' ) ); |
| aURLBuf.append( aStatus.getFileName() ); |
| |
| rtl::OUString aFileURL, aFileName; |
| osl::FileStatus::Type eType = osl::FileStatus::Unknown; |
| |
| if( resolveLink( aURLBuf.makeStringAndClear(), aFileURL, aFileName, eType ) == osl::FileBase::E_None ) |
| { |
| if( eType == osl::FileStatus::Regular ) |
| { |
| INetURLObject aPPDFile = aPPDDir; |
| aPPDFile.Append( aFileName ); |
| |
| // match extension |
| for( int nSuffix = 0; nSuffix < nSuffixes; nSuffix++ ) |
| { |
| if( aFileName.getLength() > pSuffixes[nSuffix].nSuffixLen ) |
| { |
| if( aFileName.endsWithIgnoreAsciiCaseAsciiL( pSuffixes[nSuffix].pSuffix, pSuffixes[nSuffix].nSuffixLen ) ) |
| { |
| (*pAllPPDFiles)[ aFileName.copy( 0, aFileName.getLength() - pSuffixes[nSuffix].nSuffixLen ) ] = aPPDFile.PathToFileName(); |
| break; |
| } |
| } |
| } |
| } |
| else if( eType == osl::FileStatus::Directory ) |
| { |
| scanPPDDir( aFileURL ); |
| } |
| } |
| } |
| } |
| aDir.close(); |
| } |
| } |
| |
| void PPDParser::initPPDFiles() |
| { |
| if( pAllPPDFiles ) |
| return; |
| |
| pAllPPDFiles = new std::hash_map< OUString, OUString, OUStringHash >(); |
| |
| // check installation directories |
| std::list< OUString > aPathList; |
| psp::getPrinterPathList( aPathList, PRINTER_PPDDIR ); |
| for( std::list< OUString >::const_iterator ppd_it = aPathList.begin(); ppd_it != aPathList.end(); ++ppd_it ) |
| { |
| INetURLObject aPPDDir( *ppd_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); |
| scanPPDDir( aPPDDir.GetMainURL( INetURLObject::NO_DECODE ) ); |
| } |
| if( pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() ) |
| { |
| // last try: search in directory of executable (mainly for setup) |
| OUString aExe; |
| if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None ) |
| { |
| INetURLObject aDir( aExe ); |
| aDir.removeSegment(); |
| #ifdef DEBUG |
| fprintf( stderr, "scanning last chance dir: %s\n", OUStringToOString( aDir.GetMainURL( INetURLObject::NO_DECODE ), osl_getThreadTextEncoding() ).getStr() ); |
| #endif |
| scanPPDDir( aDir.GetMainURL( INetURLObject::NO_DECODE ) ); |
| #ifdef DEBUG |
| fprintf( stderr, "SGENPRT %s\n", pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() ? "not found" : "found" ); |
| #endif |
| } |
| } |
| } |
| |
| void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh ) |
| { |
| if( bRefresh ) |
| { |
| delete pAllPPDFiles; |
| pAllPPDFiles = NULL; |
| } |
| |
| initPPDFiles(); |
| o_rDrivers.clear(); |
| |
| std::hash_map< OUString, OUString, OUStringHash >::const_iterator it; |
| for( it = pAllPPDFiles->begin(); it != pAllPPDFiles->end(); ++it ) |
| o_rDrivers.push_back( it->first ); |
| } |
| |
| String PPDParser::getPPDFile( const String& rFile ) |
| { |
| INetURLObject aPPD( rFile, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); |
| // someone might enter a full qualified name here |
| PPDDecompressStream aStream( aPPD.PathToFileName() ); |
| if( ! aStream.IsOpen() ) |
| { |
| std::hash_map< OUString, OUString, OUStringHash >::const_iterator it; |
| |
| bool bRetry = true; |
| do |
| { |
| initPPDFiles(); |
| // some PPD files contain dots beside the extension, so try name first |
| // and cut of points after that |
| rtl::OUString aBase( rFile ); |
| sal_Int32 nLastIndex = aBase.lastIndexOf( sal_Unicode( '/' ) ); |
| if( nLastIndex >= 0 ) |
| aBase = aBase.copy( nLastIndex+1 ); |
| do |
| { |
| it = pAllPPDFiles->find( aBase ); |
| nLastIndex = aBase.lastIndexOf( sal_Unicode( '.' ) ); |
| if( nLastIndex > 0 ) |
| aBase = aBase.copy( 0, nLastIndex ); |
| } while( it == pAllPPDFiles->end() && nLastIndex > 0 ); |
| |
| if( it == pAllPPDFiles->end() && bRetry ) |
| { |
| // a new file ? rehash |
| delete pAllPPDFiles; pAllPPDFiles = NULL; |
| bRetry = false; |
| // note this is optimized for office start where |
| // no new files occur and initPPDFiles is called only once |
| } |
| } while( ! pAllPPDFiles ); |
| |
| if( it != pAllPPDFiles->end() ) |
| aStream.Open( it->second ); |
| } |
| |
| String aRet; |
| if( aStream.IsOpen() ) |
| { |
| ByteString aLine; |
| aStream.ReadLine( aLine ); |
| if( aLine.Search( "*PPD-Adobe" ) == 0 ) |
| aRet = aStream.GetFileName(); |
| else |
| { |
| // our *Include hack does usually not begin |
| // with *PPD-Adobe, so try some lines for *Include |
| int nLines = 10; |
| while( aLine.Search( "*Include" ) != 0 && --nLines ) |
| aStream.ReadLine( aLine ); |
| if( nLines ) |
| aRet = aStream.GetFileName(); |
| } |
| } |
| |
| return aRet; |
| } |
| |
| String PPDParser::getPPDPrinterName( const String& rFile ) |
| { |
| String aPath = getPPDFile( rFile ); |
| String aName; |
| |
| // read in the file |
| PPDDecompressStream aStream( aPath ); |
| if( aStream.IsOpen() ) |
| { |
| String aCurLine; |
| while( ! aStream.IsEof() && aStream.IsOpen() ) |
| { |
| ByteString aByteLine; |
| aStream.ReadLine( aByteLine ); |
| aCurLine = String( aByteLine, RTL_TEXTENCODING_MS_1252 ); |
| if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL ) |
| { |
| aCurLine.Erase( 0, 9 ); |
| aCurLine.EraseLeadingChars( ' ' ); |
| aCurLine.EraseTrailingChars( ' ' ); |
| aCurLine.EraseLeadingChars( '\t' ); |
| aCurLine.EraseTrailingChars( '\t' ); |
| aCurLine.EraseTrailingChars( '\r' ); |
| aCurLine.EraseTrailingChars( '\n' ); |
| aCurLine.EraseLeadingChars( '"' ); |
| aCurLine.EraseTrailingChars( '"' ); |
| aStream.Close(); |
| aStream.Open( getPPDFile( aCurLine ) ); |
| continue; |
| } |
| if( aCurLine.CompareToAscii( "*ModelName:", 11 ) == COMPARE_EQUAL ) |
| { |
| aName = aCurLine.GetToken( 1, '"' ); |
| break; |
| } |
| else if( aCurLine.CompareToAscii( "*NickName:", 10 ) == COMPARE_EQUAL ) |
| aName = aCurLine.GetToken( 1, '"' ); |
| } |
| } |
| return aName; |
| } |
| |
| const PPDParser* PPDParser::getParser( const String& rFile ) |
| { |
| static ::osl::Mutex aMutex; |
| ::osl::Guard< ::osl::Mutex > aGuard( aMutex ); |
| |
| String aFile = rFile; |
| if( rFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL ) |
| aFile = getPPDFile( rFile ); |
| if( ! aFile.Len() ) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| fprintf( stderr, "Could not get printer PPD file \"%s\" !\n", OUStringToOString( rFile, osl_getThreadTextEncoding() ).getStr() ); |
| #endif |
| return NULL; |
| } |
| |
| for( ::std::list< PPDParser* >::const_iterator it = aAllParsers.begin(); it != aAllParsers.end(); ++it ) |
| if( (*it)->m_aFile == aFile ) |
| return *it; |
| |
| PPDParser* pNewParser = NULL; |
| if( aFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL ) |
| pNewParser = new PPDParser( aFile ); |
| else |
| { |
| PrinterInfoManager& rMgr = PrinterInfoManager::get(); |
| if( rMgr.getType() == PrinterInfoManager::CUPS ) |
| { |
| pNewParser = const_cast<PPDParser*>(static_cast<CUPSManager&>(rMgr).createCUPSParser( aFile )); |
| } |
| } |
| if( pNewParser ) |
| { |
| // this may actually be the SGENPRT parser, |
| // so ensure uniquness here |
| aAllParsers.remove( pNewParser ); |
| // insert new parser to list |
| aAllParsers.push_front( pNewParser ); |
| } |
| return pNewParser; |
| } |
| |
| void PPDParser::freeAll() |
| { |
| while( aAllParsers.begin() != aAllParsers.end() ) |
| { |
| delete aAllParsers.front(); |
| aAllParsers.pop_front(); |
| } |
| delete pAllPPDFiles; |
| pAllPPDFiles = NULL; |
| } |
| |
| PPDParser::PPDParser( const String& rFile ) : |
| m_aFile( rFile ), |
| m_bType42Capable( false ), |
| m_aFileEncoding( RTL_TEXTENCODING_MS_1252 ), |
| m_pDefaultImageableArea( NULL ), |
| m_pImageableAreas( NULL ), |
| m_pDefaultPaperDimension( NULL ), |
| m_pPaperDimensions( NULL ), |
| m_pDefaultInputSlot( NULL ), |
| m_pInputSlots( NULL ), |
| m_pDefaultResolution( NULL ), |
| m_pResolutions( NULL ), |
| m_pDefaultDuplexType( NULL ), |
| m_pDuplexTypes( NULL ), |
| m_pFontList( NULL ), |
| m_pTranslator( new PPDTranslator() ) |
| { |
| // read in the file |
| std::list< ByteString > aLines; |
| PPDDecompressStream aStream( m_aFile ); |
| bool bLanguageEncoding = false; |
| if( aStream.IsOpen() ) |
| { |
| ByteString aCurLine; |
| while( ! aStream.IsEof() ) |
| { |
| aStream.ReadLine( aCurLine ); |
| if( aCurLine.GetChar( 0 ) == '*' ) |
| { |
| if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL ) |
| { |
| aCurLine.Erase( 0, 9 ); |
| aCurLine.EraseLeadingChars( ' ' ); |
| aCurLine.EraseTrailingChars( ' ' ); |
| aCurLine.EraseLeadingChars( '\t' ); |
| aCurLine.EraseTrailingChars( '\t' ); |
| aCurLine.EraseTrailingChars( '\r' ); |
| aCurLine.EraseTrailingChars( '\n' ); |
| aCurLine.EraseLeadingChars( '"' ); |
| aCurLine.EraseTrailingChars( '"' ); |
| aStream.Close(); |
| aStream.Open( getPPDFile( String( aCurLine, m_aFileEncoding ) ) ); |
| continue; |
| } |
| else if( ! bLanguageEncoding && |
| aCurLine.CompareIgnoreCaseToAscii( "*languageencoding", 17 ) == COMPARE_EQUAL ) |
| { |
| bLanguageEncoding = true; // generally only the first one counts |
| ByteString aLower = aCurLine; |
| aLower.ToLowerAscii(); |
| if( aLower.Search( "isolatin1", 17 ) != STRING_NOTFOUND || |
| aLower.Search( "windowsansi", 17 ) != STRING_NOTFOUND ) |
| m_aFileEncoding = RTL_TEXTENCODING_MS_1252; |
| else if( aLower.Search( "isolatin2", 17 ) != STRING_NOTFOUND ) |
| m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_2; |
| else if( aLower.Search( "isolatin5", 17 ) != STRING_NOTFOUND ) |
| m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_5; |
| else if( aLower.Search( "jis83-rksj", 17 ) != STRING_NOTFOUND ) |
| m_aFileEncoding = RTL_TEXTENCODING_SHIFT_JIS; |
| else if( aLower.Search( "macstandard", 17 ) != STRING_NOTFOUND ) |
| m_aFileEncoding = RTL_TEXTENCODING_APPLE_ROMAN; |
| else if( aLower.Search( "utf-8", 17 ) != STRING_NOTFOUND ) |
| m_aFileEncoding = RTL_TEXTENCODING_UTF8; |
| } |
| } |
| aLines.push_back( aCurLine ); |
| } |
| } |
| aStream.Close(); |
| |
| // now get the Values |
| parse( aLines ); |
| #if OSL_DEBUG_LEVEL > 2 |
| fprintf( stderr, "acquired %d Keys from PPD %s:\n", m_aKeys.size(), BSTRING( m_aFile ).GetBuffer() ); |
| for( PPDParser::hash_type::const_iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it ) |
| { |
| const PPDKey* pKey = it->second; |
| char* pSetupType = "<unknown>"; |
| switch( pKey->m_eSetupType ) |
| { |
| case PPDKey::ExitServer: pSetupType = "ExitServer";break; |
| case PPDKey::Prolog: pSetupType = "Prolog";break; |
| case PPDKey::DocumentSetup: pSetupType = "DocumentSetup";break; |
| case PPDKey::PageSetup: pSetupType = "PageSetup";break; |
| case PPDKey::JCLSetup: pSetupType = "JCLSetup";break; |
| case PPDKey::AnySetup: pSetupType = "AnySetup";break; |
| default: break; |
| }; |
| fprintf( stderr, "\t\"%s\" (\"%s\") (%d values) OrderDependency: %d %s\n", |
| BSTRING( pKey->getKey() ).GetBuffer(), |
| BSTRING( pKey->m_aUITranslation ).GetBuffer(), |
| pKey->countValues(), |
| pKey->m_nOrderDependency, |
| pSetupType ); |
| for( int j = 0; j < pKey->countValues(); j++ ) |
| { |
| fprintf( stderr, "\t\t" ); |
| const PPDValue* pValue = pKey->getValue( j ); |
| if( pValue == pKey->m_pDefaultValue ) |
| fprintf( stderr, "(Default:) " ); |
| char* pVType = "<unknown>"; |
| switch( pValue->m_eType ) |
| { |
| case eInvocation: pVType = "invocation";break; |
| case eQuoted: pVType = "quoted";break; |
| case eString: pVType = "string";break; |
| case eSymbol: pVType = "symbol";break; |
| case eNo: pVType = "no";break; |
| default: break; |
| }; |
| fprintf( stderr, "option: \"%s\" (\"%s\"), value: type %s \"%s\" (\"%s\")\n", |
| BSTRING( pValue->m_aOption ).GetBuffer(), |
| BSTRING( pValue->m_aOptionTranslation ).GetBuffer(), |
| pVType, |
| BSTRING( pValue->m_aValue ).GetBuffer(), |
| BSTRING( pValue->m_aValueTranslation ).GetBuffer() ); |
| } |
| } |
| fprintf( stderr, "constraints: (%d found)\n", m_aConstraints.size() ); |
| for( std::list< PPDConstraint >::const_iterator cit = m_aConstraints.begin(); cit != m_aConstraints.end(); ++cit ) |
| { |
| fprintf( stderr, "*\"%s\" \"%s\" *\"%s\" \"%s\"\n", |
| BSTRING( cit->m_pKey1->getKey() ).GetBuffer(), |
| cit->m_pOption1 ? BSTRING( cit->m_pOption1->m_aOption ).GetBuffer() : "<nil>", |
| BSTRING( cit->m_pKey2->getKey() ).GetBuffer(), |
| cit->m_pOption2 ? BSTRING( cit->m_pOption2->m_aOption ).GetBuffer() : "<nil>" |
| ); |
| } |
| #endif |
| |
| // fill in shortcuts |
| const PPDKey* pKey; |
| |
| m_pImageableAreas = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ImageableArea" ) ) ); |
| if( m_pImageableAreas ) |
| m_pDefaultImageableArea = m_pImageableAreas->getDefaultValue(); |
| DBG_ASSERT( m_pImageableAreas, "Warning: no ImageableArea in PPD\n" ); |
| DBG_ASSERT( m_pDefaultImageableArea, "Warning: no DefaultImageableArea in PPD\n" ); |
| |
| m_pPaperDimensions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PaperDimension" ) ) ); |
| if( m_pPaperDimensions ) |
| m_pDefaultPaperDimension = m_pPaperDimensions->getDefaultValue(); |
| DBG_ASSERT( m_pPaperDimensions, "Warning: no PaperDimension in PPD\n" ); |
| DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultPaperDimension in PPD\n" ); |
| |
| m_pResolutions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) ); |
| if( m_pResolutions ) |
| m_pDefaultResolution = m_pResolutions->getDefaultValue(); |
| DBG_ASSERT( m_pResolutions, "Warning: no Resolution in PPD\n" ); |
| DBG_ASSERT( m_pDefaultResolution, "Warning: no DefaultResolution in PPD\n" ); |
| |
| m_pInputSlots = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); |
| if( m_pInputSlots ) |
| m_pDefaultInputSlot = m_pInputSlots->getDefaultValue(); |
| DBG_ASSERT( m_pPaperDimensions, "Warning: no InputSlot in PPD\n" ); |
| DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultInputSlot in PPD\n" ); |
| |
| m_pDuplexTypes = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); |
| if( m_pDuplexTypes ) |
| m_pDefaultDuplexType = m_pDuplexTypes->getDefaultValue(); |
| |
| m_pFontList = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Font" ) ) ); |
| DBG_ASSERT( m_pFontList, "Warning: no Font in PPD\n" ); |
| |
| // fill in direct values |
| if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ModelName" ) ) )) ) |
| m_aPrinterName = pKey->getValue( 0 )->m_aValue; |
| if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "NickName" ) ) )) ) |
| m_aNickName = pKey->getValue( 0 )->m_aValue; |
| if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ColorDevice" ) ) )) ) |
| m_bColorDevice = pKey->getValue( 0 )->m_aValue.CompareIgnoreCaseToAscii( "true", 4 ) == COMPARE_EQUAL ? true : false; |
| |
| if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "LanguageLevel" ) ) )) ) |
| m_nLanguageLevel = pKey->getValue( 0 )->m_aValue.ToInt32(); |
| if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) )) ) |
| m_bType42Capable = pKey->getValue( 0 )->m_aValue.EqualsIgnoreCaseAscii( "Type42" ) ? true : false; |
| } |
| |
| PPDParser::~PPDParser() |
| { |
| for( PPDParser::hash_type::iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it ) |
| delete it->second; |
| delete m_pTranslator; |
| } |
| |
| void PPDParser::insertKey( const String& rKey, PPDKey* pKey ) |
| { |
| m_aKeys[ rKey ] = pKey; |
| m_aOrderedKeys.push_back( pKey ); |
| } |
| |
| const PPDKey* PPDParser::getKey( int n ) const |
| { |
| return ((unsigned int)n < m_aOrderedKeys.size() && n >= 0) ? m_aOrderedKeys[n] : NULL; |
| } |
| |
| const PPDKey* PPDParser::getKey( const String& rKey ) const |
| { |
| PPDParser::hash_type::const_iterator it = m_aKeys.find( rKey ); |
| return it != m_aKeys.end() ? it->second : NULL; |
| } |
| |
| bool PPDParser::hasKey( const PPDKey* pKey ) const |
| { |
| return |
| pKey ? |
| ( m_aKeys.find( pKey->getKey() ) != m_aKeys.end() ? true : false ) : |
| false; |
| } |
| |
| static sal_uInt8 getNibble( sal_Char cChar ) |
| { |
| sal_uInt8 nRet = 0; |
| if( cChar >= '0' && cChar <= '9' ) |
| nRet = sal_uInt8( cChar - '0' ); |
| else if( cChar >= 'A' && cChar <= 'F' ) |
| nRet = 10 + sal_uInt8( cChar - 'A' ); |
| else if( cChar >= 'a' && cChar <= 'f' ) |
| nRet = 10 + sal_uInt8( cChar - 'a' ); |
| return nRet; |
| } |
| |
| String PPDParser::handleTranslation( const ByteString& i_rString, bool bIsGlobalized ) |
| { |
| int nOrigLen = i_rString.Len(); |
| OStringBuffer aTrans( nOrigLen ); |
| const sal_Char* pStr = i_rString.GetBuffer(); |
| const sal_Char* pEnd = pStr + nOrigLen; |
| while( pStr < pEnd ) |
| { |
| if( *pStr == '<' ) |
| { |
| pStr++; |
| sal_Char cChar; |
| while( *pStr != '>' && pStr < pEnd-1 ) |
| { |
| cChar = getNibble( *pStr++ ) << 4; |
| cChar |= getNibble( *pStr++ ); |
| aTrans.append( cChar ); |
| } |
| pStr++; |
| } |
| else |
| aTrans.append( *pStr++ ); |
| } |
| return OStringToOUString( aTrans.makeStringAndClear(), bIsGlobalized ? RTL_TEXTENCODING_UTF8 : m_aFileEncoding ); |
| } |
| |
| void PPDParser::parse( ::std::list< ByteString >& rLines ) |
| { |
| std::list< ByteString >::iterator line = rLines.begin(); |
| PPDParser::hash_type::const_iterator keyit; |
| while( line != rLines.end() ) |
| { |
| ByteString aCurrentLine( *line ); |
| ++line; |
| if( aCurrentLine.GetChar(0) != '*' ) |
| continue; |
| if( aCurrentLine.GetChar(1) == '%' ) |
| continue; |
| |
| ByteString aKey = GetCommandLineToken( 0, aCurrentLine.GetToken( 0, ':' ) ); |
| int nPos = aKey.Search( '/' ); |
| if( nPos != STRING_NOTFOUND ) |
| aKey.Erase( nPos ); |
| aKey.Erase( 0, 1 ); // remove the '*' |
| |
| if( aKey.Equals( "CloseUI" ) || aKey.Equals( "OpenGroup" ) || aKey.Equals( "CloseGroup" ) || aKey.Equals( "End" ) || aKey.Equals( "OpenSubGroup" ) || aKey.Equals( "CloseSubGroup" ) ) |
| continue; |
| |
| if( aKey.Equals( "OpenUI" ) ) |
| { |
| parseOpenUI( aCurrentLine ); |
| continue; |
| } |
| else if( aKey.Equals( "OrderDependency" ) ) |
| { |
| parseOrderDependency( aCurrentLine ); |
| continue; |
| } |
| else if( aKey.Equals( "UIConstraints" ) || aKey.Equals( "NonUIConstraints" ) ) |
| continue; // parsed in pass 2 |
| else if( aKey.Equals( "CustomPageSize" ) ) // currently not handled |
| continue; |
| |
| // default values are parsed in pass 2 |
| if( aKey.CompareTo( "Default", 7 ) == COMPARE_EQUAL ) |
| continue; |
| |
| bool bQuery = false; |
| if( aKey.GetChar( 0 ) == '?' ) |
| { |
| aKey.Erase( 0, 1 ); |
| bQuery = true; |
| } |
| |
| String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 ); |
| // handle CUPS extension for globalized PPDs |
| bool bIsGlobalizedLine = false; |
| com::sun::star::lang::Locale aTransLocale; |
| if( ( aUniKey.Len() > 3 && aUniKey.GetChar( 2 ) == '.' ) || |
| ( aUniKey.Len() > 5 && aUniKey.GetChar( 2 ) == '_' && aUniKey.GetChar( 5 ) == '.' ) ) |
| { |
| if( aUniKey.GetChar( 2 ) == '.' ) |
| { |
| aTransLocale.Language = aUniKey.Copy( 0, 2 ); |
| aUniKey = aUniKey.Copy( 3 ); |
| } |
| else |
| { |
| aTransLocale.Language = aUniKey.Copy( 0, 2 ); |
| aTransLocale.Country = aUniKey.Copy( 3, 2 ); |
| aUniKey = aUniKey.Copy( 6 ); |
| } |
| bIsGlobalizedLine = true; |
| } |
| |
| String aOption; |
| nPos = aCurrentLine.Search( ':' ); |
| if( nPos != STRING_NOTFOUND ) |
| { |
| aOption = String( aCurrentLine.Copy( 1, nPos-1 ), RTL_TEXTENCODING_MS_1252 ); |
| aOption = GetCommandLineToken( 1, aOption ); |
| int nTransPos = aOption.Search( '/' ); |
| if( nTransPos != STRING_NOTFOUND ) |
| aOption.Erase( nTransPos ); |
| } |
| |
| PPDValueType eType = eNo; |
| String aValue; |
| rtl::OUString aOptionTranslation; |
| rtl::OUString aValueTranslation; |
| if( nPos != STRING_NOTFOUND ) |
| { |
| // found a colon, there may be an option |
| ByteString aLine = aCurrentLine.Copy( 1, nPos-1 ); |
| aLine = WhitespaceToSpace( aLine ); |
| int nTransPos = aLine.Search( '/' ); |
| if( nTransPos != STRING_NOTFOUND ) |
| aOptionTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine ); |
| |
| // read in more lines if necessary for multiline values |
| aLine = aCurrentLine.Copy( nPos+1 ); |
| if( aLine.Len() ) |
| { |
| while( ! ( aLine.GetTokenCount( '"' ) & 1 ) && |
| line != rLines.end() ) |
| // while there is an even number of tokens; that means |
| // an odd number of doubleqoutes |
| { |
| // copy the newlines also |
| aLine += '\n'; |
| aLine += *line; |
| ++line; |
| } |
| } |
| aLine = WhitespaceToSpace( aLine ); |
| |
| // #i100644# handle a missing value (actually a broken PPD) |
| if( ! aLine.Len() ) |
| { |
| if( aOption.Len() && |
| aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL ) |
| eType = eInvocation; |
| else |
| eType = eQuoted; |
| } |
| // check for invocation or quoted value |
| else if( aLine.GetChar(0) == '"' ) |
| { |
| aLine.Erase( 0, 1 ); |
| nTransPos = aLine.Search( '"' ); |
| aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 ); |
| // after the second doublequote can follow a / and a translation |
| aValueTranslation = handleTranslation( aLine.Copy( nTransPos+2 ), bIsGlobalizedLine ); |
| // check for quoted value |
| if( aOption.Len() && |
| aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL ) |
| eType = eInvocation; |
| else |
| eType = eQuoted; |
| } |
| // check for symbol value |
| else if( aLine.GetChar(0) == '^' ) |
| { |
| aLine.Erase( 0, 1 ); |
| aValue = String( aLine, RTL_TEXTENCODING_MS_1252 ); |
| eType = eSymbol; |
| } |
| else |
| { |
| // must be a string value then |
| // strictly this is false because string values |
| // can contain any whitespace which is reduced |
| // to one space by now |
| // who cares ... |
| nTransPos = aLine.Search( '/' ); |
| if( nTransPos == STRING_NOTFOUND ) |
| nTransPos = aLine.Len(); |
| aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 ); |
| aValueTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine ); |
| eType = eString; |
| } |
| } |
| |
| // handle globalized PPD entries |
| if( bIsGlobalizedLine ) |
| { |
| // handle main key translations of form: |
| // *ll_CC.Translation MainKeyword/translated text: "" |
| if( aUniKey.EqualsAscii( "Translation" ) ) |
| { |
| m_pTranslator->insertKey( aOption, aOptionTranslation, aTransLocale ); |
| } |
| // handle options translations of for: |
| // *ll_CC.MainKeyword OptionKeyword/translated text: "" |
| else |
| { |
| m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale ); |
| } |
| continue; |
| } |
| |
| PPDKey* pKey = NULL; |
| keyit = m_aKeys.find( aUniKey ); |
| if( keyit == m_aKeys.end() ) |
| { |
| pKey = new PPDKey( aUniKey ); |
| insertKey( aUniKey, pKey ); |
| } |
| else |
| pKey = keyit->second; |
| |
| if( eType == eNo && bQuery ) |
| continue; |
| |
| PPDValue* pValue = pKey->insertValue( aOption ); |
| if( ! pValue ) |
| continue; |
| pValue->m_eType = eType; |
| pValue->m_aValue = aValue; |
| |
| if( aOptionTranslation.getLength() ) |
| m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale ); |
| if( aValueTranslation.getLength() ) |
| m_pTranslator->insertValue( aUniKey, aOption, aValue, aValueTranslation, aTransLocale ); |
| |
| // eventually update query and remove from option list |
| if( bQuery && pKey->m_bQueryValue == sal_False ) |
| { |
| pKey->m_aQueryValue = *pValue; |
| pKey->m_bQueryValue = true; |
| pKey->eraseValue( pValue->m_aOption ); |
| } |
| } |
| |
| // second pass: fill in defaults |
| for( line = rLines.begin(); line != rLines.end(); ++line ) |
| { |
| ByteString aLine( *line ); |
| if( aLine.CompareTo( "*Default", 8 ) == COMPARE_EQUAL ) |
| { |
| String aKey( aLine.Copy( 8 ), RTL_TEXTENCODING_MS_1252 ); |
| sal_uInt16 nPos = aKey.Search( ':' ); |
| if( nPos != STRING_NOTFOUND ) |
| { |
| aKey.Erase( nPos ); |
| String aOption( WhitespaceToSpace( aLine.Copy( nPos+9 ) ), RTL_TEXTENCODING_MS_1252 ); |
| keyit = m_aKeys.find( aKey ); |
| if( keyit != m_aKeys.end() ) |
| { |
| PPDKey* pKey = keyit->second; |
| const PPDValue* pDefValue = pKey->getValue( aOption ); |
| if( pKey->m_pDefaultValue == NULL ) |
| pKey->m_pDefaultValue = pDefValue; |
| } |
| else |
| { |
| // some PPDs contain defaults for keys that |
| // do not exist otherwise |
| // (example: DefaultResolution) |
| // so invent that key here and have a default value |
| PPDKey* pKey = new PPDKey( aKey ); |
| PPDValue* pNewValue = pKey->insertValue( aOption ); |
| pNewValue->m_eType = eInvocation; // or what ? |
| insertKey( aKey, pKey ); |
| } |
| } |
| } |
| else if( aLine.CompareTo( "*UIConstraints", 14 ) == COMPARE_EQUAL || |
| aLine.CompareTo( "*NonUIConstraints", 17 ) == COMPARE_EQUAL ) |
| parseConstraint( aLine ); |
| |
| } |
| } |
| |
| void PPDParser::parseOpenUI( const ByteString& rLine ) |
| { |
| String aTranslation; |
| ByteString aKey = rLine; |
| |
| int nPos = aKey.Search( ':' ); |
| if( nPos != STRING_NOTFOUND ) |
| aKey.Erase( nPos ); |
| nPos = aKey.Search( '/' ); |
| if( nPos != STRING_NOTFOUND ) |
| { |
| aTranslation = handleTranslation( aKey.Copy( nPos + 1 ), false ); |
| aKey.Erase( nPos ); |
| } |
| aKey = GetCommandLineToken( 1, aKey ); |
| aKey.Erase( 0, 1 ); |
| |
| String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 ); |
| PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aUniKey ); |
| PPDKey* pKey; |
| if( keyit == m_aKeys.end() ) |
| { |
| pKey = new PPDKey( aUniKey ); |
| insertKey( aUniKey, pKey ); |
| } |
| else |
| pKey = keyit->second; |
| |
| pKey->m_bUIOption = true; |
| m_pTranslator->insertKey( pKey->getKey(), aTranslation ); |
| |
| ByteString aValue = WhitespaceToSpace( rLine.GetToken( 1, ':' ) ); |
| if( aValue.CompareIgnoreCaseToAscii( "boolean" ) == COMPARE_EQUAL ) |
| pKey->m_eUIType = PPDKey::Boolean; |
| else if( aValue.CompareIgnoreCaseToAscii( "pickmany" ) == COMPARE_EQUAL ) |
| pKey->m_eUIType = PPDKey::PickMany; |
| else |
| pKey->m_eUIType = PPDKey::PickOne; |
| } |
| |
| void PPDParser::parseOrderDependency( const ByteString& rLine ) |
| { |
| ByteString aLine( rLine ); |
| int nPos = aLine.Search( ':' ); |
| if( nPos != STRING_NOTFOUND ) |
| aLine.Erase( 0, nPos+1 ); |
| |
| int nOrder = GetCommandLineToken( 0, aLine ).ToInt32(); |
| ByteString aSetup = GetCommandLineToken( 1, aLine ); |
| String aKey( GetCommandLineToken( 2, aLine ), RTL_TEXTENCODING_MS_1252 ); |
| if( aKey.GetChar( 0 ) != '*' ) |
| return; // invalid order depency |
| aKey.Erase( 0, 1 ); |
| |
| PPDKey* pKey; |
| PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aKey ); |
| if( keyit == m_aKeys.end() ) |
| { |
| pKey = new PPDKey( aKey ); |
| insertKey( aKey, pKey ); |
| } |
| else |
| pKey = keyit->second; |
| |
| pKey->m_nOrderDependency = nOrder; |
| if( aSetup.Equals( "ExitServer" ) ) |
| pKey->m_eSetupType = PPDKey::ExitServer; |
| else if( aSetup.Equals( "Prolog" ) ) |
| pKey->m_eSetupType = PPDKey::Prolog; |
| else if( aSetup.Equals( "DocumentSetup" ) ) |
| pKey->m_eSetupType = PPDKey::DocumentSetup; |
| else if( aSetup.Equals( "PageSetup" ) ) |
| pKey->m_eSetupType = PPDKey::PageSetup; |
| else if( aSetup.Equals( "JCLSetup" ) ) |
| pKey->m_eSetupType = PPDKey::JCLSetup; |
| else |
| pKey->m_eSetupType = PPDKey::AnySetup; |
| } |
| |
| void PPDParser::parseConstraint( const ByteString& rLine ) |
| { |
| bool bFailed = false; |
| |
| String aLine( rLine, RTL_TEXTENCODING_MS_1252 ); |
| aLine.Erase( 0, rLine.Search( ':' )+1 ); |
| PPDConstraint aConstraint; |
| int nTokens = GetCommandLineTokenCount( aLine ); |
| for( int i = 0; i < nTokens; i++ ) |
| { |
| String aToken = GetCommandLineToken( i, aLine ); |
| if( aToken.GetChar( 0 ) == '*' ) |
| { |
| aToken.Erase( 0, 1 ); |
| if( aConstraint.m_pKey1 ) |
| aConstraint.m_pKey2 = getKey( aToken ); |
| else |
| aConstraint.m_pKey1 = getKey( aToken ); |
| } |
| else |
| { |
| if( aConstraint.m_pKey2 ) |
| { |
| if( ! ( aConstraint.m_pOption2 = aConstraint.m_pKey2->getValue( aToken ) ) ) |
| bFailed = true; |
| } |
| else if( aConstraint.m_pKey1 ) |
| { |
| if( ! ( aConstraint.m_pOption1 = aConstraint.m_pKey1->getValue( aToken ) ) ) |
| bFailed = true; |
| } |
| else |
| // constraint for nonexistent keys; this happens |
| // e.g. in HP4PLUS3 (#75636#) |
| bFailed = true; |
| } |
| } |
| // there must be two keywords |
| if( ! aConstraint.m_pKey1 || ! aConstraint.m_pKey2 || bFailed ) |
| { |
| #ifdef __DEBUG |
| fprintf( stderr, "Warning: constraint \"%s\" is invalid\n", rLine.GetStr() ); |
| #endif |
| } |
| else |
| m_aConstraints.push_back( aConstraint ); |
| } |
| |
| String PPDParser::getDefaultPaperDimension() const |
| { |
| if( m_pDefaultPaperDimension ) |
| return m_pDefaultPaperDimension->m_aOption; |
| |
| return String(); |
| } |
| |
| bool PPDParser::getMargins( |
| const String& rPaperName, |
| int& rLeft, int& rRight, |
| int& rUpper, int& rLower ) const |
| { |
| if( ! m_pImageableAreas || ! m_pPaperDimensions ) |
| return false; |
| |
| int nPDim=-1, nImArea=-1, i; |
| for( i = 0; i < m_pImageableAreas->countValues(); i++ ) |
| if( rPaperName == m_pImageableAreas->getValue( i )->m_aOption ) |
| nImArea = i; |
| for( i = 0; i < m_pPaperDimensions->countValues(); i++ ) |
| if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption ) |
| nPDim = i; |
| if( nPDim == -1 || nImArea == -1 ) |
| return false; |
| |
| double ImLLx, ImLLy, ImURx, ImURy; |
| double PDWidth, PDHeight; |
| String aArea = m_pImageableAreas->getValue( nImArea )->m_aValue; |
| ImLLx = StringToDouble( GetCommandLineToken( 0, aArea ) ); |
| ImLLy = StringToDouble( GetCommandLineToken( 1, aArea ) ); |
| ImURx = StringToDouble( GetCommandLineToken( 2, aArea ) ); |
| ImURy = StringToDouble( GetCommandLineToken( 3, aArea ) ); |
| // sscanf( m_pImageableAreas->getValue( nImArea )->m_aValue.GetStr(), |
| // "%lg%lg%lg%lg", &ImLLx, &ImLLy, &ImURx, &ImURy ); |
| aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue; |
| PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) ); |
| PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) ); |
| // sscanf( m_pPaperDimensions->getValue( nPDim )->m_aValue.GetStr(), |
| // "%lg%lg", &PDWidth, &PDHeight ); |
| rLeft = (int)(ImLLx + 0.5); |
| rLower = (int)(ImLLy + 0.5); |
| rUpper = (int)(PDHeight - ImURy + 0.5); |
| rRight = (int)(PDWidth - ImURx + 0.5); |
| |
| return true; |
| } |
| |
| bool PPDParser::getPaperDimension( |
| const String& rPaperName, |
| int& rWidth, int& rHeight ) const |
| { |
| if( ! m_pPaperDimensions ) |
| return false; |
| |
| int nPDim=-1; |
| for( int i = 0; i < m_pPaperDimensions->countValues(); i++ ) |
| if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption ) |
| nPDim = i; |
| if( nPDim == -1 ) |
| return false; |
| |
| double PDWidth, PDHeight; |
| String aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue; |
| PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) ); |
| PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) ); |
| rHeight = (int)(PDHeight + 0.5); |
| rWidth = (int)(PDWidth + 0.5); |
| |
| return true; |
| } |
| |
| String PPDParser::matchPaper( int nWidth, int nHeight ) const |
| { |
| if( ! m_pPaperDimensions ) |
| return String(); |
| |
| int nPDim = -1; |
| double PDWidth, PDHeight; |
| double fSort = 2e36, fNewSort; |
| |
| for( int i = 0; i < m_pPaperDimensions->countValues(); i++ ) |
| { |
| String aArea = m_pPaperDimensions->getValue( i )->m_aValue; |
| PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) ); |
| PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) ); |
| PDWidth /= (double)nWidth; |
| PDHeight /= (double)nHeight; |
| if( PDWidth >= 0.9 && PDWidth <= 1.1 && |
| PDHeight >= 0.9 && PDHeight <= 1.1 ) |
| { |
| fNewSort = |
| (1.0-PDWidth)*(1.0-PDWidth) + (1.0-PDHeight)*(1.0-PDHeight); |
| if( fNewSort == 0.0 ) // perfect match |
| return m_pPaperDimensions->getValue( i )->m_aOption; |
| |
| if( fNewSort < fSort ) |
| { |
| fSort = fNewSort; |
| nPDim = i; |
| } |
| } |
| } |
| |
| static bool bDontSwap = false; |
| if( nPDim == -1 && ! bDontSwap ) |
| { |
| // swap portrait/landscape and try again |
| bDontSwap = true; |
| String rRet = matchPaper( nHeight, nWidth ); |
| bDontSwap = false; |
| return rRet; |
| } |
| |
| return nPDim != -1 ? m_pPaperDimensions->getValue( nPDim )->m_aOption : String(); |
| } |
| |
| String PPDParser::getDefaultInputSlot() const |
| { |
| if( m_pDefaultInputSlot ) |
| return m_pDefaultInputSlot->m_aValue; |
| return String(); |
| } |
| |
| String PPDParser::getSlot( int nSlot ) const |
| { |
| if( ! m_pInputSlots ) |
| return String(); |
| |
| if( nSlot > 0 && nSlot < m_pInputSlots->countValues() ) |
| return m_pInputSlots->getValue( nSlot )->m_aOption; |
| else if( m_pInputSlots->countValues() > 0 ) |
| return m_pInputSlots->getValue( (sal_uLong)0 )->m_aOption; |
| |
| return String(); |
| } |
| |
| String PPDParser::getSlotCommand( int nSlot ) const |
| { |
| if( ! m_pInputSlots ) |
| return String(); |
| |
| if( nSlot > 0 && nSlot < m_pInputSlots->countValues() ) |
| return m_pInputSlots->getValue( nSlot )->m_aValue; |
| else if( m_pInputSlots->countValues() > 0 ) |
| return m_pInputSlots->getValue( (sal_uLong)0 )->m_aValue; |
| |
| return String(); |
| } |
| |
| String PPDParser::getSlotCommand( const String& rSlot ) const |
| { |
| if( ! m_pInputSlots ) |
| return String(); |
| |
| for( int i=0; i < m_pInputSlots->countValues(); i++ ) |
| { |
| const PPDValue* pValue = m_pInputSlots->getValue( i ); |
| if( pValue->m_aOption == rSlot ) |
| return pValue->m_aValue; |
| } |
| return String(); |
| } |
| |
| String PPDParser::getPaperDimension( int nPaperDimension ) const |
| { |
| if( ! m_pPaperDimensions ) |
| return String(); |
| |
| if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() ) |
| return m_pPaperDimensions->getValue( nPaperDimension )->m_aOption; |
| else if( m_pPaperDimensions->countValues() > 0 ) |
| return m_pPaperDimensions->getValue( (sal_uLong)0 )->m_aOption; |
| |
| return String(); |
| } |
| |
| String PPDParser::getPaperDimensionCommand( int nPaperDimension ) const |
| { |
| if( ! m_pPaperDimensions ) |
| return String(); |
| |
| if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() ) |
| return m_pPaperDimensions->getValue( nPaperDimension )->m_aValue; |
| else if( m_pPaperDimensions->countValues() > 0 ) |
| return m_pPaperDimensions->getValue( (sal_uLong)0 )->m_aValue; |
| |
| return String(); |
| } |
| |
| String PPDParser::getPaperDimensionCommand( const String& rPaperDimension ) const |
| { |
| if( ! m_pPaperDimensions ) |
| return String(); |
| |
| for( int i=0; i < m_pPaperDimensions->countValues(); i++ ) |
| { |
| const PPDValue* pValue = m_pPaperDimensions->getValue( i ); |
| if( pValue->m_aOption == rPaperDimension ) |
| return pValue->m_aValue; |
| } |
| return String(); |
| } |
| |
| void PPDParser::getResolutionFromString( |
| const String& rString, |
| int& rXRes, int& rYRes ) const |
| { |
| int nPos = 0, nDPIPos; |
| |
| rXRes = rYRes = 300; |
| |
| nDPIPos = rString.SearchAscii( "dpi" ); |
| if( nDPIPos != STRING_NOTFOUND ) |
| { |
| if( ( nPos = rString.Search( 'x' ) ) != STRING_NOTFOUND ) |
| { |
| rXRes = rString.Copy( 0, nPos ).ToInt32(); |
| rYRes = rString.GetToken( 1, 'x' ).Erase( nDPIPos - nPos - 1 ).ToInt32(); |
| } |
| else |
| rXRes = rYRes = rString.Copy( 0, nDPIPos ).ToInt32(); |
| } |
| } |
| |
| void PPDParser::getDefaultResolution( int& rXRes, int& rYRes ) const |
| { |
| if( m_pDefaultResolution ) |
| { |
| getResolutionFromString( m_pDefaultResolution->m_aValue, rXRes, rYRes ); |
| return; |
| } |
| |
| rXRes = 300; |
| rYRes = 300; |
| } |
| |
| int PPDParser::getResolutions() const |
| { |
| if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && |
| m_pDefaultResolution ) |
| return 1; |
| return m_pResolutions ? m_pResolutions->countValues() : 0; |
| } |
| |
| void PPDParser::getResolution( int nNr, int& rXRes, int& rYRes ) const |
| { |
| if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution && nNr == 0 ) |
| { |
| getDefaultResolution( rXRes, rYRes ); |
| return; |
| } |
| if( ! m_pResolutions ) |
| return; |
| |
| getResolutionFromString( m_pResolutions->getValue( nNr )->m_aOption, |
| rXRes, rYRes ); |
| } |
| |
| String PPDParser::getResolutionCommand( int nXRes, int nYRes ) const |
| { |
| if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution ) |
| return m_pDefaultResolution->m_aValue; |
| |
| if( ! m_pResolutions ) |
| return String(); |
| |
| int nX, nY; |
| for( int i = 0; i < m_pResolutions->countValues(); i++ ) |
| { |
| getResolutionFromString( m_pResolutions->getValue( i )->m_aOption, |
| nX, nY ); |
| if( nX == nXRes && nY == nYRes ) |
| return m_pResolutions->getValue( i )->m_aValue; |
| } |
| return String(); |
| } |
| |
| String PPDParser::getDefaultDuplexType() const |
| { |
| if( m_pDefaultDuplexType ) |
| return m_pDefaultDuplexType->m_aValue; |
| return String(); |
| } |
| |
| String PPDParser::getDuplex( int nDuplex ) const |
| { |
| if( ! m_pDuplexTypes ) |
| return String(); |
| |
| if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() ) |
| return m_pDuplexTypes->getValue( nDuplex )->m_aOption; |
| else if( m_pDuplexTypes->countValues() > 0 ) |
| return m_pDuplexTypes->getValue( (sal_uLong)0 )->m_aOption; |
| |
| return String(); |
| } |
| |
| String PPDParser::getDuplexCommand( int nDuplex ) const |
| { |
| if( ! m_pDuplexTypes ) |
| return String(); |
| |
| if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() ) |
| return m_pDuplexTypes->getValue( nDuplex )->m_aValue; |
| else if( m_pDuplexTypes->countValues() > 0 ) |
| return m_pDuplexTypes->getValue( (sal_uLong)0 )->m_aValue; |
| |
| return String(); |
| } |
| |
| String PPDParser::getDuplexCommand( const String& rDuplex ) const |
| { |
| if( ! m_pDuplexTypes ) |
| return String(); |
| |
| for( int i=0; i < m_pDuplexTypes->countValues(); i++ ) |
| { |
| const PPDValue* pValue = m_pDuplexTypes->getValue( i ); |
| if( pValue->m_aOption == rDuplex ) |
| return pValue->m_aValue; |
| } |
| return String(); |
| } |
| |
| void PPDParser::getFontAttributes( |
| int nFont, |
| String& rEncoding, |
| String& rCharset ) const |
| { |
| if( m_pFontList && nFont >= 0 && nFont < m_pFontList->countValues() ) |
| { |
| String aAttribs = |
| WhitespaceToSpace( m_pFontList->getValue( nFont )->m_aValue ); |
| rEncoding = GetCommandLineToken( 0, aAttribs ); |
| rCharset = GetCommandLineToken( 2, aAttribs ); |
| } |
| } |
| |
| void PPDParser::getFontAttributes( |
| const String& rFont, |
| String& rEncoding, |
| String& rCharset ) const |
| { |
| if( m_pFontList ) |
| { |
| for( int i = 0; i < m_pFontList->countValues(); i++ ) |
| if( m_pFontList->getValue( i )->m_aOption == rFont ) |
| getFontAttributes( i, rEncoding, rCharset ); |
| } |
| } |
| |
| String PPDParser::getFont( int nFont ) const |
| { |
| if( ! m_pFontList ) |
| return String(); |
| |
| if( nFont >=0 && nFont < m_pFontList->countValues() ) |
| return m_pFontList->getValue( nFont )->m_aOption; |
| return String(); |
| } |
| |
| rtl::OUString PPDParser::translateKey( const rtl::OUString& i_rKey, |
| const com::sun::star::lang::Locale& i_rLocale ) const |
| { |
| rtl::OUString aResult( m_pTranslator->translateKey( i_rKey, i_rLocale ) ); |
| if( aResult.getLength() == 0 ) |
| aResult = i_rKey; |
| return aResult; |
| } |
| |
| rtl::OUString PPDParser::translateOption( const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const com::sun::star::lang::Locale& i_rLocale ) const |
| { |
| rtl::OUString aResult( m_pTranslator->translateOption( i_rKey, i_rOption, i_rLocale ) ); |
| if( aResult.getLength() == 0 ) |
| aResult = i_rOption; |
| return aResult; |
| } |
| |
| rtl::OUString PPDParser::translateValue( const rtl::OUString& i_rKey, |
| const rtl::OUString& i_rOption, |
| const rtl::OUString& i_rValue, |
| const com::sun::star::lang::Locale& i_rLocale ) const |
| { |
| rtl::OUString aResult( m_pTranslator->translateValue( i_rKey, i_rOption, i_rValue, i_rLocale ) ); |
| if( aResult.getLength() == 0 ) |
| aResult = i_rValue; |
| return aResult; |
| } |
| |
| /* |
| * PPDKey |
| */ |
| |
| PPDKey::PPDKey( const String& rKey ) : |
| m_aKey( rKey ), |
| m_pDefaultValue( NULL ), |
| m_bQueryValue( false ), |
| m_bUIOption( false ), |
| m_eUIType( PickOne ), |
| m_nOrderDependency( 100 ), |
| m_eSetupType( AnySetup ) |
| { |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| PPDKey::~PPDKey() |
| { |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| const PPDValue* PPDKey::getValue( int n ) const |
| { |
| return ((unsigned int)n < m_aOrderedValues.size() && n >= 0) ? m_aOrderedValues[n] : NULL; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| const PPDValue* PPDKey::getValue( const String& rOption ) const |
| { |
| PPDKey::hash_type::const_iterator it = m_aValues.find( rOption ); |
| return it != m_aValues.end() ? &it->second : NULL; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| const PPDValue* PPDKey::getValueCaseInsensitive( const String& rOption ) const |
| { |
| const PPDValue* pValue = getValue( rOption ); |
| if( ! pValue ) |
| { |
| for( size_t n = 0; n < m_aOrderedValues.size() && ! pValue; n++ ) |
| if( m_aOrderedValues[n]->m_aOption.EqualsIgnoreCaseAscii( rOption ) ) |
| pValue = m_aOrderedValues[n]; |
| } |
| |
| return pValue; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| void PPDKey::eraseValue( const String& rOption ) |
| { |
| PPDKey::hash_type::iterator it = m_aValues.find( rOption ); |
| if( it == m_aValues.end() ) |
| return; |
| |
| for( PPDKey::value_type::iterator vit = m_aOrderedValues.begin(); vit != m_aOrderedValues.end(); ++vit ) |
| { |
| if( *vit == &(it->second ) ) |
| { |
| m_aOrderedValues.erase( vit ); |
| break; |
| } |
| } |
| m_aValues.erase( it ); |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| PPDValue* PPDKey::insertValue( const String& rOption ) |
| { |
| if( m_aValues.find( rOption ) != m_aValues.end() ) |
| return NULL; |
| |
| PPDValue aValue; |
| aValue.m_aOption = rOption; |
| m_aValues[ rOption ] = aValue; |
| PPDValue* pValue = &m_aValues[rOption]; |
| m_aOrderedValues.push_back( pValue ); |
| return pValue; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| /* |
| * PPDContext |
| */ |
| |
| PPDContext::PPDContext( const PPDParser* pParser ) : |
| m_pParser( pParser ) |
| { |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| PPDContext& PPDContext::operator=( const PPDContext& rCopy ) |
| { |
| m_pParser = rCopy.m_pParser; |
| m_aCurrentValues = rCopy.m_aCurrentValues; |
| return *this; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| PPDContext::~PPDContext() |
| { |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| const PPDKey* PPDContext::getModifiedKey( int n ) const |
| { |
| hash_type::const_iterator it; |
| for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end() && n--; ++it ) |
| ; |
| return it != m_aCurrentValues.end() ? it->first : NULL; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| void PPDContext::setParser( const PPDParser* pParser ) |
| { |
| if( pParser != m_pParser ) |
| { |
| m_aCurrentValues.clear(); |
| m_pParser = pParser; |
| } |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| const PPDValue* PPDContext::getValue( const PPDKey* pKey ) const |
| { |
| if( ! m_pParser ) |
| return NULL; |
| |
| hash_type::const_iterator it; |
| it = m_aCurrentValues.find( pKey ); |
| if( it != m_aCurrentValues.end() ) |
| return it->second; |
| |
| if( ! m_pParser->hasKey( pKey ) ) |
| return NULL; |
| |
| const PPDValue* pValue = pKey->getDefaultValue(); |
| if( ! pValue ) |
| pValue = pKey->getValue( 0 ); |
| |
| return pValue; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| const PPDValue* PPDContext::setValue( const PPDKey* pKey, const PPDValue* pValue, bool bDontCareForConstraints ) |
| { |
| if( ! m_pParser || ! pKey ) |
| return NULL; |
| |
| // pValue can be NULL - it means ignore this option |
| |
| if( ! m_pParser->hasKey( pKey ) ) |
| return NULL; |
| |
| // check constraints |
| if( pValue ) |
| { |
| if( bDontCareForConstraints ) |
| { |
| m_aCurrentValues[ pKey ] = pValue; |
| } |
| else if( checkConstraints( pKey, pValue, true ) ) |
| { |
| m_aCurrentValues[ pKey ] = pValue; |
| |
| // after setting this value, check all constraints ! |
| hash_type::iterator it = m_aCurrentValues.begin(); |
| while( it != m_aCurrentValues.end() ) |
| { |
| if( it->first != pKey && |
| ! checkConstraints( it->first, it->second, false ) ) |
| { |
| #ifdef __DEBUG |
| fprintf( stderr, "PPDContext::setValue: option %s (%s) is constrained after setting %s to %s\n", |
| it->first->getKey().GetStr(), |
| it->second->m_aOption.GetStr(), |
| pKey->getKey().GetStr(), |
| pValue->m_aOption.GetStr() ); |
| #endif |
| resetValue( it->first, true ); |
| it = m_aCurrentValues.begin(); |
| } |
| else |
| ++it; |
| } |
| } |
| } |
| else |
| m_aCurrentValues[ pKey ] = NULL; |
| |
| return pValue; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pValue ) |
| { |
| if( ! m_pParser || ! pKey || ! pValue ) |
| return false; |
| |
| // ensure that this key is already in the list if it exists at all |
| if( m_aCurrentValues.find( pKey ) != m_aCurrentValues.end() ) |
| return checkConstraints( pKey, pValue, false ); |
| |
| // it is not in the list, insert it temporarily |
| bool bRet = false; |
| if( m_pParser->hasKey( pKey ) ) |
| { |
| const PPDValue* pDefValue = pKey->getDefaultValue(); |
| m_aCurrentValues[ pKey ] = pDefValue; |
| bRet = checkConstraints( pKey, pValue, false ); |
| m_aCurrentValues.erase( pKey ); |
| } |
| |
| return bRet; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| bool PPDContext::resetValue( const PPDKey* pKey, bool bDefaultable ) |
| { |
| if( ! pKey || ! m_pParser || ! m_pParser->hasKey( pKey ) ) |
| return false; |
| |
| const PPDValue* pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); |
| if( ! pResetValue ) |
| pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) ); |
| if( ! pResetValue && bDefaultable ) |
| pResetValue = pKey->getDefaultValue(); |
| |
| bool bRet = pResetValue ? ( setValue( pKey, pResetValue ) == pResetValue ? true : false ) : false; |
| |
| return bRet; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pNewValue, bool bDoReset ) |
| { |
| if( ! pNewValue ) |
| return true; |
| |
| // sanity checks |
| if( ! m_pParser ) |
| return false; |
| |
| if( pKey->getValue( pNewValue->m_aOption ) != pNewValue ) |
| return false; |
| |
| // None / False and the default can always be set, but be careful ! |
| // setting them might influence constrained values |
| if( pNewValue->m_aOption.EqualsAscii( "None" ) || pNewValue->m_aOption.EqualsAscii( "False" ) || |
| pNewValue == pKey->getDefaultValue() ) |
| return true; |
| |
| const ::std::list< PPDParser::PPDConstraint >& rConstraints( m_pParser->getConstraints() ); |
| for( ::std::list< PPDParser::PPDConstraint >::const_iterator it = rConstraints.begin(); it != rConstraints.end(); ++it ) |
| { |
| const PPDKey* pLeft = it->m_pKey1; |
| const PPDKey* pRight = it->m_pKey2; |
| if( ! pLeft || ! pRight || ( pKey != pLeft && pKey != pRight ) ) |
| continue; |
| |
| const PPDKey* pOtherKey = pKey == pLeft ? pRight : pLeft; |
| const PPDValue* pOtherKeyOption = pKey == pLeft ? it->m_pOption2 : it->m_pOption1; |
| const PPDValue* pKeyOption = pKey == pLeft ? it->m_pOption1 : it->m_pOption2; |
| |
| // syntax *Key1 option1 *Key2 option2 |
| if( pKeyOption && pOtherKeyOption ) |
| { |
| if( pNewValue != pKeyOption ) |
| continue; |
| if( pOtherKeyOption == getValue( pOtherKey ) ) |
| { |
| return false; |
| } |
| } |
| // syntax *Key1 option *Key2 or *Key1 *Key2 option |
| else if( pOtherKeyOption || pKeyOption ) |
| { |
| if( pKeyOption ) |
| { |
| if( ! ( pOtherKeyOption = getValue( pOtherKey ) ) ) |
| continue; // this should not happen, PPD broken |
| |
| if( pKeyOption == pNewValue && |
| ! pOtherKeyOption->m_aOption.EqualsAscii( "None" ) && |
| ! pOtherKeyOption->m_aOption.EqualsAscii( "False" ) ) |
| { |
| // check if the other value can be reset and |
| // do so if possible |
| if( bDoReset && resetValue( pOtherKey ) ) |
| continue; |
| |
| return false; |
| } |
| } |
| else if( pOtherKeyOption ) |
| { |
| if( getValue( pOtherKey ) == pOtherKeyOption && |
| ! pNewValue->m_aOption.EqualsAscii( "None" ) && |
| ! pNewValue->m_aOption.EqualsAscii( "False" ) ) |
| return false; |
| } |
| else |
| { |
| // this should not happen, PPD is broken |
| } |
| } |
| // syntax *Key1 *Key2 |
| else |
| { |
| const PPDValue* pOtherValue = getValue( pOtherKey ); |
| if( ! pOtherValue->m_aOption.EqualsAscii( "None" ) && |
| ! pOtherValue->m_aOption.EqualsAscii( "False" ) && |
| ! pNewValue->m_aOption.EqualsAscii( "None" ) && |
| ! pNewValue->m_aOption.EqualsAscii( "False" ) ) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| void PPDContext::getUnconstrainedValues( const PPDKey* pKey, ::std::list< const PPDValue* >& rValues ) |
| { |
| rValues.clear(); |
| |
| if( ! m_pParser || ! pKey || ! m_pParser->hasKey( pKey ) ) |
| return; |
| |
| int nValues = pKey->countValues(); |
| for( int i = 0; i < nValues; i++ ) |
| { |
| const PPDValue* pValue = pKey->getValue( i ); |
| if( checkConstraints( pKey, pValue ) ) |
| rValues.push_back( pValue ); |
| } |
| } |
| |
| |
| // ------------------------------------------------------------------- |
| |
| void* PPDContext::getStreamableBuffer( sal_uLong& rBytes ) const |
| { |
| rBytes = 0; |
| if( ! m_aCurrentValues.size() ) |
| return NULL; |
| hash_type::const_iterator it; |
| for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it ) |
| { |
| ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 ); |
| rBytes += aCopy.Len(); |
| rBytes += 1; // for ':' |
| if( it->second ) |
| { |
| aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 ); |
| rBytes += aCopy.Len(); |
| } |
| else |
| rBytes += 4; |
| rBytes += 1; // for '\0' |
| } |
| rBytes += 1; |
| void* pBuffer = new char[ rBytes ]; |
| memset( pBuffer, 0, rBytes ); |
| char* pRun = (char*)pBuffer; |
| for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it ) |
| { |
| ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 ); |
| int nBytes = aCopy.Len(); |
| memcpy( pRun, aCopy.GetBuffer(), nBytes ); |
| pRun += nBytes; |
| *pRun++ = ':'; |
| if( it->second ) |
| aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 ); |
| else |
| aCopy = "*nil"; |
| nBytes = aCopy.Len(); |
| memcpy( pRun, aCopy.GetBuffer(), nBytes ); |
| pRun += nBytes; |
| |
| *pRun++ = 0; |
| } |
| return pBuffer; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| void PPDContext::rebuildFromStreamBuffer( void* pBuffer, sal_uLong nBytes ) |
| { |
| if( ! m_pParser ) |
| return; |
| |
| m_aCurrentValues.clear(); |
| |
| char* pRun = (char*)pBuffer; |
| while( nBytes && *pRun ) |
| { |
| ByteString aLine( pRun ); |
| int nPos = aLine.Search( ':' ); |
| if( nPos != STRING_NOTFOUND ) |
| { |
| const PPDKey* pKey = m_pParser->getKey( String( aLine.Copy( 0, nPos ), RTL_TEXTENCODING_MS_1252 ) ); |
| if( pKey ) |
| { |
| const PPDValue* pValue = NULL; |
| String aOption( aLine.Copy( nPos+1 ), RTL_TEXTENCODING_MS_1252 ); |
| if( ! aOption.EqualsAscii( "*nil" ) ) |
| pValue = pKey->getValue( aOption ); |
| m_aCurrentValues[ pKey ] = pValue; |
| #ifdef __DEBUG |
| fprintf( stderr, "PPDContext::rebuildFromStreamBuffer: read PPDKeyValue { %s, %s }\n", pKV->m_pKey->getKey().GetStr(), pKV->m_pCurrentValue ? pKV->m_pCurrentValue->m_aOption.GetStr() : "<nil>" ); |
| #endif |
| } |
| } |
| nBytes -= aLine.Len()+1; |
| pRun += aLine.Len()+1; |
| } |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| int PPDContext::getRenderResolution() const |
| { |
| // initialize to reasonable default, if parser is not set |
| int nDPI = 300; |
| if( m_pParser ) |
| { |
| int nDPIx = 300, nDPIy = 300; |
| const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) ); |
| if( pKey ) |
| { |
| const PPDValue* pValue = getValue( pKey ); |
| if( pValue ) |
| m_pParser->getResolutionFromString( pValue->m_aOption, nDPIx, nDPIy ); |
| else |
| m_pParser->getDefaultResolution( nDPIx, nDPIy ); |
| } |
| else |
| m_pParser->getDefaultResolution( nDPIx, nDPIy ); |
| |
| nDPI = (nDPIx > nDPIy) ? nDPIx : nDPIy; |
| } |
| return nDPI; |
| } |
| |
| // ------------------------------------------------------------------- |
| |
| void PPDContext::getPageSize( String& rPaper, int& rWidth, int& rHeight ) const |
| { |
| // initialize to reasonable default, if parser is not set |
| rPaper = String( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ); |
| rWidth = 595; |
| rHeight = 842; |
| if( m_pParser ) |
| { |
| const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); |
| if( pKey ) |
| { |
| const PPDValue* pValue = getValue( pKey ); |
| if( pValue ) |
| { |
| rPaper = pValue->m_aOption; |
| m_pParser->getPaperDimension( rPaper, rWidth, rHeight ); |
| } |
| else |
| { |
| rPaper = m_pParser->getDefaultPaperDimension(); |
| m_pParser->getDefaultPaperDimension( rWidth, rHeight ); |
| } |
| } |
| } |
| } |