|  | /************************************************************** | 
|  | * | 
|  | * Licensed to the Apache Software Foundation (ASF) under one | 
|  | * or more contributor license agreements.  See the NOTICE file | 
|  | * distributed with this work for additional information | 
|  | * regarding copyright ownership.  The ASF licenses this file | 
|  | * to you under the Apache License, Version 2.0 (the | 
|  | * "License"); you may not use this file except in compliance | 
|  | * with the License.  You may obtain a copy of the License at | 
|  | * | 
|  | *   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, | 
|  | * software distributed under the License is distributed on an | 
|  | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | * KIND, either express or implied.  See the License for the | 
|  | * specific language governing permissions and limitations | 
|  | * under the License. | 
|  | * | 
|  | *************************************************************/ | 
|  |  | 
|  |  | 
|  |  | 
|  | // MARKER(update_precomp.py): autogen include statement, do not remove | 
|  | #include "precompiled_extensions.hxx" | 
|  | #include <cstdarg> | 
|  | #include <math.h> | 
|  | #include <osl/file.h> | 
|  | #include <tools/stream.hxx> | 
|  | #include <sane.hxx> | 
|  | #include <dlfcn.h> | 
|  | #include <stdio.h> | 
|  | #include <unistd.h> | 
|  | #include <sys/time.h> | 
|  | #include <sys/types.h> | 
|  | #include <sal/config.h> | 
|  |  | 
|  | #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL | 
|  | #include <stdarg.h> | 
|  | #define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d ); | 
|  | #else | 
|  | #define dump_state( a, b, c, d ) ; | 
|  | #endif | 
|  | inline void dbg_msg( const char* pString, ... ) | 
|  | { | 
|  | #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL | 
|  | va_list ap; | 
|  | va_start( ap, pString ); | 
|  | vfprintf( stderr, pString, ap ); | 
|  | va_end( ap ); | 
|  | #else | 
|  | (void)pString; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #define FAIL_SHUTDOWN_STATE( x, y, z ) \ | 
|  | if( x != SANE_STATUS_GOOD )								\ | 
|  | {														\ | 
|  | dump_state( "%s returned error %d (%s)\n",			\ | 
|  | y, x, p_strstatus( x ) );					\ | 
|  | DeInit();											\ | 
|  | return z;											\ | 
|  | } | 
|  |  | 
|  | #define FAIL_STATE( x, y, z ) \ | 
|  | if( x != SANE_STATUS_GOOD )								\ | 
|  | {														\ | 
|  | dump_state( "%s returned error %d (%s)\n",			\ | 
|  | y, x, p_strstatus( x ) );					\ | 
|  | return z;											\ | 
|  | } | 
|  |  | 
|  | #define DUMP_STATE( x, y ) \ | 
|  | if( x != SANE_STATUS_GOOD )								\ | 
|  | {														\ | 
|  | dump_state( "%s returned error %d (%s)\n",			\ | 
|  | y, x, p_strstatus( x ) );					\ | 
|  | } | 
|  |  | 
|  | #define CHECK_STATE( x, y ) \ | 
|  | if( x != SANE_STATUS_GOOD )								\ | 
|  | {														\ | 
|  | dump_state( "%s returned error %d (%s)\n",			\ | 
|  | y, x, p_strstatus( x ) );					\ | 
|  | }														\ | 
|  | else | 
|  |  | 
|  | int				Sane::nRefCount = 0; | 
|  | oslModule       Sane::pSaneLib = 0; | 
|  | SANE_Int		Sane::nVersion = 0; | 
|  | SANE_Device**	Sane::ppDevices = 0; | 
|  | int				Sane::nDevices = 0; | 
|  |  | 
|  | SANE_Status		(*Sane::p_init)( SANE_Int*, | 
|  | SANE_Auth_Callback ) = 0; | 
|  | void			(*Sane::p_exit)() = 0; | 
|  | SANE_Status		(*Sane::p_get_devices)( const SANE_Device***, | 
|  | SANE_Bool ) = 0; | 
|  | SANE_Status		(*Sane::p_open)( SANE_String_Const, SANE_Handle ) = 0; | 
|  | void			(*Sane::p_close)( SANE_Handle ) = 0; | 
|  | const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)( | 
|  | SANE_Handle, SANE_Int ) = 0; | 
|  | SANE_Status		(*Sane::p_control_option)( SANE_Handle, SANE_Int, | 
|  | SANE_Action, void*, | 
|  | SANE_Int* ) = 0; | 
|  | SANE_Status		(*Sane::p_get_parameters)( SANE_Handle, | 
|  | SANE_Parameters* ) = 0; | 
|  | SANE_Status		(*Sane::p_start)( SANE_Handle ) = 0; | 
|  | SANE_Status		(*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int, | 
|  | SANE_Int* ) = 0; | 
|  | void			(*Sane::p_cancel)( SANE_Handle ) = 0; | 
|  | SANE_Status		(*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = 0; | 
|  | SANE_Status		(*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = 0; | 
|  | SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = 0; | 
|  |  | 
|  | static sal_Bool bSaneSymbolLoadFailed = sal_False; | 
|  |  | 
|  | inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname ) | 
|  | { | 
|  | oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname ); | 
|  | if( ! pFunction ) | 
|  | { | 
|  | fprintf( stderr, "Could not load symbol %s\n", | 
|  | pSymbolname ); | 
|  | bSaneSymbolLoadFailed = sal_True; | 
|  | } | 
|  | return pFunction; | 
|  | } | 
|  |  | 
|  | SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction, | 
|  | void* pData ) | 
|  | { | 
|  | SANE_Status	nStatus = SANE_STATUS_GOOD; | 
|  | SANE_Int	nInfo = 0; | 
|  |  | 
|  | nStatus = p_control_option( maHandle, (SANE_Int)nOption, | 
|  | nAction, pData, &nInfo ); | 
|  | DUMP_STATE( nStatus, "sane_control_option" ); | 
|  | #if OSL_DEBUG_LEVEL > 1 | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | { | 
|  | const char* pAction = "Unknown"; | 
|  | switch( nAction ) | 
|  | { | 
|  | case SANE_ACTION_GET_VALUE: | 
|  | pAction = "SANE_ACTION_GET_VALUE";break; | 
|  | case SANE_ACTION_SET_VALUE: | 
|  | pAction = "SANE_ACTION_SET_VALUE";break; | 
|  | case SANE_ACTION_SET_AUTO: | 
|  | pAction = "SANE_ACTION_SET_AUTO";break; | 
|  | } | 
|  | dbg_msg( "Option: \"%s\" action: %s\n", | 
|  | ByteString( GetOptionName( nOption ), gsl_getSystemTextEncoding() ).GetBuffer(), | 
|  | pAction ); | 
|  | } | 
|  | #endif | 
|  | //	if( nInfo & ( SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS ) ) | 
|  | if( nInfo &  SANE_INFO_RELOAD_OPTIONS ) | 
|  | ReloadOptions(); | 
|  | return nStatus; | 
|  | } | 
|  |  | 
|  | Sane::Sane() : | 
|  | mppOptions( 0 ), | 
|  | mnOptions( 0 ), | 
|  | mnDevice( -1 ), | 
|  | maHandle( 0 ) | 
|  | { | 
|  | if( ! nRefCount || ! pSaneLib ) | 
|  | Init(); | 
|  | nRefCount++; | 
|  | }; | 
|  |  | 
|  | Sane::~Sane() | 
|  | { | 
|  | if( IsOpen() ) | 
|  | Close(); | 
|  | nRefCount--; | 
|  | if( ! nRefCount && pSaneLib ) | 
|  | DeInit(); | 
|  | } | 
|  |  | 
|  | void Sane::Init() | 
|  | { | 
|  | ::rtl::OUString sSaneLibName( ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ) ); | 
|  | pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); | 
|  | if( ! pSaneLib ) | 
|  | { | 
|  | sSaneLibName = ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ".1" ); | 
|  | pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); | 
|  | } | 
|  | // try reasonable places that might not be in the library search path | 
|  | if( ! pSaneLib ) | 
|  | { | 
|  | ::rtl::OUString sSaneLibSystemPath( ::rtl::OUString::createFromAscii( "/usr/local/lib/libsane" SAL_DLLEXTENSION ) ); | 
|  | osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData ); | 
|  | pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); | 
|  | } | 
|  |  | 
|  | if( pSaneLib ) | 
|  | { | 
|  | bSaneSymbolLoadFailed = sal_False; | 
|  | p_init = (SANE_Status(*)(SANE_Int*, SANE_Auth_Callback )) | 
|  | LoadSymbol( "sane_init" ); | 
|  | p_exit = (void(*)()) | 
|  | LoadSymbol( "sane_exit" ); | 
|  | p_get_devices = (SANE_Status(*)(const SANE_Device***, | 
|  | SANE_Bool )) | 
|  | LoadSymbol( "sane_get_devices" ); | 
|  | p_open = (SANE_Status(*)(SANE_String_Const, SANE_Handle )) | 
|  | LoadSymbol( "sane_open" ); | 
|  | p_close = (void(*)(SANE_Handle)) | 
|  | LoadSymbol( "sane_close" ); | 
|  | p_get_option_descriptor = (const SANE_Option_Descriptor*(*)(SANE_Handle, | 
|  | SANE_Int)) | 
|  | LoadSymbol( "sane_get_option_descriptor" ); | 
|  | p_control_option = (SANE_Status(*)(SANE_Handle, SANE_Int, | 
|  | SANE_Action, void*, SANE_Int*)) | 
|  | LoadSymbol( "sane_control_option" ); | 
|  | p_get_parameters = (SANE_Status(*)(SANE_Handle,SANE_Parameters*)) | 
|  | LoadSymbol( "sane_get_parameters" ); | 
|  | p_start = (SANE_Status(*)(SANE_Handle)) | 
|  | LoadSymbol( "sane_start" ); | 
|  | p_read = (SANE_Status(*)(SANE_Handle, SANE_Byte*, | 
|  | SANE_Int, SANE_Int* )) | 
|  | LoadSymbol( "sane_read" ); | 
|  | p_cancel = (void(*)(SANE_Handle)) | 
|  | LoadSymbol( "sane_cancel" ); | 
|  | p_set_io_mode = (SANE_Status(*)(SANE_Handle, SANE_Bool)) | 
|  | LoadSymbol( "sane_set_io_mode" ); | 
|  | p_get_select_fd = (SANE_Status(*)(SANE_Handle, SANE_Int*)) | 
|  | LoadSymbol( "sane_get_select_fd" ); | 
|  | p_strstatus = (SANE_String_Const(*)(SANE_Status)) | 
|  | LoadSymbol( "sane_strstatus" ); | 
|  | if( bSaneSymbolLoadFailed ) | 
|  | DeInit(); | 
|  | else | 
|  | { | 
|  | SANE_Status nStatus = p_init( &nVersion, 0 ); | 
|  | FAIL_SHUTDOWN_STATE( nStatus, "sane_init", ); | 
|  | nStatus = p_get_devices( (const SANE_Device***)&ppDevices, | 
|  | SANE_FALSE ); | 
|  | FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", ); | 
|  | for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ; | 
|  | } | 
|  | } | 
|  | #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL | 
|  | else | 
|  | fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION, | 
|  | dlerror() ); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void Sane::DeInit() | 
|  | { | 
|  | if( pSaneLib ) | 
|  | { | 
|  | p_exit(); | 
|  | osl_unloadModule( pSaneLib ); | 
|  | pSaneLib = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void Sane::ReloadDevices() | 
|  | { | 
|  | if( IsOpen() ) | 
|  | Close(); | 
|  | DeInit(); | 
|  | Init(); | 
|  | } | 
|  |  | 
|  | void Sane::ReloadOptions() | 
|  | { | 
|  | if( ! IsOpen() ) | 
|  | return; | 
|  |  | 
|  | SANE_Option_Descriptor* pZero = (SANE_Option_Descriptor*) | 
|  | p_get_option_descriptor( maHandle, 0 ); | 
|  | SANE_Word pOptions[2]; | 
|  | SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE, | 
|  | (void*)pOptions, NULL ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) ); | 
|  |  | 
|  | mnOptions = pOptions[ 0 ]; | 
|  | if( (size_t)pZero->size > sizeof( SANE_Word ) ) | 
|  | fprintf( stderr, "driver returned numer of options with larger size tha SANE_Word !!!\n" ); | 
|  | if( mppOptions ) | 
|  | delete [] mppOptions; | 
|  | mppOptions = (const SANE_Option_Descriptor**)new SANE_Option_Descriptor*[ mnOptions ]; | 
|  | mppOptions[ 0 ] = (SANE_Option_Descriptor*)pZero; | 
|  | for( int i = 1; i < mnOptions; i++ ) | 
|  | mppOptions[ i ] =  (SANE_Option_Descriptor*) | 
|  | p_get_option_descriptor( maHandle, i ); | 
|  |  | 
|  | CheckConsistency( NULL, sal_True ); | 
|  |  | 
|  | maReloadOptionsLink.Call( this ); | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::Open( const char* name ) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | SANE_Status nStatus = p_open( (SANE_String_Const)name, &maHandle ); | 
|  | FAIL_STATE( nStatus, "sane_open", sal_False ); | 
|  |  | 
|  | ReloadOptions(); | 
|  |  | 
|  | if( mnDevice == -1 ) | 
|  | { | 
|  | ByteString aDevice( name ); | 
|  | for( i = 0; i < nDevices; i++ ) | 
|  | { | 
|  | if( aDevice.Equals( ppDevices[i]->name ) ) | 
|  | { | 
|  | mnDevice = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::Open( int n ) | 
|  | { | 
|  | if( n >= 0 && n < nDevices ) | 
|  | { | 
|  | mnDevice = n; | 
|  | return Open( (char*)ppDevices[n]->name ); | 
|  | } | 
|  | return sal_False; | 
|  | } | 
|  |  | 
|  | void Sane::Close() | 
|  | { | 
|  | if( maHandle ) | 
|  | { | 
|  | p_close( maHandle ); | 
|  | delete [] mppOptions; | 
|  | mppOptions = 0; | 
|  | maHandle = 0; | 
|  | mnDevice = -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | int Sane::GetOptionByName( const char* rName ) | 
|  | { | 
|  | int i; | 
|  | ByteString aOption( rName ); | 
|  | for( i = 0; i < mnOptions; i++ ) | 
|  | { | 
|  | if( mppOptions[i]->name && aOption.Equals( mppOptions[i]->name ) ) | 
|  | return i; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::GetOptionValue( int n, sal_Bool& rRet ) | 
|  | { | 
|  | if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_BOOL ) | 
|  | return sal_False; | 
|  | SANE_Word nRet; | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | return sal_False; | 
|  |  | 
|  | rRet = nRet; | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::GetOptionValue( int n, ByteString& rRet ) | 
|  | { | 
|  | sal_Bool bSuccess = sal_False; | 
|  | if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_STRING ) | 
|  | return sal_False; | 
|  | char* pRet = new char[mppOptions[n]->size+1]; | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet ); | 
|  | if( nStatus == SANE_STATUS_GOOD ) | 
|  | { | 
|  | bSuccess = sal_True; | 
|  | rRet = pRet; | 
|  | } | 
|  | delete [] pRet; | 
|  | return bSuccess; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::GetOptionValue( int n, double& rRet, int nElement ) | 
|  | { | 
|  | sal_Bool bSuccess = sal_False; | 
|  |  | 
|  | if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT && | 
|  | mppOptions[n]->type != SANE_TYPE_FIXED ) ) | 
|  | return sal_False; | 
|  |  | 
|  | SANE_Word* pRet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet ); | 
|  | if( nStatus == SANE_STATUS_GOOD ) | 
|  | { | 
|  | bSuccess = sal_True; | 
|  | if( mppOptions[n]->type == SANE_TYPE_INT ) | 
|  | rRet = (double)pRet[ nElement ]; | 
|  | else | 
|  | rRet = SANE_UNFIX( pRet[nElement] ); | 
|  | } | 
|  | delete [] pRet; | 
|  | return bSuccess; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::GetOptionValue( int n, double* pSet ) | 
|  | { | 
|  | if( ! maHandle  || ! ( mppOptions[n]->type == SANE_TYPE_FIXED || | 
|  | mppOptions[n]->type == SANE_TYPE_INT ) ) | 
|  | return sal_False; | 
|  |  | 
|  | SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | { | 
|  | delete [] pFixedSet; | 
|  | return sal_False; | 
|  | } | 
|  | for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ ) | 
|  | { | 
|  | if( mppOptions[n]->type == SANE_TYPE_FIXED ) | 
|  | pSet[i] = SANE_UNFIX( pFixedSet[i] ); | 
|  | else | 
|  | pSet[i] = (double) pFixedSet[i]; | 
|  | } | 
|  | delete [] pFixedSet; | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::SetOptionValue( int n, sal_Bool bSet ) | 
|  | { | 
|  | if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_BOOL ) | 
|  | return sal_False; | 
|  | SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE; | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nRet ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | return sal_False; | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::SetOptionValue( int n, const String& rSet ) | 
|  | { | 
|  | if( ! maHandle  ||  mppOptions[n]->type != SANE_TYPE_STRING ) | 
|  | return sal_False; | 
|  | ByteString aSet( rSet, gsl_getSystemTextEncoding() ); | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, (void*)aSet.GetBuffer() ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | return sal_False; | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::SetOptionValue( int n, double fSet, int nElement ) | 
|  | { | 
|  | sal_Bool bSuccess = sal_False; | 
|  |  | 
|  | if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT && | 
|  | mppOptions[n]->type != SANE_TYPE_FIXED ) ) | 
|  | return sal_False; | 
|  |  | 
|  | SANE_Status nStatus; | 
|  | if( mppOptions[n]->size/sizeof(SANE_Word) > 1 ) | 
|  | { | 
|  | SANE_Word* pSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; | 
|  | nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet ); | 
|  | if( nStatus == SANE_STATUS_GOOD ) | 
|  | { | 
|  | pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ? | 
|  | (SANE_Word)fSet : SANE_FIX( fSet ); | 
|  | nStatus = ControlOption(  n, SANE_ACTION_SET_VALUE, pSet ); | 
|  | } | 
|  | delete [] pSet; | 
|  | } | 
|  | else | 
|  | { | 
|  | SANE_Word nSetTo = | 
|  | mppOptions[n]->type == SANE_TYPE_INT ? | 
|  | (SANE_Word)fSet : SANE_FIX( fSet ); | 
|  |  | 
|  | nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo ); | 
|  | if( nStatus == SANE_STATUS_GOOD ) | 
|  | bSuccess = sal_True; | 
|  | } | 
|  | return bSuccess; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::SetOptionValue( int n, double* pSet ) | 
|  | { | 
|  | if( ! maHandle  ||  ( mppOptions[n]->type != SANE_TYPE_INT && | 
|  | mppOptions[n]->type != SANE_TYPE_FIXED ) ) | 
|  | return sal_False; | 
|  | SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]; | 
|  | for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ ) | 
|  | { | 
|  | if( mppOptions[n]->type == SANE_TYPE_FIXED ) | 
|  | pFixedSet[i] = SANE_FIX( pSet[i] ); | 
|  | else | 
|  | pFixedSet[i] = (SANE_Word)pSet[i]; | 
|  | } | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet ); | 
|  | delete [] pFixedSet; | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | return sal_False; | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | enum FrameStyleType { | 
|  | FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated | 
|  | }; | 
|  |  | 
|  | #define BYTE_BUFFER_SIZE 32768 | 
|  |  | 
|  | static inline sal_uInt8 _ReadValue( FILE* fp, int depth ) | 
|  | { | 
|  | if( depth == 16 ) | 
|  | { | 
|  | sal_uInt16 nWord; | 
|  | // data always come in native byte order ! | 
|  | // 16 bits is not really supported by backends as of now | 
|  | // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN | 
|  | // against SANE documentation (xscanimage gets the same result | 
|  | // as we do | 
|  | fread( &nWord, 1, 2, fp ); | 
|  | return (sal_uInt8)( nWord / 256 ); | 
|  | } | 
|  | sal_uInt8 nByte; | 
|  | fread( &nByte, 1, 1, fp ); | 
|  | return nByte; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::CheckConsistency( const char* pMes, sal_Bool bInit ) | 
|  | { | 
|  | static SANE_Option_Descriptor** pDescArray = NULL; | 
|  | static SANE_Option_Descriptor*  pZero = NULL; | 
|  |  | 
|  | if( bInit ) | 
|  | { | 
|  | pDescArray = (SANE_Option_Descriptor**)mppOptions; | 
|  | if( mppOptions ) | 
|  | pZero = (SANE_Option_Descriptor*)mppOptions[0]; | 
|  | return sal_True; | 
|  | } | 
|  |  | 
|  | sal_Bool bConsistent = sal_True; | 
|  |  | 
|  | if( pDescArray != mppOptions ) | 
|  | bConsistent = sal_False; | 
|  | if( pZero != mppOptions[0] ) | 
|  | bConsistent = sal_False; | 
|  |  | 
|  | if( ! bConsistent ) | 
|  | dbg_msg( "Sane is not consistent. (%s)\n", pMes ); | 
|  |  | 
|  | return bConsistent; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::Start( BitmapTransporter& rBitmap ) | 
|  | { | 
|  | int nStream = 0, nLine = 0, i = 0; | 
|  | SANE_Parameters	aParams; | 
|  | FrameStyleType eType = FrameStyle_Gray; | 
|  | sal_Bool bSuccess = sal_True; | 
|  | sal_Bool bWidthSet = sal_False; | 
|  |  | 
|  | if( ! maHandle ) | 
|  | return sal_False; | 
|  |  | 
|  | int nWidthMM	= 0; | 
|  | int nHeightMM	= 0; | 
|  | double fTLx, fTLy, fBRx, fBRy, fResl = 0.0; | 
|  | int nOption; | 
|  | if( ( nOption = GetOptionByName( "tl-x" ) ) != -1	&& | 
|  | GetOptionValue( nOption, fTLx, 0 )				&& | 
|  | GetOptionUnit( nOption ) == SANE_UNIT_MM ) | 
|  | { | 
|  | if( ( nOption = GetOptionByName( "br-x" ) ) != -1	&& | 
|  | GetOptionValue( nOption, fBRx, 0 )				&& | 
|  | GetOptionUnit( nOption ) == SANE_UNIT_MM ) | 
|  | { | 
|  | nWidthMM = (int)fabs(fBRx - fTLx); | 
|  | } | 
|  | } | 
|  | if( ( nOption = GetOptionByName( "tl-y" ) ) != -1	&& | 
|  | GetOptionValue( nOption, fTLy, 0 )				&& | 
|  | GetOptionUnit( nOption ) == SANE_UNIT_MM ) | 
|  | { | 
|  | if( ( nOption = GetOptionByName( "br-y" ) ) != -1	&& | 
|  | GetOptionValue( nOption, fBRy, 0 )				&& | 
|  | GetOptionUnit( nOption ) == SANE_UNIT_MM ) | 
|  | { | 
|  | nHeightMM = (int)fabs(fBRy - fTLy); | 
|  | } | 
|  | } | 
|  | if( ( nOption = GetOptionByName( "resolution" ) ) != -1 ) | 
|  | GetOptionValue( nOption, fResl ); | 
|  |  | 
|  | sal_uInt8* pBuffer = NULL; | 
|  |  | 
|  | SANE_Status nStatus = SANE_STATUS_GOOD; | 
|  |  | 
|  | rBitmap.lock(); | 
|  | SvMemoryStream& aConverter = rBitmap.getStream(); | 
|  | aConverter.Seek( 0 ); | 
|  | aConverter.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); | 
|  |  | 
|  | // write bitmap stream header | 
|  | aConverter << 'B' << 'M'; | 
|  | aConverter << (sal_uInt32) 0; | 
|  | aConverter << (sal_uInt32) 0; | 
|  | aConverter << (sal_uInt32) 60; | 
|  |  | 
|  | // write BITMAPINFOHEADER | 
|  | aConverter << (sal_uInt32)40; | 
|  | aConverter << (sal_uInt32)0; // fill in width later | 
|  | aConverter << (sal_uInt32)0; // fill in height later | 
|  | aConverter << (sal_uInt16)1; | 
|  | // create header for 24 bits | 
|  | // correct later if necessary | 
|  | aConverter << (sal_uInt16)24; | 
|  | aConverter << (sal_uInt32)0; | 
|  | aConverter << (sal_uInt32)0; | 
|  | aConverter << (sal_uInt32)0; | 
|  | aConverter << (sal_uInt32)0; | 
|  | aConverter << (sal_uInt32)0; | 
|  | aConverter << (sal_uInt32)0; | 
|  |  | 
|  | for( nStream=0; nStream < 3 && bSuccess ; nStream++ ) | 
|  | { | 
|  | nStatus = p_start( maHandle ); | 
|  | DUMP_STATE( nStatus, "sane_start" ); | 
|  | CheckConsistency( "sane_start" ); | 
|  | if( nStatus == SANE_STATUS_GOOD ) | 
|  | { | 
|  | nStatus = p_get_parameters( maHandle, &aParams ); | 
|  | DUMP_STATE( nStatus, "sane_get_parameters" ); | 
|  | CheckConsistency( "sane_get_parameters" ); | 
|  | if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0) | 
|  | { | 
|  | bSuccess = sal_False; | 
|  | break; | 
|  | } | 
|  | #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL | 
|  | const char* ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB", | 
|  | "SANE_FRAME_RED", "SANE_FRAME_GREEN", | 
|  | "SANE_FRAME_BLUE", "Unknown !!!" }; | 
|  | fprintf( stderr, "Parameters for frame %d:\n", nStream ); | 
|  | if( aParams.format < 0 || aParams.format > 4 ) | 
|  | aParams.format = (SANE_Frame)5; | 
|  | fprintf( stderr, "format:           %s\n", ppFormats[ (int)aParams.format ] ); | 
|  | fprintf( stderr, "last_frame:       %s\n", aParams.last_frame ? "TRUE" : "FALSE" ); | 
|  | fprintf( stderr, "depth:            %d\n", (int)aParams.depth ); | 
|  | fprintf( stderr, "pixels_per_line:  %d\n", (int)aParams.pixels_per_line ); | 
|  | fprintf( stderr, "bytes_per_line:   %d\n", (int)aParams.bytes_per_line ); | 
|  | #endif | 
|  | if( ! pBuffer ) | 
|  | { | 
|  | pBuffer = new sal_uInt8[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ]; | 
|  | } | 
|  |  | 
|  | if( aParams.last_frame ) | 
|  | nStream=3; | 
|  |  | 
|  | switch( aParams.format ) | 
|  | { | 
|  | case SANE_FRAME_GRAY: | 
|  | eType = FrameStyle_Gray; | 
|  | if( aParams.depth == 1 ) | 
|  | eType = FrameStyle_BW; | 
|  | break; | 
|  | case SANE_FRAME_RGB: | 
|  | eType = FrameStyle_RGB; | 
|  | break; | 
|  | case SANE_FRAME_RED: | 
|  | case SANE_FRAME_GREEN: | 
|  | case SANE_FRAME_BLUE: | 
|  | eType = FrameStyle_Separated; | 
|  | break; | 
|  | default: | 
|  | fprintf( stderr, "Warning: unknown frame style !!!\n" ); | 
|  | } | 
|  |  | 
|  | sal_Bool bSynchronousRead = sal_True; | 
|  |  | 
|  | // should be fail safe, but ... ?? | 
|  | nStatus = p_set_io_mode( maHandle, SANE_FALSE ); | 
|  | CheckConsistency( "sane_set_io_mode" ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | { | 
|  | bSynchronousRead = sal_False; | 
|  | nStatus = p_set_io_mode( maHandle, SANE_TRUE ); | 
|  | CheckConsistency( "sane_set_io_mode" ); | 
|  | #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | // what ?!? | 
|  | fprintf( stderr, "Sane::Start: driver is confused\n" ); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | SANE_Int nLen=0; | 
|  | SANE_Int fd = 0; | 
|  |  | 
|  | if( ! bSynchronousRead ) | 
|  | { | 
|  | nStatus = p_get_select_fd( maHandle, &fd ); | 
|  | DUMP_STATE( nStatus, "sane_get_select_fd" ); | 
|  | CheckConsistency( "sane_get_select_fd" ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | bSynchronousRead = sal_True; | 
|  | } | 
|  | FILE* pFrame = tmpfile(); | 
|  | if( ! pFrame ) | 
|  | { | 
|  | bSuccess = sal_False; | 
|  | break; | 
|  | } | 
|  | do { | 
|  | if( ! bSynchronousRead ) | 
|  | { | 
|  | fd_set fdset; | 
|  | struct timeval tv; | 
|  |  | 
|  | FD_ZERO( &fdset ); | 
|  | FD_SET( (int)fd, &fdset ); | 
|  | tv.tv_sec = 5; | 
|  | tv.tv_usec = 0; | 
|  | if( select( fd+1, &fdset, NULL, NULL, &tv ) == 0 ) | 
|  | fprintf( stderr, "Timout on sane_read descriptor\n" ); | 
|  | } | 
|  | nLen = 0; | 
|  | nStatus = p_read( maHandle, pBuffer, BYTE_BUFFER_SIZE, &nLen ); | 
|  | CheckConsistency( "sane_read" ); | 
|  | if( nLen && ( nStatus == SANE_STATUS_GOOD || | 
|  | nStatus == SANE_STATUS_EOF ) ) | 
|  | { | 
|  | fwrite( pBuffer, 1, nLen, pFrame ); | 
|  | } | 
|  | else | 
|  | DUMP_STATE( nStatus, "sane_read" ); | 
|  | } while( nStatus == SANE_STATUS_GOOD ); | 
|  | if( nStatus != SANE_STATUS_EOF ) | 
|  | { | 
|  | fclose( pFrame ); | 
|  | bSuccess = sal_False; | 
|  | break; | 
|  | } | 
|  |  | 
|  | int nFrameLength = ftell( pFrame ); | 
|  | fseek( pFrame, 0, SEEK_SET ); | 
|  | sal_uInt32 nWidth = (sal_uInt32) aParams.pixels_per_line; | 
|  | sal_uInt32 nHeight = (sal_uInt32) (nFrameLength / aParams.bytes_per_line); | 
|  | if( ! bWidthSet ) | 
|  | { | 
|  | if( ! fResl ) | 
|  | fResl = 300; // if all else fails that's a good guess | 
|  | if( ! nWidthMM ) | 
|  | nWidthMM = (int)(((double)nWidth / fResl) * 25.4); | 
|  | if( ! nHeightMM ) | 
|  | nHeightMM = (int)(((double)nHeight / fResl) * 25.4); | 
|  | #if OSL_DEBUG_LEVEL > 1 | 
|  | fprintf( stderr, "set dimensions to (%d, %d) Pixel, (%d, %d) mm, resolution is %lg\n", (int)nWidth, (int)nHeight, (int)nWidthMM, (int)nHeightMM, fResl ); | 
|  | #endif | 
|  |  | 
|  | aConverter.Seek( 18 ); | 
|  | aConverter << (sal_uInt32)nWidth; | 
|  | aConverter << (sal_uInt32)nHeight; | 
|  | aConverter.Seek( 38 ); | 
|  | aConverter << (sal_uInt32)(1000*nWidth/nWidthMM); | 
|  | aConverter << (sal_uInt32)(1000*nHeight/nHeightMM); | 
|  | bWidthSet = sal_True; | 
|  | } | 
|  | aConverter.Seek(60); | 
|  |  | 
|  | if( eType == FrameStyle_BW ) | 
|  | { | 
|  | aConverter.Seek( 10 ); | 
|  | aConverter << (sal_uInt32)64; | 
|  | aConverter.Seek( 28 ); | 
|  | aConverter << (sal_uInt16) 1; | 
|  | aConverter.Seek( 54 ); | 
|  | // write color table | 
|  | aConverter << (sal_uInt16)0xffff; | 
|  | aConverter << (sal_uInt8)0xff; | 
|  | aConverter << (sal_uInt8)0; | 
|  | aConverter << (sal_uInt32)0; | 
|  | aConverter.Seek( 64 ); | 
|  | } | 
|  | else if( eType == FrameStyle_Gray ) | 
|  | { | 
|  | aConverter.Seek( 10 ); | 
|  | aConverter << (sal_uInt32)1084; | 
|  | aConverter.Seek( 28 ); | 
|  | aConverter << (sal_uInt16) 8; | 
|  | aConverter.Seek( 54 ); | 
|  | // write color table | 
|  | for( nLine = 0; nLine < 256; nLine++ ) | 
|  | { | 
|  | aConverter << (sal_uInt8)nLine; | 
|  | aConverter << (sal_uInt8)nLine; | 
|  | aConverter << (sal_uInt8)nLine; | 
|  | aConverter << (sal_uInt8)0; | 
|  | } | 
|  | aConverter.Seek( 1084 ); | 
|  | } | 
|  |  | 
|  | for( nLine = nHeight-1; | 
|  | nLine >= 0; nLine-- ) | 
|  | { | 
|  | fseek( pFrame, nLine * aParams.bytes_per_line, SEEK_SET ); | 
|  | if( eType == FrameStyle_BW || | 
|  | ( eType == FrameStyle_Gray && aParams.depth == 8 ) | 
|  | ) | 
|  | { | 
|  | fread( pBuffer, 1, aParams.bytes_per_line, pFrame ); | 
|  | aConverter.Write( pBuffer, aParams.bytes_per_line ); | 
|  | } | 
|  | else if( eType == FrameStyle_Gray ) | 
|  | { | 
|  | for( i = 0; i < (aParams.pixels_per_line); i++ ) | 
|  | { | 
|  | sal_uInt8 nGray = _ReadValue( pFrame, aParams.depth ); | 
|  | aConverter << nGray; | 
|  | } | 
|  | } | 
|  | else if( eType == FrameStyle_RGB ) | 
|  | { | 
|  | for( i = 0; i < (aParams.pixels_per_line); i++ ) | 
|  | { | 
|  | sal_uInt8 nRed, nGreen, nBlue; | 
|  | nRed	= _ReadValue( pFrame, aParams.depth ); | 
|  | nGreen	= _ReadValue( pFrame, aParams.depth ); | 
|  | nBlue	= _ReadValue( pFrame, aParams.depth ); | 
|  | aConverter << nBlue; | 
|  | aConverter << nGreen; | 
|  | aConverter << nRed; | 
|  | } | 
|  | } | 
|  | else if( eType == FrameStyle_Separated ) | 
|  | { | 
|  | for( i = 0; i < (aParams.pixels_per_line); i++ ) | 
|  | { | 
|  | sal_uInt8 nValue = _ReadValue( pFrame, aParams.depth ); | 
|  | switch( aParams.format ) | 
|  | { | 
|  | case SANE_FRAME_RED: | 
|  | aConverter.SeekRel( 2 ); | 
|  | aConverter << nValue; | 
|  | break; | 
|  | case SANE_FRAME_GREEN: | 
|  | aConverter.SeekRel( 1 ); | 
|  | aConverter << nValue; | 
|  | aConverter.SeekRel( 1 ); | 
|  | break; | 
|  | case SANE_FRAME_BLUE: | 
|  | aConverter << nValue; | 
|  | aConverter.SeekRel( 2 ); | 
|  | break; | 
|  | case SANE_FRAME_GRAY: | 
|  | case SANE_FRAME_RGB: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | int nGap = aConverter.Tell() & 3; | 
|  | if( nGap ) | 
|  | aConverter.SeekRel( 4-nGap ); | 
|  | } | 
|  | fclose( pFrame ); // deletes tmpfile | 
|  | if( eType != FrameStyle_Separated ) | 
|  | break; | 
|  | } | 
|  | else | 
|  | bSuccess = sal_False; | 
|  | } | 
|  | // get stream length | 
|  | aConverter.Seek( STREAM_SEEK_TO_END ); | 
|  | int nPos = aConverter.Tell(); | 
|  |  | 
|  | aConverter.Seek( 2 ); | 
|  | aConverter << (sal_uInt32) nPos+1; | 
|  | aConverter.Seek( 0 ); | 
|  |  | 
|  | rBitmap.unlock(); | 
|  |  | 
|  | if( bSuccess ) | 
|  | { | 
|  | // only cancel a successful operation | 
|  | // sane disrupts memory else | 
|  | p_cancel( maHandle ); | 
|  | CheckConsistency( "sane_cancel" ); | 
|  | } | 
|  | if( pBuffer ) | 
|  | delete [] pBuffer; | 
|  |  | 
|  | ReloadOptions(); | 
|  |  | 
|  |  | 
|  | dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" ); | 
|  |  | 
|  | return bSuccess; | 
|  | } | 
|  |  | 
|  | int Sane::GetRange( int n, double*& rpDouble ) | 
|  | { | 
|  | if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE && | 
|  | mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST ) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | rpDouble = 0; | 
|  | int nItems, i; | 
|  | sal_Bool bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED ? sal_True : sal_False; | 
|  |  | 
|  | dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name ); | 
|  | if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE ) | 
|  | { | 
|  | double fMin, fMax, fQuant; | 
|  | if( bIsFixed ) | 
|  | { | 
|  | fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min ); | 
|  | fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max ); | 
|  | fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant ); | 
|  | } | 
|  | else | 
|  | { | 
|  | fMin = (double)mppOptions[n]->constraint.range->min; | 
|  | fMax = (double)mppOptions[n]->constraint.range->max; | 
|  | fQuant = (double)mppOptions[n]->constraint.range->quant; | 
|  | } | 
|  | if( fQuant != 0.0 ) | 
|  | { | 
|  | dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n", | 
|  | fMin, fQuant, fMax ); | 
|  | nItems = (int)((fMax - fMin)/fQuant)+1; | 
|  | rpDouble = new double[ nItems ]; | 
|  | double fValue = fMin; | 
|  | for( i = 0; i < nItems; i++, fValue += fQuant ) | 
|  | rpDouble[i] = fValue; | 
|  | rpDouble[ nItems-1 ] = fMax; | 
|  | return nItems; | 
|  | } | 
|  | else | 
|  | { | 
|  | dbg_msg( "normal range [ %lg %lg ]\n", | 
|  | fMin, fMax ); | 
|  | rpDouble = new double[2]; | 
|  | rpDouble[0] = fMin; | 
|  | rpDouble[1] = fMax; | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | nItems = mppOptions[n]->constraint.word_list[0]; | 
|  | rpDouble = new double[nItems]; | 
|  | for( i=0; i<nItems; i++ ) | 
|  | { | 
|  | rpDouble[i] = bIsFixed ? | 
|  | SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) : | 
|  | (double)mppOptions[n]->constraint.word_list[i+1]; | 
|  | } | 
|  | dbg_msg( "wordlist [ %lg ... %lg ]\n", | 
|  | rpDouble[ 0 ], rpDouble[ nItems-1 ] ); | 
|  | return nItems; | 
|  | } | 
|  | } | 
|  |  | 
|  | static const char *ppUnits[] = { | 
|  | "", | 
|  | "[Pixel]", | 
|  | "[Bit]", | 
|  | "[mm]", | 
|  | "[DPI]", | 
|  | "[%]", | 
|  | "[usec]" | 
|  | }; | 
|  |  | 
|  | String Sane::GetOptionUnitName( int n ) | 
|  | { | 
|  | String aText; | 
|  | SANE_Unit nUnit = mppOptions[n]->unit; | 
|  | size_t nUnitAsSize = (size_t)nUnit; | 
|  | if (nUnitAsSize >= sizeof(ppUnits)/sizeof(ppUnits[0])) | 
|  | aText = String::CreateFromAscii( "[unknown units]" ); | 
|  | else | 
|  | aText = String( ppUnits[ nUnit ], gsl_getSystemTextEncoding() ); | 
|  | return aText; | 
|  | } | 
|  |  | 
|  | sal_Bool Sane::ActivateButtonOption( int n ) | 
|  | { | 
|  | SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, NULL ); | 
|  | if( nStatus != SANE_STATUS_GOOD ) | 
|  | return sal_False; | 
|  | return sal_True; | 
|  | } |