0

I have a String object in Delphi. I want to convert that to TByteDynArray. I have tried the implementation below.But while debugging I find that binaryData is empty after the assignment.What am I doing wrong?

procedure convertStringToTByteDynArray;
var
  binaryData:TByteDynArray;
  Data: String;

begin
   Data := '8080100B1D472';
  //Copy over string to TByteDynArray
  SetLength(binaryData,Length(Data));
  Move(Data[1],binaryData,Length(Data)); 
end
liv2hak
  • 14,472
  • 53
  • 157
  • 270

1 Answers1

4

The size of Char is 1 byte in Delphi 2007 and earlier, but is 2 bytes in Delphi 2009 and later. In the latter case, the code will put UTF-16 data into the bytearray, but will only copy half of the characters.

The core mistake you are making is that passing binarydata by itself to Move() passes the memory location of the variable itself, which is just a pointer to other memory. Passing binarydata[0] instead passes the memory location of the first element of the allocated memory that the TByteDynArray is pointing at. That is what you need to pass instead.

I also added a Length() check that avoids some rangecheck errors when those are enabled.

procedure convertStringToTByteDynArray;
var
  binaryData: TByteDynArray;
  Data: String;
begin
  Data := '8080100B1D472';
  //Copy over string to TByteDynArray
  SetLength(binaryData, Length(Data) * sizeof(Char));
  if Length(Data) > 0 then
    Move(Data[1], binaryData[0], Length(Data) * sizeof(Char)); 
end;

Alternatively:

procedure convertStringToTByteDynArray;
var
  binaryData: TByteDynArray;
  Data: String;
begin
  Data := '8080100B1D472';
  //Copy over string to TByteDynArray
  SetLength(binaryData, Length(Data) * sizeof(Char));
  Move(PChar(Data)^, PByte(binaryData)^, Length(binaryData)); 
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89
  • Or avoid the `if` with `Move(Pointer(Data)^, Pointer(BinaryData)^, Length(BinaryData))` because `if` is only needed to fit in with range checking. – David Heffernan Apr 04 '16 at 21:52
  • Worth mentioning I think is that in the version of **Move** I am looking at (Delphi 7 - more recent versions not immediately to hand), it checks for a NIL *source*, but not a NIL *destination* (which will result in an access violation). i.e. when using **Move**, an **if** to guard against a NIL source (empty *Data* in this case) is redundant. However, guarding against a NIL *destination* may still be required (tho not in this case since the implementation of the convert... function ensures that the destination (*binaryData*) will only be NIL if Data is also NIL, i.e. empty). – Deltics Apr 04 '16 at 22:36
  • @Deltics If the length is zero, surely neither of the first two args are de-referenced – David Heffernan Apr 05 '16 at 07:06
  • Binary data in both cases is dereferenced before passing it to move, in the parameter preparation (either by the [0] or the ^) – Marco van de Voort Apr 05 '16 at 07:47
  • @Marco No is not. The address is passed. Dereferencing happens inside Move. – David Heffernan Apr 05 '16 at 11:38
  • @David, yes you're right. As I say, in this specific case the issue doesn't arise but for the general case of using **Move()** you *may* need to guard (either explicitly or indirectly as a result of the implementation, as in this case) against a non-NIL *destination* where the source is non-NIL or count > 0 (conditions that you do *not* need to guard for). – Deltics Apr 05 '16 at 20:22