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.

Community
  • 1
  • 1
pfinferno
  • 1,779
  • 3
  • 34
  • 62
  • Try the debugger. Check what comes from the file. – David Heffernan Mar 08 '16 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. – pfinferno Mar 08 '16 at 18:07

1 Answers1

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;
    }
}
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 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! – pfinferno Mar 09 '16 at 11:30