1

I'm converting a delphi program to c# and I have to read data from a binary file into a struct. A way to do this was answered in a previous question I asked here: Proper struct layout from delphi packed record .

That works great, however, when trying to replicate this with another struct I have, all the data is 0, even though there is in fact data in the file. The file is set-up and was written in terms of these structs (or packed records in the delphi version), and this specific code is supposed to iterate to the last 'struct' in the file, and read it in. I'm going to list both the delphi and c# code.

Delphi:

CONST
   RecordSize=128;
   HeaderSize=128;

Testrec = packed record
     now: TDateTime;
     ShLat: longint;
     ShLong: longint;
     ShLatUn: short;
     ShLonUn: short;
     ShSens1: short;
     ShSens2: short;
     ShAlt: single;
     ShFirst: single;
     ShDepth: single;
     ShSpeed: single;
     ShHead: single;
     ShCourse: single;
     ShRoll: single;
     ShPitch: single;
     ShVOS: single;
     FiLat: longint;
     FiLong: longint;
     FiLatUn: short;
     FiLonUn: short;
     FiSens1: short;
     FiSens2: short;
     FiAlt: single;
     FiFirst: single;
     FiDepth: single;
     FiSpeed: single;
     FiHead: single;
     FiCourse: single;
     FiRoll: single;
     FiPitch: single;
     FiVOS: single;
     DataFlags: longint;
     RevFlags: longint;
     Contact: longint;
     Range1: short;
     Range2: short;
     end;

var
  RampStream:TFileStream;

Function GetLastTime:TDateTime;
var
  RRampRec:TestRec;
  LastPosition:TDateTime;
  HoldPosition:Int64;
begin
  LastPosition:=0;
  HoldPosition:= RampStream.Position;
  RampStream.Position:=128;
  While RampStream.Position < RampStream.Size do
  begin
    RampStream.Read(RRampRec,RecordSize);
    if (RRampRec.ShLat = 0) AND (RRampRec.ShLon = 0)  AND
    (RRampRec.FiLat = 0) AND (RRampRec.FiLon = 0)  then  continue;
    LastPosition:= RRampRec.Now;
  end;
  RampStream.Position:=HoldPosition;
  GetLastTime:=Lastposition;  
end;

C#:

const int RecordSize = 128;
const int HeaderSize = 128;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Testrec
{
    public double now;
    public int ShLat;
    public int ShLon;
    public short ShLat;
    public short ShLon;
    public short ShSens1;
    public short ShSens2;
    public float ShAlt;
    public float ShFirst;
    public float ShDepth;
    public float ShSpeed;
    public float ShHead;
    public float ShCourse;
    public float ShRoll;
    public float ShPitch;
    public float ShVOS;
    public int FiLat;
    public int FiLon;
    public short FhLatUn;
    public short FhLonUn;
    public short FhSens1;
    public short FhSens2; 
    public float FhAlt;
    public float FhFirst;
    public float FhDepth;
    public float FhSpeed;
    public float FhHead;
    public float FhCourse;
    public float FhRoll;
    public float FhPitch;
    public float FhVOS;
    public int DataFlags;
    public int RevFlags;
    public int Contact;
    public short Range1;
    public short Range2;
}

FileStream RampStream;

private Double GetLastTime()
{
    Testrec RRampRec = new Testrec();
    double LastPosition;
    long HoldPosition;

    LastPosition = 0;
    HoldPosition = RampStream.Position;
    RampStream.Position = 128;

    while (RampStream.Position < RampStream.Length)
    {
        RRampRec = ReadRecFromStream2(RampStream);
        if ((RRampRec.ShLat == 0) && (RRampRec.ShLong == 0) && (RRampRec.FiLat == 0) && (RRampRec.FiLon == 0))
        {
            LastPosition = RRampRec.now;
        }
    }
    RampStream.Position = HoldPosition;
    return LastPosition;
}

TestrecReadRecFromStream2(Stream stream)
{
    byte[] buffer = new byte[Marshal.SizeOf(typeof(Testrec))];
    stream.Read(buffer, 0, HeaderSize);
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    try
    {
        return (Testrec)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Testrec));
    }
    finally
    {
        handle.Free();
    }
}

Notes: the stream is already at position 128 from reading in a previous struct, the first struct of the file. So RampStream.Position = 128 when beginning these functions.

Any idea what could be going wrong here? I can verify the position of the stream is correctly going up by 128 bytes at a time. Also, I can verify that RampStream.Position is equal to RampStream.Length at the end of the while loop.

2
  • Try the debugger. Check what comes from the file. Commented Mar 8, 2016 at 17:51
  • It seems that it's one 'record' behind the last one. Which makes sense now that I look at it, the while loop is only executing when the position is < length, but needs to be == and then assign stuff. I'm curious as to why the Delphi while loop works though. It is including the last record (last 128 bytes) in the file. Commented Mar 8, 2016 at 18:07

1 Answer 1

2

The indentation of the Delphi code appears to have confused you. It should be indented like this:

while RampStream.Position < RampStream.Size do
begin
  RampStream.Read(RRampRec,RecordSize);
  if (RRampRec.ShLat = 0) and (RRampRec.ShLon = 0) 
     and (RRampRec.FiLat = 0) and (RRampRec.FiLon = 0) then  
    continue;
  LastPosition := RRampRec.Now;
end;

So, LastPosition is only assigned when the if condition is false. Your C# code assigns LastPosition when the if condition is true. To make the C# code match you would write:

while (RampStream.Position < RampStream.Length)
{
    RRampRec = ReadRecFromStream2(RampStream);
    if ((RRampRec.ShLat == 0) && (RRampRec.ShLong == 0) 
       && (RRampRec.FiLat == 0) && (RRampRec.FiLon == 0))
        continue;
    LastPosition = RRampRec.now;
}

If it were me though I would avoid the use of continue and write the look like this:

while (RampStream.Position < RampStream.Length)
{
    RRampRec = ReadRecFromStream2(RampStream);
    if ((RRampRec.ShLat != 0) || (RRampRec.ShLong != 0) 
       || (RRampRec.FiLat != 0) || (RRampRec.FiLon != 0))
        LastPosition = RRampRec.now;
}

And I'm always nervous about single/compound statements so I'd probably add the braces:

while (RampStream.Position < RampStream.Length)
{
    RRampRec = ReadRecFromStream2(RampStream);
    if ((RRampRec.ShLat != 0) || (RRampRec.ShLong != 0) 
       || (RRampRec.FiLat != 0) || (RRampRec.FiLon != 0))
    {
        LastPosition = RRampRec.now;
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

You are absolutely right. I was being thrown off by that continue and the indentation. Switched that up and it seems to be fine now. Thanks for your help again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.