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

View File

@@ -1,4 +1,5 @@
using System; using NTwain.Resources;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@@ -13,7 +14,7 @@ namespace NTwain.Data
/// </summary> /// </summary>
static class TypeExtensions 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.Int8, 1 },
{ ItemType.UInt8, 1 }, { ItemType.UInt8, 1 },
@@ -28,44 +29,108 @@ namespace NTwain.Data
{ ItemType.String255, TwainConst.String255 }, { ItemType.String255, TwainConst.String255 },
{ ItemType.String32, TwainConst.String32 }, { ItemType.String32, TwainConst.String32 },
{ ItemType.String64, TwainConst.String64 }, { ItemType.String64, TwainConst.String64 },
// TODO: find out if it should be fixed 4 bytes or intptr size
{ ItemType.Handle, IntPtr.Size }, { ItemType.Handle, IntPtr.Size },
}; };
static readonly Dictionary<Type, ItemType> _netToTwainTypes = new Dictionary<Type, ItemType>
public static int GetSize(this ItemType type)
{ {
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 #region writes
/// <summary> /// <summary>
/// Writes a TWAIN value. /// Writes a TWAIN value with type detection.
/// </summary> /// </summary>
/// <param name="baseAddr">The base addr.</param> /// <param name="baseAddr">The base addr.</param>
/// <param name="offset">The offset.</param> /// <param name="offset">The offset.</param>
/// <param name="type">The TWAIN type.</param>
/// <param name="value">The value.</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, object value)
public static void WriteValue(this IntPtr baseAddr, ref int offset, ItemType type, 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) switch (type)
{ {
case ItemType.Int8: case ItemType.Int8:
case ItemType.UInt8: case ItemType.UInt8:
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));// (byte)value); Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));
break; break;
case ItemType.Bool: case ItemType.Bool:
case ItemType.Int16: case ItemType.Int16:
case ItemType.UInt16: case ItemType.UInt16:
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));//(short)value); Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));
break; break;
case ItemType.UInt32: case ItemType.UInt32:
case ItemType.Int32: case ItemType.Int32:
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));//(int)value); Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));
break; break;
case ItemType.Fix32: case ItemType.Fix32:
TW_FIX32 f32 = (TW_FIX32)value; TW_FIX32 f32 = (TW_FIX32)value;
@@ -81,6 +146,9 @@ namespace NTwain.Data
//case ItemType.String1024: //case ItemType.String1024:
// WriteString(baseAddr, offset, value as string, 1024); // WriteString(baseAddr, offset, value as string, 1024);
// break; // break;
case ItemType.Handle:
Marshal.WriteIntPtr(baseAddr, offset, (IntPtr)value);
break;
case ItemType.String128: case ItemType.String128:
WriteString(baseAddr, offset, (string)value, 128); WriteString(baseAddr, offset, (string)value, 128);
break; break;
@@ -93,25 +161,33 @@ namespace NTwain.Data
case ItemType.String64: case ItemType.String64:
WriteString(baseAddr, offset, (string)value, 64); WriteString(baseAddr, offset, (string)value, 64);
break; break;
//case ItemType.Unicode512: //case ItemType.Unicode512:
// WriteUString(baseAddr, offset, value as string, 512); // WriteUString(baseAddr, offset, value as string, 512);
// break; // 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); Marshal.WriteInt16(baseAddr, offset, value.Whole);
if (f32.Fraction > Int16.MaxValue) 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 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> /// <summary>
@@ -123,6 +199,8 @@ namespace NTwain.Data
/// <param name="maxLength"></param> /// <param name="maxLength"></param>
static void WriteString(IntPtr baseAddr, int offset, string value, int maxLength) static void WriteString(IntPtr baseAddr, int offset, string value, int maxLength)
{ {
// TODO: mac string is not null-terminated like this?
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
{ {
// write zero // write zero

View File

@@ -95,5 +95,14 @@ namespace NTwain.Resources {
return ResourceManager.GetString("SourceNotThisSession", resourceCulture); 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"> <data name="SourceNotThisSession" xml:space="preserve">
<value>Source is not from this session.</value> <value>Source is not from this session.</value>
</data> </data>
<data name="TypeNotSupported" xml:space="preserve">
<value>Type {0} is not supported.</value>
</data>
</root> </root>