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