Delphi XE7 et les AnsiString


sous Delphi XE7, plus d'AnsiString pour Android. C'est mal, mais j'ai toujours aimé utiliser les "string" ou "AnsiString" de Delphi pour stocker toutes sortes d'informations. C'est extrêmement pratique, notamment car la notion #xx permet de mixer très facilement du texte et des données binaires, ne serait-ce que le retour chariot #13#10.

Plus de cela sous Android ! le type AnsiString n'existe tout simplement plus, Embarcadero recommande d'utiliser TBytes.

Ce qui est tout à fait dommage c'est que ces types existent en réalité, ils sont juste cachés.

Quoi qu'il en soit, voici une unité qui déclare un nouveau type ByteString qui est codé avec les dernières fonctionnalités du langage.

unit Execute.ByteStrings;

{
  ByteString for Delphi XE7 (c)2014 by Execute SARL 

  Delphi do not provide AnsiString anymore on Android Platform

  ByteString can do the trick

  NB: there's no codepage at all, only 8bits BYTE/CHAR, an UnicodeChar will lost it's high value !

  
  Take a look at this link also !
  http://andy.jgknet.de/blog/2013/10/the-return-of-the-byte-strings/


var
  s1, s2: ByteString;
begin
  s1 := 'GET / HTTP/1.0'#13#10;

  s2 := HttpGet(S1); // not a real function just a sample;

  if s2.Copy(1, 4) = '200 ' then ...
end;
}

{$ZEROBASEDSTRINGS ON} // just to remember ...

interface

type
  // 8bit Char
  ByteChar = packed record
    Value: Byte;
    // Char to ByteChar
    class operator Implicit(c: Char): ByteChar; inline;
    // ByteChar to Char
    class operator Implicit(b: ByteChar): Char; inline;
    // ByteChar = Char ?
    class operator Equal(b: ByteChar; c: Char): Boolean; inline;
    // ByteChar as an AsciiZ (ansi)string
    function AsPChar: string;
  end;
  PByteChar = ^ByteChar;

  // 8bit binary String
  ByteString = record
   // the bytes
    Bytes: array of ByteChar;
   // Get length
    function GetLength: Integer; inline;
    // Set length
    procedure SetLength(Value: Integer); inline;
    // same as above
    property Length: Integer read GetLength write SetLength;

    // Pointer to the first Byte = @Bytes[0]
    function FirstByte: PByteChar; inline;
    // Needed for some internal use
    procedure AddWord(Value: Word);
    // Concat string
    procedure AddStr(const Value: string);

    // get 1-based char
    function GetChar(Index: Integer): ByteChar; inline;
    // same as above
    property Chars[Index: Integer]: ByteChar read GetChar; default;

    // 0-based sub string
    function SubStr(Start, Len: Integer): string;
    // 1-based sub string
    function Copy(Start, Len: Integer): string; inline;

    // String to ByteString (High values lost)
    class operator Implicit(const s: string): ByteString;
    // ByteString to String
    class operator Implicit(b: ByteString): string;

    // same as Implicit conversion
    function AsString: string; inline;
    // Left part of the string till the first 0 byte if any, or the full string
    function AsPChar: string;
  end;

implementation

procedure ByteString.AddStr(const Value: string);
var
  Len: Integer;
  Idx: Integer;
begin
  Len := Length;
  Length := Len + System.Length(Value);
  for Idx := 0 to System.Length(Value) - 1 do
  begin
    Bytes[Len].Value := Ord(Value[Idx]) and 255;
    Inc(Len);
  end;
end;

procedure ByteString.AddWord(Value: Word);
var
  Len: Integer;
begin
  Len := Length;
  Length := Len + 2;
  Move(Value, Bytes[Len], 2);
end;

function ByteString.AsPChar: string;
var
  Len  : Integer;
  Index: Integer;
begin
  Len := Length;
  for Index := 0 to Len - 1 do
  begin
    if Bytes[Index].Value = 0 then
    begin
      Len := Index;
      Break;
    end;
  end;
  System.SetLength(Result, Len);
  for Index := 0 to Len - 1 do
    Result[Index] := Bytes[Index];
end;

function ByteString.AsString: string;
begin
  Result := Self;
end;

function ByteString.Copy(Start, Len: Integer): string;
begin
  Result := SubStr(Start - 1, Len);
end;

function ByteString.SubStr(Start: Integer; Len: Integer): string;
var
  Index: Integer;
begin
  if (Start < 0) or (Start >= Length) then
    Result := ''
  else begin
    if Start + Len > Length then
      Len := Length - Start;
    System.SetLength(Result, Len);
    for Index := 0 to Len - 1 do
    begin
      Result[Index] := Bytes[Start + Index];
    end;
  end;
end;

function ByteString.FirstByte: PByteChar;
begin
  Result := @Bytes[0];
end;

function ByteString.GetChar(Index: Integer): ByteChar;
begin
  Result := Bytes[Index - 1];
end;

function ByteString.GetLength: Integer;
begin
  Result := System.Length(Bytes);
end;

class operator ByteString.Implicit(b: ByteString): string;
var
  Index: Integer;
begin
  System.SetLength(Result, b.Length);
  for Index := 0 to b.Length - 1 do
    Result[Index] := b.Bytes[Index];
end;

class operator ByteString.Implicit(const s: string): ByteString;
var
  Index: Integer;
begin
  Result.SetLength(System.Length(s));
  for Index := 0 to System.Length(s) - 1 do
    Result.Bytes[Index].Value := Byte(Ord(s[Index + 1]));
end;

procedure ByteString.SetLength(Value: Integer);
begin
  System.SetLength(Bytes, Value);
end;

{ ByteChar }

class operator ByteChar.Implicit(c: Char): ByteChar;
begin
  Result.Value := Ord(c) and 255;
end;

function ByteChar.AsPChar: string;
var
  B: PByte;
  L: Integer;
begin
  B := @Self;
  L := 0;
  while B[L] <> 0 do
  begin
    Inc(L);
  end;
  SetLength(Result, L);
  while L > 0 do
  begin
    Dec(L);
    Result[L] := Char(B[L]);
  end;
end;

class operator ByteChar.Equal(b: ByteChar; c: Char): Boolean;
begin
  Result := b.Value = Ord(c);
end;

class operator ByteChar.Implicit(b: ByteChar): Char;
begin
  Result := Chr(b.Value);
end;

end.
Date de dernière modification : 03/12/2014