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