LCOV - code coverage report
Current view: top level - libreoffice/extensions/source/scanner - sane.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 495 0.0 %
Date: 2012-12-17 Functions: 0 27 0.0 %
Legend: Lines: hit not hit

          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             : #include <cstdarg>
      21             : #include <math.h>
      22             : #include <osl/file.h>
      23             : #include <tools/stream.hxx>
      24             : #include <sane.hxx>
      25             : #include <dlfcn.h>
      26             : #include <stdio.h>
      27             : #include <unistd.h>
      28             : #include <sys/time.h>
      29             : #include <sys/types.h>
      30             : #include <sal/config.h>
      31             : #include <sal/macros.h>
      32             : 
      33             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
      34             : #include <stdarg.h>
      35             : #define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d );
      36             : #else
      37             : #define dump_state( a, b, c, d ) ;
      38             : #endif
      39           0 : inline void dbg_msg( const char* pString, ... )
      40             : {
      41             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
      42             :     va_list ap;
      43             :     va_start( ap, pString );
      44             :     vfprintf( stderr, pString, ap );
      45             :     va_end( ap );
      46             : #else
      47             :     (void)pString;
      48             : #endif
      49           0 : }
      50             : 
      51             : #define FAIL_SHUTDOWN_STATE( x, y, z ) \
      52             :     if( x != SANE_STATUS_GOOD )                             \
      53             :     {                                                       \
      54             :         dump_state( "%s returned error %d (%s)\n",          \
      55             :                  y, x, p_strstatus( x ) );                  \
      56             :         DeInit();                                           \
      57             :         return z;                                           \
      58             :     }
      59             : 
      60             : #define FAIL_STATE( x, y, z ) \
      61             :     if( x != SANE_STATUS_GOOD )                             \
      62             :     {                                                       \
      63             :         dump_state( "%s returned error %d (%s)\n",          \
      64             :                  y, x, p_strstatus( x ) );                  \
      65             :         return z;                                           \
      66             :     }
      67             : 
      68             : #define DUMP_STATE( x, y ) \
      69             :     if( x != SANE_STATUS_GOOD )                             \
      70             :     {                                                       \
      71             :         dump_state( "%s returned error %d (%s)\n",          \
      72             :                  y, x, p_strstatus( x ) );                  \
      73             :     }
      74             : 
      75             : int             Sane::nRefCount = 0;
      76             : oslModule       Sane::pSaneLib = 0;
      77             : SANE_Int        Sane::nVersion = 0;
      78             : SANE_Device**   Sane::ppDevices = 0;
      79             : int             Sane::nDevices = 0;
      80             : 
      81             : SANE_Status     (*Sane::p_init)( SANE_Int*,
      82             :                                  SANE_Auth_Callback ) = 0;
      83             : void            (*Sane::p_exit)() = 0;
      84             : SANE_Status     (*Sane::p_get_devices)( const SANE_Device***,
      85             :                                         SANE_Bool ) = 0;
      86             : SANE_Status     (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = 0;
      87             : void            (*Sane::p_close)( SANE_Handle ) = 0;
      88             : const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)(
      89             :     SANE_Handle, SANE_Int ) = 0;
      90             : SANE_Status     (*Sane::p_control_option)( SANE_Handle, SANE_Int,
      91             :                                            SANE_Action, void*,
      92             :                                            SANE_Int* ) = 0;
      93             : SANE_Status     (*Sane::p_get_parameters)( SANE_Handle,
      94             :                                            SANE_Parameters* ) = 0;
      95             : SANE_Status     (*Sane::p_start)( SANE_Handle ) = 0;
      96             : SANE_Status     (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int,
      97             :                                  SANE_Int* ) = 0;
      98             : void            (*Sane::p_cancel)( SANE_Handle ) = 0;
      99             : SANE_Status     (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = 0;
     100             : SANE_Status     (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = 0;
     101             : SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = 0;
     102             : 
     103             : static sal_Bool bSaneSymbolLoadFailed = sal_False;
     104             : 
     105           0 : inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname )
     106             : {
     107           0 :     oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname );
     108           0 :     if( ! pFunction )
     109             :     {
     110             :         fprintf( stderr, "Could not load symbol %s\n",
     111           0 :                  pSymbolname );
     112           0 :         bSaneSymbolLoadFailed = sal_True;
     113             :     }
     114           0 :     return pFunction;
     115             : }
     116             : 
     117           0 : SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction,
     118             :                                  void* pData )
     119             : {
     120           0 :     SANE_Status nStatus = SANE_STATUS_GOOD;
     121           0 :     SANE_Int    nInfo = 0;
     122             : 
     123             :     nStatus = p_control_option( maHandle, (SANE_Int)nOption,
     124           0 :                                 nAction, pData, &nInfo );
     125             :     DUMP_STATE( nStatus, "sane_control_option" );
     126             : #if OSL_DEBUG_LEVEL > 1
     127             :     if( nStatus != SANE_STATUS_GOOD )
     128             :     {
     129             :         const char* pAction = "Unknown";
     130             :         switch( nAction )
     131             :         {
     132             :             case SANE_ACTION_GET_VALUE:
     133             :                 pAction = "SANE_ACTION_GET_VALUE";break;
     134             :             case SANE_ACTION_SET_VALUE:
     135             :                 pAction = "SANE_ACTION_SET_VALUE";break;
     136             :             case SANE_ACTION_SET_AUTO:
     137             :                 pAction = "SANE_ACTION_SET_AUTO";break;
     138             :         }
     139             :         dbg_msg( "Option: \"%s\" action: %s\n",
     140             :                  rtl::OUStringToOString(GetOptionName(nOption), osl_getThreadTextEncoding()).getStr(),
     141             :                  pAction );
     142             :     }
     143             : #endif
     144           0 :     if( nInfo &  SANE_INFO_RELOAD_OPTIONS )
     145           0 :         ReloadOptions();
     146           0 :     return nStatus;
     147             : }
     148             : 
     149           0 : Sane::Sane() :
     150             :         mppOptions( 0 ),
     151             :         mnOptions( 0 ),
     152             :         mnDevice( -1 ),
     153           0 :         maHandle( 0 )
     154             : {
     155           0 :     if( ! nRefCount || ! pSaneLib )
     156           0 :         Init();
     157           0 :     nRefCount++;
     158           0 : };
     159             : 
     160           0 : Sane::~Sane()
     161             : {
     162           0 :     if( IsOpen() )
     163           0 :         Close();
     164           0 :     nRefCount--;
     165           0 :     if( ! nRefCount && pSaneLib )
     166           0 :         DeInit();
     167           0 : }
     168             : 
     169           0 : void Sane::Init()
     170             : {
     171           0 :     ::rtl::OUString sSaneLibName( "libsane" SAL_DLLEXTENSION  );
     172           0 :     pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
     173           0 :     if( ! pSaneLib )
     174             :     {
     175           0 :         sSaneLibName = ::rtl::OUString("libsane" SAL_DLLEXTENSION ".1" );
     176           0 :         pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
     177             :     }
     178             :     // try reasonable places that might not be in the library search path
     179           0 :     if( ! pSaneLib )
     180             :     {
     181           0 :         ::rtl::OUString sSaneLibSystemPath( "/usr/local/lib/libsane" SAL_DLLEXTENSION  );
     182           0 :         osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData );
     183           0 :         pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
     184             :     }
     185             : 
     186           0 :     if( pSaneLib )
     187             :     {
     188           0 :         bSaneSymbolLoadFailed = sal_False;
     189             :         p_init = (SANE_Status(*)(SANE_Int*, SANE_Auth_Callback ))
     190           0 :             LoadSymbol( "sane_init" );
     191             :         p_exit = (void(*)())
     192           0 :             LoadSymbol( "sane_exit" );
     193             :         p_get_devices = (SANE_Status(*)(const SANE_Device***,
     194             :                                         SANE_Bool ))
     195           0 :             LoadSymbol( "sane_get_devices" );
     196             :         p_open = (SANE_Status(*)(SANE_String_Const, SANE_Handle ))
     197           0 :             LoadSymbol( "sane_open" );
     198             :         p_close = (void(*)(SANE_Handle))
     199           0 :             LoadSymbol( "sane_close" );
     200             :         p_get_option_descriptor = (const SANE_Option_Descriptor*(*)(SANE_Handle,
     201             :                                                               SANE_Int))
     202           0 :             LoadSymbol( "sane_get_option_descriptor" );
     203             :         p_control_option = (SANE_Status(*)(SANE_Handle, SANE_Int,
     204             :                                            SANE_Action, void*, SANE_Int*))
     205           0 :             LoadSymbol( "sane_control_option" );
     206             :         p_get_parameters = (SANE_Status(*)(SANE_Handle,SANE_Parameters*))
     207           0 :             LoadSymbol( "sane_get_parameters" );
     208             :         p_start = (SANE_Status(*)(SANE_Handle))
     209           0 :             LoadSymbol( "sane_start" );
     210             :         p_read = (SANE_Status(*)(SANE_Handle, SANE_Byte*,
     211             :                                  SANE_Int, SANE_Int* ))
     212           0 :             LoadSymbol( "sane_read" );
     213             :         p_cancel = (void(*)(SANE_Handle))
     214           0 :             LoadSymbol( "sane_cancel" );
     215             :         p_set_io_mode = (SANE_Status(*)(SANE_Handle, SANE_Bool))
     216           0 :             LoadSymbol( "sane_set_io_mode" );
     217             :         p_get_select_fd = (SANE_Status(*)(SANE_Handle, SANE_Int*))
     218           0 :             LoadSymbol( "sane_get_select_fd" );
     219             :         p_strstatus = (SANE_String_Const(*)(SANE_Status))
     220           0 :             LoadSymbol( "sane_strstatus" );
     221           0 :         if( bSaneSymbolLoadFailed )
     222           0 :             DeInit();
     223             :         else
     224             :         {
     225           0 :             SANE_Status nStatus = p_init( &nVersion, 0 );
     226           0 :             FAIL_SHUTDOWN_STATE( nStatus, "sane_init", );
     227             :             nStatus = p_get_devices( (const SANE_Device***)&ppDevices,
     228           0 :                                      SANE_FALSE );
     229           0 :             FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", );
     230           0 :             for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ;
     231             :         }
     232           0 :     }
     233             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
     234             :     else
     235             :         fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION,
     236             :                  dlerror() );
     237             : #endif
     238             : }
     239             : 
     240           0 : void Sane::DeInit()
     241             : {
     242           0 :     if( pSaneLib )
     243             :     {
     244           0 :         p_exit();
     245           0 :         osl_unloadModule( pSaneLib );
     246           0 :         pSaneLib = 0;
     247             :     }
     248           0 : }
     249             : 
     250           0 : void Sane::ReloadDevices()
     251             : {
     252           0 :     if( IsOpen() )
     253           0 :         Close();
     254           0 :     DeInit();
     255           0 :     Init();
     256           0 : }
     257             : 
     258           0 : void Sane::ReloadOptions()
     259             : {
     260           0 :     if( ! IsOpen() )
     261           0 :         return;
     262             : 
     263           0 :     const SANE_Option_Descriptor* pZero = p_get_option_descriptor( maHandle, 0 );
     264             :     SANE_Word pOptions[2];
     265             :     SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE,
     266           0 :                                             (void*)pOptions, NULL );
     267           0 :     if( nStatus != SANE_STATUS_GOOD )
     268           0 :         fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) );
     269             : 
     270           0 :     mnOptions = pOptions[ 0 ];
     271           0 :     if( (size_t)pZero->size > sizeof( SANE_Word ) )
     272           0 :         fprintf( stderr, "driver returned numer of options with larger size tha SANE_Word !!!\n" );
     273           0 :     if( mppOptions )
     274           0 :         delete [] mppOptions;
     275           0 :     mppOptions = new const SANE_Option_Descriptor*[ mnOptions ];
     276           0 :     mppOptions[ 0 ] = pZero;
     277           0 :     for( int i = 1; i < mnOptions; i++ )
     278           0 :         mppOptions[ i ] =  (SANE_Option_Descriptor*)
     279           0 :             p_get_option_descriptor( maHandle, i );
     280             : 
     281           0 :     CheckConsistency( NULL, sal_True );
     282             : 
     283           0 :     maReloadOptionsLink.Call( this );
     284             : }
     285             : 
     286           0 : sal_Bool Sane::Open( const char* name )
     287             : {
     288           0 :     SANE_Status nStatus = p_open( (SANE_String_Const)name, &maHandle );
     289           0 :     FAIL_STATE( nStatus, "sane_open", sal_False );
     290             : 
     291           0 :     ReloadOptions();
     292             : 
     293           0 :     if( mnDevice == -1 )
     294             :     {
     295           0 :         rtl::OString aDevice( name );
     296           0 :         for( int i = 0; i < nDevices; i++ )
     297             :         {
     298           0 :             if( aDevice.equals( ppDevices[i]->name ) )
     299             :             {
     300           0 :                 mnDevice = i;
     301           0 :                 break;
     302             :             }
     303           0 :         }
     304             :     }
     305             : 
     306           0 :     return sal_True;
     307             : }
     308             : 
     309           0 : sal_Bool Sane::Open( int n )
     310             : {
     311           0 :     if( n >= 0 && n < nDevices )
     312             :     {
     313           0 :         mnDevice = n;
     314           0 :         return Open( (char*)ppDevices[n]->name );
     315             :     }
     316           0 :     return sal_False;
     317             : }
     318             : 
     319           0 : void Sane::Close()
     320             : {
     321           0 :     if( maHandle )
     322             :     {
     323           0 :         p_close( maHandle );
     324           0 :         delete [] mppOptions;
     325           0 :         mppOptions = 0;
     326           0 :         maHandle = 0;
     327           0 :         mnDevice = -1;
     328             :     }
     329           0 : }
     330             : 
     331           0 : int Sane::GetOptionByName( const char* rName )
     332             : {
     333             :     int i;
     334           0 :     rtl::OString aOption( rName );
     335           0 :     for( i = 0; i < mnOptions; i++ )
     336             :     {
     337           0 :         if( mppOptions[i]->name && aOption.equals( mppOptions[i]->name ) )
     338           0 :             return i;
     339             :     }
     340           0 :     return -1;
     341             : }
     342             : 
     343           0 : sal_Bool Sane::GetOptionValue( int n, sal_Bool& rRet )
     344             : {
     345           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_BOOL )
     346           0 :         return sal_False;
     347             :     SANE_Word nRet;
     348           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet );
     349           0 :     if( nStatus != SANE_STATUS_GOOD )
     350           0 :         return sal_False;
     351             : 
     352           0 :     rRet = nRet;
     353           0 :     return sal_True;
     354             : }
     355             : 
     356           0 : sal_Bool Sane::GetOptionValue( int n, rtl::OString& rRet )
     357             : {
     358           0 :     sal_Bool bSuccess = sal_False;
     359           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_STRING )
     360           0 :         return sal_False;
     361           0 :     char* pRet = new char[mppOptions[n]->size+1];
     362           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet );
     363           0 :     if( nStatus == SANE_STATUS_GOOD )
     364             :     {
     365           0 :         bSuccess = sal_True;
     366           0 :         rRet = pRet;
     367             :     }
     368           0 :     delete [] pRet;
     369           0 :     return bSuccess;
     370             : }
     371             : 
     372           0 : sal_Bool Sane::GetOptionValue( int n, double& rRet, int nElement )
     373             : {
     374           0 :     sal_Bool bSuccess = sal_False;
     375             : 
     376           0 :     if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT &&
     377           0 :                           mppOptions[n]->type != SANE_TYPE_FIXED ) )
     378           0 :         return sal_False;
     379             : 
     380           0 :     SANE_Word* pRet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
     381           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet );
     382           0 :     if( nStatus == SANE_STATUS_GOOD )
     383             :     {
     384           0 :         bSuccess = sal_True;
     385           0 :         if( mppOptions[n]->type == SANE_TYPE_INT )
     386           0 :             rRet = (double)pRet[ nElement ];
     387             :         else
     388           0 :             rRet = SANE_UNFIX( pRet[nElement] );
     389             :     }
     390           0 :     delete [] pRet;
     391           0 :     return bSuccess;
     392             : }
     393             : 
     394           0 : sal_Bool Sane::GetOptionValue( int n, double* pSet )
     395             : {
     396           0 :     if( ! maHandle  || ! ( mppOptions[n]->type == SANE_TYPE_FIXED ||
     397           0 :                            mppOptions[n]->type == SANE_TYPE_INT ) )
     398           0 :         return sal_False;
     399             : 
     400           0 :     SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
     401           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet );
     402           0 :     if( nStatus != SANE_STATUS_GOOD )
     403             :     {
     404           0 :         delete [] pFixedSet;
     405           0 :         return sal_False;
     406             :     }
     407           0 :     for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ )
     408             :     {
     409           0 :         if( mppOptions[n]->type == SANE_TYPE_FIXED )
     410           0 :             pSet[i] = SANE_UNFIX( pFixedSet[i] );
     411             :         else
     412           0 :             pSet[i] = (double) pFixedSet[i];
     413             :     }
     414           0 :     delete [] pFixedSet;
     415           0 :     return sal_True;
     416             : }
     417             : 
     418           0 : sal_Bool Sane::SetOptionValue( int n, sal_Bool bSet )
     419             : {
     420           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_BOOL )
     421           0 :         return sal_False;
     422           0 :     SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE;
     423           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nRet );
     424           0 :     if( nStatus != SANE_STATUS_GOOD )
     425           0 :         return sal_False;
     426           0 :     return sal_True;
     427             : }
     428             : 
     429           0 : sal_Bool Sane::SetOptionValue( int n, const String& rSet )
     430             : {
     431           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_STRING )
     432           0 :         return sal_False;
     433           0 :     rtl::OString aSet(rtl::OUStringToOString(rSet, osl_getThreadTextEncoding()));
     434           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, (void*)aSet.getStr() );
     435           0 :     if( nStatus != SANE_STATUS_GOOD )
     436           0 :         return sal_False;
     437           0 :     return sal_True;
     438             : }
     439             : 
     440           0 : sal_Bool Sane::SetOptionValue( int n, double fSet, int nElement )
     441             : {
     442           0 :     sal_Bool bSuccess = sal_False;
     443             : 
     444           0 :     if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT &&
     445           0 :                           mppOptions[n]->type != SANE_TYPE_FIXED ) )
     446           0 :         return sal_False;
     447             : 
     448             :     SANE_Status nStatus;
     449           0 :     if( mppOptions[n]->size/sizeof(SANE_Word) > 1 )
     450             :     {
     451           0 :         SANE_Word* pSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
     452           0 :         nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet );
     453           0 :         if( nStatus == SANE_STATUS_GOOD )
     454             :         {
     455           0 :             pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ?
     456           0 :                 (SANE_Word)fSet : SANE_FIX( fSet );
     457           0 :             nStatus = ControlOption(  n, SANE_ACTION_SET_VALUE, pSet );
     458             :         }
     459           0 :         delete [] pSet;
     460             :     }
     461             :     else
     462             :     {
     463             :         SANE_Word nSetTo =
     464           0 :             mppOptions[n]->type == SANE_TYPE_INT ?
     465           0 :             (SANE_Word)fSet : SANE_FIX( fSet );
     466             : 
     467           0 :         nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo );
     468           0 :         if( nStatus == SANE_STATUS_GOOD )
     469           0 :             bSuccess = sal_True;
     470             :     }
     471           0 :     return bSuccess;
     472             : }
     473             : 
     474           0 : sal_Bool Sane::SetOptionValue( int n, double* pSet )
     475             : {
     476           0 :     if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT &&
     477           0 :                           mppOptions[n]->type != SANE_TYPE_FIXED ) )
     478           0 :         return sal_False;
     479           0 :     SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
     480           0 :     for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ )
     481             :     {
     482           0 :         if( mppOptions[n]->type == SANE_TYPE_FIXED )
     483           0 :             pFixedSet[i] = SANE_FIX( pSet[i] );
     484             :         else
     485           0 :             pFixedSet[i] = (SANE_Word)pSet[i];
     486             :     }
     487           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet );
     488           0 :     delete [] pFixedSet;
     489           0 :     if( nStatus != SANE_STATUS_GOOD )
     490           0 :         return sal_False;
     491           0 :     return sal_True;
     492             : }
     493             : 
     494             : enum FrameStyleType {
     495             :     FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated
     496             : };
     497             : 
     498             : #define BYTE_BUFFER_SIZE 32768
     499             : 
     500           0 : static inline sal_uInt8 _ReadValue( FILE* fp, int depth )
     501             : {
     502           0 :     if( depth == 16 )
     503             :     {
     504             :         sal_uInt16 nWord;
     505             :         // data always come in native byte order !
     506             :         // 16 bits is not really supported by backends as of now
     507             :         // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN
     508             :         // against SANE documentation (xscanimage gets the same result
     509             :         // as we do
     510           0 :         size_t items_read = fread( &nWord, 1, 2, fp );
     511             : 
     512           0 :         if (items_read != 2)
     513             :         {
     514             :              SAL_WARN( "extensions.scanner", "short read, abandoning" );
     515           0 :              return 0;
     516             :         }
     517             : 
     518           0 :         return (sal_uInt8)( nWord / 256 );
     519             :     }
     520             :     sal_uInt8 nByte;
     521           0 :     size_t items_read = fread( &nByte, 1, 1, fp );
     522           0 :     if (items_read != 1)
     523             :     {
     524             :         SAL_WARN( "extensions.scanner", "short read, abandoning" );
     525           0 :         return 0;
     526             :     }
     527           0 :     return nByte;
     528             : }
     529             : 
     530           0 : sal_Bool Sane::CheckConsistency( const char* pMes, sal_Bool bInit )
     531             : {
     532             :     static const SANE_Option_Descriptor** pDescArray = NULL;
     533             :     static const SANE_Option_Descriptor*  pZero = NULL;
     534             : 
     535           0 :     if( bInit )
     536             :     {
     537           0 :         pDescArray = mppOptions;
     538           0 :         if( mppOptions )
     539           0 :             pZero = mppOptions[0];
     540           0 :         return sal_True;
     541             :     }
     542             : 
     543           0 :     sal_Bool bConsistent = sal_True;
     544             : 
     545           0 :     if( pDescArray != mppOptions )
     546           0 :         bConsistent = sal_False;
     547           0 :     if( pZero != mppOptions[0] )
     548           0 :         bConsistent = sal_False;
     549             : 
     550           0 :     if( ! bConsistent )
     551           0 :         dbg_msg( "Sane is not consistent. (%s)\n", pMes );
     552             : 
     553           0 :     return bConsistent;
     554             : }
     555             : 
     556           0 : sal_Bool Sane::Start( BitmapTransporter& rBitmap )
     557             : {
     558           0 :     int nStream = 0, nLine = 0, i = 0;
     559             :     SANE_Parameters aParams;
     560           0 :     FrameStyleType eType = FrameStyle_Gray;
     561           0 :     sal_Bool bSuccess = sal_True;
     562           0 :     sal_Bool bWidthSet = sal_False;
     563             : 
     564           0 :     if( ! maHandle )
     565           0 :         return sal_False;
     566             : 
     567           0 :     int nWidthMM    = 0;
     568           0 :     int nHeightMM   = 0;
     569           0 :     double fTLx, fTLy, fBRx, fBRy, fResl = 0.0;
     570             :     int nOption;
     571           0 :     if( ( nOption = GetOptionByName( "tl-x" ) ) != -1   &&
     572           0 :         GetOptionValue( nOption, fTLx, 0 )              &&
     573           0 :         GetOptionUnit( nOption ) == SANE_UNIT_MM )
     574             :     {
     575           0 :         if( ( nOption = GetOptionByName( "br-x" ) ) != -1   &&
     576           0 :             GetOptionValue( nOption, fBRx, 0 )              &&
     577           0 :             GetOptionUnit( nOption ) == SANE_UNIT_MM )
     578             :         {
     579           0 :             nWidthMM = (int)fabs(fBRx - fTLx);
     580             :         }
     581             :     }
     582           0 :     if( ( nOption = GetOptionByName( "tl-y" ) ) != -1   &&
     583           0 :         GetOptionValue( nOption, fTLy, 0 )              &&
     584           0 :         GetOptionUnit( nOption ) == SANE_UNIT_MM )
     585             :     {
     586           0 :         if( ( nOption = GetOptionByName( "br-y" ) ) != -1   &&
     587           0 :             GetOptionValue( nOption, fBRy, 0 )              &&
     588           0 :             GetOptionUnit( nOption ) == SANE_UNIT_MM )
     589             :         {
     590           0 :             nHeightMM = (int)fabs(fBRy - fTLy);
     591             :         }
     592             :     }
     593           0 :     if( ( nOption = GetOptionByName( "resolution" ) ) != -1 )
     594           0 :         GetOptionValue( nOption, fResl );
     595             : 
     596           0 :     sal_uInt8* pBuffer = NULL;
     597             : 
     598           0 :     SANE_Status nStatus = SANE_STATUS_GOOD;
     599             : 
     600           0 :     rBitmap.lock();
     601           0 :     SvMemoryStream& aConverter = rBitmap.getStream();
     602           0 :     aConverter.Seek( 0 );
     603           0 :     aConverter.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
     604             : 
     605             :     // write bitmap stream header
     606           0 :     aConverter << 'B' << 'M';
     607           0 :     aConverter << (sal_uInt32) 0;
     608           0 :     aConverter << (sal_uInt32) 0;
     609           0 :     aConverter << (sal_uInt32) 60;
     610             : 
     611             :     // write BITMAPINFOHEADER
     612           0 :     aConverter << (sal_uInt32)40;
     613           0 :     aConverter << (sal_uInt32)0; // fill in width later
     614           0 :     aConverter << (sal_uInt32)0; // fill in height later
     615           0 :     aConverter << (sal_uInt16)1;
     616             :     // create header for 24 bits
     617             :     // correct later if necessary
     618           0 :     aConverter << (sal_uInt16)24;
     619           0 :     aConverter << (sal_uInt32)0;
     620           0 :     aConverter << (sal_uInt32)0;
     621           0 :     aConverter << (sal_uInt32)0;
     622           0 :     aConverter << (sal_uInt32)0;
     623           0 :     aConverter << (sal_uInt32)0;
     624           0 :     aConverter << (sal_uInt32)0;
     625             : 
     626           0 :     for( nStream=0; nStream < 3 && bSuccess ; nStream++ )
     627             :     {
     628           0 :         nStatus = p_start( maHandle );
     629             :         DUMP_STATE( nStatus, "sane_start" );
     630           0 :         CheckConsistency( "sane_start" );
     631           0 :         if( nStatus == SANE_STATUS_GOOD )
     632             :         {
     633           0 :             nStatus = p_get_parameters( maHandle, &aParams );
     634             :             DUMP_STATE( nStatus, "sane_get_parameters" );
     635           0 :             CheckConsistency( "sane_get_parameters" );
     636           0 :             if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0)
     637             :             {
     638           0 :                 bSuccess = sal_False;
     639             :                 break;
     640             :             }
     641             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
     642             :             const char* ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB",
     643             :                                   "SANE_FRAME_RED", "SANE_FRAME_GREEN",
     644             :                                   "SANE_FRAME_BLUE", "Unknown !!!" };
     645             :             fprintf( stderr, "Parameters for frame %d:\n", nStream );
     646             :             if( aParams.format < 0 || aParams.format > 4 )
     647             :                 aParams.format = (SANE_Frame)5;
     648             :             fprintf( stderr, "format:           %s\n", ppFormats[ (int)aParams.format ] );
     649             :             fprintf( stderr, "last_frame:       %s\n", aParams.last_frame ? "TRUE" : "FALSE" );
     650             :             fprintf( stderr, "depth:            %d\n", (int)aParams.depth );
     651             :             fprintf( stderr, "pixels_per_line:  %d\n", (int)aParams.pixels_per_line );
     652             :             fprintf( stderr, "bytes_per_line:   %d\n", (int)aParams.bytes_per_line );
     653             : #endif
     654           0 :             if( ! pBuffer )
     655             :             {
     656           0 :                 pBuffer = new sal_uInt8[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ];
     657             :             }
     658             : 
     659           0 :             if( aParams.last_frame )
     660           0 :                 nStream=3;
     661             : 
     662           0 :             switch( aParams.format )
     663             :             {
     664             :                 case SANE_FRAME_GRAY:
     665           0 :                     eType = FrameStyle_Gray;
     666           0 :                     if( aParams.depth == 1 )
     667           0 :                         eType = FrameStyle_BW;
     668           0 :                     break;
     669             :                 case SANE_FRAME_RGB:
     670           0 :                     eType = FrameStyle_RGB;
     671           0 :                     break;
     672             :                 case SANE_FRAME_RED:
     673             :                 case SANE_FRAME_GREEN:
     674             :                 case SANE_FRAME_BLUE:
     675           0 :                     eType = FrameStyle_Separated;
     676           0 :                     break;
     677             :                 default:
     678           0 :                     fprintf( stderr, "Warning: unknown frame style !!!\n" );
     679             :             }
     680             : 
     681           0 :             sal_Bool bSynchronousRead = sal_True;
     682             : 
     683             :             // should be fail safe, but ... ??
     684           0 :             nStatus = p_set_io_mode( maHandle, SANE_FALSE );
     685           0 :             CheckConsistency( "sane_set_io_mode" );
     686           0 :             if( nStatus != SANE_STATUS_GOOD )
     687             :             {
     688           0 :                 bSynchronousRead = sal_False;
     689           0 :                 nStatus = p_set_io_mode( maHandle, SANE_TRUE );
     690           0 :                 CheckConsistency( "sane_set_io_mode" );
     691             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
     692             :                 if( nStatus != SANE_STATUS_GOOD )
     693             :                     // what ?!?
     694             :                     fprintf( stderr, "Sane::Start: driver is confused\n" );
     695             : #endif
     696             :             }
     697             : 
     698           0 :             SANE_Int nLen=0;
     699           0 :             SANE_Int fd = 0;
     700             : 
     701           0 :             if( ! bSynchronousRead )
     702             :             {
     703           0 :                 nStatus = p_get_select_fd( maHandle, &fd );
     704             :                 DUMP_STATE( nStatus, "sane_get_select_fd" );
     705           0 :                 CheckConsistency( "sane_get_select_fd" );
     706           0 :                 if( nStatus != SANE_STATUS_GOOD )
     707           0 :                     bSynchronousRead = sal_True;
     708             :             }
     709           0 :             FILE* pFrame = tmpfile();
     710           0 :             if( ! pFrame )
     711             :             {
     712           0 :                 bSuccess = sal_False;
     713             :                 break;
     714             :             }
     715           0 :             do {
     716           0 :                 if( ! bSynchronousRead )
     717             :                 {
     718             :                     fd_set fdset;
     719             :                     struct timeval tv;
     720             : 
     721           0 :                     FD_ZERO( &fdset );
     722           0 :                     FD_SET( (int)fd, &fdset );
     723           0 :                     tv.tv_sec = 5;
     724           0 :                     tv.tv_usec = 0;
     725           0 :                     if( select( fd+1, &fdset, NULL, NULL, &tv ) == 0 )
     726           0 :                         fprintf( stderr, "Timout on sane_read descriptor\n" );
     727             :                 }
     728           0 :                 nLen = 0;
     729           0 :                 nStatus = p_read( maHandle, pBuffer, BYTE_BUFFER_SIZE, &nLen );
     730           0 :                 CheckConsistency( "sane_read" );
     731           0 :                 if( nLen && ( nStatus == SANE_STATUS_GOOD ||
     732             :                               nStatus == SANE_STATUS_EOF ) )
     733             :                 {
     734           0 :                     bSuccess = (static_cast<size_t>(nLen) == fwrite( pBuffer, 1, nLen, pFrame ));
     735           0 :                     if (!bSuccess)
     736           0 :                         break;
     737             :                 }
     738             :                 else
     739             :                     DUMP_STATE( nStatus, "sane_read" );
     740             :             } while( nStatus == SANE_STATUS_GOOD );
     741           0 :             if (nStatus != SANE_STATUS_EOF || !bSuccess)
     742             :             {
     743           0 :                 fclose( pFrame );
     744           0 :                 bSuccess = sal_False;
     745             :                 break;
     746             :             }
     747             : 
     748           0 :             int nFrameLength = ftell( pFrame );
     749           0 :             fseek( pFrame, 0, SEEK_SET );
     750           0 :             sal_uInt32 nWidth = (sal_uInt32) aParams.pixels_per_line;
     751           0 :             sal_uInt32 nHeight = (sal_uInt32) (nFrameLength / aParams.bytes_per_line);
     752           0 :             if( ! bWidthSet )
     753             :             {
     754           0 :                 if( ! fResl )
     755           0 :                     fResl = 300; // if all else fails that's a good guess
     756           0 :                 if( ! nWidthMM )
     757           0 :                     nWidthMM = (int)(((double)nWidth / fResl) * 25.4);
     758           0 :                 if( ! nHeightMM )
     759           0 :                     nHeightMM = (int)(((double)nHeight / fResl) * 25.4);
     760             : #if OSL_DEBUG_LEVEL > 1
     761             :                 fprintf( stderr, "set dimensions to (%d, %d) Pixel, (%d, %d) mm, resolution is %lg\n", (int)nWidth, (int)nHeight, (int)nWidthMM, (int)nHeightMM, fResl );
     762             : #endif
     763             : 
     764           0 :                 aConverter.Seek( 18 );
     765           0 :                 aConverter << (sal_uInt32)nWidth;
     766           0 :                 aConverter << (sal_uInt32)nHeight;
     767           0 :                 aConverter.Seek( 38 );
     768           0 :                 aConverter << (sal_uInt32)(1000*nWidth/nWidthMM);
     769           0 :                 aConverter << (sal_uInt32)(1000*nHeight/nHeightMM);
     770           0 :                 bWidthSet = sal_True;
     771             :             }
     772           0 :             aConverter.Seek(60);
     773             : 
     774           0 :             if( eType == FrameStyle_BW )
     775             :             {
     776           0 :                 aConverter.Seek( 10 );
     777           0 :                 aConverter << (sal_uInt32)64;
     778           0 :                 aConverter.Seek( 28 );
     779           0 :                 aConverter << (sal_uInt16) 1;
     780           0 :                 aConverter.Seek( 54 );
     781             :                 // write color table
     782           0 :                 aConverter << (sal_uInt16)0xffff;
     783           0 :                 aConverter << (sal_uInt8)0xff;
     784           0 :                 aConverter << (sal_uInt8)0;
     785           0 :                 aConverter << (sal_uInt32)0;
     786           0 :                 aConverter.Seek( 64 );
     787             :             }
     788           0 :             else if( eType == FrameStyle_Gray )
     789             :             {
     790           0 :                  aConverter.Seek( 10 );
     791           0 :                  aConverter << (sal_uInt32)1084;
     792           0 :                 aConverter.Seek( 28 );
     793           0 :                 aConverter << (sal_uInt16) 8;
     794           0 :                 aConverter.Seek( 54 );
     795             :                 // write color table
     796           0 :                 for( nLine = 0; nLine < 256; nLine++ )
     797             :                 {
     798           0 :                     aConverter << (sal_uInt8)nLine;
     799           0 :                     aConverter << (sal_uInt8)nLine;
     800           0 :                     aConverter << (sal_uInt8)nLine;
     801           0 :                     aConverter << (sal_uInt8)0;
     802             :                 }
     803           0 :                 aConverter.Seek( 1084 );
     804             :             }
     805             : 
     806           0 :             for (nLine = nHeight-1; nLine >= 0; --nLine)
     807             :             {
     808           0 :                 fseek( pFrame, nLine * aParams.bytes_per_line, SEEK_SET );
     809           0 :                 if( eType == FrameStyle_BW ||
     810             :                     ( eType == FrameStyle_Gray && aParams.depth == 8 )
     811             :                     )
     812             :                 {
     813           0 :                     SANE_Int items_read = fread( pBuffer, 1, aParams.bytes_per_line, pFrame );
     814           0 :                     if (items_read != aParams.bytes_per_line)
     815             :                     {
     816             :                         SAL_WARN( "extensions.scanner", "short read, padding with zeros" );
     817           0 :                         memset(pBuffer + items_read, 0, aParams.bytes_per_line - items_read);
     818             :                     }
     819           0 :                     aConverter.Write( pBuffer, aParams.bytes_per_line );
     820             :                 }
     821           0 :                 else if( eType == FrameStyle_Gray )
     822             :                 {
     823           0 :                     for( i = 0; i < (aParams.pixels_per_line); i++ )
     824             :                     {
     825           0 :                         sal_uInt8 nGray = _ReadValue( pFrame, aParams.depth );
     826           0 :                         aConverter << nGray;
     827             :                     }
     828             :                 }
     829           0 :                 else if( eType == FrameStyle_RGB )
     830             :                 {
     831           0 :                     for( i = 0; i < (aParams.pixels_per_line); i++ )
     832             :                     {
     833             :                         sal_uInt8 nRed, nGreen, nBlue;
     834           0 :                         nRed    = _ReadValue( pFrame, aParams.depth );
     835           0 :                         nGreen  = _ReadValue( pFrame, aParams.depth );
     836           0 :                         nBlue   = _ReadValue( pFrame, aParams.depth );
     837           0 :                         aConverter << nBlue;
     838           0 :                         aConverter << nGreen;
     839           0 :                         aConverter << nRed;
     840             :                     }
     841             :                 }
     842           0 :                 else if( eType == FrameStyle_Separated )
     843             :                 {
     844           0 :                     for( i = 0; i < (aParams.pixels_per_line); i++ )
     845             :                     {
     846           0 :                         sal_uInt8 nValue = _ReadValue( pFrame, aParams.depth );
     847           0 :                         switch( aParams.format )
     848             :                         {
     849             :                             case SANE_FRAME_RED:
     850           0 :                                 aConverter.SeekRel( 2 );
     851           0 :                                 aConverter << nValue;
     852           0 :                                 break;
     853             :                             case SANE_FRAME_GREEN:
     854           0 :                                 aConverter.SeekRel( 1 );
     855           0 :                                 aConverter << nValue;
     856           0 :                                 aConverter.SeekRel( 1 );
     857           0 :                                 break;
     858             :                             case SANE_FRAME_BLUE:
     859           0 :                                 aConverter << nValue;
     860           0 :                                 aConverter.SeekRel( 2 );
     861           0 :                                 break;
     862             :                             case SANE_FRAME_GRAY:
     863             :                             case SANE_FRAME_RGB:
     864           0 :                                 break;
     865             :                         }
     866             :                     }
     867             :                 }
     868           0 :                  int nGap = aConverter.Tell() & 3;
     869           0 :                  if( nGap )
     870           0 :                      aConverter.SeekRel( 4-nGap );
     871             :             }
     872           0 :             fclose( pFrame ); // deletes tmpfile
     873           0 :             if( eType != FrameStyle_Separated )
     874             :                 break;
     875             :         }
     876             :         else
     877           0 :             bSuccess = sal_False;
     878             :     }
     879             :     // get stream length
     880           0 :     aConverter.Seek( STREAM_SEEK_TO_END );
     881           0 :     int nPos = aConverter.Tell();
     882             : 
     883           0 :     aConverter.Seek( 2 );
     884           0 :     aConverter << (sal_uInt32) nPos+1;
     885           0 :     aConverter.Seek( 0 );
     886             : 
     887           0 :     rBitmap.unlock();
     888             : 
     889           0 :     if( bSuccess )
     890             :     {
     891             :         // only cancel a successful operation
     892             :         // sane disrupts memory else
     893           0 :         p_cancel( maHandle );
     894           0 :         CheckConsistency( "sane_cancel" );
     895             :     }
     896           0 :     if( pBuffer )
     897           0 :         delete [] pBuffer;
     898             : 
     899           0 :     ReloadOptions();
     900             : 
     901             : 
     902           0 :     dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" );
     903             : 
     904           0 :     return bSuccess;
     905             : }
     906             : 
     907           0 : int Sane::GetRange( int n, double*& rpDouble )
     908             : {
     909           0 :     if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE &&
     910           0 :         mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST )
     911             :     {
     912           0 :         return -1;
     913             :     }
     914             : 
     915           0 :     rpDouble = 0;
     916             :     int nItems, i;
     917           0 :     sal_Bool bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED ? sal_True : sal_False;
     918             : 
     919           0 :     dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name );
     920           0 :     if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE )
     921             :     {
     922             :         double fMin, fMax, fQuant;
     923           0 :         if( bIsFixed )
     924             :         {
     925           0 :             fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min );
     926           0 :             fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max );
     927           0 :             fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant );
     928             :         }
     929             :         else
     930             :         {
     931           0 :             fMin = (double)mppOptions[n]->constraint.range->min;
     932           0 :             fMax = (double)mppOptions[n]->constraint.range->max;
     933           0 :             fQuant = (double)mppOptions[n]->constraint.range->quant;
     934             :         }
     935           0 :         if( fQuant != 0.0 )
     936             :         {
     937             :             dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n",
     938           0 :                      fMin, fQuant, fMax );
     939           0 :             nItems = (int)((fMax - fMin)/fQuant)+1;
     940           0 :             rpDouble = new double[ nItems ];
     941           0 :             double fValue = fMin;
     942           0 :             for( i = 0; i < nItems; i++, fValue += fQuant )
     943           0 :                 rpDouble[i] = fValue;
     944           0 :             rpDouble[ nItems-1 ] = fMax;
     945           0 :             return nItems;
     946             :         }
     947             :         else
     948             :         {
     949             :             dbg_msg( "normal range [ %lg %lg ]\n",
     950           0 :                      fMin, fMax );
     951           0 :             rpDouble = new double[2];
     952           0 :             rpDouble[0] = fMin;
     953           0 :             rpDouble[1] = fMax;
     954           0 :             return 0;
     955             :         }
     956             :     }
     957             :     else
     958             :     {
     959           0 :         nItems = mppOptions[n]->constraint.word_list[0];
     960           0 :         rpDouble = new double[nItems];
     961           0 :         for( i=0; i<nItems; i++ )
     962             :         {
     963           0 :             rpDouble[i] = bIsFixed ?
     964           0 :                 SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) :
     965           0 :                 (double)mppOptions[n]->constraint.word_list[i+1];
     966             :         }
     967             :         dbg_msg( "wordlist [ %lg ... %lg ]\n",
     968           0 :                  rpDouble[ 0 ], rpDouble[ nItems-1 ] );
     969           0 :         return nItems;
     970             :     }
     971             : }
     972             : 
     973             : static const char *ppUnits[] = {
     974             :     "",
     975             :     "[Pixel]",
     976             :     "[Bit]",
     977             :     "[mm]",
     978             :     "[DPI]",
     979             :     "[%]",
     980             :     "[usec]"
     981             : };
     982             : 
     983           0 : String Sane::GetOptionUnitName( int n )
     984             : {
     985           0 :     String aText;
     986           0 :     SANE_Unit nUnit = mppOptions[n]->unit;
     987           0 :     size_t nUnitAsSize = (size_t)nUnit;
     988           0 :     if (nUnitAsSize >= SAL_N_ELEMENTS( ppUnits ))
     989           0 :         aText = rtl::OUString("[unknown units]");
     990             :     else
     991           0 :         aText = String( ppUnits[ nUnit ], osl_getThreadTextEncoding() );
     992           0 :     return aText;
     993             : }
     994             : 
     995           0 : sal_Bool Sane::ActivateButtonOption( int n )
     996             : {
     997           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, NULL );
     998           0 :     if( nStatus != SANE_STATUS_GOOD )
     999           0 :         return sal_False;
    1000           0 :     return sal_True;
    1001             : }
    1002             : 
    1003             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10