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