00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "ppdloader.h"
00021 #include "foomatic2loader.h"
00022 #include "driver.h"
00023
00024 #include <kfilterdev.h>
00025 #include <kdebug.h>
00026 #include <qfile.h>
00027 #include <math.h>
00028
00029 void kdeprint_ppdscanner_init( QIODevice* );
00030 void kdeprint_ppdscanner_terminate( bool deleteIt = true );
00031
00032 static QString processLocaleString( const QString& s )
00033 {
00034 QString res;
00035 uint pos = 0;
00036 while ( pos < s.length() )
00037 {
00038 QChar c = s[ pos++ ];
00039 if ( c == '<' )
00040 {
00041 bool flag = false;
00042 uint hc = 0;
00043 while ( pos < s.length() )
00044 {
00045 QChar cc = s[ pos++ ];
00046 uint _hc = 0;
00047 if ( cc == '>' )
00048 break;
00049 else if ( cc.isDigit() )
00050 _hc = cc.digitValue();
00051 else
00052 _hc = cc.lower().latin1() - 'a' + 10;
00053 if ( flag )
00054 {
00055 hc |= _hc;
00056 res.append( QChar( hc ) );
00057 hc = 0;
00058 }
00059 else
00060 hc = ( _hc << 4 );
00061 flag = !flag;
00062 }
00063 }
00064 else
00065 {
00066 res.append( c );
00067 }
00068 }
00069 return res;
00070 }
00071
00072 static QValueList<float> splitNumberString( const QString& s )
00073 {
00074 QValueList<float> l;
00075 int p1 = 1, p2 = 0;
00076 while ( true )
00077 {
00078 p2 = s.find( ' ', p1 );
00079 if ( p2 != -1 )
00080 {
00081 l.append( s.mid( p1, p2-p1 ).toFloat() );
00082 p1 = p2+1;
00083 }
00084 else
00085 {
00086 l.append( s.mid( p1 ).toFloat() );
00087 break;
00088 }
00089 }
00090 return l;
00091 }
00092
00093 struct PS_private
00094 {
00095 QString name;
00096 struct
00097 {
00098 float width, height;
00099 } size;
00100 struct
00101 {
00102 float left, bottom, right, top;
00103 } area;
00104 };
00105
00106 PPDLoader::PPDLoader()
00107 {
00108 m_option = 0;
00109 m_ps.setAutoDelete( true );
00110 }
00111
00112 PPDLoader::~PPDLoader()
00113 {
00114 }
00115
00116 DrMain* PPDLoader::readFromFile( const QString& filename )
00117 {
00118
00119 m_groups.clear();
00120 m_option = NULL;
00121 m_fonts.clear();
00122
00123 QIODevice *d = KFilterDev::deviceForFile( filename );
00124 if ( d && d->open( IO_ReadOnly ) )
00125 {
00126 DrMain *driver = new DrMain;
00127 bool result = true;
00128
00129 m_groups.push( driver );
00130 kdeprint_ppdscanner_init( d );
00131 if ( kdeprint_ppdparse( this ) != 0 )
00132 result = false;
00133 kdeprint_ppdscanner_terminate( true );
00134
00135 if ( result )
00136 {
00137 if ( m_groups.size() > 1 )
00138 kdWarning( 500 ) << "PPD syntax error, GROUP specification not correctly closed" << endl;
00139 if ( driver->has( "foodata" ) )
00140 {
00141 Foomatic2Loader loader;
00142 if ( loader.readFromBuffer( driver->get( "foodata" ) ) )
00143 {
00144 driver = loader.modifyDriver( driver );
00145 }
00146 else
00147 kdWarning( 500 ) << "PPD syntax error, Foomatic data read failed" << endl;
00148 }
00149 processPageSizes( driver );
00150 if ( !m_fonts.isEmpty() )
00151 driver->set( "fonts", m_fonts.join( "," ) );
00152 return driver;
00153 }
00154 else
00155 kdWarning( 500 ) << "PPD syntax error, PPD parse failed" << endl;
00156 delete driver;
00157 m_ps.clear();
00158 }
00159 else
00160 kdWarning( 500 ) << "PPD read error, unable to open device for file " << filename << endl;
00161 return 0;
00162 }
00163
00164 DrMain* PPDLoader::loadDriver( const QString& filename )
00165 {
00166 PPDLoader loader;
00167 return loader.readFromFile( filename );
00168 }
00169
00170 bool PPDLoader::openUi( const QString& name, const QString& desc, const QString& type )
00171 {
00172 if ( m_option )
00173 {
00174 qWarning( "PPD syntax error, UI specification not correctly closed" );
00175 endUi( m_option->name() );
00176 }
00177
00178 if ( type == "PickOne" || type == "PickMany" )
00179 m_option = new DrListOption;
00180 else if ( type == "Boolean" )
00181 m_option = new DrBooleanOption;
00182 else
00183 return false;
00184 if ( name[ 0 ] == '*' )
00185 m_option->setName( name.mid( 1 ) );
00186 else
00187 m_option->setName( name );
00188 if ( desc.isEmpty() )
00189 m_option->set( "text", m_option->name() );
00190 else
00191 m_option->set( "text", processLocaleString( desc ) );
00192 return true;
00193 }
00194
00195 bool PPDLoader::endUi( const QString& name )
00196 {
00197 if ( m_option && ( m_option->name() == name || m_option->name() == name.mid( 1 ) ) )
00198 {
00199 if ( m_option->name() == "PageRegion" )
00200 delete m_option;
00201 else
00202 {
00203 QString defval = m_option->get( "default" );
00204 DrGroup *grp = 0;
00205 if ( !defval.isEmpty() )
00206 m_option->setValueText( defval );
00207 if ( m_groups.size() == 1 )
00208 {
00209
00210
00211 grp = findOrCreateGroupForOption( m_option->name() );
00212 }
00213 else
00214 grp = m_groups.top();
00215 grp->addOption( m_option );
00216 if ( grp->get( "text" ).contains( "install", false ) )
00217 m_option->set( "fixed", "1" );
00218 }
00219 m_option = 0;
00220 return true;
00221 }
00222 return false;
00223 }
00224
00225 bool PPDLoader::openGroup( const QString& name, const QString& desc )
00226 {
00227 DrGroup *grp = new DrGroup;
00228 grp->setName( name );
00229 if ( desc.isEmpty() )
00230 grp->set( "text", name );
00231 else
00232 grp->set( "text", processLocaleString( desc ) );
00233 m_groups.top()->addGroup( grp );
00234 m_groups.push( grp );
00235 return true;
00236 }
00237
00238 bool PPDLoader::endGroup( const QString& name )
00239 {
00240 if ( m_groups.size() > 1 && m_groups.top()->name() == name )
00241 {
00242 m_groups.pop();
00243 return true;
00244 }
00245 return false;
00246 }
00247
00248 bool PPDLoader::putStatement( const QString& keyword, const QString& name, const QString& desc, const QStringList& values )
00249 {
00250 if ( m_option )
00251 {
00252 if ( !name.isEmpty() && m_option->name() == keyword )
00253 {
00254 if ( m_option->type() >= DrBase::List )
00255 {
00256 DrBase *ch = new DrBase;
00257 ch->setName( name );
00258 if ( desc.isEmpty() )
00259 ch->set( "text", name );
00260 else
00261 ch->set( "text", processLocaleString( desc ) );
00262 static_cast<DrListOption*>( m_option )->addChoice( ch );
00263 }
00264 else
00265 {
00266 QString fv = m_option->get( "fixedvals" );
00267 if ( fv.isEmpty() )
00268 fv = name;
00269 else
00270 fv.append( "|" + name );
00271 m_option->set( "fixedvals", fv );
00272 }
00273 }
00274 else if ( keyword == "FoomaticRIPOption" && name == m_option->name()
00275 && values.size() > 1 )
00276 {
00277 QString type = values[ 0 ];
00278 if ( type == "float" || type == "int" )
00279 {
00280 DrBase *opt = 0;
00281 if ( type == "float" )
00282 opt = new DrFloatOption;
00283 else
00284 opt = new DrIntegerOption;
00285 opt->setName( m_option->name() );
00286 opt->set( "text", m_option->get( "text" ) );
00287 opt->set( "default", m_option->get( "default" ) );
00288 if ( m_option->type() == DrBase::List )
00289 {
00290 QStringList vals;
00291 QPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( m_option )->choices() ) );
00292 for ( ; it.current(); ++it )
00293 vals.append( it.current()->name() );
00294 opt->set( "fixedvals", vals.join( "|" ) );
00295 }
00296 delete m_option;
00297 m_option = opt;
00298 }
00299
00300 }
00301 else if ( keyword == "FoomaticRIPOptionRange" && name == m_option->name()
00302 && values.size() >= 2 && ( m_option->type() == DrBase::Float || m_option->type() == DrBase::Integer ) )
00303 {
00304 m_option->set( "minval", values[ 0 ] );
00305 m_option->set( "maxval", values[ 1 ] );
00306 }
00307 }
00308 else if ( keyword == "Font" && m_groups.size() > 0 )
00309 {
00310 m_fonts << name;
00311 }
00312 return true;
00313 }
00314
00315 bool PPDLoader::putStatement2( const QString& keyword, const QString& value )
00316 {
00317 if ( !m_option && m_groups.size() == 1 )
00318 {
00319 DrGroup *driver = m_groups.top();
00320 if ( keyword == "NickName" )
00321 {
00322 driver->set( "text", value );
00323 driver->set( "description", value );
00324 }
00325 else if ( keyword == "Manufacturer" )
00326 driver->set( "manufacturer", value );
00327 else if ( keyword == "ShortNickName" )
00328 driver->set( "model", value );
00329 else if ( keyword == "ColorDevice" )
00330 driver->set( "colordevice", value == "True" ? "1" : "0" );
00331 }
00332 return true;
00333 }
00334
00335 bool PPDLoader::putDefault( const QString& keyword, const QString& value )
00336 {
00337 if ( keyword == "Resolution" && m_groups.size() > 0 )
00338 {
00339
00340
00341
00342 m_groups[ 0 ]->set( "resolution", value );
00343 }
00344
00345 if ( m_option && m_option->name() == keyword )
00346 {
00347 m_option->set( "default", value );
00348 return true;
00349 }
00350 else
00351 return false;
00352 }
00353
00354 bool PPDLoader::putConstraint( const QString& opt1, const QString& opt2, const QString& ch1, const QString& ch2 )
00355 {
00356 if ( !m_option && m_groups.size() == 1 )
00357 {
00358 DrMain *driver = static_cast<DrMain*>( m_groups.top() );
00359 driver->addConstraint( new DrConstraint( opt1, opt2, ch1, ch2 ) );
00360 }
00361 return true;
00362 }
00363
00364 bool PPDLoader::putFooData( const QString& data )
00365 {
00366 if ( !m_option && m_groups.size() == 1 )
00367 {
00368 m_groups.top()->set( "foodata", m_groups.top()->get( "foodata" ) + data + "\n" );
00369 }
00370 return true;
00371 }
00372
00373 bool PPDLoader::putFooProcessedData( const QVariant& var )
00374 {
00375 QMap<QString,QVariant>::ConstIterator it = var.mapFind( "args_byname" );
00376 if ( it != var.mapEnd() )
00377 {
00378 QVariant opts = it.data();
00379 for ( it = opts.mapBegin(); it != opts.mapEnd(); ++it )
00380 {
00381 QMap<QString,QVariant> opt = it.data().toMap();
00382 QString type = opt[ "type" ].toString();
00383 if ( type == "float" || type == "int" )
00384 {
00385 DrBase *o;
00386 if ( type == "float" )
00387 o = new DrFloatOption;
00388 else
00389 o = new DrIntegerOption;
00390 o->setName( opt[ "name" ].toString() );
00391 o->set( "text", opt[ "comment" ].toString() );
00392 o->set( "minval", opt[ "min" ].toString() );
00393 o->set( "maxval", opt[ "max" ].toString() );
00394 o->set( "default", opt[ "default" ].toString() );
00395 o->setValueText( o->get( "default" ) );
00396
00397 DrGroup *grp = 0;
00398 DrBase *old = m_groups.top()->findOption( o->name(), &grp );
00399 if ( old )
00400 {
00401 if ( old->type() == DrBase::List )
00402 {
00403 QStringList vals;
00404 QPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( old )->choices() ) );
00405 for ( ; it.current(); ++it )
00406 vals.append( it.current()->name() );
00407 o->set( "fixedvals", vals.join( "|" ) );
00408 }
00409 grp->removeOption( o->name() );
00410 grp->addOption( o );
00411 }
00412 else
00413 {
00414 qWarning( "Option %s not found in original PPD file", o->name().latin1() );
00415 delete o;
00416 }
00417 }
00418 }
00419 }
00420 return true;
00421 }
00422
00423 bool PPDLoader::putPaperDimension( const QString& name, const QString& s )
00424 {
00425 QValueList<float> l = splitNumberString( s );
00426
00427 PS_private *ps = m_ps.find( name );
00428 if ( !ps )
00429 {
00430 ps = new PS_private;
00431 ps->name = name;
00432 m_ps.insert( name, ps );
00433 }
00434 ps->size.width = l[ 0 ];
00435 ps->size.height = l[ 1 ];
00436
00437 return true;
00438 }
00439
00440 bool PPDLoader::putImageableArea( const QString& name, const QString& s )
00441 {
00442 QValueList<float> l = splitNumberString( s );
00443
00444 PS_private *ps = m_ps.find( name );
00445 if ( !ps )
00446 {
00447 ps = new PS_private;
00448 ps->name = name;
00449 m_ps.insert( name, ps );
00450 }
00451 ps->area.left = l[ 0 ];
00452 ps->area.bottom = l[ 1 ];
00453 ps->area.right = l[ 2 ];
00454 ps->area.top = l[ 3 ];
00455
00456 return true;
00457 }
00458
00459 DrGroup* PPDLoader::findOrCreateGroupForOption( const QString& optname )
00460 {
00461 QString grpname;
00462 if ( optname == "PageSize" ||
00463 optname == "InputSlot" ||
00464 optname == "ManualFeed" ||
00465 optname == "MediaType" ||
00466 optname == "MediaColor" ||
00467 optname == "MediaWeight" )
00468 grpname = "General";
00469 else if ( optname.startsWith( "stp" ) ||
00470 optname == "Cyan" ||
00471 optname == "Yellow" ||
00472 optname == "Magenta" ||
00473 optname == "Density" ||
00474 optname == "Contrast" )
00475 grpname = "Adjustments";
00476 else if ( optname.startsWith( "JCL" ) )
00477 grpname = "JCL";
00478 else
00479 grpname = "Others";
00480
00481 DrGroup *grp = 0;
00482 for ( QPtrListIterator<DrGroup> it( m_groups[ 0 ]->groups() ); it.current(); ++it )
00483 if ( it.current()->name() == grpname )
00484 {
00485 grp = it.current();
00486 break;
00487 }
00488 if ( !grp )
00489 {
00490 grp = new DrGroup;
00491 grp->setName( grpname );
00492 grp->set( "text", grpname );
00493 m_groups[ 0 ]->addGroup( grp );
00494 }
00495 return grp;
00496 }
00497
00498 void PPDLoader::processPageSizes( DrMain *driver )
00499 {
00500 QDictIterator<PS_private> it( m_ps );
00501 for ( ; it.current(); ++it )
00502 {
00503
00504
00505
00506
00507 driver->addPageSize( new DrPageSize( it.current()->name,
00508 ( int )it.current()->size.width, ( int )it.current()->size.height,
00509 ( int )it.current()->area.left, ( int )it.current()->area.bottom,
00510 ( int )ceil( it.current()->size.width - it.current()->area.right ),
00511 ( int )ceil( it.current()->size.height - it.current()->area.top ) ) );
00512 }
00513 m_ps.clear();
00514 }