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

Generated by: LCOV version 1.11