{$MODE OBJFPC}
unit dtypes;

interface

uses
  strings;

Type
Float = Single;
TFloat = Float;
TDouble = Double;

TInt  = {$IFDEF CPU64}Int64{$ELSE}Integer{$ENDIF};
TInt8  = ShortInt;
TInt16 = SmallInt;
TInt32 = LongInt;
TInt64 = Int64;
TUint  = {$IFDEF CPU64}QWord{$ELSE}LongWord{$ENDIF};
TUint8  = Byte;
TUint16 = Word;
TUint32 = Cardinal;
TUint64 = QWord;

TString = AnsiString;
TChar = AnsiChar;
TArrayOfString = array of TString;
TSetOfChar = set of TChar;

TUnicode = UnicodeString;
TUnicodeChar = UnicodeChar;
TArrayOfUnicode = array of TUnicode;

PMemAnsi = ^TMemAnsi;
TMemAnsi = packed record
  P: PAnsiChar;
  Len: Integer;
end;

TCallbackProc = procedure (UserData: Pointer);
TCallback = packed record
  Proc: TCallbackProc;
  UserData: Pointer;
end;

PArrayOfByte = ^TArrayOfByte;
TArrayOfByte = array[0..1] of Byte;
PArrayOfInt8 = ^TArrayOfInt8;
TArrayOfInt8 = array[0..1] of TInt8;
PArrayOfSingle = ^TArrayOfSingle;
TArrayOfSingle = array[0..1] of Single;
PArrayOfWord = ^TArrayOfWord;
TArrayOfWord = array[0..1] of Word;
PArrayOfCardinal = ^TArrayOfCardinal;
TArrayOfCardinal = array[0..1] of Cardinal;
PArrayOfUint32 = ^TArrayOfUint32;
TArrayOfUint32 = array[0..1] of TUint32;

TProcedure = procedure;

operator := (const S: TString): TMemAnsi;
operator := (P: PAnsiChar): TMemAnsi;
operator = (const A, B: TMemAnsi): Boolean;
operator = (const A: TMemAnsi; const B: TString): Boolean;
operator = (const A: TString; const B: TMemAnsi): Boolean; inline;

function Align(Value: Int64; Capacity: Integer): Int64;

function ToStr(Value: LongInt): TString; overload; inline;
function ToHex(Value: PtrUInt): TString; overload;
function ToStr(Value: Pointer): TString; overload;
function ToStr(Value: Boolean): TString; overload;

procedure UNUSED(constref X); inline;
// deprecated, see To/From function above
function DecodeEndianInt16(Value: TInt16; LittleEndian: Boolean): TInt16; inline; overload;
function EncodeEndianInt16(Value: TInt16; LittleEndian: Boolean): TInt16; inline; overload;
function DecodeEndianInt32(Value: TInt32; LittleEndian: Boolean): TInt32; inline; overload;
function EncodeEndianInt32(Value: TInt32; LittleEndian: Boolean): TInt32; inline; overload;
function DecodeEndianUint16(Value: TUint16; LittleEndian: Boolean): TUint16; inline; overload;
function EncodeEndianUint16(Value: TUint16; LittleEndian: Boolean): TUint16; inline; overload;
function DecodeEndianUint32(Value: TUint32; LittleEndian: Boolean): TUint32; inline; overload;
function EncodeEndianUint32(Value: TUint32; LittleEndian: Boolean): TUint32; inline; overload;
// Little-Endian: A=Sum(Ai * 256^i), Bytes: [A0,A1,...,AN]
function Int16ToLE(Value: TInt16): TInt16; inline;
function Int32ToLE(Value: TInt32): TInt32; inline;
function Int64ToLE(Value: TInt64): TInt64; inline;
function Int16FromLE(Value: TInt16): TInt16; inline;
function Int32FromLE(Value: TInt32): TInt32; inline;
function Int64FromLE(Value: TInt64): TInt64; inline;
function UInt16ToLE(Value: TUInt16): TUInt16; inline;
function UInt32ToLE(Value: TUInt32): TUInt32; inline;
function UInt64ToLE(Value: TUInt64): TUInt64; inline;
function UInt16FromLE(Value: TUInt16): TUInt16; inline;
function UInt32FromLE(Value: TUInt32): TUInt32; inline;
function UInt64FromLE(Value: TUInt64): TUInt64; inline;
// Big-Endian: A=Sum(Ai * 256^i), Bytes: [AN,...,A1,A0]
function Int16ToBE(Value: TInt16): TInt16; inline;
function Int32ToBE(Value: TInt32): TInt32; inline;
function Int64ToBE(Value: TInt64): TInt64; inline;
function Int16FromBE(Value: TInt16): TInt16; inline;
function Int32FromBE(Value: TInt32): TInt32; inline;
function Int64FromBE(Value: TInt64): TInt64; inline;
function UInt16ToBE(Value: TUInt16): TUInt16; inline;
function UInt32ToBE(Value: TUInt32): TUInt32; inline;
function UInt64ToBE(Value: TUInt64): TUInt64; inline;
function UInt16FromBE(Value: TUInt16): TUInt16; inline;
function UInt32FromBE(Value: TUInt32): TUInt32; inline;
function UInt64FromBE(Value: TUInt64): TUInt64; inline;

function Callback(Proc: TCallbackProc; UserData: Pointer = nil): TCallback; overload; inline;

operator := (Proc: TCallbackProc): TCallback;

{$IF FPC_VERSION > 20604}
operator + (const S: TString; Value: LongInt): TString; inline;
operator + (const S: TString; Value: Pointer): TString; inline;
operator + (const S: TString; Value: Boolean): TString; inline;
{$ENDIF}

implementation

uses
  dstrnum;

operator := (const S: TString): TMemAnsi;
begin
  Result.P := @S[1];
  Result.Len := Length(S);
end;

operator := (P: PAnsiChar): TMemAnsi;
begin
  Result.P := P;
  Result.Len := StrLen(P);
end;

function Align(Value: Int64; Capacity: Integer): Int64;
var
  R: Integer;
begin
  R := Value mod Capacity;
  if R = 0 then begin
    Result := Value;
    Exit;
  end;
  Result := Value + Capacity - R;
end;

operator = (const A, B: TMemAnsi): Boolean;
begin
  if A.Len <> B.Len then
    Exit(False);
  Result := StrLComp(A.P, B.P, A.Len) = 0;
end;

operator = (const A: TMemAnsi; const B: TString): Boolean;
begin
  if A.Len <> Length(B) then
    Exit(False);
  Result := StrLComp(A.P, @B[1], A.Len) = 0;
end;

operator = (const A: TString; const B: TMemAnsi): Boolean;
begin
  Result := B = A;
end;

function ToStr(Value: LongInt): TString;
begin
  Str(Value, Result);
end;

function ToHex(Value: PtrUInt): TString;
begin
  Result := UintToHex(Value);
end;

function ToStr(Value: Pointer): TString;
// workaround of hint: Conversion between ordinals and pointers is not portable
var
  U: PtrUInt absolute Value;
begin
  Result := ToHex(U);
end;

function ToStr(Value: Boolean): TString;
begin
  if Value then begin
    Result := 'true';
  end else
    Result := 'false';
end;

procedure UNUSED(constref X);
begin
end;

function DecodeEndianInt16(Value: TInt16; LittleEndian: Boolean): TInt16;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint16 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function EncodeEndianInt16(Value: TInt16; LittleEndian: Boolean): TInt16;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint16 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function DecodeEndianInt32(Value: TInt32; LittleEndian: Boolean): TInt32;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint16 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function EncodeEndianInt32(Value: TInt32; LittleEndian: Boolean): TInt32;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint16 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function DecodeEndianUint16(Value: TUint16; LittleEndian: Boolean): TUint16;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint16 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function EncodeEndianUint16(Value: TUint16; LittleEndian: Boolean): TUint16;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'EncodeEndianUint16 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function DecodeEndianUint32(Value: TUint32; LittleEndian: Boolean): TUint32;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint32 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function EncodeEndianUint32(Value: TUint32; LittleEndian: Boolean): TUint32;
begin
  UNUSED(LittleEndian);
{$IFDEF ENDIAN_LITTLE}
  Result := Value;
{$ELSE}
  Writeln(stderr, 'DecodeEndianUint32 is underdeveloped!');
  Halt(1);
{$ENDIF}
end;

function Int16ToLE(Value: TInt16): TInt16;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int32ToLE(Value: TInt32): TInt32;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int64ToLE(Value: TInt64): TInt64;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int16FromLE(Value: TInt16): TInt16;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int32FromLE(Value: TInt32): TInt32;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int64FromLE(Value: TInt64): TInt64;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt16ToLE(Value: TUInt16): TUInt16;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt32ToLE(Value: TUInt32): TUInt32;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt64ToLE(Value: TUInt64): TUInt64;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt16FromLE(Value: TUInt16): TUInt16;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt32FromLE(Value: TUInt32): TUInt32;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt64FromLE(Value: TUInt64): TUInt64;
begin
  Result := {$IFDEF ENDIAN_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int16ToBE(Value: TInt16): TInt16;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int32ToBE(Value: TInt32): TInt32;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int64ToBE(Value: TInt64): TInt64;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int16FromBE(Value: TInt16): TInt16;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int32FromBE(Value: TInt32): TInt32;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Int64FromBE(Value: TInt64): TInt64;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt16ToBE(Value: TUInt16): TUInt16;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt32ToBE(Value: TUInt32): TUInt32;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt64ToBE(Value: TUInt64): TUInt64;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt16FromBE(Value: TUInt16): TUInt16;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt32FromBE(Value: TUInt32): TUInt32;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function UInt64FromBE(Value: TUInt64): TUInt64;
begin
  Result := {$IFDEF BIG_LITTLE}Value{$ELSE}SwapEndian(Value){$ENDIF};
end;

function Callback(Proc: TCallbackProc; UserData: Pointer = nil): TCallback;
begin
  Result.Proc := Proc;
  Result.UserData := UserData;
end;

operator := (Proc: TCallbackProc): TCallback;
begin
  Result := Callback(Proc, nil);
end;

{$IF FPC_VERSION > 20604}
operator + (const S: TString; Value: LongInt): TString;
begin
  Result := S + ToStr(Value);
end;

operator + (const S: TString; Value: Pointer): TString;
begin
  Result := S + ToStr(Value);
end;

operator + (const S: TString; Value: Boolean): TString;
begin
  Result := S + ToStr(Value);
end;
{$ENDIF}

end.
