From 9e59e2355df1747c5a8e8a344d1f690d3e826253 Mon Sep 17 00:00:00 2001
From: Eugene Wang <8755753+soukoku@users.noreply.github.com>
Date: Tue, 4 Apr 2023 08:17:46 -0400
Subject: [PATCH] Start resurrecting old value reader/writer.
---
src/NTwain-temp/ValueReader.cs | 444 ----------------------
src/NTwain-temp/ValueWriter.cs | 617 -------------------------------
src/NTwain/Data/TWAINH_EXTRAS.cs | 25 +-
src/NTwain/Data/ValueReader.cs | 454 +++++++++++++++++++++++
src/NTwain/Data/ValueWriter.cs | 609 ++++++++++++++++++++++++++++++
5 files changed, 1064 insertions(+), 1085 deletions(-)
delete mode 100644 src/NTwain-temp/ValueReader.cs
delete mode 100644 src/NTwain-temp/ValueWriter.cs
create mode 100644 src/NTwain/Data/ValueReader.cs
create mode 100644 src/NTwain/Data/ValueWriter.cs
diff --git a/src/NTwain-temp/ValueReader.cs b/src/NTwain-temp/ValueReader.cs
deleted file mode 100644
index 95bdb31..0000000
--- a/src/NTwain-temp/ValueReader.cs
+++ /dev/null
@@ -1,444 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using TWAINWorkingGroup;
-using static TWAINWorkingGroup.TWAIN;
-
-namespace NTwain
-{
- ///
- /// Contains methods for reading pointers into various things.
- ///
- public static class ValueReader
- {
- ///
- /// Reads pointer as UTF8 string.
- ///
- /// Pointer to string.
- /// Number of bytes to read.
- ///
- public static unsafe string PtrToStringUTF8(IntPtr intPtr, int length)
- {
- if (intPtr == IntPtr.Zero) throw new ArgumentNullException(nameof(intPtr));
- if (length == 0) throw new ArgumentOutOfRangeException(nameof(length), length, "Length must be greater than 0.");
-
- //// safe method with 2 copies
- //var bytes = new byte[length];
- //Marshal.Copy(intPtr, bytes, 0, length);
- //return Encoding.UTF8.GetString(bytes);
-
- // unsafe method with 1 copy (does it work?)
- sbyte* bytes = (sbyte*)intPtr;
- var str = new string(bytes, 0, length, Encoding.UTF8);
- return str;
- }
-
-
-
- // most of these are modified from the original TWAIN.CapabilityToCsv()
-
- public static TValue ReadOneValueContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
- {
- if (cap.hContainer == IntPtr.Zero) return default;
-
- var lockedPtr = twain.DsmMemLock(cap.hContainer);
-
- try
- {
- TWTY itemType;
- // Mac has a level of indirection and a different structure (ick)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Crack the container...
- var onevalue = MarshalTo(lockedPtr);
- itemType = (TWTY)onevalue.ItemType;
- lockedPtr += Marshal.SizeOf(onevalue);
- }
- else
- {
- // Crack the container...
- var onevalue = MarshalTo(lockedPtr);
- itemType = onevalue.ItemType;
- lockedPtr += Marshal.SizeOf(onevalue);
- }
-
- return ReadContainerData(lockedPtr, itemType, 0);
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
- if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
- }
- }
- public static Enumeration ReadEnumerationContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
- {
- Enumeration retVal = new Enumeration();
-
- if (cap.hContainer == IntPtr.Zero) return retVal;
-
- var lockedPtr = twain.DsmMemLock(cap.hContainer);
-
- try
- {
- TWTY itemType;
- int count = 0;
-
- // Mac has a level of indirection and a different structure (ick)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Crack the container...
- var twenumerationmacosx = MarshalTo(lockedPtr);
- itemType = (TWTY)twenumerationmacosx.ItemType;
- count = (int)twenumerationmacosx.NumItems;
- retVal.DefaultIndex = (int)twenumerationmacosx.DefaultIndex;
- retVal.CurrentIndex = (int)twenumerationmacosx.CurrentIndex;
- lockedPtr += Marshal.SizeOf(twenumerationmacosx);
- }
- // Windows or the 2.4+ Linux DSM...
- else if (TWAIN.GetPlatform() == Platform.WINDOWS || ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
- {
- // Crack the container...
- var twenumeration = MarshalTo(lockedPtr);
- itemType = twenumeration.ItemType;
- count = (int)twenumeration.NumItems;
- retVal.DefaultIndex = (int)twenumeration.DefaultIndex;
- retVal.CurrentIndex = (int)twenumeration.CurrentIndex;
- lockedPtr += Marshal.SizeOf(twenumeration);
- }
- // The -2.3 Linux DSM...
- else if (twain.m_blFound020302Dsm64bit && (twain.m_linuxdsm == TWAIN.LinuxDsm.Is020302Dsm64bit))
- {
- // Crack the container...
- var twenumerationlinux64 = MarshalTo(lockedPtr);
- itemType = twenumerationlinux64.ItemType;
- count = (int)twenumerationlinux64.NumItems;
- retVal.DefaultIndex = (int)twenumerationlinux64.DefaultIndex;
- retVal.CurrentIndex = (int)twenumerationlinux64.CurrentIndex;
- lockedPtr += Marshal.SizeOf(twenumerationlinux64);
- }
- // This shouldn't be possible, but what the hey...
- else
- {
- Log.Error("This is serious, you win a cookie for getting here...");
- return retVal;
- }
-
- retVal.Items = new TValue[count];
-
- for (var i = 0; i < count; i++)
- {
- retVal.Items[i] = ReadContainerData(lockedPtr, itemType, i);
- }
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
- if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
- }
- return retVal;
- }
- public static IList ReadArrayContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
- {
- if (cap.hContainer == IntPtr.Zero) return EmptyArray.Value;
-
- var lockedPtr = twain.DsmMemLock(cap.hContainer);
-
- try
- {
- TWTY itemType;
- uint count;
-
- // Mac has a level of indirection and a different structure (ick)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Crack the container...
- var twarraymacosx = MarshalTo(lockedPtr);
- itemType = (TWTY)twarraymacosx.ItemType;
- count = twarraymacosx.NumItems;
- lockedPtr += Marshal.SizeOf(twarraymacosx);
- }
- else
- {
- // Crack the container...
- var twarray = MarshalTo(lockedPtr);
- itemType = twarray.ItemType;
- count = twarray.NumItems;
- lockedPtr += Marshal.SizeOf(twarray);
- }
-
- var arr = new TValue[count];
- for (var i = 0; i < count; i++)
- {
- arr[i] = ReadContainerData(lockedPtr, itemType, i);
- }
- return arr;
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
- if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
- }
- }
- public static Range ReadRangeContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
- {
- var retVal = new Range();
-
- if (cap.hContainer == IntPtr.Zero) return retVal;
-
- var lockedPtr = twain.DsmMemLock(cap.hContainer);
-
- try
- {
- TW_RANGE twrange = default;
- TW_RANGE_FIX32 twrangefix32 = default;
-
- // Mac has a level of indirection and a different structure (ick)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- var twrangemacosx = MarshalTo(lockedPtr);
- var twrangefix32macosx = MarshalTo(lockedPtr);
- twrange.ItemType = (TWTY)twrangemacosx.ItemType;
- twrange.MinValue = twrangemacosx.MinValue;
- twrange.MaxValue = twrangemacosx.MaxValue;
- twrange.StepSize = twrangemacosx.StepSize;
- twrange.DefaultValue = twrangemacosx.DefaultValue;
- twrange.CurrentValue = twrangemacosx.CurrentValue;
- twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
- twrangefix32.MinValue = twrangefix32macosx.MinValue;
- twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
- twrangefix32.StepSize = twrangefix32macosx.StepSize;
- twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
- twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
- }
- // Windows or the 2.4+ Linux DSM...
- else if (TWAIN.GetPlatform() == Platform.WINDOWS || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
- ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
- {
- twrange = MarshalTo(lockedPtr);
- twrangefix32 = MarshalTo(lockedPtr);
- }
- // The -2.3 Linux DSM...
- else
- {
- var twrangelinux64 = MarshalTo(lockedPtr);
- var twrangefix32macosx = MarshalTo(lockedPtr);
- twrange.ItemType = twrangelinux64.ItemType;
- twrange.MinValue = (uint)twrangelinux64.MinValue;
- twrange.MaxValue = (uint)twrangelinux64.MaxValue;
- twrange.StepSize = (uint)twrangelinux64.StepSize;
- twrange.DefaultValue = (uint)twrangelinux64.DefaultValue;
- twrange.CurrentValue = (uint)twrangelinux64.CurrentValue;
- twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
- twrangefix32.MinValue = twrangefix32macosx.MinValue;
- twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
- twrangefix32.StepSize = twrangefix32macosx.StepSize;
- twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
- twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
- }
-
- switch (twrange.ItemType)
- {
- // use dynamic since I know they fit the type.
- case TWTY.FIX32:
- retVal.MinValue = (dynamic)twrangefix32.MinValue;
- retVal.MaxValue = (dynamic)twrangefix32.MaxValue;
- retVal.StepSize = (dynamic)twrangefix32.StepSize;
- retVal.CurrentValue = (dynamic)twrangefix32.CurrentValue;
- retVal.DefaultValue = (dynamic)twrangefix32.DefaultValue;
- break;
- case TWTY.INT8:
- case TWTY.UINT8:
- case TWTY.INT16:
- case TWTY.BOOL:
- case TWTY.UINT16:
- case TWTY.INT32:
- case TWTY.UINT32:
- retVal.MinValue = (dynamic)twrange.MinValue;
- retVal.MaxValue = (dynamic)twrange.MaxValue;
- retVal.StepSize = (dynamic)twrange.StepSize;
- retVal.CurrentValue = (dynamic)twrange.CurrentValue;
- retVal.DefaultValue = (dynamic)twrange.DefaultValue;
- break;
- default:
- throw new NotSupportedException($"The value type {twrange.ItemType} is not supported as range.");
-
- }
- return retVal;
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
- if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
- }
- }
-
- ///
- /// Read the one value of a cap as string. Only STR* and HANDLE types are supported.
- ///
- ///
- ///
- ///
- ///
- public static string ReadOneValueContainerString(TWAIN twain, TW_CAPABILITY cap, bool freeMemory = true)
- {
- if (cap.hContainer == IntPtr.Zero) return null;
-
- var lockedPtr = twain.DsmMemLock(cap.hContainer);
-
- try
- {
- if (cap.ConType == TWON.ONEVALUE)
- {
- TWTY itemType;
- // Mac has a level of indirection and a different structure (ick)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Crack the container...
- var onevalue = MarshalTo(lockedPtr);
- itemType = (TWTY)onevalue.ItemType;
- lockedPtr += Marshal.SizeOf(onevalue);
- }
- else
- {
- // Crack the container...
- var onevalue = MarshalTo(lockedPtr);
- itemType = onevalue.ItemType;
- lockedPtr += Marshal.SizeOf(onevalue);
- }
-
- switch (itemType)
- {
- case TWTY.STR32:
- return MarshalTo(lockedPtr).ToString();
- case TWTY.STR64:
- return MarshalTo(lockedPtr).ToString();
- case TWTY.STR128:
- return MarshalTo(lockedPtr).ToString();
- case TWTY.STR255:
- return MarshalTo(lockedPtr).ToString();
- case TWTY.HANDLE:
- // null-terminated and encoded string.
- // good chance this ain't right.
- using (var stream = new MemoryStream())
- {
- byte read = Marshal.ReadByte(lockedPtr);
- while (read != 0)
- {
- stream.WriteByte(read);
- read = Marshal.ReadByte(lockedPtr);
- lockedPtr += 1;
- }
- // which one?
- return Encoding.Unicode.GetString(Encoding.Convert(Language.GetEncoding(), Encoding.Unicode, stream.ToArray()));
- //return Language.GetEncoding().GetString(stream.ToArray());
- }
- }
- }
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
- if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
- }
- return null;
- }
- ///
- /// Read the container pointer content.
- ///
- /// A locked pointer to the container's data pointer. If data is array this is the 0th item.
- /// The twain type.
- /// Index of the item if pointer is array.
- ///
- static TValue ReadContainerData(IntPtr intptr, TWTY type, int itemIndex) where TValue : struct
- {
- var isEnum = typeof(TValue).IsEnum;
-
- switch (type)
- {
- default:
- throw new NotSupportedException($"Unsupported item type {type} for reading.");
- // TODO: verify if needs to read int32 for small types
- case TWTY.INT8:
- intptr += 1 * itemIndex;
- if (isEnum)
- {
- return NumericToEnum(MarshalTo(intptr));
- }
- return MarshalTo(intptr);
- case TWTY.UINT8:
- intptr += 1 * itemIndex;
- if (isEnum)
- {
- return NumericToEnum(MarshalTo(intptr));
- }
- return MarshalTo(intptr);
- case TWTY.INT16:
- intptr += 2 * itemIndex;
- if (isEnum)
- {
- return NumericToEnum(MarshalTo(intptr));
- }
- return MarshalTo(intptr);
- case TWTY.BOOL:
- case TWTY.UINT16:
- intptr += 2 * itemIndex;
- if (isEnum)
- {
- return NumericToEnum(MarshalTo(intptr));
- }
- return MarshalTo(intptr);
- case TWTY.INT32:
- intptr += 4 * itemIndex;
- if (isEnum)
- {
- return NumericToEnum(MarshalTo(intptr));
- }
- return MarshalTo(intptr);
- case TWTY.UINT32:
- intptr += 4 * itemIndex;
- if (isEnum)
- {
- return NumericToEnum(MarshalTo(intptr));
- }
- return MarshalTo(intptr);
- case TWTY.FIX32:
- intptr += 4 * itemIndex;
- return MarshalTo(intptr);
- case TWTY.FRAME:
- intptr += 16 * itemIndex;
- return MarshalTo(intptr);
- case TWTY.STR32:
- intptr += TW_STR32.Size * itemIndex;
- return MarshalTo(intptr);
- case TWTY.STR64:
- intptr += TW_STR64.Size * itemIndex;
- return MarshalTo(intptr);
- case TWTY.STR128:
- intptr += TW_STR128.Size * itemIndex;
- return MarshalTo(intptr);
- case TWTY.STR255:
- intptr += TW_STR255.Size * itemIndex;
- return MarshalTo(intptr);
- }
- }
-
- static TEnum NumericToEnum(TNumber num) where TEnum : struct
- {
- // some caps returns a data type that's not the underlying datatype for the enum
- // so best way is to ToString() it and parse it as the enum type.
- var str = num.ToString();
-
- if (Enum.TryParse(str, out TEnum parsed))
- {
- return parsed;
- }
- return default;
- }
-
- static T MarshalTo(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T));
- }
-}
diff --git a/src/NTwain-temp/ValueWriter.cs b/src/NTwain-temp/ValueWriter.cs
deleted file mode 100644
index 981b584..0000000
--- a/src/NTwain-temp/ValueWriter.cs
+++ /dev/null
@@ -1,617 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using TWAINWorkingGroup;
-using static TWAINWorkingGroup.TWAIN;
-
-namespace NTwain
-{
- ///
- /// Contains methods for writing vairous things to pointers.
- ///
- public static class ValueWriter
- {
- ///
- /// Allocates and copies the string value into a pointer in UTF8 that's null-terminated.
- ///
- ///
- ///
- /// Actual number of bytes used to encode the string without the null.
- ///
- public static unsafe IntPtr StringToPtrUTF8(TWAIN twain, string value, out int length)
- {
- if (value == null)
- {
- length = 0;
- return IntPtr.Zero;
- }
-
- var utf8 = Encoding.UTF8;
- length = utf8.GetByteCount(value);
-
- var ptr = twain.DsmMemAlloc((uint)length + 1); // +1 for null-terminated
-
- // TODO: test if this works
- int written;
- byte* bytes = (byte*)ptr;
- try
- {
- // fixed for managed pointer
- fixed (char* firstChar = value)
- {
- written = Encoding.UTF8.GetBytes(firstChar, value.Length, bytes, length);
- }
-
- bytes[written] = 0;
- }
- catch
- {
- // just in case
- if (ptr != IntPtr.Zero) twain.DsmMemFree(ref ptr);
-
- throw;
- }
-
- return ptr;
- }
-
-
-
- // most of these are modified from the original TWAIN.CsvToCapability()
-
- public static void WriteOneValueContainer(TWAIN twain, ref TW_CAPABILITY twCap, TValue value) where TValue : struct
- {
- IntPtr lockedPtr = IntPtr.Zero;
- try
- {
- if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
-
- TWTY itemType = GetItemType();
-
- // Allocate the container (go for worst case, which is TW_STR255)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE_MACOSX)) + Marshal.SizeOf(default(TW_STR255))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- TW_ONEVALUE_MACOSX twonevaluemacosx = default;
- twonevaluemacosx.ItemType = (uint)itemType;
- Marshal.StructureToPtr(twonevaluemacosx, lockedPtr, false);
-
- lockedPtr += Marshal.SizeOf(twonevaluemacosx);
- }
- else
- {
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE)) + Marshal.SizeOf(default(TW_STR255))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- TW_ONEVALUE twonevalue = default;
- twonevalue.ItemType = itemType;
- Marshal.StructureToPtr(twonevalue, lockedPtr, false);
-
- lockedPtr += Marshal.SizeOf(twonevalue);
- }
-
- WriteContainerData(lockedPtr, itemType, value, 0);
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
- }
- }
-
- public static void WriteArrayContainer(TWAIN twain, ref TW_CAPABILITY twCap, TValue[] values) where TValue : struct
- {
- IntPtr lockedPtr = IntPtr.Zero;
- try
- {
- if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
-
- TWTY itemType = GetItemType();
-
- // Allocate the container (go for worst case, which is TW_STR255)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ARRAY_MACOSX)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- // Set the meta data...
- TW_ARRAY_MACOSX twarraymacosx = default;
- twarraymacosx.ItemType = (uint)itemType;
- twarraymacosx.NumItems = (uint)values.Length;
- Marshal.StructureToPtr(twarraymacosx, lockedPtr, false);
-
- // Get the pointer to the ItemList...
- lockedPtr += Marshal.SizeOf(twarraymacosx);
- }
- else
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ARRAY)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- // Set the meta data...
- TW_ARRAY twarray = default;
- twarray.ItemType = itemType;
- twarray.NumItems = (uint)values.Length;
- Marshal.StructureToPtr(twarray, lockedPtr, false);
-
- // Get the pointer to the ItemList...
- lockedPtr += Marshal.SizeOf(twarray);
- }
-
- // Set the ItemList...
- for (var i = 0; i < values.Length; i++)
- {
- WriteContainerData(lockedPtr, itemType, values[i], i);
- }
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
- }
- }
-
- public static void WriteEnumContainer(TWAIN twain, ref TW_CAPABILITY twCap, Enumeration value) where TValue : struct
- {
- IntPtr lockedPtr = IntPtr.Zero;
- try
- {
- if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
-
- TWTY itemType = GetItemType();
-
- // Allocate the container (go for worst case, which is TW_STR255)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_MACOSX)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- // Set the meta data...
- TW_ENUMERATION_MACOSX twenumerationmacosx = default;
- twenumerationmacosx.ItemType = (uint)itemType;
- twenumerationmacosx.NumItems = (uint)value.Items.Length;
- twenumerationmacosx.CurrentIndex = (uint)value.CurrentIndex;
- twenumerationmacosx.DefaultIndex = (uint)value.DefaultIndex;
- Marshal.StructureToPtr(twenumerationmacosx, lockedPtr, false);
-
- // Get the pointer to the ItemList...
- lockedPtr += Marshal.SizeOf(twenumerationmacosx);
- }
- // Windows or the 2.4+ Linux DSM...
- else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
- (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
- ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- // Set the meta data...
- TW_ENUMERATION twenumeration = default;
- twenumeration.ItemType = itemType;
- twenumeration.NumItems = (uint)value.Items.Length;
- twenumeration.CurrentIndex = (uint)value.CurrentIndex;
- twenumeration.DefaultIndex = (uint)value.CurrentIndex;
- Marshal.StructureToPtr(twenumeration, lockedPtr, false);
-
- // Get the pointer to the ItemList...
- lockedPtr += Marshal.SizeOf(twenumeration);
- }
- // The -2.3 Linux DSM...
- else
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_LINUX64)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
-
- // Set the meta data...
- TW_ENUMERATION_LINUX64 twenumerationlinux64 = default;
- twenumerationlinux64.ItemType = itemType;
- twenumerationlinux64.NumItems = (ulong)value.Items.Length;
- twenumerationlinux64.CurrentIndex = (ulong)value.CurrentIndex;
- twenumerationlinux64.DefaultIndex = (ulong)value.CurrentIndex;
- Marshal.StructureToPtr(twenumerationlinux64, lockedPtr, false);
-
- // Get the pointer to the ItemList...
- lockedPtr += Marshal.SizeOf(twenumerationlinux64);
- }
-
- // Set the ItemList...
- for (var i = 0; i < value.Items.Length; i++)
- {
- WriteContainerData(lockedPtr, itemType, value.Items[i], i);
- }
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
- }
- }
-
- public static void WriteRangeContainer(TWAIN twain, ref TW_CAPABILITY twCap, Range value) where TValue : struct
- {
- IntPtr lockedPtr = IntPtr.Zero;
- try
- {
- if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
-
- TWTY itemType = GetItemType();
-
- // Allocate the container (go for worst case, which is TW_STR255)...
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE_MACOSX))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
- }
- // Windows or the 2.4+ Linux DSM...
- else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
- (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
- ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
- }
- // The -2.3 Linux DSM...
- else
- {
- // Allocate...
- twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE_LINUX64))));
- lockedPtr = twain.DsmMemLock(twCap.hContainer);
- }
-
- // Set the Item...
- WriteRangeValues(twain, lockedPtr, itemType, value);
- }
- finally
- {
- if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
- }
- }
-
- static void WriteRangeValues(TWAIN twain, IntPtr lockedPtr, TWTY itemType, Range value) where TValue : struct
- {
- // TODO: reduce this later
-
- TW_RANGE twrange = default;
- TW_RANGE_MACOSX twrangemacosx = default;
- TW_RANGE_LINUX64 twrangelinux64 = default;
-
- switch (itemType)
- {
- default:
- throw new NotSupportedException($"{itemType} is not supported for range.");
- case TWTY.INT8:
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twrangemacosx.ItemType = (uint)itemType;
- twrangemacosx.MinValue = (uint)Convert.ToSByte(value.MinValue);
- twrangemacosx.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
- twrangemacosx.StepSize = (uint)Convert.ToSByte(value.StepSize);
- twrangemacosx.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
- twrangemacosx.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
- Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
- }
- else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
- {
- twrange.ItemType = itemType;
- twrange.MinValue = (uint)Convert.ToSByte(value.MinValue);
- twrange.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
- twrange.StepSize = (uint)Convert.ToSByte(value.StepSize);
- twrange.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
- twrange.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
- Marshal.StructureToPtr(twrange, lockedPtr, false);
- }
- else
- {
- twrangelinux64.ItemType = itemType;
- twrangelinux64.MinValue = (uint)Convert.ToSByte(value.MinValue);
- twrangelinux64.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
- twrangelinux64.StepSize = (uint)Convert.ToSByte(value.StepSize);
- twrangelinux64.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
- twrangelinux64.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
- Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
- }
- break;
- case TWTY.UINT8:
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twrangemacosx.ItemType = (uint)itemType;
- twrangemacosx.MinValue = Convert.ToByte(value.MinValue);
- twrangemacosx.MaxValue = Convert.ToByte(value.MaxValue);
- twrangemacosx.StepSize = Convert.ToByte(value.StepSize);
- twrangemacosx.DefaultValue = Convert.ToByte(value.DefaultValue);
- twrangemacosx.CurrentValue = Convert.ToByte(value.CurrentValue);
- Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
- }
- else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
- {
- twrange.ItemType = itemType;
- twrange.MinValue = Convert.ToByte(value.MinValue);
- twrange.MaxValue = Convert.ToByte(value.MaxValue);
- twrange.StepSize = Convert.ToByte(value.StepSize);
- twrange.DefaultValue = Convert.ToByte(value.DefaultValue);
- twrange.CurrentValue = Convert.ToByte(value.CurrentValue);
- Marshal.StructureToPtr(twrange, lockedPtr, false);
- }
- else
- {
- twrangelinux64.ItemType = itemType;
- twrangelinux64.MinValue = Convert.ToByte(value.MinValue);
- twrangelinux64.MaxValue = Convert.ToByte(value.MaxValue);
- twrangelinux64.StepSize = Convert.ToByte(value.StepSize);
- twrangelinux64.DefaultValue = Convert.ToByte(value.DefaultValue);
- twrangelinux64.CurrentValue = Convert.ToByte(value.CurrentValue);
- Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
- }
- break;
- case TWTY.INT16:
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twrangemacosx.ItemType = (uint)itemType;
- twrangemacosx.MinValue = (uint)Convert.ToInt16(value.MinValue);
- twrangemacosx.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
- twrangemacosx.StepSize = (uint)Convert.ToInt16(value.StepSize);
- twrangemacosx.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
- twrangemacosx.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
- Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
- }
- else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
- {
- twrange.ItemType = itemType;
- twrange.MinValue = (uint)Convert.ToInt16(value.MinValue);
- twrange.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
- twrange.StepSize = (uint)Convert.ToInt16(value.StepSize);
- twrange.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
- twrange.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
- Marshal.StructureToPtr(twrange, lockedPtr, false);
- }
- else
- {
- twrangelinux64.ItemType = itemType;
- twrangelinux64.MinValue = (uint)Convert.ToInt16(value.MinValue);
- twrangelinux64.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
- twrangelinux64.StepSize = (uint)Convert.ToInt16(value.StepSize);
- twrangelinux64.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
- twrangelinux64.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
- Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
- }
- break;
- case TWTY.BOOL:
- case TWTY.UINT16:
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twrangemacosx.ItemType = (uint)itemType;
- twrangemacosx.MinValue = Convert.ToUInt16(value.MinValue);
- twrangemacosx.MaxValue = Convert.ToUInt16(value.MaxValue);
- twrangemacosx.StepSize = Convert.ToUInt16(value.StepSize);
- twrangemacosx.DefaultValue = Convert.ToUInt16(value.DefaultValue);
- twrangemacosx.CurrentValue = Convert.ToUInt16(value.CurrentValue);
- Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
- }
- else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
- {
- twrange.ItemType = itemType;
- twrange.MinValue = Convert.ToUInt16(value.MinValue);
- twrange.MaxValue = Convert.ToUInt16(value.MaxValue);
- twrange.StepSize = Convert.ToUInt16(value.StepSize);
- twrange.DefaultValue = Convert.ToUInt16(value.DefaultValue);
- twrange.CurrentValue = Convert.ToUInt16(value.CurrentValue);
- Marshal.StructureToPtr(twrange, lockedPtr, false);
- }
- else
- {
- twrangelinux64.ItemType = itemType;
- twrangelinux64.MinValue = Convert.ToUInt16(value.MinValue);
- twrangelinux64.MaxValue = Convert.ToUInt16(value.MaxValue);
- twrangelinux64.StepSize = Convert.ToUInt16(value.StepSize);
- twrangelinux64.DefaultValue = Convert.ToUInt16(value.DefaultValue);
- twrangelinux64.CurrentValue = Convert.ToUInt16(value.CurrentValue);
- Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
- }
- break;
- case TWTY.INT32:
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twrangemacosx.ItemType = (uint)itemType;
- twrangemacosx.MinValue = (uint)Convert.ToInt32(value.MinValue);
- twrangemacosx.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
- twrangemacosx.StepSize = (uint)Convert.ToInt32(value.StepSize);
- twrangemacosx.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
- twrangemacosx.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
- Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
- }
- else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
- {
- twrange.ItemType = itemType;
- twrange.MinValue = (uint)Convert.ToInt32(value.MinValue);
- twrange.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
- twrange.StepSize = (uint)Convert.ToInt32(value.StepSize);
- twrange.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
- twrange.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
- Marshal.StructureToPtr(twrange, lockedPtr, false);
- }
- else
- {
- twrangelinux64.ItemType = itemType;
- twrangelinux64.MinValue = (uint)Convert.ToInt32(value.MinValue);
- twrangelinux64.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
- twrangelinux64.StepSize = (uint)Convert.ToInt32(value.StepSize);
- twrangelinux64.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
- twrangelinux64.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
- Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
- }
- break;
- case TWTY.UINT32:
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- twrangemacosx.ItemType = (uint)itemType;
- twrangemacosx.MinValue = Convert.ToUInt32(value.MinValue);
- twrangemacosx.MaxValue = Convert.ToUInt32(value.MaxValue);
- twrangemacosx.StepSize = Convert.ToUInt32(value.StepSize);
- twrangemacosx.DefaultValue = Convert.ToUInt32(value.DefaultValue);
- twrangemacosx.CurrentValue = Convert.ToUInt32(value.CurrentValue);
- Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
- }
- else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
- {
- twrange.ItemType = itemType;
- twrange.MinValue = Convert.ToUInt32(value.MinValue);
- twrange.MaxValue = Convert.ToUInt32(value.MaxValue);
- twrange.StepSize = Convert.ToUInt32(value.StepSize);
- twrange.DefaultValue = Convert.ToUInt32(value.DefaultValue);
- twrange.CurrentValue = Convert.ToUInt32(value.CurrentValue);
- Marshal.StructureToPtr(twrange, lockedPtr, false);
- }
- else
- {
- twrangelinux64.ItemType = itemType;
- twrangelinux64.MinValue = Convert.ToUInt32(value.MinValue);
- twrangelinux64.MaxValue = Convert.ToUInt32(value.MaxValue);
- twrangelinux64.StepSize = Convert.ToUInt32(value.StepSize);
- twrangelinux64.DefaultValue = Convert.ToUInt32(value.DefaultValue);
- twrangelinux64.CurrentValue = Convert.ToUInt32(value.CurrentValue);
- Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
- }
- break;
- case TWTY.FIX32:
- double min = Convert.ToDouble(value.MinValue);
- double max = Convert.ToDouble(value.MaxValue);
- double step = Convert.ToDouble(value.StepSize);
- double def = Convert.ToDouble(value.DefaultValue);
- double current = Convert.ToDouble(value.CurrentValue);
- if (TWAIN.GetPlatform() == Platform.MACOSX)
- {
- TW_RANGE_FIX32_MACOSX twrangefix32macosx = default;
- twrangefix32macosx.ItemType = (uint)itemType;
- twrangefix32macosx.MinValue = new TW_FIX32(min);
- twrangefix32macosx.MaxValue = new TW_FIX32(max);
- twrangefix32macosx.StepSize = new TW_FIX32(step);
- twrangefix32macosx.DefaultValue = new TW_FIX32(def);
- twrangefix32macosx.CurrentValue = new TW_FIX32(current);
- Marshal.StructureToPtr(twrangefix32macosx, lockedPtr, false);
- }
- else
- {
- TW_RANGE_FIX32 twrangefix32 = default;
- twrangefix32.ItemType = itemType;
- twrangefix32.MinValue = new TW_FIX32(min);
- twrangefix32.MaxValue = new TW_FIX32(max);
- twrangefix32.StepSize = new TW_FIX32(step);
- twrangefix32.DefaultValue = new TW_FIX32(def);
- twrangefix32.CurrentValue = new TW_FIX32(current);
- Marshal.StructureToPtr(twrangefix32, lockedPtr, false);
- }
- break;
- }
- }
-
- static TWTY GetItemType() where TValue : struct
- {
- var type = typeof(TValue);
- if (type == typeof(BoolType)) return TWTY.BOOL;
- if (type == typeof(TW_FIX32)) return TWTY.FIX32;
- if (type == typeof(TW_STR32)) return TWTY.STR32;
- if (type == typeof(TW_STR64)) return TWTY.STR64;
- if (type == typeof(TW_STR128)) return TWTY.STR128;
- if (type == typeof(TW_STR255)) return TWTY.STR255;
- if (type == typeof(TW_FRAME)) return TWTY.FRAME;
-
- if (type.IsEnum)
- {
- type = type.GetEnumUnderlyingType();
- }
-
- if (type == typeof(ushort)) return TWTY.UINT16;
- if (type == typeof(short)) return TWTY.INT16;
- if (type == typeof(uint)) return TWTY.UINT32;
- if (type == typeof(int)) return TWTY.INT32;
- if (type == typeof(byte)) return TWTY.UINT8;
- if (type == typeof(sbyte)) return TWTY.INT8;
-
- throw new NotSupportedException($"{type.Name} is not supported for writing.");
- }
-
- ///
- /// Writes single piece of value to the container pointer.
- ///
- ///
- /// A locked pointer to the container's data pointer. If data is array this is the 0th item.
- /// The twain type.
- ///
- /// Index of the item if pointer is array.
- static void WriteContainerData(IntPtr intptr, TWTY type, TValue value, int itemIndex) where TValue : struct
- {
- switch (type)
- {
- default:
- throw new NotSupportedException($"Unsupported item type {type} for writing.");
- // TODO: for small types needs to fill whole int32 before writing?
- case TWTY.INT8:
- intptr += 1 * itemIndex;
- //int intval = Convert.ToSByte(value);
- //Marshal.StructureToPtr(intval, intptr, false);
- Marshal.StructureToPtr(Convert.ToSByte(value), intptr, false);
- break;
- case TWTY.UINT8:
- intptr += 1 * itemIndex;
- //uint uintval = Convert.ToByte(value);
- //Marshal.StructureToPtr(uintval, intptr, false);
- Marshal.StructureToPtr(Convert.ToByte(value), intptr, false);
- break;
- case TWTY.INT16:
- intptr += 2 * itemIndex;
- //intval = Convert.ToInt16(value);
- //Marshal.StructureToPtr(intval, intptr, false);
- Marshal.StructureToPtr(Convert.ToInt16(value), intptr, false);
- break;
- case TWTY.BOOL:
- case TWTY.UINT16:
- intptr += 2 * itemIndex;
- //uintval = Convert.ToUInt16(value);
- //Marshal.StructureToPtr(uintval, intptr, false);
- Marshal.StructureToPtr(Convert.ToUInt16(value), intptr, false);
- break;
- case TWTY.INT32:
- intptr += 4 * itemIndex;
- Marshal.StructureToPtr(Convert.ToInt32(value), intptr, false);
- break;
- case TWTY.UINT32:
- intptr += 4 * itemIndex;
- Marshal.StructureToPtr(Convert.ToUInt32(value), intptr, false);
- break;
- case TWTY.FIX32:
- intptr += 4 * itemIndex;
- Marshal.StructureToPtr(value, intptr, false);
- break;
- case TWTY.FRAME:
- intptr += 16 * itemIndex;
- Marshal.StructureToPtr(value, intptr, false);
- break;
- case TWTY.STR32:
- intptr += TW_STR32.Size * itemIndex;
- Marshal.StructureToPtr(value, intptr, false);
- break;
- case TWTY.STR64:
- intptr += TW_STR64.Size * itemIndex;
- Marshal.StructureToPtr(value, intptr, false);
- break;
- case TWTY.STR128:
- intptr += TW_STR128.Size * itemIndex;
- Marshal.StructureToPtr(value, intptr, false);
- break;
- case TWTY.STR255:
- intptr += TW_STR255.Size * itemIndex;
- Marshal.StructureToPtr(value, intptr, false);
- break;
- }
- }
- }
-}
diff --git a/src/NTwain/Data/TWAINH_EXTRAS.cs b/src/NTwain/Data/TWAINH_EXTRAS.cs
index 44e105f..5770886 100644
--- a/src/NTwain/Data/TWAINH_EXTRAS.cs
+++ b/src/NTwain/Data/TWAINH_EXTRAS.cs
@@ -710,30 +710,7 @@ namespace NTwain.Data
string? val = null;
if (UTF8string != IntPtr.Zero && Size > 0)
{
- var locked = mgr.Lock(UTF8string);
- if (locked != IntPtr.Zero)
- {
- // does this work? who knows.
- try
- {
-#if NETFRAMEWORK
- // safe method but with 2 copies (arr and parsed string)
- var bytes = new byte[Size];
- Marshal.Copy(locked, bytes, 0, bytes.Length);
- val = Encoding.UTF8.GetString(bytes);
-
- //// unsafe method with 1 copy (does it work?)
- //sbyte* bytes = (sbyte*)locked;
- //val = new string(bytes, 0, length, Encoding.UTF8);
-#else
- val = Marshal.PtrToStringUTF8(locked, (int)Size);
-#endif
- }
- finally
- {
- mgr.Unlock(UTF8string);
- }
- }
+ val = ValueReader.PtrToStringUTF8(mgr, UTF8string, (int)Size);
}
if (freeMemory) Free(mgr);
return val;
diff --git a/src/NTwain/Data/ValueReader.cs b/src/NTwain/Data/ValueReader.cs
new file mode 100644
index 0000000..14a87b3
--- /dev/null
+++ b/src/NTwain/Data/ValueReader.cs
@@ -0,0 +1,454 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace NTwain.Data
+{
+ ///
+ /// Contains methods for reading pointers into various things.
+ ///
+ static class ValueReader
+ {
+ ///
+ /// Reads pointer as UTF8 string.
+ ///
+ /// Pointer to string.
+ /// Number of bytes to read.
+ ///
+ public static string? PtrToStringUTF8(IMemoryManager memMgr, IntPtr data, int length)
+ {
+ string? val = null;
+ var locked = memMgr.Lock(data);
+ if (locked != IntPtr.Zero)
+ {
+ // does this work? who knows.
+ try
+ {
+#if NETFRAMEWORK
+ // safe method but with 2 copies (arr and parsed string)
+ var bytes = new byte[length];
+ Marshal.Copy(locked, bytes, 0, bytes.Length);
+ val = Encoding.UTF8.GetString(bytes);
+
+ //// unsafe method with 1 copy (does it work?)
+ //sbyte* bytes = (sbyte*)locked;
+ //val = new string(bytes, 0, length, Encoding.UTF8);
+#else
+ val = Marshal.PtrToStringUTF8(locked, length);
+#endif
+ }
+ finally
+ {
+ memMgr.Unlock(data);
+ }
+ }
+ return val;
+ }
+
+
+
+ // most of these are modified from the original TWAIN.CapabilityToCsv()
+
+ //public static TValue ReadOneValueContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
+ //{
+ // if (cap.hContainer == IntPtr.Zero) return default;
+
+ // var lockedPtr = memMgr.Lock(cap.hContainer);
+
+ // try
+ // {
+ // TWTY itemType;
+ // // Mac has a level of indirection and a different structure (ick)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Crack the container...
+ // var onevalue = MarshalTo(lockedPtr);
+ // itemType = (TWTY)onevalue.ItemType;
+ // lockedPtr += Marshal.SizeOf(onevalue);
+ // }
+ // else
+ // {
+ // // Crack the container...
+ // var onevalue = MarshalTo(lockedPtr);
+ // itemType = onevalue.ItemType;
+ // lockedPtr += Marshal.SizeOf(onevalue);
+ // }
+
+ // return ReadContainerData(lockedPtr, itemType, 0);
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
+ // if (freeMemory) memMgr.Free(ref cap.hContainer);
+ // }
+ //}
+ //public static Enumeration ReadEnumerationContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
+ //{
+ // Enumeration retVal = new Enumeration();
+
+ // if (cap.hContainer == IntPtr.Zero) return retVal;
+
+ // var lockedPtr = memMgr.Lock(cap.hContainer);
+
+ // try
+ // {
+ // TWTY itemType;
+ // int count = 0;
+
+ // // Mac has a level of indirection and a different structure (ick)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Crack the container...
+ // var twenumerationmacosx = MarshalTo(lockedPtr);
+ // itemType = (TWTY)twenumerationmacosx.ItemType;
+ // count = (int)twenumerationmacosx.NumItems;
+ // retVal.DefaultIndex = (int)twenumerationmacosx.DefaultIndex;
+ // retVal.CurrentIndex = (int)twenumerationmacosx.CurrentIndex;
+ // lockedPtr += Marshal.SizeOf(twenumerationmacosx);
+ // }
+ // // Windows or the 2.4+ Linux DSM...
+ // else if (TWAIN.GetPlatform() == Platform.WINDOWS || ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
+ // {
+ // // Crack the container...
+ // var twenumeration = MarshalTo(lockedPtr);
+ // itemType = twenumeration.ItemType;
+ // count = (int)twenumeration.NumItems;
+ // retVal.DefaultIndex = (int)twenumeration.DefaultIndex;
+ // retVal.CurrentIndex = (int)twenumeration.CurrentIndex;
+ // lockedPtr += Marshal.SizeOf(twenumeration);
+ // }
+ // // The -2.3 Linux DSM...
+ // else if (twain.m_blFound020302Dsm64bit && (twain.m_linuxdsm == TWAIN.LinuxDsm.Is020302Dsm64bit))
+ // {
+ // // Crack the container...
+ // var twenumerationlinux64 = MarshalTo(lockedPtr);
+ // itemType = twenumerationlinux64.ItemType;
+ // count = (int)twenumerationlinux64.NumItems;
+ // retVal.DefaultIndex = (int)twenumerationlinux64.DefaultIndex;
+ // retVal.CurrentIndex = (int)twenumerationlinux64.CurrentIndex;
+ // lockedPtr += Marshal.SizeOf(twenumerationlinux64);
+ // }
+ // // This shouldn't be possible, but what the hey...
+ // else
+ // {
+ // Log.Error("This is serious, you win a cookie for getting here...");
+ // return retVal;
+ // }
+
+ // retVal.Items = new TValue[count];
+
+ // for (var i = 0; i < count; i++)
+ // {
+ // retVal.Items[i] = ReadContainerData(lockedPtr, itemType, i);
+ // }
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
+ // if (freeMemory) memMgr.Free(ref cap.hContainer);
+ // }
+ // return retVal;
+ //}
+ //public static IList ReadArrayContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
+ //{
+ // if (cap.hContainer == IntPtr.Zero) return EmptyArray.Value;
+
+ // var lockedPtr = memMgr.Lock(cap.hContainer);
+
+ // try
+ // {
+ // TWTY itemType;
+ // uint count;
+
+ // // Mac has a level of indirection and a different structure (ick)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Crack the container...
+ // var twarraymacosx = MarshalTo(lockedPtr);
+ // itemType = (TWTY)twarraymacosx.ItemType;
+ // count = twarraymacosx.NumItems;
+ // lockedPtr += Marshal.SizeOf(twarraymacosx);
+ // }
+ // else
+ // {
+ // // Crack the container...
+ // var twarray = MarshalTo(lockedPtr);
+ // itemType = twarray.ItemType;
+ // count = twarray.NumItems;
+ // lockedPtr += Marshal.SizeOf(twarray);
+ // }
+
+ // var arr = new TValue[count];
+ // for (var i = 0; i < count; i++)
+ // {
+ // arr[i] = ReadContainerData(lockedPtr, itemType, i);
+ // }
+ // return arr;
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
+ // if (freeMemory) memMgr.Free(ref cap.hContainer);
+ // }
+ //}
+ //public static Range ReadRangeContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
+ //{
+ // var retVal = new Range();
+
+ // if (cap.hContainer == IntPtr.Zero) return retVal;
+
+ // var lockedPtr = memMgr.Lock(cap.hContainer);
+
+ // try
+ // {
+ // TW_RANGE twrange = default;
+ // TW_RANGE_FIX32 twrangefix32 = default;
+
+ // // Mac has a level of indirection and a different structure (ick)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // var twrangemacosx = MarshalTo(lockedPtr);
+ // var twrangefix32macosx = MarshalTo(lockedPtr);
+ // twrange.ItemType = (TWTY)twrangemacosx.ItemType;
+ // twrange.MinValue = twrangemacosx.MinValue;
+ // twrange.MaxValue = twrangemacosx.MaxValue;
+ // twrange.StepSize = twrangemacosx.StepSize;
+ // twrange.DefaultValue = twrangemacosx.DefaultValue;
+ // twrange.CurrentValue = twrangemacosx.CurrentValue;
+ // twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
+ // twrangefix32.MinValue = twrangefix32macosx.MinValue;
+ // twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
+ // twrangefix32.StepSize = twrangefix32macosx.StepSize;
+ // twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
+ // twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
+ // }
+ // // Windows or the 2.4+ Linux DSM...
+ // else if (TWAIN.GetPlatform() == Platform.WINDOWS || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
+ // ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
+ // {
+ // twrange = MarshalTo(lockedPtr);
+ // twrangefix32 = MarshalTo(lockedPtr);
+ // }
+ // // The -2.3 Linux DSM...
+ // else
+ // {
+ // var twrangelinux64 = MarshalTo(lockedPtr);
+ // var twrangefix32macosx = MarshalTo(lockedPtr);
+ // twrange.ItemType = twrangelinux64.ItemType;
+ // twrange.MinValue = (uint)twrangelinux64.MinValue;
+ // twrange.MaxValue = (uint)twrangelinux64.MaxValue;
+ // twrange.StepSize = (uint)twrangelinux64.StepSize;
+ // twrange.DefaultValue = (uint)twrangelinux64.DefaultValue;
+ // twrange.CurrentValue = (uint)twrangelinux64.CurrentValue;
+ // twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
+ // twrangefix32.MinValue = twrangefix32macosx.MinValue;
+ // twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
+ // twrangefix32.StepSize = twrangefix32macosx.StepSize;
+ // twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
+ // twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
+ // }
+
+ // switch (twrange.ItemType)
+ // {
+ // // use dynamic since I know they fit the type.
+ // case TWTY.FIX32:
+ // retVal.MinValue = (dynamic)twrangefix32.MinValue;
+ // retVal.MaxValue = (dynamic)twrangefix32.MaxValue;
+ // retVal.StepSize = (dynamic)twrangefix32.StepSize;
+ // retVal.CurrentValue = (dynamic)twrangefix32.CurrentValue;
+ // retVal.DefaultValue = (dynamic)twrangefix32.DefaultValue;
+ // break;
+ // case TWTY.INT8:
+ // case TWTY.UINT8:
+ // case TWTY.INT16:
+ // case TWTY.BOOL:
+ // case TWTY.UINT16:
+ // case TWTY.INT32:
+ // case TWTY.UINT32:
+ // retVal.MinValue = (dynamic)twrange.MinValue;
+ // retVal.MaxValue = (dynamic)twrange.MaxValue;
+ // retVal.StepSize = (dynamic)twrange.StepSize;
+ // retVal.CurrentValue = (dynamic)twrange.CurrentValue;
+ // retVal.DefaultValue = (dynamic)twrange.DefaultValue;
+ // break;
+ // default:
+ // throw new NotSupportedException($"The value type {twrange.ItemType} is not supported as range.");
+
+ // }
+ // return retVal;
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
+ // if (freeMemory) memMgr.Free(ref cap.hContainer);
+ // }
+ //}
+
+ /////
+ ///// Read the one value of a cap as string. Only STR* and HANDLE types are supported.
+ /////
+ /////
+ /////
+ /////
+ /////
+ //public static string ReadOneValueContainerString(IMemoryManager memMgr, TW_CAPABILITY cap, bool freeMemory = true)
+ //{
+ // if (cap.hContainer == IntPtr.Zero) return null;
+
+ // var lockedPtr = memMgr.Lock(cap.hContainer);
+
+ // try
+ // {
+ // if (cap.ConType == TWON.ONEVALUE)
+ // {
+ // TWTY itemType;
+ // // Mac has a level of indirection and a different structure (ick)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Crack the container...
+ // var onevalue = MarshalTo(lockedPtr);
+ // itemType = (TWTY)onevalue.ItemType;
+ // lockedPtr += Marshal.SizeOf(onevalue);
+ // }
+ // else
+ // {
+ // // Crack the container...
+ // var onevalue = MarshalTo(lockedPtr);
+ // itemType = onevalue.ItemType;
+ // lockedPtr += Marshal.SizeOf(onevalue);
+ // }
+
+ // switch (itemType)
+ // {
+ // case TWTY.STR32:
+ // return MarshalTo(lockedPtr).ToString();
+ // case TWTY.STR64:
+ // return MarshalTo(lockedPtr).ToString();
+ // case TWTY.STR128:
+ // return MarshalTo(lockedPtr).ToString();
+ // case TWTY.STR255:
+ // return MarshalTo(lockedPtr).ToString();
+ // case TWTY.HANDLE:
+ // // null-terminated and encoded string.
+ // // good chance this ain't right.
+ // using (var stream = new MemoryStream())
+ // {
+ // byte read = Marshal.ReadByte(lockedPtr);
+ // while (read != 0)
+ // {
+ // stream.WriteByte(read);
+ // read = Marshal.ReadByte(lockedPtr);
+ // lockedPtr += 1;
+ // }
+ // // which one?
+ // return Encoding.Unicode.GetString(Encoding.Convert(Language.GetEncoding(), Encoding.Unicode, stream.ToArray()));
+ // //return Language.GetEncoding().GetString(stream.ToArray());
+ // }
+ // }
+ // }
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
+ // if (freeMemory) memMgr.Free(ref cap.hContainer);
+ // }
+ // return null;
+ //}
+ /////
+ ///// Read the container pointer content.
+ /////
+ ///// A locked pointer to the container's data pointer. If data is array this is the 0th item.
+ ///// The twain type.
+ ///// Index of the item if pointer is array.
+ /////
+ //static TValue ReadContainerData(IntPtr intptr, TWTY type, int itemIndex) where TValue : struct
+ //{
+ // var isEnum = typeof(TValue).IsEnum;
+
+ // switch (type)
+ // {
+ // default:
+ // throw new NotSupportedException($"Unsupported item type {type} for reading.");
+ // // TODO: verify if needs to read int32 for small types
+ // case TWTY.INT8:
+ // intptr += 1 * itemIndex;
+ // if (isEnum)
+ // {
+ // return NumericToEnum(MarshalTo(intptr));
+ // }
+ // return MarshalTo(intptr);
+ // case TWTY.UINT8:
+ // intptr += 1 * itemIndex;
+ // if (isEnum)
+ // {
+ // return NumericToEnum(MarshalTo(intptr));
+ // }
+ // return MarshalTo(intptr);
+ // case TWTY.INT16:
+ // intptr += 2 * itemIndex;
+ // if (isEnum)
+ // {
+ // return NumericToEnum(MarshalTo(intptr));
+ // }
+ // return MarshalTo(intptr);
+ // case TWTY.BOOL:
+ // case TWTY.UINT16:
+ // intptr += 2 * itemIndex;
+ // if (isEnum)
+ // {
+ // return NumericToEnum(MarshalTo(intptr));
+ // }
+ // return MarshalTo(intptr);
+ // case TWTY.INT32:
+ // intptr += 4 * itemIndex;
+ // if (isEnum)
+ // {
+ // return NumericToEnum(MarshalTo(intptr));
+ // }
+ // return MarshalTo(intptr);
+ // case TWTY.UINT32:
+ // intptr += 4 * itemIndex;
+ // if (isEnum)
+ // {
+ // return NumericToEnum(MarshalTo(intptr));
+ // }
+ // return MarshalTo(intptr);
+ // case TWTY.FIX32:
+ // intptr += 4 * itemIndex;
+ // return MarshalTo(intptr);
+ // case TWTY.FRAME:
+ // intptr += 16 * itemIndex;
+ // return MarshalTo(intptr);
+ // case TWTY.STR32:
+ // intptr += TW_STR32.Size * itemIndex;
+ // return MarshalTo(intptr);
+ // case TWTY.STR64:
+ // intptr += TW_STR64.Size * itemIndex;
+ // return MarshalTo(intptr);
+ // case TWTY.STR128:
+ // intptr += TW_STR128.Size * itemIndex;
+ // return MarshalTo(intptr);
+ // case TWTY.STR255:
+ // intptr += TW_STR255.Size * itemIndex;
+ // return MarshalTo(intptr);
+ // }
+ //}
+
+ //static TEnum NumericToEnum(TNumber num) where TEnum : struct
+ //{
+ // // some caps returns a data type that's not the underlying datatype for the enum
+ // // so best way is to ToString() it and parse it as the enum type.
+ // var str = num.ToString();
+
+ // if (Enum.TryParse(str, out TEnum parsed))
+ // {
+ // return parsed;
+ // }
+ // return default;
+ //}
+
+ //static T MarshalTo(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T));
+ }
+}
diff --git a/src/NTwain/Data/ValueWriter.cs b/src/NTwain/Data/ValueWriter.cs
new file mode 100644
index 0000000..92c5125
--- /dev/null
+++ b/src/NTwain/Data/ValueWriter.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace NTwain.Data
+{
+ ///
+ /// Contains methods for writing vairous things to pointers.
+ ///
+ static class ValueWriter
+ {
+ /////
+ ///// Allocates and copies the string value into a pointer in UTF8 that's null-terminated.
+ /////
+ /////
+ /////
+ ///// Actual number of bytes used to encode the string without the null.
+ /////
+ //public static unsafe IntPtr StringToPtrUTF8(IMemoryManager memMgr, string value, out int length)
+ //{
+ // if (value == null)
+ // {
+ // length = 0;
+ // return IntPtr.Zero;
+ // }
+
+ // var utf8 = Encoding.UTF8;
+ // length = utf8.GetByteCount(value);
+
+ // var ptr = memMgr.Alloc((uint)length + 1); // +1 for null-terminated
+
+ // // TODO: test if this works
+ // int written;
+ // byte* bytes = (byte*)ptr;
+ // try
+ // {
+ // // fixed for managed pointer
+ // fixed (char* firstChar = value)
+ // {
+ // written = Encoding.UTF8.GetBytes(firstChar, value.Length, bytes, length);
+ // }
+
+ // bytes[written] = 0;
+ // }
+ // finally
+ // {
+ // if (ptr != IntPtr.Zero) memMgr.Free(ptr);
+ // }
+
+ // return ptr;
+ //}
+
+
+
+ // most of these are modified from the original TWAIN.CsvToCapability()
+
+ //public static void WriteOneValueContainer(IMemoryManager memMgr, ref TW_CAPABILITY twCap, TValue value) where TValue : struct
+ //{
+ // IntPtr lockedPtr = IntPtr.Zero;
+ // try
+ // {
+ // if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
+
+ // TWTY itemType = GetItemType();
+
+ // // Allocate the container (go for worst case, which is TW_STR255)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE_MACOSX)) + Marshal.SizeOf(default(TW_STR255))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // TW_ONEVALUE_MACOSX twonevaluemacosx = default;
+ // twonevaluemacosx.ItemType = (uint)itemType;
+ // Marshal.StructureToPtr(twonevaluemacosx, lockedPtr, false);
+
+ // lockedPtr += Marshal.SizeOf(twonevaluemacosx);
+ // }
+ // else
+ // {
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE)) + Marshal.SizeOf(default(TW_STR255))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // TW_ONEVALUE twonevalue = default;
+ // twonevalue.ItemType = itemType;
+ // Marshal.StructureToPtr(twonevalue, lockedPtr, false);
+
+ // lockedPtr += Marshal.SizeOf(twonevalue);
+ // }
+
+ // WriteContainerData(lockedPtr, itemType, value, 0);
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
+ // }
+ //}
+
+ //public static void WriteArrayContainer(IMemoryManager memMgr, ref TW_CAPABILITY twCap, TValue[] values) where TValue : struct
+ //{
+ // IntPtr lockedPtr = IntPtr.Zero;
+ // try
+ // {
+ // if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
+
+ // TWTY itemType = GetItemType();
+
+ // // Allocate the container (go for worst case, which is TW_STR255)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ARRAY_MACOSX)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // // Set the meta data...
+ // TW_ARRAY_MACOSX twarraymacosx = default;
+ // twarraymacosx.ItemType = (uint)itemType;
+ // twarraymacosx.NumItems = (uint)values.Length;
+ // Marshal.StructureToPtr(twarraymacosx, lockedPtr, false);
+
+ // // Get the pointer to the ItemList...
+ // lockedPtr += Marshal.SizeOf(twarraymacosx);
+ // }
+ // else
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ARRAY)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // // Set the meta data...
+ // TW_ARRAY twarray = default;
+ // twarray.ItemType = itemType;
+ // twarray.NumItems = (uint)values.Length;
+ // Marshal.StructureToPtr(twarray, lockedPtr, false);
+
+ // // Get the pointer to the ItemList...
+ // lockedPtr += Marshal.SizeOf(twarray);
+ // }
+
+ // // Set the ItemList...
+ // for (var i = 0; i < values.Length; i++)
+ // {
+ // WriteContainerData(lockedPtr, itemType, values[i], i);
+ // }
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
+ // }
+ //}
+
+ //public static void WriteEnumContainer(IMemoryManager memMgr, ref TW_CAPABILITY twCap, Enumeration value) where TValue : struct
+ //{
+ // IntPtr lockedPtr = IntPtr.Zero;
+ // try
+ // {
+ // if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
+
+ // TWTY itemType = GetItemType();
+
+ // // Allocate the container (go for worst case, which is TW_STR255)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_MACOSX)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // // Set the meta data...
+ // TW_ENUMERATION_MACOSX twenumerationmacosx = default;
+ // twenumerationmacosx.ItemType = (uint)itemType;
+ // twenumerationmacosx.NumItems = (uint)value.Items.Length;
+ // twenumerationmacosx.CurrentIndex = (uint)value.CurrentIndex;
+ // twenumerationmacosx.DefaultIndex = (uint)value.DefaultIndex;
+ // Marshal.StructureToPtr(twenumerationmacosx, lockedPtr, false);
+
+ // // Get the pointer to the ItemList...
+ // lockedPtr += Marshal.SizeOf(twenumerationmacosx);
+ // }
+ // // Windows or the 2.4+ Linux DSM...
+ // else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
+ // (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
+ // ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // // Set the meta data...
+ // TW_ENUMERATION twenumeration = default;
+ // twenumeration.ItemType = itemType;
+ // twenumeration.NumItems = (uint)value.Items.Length;
+ // twenumeration.CurrentIndex = (uint)value.CurrentIndex;
+ // twenumeration.DefaultIndex = (uint)value.CurrentIndex;
+ // Marshal.StructureToPtr(twenumeration, lockedPtr, false);
+
+ // // Get the pointer to the ItemList...
+ // lockedPtr += Marshal.SizeOf(twenumeration);
+ // }
+ // // The -2.3 Linux DSM...
+ // else
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_LINUX64)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+
+ // // Set the meta data...
+ // TW_ENUMERATION_LINUX64 twenumerationlinux64 = default;
+ // twenumerationlinux64.ItemType = itemType;
+ // twenumerationlinux64.NumItems = (ulong)value.Items.Length;
+ // twenumerationlinux64.CurrentIndex = (ulong)value.CurrentIndex;
+ // twenumerationlinux64.DefaultIndex = (ulong)value.CurrentIndex;
+ // Marshal.StructureToPtr(twenumerationlinux64, lockedPtr, false);
+
+ // // Get the pointer to the ItemList...
+ // lockedPtr += Marshal.SizeOf(twenumerationlinux64);
+ // }
+
+ // // Set the ItemList...
+ // for (var i = 0; i < value.Items.Length; i++)
+ // {
+ // WriteContainerData(lockedPtr, itemType, value.Items[i], i);
+ // }
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
+ // }
+ //}
+
+ //public static void WriteRangeContainer(IMemoryManager memMgr, ref TW_CAPABILITY twCap, Range value) where TValue : struct
+ //{
+ // IntPtr lockedPtr = IntPtr.Zero;
+ // try
+ // {
+ // if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
+
+ // TWTY itemType = GetItemType();
+
+ // // Allocate the container (go for worst case, which is TW_STR255)...
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_RANGE_MACOSX))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+ // }
+ // // Windows or the 2.4+ Linux DSM...
+ // else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
+ // (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
+ // ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_RANGE))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+ // }
+ // // The -2.3 Linux DSM...
+ // else
+ // {
+ // // Allocate...
+ // twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_RANGE_LINUX64))));
+ // lockedPtr = memMgr.Lock(twCap.hContainer);
+ // }
+
+ // // Set the Item...
+ // WriteRangeValues(twain, lockedPtr, itemType, value);
+ // }
+ // finally
+ // {
+ // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
+ // }
+ //}
+
+ //static void WriteRangeValues(IMemoryManager memMgr, IntPtr lockedPtr, TWTY itemType, Range value) where TValue : struct
+ //{
+ // // TODO: reduce this later
+
+ // TW_RANGE twrange = default;
+ // TW_RANGE_MACOSX twrangemacosx = default;
+ // TW_RANGE_LINUX64 twrangelinux64 = default;
+
+ // switch (itemType)
+ // {
+ // default:
+ // throw new NotSupportedException($"{itemType} is not supported for range.");
+ // case TWTY.INT8:
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twrangemacosx.ItemType = (uint)itemType;
+ // twrangemacosx.MinValue = (uint)Convert.ToSByte(value.MinValue);
+ // twrangemacosx.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
+ // twrangemacosx.StepSize = (uint)Convert.ToSByte(value.StepSize);
+ // twrangemacosx.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
+ // twrangemacosx.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
+ // }
+ // else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
+ // {
+ // twrange.ItemType = itemType;
+ // twrange.MinValue = (uint)Convert.ToSByte(value.MinValue);
+ // twrange.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
+ // twrange.StepSize = (uint)Convert.ToSByte(value.StepSize);
+ // twrange.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
+ // twrange.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
+ // Marshal.StructureToPtr(twrange, lockedPtr, false);
+ // }
+ // else
+ // {
+ // twrangelinux64.ItemType = itemType;
+ // twrangelinux64.MinValue = (uint)Convert.ToSByte(value.MinValue);
+ // twrangelinux64.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
+ // twrangelinux64.StepSize = (uint)Convert.ToSByte(value.StepSize);
+ // twrangelinux64.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
+ // twrangelinux64.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
+ // }
+ // break;
+ // case TWTY.UINT8:
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twrangemacosx.ItemType = (uint)itemType;
+ // twrangemacosx.MinValue = Convert.ToByte(value.MinValue);
+ // twrangemacosx.MaxValue = Convert.ToByte(value.MaxValue);
+ // twrangemacosx.StepSize = Convert.ToByte(value.StepSize);
+ // twrangemacosx.DefaultValue = Convert.ToByte(value.DefaultValue);
+ // twrangemacosx.CurrentValue = Convert.ToByte(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
+ // }
+ // else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
+ // {
+ // twrange.ItemType = itemType;
+ // twrange.MinValue = Convert.ToByte(value.MinValue);
+ // twrange.MaxValue = Convert.ToByte(value.MaxValue);
+ // twrange.StepSize = Convert.ToByte(value.StepSize);
+ // twrange.DefaultValue = Convert.ToByte(value.DefaultValue);
+ // twrange.CurrentValue = Convert.ToByte(value.CurrentValue);
+ // Marshal.StructureToPtr(twrange, lockedPtr, false);
+ // }
+ // else
+ // {
+ // twrangelinux64.ItemType = itemType;
+ // twrangelinux64.MinValue = Convert.ToByte(value.MinValue);
+ // twrangelinux64.MaxValue = Convert.ToByte(value.MaxValue);
+ // twrangelinux64.StepSize = Convert.ToByte(value.StepSize);
+ // twrangelinux64.DefaultValue = Convert.ToByte(value.DefaultValue);
+ // twrangelinux64.CurrentValue = Convert.ToByte(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
+ // }
+ // break;
+ // case TWTY.INT16:
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twrangemacosx.ItemType = (uint)itemType;
+ // twrangemacosx.MinValue = (uint)Convert.ToInt16(value.MinValue);
+ // twrangemacosx.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
+ // twrangemacosx.StepSize = (uint)Convert.ToInt16(value.StepSize);
+ // twrangemacosx.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
+ // twrangemacosx.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
+ // }
+ // else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
+ // {
+ // twrange.ItemType = itemType;
+ // twrange.MinValue = (uint)Convert.ToInt16(value.MinValue);
+ // twrange.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
+ // twrange.StepSize = (uint)Convert.ToInt16(value.StepSize);
+ // twrange.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
+ // twrange.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
+ // Marshal.StructureToPtr(twrange, lockedPtr, false);
+ // }
+ // else
+ // {
+ // twrangelinux64.ItemType = itemType;
+ // twrangelinux64.MinValue = (uint)Convert.ToInt16(value.MinValue);
+ // twrangelinux64.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
+ // twrangelinux64.StepSize = (uint)Convert.ToInt16(value.StepSize);
+ // twrangelinux64.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
+ // twrangelinux64.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
+ // }
+ // break;
+ // case TWTY.BOOL:
+ // case TWTY.UINT16:
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twrangemacosx.ItemType = (uint)itemType;
+ // twrangemacosx.MinValue = Convert.ToUInt16(value.MinValue);
+ // twrangemacosx.MaxValue = Convert.ToUInt16(value.MaxValue);
+ // twrangemacosx.StepSize = Convert.ToUInt16(value.StepSize);
+ // twrangemacosx.DefaultValue = Convert.ToUInt16(value.DefaultValue);
+ // twrangemacosx.CurrentValue = Convert.ToUInt16(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
+ // }
+ // else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
+ // {
+ // twrange.ItemType = itemType;
+ // twrange.MinValue = Convert.ToUInt16(value.MinValue);
+ // twrange.MaxValue = Convert.ToUInt16(value.MaxValue);
+ // twrange.StepSize = Convert.ToUInt16(value.StepSize);
+ // twrange.DefaultValue = Convert.ToUInt16(value.DefaultValue);
+ // twrange.CurrentValue = Convert.ToUInt16(value.CurrentValue);
+ // Marshal.StructureToPtr(twrange, lockedPtr, false);
+ // }
+ // else
+ // {
+ // twrangelinux64.ItemType = itemType;
+ // twrangelinux64.MinValue = Convert.ToUInt16(value.MinValue);
+ // twrangelinux64.MaxValue = Convert.ToUInt16(value.MaxValue);
+ // twrangelinux64.StepSize = Convert.ToUInt16(value.StepSize);
+ // twrangelinux64.DefaultValue = Convert.ToUInt16(value.DefaultValue);
+ // twrangelinux64.CurrentValue = Convert.ToUInt16(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
+ // }
+ // break;
+ // case TWTY.INT32:
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twrangemacosx.ItemType = (uint)itemType;
+ // twrangemacosx.MinValue = (uint)Convert.ToInt32(value.MinValue);
+ // twrangemacosx.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
+ // twrangemacosx.StepSize = (uint)Convert.ToInt32(value.StepSize);
+ // twrangemacosx.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
+ // twrangemacosx.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
+ // }
+ // else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
+ // {
+ // twrange.ItemType = itemType;
+ // twrange.MinValue = (uint)Convert.ToInt32(value.MinValue);
+ // twrange.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
+ // twrange.StepSize = (uint)Convert.ToInt32(value.StepSize);
+ // twrange.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
+ // twrange.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
+ // Marshal.StructureToPtr(twrange, lockedPtr, false);
+ // }
+ // else
+ // {
+ // twrangelinux64.ItemType = itemType;
+ // twrangelinux64.MinValue = (uint)Convert.ToInt32(value.MinValue);
+ // twrangelinux64.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
+ // twrangelinux64.StepSize = (uint)Convert.ToInt32(value.StepSize);
+ // twrangelinux64.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
+ // twrangelinux64.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
+ // }
+ // break;
+ // case TWTY.UINT32:
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // twrangemacosx.ItemType = (uint)itemType;
+ // twrangemacosx.MinValue = Convert.ToUInt32(value.MinValue);
+ // twrangemacosx.MaxValue = Convert.ToUInt32(value.MaxValue);
+ // twrangemacosx.StepSize = Convert.ToUInt32(value.StepSize);
+ // twrangemacosx.DefaultValue = Convert.ToUInt32(value.DefaultValue);
+ // twrangemacosx.CurrentValue = Convert.ToUInt32(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
+ // }
+ // else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
+ // {
+ // twrange.ItemType = itemType;
+ // twrange.MinValue = Convert.ToUInt32(value.MinValue);
+ // twrange.MaxValue = Convert.ToUInt32(value.MaxValue);
+ // twrange.StepSize = Convert.ToUInt32(value.StepSize);
+ // twrange.DefaultValue = Convert.ToUInt32(value.DefaultValue);
+ // twrange.CurrentValue = Convert.ToUInt32(value.CurrentValue);
+ // Marshal.StructureToPtr(twrange, lockedPtr, false);
+ // }
+ // else
+ // {
+ // twrangelinux64.ItemType = itemType;
+ // twrangelinux64.MinValue = Convert.ToUInt32(value.MinValue);
+ // twrangelinux64.MaxValue = Convert.ToUInt32(value.MaxValue);
+ // twrangelinux64.StepSize = Convert.ToUInt32(value.StepSize);
+ // twrangelinux64.DefaultValue = Convert.ToUInt32(value.DefaultValue);
+ // twrangelinux64.CurrentValue = Convert.ToUInt32(value.CurrentValue);
+ // Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
+ // }
+ // break;
+ // case TWTY.FIX32:
+ // double min = Convert.ToDouble(value.MinValue);
+ // double max = Convert.ToDouble(value.MaxValue);
+ // double step = Convert.ToDouble(value.StepSize);
+ // double def = Convert.ToDouble(value.DefaultValue);
+ // double current = Convert.ToDouble(value.CurrentValue);
+ // if (TwainPlatform.IsMacOSX)
+ // {
+ // TW_RANGE_FIX32_MACOSX twrangefix32macosx = default;
+ // twrangefix32macosx.ItemType = (uint)itemType;
+ // twrangefix32macosx.MinValue = new TW_FIX32(min);
+ // twrangefix32macosx.MaxValue = new TW_FIX32(max);
+ // twrangefix32macosx.StepSize = new TW_FIX32(step);
+ // twrangefix32macosx.DefaultValue = new TW_FIX32(def);
+ // twrangefix32macosx.CurrentValue = new TW_FIX32(current);
+ // Marshal.StructureToPtr(twrangefix32macosx, lockedPtr, false);
+ // }
+ // else
+ // {
+ // TW_RANGE_FIX32 twrangefix32 = default;
+ // twrangefix32.ItemType = itemType;
+ // twrangefix32.MinValue = new TW_FIX32(min);
+ // twrangefix32.MaxValue = new TW_FIX32(max);
+ // twrangefix32.StepSize = new TW_FIX32(step);
+ // twrangefix32.DefaultValue = new TW_FIX32(def);
+ // twrangefix32.CurrentValue = new TW_FIX32(current);
+ // Marshal.StructureToPtr(twrangefix32, lockedPtr, false);
+ // }
+ // break;
+ // }
+ //}
+
+ //static TWTY GetItemType() where TValue : struct
+ //{
+ // var type = typeof(TValue);
+ // if (type == typeof(BoolType)) return TWTY.BOOL;
+ // if (type == typeof(TW_FIX32)) return TWTY.FIX32;
+ // if (type == typeof(TW_STR32)) return TWTY.STR32;
+ // if (type == typeof(TW_STR64)) return TWTY.STR64;
+ // if (type == typeof(TW_STR128)) return TWTY.STR128;
+ // if (type == typeof(TW_STR255)) return TWTY.STR255;
+ // if (type == typeof(TW_FRAME)) return TWTY.FRAME;
+
+ // if (type.IsEnum)
+ // {
+ // type = type.GetEnumUnderlyingType();
+ // }
+
+ // if (type == typeof(ushort)) return TWTY.UINT16;
+ // if (type == typeof(short)) return TWTY.INT16;
+ // if (type == typeof(uint)) return TWTY.UINT32;
+ // if (type == typeof(int)) return TWTY.INT32;
+ // if (type == typeof(byte)) return TWTY.UINT8;
+ // if (type == typeof(sbyte)) return TWTY.INT8;
+
+ // throw new NotSupportedException($"{type.Name} is not supported for writing.");
+ //}
+
+ /////
+ ///// Writes single piece of value to the container pointer.
+ /////
+ /////
+ ///// A locked pointer to the container's data pointer. If data is array this is the 0th item.
+ ///// The twain type.
+ /////
+ ///// Index of the item if pointer is array.
+ //static void WriteContainerData(IntPtr intptr, TWTY type, TValue value, int itemIndex) where TValue : struct
+ //{
+ // switch (type)
+ // {
+ // default:
+ // throw new NotSupportedException($"Unsupported item type {type} for writing.");
+ // // TODO: for small types needs to fill whole int32 before writing?
+ // case TWTY.INT8:
+ // intptr += 1 * itemIndex;
+ // //int intval = Convert.ToSByte(value);
+ // //Marshal.StructureToPtr(intval, intptr, false);
+ // Marshal.StructureToPtr(Convert.ToSByte(value), intptr, false);
+ // break;
+ // case TWTY.UINT8:
+ // intptr += 1 * itemIndex;
+ // //uint uintval = Convert.ToByte(value);
+ // //Marshal.StructureToPtr(uintval, intptr, false);
+ // Marshal.StructureToPtr(Convert.ToByte(value), intptr, false);
+ // break;
+ // case TWTY.INT16:
+ // intptr += 2 * itemIndex;
+ // //intval = Convert.ToInt16(value);
+ // //Marshal.StructureToPtr(intval, intptr, false);
+ // Marshal.StructureToPtr(Convert.ToInt16(value), intptr, false);
+ // break;
+ // case TWTY.BOOL:
+ // case TWTY.UINT16:
+ // intptr += 2 * itemIndex;
+ // //uintval = Convert.ToUInt16(value);
+ // //Marshal.StructureToPtr(uintval, intptr, false);
+ // Marshal.StructureToPtr(Convert.ToUInt16(value), intptr, false);
+ // break;
+ // case TWTY.INT32:
+ // intptr += 4 * itemIndex;
+ // Marshal.StructureToPtr(Convert.ToInt32(value), intptr, false);
+ // break;
+ // case TWTY.UINT32:
+ // intptr += 4 * itemIndex;
+ // Marshal.StructureToPtr(Convert.ToUInt32(value), intptr, false);
+ // break;
+ // case TWTY.FIX32:
+ // intptr += 4 * itemIndex;
+ // Marshal.StructureToPtr(value, intptr, false);
+ // break;
+ // case TWTY.FRAME:
+ // intptr += 16 * itemIndex;
+ // Marshal.StructureToPtr(value, intptr, false);
+ // break;
+ // case TWTY.STR32:
+ // intptr += TW_STR32.Size * itemIndex;
+ // Marshal.StructureToPtr(value, intptr, false);
+ // break;
+ // case TWTY.STR64:
+ // intptr += TW_STR64.Size * itemIndex;
+ // Marshal.StructureToPtr(value, intptr, false);
+ // break;
+ // case TWTY.STR128:
+ // intptr += TW_STR128.Size * itemIndex;
+ // Marshal.StructureToPtr(value, intptr, false);
+ // break;
+ // case TWTY.STR255:
+ // intptr += TW_STR255.Size * itemIndex;
+ // Marshal.StructureToPtr(value, intptr, false);
+ // break;
+ // }
+ //}
+ }
+}