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