aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/base/UFiles.pas22
-rw-r--r--src/base/USong.pas60
-rw-r--r--src/screens/UScreenEditSub.pas7
3 files changed, 80 insertions, 9 deletions
diff --git a/src/base/UFiles.pas b/src/base/UFiles.pas
index a46d4e0d..2820a08c 100644
--- a/src/base/UFiles.pas
+++ b/src/base/UFiles.pas
@@ -102,6 +102,22 @@ var
SaveSong := ssrEncodingError;
end;
+ procedure WriteCustomTags;
+ var
+ I: integer;
+ Line: RawByteString;
+ begin
+ for I := 0 to High(Song.CustomTags) do
+ begin
+ Line := EncodeToken(Song.CustomTags[I].Content);
+ if (Length(Song.CustomTags[I].Tag) > 0) then
+ Line := EncodeToken(Song.CustomTags[I].Tag) + ':' + Line;
+
+ SongFile.WriteLine('#' + Line);
+ end;
+
+ end;
+
begin
// Relative := true; // override (idea - use shift+S to save with relative)
Result := ssrOK;
@@ -109,6 +125,9 @@ begin
try
SongFile := TMemTextFileStream.Create(Name, fmCreate);
try
+ // to-do: should we really write the BOM?
+ // it causes problems w/ older versions
+ // e.g. usdx 1.0.1a or ultrastar < 0.7.0
if (Song.Encoding = encUTF8) then
SongFile.WriteString(UTF8_BOM);
@@ -136,6 +155,9 @@ begin
SongFile.WriteLine('#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
SongFile.WriteLine('#GAP:' + FloatToStr(Song.GAP));
+ // write custom header tags
+ WriteCustomTags;
+
RelativeSubTime := 0;
for B := 1 to High(Song.BPM) do
SongFile.WriteLine('B ' + FloatToStr(Song.BPM[B].StartBeat) + ' '
diff --git a/src/base/USong.pas b/src/base/USong.pas
index a6d46c4c..d76718d2 100644
--- a/src/base/USong.pas
+++ b/src/base/USong.pas
@@ -76,6 +76,14 @@ type
Score: integer;
end;
+ { used to hold header tags that are not supported by this version of
+ usdx (e.g. some tags from ultrastar 0.7.0) when songs are loaded in
+ songeditor. They will be written the end of the song header }
+ TCustomHeaderTag = record
+ Tag: UTF8String;
+ Content: UTF8String;
+ end;
+
TSong = class
private
FileLineNo : integer; // line, which is read last, for error reporting
@@ -91,12 +99,11 @@ type
function ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar;
function ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString;
- function ReadTXTHeader(SongFile: TTextFileStream): boolean;
+ function ReadTXTHeader(SongFile: TTextFileStream; ReadCustomTags: Boolean): boolean;
function ReadXMLHeader(const aFileName: IPath): boolean;
function GetFolderCategory(const aFileName: IPath): UTF8String;
function FindSongFile(Dir: IPath; Mask: UTF8String): IPath;
-
public
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)
@@ -131,6 +138,8 @@ type
Encoding: TEncoding;
+ CustomTags: array of TCustomHeaderTag;
+
Score: array[0..2] of array of TScore;
// these are used when sorting is enabled
@@ -154,7 +163,7 @@ type
constructor Create(const aFileName : IPath); overload;
function LoadSong: boolean;
function LoadXMLSong: boolean;
- function Analyse(): boolean;
+ function Analyse(const ReadCustomTags: Boolean = false): boolean;
function AnalyseXML(): boolean;
procedure Clear();
end;
@@ -177,6 +186,7 @@ constructor TSong.Create();
begin
inherited;
+ // to-do : special create for category "songs"
//dirty fix to fix folders=on
Self.Path := PATH_NONE();
Self.FileName := PATH_NONE();
@@ -211,7 +221,7 @@ begin
if (aFileName.IsChildOf(CurSongPath, true)) then
begin
// songs are in the "root" of the songdir => use songdir for the categorys name
- Result := CurSongPath.ToUTF8; // TODO: remove trailing path-delim?
+ Result := CurSongPath.RemovePathDelim.ToUTF8;
end
else
begin
@@ -824,7 +834,6 @@ begin
end;
-
{**
* "International" StrToFloat variant. Uses either ',' or '.' as decimal
* separator.
@@ -839,7 +848,7 @@ begin
Result := StrToFloatDef(TempValue, 0);
end;
-function TSong.ReadTXTHeader(SongFile: TTextFileStream): boolean;
+function TSong.ReadTXTHeader(SongFile: TTextFileStream; ReadCustomTags: Boolean): boolean;
var
Line, Identifier: string;
Value: string;
@@ -847,6 +856,21 @@ var
Done: byte; // bit-vector of mandatory fields
EncFile: IPath; // encoded filename
FullFileName: string;
+
+ { adds a custom header tag to the song
+ if there is no ':' in the read line, Tag should be empty
+ and the whole line should be in Content }
+ procedure AddCustomTag(const Tag, Content: String);
+ var Len: Integer;
+ begin
+ if ReadCustomTags then
+ begin
+ Len := Length(CustomTags);
+ SetLength(CustomTags, Len + 1);
+ CustomTags[Len].Tag := DecodeStringUTF8(Tag, Encoding);
+ CustomTags[Len].Content := DecodeStringUTF8(Content, Encoding);
+ end;
+ end;
begin
Result := true;
Done := 0;
@@ -876,7 +900,17 @@ begin
//Line has no Seperator, ignore non header field
if (SepPos = 0) then
+ begin
+ AddCustomTag('', Copy(Line, 2, Length(Line) - 1));
+ // read next line
+ if (not SongFile.ReadLine(Line)) then
+ begin
+ Result := false;
+ Log.LogError('File incomplete or not Ultrastar txt (A): ' + FullFileName);
+ Break;
+ end;
Continue;
+ end;
//Read Identifier and Value
Identifier := UpperCase(Trim(Copy(Line, 2, SepPos - 2))); //Uppercase is for Case Insensitive Checks
@@ -887,6 +921,7 @@ begin
begin
Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName,
'TSong.ReadTXTHeader');
+ AddCustomTag(Identifier, '');
end
else
begin
@@ -1034,6 +1069,12 @@ begin
else if (Identifier = 'ENCODING') then
begin
self.Encoding := ParseEncoding(Value, DEFAULT_ENCODING);
+ end
+
+ // unsupported tag
+ else
+ begin
+ AddCustomTag(Identifier, Value);
end;
end; // End check for non-empty Value
@@ -1220,6 +1261,9 @@ begin
// set to default encoding
Encoding := DEFAULT_ENCODING;
+ // clear custom header tags
+ SetLength(CustomTags, 0);
+
//Required Information
Mp3 := PATH_NONE;
SetLength(BPM, 0);
@@ -1240,7 +1284,7 @@ begin
Relative := false;
end;
-function TSong.Analyse(): boolean;
+function TSong.Analyse(const ReadCustomTags: Boolean): boolean;
var
SongFile: TTextFileStream;
begin
@@ -1256,7 +1300,7 @@ begin
Self.clear;
//Read Header
- Result := Self.ReadTxTHeader(SongFile)
+ Result := Self.ReadTxTHeader(SongFile, ReadCustomTags)
finally
SongFile.Free;
end;
diff --git a/src/screens/UScreenEditSub.pas b/src/screens/UScreenEditSub.pas
index 00e62c16..04407005 100644
--- a/src/screens/UScreenEditSub.pas
+++ b/src/screens/UScreenEditSub.pas
@@ -1296,7 +1296,12 @@ begin
if FileExt.ToUTF8 = '.xml' then
Error := not CurrentSong.LoadXMLSong()
else
- Error := not CurrentSong.LoadSong();
+ begin
+ // reread header with custom tags
+ Error := not CurrentSong.Analyse(true);
+ if not Error then
+ Error := not CurrentSong.LoadSong;
+ end;
except
Error := true;
end;