using NTwain.Internals;
using NTwain.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
namespace NTwain.Data
{
//// This file contains custom logic added to the twain types.
//// Separating the raw field definitions out makes finding all the
//// custom code logic easier. Mostly this just makes the fields
//// into .net friendly properties.
//// potentially unit tests for the twain types only need to target
//// code in this file since everything else is just interop and
//// field definitions.
//// most of the doc text are copied from the twain spec pdf.
///
/// Stores a fixed point number. This can be implicitly converted
/// to a float in dotnet.
///
public partial struct TWFix32 : IEquatable, IConvertible
{
// the conversion logic is found in the spec.
float ToFloat()
{
return (float)_whole + _frac / 65536f;
}
TWFix32(float value)
{
//int temp = (int)(value * 65536.0 + 0.5);
//_whole = (short)(temp >> 16);
//_frac = (ushort)(temp & 0x0000ffff);
// different version from twain faq
bool sign = value < 0;
int temp = (int)(value * 65536.0 + (sign ? (-0.5) : 0.5));
_whole = (short)(temp >> 16);
_frac = (ushort)(temp & 0x0000ffff);
}
///
/// The Whole part of the floating point number. This number is signed.
///
public short Whole { get { return _whole; } set { _whole = value; } }
///
/// The Fractional part of the floating point number. This number is unsigned.
///
public ushort Fraction { get { return _frac; } set { _frac = value; } }
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return ToFloat().ToString(CultureInfo.InvariantCulture);
}
#region equals
///
/// Determines whether the specified is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object obj)
{
if (!(obj is TWFix32))
return false;
return Equals((TWFix32)obj);
}
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
///
public bool Equals(TWFix32 other)
{
return _whole == other._whole && _frac == other._frac;
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
return _whole ^ _frac;
}
#endregion
#region static stuff
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator float(TWFix32 value)
{
return value.ToFloat();
}
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator TWFix32(float value)
{
return new TWFix32(value);
}
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator double(TWFix32 value)
{
return value.ToFloat();
}
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator TWFix32(double value)
{
return new TWFix32((float)value);
}
///
/// Implements the operator ==.
///
/// The value1.
/// The value2.
/// The result of the operator.
public static bool operator ==(TWFix32 value1, TWFix32 value2)
{
return value1.Equals(value2);
}
///
/// Implements the operator !=.
///
/// The value1.
/// The value2.
/// The result of the operator.
public static bool operator !=(TWFix32 value1, TWFix32 value2)
{
return !value1.Equals(value2);
}
#endregion
#region IConvertable
TypeCode IConvertible.GetTypeCode()
{
return TypeCode.Single;
}
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return this != 0;
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return Convert.ToByte((float)this);
}
char IConvertible.ToChar(IFormatProvider provider)
{
return Convert.ToChar((float)this);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime((float)this);
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal((float)this);
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return Convert.ToDouble((float)this);
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return Convert.ToInt16((float)this);
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return Convert.ToInt32((float)this);
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return Convert.ToInt64((float)this);
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return Convert.ToSByte((float)this);
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return Convert.ToSingle((float)this);
}
string IConvertible.ToString(IFormatProvider provider)
{
return this.ToString();
}
object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType((float)this, conversionType, CultureInfo.InvariantCulture);
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16((float)this);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32((float)this);
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64((float)this);
}
#endregion
}
///
/// Embedded in the structure.
/// Defines a frame rectangle in ICapUnits coordinates.
///
public partial struct TWFrame : IEquatable
{
#region properties
///
/// Value of the left-most edge of the rectangle.
///
public float Left { get { return _left; } set { _left = value; } }
///
/// Value of the top-most edge of the rectangle.
///
public float Top { get { return _top; } set { _top = value; } }
///
/// Value of the right-most edge of the rectangle.
///
public float Right { get { return _right; } set { _right = value; } }
///
/// Value of the bottom-most edge of the rectangle.
///
public float Bottom { get { return _bottom; } set { _bottom = value; } }
#endregion
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "L={0}, T={1}, R={2}, B={3}", Left, Top, Right, Bottom);
}
#region equals
///
/// Determines whether the specified is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object obj)
{
if (!(obj is TWFrame))
return false;
return Equals((TWFrame)obj);
}
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
///
public bool Equals(TWFrame other)
{
return _left == other._left && _top == other._top &&
_right == other._right && _bottom == other._bottom;
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
return _left.GetHashCode() ^ _top.GetHashCode() ^
_right.GetHashCode() ^ _bottom.GetHashCode();
}
#endregion
#region static stuff
///
/// Implements the operator ==.
///
/// The value1.
/// The value2.
/// The result of the operator.
public static bool operator ==(TWFrame value1, TWFrame value2)
{
return value1.Equals(value2);
}
///
/// Implements the operator !=.
///
/// The value1.
/// The value2.
/// The result of the operator.
public static bool operator !=(TWFrame value1, TWFrame value2)
{
return !value1.Equals(value2);
}
#endregion
}
///
/// Embedded in the structure that is embedded in the
/// structure. Defines the parameters used for channel-specific transformation. The transform can be
/// described either as an extended form of the gamma function or as a table look-up with linear
/// interpolation.
///
public partial struct TWDecodeFunction : IEquatable
{
#region properties
///
/// Starting input value of the extended gamma function. Defines the
/// minimum input value of channel data.
///
public float StartIn { get { return _startIn; } }//set { _startIn = value; } }
///
/// Ending input value of the extended gamma function. Defines the maximum
/// input value of channel data.
///
public float BreakIn { get { return _breakIn; } }//set { _breakIn = value; } }
///
/// The input value at which the transform switches from linear
/// transformation/interpolation to gamma transformation.
///
public float EndIn { get { return _endIn; } }//set { _endIn = value; } }
///
/// Starting output value of the extended gamma function. Defines the
/// minimum output value of channel data.
///
public float StartOut { get { return _startOut; } }//set { _startOut = value; } }
///
/// Ending output value of the extended gamma function. Defines the
/// maximum output value of channel data.
///
public float BreakOut { get { return _breakOut; } }//set { _breakOut = value; } }
///
/// The output value at which the transform switches from linear
/// transformation/interpolation to gamma transformation.
///
public float EndOut { get { return _endOut; } }//set { _endOut = value; } }
///
/// Constant value. The exponential used in the gamma function.
///
public float Gamma { get { return _gamma; } }//set { _gamma = value; } }
///
/// The number of samples in the look-up table. Includes the values of StartIn
/// and EndIn. Zero-based index (actually, number of samples - 1). If zero, use
/// extended gamma, otherwise use table look-up.
///
public float SampleCount { get { return _sampleCount; } }//set { _sampleCount = value; } }
#endregion
#region equals
///
/// Determines whether the specified is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object obj)
{
if (!(obj is TWDecodeFunction))
return false;
return Equals((TWDecodeFunction)obj);
}
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
///
public bool Equals(TWDecodeFunction other)
{
return _startIn == other._startIn && _startOut == other._startOut &&
_breakIn == other._breakIn && _breakOut == other._breakOut &&
_endIn == other._endIn && _endOut == other._endOut &&
_gamma == other._gamma && _sampleCount == other._sampleCount;
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
return _startIn.GetHashCode() ^ _startOut.GetHashCode() ^
_breakIn.GetHashCode() ^ _breakOut.GetHashCode() ^
_endIn.GetHashCode() ^ _endOut.GetHashCode() ^
_gamma.GetHashCode() ^ _sampleCount.GetHashCode();
}
#endregion
#region static stuff
///
/// Implements the operator ==.
///
/// The value1.
/// The value2.
/// The result of the operator.
public static bool operator ==(TWDecodeFunction value1, TWDecodeFunction value2)
{
return value1.Equals(value2);
}
///
/// Implements the operator !=.
///
/// The value1.
/// The value2.
/// The result of the operator.
public static bool operator !=(TWDecodeFunction value1, TWDecodeFunction value2)
{
return !value1.Equals(value2);
}
#endregion
}
///
/// Specifies the parametrics used for either the ABC or LMN transform stages.
///
public partial struct TWTransformStage
{
///
/// Channel-specific transform parameters.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public TWDecodeFunction[] Decode { get { return _decode; } }//set { _decode = value; } }
///
/// Flattened 3x3 matrix that specifies how channels are mixed in.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public TWFix32[] Mix { get { return _mix; } }//set { _mix = value; } }
///
/// Gets the value as matrix.
///
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Body"),
System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Return")]
public TWFix32[,] GetMixMatrix()
{
// from http://stackoverflow.com/questions/3845235/convert-array-to-matrix, haven't tested it
TWFix32[,] mat = new TWFix32[3, 3];
Buffer.BlockCopy(_mix, 0, mat, 0, _mix.Length * 4);
return mat;
}
}
///
/// Stores a group of associated individual values for a capability.
/// The values need have no relationship to one another aside from
/// being used to describe the same "value" of the capability
///
public partial class TWArray
{
///
/// The type of items in the array. All items in the array have the same size.
///
public ItemType ItemType { get { return (ItemType)_itemType; } set { _itemType = (ushort)value; } }
/////
///// How many items are in the array.
/////
//public int Count { get { return (int)_numItems; } set { _numItems = (uint)value; } }
///
/// Array of ItemType values starts here.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public object[] ItemList
{
get { return _itemList; }
set
{
_itemList = value;
if (value != null) { _numItems = (uint)value.Length; }
else { _numItems = 0; }
}
}
}
///
/// Used to get audio info.
///
public partial class TWAudioInfo
{
internal TWAudioInfo() { }
///
/// Name of audio data.
///
public string Name { get { return _name; } }
}
///
/// Used in Callback mechanism for sending messages from the Source to the Application.
/// Applications version 2.2 or higher must use .
///
partial class TWCallback
{
///
/// Initializes a new instance of the class.
///
/// The callback function’s entry point.
public TWCallback(CallbackDelegate callback)
{
_callBackProc = callback;
}
///
/// An application defined reference constant.
///
///
/// The reference constant.
///
public uint RefCon { get { return _refCon; } set { _refCon = value; } }
///
/// Initialized to any valid DG_CONTROL / DAT_NULL message.
///
///
/// The message.
///
public short Message { get { return _message; } set { _message = value; } }
}
///
/// Used in the Callback mechanism for sending messages from the Source to the Application.
///
partial class TWCallback2
{
///
/// Initializes a new instance of the class.
///
/// The callback function’s entry point.
public TWCallback2(CallbackDelegate callback)
{
_callBackProc = callback;
}
///
/// An application defined reference constant. It has a different size on different
/// platforms.
///
///
/// The reference constant.
///
public UIntPtr RefCon { get { return _refCon; } set { _refCon = value; } }
///
/// Initialized to any valid DG_CONTROL / DAT_NULL message.
///
///
/// The message.
///
public short Message { get { return _message; } set { _message = value; } }
}
///
/// Used by an application either to get information about, or control the setting of a capability.
///
public sealed partial class TWCapability : IDisposable
{
#region ctors
///
/// Initializes a new instance of the class.
///
/// The capability.
public TWCapability(CapabilityId capability)
{
Capability = capability;
ContainerType = ContainerType.DoNotCare;
}
///
/// Initializes a new instance of the class.
///
/// The capability.
/// The value.
public TWCapability(CapabilityId capability, TWOneValue value)
{
Capability = capability;
ContainerType = ContainerType.OneValue;
SetOneValue(value);
}
///
/// Initializes a new instance of the class.
///
/// The capability.
/// The value.
public TWCapability(CapabilityId capability, TWEnumeration value)
{
Capability = capability;
ContainerType = ContainerType.Enum;
SetEnumValue(value);
}
///
/// Initializes a new instance of the class.
///
/// The capability.
/// The value.
public TWCapability(CapabilityId capability, TWRange value)
{
Capability = capability;
ContainerType = ContainerType.Range;
SetRangeValue(value);
}
#endregion
#region properties
///
/// Id of capability to set or get.
///
public CapabilityId Capability { get { return (CapabilityId)_cap; } set { _cap = (ushort)value; } }
///
/// The type of the container structure referenced by the pointer internally. The container
/// will be one of four types: , ,
/// , or .
///
public ContainerType ContainerType { get { return (ContainerType)_conType; } set { _conType = (ushort)value; } }
internal IntPtr Container { get { return _hContainer; } }
#endregion
#region value functions
void SetOneValue(TWOneValue value)
{
if (value == null) { throw new ArgumentNullException("value"); }
ContainerType = ContainerType.OneValue;
// since one value can only house UInt32 we will not allow type size > 4
if (TypeReader.GetItemTypeSize(value.ItemType) > 4) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.BadValueType, "TWOneValue")); }
_hContainer = PlatformInfo.Current.MemoryManager.Allocate((uint)Marshal.SizeOf(value));
if (_hContainer != IntPtr.Zero)
{
Marshal.StructureToPtr(value, _hContainer, false);
}
}
void SetEnumValue(TWEnumeration value)
{
if (value == null) { throw new ArgumentNullException("value"); }
ContainerType = ContainerType.Enum;
Int32 valueSize = TWEnumeration.ItemOffset + value.ItemList.Length * TypeReader.GetItemTypeSize(value.ItemType);
int offset = 0;
_hContainer = PlatformInfo.Current.MemoryManager.Allocate((uint)valueSize);
IntPtr baseAddr = PlatformInfo.Current.MemoryManager.Lock(_hContainer);
// can't safely use StructureToPtr here so write it our own
WriteValue(baseAddr, ref offset, ItemType.UInt16, value.ItemType);
WriteValue(baseAddr, ref offset, ItemType.UInt32, (uint)value.ItemList.Length);
WriteValue(baseAddr, ref offset, ItemType.UInt32, value.CurrentIndex);
WriteValue(baseAddr, ref offset, ItemType.UInt32, value.DefaultIndex);
foreach (var item in value.ItemList)
{
WriteValue(baseAddr, ref offset, value.ItemType, item);
}
PlatformInfo.Current.MemoryManager.Unlock(baseAddr);
}
void SetRangeValue(TWRange value)
{
if (value == null) { throw new ArgumentNullException("value"); }
ContainerType = ContainerType.Range;
// since range value can only house UInt32 we will not allow type size > 4
if (TypeReader.GetItemTypeSize(value.ItemType) > 4) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.BadValueType, "TWRange")); }
_hContainer = PlatformInfo.Current.MemoryManager.Allocate((uint)Marshal.SizeOf(value));
if (_hContainer != IntPtr.Zero)
{
Marshal.StructureToPtr(value, _hContainer, false);
}
}
#endregion
#region writes
///
/// Entry call for writing values to a pointer.
///
///
///
///
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
void WriteValue(IntPtr baseAddr, ref int offset, ItemType type, object value)
{
switch (type)
{
case ItemType.Int8:
case ItemType.UInt8:
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));// (byte)value);
break;
case ItemType.Bool:
case ItemType.Int16:
case ItemType.UInt16:
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));//(short)value);
break;
case ItemType.UInt32:
case ItemType.Int32:
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));//(int)value);
break;
case ItemType.Fix32:
TWFix32 f32 = (TWFix32)value;
Marshal.WriteInt16(baseAddr, offset, f32.Whole);
if (f32.Fraction > Int16.MaxValue)
{
Marshal.WriteInt16(baseAddr, offset + 2, (Int16)(f32.Fraction - 32768));
}
else
{
Marshal.WriteInt16(baseAddr, offset + 2, (Int16)f32.Fraction);
}
break;
case ItemType.Frame:
TWFrame frame = (TWFrame)value;
WriteValue(baseAddr, ref offset, ItemType.Fix32, frame.Left);
WriteValue(baseAddr, ref offset, ItemType.Fix32, frame.Top);
WriteValue(baseAddr, ref offset, ItemType.Fix32, frame.Right);
WriteValue(baseAddr, ref offset, ItemType.Fix32, frame.Bottom);
return; // no need to update offset for this
//case ItemType.String1024:
// WriteString(baseAddr, offset, value as string, 1024);
// break;
case ItemType.String128:
WriteString(baseAddr, offset, (string)value, 128);
break;
case ItemType.String255:
WriteString(baseAddr, offset, (string)value, 255);
break;
case ItemType.String32:
WriteString(baseAddr, offset, (string)value, 32);
break;
case ItemType.String64:
WriteString(baseAddr, offset, (string)value, 64);
break;
//case ItemType.Unicode512:
// WriteUString(baseAddr, offset, value as string, 512);
// break;
}
offset += TypeReader.GetItemTypeSize(type);
}
///
/// Writes string value.
///
///
///
///
///
static void WriteString(IntPtr baseAddr, int offset, string item, int maxLength)
{
if (string.IsNullOrEmpty(item))
{
// write zero
Marshal.WriteByte(baseAddr, offset, 0);
}
else
{
for (int i = 0; i < maxLength; i++)
{
if (i == item.Length)
{
// string end reached, so write \0 and quit
Marshal.WriteByte(baseAddr, offset, 0);
return;
}
else
{
Marshal.WriteByte(baseAddr, offset, (byte)item[i]);
offset++;
}
}
// when ended normally also write \0
Marshal.WriteByte(baseAddr, offset, 0);
}
}
/////
///// Writes unicode string value.
/////
/////
/////
/////
/////
//[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
//private void WriteUString(IntPtr baseAddr, int offset, string item, int maxLength)
//{
// if (string.IsNullOrEmpty(item))
// {
// // write zero
// Marshal.WriteInt16(baseAddr, offset, (char)0);
// }
// else
// {
// // use 2 bytes per char
// for (int i = 0; i < maxLength; i++)
// {
// if (i == item.Length)
// {
// // string end reached, so write \0 and quit
// Marshal.WriteInt16(baseAddr, offset, (char)0);
// return;
// }
// else
// {
// Marshal.WriteInt16(baseAddr, offset, item[i]);
// offset += 2;
// }
// }
// // when ended normally also write \0
// Marshal.WriteByte(baseAddr, offset, 0);
// }
//}
#endregion
#region IDisposable Members
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool disposing)
{
if (disposing) { }
if (_hContainer != IntPtr.Zero)
{
PlatformInfo.Current.MemoryManager.Free(_hContainer);
_hContainer = IntPtr.Zero;
}
}
///
/// Finalizes an instance of the class.
///
~TWCapability()
{
Dispose(false);
}
#endregion
///
/// A general method that returns the data in a .
///
/// The list to populate if necessary.
///
public IList