Timotej Leginus
Timotej Leginus

Reputation: 294

Can't copy a fixed-size byte array from a struct to another array in a struct in C#

Using the NetworkInfo2SecurityParameter function I am trying to copy the fixed-size buffer unkRandom from from LdnNetworkInfo struct held in NetworkInfo struct to the SecurityParameter struct's buffer.

Basically I am making a method to convert these two types, and I want to copy these two arrays to another. This code features all structs relevant.

The error is happening at the Buffer.MemoryCopy() function. The error is "You cannot use fixed size buffers contained in unfixed expressions. Try using the 'fixed' statement"

unsafe void NetworkInfo2SecurityParameter(NetworkInfo info, out SecurityParameter output)
{
    output = new SecurityParameter();
    output.sessionId = info.networkId.sessionId;
    Buffer.MemoryCopy(output.unkRandom, info.ldn.unkRandom, 16, 16);
}

struct SecurityParameter {
    public unsafe fixed byte unkRandom[16];// = new byte[16];
    public SessionId sessionId;
};

struct NetworkInfo : /sf::/LargeData {
    public NetworkId networkId;
    public CommonNetworkInfo common;
    public LdnNetworkInfo ldn;
};

struct LdnNetworkInfo {
    public unsafe fixed byte unkRandom[16];// = new byte[16];
    public ushort securityMode;
    public byte stationAcceptPolicy;
    public unsafe fixed byte _unk1[3];// = new byte[3];
    public byte nodeCountMax;
    public byte nodeCount;
    //TODO non primitive array,,
    private unsafe fixed byte _nodes[sizeof(NodeInfo)*NodeCountMax]; //Needs to be fixed array, and needs to be casted to NodeInfo span, so thats why its size is this
    public unsafe fixed Span<NodeInfo> nodes => MemoryMarshal.Cast<byte, NodeInfo>(MemoryMarshal.CreateSpan(ref _nodes[0], 128));
    public ushort _unk2;
    public ushort advertiseDataSize;
    public unsafe fixed byte advertiseData[AdvertiseDataSizeMax];// = new byte[AdvertiseDataSizeMax];
    public unsafe fixed byte _unk3[148];// = new byte[148];
};

Upvotes: 1

Views: 696

Answers (2)

Engineer
Engineer

Reputation: 8847

struct is assignable, like any primitive. Undoubtedly faster than Buffer.MemoryCopy() would be:

public unsafe struct FixedSizeBufferWrapper
{
    public unsafe fixed byte unkRandom[16];
}

unsafe 
{
    fixed (byte* firstStruct = somewhere.securityParameter, otherStruct = somewhereElse.ldnNetworkInfo )
    {
        //one assignment blits all contents
        *((FixedSizeBufferWrapper*)firstStruct.unkRandom) =
        *((FixedSizeBufferWrapper*)otherStruct.unkRandom);
    }
}

We cast buffers in each of your original structs to the wrapper pointer type and dereference each pointer SO THAT we can assign one to the other; assigning fixed buffers directly is not possible.

We have to cast outside the fixed statement because (at least in my version of C#) we aren't allowed to cast inside fixed(...) and we cannot assign anything other than a primitive type (usually byte[]) as the buffer type. The wrapper struct exists purely for this casting / assignment.

Upvotes: 1

Timotej Leginus
Timotej Leginus

Reputation: 294

Fixed it with this approach: I created a new variable called ret, which I did copy the data to, and then I assigned ret to output.

unsafe void NetworkInfo2SecurityParameter(NetworkInfo info, out SecurityParameter output)
        {
            var ret = new SecurityParameter();
            output.sessionId = info.networkId.sessionId;
            Buffer.MemoryCopy(ret.unkRandom, info.ldn.unkRandom, 16, 16);
            output = ret;
        }

Upvotes: 0

Related Questions