You've already forked lazarus-ccr
reading unicode tags and filenames, show/hide app window with single click tray icon, create album cover if not exists, several fixes when there is just one song in collection, artist tree icons, handling of track numbers in n[/m] format, show path of current file (in playlist and title list), log output was corrupt due the use of crt unit, etc. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1761 8e941d3f-bd1b-0410-a28a-d453659cc2b4
468 lines
11 KiB
ObjectPascal
468 lines
11 KiB
ObjectPascal
|
|
{
|
|
|
|
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, 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;
|
|
writeln('utf16');
|
|
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);
|
|
writeln('------>');
|
|
writeln(DiskFree(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.
|