Ignore:
Timestamp:
Apr 3, 2025, 10:49:00 PM (2 weeks ago)
Author:
chronos
Message:
  • Modified: Updated Common package.
File:
1 moved

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/Packages/Common/Common.pas

    r20 r21  
    1 unit UCommon;
    2 
    3 {$mode delphi}
     1unit Common;
    42
    53interface
    64
    75uses
    8   {$ifdef Windows}Windows,{$endif}
    9   {$ifdef Linux}baseunix,{$endif}
    10   Classes, SysUtils, StrUtils, Dialogs, Process, LCLIntf,
    11   FileUtil; //, ShFolder, ShellAPI;
     6  {$IFDEF WINDOWS}Windows,{$ENDIF}
     7  {$IFDEF UNIX}baseunix,{$ENDIF}
     8  Classes, SysUtils, StrUtils, Dialogs, Process, LCLIntf, Graphics,
     9  FileUtil, Generics.Collections; //, ShFolder, ShellAPI;
    1210
    1311type
    1412  TArrayOfByte = array of Byte;
    15   TArrayOfString = array of string;
    1613  TExceptionEvent = procedure(Sender: TObject; E: Exception) of object;
    1714
     
    2825    unfDNSDomainName = 11);
    2926
     27  TFilterMethod = function (FileName: string): Boolean of object;
     28  TFileNameMethod = procedure (FileName: string) of object;
     29
    3030var
    3131  ExceptionHandler: TExceptionEvent;
    3232  DLLHandle1: HModule;
    3333
    34 {$IFDEF Windows}
    35   GetUserNameEx: procedure (NameFormat: DWORD;
    36     lpNameBuffer: LPSTR; nSize: PULONG); stdcall;
    37 {$ENDIF}
    38 
    39 function IntToBin(Data: Int64; Count: Byte): string;
     34  {$IFDEF WINDOWS}
     35    GetUserNameEx: procedure (NameFormat: DWORD;
     36      lpNameBuffer: LPSTR; nSize: PULONG); stdcall;
     37  {$ENDIF}
     38
     39const
     40  clLightBlue = TColor($FF8080);
     41  clLightGreen = TColor($80FF80);
     42  clLightRed = TColor($8080FF);
     43
     44function AddLeadingZeroes(const aNumber, Length : integer) : string;
    4045function BinToInt(BinStr: string): Int64;
    41 function TryHexToInt(Data: string; var Value: Integer): Boolean;
    42 function TryBinToInt(Data: string; var Value: Integer): Boolean;
    4346function BinToHexString(Source: AnsiString): string;
    4447//function DelTree(DirName : string): Boolean;
     
    4649function BCDToInt(Value: Byte): Byte;
    4750function CompareByteArray(Data1, Data2: TArrayOfByte): Boolean;
     51procedure CopyStringArray(Dest: TStringArray; Source: array of string);
     52function CombinePaths(Path1, Path2: string): string;
     53function ComputerName: string;
     54procedure DeleteFiles(APath, AFileSpec: string);
     55function EndsWith(Text, What: string): Boolean;
     56function Explode(Separator: Char; Data: string): TStringArray;
     57procedure ExecuteProgram(Executable: string; Parameters: array of string;
     58  Environment: array of string; CurrentDirectory: string = '');
     59procedure ExecuteProgramOutput(Executable: string; Parameters: array of string;
     60  Environment: array of string; out Output, Error: string;
     61  out ExitCode: Integer; CurrentDirectory: string = '');
     62procedure FileDialogUpdateFilterFileType(FileDialog: TOpenDialog);
     63procedure FreeThenNil(var Obj);
     64function GetDirCount(Dir: string): Integer;
    4865function GetUserName: string;
    49 function LoggedOnUserNameEx(Format: TUserNameFormat): string;
    50 function SplitString(var Text: string; Count: Word): string;
    5166function GetBitCount(Variable: QWord; MaxIndex: Integer): Integer;
    5267function GetBit(Variable: QWord; Index: Byte): Boolean;
     68function GetStringPart(var Text: string; Separator: string): string;
     69function GetEnvironmentVariables: TStringArray;
     70function GenerateNewName(OldName: string): string;
     71function GetFileFilterItemExt(Filter: string; Index: Integer): string;
     72function IntToBin(Data: Int64; Count: Byte): string;
     73function Implode(Separator: string; List: TList<string>): string; overload;
     74function Implode(Separator: string; List: array of string): string; overload;
     75function Implode(Separator: string; List: TStringList; Around: string = ''): string; overload;
     76function LastPos(const SubStr: String; const S: String): Integer;
     77function LoadFileToStr(const FileName: TFileName): AnsiString;
     78function LoggedOnUserNameEx(Format: TUserNameFormat): string;
     79function MergeArray(A, B: array of string): TStringArray;
     80function OccurenceOfChar(What: Char; Where: string): Integer;
     81procedure OpenWebPage(URL: string);
     82procedure OpenEmail(Email: string);
     83procedure OpenFileInShell(FileName: string);
     84function PosFromIndex(SubStr: string; Text: string;
     85  StartIndex: Integer): Integer;
     86function PosFromIndexReverse(SubStr: string; Text: string;
     87  StartIndex: Integer): Integer;
     88function RemoveQuotes(Text: string): string;
     89procedure SaveStringToFile(S, FileName: string);
    5390procedure SetBit(var Variable: Int64; Index: Byte; State: Boolean); overload;
    5491procedure SetBit(var Variable: QWord; Index: Byte; State: Boolean); overload;
    5592procedure SetBit(var Variable: Cardinal; Index: Byte; State: Boolean); overload;
    5693procedure SetBit(var Variable: Word; Index: Byte; State: Boolean); overload;
    57 function AddLeadingZeroes(const aNumber, Length : integer) : string;
    58 function LastPos(const SubStr: String; const S: String): Integer;
    59 function GenerateNewName(OldName: string): string;
    60 function GetFileFilterItemExt(Filter: string; Index: Integer): string;
    61 procedure FileDialogUpdateFilterFileType(FileDialog: TOpenDialog);
    62 procedure DeleteFiles(APath, AFileSpec: string);
    63 procedure OpenWebPage(URL: string);
    64 procedure OpenFileInShell(FileName: string);
    65 procedure ExecuteProgram(CommandLine: string);
    66 procedure FreeThenNil(var Obj);
    67 function RemoveQuotes(Text: string): string;
    68 function ComputerName: string;
    69 function OccurenceOfChar(What: Char; Where: string): Integer;
    70 function GetDirCount(Dir: string): Integer;
    71 function MergeArray(A, B: array of string): TArrayOfString;
    72 function LoadFileToStr(const FileName: TFileName): AnsiString;
     94procedure SearchFiles(AList: TStrings; Dir: string;
     95  FilterMethod: TFilterMethod = nil; FileNameMethod: TFileNameMethod = nil);
     96procedure SortStrings(Strings: TStrings);
     97function SplitString(var Text: string; Count: Word): string;
     98function StripTags(const S: string): string;
     99function StartsWith(Text, What: string): Boolean;
     100function TryHexToInt(Data: string; out Value: Integer): Boolean;
     101function TryBinToInt(Data: string; out Value: Integer): Boolean;
    73102
    74103
    75104implementation
    76105
    77 function BinToInt(BinStr : string) : Int64;
    78 var
    79   i : byte;
    80   RetVar : Int64;
     106resourcestring
     107  SExecutionError = 'Excution error: %s (exit code: %d)';
     108
     109function StartsWith(Text, What: string): Boolean;
     110begin
     111  Result := Copy(Text, 1, Length(Text)) = What;
     112end;
     113
     114function EndsWith(Text, What: string): Boolean;
     115begin
     116  Result := Copy(Text, Length(Text) - Length(What) + 1, MaxInt) = What;
     117end;
     118
     119function BinToInt(BinStr: string): Int64;
     120var
     121  I: Byte;
     122  RetVar: Int64;
    81123begin
    82124  BinStr := UpperCase(BinStr);
    83   if BinStr[length(BinStr)] = 'B' then Delete(BinStr,length(BinStr),1);
     125  if BinStr[length(BinStr)] = 'B' then Delete(BinStr, Length(BinStr), 1);
    84126  RetVar := 0;
    85   for i := 1 to length(BinStr) do begin
    86     if not (BinStr[i] in ['0','1']) then begin
     127  for I := 1 to Length(BinStr) do begin
     128    if not (BinStr[I] in ['0','1']) then begin
    87129      RetVar := 0;
    88130      Break;
    89131    end;
    90     RetVar := (RetVar shl 1) + (byte(BinStr[i]) and 1) ;
     132    RetVar := (RetVar shl 1) + (Byte(BinStr[I]) and 1);
    91133  end;
    92134
     
    98140  I: Integer;
    99141begin
     142  Result := '';
    100143  for I := 1 to Length(Source) do begin
    101144    Result := Result + LowerCase(IntToHex(Ord(Source[I]), 2));
    102145  end;
    103146end;
    104 
    105147
    106148procedure DeleteFiles(APath, AFileSpec: string);
     
    112154  Path := IncludeTrailingPathDelimiter(APath);
    113155
    114   Find := FindFirst(UTF8Decode(Path + AFileSpec), faAnyFile xor faDirectory, SearchRec);
     156  Find := FindFirst(Path + AFileSpec, faAnyFile xor faDirectory, SearchRec);
    115157  while Find = 0 do begin
    116     DeleteFile(Path + UTF8Encode(SearchRec.Name));
     158    DeleteFile(Path + SearchRec.Name);
    117159
    118160    Find := SysUtils.FindNext(SearchRec);
     
    120162  FindClose(SearchRec);
    121163end;
    122 
    123164
    124165function GetFileFilterItemExt(Filter: string; Index: Integer): string;
     
    143184  if FileExt <> '.*' then
    144185    FileDialog.FileName := ChangeFileExt(FileDialog.FileName, FileExt)
     186end;
     187
     188function GetEnvironmentVariables: TStringArray;
     189var
     190  I: Integer;
     191begin
     192  Result := Default(TStringArray);
     193  SetLength(Result, GetEnvironmentVariableCount);
     194  for I := 0 to GetEnvironmentVariableCount - 1 do
     195    Result[I] := GetEnvironmentString(I);
    145196end;
    146197
     
    185236end;*)
    186237
     238function Implode(Separator: string; List: array of string): string;
     239var
     240  I: Integer;
     241begin
     242  Result := '';
     243  for I := 0 to Length(List) - 1 do begin
     244    Result := Result + List[I];
     245    if I < Length(List) - 1 then Result := Result + Separator;
     246  end;
     247end;
     248
     249function Implode(Separator: string; List: TStringList; Around: string = ''): string;
     250var
     251  I: Integer;
     252begin
     253  Result := '';
     254  for I := 0 to List.Count - 1 do begin
     255    Result := Result + Around + List[I] + Around;
     256    if I < List.Count - 1 then Result := Result + Separator;
     257  end;
     258end;
     259
    187260function LastPos(const SubStr: String; const S: String): Integer;
    188261begin
     
    230303end;
    231304
    232 function TryHexToInt(Data: string; var Value: Integer): Boolean;
     305function TryHexToInt(Data: string; out Value: Integer): Boolean;
    233306var
    234307  I: Integer;
     
    246319end;
    247320
    248 function TryBinToInt(Data: string; var Value: Integer): Boolean;
     321function TryBinToInt(Data: string; out Value: Integer): Boolean;
    249322var
    250323  I: Integer;
     
    274347end;
    275348
    276 function Explode(Separator: char; Data: string): TArrayOfString;
    277 begin
    278   SetLength(Result, 0);
    279   while Pos(Separator, Data) > 0 do begin
     349function Explode(Separator: Char; Data: string): TStringArray;
     350var
     351  Index: Integer;
     352begin
     353  Result := Default(TStringArray);
     354  repeat
     355    Index := Pos(Separator, Data);
     356    if Index > 0 then begin
     357      SetLength(Result, Length(Result) + 1);
     358      Result[High(Result)] := Copy(Data, 1, Index - 1);
     359      Delete(Data, 1, Index);
     360    end else Break;
     361  until False;
     362  if Data <> '' then begin
    280363    SetLength(Result, Length(Result) + 1);
    281     Result[High(Result)] := Copy(Data, 1, Pos(Separator, Data) - 1);
    282     Delete(Data, 1, Pos(Separator, Data));
    283   end;
    284   SetLength(Result, Length(Result) + 1);
    285   Result[High(Result)] := Data;
    286 end;
    287 
    288 {$IFDEF Windows}
     364    Result[High(Result)] := Data;
     365  end;
     366end;
     367
     368function Implode(Separator: string; List: TList<string>): string;
     369var
     370  I: Integer;
     371begin
     372  Result := '';
     373  for I := 0 to List.Count - 1 do begin
     374    Result := Result + List[I];
     375    if I < List.Count - 1 then Result := Result + Separator;
     376  end;
     377end;
     378
     379{$IFDEF WINDOWS}
    289380function GetUserName: string;
    290381const
     
    294385begin
    295386  L := MAX_USERNAME_LENGTH + 2;
     387  Result := Default(string);
    296388  SetLength(Result, L);
    297389  if Windows.GetUserName(PChar(Result), L) and (L > 0) then begin
     
    307399  end;
    308400end;
    309 {$endif}
     401{$ENDIF}
    310402
    311403function ComputerName: string;
    312 {$ifdef mswindows}
     404{$IFDEF WINDOWS}
    313405const
    314406 INFO_BUFFER_SIZE = 32767;
     
    325417  end;
    326418end;
    327 {$endif}
    328 {$ifdef unix}
     419{$ENDIF}
     420{$IFDEF UNIX}
    329421var
    330422  Name: UtsName;
    331423begin
     424  Name := Default(UtsName);
    332425  fpuname(Name);
    333426  Result := Name.Nodename;
    334427end;
    335 {$endif}
    336 
    337 {$ifdef windows}
     428{$ENDIF}
     429
     430{$IFDEF WINDOWS}
    338431function LoggedOnUserNameEx(Format: TUserNameFormat): string;
    339432const
     
    413506procedure LoadLibraries;
    414507begin
    415   {$IFDEF Windows}
     508  {$IFDEF WINDOWS}
    416509  DLLHandle1 := LoadLibrary('secur32.dll');
    417510  if DLLHandle1 <> 0 then
     
    424517procedure FreeLibraries;
    425518begin
    426   {$IFDEF Windows}
     519  {$IFDEF WINDOWS}
    427520  if DLLHandle1 <> 0 then FreeLibrary(DLLHandle1);
    428521  {$ENDIF}
    429522end;
    430523
    431 procedure ExecuteProgram(CommandLine: string);
     524procedure ExecuteProgram(Executable: string; Parameters: array of string;
     525  Environment: array of string; CurrentDirectory: string = '');
    432526var
    433527  Process: TProcess;
    434 begin
     528  I: Integer;
     529begin
     530  Process := TProcess.Create(nil);
    435531  try
    436     Process := TProcess.Create(nil);
    437     Process.CommandLine := CommandLine;
     532    Process.Executable := Executable;
     533    for I := 0 to Length(Parameters) - 1 do
     534      Process.Parameters.Add(Parameters[I]);
     535    for I := 0 to Length(Environment) - 1 do
     536      Process.Environment.Add(Environment[I]);
     537    Process.CurrentDirectory := CurrentDirectory;
     538    Process.ShowWindow := swoHIDE;
    438539    Process.Options := [poNoConsole];
    439540    Process.Execute;
     
    443544end;
    444545
     546procedure ExecuteProgramOutput(Executable: string; Parameters: array of string;
     547  Environment: array of string; out Output, Error: string; out ExitCode: Integer;
     548  CurrentDirectory: string);
     549var
     550  Process: TProcess;
     551  I: Integer;
     552  ReadCount: Integer;
     553  Buffer: string;
     554const
     555  BufferSize = 1000;
     556begin
     557  Process := TProcess.Create(nil);
     558  try
     559    Process.Executable := Executable;
     560    for I := 0 to Length(Parameters) - 1 do
     561      Process.Parameters.Add(Parameters[I]);
     562    for I := 0 to Length(Environment) - 1 do
     563      Process.Environment.Add(Environment[I]);
     564    Process.CurrentDirectory := CurrentDirectory;
     565    Process.ShowWindow := swoHIDE;
     566    Process.Options := [poNoConsole, poUsePipes];
     567    Process.Execute;
     568
     569    Output := '';
     570    Error := '';
     571    Buffer := '';
     572    SetLength(Buffer, BufferSize);
     573    while Process.Running do begin
     574      if Process.Output.NumBytesAvailable > 0 then begin
     575        ReadCount := Process.Output.Read(Buffer[1], Length(Buffer));
     576        Output := Output + Copy(Buffer, 1, ReadCount);
     577      end;
     578
     579      if Process.Stderr.NumBytesAvailable > 0 then begin
     580        ReadCount := Process.Stderr.Read(Buffer[1], Length(Buffer));
     581        Error := Error + Copy(Buffer, 1, ReadCount)
     582      end;
     583
     584      Sleep(10);
     585    end;
     586
     587    if Process.Output.NumBytesAvailable > 0 then begin
     588      ReadCount := Process.Output.Read(Buffer[1], Length(Buffer));
     589      Output := Output + Copy(Buffer, 1, ReadCount);
     590    end;
     591
     592    if Process.Stderr.NumBytesAvailable > 0 then begin
     593      ReadCount := Process.Stderr.Read(Buffer[1], Length(Buffer));
     594      Error := Error + Copy(Buffer, 1, ReadCount);
     595    end;
     596
     597    ExitCode := Process.ExitCode;
     598
     599    if (ExitCode <> 0) or (Error <> '') then
     600      raise Exception.Create(Format(SExecutionError, [Output + Error, ExitCode]));
     601  finally
     602    Process.Free;
     603  end;
     604end;
     605
    445606procedure FreeThenNil(var Obj);
    446607begin
     
    454615end;
    455616
     617procedure OpenEmail(Email: string);
     618begin
     619  OpenURL('mailto:' + Email);
     620end;
     621
    456622procedure OpenFileInShell(FileName: string);
    457623begin
    458   ExecuteProgram('cmd.exe /c start "' + FileName + '"');
     624  ExecuteProgram('cmd.exe', ['/c', 'start', FileName], []);
    459625end;
    460626
     
    482648end;
    483649
    484 function MergeArray(A, B: array of string): TArrayOfString;
    485 var
    486   I: Integer;
    487 begin
     650function MergeArray(A, B: array of string): TStringArray;
     651var
     652  I: Integer;
     653begin
     654  Result := Default(TStringArray);
    488655  SetLength(Result, Length(A) + Length(B));
    489656  for I := 0 to Length(A) - 1 do
     
    511678end;
    512679
     680function DefaultSearchFilter(const FileName: string): Boolean;
     681begin
     682  Result := True;
     683end;
     684
     685procedure SaveStringToFile(S, FileName: string);
     686var
     687  F: TextFile;
     688begin
     689  AssignFile(F, FileName);
     690  try
     691    ReWrite(F);
     692    Write(F, S);
     693  finally
     694    CloseFile(F);
     695  end;
     696end;
     697
     698procedure SearchFiles(AList: TStrings; Dir: string;
     699  FilterMethod: TFilterMethod = nil; FileNameMethod: TFileNameMethod = nil);
     700var
     701  SR: TSearchRec;
     702begin
     703  Dir := IncludeTrailingPathDelimiter(Dir);
     704  if FindFirst(Dir + '*', faAnyFile, SR) = 0 then
     705    try
     706      repeat
     707        if (SR.Name = '.') or (SR.Name = '..') or (Assigned(FilterMethod) and (not FilterMethod(SR.Name) or
     708          not FilterMethod(Copy(Dir, 3, Length(Dir)) + SR.Name))) then Continue;
     709        if Assigned(FileNameMethod) then
     710          FileNameMethod(Dir + SR.Name);
     711        AList.Add(Dir + SR.Name);
     712        if (SR.Attr and faDirectory) <> 0 then
     713          SearchFiles(AList, Dir + SR.Name, FilterMethod);
     714      until FindNext(SR) <> 0;
     715    finally
     716      FindClose(SR);
     717    end;
     718end;
     719
     720function GetStringPart(var Text: string; Separator: string): string;
     721var
     722  P: Integer;
     723begin
     724  P := Pos(Separator, Text);
     725  if P > 0 then begin
     726    Result := Copy(Text, 1, P - 1);
     727    Delete(Text, 1, P - 1 + Length(Separator));
     728  end else begin
     729    Result := Text;
     730    Text := '';
     731  end;
     732  Result := Trim(Result);
     733  Text := Trim(Text);
     734end;
     735
     736function StripTags(const S: string): string;
     737var
     738  Len: Integer;
     739
     740  function ReadUntil(const ReadFrom: Integer; const C: Char): Integer;
     741  var
     742    J: Integer;
     743  begin
     744    for J := ReadFrom to Len do
     745      if (S[j] = C) then
     746      begin
     747        Result := J;
     748        Exit;
     749      end;
     750    Result := Len + 1;
     751  end;
     752
     753var
     754  I, APos: Integer;
     755begin
     756  Len := Length(S);
     757  I := 0;
     758  Result := '';
     759  while (I <= Len) do begin
     760    Inc(I);
     761    APos := ReadUntil(I, '<');
     762    Result := Result + Copy(S, I, APos - i);
     763    I := ReadUntil(APos + 1, '>');
     764  end;
     765end;
     766
     767function PosFromIndex(SubStr: string; Text: string;
     768  StartIndex: Integer): Integer;
     769var
     770  I, MaxLen: SizeInt;
     771  Ptr: PAnsiChar;
     772begin
     773  Result := 0;
     774  if (StartIndex < 1) or (StartIndex > Length(Text) - Length(SubStr)) then Exit;
     775  if Length(SubStr) > 0 then begin
     776    MaxLen := Length(Text) - Length(SubStr) + 1;
     777    I := StartIndex;
     778    Ptr := @Text[StartIndex];
     779    while (I <= MaxLen) do begin
     780      if (SubStr[1] = Ptr^) and (CompareByte(Substr[1], Ptr^, Length(SubStr)) = 0) then begin
     781        Result := I;
     782        Exit;
     783      end;
     784      Inc(I);
     785      Inc(Ptr);
     786    end;
     787  end;
     788end;
     789
     790function PosFromIndexReverse(SubStr: string; Text: string;
     791  StartIndex: Integer): Integer;
     792var
     793  I: SizeInt;
     794  Ptr: PAnsiChar;
     795begin
     796  Result := 0;
     797  if (StartIndex < 1) or (StartIndex > Length(Text)) then Exit;
     798  if Length(SubStr) > 0 then begin
     799    I := StartIndex;
     800    Ptr := @Text[StartIndex];
     801    while (I > 0) do begin
     802      if (SubStr[1] = Ptr^) and (CompareByte(Substr[1], Ptr^, Length(SubStr)) = 0) then begin
     803        Result := I;
     804        Exit;
     805      end;
     806      Dec(I);
     807      Dec(Ptr);
     808    end;
     809  end;
     810end;
     811
     812procedure CopyStringArray(Dest: TStringArray; Source: array of string);
     813var
     814  I: Integer;
     815begin
     816  SetLength(Dest, Length(Source));
     817  for I := 0 to Length(Dest) - 1 do
     818    Dest[I] := Source[I];
     819end;
     820
     821function CombinePaths(Path1, Path2: string): string;
     822begin
     823  Result := Path1;
     824  if Result <> '' then Result := Result + DirectorySeparator + Path2
     825    else Result := Path2;
     826end;
     827
     828procedure SortStrings(Strings: TStrings);
     829var
     830  Tmp: TStringList;
     831begin
     832  Strings.BeginUpdate;
     833  try
     834    if Strings is TStringList then begin
     835      TStringList(Strings).Sort;
     836    end else begin
     837      Tmp := TStringList.Create;
     838      try
     839        Tmp.Assign(Strings);
     840        Tmp.Sort;
     841        Strings.Assign(Tmp);
     842      finally
     843        Tmp.Free;
     844      end;
     845    end;
     846  finally
     847    Strings.EndUpdate;
     848  end;
     849end;
    513850
    514851
Note: See TracChangeset for help on using the changeset viewer.