Создание функции для обратного порядка шестнадцатеричного значения в виде строки - PullRequest
0 голосов
/ 12 июня 2019

как это выразить ...

Я весь день изо всех сил пытался обратить значение UID карты NIF Mifare, значение, которое я прочитал в виде шестнадцатеричной строки, которую я могу преобразовать в целое число,это очень хорошо работает с 4-байтовым UID.

Вещи запутываются, когда дело доходит до карты mifare desfire, которая может иметь большой пример UID:

04 44 44 22 E0 62 80

Значение читается правильно ия могу даже преобразовать это в десятичное число, используя мои функции StrToInt ('$' + TheUIDvalue)

теперь странная часть состоит в том, что мне нужно обратить это, используя следующую функцию:

function HexToInt(s: string): Longword;
var
  b: byte;
  c: Char;
begin
  Result := 0;
  s := UpperCase(s);
  for b := 1 to Length(s) do
  begin
    Result := Result * 16;
    c := s[b];
    case c of
      '0' .. '9':
        Inc(Result, Ord(c) - Ord('0'));
      'A' .. 'F':
        Inc(Result, Ord(c) - Ord('A') + 10);
    else
      begin
        Result := 0
      end;
    end;
  end;
end;

function LongEndian(L : UInt64) : UInt64;
begin
  result := ((L and $000000FF) shl 24) or
            ((L and $0000FF00) shl 8) or
            ((L and $00FF0000) shr 8) or
            ((L and $FF000000) shr 24);
end;

function TfrmMain.HexResponseReversed ( input: string): string;
begin
  result := IntToHex(EndianLong(hexToInt(input)));
end;



The result i get is : 
         80 62 E0 22
04 44 44 22 E0 62 80

Так что здесь что-то серьезно упущено ... прошу прощения за грязный код

Я подозреваю, что что-то не так с функцией IntToHex

1 Ответ

6 голосов
/ 13 июня 2019

Ваша функция HexToInt() возвращает LongWord, поэтому ее вывод зависит от платформы. Для 64-битных платформ POSIX, таких как Linux и iOS, это 8 байтов, для других платформ - 4 байта.

Кроме того, ваша функция LongEndian() заменяет только 4 байта, несмотря на работу с 8-байтовым UInt64.

Итак, вы должны либо:

  • исправление этих функций для работы с полными 8 байтами на всех платформах, например:

    function HexToInt64(s: string): UInt64;
    var
      Len, I: Integer;
      c: Char;
    begin
      Result := 0;
      Len := Length(s);
      if Len = 0 then Exit;
      if Odd(Len) then
      begin
        s := '0' + s;
        Inc(Len);
      end;
      if Len > 16 then Exit;
      for I := 1 to Len do
      begin
        Result := Result * 16;
        c := s[I];
        case c of
          '0' .. '9':
            Inc(Result, Ord(c) - Ord('0'));
          'A' .. 'F':
            Inc(Result, Ord(c) - Ord('A') + 10);
          'a' .. 'f':
            Inc(Result, Ord(c) - Ord('a') + 10);
        else
          begin
            Result := 0;
            Exit;
          end;
        end;
      end;
    end;
    
    function EndianLong(L : UInt64) : UInt64;
    begin
      Result := ((L and $00000000000000FF) shl 56) or
                ((L and $000000000000FF00) shl 40) or
                ((L and $0000000000FF0000) shl 24) or
                ((L and $00000000FF000000) shl 8) or
                ((L and $000000FF00000000) shr 8) or
                ((L and $0000FF0000000000) shr 24) or
                ((L and $00FF000000000000) shr 40) or
                ((L and $FF00000000000000) shr 56);
    end;
    
    function TfrmMain.HexResponseReversed(input: string): string;
    begin
      Result := IntToHex(EndianLong(HexToInt64(input)));
    end;
    
  • декодирует отдельные пары HH шестнадцатеричной строки в байтовый массив, затем меняет порядок элементов массива и затем создает новую шестнадцатеричную строку из элементов массива:

    uses
      ..., Classes;
    
    function HexToBytes(s: string): TBytes;
    var
      Len: Integer;
    begin
      Result := nil;
      Len := Length(s);
      if Len = 0 then Exit;
      if Odd(Len) then
      begin
        s := '0' + s;
        Inc(Len);
      end;
      Len := Len div 2;
      SetLength(Result, Len);
      if HexToBin(PChar(s), PAnsiChar(PByte(Result)), Len) <> Len then
        SetLength(Result, 0);
    end;
    
    function BytesToHex(Bytes: TBytes): string;
    var
      Len: Integer;
    begin
      Result := nil;
      Len := Length(Bytes);
      if Len = 0 then Exit;
      SetLength(Result, Len * 2);
      BinToHex(PAnsiChar(PByte(Bytes)), PChar(Result), Len);
    end;
    
    function EndianLong(Bytes : TBytes) : TBytes;
    var
      Len, I, J: Integer;
      B: Byte;
    begin
      Result := nil;
      Len := Length(Bytes); 
      if Len = 0 then Exit;
      Result := Copy(Bytes, 0, Len);
      if Len = 1 then Exit;
      J := Pred(Len);
      for I := 0 to Pred(Len div 2) do
      begin
        B := Result[I];
        Result[I] := Result[J];
        Result[J] := B;
        Dec(J);
      end;
    end;
    
    function TfrmMain.HexResponseReversed(input: string): string;
    begin
      Result := BytesToHex(EndianLong(HexToBytes(input)));
    end;
    

При этом третьим вариантом было бы просто поменять пары HH входной строки напрямую, без преобразования всей входной строки в целочисленный или байтовый массив вообще:

uses
  ..., SysUtils;

function TfrmMain.HexResponseReversed(input: string): string;
const
  HexDigits = ['0'..'9', 'A'..'F', 'a'..'f'];
var
  Len, I: Integer;
  P, Q: PChar;
  Hex: array[0..1] of Char;
begin
  Result := '';
  Len := Length(input);
  if Len = 0 then Exit;
  Result := input;
  if Odd(Len) then
  begin
    Result := '0' + Result;
    Inc(Len);
  end;
  Len := Len div 2;
  if Len = 1 then Exit;
  UniqueString(Result);
  P := PChar(Result);
  Q := AnsiLastChar(Result);
  Dec(Q);
  For I := 1 to Len div 2 do
  begin
    Move(P^, Hex, SizeOf(Hex));
    if not ((Hex[0] in HexDigits) and (Hex[1] in HexDigits)) then
    begin
      Result := '';
      Exit;
    end;
    Move(Q^, P^, SizeOf(Hex));
    Move(Hex, Q^, SizeOf(Hex));
    Inc(P, 2);
    Dec(Q, 2);
  end;
end;
...