mirror of
https://github.com/soukoku/ntwain.git
synced 2025-11-24 08:47:06 +08:00
Changed to return value container for available cap value to prevent long range enumerations.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!--change these in each release-->
|
<!--change these in each release-->
|
||||||
<VersionPrefix>4.0.0.0</VersionPrefix>
|
<VersionPrefix>4.0.0.0</VersionPrefix>
|
||||||
<VersionSuffix>alpha.16</VersionSuffix>
|
<VersionSuffix>alpha.17</VersionSuffix>
|
||||||
|
|
||||||
<!--keep it the same until major # changes-->
|
<!--keep it the same until major # changes-->
|
||||||
<AssemblyVersion>4.0.0.0</AssemblyVersion>
|
<AssemblyVersion>4.0.0.0</AssemblyVersion>
|
||||||
|
|||||||
@@ -41,14 +41,10 @@ namespace NTwain.Caps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<TValue> Get()
|
public ValueContainer<TValue> Get()
|
||||||
{
|
{
|
||||||
LastSTS = _twain.GetCapValues(Cap, out IList<TValue> values);
|
LastSTS = _twain.GetCapValues(Cap, out ValueContainer<TValue> value);
|
||||||
if (LastSTS.IsSuccess)
|
return value;
|
||||||
{
|
|
||||||
return values;
|
|
||||||
};
|
|
||||||
return Array.Empty<TValue>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<TValue> GetCurrent()
|
public IList<TValue> GetCurrent()
|
||||||
@@ -57,7 +53,7 @@ namespace NTwain.Caps
|
|||||||
if (LastSTS.IsSuccess)
|
if (LastSTS.IsSuccess)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
};
|
}
|
||||||
return Array.Empty<TValue>();
|
return Array.Empty<TValue>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +63,7 @@ namespace NTwain.Caps
|
|||||||
if (LastSTS.IsSuccess)
|
if (LastSTS.IsSuccess)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
};
|
}
|
||||||
return Array.Empty<TValue>();
|
return Array.Empty<TValue>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +73,7 @@ namespace NTwain.Caps
|
|||||||
if (LastSTS.IsSuccess)
|
if (LastSTS.IsSuccess)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
};
|
}
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +83,7 @@ namespace NTwain.Caps
|
|||||||
if (LastSTS.IsSuccess)
|
if (LastSTS.IsSuccess)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
};
|
}
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +93,7 @@ namespace NTwain.Caps
|
|||||||
if (LastSTS.IsSuccess)
|
if (LastSTS.IsSuccess)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
};
|
}
|
||||||
return Array.Empty<string>();
|
return Array.Empty<string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
66
src/NTwain/Caps/ValueContainer.cs
Normal file
66
src/NTwain/Caps/ValueContainer.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NTwain.Caps;
|
||||||
|
|
||||||
|
public record ValueContainer<TValue> where TValue : struct
|
||||||
|
{
|
||||||
|
public TWON ContainerType { get; set; }
|
||||||
|
|
||||||
|
public TValue? OneValue { get; set; }
|
||||||
|
|
||||||
|
public IList<TValue>? ArrayValue { get; set; }
|
||||||
|
|
||||||
|
public EnumValue<TValue>? EnumValue { get; set; }
|
||||||
|
|
||||||
|
public RangeValue<TValue>? RangeValue { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<TValue> GetValues()
|
||||||
|
{
|
||||||
|
return ContainerType switch
|
||||||
|
{
|
||||||
|
TWON.ONEVALUE => OneValue.HasValue ? ToEnumerable(OneValue.Value) : [],
|
||||||
|
TWON.ARRAY => ArrayValue ?? [],
|
||||||
|
TWON.ENUMERATION => EnumValue?.Items ?? [],
|
||||||
|
TWON.RANGE => RangeValue != null ? GenerateRangeValues(RangeValue) : [],
|
||||||
|
_ => [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<TValue> ToEnumerable(TValue value)
|
||||||
|
{
|
||||||
|
yield return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<TValue> GenerateRangeValues(RangeValue<TValue> range)
|
||||||
|
{
|
||||||
|
var de = new DynamicEnumerator<TValue>(range.Min, range.Max, range.Step);
|
||||||
|
while (de.MoveNext())
|
||||||
|
{
|
||||||
|
yield return de.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record EnumValue<TValue> where TValue : struct
|
||||||
|
{
|
||||||
|
public TValue[] Items { get; set; } = [];
|
||||||
|
|
||||||
|
public int CurrentIndex { get; set; }
|
||||||
|
|
||||||
|
public int DefaultIndex { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RangeValue<TValue> where TValue : struct
|
||||||
|
{
|
||||||
|
public TValue Min { get; set; }
|
||||||
|
|
||||||
|
public TValue Max { get; set; }
|
||||||
|
|
||||||
|
public TValue Step { get; set; }
|
||||||
|
|
||||||
|
public TValue DefaultValue;
|
||||||
|
|
||||||
|
public TValue CurrentValue;
|
||||||
|
}
|
||||||
48
src/NTwain/Data/DynamicEnumerator.cs
Normal file
48
src/NTwain/Data/DynamicEnumerator.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NTwain.Data;
|
||||||
|
|
||||||
|
// dynamic is a cheap hack to sidestep the compiler restrictions if I know TValue is numeric
|
||||||
|
class DynamicEnumerator<TValue> : IEnumerator<TValue> where TValue : struct
|
||||||
|
{
|
||||||
|
private readonly TValue _min;
|
||||||
|
private readonly TValue _max;
|
||||||
|
private readonly TValue _step;
|
||||||
|
private TValue _cur;
|
||||||
|
bool started = false;
|
||||||
|
|
||||||
|
public DynamicEnumerator(TValue min, TValue max, TValue step)
|
||||||
|
{
|
||||||
|
_min = min;
|
||||||
|
_max = max;
|
||||||
|
_step = step;
|
||||||
|
_cur = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue Current => _cur;
|
||||||
|
|
||||||
|
object System.Collections.IEnumerator.Current => this.Current;
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (!started)
|
||||||
|
{
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var next = _cur + (dynamic)_step;
|
||||||
|
if (next == _cur || next < _min || next > _max) return false;
|
||||||
|
|
||||||
|
_cur = next;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_cur = _min;
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2590,7 +2590,9 @@ namespace NTwain.Data
|
|||||||
|
|
||||||
ICONID = 962,
|
ICONID = 962,
|
||||||
DSMID = 461,
|
DSMID = 461,
|
||||||
DSMCODEID = 63
|
DSMCODEID = 63,
|
||||||
|
|
||||||
|
DONTCARE = 0xffff
|
||||||
}
|
}
|
||||||
|
|
||||||
///// <summary>
|
///// <summary>
|
||||||
|
|||||||
@@ -284,58 +284,13 @@ namespace NTwain.Data
|
|||||||
if (MinValue is not IConvertible)
|
if (MinValue is not IConvertible)
|
||||||
throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration.");
|
throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration.");
|
||||||
|
|
||||||
return new DynamicEnumerator(MinValue, MaxValue, StepSize);
|
return new DynamicEnumerator<TValue>(MinValue, MaxValue, StepSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||||
{
|
{
|
||||||
return ((IEnumerable<TValue>)this).GetEnumerator();
|
return ((IEnumerable<TValue>)this).GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
// dynamic is a cheap hack to sidestep the compiler restrictions if I know TValue is numeric
|
|
||||||
class DynamicEnumerator : IEnumerator<TValue>
|
|
||||||
{
|
|
||||||
private readonly TValue _min;
|
|
||||||
private readonly TValue _max;
|
|
||||||
private readonly TValue _step;
|
|
||||||
private TValue _cur;
|
|
||||||
bool started = false;
|
|
||||||
|
|
||||||
public DynamicEnumerator(TValue min, TValue max, TValue step)
|
|
||||||
{
|
|
||||||
_min = min;
|
|
||||||
_max = max;
|
|
||||||
_step = step;
|
|
||||||
_cur = min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TValue Current => _cur;
|
|
||||||
|
|
||||||
object System.Collections.IEnumerator.Current => this.Current;
|
|
||||||
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (!started)
|
|
||||||
{
|
|
||||||
started = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var next = _cur + (dynamic)_step;
|
|
||||||
if (next == _cur || next < _min || next > _max) return false;
|
|
||||||
|
|
||||||
_cur = next;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
_cur = _min;
|
|
||||||
started = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible
|
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using NTwain.Caps;
|
using NTwain.Caps;
|
||||||
using NTwain.Data;
|
using NTwain.Data;
|
||||||
using NTwain.Triplets;
|
using NTwain.Triplets;
|
||||||
using NTwain.Triplets.ControlDATs;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -178,31 +177,47 @@ namespace NTwain
|
|||||||
/// <param name="cap"></param>
|
/// <param name="cap"></param>
|
||||||
/// <param name="values"></param>
|
/// <param name="values"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public STS GetCapValues<TValue>(CAP cap, out IList<TValue> values) where TValue : struct
|
public STS GetCapValues<TValue>(CAP cap, out ValueContainer<TValue> value) where TValue : struct
|
||||||
{
|
{
|
||||||
values = new List<TValue>();
|
value = new ValueContainer<TValue> { ContainerType = TWON.DONTCARE };
|
||||||
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
|
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
{
|
{
|
||||||
|
value.ContainerType = twcap.ConType;
|
||||||
switch (twcap.ConType)
|
switch (twcap.ConType)
|
||||||
{
|
{
|
||||||
case TWON.ONEVALUE:
|
case TWON.ONEVALUE:
|
||||||
values.Add(twcap.ReadOneValue<TValue>(this));
|
value.OneValue = twcap.ReadOneValue<TValue>(this);
|
||||||
break;
|
break;
|
||||||
case TWON.ENUMERATION:
|
case TWON.ENUMERATION:
|
||||||
var twenum = twcap.ReadEnumeration<TValue>(this);
|
var twenum = twcap.ReadEnumeration<TValue>(this);
|
||||||
if (twenum.Items != null && twenum.Items.Length > 0)
|
if (twenum.Items != null)
|
||||||
((List<TValue>)values).AddRange(twenum.Items);
|
{
|
||||||
|
value.EnumValue = new EnumValue<TValue>
|
||||||
|
{
|
||||||
|
CurrentIndex = twenum.CurrentIndex,
|
||||||
|
DefaultIndex = twenum.DefaultIndex,
|
||||||
|
Items = twenum.Items
|
||||||
|
};
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TWON.RANGE:
|
case TWON.RANGE:
|
||||||
// This can be slow
|
var range = twcap.ReadRange<TValue>(this);
|
||||||
var twrange = twcap.ReadRange<TValue>(this);
|
value.RangeValue = new RangeValue<TValue>
|
||||||
((List<TValue>)values).AddRange(twrange);
|
{
|
||||||
|
Min = range.MinValue,
|
||||||
|
Max = range.MaxValue,
|
||||||
|
Step = range.StepSize,
|
||||||
|
DefaultValue = range.DefaultValue,
|
||||||
|
CurrentValue = range.CurrentValue
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
case TWON.ARRAY:
|
case TWON.ARRAY:
|
||||||
var twarr = twcap.ReadArray<TValue>(this);
|
var twarr = twcap.ReadArray<TValue>(this);
|
||||||
if (twarr != null && twarr.Count > 0)
|
if (twarr != null)
|
||||||
((List<TValue>)values).AddRange(twarr);
|
{
|
||||||
|
value.ArrayValue = twarr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
twcap.Free(this); break;
|
twcap.Free(this); break;
|
||||||
|
|||||||
Reference in New Issue
Block a user