C# and USBHIDDRIVER write() always return false - c#

Work with http://www.florian-leitner.de/index.php/2007/08/03/hid-usb-driver-library/
`USBHIDDRIVER.USBInterface usbI = new USBInterface("vid_0b6a", "pid_0022");
byte[] startCMD = new byte[8];
startCMD[7] = 4;
usbI.Connect();
usbI.write(startCMD);`
"cnnect" return true but "write' always return false, return in this place:
`Result = USBSharp.WriteFile(hidHandle, ref outputReportBuffer[0],
outputReportBuffer.Length, ref NumberOfBytesWritten, 0);
Success = (Result == 0) ? false : true;`

Related

Splitting ReadOnlySequence into lines then ReadOnlySequence by delimiters

I am trying to split the following chunked memory into ReadOnlySequence<char> by newline \n and then delimiters (in this example of ").
I have the partially working (by lines) code below which when I tweak I get exceptions, and currently have the incorrect output of: hello, fun, one.
I believe my issues are with my use of ReadOnlySequence.Slice() and SequencePosition, as this seems linked to the position of the starting sequence, and not the start of the sliced ReadOnlySequence (at least as I understand).
I am kindly seeking advice towards a corrected example of the below, so that we get the expected:
hello, much, fun, done.
using System;
using System.Buffers;
namespace NotMuchFunYet
{
class Program
{
static void Main(string[] args)
{
var buffer = GetExampleBuffer();
while (TryReadLine(ref buffer, out var line))
{
while (GetString(ref line, out var token))
{
Console.WriteLine(token.ToString());
}
}
}
private static ReadOnlySequence<char> GetExampleBuffer()
{
Chunk<char> startChnk;
var currentChnk = startChnk = new Chunk<char>(new ReadOnlyMemory<char>("\"hello\".\"mu".ToCharArray()));
currentChnk = currentChnk.Add(new ReadOnlyMemory<char>("ch\".".ToCharArray()));
currentChnk = currentChnk.Add(new ReadOnlyMemory<char>("\"fun\"".ToCharArray()));
currentChnk = currentChnk.Add(new ReadOnlyMemory<char>("\n\"done\"\n".ToCharArray()));
return new ReadOnlySequence<char>(startChnk, 0, currentChnk, currentChnk.Memory.Length);
}
private static bool TryReadLine(ref ReadOnlySequence<char> buffer, out ReadOnlySequence<char> line)
{
var position = buffer.PositionOf('\n'); // Look for a EOL in the buffer.
if (position == null)
{
line = default;
return false;
}
line = buffer.Slice(0, position.Value); // Skip the line + the \n.
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
return true;
}
public static bool GetString(ref ReadOnlySequence<char> line, out ReadOnlySequence<char> property)
{
var start = line.PositionOf('"');
if (start == null)
{
property = default;
return false;
}
property = line.Slice(start.Value.GetInteger() + 1);
var end = property.PositionOf('"');
if (end == null)
{
property = default;
return false;
}
property = property.Slice(0, end.Value);
line = line.Slice(line.GetPosition(1, end.Value));
return true;
}
}
class Chunk<T> : ReadOnlySequenceSegment<T>
{
public Chunk(ReadOnlyMemory<T> memory) => Memory = memory;
public Chunk<T> Add(ReadOnlyMemory<T> mem)
{
var segment = new Chunk<T>(mem) { RunningIndex = RunningIndex + Memory.Length };
Next = segment;
return segment;
}
}
}
Changing the first property fetch in GetString() method resolves this, from:
property = line.Slice(start.Value.GetInteger() + 1);
To:
property = line.Slice(line.GetPosition(1, start.Value));
Giving the code:
using System;
using System.Buffers;
namespace NowMuchFun
{
class Program
{
static void Main(string[] args)
{
var buffer = GetExampleBuffer();
while (TryReadLine(ref buffer, out var line))
{
while (GetString(ref line, out var token))
{
Console.WriteLine(token.ToString());
}
}
}
private static ReadOnlySequence<char> GetExampleBuffer()
{
Chunk<char> startChnk;
var currentChnk = startChnk = new Chunk<char>(new ReadOnlyMemory<char>("\"hello\".\"mu".ToCharArray()));
currentChnk = currentChnk.Add(new ReadOnlyMemory<char>("ch\".".ToCharArray()));
currentChnk = currentChnk.Add(new ReadOnlyMemory<char>("\"fun\"".ToCharArray()));
currentChnk = currentChnk.Add(new ReadOnlyMemory<char>("\n\"done\"\n".ToCharArray()));
return new ReadOnlySequence<char>(startChnk, 0, currentChnk, currentChnk.Memory.Length);
}
private static bool TryReadLine(ref ReadOnlySequence<char> buffer, out ReadOnlySequence<char> line)
{
var position = buffer.PositionOf('\n'); // Look for a EOL in the buffer.
if (position == null)
{
line = default;
return false;
}
line = buffer.Slice(0, position.Value); // Skip the line + the \n.
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
return true;
}
public static bool GetString(ref ReadOnlySequence<char> line, out ReadOnlySequence<char> property)
{
var start = line.PositionOf('"');
if (start == null)
{
property = default;
return false;
}
// property = line.Slice(start.Value.GetInteger() + 1);
// REPLACE WITH BELOW:
property = line.Slice(line.GetPosition(1, start.Value));
var end = property.PositionOf('"');
if (end == null)
{
property = default;
return false;
}
property = property.Slice(0, end.Value);
line = line.Slice(line.GetPosition(1, end.Value));
return true;
}
}
class Chunk<T> : ReadOnlySequenceSegment<T>
{
public Chunk(ReadOnlyMemory<T> memory) => Memory = memory;
public Chunk<T> Add(ReadOnlyMemory<T> mem)
{
var segment = new Chunk<T>(mem) { RunningIndex = RunningIndex + Memory.Length };
Next = segment;
return segment;
}
}
}

Problem with the SDK Azure for FACE API With FileStream picture

We try to use the sdk to use the cognitives services of Microsoft. We use the Interface IFaceOperatiosn which inside there's a method to send a picture by stream like:DetectWithStreamWithHttpMessagesAsync. When we try to use it, we reach a APIErrorException which the message is Bad request but don't know where is the problem so there's our code:
public async Task<List<FaceAPI.Face>> DetectFace(string picture)
{
try
{
Stream img = new FileStream(picture, FileMode.Open);
var res = await detect.DetectWithStreamWithHttpMessagesAsync(img);
List<FaceAPI.Face> result = new List<FaceAPI.Face>();
for (int i = 0; i < res.Body.Count; i++)
{
result.Add(new FaceAPI.Face { Age = (double)res.Body[i].FaceAttributes.Age, Bald = res.Body[i].FaceAttributes.Hair.Bald > 0.5 ? true : false, Beard = res.Body[i].FaceAttributes.FacialHair.Beard > 0.5 ? true : false, Gender = res.Body[i].FaceAttributes.Gender.Value.Equals(Gender.Male) ? true : false, Glasses = res.Body[i].FaceAttributes.Glasses.Value.Equals(GlassesType.NoGlasses) ? false : true, Hair = res.Body[i].FaceAttributes.Hair.HairColor.ToString(), Moustache = res.Body[i].FaceAttributes.FacialHair.Moustache > 0.5 ? true : false,Rectangle=new System.Drawing.Rectangle { X = res.Body[i].FaceRectangle.Left, Y = res.Body[i].FaceRectangle.Top, Height = res.Body[i].FaceRectangle.Height, Width = res.Body[i].FaceRectangle.Width } });
}
return result;
}
catch (APIErrorException e)
{
Debug.WriteLine(e.Message);
return null;
}
catch (SerializationException e)
{
Debug.WriteLine(e.Message);
return null;
}
catch (ValidationException e)
{
Debug.WriteLine(e.Message);
return null;
}
}
Normally it returns a list of Face.
You need to put a wich attribute you want retrieve for the detection like this:
var requiredFaceAttributes = new FaceAttributeType[] {
FaceAttributeType.Age,
FaceAttributeType.Hair,
FaceAttributeType.Gender,
FaceAttributeType.Smile,
FaceAttributeType.FacialHair,
FaceAttributeType.Glasses
};
var res = await detect.DetectWithStreamWithHttpMessagesAsync(picture,true,true,requiredFaceAttributes);

ECDSA signing in c# verify in c

I'm trying to sign data in C#, using ECDSA algorithm (this part looks OK) and to verify signature in C using Windows crypto API.
Signature part:
CngKeyCreationParameters keyCreationParameters = new CngKeyCreationParameters();
keyCreationParameters.ExportPolicy = CngExportPolicies.AllowPlaintextExport;
keyCreationParameters.KeyUsage = CngKeyUsages.Signing;
CngKey key = CngKey.Create(CngAlgorithm.ECDsaP256, null, keyCreationParameters);
ECDsaCng dsa = new ECDsaCng(key); //dsa = Digital Signature Algorithm
byte[] privateKey = dsa.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
File.WriteAllText("privatekey.txt", String.Join(",", privateKey));
byte[] publicKey = dsa.Key.Export(CngKeyBlobFormat.EccPublicBlob);
File.WriteAllText("publicKey.txt", String.Join(",", publicKey));
CngKey importedKey = CngKey.Import(File.ReadAllText("privatekey.txt").Split(',').Select(m => byte.Parse(m)).ToArray(), CngKeyBlobFormat.EccPrivateBlob);
ECDsaCng importedDSA = new ECDsaCng(importedKey); //dsa = Digital Signature Algorithm
byte[] signed = dsa.SignData(new byte[] { 1, 2, 3, 4, 5 });
File.WriteAllText("signed.txt", String.Join(",", signed));
At this point I'm able to create a signature key and export it to a byte buffer in a file.
Problems come when I'm trying to import this public key in C using windows crypto API.
BYTE KeyBlob[] = { // public key exported by above c# code
69,67,83,49,32,0,0,0,227,146,138,255,218,235,122,141,44,110,211,95,59,227,226,163,81,188,242,115,60,171,46,141,221,117,169,139,42,143,67,85,144,242,232,188,22,158,230,15,110,6,214,252,252,242,224,241,110,186,1,244,176,65,88,184,94,19,98,174,158,7,154,152
};
int _tmain()
{
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwBlobLen;
BYTE* pbKeyBlob;
if (!CryptAcquireContext(
&hProv,
NULL,
MS_ENHANCED_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
printf(" Error in AcquireContext 0x%08x \n", GetLastError());
return 1;
}
if (!CryptImportKey(
hProv,
KeyBlob,
sizeof(DesKeyBlob),
0,
CRYPT_EXPORTABLE,
&hKey))
{
printf("Error 0x%08x in importing the key \n",
GetLastError());
}
which returns
Error 0x80090007 in importing the key
which is (believing winerror.h) :
//
// MessageId: NTE_BAD_VER
//
// MessageText:
//
// Bad Version of provider.
//
#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L)
What do I do wrong?
Thanks to this wonderful website I just found : referencesouce.microsoft.com, I've been able to disassemble what the C# API does when verifying a signature and importing a key.
Apparently I need ncrypt/bcrypt, and signature is verified against a hash, and not the data itself:
public bool VerifyData(Stream data, byte[] signature) {
if (data == null) {
throw new ArgumentNullException("data");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
using (BCryptHashAlgorithm hashAlgorithm = new BCryptHashAlgorithm(HashAlgorithm, BCryptNative.ProviderName.MicrosoftPrimitiveProvider)) {
hashAlgorithm.HashStream(data);
byte[] hashValue = hashAlgorithm.HashFinal();
return VerifyHash(hashValue, signature);
}
}
[SecuritySafeCritical]
public override bool VerifyHash(byte[] hash, byte[] signature) {
if (hash == null) {
throw new ArgumentNullException("hash");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
// We need to get the raw key handle to verify the signature. Asserting here is safe since verifiation
// is not a protected operation, and we do not expose the handle to the user code.
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
// This looks odd, but Key.Handle is really a duplicate so we need to dispose it
using (SafeNCryptKeyHandle keyHandle = Key.Handle) {
CodeAccessPermission.RevertAssert();
return NCryptNative.VerifySignature(keyHandle, hash, signature);
}
}
Here is a native solution, for whoever needs that:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
char key[72] = { 69,67,83,49,32,0,0,0,227,146,138,255,218,235,122,141,44,110,211,95,59,227,226,163,81,188,242,115,60,171,46,141,221,117,169,139,42,143,67,85,144,242,232,188,22,158,230,15,110,6,214,252,252,242,224,241,110,186,1,244,176,65,88,184,94,19,98,174,158,7,154,152 };
char sign[64] = { 165,50,54,149,14,175,128,54,21,30,129,165,137,203,45,123,180,121,118,20,15,61,253,186,65,129,21,26,54,84,40,205,103,254,108,34,126,205,116,183,44,189,5,180,28,119,228,70,127,116,227,248,232,144,53,226,185,251,217,179,148,88,208,152 };
char message[] = { 1, 2, 3, 4, 5 };
BOOL crypt_init(char* key, unsigned long key_len)
{
HCRYPTPROV hProv = NULL;
BCRYPT_ALG_HANDLE hHashAlg = NULL, hSignAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
PBYTE pbHash = NULL;
PBYTE pbHashObject = NULL;
DWORD cbHashObject = 0,
cbHash = 0,
cbData = 0;
NTSTATUS status;
if (ERROR_SUCCESS != NCryptOpenStorageProvider(&hProv, NULL, 0)) {
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return FALSE;
}
NCRYPT_KEY_HANDLE keyHandle;
if (ERROR_SUCCESS != NCryptImportKey(hProv, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, &keyHandle, (PBYTE)key, 72, 0)) {
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hHashAlg,
BCRYPT_SHA256_ALGORITHM,
NULL,
0)))
{
printf("BCryptOpenAlgorithmProvider failed - err=0x%x.\n", status);
return false;
}
if(!BCRYPT_SUCCESS(status = BCryptGetProperty(hHashAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0))) {
printf("BCryptGetProperty failed - err=0x%x.\n", status);
return FALSE;
}
pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
if (NULL == pbHashObject) {
printf("memory allocation failed\n");
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hHashAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0))) {
printf("BCryptGetProperty failed - err=0x%x.\n", status);
return FALSE;
}
pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
if (NULL == pbHash)
{
printf("memory allocation failed\n");
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptCreateHash(hHashAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0)))
{
printf("BCryptCreateHash failed - err=0x%x.\n", status);
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptHashData(hHash, (PBYTE)message, sizeof(message), 0)))
{
printf("BCryptHashData failed - err=0x%x.\n", status);
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptFinishHash(hHash, pbHash, cbHash, 0)))
{
printf("BCryptFinishHash failed - err=0x%x.\n", status);
return FALSE;
}
if(ERROR_SUCCESS != NCryptVerifySignature(keyHandle, NULL, pbHash, cbHash, (PBYTE) sign, sizeof(sign), 0)) {
printf("BCryptVerifySignature failed - err=0x%x.\n", status);
return FALSE;
}
return TRUE;
}
int main() {
crypt_init(key, 72);
}

Comparing a single array against multiple different arays

For a small project on processor affinity, I want to create a simpler method than just a bunch of if(lvProcessors.Items[0].Checked == true && lvProcessors.Items[1] == true etc) comparing their exact values to see which code needs to be transferred to an (IntPtr).
To make the code slightly more efficiƫnt, I would like to compare an array containing booleans, to at least 14 other arrays containing booleans.
Example code:
var CheckState = new[] { lvProcessors.Items[0].Checked, lvProcessors.Items[1].Checked, lvProcessors.Items[2].Checked, lvProcessors.Items[3].Checked };
//setcore1 == 1, setcore2 == 2, etc
var SetCore1 = new[] { true, false,false,false };
var SetCore2 = new[] { true, true, false, false };
var SetCore3 = new[] { false, true, false, false };
var SetCore4 = new[] { true, false, true, false };
var SetCore5 = new[] { false, true, true, false };
var SetCore6 = new[] { true, true, true, false };
var SetCore7 = new[] { false, false, false, true };
var SetCore8 = new[] { true, false, false, true };
var SetCore9 = new[] { false, true, false, true };
var SetCore10 = new[] { true, true, false, true };
var SetCore11 = new[] { false, false, true, true };
var SetCore12 = new[] { true, false, true, true };
var SetCore13 = new[] { false, true, true, true };
var SetCore14 = new[] { true, true, true, true };
int switchcounter = 1;
switch (switchcounter)
{
case 15:
break;
default:
if (Enumerable.SequenceEqual(CheckState,<insertdynamicarrayname))
{
AffinityState = (IntPtr)switchcounter;
}
else
{
switchcounter++;
goto default;
}
break;
}
So if the first checkbox in the listview lvProcessors is checked, the var CheckState will generate an array containing { true, false,false,false }
This in turn must be compared to one of the SetCore arrays, and will in this case cause a match with SetCore1.
So what I would like to know is; how can I create a dynamic arrayname, based on the switchcounter on the code, that will fuse "SetCore" and switchcounter.ToString(), thus creating SetCore1, SetCore2, SetCore3, etc.
[EDIT]
As suggested by #Luaan, I've implemented his code to what I would've like it to be:
var SetCore1 = new[] { true, false, false, false};
[..]
var SetCore15 = new[] { true, true, true, true };
var allSets = new [] { SetCore1, SetCore2, SetCore3,SetCore4,SetCore5,SetCore6,SetCore7,SetCore8,SetCore9,SetCore10,SetCore11,SetCore12,SetCore13,SetCore14,SetCore15 };
foreach (var set in allSets)
{
MessageBox.Show(counter.ToString());
if (Enumerable.SequenceEqual(set, CheckState))
{
AffinityState = (IntPtr)counter;
break;
}
else if (Enumerable.SequenceEqual(set, CheckState) == false)
{
counter++;
}
}
EditProcess.ProcessorAffinity = (IntPtr)AffinityState;
In this code, depending on the input of the listviewcheckboxes, it will match the depending result to a SetCore and using the counter it will give the proper int which is converted at the end of the foreach loop and set the very specific cores(i.e. 1, 2 or 0, 2, 3, etc) to be used for the selected process which has been selected earlier in the code(not visible).
Thanks for the suggestion on bitmasks, they look useful, but currently I have no idea how to implement them without taking half my application apart.
Just make an array of arrays:
var allSets = new [][] { SetCore1, SetCore2, SetCore3, ... }
Then you can use a simple for cycle:
for (var i = 0; i < allSets.Length; i++)
HandleSet(allSets[i]);
Using Enumerable.SequenceEqual is going to be a bit slow. If you care about performance (I don't think you necessarily do in a case like this), have a look at BitArray - it's much smaller in memory, and the match is mostly a simple bitmasking.
EDIT:
If you want to convert between a bool[] and int (or byte, whatever you need), you can use something like this:
public bool[] ToBoolArray(int val)
{
var bits = new bool[sizeof(int) * 8];
for (var i = 0; i < bits.Length; i++)
{
bits[i] = (val & (1 << i)) > 0;
}
return bits;
}
public int ToInt32(bool[] bits)
{
var output = default(int);
for (var i = 0; i < bits.Length; i++)
{
output |= bits[i] ? 1 << i : 0;
}
return output;
}
This avoids having to deal with tons of annoying strings. Using a BitArray this is even simpler - creating a BitArray from int is trivial (there's a constructor), and changing it back to int can be done easily as above, just use bits.Get(i) instead of bits[i].
Or even better, make your own class for handling this:
public sealed class CpuMask
{
private int _bits;
public bool this[int index]
{
get { return (_bits & (1 << index)) > 0; }
set { if (value) _bits |= (1 << index); else _bits &= ~(1 << index); }
}
public CpuMask(int mask)
{
_bits = mask;
}
public CpuMask(IntPtr mask) : this(mask.ToInt32()) { }
public IntPtr ToIntPtr() { return new IntPtr(_bits); }
}

Reading string array from a HDF5 dataset

I am trying to read a string dataset from a HDF5 file in C# into a array of strings. I was able to read into the dataset using the following code:
//read the no of rows and columns
var datasetID = H5D.open(fileId,"dimensions");
var dataTypeId = H5D.getType(datasetID);
var dataType = H5T.getClass(dataTypeId);
var length = H5T.getSize(dataTypeId);
int[] dDim = new int[length];
H5D.read(datasetID, dataTypeId, new H5Array<int>(dDim));
I tried to do the same for string dataset but I get all the values initialized to null. So I referred this link (https://www.mail-archive.com/hdf-forum#hdfgroup.org/msg02980.html). I was able to read them as bytes, but I don't know the size the byte array should be initialized to. The code i have right now to read string is this:
//read string
datasetID = H5D.open(fileId, "names");
var dataSpaceId = H5D.getSpace(datasetID);
long[] dims = H5S.getSimpleExtentDims(dataSpaceId);
dataTypeId = H5T.copy(H5T.H5Type.C_S1);
//hard coding the no of string to read (213)
byte[] buffer = new byte[dims[0]*213];
Console.WriteLine(dims[0]);
H5D.read(datasetID, dataTypeId, new H5Array<byte>(buffer));
Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(buffer)); `.
If you do not know in advance what your data type will be, try the following code. It is incomplete for data types but it is easily modifiable:
public static Array Read1DArray(this H5FileId fileId, string dataSetName)
{
var dataset = H5D.open(fileId, dataSetName);
var space = H5D.getSpace(dataset);
var dims = H5S.getSimpleExtentDims(space);
var dtype = H5D.getType(dataset);
var size = H5T.getSize(dtype);
var classID = H5T.getClass(dtype);
var rank = H5S.getSimpleExtentNDims(space);
var status = H5S.getSimpleExtentDims(space);
// Read data into byte array
var dataArray = new Byte[status[0]*size];
var wrapArray = new H5Array<Byte>(dataArray);
H5D.read(dataset, dtype, wrapArray);
// Convert types
Array returnArray = null;
Type dataType = null;
switch (classID)
{
case H5T.H5TClass.STRING:
dataType = typeof(string);
break;
case H5T.H5TClass.FLOAT:
if (size == 4)
dataType = typeof(float);
else if (size == 8)
dataType = typeof(double);
break;
case H5T.H5TClass.INTEGER:
if (size == 2)
dataType = typeof(Int16);
else if (size == 4)
dataType = typeof(Int32);
else if (size == 8)
dataType = typeof(Int64);
break;
}
if (dataType == typeof (string))
{
var cSet = H5T.get_cset(dtype);
string[] stringArray = new String[status[0]];
for (int i = 0; i < status[0]; i++)
{
byte[] buffer = new byte[size];
Array.Copy(dataArray, i*size, buffer, 0, size);
Encoding enc = null;
switch (cSet)
{
case H5T.CharSet.ASCII:
enc = new ASCIIEncoding();
break;
case H5T.CharSet.UTF8:
enc = new UTF8Encoding();
break;
case H5T.CharSet.ERROR:
break;
}
stringArray[i] = enc.GetString(buffer).TrimEnd('\0');
}
returnArray = stringArray;
}
else
{
returnArray = Array.CreateInstance(dataType, status[0]);
Buffer.BlockCopy(dataArray, 0, returnArray, 0, (int) status[0]*size);
}
H5S.close(space);
H5T.close(dtype);
H5D.close(dataset);
return returnArray;
}
your start was exceptionally helpful! With it and some help from HDF5 Example code, I was able to come up with some generic extensions, that would reduce your code to:
//read string
string[] datasetValue = fileId.Read1DArray<string>("names");
The extensions look something like this (which is, or should be, exactly the same as from the referenced question.):
public static class HdfExtensions
{
// thank you https://stackoverflow.com/questions/4133377/splitting-a-string-number-every-nth-character-number
public static IEnumerable<String> SplitInParts(this String s, Int32 partLength)
{
if (s == null)
throw new ArgumentNullException("s");
if (partLength <= 0)
throw new ArgumentException("Part length has to be positive.", "partLength");
for (var i = 0; i < s.Length; i += partLength)
yield return s.Substring(i, Math.Min(partLength, s.Length - i));
}
public static T[] Read1DArray<T>(this H5FileId fileId, string dataSetName)
{
var dataset = H5D.open(fileId, dataSetName);
var space = H5D.getSpace(dataset);
var dims = H5S.getSimpleExtentDims(space);
var dataType = H5D.getType(dataset);
if (typeof(T) == typeof(string))
{
int stringLength = H5T.getSize(dataType);
byte[] buffer = new byte[dims[0] * stringLength];
H5D.read(dataset, dataType, new H5Array<byte>(buffer));
string stuff = System.Text.ASCIIEncoding.ASCII.GetString(buffer);
return stuff.SplitInParts(stringLength).Select(ss => (T)(object)ss).ToArray();
}
T[] dataArray = new T[dims[0]];
var wrapArray = new H5Array<T>(dataArray);
H5D.read(dataset, dataType, wrapArray);
return dataArray;
}
public static T[,] Read2DArray<T>(this H5FileId fileId, string dataSetName)
{
var dataset = H5D.open(fileId, dataSetName);
var space = H5D.getSpace(dataset);
var dims = H5S.getSimpleExtentDims(space);
var dataType = H5D.getType(dataset);
if (typeof(T) == typeof(string))
{
// this will also need a string hack...
}
T[,] dataArray = new T[dims[0], dims[1]];
var wrapArray = new H5Array<T>(dataArray);
H5D.read(dataset, dataType, wrapArray);
return dataArray;
}
}

Categories