• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kdeprint
 

kdeprint

ppdloader.cpp
00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2001-2003 Michael Goffioul <kdeprint@swing.be>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation.
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #ifndef _GNU_SOURCE
00021 #define _GNU_SOURCE   /* Needed for getline */
00022 #endif
00023 
00024 #include "ppdloader.h"
00025 #include "foomatic2loader.h"
00026 #include "driver.h"
00027 
00028 #include <kfilterdev.h>
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 #include <ktempfile.h>
00032 #include <tqfile.h>
00033 #include <math.h>
00034 #include <stdlib.h>
00035 
00036 void kdeprint_ppdscanner_init( TQIODevice* );
00037 void kdeprint_ppdscanner_terminate( bool deleteIt = true );
00038 int kdeprint_ppdscanner_numberoflines();
00039 
00040 static TQString processLocaleString( const TQString& s )
00041 {
00042     TQString res;
00043     uint pos = 0;
00044     while ( pos < s.length() )
00045     {
00046         TQChar c = s[ pos++ ];
00047         if ( c == '<' )
00048         {
00049             bool flag = false;
00050             uint hc = 0;
00051             while ( pos < s.length() )
00052             {
00053                 TQChar cc = s[ pos++ ];
00054                 uint _hc = 0;
00055                 if ( cc == '>' )
00056                     break;
00057                 else if ( cc.isDigit() )
00058                     _hc = cc.digitValue();
00059                 else
00060                     _hc = cc.lower().latin1() - 'a' + 10;
00061                 if ( flag )
00062                 {
00063                     hc |= _hc;
00064                     res.append( TQChar( hc ) );
00065                     hc = 0;
00066                 }
00067                 else
00068                     hc = ( _hc << 4 );
00069                 flag = !flag;
00070             }
00071         }
00072         else
00073         {
00074             res.append( c );
00075         }
00076     }
00077     return res;
00078 }
00079 
00080 static TQValueList<float> splitNumberString( const TQString& _s )
00081 {
00082         TQString s = _s.simplifyWhiteSpace();
00083     TQValueList<float> l;
00084     int p1 = 1, p2 = 0;
00085     while ( true )
00086     {
00087         p2 = s.find( ' ', p1 );
00088         if ( p2 != -1 )
00089         {
00090             l.append( s.mid( p1, p2-p1 ).toFloat() );
00091             p1 = p2+1;
00092         }
00093         else
00094         {
00095             // ignore the final quote
00096             l.append( s.mid( p1, s.length() - p1 - 1 ).toFloat() );
00097             break;
00098         }
00099     }
00100     return l;
00101 }
00102 
00103 struct PS_private
00104 {
00105     TQString name;
00106     struct
00107     {
00108         float width, height;
00109     } size;
00110     struct
00111     {
00112         float left, bottom, right, top;
00113     } area;
00114 };
00115 
00116 PPDLoader::PPDLoader()
00117 {
00118     m_option = 0;
00119     m_ps.setAutoDelete( true );
00120 }
00121 
00122 PPDLoader::~PPDLoader()
00123 {
00124 }
00125 
00126 DrMain* PPDLoader::readFromFile( const TQString& filename )
00127 {
00128     bool ppdFilenameIsTempFile = false;
00129     TQString ppdFilename = filename;
00130 
00131     if (filename.startsWith("compressed-ppd:")) {
00132         KTempFile tempFile(TQString::null, "ppd", 0600);
00133         tempFile.setAutoDelete(false);
00134         ppdFilename = tempFile.name();
00135 
00136         TQStringList filenameParts = TQStringList::split(":", filename);
00137         TQString databaseFilename = TQString::null;
00138         TQString compressedFilename = TQString::null;
00139         int i = 0;
00140         for (TQStringList::Iterator it = filenameParts.begin(); it != filenameParts.end(); ++it) {
00141             if (i == 1) {
00142                 databaseFilename = *it;
00143             }
00144             else if (i > 1) {
00145                 compressedFilename += *it;
00146             }
00147             i++;
00148         }
00149 
00150         TQString command = databaseFilename + " cat " + compressedFilename;
00151 
00152         FILE* file = popen(command.ascii(), "r");
00153         if (file) {
00154             char * line = NULL;
00155             size_t len = 0;
00156             ssize_t read;
00157 
00158             FILE* tmpFileStream = tempFile.fstream();
00159 
00160             while ((read = getline(&line, &len, file)) != -1) {
00161                 fputs(line, tmpFileStream);
00162             }
00163             if (line) {
00164                 free(line);
00165             }
00166 
00167             tempFile.close();
00168             pclose(file);
00169         }
00170         else {
00171             fprintf(stderr, "Can't open driver file : %s\n", compressedFilename.ascii());
00172             return 0;
00173         }
00174 
00175         ppdFilenameIsTempFile = true;
00176     }
00177 
00178     // Initialization
00179     m_groups.clear();
00180     m_option = NULL;
00181     m_fonts.clear();
00182     // Open driver file
00183     TQIODevice *d = KFilterDev::deviceForFile( ppdFilename );
00184     if ( d && d->open( IO_ReadOnly ) )
00185     {
00186         DrMain *driver = new DrMain;
00187         bool result = true;
00188 
00189         m_groups.push( driver );
00190         kdeprint_ppdscanner_init( d );
00191         if ( kdeprint_ppdparse( this ) != 0 )
00192             result = false;
00193         kdeprint_ppdscanner_terminate( true );
00194 
00195         if ( result )
00196         {
00197             if ( m_groups.size() > 1 )
00198                 kdWarning( 500 ) << "PPD syntax error, GROUP specification not correctly closed" << endl;
00199             if ( driver->has( "foodata" ) )
00200             {
00201                 Foomatic2Loader loader;
00202                 if ( loader.readFromBuffer( driver->get( "foodata" ) ) )
00203                 {
00204                     driver = loader.modifyDriver( driver );
00205                 }
00206                 else
00207                     kdWarning( 500 ) << "PPD syntax error, Foomatic data read failed" << endl;
00208             }
00209             processPageSizes( driver );
00210             if ( !m_fonts.isEmpty() )
00211                 driver->set( "fonts", m_fonts.join( "," ) );
00212             if (ppdFilenameIsTempFile) {
00213                 driver->set("temporary-cppd", ppdFilename);
00214             }
00215             return driver;
00216         }
00217         else
00218             kdWarning( 500 ) << "PPD syntax error, PPD parse failed" << endl;
00219         delete driver;
00220         m_ps.clear();
00221     }
00222     else
00223         kdWarning( 500 ) << "PPD read error, unable to open device for file " << ppdFilename << endl;
00224     return 0;
00225 }
00226 
00227 DrMain* PPDLoader::loadDriver( const TQString& filename, TQString* msg )
00228 {
00229     PPDLoader loader;
00230     DrMain *driver = loader.readFromFile( filename );
00231     if ( !driver && msg )
00232         *msg = filename + i18n( "(line %1): " ).arg( kdeprint_ppdscanner_numberoflines() ) + loader.errorMsg();
00233     return driver;
00234 }
00235 
00236 bool PPDLoader::openUi( const TQString& name, const TQString& desc, const TQString& type )
00237 {
00238     if ( m_option )
00239     {
00240         qWarning( "PPD syntax error, UI specification not correctly closed" );
00241         endUi( m_option->name() );
00242     }
00243 
00244     if ( type == "PickOne" || type == "PickMany" )
00245         m_option = new DrListOption;
00246     else if ( type == "Boolean" )
00247         m_option = new DrBooleanOption;
00248     else
00249         return false;
00250     if ( name[ 0 ] == '*' )
00251         m_option->setName( name.mid( 1 ) );
00252     else
00253         m_option->setName( name );
00254     if ( desc.isEmpty() )
00255         m_option->set( "text", m_option->name() );
00256     else
00257         m_option->set( "text", processLocaleString( desc ) );
00258     return true;
00259 }
00260 
00261 bool PPDLoader::endUi( const TQString& name )
00262 {
00263     if ( m_option && ( m_option->name() == name || m_option->name() == name.mid( 1 ) ) )
00264     {
00265         if ( m_option->name() == "PageRegion" )
00266             delete m_option;
00267         else
00268         {
00269             TQString defval = m_option->get( "default" );
00270             DrGroup *grp = 0;
00271             if ( !defval.isEmpty() )
00272                 m_option->setValueText( defval );
00273             if ( m_groups.size() == 1 )
00274             {
00275                 // we don't have any group defined, create the
00276                 // most adapted one.
00277                 grp = findOrCreateGroupForOption( m_option->name() );
00278             }
00279             else
00280                 grp = m_groups.top();
00281             grp->addOption( m_option );
00282             if ( grp->get( "text" ).contains( "install", false ) )
00283                 m_option->set( "fixed", "1" );
00284         }
00285         m_option = 0;
00286         return true;
00287     }
00288     return false;
00289 }
00290 
00291 bool PPDLoader::openGroup( const TQString& name, const TQString& desc )
00292 {
00293     DrGroup *grp = new DrGroup;
00294     grp->setName( name );
00295     if ( desc.isEmpty() )
00296         grp->set( "text", name );
00297     else
00298         grp->set( "text", processLocaleString( desc ) );
00299     m_groups.top()->addGroup( grp );
00300     m_groups.push( grp );
00301     return true;
00302 }
00303 
00304 bool PPDLoader::endGroup( const TQString& name )
00305 {
00306     if ( m_groups.size() > 1 && m_groups.top()->name() == name )
00307     {
00308         m_groups.pop();
00309         return true;
00310     }
00311     return false;
00312 }
00313 
00314 bool PPDLoader::putStatement( const TQString& keyword, const TQString& name, const TQString& desc, const TQStringList& values )
00315 {
00316     if ( m_option )
00317     {
00318         if ( !name.isEmpty() && m_option->name() == keyword )
00319         {
00320             if ( m_option->type() >= DrBase::List )
00321             {
00322                 DrBase *ch = new DrBase;
00323                 ch->setName( name );
00324                 if ( desc.isEmpty() )
00325                     ch->set( "text", name );
00326                 else
00327                     ch->set( "text", processLocaleString( desc ) );
00328                 static_cast<DrListOption*>( m_option )->addChoice( ch );
00329             }
00330             else
00331             {
00332                 TQString fv = m_option->get( "fixedvals" );
00333                 if ( fv.isEmpty() )
00334                     fv = name;
00335                 else
00336                     fv.append( "|" + name );
00337                 m_option->set( "fixedvals", fv );
00338             }
00339         }
00340         else if ( keyword == "FoomaticRIPOption" && name == m_option->name()
00341                 && values.size() > 1 )
00342         {
00343             TQString type = values[ 0 ];
00344             if ( type == "float" || type == "int" )
00345             {
00346                 DrBase *opt = 0;
00347                 if ( type == "float" )
00348                     opt = new DrFloatOption;
00349                 else
00350                     opt = new DrIntegerOption;
00351                 opt->setName( m_option->name() );
00352                 opt->set( "text", m_option->get( "text" ) );
00353                 opt->set( "default", m_option->get( "default" ) );
00354                 if ( m_option->type() == DrBase::List )
00355                 {
00356                     TQStringList vals;
00357                     TQPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( m_option )->choices() ) );
00358                     for ( ; it.current(); ++it )
00359                         vals.append( it.current()->name() );
00360                     opt->set( "fixedvals", vals.join( "|" ) );
00361                 }
00362                 delete m_option;
00363                 m_option = opt;
00364             }
00365             // FIXME: support other option types
00366         }
00367         else if ( keyword == "FoomaticRIPOptionRange" && name == m_option->name()
00368                 && values.size() >= 2 && ( m_option->type() == DrBase::Float || m_option->type() == DrBase::Integer ) )
00369         {
00370             m_option->set( "minval", values[ 0 ] );
00371             m_option->set( "maxval", values[ 1 ] );
00372         }
00373     }
00374     else if ( keyword == "Font" && m_groups.size() > 0 )
00375     {
00376         m_fonts << name;
00377     }
00378     return true;
00379 }
00380 
00381 bool PPDLoader::putStatement2( const TQString& keyword, const TQString& value )
00382 {
00383     if ( !m_option && m_groups.size() == 1 )
00384     {
00385         DrGroup *driver = m_groups.top();
00386         if ( keyword == "NickName" )
00387         {
00388             driver->set( "text", value );
00389             driver->set( "description", value );
00390         }
00391         else if ( keyword == "Manufacturer" )
00392             driver->set( "manufacturer", value );
00393         else if ( keyword == "ShortNickName" )
00394             driver->set( "model", value );
00395         else if ( keyword == "ColorDevice" )
00396             driver->set( "colordevice", value == "True" ? "1" : "0" );
00397     }
00398     return true;
00399 }
00400 
00401 bool PPDLoader::putDefault( const TQString& keyword, const TQString& value )
00402 {
00403     if ( keyword == "Resolution" && m_groups.size() > 0 )
00404     {
00405         // Store default resolution as it could be fed back
00406         // to the application. And default resolution can
00407         // occur outside a OpenUI/CloseUI pair.
00408         m_groups[ 0 ]->set( "resolution", value );
00409     }
00410 
00411     if ( m_option && m_option->name() == keyword )
00412     {
00413         m_option->set( "default", value );
00414         return true;
00415     }
00416     else
00417         return false;
00418 }
00419 
00420 bool PPDLoader::putConstraint( const TQString& opt1, const TQString& opt2, const TQString& ch1, const TQString& ch2 )
00421 {
00422     if ( !m_option && m_groups.size() == 1 )
00423     {
00424         DrMain *driver = static_cast<DrMain*>( m_groups.top() );
00425         driver->addConstraint( new DrConstraint( opt1, opt2, ch1, ch2 ) );
00426     }
00427     return true;
00428 }
00429 
00430 bool PPDLoader::putFooData( const TQString& data )
00431 {
00432     if ( !m_option && m_groups.size() == 1 )
00433     {
00434         m_groups.top()->set( "foodata", m_groups.top()->get( "foodata" ) + data + "\n" );
00435     }
00436     return true;
00437 }
00438 
00439 bool PPDLoader::putFooProcessedData( const TQVariant& var )
00440 {
00441     TQMap<TQString,TQVariant>::ConstIterator it = var.mapFind( "args_byname" );
00442     if ( it != var.mapEnd() )
00443     {
00444         TQVariant opts = it.data();
00445         for ( it = opts.mapBegin(); it != opts.mapEnd(); ++it )
00446         {
00447             TQMap<TQString,TQVariant> opt = it.data().toMap();
00448             TQString type = opt[ "type" ].toString();
00449             if ( type == "float" || type == "int" )
00450             {
00451                 DrBase *o;
00452                 if ( type == "float" )
00453                     o = new DrFloatOption;
00454                 else
00455                     o = new DrIntegerOption;
00456                 o->setName( opt[ "name" ].toString() );
00457                 o->set( "text", opt[ "comment" ].toString() );
00458                 o->set( "minval", opt[ "min" ].toString() );
00459                 o->set( "maxval", opt[ "max" ].toString() );
00460                 o->set( "default", opt[ "default" ].toString() );
00461                 o->setValueText( o->get( "default" ) );
00462 
00463                 DrGroup *grp = 0;
00464                 DrBase *old = m_groups.top()->findOption( o->name(), &grp );
00465                 if ( old )
00466                 {
00467                     if ( old->type() == DrBase::List )
00468                     {
00469                         TQStringList vals;
00470                         TQPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( old )->choices() ) );
00471                         for ( ; it.current(); ++it )
00472                             vals.append( it.current()->name() );
00473                         o->set( "fixedvals", vals.join( "|" ) );
00474                     }
00475                     grp->removeOption( o->name() );
00476                     grp->addOption( o );
00477                 }
00478                 else
00479                 {
00480                     qWarning( "Option %s not found in original PPD file", o->name().latin1() );
00481                     delete o;
00482                 }
00483             }
00484         }
00485     }
00486     return true;
00487 }
00488 
00489 bool PPDLoader::putPaperDimension( const TQString& name, const TQString& s )
00490 {
00491     TQValueList<float> l = splitNumberString( s );
00492 
00493     PS_private *ps = m_ps.find( name );
00494     if ( !ps )
00495     {
00496         ps = new PS_private;
00497         ps->name = name;
00498         m_ps.insert( name, ps );
00499     }
00500     ps->size.width = l[ 0 ];
00501     ps->size.height = l[ 1 ];
00502 
00503     return true;
00504 }
00505 
00506 bool PPDLoader::putImageableArea( const TQString& name, const TQString& s )
00507 {
00508     TQValueList<float> l = splitNumberString( s );
00509 
00510     PS_private *ps = m_ps.find( name );
00511     if ( !ps )
00512     {
00513         ps = new PS_private;
00514         ps->name = name;
00515         m_ps.insert( name, ps );
00516     }
00517     ps->area.left = l[ 0 ];
00518     ps->area.bottom = l[ 1 ];
00519     ps->area.right = l[ 2 ];
00520     ps->area.top = l[ 3 ];
00521 
00522     return true;
00523 }
00524 
00525 DrGroup* PPDLoader::findOrCreateGroupForOption( const TQString& optname )
00526 {
00527     TQString grpname;
00528     if ( optname == "PageSize" ||
00529             optname == "InputSlot" ||
00530             optname == "ManualFeed" ||
00531             optname == "MediaType" ||
00532             optname == "MediaColor" ||
00533             optname == "MediaWeight" )
00534         grpname = "General";
00535     else if ( optname.startsWith( "stp" ) ||
00536             optname == "Cyan" ||
00537             optname == "Yellow" ||
00538             optname == "Magenta" ||
00539             optname == "Density" ||
00540             optname == "Contrast" )
00541         grpname = "Adjustments";
00542     else if ( optname.startsWith( "JCL" ) )
00543         grpname = "JCL";
00544     else
00545         grpname = "Others";
00546 
00547     DrGroup *grp = 0;
00548     for ( TQPtrListIterator<DrGroup> it( m_groups[ 0 ]->groups() ); it.current(); ++it )
00549         if ( it.current()->name() == grpname )
00550         {
00551             grp = it.current();
00552             break;
00553         }
00554     if ( !grp )
00555     {
00556         grp = new DrGroup;
00557         grp->setName( grpname );
00558         grp->set( "text", grpname );
00559         m_groups[ 0 ]->addGroup( grp );
00560     }
00561     return grp;
00562 }
00563 
00564 void PPDLoader::processPageSizes( DrMain *driver )
00565 {
00566     TQDictIterator<PS_private> it( m_ps );
00567     for ( ; it.current(); ++it )
00568     {
00569         //qDebug( "ADDING PAGESIZE: %16s, Size = ( %.2f, %.2f ),  Area = ( %.2f, %.2f, %.2f, %.2f )", it.current()->name.latin1(),
00570         //      it.current()->size.width, it.current()->size.height,
00571         //      it.current()->area.left, it.current()->area.bottom,
00572         //      it.current()->area.right, it.current()->area.top );
00573         driver->addPageSize( new DrPageSize( it.current()->name,
00574                     ( int )it.current()->size.width, ( int )it.current()->size.height,
00575                     ( int )it.current()->area.left, ( int )it.current()->area.bottom,
00576                     ( int )ceil( it.current()->size.width - it.current()->area.right ),
00577                     ( int )ceil( it.current()->size.height - it.current()->area.top ) ) );
00578     }
00579     m_ps.clear();
00580 }
00581 
00582 void PPDLoader::setErrorMsg( const TQString& msg )
00583 {
00584     m_errormsg = msg;
00585 }
00586 
00587 TQString PPDLoader::errorMsg() const
00588 {
00589     return m_errormsg;
00590 }

kdeprint

Skip menu "kdeprint"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdeprint

Skip menu "kdeprint"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdeprint by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |