
{

  some helper functions/procedures

  written by Sebastian Kraft
  sebastian_kraft@gmx.de

  This software is free under the GNU Public License

  (c)2005-2008
}

Unit functions;

{$mode objfpc}{$H+}

Interface

Uses 
  Classes, SysUtils, math,
  debug, config;



//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function crc32(path: String): longint;

Function crc32_math(path: String): int64;

Function DirectoryIsEmpty(Directory: String): Boolean;

Function EraseDirectory(Directory: String): Boolean; //delete directory and all subdirectories/files in it

Function UTF8toLatin1(utfstring: ansistring): ansistring;

Function Latin1toUTF8(latin1string: ansistring): ansistring;

Function rmZeroChar(s: ansistring): ansistring;

Function FileCopy(Const FromFile, ToFile: String): boolean;

Function FreeSpaceOnDAP: int64;

Function ByteToFmtString(bytes: int64; d1, d2: byte): string;
// converts i.e. 1024 to 1,0 KB
// d1, d2 sets amount of digits before and after ','

Function SecondsToFmtStr(seconds: longint): string;//converts integer to mm:ss time format

Function MSecondsToFmtStr(MSeconds: longint): string;

function MakeValidFilename(Filename: String): string;

procedure BubbleSort(var Items: TStrings);

function IntTodB(i, ref: longint):integer;


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


Implementation

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function crc32(path: String): longint;
//creates an very, very basic checksum to identify files

Var fhandle: THandle;
  buf: array [0..63] Of word;
  z: byte;
  i, eofile: longint;
  l: longint;
Begin
 {$Q-}
  fhandle := sysutils.fileopen(path, fmOpenRead);
  l := 0;
  i := 0;
  z := 0;
  eofile := 0;
  While (eofile<>-1) And (i<256) Do
    Begin
      eofile := FileRead(fhandle, buf, sizeof(buf));
      If (eofile<>-1) Then For z:=0 To high(buf) Do begin
                            L := L+buf[z];
                        end;
      inc(i);
    End;
  FileClose(fhandle);
  result := l;
 {$Q+}
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function crc32_math(path: String): int64;
//creates an very, very basic checksum to identify files

Var fhandle: THandle;
  buf: array [0..63] Of int64;
  z: byte;
  i, eofile: longint;
  l: int64;
Begin
  fhandle := sysutils.fileopen(path, fmOpenRead);
  l := 0;
  i := 0;
  z := 0;
  eofile := 0;
  While (eofile<>-1) And (i<256) Do
    Begin
      eofile := FileRead(fhandle, buf, high(buf));
      l := l+sumInt(buf);
      inc(i);
    End;
  FileClose(fhandle);
  result := l;

End;


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function EraseDirectory(Directory: String): Boolean;

Var Srec: TSearchRec;
Begin
  result := false;
  If DirectoryExists(Directory)Then
    Begin
      Try
        FindFirst(IncludeTrailingPathDelimiter(Directory) + '*', faAnyFile, Srec);
        Repeat
          Begin
            If (Srec.Name <> '.') And (Srec.Name <> '..') Then
              DeleteFile(Directory+DirectorySeparator+Srec.Name);
          End;
        Until FindNext(Srec)<>0;
        FindClose(Srec);
        result := RemoveDir(Directory);
      Except
        result := false;
      End;
    End;

End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function UTF8toLatin1(utfstring: ansistring): ansistring;

Var i: integer;
  tmps: string;
  utf16: boolean;
Begin
  i := 0;
  tmps := '';
  utf16 := false;

  If length(utfstring)>0 Then
    Begin
      Repeat
        Begin
          inc(i);
          Case byte(utfstring[i]) Of 
            $ff: If byte(utfstring[i+1])=$fe Then utf16 := true;
            $c3:
                 Begin
                   Delete(utfstring, i, 1);
                   utfstring[i] := char(byte(utfstring[i])+64);
                 End;
            $c2:
                 Begin
                   Delete(utfstring, i, 1);
                   dec(i);
                 End;
          End;
        End;
      Until (i>=length(utfstring)-1) Or utf16;
      //if utf16 detected
      If utf16 Then
        Begin
          i := i+2;
          DebugOutLn('utf16',0);
          Repeat
            Begin
              inc(i);
              If byte(utfstring[i])<>0 Then tmps := tmps+utfstring[i];
            End;
          Until (i>=length(utfstring));
        End;
    End;

  If Not utf16 Then result := utfstring
  Else Result := tmps;
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function rmZeroChar(s: ansistring): ansistring;

Var i: integer;
Begin
  i := 0;
  If s<>'' Then
    Begin
      Repeat
        Begin
          inc(i);
          If byte(s[i])=0 Then
            Begin
              Delete(s, i, 1);
              dec(i);
            End;
        End;
      Until i>=length(s)-1;
    End;
  Result := s;
End;


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function Latin1toUTF8(latin1string: ansistring): ansistring;

Var i: integer;
  c: char;
  tmps: string;
  utf16: boolean;
Begin
  i := 0;
  utf16 := false;
  If length(latin1string)>0 Then
    Begin
      Repeat
        Begin
          inc(i);
          Case byte(latin1string[i]) Of 
            $ff: If byte(latin1string[i+1])=$fe Then utf16 := true;
            $00..$1f:
                      Begin
                        Delete(latin1string, i, 1);
                        dec(i);
                      End;
            $c0..$fd:
                      Begin
                        //c0..ff ist der gesamte wertebereich!!
                        If (byte(latin1string[i])=$c3) And (byte(latin1string[i+1])<$C0) Then inc(i)
                        Else
                          Begin
                            latin1string[i] := char(byte(latin1string[i])-64);
                            insert(char($c3), latin1string, i);
                            inc(i);
                          End;
                      End;

{     $a1..$bf:  begin
                        c:=latin1string[i];
                        insert(char($c2), latin1string, i);
//                        utfstring[i]:=char(byte(utfstring[i])+64);
                        inc(i);
                      end;}
          End;
        End;
      Until (i>=length(latin1string)-1) Or utf16;
      //if utf16 detected
      If utf16 Then
        Begin

//latin1string:=AnsiToUtf8(latin1string); may also work instead of following own utf16->utf8 routine
          inc(i);
          Repeat
            Begin
              inc(i);
              If byte(latin1string[i])>$1f Then
                If byte(latin1string[i])<$c0 Then
                  tmps := tmps+char(byte(latin1string[i]))
              Else
                tmps := tmps+char($c3)+char(byte(latin1string[i])-64);
            End;
          Until (i>=length(latin1string));
        End;
    End;
  If Not utf16 Then result := latin1string
  Else Result := tmps;
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

{   Function to copy a file FromFile -> ToFile    , mainly used while upload to player device}
Function FileCopy(Const FromFile, ToFile: String): boolean;

Var 
  FromF, ToF: file;
  NumRead, NumWritten: Word;
  Buf: array[1..4096] Of byte;
Begin
  Try
    AssignFile(FromF, FromFile);
    Reset(FromF, 1);              { Record size = 1 }
    AssignFile(ToF, ToFile);      { Open output file }
    Rewrite(ToF, 1);              { Record size = 1 }
    Repeat
      BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
      BlockWrite(ToF, Buf, NumRead, NumWritten);
    Until (NumRead = 0) Or (NumWritten <> NumRead);
    CloseFile(FromF);
    CloseFile(ToF);
    result := true;
  Except
    result := false;
  End;
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function FreeSpaceOnDAP: int64;

Var tmps: string;
Begin
  tmps := GetCurrentDir;
  // get free memory on player, format string
  SetCurrentDir(CactusConfig.DAPPath);
  result := DiskFree(0);
  DebugOutLn('------>',0);
  DebugOutLn(Format('DiskFree=%d',[DiskFree(0)]),0);
  SetCurrentDir(tmps);
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function ByteToFmtString(bytes: int64; d1, d2: byte): string;

Var r: real;
  count: byte;
  comma, prefix, s1, s2: string;
  subzero:boolean;
Begin
  count := 0;
  if bytes>=0 then subzero:=false else subzero:=true;
  
  r := abs(bytes);
  While (r>=power(10, d1)) Do
    Begin
      r := r / 1024;
      inc(count);
    End;

  Case count Of 
    0: prefix := 'Byte';
    1: prefix := 'KB';
    2: prefix := 'MB';
    3: prefix := 'GB';
    4: prefix := 'TB';
    5: prefix := 'PB';
  End;

  str(round (r*power(10, d2)) , s2);

  If r >= 1 Then
    Begin
      s1 := copy(s2, 0, length(s2)-d2);
      s2 := copy(s2, length(s2)-d2+1, d2);
    End
  Else s1 := '0';

  If d2<>0 Then comma := ','
  Else
    Begin
      comma := '';
      s2 := '';
    End;
  if subzero=false then result := s1+comma+s2+' '+prefix else result := '- ' + s1+comma+s2+' '+prefix
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function SecondsToFmtStr(seconds: longint): string;

Var min, sec: longint;
  s, s2: string;
Begin
if seconds>0 then begin
  min := seconds Div 60;
  sec := seconds Mod 60;
  str(min, s);
  str(sec, s2);
  If min<10 Then s := '0'+s;
  If sec<10 Then s2 := '0'+s2;
  result := s+':'+s2;
 end else Result:='00:00';
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function MSecondsToFmtStr(MSeconds: longint): string;
Begin
  if MSeconds>1000 then result := SecondsToFmtStr(MSeconds Div 1000)
        else Result:='00:00';
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function DirectoryIsEmpty(Directory: String): Boolean;

Var 
  SeR: TSearchRec;
  i: Integer;
Begin
  Result := False;
  FindFirst(IncludeTrailingPathDelimiter(Directory) + '*', faAnyFile, SeR);
  For i := 1 To 2 Do
    If (SeR.Name = '.') Or (SeR.Name = '..') Then
      Result := FindNext(SeR) <> 0;
  FindClose(SeR);
End;

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function MakeValidFilename(Filename: String): string;
var
  I: integer;
  { for long file names } // FIXME taken from code for win32 - list correct/complete??
  LongForbiddenChars  : set of Char = ['<', '>', '|', '"', '\', '/', ':', '*', '?'];
begin
  for I := 1 to Length(Filename) do
    if (Filename[I] in LongForbiddenChars) then
      Filename[I] := ' ';
  result := Filename;
end;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

procedure BubbleSort(var Items: TStrings);
var
  done: boolean;
  i, n: integer;
  Dummy: string;
begin
  n := Items.Count;

  repeat
    done := true;
    for i := 0 to n - 2 do
      if Items[i] > Items[i + 1] then
      begin
        Dummy := Items[i];
        Items[i] := Items[i + 1];
        Items[i + 1] := Dummy;

        done := false;
      end;
  until done;
end;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function IntTodB(i, ref: longint): integer;
var dB: Real;
begin
  if i=0 then db:=0.001 else dB:=i;
  dB:= 20*log10(dB/ref);
  result:=round(dB);
end;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

End.
