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