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