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