Files
libreoffice/extensions/source/scanner/sane.cxx

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

994 lines
34 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
re-base on ALv2 code. Includes (at least) relevant parts of: linecap: Reintegrating finished LineCap feature Patch contributed by Regina Henschel http://svn.apache.org/viewvc?view=revision&revision=1232507 Patches contributed by Sven Jacobi impress212: #i81610# fixed animation export http://svn.apache.org/viewvc?view=revision&revision=1167620 impress212: drawinglayer gbuild environment changes http://svn.apache.org/viewvc?view=revision&revision=1167627 http://svn.apache.org/viewvc?view=revision&revision=1167628 impress212: DffPropSet -> minor code improvements, removing table http://svn.apache.org/viewvc?view=revision&revision=1167634 impress212: #158494# fixed excel import (text rotation) http://svn.apache.org/viewvc?view=revision&revision=1167638 Patches contributed by Armin Le Grand Svg: Reintegrated Svg replacement from /branches/alg/svgreplavement http://svn.apache.org/viewvc?view=revision&revision=1220836 #118728# changed indentifying definitions for Svg file detection http://svn.apache.org/viewvc?view=revision&revision=1229961 #118838# LineGeometry creation for complicated cases optimized to create single Polygons http://svn.apache.org/viewvc?view=revision&revision=1236232 #119176# corrected file type detection for SVG for svg files without xml header http://svn.apache.org/viewvc?view=revision&revision=1309445 #118728# Extended Svg file detection http://svn.apache.org/viewvc?view=revision&revision=1230531 #118529# solve break converters and convert commands for OLEs and images http://svn.apache.org/viewvc?view=revision&revision=1186168 svg: added WaE changes from branch svgreplacement to trunc http://svn.apache.org/viewvc?view=revision&revision=1222974 svg: corrected missing member initialization http://svn.apache.org/viewvc?view=revision&revision=1226134 fix for #118525#: Using primitives for chart sub-geometry visualisation http://svn.apache.org/viewvc?view=revision&revision=1226879 #118898# Adapted ImpGraphic::ImplGetBitmap to correctly convert metafiles to bitmapEx ... http://svn.apache.org/viewvc?view=revision&revision=1293316 fix for #118525#: removed no longer used variable maOriginalMapMode, one more exception eliminated http://svn.apache.org/viewvc?view=revision&revision=1227097 #16758# Added buffering to the VDev usages of the VclProcessor2D derivates... http://svn.apache.org/viewvc?view=revision&revision=1229521 #116758# Secured VDev buffer device to Vcl deinit http://svn.apache.org/viewvc?view=revision&revision=1230574 #116758# added remembering allocated VDevs for VDevBuffer to be able to also delete these when vcl goes down; it should never happen, but You never know http://svn.apache.org/viewvc?view=revision&revision=1230927 #118730# Changed SvgClipPathNode to use MaskPrimitive2D for primitive representation instead of TransparencePrimitive2D http://svn.apache.org/viewvc?view=revision&revision=1231198 #118822# secured 3D geometry creation (slices) by subdividing the 2D source polyPolygon early http://svn.apache.org/viewvc?view=revision&revision=1234749 #118829# enhanced Svg gradient quality, obstacles avoided http://svn.apache.org/viewvc?view=revision&revision=1235361 #118834# Unified usage of TextBreakupHelper as single tooling class for i18n text primitive breakup http://svn.apache.org/viewvc?view=revision&revision=1236110 #118853# added square pixel size limit to conversion of TransparencePrimitive2D to Metafile action http://svn.apache.org/viewvc?view=revision&revision=1237656 #118824# coreccted mirroring and boundrect when the graphicmanager is used for bitmap output http://svn.apache.org/viewvc?view=revision&revision=1240097 #115092# Corrected VclProcessor2D::RenderPolygonStrokePrimitive2D for various optimization scenarios http://svn.apache.org/viewvc?view=revision&revision=1241434 #118783# Corrected errors in ID strings, corrected Svg line/fill export, corrected polygon close state http://svn.apache.org/viewvc?view=revision&revision=1232006 #118796# corrected null-pointer usage in SVG text exporter http://svn.apache.org/viewvc?view=revision&revision=1240262 #118729# Use GraphicStreamUrl and GraphicUrl to allow multi image import with linked graphics, too http://svn.apache.org/viewvc?view=revision&revision=1229962 #118898# corrected error in GDIMetaFile::GetBoundRect in handling MetaFloatTransparentAction http://svn.apache.org/viewvc?view=revision&revision=1293349 #118855# Corrected handling of possibly created empty clipRegions after PolyPolygon clipping http://svn.apache.org/viewvc?view=revision&revision=1237725 #115962# Better (but not yet optimal, see comments in task) handling of MetaFloatTransparentAction in PDF export http://svn.apache.org/viewvc?view=revision&revision=1241078 IP clearance: #118466# This patch removes librsvg, libcroco, libgsf, ... http://svn.apache.org/viewvc?view=revision&revision=1200879 118779# Added svg content streaming in/out to ImpGraphic stream operators http://svn.apache.org/viewvc?view=revision&revision=1231908 linecap: correctons for WaE and mac drawing http://svn.apache.org/viewvc?view=revision&revision=1232793 svg: uses current system Dpi for Svg replacement image creation http://svn.apache.org/viewvc?view=revision&revision=1233948 Patches contributed by Mathias Bauer (and others) gnumake4 work variously http://svn.apache.org/viewvc?view=revision&revision=1394326 http://svn.apache.org/viewvc?view=revision&revision=1396797 http://svn.apache.org/viewvc?view=revision&revision=1397315 http://svn.apache.org/viewvc?view=revision&revision=1394326 Remove duplicate header includes. cws mba34issues01: #i117720#: convert assertion into warning http://svn.apache.org/viewvc?view=revision&revision=1172352 118485 - Styles for OLEs are not saved. Submitted by Armin Le Grand. http://svn.apache.org/viewvc?view=revision&revision=1182166 cws mba34issues01: #i117714#: remove assertion http://svn.apache.org/viewvc?view=revision&revision=1172357 Patch contributed by Jurgen Schmidt add some additional checks to ensure proper reading operations http://svn.apache.org/viewvc?view=revision&revision=1209022 mostly prefer our stream / bounds checking work. Patches contributed by Herbert Duerr #i118816# add clarifying comment regarding Font::*Color*() methods http://svn.apache.org/viewvc?view=revision&revision=1233833 extend macro->string handling for empty strings http://svn.apache.org/viewvc?view=revision&revision=1175801 avoid magic constants for SALCOLOR_NONE http://svn.apache.org/viewvc?view=revision&revision=1177543 initialize slant properly in ImplFontMetricData constructor (author=iorsh) http://svn.apache.org/viewvc?view=revision&revision=1177551 #i118675# make check for extension updates more stable http://svn.apache.org/viewvc?view=revision&revision=1214797 #a118617# remove VBasicEventListener.dll binary There are no known users depending on its CLSID http://svn.apache.org/viewvc?view=revision&revision=1203697 Patches contributed by Ariel Constenla-Haile Fix build breaker on Linux/gcc http://svn.apache.org/viewvc?view=revision&revision=1221104 Fix crash when trying to instantiate css.graphic.GraphicRasterizer_RSVG http://svn.apache.org/viewvc?view=revision&revision=1215559 Patches contributed by Oliver-Rainer Wittmann sw34bf06: #i117962# - method <SwFlyFrm::IsPaint(..)> - consider instances of <SwFlyDrawObj> http://svn.apache.org/viewvc?view=revision&revision=1172120 sw34bf06: #i117783# - Writer's implementation of XPagePrintable - apply print settings to new printing routines http://svn.apache.org/viewvc?view=revision&revision=1172115 gnumake4 work variously from Hans-Joachim Lankenau http://svn.apache.org/viewvc?view=revision&revision=1397315 http://svn.apache.org/viewvc?view=revision&revision=1396797 http://svn.apache.org/viewvc?view=revision&revision=1396782 http://svn.apache.org/viewvc?view=revision&revision=1394707 plus some amount of re-splitting of legacy headers. Patch contributed by Pavel Janik WaE: Remove unused variables. http://svn.apache.org/viewvc?view=revision&revision=1230697 Patches contributed by Takashi Ono mingwport35: i#117795: MinGW port fix for vcl2gnumake http://svn.apache.org/viewvc?view=revision&revision=1172091 mingwport35: i#117795: MinGW port fix for vcl2gnumake http://svn.apache.org/viewvc?view=revision&revision=1172091 Patch contributed by Christian Lippka impress212: #i98044# re enable Text menu for outline and title shapes http://svn.apache.org/viewvc?view=revision&revision=1167639 Patch contributed by Andre Fischer 118674: Made category B code optional and disabled by default. http://svn.apache.org/viewvc?view=revision&revision=1215131 118881: Ignore empty paragraphs after bullets. http://svn.apache.org/viewvc?view=revision&revision=1296205 Patches contributed by Philipp Lohmann ooo340fixes: #i117780# use rtl allocator http://svn.apache.org/viewvc?view=revision&revision=1172087 ooo34gsl02: #i117807# fix an off by one error (index actually inside the pfb section header) http://svn.apache.org/viewvc?view=revision&revision=1167576 various cleanups, related compilation fixes, warning cleanups, re-working of obsolete stl template pieces to use boost instead, changed string classes, re-adapt KDE about data, about dialog, fixing warnings, and other fixes & improvements. Disable svg import / render for about/ branding code-paths for now. Restore full icon theme set. Remove OS/2 conditionals and sources. Remove conflicting gtk/full-screen monitors support. Retain existing svg rasterizer files - temporarily disabled. Standardize stringificaiton and fixup dllpostfix issues. Rename SvgGradientHelper::== to equalTo to avoid overloading issues. Use the flat GdiPlus API for LineCaps calls.
2012-10-09 12:22:23 +01:00
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <type_traits>
2002-04-03 12:24:35 +00:00
#include <math.h>
New loplugin:unsignedcompare "Find explicit casts from signed to unsigned integer in comparison against unsigned integer, where the cast is presumably used to avoid warnings about signed vs. unsigned comparisons, and could thus be replaced with o3tl::make_unsigned for clairty." (compilerplugins/clang/unsignedcompare.cxx) o3tl::make_unsigned requires its argument to be non-negative, and there is a chance that some original code like static_cast<sal_uInt32>(n) >= c used the explicit cast to actually force a (potentially negative) value of sal_Int32 to be interpreted as an unsigned sal_uInt32, rather than using the cast to avoid a false "signed vs. unsigned comparison" warning in a case where n is known to be non-negative. It appears that restricting this plugin to non- equality comparisons (<, >, <=, >=) and excluding equality comparisons (==, !=) is a useful heuristic to avoid such false positives. The only remainging false positive I found was 0288c8ffecff4956a52b9147d441979941e8b87f "Rephrase cast from sal_Int32 to sal_uInt32". But which of course does not mean that there were no further false positivies that I missed. So this commit may accidentally introduce some false hits of the assert in o3tl::make_unsigned. At least, it passed a full (Linux ASan+UBSan --enable-dbgutil) `make check && make screenshot`. It is by design that o3tl::make_unsigned only accepts signed integer parameter types (and is not defined as a nop for unsigned ones), to avoid unnecessary uses which would in general be suspicious. But the STATIC_ARRAY_SELECT macro in include/oox/helper/helper.hxx is used with both signed and unsigned types, so needs a little oox::detail::make_unsigned helper function for now. (The ultimate fix being to get rid of the macro in the first place.) Change-Id: Ia4adc9f44c70ad1dfd608784cac39ee922c32175 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87556 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2020-01-27 09:30:39 +01:00
#include <o3tl/safeint.hxx>
#include <osl/file.h>
#include <sal/log.hxx>
2000-09-18 15:18:56 +00:00
#include <tools/stream.hxx>
#include <unotools/tempfile.hxx>
#include "sane.hxx"
2000-09-18 15:18:56 +00:00
#include <dlfcn.h>
#include <stdio.h>
#include <sys/time.h>
#include <sal/config.h>
#include <sal/macros.h>
#include <memory>
2000-09-18 15:18:56 +00:00
#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
2000-09-18 15:18:56 +00:00
#include <stdarg.h>
#define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d );
#else
#define dump_state( a, b, c, d ) ;
#endif
static void dbg_msg( const char* pString, ... )
2000-09-18 15:18:56 +00:00
{
#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
2000-09-18 15:18:56 +00:00
va_list ap;
va_start( ap, pString );
vfprintf( stderr, pString, ap );
va_end( ap );
#else
(void)pString;
2000-09-18 15:18:56 +00:00
#endif
}
#define FAIL_SHUTDOWN_STATE( x, y, z ) \
if( x != SANE_STATUS_GOOD ) \
{ \
dump_state( "%s returned error %d (%s)\n", \
y, x, p_strstatus( x ) ); \
DeInit(); \
return z; \
}
#define FAIL_STATE( x, y, z ) \
if( x != SANE_STATUS_GOOD ) \
{ \
dump_state( "%s returned error %d (%s)\n", \
y, x, p_strstatus( x ) ); \
return z; \
}
#define DUMP_STATE( x, y ) \
if( x != SANE_STATUS_GOOD ) \
{ \
dump_state( "%s returned error %d (%s)\n", \
y, x, p_strstatus( x ) ); \
}
int Sane::nRefCount = 0;
oslModule Sane::pSaneLib = nullptr;
2000-09-18 15:18:56 +00:00
SANE_Int Sane::nVersion = 0;
SANE_Device** Sane::ppDevices = nullptr;
2000-09-18 15:18:56 +00:00
int Sane::nDevices = 0;
SANE_Status (*Sane::p_init)( SANE_Int*,
SANE_Auth_Callback ) = nullptr;
void (*Sane::p_exit)() = nullptr;
2000-09-18 15:18:56 +00:00
SANE_Status (*Sane::p_get_devices)( const SANE_Device***,
SANE_Bool ) = nullptr;
SANE_Status (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = nullptr;
void (*Sane::p_close)( SANE_Handle ) = nullptr;
2000-09-18 15:18:56 +00:00
const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)(
SANE_Handle, SANE_Int ) = nullptr;
2000-09-18 15:18:56 +00:00
SANE_Status (*Sane::p_control_option)( SANE_Handle, SANE_Int,
SANE_Action, void*,
SANE_Int* ) = nullptr;
2000-09-18 15:18:56 +00:00
SANE_Status (*Sane::p_get_parameters)( SANE_Handle,
SANE_Parameters* ) = nullptr;
SANE_Status (*Sane::p_start)( SANE_Handle ) = nullptr;
2000-09-18 15:18:56 +00:00
SANE_Status (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int,
SANE_Int* ) = nullptr;
void (*Sane::p_cancel)( SANE_Handle ) = nullptr;
SANE_Status (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = nullptr;
SANE_Status (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = nullptr;
SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = nullptr;
2000-09-18 15:18:56 +00:00
static bool bSaneSymbolLoadFailed = false;
2000-09-18 15:18:56 +00:00
inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname )
2000-09-18 15:18:56 +00:00
{
oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname );
if( ! pFunction )
2000-09-18 15:18:56 +00:00
{
fprintf( stderr, "Could not load symbol %s\n",
pSymbolname );
bSaneSymbolLoadFailed = true;
2000-09-18 15:18:56 +00:00
}
return pFunction;
2000-09-18 15:18:56 +00:00
}
SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction,
void* pData )
{
SANE_Int nInfo = 0;
SANE_Status nStatus = p_control_option( maHandle, static_cast<SANE_Int>(nOption),
2000-09-18 15:18:56 +00:00
nAction, pData, &nInfo );
DUMP_STATE( nStatus, "sane_control_option" );
#if OSL_DEBUG_LEVEL > 0
2000-09-18 15:18:56 +00:00
if( nStatus != SANE_STATUS_GOOD )
{
2008-07-31 11:58:34 +00:00
const char* pAction = "Unknown";
2000-09-18 15:18:56 +00:00
switch( nAction )
{
case SANE_ACTION_GET_VALUE:
pAction = "SANE_ACTION_GET_VALUE";break;
case SANE_ACTION_SET_VALUE:
pAction = "SANE_ACTION_SET_VALUE";break;
case SANE_ACTION_SET_AUTO:
pAction = "SANE_ACTION_SET_AUTO";break;
}
dbg_msg( "Option: \"%s\" action: %s\n",
OUStringToOString(GetOptionName(nOption), osl_getThreadTextEncoding()).getStr(),
2000-09-18 15:18:56 +00:00
pAction );
}
#endif
if( nInfo & SANE_INFO_RELOAD_OPTIONS )
ReloadOptions();
return nStatus;
}
Sane::Sane() :
mnOptions( 0 ),
mnDevice( -1 ),
maHandle( nullptr )
2000-09-18 15:18:56 +00:00
{
if( ! nRefCount || ! pSaneLib )
Init();
nRefCount++;
};
Sane::~Sane()
{
if( IsOpen() )
Close();
nRefCount--;
if( ! nRefCount && pSaneLib )
DeInit();
}
void Sane::Init()
{
OUString sSaneLibName( "libsane" SAL_DLLEXTENSION );
pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
if( ! pSaneLib )
{
sSaneLibName = "libsane" SAL_DLLEXTENSION ".1";
pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
}
// try reasonable places that might not be in the library search path
if( ! pSaneLib )
{
OUString sSaneLibSystemPath( "/usr/local/lib/libsane" SAL_DLLEXTENSION );
osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData );
pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
}
2000-09-18 15:18:56 +00:00
if( pSaneLib )
{
bSaneSymbolLoadFailed = false;
p_init = reinterpret_cast<SANE_Status(*)(SANE_Int*, SANE_Auth_Callback )>(
LoadSymbol( "sane_init" ));
p_exit = reinterpret_cast<void(*)()>(
LoadSymbol( "sane_exit" ));
p_get_devices = reinterpret_cast<SANE_Status(*)(const SANE_Device***,
SANE_Bool )>(
LoadSymbol( "sane_get_devices" ));
p_open = reinterpret_cast<SANE_Status(*)(SANE_String_Const, SANE_Handle )>(
LoadSymbol( "sane_open" ));
p_close = reinterpret_cast<void(*)(SANE_Handle)>(
LoadSymbol( "sane_close" ));
p_get_option_descriptor = reinterpret_cast<const SANE_Option_Descriptor*(*)(SANE_Handle,
SANE_Int)>(
LoadSymbol( "sane_get_option_descriptor" ));
p_control_option = reinterpret_cast<SANE_Status(*)(SANE_Handle, SANE_Int,
SANE_Action, void*, SANE_Int*)>(
LoadSymbol( "sane_control_option" ));
p_get_parameters = reinterpret_cast<SANE_Status(*)(SANE_Handle,SANE_Parameters*)>(
LoadSymbol( "sane_get_parameters" ));
p_start = reinterpret_cast<SANE_Status(*)(SANE_Handle)>(
LoadSymbol( "sane_start" ));
p_read = reinterpret_cast<SANE_Status(*)(SANE_Handle, SANE_Byte*,
SANE_Int, SANE_Int* )>(
LoadSymbol( "sane_read" ));
p_cancel = reinterpret_cast<void(*)(SANE_Handle)>(
LoadSymbol( "sane_cancel" ));
p_set_io_mode = reinterpret_cast<SANE_Status(*)(SANE_Handle, SANE_Bool)>(
LoadSymbol( "sane_set_io_mode" ));
p_get_select_fd = reinterpret_cast<SANE_Status(*)(SANE_Handle, SANE_Int*)>(
LoadSymbol( "sane_get_select_fd" ));
p_strstatus = reinterpret_cast<SANE_String_Const(*)(SANE_Status)>(
LoadSymbol( "sane_strstatus" ));
2000-09-18 15:18:56 +00:00
if( bSaneSymbolLoadFailed )
DeInit();
else
{
SANE_Status nStatus = p_init( &nVersion, nullptr );
2000-09-18 15:18:56 +00:00
FAIL_SHUTDOWN_STATE( nStatus, "sane_init", );
nStatus = p_get_devices( const_cast<const SANE_Device***>(&ppDevices),
2000-09-18 15:18:56 +00:00
SANE_FALSE );
FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", );
2008-10-10 13:02:43 +00:00
for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ;
2000-09-18 15:18:56 +00:00
}
}
#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
2000-09-18 15:18:56 +00:00
else
fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION,
2000-09-18 15:18:56 +00:00
dlerror() );
#endif
}
void Sane::DeInit()
{
if( pSaneLib )
{
p_exit();
osl_unloadModule( pSaneLib );
pSaneLib = nullptr;
2000-09-18 15:18:56 +00:00
}
}
void Sane::ReloadDevices()
{
if( IsOpen() )
Close();
DeInit();
Init();
}
void Sane::ReloadOptions()
{
if( ! IsOpen() )
return;
const SANE_Option_Descriptor* pZero = p_get_option_descriptor( maHandle, 0 );
2000-09-18 15:18:56 +00:00
SANE_Word pOptions[2];
SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE,
static_cast<void*>(pOptions), nullptr );
2000-09-18 15:18:56 +00:00
if( nStatus != SANE_STATUS_GOOD )
fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) );
mnOptions = pOptions[ 0 ];
New loplugin:unsignedcompare "Find explicit casts from signed to unsigned integer in comparison against unsigned integer, where the cast is presumably used to avoid warnings about signed vs. unsigned comparisons, and could thus be replaced with o3tl::make_unsigned for clairty." (compilerplugins/clang/unsignedcompare.cxx) o3tl::make_unsigned requires its argument to be non-negative, and there is a chance that some original code like static_cast<sal_uInt32>(n) >= c used the explicit cast to actually force a (potentially negative) value of sal_Int32 to be interpreted as an unsigned sal_uInt32, rather than using the cast to avoid a false "signed vs. unsigned comparison" warning in a case where n is known to be non-negative. It appears that restricting this plugin to non- equality comparisons (<, >, <=, >=) and excluding equality comparisons (==, !=) is a useful heuristic to avoid such false positives. The only remainging false positive I found was 0288c8ffecff4956a52b9147d441979941e8b87f "Rephrase cast from sal_Int32 to sal_uInt32". But which of course does not mean that there were no further false positivies that I missed. So this commit may accidentally introduce some false hits of the assert in o3tl::make_unsigned. At least, it passed a full (Linux ASan+UBSan --enable-dbgutil) `make check && make screenshot`. It is by design that o3tl::make_unsigned only accepts signed integer parameter types (and is not defined as a nop for unsigned ones), to avoid unnecessary uses which would in general be suspicious. But the STATIC_ARRAY_SELECT macro in include/oox/helper/helper.hxx is used with both signed and unsigned types, so needs a little oox::detail::make_unsigned helper function for now. (The ultimate fix being to get rid of the macro in the first place.) Change-Id: Ia4adc9f44c70ad1dfd608784cac39ee922c32175 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87556 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2020-01-27 09:30:39 +01:00
if( o3tl::make_unsigned(pZero->size) > sizeof( SANE_Word ) )
fprintf( stderr, "driver returned number of options with larger size than SANE_Word!!!\n" );
mppOptions.reset(new const SANE_Option_Descriptor*[ mnOptions ]);
mppOptions[ 0 ] = pZero;
2000-09-18 15:18:56 +00:00
for( int i = 1; i < mnOptions; i++ )
mppOptions[ i ] = p_get_option_descriptor( maHandle, i );
2000-09-18 15:18:56 +00:00
CheckConsistency( nullptr, true );
2000-09-18 15:18:56 +00:00
maReloadOptionsLink.Call( *this );
2000-09-18 15:18:56 +00:00
}
bool Sane::Open( const char* name )
2000-09-18 15:18:56 +00:00
{
SANE_Status nStatus = p_open( reinterpret_cast<SANE_String_Const>(name), &maHandle );
FAIL_STATE( nStatus, "sane_open", false );
2000-09-18 15:18:56 +00:00
ReloadOptions();
if( mnDevice == -1 )
{
OString aDevice( name );
for( int i = 0; i < nDevices; i++ )
2000-09-18 15:18:56 +00:00
{
if( aDevice == ppDevices[i]->name )
2000-09-18 15:18:56 +00:00
{
mnDevice = i;
break;
}
}
}
return true;
2000-09-18 15:18:56 +00:00
}
bool Sane::Open( int n )
2000-09-18 15:18:56 +00:00
{
if( n >= 0 && n < nDevices )
{
mnDevice = n;
return Open( ppDevices[n]->name );
2000-09-18 15:18:56 +00:00
}
return false;
2000-09-18 15:18:56 +00:00
}
void Sane::Close()
{
if( maHandle )
{
p_close( maHandle );
mppOptions.reset();
maHandle = nullptr;
2000-09-18 15:18:56 +00:00
mnDevice = -1;
}
}
int Sane::GetOptionByName( const char* rName )
{
int i;
OString aOption( rName );
2000-09-18 15:18:56 +00:00
for( i = 0; i < mnOptions; i++ )
{
if( mppOptions[i]->name && aOption == mppOptions[i]->name )
2000-09-18 15:18:56 +00:00
return i;
}
return -1;
}
bool Sane::GetOptionValue( int n, bool& rRet )
2000-09-18 15:18:56 +00:00
{
if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL )
return false;
2000-09-18 15:18:56 +00:00
SANE_Word nRet;
SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet );
if( nStatus != SANE_STATUS_GOOD )
return false;
2000-09-18 15:18:56 +00:00
rRet = nRet;
return true;
2000-09-18 15:18:56 +00:00
}
bool Sane::GetOptionValue( int n, OString& rRet )
2000-09-18 15:18:56 +00:00
{
bool bSuccess = false;
2000-09-18 15:18:56 +00:00
if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING )
return false;
std::unique_ptr<char[]> pRet(new char[mppOptions[n]->size+1]);
SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet.get() );
2000-09-18 15:18:56 +00:00
if( nStatus == SANE_STATUS_GOOD )
{
bSuccess = true;
rRet = pRet.get();
2000-09-18 15:18:56 +00:00
}
return bSuccess;
}
bool Sane::GetOptionValue( int n, double& rRet, int nElement )
2000-09-18 15:18:56 +00:00
{
bool bSuccess = false;
2000-09-18 15:18:56 +00:00
if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
mppOptions[n]->type != SANE_TYPE_FIXED ) )
return false;
2000-09-18 15:18:56 +00:00
std::unique_ptr<SANE_Word[]> pRet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet.get() );
2000-09-18 15:18:56 +00:00
if( nStatus == SANE_STATUS_GOOD )
{
bSuccess = true;
2000-09-18 15:18:56 +00:00
if( mppOptions[n]->type == SANE_TYPE_INT )
rRet = static_cast<double>(pRet[ nElement ]);
2000-09-18 15:18:56 +00:00
else
rRet = SANE_UNFIX( pRet[nElement] );
}
return bSuccess;
}
bool Sane::GetOptionValue( int n, double* pSet )
2000-09-18 15:18:56 +00:00
{
if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_FIXED &&
mppOptions[n]->type != SANE_TYPE_INT ) )
return false;
2000-09-18 15:18:56 +00:00
std::unique_ptr<SANE_Word[]> pFixedSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet.get() );
2000-09-18 15:18:56 +00:00
if( nStatus != SANE_STATUS_GOOD )
return false;
for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ )
2000-09-18 15:18:56 +00:00
{
if( mppOptions[n]->type == SANE_TYPE_FIXED )
pSet[i] = SANE_UNFIX( pFixedSet[i] );
else
pSet[i] = static_cast<double>(pFixedSet[i]);
2000-09-18 15:18:56 +00:00
}
return true;
2000-09-18 15:18:56 +00:00
}
void Sane::SetOptionValue( int n, bool bSet )
2000-09-18 15:18:56 +00:00
{
if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL )
return;
2000-09-18 15:18:56 +00:00
SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE;
ControlOption( n, SANE_ACTION_SET_VALUE, &nRet );
2000-09-18 15:18:56 +00:00
}
void Sane::SetOptionValue( int n, std::u16string_view rSet )
2000-09-18 15:18:56 +00:00
{
if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING )
return;
OString aSet(OUStringToOString(rSet, osl_getThreadTextEncoding()));
ControlOption( n, SANE_ACTION_SET_VALUE, const_cast<char *>(aSet.getStr()) );
2000-09-18 15:18:56 +00:00
}
void Sane::SetOptionValue( int n, double fSet, int nElement )
2000-09-18 15:18:56 +00:00
{
if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
mppOptions[n]->type != SANE_TYPE_FIXED ) )
return;
2000-09-18 15:18:56 +00:00
if( mppOptions[n]->size/sizeof(SANE_Word) > 1 )
{
std::unique_ptr<SANE_Word[]> pSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet.get() );
2000-09-18 15:18:56 +00:00
if( nStatus == SANE_STATUS_GOOD )
{
pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ?
static_cast<SANE_Word>(fSet) : SANE_FIX( fSet );
ControlOption( n, SANE_ACTION_SET_VALUE, pSet.get() );
2000-09-18 15:18:56 +00:00
}
}
else
{
SANE_Word nSetTo =
mppOptions[n]->type == SANE_TYPE_INT ?
static_cast<SANE_Word>(fSet) : SANE_FIX( fSet );
2000-09-18 15:18:56 +00:00
ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo );
2000-09-18 15:18:56 +00:00
}
}
void Sane::SetOptionValue( int n, double const * pSet )
2000-09-18 15:18:56 +00:00
{
if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
mppOptions[n]->type != SANE_TYPE_FIXED ) )
return;
std::unique_ptr<SANE_Word[]> pFixedSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]);
for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ )
2000-09-18 15:18:56 +00:00
{
if( mppOptions[n]->type == SANE_TYPE_FIXED )
pFixedSet[i] = SANE_FIX( pSet[i] );
else
pFixedSet[i] = static_cast<SANE_Word>(pSet[i]);
2000-09-18 15:18:56 +00:00
}
ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet.get() );
2000-09-18 15:18:56 +00:00
}
namespace {
2000-09-18 15:18:56 +00:00
enum FrameStyleType {
FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated
};
}
2000-09-18 15:18:56 +00:00
#define BYTE_BUFFER_SIZE 32768
static sal_uInt8 ReadValue( FILE* fp, int depth )
2000-09-18 15:18:56 +00:00
{
if( depth == 16 )
{
sal_uInt16 nWord;
2000-09-18 15:18:56 +00:00
// data always come in native byte order !
// 16 bits is not really supported by backends as of now
// e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN
// against SANE documentation (xscanimage gets the same result
// as we do
2012-04-21 14:29:14 +02:00
size_t items_read = fread( &nWord, 1, 2, fp );
if (items_read != 2)
2012-04-21 14:29:14 +02:00
{
SAL_WARN( "extensions.scanner", "short read, abandoning" );
return 0;
2012-04-21 14:29:14 +02:00
}
return static_cast<sal_uInt8>( nWord / 256 );
2000-09-18 15:18:56 +00:00
}
sal_uInt8 nByte;
2012-04-21 14:29:14 +02:00
size_t items_read = fread( &nByte, 1, 1, fp );
if (items_read != 1)
2012-04-21 14:29:14 +02:00
{
SAL_WARN( "extensions.scanner", "short read, abandoning" );
return 0;
2012-04-21 14:29:14 +02:00
}
2000-09-18 15:18:56 +00:00
return nByte;
}
bool Sane::CheckConsistency( const char* pMes, bool bInit )
2000-09-18 15:18:56 +00:00
{
static const SANE_Option_Descriptor** pDescArray = nullptr;
static const SANE_Option_Descriptor* pZero = nullptr;
2000-09-18 15:18:56 +00:00
if( bInit )
{
pDescArray = mppOptions.get();
2000-09-18 15:18:56 +00:00
if( mppOptions )
pZero = mppOptions[0];
return true;
2000-09-18 15:18:56 +00:00
}
bool bConsistent = true;
2000-09-18 15:18:56 +00:00
if( pDescArray != mppOptions.get() )
bConsistent = false;
2000-09-18 15:18:56 +00:00
if( pZero != mppOptions[0] )
bConsistent = false;
2000-09-18 15:18:56 +00:00
if( ! bConsistent )
dbg_msg( "Sane is not consistent. (%s)\n", pMes );
return bConsistent;
}
bool Sane::Start( BitmapTransporter& rBitmap )
2000-09-18 15:18:56 +00:00
{
int nStream = 0, nLine = 0, i = 0;
SANE_Parameters aParams;
FrameStyleType eType = FrameStyle_Gray;
bool bSuccess = true;
bool bWidthSet = false;
2000-09-18 15:18:56 +00:00
if( ! maHandle )
return false;
2000-09-18 15:18:56 +00:00
int nWidthMM = 0;
int nHeightMM = 0;
double fTLx, fTLy, fResl = 0.0;
int nOption;
nOption = GetOptionByName( "tl-x" );
if( nOption != -1 &&
GetOptionValue( nOption, fTLx ) &&
GetOptionUnit( nOption ) == SANE_UNIT_MM )
{
double fBRx;
nOption = GetOptionByName( "br-x" );
if( nOption != -1 &&
GetOptionValue( nOption, fBRx ) &&
GetOptionUnit( nOption ) == SANE_UNIT_MM )
{
nWidthMM = static_cast<int>(fabs(fBRx - fTLx));
}
}
nOption = GetOptionByName( "tl-y" );
if( nOption != -1 &&
GetOptionValue( nOption, fTLy ) &&
GetOptionUnit( nOption ) == SANE_UNIT_MM )
{
double fBRy;
nOption = GetOptionByName( "br-y" );
if( nOption != -1 &&
GetOptionValue( nOption, fBRy ) &&
GetOptionUnit( nOption ) == SANE_UNIT_MM )
{
nHeightMM = static_cast<int>(fabs(fBRy - fTLy));
}
}
if( ( nOption = GetOptionByName( "resolution" ) ) != -1 )
(void)GetOptionValue( nOption, fResl );
std::unique_ptr<sal_uInt8[]> pBuffer;
2000-09-18 15:18:56 +00:00
SANE_Status nStatus = SANE_STATUS_GOOD;
rBitmap.lock();
SvMemoryStream& aConverter = rBitmap.getStream();
aConverter.Seek( 0 );
aConverter.SetEndian( SvStreamEndian::LITTLE );
2000-09-18 15:18:56 +00:00
// write bitmap stream header
aConverter.WriteChar( 'B' ).WriteChar( 'M' );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 60 );
2000-09-18 15:18:56 +00:00
// write BITMAPINFOHEADER
aConverter.WriteUInt32( 40 );
aConverter.WriteUInt32( 0 ); // fill in width later
aConverter.WriteUInt32( 0 ); // fill in height later
aConverter.WriteUInt16( 1 );
2000-09-18 15:18:56 +00:00
// create header for 24 bits
// correct later if necessary
aConverter.WriteUInt16( 24 );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 0 );
aConverter.WriteUInt32( 0 );
2000-09-18 15:18:56 +00:00
for( nStream=0; nStream < 3 && bSuccess ; nStream++ )
{
nStatus = p_start( maHandle );
DUMP_STATE( nStatus, "sane_start" );
CheckConsistency( "sane_start" );
if( nStatus == SANE_STATUS_GOOD )
{
nStatus = p_get_parameters( maHandle, &aParams );
DUMP_STATE( nStatus, "sane_get_parameters" );
CheckConsistency( "sane_get_parameters" );
if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0)
{
bSuccess = false;
break;
}
#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
const char* const ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB",
2000-09-18 15:18:56 +00:00
"SANE_FRAME_RED", "SANE_FRAME_GREEN",
"SANE_FRAME_BLUE", "Unknown !!!" };
fprintf( stderr, "Parameters for frame %d:\n", nStream );
if( static_cast<
typename std::make_unsigned<
typename std::underlying_type<SANE_Frame>::type>::type>(
aParams.format)
> 4 )
{
aParams.format = SANE_Frame(5);
}
fprintf( stderr, "format: %s\n", ppFormats[ static_cast<int>(aParams.format) ] );
2000-09-18 15:18:56 +00:00
fprintf( stderr, "last_frame: %s\n", aParams.last_frame ? "TRUE" : "FALSE" );
fprintf( stderr, "depth: %d\n", static_cast<int>(aParams.depth) );
fprintf( stderr, "pixels_per_line: %d\n", static_cast<int>(aParams.pixels_per_line) );
fprintf( stderr, "bytes_per_line: %d\n", static_cast<int>(aParams.bytes_per_line) );
2000-09-18 15:18:56 +00:00
#endif
if( ! pBuffer )
{
pBuffer.reset(new sal_uInt8[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ]);
2000-09-18 15:18:56 +00:00
}
if( aParams.last_frame )
nStream=3;
switch( aParams.format )
{
case SANE_FRAME_GRAY:
eType = FrameStyle_Gray;
if( aParams.depth == 1 )
eType = FrameStyle_BW;
break;
case SANE_FRAME_RGB:
eType = FrameStyle_RGB;
break;
case SANE_FRAME_RED:
case SANE_FRAME_GREEN:
case SANE_FRAME_BLUE:
eType = FrameStyle_Separated;
break;
default:
fprintf( stderr, "Warning: unknown frame style !!!\n" );
}
bool bSynchronousRead = true;
2000-09-18 15:18:56 +00:00
// should be fail safe, but ... ??
nStatus = p_set_io_mode( maHandle, SANE_FALSE );
CheckConsistency( "sane_set_io_mode" );
if( nStatus != SANE_STATUS_GOOD )
{
bSynchronousRead = false;
nStatus = p_set_io_mode(maHandle, SANE_TRUE);
2000-09-18 15:18:56 +00:00
CheckConsistency( "sane_set_io_mode" );
if (nStatus != SANE_STATUS_GOOD)
{
SAL_WARN("extensions.scanner", "SANE driver status is: " << nStatus);
}
2000-09-18 15:18:56 +00:00
}
SANE_Int nLen=0;
SANE_Int fd = 0;
if( ! bSynchronousRead )
{
nStatus = p_get_select_fd( maHandle, &fd );
DUMP_STATE( nStatus, "sane_get_select_fd" );
CheckConsistency( "sane_get_select_fd" );
if( nStatus != SANE_STATUS_GOOD )
bSynchronousRead = true;
2000-09-18 15:18:56 +00:00
}
utl::TempFile aFrame;
aFrame.EnableKillingFile();
FILE* pFrame = fopen(OUStringToOString(aFrame.GetFileName(), osl_getThreadTextEncoding()).getStr(), "w+b");
2000-09-18 15:18:56 +00:00
if( ! pFrame )
{
bSuccess = false;
2000-09-18 15:18:56 +00:00
break;
}
do {
if( ! bSynchronousRead )
{
fd_set fdset;
struct timeval tv;
FD_ZERO( &fdset );
FD_SET( static_cast<int>(fd), &fdset );
2000-09-18 15:18:56 +00:00
tv.tv_sec = 5;
tv.tv_usec = 0;
if( select( fd+1, &fdset, nullptr, nullptr, &tv ) == 0 )
fprintf( stderr, "Timeout on sane_read descriptor\n" );
2000-09-18 15:18:56 +00:00
}
nLen = 0;
nStatus = p_read( maHandle, pBuffer.get(), BYTE_BUFFER_SIZE, &nLen );
2000-09-18 15:18:56 +00:00
CheckConsistency( "sane_read" );
if( nLen && ( nStatus == SANE_STATUS_GOOD ||
nStatus == SANE_STATUS_EOF ) )
{
bSuccess = (static_cast<size_t>(nLen) == fwrite( pBuffer.get(), 1, nLen, pFrame ));
if (!bSuccess)
break;
2000-09-18 15:18:56 +00:00
}
else
DUMP_STATE( nStatus, "sane_read" );
} while( nStatus == SANE_STATUS_GOOD );
if (nStatus != SANE_STATUS_EOF || !bSuccess)
2000-09-18 15:18:56 +00:00
{
fclose( pFrame );
bSuccess = false;
2000-09-18 15:18:56 +00:00
break;
}
int nFrameLength = ftell( pFrame );
fseek( pFrame, 0, SEEK_SET );
sal_uInt32 nWidth = static_cast<sal_uInt32>(aParams.pixels_per_line);
sal_uInt32 nHeight = static_cast<sal_uInt32>(nFrameLength / aParams.bytes_per_line);
2000-09-18 15:18:56 +00:00
if( ! bWidthSet )
{
if( ! fResl )
fResl = 300; // if all else fails that's a good guess
if( ! nWidthMM )
nWidthMM = static_cast<int>((static_cast<double>(nWidth) / fResl) * 25.4);
if( ! nHeightMM )
nHeightMM = static_cast<int>((static_cast<double>(nHeight) / fResl) * 25.4);
SAL_INFO("extensions.scanner", "set dimensions to(" << nWidth << ", " << nHeight << ") Pixel, (" << nWidthMM << ", " << nHeightMM <<
") mm, resolution is " << fResl);
2000-09-18 15:18:56 +00:00
aConverter.Seek( 18 );
aConverter.WriteUInt32( nWidth );
aConverter.WriteUInt32( nHeight );
aConverter.Seek( 38 );
aConverter.WriteUInt32( 1000*nWidth/nWidthMM );
aConverter.WriteUInt32( 1000*nHeight/nHeightMM );
bWidthSet = true;
2000-09-18 15:18:56 +00:00
}
aConverter.Seek(60);
if( eType == FrameStyle_BW )
{
aConverter.Seek( 10 );
aConverter.WriteUInt32( 64 );
2000-09-18 15:18:56 +00:00
aConverter.Seek( 28 );
aConverter.WriteUInt16( 1 );
2000-09-18 15:18:56 +00:00
aConverter.Seek( 54 );
// write color table
aConverter.WriteUInt16( 0xffff );
aConverter.WriteUChar( 0xff );
aConverter.WriteUChar( 0 );
aConverter.WriteUInt32( 0 );
2000-09-18 15:18:56 +00:00
aConverter.Seek( 64 );
}
else if( eType == FrameStyle_Gray )
{
aConverter.Seek( 10 );
aConverter.WriteUInt32( 1084 );
2000-09-18 15:18:56 +00:00
aConverter.Seek( 28 );
aConverter.WriteUInt16( 8 );
2000-09-18 15:18:56 +00:00
aConverter.Seek( 54 );
// write color table
for( nLine = 0; nLine < 256; nLine++ )
{
aConverter.WriteUChar( nLine );
aConverter.WriteUChar( nLine );
aConverter.WriteUChar( nLine );
aConverter.WriteUChar( 0 );
2000-09-18 15:18:56 +00:00
}
aConverter.Seek( 1084 );
}
for (nLine = nHeight-1; nLine >= 0; --nLine)
2000-09-18 15:18:56 +00:00
{
if (fseek(pFrame, nLine * aParams.bytes_per_line, SEEK_SET) == -1)
{
bSuccess = false;
break;
}
2000-09-18 15:18:56 +00:00
if( eType == FrameStyle_BW ||
( eType == FrameStyle_Gray && aParams.depth == 8 )
)
{
SANE_Int items_read = fread( pBuffer.get(), 1, aParams.bytes_per_line, pFrame );
if (items_read != aParams.bytes_per_line)
2012-04-21 14:29:14 +02:00
{
SAL_WARN( "extensions.scanner", "short read, padding with zeros" );
memset(pBuffer.get() + items_read, 0, aParams.bytes_per_line - items_read);
2012-04-21 14:29:14 +02:00
}
aConverter.WriteBytes(pBuffer.get(), aParams.bytes_per_line);
2000-09-18 15:18:56 +00:00
}
else if( eType == FrameStyle_Gray )
{
for( i = 0; i < (aParams.pixels_per_line); i++ )
{
sal_uInt8 nGray = ReadValue( pFrame, aParams.depth );
aConverter.WriteUChar( nGray );
2000-09-18 15:18:56 +00:00
}
}
else if( eType == FrameStyle_RGB )
{
for( i = 0; i < (aParams.pixels_per_line); i++ )
{
sal_uInt8 nRed, nGreen, nBlue;
nRed = ReadValue( pFrame, aParams.depth );
nGreen = ReadValue( pFrame, aParams.depth );
nBlue = ReadValue( pFrame, aParams.depth );
aConverter.WriteUChar( nBlue );
aConverter.WriteUChar( nGreen );
aConverter.WriteUChar( nRed );
2000-09-18 15:18:56 +00:00
}
}
else if( eType == FrameStyle_Separated )
{
for( i = 0; i < (aParams.pixels_per_line); i++ )
{
sal_uInt8 nValue = ReadValue( pFrame, aParams.depth );
2000-09-18 15:18:56 +00:00
switch( aParams.format )
{
case SANE_FRAME_RED:
aConverter.SeekRel( 2 );
aConverter.WriteUChar( nValue );
2000-09-18 15:18:56 +00:00
break;
case SANE_FRAME_GREEN:
aConverter.SeekRel( 1 );
aConverter.WriteUChar( nValue );
2000-09-18 15:18:56 +00:00
aConverter.SeekRel( 1 );
break;
case SANE_FRAME_BLUE:
aConverter.WriteUChar( nValue );
2000-09-18 15:18:56 +00:00
aConverter.SeekRel( 2 );
break;
case SANE_FRAME_GRAY:
case SANE_FRAME_RGB:
break;
2000-09-18 15:18:56 +00:00
}
}
}
int nGap = aConverter.Tell() & 3;
if (nGap)
aConverter.SeekRel( 4-nGap );
2000-09-18 15:18:56 +00:00
}
fclose( pFrame ); // deletes tmpfile
if( eType != FrameStyle_Separated )
break;
}
else
bSuccess = false;
2000-09-18 15:18:56 +00:00
}
// get stream length
int nPos = aConverter.TellEnd();
2000-09-18 15:18:56 +00:00
aConverter.Seek( 2 );
aConverter.WriteUInt32( nPos+1 );
2000-09-18 15:18:56 +00:00
aConverter.Seek( 0 );
rBitmap.unlock();
if( bSuccess )
{
// only cancel a successful operation
// sane disrupts memory else
p_cancel( maHandle );
CheckConsistency( "sane_cancel" );
}
pBuffer.reset();
2000-09-18 15:18:56 +00:00
ReloadOptions();
dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" );
return bSuccess;
}
int Sane::GetRange( int n, std::unique_ptr<double[]>& rpDouble )
2000-09-18 15:18:56 +00:00
{
if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE &&
mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST )
{
return -1;
}
rpDouble = nullptr;
2000-09-18 15:18:56 +00:00
int nItems, i;
bool bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED;
2000-09-18 15:18:56 +00:00
dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name );
if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE )
{
double fMin, fMax, fQuant;
if( bIsFixed )
{
fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min );
fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max );
fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant );
}
else
{
fMin = static_cast<double>(mppOptions[n]->constraint.range->min);
fMax = static_cast<double>(mppOptions[n]->constraint.range->max);
fQuant = static_cast<double>(mppOptions[n]->constraint.range->quant);
2000-09-18 15:18:56 +00:00
}
if( fQuant != 0.0 )
{
dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n",
fMin, fQuant, fMax );
nItems = static_cast<int>((fMax - fMin)/fQuant)+1;
rpDouble.reset(new double[ nItems ]);
2000-09-18 15:18:56 +00:00
double fValue = fMin;
for( i = 0; i < nItems; i++, fValue += fQuant )
rpDouble[i] = fValue;
rpDouble[ nItems-1 ] = fMax;
return nItems;
}
else
{
dbg_msg( "normal range [ %lg %lg ]\n",
fMin, fMax );
rpDouble.reset(new double[2]);
2000-09-18 15:18:56 +00:00
rpDouble[0] = fMin;
rpDouble[1] = fMax;
return 0;
}
}
else
{
nItems = mppOptions[n]->constraint.word_list[0];
rpDouble.reset(new double[nItems]);
2000-09-18 15:18:56 +00:00
for( i=0; i<nItems; i++ )
{
rpDouble[i] = bIsFixed ?
SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) :
static_cast<double>(mppOptions[n]->constraint.word_list[i+1]);
2000-09-18 15:18:56 +00:00
}
dbg_msg( "wordlist [ %lg ... %lg ]\n",
2000-09-18 15:18:56 +00:00
rpDouble[ 0 ], rpDouble[ nItems-1 ] );
return nItems;
}
}
static const char *ppUnits[] = {
2000-09-18 15:18:56 +00:00
"",
"[Pixel]",
"[Bit]",
"[mm]",
"[DPI]",
"[%]",
"[usec]"
};
OUString Sane::GetOptionUnitName( int n )
2000-09-18 15:18:56 +00:00
{
OUString aText;
2000-09-18 15:18:56 +00:00
SANE_Unit nUnit = mppOptions[n]->unit;
size_t nUnitAsSize = static_cast<size_t>(nUnit);
if (nUnitAsSize >= SAL_N_ELEMENTS( ppUnits ))
aText = "[unknown units]";
2000-09-18 15:18:56 +00:00
else
aText = OUString( ppUnits[ nUnit ], strlen(ppUnits[ nUnit ]), osl_getThreadTextEncoding() );
2000-09-18 15:18:56 +00:00
return aText;
}
bool Sane::ActivateButtonOption( int n )
2000-09-18 15:18:56 +00:00
{
SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, nullptr );
return nStatus == SANE_STATUS_GOOD;
2000-09-18 15:18:56 +00:00
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */