pfinferno
pfinferno

Reputation: 1945

Converting Delphi pointer and stream.Read to c#

I'm trying to convert an old Delphi app into C#. It does some stuff with binary files written via packed records which I've put below. However, only the BInfoRec record is guaranteed to be in the file and appearing first. The others may or may not be in there, and the order of them is unknown. I'm having trouble with one method in particular. It's getting the number of bytes being read in via FileStream.Read and reading those into one of the packed records. Then, in the first if statement (in the delphi version), it is allocating memory on the heap, and doing the same thing as before, but reading it into a pointer. I'm trying to figure out the best way to go about this but I'm by no means an expert with Delphi.

Delphi code:

StartP = packed record
    x:SmallInt;
    y:SmallInt;
end;

InfoP = packed record
 Ycoord:double;       
 Xcoord:double;              
 //other vars here
end;

HeadP = packed record
    NumP:DWORD;
    SizeStruct:DWORD;
    SizePoStruct:DWORD;
    //other vars here
end;

BInfoRec = packed record
    StructNum : WORD ;
    in_size : WORD ;    
    //other variables here
end;

var
  tStream:TFileStream;
  bInfo:BInfoRec;
  RestOfBFile:Pointer;
  sizeofRest:Integer;

Function LoadBFile(FileName:String):Boolean;
var
   sizeread:Integer;
begin
  Try
     LoadBFile:=False;
     tStream:=TFileStream.Create(Filename,fmOpenRead );
     sizeofRest:=tStream.Size-Sizeof(bInfo);
     sizeread:=tStream.Read(bInfo,Sizeof(bInfo));
     if sizeread = Sizeof(bInfo) then
     begin                                         //best way to convert this?
          RestOfBFile:=AllocMem(sizeofRest);
          sizeread:=tStream.Read(RestOfBFile^,sizeofRest);
          if SizeofRest= SizeRead then
             LoadBFile:=True;
     end;
     tStream.Free;
   except
        LoadBFile:=False;
        tStream.Free;
   end;
end;

C# (what I have so far):

[Serializable()]
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct StartP
{
    public short x;
    public short y;
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct InfoP
{
    public double Ycoord;
    public double Xcoord;
    //other vars here
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct HeadP
{
    public UInt32 NumP;
    public UInt32 SizeStruct;
    public UInt32 SizePoStruct;
    //other vars here
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct BInfoRec
{
    public ushort StructNum;
    public ushort in_size;          
}

BInfoRec bInfo;
int sizeOfRest;

private Boolean LoadBFile(string fileName)
{
    int sizeRead;
    byte[] buffer = new byte[Marshal.SizeOf(bInfo)];

    try
    {
        using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
        {
            sizeOfRest = (int)stream.Length - Marshal.SizeOf(typeof(BInfoRec));
            sizeRead = stream.Read(buffer, 0, Marshal.SizeOf(typeof(BInfoRec)));
            if (sizeRead == Marshal.SizeOf(typeof(BInfoRec)))
            {
                //what goes here??

                if (sizeOfRest == sizeRead)
                {
                    return true;
                }
            }
        }
    }
    catch (Exception ex)
    {
        return false;
    }
}

I was thinking about creating a new byte array of unknown size and using a BinaryReader to read in the rest of the file to that array, then just checking the size of that. Not sure if it's the best way though?

Upvotes: 2

Views: 561

Answers (1)

David Heffernan
David Heffernan

Reputation: 612993

It's a block of memory of arbitrary size. I don't see that you have many options other than a byte array. Yes you could allocate unmanaged memory (e.g. with Marshal.AllocHGlobal) but that would hardly be convenient.

So, yes, if I were you I would allocate a byte array, and read the contents into it.

Upvotes: 1

Related Questions