aboutsummaryrefslogtreecommitdiffstats
path: root/unicode/src/base
diff options
context:
space:
mode:
authortobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2009-07-23 18:09:11 +0000
committertobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2009-07-23 18:09:11 +0000
commit21c1082f916cc9a4d7be625c132e02b1fc1d8012 (patch)
treecf3c705058db9839ba80cebfaf0fe69086fa38f2 /unicode/src/base
parent446eec893b7915d80a4504d40bbfc6f77cafa550 (diff)
downloadusdx-21c1082f916cc9a4d7be625c132e02b1fc1d8012.tar.gz
usdx-21c1082f916cc9a4d7be625c132e02b1fc1d8012.tar.xz
usdx-21c1082f916cc9a4d7be625c132e02b1fc1d8012.zip
- IPath integration
- BASS is now unicode compatible git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@1875 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'unicode/src/base')
-rw-r--r--unicode/src/base/TextGL.pas22
-rw-r--r--unicode/src/base/UCatCovers.pas114
-rw-r--r--unicode/src/base/UCommandLine.pas25
-rw-r--r--unicode/src/base/UCommon.pas82
-rw-r--r--unicode/src/base/UConfig.pas8
-rw-r--r--unicode/src/base/UCovers.pas51
-rw-r--r--unicode/src/base/UDLLManager.pas57
-rw-r--r--unicode/src/base/UDataBase.pas23
-rw-r--r--unicode/src/base/UFilename.pas464
-rw-r--r--unicode/src/base/UFiles.pas142
-rw-r--r--unicode/src/base/UFilesystem.pas2
-rw-r--r--unicode/src/base/UFont.pas47
-rw-r--r--unicode/src/base/UGraphic.pas22
-rw-r--r--unicode/src/base/UImage.pas63
-rw-r--r--unicode/src/base/UIni.pas179
-rw-r--r--unicode/src/base/ULanguage.pas31
-rw-r--r--unicode/src/base/ULog.pas22
-rw-r--r--unicode/src/base/UMain.pas8
-rw-r--r--unicode/src/base/UMusic.pas53
-rw-r--r--unicode/src/base/UPath.pas260
-rw-r--r--unicode/src/base/UPathUtils.pas120
-rw-r--r--unicode/src/base/UPlatform.pas95
-rw-r--r--unicode/src/base/UPlatformLinux.pas98
-rw-r--r--unicode/src/base/UPlatformMacOSX.pas92
-rw-r--r--unicode/src/base/UPlatformWindows.pas125
-rw-r--r--unicode/src/base/UPlaylist.pas250
-rw-r--r--unicode/src/base/USkins.pas77
-rw-r--r--unicode/src/base/USong.pas291
-rw-r--r--unicode/src/base/USongs.pas68
-rw-r--r--unicode/src/base/UTextEncoding.pas474
-rw-r--r--unicode/src/base/UTexture.pas45
-rw-r--r--unicode/src/base/UThemes.pas41
-rw-r--r--unicode/src/base/UUnicodeUtils.pas10
-rw-r--r--unicode/src/base/UXMLSong.pas86
34 files changed, 1517 insertions, 2030 deletions
diff --git a/unicode/src/base/TextGL.pas b/unicode/src/base/TextGL.pas
index 65d716c2..7fe98d29 100644
--- a/unicode/src/base/TextGL.pas
+++ b/unicode/src/base/TextGL.pas
@@ -37,9 +37,10 @@ uses
gl,
glext,
SDL,
+ Classes,
UTexture,
UFont,
- Classes,
+ UPath,
ULog;
type
@@ -75,26 +76,26 @@ uses
UMain,
UPathUtils;
-function FindFontFile(FontIni: TCustomIniFile; Font: string): string;
+function FindFontFile(FontIni: TCustomIniFile; Font: string): IPath;
var
- Filename: string;
+ Filename: IPath;
begin
- Filename := FontIni.ReadString(Font, 'File', '');
- Result := FontPath + Filename;
+ Filename := Path(FontIni.ReadString(Font, 'File', ''));
+ Result := FontPath.Append(Filename);
// if path does not exist, try as an absolute path
- if (not FileExists(Result)) then
+ if (not Result.IsFile) then
Result := Filename;
end;
procedure BuildFont;
var
FontIni: TMemIniFile;
- FontFile: string;
+ FontFile: IPath;
begin
ActFont := 0;
SetLength(Fonts, 4);
- FontIni := TMemIniFile.Create(FontPath + 'fonts.ini');
+ FontIni := TMemIniFile.Create(FontPath.Append('fonts.ini').ToNative);
try
@@ -117,8 +118,9 @@ begin
FontFile := FindFontFile(FontIni, 'Outline2');
Fonts[3].Font := TFTScalableOutlineFont.Create(FontFile, 64, 0.08);
- except on E: Exception do
- Log.LogCritical(E.Message, 'BuildFont');
+ except
+ on E: Exception do
+ Log.LogCritical(E.Message, 'BuildFont');
end;
// close ini-file
diff --git a/unicode/src/base/UCatCovers.pas b/unicode/src/base/UCatCovers.pas
index 86f675c5..6e004b22 100644
--- a/unicode/src/base/UCatCovers.pas
+++ b/unicode/src/base/UCatCovers.pas
@@ -38,20 +38,21 @@ interface
{$I switches.inc}
uses
- UIni;
+ UIni,
+ UPath;
type
TCatCovers = class
protected
- cNames: array [0..high(ISorting)] of array of string;
- cFiles: array [0..high(ISorting)] of array of string;
+ cNames: array [0..high(ISorting)] of array of UTF8String;
+ cFiles: array [0..high(ISorting)] of array of IPath;
public
constructor Create;
procedure Load; //Load Cover aus Cover.ini and Cover Folder
- procedure LoadPath(const CoversPath: string);
- procedure Add(Sorting: integer; Name, Filename: string); //Add a Cover
- function CoverExists(Sorting: integer; Name: string): boolean; //Returns True when a cover with the given Name exists
- function GetCover(Sorting: integer; Name: string): string; //Returns the Filename of a Cover
+ procedure LoadPath(const CoversPath: IPath);
+ procedure Add(Sorting: integer; const Name: UTF8String; const Filename: IPath); //Add a Cover
+ function CoverExists(Sorting: integer; const Name: UTF8String): boolean; //Returns True when a cover with the given Name exists
+ function GetCover(Sorting: integer; const Name: UTF8String): IPath; //Returns the Filename of a Cover
end;
var
@@ -63,9 +64,10 @@ uses
IniFiles,
SysUtils,
Classes,
- // UFiles,
+ UFilesystem,
ULog,
UMain,
+ UUnicodeUtils,
UPathUtils;
constructor TCatCovers.Create;
@@ -79,25 +81,28 @@ var
I: integer;
begin
for I := 0 to CoverPaths.Count-1 do
- LoadPath(CoverPaths[I]);
+ LoadPath(CoverPaths[I] as IPath);
end;
(**
* Load Cover from Cover.ini and Cover Folder
*)
-procedure TCatCovers.LoadPath(const CoversPath: string);
+procedure TCatCovers.LoadPath(const CoversPath: IPath);
var
Ini: TMemIniFile;
- SR: TSearchRec;
List: TStringlist;
I, J: Integer;
- Name, Filename, Temp: string;
+ Filename: IPath;
+ Name, TmpName: UTF8String;
+ CatCover: IPath;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
begin
Ini := nil;
List := nil;
try
- Ini := TMemIniFile.Create(CoversPath + 'covers.ini');
+ Ini := TMemIniFile.Create(CoversPath.Append('covers.ini').ToNative);
List := TStringlist.Create;
//Add every Cover in Covers Ini for Every Sorting option
@@ -106,63 +111,65 @@ begin
Ini.ReadSection(ISorting[I], List);
for J := 0 to List.Count - 1 do
- Add(I, List.Strings[J], CoversPath + Ini.ReadString(ISorting[I], List.Strings[J], 'NoCover.jpg'));
+ begin
+ CatCover := Path(Ini.ReadString(ISorting[I], List.Strings[J], 'NoCover.jpg'));
+ Add(I, List.Strings[J], CoversPath.Append(CatCover));
+ end;
end;
finally
Ini.Free;
List.Free;
end;
- try
- //Add Covers from Folder
- if (FindFirst (CoversPath + '*.jpg', faAnyFile, SR) = 0) then
- repeat
- //Add Cover if it doesn't exist for every Section
- Name := SR.Name;
- Filename := CoversPath + Name;
- Delete (Name, length(Name) - 3, 4);
-
- for I := 0 to high(ISorting) do
- begin
- Temp := Name;
- if ((I = sTitle) or (I = sTitle2)) and (Pos ('Title', Temp) <> 0) then
- Delete (Temp, Pos ('Title', Temp), 5)
- else if (I = sArtist) or (I = sArtist2) and (Pos ('Artist', Temp) <> 0) then
- Delete (Temp, Pos ('Artist', Temp), 6);
-
- if not CoverExists(I, Temp) then
- Add (I, Temp, Filename);
- end;
- until FindNext (SR) <> 0;
- finally
- FindClose (SR);
+ //Add Covers from Folder
+ Iter := FileSystem.FileFind(CoversPath.Append('*.jpg'), 0);
+ while Iter.HasNext do
+ begin
+ FileInfo := Iter.Next;
+
+ //Add Cover if it doesn't exist for every Section
+ Filename := CoversPath.Append(FileInfo.Name);
+ Name := FileInfo.Name.SetExtension('').ToUTF8;
+
+ for I := 0 to high(ISorting) do
+ begin
+ TmpName := Name;
+ if ((I = sTitle) or (I = sTitle2)) and (UTF8Pos('Title', TmpName) <> 0) then
+ UTF8Delete(TmpName, UTF8Pos('Title', TmpName), 5)
+ else if (I = sArtist) or (I = sArtist2) and (UTF8Pos('Artist', TmpName) <> 0) then
+ UTF8Delete(TmpName, UTF8Pos('Artist', TmpName), 6);
+
+ if not CoverExists(I, TmpName) then
+ Add(I, TmpName, Filename);
+ end;
end;
end;
//Add a Cover
-procedure TCatCovers.Add(Sorting: integer; Name, Filename: string);
+procedure TCatCovers.Add(Sorting: integer; const Name: UTF8String; const Filename: IPath);
begin
- if FileExists (Filename) then //If Exists -> Add
+ if Filename.IsFile then //If Exists -> Add
begin
- SetLength (CNames[Sorting], Length(CNames[Sorting]) + 1);
- SetLength (CFiles[Sorting], Length(CNames[Sorting]) + 1);
+ SetLength(CNames[Sorting], Length(CNames[Sorting]) + 1);
+ SetLength(CFiles[Sorting], Length(CNames[Sorting]) + 1);
- CNames[Sorting][high(cNames[Sorting])] := Uppercase(Name);
+ CNames[Sorting][high(cNames[Sorting])] := UTF8Uppercase(Name);
CFiles[Sorting][high(cNames[Sorting])] := FileName;
end;
end;
//Returns True when a cover with the given Name exists
-function TCatCovers.CoverExists(Sorting: integer; Name: string): boolean;
+function TCatCovers.CoverExists(Sorting: integer; const Name: UTF8String): boolean;
var
I: Integer;
+ UpperName: UTF8String;
begin
Result := False;
- Name := Uppercase(Name); //Case Insensitiv
+ UpperName := UTF8Uppercase(Name); //Case Insensitiv
for I := 0 to high(cNames[Sorting]) do
begin
- if (cNames[Sorting][I] = Name) then //Found Name
+ if (cNames[Sorting][I] = UpperName) then //Found Name
begin
Result := true;
break; //Break For Loop
@@ -171,16 +178,18 @@ begin
end;
//Returns the Filename of a Cover
-function TCatCovers.GetCover(Sorting: integer; Name: string): string;
+function TCatCovers.GetCover(Sorting: integer; const Name: UTF8String): IPath;
var
I: Integer;
+ UpperName: UTF8String;
+ NoCoverPath: IPath;
begin
- Result := '';
- Name := Uppercase(Name);
+ Result := PATH_NONE;
+ UpperName := UTF8Uppercase(Name);
for I := 0 to high(cNames[Sorting]) do
begin
- if cNames[Sorting][I] = Name then
+ if cNames[Sorting][I] = UpperName then
begin
Result := cFiles[Sorting][I];
Break;
@@ -188,13 +197,14 @@ begin
end;
//No Cover
- if (Result = '') then
+ if (Result.IsUnset) then
begin
for I := 0 to CoverPaths.Count-1 do
begin
- if (FileExists(CoverPaths[I] + 'NoCover.jpg')) then
+ NoCoverPath := (CoverPaths[I] as IPath).Append('NoCover.jpg');
+ if (NoCoverPath.IsFile) then
begin
- Result := CoverPaths[I] + 'NoCover.jpg';
+ Result := NoCoverPath;
Break;
end;
end;
diff --git a/unicode/src/base/UCommandLine.pas b/unicode/src/base/UCommandLine.pas
index 281a480d..ac0db2c2 100644
--- a/unicode/src/base/UCommandLine.pas
+++ b/unicode/src/base/UCommandLine.pas
@@ -33,6 +33,9 @@ interface
{$I switches.inc}
+uses
+ UPath;
+
type
TScreenMode = (scmDefault, scmFullscreen, scmWindowed);
@@ -64,9 +67,9 @@ type
Screens: integer;
// some strings set when reading infos {Length=0: Not Set}
- SongPath: string;
- ConfigFile: string;
- ScoreFile: string;
+ SongPath: IPath;
+ ConfigFile: IPath;
+ ScoreFile: IPath;
// pseudo integer values
property Language: integer read GetLanguage;
@@ -144,9 +147,9 @@ begin
Screens := -1;
// some strings set when reading infos {Length=0 Not Set}
- SongPath := '';
- ConfigFile := '';
- ScoreFile := '';
+ SongPath := PATH_NONE;
+ ConfigFile := PATH_NONE;
+ ScoreFile := PATH_NONE;
end;
{**
@@ -248,7 +251,7 @@ begin
if (PCount > I) then
begin
// write value to string
- SongPath := ParamStr(I + 1);
+ SongPath := Path(ParamStr(I + 1));
end;
end
@@ -258,11 +261,11 @@ begin
if (PCount > I) then
begin
// write value to string
- ConfigFile := ParamStr(I + 1);
+ ConfigFile := Path(ParamStr(I + 1));
// is this a relative path -> then add gamepath
- if Not ((Length(ConfigFile) > 2) AND (ConfigFile[2] = ':')) then
- ConfigFile := ExtractFilePath(ParamStr(0)) + Configfile;
+ if (not ConfigFile.IsAbsolute) then
+ ConfigFile := Platform.GetExecutionDir().Append(ConfigFile);
end;
end
@@ -272,7 +275,7 @@ begin
if (PCount > I) then
begin
// write value to string
- ScoreFile := ParamStr(I + 1);
+ ScoreFile := Path(ParamStr(I + 1));
end;
end;
diff --git a/unicode/src/base/UCommon.pas b/unicode/src/base/UCommon.pas
index d7c36196..c0a98815 100644
--- a/unicode/src/base/UCommon.pas
+++ b/unicode/src/base/UCommon.pas
@@ -41,7 +41,8 @@ uses
{$ENDIF}
sdl,
UConfig,
- ULog;
+ ULog,
+ UPath;
type
TMessageType = (mtInfo, mtError);
@@ -65,8 +66,16 @@ procedure RestoreNumericLocale();
function MakeLong(a, b: word): longint;
{$ENDIF}
-function AdaptFilePaths(const aPath: widestring): widestring;
-function FileExistsInsensitive(var FileName: string): boolean;
+type
+ TDirectoryEntry = record
+ Name: IPath;
+ IsDirectory: boolean;
+ IsFile: boolean;
+ end;
+
+ TDirectoryEntryArray = array of TDirectoryEntry;
+
+function DirectoryFindFiles(Dir: IPath; Filter: UTF8String; ReturnAllSubDirs: boolean): TDirectoryEntryArray;
// A stable alternative to TList.Sort() (use TList.Sort() if applicable, see below)
procedure MergeSort(List: TList; CompareFunc: TListSortCompare);
@@ -82,6 +91,7 @@ uses
{$IFDEF Delphi}
Dialogs,
{$ENDIF}
+ UFilesystem,
UMain,
UUnicodeUtils;
@@ -206,12 +216,6 @@ begin
exOverflow, exUnderflow, exPrecision]);
end;
-function AdaptFilePaths(const aPath: WideString): WideString;
-begin
- result := StringReplaceW(aPath, '\', PathDelim);//, [rfReplaceAll]);
-end;
-
-
{$IFNDEF MSWINDOWS}
procedure ZeroMemory(Destination: pointer; Length: dword);
begin
@@ -225,42 +229,44 @@ end;
{$ENDIF}
-{ TODO: REMOVE }
-// Checks if a regular files or directory with the given name exists.
-// The comparison is case insensitive.
-function FileExistsInsensitive(var FileName: string): boolean;
+function DirectoryFindFiles(Dir: IPath; Filter: UTF8String; ReturnAllSubDirs: Boolean): TDirectoryEntryArray;
var
- FilePath, LocalFileName: string;
- SearchInfo: TSearchRec;
+ i: integer;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
+ FileName: IPath;
+ Attrib: integer;
begin
-{$IF Defined(Linux) or Defined(FreeBSD)}
- // speed up standard case
- if FileExists(FileName) then
- begin
- Result := true;
- exit;
- end;
+ i := 0;
+ Filter := UTF8LowerCase(Filter);
- Result := false;
-
- FilePath := ExtractFilePath(FileName);
- if (FindFirst(FilePath + '*', faAnyFile, SearchInfo) = 0) then
+ // search for all files and directories
+ Iter := FileSystem.FileFind(Dir.Append('*'), faAnyFile);
+ while (Iter.HasNext) do
begin
- LocalFileName := ExtractFileName(FileName);
- repeat
- if (AnsiSameText(LocalFileName, SearchInfo.Name)) then
+ FileInfo := Iter.Next;
+ FileName := FileInfo.Name;
+ if (not FileName.Equals('.')) and (not FileName.Equals('..')) then
+ begin
+ Attrib := Dir.Append(FileName).GetAttr();
+ if ReturnAllSubDirs and ((Attrib and faDirectory) <> 0) then
begin
- FileName := FilePath + SearchInfo.Name;
- Result := true;
- break;
+ SetLength(Result, i + 1);
+ Result[i].Name := FileName;
+ Result[i].IsDirectory := true;
+ Result[i].IsFile := false;
+ i := i + 1;
+ end
+ else if (Filter = '') or (Pos(Filter, LowerCase(FileName.ToUTF8)) > 0) then
+ begin
+ SetLength(Result, i + 1);
+ Result[i].Name := FileName;
+ Result[i].IsDirectory := false;
+ Result[i].IsFile := true;
+ i := i + 1;
end;
- until (FindNext(SearchInfo) <> 0);
+ end;
end;
- FindClose(SearchInfo);
-{$ELSE}
- // Windows and Mac OS X do not have case sensitive file systems
- Result := FileExists(FileName);
-{$IFEND}
end;
// +++++++++++++++++++++ helpers for RWOpsFromStream() +++++++++++++++
diff --git a/unicode/src/base/UConfig.pas b/unicode/src/base/UConfig.pas
index 1214f36f..f6dc69a5 100644
--- a/unicode/src/base/UConfig.pas
+++ b/unicode/src/base/UConfig.pas
@@ -90,7 +90,7 @@ interface
{$I switches.inc}
uses
- Sysutils;
+ SysUtils;
const
// IMPORTANT:
@@ -156,6 +156,12 @@ const
(FPC_RELEASE * VERSION_MINOR) +
(FPC_PATCH * VERSION_RELEASE);
+ // FPC 2.2.0 unicode support is very buggy. The cwstring unit for example
+ // always crashes whenever UTF8ToAnsi() is called on a non UTF8 encoded string
+ // what is fixed in 2.2.2.
+ {$IF Defined(FPC) and (FPC_VERSION_INT < 2002002)} // < 2.2.2
+ {$MESSAGE FATAL 'FPC >= 2.2.2 required!'}
+ {$IFEND}
{$IFDEF HaveFFmpeg}
diff --git a/unicode/src/base/UCovers.pas b/unicode/src/base/UCovers.pas
index 8e7934b2..0dbe672a 100644
--- a/unicode/src/base/UCovers.pas
+++ b/unicode/src/base/UCovers.pas
@@ -50,7 +50,8 @@ uses
SysUtils,
Classes,
UImage,
- UTexture;
+ UTexture,
+ UPath;
type
ECoverDBException = class(Exception)
@@ -59,9 +60,9 @@ type
TCover = class
private
ID: int64;
- Filename: WideString;
+ Filename: IPath;
public
- constructor Create(ID: int64; Filename: WideString);
+ constructor Create(ID: int64; Filename: IPath);
function GetPreviewTexture(): TTexture;
function GetTexture(): TTexture;
end;
@@ -76,19 +77,19 @@ type
private
DB: TSQLiteDatabase;
procedure InitCoverDatabase();
- function CreateThumbnail(const Filename: WideString; var Info: TThumbnailInfo): PSDL_Surface;
+ function CreateThumbnail(const Filename: IPath; var Info: TThumbnailInfo): PSDL_Surface;
function LoadCover(CoverID: int64): TTexture;
procedure DeleteCover(CoverID: int64);
- function FindCoverIntern(const Filename: WideString): int64;
+ function FindCoverIntern(const Filename: IPath): int64;
procedure Open();
function GetVersion(): integer;
procedure SetVersion(Version: integer);
public
constructor Create();
destructor Destroy; override;
- function AddCover(const Filename: WideString): TCover;
- function FindCover(const Filename: WideString): TCover;
- function CoverExists(const Filename: WideString): boolean;
+ function AddCover(const Filename: IPath): TCover;
+ function FindCover(const Filename: IPath): TCover;
+ function CoverExists(const Filename: IPath): boolean;
function GetMaxCoverSize(): integer;
procedure SetMaxCoverSize(Size: integer);
end;
@@ -141,7 +142,7 @@ end;
{ TCover }
-constructor TCover.Create(ID: int64; Filename: WideString);
+constructor TCover.Create(ID: int64; Filename: IPath);
begin
Self.ID := ID;
Self.Filename := Filename;
@@ -210,11 +211,11 @@ end;
procedure TCoverDatabase.Open();
var
Version: integer;
- Filename: UTF8String;
+ Filename: IPath;
begin
- Filename := Platform.GetGameUserPath() + COVERDB_FILENAME;
+ Filename := Platform.GetGameUserPath().Append(COVERDB_FILENAME);
- DB := TSQLiteDatabase.Create(Filename);
+ DB := TSQLiteDatabase.Create(Filename.ToUTF8());
Version := GetVersion();
// check version, if version is too old/new, delete database file
@@ -223,10 +224,10 @@ begin
Log.LogInfo('Outdated cover-database file found', 'TCoverDatabase.Open');
// close and delete outdated file
DB.Free;
- if (not DeleteFile(Filename)) then
- raise ECoverDBException.Create('Could not delete ' + Filename);
+ if (not Filename.DeleteFile()) then
+ raise ECoverDBException.Create('Could not delete ' + Filename.ToNative);
// reopen
- DB := TSQLiteDatabase.Create(Filename);
+ DB := TSQLiteDatabase.Create(Filename.ToUTF8());
Version := 0;
end;
@@ -266,14 +267,14 @@ begin
')');
end;
-function TCoverDatabase.FindCoverIntern(const Filename: WideString): int64;
+function TCoverDatabase.FindCoverIntern(const Filename: IPath): int64;
begin
Result := DB.GetTableValue('SELECT [ID] FROM ['+COVER_TBL+'] ' +
'WHERE [Filename] = ?',
- [UTF8Encode(Filename)]);
+ [Filename.ToUTF8]);
end;
-function TCoverDatabase.FindCover(const Filename: WideString): TCover;
+function TCoverDatabase.FindCover(const Filename: IPath): TCover;
var
CoverID: int64;
begin
@@ -287,7 +288,7 @@ begin
end;
end;
-function TCoverDatabase.CoverExists(const Filename: WideString): boolean;
+function TCoverDatabase.CoverExists(const Filename: IPath): boolean;
begin
Result := false;
try
@@ -297,7 +298,7 @@ begin
end;
end;
-function TCoverDatabase.AddCover(const Filename: WideString): TCover;
+function TCoverDatabase.AddCover(const Filename: IPath): TCover;
var
CoverID: int64;
Thumbnail: PSDL_Surface;
@@ -329,7 +330,7 @@ begin
DB.ExecSQL('INSERT INTO ['+COVER_TBL+'] ' +
'([Filename], [Date], [Width], [Height]) VALUES' +
'(?, ?, ?, ?)',
- [UTF8Encode(Filename), DateTimeToUnixTime(FileDate),
+ [Filename.ToUTF8, DateTimeToUnixTime(FileDate),
Info.CoverWidth, Info.CoverHeight]);
// get auto-generated cover ID
@@ -358,7 +359,7 @@ var
PixelFmt: TImagePixelFmt;
Data: PChar;
DataSize: integer;
- Filename: WideString;
+ Filename: IPath;
Table: TSQLiteUniTable;
begin
Table := nil;
@@ -371,7 +372,7 @@ begin
'USING(ID) ' +
'WHERE [ID] = %d', [CoverID]));
- Filename := UTF8Decode(Table.FieldAsString(0));
+ Filename := Path(Table.FieldAsString(0));
PixelFmt := TImagePixelFmt(Table.FieldAsInteger(1));
Width := Table.FieldAsInteger(2);
Height := Table.FieldAsInteger(3);
@@ -403,7 +404,7 @@ end;
* Returns a pointer to an array of bytes containing the texture data in the
* requested size
*)
-function TCoverDatabase.CreateThumbnail(const Filename: WideString; var Info: TThumbnailInfo): PSDL_Surface;
+function TCoverDatabase.CreateThumbnail(const Filename: IPath; var Info: TThumbnailInfo): PSDL_Surface;
var
//TargetAspect, SourceAspect: double;
//TargetWidth, TargetHeight: integer;
@@ -417,7 +418,7 @@ begin
Thumbnail := LoadImage(Filename);
if (not assigned(Thumbnail)) then
begin
- Log.LogError('Could not load cover: "'+ Filename +'"', 'TCoverDatabase.AddCover');
+ Log.LogError('Could not load cover: "'+ Filename.ToNative +'"', 'TCoverDatabase.AddCover');
Exit;
end;
diff --git a/unicode/src/base/UDLLManager.pas b/unicode/src/base/UDLLManager.pas
index dd05d733..d5bb1480 100644
--- a/unicode/src/base/UDLLManager.pas
+++ b/unicode/src/base/UDLLManager.pas
@@ -35,7 +35,9 @@ interface
uses
ModiSDK,
- UFiles;
+ UFiles,
+ UPath,
+ UFilesystem;
type
TDLLMan = class
@@ -47,14 +49,14 @@ type
P_RData: pModi_RData;
public
Plugins: array of TPluginInfo;
- PluginPaths: array of string;
+ PluginPaths: array of IPath;
Selected: ^TPluginInfo;
constructor Create;
procedure GetPluginList;
procedure ClearPluginInfo(No: cardinal);
- function LoadPluginInfo(Filename: string; No: cardinal): boolean;
+ function LoadPluginInfo(const Filename: IPath; No: cardinal): boolean;
function LoadPlugin(No: cardinal): boolean;
procedure UnLoadPlugin;
@@ -107,27 +109,26 @@ end;
procedure TDLLMan.GetPluginList;
var
- SearchRecord: TSearchRec;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
begin
-
- if FindFirst(PluginPath + '*' + DLLExt, faAnyFile, SearchRecord) = 0 then
+ Iter := FileSystem.FileFind(PluginPath.Append('*' + DLLExt), 0);
+ while (Iter.HasNext) do
begin
- repeat
- SetLength(Plugins, Length(Plugins)+1);
- SetLength(PluginPaths, Length(Plugins));
+ SetLength(Plugins, Length(Plugins)+1);
+ SetLength(PluginPaths, Length(Plugins));
- if LoadPluginInfo(SearchRecord.Name, High(Plugins)) then // loaded succesful
- begin
- PluginPaths[High(PluginPaths)] := SearchRecord.Name;
- end
- else // error loading
- begin
- SetLength(Plugins, Length(Plugins)-1);
- SetLength(PluginPaths, Length(Plugins));
- end;
-
- until FindNext(SearchRecord) <> 0;
- FindClose(SearchRecord);
+ FileInfo := Iter.Next;
+
+ if LoadPluginInfo(FileInfo.Name, High(Plugins)) then // loaded succesful
+ begin
+ PluginPaths[High(PluginPaths)] := FileInfo.Name;
+ end
+ else // error loading
+ begin
+ SetLength(Plugins, Length(Plugins)-1);
+ SetLength(PluginPaths, Length(Plugins));
+ end;
end;
end;
@@ -164,7 +165,7 @@ begin
Plugins[No].EnLineBonus_O := true;
end;
-function TDLLMan.LoadPluginInfo(Filename: string; No: cardinal): boolean;
+function TDLLMan.LoadPluginInfo(const Filename: IPath; No: cardinal): boolean;
var
hLibg: THandle;
Info: pModi_PluginInfo;
@@ -182,7 +183,7 @@ begin
}
// load libary
- hLibg := LoadLibrary(PChar(PluginPath + Filename));
+ hLibg := LoadLibrary(PChar(PluginPath.Append(Filename).ToNative));
// if loaded
if (hLibg <> 0) then
begin
@@ -197,19 +198,19 @@ begin
Result := true;
end
else
- Log.LogError('Could not load plugin "' + Filename + '": Info procedure not found');
+ Log.LogError('Could not load plugin "' + Filename.ToNative + '": Info procedure not found');
FreeLibrary (hLibg);
end
else
- Log.LogError('Could not load plugin "' + Filename + '": Libary not loaded');
+ Log.LogError('Could not load plugin "' + Filename.ToNative + '": Libary not loaded');
end;
function TDLLMan.LoadPlugin(No: cardinal): boolean;
begin
Result := true;
// load libary
- hLib := LoadLibrary(PChar(PluginPath + PluginPaths[No]));
+ hLib := LoadLibrary(PChar(PluginPath.Append(PluginPaths[No]).ToNative));
// if loaded
if (hLib <> 0) then
begin
@@ -226,11 +227,11 @@ begin
end
else
begin
- Log.LogError('Could not load plugin "' + PluginPaths[No] + '": Procedures not found');
+ Log.LogError('Could not load plugin "' + PluginPaths[No].ToNative + '": Procedures not found');
end;
end
else
- Log.LogError('Could not load plugin "' + PluginPaths[No] + '": Libary not loaded');
+ Log.LogError('Could not load plugin "' + PluginPaths[No].ToNative + '": Libary not loaded');
end;
procedure TDLLMan.UnLoadPlugin;
diff --git a/unicode/src/base/UDataBase.pas b/unicode/src/base/UDataBase.pas
index 87e9519c..90cee974 100644
--- a/unicode/src/base/UDataBase.pas
+++ b/unicode/src/base/UDataBase.pas
@@ -34,10 +34,11 @@ interface
{$I switches.inc}
uses
+ Classes,
+ SQLiteTable3,
USongs,
USong,
- Classes,
- SQLiteTable3;
+ UPath;
//--------------------
//DataBaseSystem - Class including all DB Methods
@@ -88,16 +89,16 @@ type
TDataBaseSystem = class
private
ScoreDB: TSQLiteDatabase;
- fFilename: string;
+ fFilename: IPath;
function GetVersion(): integer;
procedure SetVersion(Version: integer);
public
- property Filename: string read fFilename;
+ property Filename: IPath read fFilename;
destructor Destroy; override;
- procedure Init(const Filename: string);
+ procedure Init(const Filename: IPath);
procedure ReadScore(Song: TSong);
procedure AddScore(Song: TSong; Level: integer; const Name: UTF8String; Score: integer);
procedure WriteScore(Song: TSong);
@@ -128,19 +129,19 @@ const
(**
* Opens Database and Create Tables if not Exist
*)
-procedure TDataBaseSystem.Init(const Filename: string);
+procedure TDataBaseSystem.Init(const Filename: IPath);
var
Version: integer;
begin
if Assigned(ScoreDB) then
Exit;
- Log.LogStatus('Initializing database: "'+Filename+'"', 'TDataBaseSystem.Init');
+ Log.LogStatus('Initializing database: "'+Filename.ToNative+'"', 'TDataBaseSystem.Init');
try
// Open Database
- ScoreDB := TSQLiteDatabase.Create(Filename);
+ ScoreDB := TSQLiteDatabase.Create(Filename.ToUTF8);
fFilename := Filename;
// Close and delete outdated file
@@ -150,10 +151,10 @@ begin
Log.LogInfo('Outdated cover-database file found', 'TDataBaseSystem.Init');
// Close and delete outdated file
ScoreDB.Free;
- if (not DeleteFile(Filename)) then
- raise Exception.Create('Could not delete ' + Filename);
+ if (not Filename.DeleteFile()) then
+ raise Exception.Create('Could not delete ' + Filename.ToNative);
// Reopen
- ScoreDB := TSQLiteDatabase.Create(Filename);
+ ScoreDB := TSQLiteDatabase.Create(Filename.ToUTF8);
Version := 0;
end;
diff --git a/unicode/src/base/UFilename.pas b/unicode/src/base/UFilename.pas
deleted file mode 100644
index c2ccaec8..00000000
--- a/unicode/src/base/UFilename.pas
+++ /dev/null
@@ -1,464 +0,0 @@
-{* UltraStar Deluxe - Karaoke Game
- *
- * UltraStar Deluxe is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *}
-
-unit UFilename;
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-interface
-
-uses
- {$IFDEF MSWINDOWS}
- TntClasses,
- {$ENDIF}
- Classes;
-
-type
- TPathEncoding = (
- // pencLossless,
- pencSystemUTF8, // use system encoding. Mac: UTF8, Linux: None, Win: UTF8
- // Note:
- // - On windows, this format is lossless but is not
- // supported direclty (UTF-16 only).
- // - This is the best format to store filenames as there is
- // no dataloss.
- // - Do not use with glPrint() or other display functions
- // as the resulting string is neither guaranteed to be
- // UTF-8 nor ANSI.
-
- pencSystemANSI, // use system encoding. Mac: UTF8, Linux: None, Win: ANSI
- // Note:
- // - On windows, the ANSI format may break filenames
- // that are not encoded in the active codepage.
- // - Use only if there is no equivalent WideString
- // filesystem function.
- // - Do not use with glPrint() or other display functions
- // as the resulting string is neither guaranteed to be
- // UTF-8 nor ANSI.
-
- // pencPrintable,
- pencUTF8 // tries to present the filename as UTF-8 encoded string
- // that can be used for printing etc.
- // Note:
- // - Some characters whose encodings are unknown are
- // represented either by '?' or as the representative of
- // a different encoding.
- // - On linux not all filenames can be represented
- // correclty in UTF-8 as it does not have filename
- // encodings (though most filenames are stored in UTF-8).
- // - Never use the result to store filenames or open files
- // as the filenames may break due to conversion.
- );
-
- IPath = interface;
-
- {$IFDEF MSWINDOWS}
- TUniFileStream = class(TTntFileStream)
- {$ELSE}
- TUniFileStream = class(TFileStream)
- {$ENDIF}
- public
- constructor Create(const FileName: IPath; Mode: Word);
- end;
-
- TUniMemoryStream = class(TMemoryStream)
- public
- procedure LoadFromFile(const FileName: IPath);
- procedure SaveToFile(const FileName: IPath);
- end;
-
- IPath = interface
- function ToString(Encoding: TPathEncoding = pencSystemUTF8): AnsiString;
- function ToWideString(): WideString;
-
- function Adjust(): boolean;
-
- function Expand(): IPath;
- {** File must be closed with FileClose(Handle) after usage }
- function CreateFile(): integer;
- function CreateDir(): boolean;
- {** File must be closed with FileClose(Handle) after usage }
- function Open(Mode: LongWord): integer;
- {** Stream must be freed with TUniFileStream.Free after usage }
- function OpenStream(Mode: Word): TUniFileStream;
- function GetFileAge(): integer; overload;
- function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
- function Exists(): boolean;
- function IsFile(): boolean;
- function IsDirectory(): boolean;
- function GetAttr(): cardinal;
- function SetAttr(Attr: Integer): boolean;
- function IsReadOnly(): boolean;
- function SetReadOnly(ReadOnly: boolean): boolean;
- function ForceDirectories(): boolean; //-
- function FileSearch(const DirList: IPath): IPath; //-
- function Rename(const NewName: IPath): boolean;
- function DeleteFile(): boolean;
- function DeleteEmptyDir(): boolean;
- function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
- end;
-
-function Path(const Name: AnsiString; Encoding: TPathEncoding = pencSystemANSI): IPath; overload;
-function Path(const Name: WideString): IPath; overload;
-function Path(PathComponents: array of const): IPath; overload;
-
-implementation
-
-uses
- UFilesystem,
- SysUtils;
-
-type
- TPathImpl = class(TInterfacedObject, IPath)
- private
- fName: AnsiString;
- public
- constructor Create(const Name: string);
- destructor Destroy(); override;
-
- function ToString(Encoding: TPathEncoding = pencSystemANSI): AnsiString;
- function ToWideString(): WideString;
-
- //function Append(const IPath): IPath;
- function Adjust(): boolean;
- {**
- * Removes trailing path-delimiter and replaces path-delimiters with '/'.
- *}
- procedure Unify();
- function Expand(): IPath;
-
- (*
- function IncludeTrailingPathDelimiter(): IPath;
- function ExcludeTrailingPathDelimiter(): IPath;
- function ChangeFileExt(const Extension: IPath): IPath;
- function ExtractFilePath(): IPath;
- function ExtractFileDir(): IPath;
- function ExtractFileDrive(): IPath;
- function ExtractFileName(): IPath;
- function ExtractFileExt(): IPath;
- function ExtractRelativePath(const BaseName: IPath): IPath;
- *)
-
- function CreateFile(): integer;
- function CreateDir(): boolean;
- function Open(Mode: LongWord): integer;
- function OpenStream(Mode: Word): TUniFileStream;
- function GetFileAge(): integer; overload;
- function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
- function Exists(): boolean;
- function IsFile(): boolean;
- function IsDirectory(): boolean;
- function GetAttr(): cardinal;
- function SetAttr(Attr: Integer): boolean;
- function IsReadOnly(): boolean;
- function SetReadOnly(ReadOnly: boolean): boolean;
- function ForceDirectories(): boolean;
- function FileSearch(const DirList: IPath): IPath;
- function Rename(const NewName: IPath): boolean;
- function DeleteFile(): boolean;
- function DeleteEmptyDir(): boolean;
- function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
- end;
-
- IPathIterator = interface
- function Next(): IPath;
- end;
-
- TPathIteratorImpl = class(TInterfacedObject, IPathIterator)
- private
- fPath: IPath;
- fPos: integer;
- public
- constructor Create(Path: IPath);
-
- function Next(): IPath;
- end;
-
-function Path(const Name: AnsiString; Encoding: TPathEncoding): IPath;
-begin
- {$IFDEF MSWINDOWS}
- case Encoding of
- pencUTF8:
- // TODO: Check if UTF8
- Result := TPathImpl.Create(Name);
- pencSystemANSI:
- Result := TPathImpl.Create(AnsiToUtf8(Name));
- else
- raise Exception.Create('Unhandled encoding');
- end;
- {$ELSE}
- Result := TPathImpl.Create(Name);
- {$ENDIF}
-end;
-
-function Path(const Name: WideString): IPath;
-begin
- Result := TPathImpl.Create(UTF8Encode(Name));
-end;
-
-function Path(PathComponents: array of const): IPath;
-var
- CompIndex: integer;
- Name: string;
-begin
- Name := '';
- for CompIndex := 0 to High(PathComponents) do
- begin
- with PathComponents[CompIndex] do
- begin
- case (VType) of
- vtString:
- Name := Name + VString^;
- vtAnsiString:
- Name := Name + AnsiString(VAnsiString);
- vtWideString:
- Name := Name + UTF8Encode(WideString(VWideString));
- vtObject:
- raise Exception.Create('Unhandled Object type');
- else
- raise Exception.Create('Unhandled Path type');
- end;
- end;
- Name := Name + PathDelim;
- end;
- Result := Path(Name);
-end;
-
-constructor TPathImpl.Create(const Name: string);
-begin
- inherited Create();
- fName := Name;
- Unify();
-end;
-
-destructor TPathImpl.Destroy();
-begin
- inherited;
-end;
-
-procedure TPathImpl.Unify();
-var
- I: integer;
-begin
- for I := 1 to Length(fName) do
- begin
- if (fName[I] in ['\', '/']) then
- fName[I] := PathDelim;
- end;
- fName := ExcludeTrailingPathDelimiter(fName);
-end;
-
-function TPathImpl.ToString(Encoding: TPathEncoding): AnsiString;
-begin
- {$IFDEF MSWINDOWS}
- case Encoding of
- pencUTF8:
- Result := fName;
- pencSystemANSI:
- Result := Utf8ToAnsi(fName);
- else
- raise Exception.Create('Unhandled encoding');
- end;
- {$ELSE}
- Result := fName;
- {$ENDIF}
-end;
-
-function TPathImpl.ToWideString(): WideString;
-begin
- Result := UTF8Decode(fName);
-end;
-
-function TPathImpl.Adjust(): boolean;
-begin
- Result := false; //TODO
-end;
-
-
-
-function TPathImpl.Expand(): IPath;
-begin
- Result := FileSystem.ExpandFileName(Self);
-end;
-
-function TPathImpl.CreateFile(): integer;
-begin
- Result := FileSystem.FileCreate(Self);
-end;
-
-function TPathImpl.CreateDir(): boolean;
-begin
- Result := FileSystem.DirectoryCreate(Self);
-end;
-
-function TPathImpl.Open(Mode: LongWord): integer;
-begin
- Result := FileSystem.FileOpen(Self, Mode);
-end;
-
-function TPathImpl.OpenStream(Mode: Word): TUniFileStream;
-begin
- Result := TUniFileStream.Create(Self, Mode);
-end;
-
-function TPathImpl.GetFileAge(): integer;
-begin
- Result := FileSystem.FileAge(Self);
-end;
-
-function TPathImpl.GetFileAge(out FileDateTime: TDateTime): boolean;
-begin
- Result := FileSystem.FileAge(Self, FileDateTime);
-end;
-
-function TPathImpl.Exists(): boolean;
-begin
- Result := IsFile() or IsDirectory();
-end;
-
-function TPathImpl.IsFile(): boolean;
-begin
- Result := FileSystem.FileExists(Self);
-end;
-
-function TPathImpl.IsDirectory(): boolean;
-begin
- Result := FileSystem.DirectoryExists(Self);
-end;
-
-function TPathImpl.GetAttr(): cardinal;
-begin
- Result := FileSystem.FileGetAttr(Self);
-end;
-
-function TPathImpl.SetAttr(Attr: Integer): boolean;
-begin
- Result := FileSystem.FileSetAttr(Self, Attr);
-end;
-
-function TPathImpl.IsReadOnly(): boolean;
-begin
- Result := FileSystem.FileIsReadOnly(Self);
-end;
-
-function TPathImpl.SetReadOnly(ReadOnly: boolean): boolean;
-begin
- Result := FileSystem.FileSetReadOnly(Self, ReadOnly);
-end;
-
-function TPathImpl.ForceDirectories(): boolean;
-begin
- Result := FileSystem.ForceDirectories(Self);
-end;
-
-function TPathImpl.FileSearch(const DirList: IPath): IPath;
-begin
- Result := FileSystem.FileSearch(Self, DirList);
-end;
-
-function TPathImpl.Rename(const NewName: IPath): boolean;
-begin
- Result := FileSystem.RenameFile(Self, NewName);
-end;
-
-function TPathImpl.DeleteFile(): boolean;
-begin
- Result := FileSystem.DeleteFile(Self);
-end;
-
-function TPathImpl.DeleteEmptyDir(): boolean;
-begin
- Result := FileSystem.RemoveDir(Self);
-end;
-
-function TPathImpl.CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
-begin
- Result := FileSystem.CopyFile(Self, Target, FailIfExists);
-end;
-
-
-
-{ TPathIteratorImpl }
-
-constructor TPathIteratorImpl.Create(Path: IPath);
-begin
- fPath := Path;
- fPos := -1;
-end;
-
-function TPathIteratorImpl.Next(): IPath;
-begin
-end;
-
-
-{ TUniFileStream }
-
-{$IFDEF MSWINDOWS}
-
-constructor TUniFileStream.Create(const FileName: IPath; Mode: Word);
-begin
- inherited Create(FileName.ToWideString(), Mode);
-end;
-
-{$ELSE}
-
-constructor TUniFileStream.Create(const FileName: IPath; Mode: Word);
-begin
- inherited Create(FileName.ToSystemString(), Mode);
-end;
-
-{$ENDIF}
-
-{ TUniMemoryStream }
-
-procedure TUniMemoryStream.LoadFromFile(const FileName: IPath);
-var
- Stream: TStream;
-begin
- Stream := TUniFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
- try
- LoadFromStream(Stream);
- finally
- Stream.Free;
- end;
-end;
-
-procedure TUniMemoryStream.SaveToFile(const FileName: IPath);
-var
- Stream: TStream;
-begin
- Stream := TUniFileStream.Create(FileName, fmCreate);
- try
- SaveToStream(Stream);
- finally
- Stream.Free;
- end;
-end;
-
-end.
diff --git a/unicode/src/base/UFiles.pas b/unicode/src/base/UFiles.pas
index bfcd63d2..9996eeb1 100644
--- a/unicode/src/base/UFiles.pas
+++ b/unicode/src/base/UFiles.pas
@@ -34,10 +34,12 @@ interface
uses
SysUtils,
+ Classes,
ULog,
UMusic,
USongs,
- USong;
+ USong,
+ UPath;
procedure ResetSingTemp;
@@ -48,7 +50,7 @@ type
* Throws a TEncodingException if the song's fields cannot be encoded in the
* requested encoding.
*}
-function SaveSong(const Song: TSong; const Lines: TLines; const Name: string; Relative: boolean): TSaveSongResult;
+function SaveSong(const Song: TSong; const Lines: TLines; const Name: IPath; Relative: boolean): TSaveSongResult;
implementation
@@ -81,7 +83,7 @@ end;
//--------------------
// Saves a Song
//--------------------
-function SaveSong(const Song: TSong; const Lines: TLines; const Name: string; Relative: boolean): TSaveSongResult;
+function SaveSong(const Song: TSong; const Lines: TLines; const Name: IPath; Relative: boolean): TSaveSongResult;
var
C: integer;
N: integer;
@@ -89,9 +91,9 @@ var
B: integer;
RelativeSubTime: integer;
NoteState: AnsiString;
- SongFile: TextFile;
+ SongFile: TTextFileStream;
- function EncodeToken(const Str: UTF8String): AnsiString;
+ function EncodeToken(const Str: UTF8String): RawByteString;
var
Success: boolean;
begin
@@ -100,89 +102,87 @@ var
SaveSong := ssrEncodingError;
end;
- function EncodeFilename(const Filename: WideString): AnsiString;
- begin
- // TODO: Unicode
- Result := Filename;
- end;
-
begin
// Relative := true; // override (idea - use shift+S to save with relative)
- AssignFile(SongFile, Name);
- Rewrite(SongFile);
-
Result := ssrOK;
+ SongFile := nil;
- if (Song.Encoding = encUTF8) then
- Write(SongFile, UTF8_BOM);
+ try
+ SongFile := TTextFileStream.Create(Name, fmCreate);
- Writeln(SongFile, '#ENCODING:' + EncodingName(Song.Encoding));
- Writeln(SongFile, '#TITLE:' + EncodeToken(Song.Title));
- Writeln(SongFile, '#ARTIST:' + EncodeToken(Song.Artist));
+ if (Song.Encoding = encUTF8) then
+ SongFile.Write(UTF8_BOM);
- if Song.Creator <> '' then Writeln(SongFile, '#CREATOR:' + EncodeToken(Song.Creator));
- if Song.Edition <> 'Unknown' then Writeln(SongFile, '#EDITION:' + EncodeToken(Song.Edition));
- if Song.Genre <> 'Unknown' then Writeln(SongFile, '#GENRE:' + EncodeToken(Song.Genre));
- if Song.Language <> 'Unknown' then Writeln(SongFile, '#LANGUAGE:' + EncodeToken(Song.Language));
+ SongFile.WriteLine('#ENCODING:' + EncodingName(Song.Encoding));
+ SongFile.WriteLine('#TITLE:' + EncodeToken(Song.Title));
+ SongFile.WriteLine('#ARTIST:' + EncodeToken(Song.Artist));
- Writeln(SongFile, '#MP3:' + EncodeFilename(Song.Mp3));
- if Song.Cover <> '' then Writeln(SongFile, '#COVER:' + EncodeFilename(Song.Cover));
- if Song.Background <> '' then Writeln(SongFile, '#BACKGROUND:' + EncodeFilename(Song.Background));
- if Song.Video <> '' then Writeln(SongFile, '#VIDEO:' + EncodeFilename(Song.Video));
+ if Song.Creator <> '' then SongFile.WriteLine('#CREATOR:' + EncodeToken(Song.Creator));
+ if Song.Edition <> 'Unknown' then SongFile.WriteLine('#EDITION:' + EncodeToken(Song.Edition));
+ if Song.Genre <> 'Unknown' then SongFile.WriteLine('#GENRE:' + EncodeToken(Song.Genre));
+ if Song.Language <> 'Unknown' then SongFile.WriteLine('#LANGUAGE:' + EncodeToken(Song.Language));
- if Song.VideoGAP <> 0 then Writeln(SongFile, '#VIDEOGAP:' + FloatToStr(Song.VideoGAP));
- if Song.Resolution <> 4 then Writeln(SongFile, '#RESOLUTION:' + IntToStr(Song.Resolution));
- if Song.NotesGAP <> 0 then Writeln(SongFile, '#NOTESGAP:' + IntToStr(Song.NotesGAP));
- if Song.Start <> 0 then Writeln(SongFile, '#START:' + FloatToStr(Song.Start));
- if Song.Finish <> 0 then Writeln(SongFile, '#END:' + IntToStr(Song.Finish));
- if Relative then Writeln(SongFile, '#RELATIVE:yes');
+ SongFile.WriteLine('#MP3:' + EncodeToken(Song.Mp3.ToUTF8));
+ if Song.Cover.IsSet then SongFile.WriteLine('#COVER:' + EncodeToken(Song.Cover.ToUTF8));
+ if Song.Background.IsSet then SongFile.WriteLine('#BACKGROUND:' + EncodeToken(Song.Background.ToUTF8));
+ if Song.Video.IsSet then SongFile.WriteLine('#VIDEO:' + EncodeToken(Song.Video.ToUTF8));
- Writeln(SongFile, '#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
- Writeln(SongFile, '#GAP:' + FloatToStr(Song.GAP));
+ if Song.VideoGAP <> 0 then SongFile.WriteLine('#VIDEOGAP:' + FloatToStr(Song.VideoGAP));
+ if Song.Resolution <> 4 then SongFile.WriteLine('#RESOLUTION:' + IntToStr(Song.Resolution));
+ if Song.NotesGAP <> 0 then SongFile.WriteLine('#NOTESGAP:' + IntToStr(Song.NotesGAP));
+ if Song.Start <> 0 then SongFile.WriteLine('#START:' + FloatToStr(Song.Start));
+ if Song.Finish <> 0 then SongFile.WriteLine('#END:' + IntToStr(Song.Finish));
+ if Relative then SongFile.WriteLine('#RELATIVE:yes');
- RelativeSubTime := 0;
- for B := 1 to High(Song.BPM) do
- Writeln(SongFile, 'B ' + FloatToStr(Song.BPM[B].StartBeat) + ' '
- + FloatToStr(Song.BPM[B].BPM/4));
+ SongFile.WriteLine('#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
+ SongFile.WriteLine('#GAP:' + FloatToStr(Song.GAP));
- for C := 0 to Lines.High do
- begin
- for N := 0 to Lines.Line[C].HighNote do
+ RelativeSubTime := 0;
+ for B := 1 to High(Song.BPM) do
+ SongFile.WriteLine('B ' + FloatToStr(Song.BPM[B].StartBeat) + ' '
+ + FloatToStr(Song.BPM[B].BPM/4));
+
+ for C := 0 to Lines.High do
begin
- with Lines.Line[C].Note[N] do
+ for N := 0 to Lines.Line[C].HighNote do
begin
- //Golden + Freestyle Note Patch
- case Lines.Line[C].Note[N].NoteType of
- ntFreestyle: NoteState := 'F ';
- ntNormal: NoteState := ': ';
- ntGolden: NoteState := '* ';
- end; // case
- S := NoteState + IntToStr(Start-RelativeSubTime) + ' '
- + IntToStr(Length) + ' '
- + IntToStr(Tone) + ' '
- + EncodeToken(Text);
-
- Writeln(SongFile, S);
- end; // with
- end; // N
-
- if C < Lines.High then // don't write end of last sentence
- begin
- if not Relative then
- S := '- ' + IntToStr(Lines.Line[C+1].Start)
- else
+ with Lines.Line[C].Note[N] do
+ begin
+ //Golden + Freestyle Note Patch
+ case Lines.Line[C].Note[N].NoteType of
+ ntFreestyle: NoteState := 'F ';
+ ntNormal: NoteState := ': ';
+ ntGolden: NoteState := '* ';
+ end; // case
+ S := NoteState + IntToStr(Start-RelativeSubTime) + ' '
+ + IntToStr(Length) + ' '
+ + IntToStr(Tone) + ' '
+ + EncodeToken(Text);
+
+ SongFile.WriteLine(S);
+ end; // with
+ end; // N
+
+ if C < Lines.High then // don't write end of last sentence
begin
- S := '- ' + IntToStr(Lines.Line[C+1].Start - RelativeSubTime) +
- ' ' + IntToStr(Lines.Line[C+1].Start - RelativeSubTime);
- RelativeSubTime := Lines.Line[C+1].Start;
+ if not Relative then
+ S := '- ' + IntToStr(Lines.Line[C+1].Start)
+ else
+ begin
+ S := '- ' + IntToStr(Lines.Line[C+1].Start - RelativeSubTime) +
+ ' ' + IntToStr(Lines.Line[C+1].Start - RelativeSubTime);
+ RelativeSubTime := Lines.Line[C+1].Start;
+ end;
+ SongFile.WriteLine(S);
end;
- Writeln(SongFile, S);
- end;
- end; // C
+ end; // C
- Writeln(SongFile, 'E');
+ SongFile.WriteLine('E');
+ except
+ Result := ssrFileError;
+ end;
- CloseFile(SongFile);
+ SongFile.Free;
end;
end.
diff --git a/unicode/src/base/UFilesystem.pas b/unicode/src/base/UFilesystem.pas
index 480d3376..1cfb6837 100644
--- a/unicode/src/base/UFilesystem.pas
+++ b/unicode/src/base/UFilesystem.pas
@@ -223,7 +223,7 @@ end;
function TFileSystemImpl.CreateFileStream(const FileName: IPath; Mode: Word): THandleStream;
begin
- Result := TUnicodeFileStream.Create(FileName, Mode);
+ Result := TBinaryFileStream.Create(FileName, Mode);
end;
function TFileSystemImpl.FileFind(const FilePattern: IPath; Attr: Integer): IFileIterator;
diff --git a/unicode/src/base/UFont.pas b/unicode/src/base/UFont.pas
index ce52ed96..d91dca59 100644
--- a/unicode/src/base/UFont.pas
+++ b/unicode/src/base/UFont.pas
@@ -47,13 +47,14 @@ uses
glext,
glu,
sdl,
+ Math,
+ Classes,
+ SysUtils,
UUnicodeUtils,
{$IFDEF BITMAP_FONT}
UTexture,
{$ENDIF}
- Math,
- Classes,
- SysUtils;
+ UPath;
type
@@ -506,7 +507,7 @@ type
procedure ResetIntern();
protected
- fFilename: AnsiString; //**< filename of the font-file
+ fFilename: IPath; //**< filename of the font-file
fSize: integer; //**< Font base size (in pixels)
fOutset: single; //**< size of outset extrusion (in pixels)
fFace: FT_Face; //**< Holds the height of the font
@@ -537,7 +538,7 @@ type
* @param LoadFlags flags passed to FT_Load_Glyph()
* @raises Exception if the font-file could not be loaded
*}
- constructor Create(const Filename: AnsiString;
+ constructor Create(const Filename: IPath;
Size: integer; Outset: single = 0.0;
LoadFlags: FT_Int32 = FT_LOAD_DEFAULT);
@@ -567,7 +568,7 @@ type
* The extrusion in pixels is Size*OutsetAmount
* (0.0 -> no extrusion, 0.1 -> 10%).
*}
- constructor Create(const Filename: AnsiString;
+ constructor Create(const Filename: IPath;
Size: integer; OutsetAmount: single = 0.0;
UseMipmaps: boolean = true);
@@ -585,7 +586,7 @@ type
*}
TFTOutlineFont = class(TFont)
private
- fFilename: AnsiString;
+ fFilename: IPath;
fSize: integer;
fOutset: single;
fInnerFont, fOutlineFont: TFTFont;
@@ -612,7 +613,7 @@ type
procedure SetReflectionPass(Enable: boolean); override;
public
- constructor Create(const Filename: AnsiString;
+ constructor Create(const Filename: IPath;
Size: integer; Outset: single;
LoadFlags: FT_Int32 = FT_LOAD_DEFAULT);
destructor Destroy; override;
@@ -646,7 +647,7 @@ type
function CreateMipmap(Level: integer; Scale: single): TFont; override;
public
- constructor Create(const Filename: AnsiString;
+ constructor Create(const Filename: IPath;
Size: integer; OutsetAmount: single;
UseMipmaps: boolean = true);
@@ -688,7 +689,7 @@ type
* @param InfoFile the name of the info (.dat) file
* @raises Exception if the file is corrupted
*}
- procedure LoadFontInfo(const InfoFile: AnsiString);
+ procedure LoadFontInfo(const InfoFile: IPath);
protected
procedure Render(const Text: UCS4String); override;
@@ -708,7 +709,7 @@ type
* (y-axis up) and from the lower edge of the glyphs bounding box)
* @param(Ascender pixels from baseline to top of highest glyph)
*}
- constructor Create(const Filename: AnsiString; Outline: integer;
+ constructor Create(const Filename: IPath; Outline: integer;
Baseline, Ascender, Descender: integer);
destructor Destroy(); override;
@@ -1406,7 +1407,7 @@ end;
*}
constructor TFTFont.Create(
- const Filename: AnsiString;
+ const Filename: IPath;
Size: integer; Outset: single;
LoadFlags: FT_Int32);
var
@@ -1422,8 +1423,8 @@ begin
fPart := fpNone;
// load font information
- if (FT_New_Face(TFreeType.GetLibrary(), PChar(Filename), 0, fFace) <> 0) then
- raise Exception.Create('FT_New_Face: Could not load font ''' + Filename + '''');
+ if (FT_New_Face(TFreeType.GetLibrary(), PChar(Filename.ToNative), 0, fFace) <> 0) then
+ raise Exception.Create('FT_New_Face: Could not load font ''' + Filename.ToNative + '''');
// support scalable fonts only
if (not FT_IS_SCALABLE(fFace)) then
@@ -1645,7 +1646,7 @@ end;
* TFTScalableFont
*}
-constructor TFTScalableFont.Create(const Filename: AnsiString;
+constructor TFTScalableFont.Create(const Filename: IPath;
Size: integer; OutsetAmount: single;
UseMipmaps: boolean);
var
@@ -1701,7 +1702,7 @@ end;
*}
constructor TFTOutlineFont.Create(
- const Filename: AnsiString;
+ const Filename: IPath;
Size: integer; Outset: single;
LoadFlags: FT_Int32);
begin
@@ -1893,7 +1894,7 @@ end;
*}
constructor TFTScalableOutlineFont.Create(
- const Filename: AnsiString;
+ const Filename: IPath;
Size: integer; OutsetAmount: single;
UseMipmaps: boolean);
var
@@ -2555,7 +2556,7 @@ end;
* TBitmapFont
*}
-constructor TBitmapFont.Create(const Filename: AnsiString; Outline: integer;
+constructor TBitmapFont.Create(const Filename: IPath; Outline: integer;
Baseline, Ascender, Descender: integer);
begin
inherited Create();
@@ -2567,7 +2568,7 @@ begin
fAscender := Ascender;
fDescender := Descender;
- LoadFontInfo(ChangeFileExt(Filename, '.dat'));
+ LoadFontInfo(Filename.SetExtension('.dat'));
ResetIntern();
end;
@@ -2597,18 +2598,18 @@ begin
fWidths[Count] := Round(fWidths[Count] * WidthMult) + WidthAdd;
end;
-procedure TBitmapFont.LoadFontInfo(const InfoFile: AnsiString);
+procedure TBitmapFont.LoadFontInfo(const InfoFile: IPath);
var
- Stream: TFileStream;
+ Stream: THandleStream;
begin
FillChar(fWidths[0], Length(fWidths), 0);
Stream := nil;
try
- Stream := TFileStream.Create(InfoFile, fmOpenRead);
+ Stream := TBinaryFileStream.Create(InfoFile, fmOpenRead);
Stream.Read(fWidths, 256);
except
- raise Exception.Create('Could not read font info file ''' + InfoFile + '''');
+ raise Exception.Create('Could not read font info file ''' + InfoFile.ToNative + '''');
end;
Stream.Free;
end;
diff --git a/unicode/src/base/UGraphic.pas b/unicode/src/base/UGraphic.pas
index 7c5b18fd..9c12d998 100644
--- a/unicode/src/base/UGraphic.pas
+++ b/unicode/src/base/UGraphic.pas
@@ -340,7 +340,7 @@ begin
Tex_Cursor_Unpressed := Texture.LoadTexture(Skin.GetTextureFileName('Cursor'), TEXTURE_TYPE_TRANSPARENT, 0);
- if (Skin.GetTextureFileName('Cursor_Pressed') <> '') then
+ if (Skin.GetTextureFileName('Cursor_Pressed').IsSet) then
Tex_Cursor_Pressed := Texture.LoadTexture(Skin.GetTextureFileName('Cursor_Pressed'), TEXTURE_TYPE_TRANSPARENT, 0)
else
Tex_Cursor_Pressed.TexNum := 0;
@@ -389,14 +389,14 @@ begin
End;
Col := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_SingLineBonusBack[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('LineBonusBack')), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_SingLineBonusBack[P] := Texture.LoadTexture(Skin.GetTextureFileName('LineBonusBack'), TEXTURE_TYPE_COLORIZED, Col);
end;
//## backgrounds for the scores ##
for P := 0 to 5 do begin
LoadColor(R, G, B, 'P' + IntToStr(P+1) + 'Light');
Col := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_ScoreBG[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreBG')), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_ScoreBG[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreBG'), TEXTURE_TYPE_COLORIZED, Col);
end;
@@ -411,23 +411,23 @@ begin
//NoteBar ScoreBar
LoadColor(R, G, B, 'P' + IntToStr(P) + 'Dark');
Col := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_Score_NoteBarLevel_Dark[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreLevel_Dark')), TEXTURE_TYPE_COLORIZED, Col);
- Tex_Score_NoteBarRound_Dark[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreLevel_Dark_Round')), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_Score_NoteBarLevel_Dark[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Dark'), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_Score_NoteBarRound_Dark[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Dark_Round'), TEXTURE_TYPE_COLORIZED, Col);
//LineBonus ScoreBar
LoadColor(R, G, B, 'P' + IntToStr(P) + 'Light');
Col := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_Score_NoteBarLevel_Light[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreLevel_Light')), TEXTURE_TYPE_COLORIZED, Col);
- Tex_Score_NoteBarRound_Light[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreLevel_Light_Round')), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_Score_NoteBarLevel_Light[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Light'), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_Score_NoteBarRound_Light[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Light_Round'), TEXTURE_TYPE_COLORIZED, Col);
//GoldenNotes ScoreBar
LoadColor(R, G, B, 'P' + IntToStr(P) + 'Lightest');
Col := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_Score_NoteBarLevel_Lightest[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreLevel_Lightest')), TEXTURE_TYPE_COLORIZED, Col);
- Tex_Score_NoteBarRound_Lightest[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('ScoreLevel_Lightest_Round')), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_Score_NoteBarLevel_Lightest[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Lightest'), TEXTURE_TYPE_COLORIZED, Col);
+ Tex_Score_NoteBarRound_Lightest[P] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Lightest_Round'), TEXTURE_TYPE_COLORIZED, Col);
end;
//## rating pictures that show a picture according to your rate ##
for P := 0 to 7 do begin
- Tex_Score_Ratings[P] := Texture.LoadTexture(pchar(Skin.GetTextureFileName('Rating_'+IntToStr(P))), TEXTURE_TYPE_TRANSPARENT, 0);
+ Tex_Score_Ratings[P] := Texture.LoadTexture(Skin.GetTextureFileName('Rating_'+IntToStr(P)), TEXTURE_TYPE_TRANSPARENT, 0);
end;
Log.LogStatus('Loading Textures - Done', 'LoadTextures');
@@ -464,7 +464,7 @@ begin
end;
// load icon image (must be 32x32 for win32)
- Icon := LoadImage(ResourcesPath + WINDOW_ICON);
+ Icon := LoadImage(ResourcesPath.Append(WINDOW_ICON));
if (Icon <> nil) then
SDL_WM_SetIcon(Icon, 0);
diff --git a/unicode/src/base/UImage.pas b/unicode/src/base/UImage.pas
index 60b0a3a2..25b0d1e2 100644
--- a/unicode/src/base/UImage.pas
+++ b/unicode/src/base/UImage.pas
@@ -34,7 +34,8 @@ interface
{$I switches.inc}
uses
- SDL;
+ SDL,
+ UPath;
{$DEFINE HavePNG}
{$DEFINE HaveBMP}
@@ -131,20 +132,20 @@ type
*******************************************************)
{$IFDEF HavePNG}
-function WritePNGImage(const FileName: string; Surface: PSDL_Surface): boolean;
+function WritePNGImage(const FileName: IPath; Surface: PSDL_Surface): boolean;
{$ENDIF}
{$IFDEF HaveBMP}
-function WriteBMPImage(const FileName: string; Surface: PSDL_Surface): boolean;
+function WriteBMPImage(const FileName: IPath; Surface: PSDL_Surface): boolean;
{$ENDIF}
{$IFDEF HaveJPG}
-function WriteJPGImage(const FileName: string; Surface: PSDL_Surface; Quality: integer): boolean;
+function WriteJPGImage(const FileName: IPath; Surface: PSDL_Surface; Quality: integer): boolean;
{$ENDIF}
(*******************************************************
* Image loading
*******************************************************)
-function LoadImage(const Filename: string): PSDL_Surface;
+function LoadImage(const Filename: IPath): PSDL_Surface;
(*******************************************************
* Image manipulation
@@ -282,17 +283,17 @@ end;
procedure user_read_data(png_ptr: png_structp; data: png_bytep; length: png_size_t); cdecl;
var
- inFile: TFileStream;
+ inFile: THandleStream;
begin
- inFile := TFileStream(png_get_io_ptr(png_ptr));
+ inFile := THandleStream(png_get_io_ptr(png_ptr));
inFile.Read(data^, length);
end;
procedure user_write_data(png_ptr: png_structp; data: png_bytep; length: png_size_t); cdecl;
var
- outFile: TFileStream;
+ outFile: THandleStream;
begin
- outFile := TFileStream(png_get_io_ptr(png_ptr));
+ outFile := THandleStream(png_get_io_ptr(png_ptr));
outFile.Write(data^, length);
end;
@@ -323,11 +324,11 @@ end;
(*
* ImageData must be in RGB-format
*)
-function WritePNGImage(const FileName: string; Surface: PSDL_Surface): boolean;
+function WritePNGImage(const FileName: IPath; Surface: PSDL_Surface): boolean;
var
png_ptr: png_structp;
info_ptr: png_infop;
- pngFile: TFileStream;
+ pngFile: THandleStream;
row: integer;
rowData: array of png_bytep;
// rowStride: integer;
@@ -339,9 +340,9 @@ begin
// open file for writing
try
- pngFile := TFileStream.Create(FileName, fmCreate);
+ pngFile := TBinaryFileStream.Create(FileName, fmCreate);
except
- Log.LogError('Could not open file: "' + FileName + '"', 'WritePngImage');
+ Log.LogError('Could not open file: "' + FileName.ToNative + '"', 'WritePngImage');
Exit;
end;
@@ -500,9 +501,9 @@ type
(*
* ImageData must be in BGR-format
*)
-function WriteBMPImage(const FileName: string; Surface: PSDL_Surface): boolean;
+function WriteBMPImage(const FileName: IPath; Surface: PSDL_Surface): boolean;
var
- bmpFile: TFileStream;
+ bmpFile: THandleStream;
FileInfo: BITMAPINFOHEADER;
FileHeader: BITMAPFILEHEADER;
Converted: boolean;
@@ -513,9 +514,9 @@ begin
// open file for writing
try
- bmpFile := TFileStream.Create(FileName, fmCreate);
+ bmpFile := TBinaryFileStream.Create(FileName, fmCreate);
except
- Log.LogError('Could not open file: "' + FileName + '"', 'WriteBMPImage');
+ Log.LogError('Could not open file: "' + FileName.ToNative + '"', 'WriteBMPImage');
Exit;
end;
@@ -579,7 +580,7 @@ begin
Result := true;
finally
- Log.LogError('Could not write file: "' + FileName + '"', 'WriteBMPImage');
+ Log.LogError('Could not write file: "' + FileName.ToNative + '"', 'WriteBMPImage');
end;
if (Converted) then
@@ -597,7 +598,7 @@ end;
{$IFDEF HaveJPG}
-function WriteJPGImage(const FileName: string; Surface: PSDL_Surface; Quality: integer): boolean;
+function WriteJPGImage(const FileName: IPath; Surface: PSDL_Surface; Quality: integer): boolean;
var
{$IFDEF Delphi}
Bitmap: TBitmap;
@@ -676,9 +677,9 @@ begin
try
// compress image (don't forget this line, otherwise it won't be compressed)
Jpeg.Compress();
- Jpeg.SaveToFile(FileName);
+ Jpeg.SaveToFile(FileName.ToNative);
except
- Log.LogError('Could not save file: "' + FileName + '"', 'WriteJPGImage');
+ Log.LogError('Could not save file: "' + FileName.ToNative + '"', 'WriteJPGImage');
Exit;
end;
Jpeg.Free;
@@ -763,27 +764,25 @@ end;
(*
* Loads an image from the given file
*)
-function LoadImage(const Filename: string): PSDL_Surface;
+function LoadImage(const Filename: IPath): PSDL_Surface;
var
- FilenameFound: string;
+ FilenameCaseAdj: IPath;
begin
- Result := nil;
+ Result := nil;
- // FileExistsInsensitive() requires a var-arg
- FilenameFound := Filename;
-
- // try to find the file case insensitive
- if (not FileExistsInsensitive(FilenameFound)) then
+ // try to adjust filename's case and check if it exists
+ FilenameCaseAdj := Filename.AdjustCase(false);
+ if (not FilenameCaseAdj.IsFile) then
begin
- Log.LogError('Image-File does not exist "'+FilenameFound+'"', 'LoadImage');
+ Log.LogError('Image-File does not exist "' + FilenameCaseAdj.ToNative + '"', 'LoadImage');
Exit;
end;
// load from file
try
- Result := IMG_Load(PChar(FilenameFound));
+ Result := IMG_Load(PChar(FilenameCaseAdj.ToNative));
except
- Log.LogError('Could not load from file "'+FilenameFound+'"', 'LoadImage');
+ Log.LogError('Could not load from file "' + FilenameCaseAdj.ToNative + '"', 'LoadImage');
Exit;
end;
end;
diff --git a/unicode/src/base/UIni.pas b/unicode/src/base/UIni.pas
index bf068f11..85f925ad 100644
--- a/unicode/src/base/UIni.pas
+++ b/unicode/src/base/UIni.pas
@@ -36,9 +36,11 @@ interface
uses
Classes,
IniFiles,
+ SysUtils,
ULog,
UTextEncoding,
- SysUtils;
+ UFilesystem,
+ UPath;
type
// TInputDeviceConfig stores the configuration for an input device.
@@ -71,11 +73,10 @@ type
TBackgroundMusicOption = (bmoOff, bmoOn);
TIni = class
private
- function RemoveFileExt(FullName: string): string;
function ExtractKeyIndex(const Key, Prefix, Suffix: string): integer;
function GetMaxKeyIndex(Keys: TStringList; const Prefix, Suffix: string): integer;
- function GetArrayIndex(const SearchArray: array of string; Value: string; CaseInsensitiv: boolean = false): integer;
- function ReadArrayIndex(const SearchArray: array of string; IniFile: TCustomIniFile;
+ function GetArrayIndex(const SearchArray: array of UTF8String; Value: string; CaseInsensitiv: boolean = false): integer;
+ function ReadArrayIndex(const SearchArray: array of UTF8String; IniFile: TCustomIniFile;
IniSection: string; IniProperty: string; Default: integer): integer;
procedure LoadInputDeviceCfg(IniFile: TMemIniFile);
@@ -92,7 +93,7 @@ type
NameTemplate: array[0..11] of UTF8String;
//Filename of the opened iniFile
- Filename: string;
+ Filename: IPath;
// Game
Players: integer;
@@ -165,19 +166,19 @@ type
var
Ini: TIni;
- IResolution: array of string;
- ILanguage: array of string;
- ITheme: array of string;
- ISkin: array of string;
+ IResolution: array of UTF8String;
+ ILanguage: array of UTF8String;
+ ITheme: array of UTF8String;
+ ISkin: array of UTF8String;
const
- IPlayers: array[0..4] of string = ('1', '2', '3', '4', '6');
- IPlayersVals: array[0..4] of integer = ( 1 , 2 , 3 , 4 , 6 );
+ IPlayers: array[0..4] of UTF8String = ('1', '2', '3', '4', '6');
+ IPlayersVals: array[0..4] of integer = ( 1 , 2 , 3 , 4 , 6 );
- IDifficulty: array[0..2] of string = ('Easy', 'Medium', 'Hard');
- ITabs: array[0..1] of string = ('Off', 'On');
+ IDifficulty: array[0..2] of UTF8String = ('Easy', 'Medium', 'Hard');
+ ITabs: array[0..1] of UTF8String = ('Off', 'On');
- ISorting: array[0..7] of string = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2');
+ ISorting: array[0..7] of UTF8String = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2');
sEdition = 0;
sGenre = 1;
sLanguage = 2;
@@ -187,71 +188,71 @@ const
sTitle2 = 6;
sArtist2 = 7;
- IDebug: array[0..1] of string = ('Off', 'On');
+ IDebug: array[0..1] of UTF8String = ('Off', 'On');
- IScreens: array[0..1] of string = ('1', '2');
- IFullScreen: array[0..1] of string = ('Off', 'On');
- IDepth: array[0..1] of string = ('16 bit', '32 bit');
- IVisualizer: array[0..2] of string = ('Off', 'WhenNoVideo','On');
+ IScreens: array[0..1] of UTF8String = ('1', '2');
+ IFullScreen: array[0..1] of UTF8String = ('Off', 'On');
+ IDepth: array[0..1] of UTF8String = ('16 bit', '32 bit');
+ IVisualizer: array[0..2] of UTF8String = ('Off', 'WhenNoVideo','On');
- IBackgroundMusic: array[0..1] of string = ('Off', 'On');
+ IBackgroundMusic: array[0..1] of UTF8String = ('Off', 'On');
- ITextureSize: array[0..3] of string = ('64', '128', '256', '512');
- ITextureSizeVals: array[0..3] of integer = ( 64, 128, 256, 512);
+ ITextureSize: array[0..3] of UTF8String = ('64', '128', '256', '512');
+ ITextureSizeVals: array[0..3] of integer = ( 64, 128, 256, 512);
- ISingWindow: array[0..1] of string = ('Small', 'Big');
+ ISingWindow: array[0..1] of UTF8String = ('Small', 'Big');
//SingBar Mod
- IOscilloscope: array[0..1] of string = ('Off', 'On');
+ IOscilloscope: array[0..1] of UTF8String = ('Off', 'On');
- ISpectrum: array[0..1] of string = ('Off', 'On');
- ISpectrograph: array[0..1] of string = ('Off', 'On');
- IMovieSize: array[0..2] of string = ('Half', 'Full [Vid]', 'Full [BG+Vid]');
+ ISpectrum: array[0..1] of UTF8String = ('Off', 'On');
+ ISpectrograph: array[0..1] of UTF8String = ('Off', 'On');
+ IMovieSize: array[0..2] of UTF8String = ('Half', 'Full [Vid]', 'Full [BG+Vid]');
- IClickAssist: array[0..1] of string = ('Off', 'On');
- IBeatClick: array[0..1] of string = ('Off', 'On');
- ISavePlayback: array[0..1] of string = ('Off', 'On');
+ IClickAssist: array[0..1] of UTF8String = ('Off', 'On');
+ IBeatClick: array[0..1] of UTF8String = ('Off', 'On');
+ ISavePlayback: array[0..1] of UTF8String = ('Off', 'On');
- IThreshold: array[0..3] of string = ('5%', '10%', '15%', '20%');
+ IThreshold: array[0..3] of UTF8String = ('5%', '10%', '15%', '20%');
IThresholdVals: array[0..3] of single = (0.05, 0.10, 0.15, 0.20);
- IVoicePassthrough: array[0..1] of string = ('Off', 'On');
+ IVoicePassthrough: array[0..1] of UTF8String = ('Off', 'On');
- IAudioOutputBufferSize: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
- IAudioOutputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 );
+ IAudioOutputBufferSize: array[0..9] of UTF8String = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
+ IAudioOutputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 );
- IAudioInputBufferSize: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
- IAudioInputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 );
+ IAudioInputBufferSize: array[0..9] of UTF8String = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
+ IAudioInputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 );
//Song Preview
- IPreviewVolume: array[0..10] of string = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%');
- IPreviewVolumeVals: array[0..10] of single = ( 0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00 );
+ IPreviewVolume: array[0..10] of UTF8String = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%');
+ IPreviewVolumeVals: array[0..10] of single = ( 0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00 );
- IPreviewFading: array[0..5] of string = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs');
- IPreviewFadingVals: array[0..5] of integer = ( 0, 1, 2, 3, 4, 5 );
+ IPreviewFading: array[0..5] of UTF8String = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs');
+ IPreviewFadingVals: array[0..5] of integer = ( 0, 1, 2, 3, 4, 5 );
- ILyricsFont: array[0..2] of string = ('Plain', 'OLine1', 'OLine2');
- ILyricsEffect: array[0..4] of string = ('Simple', 'Zoom', 'Slide', 'Ball', 'Shift');
- ISolmization: array[0..3] of string = ('Off', 'Euro', 'Jap', 'American');
- INoteLines: array[0..1] of string = ('Off', 'On');
+ ILyricsFont: array[0..2] of UTF8String = ('Plain', 'OLine1', 'OLine2');
+ ILyricsEffect: array[0..4] of UTF8String = ('Simple', 'Zoom', 'Slide', 'Ball', 'Shift');
+ ISolmization: array[0..3] of UTF8String = ('Off', 'Euro', 'Jap', 'American');
+ INoteLines: array[0..1] of UTF8String = ('Off', 'On');
- IColor: array[0..8] of string = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');
+ IColor: array[0..8] of UTF8String = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');
// Advanced
- ILoadAnimation: array[0..1] of string = ('Off', 'On');
- IEffectSing: array[0..1] of string = ('Off', 'On');
- IScreenFade: array[0..1] of string = ('Off', 'On');
- IAskbeforeDel: array[0..1] of string = ('Off', 'On');
- IOnSongClick: array[0..2] of string = ('Sing', 'Select Players', 'Open Menu');
- ILineBonus: array[0..1] of string = ('Off', 'On');
- IPartyPopup: array[0..1] of string = ('Off', 'On');
+ ILoadAnimation: array[0..1] of UTF8String = ('Off', 'On');
+ IEffectSing: array[0..1] of UTF8String = ('Off', 'On');
+ IScreenFade: array[0..1] of UTF8String = ('Off', 'On');
+ IAskbeforeDel: array[0..1] of UTF8String = ('Off', 'On');
+ IOnSongClick: array[0..2] of UTF8String = ('Sing', 'Select Players', 'Open Menu');
+ ILineBonus: array[0..1] of UTF8String = ('Off', 'On');
+ IPartyPopup: array[0..1] of UTF8String = ('Off', 'On');
- IJoypad: array[0..1] of string = ('Off', 'On');
- IMouse: array[0..2] of string = ('Off', 'Hardware Cursor', 'Software Cursor');
+ IJoypad: array[0..1] of UTF8String = ('Off', 'On');
+ IMouse: array[0..2] of UTF8String = ('Off', 'Hardware Cursor', 'Software Cursor');
// Recording options
- IChannelPlayer: array[0..6] of string = ('Off', '1', '2', '3', '4', '5', '6');
- IMicBoost: array[0..3] of string = ('Off', '+6dB', '+12dB', '+18dB');
+ IChannelPlayer: array[0..6] of UTF8String = ('Off', '1', '2', '3', '4', '5', '6');
+ IMicBoost: array[0..3] of UTF8String = ('Off', '+6dB', '+12dB', '+18dB');
implementation
@@ -268,14 +269,6 @@ uses
UUnicodeUtils;
(**
- * Returns the filename without its fileextension
- *)
-function TIni.RemoveFileExt(FullName: string): string;
-begin
- Result := ChangeFileExt(FullName, '');
-end;
-
-(**
* Extracts an index of a key that is surrounded by a Prefix/Suffix pair.
* Example: ExtractKeyIndex('MyKey[1]', '[', ']') will return 1.
*)
@@ -325,7 +318,7 @@ end;
* Returns the index of Value in SearchArray
* or -1 if Value is not in SearchArray.
*)
-function TIni.GetArrayIndex(const SearchArray: array of string; Value: string;
+function TIni.GetArrayIndex(const SearchArray: array of UTF8String; Value: string;
CaseInsensitiv: boolean = false): integer;
var
i: integer;
@@ -349,7 +342,7 @@ end;
* If SearchArray does not contain the property value, the default value is
* returned.
*)
-function TIni.ReadArrayIndex(const SearchArray: array of string; IniFile: TCustomIniFile;
+function TIni.ReadArrayIndex(const SearchArray: array of UTF8String; IniFile: TCustomIniFile;
IniSection: string; IniProperty: string; Default: integer): integer;
var
StrValue: string;
@@ -464,7 +457,7 @@ begin
begin
if (Pos('SONGDIR', UpperCase(PathStrings[I])) = 1) then
begin
- AddSongPath(IniFile.ReadString('Directories', PathStrings[I], ''));
+ AddSongPath(Path(IniFile.ReadString('Directories', PathStrings[I], '')));
end;
end;
@@ -477,18 +470,23 @@ var
ThemeIni: TMemIniFile;
ThemeName: string;
I: integer;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
begin
// Theme
SetLength(ITheme, 0);
- Log.LogStatus('Searching for Theme : ' + ThemePath + '*.ini', 'Theme');
+ Log.LogStatus('Searching for Theme : ' + ThemePath.ToNative + '*.ini', 'Theme');
+
- FindFirst(ThemePath + '*.ini',faAnyFile, SearchResult);
- Repeat
- Log.LogStatus('Found Theme: ' + SearchResult.Name, 'Theme');
+ Iter := FileSystem.FileFind(ThemePath.Append('*.ini'), 0);
+ while (Iter.HasNext) do
+ begin
+ FileInfo := Iter.Next;
+ Log.LogStatus('Found Theme: ' + FileInfo.Name.ToNative, 'Theme');
//Read Themename from Theme
- ThemeIni := TMemIniFile.Create(SearchResult.Name);
- ThemeName := UpperCase(ThemeIni.ReadString('Theme','Name', RemoveFileExt(SearchResult.Name)));
+ ThemeIni := TMemIniFile.Create(FileInfo.Name.ToNative);
+ ThemeName := UpperCase(ThemeIni.ReadString('Theme','Name', FileInfo.Name.SetExtension('').ToNative));
ThemeIni.Free;
//Search for Skins for this Theme
@@ -497,12 +495,11 @@ begin
if UpperCase(Skin.Skin[I].Theme) = ThemeName then
begin
SetLength(ITheme, Length(ITheme)+1);
- ITheme[High(ITheme)] := RemoveFileExt(SearchResult.Name);
+ ITheme[High(ITheme)] := FileInfo.Name.SetExtension('').ToNative;
break;
end;
end;
- until FindNext(SearchResult) <> 0;
- FindClose(SearchResult);
+ end;
// No Theme Found
if (Length(ITheme) = 0) then
@@ -523,7 +520,7 @@ end;
procedure TIni.LoadScreenModes(IniFile: TCustomIniFile);
// swap two strings
- procedure swap(var s1, s2: string);
+ procedure swap(var s1, s2: UTF8String);
var
s3: string;
begin
@@ -631,19 +628,15 @@ var
begin
GamePath := Platform.GetGameUserPath;
- Log.LogStatus( 'GamePath : ' +GamePath , '' );
+ Log.LogStatus( 'GamePath : ' +GamePath.ToNative , '' );
- if (Params.ConfigFile <> '') then
- try
- FileName := Params.ConfigFile;
- except
- FileName := GamePath + 'config.ini';
- end
+ if (Params.ConfigFile.IsSet) then
+ FileName := Params.ConfigFile
else
- FileName := GamePath + 'config.ini';
+ FileName := GamePath.Append('config.ini');
- Log.LogStatus( 'Using config : ' + FileName , 'Ini');
- IniFile := TMemIniFile.Create( FileName );
+ Log.LogStatus('Using config : ' + FileName.ToNative, 'Ini');
+ IniFile := TMemIniFile.Create(FileName.ToNative);
// Name
for I := 0 to 11 do
@@ -784,13 +777,13 @@ procedure TIni.Save;
var
IniFile: TIniFile;
begin
- if (FileExists(Filename) and FileIsReadOnly(Filename)) then
+ if (Filename.IsFile and Filename.IsReadOnly) then
begin
Log.LogError('Config-file is read-only', 'TIni.Save');
Exit;
end;
- IniFile := TIniFile.Create(Filename);
+ IniFile := TIniFile.Create(Filename.ToNative);
// Players
IniFile.WriteString('Game', 'Players', IPlayers[Players]);
@@ -930,9 +923,9 @@ var
IniFile: TIniFile;
I: integer;
begin
- if not FileIsReadOnly(Filename) then
+ if not Filename.IsReadOnly() then
begin
- IniFile := TIniFile.Create(Filename);
+ IniFile := TIniFile.Create(Filename.ToNative);
//Name Templates for Names Mod
for I := 0 to High(Name) do
@@ -950,9 +943,9 @@ procedure TIni.SaveLevel;
var
IniFile: TIniFile;
begin
- if not FileIsReadOnly(Filename) then
+ if not Filename.IsReadOnly() then
begin
- IniFile := TIniFile.Create(Filename);
+ IniFile := TIniFile.Create(Filename.ToNative);
// Difficulty
IniFile.WriteString('Game', 'Difficulty', IDifficulty[Difficulty]);
diff --git a/unicode/src/base/ULanguage.pas b/unicode/src/base/ULanguage.pas
index 9571358e..88b6647f 100644
--- a/unicode/src/base/ULanguage.pas
+++ b/unicode/src/base/ULanguage.pas
@@ -79,6 +79,8 @@ uses
Classes,
SysUtils,
ULog,
+ UPath,
+ UFilesystem,
UPathUtils;
{**
@@ -129,23 +131,26 @@ end;
*}
procedure TLanguage.LoadList;
var
- SR: TSearchRec; // for parsing directory
+ Iter: IFileIterator;
+ IniInfo: TFileInfo;
+ LangName: string;
begin
SetLength(List, 0);
SetLength(ILanguage, 0);
- if FindFirst(LanguagesPath + '*.ini', 0, SR) = 0 then
+ Iter := FileSystem.FileFind(LanguagesPath.Append('*.ini'), 0);
+ while(Iter.HasNext) do
begin
- repeat
- SetLength(List, Length(List)+1);
- SetLength(ILanguage, Length(ILanguage)+1);
- SR.Name := ChangeFileExt(SR.Name, '');
-
- List[High(List)].Name := SR.Name;
- ILanguage[High(ILanguage)] := SR.Name;
- until (FindNext(SR) <> 0);
- SysUtils.FindClose(SR);
- end; // if FindFirst
+ IniInfo := Iter.Next;
+
+ LangName := IniInfo.Name.SetExtension('').ToUTF8;
+
+ SetLength(List, Length(List)+1);
+ List[High(List)].Name := LangName;
+
+ SetLength(ILanguage, Length(ILanguage)+1);
+ ILanguage[High(ILanguage)] := LangName;
+ end;
end;
{**
@@ -158,7 +163,7 @@ var
S: TStringList;
begin
SetLength(Entry, 0);
- IniFile := TIniFile.Create(LanguagesPath + Language + '.ini');
+ IniFile := TIniFile.Create(LanguagesPath.Append(Language + '.ini').ToNative);
S := TStringList.Create;
IniFile.ReadSectionValues('Text', S);
diff --git a/unicode/src/base/ULog.pas b/unicode/src/base/ULog.pas
index 6f7aa644..08a64e2b 100644
--- a/unicode/src/base/ULog.pas
+++ b/unicode/src/base/ULog.pas
@@ -34,7 +34,8 @@ interface
{$I switches.inc}
uses
- Classes;
+ Classes,
+ UPath;
(*
* LOG_LEVEL_[TYPE] defines the "minimum" index for logs of type TYPE. Each
@@ -198,7 +199,7 @@ begin
if not BenchmarkFileOpened then
begin
BenchmarkFileOpened := true;
- AssignFile(BenchmarkFile, LogPath + 'Benchmark.log');
+ AssignFile(BenchmarkFile, LogPath.Append('Benchmark.log').ToNative);
{$I-}
Rewrite(BenchmarkFile);
if IOResult = 0 then
@@ -270,7 +271,7 @@ procedure TLog.LogToFile(const Text: string);
begin
if (FileOutputEnabled and not LogFileOpened) then
begin
- AssignFile(LogFile, LogPath + 'Error.log');
+ AssignFile(LogFile, LogPath.Append('Error.log').ToNative);
{$I-}
Rewrite(LogFile);
if IOResult = 0 then
@@ -399,20 +400,19 @@ end;
procedure TLog.LogVoice(SoundNr: integer);
var
- FS: TFileStream;
- FileName: string;
+ FS: TBinaryFileStream;
+ Prefix: string;
+ FileName: IPath;
Num: integer;
begin
for Num := 1 to 9999 do begin
- FileName := IntToStr(Num);
- while Length(FileName) < 4 do
- FileName := '0' + FileName;
- FileName := LogPath + 'Voice' + FileName + '.raw';
- if not FileExists(FileName) then
+ Prefix := Format('Voice%.4d', [Num]);
+ FileName := LogPath.Append(Prefix + '.raw');
+ if not FileName.Exists() then
break
end;
- FS := TFileStream.Create(FileName, fmCreate);
+ FS := TBinaryFileStream.Create(FileName, fmCreate);
AudioInputProcessor.Sound[SoundNr].LogBuffer.Seek(0, soBeginning);
FS.CopyFrom(AudioInputProcessor.Sound[SoundNr].LogBuffer, AudioInputProcessor.Sound[SoundNr].LogBuffer.Size);
diff --git a/unicode/src/base/UMain.pas b/unicode/src/base/UMain.pas
index 5b07c9ae..6ab4e187 100644
--- a/unicode/src/base/UMain.pas
+++ b/unicode/src/base/UMain.pas
@@ -196,7 +196,7 @@ begin
// Theme
Log.BenchmarkStart(1);
Log.LogStatus('Load Themes', 'Initialization');
- Theme := TTheme.Create(ThemePath + ITheme[Ini.Theme] + '.ini', Ini.Color);
+ Theme := TTheme.Create(ThemePath.Append(ITheme[Ini.Theme] + '.ini'), Ini.Color);
Log.BenchmarkEnd(1);
Log.LogBenchmark('Loading Themes', 1);
@@ -252,10 +252,10 @@ begin
Log.LogStatus('DataBase System', 'Initialization');
DataBase := TDataBaseSystem.Create;
- if (Params.ScoreFile = '') then
- DataBase.Init (Platform.GetGameUserPath + 'Ultrastar.db')
+ if (Params.ScoreFile.IsUnset) then
+ DataBase.Init(Platform.GetGameUserPath.Append('Ultrastar.db'))
else
- DataBase.Init (Params.ScoreFile);
+ DataBase.Init(Params.ScoreFile);
Log.BenchmarkEnd(1);
Log.LogBenchmark('Loading DataBase System', 1);
diff --git a/unicode/src/base/UMusic.pas b/unicode/src/base/UMusic.pas
index b959ea05..51759b6f 100644
--- a/unicode/src/base/UMusic.pas
+++ b/unicode/src/base/UMusic.pas
@@ -34,10 +34,11 @@ interface
{$I switches.inc}
uses
- UTime,
SysUtils,
Classes,
- UBeatTimer;
+ UTime,
+ UBeatTimer,
+ UPath;
type
TNoteType = (ntFreestyle, ntNormal, ntGolden);
@@ -315,7 +316,7 @@ type
// soundcard output-devices information
TAudioOutputDevice = class
public
- Name: string; // soundcard name
+ Name: UTF8String; // soundcard name
end;
TAudioOutputDeviceList = array of TAudioOutputDevice;
@@ -324,7 +325,7 @@ type
['{63A5EBC3-3F4D-4F23-8DFB-B5165FCE33DD}']
function GetName: String;
- function Open(const Filename: string): boolean; // true if succeed
+ function Open(const Filename: IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -376,7 +377,7 @@ type
// nil-pointers is not neccessary anymore.
// PlaySound/StopSound will be removed then, OpenSound will be renamed to
// CreateSound.
- function OpenSound(const Filename: String): TAudioPlaybackStream;
+ function OpenSound(const Filename: IPath): TAudioPlaybackStream;
procedure PlaySound(Stream: TAudioPlaybackStream);
procedure StopSound(Stream: TAudioPlaybackStream);
@@ -391,7 +392,7 @@ type
IGenericDecoder = Interface
['{557B0E9A-604D-47E4-B826-13769F3E10B7}']
- function GetName(): String;
+ function GetName(): string;
function InitializeDecoder(): boolean;
function FinalizeDecoder(): boolean;
//function IsSupported(const Filename: string): boolean;
@@ -406,7 +407,7 @@ type
IAudioDecoder = Interface( IGenericDecoder )
['{AB47B1B6-2AA9-4410-BF8C-EC79561B5478}']
- function Open(const Filename: string): TAudioDecodeStream;
+ function Open(const Filename: IPath): TAudioDecodeStream;
end;
IAudioInput = Interface
@@ -497,7 +498,7 @@ type
procedure StartBgMusic();
procedure PauseBgMusic();
// TODO
- //function AddSound(Filename: string): integer;
+ //function AddSound(Filename: IPath): integer;
//procedure RemoveSound(ID: integer);
//function GetSound(ID: integer): TAudioPlaybackStream;
//property Sound[ID: integer]: TAudioPlaybackStream read GetSound; default;
@@ -654,7 +655,7 @@ begin
FilterInterfaceList(IAudioDecoder, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
begin
- CurrentAudioDecoder := IAudioDecoder(InterfaceList[i]);
+ CurrentAudioDecoder := InterfaceList[i] as IAudioDecoder;
if (not CurrentAudioDecoder.InitializeDecoder()) then
begin
Log.LogError('Initialize failed, Removing - '+ CurrentAudioDecoder.GetName);
@@ -671,7 +672,7 @@ begin
FilterInterfaceList(IAudioPlayback, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
begin
- CurrentAudioPlayback := IAudioPlayback(InterfaceList[i]);
+ CurrentAudioPlayback := InterfaceList[i] as IAudioPlayback;
if (CurrentAudioPlayback.InitializePlayback()) then
begin
DefaultAudioPlayback := CurrentAudioPlayback;
@@ -686,7 +687,7 @@ begin
FilterInterfaceList(IAudioInput, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
begin
- CurrentAudioInput := IAudioInput(InterfaceList[i]);
+ CurrentAudioInput := InterfaceList[i] as IAudioInput;
if (CurrentAudioInput.InitializeRecord()) then
begin
DefaultAudioInput := CurrentAudioInput;
@@ -719,7 +720,7 @@ begin
FilterInterfaceList(IVideoPlayback, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
begin
- VideoInterface := IVideoPlayback(InterfaceList[i]);
+ VideoInterface := InterfaceList[i] as IVideoPlayback;
if (VideoInterface.Init()) then
begin
DefaultVideoPlayback := VideoInterface;
@@ -734,7 +735,7 @@ begin
FilterInterfaceList(IVideoVisualization, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
begin
- VisualInterface := IVideoVisualization(InterfaceList[i]);
+ VisualInterface := InterfaceList[i] as IVideoVisualization;
if (VisualInterface.Init()) then
begin
DefaultVisualization := VisualInterface;
@@ -748,7 +749,7 @@ begin
// now that we have all interfaces, we can dump them
// TODO: move this to another place
- if FindCmdLineSwitch( cMediaInterfaces ) then
+ if FindCmdLineSwitch(cMediaInterfaces) then
begin
DumpMediaInterfaces();
halt;
@@ -772,27 +773,27 @@ begin
// finalize audio playback interfaces (should be done before the decoders)
FilterInterfaceList(IAudioPlayback, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
- IAudioPlayback(InterfaceList[i]).FinalizePlayback();
+ (InterfaceList[i] as IAudioPlayback).FinalizePlayback();
// finalize audio input interfaces
FilterInterfaceList(IAudioInput, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
- IAudioInput(InterfaceList[i]).FinalizeRecord();
+ (InterfaceList[i] as IAudioInput).FinalizeRecord();
// finalize audio decoder interfaces
FilterInterfaceList(IAudioDecoder, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
- IAudioDecoder(InterfaceList[i]).FinalizeDecoder();
+ (InterfaceList[i] as IAudioDecoder).FinalizeDecoder();
// finalize video interfaces
FilterInterfaceList(IVideoPlayback, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
- IVideoPlayback(InterfaceList[i]).Finalize();
+ (InterfaceList[i] as IVideoPlayback).Finalize();
// finalize audio decoder interfaces
FilterInterfaceList(IVideoVisualization, MediaManager, InterfaceList);
for i := 0 to InterfaceList.Count-1 do
- IVideoVisualization(InterfaceList[i]).Finalize();
+ (InterfaceList[i] as IVideoVisualization).Finalize();
InterfaceList.Free;
@@ -855,14 +856,14 @@ procedure TSoundLibrary.LoadSounds();
begin
UnloadSounds();
- Start := AudioPlayback.OpenSound(SoundPath + 'Common start.mp3');
- Back := AudioPlayback.OpenSound(SoundPath + 'Common back.mp3');
- Swoosh := AudioPlayback.OpenSound(SoundPath + 'menu swoosh.mp3');
- Change := AudioPlayback.OpenSound(SoundPath + 'select music change music 50.mp3');
- Option := AudioPlayback.OpenSound(SoundPath + 'option change col.mp3');
- Click := AudioPlayback.OpenSound(SoundPath + 'rimshot022b.mp3');
+ Start := AudioPlayback.OpenSound(SoundPath.Append('Common start.mp3'));
+ Back := AudioPlayback.OpenSound(SoundPath.Append('Common back.mp3'));
+ Swoosh := AudioPlayback.OpenSound(SoundPath.Append('menu swoosh.mp3'));
+ Change := AudioPlayback.OpenSound(SoundPath.Append('select music change music 50.mp3'));
+ Option := AudioPlayback.OpenSound(SoundPath.Append('option change col.mp3'));
+ Click := AudioPlayback.OpenSound(SoundPath.Append('rimshot022b.mp3'));
- BGMusic := AudioPlayback.OpenSound(SoundPath + 'Bebeto_-_Loop010.mp3');
+ BGMusic := AudioPlayback.OpenSound(SoundPath.Append('Bebeto_-_Loop010.mp3'));
if (BGMusic <> nil) then
BGMusic.Loop := True;
diff --git a/unicode/src/base/UPath.pas b/unicode/src/base/UPath.pas
index 5203e7eb..fc8c028e 100644
--- a/unicode/src/base/UPath.pas
+++ b/unicode/src/base/UPath.pas
@@ -45,14 +45,17 @@ type
IPath = interface;
{**
- * TUnicodeFileStream
+ * TBinaryFileStream (inherited from THandleStream)
*}
{$IFDEF MSWINDOWS}
- TUnicodeFileStream = class(TTntFileStream)
+ TBinaryFileStream = class(TTntFileStream)
{$ELSE}
- TUnicodeFileStream = class(TFileStream)
+ TBinaryFileStream = class(TFileStream)
{$ENDIF}
public
+ {**
+ * @seealso TFileStream.Create for valid Mode parameters
+ *}
constructor Create(const FileName: IPath; Mode: Word);
end;
@@ -65,13 +68,28 @@ type
procedure SaveToFile(const FileName: IPath);
end;
+ TTextFileStream = class(TBinaryFileStream)
+ function ReadLine(var Line: UTF8String): boolean; overload;
+ function ReadLine(var Line: AnsiString): boolean; overload;
+ procedure Write(Str: RawByteString);
+ procedure WriteLine(Line: RawByteString = '');
+ end;
+
+ {**
+ * pdKeep: Keep path as is, neither remove or append a delimiter
+ * pdAppend: Append a delimiter if path does not have a trailing one
+ * pdRemove: Remove a trailing delimiter from the path
+ *}
+ TPathDelimOption = (pdKeep, pdAppend, pdRemove);
+
IPathDynArray = array of IPath;
-
+
{**
* IPath
* The Path's pathname is immutable and cannot be changed after creation.
*}
IPath = interface
+ ['{686BF103-CE43-4598-B85D-A2C3AF950897}']
{**
* Returns the path as an UTF8 encoded string.
* If UseNativeDelim is set to true, the native path delimiter ('\' on win32)
@@ -100,11 +118,6 @@ type
*}
function Open(Mode: LongWord): THandle;
- {**
- * Note: Stream must be freed with TUniFileStream.Free after usage
- *}
- function OpenStream(Mode: Word): TUnicodeFileStream;
-
{** @seealso SysUtils.ExtractFileDrive() *}
function GetDrive(): IPath;
@@ -125,7 +138,9 @@ type
* The file itself is not changed, use Rename() for this task.
* @seealso SysUtils.ChangeFileExt()
*}
- function SetExtension(const Extension: IPath): IPath;
+ function SetExtension(const Extension: IPath): IPath; overload;
+ function SetExtension(const Extension: RawByteString): IPath; overload;
+ function SetExtension(const Extension: WideString): IPath; overload;
{**
* Returns the representation of the path relative to Basename.
@@ -143,16 +158,19 @@ type
* end with a path delimiter one is inserted in front of the Child path.
* Example: Path('parent').Append(Path('child')) -> Path('parent/child')
*}
- function Append(const Child: IPath): IPath;
+ function Append(const Child: IPath; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
+ function Append(const Child: RawByteString; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
+ function Append(const Child: WideString; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
{**
- * Splits the path into its components.
- * Example: C:\test\dir -> ['C:\', 'test\', 'dir']
+ * Splits the path into its components. Path delimiters are not removed from
+ * components.
+ * Example: C:\test\my\dir -> ['C:\', 'test\', 'my\', 'dir']
*}
function SplitDirs(): IPathDynArray;
{**
- * Returns the parent directory or PathNone if none exists.
+ * Returns the parent directory or PATH_NONE if none exists.
*}
function GetParent(): IPath;
@@ -171,10 +189,10 @@ type
function AdjustCase(AdjustAllLevels: boolean): IPath;
{** @seealso SysUtils.IncludeTrailingPathDelimiter() *}
- function IncludeTrailingPathDelimiter(): IPath;
+ function AppendPathDelim(): IPath;
{** @seealso SysUtils.ExcludeTrailingPathDelimiter() *}
- function ExcludeTrailingPathDelimiter(): IPath;
+ function RemovePathDelim(): IPath;
function Exists(): boolean;
function IsFile(): boolean;
@@ -188,12 +206,28 @@ type
function SetReadOnly(ReadOnly: boolean): boolean;
{**
+ * Checks if this path points to nothing, that means the path consists of
+ * the empty string '' and hence equals PATH_NONE.
+ * This is a shortcut for IPath.Equals('') or IPath.Equals(PATH_NONE).
+ * If IsUnset() returns true this path and PATH_NONE are equal but they must
+ * not be identical as the references might point to different objects.
+ *
+ * Example:
+ * Path('').Equals(PATH_EMPTY) -> true
+ * Path('') = PATH_EMPTY -> false
+ *}
+ function IsUnset(): boolean;
+ function IsSet(): boolean;
+
+ {**
* Compares this path with Other and returns true if both paths are
* equal. Both paths are expanded and trailing slashes excluded before
* comparison. If IgnoreCase is true, the case will be ignored on
* case-sensitive filesystems.
*}
- function Equals(const Other: IPath; IgnoreCase: boolean = false): boolean;
+ function Equals(const Other: IPath; IgnoreCase: boolean = false): boolean; overload;
+ function Equals(const Other: RawByteString; IgnoreCase: boolean = false): boolean; overload;
+ function Equals(const Other: WideString; IgnoreCase: boolean = false): boolean; overload;
{**
* Searches for a file in DirList. The Result is nil if the file was
@@ -222,17 +256,17 @@ type
* - On Apple only UTF8 is supported
* - Same applies to Unix with LC_CTYPE set to UTF8 encoding (default on newer systems)
*}
-function Path(const PathName: RawByteString): IPath; overload;
+function Path(const PathName: RawByteString; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
{**
* Creates a new path with the given UTF-16 pathname.
*}
-function Path(const PathName: WideString): IPath; overload;
+function Path(const PathName: WideString; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
{**
- * Returns a reference to a singleton with path simply set to ''.
+ * Returns a singleton for Path('').
*}
-function PathNone(): IPath;
+function PATH_NONE(): IPath;
implementation
@@ -247,7 +281,7 @@ type
{**
* Unifies the filename. Path-delimiters are replaced by '/'.
*}
- procedure Unify();
+ procedure Unify(DelimOption: TPathDelimOption);
{**
* Returns a copy of fName with path delimiters changed to '/'.
@@ -257,7 +291,7 @@ type
procedure AssertRefCount; inline;
public
- constructor Create(const Name: UTF8String);
+ constructor Create(const Name: UTF8String; DelimOption: TPathDelimOption);
destructor Destroy(); override;
function ToUTF8(UseNativeDelim: boolean): UTF8String;
@@ -265,27 +299,36 @@ type
function ToNative(): RawByteString;
function Open(Mode: LongWord): THandle;
- function OpenStream(Mode: Word): TUnicodeFileStream;
function GetDrive(): IPath;
function GetPath(): IPath;
function GetDir(): IPath;
function GetName(): IPath;
function GetExtension(): IPath;
- function SetExtension(const Extension: IPath): IPath;
+
+ function SetExtension(const Extension: IPath): IPath; overload;
+ function SetExtension(const Extension: RawByteString): IPath; overload;
+ function SetExtension(const Extension: WideString): IPath; overload;
+
function GetRelativePath(const BaseName: IPath): IPath;
function GetAbsolutePath(): IPath;
function GetParent(): IPath;
function SplitDirs(): IPathDynArray;
- function Append(const Child: IPath): IPath;
- function Equals(const Other: IPath; IgnoreCase: boolean): boolean;
+ function Append(const Child: IPath; DelimOption: TPathDelimOption): IPath; overload;
+ function Append(const Child: RawByteString; DelimOption: TPathDelimOption): IPath; overload;
+ function Append(const Child: WideString; DelimOption: TPathDelimOption): IPath; overload;
+
+ function Equals(const Other: IPath; IgnoreCase: boolean): boolean; overload;
+ function Equals(const Other: RawByteString; IgnoreCase: boolean): boolean; overload;
+ function Equals(const Other: WideString; IgnoreCase: boolean): boolean; overload;
+
function IsChildOf(const Parent: IPath; Direct: boolean): boolean;
function AdjustCase(AdjustAllLevels: boolean): IPath;
- function IncludeTrailingPathDelimiter(): IPath;
- function ExcludeTrailingPathDelimiter(): IPath;
+ function AppendPathDelim(): IPath;
+ function RemovePathDelim(): IPath;
function GetFileAge(): integer; overload;
function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
@@ -297,7 +340,10 @@ type
function SetAttr(Attr: Integer): boolean;
function IsReadOnly(): boolean;
function SetReadOnly(ReadOnly: boolean): boolean;
-
+
+ function IsUnset(): boolean;
+ function IsSet(): boolean;
+
function FileSearch(const DirList: IPath): IPath;
function CreateFile(): THandle;
@@ -308,34 +354,36 @@ type
function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
end;
-function Path(const PathName: RawByteString): IPath;
+function Path(const PathName: RawByteString; DelimOption: TPathDelimOption): IPath;
begin
if (IsUTF8String(PathName)) then
- Result := TPathImpl.Create(PathName)
+ Result := TPathImpl.Create(PathName, DelimOption)
else if (IsNativeUTF8()) then
- Result := PathNone
+ Result := PATH_NONE
else
- Result := TPathImpl.Create(AnsiToUtf8(PathName));
+ Result := TPathImpl.Create(AnsiToUtf8(PathName), DelimOption);
end;
-function Path(const PathName: WideString): IPath;
+function Path(const PathName: WideString; DelimOption: TPathDelimOption): IPath;
begin
- Result := TPathImpl.Create(UTF8Encode(PathName));
+ Result := TPathImpl.Create(UTF8Encode(PathName), DelimOption);
end;
procedure TPathImpl.AssertRefCount;
begin
+ {$IFDEF FPC}
if (FRefCount <= 0) then
raise Exception.Create('RefCount error: ' + inttostr(FRefCount));
+ {$ENDIF}
end;
-constructor TPathImpl.Create(const Name: UTF8String);
+constructor TPathImpl.Create(const Name: UTF8String; DelimOption: TPathDelimOption);
begin
inherited Create();
fName := Name;
- Unify();
+ Unify(DelimOption);
end;
destructor TPathImpl.Destroy();
@@ -343,7 +391,7 @@ begin
inherited;
end;
-procedure TPathImpl.Unify();
+procedure TPathImpl.Unify(DelimOption: TPathDelimOption);
var
I: integer;
begin
@@ -353,6 +401,12 @@ begin
if (fName[I] in ['\', '/']) and (fName[I] <> PathDelim) then
fName[I] := PathDelim;
end;
+
+ // Include/ExcludeTrailingPathDelimiter need PathDelim as path delimiter
+ case DelimOption of
+ pdAppend: fName := IncludeTrailingPathDelimiter(fName);
+ pdRemove: fName := ExcludeTrailingPathDelimiter(fName);
+ end;
end;
function TPathImpl.GetPortableString(): UTF8String;
@@ -430,6 +484,16 @@ begin
Result := FileSystem.ChangeFileExt(Self, Extension);
end;
+function TPathImpl.SetExtension(const Extension: RawByteString): IPath;
+begin
+ Result := SetExtension(Path(Extension));
+end;
+
+function TPathImpl.SetExtension(const Extension: WideString): IPath;
+begin
+ Result := SetExtension(Path(Extension));
+end;
+
function TPathImpl.GetRelativePath(const BaseName: IPath): IPath;
begin
AssertRefCount;
@@ -448,9 +512,9 @@ var
begin
AssertRefCount;
- Result := PathNone;
+ Result := PATH_NONE;
- CurPath := Self.ExcludeTrailingPathDelimiter();
+ CurPath := Self.RemovePathDelim();
// check if current path has a parent (no further '/')
if (Pos(PathDelim, CurPath.ToUTF8()) = 0) then
Exit;
@@ -491,7 +555,7 @@ begin
// TODO: remove this workaround for FPC bug
TmpPath := CurPath;
CurPath := TmpPath.GetParent();
- until (CurPath = PathNone);
+ until (CurPath = PATH_NONE);
// reverse list
SetLength(Result, Length(Components));
@@ -499,28 +563,56 @@ begin
Result[I] := Components[High(Components)-I];
end;
-function TPathImpl.Append(const Child: IPath): IPath;
+function TPathImpl.Append(const Child: IPath; DelimOption: TPathDelimOption): IPath;
+var
+ TmpResult: IPath;
begin
AssertRefCount;
if (fName = '') then
- Result := Child
+ TmpResult := Child
else
- Result := Path(Self.IncludeTrailingPathDelimiter().ToUTF8() + Child.ToUTF8());
+ TmpResult := Path(Self.AppendPathDelim().ToUTF8() + Child.ToUTF8());
+
+ case DelimOption of
+ pdKeep: Result := TmpResult;
+ pdAppend: Result := TmpResult.AppendPathDelim;
+ pdRemove: Result := TmpResult.RemovePathDelim;
+ end;
+end;
+
+function TPathImpl.Append(const Child: RawByteString; DelimOption: TPathDelimOption): IPath;
+begin
+ Result := Append(Path(Child), DelimOption);
+end;
+
+function TPathImpl.Append(const Child: WideString; DelimOption: TPathDelimOption): IPath;
+begin
+ Result := Append(Path(Child), DelimOption);
end;
function TPathImpl.Equals(const Other: IPath; IgnoreCase: boolean): boolean;
var
SelfPath, OtherPath: UTF8String;
begin
- SelfPath := Self.GetAbsolutePath().ExcludeTrailingPathDelimiter().ToUTF8();
- OtherPath := Other.GetAbsolutePath().ExcludeTrailingPathDelimiter().ToUTF8();
+ SelfPath := Self.GetAbsolutePath().RemovePathDelim().ToUTF8();
+ OtherPath := Other.GetAbsolutePath().RemovePathDelim().ToUTF8();
if (FileSystem.IsCaseSensitive() and not IgnoreCase) then
Result := (CompareStr(SelfPath, OtherPath) = 0)
else
Result := (CompareText(SelfPath, OtherPath) = 0);
end;
+function TPathImpl.Equals(const Other: RawByteString; IgnoreCase: boolean): boolean;
+begin
+ Result := Equals(Path(Other), IgnoreCase);
+end;
+
+function TPathImpl.Equals(const Other: WideString; IgnoreCase: boolean): boolean;
+begin
+ Result := Equals(Path(Other), IgnoreCase);
+end;
+
function TPathImpl.IsChildOf(const Parent: IPath; Direct: boolean): boolean;
var
SelfPath, ParentPath: UTF8String;
@@ -533,11 +625,11 @@ begin
// TODO: remove workaround for fpc refcount bug
TmpPath := Self.GetParent();
TmpPath2 := TmpPath.GetAbsolutePath();
- SelfPath := TmpPath2.IncludeTrailingPathDelimiter().ToUTF8();
+ SelfPath := TmpPath2.AppendPathDelim().ToUTF8();
// TODO: remove workaround for fpc refcount bug
TmpPath := Parent.GetAbsolutePath();
- ParentPath := TmpPath.IncludeTrailingPathDelimiter().ToUTF8();
+ ParentPath := TmpPath.AppendPathDelim().ToUTF8();
// simply check if this paths parent path (SelfPath) equals ParentPath
Result := (SelfPath = ParentPath);
@@ -546,11 +638,11 @@ begin
begin
// TODO: remove workaround for fpc refcount bug
TmpPath := Self.GetAbsolutePath();
- SelfPath := TmpPath.IncludeTrailingPathDelimiter().ToUTF8();
+ SelfPath := TmpPath.AppendPathDelim().ToUTF8();
// TODO: remove workaround for fpc refcount bug
TmpPath := Parent.GetAbsolutePath();
- ParentPath := TmpPath.IncludeTrailingPathDelimiter().ToUTF8();
+ ParentPath := TmpPath.AppendPathDelim().ToUTF8();
if (Length(SelfPath) <= Length(ParentPath)) then
Exit;
@@ -583,12 +675,12 @@ begin
// extract name component of current path
// TODO: remove workaround for fpc refcount bug
- TmpPath := CurPath.ExcludeTrailingPathDelimiter();
+ TmpPath := CurPath.RemovePathDelim();
LocalName := TmpPath.GetName();
// try to adjust parent
OldParent := CurPath.GetParent();
- if (OldParent <> PathNone) then
+ if (OldParent <> PATH_NONE) then
begin
if (not AdjustAllLevels) then
begin
@@ -663,13 +755,13 @@ begin
end;
end;
-function TPathImpl.IncludeTrailingPathDelimiter(): IPath;
+function TPathImpl.AppendPathDelim(): IPath;
begin
AssertRefCount;
Result := FileSystem.IncludeTrailingPathDelimiter(Self);
end;
-function TPathImpl.ExcludeTrailingPathDelimiter(): IPath;
+function TPathImpl.RemovePathDelim(): IPath;
begin
AssertRefCount;
Result := FileSystem.ExcludeTrailingPathDelimiter(Self);
@@ -693,11 +785,6 @@ begin
Result := FileSystem.FileOpen(Self, Mode);
end;
-function TPathImpl.OpenStream(Mode: Word): TUnicodeFileStream;
-begin
- Result := TUnicodeFileStream.Create(Self, Mode);
-end;
-
function TPathImpl.GetFileAge(): integer;
begin
Result := FileSystem.FileAge(Self);
@@ -759,6 +846,16 @@ begin
Result := FileSystem.FileSetReadOnly(Self, ReadOnly);
end;
+function TPathImpl.IsUnset(): boolean;
+begin
+ Result := (fName = '');
+end;
+
+function TPathImpl.IsSet(): boolean;
+begin
+ Result := (fName <> '');
+end;
+
function TPathImpl.FileSearch(const DirList: IPath): IPath;
begin
AssertRefCount;
@@ -786,23 +883,38 @@ begin
end;
-{ TUnicodeFileStream }
+{ TBinaryFileStream }
+constructor TBinaryFileStream.Create(const FileName: IPath; Mode: Word);
+begin
{$IFDEF MSWINDOWS}
+ inherited Create(FileName.ToWide(), Mode);
+{$ELSE}
+ inherited Create(FileName.ToNative(), Mode);
+{$ENDIF}
+end;
+
+{ TTextFileStream }
-constructor TUnicodeFileStream.Create(const FileName: IPath; Mode: Word);
+function TTextFileStream.ReadLine(var Line: UTF8String): boolean;
begin
- inherited Create(FileName.ToWide(), Mode);
+ // TODO
end;
-{$ELSE}
+function TTextFileStream.ReadLine(var Line: AnsiString): boolean;
+begin
+ // TODO
+end;
-constructor TUnicodeFileStream.Create(const FileName: IPath; Mode: Word);
+procedure TTextFileStream.WriteLine(Line: RawByteString);
begin
- inherited Create(FileName.ToNative(), Mode);
+ Self.WriteBuffer(Line[1], Length(Line));
end;
-{$ENDIF}
+procedure TTextFileStream.Write(Str: RawByteString);
+begin
+ Self.WriteBuffer(Str[1], Length(Str));
+end;
{ TUnicodeMemoryStream }
@@ -810,7 +922,7 @@ procedure TUnicodeMemoryStream.LoadFromFile(const FileName: IPath);
var
Stream: TStream;
begin
- Stream := TUnicodeFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ Stream := TBinaryFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
@@ -822,7 +934,7 @@ procedure TUnicodeMemoryStream.SaveToFile(const FileName: IPath);
var
Stream: TStream;
begin
- Stream := TUnicodeFileStream.Create(FileName, fmCreate);
+ Stream := TBinaryFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
@@ -831,17 +943,17 @@ begin
end;
var
- PathNone_Singelton: IPath;
+ PATH_NONE_Singelton: IPath;
-function PathNone(): IPath;
+function PATH_NONE(): IPath;
begin
- Result := PathNone_Singelton;
+ Result := PATH_NONE_Singelton;
end;
initialization
- PathNone_Singelton := Path('');
+ PATH_NONE_Singelton := Path('');
finalization
- PathNone_Singelton := nil;
+ PATH_NONE_Singelton := nil;
end.
diff --git a/unicode/src/base/UPathUtils.pas b/unicode/src/base/UPathUtils.pas
index 4c4d3bc0..c2bcdd4b 100644
--- a/unicode/src/base/UPathUtils.pas
+++ b/unicode/src/base/UPathUtils.pas
@@ -35,28 +35,29 @@ interface
uses
SysUtils,
- Classes;
+ Classes,
+ UPath;
var
// Absolute Paths
- GamePath: string;
- SoundPath: string;
- SongPaths: TStringList;
- LogPath: string;
- ThemePath: string;
- SkinsPath: string;
- ScreenshotsPath: string;
- CoverPaths: TStringList;
- LanguagesPath: string;
- PluginPath: string;
- VisualsPath: string;
- FontPath: string;
- ResourcesPath: string;
- PlayListPath: string;
-
-function FindPath(out PathResult: string; const RequestedPath: string; NeedsWritePermission: boolean): boolean;
+ GamePath: IPath;
+ SoundPath: IPath;
+ SongPaths: IInterfaceList;
+ LogPath: IPath;
+ ThemePath: IPath;
+ SkinsPath: IPath;
+ ScreenshotsPath: IPath;
+ CoverPaths: IInterfaceList;
+ LanguagesPath: IPath;
+ PluginPath: IPath;
+ VisualsPath: IPath;
+ FontPath: IPath;
+ ResourcesPath: IPath;
+ PlaylistPath: IPath;
+
+function FindPath(out PathResult: IPath; const RequestedPath: IPath; NeedsWritePermission: boolean): boolean;
procedure InitializePaths;
-procedure AddSongPath(const Path: string);
+procedure AddSongPath(const Path: IPath);
implementation
@@ -66,33 +67,38 @@ uses
UCommandLine,
ULog;
-procedure AddSpecialPath(var PathList: TStringList; const Path: string);
+procedure AddSpecialPath(var PathList: IInterfaceList; const Path: IPath);
var
Index: integer;
- PathAbs, OldPathAbs: string;
+ PathAbs, PathTmp: IPath;
+ OldPath, OldPathAbs, OldPathTmp: IPath;
begin
if (PathList = nil) then
- PathList := TStringList.Create;
+ PathList := TInterfaceList.Create;
- if (Path = '') or not ForceDirectories(Path) then
+ if Path.Equals(PATH_NONE) or not Path.CreateDirectory(true) then
Exit;
- PathAbs := IncludeTrailingPathDelimiter(ExpandFileName(Path));
+ PathTmp := Path.GetAbsolutePath();
+ PathAbs := PathTmp.AppendPathDelim();
// check if path or a part of the path was already added
for Index := 0 to PathList.Count-1 do
begin
- OldPathAbs := IncludeTrailingPathDelimiter(ExpandFileName(PathList[Index]));
+ OldPath := PathList[Index] as IPath;
+ OldPathTmp := OldPath.GetAbsolutePath();
+ OldPathAbs := OldPathTmp.AppendPathDelim();
+
// check if the new directory is a sub-directory of a previously added one.
// This is also true, if both paths point to the same directories.
- if (AnsiStartsText(OldPathAbs, PathAbs)) then
+ if (OldPathAbs.IsChildOf(PathAbs, false) or OldPathAbs.Equals(PathAbs)) then
begin
// ignore the new path
Exit;
end;
// check if a previously added directory is a sub-directory of the new one.
- if (AnsiStartsText(PathAbs, OldPathAbs)) then
+ if (PathAbs.IsChildOf(OldPathAbs, false)) then
begin
// replace the old with the new one.
PathList[Index] := PathAbs;
@@ -103,12 +109,12 @@ begin
PathList.Add(PathAbs);
end;
-procedure AddSongPath(const Path: string);
+procedure AddSongPath(const Path: IPath);
begin
AddSpecialPath(SongPaths, Path);
end;
-procedure AddCoverPath(const Path: string);
+procedure AddCoverPath(const Path: IPath);
begin
AddSpecialPath(CoverPaths, Path);
end;
@@ -117,30 +123,27 @@ end;
* Initialize a path variable
* After setting paths, make sure that paths exist
*)
-function FindPath(out PathResult: string;
- const RequestedPath: string;
- NeedsWritePermission: boolean)
- : boolean;
+function FindPath(
+ out PathResult: IPath;
+ const RequestedPath: IPath;
+ NeedsWritePermission: boolean): boolean;
begin
Result := false;
- if (RequestedPath = '') then
+ if (RequestedPath.Equals(PATH_NONE)) then
Exit;
// Make sure the directory exists
- if (not ForceDirectories(RequestedPath)) then
+ if (not RequestedPath.CreateDirectory(true)) then
begin
- PathResult := '';
+ PathResult := PATH_NONE;
Exit;
end;
- PathResult := IncludeTrailingPathDelimiter(RequestedPath);
+ PathResult := RequestedPath.AppendPathDelim();
- if (NeedsWritePermission) and
- (FileIsReadOnly(RequestedPath)) then
- begin
+ if (NeedsWritePermission) and RequestedPath.IsReadOnly() then
Exit;
- end;
Result := true;
end;
@@ -149,40 +152,45 @@ end;
* Function sets all absolute paths e.g. song path and makes sure the directorys exist
*)
procedure InitializePaths;
+var
+ SharedPath, UserPath: IPath;
begin
// Log directory (must be writable)
if (not FindPath(LogPath, Platform.GetLogPath, true)) then
begin
Log.FileOutputEnabled := false;
- Log.LogWarn('Log directory "'+ Platform.GetLogPath +'" not available', 'InitializePaths');
+ Log.LogWarn('Log directory "'+ Platform.GetLogPath.ToNative +'" not available', 'InitializePaths');
end;
- FindPath(SoundPath, Platform.GetGameSharedPath + 'sounds', false);
- FindPath(ThemePath, Platform.GetGameSharedPath + 'themes', false);
- FindPath(SkinsPath, Platform.GetGameSharedPath + 'themes', false);
- FindPath(LanguagesPath, Platform.GetGameSharedPath + 'languages', false);
- FindPath(PluginPath, Platform.GetGameSharedPath + 'plugins', false);
- FindPath(VisualsPath, Platform.GetGameSharedPath + 'visuals', false);
- FindPath(FontPath, Platform.GetGameSharedPath + 'fonts', false);
- FindPath(ResourcesPath, Platform.GetGameSharedPath + 'resources', false);
+ SharedPath := Platform.GetGameSharedPath;
+ UserPath := Platform.GetGameUserPath;
+
+ FindPath(SoundPath, SharedPath.Append('sounds'), false);
+ FindPath(ThemePath, SharedPath.Append('themes'), false);
+ FindPath(SkinsPath, SharedPath.Append('themes'), false);
+ FindPath(LanguagesPath, SharedPath.Append('languages'), false);
+ FindPath(PluginPath, SharedPath.Append('plugins'), false);
+ FindPath(VisualsPath, SharedPath.Append('visuals'), false);
+ FindPath(FontPath, SharedPath.Append('fonts'), false);
+ FindPath(ResourcesPath, SharedPath.Append('resources'), false);
// Playlists are not shared as we need one directory to write too
- FindPath(PlaylistPath, Platform.GetGameUserPath + 'playlists', true);
+ FindPath(PlaylistPath, UserPath.Append('playlists'), true);
// Screenshot directory (must be writable)
- if (not FindPath(ScreenshotsPath, Platform.GetGameUserPath + 'screenshots', true)) then
+ if (not FindPath(ScreenshotsPath, UserPath.Append('screenshots'), true)) then
begin
- Log.LogWarn('Screenshot directory "'+ Platform.GetGameUserPath +'" not available', 'InitializePaths');
+ Log.LogWarn('Screenshot directory "'+ UserPath.ToNative +'" not available', 'InitializePaths');
end;
// Add song paths
AddSongPath(Params.SongPath);
- AddSongPath(Platform.GetGameSharedPath + 'songs');
- AddSongPath(Platform.GetGameUserPath + 'songs');
+ AddSongPath(SharedPath.Append('songs'));
+ AddSongPath(UserPath.Append('songs'));
// Add category cover paths
- AddCoverPath(Platform.GetGameSharedPath + 'covers');
- AddCoverPath(Platform.GetGameUserPath + 'covers');
+ AddCoverPath(SharedPath.Append('covers'));
+ AddCoverPath(UserPath.Append('covers'));
end;
end.
diff --git a/unicode/src/base/UPlatform.pas b/unicode/src/base/UPlatform.pas
index 6f13481c..11c67fa7 100644
--- a/unicode/src/base/UPlatform.pas
+++ b/unicode/src/base/UPlatform.pas
@@ -39,28 +39,20 @@ interface
{$I switches.inc}
uses
- Classes;
+ Classes,
+ UPath;
type
- TDirectoryEntry = record
- Name: WideString;
- IsDirectory: boolean;
- IsFile: boolean;
- end;
-
- TDirectoryEntryArray = array of TDirectoryEntry;
-
TPlatform = class
- function GetExecutionDir(): string;
+ function GetExecutionDir(): IPath;
procedure Init; virtual;
- function DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray; virtual; abstract;
+
function TerminateIfAlreadyRunning(var WndTitle: string): boolean; virtual;
- function FindSongFile(Dir, Mask: WideString): WideString; virtual;
procedure Halt; virtual;
- function GetLogPath: WideString; virtual; abstract;
- function GetGameSharedPath: WideString; virtual; abstract;
- function GetGameUserPath: WideString; virtual; abstract;
- function CopyFile(const Source, Target: WideString; FailIfExists: boolean): boolean; virtual;
+
+ function GetLogPath: IPath; virtual; abstract;
+ function GetGameSharedPath: IPath; virtual; abstract;
+ function GetGameUserPath: IPath; virtual; abstract;
end;
function Platform(): TPlatform;
@@ -76,7 +68,9 @@ uses
{$ELSEIF Defined(UNIX)}
UPlatformLinux,
{$IFEND}
- ULog;
+ ULog,
+ UUnicodeUtils,
+ UFilesystem;
// I modified it to use the Platform_singleton in this location (in the implementation)
@@ -109,9 +103,13 @@ end;
{**
* Returns the directory of the executable
*}
-function TPlatform.GetExecutionDir(): string;
+function TPlatform.GetExecutionDir(): IPath;
+var
+ ExecName, ExecDir: IPath;
begin
- Result := ExpandFileName(ExtractFilePath(ParamStr(0)));
+ ExecName := Path(ParamStr(0));
+ ExecDir := ExecName.GetPath;
+ Result := ExecDir.GetAbsolutePath();
end;
(**
@@ -122,65 +120,6 @@ begin
Result := false;
end;
-(**
- * Default FindSongFile() implementation
- *)
-function TPlatform.FindSongFile(Dir, Mask: WideString): WideString;
-var
- SR: TSearchRec; // for parsing song directory
-begin
- Result := '';
- if SysUtils.FindFirst(Dir + Mask, faDirectory, SR) = 0 then
- begin
- Result := SR.Name;
- end;
- SysUtils.FindClose(SR);
-end;
-
-function TPlatform.CopyFile(const Source, Target: WideString; FailIfExists: boolean): boolean;
-const
- COPY_BUFFER_SIZE = 4096; // a good tradeoff between speed and memory consumption
-var
- SourceFile, TargetFile: TFileStream;
- FileCopyBuffer: array [0..COPY_BUFFER_SIZE-1] of byte; // temporary copy-buffer.
- NumberOfBytes: integer; // number of bytes read from SourceFile
-begin
- Result := false;
- SourceFile := nil;
- TargetFile := nil;
-
- // if overwrite is disabled return if the target file already exists
- if (FailIfExists and FileExists(Target)) then
- Exit;
-
- try
- try
- // open source and target file (might throw an exception on error)
- SourceFile := TFileStream.Create(Source, fmOpenRead);
- TargetFile := TFileStream.Create(Target, fmCreate or fmOpenWrite);
-
- while true do
- begin
- // read a block from the source file and check for errors or EOF
- NumberOfBytes := SourceFile.Read(FileCopyBuffer, SizeOf(FileCopyBuffer));
- if (NumberOfBytes <= 0) then
- Break;
- // write block to target file and check if everything was written
- if (TargetFile.Write(FileCopyBuffer, NumberOfBytes) <> NumberOfBytes) then
- Exit;
- end;
- except
- Exit;
- end;
- finally
- SourceFile.Free;
- TargetFile.Free;
- end;
-
- Result := true;
-end;
-
-
initialization
{$IF Defined(MSWINDOWS)}
Platform_singleton := TPlatformWindows.Create;
diff --git a/unicode/src/base/UPlatformLinux.pas b/unicode/src/base/UPlatformLinux.pas
index 7efeb963..f318d49d 100644
--- a/unicode/src/base/UPlatformLinux.pas
+++ b/unicode/src/base/UPlatformLinux.pas
@@ -44,15 +44,13 @@ type
UseLocalDirs: boolean;
procedure DetectLocalExecution();
- function GetHomeDir(): string;
+ function GetHomeDir(): IPath;
public
procedure Init; override;
-
- function DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: Boolean): TDirectoryEntryArray; override;
-
- function GetLogPath : WideString; override;
- function GetGameSharedPath : WideString; override;
- function GetGameUserPath : WideString; override;
+
+ function GetLogPath : IPath; override;
+ function GetGameSharedPath : IPath; override;
+ function GetGameUserPath : IPath; override;
end;
implementation
@@ -60,9 +58,7 @@ implementation
uses
UCommandLine,
BaseUnix,
- {$IF FPC_VERSION_INT >= 2002002}
pwd,
- {$IFEND}
SysUtils,
ULog;
@@ -88,113 +84,65 @@ end;
*}
procedure TPlatformLinux.DetectLocalExecution();
var
- LocalDir: string;
+ LocalDir, LanguageDir: IPath;
begin
- LocalDir := GetExecutionDir();
-
// we just check if the 'languages' folder exists in the
// directory of the executable. If so -> local execution.
- UseLocalDirs := (DirectoryExists(LocalDir + 'languages'));
-end;
-
-function TPlatformLinux.DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: Boolean): TDirectoryEntryArray;
-var
- i: Integer;
- TheDir : pDir;
- ADirent : pDirent;
- lAttrib : integer;
-begin
- i := 0;
- Filter := LowerCase(Filter);
-
- TheDir := FpOpenDir(Dir);
- if Assigned(TheDir) then
- begin
- repeat
- ADirent := FpReadDir(TheDir^);
-
- if Assigned(ADirent) and (ADirent^.d_name <> '.') and (ADirent^.d_name <> '..') then
- begin
- lAttrib := FileGetAttr(Dir + ADirent^.d_name);
- if ReturnAllSubDirs and ((lAttrib and faDirectory) <> 0) then
- begin
- SetLength(Result, i + 1);
- Result[i].Name := ADirent^.d_name;
- Result[i].IsDirectory := true;
- Result[i].IsFile := false;
- i := i + 1;
- end
- else if (Length(Filter) = 0) or (Pos( Filter, LowerCase(ADirent^.d_name)) > 0) then
- begin
- SetLength(Result, i + 1);
- Result[i].Name := ADirent^.d_name;
- Result[i].IsDirectory := false;
- Result[i].IsFile := true;
- i := i + 1;
- end;
- end;
- until (ADirent = nil);
-
- FpCloseDir(TheDir^);
- end;
+ LocalDir := GetExecutionDir();
+ LanguageDir := LocalDir.Append('languages');
+ UseLocalDirs := LanguageDir.IsDirectory;
end;
-function TPlatformLinux.GetLogPath: WideString;
+function TPlatformLinux.GetLogPath: IPath;
begin
if UseLocalDirs then
Result := GetExecutionDir()
else
- Result := GetGameUserPath() + 'logs/';
+ Result := GetGameUserPath().Append('logs', pdAppend);
// create non-existing directories
- ForceDirectories(Result);
+ Result.CreateDirectory(true);
end;
-function TPlatformLinux.GetGameSharedPath: WideString;
+function TPlatformLinux.GetGameSharedPath: IPath;
begin
if UseLocalDirs then
Result := GetExecutionDir()
else
- Result := IncludeTrailingPathDelimiter(INSTALL_DATADIR);
+ Result := Path(INSTALL_DATADIR, pdAppend);
end;
-function TPlatformLinux.GetGameUserPath: WideString;
+function TPlatformLinux.GetGameUserPath: IPath;
begin
if UseLocalDirs then
Result := GetExecutionDir()
else
- Result := GetHomeDir() + '.ultrastardx/';
+ Result := GetHomeDir().Append('.ultrastardx', pdAppend);
end;
{**
* Returns the user's home directory terminated by a path delimiter
*}
-function TPlatformLinux.GetHomeDir(): string;
-{$IF FPC_VERSION_INT >= 2002002}
+function TPlatformLinux.GetHomeDir(): IPath;
var
PasswdEntry: PPasswd;
-{$IFEND}
begin
- Result := '';
+ Result := PATH_NONE;
- {$IF FPC_VERSION_INT >= 2002002}
// try to retrieve the info from passwd
PasswdEntry := FpGetpwuid(FpGetuid());
if (PasswdEntry <> nil) then
- Result := PasswdEntry.pw_dir;
- {$IFEND}
+ Result := Path(PasswdEntry.pw_dir);
// fallback if passwd does not contain the path
- if (Result = '') then
- Result := GetEnvironmentVariable('HOME');
+ if (Result.IsUnset) then
+ Result := Path(GetEnvironmentVariable('HOME'));
// add trailing path delimiter (normally '/')
- if (Result <> '') then
- Result := IncludeTrailingPathDelimiter(Result);
+ if (Result.IsSet) then
+ Result := Result.AppendPathDelim();
- {$IF FPC_VERSION_INT >= 2002002}
// GetUserDir() is another function that returns a user path.
// It uses env-var HOME or a fallback to a temp-dir.
//Result := GetUserDir();
- {$IFEND}
end;
end.
diff --git a/unicode/src/base/UPlatformMacOSX.pas b/unicode/src/base/UPlatformMacOSX.pas
index 08ad247d..aa1eb7cf 100644
--- a/unicode/src/base/UPlatformMacOSX.pas
+++ b/unicode/src/base/UPlatformMacOSX.pas
@@ -36,7 +36,8 @@ interface
uses
Classes,
ULog,
- UPlatform;
+ UPlatform,
+ UPath;
type
{**
@@ -93,13 +94,13 @@ type
* GetBundlePath returns the path to the application bundle
* UltraStarDeluxe.app.
*}
- function GetBundlePath: WideString;
+ function GetBundlePath: IPath;
{**
* GetApplicationSupportPath returns the path to
* $HOME/Library/Application Support/UltraStarDeluxe.
*}
- function GetApplicationSupportPath: WideString;
+ function GetApplicationSupportPath: IPath;
{**
* see the description of @link(Init).
@@ -116,30 +117,24 @@ type
procedure Init; override;
{**
- * DirectoryFindFiles returns all entries of a folder with names and
- * booleans about their type, i.e. file or directory.
- *}
- function DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray; override;
-
- {**
* GetLogPath returns the path for log messages. Currently it is set to
* $HOME/Library/Application Support/UltraStarDeluxe/Log.
*}
- function GetLogPath : WideString; override;
+ function GetLogPath : IPath; override;
{**
* GetGameSharedPath returns the path for shared resources. Currently it
* is set to /Library/Application Support/UltraStarDeluxe.
* However it is not used.
*}
- function GetGameSharedPath : WideString; override;
+ function GetGameSharedPath : IPath; override;
{**
* GetGameUserPath returns the path for user resources. Currently it is
* set to $HOME/Library/Application Support/UltraStarDeluxe.
* This is where a user can add songs, themes, ....
*}
- function GetGameUserPath : WideString; override;
+ function GetGameUserPath : IPath; override;
end;
implementation
@@ -248,87 +243,38 @@ begin
ChDir(OldBaseDir);
end;
-function TPlatformMacOSX.GetBundlePath: WideString;
+function TPlatformMacOSX.GetBundlePath: IPath;
var
- i, pos : integer;
+ TmpPath: IPath;
begin
// Mac applications are packaged in folders.
// Cutting the last two folders yields the application folder.
-
- Result := GetExecutionDir();
- for i := 1 to 2 do
- begin
- pos := Length(Result);
- repeat
- Delete(Result, pos, 1);
- pos := Length(Result);
- until (pos = 0) or (Result[pos] = '/');
- end;
+ TmpPath := GetExecutionDir().GetParent;
+ Result := TmpPath.GetParent;
end;
-function TPlatformMacOSX.GetApplicationSupportPath: WideString;
+function TPlatformMacOSX.GetApplicationSupportPath: IPath;
const
PathName : string = '/Library/Application Support/UltraStarDeluxe';
+ HomeDir: IPath;
begin
- Result := GetEnvironmentVariable('HOME') + PathName + '/';
+ HomeDir := GetEnvironmentVariable('HOME');
+ Result := HomeDir.Append(PathName, true);
end;
-function TPlatformMacOSX.GetLogPath: WideString;
+function TPlatformMacOSX.GetLogPath: IPath;
begin
- Result := GetApplicationSupportPath + 'Logs';
+ Result := GetApplicationSupportPath.Append('Logs');
end;
-function TPlatformMacOSX.GetGameSharedPath: WideString;
+function TPlatformMacOSX.GetGameSharedPath: IPath;
begin
Result := GetApplicationSupportPath;
end;
-function TPlatformMacOSX.GetGameUserPath: WideString;
+function TPlatformMacOSX.GetGameUserPath: IPath;
begin
Result := GetApplicationSupportPath;
end;
-{ TODO: REMOVE }
-function TPlatformMacOSX.DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray;
-var
- i : integer;
- TheDir : pdir;
- ADirent : pDirent;
- lAttrib : integer;
-begin
- i := 0;
- Filter := LowerCase(Filter);
-
- TheDir := FpOpenDir(Dir);
- if Assigned(TheDir) then
- begin
- repeat
- ADirent := FpReadDir(TheDir^);
-
- if Assigned(ADirent) and (ADirent^.d_name <> '.') and (ADirent^.d_name <> '..') then
- begin
- lAttrib := FileGetAttr(Dir + ADirent^.d_name);
- if ReturnAllSubDirs and ((lAttrib and faDirectory) <> 0) then
- begin
- SetLength(Result, i + 1);
- Result[i].Name := ADirent^.d_name;
- Result[i].IsDirectory := true;
- Result[i].IsFile := false;
- i := i + 1;
- end
- else if (Length(Filter) = 0) or (Pos( Filter, LowerCase(ADirent^.d_name)) > 0) then
- begin
- SetLength(Result, i + 1);
- Result[i].Name := ADirent^.d_name;
- Result[i].IsDirectory := false;
- Result[i].IsFile := true;
- i := i + 1;
- end;
- end;
- until (ADirent = nil);
-
- FpCloseDir(TheDir^);
- end;
-end;
-
end.
diff --git a/unicode/src/base/UPlatformWindows.pas b/unicode/src/base/UPlatformWindows.pas
index e198958a..2d0bd212 100644
--- a/unicode/src/base/UPlatformWindows.pas
+++ b/unicode/src/base/UPlatformWindows.pas
@@ -38,21 +38,19 @@ interface
uses
Classes,
- UPlatform;
+ UPlatform,
+ UPath;
type
TPlatformWindows = class(TPlatform)
private
- function GetSpecialPath(CSIDL: integer): WideString;
+ function GetSpecialPath(CSIDL: integer): IPath;
public
- function DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: Boolean): TDirectoryEntryArray; override;
function TerminateIfAlreadyRunning(var WndTitle: String): Boolean; override;
- function GetLogPath: WideString; override;
- function GetGameSharedPath: WideString; override;
- function GetGameUserPath: WideString; override;
-
- function CopyFile(const Source, Target: WideString; FailIfExists: boolean): boolean; override;
+ function GetLogPath: IPath; override;
+ function GetGameSharedPath: IPath; override;
+ function GetGameUserPath: IPath; override;
end;
implementation
@@ -63,62 +61,10 @@ uses
Windows,
UConfig;
-type
- TSearchRecW = record
- Time: Integer;
- Size: Integer;
- Attr: Integer;
- Name: WideString;
- ExcludeAttr: Integer;
- FindHandle: THandle;
- FindData: TWin32FindDataW;
- end;
-
-function FindFirstW(const Path: WideString; Attr: Integer; var F: TSearchRecW): Integer; forward;
-function FindNextW(var F: TSearchRecW): Integer; forward;
-procedure FindCloseW(var F: TSearchRecW); forward;
+(*
function FindMatchingFileW(var F: TSearchRecW): Integer; forward;
function DirectoryExistsW(const Directory: widestring): Boolean; forward;
-function FindFirstW(const Path: widestring; Attr: Integer; var F: TSearchRecW): Integer;
-const
- faSpecial = faHidden or faSysFile or faVolumeID or faDirectory;
-begin
- F.ExcludeAttr := not Attr and faSpecial;
-{$IFDEF Delphi}
- F.FindHandle := FindFirstFileW(PWideChar(Path), F.FindData);
-{$ELSE}
- F.FindHandle := FindFirstFileW(PWideChar(Path), @F.FindData);
-{$ENDIF}
- if F.FindHandle <> INVALID_HANDLE_VALUE then
- begin
- Result := FindMatchingFileW(F);
- if Result <> 0 then FindCloseW(F);
- end else
- Result := GetLastError;
-end;
-
-function FindNextW(var F: TSearchRecW): Integer;
-begin
-{$IFDEF Delphi}
- if FindNextFileW(F.FindHandle, F.FindData) then
-{$ELSE}
- if FindNextFileW(F.FindHandle, @F.FindData) then
-{$ENDIF}
- Result := FindMatchingFileW(F)
- else
- Result := GetLastError;
-end;
-
-procedure FindCloseW(var F: TSearchRecW);
-begin
- if F.FindHandle <> INVALID_HANDLE_VALUE then
- begin
- Windows.FindClose(F.FindHandle);
- F.FindHandle := INVALID_HANDLE_VALUE;
- end;
-end;
-
function FindMatchingFileW(var F: TSearchRecW): Integer;
var
LocalFileTime: TFileTime;
@@ -151,6 +97,7 @@ begin
Code := GetFileAttributesW(PWideChar(Directory));
Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
end;
+*)
//------------------------------
//Start more than One Time Prevention
@@ -180,41 +127,6 @@ begin
end;
end;
-function TPlatformWindows.DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: Boolean): TDirectoryEntryArray;
-var
- i : Integer;
- SR : TSearchRecW;
- Attrib : Integer;
-begin
- i := 0;
- Filter := LowerCase(Filter);
-
- if FindFirstW(Dir + '*', faAnyFile or faDirectory, SR) = 0 then
- repeat
- if (SR.Name <> '.') and (SR.Name <> '..') then
- begin
- Attrib := FileGetAttr(Dir + SR.name);
- if ReturnAllSubDirs and ((Attrib and faDirectory) <> 0) then
- begin
- SetLength( Result, i + 1);
- Result[i].Name := SR.name;
- Result[i].IsDirectory := true;
- Result[i].IsFile := false;
- i := i + 1;
- end
- else if (Length(Filter) = 0) or (Pos( Filter, LowerCase(SR.Name)) > 0) then
- begin
- SetLength( Result, i + 1);
- Result[i].Name := SR.Name;
- Result[i].IsDirectory := false;
- Result[i].IsFile := true;
- i := i + 1;
- end;
- end;
- until FindNextW(SR) <> 0;
- FindCloseW(SR);
-end;
-
(**
* Returns the path of a special folder.
*
@@ -225,37 +137,30 @@ end;
* CSIDL_PERSONAL (e.g. C:\Documents and Settings\username\My Documents)
* CSIDL_MYMUSIC (e.g. C:\Documents and Settings\username\My Documents\My Music)
*)
-function TPlatformWindows.GetSpecialPath(CSIDL: integer): WideString;
+function TPlatformWindows.GetSpecialPath(CSIDL: integer): IPath;
var
Buffer: array [0..MAX_PATH-1] of WideChar;
begin
-{$IF Defined(Delphi) or (FPC_VERSION_INT >= 2002002)} // >= 2.2.2
if (SHGetSpecialFolderPathW(0, @Buffer, CSIDL, false)) then
- Result := Buffer
+ Result := Path(Buffer)
else
-{$IFEND}
- Result := '';
+ Result := PATH_NONE;
end;
-function TPlatformWindows.GetLogPath: WideString;
+function TPlatformWindows.GetLogPath: IPath;
begin
Result := GetExecutionDir();
end;
-function TPlatformWindows.GetGameSharedPath: WideString;
+function TPlatformWindows.GetGameSharedPath: IPath;
begin
Result := GetExecutionDir();
end;
-function TPlatformWindows.GetGameUserPath: WideString;
+function TPlatformWindows.GetGameUserPath: IPath;
begin
- //Result := GetSpecialPath(CSIDL_APPDATA) + PathDelim + 'UltraStarDX' + PathDelim;
+ //Result := GetSpecialPath(CSIDL_APPDATA).Append('UltraStarDX', pdAppend);
Result := GetExecutionDir();
end;
-function TPlatformWindows.CopyFile(const Source, Target: WideString; FailIfExists: boolean): boolean;
-begin
- Result := Windows.CopyFileW(PWideChar(Source), PWideChar(Target), FailIfExists);
-end;
-
end.
diff --git a/unicode/src/base/UPlaylist.pas b/unicode/src/base/UPlaylist.pas
index cc983a9e..09c196ef 100644
--- a/unicode/src/base/UPlaylist.pas
+++ b/unicode/src/base/UPlaylist.pas
@@ -34,7 +34,9 @@ interface
{$I switches.inc}
uses
+ Classes,
USong,
+ UPath,
UPathUtils;
type
@@ -47,8 +49,8 @@ type
APlaylistItem = array of TPlaylistItem;
TPlaylist = record
- Name: string;
- Filename: String;
+ Name: UTF8String;
+ Filename: IPath;
Items: APlaylistItem;
end;
@@ -68,20 +70,20 @@ type
Playlists: APlaylist;
constructor Create;
- Procedure LoadPlayLists;
- Function LoadPlayList(Index: Cardinal; const Filename: String): Boolean;
- Procedure SavePlayList(Index: Cardinal);
+ procedure LoadPlayLists;
+ function LoadPlayList(Index: Cardinal; const Filename: IPath): Boolean;
+ procedure SavePlayList(Index: Cardinal);
- Procedure SetPlayList(Index: Cardinal);
+ procedure SetPlayList(Index: Cardinal);
- Function AddPlaylist(const Name: string): Cardinal;
- Procedure DelPlaylist(const Index: Cardinal);
+ function AddPlaylist(const Name: UTF8String): Cardinal;
+ procedure DelPlaylist(const Index: Cardinal);
- Procedure AddItem(const SongID: Cardinal; const iPlaylist: Integer = -1);
- Procedure DelItem(const iItem: Cardinal; const iPlaylist: Integer = -1);
+ procedure AddItem(const SongID: Cardinal; const iPlaylist: Integer = -1);
+ procedure DelItem(const iItem: Cardinal; const iPlaylist: Integer = -1);
- Procedure GetNames(var PLNames: array of string);
- Function GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer = -1): Integer;
+ procedure GetNames(var PLNames: array of UTF8String);
+ function GetIndexbySongID(const SongID: Cardinal; const iPlaylist: Integer = -1): Integer;
end;
{Modes:
@@ -95,13 +97,15 @@ type
implementation
-uses USongs,
- ULog,
- UMain,
- //UFiles,
- UGraphic,
- UThemes,
- SysUtils;
+uses
+ SysUtils,
+ USongs,
+ ULog,
+ UMain,
+ UFilesystem,
+ UGraphic,
+ UThemes,
+ UUnicodeUtils;
//----------
//Create - Construct Class - Dummy for now
@@ -117,90 +121,90 @@ end;
//----------
Procedure TPlayListManager.LoadPlayLists;
var
- SR: TSearchRec;
Len: Integer;
PlayListBuffer: TPlayList;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
begin
SetLength(Playlists, 0);
- if FindFirst(PlayListPath + '*.upl', 0, SR) = 0 then
+ Iter := FileSystem.FileFind(PlayListPath.Append('*.upl'), 0);
+ while (Iter.HasNext) do
begin
- repeat
- Len := Length(Playlists);
- SetLength(Playlists, Len +1);
+ Len := Length(Playlists);
+ SetLength(Playlists, Len + 1);
+
+ FileInfo := Iter.Next;
- if not LoadPlayList (Len, Sr.Name) then
- SetLength(Playlists, Len)
- else
+ if not LoadPlayList(Len, FileInfo.Name) then
+ SetLength(Playlists, Len)
+ else
+ begin
+ // Sort the Playlists - Insertion Sort
+ PlayListBuffer := Playlists[Len];
+ Dec(Len);
+ while (Len >= 0) AND (CompareText(Playlists[Len].Name, PlayListBuffer.Name) >= 0) do
begin
- // Sort the Playlists - Insertion Sort
- PlayListBuffer := Playlists[Len];
- Dec(Len);
- while (Len >= 0) AND (CompareText(Playlists[Len].Name, PlayListBuffer.Name) >= 0) do
- begin
- Playlists[Len+1] := Playlists[Len];
- Dec(Len);
- end;
- Playlists[Len+1] := PlayListBuffer;
+ Playlists[Len+1] := Playlists[Len];
+ Dec(Len);
end;
-
- until FindNext(SR) <> 0;
- FindClose(SR);
- end;
+ Playlists[Len+1] := PlayListBuffer;
+ end;
+ end;
end;
//----------
//LoadPlayList - Load a Playlist in the Array
//----------
-Function TPlayListManager.LoadPlayList(Index: Cardinal; const Filename: String): Boolean;
- var
- F: TextFile;
- Line: String;
- PosDelimiter: Integer;
- SongID: Integer;
- Len: Integer;
+function TPlayListManager.LoadPlayList(Index: Cardinal; const Filename: IPath): Boolean;
- Function FindSong(Artist, Title: UTF8String): Integer;
+ function FindSong(Artist, Title: UTF8String): Integer;
var I: Integer;
begin
Result := -1;
For I := low(CatSongs.Song) to high(CatSongs.Song) do
begin
- if (CatSongs.Song[I].Title = Title) AND (CatSongs.Song[I].Artist = Artist) then
+ if (CatSongs.Song[I].Title = Title) and (CatSongs.Song[I].Artist = Artist) then
begin
Result := I;
Break;
end;
end;
end;
+
+var
+ TextStream: TTextFileStream;
+ Line: UTF8String;
+ PosDelimiter: Integer;
+ SongID: Integer;
+ Len: Integer;
+ FilenameAbs: IPath;
begin
- if not FileExists(PlayListPath + Filename) then
- begin
- Log.LogError('Could not load Playlist: ' + Filename);
- Result := False;
- Exit;
+ //Load File
+ try
+ FilenameAbs := PlaylistPath.Append(Filename);
+ TextStream := TTextFileStream.Create(FilenameAbs, fmOpenRead);
+ except
+ begin
+ Log.LogError('Could not load Playlist: ' + FilenameAbs.ToNative);
+ Result := False;
+ Exit;
+ end;
end;
Result := True;
- //Load File
- AssignFile(F, PlayListPath + FileName);
- Reset(F);
-
//Set Filename
- PlayLists[Index].Filename := Filename;
- PlayLists[Index].Name := '';
+ Playlists[Index].Filename := Filename;
+ Playlists[Index].Name := '';
//Read Until End of File
- While not Eof(F) do
+ while TextStream.ReadLine(Line) do
begin
- //Read Curent Line
- Readln(F, Line);
-
if (Length(Line) > 0) then
begin
- PosDelimiter := Pos(':', Line);
- if (PosDelimiter <> 0) then
+ PosDelimiter := UTF8Pos(':', Line);
+ if (PosDelimiter <> 0) then
begin
//Comment or Name String
if (Line[1] = '#') then
@@ -224,7 +228,7 @@ begin
PlayLists[Index].Items[Len].Artist := Trim(copy(Line, 1, PosDelimiter - 1));
PlayLists[Index].Items[Len].Title := Trim(copy(Line, PosDelimiter + 1, Length(Line) - PosDelimiter));
end
- else Log.LogError('Could not find Song in Playlist: ' + PlayLists[Index].Filename + ', ' + Line);
+ else Log.LogError('Could not find Song in Playlist: ' + PlayLists[Index].Filename.ToNative + ', ' + Line);
end;
end;
end;
@@ -233,71 +237,70 @@ begin
//If no special name is given, use Filename
if PlayLists[Index].Name = '' then
begin
- PlayLists[Index].Name := ChangeFileExt(FileName, '');
+ PlayLists[Index].Name := FileName.SetExtension('').ToUTF8;
end;
//Finish (Close File)
- CloseFile(F);
+ TextStream.Free;
end;
-//----------
-//SavePlayList - Saves the specified Playlist
-//----------
-Procedure TPlayListManager.SavePlayList(Index: Cardinal);
+{**
+ * Saves the specified Playlist
+ *}
+procedure TPlayListManager.SavePlayList(Index: Cardinal);
var
- F: TextFile;
+ TextStream: TTextFileStream;
+ PlaylistFile: IPath;
I: Integer;
begin
- if (Not FileExists(PlaylistPath + Playlists[Index].Filename)) OR (Not FileisReadOnly(PlaylistPath + Playlists[Index].Filename)) then
- begin
+ PlaylistFile := PlaylistPath.Append(Playlists[Index].Filename);
- //open File for Rewriting
- AssignFile(F, PlaylistPath + Playlists[Index].Filename);
- try
- try
- Rewrite(F);
+ // cannot update read-only file
+ if PlaylistFile.IsFile() and PlaylistFile.IsReadOnly() then
+ Exit;
- //Write Version (not nessecary but helpful)
- WriteLn(F, '######################################');
- WriteLn(F, '#Ultrastar Deluxe Playlist Format v1.0');
- WriteLn(F, '#Playlist "' + Playlists[Index].Name + '" with ' + InttoStr(Length(Playlists[Index].Items)) + ' Songs.');
- WriteLn(F, '######################################');
+ // open file for rewriting
+ TextStream := TTextFileStream.Create(PlaylistFile, fmCreate);
+ try
+ // Write version (not nessecary but helpful)
+ TextStream.WriteLine('######################################');
+ TextStream.WriteLine('#Ultrastar Deluxe Playlist Format v1.0');
+ TextStream.WriteLine(Format('#Playlist %s with %d Songs.',
+ [ Playlists[Index].Name, Length(Playlists[Index].Items) ]));
+ TextStream.WriteLine('######################################');
- //Write Name Information
- WriteLn(F, '#Name: ' + Playlists[Index].Name);
+ // Write name information
+ TextStream.WriteLine('#Name: ' + Playlists[Index].Name);
- //Write Song Information
- WriteLn(F, '#Songs:');
+ // Write song information
+ TextStream.WriteLine('#Songs:');
- For I := 0 to high(Playlists[Index].Items) do
- begin
- WriteLn(F, Playlists[Index].Items[I].Artist + ' : ' + Playlists[Index].Items[I].Title);
- end;
- except
- log.LogError('Could not write Playlistfile "' + Playlists[Index].Name + '"');
- end;
- finally
- CloseFile(F);
+ for I := 0 to high(Playlists[Index].Items) do
+ begin
+ TextStream.WriteLine(Playlists[Index].Items[I].Artist + ' : ' + Playlists[Index].Items[I].Title);
end;
+ except
+ Log.LogError('Could not write Playlistfile "' + Playlists[Index].Name + '"');
end;
+ TextStream.Free;
end;
-//----------
-//SetPlayList - Display a Playlist in CatSongs
-//----------
-Procedure TPlayListManager.SetPlayList(Index: Cardinal);
+{**
+ * Display a Playlist in CatSongs
+ *}
+procedure TPlayListManager.SetPlayList(Index: Cardinal);
var
I: Integer;
begin
- If (Int(Index) > High(PlayLists)) then
+ if (Int(Index) > High(PlayLists)) then
exit;
//Hide all Songs
- For I := 0 to high(CatSongs.Song) do
+ for I := 0 to high(CatSongs.Song) do
CatSongs.Song[I].Visible := False;
//Show Songs in PL
- For I := 0 to high(PlayLists[Index].Items) do
+ for I := 0 to high(PlayLists[Index].Items) do
begin
CatSongs.Song[PlayLists[Index].Items[I].SongID].Visible := True;
end;
@@ -324,31 +327,30 @@ end;
//----------
//AddPlaylist - Adds a Playlist and Returns the Index
//----------
-Function TPlayListManager.AddPlaylist(const Name: string): Cardinal;
+function TPlayListManager.AddPlaylist(const Name: UTF8String): cardinal;
var
I: Integer;
+ PlaylistFile: IPath;
begin
Result := Length(Playlists);
SetLength(Playlists, Result + 1);
// Sort the Playlists - Insertion Sort
- while (Result > 0) AND (CompareText(Playlists[Result - 1].Name, Name) >= 0) do
+ while (Result > 0) and (CompareText(Playlists[Result - 1].Name, Name) >= 0) do
begin
Dec(Result);
Playlists[Result+1] := Playlists[Result];
end;
- Playlists[Result].Name := Name;
+ Playlists[Result].Name := Name;
I := 1;
- if (not FileExists(PlaylistPath + Name + '.upl')) then
- Playlists[Result].Filename := Name + '.upl'
- else
+ PlaylistFile := PlaylistPath.Append(Name + '.upl');
+ while (PlaylistFile.Exists) do
begin
- repeat
- Inc(I);
- until not FileExists(PlaylistPath + Name + InttoStr(I) + '.upl');
- Playlists[Result].Filename := Name + InttoStr(I) + '.upl';
+ Inc(I);
+ PlaylistFile := PlaylistPath.Append(Name + InttoStr(I) + '.upl');
end;
+ Playlists[Result].Filename := PlaylistFile;
//Save new Playlist
SavePlayList(Result);
@@ -357,28 +359,28 @@ end;
//----------
//DelPlaylist - Deletes a Playlist
//----------
-Procedure TPlayListManager.DelPlaylist(const Index: Cardinal);
+procedure TPlayListManager.DelPlaylist(const Index: Cardinal);
var
I: Integer;
- Filename: String;
+ Filename: IPath;
begin
- If Int(Index) > High(Playlists) then
+ if Int(Index) > High(Playlists) then
Exit;
- Filename := PlaylistPath + Playlists[Index].Filename;
+ Filename := PlaylistPath.Append(Playlists[Index].Filename);
//If not FileExists or File is not Writeable then exit
- If (Not FileExists(Filename)) OR (FileisReadOnly(Filename)) then
+ if (not Filename.IsFile()) or (Filename.IsReadOnly()) then
Exit;
//Delete Playlist from FileSystem
- if Not DeleteFile(Filename) then
+ if not Filename.DeleteFile() then
Exit;
//Delete Playlist from Array
//move all PLs to the Hole
- For I := Index to High(Playlists)-1 do
+ for I := Index to High(Playlists)-1 do
PlayLists[I] := PlayLists[I+1];
//Delete last Playlist
@@ -471,7 +473,7 @@ end;
//----------
//GetNames - Writes Playlist Names in a Array
//----------
-Procedure TPlayListManager.GetNames(var PLNames: array of String);
+procedure TPlayListManager.GetNames(var PLNames: array of UTF8String);
var
I: Integer;
Len: Integer;
diff --git a/unicode/src/base/USkins.pas b/unicode/src/base/USkins.pas
index a19b7546..6ef5c596 100644
--- a/unicode/src/base/USkins.pas
+++ b/unicode/src/base/USkins.pas
@@ -33,31 +33,34 @@ interface
{$I switches.inc}
+uses
+ UPath;
+
type
TSkinTexture = record
Name: string;
- FileName: string;
+ FileName: IPath;
end;
TSkinEntry = record
Theme: string;
Name: string;
- Path: string;
- FileName: string;
+ Path: IPath;
+ FileName: IPath;
Creator: string; // not used yet
end;
TSkin = class
Skin: array of TSkinEntry;
SkinTexture: array of TSkinTexture;
- SkinPath: string;
+ SkinPath: IPath;
Color: integer;
constructor Create;
procedure LoadList;
- procedure ParseDir(Dir: string);
- procedure LoadHeader(FileName: string);
+ procedure ParseDir(Dir: IPath);
+ procedure LoadHeader(FileName: IPath);
procedure LoadSkin(Name: string);
- function GetTextureFileName(TextureName: string): string;
+ function GetTextureFileName(TextureName: string): IPath;
function GetSkinNumber(Name: string): integer;
procedure onThemeChange;
end;
@@ -74,7 +77,8 @@ uses
UIni,
ULog,
UMain,
- UPathUtils;
+ UPathUtils,
+ UFileSystem;
constructor TSkin.Create;
begin
@@ -86,45 +90,43 @@ end;
procedure TSkin.LoadList;
var
- SR: TSearchRec;
+ Iter: IFileIterator;
+ DirInfo: TFileInfo;
begin
- if FindFirst(SkinsPath+'*', faDirectory, SR) = 0 then
+ Iter := FileSystem.FileFind(SkinsPath.Append('*'), faDirectory);
+ while Iter.HasNext do
begin
- repeat
- if (SR.Name <> '.') and (SR.Name <> '..') then
- ParseDir(SkinsPath + SR.Name + PathDelim);
- until FindNext(SR) <> 0;
- end; // if
- FindClose(SR);
+ DirInfo := Iter.Next();
+ if (not DirInfo.Name.Equals('.')) and (not DirInfo.Name.Equals('..')) then
+ ParseDir(SkinsPath.Append(DirInfo.Name, pdAppend));
+ end;
end;
-procedure TSkin.ParseDir(Dir: string);
+procedure TSkin.ParseDir(Dir: IPath);
var
- SR: TSearchRec;
+ Iter: IFileIterator;
+ IniInfo: TFileInfo;
begin
- if FindFirst(Dir + '*.ini', faAnyFile, SR) = 0 then
+ Iter := FileSystem.FileFind(Dir.Append('*.ini'), 0);
+ while Iter.HasNext do
begin
- repeat
-
- if (SR.Name <> '.') and (SR.Name <> '..') then
- LoadHeader(Dir + SR.Name);
-
- until FindNext(SR) <> 0;
+ IniInfo := Iter.Next;
+ LoadHeader(Dir.Append(IniInfo.Name));
end;
end;
-procedure TSkin.LoadHeader(FileName: string);
+procedure TSkin.LoadHeader(FileName: IPath);
var
SkinIni: TMemIniFile;
S: integer;
begin
- SkinIni := TMemIniFile.Create(FileName);
+ SkinIni := TMemIniFile.Create(FileName.ToNative);
S := Length(Skin);
SetLength(Skin, S+1);
- Skin[S].Path := IncludeTrailingPathDelimiter(ExtractFileDir(FileName));
- Skin[S].FileName := ExtractFileName(FileName);
+ Skin[S].Path := FileName.GetPath;
+ Skin[S].FileName := FileName.GetName;
Skin[S].Theme := SkinIni.ReadString('Skin', 'Theme', '');
Skin[S].Name := SkinIni.ReadString('Skin', 'Name', '');
Skin[S].Creator := SkinIni.ReadString('Skin', 'Creator', '');
@@ -142,7 +144,7 @@ begin
S := GetSkinNumber(Name);
SkinPath := Skin[S].Path;
- SkinIni := TMemIniFile.Create(SkinPath + Skin[S].FileName);
+ SkinIni := TMemIniFile.Create(SkinPath.Append(Skin[S].FileName).ToNative);
SL := TStringList.Create;
SkinIni.ReadSection('Textures', SL);
@@ -151,30 +153,29 @@ begin
for T := 0 to SL.Count-1 do
begin
SkinTexture[T].Name := SL.Strings[T];
- SkinTexture[T].FileName := SkinIni.ReadString('Textures', SL.Strings[T], '');
+ SkinTexture[T].FileName := Path(SkinIni.ReadString('Textures', SL.Strings[T], ''));
end;
SL.Free;
SkinIni.Free;
end;
-function TSkin.GetTextureFileName(TextureName: string): string;
+function TSkin.GetTextureFileName(TextureName: string): IPath;
var
T: integer;
begin
- Result := '';
+ Result := PATH_NONE;
for T := 0 to High(SkinTexture) do
begin
- if ( SkinTexture[T].Name = TextureName ) and
- ( SkinTexture[T].FileName <> '' ) then
+ if (SkinTexture[T].Name = TextureName) and
+ (SkinTexture[T].FileName.IsSet) then
begin
- Result := SkinPath + SkinTexture[T].FileName;
+ Result := SkinPath.Append(SkinTexture[T].FileName);
end;
end;
- if ( TextureName <> '' ) and
- ( Result <> '' ) then
+ if (TextureName <> '') and (Result.IsSet) then
begin
//Log.LogError('', '-----------------------------------------');
//Log.LogError(TextureName+' - '+ Result, 'TSkin.GetTextureFileName');
diff --git a/unicode/src/base/USong.pas b/unicode/src/base/USong.pas
index 86349359..203ff517 100644
--- a/unicode/src/base/USong.pas
+++ b/unicode/src/base/USong.pas
@@ -57,7 +57,9 @@ uses
{$ENDIF}
UCatCovers,
UXMLSong,
- UTextEncoding;
+ UTextEncoding,
+ UFilesystem,
+ UPath;
type
@@ -74,6 +76,7 @@ type
end;
TSong = class
+ private
FileLineNo : integer; // line, which is read last, for error reporting
function EncodeFilename(Filename: string): string;
@@ -81,19 +84,22 @@ type
procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: UTF8String);
procedure NewSentence(LineNumberP: integer; Param1, Param2: integer);
- function ReadTXTHeader( const aFileName : WideString ): boolean;
- function ReadXMLHeader( const aFileName : WideString ): boolean;
+ function ReadTXTHeader(const aFileName: IPath): boolean;
+ function ReadXMLHeader(const aFileName: IPath): boolean;
+
+ function GetFolderCategory(const aFileName: IPath): UTF8String;
+ function FindSongFile(Dir: IPath; Mask: UTF8String): IPath;
+
public
- Path: WideString;
- Folder: WideString; // for sorting by folder
- fFileName,
- FileName: WideString;
+ Path: IPath; // kust path component of file (only set if file was found)
+ Folder: UTF8String; // for sorting by folder (only set if file was found)
+ FileName: IPath; // just name component of file (only set if file was found)
// filenames
- Cover: WideString;
- Mp3: WideString;
- Background: WideString;
- Video: WideString;
+ Cover: IPath;
+ Mp3: IPath;
+ Background: IPath;
+ Video: IPath;
// sorting methods
Genre: UTF8String;
@@ -127,7 +133,7 @@ type
OrderTyp: integer; // type of sorting for this button (0=name)
CatNumber: integer; // Count of Songs in Category for Cats and Number of Song in Category for Songs
- SongFile: TextFile; // all procedures in this unit operate on this file
+ //SongFile: TextFile; // all procedures in this unit operate on this file
Base : array[0..1] of integer;
Rel : array[0..1] of integer;
@@ -140,7 +146,7 @@ type
constructor Create(); overload;
- constructor Create( const aFileName : WideString ); overload;
+ constructor Create(const aFileName : IPath); overload;
function LoadSong: boolean;
function LoadXMLSong: boolean;
function Analyse(): boolean;
@@ -167,58 +173,61 @@ begin
inherited;
end;
-constructor TSong.Create( const aFileName: WideString );
- // This may be changed, when we rewrite song select code.
- // it is some kind of dirty, but imho the best possible
- // solution as we do atm not support nested categorys.
- // it works like the folder sorting in 1.0.1a
- // folder is set to the first folder under the songdir
- // so songs ~/.ultrastardx/songs/punk is in the same
- // category as songs in shared/ultrastardx/songs are.
- // note: folder is just the name of a category it has
- // nothing to do with the path used for file loading
- function GetFolderCategory: WideString;
- var
- I: Integer;
- P: Integer; //position of next path delimiter
- begin
- Result := 'Unknown'; //default folder category, if we can't locate the song dir
+// This may be changed, when we rewrite song select code.
+// it is some kind of dirty, but imho the best possible
+// solution as we do atm not support nested categorys.
+// it works like the folder sorting in 1.0.1a
+// folder is set to the first folder under the songdir
+// so songs ~/.ultrastardx/songs/punk is in the same
+// category as songs in shared/ultrastardx/songs are.
+// note: folder is just the name of a category it has
+// nothing to do with the path used for file loading
+function TSong.GetFolderCategory(const aFileName: IPath): UTF8String;
+var
+ I: Integer;
+ CurSongPath: IPath;
+ CurSongPathRel: IPath;
+begin
+ Result := 'Unknown'; //default folder category, if we can't locate the song dir
- for I := 0 to SongPaths.Count-1 do
- if (AnsiStartsText(SongPaths.Strings[I], aFilename)) then
+ for I := 0 to SongPaths.Count-1 do
+ begin
+ CurSongPath := SongPaths[I] as IPath;
+ if (aFileName.IsChildOf(CurSongPath, false)) then
+ begin
+ if (aFileName.IsChildOf(CurSongPath, true)) then
begin
- P := PosEx(PathDelim, aFilename, Length(SongPaths.Strings[I]) + 1);
-
- If (P > 0) then
- begin
- // we have found the category name => get it
- Result := copy(self.Path, Length(SongPaths.Strings[I]) + 1, P - Length(SongPaths.Strings[I]) - 1);
- end
- else
- begin
- // songs are in the "root" of the songdir => use songdir for the categorys name
- Result := SongPaths.Strings[I];
- end;
-
- Exit;
+ // songs are in the "root" of the songdir => use songdir for the categorys name
+ Result := CurSongPath.ToUTF8; // TODO: remove trailing path-delim?
+ end
+ else
+ begin
+ // use the first subdirectory below CurSongPath as the category name
+ CurSongPathRel := aFileName.GetRelativePath(CurSongPath.AppendPathDelim);
+ Result := CurSongPathRel.SplitDirs[0].RemovePathDelim.ToUTF8;
end;
+ Exit;
+ end;
end;
+end;
+
+constructor TSong.Create(const aFileName: IPath);
begin
inherited Create();
Mult := 1;
MultBPM := 4;
- fFileName := aFileName;
LastError := '';
- if fileexists( aFileName ) then
+ Self.Path := aFileName.GetPath;
+ Self.FileName := aFileName.GetName;
+ Self.Folder := GetFolderCategory(aFileName);
+
+ (*
+ if (aFileName.IsFile) then
begin
- self.Path := ExtractFilePath( aFileName );
- self.Folder := GetFolderCategory;
- self.FileName := ExtractFileName( aFileName );
- (*
- if ReadTXTHeader( aFileName ) then
+ if ReadTXTHeader(aFileName) then
begin
LoadSong();
end
@@ -227,8 +236,21 @@ begin
Log.LogError('Error Loading SongHeader, abort Song Loading');
Exit;
end;
- *)
end;
+ *)
+end;
+
+function TSong.FindSongFile(Dir: IPath; Mask: UTF8String): IPath;
+var
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
+ FileName: IPath;
+begin
+ Iter := FileSystem.FileFind(Dir.Append(Mask), faDirectory);
+ if (Iter.HasNext) then
+ Result := Iter.Next.Name
+ else
+ Result := PATH_NONE;
end;
function TSong.EncodeFilename(Filename: string): string;
@@ -247,7 +269,7 @@ end;
//Load TXT Song
function TSong.LoadSong(): boolean;
var
- TempC: char;
+ TempC: AnsiChar;
Text: UTF8String;
Count: integer;
Both: boolean;
@@ -256,15 +278,19 @@ var
Param3: integer;
ParamS: UTF8String;
I: integer;
+ NotesFound: boolean;
+ TextStream: TTextFileStream;
+ FileNamePath: IPath;
begin
Result := false;
LastError := '';
- if not FileExists(Path + PathDelim + FileName) then
+ FileNamePath := Path.Append(FileName);
+ if not FileNamePath.IsFile() then
begin
LastError := 'ERROR_CORRUPT_SONG_FILE_NOT_FOUND';
- Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()');
- exit;
+ Log.LogError('File not found: "' + FileNamePath.ToNative + '"', 'TSong.LoadSong()');
+ Exit;
end;
MultBPM := 4; // multiply beat-count of note by 4
@@ -275,34 +301,42 @@ begin
if Length(Player) = 2 then
Both := true;
+ {$MESSAGE warn 'TODO: TSong.LoadSong'}
+
+ (*
try
// Open song file for reading.....
- FileMode := fmOpenRead;
- AssignFile(SongFile, fFileName);
- Reset(SongFile);
+ TextStream := nil;
+ TextStream := TBinaryFileStream.Create(FullFileName, fmOpenRead);
//Clear old Song Header
- if (self.Path = '') then
- self.Path := ExtractFilePath(FileName);
+ if (Self.Path.IsUnset) then
+ Self.Path := FullFileName.GetPath();
- if (self.FileName = '') then
- self.Filename := ExtractFileName(FileName);
+ if (Self.FileName.IsUnset) then
+ Self.Filename := FullFileName.GetName();
- FileLineNo := 0;
//Search for Note Begining
- repeat
- ReadLn(SongFile, Text);
+ FileLineNo := 0;
+ NotesFound := false;
+ while (TextStream.ReadLine(Text)) do
+ begin
Inc(FileLineNo);
-
- if (Eof(SongFile)) then
- begin //Song File Corrupted - No Notes
- CloseFile(SongFile);
- Log.LogError('Could not load txt File, no Notes found: ' + FileName);
- LastError := 'ERROR_CORRUPT_SONG_NO_NOTES';
- Exit;
+ if (Length(Text) > 0) and (Text[0] in [':', 'F', '*']) then
+ begin
+ TempC := Text[0];
+ NotesFound := true;
+ Break;
end;
- Read(SongFile, TempC);
- until ((TempC = ':') or (TempC = 'F') or (TempC = '*'));
+ end;
+
+ if (not NotesFound) then
+ begin //Song File Corrupted - No Notes
+ TextStream.Free;
+ Log.LogError('Could not load txt File, no Notes found: ' + FileName);
+ LastError := 'ERROR_CORRUPT_SONG_NO_NOTES';
+ Exit;
+ end;
SetLength(Lines, 2);
for Count := 0 to High(Lines) do
@@ -327,7 +361,7 @@ begin
while (TempC <> 'E') and (not EOF(SongFile)) do
begin
- if (TempC = ':') or (TempC = '*') or (TempC = 'F') then
+ if (TempC in [':', '*', 'F']) then
begin
// read notes
Read(SongFile, Param1);
@@ -398,7 +432,7 @@ begin
if (Length(Lines[I].Line) < 2) then
begin
LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS';
- Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"');
+ Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + FullFileName + '"');
exit;
end;
@@ -425,10 +459,11 @@ begin
end;
LastError := 'ERROR_CORRUPT_SONG_ERROR_IN_LINE';
- Log.LogError('Error Loading File: "' + fFileName + '" in Line ' + inttostr(FileLineNo));
+ Log.LogError('Error Loading File: "' + FullFileName + '" in Line ' + inttostr(FileLineNo));
exit;
end;
-
+ *)
+
Result := true;
end;
@@ -447,13 +482,15 @@ var
NoteType: char;
SentenceEnd, Rest, Time: integer;
Parser: TParser;
+ FileNamePath: IPath;
begin
Result := false;
LastError := '';
- if not FileExists(Path + PathDelim + FileName) then
+ FileNamePath := Path.Append(FileName);
+ if not FileNamePath.IsFile() then
begin
- Log.LogError('File not found: "' + Path + PathDelim + FileName + '"', 'TSong.LoadSong()');
+ Log.LogError('File not found: "' + FileNamePath.ToNative + '"', 'TSong.LoadSong()');
exit;
end;
@@ -491,7 +528,7 @@ begin
//Try to Parse the Song
- if Parser.ParseSong(Path + PathDelim + FileName) then
+ if Parser.ParseSong(FileNamePath) then
begin
//Writeln('XML Inputfile Parsed succesful');
@@ -558,7 +595,7 @@ begin
end
else
begin
- Log.LogError('Could not parse Inputfile: ' + Path + PathDelim + FileName);
+ Log.LogError('Could not parse Inputfile: ' + FileNamePath.ToNative);
exit;
end;
@@ -570,10 +607,11 @@ begin
Result := true;
end;
-function TSong.ReadXMLHeader(const aFileName : WideString): boolean;
+function TSong.ReadXMLHeader(const aFileName : IPath): boolean;
var
Done : byte;
Parser : TParser;
+ FileNamePath: IPath;
begin
Result := true;
Done := 0;
@@ -582,7 +620,8 @@ begin
Parser := TParser.Create;
Parser.Settings.DashReplacement := '~';
- if Parser.ParseSong(self.Path + self.FileName) then
+ FileNamePath := Self.Path.Append(Self.FileName);
+ if Parser.ParseSong(FileNamePath) then
begin
//-----------
//Required Attributes
@@ -601,9 +640,9 @@ begin
Done := Done or 2;
//MP3 File //Test if Exists
- self.Mp3 := platform.FindSongFile(Path, '*.mp3');
+ Self.Mp3 := FindSongFile(Self.Path, '*.mp3');
//Add Mp3 Flag to Done
- if (FileExists(self.Path + self.Mp3)) then
+ if (Self.Path.Append(Self.Mp3).IsFile()) then
Done := Done or 4;
//Beats per Minute
@@ -624,10 +663,10 @@ begin
self.GAP := Parser.SongInfo.Header.Gap;
//Cover Picture
- self.Cover := platform.FindSongFile(Path, '*[CO].jpg');
+ self.Cover := FindSongFile(Path, '*[CO].jpg');
//Background Picture
- self.Background := platform.FindSongFile(Path, '*[BG].jpg');
+ self.Background := FindSongFile(Path, '*[BG].jpg');
// Video File
// self.Video := Value
@@ -648,7 +687,7 @@ begin
self.Language := Parser.SongInfo.Header.Language;
end
else
- Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName);
+ Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName.ToNative);
Parser.Free;
@@ -657,36 +696,35 @@ begin
begin
Result := false;
if (Done and 8) = 0 then //No BPM Flag
- Log.LogError('BPM Tag Missing: ' + self.FileName)
+ Log.LogError('BPM Tag Missing: ' + self.FileName.ToNative)
else if (Done and 4) = 0 then //No MP3 Flag
- Log.LogError('MP3 Tag/File Missing: ' + self.FileName)
+ Log.LogError('MP3 Tag/File Missing: ' + self.FileName.ToNative)
else if (Done and 2) = 0 then //No Artist Flag
- Log.LogError('Artist Tag Missing: ' + self.FileName)
+ Log.LogError('Artist Tag Missing: ' + self.FileName.ToNative)
else if (Done and 1) = 0 then //No Title Flag
- Log.LogError('Title Tag Missing: ' + self.FileName)
+ Log.LogError('Title Tag Missing: ' + self.FileName.ToNative)
else //unknown Error
- Log.LogError('File Incomplete or not SingStar XML (B - '+ inttostr(Done) +'): ' + aFileName);
+ Log.LogError('File Incomplete or not SingStar XML (B - '+ inttostr(Done) +'): ' + aFileName.ToNative);
end;
end;
-function TSong.ReadTXTHeader(const aFileName : WideString): boolean;
-
- {**
- * "International" StrToFloat variant. Uses either ',' or '.' as decimal
- * separator.
- *}
- function StrToFloatI18n(const Value: string): extended;
- var
- TempValue : string;
- begin
- TempValue := Value;
- if (Pos(',', TempValue) <> 0) then
- TempValue[Pos(',', TempValue)] := '.';
- Result := StrToFloatDef(TempValue, 0);
- end;
+{**
+ * "International" StrToFloat variant. Uses either ',' or '.' as decimal
+ * separator.
+ *}
+function StrToFloatI18n(const Value: string): extended;
+var
+ TempValue : string;
+begin
+ TempValue := Value;
+ if (Pos(',', TempValue) <> 0) then
+ TempValue[Pos(',', TempValue)] := '.';
+ Result := StrToFloatDef(TempValue, 0);
+end;
+function TSong.ReadTXTHeader(const aFileName : IPath): boolean;
var
Line, Identifier: string;
Value: string;
@@ -697,6 +735,10 @@ begin
Result := true;
Done := 0;
+ {$message warn 'TSong.ReadTXTHeader'}
+
+ (*
+
//Read first Line
ReadLn (SongFile, Line);
@@ -913,7 +955,7 @@ begin
else //unknown Error
Log.LogError('File Incomplete or not Ultrastar TxT (B - '+ inttostr(Done) +'): ' + aFileName);
end;
-
+ *)
end;
function TSong.GetErrorLineNo: integer;
@@ -1034,7 +1076,8 @@ begin
end
else
begin //use old line if it there were no notes added since last call of NewSentence
- Log.LogError('Error loading Song, sentence w/o note found in line ' + InttoStr(FileLineNo) + ': ' + Filename);
+ Log.LogError('Error loading Song, sentence w/o note found in line ' +
+ InttoStr(FileLineNo) + ': ' + Filename.ToNative);
end;
Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote := -1;
@@ -1076,7 +1119,7 @@ begin
Encoding := DEFAULT_ENCODING;
//Required Information
- Mp3 := '';
+ Mp3 := PATH_NONE;
SetLength(BPM, 0);
GAP := 0;
@@ -1084,9 +1127,9 @@ begin
Finish := 0;
//Additional Information
- Background := '';
- Cover := '';
- Video := '';
+ Background := PATH_NONE;
+ Cover := PATH_NONE;
+ Video := PATH_NONE;
VideoGAP := 0;
NotesGAP := 0;
Resolution := 4;
@@ -1096,7 +1139,8 @@ begin
end;
function TSong.Analyse(): boolean;
-
+var
+ SongFile: TTextFileStream;
begin
Result := false;
@@ -1104,20 +1148,17 @@ begin
FileLineNo := 0;
//Open File and set File Pointer to the beginning
- AssignFile(SongFile, self.Path + self.FileName);
-
+ SongFile := TTextFileStream.Create(Self.Path.Append(Self.FileName), fmOpenRead);
try
- Reset(SongFile);
-
//Clear old Song Header
- self.clear;
+ Self.clear;
//Read Header
- Result := self.ReadTxTHeader( FileName )
+ Result := self.ReadTxTHeader(FileName)
//And Close File
finally
- CloseFile(SongFile);
+ SongFile.Free;
end;
end;
diff --git a/unicode/src/base/USongs.pas b/unicode/src/base/USongs.pas
index 2b2bcf49..55ddc5e9 100644
--- a/unicode/src/base/USongs.pas
+++ b/unicode/src/base/USongs.pas
@@ -40,28 +40,26 @@ interface
{$ENDIF}
uses
+ SysUtils,
+ Classes,
{$IFDEF MSWINDOWS}
Windows,
DirWatch,
{$ELSE}
{$IFNDEF DARWIN}
- syscall,
+ syscall,
{$ENDIF}
baseunix,
UnixType,
{$ENDIF}
- SysUtils,
- Classes,
UPlatform,
ULog,
UTexture,
UCommon,
- {$IFDEF DARWIN}
- cthreads,
- {$ENDIF}
{$IFDEF USE_PSEUDO_THREAD}
- PseudoThread,
+ PseudoThread,
{$ENDIF}
+ UPath,
USong,
UCatCovers;
@@ -107,11 +105,10 @@ type
procedure LoadSongList; // load all songs
- procedure BrowseDir(Dir: widestring); // should return number of songs in the future
- procedure BrowseTXTFiles(Dir: widestring);
- procedure BrowseXMLFiles(Dir: widestring);
+ procedure BrowseDir(Dir: IPath); // should return number of songs in the future
+ procedure BrowseTXTFiles(Dir: IPath);
+ procedure BrowseXMLFiles(Dir: IPath);
procedure Sort(Order: integer);
- function FindSongFile(Dir, Mask: widestring): widestring;
property Processing: boolean read fProcessing;
end;
@@ -165,6 +162,7 @@ uses
UIni,
UPathUtils,
UNote,
+ UFilesystem,
UUnicodeUtils;
constructor TSongs.Create();
@@ -239,7 +237,7 @@ begin
// browse directories
for I := 0 to SongPaths.Count-1 do
- BrowseDir(SongPaths[I]);
+ BrowseDir(SongPaths[I] as IPath);
if assigned(CatSongs) then
CatSongs.Refresh;
@@ -271,13 +269,13 @@ begin
Resume();
end;
-procedure TSongs.BrowseDir(Dir: widestring);
+procedure TSongs.BrowseDir(Dir: IPath);
begin
BrowseTXTFiles(Dir);
BrowseXMLFiles(Dir);
end;
-procedure TSongs.BrowseTXTFiles(Dir: widestring);
+procedure TSongs.BrowseTXTFiles(Dir: IPath);
var
i: integer;
Files: TDirectoryEntryArray;
@@ -285,27 +283,27 @@ var
begin
try
- Files := Platform.DirectoryFindFiles(Dir, '.txt', true)
+ Files := DirectoryFindFiles(Dir, '.txt', true)
except
- Log.LogError('Couldn''t deal with directory/file: ' + Dir + ' in TSongs.BrowseTXTFiles')
+ Log.LogError('Couldn''t deal with directory/file: ' + Dir.ToNative + ' in TSongs.BrowseTXTFiles')
end;
for i := 0 to Length(Files) - 1 do
begin
if Files[i].IsDirectory then
begin
- BrowseTXTFiles(Dir + Files[i].Name + PathDelim); //Recursive Call
+ BrowseTXTFiles(Dir.Append(Files[i].Name, pdAppend)); //Recursive Call
end
else
begin
- lSong := TSong.create(Dir + Files[i].Name);
+ lSong := TSong.Create(Dir.Append(Files[i].Name));
if lSong.Analyse then
SongList.add(lSong)
else
begin
- Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".');
- freeandnil(lSong);
+ Log.LogError('AnalyseFile failed for "' + Files[i].Name.ToNative + '".');
+ FreeAndNil(lSong);
end;
end;
@@ -314,7 +312,7 @@ begin
end;
-procedure TSongs.BrowseXMLFiles(Dir: widestring);
+procedure TSongs.BrowseXMLFiles(Dir: IPath);
var
i: integer;
Files: TDirectoryEntryArray;
@@ -322,26 +320,26 @@ var
begin
try
- Files := Platform.DirectoryFindFiles(Dir, '.xml', true)
+ Files := DirectoryFindFiles(Dir, '.xml', true)
except
- Log.LogError('Couldn''t deal with directory/file: ' + Dir + ' in TSongs.BrowseXMLFiles')
+ Log.LogError('Couldn''t deal with directory/file: ' + Dir.ToNative + ' in TSongs.BrowseXMLFiles')
end;
for i := 0 to Length(Files) - 1 do
begin
if Files[i].IsDirectory then
begin
- BrowseXMLFiles(Dir + Files[i].Name + PathDelim); // Recursive Call
+ BrowseXMLFiles(Dir.Append(Files[i].Name, pdAppend)); // Recursive Call
end
else
begin
- lSong := TSong.create(Dir + Files[i].Name);
+ lSong := TSong.Create(Dir.Append(Files[i].Name));
if lSong.AnalyseXML then
SongList.add(lSong)
else
begin
- Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".');
+ Log.LogError('AnalyseFile failed for "' + Files[i].Name.ToNative + '".');
freeandnil(lSong);
end;
@@ -377,7 +375,7 @@ end;
function CompareByFolder(Song1, Song2: Pointer): integer;
begin
- Result := CompareText(TSong(Song1).Folder, TSong(Song2).Folder);
+ Result := UTF8CompareText(TSong(Song1).Folder, TSong(Song2).Folder);
end;
function CompareByLanguage(Song1, Song2: Pointer): integer;
@@ -419,18 +417,6 @@ begin
MergeSort(SongList, CompareFunc);
end;
-function TSongs.FindSongFile(Dir, Mask: widestring): widestring;
-var
- SR: TSearchRec; // for parsing song directory
-begin
- Result := '';
- if FindFirst(Dir + Mask, faDirectory, SR) = 0 then
- begin
- Result := SR.Name;
- end; // if
- FindClose(SR);
-end;
-
procedure TCatSongs.SortSongs();
begin
case Ini.Sorting of
@@ -603,7 +589,7 @@ begin
end;
sFolder: begin
- if (CompareText(CurCategory, CurSong.Folder) <> 0) then
+ if (UTF8CompareText(CurCategory, CurSong.Folder) <> 0) then
begin
CurCategory := CurSong.Folder;
// add folder tab
@@ -831,7 +817,7 @@ begin
begin
case Filter of
fltAll:
- TmpString := Song[I].Artist + ' ' + Song[i].Title + ' ' + UTF8Encode(Song[i].Folder);
+ TmpString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder;
fltTitle:
TmpString := Song[I].Title;
fltArtist:
diff --git a/unicode/src/base/UTextEncoding.pas b/unicode/src/base/UTextEncoding.pas
index 966064c0..a0d455dd 100644
--- a/unicode/src/base/UTextEncoding.pas
+++ b/unicode/src/base/UTextEncoding.pas
@@ -1,239 +1,239 @@
-{* UltraStar Deluxe - Karaoke Game
- *
- * UltraStar Deluxe is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * $URL: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/menu/UMenuText.pas $
- * $Id: UMenuText.pas 1485 2008-10-28 20:16:05Z tobigun $
- *}
-
-unit UTextEncoding;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- SysUtils;
-
-type
- TEncoding = (
- encLocale, // current locale (needs cwstring on linux)
- encUTF8, // UTF-8
- encCP1250, // Windows-1250 Central/Eastern Europe (used by Ultrastar)
- encCP1252 // Windows-1252 Western Europe (used by UltraStar Deluxe < 1.1)
- );
-
-const
- UTF8_BOM: UTF8String = #$EF#$BB#$BF;
-
-{**
- * Decodes Src encoded in SrcEncoding to a UTF-16 or UTF-8 encoded Dst string.
- * Returns true if the conversion was successful.
- *}
-function DecodeString(const Src: AnsiString; out Dst: WideString; SrcEncoding: TEncoding): boolean; overload;
-function DecodeString(const Src: AnsiString; SrcEncoding: TEncoding): WideString; overload;
-function DecodeStringUTF8(const Src: AnsiString; out Dst: UTF8String; SrcEncoding: TEncoding): boolean; overload;
-function DecodeStringUTF8(const Src: AnsiString; SrcEncoding: TEncoding): UTF8String; overload;
-
-{**
- * Encodes the UTF-16 or UTF-8 encoded Src string to Dst using DstEncoding
- * Returns true if the conversion was successful.
- *}
-function EncodeString(const Src: WideString; out Dst: AnsiString; DstEncoding: TEncoding): boolean; overload;
-function EncodeString(const Src: WideString; DstEncoding: TEncoding): AnsiString; overload;
-function EncodeStringUTF8(const Src: UTF8String; out Dst: AnsiString; DstEncoding: TEncoding): boolean; overload;
-function EncodeStringUTF8(const Src: UTF8String; DstEncoding: TEncoding): AnsiString; overload;
-
-{**
- * If Text starts with an UTF-8 BOM, the BOM is removed and true will
- * be returned.
- *}
-function CheckReplaceUTF8BOM(var Text: AnsiString): boolean;
-
-{**
- * Parses an encoding string to its TEncoding equivalent.
- * Surrounding whitespace and dashes ('-') are removed, the upper-cased
- * resulting value is then compared with TEncodingNames.
- * If the encoding was not found, the result is set to the Default encoding.
- *}
-function ParseEncoding(const EncodingStr: AnsiString; Default: TEncoding): TEncoding;
-
-{**
- * Returns the name of an encoding.
- *}
-function EncodingName(Encoding: TEncoding): AnsiString;
-
-implementation
-
-uses
- StrUtils,
- UUnicodeUtils;
-
-type
- IEncoder = interface
- function GetName(): AnsiString;
- function Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean;
- function Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean;
- end;
-
- TEncoder = class(TInterfacedObject, IEncoder)
- public
- function GetName(): AnsiString; virtual; abstract;
- function Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean; virtual; abstract;
- function Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean; virtual; abstract;
- end;
-
- TSingleByteEncoder = class(TEncoder)
- public
- function Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean; override;
- function Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean; override;
- function DecodeChar(InChr: AnsiChar; out OutChr: UCS4Char): boolean; virtual; abstract;
- function EncodeChar(InChr: UCS4Char; out OutChr: AnsiChar): boolean; virtual; abstract;
- end;
-
-const
- ERROR_CHAR = '?';
-
-var
- Encoders: array[TEncoding] of IEncoder;
-
-function TSingleByteEncoder.Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean;
-var
- I: integer;
-begin
- SetLength(OutStr, LengthUCS4(InStr));
- Result := true;
- for I := 1 to Length(OutStr) do
- begin
- if (not EncodeChar(InStr[I-1], OutStr[I])) then
- Result := false;
- end;
-end;
-
-function TSingleByteEncoder.Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean;
-var
- I: integer;
-begin
- SetLength(OutStr, Length(InStr)+1);
- Result := true;
- for I := 1 to Length(InStr) do
- begin
- if (not DecodeChar(InStr[I], OutStr[I-1])) then
- Result := false;
- end;
- OutStr[High(OutStr)] := 0;
-end;
-
-function DecodeString(const Src: AnsiString; out Dst: WideString; SrcEncoding: TEncoding): boolean;
-var
- DstUCS4: UCS4String;
-begin
- Result := Encoders[SrcEncoding].Decode(Src, DstUCS4);
- Dst := UCS4StringToWideString(DstUCS4);
-end;
-
-function DecodeString(const Src: AnsiString; SrcEncoding: TEncoding): WideString;
-begin
- DecodeString(Src, Result, SrcEncoding);
-end;
-
-function DecodeStringUTF8(const Src: AnsiString; out Dst: UTF8String; SrcEncoding: TEncoding): boolean;
-var
- DstUCS4: UCS4String;
-begin
- Result := Encoders[SrcEncoding].Decode(Src, DstUCS4);
- Dst := UCS4ToUTF8String(DstUCS4);
-end;
-
-function DecodeStringUTF8(const Src: AnsiString; SrcEncoding: TEncoding): UTF8String;
-begin
- DecodeStringUTF8(Src, Result, SrcEncoding);
-end;
-
-function EncodeString(const Src: WideString; out Dst: AnsiString; DstEncoding: TEncoding): boolean;
-begin
- Result := Encoders[DstEncoding].Encode(WideStringToUCS4String(Src), Dst);
-end;
-
-function EncodeString(const Src: WideString; DstEncoding: TEncoding): AnsiString;
-begin
- EncodeString(Src, Result, DstEncoding);
-end;
-
-function EncodeStringUTF8(const Src: UTF8String; out Dst: AnsiString; DstEncoding: TEncoding): boolean;
-begin
- Result := Encoders[DstEncoding].Encode(UTF8ToUCS4String(Src), Dst);
-end;
-
-function EncodeStringUTF8(const Src: UTF8String; DstEncoding: TEncoding): AnsiString;
-begin
- EncodeStringUTF8(Src, Result, DstEncoding);
-end;
-
-function CheckReplaceUTF8BOM(var Text: AnsiString): boolean;
-begin
- if AnsiStartsStr(UTF8_BOM, Text) then
- begin
- Text := Copy(Text, Length(UTF8_BOM)+1, Length(Text)-Length(UTF8_BOM));
- Result := true;
- Exit;
- end;
- Result := false;
-end;
-
-function ParseEncoding(const EncodingStr: AnsiString; Default: TEncoding): TEncoding;
-var
- PrepStr: AnsiString; // prepared encoding string
- Encoding: TEncoding;
-begin
- // remove surrounding whitespace, replace dashes, to upper case
- PrepStr := UpperCase(AnsiReplaceStr(Trim(EncodingStr), '-', ''));
- for Encoding := Low(TEncoding) to High(TEncoding) do
- begin
- if (Encoders[Encoding].GetName() = PrepStr) then
- begin
- Result := Encoding;
- Exit;
+{* UltraStar Deluxe - Karaoke Game
+ *
+ * UltraStar Deluxe is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/menu/UMenuText.pas $
+ * $Id: UMenuText.pas 1485 2008-10-28 20:16:05Z tobigun $
+ *}
+
+unit UTextEncoding;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ SysUtils,
+ UUnicodeUtils;
+
+type
+ TEncoding = (
+ encLocale, // current locale (needs cwstring on linux)
+ encUTF8, // UTF-8
+ encCP1250, // Windows-1250 Central/Eastern Europe (used by Ultrastar)
+ encCP1252 // Windows-1252 Western Europe (used by UltraStar Deluxe < 1.1)
+ );
+
+const
+ UTF8_BOM: UTF8String = #$EF#$BB#$BF;
+
+{**
+ * Decodes Src encoded in SrcEncoding to a UTF-16 or UTF-8 encoded Dst string.
+ * Returns true if the conversion was successful.
+ *}
+function DecodeString(const Src: RawByteString; out Dst: WideString; SrcEncoding: TEncoding): boolean; overload;
+function DecodeString(const Src: RawByteString; SrcEncoding: TEncoding): WideString; overload;
+function DecodeStringUTF8(const Src: RawByteString; out Dst: UTF8String; SrcEncoding: TEncoding): boolean; overload;
+function DecodeStringUTF8(const Src: RawByteString; SrcEncoding: TEncoding): UTF8String; overload;
+
+{**
+ * Encodes the UTF-16 or UTF-8 encoded Src string to Dst using DstEncoding
+ * Returns true if the conversion was successful.
+ *}
+function EncodeString(const Src: WideString; out Dst: RawByteString; DstEncoding: TEncoding): boolean; overload;
+function EncodeString(const Src: WideString; DstEncoding: TEncoding): RawByteString; overload;
+function EncodeStringUTF8(const Src: UTF8String; out Dst: RawByteString; DstEncoding: TEncoding): boolean; overload;
+function EncodeStringUTF8(const Src: UTF8String; DstEncoding: TEncoding): RawByteString; overload;
+
+{**
+ * If Text starts with an UTF-8 BOM, the BOM is removed and true will
+ * be returned.
+ *}
+function CheckReplaceUTF8BOM(var Text: RawByteString): boolean;
+
+{**
+ * Parses an encoding string to its TEncoding equivalent.
+ * Surrounding whitespace and dashes ('-') are removed, the upper-cased
+ * resulting value is then compared with TEncodingNames.
+ * If the encoding was not found, the result is set to the Default encoding.
+ *}
+function ParseEncoding(const EncodingStr: AnsiString; Default: TEncoding): TEncoding;
+
+{**
+ * Returns the name of an encoding.
+ *}
+function EncodingName(Encoding: TEncoding): AnsiString;
+
+implementation
+
+uses
+ StrUtils;
+
+type
+ IEncoder = interface
+ function GetName(): AnsiString;
+ function Encode(const InStr: UCS4String; out OutStr: RawByteString): boolean;
+ function Decode(const InStr: RawByteString; out OutStr: UCS4String): boolean;
+ end;
+
+ TEncoder = class(TInterfacedObject, IEncoder)
+ public
+ function GetName(): AnsiString; virtual; abstract;
+ function Encode(const InStr: UCS4String; out OutStr: RawByteString): boolean; virtual; abstract;
+ function Decode(const InStr: RawByteString; out OutStr: UCS4String): boolean; virtual; abstract;
+ end;
+
+ TSingleByteEncoder = class(TEncoder)
+ public
+ function Encode(const InStr: UCS4String; out OutStr: RawByteString): boolean; override;
+ function Decode(const InStr: RawByteString; out OutStr: UCS4String): boolean; override;
+ function DecodeChar(InChr: AnsiChar; out OutChr: UCS4Char): boolean; virtual; abstract;
+ function EncodeChar(InChr: UCS4Char; out OutChr: AnsiChar): boolean; virtual; abstract;
+ end;
+
+const
+ ERROR_CHAR = '?';
+
+var
+ Encoders: array[TEncoding] of IEncoder;
+
+function TSingleByteEncoder.Encode(const InStr: UCS4String; out OutStr: RawByteString): boolean;
+var
+ I: integer;
+begin
+ SetLength(OutStr, LengthUCS4(InStr));
+ Result := true;
+ for I := 1 to Length(OutStr) do
+ begin
+ if (not EncodeChar(InStr[I-1], OutStr[I])) then
+ Result := false;
+ end;
+end;
+
+function TSingleByteEncoder.Decode(const InStr: RawByteString; out OutStr: UCS4String): boolean;
+var
+ I: integer;
+begin
+ SetLength(OutStr, Length(InStr)+1);
+ Result := true;
+ for I := 1 to Length(InStr) do
+ begin
+ if (not DecodeChar(InStr[I], OutStr[I-1])) then
+ Result := false;
+ end;
+ OutStr[High(OutStr)] := 0;
+end;
+
+function DecodeString(const Src: RawByteString; out Dst: WideString; SrcEncoding: TEncoding): boolean;
+var
+ DstUCS4: UCS4String;
+begin
+ Result := Encoders[SrcEncoding].Decode(Src, DstUCS4);
+ Dst := UCS4StringToWideString(DstUCS4);
+end;
+
+function DecodeString(const Src: RawByteString; SrcEncoding: TEncoding): WideString;
+begin
+ DecodeString(Src, Result, SrcEncoding);
+end;
+
+function DecodeStringUTF8(const Src: RawByteString; out Dst: UTF8String; SrcEncoding: TEncoding): boolean;
+var
+ DstUCS4: UCS4String;
+begin
+ Result := Encoders[SrcEncoding].Decode(Src, DstUCS4);
+ Dst := UCS4ToUTF8String(DstUCS4);
+end;
+
+function DecodeStringUTF8(const Src: RawByteString; SrcEncoding: TEncoding): UTF8String;
+begin
+ DecodeStringUTF8(Src, Result, SrcEncoding);
+end;
+
+function EncodeString(const Src: WideString; out Dst: RawByteString; DstEncoding: TEncoding): boolean;
+begin
+ Result := Encoders[DstEncoding].Encode(WideStringToUCS4String(Src), Dst);
+end;
+
+function EncodeString(const Src: WideString; DstEncoding: TEncoding): RawByteString;
+begin
+ EncodeString(Src, Result, DstEncoding);
+end;
+
+function EncodeStringUTF8(const Src: UTF8String; out Dst: RawByteString; DstEncoding: TEncoding): boolean;
+begin
+ Result := Encoders[DstEncoding].Encode(UTF8ToUCS4String(Src), Dst);
+end;
+
+function EncodeStringUTF8(const Src: UTF8String; DstEncoding: TEncoding): RawByteString;
+begin
+ EncodeStringUTF8(Src, Result, DstEncoding);
+end;
+
+function CheckReplaceUTF8BOM(var Text: RawByteString): boolean;
+begin
+ if AnsiStartsStr(UTF8_BOM, Text) then
+ begin
+ Text := Copy(Text, Length(UTF8_BOM)+1, Length(Text)-Length(UTF8_BOM));
+ Result := true;
+ Exit;
+ end;
+ Result := false;
+end;
+
+function ParseEncoding(const EncodingStr: AnsiString; Default: TEncoding): TEncoding;
+var
+ PrepStr: AnsiString; // prepared encoding string
+ Encoding: TEncoding;
+begin
+ // remove surrounding whitespace, replace dashes, to upper case
+ PrepStr := UpperCase(AnsiReplaceStr(Trim(EncodingStr), '-', ''));
+ for Encoding := Low(TEncoding) to High(TEncoding) do
+ begin
+ if (Encoders[Encoding].GetName() = PrepStr) then
+ begin
+ Result := Encoding;
+ Exit;
end;
end;
- Result := Default;
-end;
-
-function EncodingName(Encoding: TEncoding): AnsiString;
-begin
- Result := Encoders[Encoding].GetName();
-end;
-
-{$I ../encoding/Locale.inc}
-{$I ../encoding/UTF8.inc}
-{$I ../encoding/CP1250.inc}
-{$I ../encoding/CP1252.inc}
-
-initialization
- Encoders[encLocale] := TEncoderLocale.Create;
- Encoders[encUTF8] := TEncoderUTF8.Create;
- Encoders[encCP1250] := TEncoderCP1250.Create;
- Encoders[encCP1252] := TEncoderCP1252.Create;
-
-end.
+ Result := Default;
+end;
+
+function EncodingName(Encoding: TEncoding): AnsiString;
+begin
+ Result := Encoders[Encoding].GetName();
+end;
+
+{$I ../encoding/Locale.inc}
+{$I ../encoding/UTF8.inc}
+{$I ../encoding/CP1250.inc}
+{$I ../encoding/CP1252.inc}
+
+initialization
+ Encoders[encLocale] := TEncoderLocale.Create;
+ Encoders[encUTF8] := TEncoderUTF8.Create;
+ Encoders[encCP1250] := TEncoderCP1250.Create;
+ Encoders[encCP1252] := TEncoderCP1252.Create;
+
+end.
diff --git a/unicode/src/base/UTexture.pas b/unicode/src/base/UTexture.pas
index 97f244fe..04badae4 100644
--- a/unicode/src/base/UTexture.pas
+++ b/unicode/src/base/UTexture.pas
@@ -40,6 +40,7 @@ uses
Classes,
SysUtils,
UCommon,
+ UPath,
SDL,
SDL_Image;
@@ -66,7 +67,7 @@ type
TexX2: real;
TexY2: real;
Alpha: real;
- Name: string; // experimental for handling cache images. maybe it's useful for dynamic skins
+ Name: IPath; // experimental for handling cache images. maybe it's useful for dynamic skins
end;
type
@@ -91,7 +92,7 @@ procedure AdjustPixelFormat(var TexSurface: PSDL_Surface; Typ: TTextureType);
type
PTextureEntry = ^TTextureEntry;
TTextureEntry = record
- Name: string;
+ Name: IPath;
Typ: TTextureType;
Color: cardinal;
@@ -105,7 +106,7 @@ type
Texture: array of TTextureEntry;
public
procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Color: cardinal; Cache: boolean);
- function FindTexture(const Name: string; Typ: TTextureType; Color: cardinal): integer;
+ function FindTexture(const Name: IPath; Typ: TTextureType; Color: cardinal): integer;
end;
TTextureUnit = class
@@ -116,14 +117,14 @@ type
procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Cache: boolean = false); overload;
procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Color: cardinal; Cache: boolean = false); overload;
- function GetTexture(const Name: string; Typ: TTextureType; FromCache: boolean = false): TTexture; overload;
- function GetTexture(const Name: string; Typ: TTextureType; Col: LongWord; FromCache: boolean = false): TTexture; overload;
- function LoadTexture(FromRegistry: boolean; const Identifier: string; Typ: TTextureType; Col: LongWord): TTexture; overload;
- function LoadTexture(const Identifier: string; Typ: TTextureType; Col: LongWord): TTexture; overload;
- function LoadTexture(const Identifier: string): TTexture; overload;
- function CreateTexture(Data: PChar; const Name: string; Width, Height: word; BitsPerPixel: byte): TTexture;
- procedure UnloadTexture(const Name: string; Typ: TTextureType; FromCache: boolean); overload;
- procedure UnloadTexture(const Name: string; Typ: TTextureType; Col: cardinal; FromCache: boolean); overload;
+ function GetTexture(const Name: IPath; Typ: TTextureType; FromCache: boolean = false): TTexture; overload;
+ function GetTexture(const Name: IPath; Typ: TTextureType; Col: LongWord; FromCache: boolean = false): TTexture; overload;
+ function LoadTexture(FromRegistry: boolean; const Identifier: IPath; Typ: TTextureType; Col: LongWord): TTexture; overload;
+ function LoadTexture(const Identifier: IPath; Typ: TTextureType; Col: LongWord): TTexture; overload;
+ function LoadTexture(const Identifier: IPath): TTexture; overload;
+ function CreateTexture(Data: PChar; const Name: IPath; Width, Height: word; BitsPerPixel: byte): TTexture;
+ procedure UnloadTexture(const Name: IPath; Typ: TTextureType; FromCache: boolean); overload;
+ procedure UnloadTexture(const Name: IPath; Typ: TTextureType; Col: cardinal; FromCache: boolean); overload;
//procedure FlushTextureDatabase();
constructor Create;
@@ -188,7 +189,7 @@ begin
Texture[TextureIndex].Texture := Tex;
end;
-function TTextureDatabase.FindTexture(const Name: string; Typ: TTextureType; Color: cardinal): integer;
+function TTextureDatabase.FindTexture(const Name: IPath; Typ: TTextureType; Color: cardinal): integer;
var
TextureIndex: integer;
CurrentTexture: PTextureEntry;
@@ -235,18 +236,18 @@ begin
TextureDatabase.AddTexture(Tex, Typ, Color, Cache);
end;
-function TTextureUnit.LoadTexture(FromRegistry: boolean; const Identifier: string; Typ: TTextureType; Col: LongWord): TTexture;
+function TTextureUnit.LoadTexture(FromRegistry: boolean; const Identifier: IPath; Typ: TTextureType; Col: LongWord): TTexture;
begin
// FIXME: what is the FromRegistry parameter supposed to do?
Result := LoadTexture(Identifier, Typ, Col);
end;
-function TTextureUnit.LoadTexture(const Identifier: string): TTexture;
+function TTextureUnit.LoadTexture(const Identifier: IPath): TTexture;
begin
Result := LoadTexture(Identifier, TEXTURE_TYPE_PLAIN, 0);
end;
-function TTextureUnit.LoadTexture(const Identifier: string; Typ: TTextureType; Col: LongWord): TTexture;
+function TTextureUnit.LoadTexture(const Identifier: IPath; Typ: TTextureType; Col: LongWord): TTexture;
var
TexSurface: PSDL_Surface;
newWidth, newHeight: integer;
@@ -260,7 +261,7 @@ begin
TexSurface := LoadImage(Identifier);
if not assigned(TexSurface) then
begin
- Log.LogError('Could not load texture: "' + Identifier +'" with type "'+ TextureTypeToStr(Typ) +'"',
+ Log.LogError('Could not load texture: "' + Identifier.ToNative +'" with type "'+ TextureTypeToStr(Typ) +'"',
'TTextureUnit.LoadTexture');
Exit;
end;
@@ -363,16 +364,16 @@ begin
SDL_FreeSurface(TexSurface);
end;
-function TTextureUnit.GetTexture(const Name: string; Typ: TTextureType; FromCache: boolean): TTexture;
+function TTextureUnit.GetTexture(const Name: IPath; Typ: TTextureType; FromCache: boolean): TTexture;
begin
Result := GetTexture(Name, Typ, 0, FromCache);
end;
-function TTextureUnit.GetTexture(const Name: string; Typ: TTextureType; Col: LongWord; FromCache: boolean): TTexture;
+function TTextureUnit.GetTexture(const Name: IPath; Typ: TTextureType; Col: LongWord; FromCache: boolean): TTexture;
var
TextureIndex: integer;
begin
- if (Name = '') then
+ if (Name.IsUnset) then
begin
// zero texture data
FillChar(Result, SizeOf(Result), 0);
@@ -413,7 +414,7 @@ begin
Result := TextureDatabase.Texture[TextureIndex].Texture;
end;
-function TTextureUnit.CreateTexture(Data: PChar; const Name: string; Width, Height: word; BitsPerPixel: byte): TTexture;
+function TTextureUnit.CreateTexture(Data: PChar; const Name: IPath; Width, Height: word; BitsPerPixel: byte): TTexture;
var
//Error: integer;
ActTex: GLuint;
@@ -467,12 +468,12 @@ begin
Result.Name := Name;
end;
-procedure TTextureUnit.UnloadTexture(const Name: string; Typ: TTextureType; FromCache: boolean);
+procedure TTextureUnit.UnloadTexture(const Name: IPath; Typ: TTextureType; FromCache: boolean);
begin
UnloadTexture(Name, Typ, 0, FromCache);
end;
-procedure TTextureUnit.UnloadTexture(const Name: string; Typ: TTextureType; Col: cardinal; FromCache: boolean);
+procedure TTextureUnit.UnloadTexture(const Name: IPath; Typ: TTextureType; Col: cardinal; FromCache: boolean);
var
T: integer;
TexNum: GLuint;
diff --git a/unicode/src/base/UThemes.pas b/unicode/src/base/UThemes.pas
index 3fd77853..11ec746c 100644
--- a/unicode/src/base/UThemes.pas
+++ b/unicode/src/base/UThemes.pas
@@ -34,11 +34,12 @@ interface
{$I switches.inc}
uses
- ULog,
IniFiles,
SysUtils,
Classes,
- UTexture;
+ ULog,
+ UTexture,
+ UPath;
type
TRGB = record
@@ -531,10 +532,10 @@ type
TextFound: TThemeText;
//Translated Texts
- Songsfound: string;
- NoSongsfound: string;
- CatText: string;
- IType: array [0..2] of string;
+ Songsfound: UTF8String;
+ NoSongsfound: UTF8String;
+ CatText: UTF8String;
+ IType: array [0..2] of UTF8String;
end;
//Party Screens
@@ -761,11 +762,11 @@ type
Playlist: TThemePlaylist;
- ILevel: array[0..2] of string;
+ ILevel: array[0..2] of UTF8String;
- constructor Create(const FileName: string); overload; // Initialize theme system
- constructor Create(const FileName: string; Color: integer); overload; // Initialize theme system with color
- function LoadTheme(FileName: string; sColor: integer): boolean; // Load some theme settings from file
+ constructor Create(const FileName: IPath); overload; // Initialize theme system
+ constructor Create(const FileName: IPath; Color: integer); overload; // Initialize theme system with color
+ function LoadTheme(const FileName: IPath; sColor: integer): boolean; // Load some theme settings from file
procedure LoadColors;
@@ -845,12 +846,12 @@ begin
glColor4f(Color.R, Color.G, Color.B, Min(Color.A, Alpha));
end;
-constructor TTheme.Create(const FileName: string);
+constructor TTheme.Create(const FileName: IPath);
begin
Create(FileName, 0);
end;
-constructor TTheme.Create(const FileName: string; Color: integer);
+constructor TTheme.Create(const FileName: IPath; Color: integer);
begin
inherited Create();
@@ -893,7 +894,7 @@ begin
end;
-function TTheme.LoadTheme(FileName: string; sColor: integer): boolean;
+function TTheme.LoadTheme(const FileName: IPath; sColor: integer): boolean;
var
I: integer;
begin
@@ -901,23 +902,21 @@ begin
CreateThemeObjects();
- Log.LogStatus('Loading: '+ FileName, 'TTheme.LoadTheme');
-
- FileName := AdaptFilePaths(FileName);
+ Log.LogStatus('Loading: '+ FileName.ToNative, 'TTheme.LoadTheme');
- if not FileExists(FileName) then
+ if not FileName.IsFile() then
begin
- Log.LogError('Theme does not exist ('+ FileName +')', 'TTheme.LoadTheme');
+ Log.LogError('Theme does not exist ('+ FileName.ToNative +')', 'TTheme.LoadTheme');
end;
- if FileExists(FileName) then
+ if FileName.IsFile() then
begin
Result := true;
{$IFDEF THEMESAVE}
- ThemeIni := TIniFile.Create(FileName);
+ ThemeIni := TIniFile.Create(FileName.ToNative);
{$ELSE}
- ThemeIni := TMemIniFile.Create(FileName);
+ ThemeIni := TMemIniFile.Create(FileName.ToNative);
{$ENDIF}
if ThemeIni.ReadString('Theme', 'Name', '') <> '' then
diff --git a/unicode/src/base/UUnicodeUtils.pas b/unicode/src/base/UUnicodeUtils.pas
index ce1731b6..29be778a 100644
--- a/unicode/src/base/UUnicodeUtils.pas
+++ b/unicode/src/base/UUnicodeUtils.pas
@@ -149,6 +149,11 @@ function UCS4UpperCase(const str: UCS4String): UCS4String; overload;
function UCS4CharToString(ch: UCS4Char): UCS4String;
{**
+ * @seealso System.Pos()
+ *}
+function UTF8Pos(const substr: UTF8String; const str: UTF8String): Integer;
+
+{**
* Copies a segment of str starting with Index (1-based) with Count characters (not bytes).
*}
function UTF8Copy(const str: UTF8String; Index: Integer = 1; Count: Integer = -1): UTF8String;
@@ -520,6 +525,11 @@ begin
Result[1] := 0;
end;
+function UTF8Pos(const substr: UTF8String; const str: UTF8String): Integer;
+begin
+ Result := Pos(substr, str);
+end;
+
function UTF8Copy(const str: UTF8String; Index: Integer; Count: Integer): UTF8String;
begin
Result := UCS4ToUTF8String(UCS4Copy(UTF8ToUCS4String(str), Index-1, Count));
diff --git a/unicode/src/base/UXMLSong.pas b/unicode/src/base/UXMLSong.pas
index 58b48789..e8962539 100644
--- a/unicode/src/base/UXMLSong.pas
+++ b/unicode/src/base/UXMLSong.pas
@@ -34,7 +34,9 @@ interface
{$I switches.inc}
uses
- Classes;
+ Classes,
+ UPath,
+ UUnicodeUtils;
type
TNote = record
@@ -42,30 +44,30 @@ type
Duration: Cardinal;
Tone: Integer;
NoteTyp: Byte;
- Lyric: String;
+ Lyric: UTF8String;
end;
- ANote = Array of TNote;
+ ANote = array of TNote;
TSentence = record
Singer: Byte;
Duration: Cardinal;
Notes: ANote;
end;
- ASentence = Array of TSentence;
+ ASentence = array of TSentence;
- TSongInfo = Record
+ TSongInfo = record
ID: Cardinal;
DualChannel: Boolean;
- Header: Record
- Artist: String;
- Title: String;
+ Header: record
+ Artist: UTF8String;
+ Title: UTF8String;
Gap: Cardinal;
BPM: Real;
Resolution: Byte;
- Edition: String;
- Genre: String;
- Year: String;
- Language: String;
+ Edition: UTF8String;
+ Genre: UTF8String;
+ Year: UTF8String;
+ Language: UTF8String;
end;
CountSentences: Cardinal;
Sentences: ASentence;
@@ -81,23 +83,23 @@ type
BindLyrics: Boolean; //Should the Lyrics be bind to the last Word (no Space)
FirstNote: Boolean; //Is this the First Note found? For Gap calculating
- Function ParseLine(Line: String): Boolean;
+ function ParseLine(Line: RawByteString): Boolean;
public
SongInfo: TSongInfo;
- ErrorMessage: String;
- Edition: String;
- SingstarVersion: String;
+ ErrorMessage: string;
+ Edition: UTF8String;
+ SingstarVersion: string;
- Settings: Record
+ Settings: record
DashReplacement: Char;
end;
- Constructor Create;
+ constructor Create;
- Function ParseConfigforEdition(const Filename: String): String;
+ function ParseConfigForEdition(const Filename: IPath): String;
- Function ParseSongHeader(const Filename: String): Boolean; //Parse Song Header only
- Function ParseSong (const Filename: String): Boolean; //Parse whole Song
+ function ParseSongHeader(const Filename: IPath): Boolean; //Parse Song Header only
+ function ParseSong (const Filename: IPath): Boolean; //Parse whole Song
end;
const
@@ -114,9 +116,12 @@ const
DS_Both = 3;
implementation
-uses SysUtils, StrUtils;
-Constructor TParser.Create;
+uses
+ SysUtils,
+ StrUtils;
+
+constructor TParser.Create;
begin
inherited Create;
ErrorMessage := '';
@@ -124,19 +129,28 @@ begin
DecimalSeparator := '.';
end;
-Function TParser.ParseSong (const Filename: String): Boolean;
-var I: Integer;
+function TParser.ParseSong(const Filename: IPath): Boolean;
+var
+ I: Integer;
+ FileStream: TBinaryFileStream;
begin
+ {$message warn 'TODO: TParser.ParseSong'}
+
+(*
Result := False;
- if FileExists(Filename) then
+ if Filename.IsFile() then
begin
SSFile := TStringList.Create;
+ ErrorMessage := 'Can''t open melody.xml file';
+
try
- ErrorMessage := 'Can''t open melody.xml file';
- SSFile.LoadFromFile(Filename);
+ FileStream := TBinaryFileStream.Create(Filename);
+ SSFile.LoadFromStream(FileStream);
+
ErrorMessage := '';
Result := True;
+
I := 0;
SongInfo.CountSentences := 0;
@@ -153,7 +167,7 @@ begin
SetLength(SongInfo.Sentences, 0);
- While Result And (I < SSFile.Count) do
+ while Result and (I < SSFile.Count) do
begin
Result := ParseLine(SSFile.Strings[I]);
@@ -164,12 +178,16 @@ begin
SSFile.Free;
end;
end;
+ *)
end;
-Function TParser.ParseSongHeader (const Filename: String): Boolean;
+function TParser.ParseSongHeader (const Filename: IPath): Boolean;
var I: Integer;
begin
Result := False;
+
+ {$message warn 'TODO: TParser.ParseSong'}
+ (*
if FileExists(Filename) then
begin
SSFile := TStringList.Create;
@@ -211,6 +229,7 @@ begin
end
else
ErrorMessage := 'Can''t find melody.xml file';
+ *)
end;
Function TParser.ParseLine(Line: String): Boolean;
@@ -569,7 +588,7 @@ begin
Result := true;
end;
-Function TParser.ParseConfigforEdition(const Filename: String): String;
+Function TParser.ParseConfigForEdition(const Filename: IPath): String;
var
txt: TStringlist;
I: Integer;
@@ -578,6 +597,10 @@ var
begin
Result := '';
txt := TStringlist.Create;
+
+ {$message warn 'TODO: TParser.ParseConfigForEdition'}
+
+ (*
try
txt.LoadFromFile(Filename);
@@ -601,6 +624,7 @@ begin
finally
txt.Free;
end;
+ *)
end;
end.