Added value writer with type detection.

This commit is contained in:
Eugene Wang 2018-11-25 21:52:10 -05:00
parent 5e4fd5f7c8
commit fe6b55bb72
4 changed files with 121 additions and 31 deletions

View File

@ -34,7 +34,7 @@ namespace NTwain
public TW_CAPABILITY Generate<T>(CapabilityId cap, ItemType type, T value)
{
// size of data + uint16 item type
var valueSz = type.GetSize();
var valueSz = type.GetByteSize();
if (valueSz < 4) valueSz = 4; // onevalue container value minimum is 32bit
var memSz = valueSz + 2; // + item type field
@ -52,7 +52,7 @@ namespace NTwain
{
int offset = 0;
// TODO: type size may be different on mac
baseAddr.WriteValue(ref offset, ItemType.UInt16, value);
baseAddr.WriteValue(ref offset, type, ItemType.UInt16);
// ONEVALUE is special in value can be uint32 or string
// if less than uint32 put it in lower word
// (string value seems undocumented but internet says put it as-is and not a pointer)
@ -61,7 +61,7 @@ namespace NTwain
Marshal.WriteInt16(baseAddr, offset, 0);
offset += 2;
}
baseAddr.WriteValue(ref offset, type, value);
baseAddr.WriteValue(ref offset, value, type);
}
finally
{
@ -90,7 +90,7 @@ namespace NTwain
};
if (twCap.hContainer != IntPtr.Zero)
{
var listSz = value.Type.GetSize() * value.ItemList.Length;
var listSz = value.Type.GetByteSize() * value.ItemList.Length;
TW_ARRAY container = new TW_ARRAY
{
ItemType = (ushort)value.Type,
@ -105,7 +105,7 @@ namespace NTwain
int offset = 0;
foreach (var it in value.ItemList)
{
baseAddr.WriteValue(ref offset, value.Type, it);
baseAddr.WriteValue(ref offset, it, value.Type);
}
}
finally
@ -149,7 +149,7 @@ namespace NTwain
};
if (twCap.hContainer != IntPtr.Zero)
{
var listSz = value.Type.GetSize() * value.ItemList.Length;
var listSz = value.Type.GetByteSize() * value.ItemList.Length;
TW_ENUMERATION container = new TW_ENUMERATION
{
ItemType = (ushort)value.Type,
@ -166,7 +166,7 @@ namespace NTwain
int offset = 0;
foreach (var it in value.ItemList)
{
baseAddr.WriteValue(ref offset, value.Type, it);
baseAddr.WriteValue(ref offset, it, value.Type);
}
}
finally

View File

@ -1,4 +1,5 @@
using System;
using NTwain.Resources;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@ -13,7 +14,7 @@ namespace NTwain.Data
/// </summary>
static class TypeExtensions
{
static readonly Dictionary<ItemType, int> _sizes = new Dictionary<ItemType, int>
static readonly Dictionary<ItemType, int> _twainBytes = new Dictionary<ItemType, int>
{
{ ItemType.Int8, 1 },
{ ItemType.UInt8, 1 },
@ -28,44 +29,108 @@ namespace NTwain.Data
{ ItemType.String255, TwainConst.String255 },
{ ItemType.String32, TwainConst.String32 },
{ ItemType.String64, TwainConst.String64 },
// TODO: find out if it should be fixed 4 bytes or intptr size
{ ItemType.Handle, IntPtr.Size },
};
public static int GetSize(this ItemType type)
static readonly Dictionary<Type, ItemType> _netToTwainTypes = new Dictionary<Type, ItemType>
{
if(_sizes.TryGetValue(type, out int size)) return size;
{ typeof(sbyte), ItemType.Int8 },
{ typeof(byte), ItemType.UInt8 },
{ typeof(short), ItemType.Int16 },
{ typeof(ushort), ItemType.UInt16 },
{ typeof(int), ItemType.Int32 },
{ typeof(uint), ItemType.UInt32 },
{ typeof(TW_FIX32), ItemType.Fix32 },
{ typeof(TW_FRAME), ItemType.Frame },
{ typeof(IntPtr), ItemType.Handle },
{ typeof(UIntPtr), ItemType.Handle },
};
throw new NotSupportedException($"Unsupported item type {type}.");
internal static int GetByteSize(this ItemType type)
{
if (_twainBytes.TryGetValue(type, out int size)) return size;
throw new NotSupportedException(string.Format(MsgText.TypeNotSupported, type));
}
#region writes
/// <summary>
/// Writes a TWAIN value.
/// Writes a TWAIN value with type detection.
/// </summary>
/// <param name="baseAddr">The base addr.</param>
/// <param name="offset">The offset.</param>
/// <param name="type">The TWAIN type.</param>
/// <param name="value">The value.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
public static void WriteValue(this IntPtr baseAddr, ref int offset, ItemType type, object value)
public static void WriteValue(this IntPtr baseAddr, ref int offset, object value)
{
var rawType = value.GetType();
if (rawType.IsEnum)
{
// convert enum to numerical value
rawType = Enum.GetUnderlyingType(rawType);
value = Convert.ChangeType(value, rawType);
}
if (_netToTwainTypes.ContainsKey(rawType))
{
WriteValue(baseAddr, ref offset, value, _netToTwainTypes[rawType]);
}
else if (rawType == typeof(string))
{
var strVal = value.ToString();
if (strVal.Length <= 32)
{
WriteValue(baseAddr, ref offset, strVal, ItemType.String32);
}
else if (strVal.Length <= 64)
{
WriteValue(baseAddr, ref offset, strVal, ItemType.String64);
}
else if (strVal.Length <= 128)
{
WriteValue(baseAddr, ref offset, strVal, ItemType.String128);
}
else if (strVal.Length <= 255)
{
WriteValue(baseAddr, ref offset, strVal, ItemType.String255);
}
else
{
throw new NotSupportedException(string.Format(MsgText.MaxStringLengthExceeded, 255));
}
}
else
{
throw new NotSupportedException(string.Format(MsgText.TypeNotSupported, rawType));
}
}
/// <summary>
/// Writes a TWAIN value as specified type.
/// </summary>
/// <param name="baseAddr">The base addr.</param>
/// <param name="offset">The offset.</param>
/// <param name="value">The value.</param>
/// <param name="type">The TWAIN type.</param>
public static void WriteValue(this IntPtr baseAddr, ref int offset, object value, ItemType type)
{
switch (type)
{
case ItemType.Int8:
case ItemType.UInt8:
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));// (byte)value);
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));
break;
case ItemType.Bool:
case ItemType.Int16:
case ItemType.UInt16:
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));//(short)value);
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));
break;
case ItemType.UInt32:
case ItemType.Int32:
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));//(int)value);
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));
break;
case ItemType.Fix32:
TW_FIX32 f32 = (TW_FIX32)value;
@ -81,6 +146,9 @@ namespace NTwain.Data
//case ItemType.String1024:
// WriteString(baseAddr, offset, value as string, 1024);
// break;
case ItemType.Handle:
Marshal.WriteIntPtr(baseAddr, offset, (IntPtr)value);
break;
case ItemType.String128:
WriteString(baseAddr, offset, (string)value, 128);
break;
@ -93,25 +161,33 @@ namespace NTwain.Data
case ItemType.String64:
WriteString(baseAddr, offset, (string)value, 64);
break;
//case ItemType.Unicode512:
// WriteUString(baseAddr, offset, value as string, 512);
// break;
//case ItemType.Unicode512:
// WriteUString(baseAddr, offset, value as string, 512);
// break;
}
offset += type.GetSize();
offset += type.GetByteSize();
}
private static void WriteFix32(IntPtr baseAddr, ref int offset, TW_FIX32 f32)
static void WriteFix32(IntPtr baseAddr, ref int offset, TW_FIX32 value)
{
Marshal.WriteInt16(baseAddr, offset, f32.Whole);
if (f32.Fraction > Int16.MaxValue)
Marshal.WriteInt16(baseAddr, offset, value.Whole);
offset += _twainBytes[ItemType.Int16];
if (value.Fraction > Int16.MaxValue)
{
Marshal.WriteInt16(baseAddr, offset + 2, (Int16)(f32.Fraction - 32768));
Marshal.WriteInt16(baseAddr, offset, (Int16)(value.Fraction - 32768));
}
else
{
Marshal.WriteInt16(baseAddr, offset + 2, (Int16)f32.Fraction);
Marshal.WriteInt16(baseAddr, offset, (Int16)value.Fraction);
}
offset += _sizes[ItemType.Fix32];
offset += _twainBytes[ItemType.Fix32];
}
static void WriteFrame(IntPtr baseAddr, ref int offset, TW_FRAME value)
{
WriteFix32(baseAddr, ref offset, value._left);
WriteFix32(baseAddr, ref offset, value._top);
WriteFix32(baseAddr, ref offset, value._right);
WriteFix32(baseAddr, ref offset, value._bottom);
}
/// <summary>
@ -123,6 +199,8 @@ namespace NTwain.Data
/// <param name="maxLength"></param>
static void WriteString(IntPtr baseAddr, int offset, string value, int maxLength)
{
// TODO: mac string is not null-terminated like this?
if (string.IsNullOrEmpty(value))
{
// write zero

View File

@ -95,5 +95,14 @@ namespace NTwain.Resources {
return ResourceManager.GetString("SourceNotThisSession", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type {0} is not supported..
/// </summary>
internal static string TypeNotSupported {
get {
return ResourceManager.GetString("TypeNotSupported", resourceCulture);
}
}
}
}

View File

@ -129,4 +129,7 @@
<data name="SourceNotThisSession" xml:space="preserve">
<value>Source is not from this session.</value>
</data>
<data name="TypeNotSupported" xml:space="preserve">
<value>Type {0} is not supported.</value>
</data>
</root>