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>
|
||||
<!--change these in each release-->
|
||||
<VersionPrefix>4.0.0.0</VersionPrefix>
|
||||
<VersionSuffix>alpha.16</VersionSuffix>
|
||||
<VersionSuffix>alpha.17</VersionSuffix>
|
||||
|
||||
<!--keep it the same until major # changes-->
|
||||
<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);
|
||||
if (LastSTS.IsSuccess)
|
||||
{
|
||||
return values;
|
||||
};
|
||||
return Array.Empty<TValue>();
|
||||
LastSTS = _twain.GetCapValues(Cap, out ValueContainer<TValue> value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public IList<TValue> GetCurrent()
|
||||
@@ -57,7 +53,7 @@ namespace NTwain.Caps
|
||||
if (LastSTS.IsSuccess)
|
||||
{
|
||||
return value;
|
||||
};
|
||||
}
|
||||
return Array.Empty<TValue>();
|
||||
}
|
||||
|
||||
@@ -67,7 +63,7 @@ namespace NTwain.Caps
|
||||
if (LastSTS.IsSuccess)
|
||||
{
|
||||
return value;
|
||||
};
|
||||
}
|
||||
return Array.Empty<TValue>();
|
||||
}
|
||||
|
||||
@@ -77,7 +73,7 @@ namespace NTwain.Caps
|
||||
if (LastSTS.IsSuccess)
|
||||
{
|
||||
return value;
|
||||
};
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
@@ -87,7 +83,7 @@ namespace NTwain.Caps
|
||||
if (LastSTS.IsSuccess)
|
||||
{
|
||||
return value;
|
||||
};
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
@@ -97,7 +93,7 @@ namespace NTwain.Caps
|
||||
if (LastSTS.IsSuccess)
|
||||
{
|
||||
return value;
|
||||
};
|
||||
}
|
||||
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,
|
||||
DSMID = 461,
|
||||
DSMCODEID = 63
|
||||
DSMCODEID = 63,
|
||||
|
||||
DONTCARE = 0xffff
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
|
||||
@@ -284,58 +284,13 @@ namespace NTwain.Data
|
||||
if (MinValue is not IConvertible)
|
||||
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()
|
||||
{
|
||||
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
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using NTwain.Caps;
|
||||
using NTwain.Data;
|
||||
using NTwain.Triplets;
|
||||
using NTwain.Triplets.ControlDATs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -178,31 +177,47 @@ namespace NTwain
|
||||
/// <param name="cap"></param>
|
||||
/// <param name="values"></param>
|
||||
/// <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>();
|
||||
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
|
||||
value = new ValueContainer<TValue> { ContainerType = TWON.DONTCARE };
|
||||
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
|
||||
if (sts.RC == TWRC.SUCCESS)
|
||||
{
|
||||
value.ContainerType = twcap.ConType;
|
||||
switch (twcap.ConType)
|
||||
{
|
||||
case TWON.ONEVALUE:
|
||||
values.Add(twcap.ReadOneValue<TValue>(this));
|
||||
value.OneValue = twcap.ReadOneValue<TValue>(this);
|
||||
break;
|
||||
case TWON.ENUMERATION:
|
||||
var twenum = twcap.ReadEnumeration<TValue>(this);
|
||||
if (twenum.Items != null && twenum.Items.Length > 0)
|
||||
((List<TValue>)values).AddRange(twenum.Items);
|
||||
if (twenum.Items != null)
|
||||
{
|
||||
value.EnumValue = new EnumValue<TValue>
|
||||
{
|
||||
CurrentIndex = twenum.CurrentIndex,
|
||||
DefaultIndex = twenum.DefaultIndex,
|
||||
Items = twenum.Items
|
||||
};
|
||||
}
|
||||
break;
|
||||
case TWON.RANGE:
|
||||
// This can be slow
|
||||
var twrange = twcap.ReadRange<TValue>(this);
|
||||
((List<TValue>)values).AddRange(twrange);
|
||||
var range = twcap.ReadRange<TValue>(this);
|
||||
value.RangeValue = new RangeValue<TValue>
|
||||
{
|
||||
Min = range.MinValue,
|
||||
Max = range.MaxValue,
|
||||
Step = range.StepSize,
|
||||
DefaultValue = range.DefaultValue,
|
||||
CurrentValue = range.CurrentValue
|
||||
};
|
||||
break;
|
||||
case TWON.ARRAY:
|
||||
var twarr = twcap.ReadArray<TValue>(this);
|
||||
if (twarr != null && twarr.Count > 0)
|
||||
((List<TValue>)values).AddRange(twarr);
|
||||
if (twarr != null)
|
||||
{
|
||||
value.ArrayValue = twarr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
twcap.Free(this); break;
|
||||
|
||||
Reference in New Issue
Block a user