LCOV - code coverage report
Current view: top level - extensions/source/scanner - sane.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 495 0.2 %
Date: 2014-11-03 Functions: 2 29 6.9 %
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             : #include <boost/scoped_array.hpp>
      33             : 
      34             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
      35             : #include <stdarg.h>
      36             : #define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d );
      37             : #else
      38             : #define dump_state( a, b, c, d ) ;
      39             : #endif
      40           0 : inline void dbg_msg( const char* pString, ... )
      41             : {
      42             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
      43             :     va_list ap;
      44             :     va_start( ap, pString );
      45             :     vfprintf( stderr, pString, ap );
      46             :     va_end( ap );
      47             : #else
      48             :     (void)pString;
      49             : #endif
      50           0 : }
      51             : 
      52             : #define FAIL_SHUTDOWN_STATE( x, y, z ) \
      53             :     if( x != SANE_STATUS_GOOD )                             \
      54             :     {                                                       \
      55             :         dump_state( "%s returned error %d (%s)\n",          \
      56             :                  y, x, p_strstatus( x ) );                  \
      57             :         DeInit();                                           \
      58             :         return z;                                           \
      59             :     }
      60             : 
      61             : #define FAIL_STATE( x, y, z ) \
      62             :     if( x != SANE_STATUS_GOOD )                             \
      63             :     {                                                       \
      64             :         dump_state( "%s returned error %d (%s)\n",          \
      65             :                  y, x, p_strstatus( x ) );                  \
      66             :         return z;                                           \
      67             :     }
      68             : 
      69             : #define DUMP_STATE( x, y ) \
      70             :     if( x != SANE_STATUS_GOOD )                             \
      71             :     {                                                       \
      72             :         dump_state( "%s returned error %d (%s)\n",          \
      73             :                  y, x, p_strstatus( x ) );                  \
      74             :     }
      75             : 
      76             : int             Sane::nRefCount = 0;
      77             : oslModule       Sane::pSaneLib = 0;
      78             : SANE_Int        Sane::nVersion = 0;
      79             : SANE_Device**   Sane::ppDevices = 0;
      80             : int             Sane::nDevices = 0;
      81             : 
      82             : SANE_Status     (*Sane::p_init)( SANE_Int*,
      83             :                                  SANE_Auth_Callback ) = 0;
      84             : void            (*Sane::p_exit)() = 0;
      85             : SANE_Status     (*Sane::p_get_devices)( const SANE_Device***,
      86             :                                         SANE_Bool ) = 0;
      87             : SANE_Status     (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = 0;
      88             : void            (*Sane::p_close)( SANE_Handle ) = 0;
      89             : const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)(
      90             :     SANE_Handle, SANE_Int ) = 0;
      91             : SANE_Status     (*Sane::p_control_option)( SANE_Handle, SANE_Int,
      92             :                                            SANE_Action, void*,
      93             :                                            SANE_Int* ) = 0;
      94             : SANE_Status     (*Sane::p_get_parameters)( SANE_Handle,
      95             :                                            SANE_Parameters* ) = 0;
      96             : SANE_Status     (*Sane::p_start)( SANE_Handle ) = 0;
      97             : SANE_Status     (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int,
      98             :                                  SANE_Int* ) = 0;
      99             : void            (*Sane::p_cancel)( SANE_Handle ) = 0;
     100             : SANE_Status     (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = 0;
     101             : SANE_Status     (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = 0;
     102             : SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = 0;
     103             : 
     104             : static bool bSaneSymbolLoadFailed = false;
     105             : 
     106           0 : inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname )
     107             : {
     108           0 :     oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname );
     109           0 :     if( ! pFunction )
     110             :     {
     111             :         fprintf( stderr, "Could not load symbol %s\n",
     112           0 :                  pSymbolname );
     113           0 :         bSaneSymbolLoadFailed = true;
     114             :     }
     115           0 :     return pFunction;
     116             : }
     117             : 
     118           0 : SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction,
     119             :                                  void* pData )
     120             : {
     121           0 :     SANE_Int    nInfo = 0;
     122             : 
     123             :     SANE_Status 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             :                  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 :     OUString sSaneLibName( "libsane" SAL_DLLEXTENSION  );
     172           0 :     pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
     173           0 :     if( ! pSaneLib )
     174             :     {
     175           0 :         sSaneLibName = "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 :         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 = 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, true );
     282             : 
     283           0 :     maReloadOptionsLink.Call( this );
     284             : }
     285             : 
     286           0 : 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", false );
     290             : 
     291           0 :     ReloadOptions();
     292             : 
     293           0 :     if( mnDevice == -1 )
     294             :     {
     295           0 :         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 true;
     307             : }
     308             : 
     309           0 : 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 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 :     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 : bool Sane::GetOptionValue( int n, bool& rRet )
     344             : {
     345           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_BOOL )
     346           0 :         return 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 false;
     351             : 
     352           0 :     rRet = nRet;
     353           0 :     return true;
     354             : }
     355             : 
     356           0 : bool Sane::GetOptionValue( int n, OString& rRet )
     357             : {
     358           0 :     bool bSuccess = false;
     359           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_STRING )
     360           0 :         return false;
     361           0 :     boost::scoped_array<char> pRet(new char[mppOptions[n]->size+1]);
     362           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet.get() );
     363           0 :     if( nStatus == SANE_STATUS_GOOD )
     364             :     {
     365           0 :         bSuccess = true;
     366           0 :         rRet = pRet.get();
     367             :     }
     368           0 :     return bSuccess;
     369             : }
     370             : 
     371           0 : bool Sane::GetOptionValue( int n, double& rRet, int nElement )
     372             : {
     373           0 :     bool bSuccess = false;
     374             : 
     375           0 :     if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT &&
     376           0 :                           mppOptions[n]->type != SANE_TYPE_FIXED ) )
     377           0 :         return false;
     378             : 
     379           0 :     boost::scoped_array<SANE_Word> pRet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
     380           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet.get() );
     381           0 :     if( nStatus == SANE_STATUS_GOOD )
     382             :     {
     383           0 :         bSuccess = true;
     384           0 :         if( mppOptions[n]->type == SANE_TYPE_INT )
     385           0 :             rRet = (double)pRet[ nElement ];
     386             :         else
     387           0 :             rRet = SANE_UNFIX( pRet[nElement] );
     388             :     }
     389           0 :     return bSuccess;
     390             : }
     391             : 
     392           0 : bool Sane::GetOptionValue( int n, double* pSet )
     393             : {
     394           0 :     if( ! maHandle  || ! ( mppOptions[n]->type == SANE_TYPE_FIXED ||
     395           0 :                            mppOptions[n]->type == SANE_TYPE_INT ) )
     396           0 :         return false;
     397             : 
     398           0 :     boost::scoped_array<SANE_Word> pFixedSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
     399           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet.get() );
     400           0 :     if( nStatus != SANE_STATUS_GOOD )
     401           0 :         return false;
     402           0 :     for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ )
     403             :     {
     404           0 :         if( mppOptions[n]->type == SANE_TYPE_FIXED )
     405           0 :             pSet[i] = SANE_UNFIX( pFixedSet[i] );
     406             :         else
     407           0 :             pSet[i] = (double) pFixedSet[i];
     408             :     }
     409           0 :     return true;
     410             : }
     411             : 
     412           0 : bool Sane::SetOptionValue( int n, bool bSet )
     413             : {
     414           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_BOOL )
     415           0 :         return false;
     416           0 :     SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE;
     417           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nRet );
     418           0 :     if( nStatus != SANE_STATUS_GOOD )
     419           0 :         return false;
     420           0 :     return true;
     421             : }
     422             : 
     423           0 : bool Sane::SetOptionValue( int n, const OUString& rSet )
     424             : {
     425           0 :     if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_STRING )
     426           0 :         return false;
     427           0 :     OString aSet(OUStringToOString(rSet, osl_getThreadTextEncoding()));
     428           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, (void*)aSet.getStr() );
     429           0 :     if( nStatus != SANE_STATUS_GOOD )
     430           0 :         return false;
     431           0 :     return true;
     432             : }
     433             : 
     434           0 : bool Sane::SetOptionValue( int n, double fSet, int nElement )
     435             : {
     436           0 :     bool bSuccess = false;
     437             : 
     438           0 :     if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT &&
     439           0 :                           mppOptions[n]->type != SANE_TYPE_FIXED ) )
     440           0 :         return false;
     441             : 
     442             :     SANE_Status nStatus;
     443           0 :     if( mppOptions[n]->size/sizeof(SANE_Word) > 1 )
     444             :     {
     445           0 :         boost::scoped_array<SANE_Word> pSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
     446           0 :         nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet.get() );
     447           0 :         if( nStatus == SANE_STATUS_GOOD )
     448             :         {
     449           0 :             pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ?
     450           0 :                 (SANE_Word)fSet : SANE_FIX( fSet );
     451           0 :             nStatus = ControlOption(  n, SANE_ACTION_SET_VALUE, pSet.get() );
     452           0 :         }
     453             :     }
     454             :     else
     455             :     {
     456             :         SANE_Word nSetTo =
     457           0 :             mppOptions[n]->type == SANE_TYPE_INT ?
     458           0 :             (SANE_Word)fSet : SANE_FIX( fSet );
     459             : 
     460           0 :         nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo );
     461           0 :         if( nStatus == SANE_STATUS_GOOD )
     462           0 :             bSuccess = true;
     463             :     }
     464           0 :     return bSuccess;
     465             : }
     466             : 
     467           0 : bool Sane::SetOptionValue( int n, double* pSet )
     468             : {
     469           0 :     if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT &&
     470           0 :                           mppOptions[n]->type != SANE_TYPE_FIXED ) )
     471           0 :         return false;
     472           0 :     boost::scoped_array<SANE_Word> pFixedSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
     473           0 :     for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ )
     474             :     {
     475           0 :         if( mppOptions[n]->type == SANE_TYPE_FIXED )
     476           0 :             pFixedSet[i] = SANE_FIX( pSet[i] );
     477             :         else
     478           0 :             pFixedSet[i] = (SANE_Word)pSet[i];
     479             :     }
     480           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet.get() );
     481           0 :     if( nStatus != SANE_STATUS_GOOD )
     482           0 :         return false;
     483           0 :     return true;
     484             : }
     485             : 
     486             : enum FrameStyleType {
     487             :     FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated
     488             : };
     489             : 
     490             : #define BYTE_BUFFER_SIZE 32768
     491             : 
     492           0 : static inline sal_uInt8 _ReadValue( FILE* fp, int depth )
     493             : {
     494           0 :     if( depth == 16 )
     495             :     {
     496             :         sal_uInt16 nWord;
     497             :         // data always come in native byte order !
     498             :         // 16 bits is not really supported by backends as of now
     499             :         // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN
     500             :         // against SANE documentation (xscanimage gets the same result
     501             :         // as we do
     502           0 :         size_t items_read = fread( &nWord, 1, 2, fp );
     503             : 
     504           0 :         if (items_read != 2)
     505             :         {
     506             :              SAL_WARN( "extensions.scanner", "short read, abandoning" );
     507           0 :              return 0;
     508             :         }
     509             : 
     510           0 :         return (sal_uInt8)( nWord / 256 );
     511             :     }
     512             :     sal_uInt8 nByte;
     513           0 :     size_t items_read = fread( &nByte, 1, 1, fp );
     514           0 :     if (items_read != 1)
     515             :     {
     516             :         SAL_WARN( "extensions.scanner", "short read, abandoning" );
     517           0 :         return 0;
     518             :     }
     519           0 :     return nByte;
     520             : }
     521             : 
     522           0 : bool Sane::CheckConsistency( const char* pMes, bool bInit )
     523             : {
     524             :     static const SANE_Option_Descriptor** pDescArray = NULL;
     525             :     static const SANE_Option_Descriptor*  pZero = NULL;
     526             : 
     527           0 :     if( bInit )
     528             :     {
     529           0 :         pDescArray = mppOptions;
     530           0 :         if( mppOptions )
     531           0 :             pZero = mppOptions[0];
     532           0 :         return true;
     533             :     }
     534             : 
     535           0 :     bool bConsistent = true;
     536             : 
     537           0 :     if( pDescArray != mppOptions )
     538           0 :         bConsistent = false;
     539           0 :     if( pZero != mppOptions[0] )
     540           0 :         bConsistent = false;
     541             : 
     542           0 :     if( ! bConsistent )
     543           0 :         dbg_msg( "Sane is not consistent. (%s)\n", pMes );
     544             : 
     545           0 :     return bConsistent;
     546             : }
     547             : 
     548           0 : bool Sane::Start( BitmapTransporter& rBitmap )
     549             : {
     550           0 :     int nStream = 0, nLine = 0, i = 0;
     551             :     SANE_Parameters aParams;
     552           0 :     FrameStyleType eType = FrameStyle_Gray;
     553           0 :     bool bSuccess = true;
     554           0 :     bool bWidthSet = false;
     555             : 
     556           0 :     if( ! maHandle )
     557           0 :         return false;
     558             : 
     559           0 :     int nWidthMM    = 0;
     560           0 :     int nHeightMM   = 0;
     561           0 :     double fTLx, fTLy, fBRx, fBRy, fResl = 0.0;
     562             :     int nOption;
     563           0 :     if( ( nOption = GetOptionByName( "tl-x" ) ) != -1   &&
     564           0 :         GetOptionValue( nOption, fTLx, 0 )              &&
     565           0 :         GetOptionUnit( nOption ) == SANE_UNIT_MM )
     566             :     {
     567           0 :         if( ( nOption = GetOptionByName( "br-x" ) ) != -1   &&
     568           0 :             GetOptionValue( nOption, fBRx, 0 )              &&
     569           0 :             GetOptionUnit( nOption ) == SANE_UNIT_MM )
     570             :         {
     571           0 :             nWidthMM = (int)fabs(fBRx - fTLx);
     572             :         }
     573             :     }
     574           0 :     if( ( nOption = GetOptionByName( "tl-y" ) ) != -1   &&
     575           0 :         GetOptionValue( nOption, fTLy, 0 )              &&
     576           0 :         GetOptionUnit( nOption ) == SANE_UNIT_MM )
     577             :     {
     578           0 :         if( ( nOption = GetOptionByName( "br-y" ) ) != -1   &&
     579           0 :             GetOptionValue( nOption, fBRy, 0 )              &&
     580           0 :             GetOptionUnit( nOption ) == SANE_UNIT_MM )
     581             :         {
     582           0 :             nHeightMM = (int)fabs(fBRy - fTLy);
     583             :         }
     584             :     }
     585           0 :     if( ( nOption = GetOptionByName( "resolution" ) ) != -1 )
     586           0 :         (void)GetOptionValue( nOption, fResl );
     587             : 
     588           0 :     sal_uInt8* pBuffer = NULL;
     589             : 
     590           0 :     SANE_Status nStatus = SANE_STATUS_GOOD;
     591             : 
     592           0 :     rBitmap.lock();
     593           0 :     SvMemoryStream& aConverter = rBitmap.getStream();
     594           0 :     aConverter.Seek( 0 );
     595           0 :     aConverter.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
     596             : 
     597             :     // write bitmap stream header
     598           0 :     aConverter.WriteChar( 'B' ).WriteChar( 'M' );
     599           0 :     aConverter.WriteUInt32( 0 );
     600           0 :     aConverter.WriteUInt32( 0 );
     601           0 :     aConverter.WriteUInt32( 60 );
     602             : 
     603             :     // write BITMAPINFOHEADER
     604           0 :     aConverter.WriteUInt32( 40 );
     605           0 :     aConverter.WriteUInt32( 0 ); // fill in width later
     606           0 :     aConverter.WriteUInt32( 0 ); // fill in height later
     607           0 :     aConverter.WriteUInt16( 1 );
     608             :     // create header for 24 bits
     609             :     // correct later if necessary
     610           0 :     aConverter.WriteUInt16( 24 );
     611           0 :     aConverter.WriteUInt32( 0 );
     612           0 :     aConverter.WriteUInt32( 0 );
     613           0 :     aConverter.WriteUInt32( 0 );
     614           0 :     aConverter.WriteUInt32( 0 );
     615           0 :     aConverter.WriteUInt32( 0 );
     616           0 :     aConverter.WriteUInt32( 0 );
     617             : 
     618           0 :     for( nStream=0; nStream < 3 && bSuccess ; nStream++ )
     619             :     {
     620           0 :         nStatus = p_start( maHandle );
     621             :         DUMP_STATE( nStatus, "sane_start" );
     622           0 :         CheckConsistency( "sane_start" );
     623           0 :         if( nStatus == SANE_STATUS_GOOD )
     624             :         {
     625           0 :             nStatus = p_get_parameters( maHandle, &aParams );
     626             :             DUMP_STATE( nStatus, "sane_get_parameters" );
     627           0 :             CheckConsistency( "sane_get_parameters" );
     628           0 :             if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0)
     629             :             {
     630           0 :                 bSuccess = false;
     631           0 :                 break;
     632             :             }
     633             : #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
     634             :             const char* ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB",
     635             :                                   "SANE_FRAME_RED", "SANE_FRAME_GREEN",
     636             :                                   "SANE_FRAME_BLUE", "Unknown !!!" };
     637             :             fprintf( stderr, "Parameters for frame %d:\n", nStream );
     638             :             if( aParams.format < 0 || aParams.format > 4 )
     639             :                 aParams.format = (SANE_Frame)5;
     640             :             fprintf( stderr, "format:           %s\n", ppFormats[ (int)aParams.format ] );
     641             :             fprintf( stderr, "last_frame:       %s\n", aParams.last_frame ? "TRUE" : "FALSE" );
     642             :             fprintf( stderr, "depth:            %d\n", (int)aParams.depth );
     643             :             fprintf( stderr, "pixels_per_line:  %d\n", (int)aParams.pixels_per_line );
     644             :             fprintf( stderr, "bytes_per_line:   %d\n", (int)aParams.bytes_per_line );
     645             : #endif
     646           0 :             if( ! pBuffer )
     647             :             {
     648           0 :                 pBuffer = new sal_uInt8[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ];
     649             :             }
     650             : 
     651           0 :             if( aParams.last_frame )
     652           0 :                 nStream=3;
     653             : 
     654           0 :             switch( aParams.format )
     655             :             {
     656             :                 case SANE_FRAME_GRAY:
     657           0 :                     eType = FrameStyle_Gray;
     658           0 :                     if( aParams.depth == 1 )
     659           0 :                         eType = FrameStyle_BW;
     660           0 :                     break;
     661             :                 case SANE_FRAME_RGB:
     662           0 :                     eType = FrameStyle_RGB;
     663           0 :                     break;
     664             :                 case SANE_FRAME_RED:
     665             :                 case SANE_FRAME_GREEN:
     666             :                 case SANE_FRAME_BLUE:
     667           0 :                     eType = FrameStyle_Separated;
     668           0 :                     break;
     669             :                 default:
     670           0 :                     fprintf( stderr, "Warning: unknown frame style !!!\n" );
     671             :             }
     672             : 
     673           0 :             bool bSynchronousRead = true;
     674             : 
     675             :             // should be fail safe, but ... ??
     676           0 :             nStatus = p_set_io_mode( maHandle, SANE_FALSE );
     677           0 :             CheckConsistency( "sane_set_io_mode" );
     678           0 :             if( nStatus != SANE_STATUS_GOOD )
     679             :             {
     680           0 :                 bSynchronousRead = false;
     681           0 :                 nStatus = p_set_io_mode( maHandle, SANE_TRUE );
     682           0 :                 CheckConsistency( "sane_set_io_mode" );
     683             :                 SAL_WARN_IF(nStatus != SANE_STATUS_GOOD, "extensions.scanner", "driver is confused" );
     684             :             }
     685             : 
     686           0 :             SANE_Int nLen=0;
     687           0 :             SANE_Int fd = 0;
     688             : 
     689           0 :             if( ! bSynchronousRead )
     690             :             {
     691           0 :                 nStatus = p_get_select_fd( maHandle, &fd );
     692             :                 DUMP_STATE( nStatus, "sane_get_select_fd" );
     693           0 :                 CheckConsistency( "sane_get_select_fd" );
     694           0 :                 if( nStatus != SANE_STATUS_GOOD )
     695           0 :                     bSynchronousRead = true;
     696             :             }
     697           0 :             FILE* pFrame = tmpfile();
     698           0 :             if( ! pFrame )
     699             :             {
     700           0 :                 bSuccess = false;
     701           0 :                 break;
     702             :             }
     703           0 :             do {
     704           0 :                 if( ! bSynchronousRead )
     705             :                 {
     706             :                     fd_set fdset;
     707             :                     struct timeval tv;
     708             : 
     709           0 :                     FD_ZERO( &fdset );
     710           0 :                     FD_SET( (int)fd, &fdset );
     711           0 :                     tv.tv_sec = 5;
     712           0 :                     tv.tv_usec = 0;
     713           0 :                     if( select( fd+1, &fdset, NULL, NULL, &tv ) == 0 )
     714           0 :                         fprintf( stderr, "Timout on sane_read descriptor\n" );
     715             :                 }
     716           0 :                 nLen = 0;
     717           0 :                 nStatus = p_read( maHandle, pBuffer, BYTE_BUFFER_SIZE, &nLen );
     718           0 :                 CheckConsistency( "sane_read" );
     719           0 :                 if( nLen && ( nStatus == SANE_STATUS_GOOD ||
     720             :                               nStatus == SANE_STATUS_EOF ) )
     721             :                 {
     722           0 :                     bSuccess = (static_cast<size_t>(nLen) == fwrite( pBuffer, 1, nLen, pFrame ));
     723           0 :                     if (!bSuccess)
     724           0 :                         break;
     725             :                 }
     726             :                 else
     727             :                     DUMP_STATE( nStatus, "sane_read" );
     728             :             } while( nStatus == SANE_STATUS_GOOD );
     729           0 :             if (nStatus != SANE_STATUS_EOF || !bSuccess)
     730             :             {
     731           0 :                 fclose( pFrame );
     732           0 :                 bSuccess = false;
     733           0 :                 break;
     734             :             }
     735             : 
     736           0 :             int nFrameLength = ftell( pFrame );
     737           0 :             fseek( pFrame, 0, SEEK_SET );
     738           0 :             sal_uInt32 nWidth = (sal_uInt32) aParams.pixels_per_line;
     739           0 :             sal_uInt32 nHeight = (sal_uInt32) (nFrameLength / aParams.bytes_per_line);
     740           0 :             if( ! bWidthSet )
     741             :             {
     742           0 :                 if( ! fResl )
     743           0 :                     fResl = 300; // if all else fails that's a good guess
     744           0 :                 if( ! nWidthMM )
     745           0 :                     nWidthMM = (int)(((double)nWidth / fResl) * 25.4);
     746           0 :                 if( ! nHeightMM )
     747           0 :                     nHeightMM = (int)(((double)nHeight / fResl) * 25.4);
     748             : #if OSL_DEBUG_LEVEL > 1
     749             :                 fprintf( stderr, "set dimensions to (%d, %d) Pixel, (%d, %d) mm, resolution is %lg\n", (int)nWidth, (int)nHeight, (int)nWidthMM, (int)nHeightMM, fResl );
     750             : #endif
     751             : 
     752           0 :                 aConverter.Seek( 18 );
     753           0 :                 aConverter.WriteUInt32( nWidth );
     754           0 :                 aConverter.WriteUInt32( nHeight );
     755           0 :                 aConverter.Seek( 38 );
     756           0 :                 aConverter.WriteUInt32( (1000*nWidth/nWidthMM) );
     757           0 :                 aConverter.WriteUInt32( (1000*nHeight/nHeightMM) );
     758           0 :                 bWidthSet = true;
     759             :             }
     760           0 :             aConverter.Seek(60);
     761             : 
     762           0 :             if( eType == FrameStyle_BW )
     763             :             {
     764           0 :                 aConverter.Seek( 10 );
     765           0 :                 aConverter.WriteUInt32( 64 );
     766           0 :                 aConverter.Seek( 28 );
     767           0 :                 aConverter.WriteUInt16( 1 );
     768           0 :                 aConverter.Seek( 54 );
     769             :                 // write color table
     770           0 :                 aConverter.WriteUInt16( 0xffff );
     771           0 :                 aConverter.WriteUChar( 0xff );
     772           0 :                 aConverter.WriteUChar( 0 );
     773           0 :                 aConverter.WriteUInt32( 0 );
     774           0 :                 aConverter.Seek( 64 );
     775             :             }
     776           0 :             else if( eType == FrameStyle_Gray )
     777             :             {
     778           0 :                  aConverter.Seek( 10 );
     779           0 :                  aConverter.WriteUInt32( 1084 );
     780           0 :                 aConverter.Seek( 28 );
     781           0 :                 aConverter.WriteUInt16( 8 );
     782           0 :                 aConverter.Seek( 54 );
     783             :                 // write color table
     784           0 :                 for( nLine = 0; nLine < 256; nLine++ )
     785             :                 {
     786           0 :                     aConverter.WriteUChar( nLine );
     787           0 :                     aConverter.WriteUChar( nLine );
     788           0 :                     aConverter.WriteUChar( nLine );
     789           0 :                     aConverter.WriteUChar( 0 );
     790             :                 }
     791           0 :                 aConverter.Seek( 1084 );
     792             :             }
     793             : 
     794           0 :             for (nLine = nHeight-1; nLine >= 0; --nLine)
     795             :             {
     796           0 :                 fseek( pFrame, nLine * aParams.bytes_per_line, SEEK_SET );
     797           0 :                 if( eType == FrameStyle_BW ||
     798           0 :                     ( eType == FrameStyle_Gray && aParams.depth == 8 )
     799             :                     )
     800             :                 {
     801           0 :                     SANE_Int items_read = fread( pBuffer, 1, aParams.bytes_per_line, pFrame );
     802           0 :                     if (items_read != aParams.bytes_per_line)
     803             :                     {
     804             :                         SAL_WARN( "extensions.scanner", "short read, padding with zeros" );
     805           0 :                         memset(pBuffer + items_read, 0, aParams.bytes_per_line - items_read);
     806             :                     }
     807           0 :                     aConverter.Write( pBuffer, aParams.bytes_per_line );
     808             :                 }
     809           0 :                 else if( eType == FrameStyle_Gray )
     810             :                 {
     811           0 :                     for( i = 0; i < (aParams.pixels_per_line); i++ )
     812             :                     {
     813           0 :                         sal_uInt8 nGray = _ReadValue( pFrame, aParams.depth );
     814           0 :                         aConverter.WriteUChar( nGray );
     815             :                     }
     816             :                 }
     817           0 :                 else if( eType == FrameStyle_RGB )
     818             :                 {
     819           0 :                     for( i = 0; i < (aParams.pixels_per_line); i++ )
     820             :                     {
     821             :                         sal_uInt8 nRed, nGreen, nBlue;
     822           0 :                         nRed    = _ReadValue( pFrame, aParams.depth );
     823           0 :                         nGreen  = _ReadValue( pFrame, aParams.depth );
     824           0 :                         nBlue   = _ReadValue( pFrame, aParams.depth );
     825           0 :                         aConverter.WriteUChar( nBlue );
     826           0 :                         aConverter.WriteUChar( nGreen );
     827           0 :                         aConverter.WriteUChar( nRed );
     828             :                     }
     829             :                 }
     830           0 :                 else if( eType == FrameStyle_Separated )
     831             :                 {
     832           0 :                     for( i = 0; i < (aParams.pixels_per_line); i++ )
     833             :                     {
     834           0 :                         sal_uInt8 nValue = _ReadValue( pFrame, aParams.depth );
     835           0 :                         switch( aParams.format )
     836             :                         {
     837             :                             case SANE_FRAME_RED:
     838           0 :                                 aConverter.SeekRel( 2 );
     839           0 :                                 aConverter.WriteUChar( nValue );
     840           0 :                                 break;
     841             :                             case SANE_FRAME_GREEN:
     842           0 :                                 aConverter.SeekRel( 1 );
     843           0 :                                 aConverter.WriteUChar( nValue );
     844           0 :                                 aConverter.SeekRel( 1 );
     845           0 :                                 break;
     846             :                             case SANE_FRAME_BLUE:
     847           0 :                                 aConverter.WriteUChar( nValue );
     848           0 :                                 aConverter.SeekRel( 2 );
     849           0 :                                 break;
     850             :                             case SANE_FRAME_GRAY:
     851             :                             case SANE_FRAME_RGB:
     852           0 :                                 break;
     853             :                         }
     854             :                     }
     855             :                 }
     856           0 :                  int nGap = aConverter.Tell() & 3;
     857           0 :                  if( nGap )
     858           0 :                      aConverter.SeekRel( 4-nGap );
     859             :             }
     860           0 :             fclose( pFrame ); // deletes tmpfile
     861           0 :             if( eType != FrameStyle_Separated )
     862           0 :                 break;
     863             :         }
     864             :         else
     865           0 :             bSuccess = false;
     866             :     }
     867             :     // get stream length
     868           0 :     aConverter.Seek( STREAM_SEEK_TO_END );
     869           0 :     int nPos = aConverter.Tell();
     870             : 
     871           0 :     aConverter.Seek( 2 );
     872           0 :     aConverter.WriteUInt32( nPos+1 );
     873           0 :     aConverter.Seek( 0 );
     874             : 
     875           0 :     rBitmap.unlock();
     876             : 
     877           0 :     if( bSuccess )
     878             :     {
     879             :         // only cancel a successful operation
     880             :         // sane disrupts memory else
     881           0 :         p_cancel( maHandle );
     882           0 :         CheckConsistency( "sane_cancel" );
     883             :     }
     884           0 :     if( pBuffer )
     885           0 :         delete [] pBuffer;
     886             : 
     887           0 :     ReloadOptions();
     888             : 
     889             : 
     890           0 :     dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" );
     891             : 
     892           0 :     return bSuccess;
     893             : }
     894             : 
     895           0 : int Sane::GetRange( int n, double*& rpDouble )
     896             : {
     897           0 :     if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE &&
     898           0 :         mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST )
     899             :     {
     900           0 :         return -1;
     901             :     }
     902             : 
     903           0 :     rpDouble = 0;
     904             :     int nItems, i;
     905           0 :     bool bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED ? sal_True : sal_False;
     906             : 
     907           0 :     dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name );
     908           0 :     if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE )
     909             :     {
     910             :         double fMin, fMax, fQuant;
     911           0 :         if( bIsFixed )
     912             :         {
     913           0 :             fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min );
     914           0 :             fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max );
     915           0 :             fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant );
     916             :         }
     917             :         else
     918             :         {
     919           0 :             fMin = (double)mppOptions[n]->constraint.range->min;
     920           0 :             fMax = (double)mppOptions[n]->constraint.range->max;
     921           0 :             fQuant = (double)mppOptions[n]->constraint.range->quant;
     922             :         }
     923           0 :         if( fQuant != 0.0 )
     924             :         {
     925             :             dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n",
     926           0 :                      fMin, fQuant, fMax );
     927           0 :             nItems = (int)((fMax - fMin)/fQuant)+1;
     928           0 :             rpDouble = new double[ nItems ];
     929           0 :             double fValue = fMin;
     930           0 :             for( i = 0; i < nItems; i++, fValue += fQuant )
     931           0 :                 rpDouble[i] = fValue;
     932           0 :             rpDouble[ nItems-1 ] = fMax;
     933           0 :             return nItems;
     934             :         }
     935             :         else
     936             :         {
     937             :             dbg_msg( "normal range [ %lg %lg ]\n",
     938           0 :                      fMin, fMax );
     939           0 :             rpDouble = new double[2];
     940           0 :             rpDouble[0] = fMin;
     941           0 :             rpDouble[1] = fMax;
     942           0 :             return 0;
     943             :         }
     944             :     }
     945             :     else
     946             :     {
     947           0 :         nItems = mppOptions[n]->constraint.word_list[0];
     948           0 :         rpDouble = new double[nItems];
     949           0 :         for( i=0; i<nItems; i++ )
     950             :         {
     951           0 :             rpDouble[i] = bIsFixed ?
     952           0 :                 SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) :
     953           0 :                 (double)mppOptions[n]->constraint.word_list[i+1];
     954             :         }
     955             :         dbg_msg( "wordlist [ %lg ... %lg ]\n",
     956           0 :                  rpDouble[ 0 ], rpDouble[ nItems-1 ] );
     957           0 :         return nItems;
     958             :     }
     959             : }
     960             : 
     961             : static const char *ppUnits[] = {
     962             :     "",
     963             :     "[Pixel]",
     964             :     "[Bit]",
     965             :     "[mm]",
     966             :     "[DPI]",
     967             :     "[%]",
     968             :     "[usec]"
     969             : };
     970             : 
     971           0 : OUString Sane::GetOptionUnitName( int n )
     972             : {
     973           0 :     OUString aText;
     974           0 :     SANE_Unit nUnit = mppOptions[n]->unit;
     975           0 :     size_t nUnitAsSize = (size_t)nUnit;
     976           0 :     if (nUnitAsSize >= SAL_N_ELEMENTS( ppUnits ))
     977           0 :         aText = "[unknown units]";
     978             :     else
     979           0 :         aText = OUString( ppUnits[ nUnit ], strlen(ppUnits[ nUnit ]), osl_getThreadTextEncoding() );
     980           0 :     return aText;
     981             : }
     982             : 
     983           0 : bool Sane::ActivateButtonOption( int n )
     984             : {
     985           0 :     SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, NULL );
     986           0 :     if( nStatus != SANE_STATUS_GOOD )
     987           0 :         return false;
     988           0 :     return true;
     989          66 : }
     990             : 
     991             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10