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