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