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