(*
 *  Copyright (c) 2021-2022 Serg Shutkin
 *
 *  This software is provided 'as-is', without any express or
 *  implied warranty. In no event will the authors be held
 *  liable for any damages arising from the use of this software.
 *
 *  Permission is granted to anyone to use this software for any purpose,
 *  including commercial applications, and to alter it and redistribute
 *  it freely, subject to the following restrictions:
 *
 *  1. The origin of this software must not be misrepresented;
 *     you must not claim that you wrote the original software.
 *     If you use this software in a product, an acknowledgment
 *     in the product documentation would be appreciated but
 *     is not required.
 *
 *  2. Altered source versions must be plainly marked as such,
 *     and must not be misrepresented as being the original software.
 *
 *  3. This notice may not be removed or altered from any
 *     source distribution.
 *)

// Rus: требуется проверка при работе с флагами переполнения. На данный момент
//      проблем не возникало.
// Eng: validation is required when dealing with overflow flags. At the moment
//      there have been no problems.

unit gegl_external_Utils;
{$I gegl_config.cfg}

interface

const
  // Rus: константы задаваемые при вызове geStrToInt
  // Eng: constants set when calling geStrToInt
  isByte      = 0;
  isShortInt  = 0;
  {$IfDef USE_CPU16}
  isWord      = 1;
  isSmallInt  = 1;
  {$EndIf}
  {$IfDef USE_CPU32}
  isLongWord  = 2;
  isInteger   = 2;
  {$EndIf}
  {$IfDef USE_CPU64}
  isQWord     = 3;
  isInt64      = 3;
  {$EndIf}
  {$IfDef CPU8}
  maxSize     = 0;
  {$EndIf}
  {$IfDef CPU16}
  maxSize     = 1;
  {$EndIf}
  {$IfDef CPU32}
  maxSize     = 2;
  {$EndIf}
  {$IfDef CPU64}
  maxSize     = 3;
  {$EndIf}

type
  PmaxIntVal = ^maxIntVal;
  PmaxUIntVal = ^maxUIntVal;
  {$IfDef CPU8}
  maxIntVal = {$IfNDef UP_CPU}ShortInt{$Else}SmallInt{$EndIf};
  maxUIntVal = {$IfNDef UP_CPU}Byte{$Else}Word{$EndIf};
  {$EndIf}
  {$IfDef CPU16}
  maxIntVal = {$IfNDef UP_CPU}SmallInt{$Else}Integer{$EndIf};
  maxUIntVal = {$IfNDef UP_CPU}Word{$Else}LongWord{$EndIf};
  {$EndIf}
  {$IfDef CPU32}
  maxIntVal = {$IfNDef UP_CPU}Int64{$Else}Integer{$EndIf};
  maxUIntVal = {$IfNDef UP_CPU}LongWord{$Else}QWord{$EndIf};
  {$EndIf}
  {$IfDef CPU64}
  maxIntVal = Int64;
  maxUIntVal = QWord;
  {$EndIf}
  {$IfDef USE_STRING}
  useString = String;
  {$EndIf}
  {$IfDef USE_ANSISTRING}
  useString = AnsiString;
  {$EndIf}
  {$IfDef USE_UTF8STRING}
  useString = UTF8String;
  {$EndIf} 

// Rus: эта функция для десятичных чисел со знаком.
// Eng: this function is for signed decimal numbers.
{$IfNDef UNICODESTRING_ONLI}
function geCharToInt(const aStr: array of Char; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToInt(const Str: useString; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}
{$IfDef USE_UNICODESTRING}
function geWCharToInt(const aStr: array of WideChar; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToInt(const Str: UnicodeString; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}

// Rus: эта функция только для десятичных чисел без знака!!!
// Eng: this function is only for unsigned decimal numbers!!!
{$IfNDef UNICODESTRING_ONLI}
function geCharToUInt(const aStr: array of Char; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToUInt(const Str: useString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}
{$IfDef USE_UNICODESTRING}
function geWCharToUInt(const aStr: array of WideChar; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToUInt(const Str: UnicodeString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}

// Rus: для работы с шестнадцатеричными, восьмеричными и двоичными данными.
// Eng: for working with hexadecimal, octal and binary data.
{$IfNDef UNICODESTRING_ONLI}
function geHOBCharToUInt(const aStr: array of Char; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geHOBStrToUInt(const Str: useString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}
{$IfDef USE_UNICODESTRING}
function geHOBWCharToUInt(const aStr: array of WideChar; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geHOBStrToUInt(const Str: UnicodeString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}

(* Rus: Ниже реализованы стандартные функции для перевода строк в число. Их
 *      использование будет проще для большинства. Функции отмечены префиксом.
 *      s_ - функции возвращают результат (если операция была неудачной, то
 *      в результате вернётся ноль, но вы не узнаете, что операция была неудачной).
 *      sc_ - результат функций удачная или не удачная была операция. Сам
 *      конечный числовой результат считывайте в Value.
 * Eng: The standard functions for converting strings to numbers are implemented
 *      below. Their use will be easier for most. Functions are marked with a prefix.
 *      s_ - functions return a result (if the operation was unsuccessful, the result
 *      will be zero, but you will not know that the operation was unsuccessful).
 *      sc_ - the result of the functions - the operation was successful or
 *      unsuccessful. Read the final numerical result in Value.
 *)
// sc_ - speed + check
// s_ - speed (not check)

// Rus: Числа со знаком. Здесь нельзя использовать шестнадцатеричные, восьмеричные
//      и двоичные числа.
// Eng: Signed numbers. Hexadecimal, octal and binary numbers cannot be used here.
{$IfNDef UNICODESTRING_ONLI}
function sc_StrToShortInt(const Str: useString; out Value: ShortInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // byte
function s_StrToShortInt(const Str: useString): ShortInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // byte
{$IfDef USE_CPU16}
function sc_StrToSmallInt(const Str: useString; out Value: SmallInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // word
function s_StrToSmallInt(const Str: useString): SmallInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // word
{$EndIf}
{$IfDef USE_CPU32}
function sc_StrToInt(const Str: useString; out Value: Integer): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt(const Str: useString): Integer; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$IfDef USE_CPU64}
function sc_StrToInt64(const Str: useString; out Value: Int64): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt64(const Str: useString): Int64; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$EndIf}
{$IfDef USE_UNICODESTRING}
function sc_StrToShortInt(const Str: UnicodeString; out Value: ShortInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // byte
function s_StrToShortInt(const Str: UnicodeString): ShortInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // byte
{$IfDef USE_CPU16}
function sc_StrToSmallInt(const Str: UnicodeString; out Value: SmallInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // word
function s_StrToSmallInt(const Str: UnicodeString): SmallInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // word
{$EndIf}
{$IfDef USE_CPU32}
function sc_StrToInt(const Str: UnicodeString; out Value: Integer): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt(const Str: UnicodeString): Integer; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$IfDef USE_CPU64}
function sc_StrToInt64(const Str: UnicodeString; out Value: Int64): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt64(const Str: UnicodeString): Int64; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$EndIf}

// Rus: Числа без знака. Эти функции могут использоваться и для шестнадцатеричныи
//      и восьмеричных и двоичных чисел. Данные функции не должны содержать
//      ведущие нули для десятеричной системы счисления.
// Eng: Numbers without a sign. These functions can be used for hexadecimal, octal
//      and binary numbers as well. These functions must not contain leading zeros
//      for the decimal number system.
{$IfNDef UNICODESTRING_ONLI}
function sc_StrToByte(const Str: useString; out Value: Byte): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToByte(const Str: useString): Byte; {$IfDef ADD_FAST}inline;{$EndIf}
{$IfDef USE_CPU16}
function sc_StrToWord(const Str: useString; out Value: Word): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToWord(const Str: useString): Word; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$IfDef USE_CPU32}
function sc_StrToLongWord(const Str: useString; out Value: LongWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToLongWord(const Str: useString): LongWord; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$IfDef USE_CPU64}
function sc_StrToQWord(const Str: useString; out Value: QWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToQWord(const Str: useString): QWord; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$EndIf}
{$IfDef USE_UNICODESTRING}
function sc_StrToByte(const Str: UnicodeString; out Value: Byte): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToByte(const Str: UnicodeString): Byte; {$IfDef ADD_FAST}inline;{$EndIf}
{$IfDef USE_CPU16}
function sc_StrToWord(const Str: UnicodeString; out Value: Word): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToWord(const Str: UnicodeString): Word; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$IfDef USE_CPU32}
function sc_StrToLongWord(const Str: UnicodeString; out Value: LongWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToLongWord(const Str: UnicodeString): LongWord; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$IfDef USE_CPU64}
function sc_StrToQWord(const Str: UnicodeString; out Value: QWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToQWord(const Str: UnicodeString): QWord; {$IfDef ADD_FAST}inline;{$EndIf}
{$EndIf}
{$EndIf}

implementation
{$Goto on}

const
  dataHex: array[0..54] of Byte = (  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 16, 16, 16, 16, 16, 16,
                                    16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
                                    16,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 16, 16, 16, 16, 16,
                                    16, 10, 11, 12, 13, 14, 15);

type
  PgeUseParametr = ^geUseParametr;
  geUseParametr = record
    maxLen: LongWord;
    maxNumDiv10: maxUIntVal;
    maxNumeric: maxUIntVal;
  end;

  PgeHOBParameter = ^geHOBParameter;
  geHOBParameter = record
    maxLen16, maxLen8, maxLen2: maxUIntVal;
  end;
  
var
  allIntParametr, allUIntParametr: array[0..7] of geUseParametr;
  allHOBParametr: array[0..3] of geHOBParameter;

// Rus: выставляем необходимые параметры. Иначе geStrToInt работать не будет.
//      В блоке инициализации.
// Eng: set the required parameters. Otherwise geStrToInt won't work.
//      in the initialization block.
procedure SetNumberParametr;
begin
  allUIntParametr[isByte].maxLen := 3;
  allUIntParametr[isByte].maxNumeric := 255;
  allUIntParametr[isByte].maxNumDiv10 := 25;
  allIntParametr[isShortInt].maxLen := 4;
  allIntParametr[isShortInt].maxNumeric := 127;
  allIntParametr[isShortInt].maxNumDiv10 := 12;
  {$IfDef USE_CPU16}
  allUIntParametr[isWord].maxLen := 5;
  allUIntParametr[isWord].maxNumeric := 65535;
  allUIntParametr[isWord].maxNumDiv10 := 6553;
  allIntParametr[isSmallInt].maxLen := 6;
  allIntParametr[isSmallInt].maxNumeric := 32767;
  allIntParametr[isSmallInt].maxNumDiv10 := 3276;
  {$EndIf}
  {$IfDef USE_CPU32}
  allUIntParametr[isLongWord].maxLen := 10;
  allUIntParametr[isLongWord].maxNumeric := 4294967295;
  allUIntParametr[isLongWord].maxNumDiv10 := 429496729;
  allIntParametr[isInteger].maxLen := 11;
  allIntParametr[isInteger].maxNumeric := 2147483647;
  allIntParametr[isInteger].maxNumDiv10 := 214748364;
  {$EndIf}
  {$IfDef USE_CPU64}
  allUIntParametr[isQWord].maxLen := 20;
  allUIntParametr[isQWord].maxNumeric := 18446744073709551615;
  allUIntParametr[isQWord].maxNumDiv10 := 1844674407370955161;
  allIntParametr[isInt64].maxLen := 20;
  allIntParametr[isInt64].maxNumeric := 9223372036854775807;
  allIntParametr[isInt64].maxNumDiv10 := 922337203685477580;
  {$EndIf}

  allHOBParametr[isByte].maxLen16 := 3;
  allHOBParametr[isByte].maxLen8 := 4;
  allHOBParametr[isByte].maxLen2 := 9;
  {$IfDef USE_CPU16}
  allHOBParametr[isWord].maxLen16 := 5;
  allHOBParametr[isWord].maxLen8 := 7;
  allHOBParametr[isWord].maxLen2 := 17;
  {$EndIf}
  {$IfDef USE_CPU32}
  allHOBParametr[isLongWord].maxLen16 := 9;
  allHOBParametr[isLongWord].maxLen8 := 12;
  allHOBParametr[isLongWord].maxLen2 := 33;
  {$EndIf}
  {$IfDef USE_CPU64}
  allHOBParametr[isQWord].maxLen16 := 17;
  allHOBParametr[isQWord].maxLen8 := 23;
  allHOBParametr[isQWord].maxLen2 := 65;
  {$EndIf}
end;

{$IfNDef UNICODESTRING_ONLI}
function geStrToInt(const Str: useString; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean; inline;
begin
  Result := geCharToInt(Str[1..Length(Str)], Value, Size);
end;

function geStrToUInt(const Str: useString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
begin
  Result := geCharToUInt(Str[1..Length(Str)], Value, Size);
end;

function geHOBStrToUInt(const Str: useString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
begin
  Result := geHOBCharToUInt(Str[1..Length(Str)], Value, Size);
end;

function sc_StrToShortInt(const Str: useString; out Value: ShortInt): Boolean;
var
  n: maxIntVal;
begin
  Result := geCharToInt(Str[1..Length(Str)], n, isShortInt);
  Value := n;
end;

function s_StrToShortInt(const Str: useString): ShortInt;
var
  n: maxIntVal;
begin
  geCharToInt(Str[1..Length(Str)], n, isShortInt);
  Result := n;
end;

{$IfDef USE_CPU16}
function sc_StrToSmallInt(const Str: useString; out Value: SmallInt): Boolean;
var
  n: maxIntVal;
begin
  Result := geCharToInt(Str[1..Length(Str)], n, isSmallInt);
  Value := n;
end;

function s_StrToSmallInt(const Str: useString): SmallInt;
var
  n: maxIntVal;
begin
  geCharToInt(Str[1..Length(Str)], n, isSmallInt);
  Result := n;
end;
{$EndIf}

{$IfDef USE_CPU32}
function sc_StrToInt(const Str: useString; out Value: Integer): Boolean;
var
  n: maxIntVal;
begin
  Result := geCharToInt(Str[1..Length(Str)], n, isInteger);
  Value := n;
end;

function s_StrToInt(const Str: useString): Integer;
var
  n: maxIntVal;
begin
  geCharToInt(Str[1..Length(Str)], n, isInteger);
  Result := n;
end;
{$EndIf}

{$IfDef USE_CPU64}
function sc_StrToInt64(const Str: useString; out Value: Int64): Boolean;
begin
  Result := geCharToInt(Str[1..Length(Str)], Value, isInt64);
end;

function s_StrToInt64(const Str: useString): Int64;
begin
  geCharToInt(Str[1..Length(Str)], Result, isInt64);
end;

{$EndIf}

function sc_StrToByte(const Str: useString; out Value: Byte): Boolean;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBCharToUInt(Str[1..Length(Str)], n, isByte)
  else
    Result := geCharToUInt(Str[1..Length(Str)], n, isByte);
  Value := n;
end;

function s_StrToByte(const Str: useString): Byte;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBCharToUInt(Str[1..Length(Str)], n, isByte)
  else
    geCharToUInt(Str[1..Length(Str)], n, isByte);
  Result := n;
end;

{$IfDef USE_CPU16}
function sc_StrToWord(const Str: useString; out Value: Word): Boolean;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBCharToUInt(Str[1..Length(Str)], n, isWord)
  else
    Result := geCharToUInt(Str[1..Length(Str)], n, isWord);
  Value := n;
end;

function s_StrToWord(const Str: useString): Word;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBCharToUInt(Str[1..Length(Str)], n, isWord)
  else
    geCharToUInt(Str[1..Length(Str)], n, isWord);
  Result := n;
end;
{$EndIf}

{$IfDef USE_CPU32}
function sc_StrToLongWord(const Str: useString; out Value: LongWord): Boolean;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBCharToUInt(Str[1..Length(Str)], n, isLongWord)
  else
    Result := geCharToUInt(Str[1..Length(Str)], n, isLongWord);
  Value := n;
end;

function s_StrToLongWord(const Str: useString): LongWord;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBCharToUInt(Str[1..Length(Str)], n, isLongWord)
  else
    geCharToUInt(Str[1..Length(Str)], n, isLongWord);
  Result := n;
end;
{$EndIf}

{$IfDef USE_CPU64}
function sc_StrToQWord(const Str: useString; out Value: QWord): Boolean;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBCharToUInt(Str[1..Length(Str)], Value, isQWord)
  else
    Result := geCharToUInt(Str[1..Length(Str)], Value, isQWord);
end;

function s_StrToQWord(const Str: useString): QWord;
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBCharToUInt(Str[1..Length(Str)], Result, isQWord)
  else
    geCharToUInt(Str[1..Length(Str)], Result, isQWord);
end;
{$EndIf}

function geCharToUInt(const aStr: array of Char; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
var
  lenStr, i: maxUIntVal;
  m, n, z: maxUIntVal;
  useParametr: PgeUseParametr;
  correct: maxUIntVal = 0;
begin
  {$push}
  {$Q-}{$R-}
  Result := False;
  Value := 0;
  if Size > maxSize then
    Exit;
  lenStr := Length(aStr);
  if lenStr = 0 then
    exit;
  m := Byte(aStr[0]);
  i := 1;

  while m = 48 do
  begin
    if (lenStr - correct) = 1 then
    begin
      Result := True;
      exit;
    end;
    m := Byte(aStr[i]);
    inc(i);
    inc(correct);
  end;
    
  m := m - 48;
  if m > 9 then
    exit;
  if (lenStr - correct) = 1 then
  begin
    Value := m;
    Result := true;
    Exit;
  end;
  useParametr := @allUIntParametr[Size];
  if lenStr > useParametr^.maxLen then
    Exit;
  while i < lenStr - 1 do
  begin
    n := (Byte(aStr[i]) - 48);
    if n > 9 then
      Exit;
    m := m * 10 + n;
    inc(i);
  end;
  if m > useParametr^.maxNumDiv10 then
    exit;
  m := m * 10;
  z := Byte(aStr[i]) - 48;
  if z > 9 then
    exit;
  n := useParametr^.maxNumeric - m;
  if z > n then
    exit;
  Value := m + z;
  Result := true;
  {$pop}
end;

function geHOBCharToUInt(const aStr: array of Char; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
var
  lenStr, i: maxUIntVal;
  m, n, nshl, z: maxUIntVal;
  Pnshl: PmaxUIntVal;
  correct: maxUIntVal = 0;
  useParametr: PgeHOBParameter;
begin
  {$push}
  {$Q-}{$R-}
  Result := False;
  Value := 0;
  if Size > maxSize then
    exit;
  lenStr := Length(aStr);
  if lenStr = 0 then
    exit;
    
  m := Byte(aStr[0]);
  n := Byte(aStr[1]);
  i := 1;
  if m = 48 then
  begin
    if n > 97 then
      n := n - 32;
    m := 38;
    if (n = 66) or (n = 88) or (n = 79) then
    begin
      correct := 1;
      i := 2;
      if n = 66 then
      begin
        m := 37;
      end
      else
        if n = 88 then
          m := 36;
      n := Byte(aStr[2]);
    end;
  end;

  while n = 48 do
  begin
    if (lenStr - correct) = 1 then
    begin
      Result := True;
      exit;
    end;
    inc(i);
    inc(correct);
    n := Byte(aStr[i]);
  end;    

  n := n - 48;
  useParametr := @allHOBParametr[Size];
  if m = 38 then
  begin
    if (lenStr - correct) > useParametr^.maxLen8 then
      exit;
    if useParametr^.maxLen8 = (lenStr - correct) then
      if (Size = isByte) or (Size = isLongWord) then
      begin
        if n > 3 then
          exit;
      end
      else
        if n > 1 then
          exit;
    nshl := 3;
    z := 7;
  end
  else
    if m = 37 then
    begin
      if (lenStr - correct) > useParametr^.maxLen2 then
        exit;
      nshl := 1;
      z := 1;
    end;
  if m = 36 then
  begin
    if (lenStr - correct) > useParametr^.maxLen16 then
      exit;
    m := 0;
    while i <= lenStr - 1 do
    begin
      m := m shl 4;
      n := Byte(aStr[i]) - 48;
      if n > 55 then
        exit;
      n := dataHex[n];
      if n = 16 then
        exit;
      m := m + n; 
      inc(i);
    end;
  end
  else begin
    Pnshl := @nshl;
    m := n;
    if m > z then
      exit;
    inc(i);
    while i <= lenStr - 1 do
    begin
      m := m shl Pnshl^;
      n := Byte(aStr[i]) - 48;
      if n > z then
        exit;
      m := m + n;
      inc(i);
    end;
  end;
  Value := m;
  Result := true;
  {$pop}
end;

function geCharToInt(const aStr: array of char; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean;
var
  lenStr, i: maxUIntVal;
  m, n, z: maxUIntVal;
  useParametr: PgeUseParametr;
  IntMinus: Boolean = False;
  correct: maxUIntVal = 0;
label
  jmpEndStr;
begin
  {$push}
  {$Q-}{$R-}
  Result := False;
  Value := 0;
  if Size > maxSize then
    Exit;

  lenStr := Length(aStr);
  if lenStr = 0 then
    exit;

  m := Byte(aStr[0]);

  i := 1;
  if m = 45 then
  begin
    if lenStr = 1 then
      exit;
    IntMinus := True;
    m := Byte(aStr[i]);
    inc(i);
  end;

  while m = 48 do
  begin
    if (lenStr - correct) = 1 then
    begin
      Result := True;
      exit;
    end;
    m := Byte(aStr[i]);
    inc(i);
    inc(correct);
  end;

  m := m - 48;
  if m > 9 then
    exit;

  useParametr := @allIntParametr[Size];
  if i > lenStr - 1 then
  begin
    z := 0;
    goto jmpEndStr;
  end;
  
  if (lenStr - correct) > useParametr^.maxLen then
    Exit;
  while i < lenStr - 1 do
  begin
    n := (Byte(aStr[i]) - 48);
    if n > 9 then
      Exit;
    m := m * 10 + n;
    inc(i);
  end;

  if m > useParametr^.maxNumDiv10 then
    exit;
  m := m * 10;
  z := Byte(aStr[i]) - 48;
  if z > 9 then
    exit;

jmpEndStr:
  if IntMinus then
    n := useParametr^.maxNumeric + 1 - m
  else
    n := useParametr^.maxNumeric - m;
  if z > n then
    exit;

  if IntMinus then
    Value := - m - z
  else
    Value := m + z;
  Result := true;
  {$pop}
end;
{$EndIf}

{$IfDef USE_UNICODESTRING}
function geStrToInt(const Str: UnicodeString; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean; inline;
begin
  Result := geWCharToInt(Str[1..Length(Str)], Value, Size);
end;

function geStrToUInt(const Str: UnicodeString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
begin
  Result := geWCharToUInt(Str[1..Length(Str)], Value, Size);;
end;

function geHOBStrToUInt(const Str: UnicodeString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
begin
  Result := geHOBWCharToUInt(Str[1..Length(Str)], Value, Size);
end;

function sc_StrToShortInt(const Str: UnicodeString; out Value: ShortInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // byte
var
  n: maxIntVal;
begin
  Result := geWCharToInt(Str[1..Length(Str)], n, isShortInt);
  Value := n;
end;

function s_StrToShortInt(const Str: UnicodeString): ShortInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // byte
var
  n: maxIntVal;
begin
  geWCharToInt(Str[1..Length(Str)], n, isShortInt);
  Result := n;
end;
{$IfDef USE_CPU16}
function sc_StrToSmallInt(const Str: UnicodeString; out Value: SmallInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // word
var
  n: maxIntVal;
begin
  Result := geWCharToInt(Str[1..Length(Str)], n, isSmallInt);
  Value := n;
end;

function s_StrToSmallInt(const Str: UnicodeString): SmallInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // word
var
  n: maxIntVal;
begin
  geWCharToInt(Str[1..Length(Str)], n, isSmallInt);
  Result := n;
end;
{$EndIf}
{$IfDef USE_CPU32}
function sc_StrToInt(const Str: UnicodeString; out Value: Integer): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxIntVal;
begin
  Result := geWCharToInt(Str[1..Length(Str)], n, isInteger);
  Value := n;
end;

function s_StrToInt(const Str: UnicodeString): Integer; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxIntVal;
begin
  geWCharToInt(Str[1..Length(Str)], n, isInteger);
  Result := n;
end;
{$EndIf}
{$IfDef USE_CPU64}
function sc_StrToInt64(const Str: UnicodeString; out Value: Int64): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
begin
  Result := geWCharToInt(Str[1..Length(Str)], Value, isInt64);
end;

function s_StrToInt64(const Str: UnicodeString): Int64; {$IfDef ADD_FAST}inline;{$EndIf}
begin
  geWCharToInt(Str[1..Length(Str)], Result, isInt64);
end;
{$EndIf}

function sc_StrToByte(const Str: UnicodeString; out Value: Byte): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBWCharToUInt(Str[1..Length(Str)], n, isByte)
  else
    Result := geWCharToUInt(Str[1..Length(Str)], n, isByte);
  Value := n;
end;

function s_StrToByte(const Str: UnicodeString): Byte; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBWCharToUInt(Str[1..Length(Str)], n, isByte)
  else
    geWCharToUInt(Str[1..Length(Str)], n, isByte);
  Result := n;
end;
{$IfDef USE_CPU16}
function sc_StrToWord(const Str: UnicodeString; out Value: Word): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBWCharToUInt(Str[1..Length(Str)], n, isWord)
  else
    Result := geWCharToUInt(Str[1..Length(Str)], n, isWord);
  Value := n;
end;

function s_StrToWord(const Str: UnicodeString): Word; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBWCharToUInt(Str[1..Length(Str)], n, isWord)
  else
    geWCharToUInt(Str[1..Length(Str)], n, isWord);
  Result := n;
end;
{$EndIf}
{$IfDef USE_CPU32}
function sc_StrToLongWord(const Str: UnicodeString; out Value: LongWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBWCharToUInt(Str[1..Length(Str)], n, isLongWord)
  else
    Result := geWCharToUInt(Str[1..Length(Str)], n, isLongWord);
  Value := n;
end;

function s_StrToLongWord(const Str: UnicodeString): LongWord; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBWCharToUInt(Str[1..Length(Str)], n, isLongWord)
  else
    geWCharToUInt(Str[1..Length(Str)], n, isLongWord);
  Result := n;
end;
{$EndIf}
{$IfDef USE_CPU64}
function sc_StrToQWord(const Str: UnicodeString; out Value: QWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    Result := geHOBWCharToUInt(Str[1..Length(Str)], Value, isQWord)
  else
    Result := geWCharToUInt(Str[1..Length(Str)], Value, isQWord);
end;

function s_StrToQWord(const Str: UnicodeString): QWord; {$IfDef ADD_FAST}inline;{$EndIf}
var
  n: maxUIntVal;
begin
  n := Byte(Str[1]);
  if (n = 48) or ((n >= 36) and (n <= 38)) then
    geHOBWCharToUInt(Str[1..Length(Str)], Result, isQWord)
  else
    geWCharToUInt(Str[1..Length(Str)], Result, isQWord);
end;

{$EndIf}

function geWCharToUInt(const aStr: array of WideChar; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
var
  lenStr, i: maxUIntVal;
  m, n, z: maxUIntVal;
  useParametr: PgeUseParametr;
  correct: maxUIntVal = 0;
begin
  {$push}
  {$Q-}{$R-}
  Result := False;
  Value := 0;
  if Size > maxSize then
    Exit;
  lenStr := Length(aStr);
  if lenStr = 0 then
    exit;
  m := Word(aStr[0]);

  i := 0;

  while m = 48 do
  begin
    if (lenStr - correct) = 1 then
    begin
      Result := True;
      exit;
    end;
    m := Word(aStr[i]);
    inc(i);
    inc(correct);
  end;

  m := m - 48;
  if m > 9 then
    exit;
  if (lenStr - correct) = 1 then
  begin
    Value := m;
    Result := true;
    Exit;
  end;
  useParametr := @allUIntParametr[Size];
  if lenStr > useParametr^.maxLen then
    Exit;
  while i < lenStr - 1 do
  begin
    n := (Word(aStr[i]) - 48);
    if n > 9 then
      Exit;
    m := m * 10 + n;
    inc(i);
  end;
  if m > useParametr^.maxNumDiv10 then
    exit;
  m := m * 10;
  z := Word(aStr[i]) - 48;
  if z > 9 then
    exit;
  n := useParametr^.maxNumeric - m;
  if z > n then
    exit;
  Value := m + z;
  Result := true;
  {$pop}
end;

function geHOBWCharToUInt(const aStr: array of WideChar; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
var
  lenStr, i: maxUIntVal;
  m, n, nshl, z: maxUIntVal;
  Pnshl: PmaxUIntVal;
  correct: maxUIntVal = 0;
  useParametr: PgeHOBParameter;
begin
  {$push}
  {$Q-}{$R-}
  Result := False;
  Value := 0;
  if Size > maxSize then
    exit;
  lenStr := Length(aStr);
  if lenStr = 0 then
    exit;
    
  m := Word(aStr[0]);
  n := Word(aStr[1]);
  i := 1;
  if m = 48 then
  begin
    if lenStr = 1 then
    begin
      Result := True;
      exit;
    end;

    if n > 97 then
      n := n - 32;
    m := 38;
    if (n = 66) or (n = 88) or (n = 79) then
    begin
      correct := 1;
      i := 3;
      if n = 66 then
      begin
        m := 37;
      end
      else
        if n = 88 then
          m := 36;
      n := Word(aStr[2]);
    end;
  end;

  while n = 48 do
  begin
    if (lenStr - correct) = 1 then
    begin
      Result := True;
      exit;
    end;
    inc(i);
    inc(correct);
    n := Word(aStr[i]);
  end;

  n := n - 48;
  useParametr := @allHOBParametr[Size];
  if m = 38 then
  begin
    if (lenStr - correct) > useParametr^.maxLen8 then
      exit;
    if useParametr^.maxLen8 = (lenStr - correct) then
      if (Size = isByte) or (Size = isLongWord) then
      begin
        if n > 3 then
          exit;
      end
      else
        if n > 1 then
          exit;
    nshl := 3;
    z := 7;
  end
  else
    if m = 37 then
    begin
      if (lenStr - correct) > useParametr^.maxLen2 then
        exit;
      nshl := 1;
      z := 1;
    end;
  if m = 36 then
  begin
    if (lenStr - correct) > useParametr^.maxLen16 then
      exit;
    m := 0;
    while i <= lenStr do
    begin
      m := m shl 4;
      n := Word(aStr[i]) - 48;
      if n > 55 then
        exit;
      n := dataHex[n];
      if n = 16 then
        exit;
      m := m + n;
      inc(i);
    end;
  end
  else begin
    Pnshl := @nshl;
    m := n;
    if m > z then
      exit;
    inc(i);
    while i <= lenStr do
    begin
      m := m shl Pnshl^;
      n := Word(aStr[i]) - 48;
      if n > z then
        exit;
      m := m + n;
      inc(i);
    end;
  end;
  Value := m;
  Result := true;
  {$pop}
end;

function geWCharToInt(const aStr: array of WideChar; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean;
var
  lenStr, i: maxUIntVal;
  m, n, z: maxUIntVal;
  useParametr: PgeUseParametr;
  IntMinus: Boolean = False;
  correct: maxUIntVal = 0;
label
  jmpEndStr, loopZero;
begin
  {$push}
  {$Q-}{$R-}
  Result := False;
  Value := 0;
  if Size > maxSize then
    Exit;

  lenStr := Length(aStr);
  if lenStr = 0 then
    exit;
    
  m := Word(aStr[0]);
  if m > 57 then
    Exit;

  if (lenStr = 1) and (m = 48) then
  begin
    Result := True;
    exit;
  end;
  i := 1;
  if m = 45 then
  begin
    if lenStr = 1 then
      exit;
    IntMinus := True;
    m := Word(aStr[i]);                
    inc(i);
  end;

loopZero:
  if m = 48 then
  begin
    inc(i);
    inc(correct);
    m := Word(aStr[i]);
    goto loopZero;
  end;

  inc(i);
  m := m - 48;
  if m > 9 then
    exit;

  useParametr := @allIntParametr[Size];
  if i > lenStr - 1 then
  begin
    z := 0;
    goto jmpEndStr;
  end;
  if (lenStr - correct) > useParametr^.maxLen then
    Exit;
  while i < lenStr - 1 do              
  begin
    n := (Word(aStr[i]) - 48);         
    if n > 9 then
      Exit;
    m := m * 10 + n;
    inc(i);
  end;

  if m > useParametr^.maxNumDiv10 then
    exit;
  m := m * 10;
  z := Word(aStr[i]) - 48;           
  if z > 9 then
    exit;

jmpEndStr:
  if IntMinus then
    n := useParametr^.maxNumeric + 1 - m
  else
    n := useParametr^.maxNumeric - m;
  if z > n then
    exit;

  if IntMinus then
    Value := - m - z
  else
    Value := m + z;
  Result := true;
  {$pop}
end;
{$EndIf}

initialization

  SetNumberParametr;

end.
