0

Parameters: InLong = 0, Posit = 5, and from an ASCII file TmPChar{.,STX,NUL,NUL}

Delphi code

Procedure TForm1.GetLongFromBuf(Var InLong : Longint; Posit : Integer; ZRepB : ZrepBuf);
Var
  TmpPChar     : Array[0..3] Of Char;
  PLong        : ^Longint;
  I            : Byte;
Begin
For I:= 0 To 3 Do
   TmpPChar[I] := ZRepB[Posit+I];
PLong := @TmpPChar;
InLong := PLong^;
End;

Outputs: TmPChar {'.', #2, #0, #0}, PLong = 13F54C, InLong = 558

C# code

unsafe static long GetLongFromBuf(long InLong, int Posit, char[] ZRepB){
 long* Plong;
 char[] TmpPChar = new char[4];
 for (byte i = 0; i < TmpPChar.Length; i++){
    TmpPChar[i] = ZRepB[(Posit-1) + (i)];
 }
 fixed(char* ch = TmpPChar){
  PLong = (long*)&ch;
  InLong ^= (long)PLong;
 }
 return InLong;
}

Outputs: TmPChar{'.','\u0002','\0','0'}, PLong = 0x0000000000b3cc18, InLong = 11783192

Adonis Pso
  • 25
  • 7
  • 2
    What version of Delphi? Is Char unicode (since d2009)? WTF here: `InLong ^= (long)PLong;` ? – MBo Mar 19 '19 at 10:58
  • In addition to the questions @MBo asked, How is `ZrepBuf` defined? – J... Mar 19 '19 at 11:07
  • Also, there is no XOR in the Delphi code. Why are you using it in C#? Are you confusing the dereference operator? – J... Mar 19 '19 at 11:15
  • @MBo thank you for your immediate response. It is Delphi 5 with non Unicode d2005. By (InLong ^= (long)PLong; ) i am decrypting the value using the XOR Encryption Method, it is equivalent to InLong = InLong ^ (long)Plong; But i am not sure 100% for the fixed block if it is the correct conversion to C#. – Adonis Pso Mar 19 '19 at 11:22
  • C# `char` is 16 bit, Delphi 5 and D2005 `char` is 8 bit. Also, the Delphi code is not even close to the C# code. The C# code uses bitwise xor, the Delphi does not. It's not really our place to write the code for you. I suggest you spend more time in the debugger, and reading documentation, so that you understand clearly what the C# code actually does. – David Heffernan Mar 19 '19 at 11:25
  • @J... ZrepBuf is a char array of 140 chars, where its char represent a byte from a FileStream Read. – Adonis Pso Mar 19 '19 at 11:31
  • @AdonisPso: The Delphi code **does not exclusive-or anything**. In Delphi, `^` dereferences a pointer, nothing else. The operator for exclusive-or is the keyword `xor`. The code simply interprets 4 bytes from the buffer ZRepB as a 32 bit Longint, nothing else. The way it is done is pretty convoluted, and could simply be done as: `InLong := PLongint(@ZRepB[Posit])^;` Like J..., I have the impression you don't *understand* the Delphi code at all. – Rudy Velthuis Mar 19 '19 at 11:35
  • @AdonisPso: in Delphi, the `^` operator (originally, an upward arrow) is the pointer operator, like `*` in C or C++ (or C#). So `Plong^` in Delphi does the same as `*Plong` in C: it dereferences the pointer `Plong`. – Rudy Velthuis Mar 19 '19 at 11:45
  • @David: indeed, as I said, a few comments further up. – Rudy Velthuis Mar 19 '19 at 16:18
  • @David: you are the echo, I am the echo, you are the walrus, goo goo g'joob . – Rudy Velthuis Mar 19 '19 at 17:24

1 Answers1

3

It appears that you are using this Delphi code without really understanding what it is doing. From your results, we can conclude you are using a pre-unicode version of Delphi (ie: D2007 or earlier). We can also guess that ZrepBuf is defining an array of bytes or [Ansi]Char. The method, then, works as follows :

For I:= 0 To 3 Do
  TmpPChar[I] := ZRepB[Posit+I];  /* Copy four sequential bytes to TmpPChar array */
PLong := @TmpPChar;               /* Take a pointer to the head of the array */ 
InLong := PLong^;                 /* Dereference the pointer, interpreting as a 32-bit int */

This is code to convert four bytes to a 32-bit integer. In Delphi the LongInt type is an alias for the 32-bit integer type, equivalent to the int type in C#, not long. There is no use of the XOR operator in the Delphi code. In PLong^, the ^ operator is a dereference operation.

In C# you can avoid unsafe code entirely and simply perform this conversion using the BitConverter class:

 byte[] b = new byte[4] { 0x2E, 0x02, 0x00, 0x00 }; 
 int result = BitConverter.ToInt32(b, 0);  // result == 558

Here I've defined the input array as a byte[] since a char in C# (and in Delphi 2009 or newer) is a 16-bit type (two bytes) for storing Unicode characters. The data you are reading is ANSI encoded - I'm presuming you understand how to read your text file into a byte array.

Incidentally, in more modern Delphi you could also re-write the pointer code above to use the TEncoding class to perform this function as described here in a similar way to the BitConverter class in C#.

J...
  • 30,968
  • 6
  • 66
  • 143
  • I have to change the "my code" as I have not written the code I am doing the conversion to C#. I have been misleaded with (^) symbol in Delphi. After i gave to the byte array the fours TmPChar elements I got the same value to C# as correctly @J... wrote . byte[] b = new byte[4] { Convert.ToByte(TmpPChar[0]), Convert.ToByte(TmpPChar[1]) , Convert.ToByte(TmpPChar[2]) , Convert.ToByte(TmpPChar[3]) }; InLong = BitConverter.ToInt32(b, 0); – Adonis Pso Mar 19 '19 at 11:55
  • 1
    note that this assumes the operating system is big-endian. – Jesse de Wit Mar 19 '19 at 12:43
  • @JessedeWit: How so? TmpPChar[0] is 0x2E, TmpPChar[1] is 0x02, rest ist 0. This is most definitely little-endian for 0x0000022E = 558. But I would never use an **array of char (TmpPChar) as intermediate**. I would use bytes directly. – Rudy Velthuis Mar 19 '19 at 13:41
  • @JessedeWit Windows is little-endian and this assumes that byte order, yes. OP can trivially swap the byte order if support for other platforms is required. – J... Mar 19 '19 at 13:45
  • Or assumes it is little-endian, my point is the operating system endianness matters. From the remarks of BitConverter.ToInt32: _The order of bytes in the array must reflect the endianness of the computer system's architecture;_ – Jesse de Wit Mar 19 '19 at 13:48
  • @JessedeWit very nice point but it is Little Endian and my C# code conversion refers to Little Endian also. – Adonis Pso Mar 19 '19 at 14:56
  • @AdonisPso I don't see where any C# code in the answer or comments mandates little endian – David Heffernan Mar 19 '19 at 15:20
  • 1
    @AdonisPso Your C# code is also far more complicated than you need. The function should accept a byte array and then use `BitConverter.ToInt32(arr, index)`. All this copying to temp arrays is pointless. – David Heffernan Mar 19 '19 at 15:24
  • @David: Both in Delphi and in C#, the entire function is rather obsolete. In Delphi, you can do: `myLongint := PLongint(@ZrepB[Posit]);`. In C# you can do `myInt32 = BitConverter(ZrepB, posit);`. – Rudy Velthuis Mar 19 '19 at 15:58
  • @You said the C# part. I don't see you talk about the Delphi part. I should have inserted "your" before the BitConverter part, sorry. Oh, wait... now I see you echoed my comment in the other comment section. – Rudy Velthuis Mar 19 '19 at 16:13