aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors_alexander <s_alexander@b956fd51-792f-4845-bead-9b4dfca2ff2c>2009-11-09 00:27:55 +0000
committers_alexander <s_alexander@b956fd51-792f-4845-bead-9b4dfca2ff2c>2009-11-09 00:27:55 +0000
commit917901e8e33438c425aef50a0a7417f32d77b760 (patch)
tree95f081dd0d9a206bba3bd9c0a70e7a9a4cddafc8
parent474452a88427e6ea83d6435b117e5deb1d4cd0c6 (diff)
downloadusdx-917901e8e33438c425aef50a0a7417f32d77b760.tar.gz
usdx-917901e8e33438c425aef50a0a7417f32d77b760.tar.xz
usdx-917901e8e33438c425aef50a0a7417f32d77b760.zip
merged unicode branch (r1931) into trunk
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1939 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--BuildBot.trigger2
-rw-r--r--COPYRIGHT.txt56
-rw-r--r--ChangeLog.GERMAN.txt402
-rw-r--r--DisplayChanges.patch14
-rw-r--r--Makefile.in1
-rw-r--r--RELEASEBLOCKERS.txt61
-rwxr-xr-xconfigure5
-rw-r--r--dists/delphi2005/readme.txt10
-rw-r--r--dists/delphi7/readme.txt10
-rwxr-xr-xdists/lazarus/readme.txt30
-rw-r--r--game/fonts/DejaVu/AUTHORS44
-rw-r--r--game/fonts/DejaVu/DejaVuSans-Bold.ttfbin0 -> 561576 bytes
-rw-r--r--game/fonts/DejaVu/DejaVuSans.ttfbin0 -> 611552 bytes
-rw-r--r--game/fonts/DejaVu/LICENSE99
-rw-r--r--game/fonts/DejaVu/README59
-rw-r--r--game/fonts/FreeSans/AUTHORS191
-rw-r--r--game/fonts/FreeSans/COPYING341
-rw-r--r--game/fonts/FreeSans/CREDITS506
-rw-r--r--game/fonts/FreeSans/FreeSans.ttf (renamed from game/fonts/FreeSans.ttf)bin770828 -> 770828 bytes
-rw-r--r--game/fonts/FreeSans/FreeSansBold.ttf (renamed from game/fonts/FreeSansBold.ttf)bin250228 -> 250228 bytes
-rw-r--r--game/fonts/FreeSans/README108
-rw-r--r--game/fonts/Vera.ttfbin65932 -> 0 bytes
-rw-r--r--game/fonts/VeraBd.ttfbin58716 -> 0 bytes
-rw-r--r--game/fonts/bold/eurostar_regular_bold.datbin256 -> 0 bytes
-rw-r--r--game/fonts/bold/eurostar_regular_bold.pngbin84067 -> 0 bytes
-rwxr-xr-xgame/fonts/fonts.ini22
-rw-r--r--game/fonts/fontsTTF.ini11
-rw-r--r--game/fonts/normal/eurostar_regular.datbin256 -> 0 bytes
-rw-r--r--game/fonts/normal/eurostar_regular.pngbin59609 -> 0 bytes
-rw-r--r--game/fonts/outline1/outline1.datbin256 -> 0 bytes
-rw-r--r--game/fonts/outline1/outline1.pngbin74739 -> 0 bytes
-rw-r--r--game/fonts/outline2/outline2.datbin256 -> 0 bytes
-rw-r--r--game/fonts/outline2/outline2.pngbin106020 -> 0 bytes
-rw-r--r--game/languages/Catalan.ini784
-rw-r--r--game/languages/Croatian.ini806
-rw-r--r--game/languages/Dutch.ini794
-rw-r--r--game/languages/English.ini16
-rw-r--r--game/languages/Euskara.ini794
-rw-r--r--game/languages/Finnish.ini112
-rw-r--r--game/languages/French.ini796
-rw-r--r--game/languages/German.ini134
-rw-r--r--game/languages/Greek.ini798
-rw-r--r--game/languages/Italian.ini38
-rw-r--r--game/languages/Japanese.inibin19466 -> 12901 bytes
-rw-r--r--game/languages/Portuguese.ini794
-rw-r--r--game/languages/Spanish.ini796
-rw-r--r--game/languages/Swedish.ini794
-rwxr-xr-xgame/languages/convert.sh43
-rw-r--r--game/languages/old/Danish.ini592
-rw-r--r--game/languages/old/French.ini618
-rw-r--r--game/languages/old/Norwegian.ini592
-rw-r--r--game/languages/old/Polish.ini606
-rw-r--r--game/languages/old/Serbian.ini594
-rw-r--r--game/languages/old/Slovak.ini602
-rw-r--r--game/languages/old/Slovenian.ini642
-rw-r--r--game/languages/old/readme.txt570
-rw-r--r--game/themes/Deluxe/Ocean.ini35
-rw-r--r--installerdependencies/documents/license.txt250
-rw-r--r--plugins/Don't_Get_Worse/Hold_The_Line.bdsproj175
-rw-r--r--plugins/Don't_Get_Worse/Hold_The_Line.lpi108
-rw-r--r--src/Makefile.in2
-rw-r--r--src/base/TextGL.pas323
-rw-r--r--src/base/TextGLFreetype.pas222
-rw-r--r--src/base/UBeatTimer.pas338
-rw-r--r--src/base/UCatCovers.pas116
-rw-r--r--src/base/UCommandLine.pas25
-rw-r--r--src/base/UCommon.pas321
-rw-r--r--src/base/UConfig.pas8
-rw-r--r--src/base/UCovers.pas56
-rw-r--r--src/base/UDLLManager.pas59
-rw-r--r--src/base/UDataBase.pas163
-rw-r--r--src/base/UEditorLyrics.pas4
-rw-r--r--src/base/UFiles.pas202
-rw-r--r--src/base/UFilesystem.pas692
-rw-r--r--src/base/UFont.pas440
-rw-r--r--src/base/UGraphic.pas34
-rw-r--r--src/base/UImage.pas112
-rw-r--r--src/base/UIni.pas279
-rw-r--r--src/base/ULanguage.pas203
-rw-r--r--src/base/ULog.pas44
-rw-r--r--src/base/ULyrics.pas4
-rw-r--r--src/base/UMain.pas32
-rw-r--r--src/base/UMusic.pas63
-rw-r--r--src/base/UNote.pas8
-rw-r--r--src/base/UParty.pas6
-rw-r--r--src/base/UPath.pas1427
-rw-r--r--src/base/UPathUtils.pas196
-rw-r--r--src/base/UPlatform.pas95
-rw-r--r--src/base/UPlatformLinux.pas102
-rw-r--r--src/base/UPlatformMacOSX.pas194
-rw-r--r--src/base/UPlatformWindows.pas159
-rw-r--r--src/base/UPlaylist.pas258
-rw-r--r--src/base/USkins.pas77
-rw-r--r--src/base/USong.pas1050
-rw-r--r--src/base/USongs.pas419
-rw-r--r--src/base/UTextEncoding.pas270
-rw-r--r--src/base/UTexture.pas47
-rw-r--r--src/base/UThemes.pas67
-rw-r--r--src/base/UUnicodeUtils.pas670
-rw-r--r--src/base/UXMLSong.pas97
-rw-r--r--src/encoding/CP1250.inc236
-rw-r--r--src/encoding/CP1252.inc122
-rw-r--r--src/encoding/Locale.inc55
-rw-r--r--src/encoding/UTF8.inc70
-rw-r--r--src/lib/FreeImage/FreeBitmap.pas2
-rw-r--r--src/lib/SQLite/SQLite3.pas2
-rw-r--r--src/lib/TntUnicodeControls/License.txt11
-rw-r--r--src/lib/TntUnicodeControls/Readme.txt53
-rw-r--r--src/lib/TntUnicodeControls/TntClasses.pas1799
-rw-r--r--src/lib/TntUnicodeControls/TntCompilers.inc378
-rw-r--r--src/lib/TntUnicodeControls/TntFormatStrUtils.pas521
-rw-r--r--src/lib/TntUnicodeControls/TntSysUtils.pas1753
-rw-r--r--src/lib/TntUnicodeControls/TntSystem.pas1427
-rw-r--r--src/lib/TntUnicodeControls/TntWideStrUtils.pas455
-rw-r--r--src/lib/TntUnicodeControls/TntWideStrings.pas846
-rw-r--r--src/lib/TntUnicodeControls/TntWindows.pas1501
-rw-r--r--src/lib/ctypes/ctypes.pas144
-rw-r--r--src/lib/ffmpeg/avformat.pas2
-rw-r--r--src/lib/ffmpeg/avio.pas17
-rw-r--r--src/lib/fft/UFFT.pas2
-rw-r--r--src/lib/freetype/demo/engine-test.bdsproj14
-rw-r--r--src/lib/freetype/demo/engine-test.dpr16
-rw-r--r--src/lib/freetype/demo/engine-test.lpi39
-rw-r--r--src/lib/freetype/freetype.pas911
-rw-r--r--src/lib/freetype/ftconfig.inc35
-rw-r--r--src/lib/freetype/ftglyph.inc435
-rw-r--r--src/lib/freetype/ftimage.inc803
-rw-r--r--src/lib/freetype/ftoutln.inc497
-rw-r--r--src/lib/freetype/ftstroke.inc711
-rw-r--r--src/lib/freetype/fttypes.inc311
-rw-r--r--src/lib/lib-info.txt118
-rw-r--r--src/lib/midi/CIRCBUF.PAS2
-rw-r--r--src/lib/midi/DELPHMCB.PAS2
-rw-r--r--src/lib/midi/MIDIDEFS.PAS2
-rw-r--r--src/lib/midi/MIDITYPE.PAS2
-rw-r--r--src/lib/midi/MidiFile.pas28
-rw-r--r--src/lib/midi/MidiScope.pas2
-rw-r--r--src/lib/midi/Midicons.pas2
-rw-r--r--src/lib/midi/Midiin.pas2
-rw-r--r--src/lib/midi/Midiout.pas2
-rw-r--r--src/lib/other/DirWatch.pas2
-rw-r--r--src/lib/projectM/projectM.pas2
-rw-r--r--src/lib/zlib/zlib.pas2
-rw-r--r--src/media/UAudioCore_Bass.pas12
-rw-r--r--src/media/UAudioDecoder_Bass.pas21
-rw-r--r--src/media/UAudioDecoder_FFmpeg.pas39
-rw-r--r--src/media/UAudioInput_Bass.pas5
-rw-r--r--src/media/UAudioPlaybackBase.pas23
-rw-r--r--src/media/UAudioPlayback_Bass.pas6
-rw-r--r--src/media/UMediaCore_FFmpeg.pas124
-rw-r--r--src/media/UMedia_dummy.pas15
-rw-r--r--src/media/UVideo.pas22
-rw-r--r--src/media/UVisualizer.pas5
-rw-r--r--src/menu/UDisplay.pas66
-rw-r--r--src/menu/UMenu.pas241
-rw-r--r--src/menu/UMenuBackground.pas166
-rw-r--r--src/menu/UMenuBackgroundColor.pas144
-rw-r--r--src/menu/UMenuBackgroundFade.pas352
-rw-r--r--src/menu/UMenuBackgroundNone.pas138
-rw-r--r--src/menu/UMenuBackgroundTexture.pas251
-rw-r--r--src/menu/UMenuBackgroundVideo.pas407
-rw-r--r--src/menu/UMenuSelectSlide.pas2
-rw-r--r--src/menu/UMenuText.pas49
-rw-r--r--src/screens/UScreenCredits.pas97
-rw-r--r--src/screens/UScreenEdit.pas11
-rw-r--r--src/screens/UScreenEditConvert.pas679
-rw-r--r--src/screens/UScreenEditHeader.pas54
-rw-r--r--src/screens/UScreenEditSub.pas155
-rw-r--r--src/screens/UScreenLevel.pas15
-rw-r--r--src/screens/UScreenLoading.pas11
-rw-r--r--src/screens/UScreenMain.pas32
-rw-r--r--src/screens/UScreenName.pas20
-rw-r--r--src/screens/UScreenOpen.pas99
-rw-r--r--src/screens/UScreenOptions.pas17
-rw-r--r--src/screens/UScreenOptionsAdvanced.pas15
-rw-r--r--src/screens/UScreenOptionsGame.pas27
-rw-r--r--src/screens/UScreenOptionsGraphics.pas16
-rw-r--r--src/screens/UScreenOptionsLyrics.pas13
-rw-r--r--src/screens/UScreenOptionsRecord.pas27
-rw-r--r--src/screens/UScreenOptionsSound.pas15
-rw-r--r--src/screens/UScreenOptionsThemes.pas19
-rw-r--r--src/screens/UScreenPartyNewRound.pas31
-rw-r--r--src/screens/UScreenPartyOptions.pas41
-rw-r--r--src/screens/UScreenPartyPlayer.pas22
-rw-r--r--src/screens/UScreenPartyScore.pas37
-rw-r--r--src/screens/UScreenPartyWin.pas22
-rw-r--r--src/screens/UScreenPopup.pas148
-rw-r--r--src/screens/UScreenScore.pas20
-rw-r--r--src/screens/UScreenSing.pas61
-rw-r--r--src/screens/UScreenSingModi.pas32
-rw-r--r--src/screens/UScreenSong.pas130
-rw-r--r--src/screens/UScreenSongJumpto.pas94
-rw-r--r--src/screens/UScreenSongMenu.pas39
-rw-r--r--src/screens/UScreenStatDetail.pas19
-rw-r--r--src/screens/UScreenStatMain.pas42
-rw-r--r--src/screens/UScreenTop5.pas20
-rw-r--r--src/screens/UScreenWelcome.pas8
-rw-r--r--src/switches.inc32
-rw-r--r--src/ultrastardx.dpr37
200 files changed, 28315 insertions, 13006 deletions
diff --git a/.gitignore b/.gitignore
index 9a5d4999..30aa3eff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,6 @@ Thumbs.db
*.bdsproj.local
*.bak
*~
-Thumbs.db
Makefile
config.log
config.status
diff --git a/BuildBot.trigger b/BuildBot.trigger
index 56a6051c..be162472 100644
--- a/BuildBot.trigger
+++ b/BuildBot.trigger
@@ -1 +1 @@
-1 \ No newline at end of file
+4 \ No newline at end of file
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 2dbd2616..cbc9105d 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -1,29 +1,29 @@
-Ultrastar Deluxe
-Copyright (C) 2007-2008 by the following:
-
-If you have contributed to this project then you deserve to be on this
-list. Contact us (see: AUTHORS) and we'll add you.
-
-Jay Binks "jaybinks"
-Dirk Dunger "blindy"
-"eddie-0815"
-Mike Gränz "mog"
-Tobias Gunkel "tobigun"
-"mota"
-"s_alexander"
-Karl-Michael Schindler "mischi"
-Philipp Steinhardt "whiteshark"
-
-Based on UltraStar written by:
-"Corvus5"
-
-Patches contributed by:
-"d0ccrazy"
-"elBandito07"
-"f1fth_freed0m"
-"GogolNr1"
-"jekatt"
-Benedikt Krueger
-Holger Kuhn "hawkear"
-Florian Küpper "flokuep"
+Ultrastar Deluxe
+Copyright (C) 2007-2008 by the following:
+
+If you have contributed to this project then you deserve to be on this
+list. Contact us (see: AUTHORS) and we'll add you.
+
+Jay Binks "jaybinks"
+Dirk Dunger "blindy"
+"eddie-0815"
+Mike Gränz "mog"
+Tobias Gunkel "tobigun"
+"mota"
+Alexander S. "s_alexander"
+Karl-Michael Schindler "mischi"
+Philipp Steinhardt "whiteshark"
+
+Based on UltraStar written by:
+"Corvus5"
+
+Patches contributed by:
+"d0ccrazy"
+"elBandito07"
+"f1fth_freed0m"
+"GogolNr1"
+"jekatt"
+Benedikt Krueger
+Holger Kuhn "hawkear"
+Florian Küpper "flokuep"
Wesley Stessens "profoX" \ No newline at end of file
diff --git a/ChangeLog.GERMAN.txt b/ChangeLog.GERMAN.txt
index cf9b3391..6c2e1cd9 100644
--- a/ChangeLog.GERMAN.txt
+++ b/ChangeLog.GERMAN.txt
@@ -1,202 +1,202 @@
-UltraStar Deluxe 1.00 (by Ultrastar Deluxe Team)
------------------------------
-
---------------
-Theme System
---------------
-Upd: Neues Skin/Theme System aus Ultrastar 0.5.1
-Upd: Laden von selbsterstellten Themes ermöglicht
-Upd: Covereigenschaften in Theme.ini ausgelagert (z.B. Position)
-Upd: Optionale Coverspiegelungen hinzugefügt
-Upd: Neue Coveranordnung (Bessereres Aussehen mit vielen Songs). (Kann im Theme an und ausgeschaltet werden)
-Upd: SongScreen Equalizer Objekt hinzugefügt
-Upd: Optionale Spiegelungen zu Buttons und Statics hinzugefügt. (Reflection = 1)
-Upd: Buttons können nun im Theme zu Gruppen zusammengefasst werden.z.B. Deluxe Theme Main Menu Tools Collection.
-Upd: Buttons könen vom Theme ausgeblendet werden. z.B. für den Exit Button, oder falls Hotkeys existieren.
-Upd: Texte können nun eine Länge (w= ..) erhalten. Sie werden dann bei der gegebenen Länge umgebrochen.
-
---------------
-Aufnahme Optionen
---------------
-Upd: Ultrastar 0.5.2 Recording Optionen hinzugefügt
-Fix: Soundcard Einträge wurden mehrmals in die Config.Ini eingetragen
-Fix: Mehr als ein Singstaradapter sind jetzt möglich(2 Soundkarten mit dem selben Namen)
-
---------------
-Song Screen
---------------
-Upd: Playlist Support hinzugefügt
-
-Upd: Song Suche (mit Interface)
-Upd: Jump to Letter Hotkey
-Upd: Songscreen Menu ähnlich wie bei Singstar
-Upd: Spielernamen können nun vor dem Singen geändert werden
-Upd: Song Vorschau Lautstärke kann nun geändert werden
-Upd: Song Vorschau kann eingefadet werden
-
---------------
-Party Modus
---------------
-Upd: Party Modus hinzugefügt:
- 3 Teams mit bis zu 4 Spielern möglich
- => insgesamt 12 Spieler
-Upd: Modi SDK: Party Modi können mit etwas Programmiererfahrung leicht erstellt werden.
-Upd: 4 Standard Party Modi Plugins: Duell, Hold the Line, Until 5000, Blind Mode
-
---------------
-Effekte
---------------
-Upd: Neue Perfect Note Effekte
-Upd: Effekt bei perfekt gesungenem Satz hinzugefügt
-Upd: Goldene Noten haben jetzt einen Singstar ähnlichen Glitzereffekt, und sind nicht mehr gelb.
-Upd: Neuer Effekt bei getroffenen Goldenen Noten
-Upd: Neuer Menü-Übergangs-Effekt: Screen verschwimmt und "fliegt aus dem Bild heraus". Neue Möglichkeiten für Theme-Ersteller
-
---------------
-Sonstiges
---------------
-Upd: Deluxe Theme hinzugefügt: Theme mit PS3 ähnlichem Aussehen
-Upd: Neues Score Speicherungssystem (basierend auf SQLite)
-Upd: Statistiken hinzugefügt. Generelle Statistiken und
- Beste Scores, Beste Sänger, beliebteste Songs, beliebteste Bands
-Upd: Einige On Screen Fehler Benachrichtigungen hinzugefügt, die neuen Spielern helfen sollten.
-Upd: Neuer Erweiterter Options Screen hinzugefügt
-Upd: Abfrage vor dem Beenden hinzugefügt
-Upd: Song Hintergrundbilder können jetzt auch auf voller Bildschrimfläche dargestellt werden.
-Upd: Im Editor werden jetzt zusätzlich die richtigen Notennamen ausgegeben (C, F#, etc.)
-Upd: Neue Schriftarten
-Upd: Bessere Unterstützung für Kommandozeilen Parameter
-Fix: Nahezu keine Abstürze mehr wegen fehlerhaften TXT-Dateien.
- In Game Popup hinzugefügt und einen Rücksprunk zum Songscreen.
- Selbst der Partymodus wird nicht unterbrochen.
-Fix: Workaround für Cover und Hintergrund JPEG-Errors
-Fix: Videosize kann wieder geändert werden.
-Fix: Bug in LineBonus Popup behoben das zu Speicherüberläufen führen kann.
-Fix: Bug in SelectSlide behoben der zu Fehlern mit weniger als 3 optionen führen kann.
- Automatisches Resizing hinzugefügt
-Fix: Backgrounds can be used now in option Screens, too
-Fix: Unnützer Speicherverbauch wenn ein Song mit Video abgespielt wird. Einige Videodaten blieben im Speicher nachdem der Song beendet wurde.
- Dies könnte zu einem Out Of Memory Error führen wenn viele Songs mit Video gespielt werden.
-Fix: Einige Speichernutzungs und Ladezeit Updates
-Fix: Falsche Satzübergänge wenn T im Editor benutzt wurde und sich 2 Noten von verschiedenen
- Sätzen überlagerten.
-Fix: Editor stürzte ab wenn die letzte Note eines Satzes gelöscht wurde.
-Fix: [Midi Converter]Noten wurden mehrmals hinzugefügt wenn eine Datei mehrmals geöffnet wurde
- oder der Save Button mehrmals gedrückt wurde.
-Fix: [Midi Converter]Satzübergänge werden nun vom Mide Converter automatisch berechnet.
-
-UltraStar 0.5.0 ultra-star.dl.am Mod X-Mas Edition (by Mota und Whiteshark)
------------------------------
-Upd: Neue schnellerer und fehlerresistenter Headereinlesefunktion
-Upd: Bewertungs Bar (Singstar Like)
-Upd: PhrasenBonus + Popups
-
-Upd: Skin verschönert
-
-UltraStar 0.5.0 ultra-star.dl.am Mod r10 (by Mota und Whiteshark)
------------------------------
-Fix: Ein kleiner Bug bei der Pause Funktion wurde gefixt.
-Fix: Ein Bug im Theme System wurde behoben. (SelectSlide konnte nicht weniger als 3 Einträge enthalten.)
-Fix: Skin, Beschränkung auf 4 Skins aufgehoben
-Fix: Noten Texturen werden anders/besser eingelesen
-
-Upd: Zahlen bei der Songauswahl sind jetzt sinnvoller.
-Upd: Anzahl der Songs die eine Kategorie beinhaltet wird in der Übersicht angezeigt
-Upd: Neuer Notenskin
-
-Upd: LanguageTag + Sortierung
-Upd: Unterstützung der Covers.ini aus 0.5.1 - Für alle Sortier-Funtionen. Die alte Möglichkeit ohne die Covers.ini ist weiterhin möglich, genauso wie eine Kombination beider Methoden.
-
-UltraStar 0.5.0 ultra-star.dl.am Mod r9 (Release by Whiteshark)
------------------------------
-
-Upd: BPM und VideoGap Angaben mit Punkt werden jetzt auch eingelesen. Es wird aber in diesem Fall in der Error.log eine meldung mit dem Namen des Fehlerhaften Songs ausgegeben.
-Upd: Sollte beim Einlesen eines Songs(speziell beim Header) ein Fehler auftreten wird in der Error.log der Songname + Zeile ausgegeben.
-
-Upd, Beta: Pause. P drücken und der Song wird pausiert, nocheinmal P und es kann wieder gesungen werden. Noch keine Anzeige ob Pause aktiviert wird, und noch kein Pause Menü.
-
-bekannte Probleme:
-Stellt man die Aufnahme Funktion ein, kommt es zu einem extremen CPU-Zeit verbrauch und es fängt an zu Laggen
-
-UltraStar 0.5.0 ultra-star.dl.am Mod r8b (Release by Whiteshark)
------------------------------
-Fix: Random Funktionen funktionieren alle ohne Fehler
-Fix: In der Kategorieauswahl wird jetzt beim Start immer die erste Kategorie angezeigt
-Fix: Musik wird nach Kategoriewechsel korrekt abgespielt
-Fix: Richtiger Text wird jetzt nicht mehr zu falscher Musik abgespielt
-Fix: Nach Beenden eines Songs ist dieser jetzt wieder in der Übersicht angewählt
-Fix: Midi-konvertor Bug behoben (Nur Freestyle Noten anstatt Normalen)
-
-Thx to: dennisthemenace und mota für die super Bug-Reports :P
-
-Upd: doomhammers Cover sind Integriert: thx to doomhammer
-
-UltraStar 0.5.0 ultra-star.dl.am Mod r8a (Release by Whiteshark)
------------------------------
-Fix: Theme System konnte nicht ausgewählt werden (workaround: Nur bis zu 4 Themes möglich)
-Fix: Richtige Kategorie wird angezeigt nach Druck von Escape
-
-Upd: Neue Random Funktionen: R + [Strg]: Random in allen Kategorien (Hier wird die Kategorie oben noch falsch angezeigt); R + [Shift]: Zufällige Kategorie
-Upd: Gerade gewählte Kategorie wird oben links in der Ecke gezeigt
-
-UltraStar 0.5.0 ultra-star.dl.am Mod r8 (Release by Whiteshark)
------------------------------
-Fix: Creatorbug behoben
-Fix: Wenn Tabs=on kam es manchmal vor das der angewählte Song nicht mit dem Angezeigten übereingestimmt hat
-
-Upd: Theme System komplett
- -Bei Start nach Themes Suchen
- -Den ThemeOptions Screen ändern
-Upd: Neue Farben für Themes :)
-Upd: kleine änderungen am Editor
- -Leerzeichen im Header werden automatisch korrigiert
- -Header ist nicht mehr Case Sensitive
-
-Upd: Skin Ordner gesäubert, Es gibt jetzt 2 Skins: Motas und der Original Skin
-Upd: Ordner haben ihr eigenes Cover, welches angezeigt wird falls kein spezielles Cover vorhanden ist
-Upd: Der BewertungsText (Ultrastar, Singstar, etc.) kann jetzt übersetzt werden
-
-Upd: Falls eine Sprache nicht komplett ist werden die nicht übersetzten Texte, mit der Englischen Sprachdatei übersetzt. (Falls es zu nicht kompletten Sprachdateien kommt)
-
-Upd: neues Kategorie System:
- -Wenn eine Kategorie angewählt wird, werden nur die enthaltenden Songs angezeigt.
- -Mit Escape gehts zurück in die Kategorie Auswahl
- -Mit Hoch und Runter kann die Kategorie gewechselt werden.
-
-UltraStar 0.5.0 mota patch r7 (Release by Mota)
------------------------------
-- Neues Notendesign.
-- versch. Neue Grafiken.
-- Neue Bewertung "Ultrastar" ab 9810 Punkte.
-- Textgröße-Bug im Editor behoben.
-
-UltraStar 0.5.0 mota patch r6 - 17.11.06 (Release by Mota)
-----------------------------------------
-- Editiorfunktionen für Goldene/Freestyle-Noten. (Tasten [G] und [F])
-- Speicherfunktion des Editors angepasst.
-- Verändertes Theme "SingStar".
-
-UltraStar 0.5.0 mota patch r5 - 16.11.06 (Release by Mota)
-----------------------------------------
-- Goldene Noten werden dargestellt
-- Zufallsauswahl verbessert
-
-UltraStar 0.5.0 mota patch r4 (Release by Mota)
------------------------------
-- Perfekt-Stern animation
-
-UltraStar 0.5.0 mota patch r3 (Release by Mota)
------------------------------
-- Sortierung Title2 und Artist2 -> Zahlen in Ordner "#"
-
-UltraStar 0.5.0 mota patch r2 (Release by Mota)
------------------------------
-- Eigene Cover für alle Sortierungen
-
-UltraStar 0.5.0 mota patch (Release by Mota)
---------------------------
-- Eigene Cover für Sortierung nach Edition.
-
-UltraStar 0.5.0 (by Corvus5)
---------------------------
+UltraStar Deluxe 1.00 (by Ultrastar Deluxe Team)
+-----------------------------
+
+--------------
+Theme System
+--------------
+Upd: Neues Skin/Theme System aus Ultrastar 0.5.1
+Upd: Laden von selbsterstellten Themes ermöglicht
+Upd: Covereigenschaften in Theme.ini ausgelagert (z.B. Position)
+Upd: Optionale Coverspiegelungen hinzugefügt
+Upd: Neue Coveranordnung (Bessereres Aussehen mit vielen Songs). (Kann im Theme an und ausgeschaltet werden)
+Upd: SongScreen Equalizer Objekt hinzugefügt
+Upd: Optionale Spiegelungen zu Buttons und Statics hinzugefügt. (Reflection = 1)
+Upd: Buttons können nun im Theme zu Gruppen zusammengefasst werden.z.B. Deluxe Theme Main Menu Tools Collection.
+Upd: Buttons könen vom Theme ausgeblendet werden. z.B. für den Exit Button, oder falls Hotkeys existieren.
+Upd: Texte können nun eine Länge (w= ..) erhalten. Sie werden dann bei der gegebenen Länge umgebrochen.
+
+--------------
+Aufnahme Optionen
+--------------
+Upd: Ultrastar 0.5.2 Recording Optionen hinzugefügt
+Fix: Soundcard Einträge wurden mehrmals in die Config.Ini eingetragen
+Fix: Mehr als ein Singstaradapter sind jetzt möglich(2 Soundkarten mit dem selben Namen)
+
+--------------
+Song Screen
+--------------
+Upd: Playlist Support hinzugefügt
+
+Upd: Song Suche (mit Interface)
+Upd: Jump to Letter Hotkey
+Upd: Songscreen Menu ähnlich wie bei Singstar
+Upd: Spielernamen können nun vor dem Singen geändert werden
+Upd: Song Vorschau Lautstärke kann nun geändert werden
+Upd: Song Vorschau kann eingefadet werden
+
+--------------
+Party Modus
+--------------
+Upd: Party Modus hinzugefügt:
+ 3 Teams mit bis zu 4 Spielern möglich
+ => insgesamt 12 Spieler
+Upd: Modi SDK: Party Modi können mit etwas Programmiererfahrung leicht erstellt werden.
+Upd: 4 Standard Party Modi Plugins: Duell, Hold the Line, Until 5000, Blind Mode
+
+--------------
+Effekte
+--------------
+Upd: Neue Perfect Note Effekte
+Upd: Effekt bei perfekt gesungenem Satz hinzugefügt
+Upd: Goldene Noten haben jetzt einen Singstar ähnlichen Glitzereffekt, und sind nicht mehr gelb.
+Upd: Neuer Effekt bei getroffenen Goldenen Noten
+Upd: Neuer Menü-Übergangs-Effekt: Screen verschwimmt und "fliegt aus dem Bild heraus". Neue Möglichkeiten für Theme-Ersteller
+
+--------------
+Sonstiges
+--------------
+Upd: Deluxe Theme hinzugefügt: Theme mit PS3 ähnlichem Aussehen
+Upd: Neues Score Speicherungssystem (basierend auf SQLite)
+Upd: Statistiken hinzugefügt. Generelle Statistiken und
+ Beste Scores, Beste Sänger, beliebteste Songs, beliebteste Bands
+Upd: Einige On Screen Fehler Benachrichtigungen hinzugefügt, die neuen Spielern helfen sollten.
+Upd: Neuer Erweiterter Options Screen hinzugefügt
+Upd: Abfrage vor dem Beenden hinzugefügt
+Upd: Song Hintergrundbilder können jetzt auch auf voller Bildschrimfläche dargestellt werden.
+Upd: Im Editor werden jetzt zusätzlich die richtigen Notennamen ausgegeben (C, F#, etc.)
+Upd: Neue Schriftarten
+Upd: Bessere Unterstützung für Kommandozeilen Parameter
+Fix: Nahezu keine Abstürze mehr wegen fehlerhaften TXT-Dateien.
+ In Game Popup hinzugefügt und einen Rücksprunk zum Songscreen.
+ Selbst der Partymodus wird nicht unterbrochen.
+Fix: Workaround für Cover und Hintergrund JPEG-Errors
+Fix: Videosize kann wieder geändert werden.
+Fix: Bug in LineBonus Popup behoben das zu Speicherüberläufen führen kann.
+Fix: Bug in SelectSlide behoben der zu Fehlern mit weniger als 3 optionen führen kann.
+ Automatisches Resizing hinzugefügt
+Fix: Backgrounds can be used now in option Screens, too
+Fix: Unnützer Speicherverbauch wenn ein Song mit Video abgespielt wird. Einige Videodaten blieben im Speicher nachdem der Song beendet wurde.
+ Dies könnte zu einem Out Of Memory Error führen wenn viele Songs mit Video gespielt werden.
+Fix: Einige Speichernutzungs und Ladezeit Updates
+Fix: Falsche Satzübergänge wenn T im Editor benutzt wurde und sich 2 Noten von verschiedenen
+ Sätzen überlagerten.
+Fix: Editor stürzte ab wenn die letzte Note eines Satzes gelöscht wurde.
+Fix: [Midi Converter]Noten wurden mehrmals hinzugefügt wenn eine Datei mehrmals geöffnet wurde
+ oder der Save Button mehrmals gedrückt wurde.
+Fix: [Midi Converter]Satzübergänge werden nun vom Mide Converter automatisch berechnet.
+
+UltraStar 0.5.0 ultra-star.dl.am Mod X-Mas Edition (by Mota und Whiteshark)
+-----------------------------
+Upd: Neue schnellerer und fehlerresistenter Headereinlesefunktion
+Upd: Bewertungs Bar (Singstar Like)
+Upd: PhrasenBonus + Popups
+
+Upd: Skin verschönert
+
+UltraStar 0.5.0 ultra-star.dl.am Mod r10 (by Mota und Whiteshark)
+-----------------------------
+Fix: Ein kleiner Bug bei der Pause Funktion wurde gefixt.
+Fix: Ein Bug im Theme System wurde behoben. (SelectSlide konnte nicht weniger als 3 Einträge enthalten.)
+Fix: Skin, Beschränkung auf 4 Skins aufgehoben
+Fix: Noten Texturen werden anders/besser eingelesen
+
+Upd: Zahlen bei der Songauswahl sind jetzt sinnvoller.
+Upd: Anzahl der Songs die eine Kategorie beinhaltet wird in der Übersicht angezeigt
+Upd: Neuer Notenskin
+
+Upd: LanguageTag + Sortierung
+Upd: Unterstützung der Covers.ini aus 0.5.1 - Für alle Sortier-Funtionen. Die alte Möglichkeit ohne die Covers.ini ist weiterhin möglich, genauso wie eine Kombination beider Methoden.
+
+UltraStar 0.5.0 ultra-star.dl.am Mod r9 (Release by Whiteshark)
+-----------------------------
+
+Upd: BPM und VideoGap Angaben mit Punkt werden jetzt auch eingelesen. Es wird aber in diesem Fall in der Error.log eine meldung mit dem Namen des Fehlerhaften Songs ausgegeben.
+Upd: Sollte beim Einlesen eines Songs(speziell beim Header) ein Fehler auftreten wird in der Error.log der Songname + Zeile ausgegeben.
+
+Upd, Beta: Pause. P drücken und der Song wird pausiert, nocheinmal P und es kann wieder gesungen werden. Noch keine Anzeige ob Pause aktiviert wird, und noch kein Pause Menü.
+
+bekannte Probleme:
+Stellt man die Aufnahme Funktion ein, kommt es zu einem extremen CPU-Zeit verbrauch und es fängt an zu Laggen
+
+UltraStar 0.5.0 ultra-star.dl.am Mod r8b (Release by Whiteshark)
+-----------------------------
+Fix: Random Funktionen funktionieren alle ohne Fehler
+Fix: In der Kategorieauswahl wird jetzt beim Start immer die erste Kategorie angezeigt
+Fix: Musik wird nach Kategoriewechsel korrekt abgespielt
+Fix: Richtiger Text wird jetzt nicht mehr zu falscher Musik abgespielt
+Fix: Nach Beenden eines Songs ist dieser jetzt wieder in der Übersicht angewählt
+Fix: Midi-konvertor Bug behoben (Nur Freestyle Noten anstatt Normalen)
+
+Thx to: dennisthemenace und mota für die super Bug-Reports :P
+
+Upd: doomhammers Cover sind Integriert: thx to doomhammer
+
+UltraStar 0.5.0 ultra-star.dl.am Mod r8a (Release by Whiteshark)
+-----------------------------
+Fix: Theme System konnte nicht ausgewählt werden (workaround: Nur bis zu 4 Themes möglich)
+Fix: Richtige Kategorie wird angezeigt nach Druck von Escape
+
+Upd: Neue Random Funktionen: R + [Strg]: Random in allen Kategorien (Hier wird die Kategorie oben noch falsch angezeigt); R + [Shift]: Zufällige Kategorie
+Upd: Gerade gewählte Kategorie wird oben links in der Ecke gezeigt
+
+UltraStar 0.5.0 ultra-star.dl.am Mod r8 (Release by Whiteshark)
+-----------------------------
+Fix: Creatorbug behoben
+Fix: Wenn Tabs=on kam es manchmal vor das der angewählte Song nicht mit dem Angezeigten übereingestimmt hat
+
+Upd: Theme System komplett
+ -Bei Start nach Themes Suchen
+ -Den ThemeOptions Screen ändern
+Upd: Neue Farben für Themes :)
+Upd: kleine änderungen am Editor
+ -Leerzeichen im Header werden automatisch korrigiert
+ -Header ist nicht mehr Case Sensitive
+
+Upd: Skin Ordner gesäubert, Es gibt jetzt 2 Skins: Motas und der Original Skin
+Upd: Ordner haben ihr eigenes Cover, welches angezeigt wird falls kein spezielles Cover vorhanden ist
+Upd: Der BewertungsText (Ultrastar, Singstar, etc.) kann jetzt übersetzt werden
+
+Upd: Falls eine Sprache nicht komplett ist werden die nicht übersetzten Texte, mit der Englischen Sprachdatei übersetzt. (Falls es zu nicht kompletten Sprachdateien kommt)
+
+Upd: neues Kategorie System:
+ -Wenn eine Kategorie angewählt wird, werden nur die enthaltenden Songs angezeigt.
+ -Mit Escape gehts zurück in die Kategorie Auswahl
+ -Mit Hoch und Runter kann die Kategorie gewechselt werden.
+
+UltraStar 0.5.0 mota patch r7 (Release by Mota)
+-----------------------------
+- Neues Notendesign.
+- versch. Neue Grafiken.
+- Neue Bewertung "Ultrastar" ab 9810 Punkte.
+- Textgröße-Bug im Editor behoben.
+
+UltraStar 0.5.0 mota patch r6 - 17.11.06 (Release by Mota)
+----------------------------------------
+- Editiorfunktionen für Goldene/Freestyle-Noten. (Tasten [G] und [F])
+- Speicherfunktion des Editors angepasst.
+- Verändertes Theme "SingStar".
+
+UltraStar 0.5.0 mota patch r5 - 16.11.06 (Release by Mota)
+----------------------------------------
+- Goldene Noten werden dargestellt
+- Zufallsauswahl verbessert
+
+UltraStar 0.5.0 mota patch r4 (Release by Mota)
+-----------------------------
+- Perfekt-Stern animation
+
+UltraStar 0.5.0 mota patch r3 (Release by Mota)
+-----------------------------
+- Sortierung Title2 und Artist2 -> Zahlen in Ordner "#"
+
+UltraStar 0.5.0 mota patch r2 (Release by Mota)
+-----------------------------
+- Eigene Cover für alle Sortierungen
+
+UltraStar 0.5.0 mota patch (Release by Mota)
+--------------------------
+- Eigene Cover für Sortierung nach Edition.
+
+UltraStar 0.5.0 (by Corvus5)
+--------------------------
- Original Code \ No newline at end of file
diff --git a/DisplayChanges.patch b/DisplayChanges.patch
index c22be897..9cb00a18 100644
--- a/DisplayChanges.patch
+++ b/DisplayChanges.patch
@@ -1,8 +1,8 @@
-Index: src/menu/UDisplay.pas
-===================================================================
---- src/menu/UDisplay.pas (revision 1702)
-+++ src/menu/UDisplay.pas (working copy)
-@@ -42,8 +42,65 @@
+Index: src/menu/UDisplay.pas
+===================================================================
+--- src/menu/UDisplay.pas (revision 1702)
++++ src/menu/UDisplay.pas (working copy)
+@@ -42,8 +42,65 @@
SysUtils;
type
@@ -68,7 +68,7 @@ Index: src/menu/UDisplay.pas
//fade-to-black-hack
BlackScreen: boolean;
-@@ -53,7 +110,7 @@
+@@ -53,7 +110,7 @@
LastFadeTime: cardinal; // last fade update time
FadeTex: array[1..2] of GLuint;
@@ -77,7 +77,7 @@ Index: src/menu/UDisplay.pas
FPSCounter: cardinal;
LastFPS: cardinal;
NextFPSSwap: cardinal;
-@@ -78,7 +135,7 @@
+@@ -78,7 +135,7 @@
procedure SaveScreenShot;
function Draw: boolean;
diff --git a/Makefile.in b/Makefile.in
index 2772147d..535f7dc9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -215,6 +215,7 @@ install-strip:
install
.PHONY: install-all
+#install-all: install-exec install-plugins install-data
install-all: install-exec install-data
.PHONY: install-exec
diff --git a/RELEASEBLOCKERS.txt b/RELEASEBLOCKERS.txt
index 54d7342e..bcac2887 100644
--- a/RELEASEBLOCKERS.txt
+++ b/RELEASEBLOCKERS.txt
@@ -1,31 +1,32 @@
-Blockers for the outstanding 1.1 release
-if you want to help us then start at this tasks
-
-Missing party mode (contact whiteshark to get further information on how to help)
-- finishing new one (partymode branch)
- pro: should be easy to port to all supported platforms
- it should be easy to extended w/ lua support
- basic plugin support, not only party modes
- con: work!
- modes has to be adapted
- work!
-- merge the old one
- pro: less work
- it is known to work and there are many existing modis
- con: may be difficult to port to other platforms than windows
-
-Unicode support (contact tobigun to get further information on how to help)
-- there is a unicode branch
-- seems to work except for some glitches
-
-Microfone playback
-- buffers have to be adjusted
- - this may be done automatically (prefer this!)
- - or at least the user has to manually adjust this
-- there may be other problems as due to the missing buffer adjustment there were no extensive tests
-
-Theme changes
-- there are some problems w/ theme-object positions mainly in the option-screens
-
-There are also assembla tickets that need to be fixed
+Blockers for the outstanding 1.1 release
+if you want to help us then start at this tasks
+
+Missing party mode (contact whiteshark to get further information on how to help)
+- finishing new one (partymode branch)
+ pro: should be easy to port to all supported platforms
+ it should be easy to extended w/ lua support
+ basic plugin support, not only party modes
+ con: work!
+ modes has to be adapted
+ work!
+- merge the old one
+ pro: less work
+ it is known to work and there are many existing modis
+ con: may be difficult to port to other platforms than windows
+
+Unicode support (contact tobigun to get further information on how to help)
+- should work now but needs some testing
+- report bugs specific to the unicode branch (cross-check the trunk) at
+ our forum (http://ultrastardeluxe.xtremeweb-hosting.net/)
+
+Microfone playback
+- buffers have to be adjusted
+ - this may be done automatically (prefer this!)
+ - or at least the user has to manually adjust this
+- there may be other problems as due to the missing buffer adjustment there were no extensive tests
+
+Theme changes
+- there are some problems w/ theme-object positions mainly in the option-screens
+
+There are also assembla tickets that need to be fixed
http://www.assembla.com/spaces/usdx/milestones/26192-UltraStar-Deluxe-1-1-Release \ No newline at end of file
diff --git a/configure b/configure
index c1edbf6b..b2351c6a 100755
--- a/configure
+++ b/configure
@@ -2502,7 +2502,7 @@ fi
# valgrind
# Check whether --enable-valgrind was given.
if test "${enable_valgrind+set}" = set; then
- enableval=$enable_valgrind; test x$enableval = xyes && PFLAGS_EXTRA="$PFLAGS_EXTRA -gv"
+ enableval=$enable_valgrind; test x$enableval = xyes && PFLAGS_EXTRA="$PFLAGS_EXTRA -pv"
fi
@@ -6937,8 +6937,7 @@ $debug ||
if test -n "$CONFIG_FILES"; then
-ac_cr='
-'
+ac_cr=' '
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
ac_cs_awk_cr='\\r'
diff --git a/dists/delphi2005/readme.txt b/dists/delphi2005/readme.txt
index 2901b48a..64168d3c 100644
--- a/dists/delphi2005/readme.txt
+++ b/dists/delphi2005/readme.txt
@@ -1,5 +1,5 @@
-(Turbo-)Delphi 2005/2006 Project file
---------------------------------------
-1. Copy ultrastardx.bdsproj to <ultrastardx>/src
-2. Double-click <ultrastardx>/src/ultrastardx.bdsproj
-
+(Turbo-)Delphi 2005/2006 Project file
+--------------------------------------
+1. Copy ultrastardx.bdsproj to <ultrastardx>/src
+2. Double-click <ultrastardx>/src/ultrastardx.bdsproj
+
diff --git a/dists/delphi7/readme.txt b/dists/delphi7/readme.txt
index 1ede3162..fa77699b 100644
--- a/dists/delphi7/readme.txt
+++ b/dists/delphi7/readme.txt
@@ -1,5 +1,5 @@
-Delphi 7 Project file
---------------------------------------
-1. Copy ultrastardx.dof to <ultrastardx>/src
-2. Double-click <ultrastardx>/src/ultrastardx.dpr
-
+Delphi 7 Project file
+--------------------------------------
+1. Copy ultrastardx.dof to <ultrastardx>/src
+2. Double-click <ultrastardx>/src/ultrastardx.dpr
+
diff --git a/dists/lazarus/readme.txt b/dists/lazarus/readme.txt
index c828266b..012ee37a 100755
--- a/dists/lazarus/readme.txt
+++ b/dists/lazarus/readme.txt
@@ -1,15 +1,15 @@
-Lazarus Project file
---------------------------------------
-
-Unix:
- 1. Copy "ultrastardx-unix.lpi" to <ultrastardx>/src
- (you may rename it to ultrastardx.lpi if you want)
- 2. Start Lazarus, click on "Project -> Open Project ..."
- and select "ultrastardx-unix.lpi"
-
-Windows:
- 1. Copy "ultrastardx-win.lpi" to <ultrastardx>/src
- (you may rename it to ultrastardx.lpi if you want)
- 2. Copy "clean.bat" to <ultrastardx>/src
- 3. Start Lazarus, click on "Project -> Open Project ..."
- and select "ultrastardx-win.lpi"
+Lazarus Project file
+--------------------------------------
+
+Unix:
+ 1. Copy "ultrastardx-unix.lpi" to <ultrastardx>/src
+ (you may rename it to ultrastardx.lpi if you want)
+ 2. Start Lazarus, click on "Project -> Open Project ..."
+ and select "ultrastardx-unix.lpi"
+
+Windows:
+ 1. Copy "ultrastardx-win.lpi" to <ultrastardx>/src
+ (you may rename it to ultrastardx.lpi if you want)
+ 2. Copy "clean.bat" to <ultrastardx>/src
+ 3. Start Lazarus, click on "Project -> Open Project ..."
+ and select "ultrastardx-win.lpi"
diff --git a/game/fonts/DejaVu/AUTHORS b/game/fonts/DejaVu/AUTHORS
new file mode 100644
index 00000000..66b7e445
--- /dev/null
+++ b/game/fonts/DejaVu/AUTHORS
@@ -0,0 +1,44 @@
+Adrian Schroeter
+Andrey Valentinovich Panov
+Ben Laenen
+Besarion Gugushvili
+Bhikkhu Pesala
+Clayborne Arevalo
+Dafydd Harries
+Danilo Segan
+Davide Viti
+David Jez
+David Lawrence Ramsey
+Denis Jacquerye
+Dwayne Bailey
+Eugeniy Meshcheryakov
+Gee Fung Sit
+Heikki Lindroos
+James Cloos
+James Crippen
+John Karp
+Keenan Pepper
+Lars Naesbye Christensen
+Mashrab Kuvatov
+Max Berger
+Mederic Boquien
+Michael Everson
+Misu Moldovan
+Nguyen Thai Ngoc Duy
+Nicolas Mailhot
+Ognyan Kulev
+Ondrej Koala Vacha
+Peter Cernak
+Remy Oudompheng
+Roozbeh Pournader
+Sahak Petrosyan
+Sander Vesik
+Stepan Roh
+Stephen Hartke
+Tavmjong Bah
+Tim May
+Valentin Stoykov
+Vasek Stodulka
+Wesley Transue
+
+$Id: AUTHORS 2162 2007-12-27 12:39:07Z ben_laenen $
diff --git a/game/fonts/DejaVu/DejaVuSans-Bold.ttf b/game/fonts/DejaVu/DejaVuSans-Bold.ttf
new file mode 100644
index 00000000..29da1369
--- /dev/null
+++ b/game/fonts/DejaVu/DejaVuSans-Bold.ttf
Binary files differ
diff --git a/game/fonts/DejaVu/DejaVuSans.ttf b/game/fonts/DejaVu/DejaVuSans.ttf
new file mode 100644
index 00000000..e0699fec
--- /dev/null
+++ b/game/fonts/DejaVu/DejaVuSans.ttf
Binary files differ
diff --git a/game/fonts/DejaVu/LICENSE b/game/fonts/DejaVu/LICENSE
new file mode 100644
index 00000000..254e2cc4
--- /dev/null
+++ b/game/fonts/DejaVu/LICENSE
@@ -0,0 +1,99 @@
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
+
+Bitstream Vera Fonts Copyright
+------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
+a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall
+be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words "Bitstream" or the word
+"Vera".
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the "Bitstream
+Vera" names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font Software
+without prior written authorization from the Gnome Foundation or Bitstream
+Inc., respectively. For further information, contact: fonts at gnome dot
+org.
+
+Arev Fonts Copyright
+------------------------------
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free
+. fr.
+
+$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
diff --git a/game/fonts/DejaVu/README b/game/fonts/DejaVu/README
new file mode 100644
index 00000000..6882268b
--- /dev/null
+++ b/game/fonts/DejaVu/README
@@ -0,0 +1,59 @@
+DejaVu fonts 2.26 (c)2004-2008 DejaVu fonts team
+------------------------------------------------
+
+The DejaVu fonts are a font family based on the Bitstream Vera Fonts
+(http://gnome.org/fonts/). Its purpose is to provide a wider range of
+characters (see status.txt for more information) while maintaining the
+original look and feel.
+
+DejaVu fonts are based on Bitstream Vera fonts version 1.10.
+
+Available fonts (Sans = sans serif, Mono = monospaced):
+
+DejaVu Sans Mono
+DejaVu Sans Mono Bold
+DejaVu Sans Mono Bold Oblique
+DejaVu Sans Mono Oblique
+DejaVu Sans
+DejaVu Sans Bold
+DejaVu Sans Bold Oblique
+DejaVu Sans Oblique
+DejaVu Sans ExtraLight (experimental)
+DejaVu Serif
+DejaVu Serif Bold
+DejaVu Serif Bold Italic (experimental)
+DejaVu Serif Italic (experimental)
+DejaVu Sans Condensed (experimental)
+DejaVu Sans Condensed Bold (experimental)
+DejaVu Sans Condensed Bold Oblique (experimental)
+DejaVu Sans Condensed Oblique (experimental)
+DejaVu Serif Condensed (experimental)
+DejaVu Serif Condensed Bold (experimental)
+DejaVu Serif Condensed Bold Italic (experimental)
+DejaVu Serif Condensed Italic (experimental)
+
+All fonts are also available as derivative called DejaVu LGC with support
+only for Latin, Greek and Cyrillic scripts.
+
+For license information see LICENSE. What's new is described in NEWS. Known
+bugs are in BUGS. All authors are mentioned in AUTHORS.
+
+Fonts are published in source form as SFD files (Spline Font Database from
+FontForge - http://fontforge.sf.net/) and in compiled form as TTF files
+(TrueType fonts).
+
+For more information go to http://dejavu.sourceforge.net/.
+
+Characters from Arev fonts, Copyright (c) 2006 by Tavmjong Bah:
+---------------------------
+U+01BA, U+01BF, U+01F7, U+021C-U+021D, U+0220, U+0222-U+0223,
+U+02B9, U+02BA, U+02BD, U+02C2-U+02C5, U+02d4-U+02D5,
+U+02D7, U+02EC-U+02EE, U+0346-U+034E, U+0360, U+0362,
+U+03E2-03EF, U+0460-0463, U+0466-U+0486, U+0488-U+0489, U+04A8-U+04A9,
+U+0500-U+050F, U+2055-205E, U+20B0, U+20B2-U+20B3, U+2102, U+210D, U+210F,
+U+2111, U+2113, U+2115, U+2118-U+211A, U+211C-U+211D, U+2124, U+2135,
+U+213C-U+2140, U+2295-U+2298, U+2308-U+230B, U+26A2-U+26B1, U+2701-U+2704,
+U+2706-U+2709, U+270C-U+274B, U+2758-U+275A, U+2761-U+2775, U+2780-U+2794,
+U+2798-U+27AF, U+27B1-U+27BE, U+FB05-U+FB06
+
+$Id: README 2263 2008-07-26 19:48:13Z ben_laenen $
diff --git a/game/fonts/FreeSans/AUTHORS b/game/fonts/FreeSans/AUTHORS
new file mode 100644
index 00000000..fbb0e990
--- /dev/null
+++ b/game/fonts/FreeSans/AUTHORS
@@ -0,0 +1,191 @@
+-*- mode:text; coding:utf-8; -*-
+ GNU FreeFont Authors
+ ====================
+
+The FreeFont collection is being maintained by
+ Steve White <stevan.white AT googlemail.com>
+The folowing list cites the other contributors that contributed to
+particular ISO 10646 blocks.
+
+* URW++ Design & Development GmbH <http://www.urwpp.de/>
+
+ Basic Latin (U+0041-U+007A)
+ Latin-1 Supplement (U+00C0-U+00FF) (most)
+ Latin Extended-A (U+0100-U+017F)
+ Spacing Modifier Letters (U+02B0-U+02FF)
+ Mathematical Operators (U+2200-U+22FF) (parts)
+ Block Elements (U+2580-U+259F)
+ Dingbats (U+2700-U+27BF)
+
+* Yannis Haralambous <yannis.haralambous AT enst-bretagne.fr> and John
+ Plaice <plaice AT omega.cse.unsw.edu.au>
+
+ Latin Extended-B (U+0180-U+024F)
+ IPA Extensions (U+0250-U+02AF)
+ Greek (U+0370-U+03FF)
+ Armenian (U+0530-U+058F)
+ Hebrew (U+0590-U+05FF)
+ Arabic (U+0600-U+06FF)
+ Currency Symbols (U+20A0-U+20CF)
+ Arabic Presentation Forms-A (U+FB50-U+FDFF)
+ Arabic Presentation Forms-B (U+FE70-U+FEFF)
+
+* Young U. Ryu <ryoung AT utdallas.edu>
+
+ Arrows (U+2190-U+21FF)
+ Mathematical Symbols (U+2200-U+22FF)
+
+* Valek Filippov <frob AT df.ru>
+
+ Cyrillic (U+0400-U+04FF)
+
+* Wadalab Kanji Comittee
+
+ Hiragana (U+3040-U+309F)
+ Katakana (U+30A0-U+30FF)
+
+* Angelo Haritsis <ah AT computer.org>
+
+ Greek (U+0370-U+03FF)
+
+* Yannis Haralambous and Virach Sornlertlamvanich
+
+ Thai (U+0E00-U+0E7F)
+
+* Shaheed R. Haque <srhaque AT iee.org>
+
+ Bengali (U+0980-U+09FF)
+
+* Sam Stepanyan <sam AT arminco.com>
+
+ Armenian (U+0530-U+058F)
+
+* Mohamed Ishan <ishan AT mitf.f2s.com>
+
+ Thaana (U+0780-U+07BF)
+
+* Sushant Kumar Dash <sushant AT writeme.com>
+
+ Oriya (U+0B00-U+0B7F)
+
+* Harsh Kumar <harshkumar AT vsnl.com>
+
+ Devanagari (U+0900-U+097F)
+ Bengali (U+0980-U+09FF)
+ Gurmukhi (U+0A00-U+0A7F)
+ Gujarati (U+0A80-U+0AFF)
+
+* Prasad A. Chodavarapu <chprasad AT hotmail.com>
+
+ Telugu (U+0C00-U+0C7F)
+
+* Frans Velthuis <velthuis AT rc.rug.nl> and Anshuman Pandey
+ <apandey AT u.washington.edu>
+
+ Devanagari (U+0900-U+097F)
+
+* Hardip Singh Pannu <HSPannu AT aol.com>
+
+ Gurmukhi (U+0A00-U+0A7F)
+
+* Jeroen Hellingman <jehe AT kabelfoon.nl>
+
+ Oriya (U+0B00-U+0B7F)
+ Malayalam (U+0D00-U+0D7F)
+
+* Thomas Ridgeway <email needed>
+
+ Tamil (U+0B80-U+0BFF)
+
+* Berhanu Beyene <1beyene AT informatik.uni-hamburg.de>,
+ Prof. Dr. Manfred Kudlek <kudlek AT informatik.uni-hamburg.de>, Olaf
+ Kummer <kummer AT informatik.uni-hamburg.de>, and Jochen Metzinger <?>
+
+ Ethiopic (U+1200-U+137F)
+
+* Maxim Iorsh <iorsh AT users.sourceforge.net>
+
+ Hebrew (U+0590-U+05FF)
+
+* Vyacheslav Dikonov <sdiconov AT mail.ru>
+
+ Syriac (U+0700-U+074A)
+ Braille (U+2800-U+28FF)
+
+* Panayotis Katsaloulis <panayotis AT panayotis.com>
+
+ Greek Extended (U+1F00-U+1FFF)
+
+* M.S. Sridhar <mssridhar AT vsnl.com>
+
+ Devanagari (U+0900-U+097F)
+ Bengali (U+0980-U+09FF)
+ Gurmukhi (U+0A00-U+0A7F)
+ Gujarati (U+0A80-U+0AFF)
+ Oriya (U+0B00-U+0B7F)
+ Tamil (U+0B80-U+0BFF)
+ Telugu (U+0C00-U+0C7F)
+ Kannada (U+0C80-U+0CFF)
+ Malayalam (U+0D00-U+0D7F)
+
+* DMS Electronics, The Sri Lanka Tipitaka Project, and Noah Levitt
+ <nlevitt AT columbia.edu>
+
+ Sinhala (U+0D80-U+0DFF)
+
+* Dan Shurovich Chirkov <dansh AT chirkov.com>
+
+ Cyrillic (U+0400-U+04FF)
+
+* Abbas Izad <abbasizad AT hotmail.com>
+
+ Arabic (U+0600-U+06FF)
+ Arabic Presentation Forms-A (U+FB50-U+FDFF)
+ Arabic Presentation Forms-B (U+FE70-U+FEFF)
+
+* Denis Jacquerye <moyogo AT gmail.com>
+
+ Latin Extended-B (U+0180-U+024F)
+ IPA Extensions (U+0250-U+02AF)
+
+* K.H. Hussain <hussain AT kfri.org> and R. Chitrajan
+
+ Malayalam (U+0D00-U+0D7F)
+
+* Solaiman Karim <solaiman AT ekushey.org> and Omi Azad <omi AT ekushey.org>
+
+ Bengali (U+0980-U+09FF)
+
+* Sonali Sonania <sonalisonania AT gmail.com> and Monika Shah
+ <monikapatira AT gmail.com>
+
+ Devanagari (U+0900-U+097F)
+ Gujarati (U+0A80-U+0AFF)
+
+* Pravin Satpute <pravin_ind21 AT hotmail.com>, Bageshri Salvi
+ <sbagrshri AT yahoo.co.in>, Rahul Bhalerao <rahul_pb_india AT
+ yahoo.com> and Sandeep Shedmake <surgs2k47 AT yahoo.co.in>
+
+ Devanagari (U+0900-U+097F)
+ Gujarati (U+0A80-U+0AFF)
+ Oriya (U+0B00-U+0B7F)
+ Malayalam (U+0D00-U+0D7F)
+ Tamil (U+0B80-U+0BFF)
+
+
+* Kulbir Singh Thind
+
+ Gurmukhi (U+0A00-U+0A7F)
+
+* Gia Shervashidze <giasher AT telenet.ge>
+
+ Georgian (U+10A0-U+10FF)
+
+* Primož Peterlin <primoz.peterlin AT biofiz.mf.uni-lj.si>
+ maintained FreeFont for several years, and is thanked for all his work.
+
+Please see the CREDITS file for details on who contributed particular
+subsets of the glyphs in font files.
+
+--------------------------------------------------------------------------
+$Id: AUTHORS,v 1.15 2008/08/30 09:31:54 Stevan_White Exp $
diff --git a/game/fonts/FreeSans/COPYING b/game/fonts/FreeSans/COPYING
new file mode 100644
index 00000000..7f1c9b60
--- /dev/null
+++ b/game/fonts/FreeSans/COPYING
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-13017, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/game/fonts/FreeSans/CREDITS b/game/fonts/FreeSans/CREDITS
new file mode 100644
index 00000000..0cc30949
--- /dev/null
+++ b/game/fonts/FreeSans/CREDITS
@@ -0,0 +1,506 @@
+-*- mode:text; coding:utf-8; -*-
+ GNU FreeFont Credits
+ ====================
+
+This file lists contributors and contributions to the GNU FreeFont project.
+
+
+* URW++ Design & Development GmbH <http://www.urwpp.de/>
+
+URW++ donated a set of 35 core PostScript Type 1 fonts to the
+Ghostscript project <http://www.cs.wisc.edu/~ghost/>, to be available
+under the terms of GNU General Public License (GPL).
+
+ Basic Latin (U+0041-U+007A)
+ Latin-1 Supplement (U+00C0-U+00FF)
+ Latin Extended-A (U+0100-U+017F)
+ Spacing Modifier Letters (U+02B0-U+02FF)
+ Mathematical Operators (U+2200-U+22FF)
+ Block Elements (U+2580-U+259F)
+ Dingbats (U+2700-U+27BF)
+
+
+* Yannis Haralambous <yannis.haralambous AT enst-bretagne.fr> and John
+ Plaice <plaice AT omega.cse.unsw.edu.au>
+
+Yannis Haralambous and John Plaice are the authors of Omega
+typesetting system, <http://omega.cse.unsw.edu.au/>. Omega is an
+extension of TeX. Its first release, aims primarily at improving TeX's
+multilingual abilities. In Omega all characters and pointers into
+data-structures are 16-bit wide, instead of 8-bit, thereby eliminating
+many of the trivial limitations of TeX. Omega also allows multiple
+input and output character sets, and uses programmable filters to
+translate from one encoding to another, to perform contextual
+analysis, etc. Internally, Omega uses the universal 16-bit Unicode
+standard character set, based on ISO-10646. These improvements not
+only make it a lot easier for TeX users to cope with multiple or
+complex languages, like Arabic, Indic, Khmer, Chinese, Japanese or
+Korean, in one document, but will also form the basis for future
+developments in other areas, such as native color support and
+hypertext features. ... Fonts for UT1 (omlgc family) and UT2 (omah
+family) are under development: these fonts are in PostScript format
+and visually close to Times and Helvetica font families. (from the
+Omega WWW site). Omega fonts are available subject to GPL
+<http://www.ctan.org/tex-archive/help/Catalogue/entries/omegafonts.html>.
+
+ Latin Extended-B (U+0180-U+024F)
+ IPA Extensions (U+0250-U+02AF)
+ Greek (U+0370-U+03FF)
+ Armenian (U+0530-U+058F)
+ Hebrew (U+0590-U+05FF)
+ Arabic (U+0600-U+06FF)
+ Currency Symbols (U+20A0-U+20CF)
+ Arabic Presentation Forms-A (U+FB50-U+FDFF)
+ Arabic Presentation Forms-B (U+FE70-U+FEFF)
+
+
+* Valek Filippov <frob AT df.ru>
+
+Valek Filippov added Cyrillic glyphs and composite Latin Extended A to
+the whole set of the abovementioned URW set of 35 PostScript core
+fonts, <ftp://ftp.gnome.ru/fonts/urw/>. The fonts are available under
+GPL.
+
+ Latin Extended-A (U+0100-U+017F)
+ Cyrillic (U+0400-U+04FF)
+
+
+* Wadalab Kanji Comittee
+
+Between April 1990 and March 1992, Wadalab Kanji Comittee put together
+a series of scalable font files with Japanese scripts, in four forms:
+Sai Micho, Chu Mincho, Cho Kaku and Saimaru. The font files are
+written in custom file format, while tools for conversion into
+Metafont and PostScript Type 1 are also supplied. The Wadalab Kanji
+Comittee has later been dismissed, and the resulting files can be now
+found on the FTP server of the Depertment of Mathematical Engineering
+and Information Physics, Faculty of Engineering, University of Tokyo
+<ftp://ftp.ipl.t.u-tokyo.ac.jp/Font/>.
+
+ Hiragana (U+3040-U+309F)
+ Katakana (U+30A0-U+30FF)
+
+
+* Young U. Ryu <ryoung AT utdallas.edu>
+
+Young Ryu is the author of Txfonts, a set of mathematical symbols
+designed to accompany text typeset in Times or its variants. In the
+documentation, Young adresses the design of mathematical symbols: "The
+Adobe Times fonts are thicker than the CM fonts. Designing math fonts
+for Times based on the rule thickness of Times = , , + , / , < ,
+etc. would result in too thick math symbols, in my opinion. In the TX
+fonts, these glyphs are thinner than those of original Times
+fonts. That is, the rule thickness of these glyphs is around 85% of
+that of the Times fonts, but still thicker than that of the CM fonts."
+TX fonts are are distributed under the GNU public license (GPL).
+<http://www.ctan.org/tex-archive/fonts/txfonts/>.
+
+ Arrows (U+2190-U+21FF)
+ Mathematical Symbols (U+2200-U+22FF)
+
+
+* Angelo Haritsis <ah AT computer.org>
+
+Angelo Haritsis has compiled a set of Greek Type 1 fonts, available on
+<ftp://ftp.hellug.gr/pub/unix/linux/GREEK/fonts/greekXfonts-Type1-1.1.tgz>.
+The glyphs from this source has been used to compose Greek glyphs in
+FreeSans and FreeMono.
+
+Angelo's licence says: "You can enjoy free use of these fonts for
+educational or commercial purposes. All derived works should include
+this paragraph. If you want to change something please let me have
+your changes (via email) so that they can go into the next
+version. You can also send comments etc to the above address."
+
+ Greek (U+0370-U+03FF)
+
+
+* Yannis Haralambous and Virach Sornlertlamvanich
+
+In 1999, Yannis Haralambous and Virach Sornlertlamvanich made a set of
+glyphs covering the Thai national standard NF3, in both upright and
+slanted shape. The collection of glyphs have been made part of GNU
+intlfonts 1.2 package and is available on
+<ftp://ftp.gnu.org/pub/gnu/intlfonts/> under GPL.
+
+ Thai (U+0E00-U+0E7F)
+
+
+* Shaheed R. Haque <srhaque AT iee.org>
+
+Shaheed Haque has developed a basic set of basic Bengali glyphs
+(without ligatures), using ISO10646 encoding. They are available under
+the XFree86 license at <http://www.btinternet.com/~shaheedhaque/>.
+
+Copyright (C) 2001 S.R.Haque <srhaque AT iee.org>. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL S.R.HAQUE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of S.R.Haque shall not be
+used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from
+S.R.Haque.
+
+ Bengali (U+0980-U+09FF)
+
+
+* Sam Stepanyan <sam AT arminco.com>
+
+Sam Stepanyan created a set of Armenian sans serif glyphs visually
+compatible with Helvetica or Arial. Available on
+<http://www.editum.com.ar/mashtots/html/fonts/ara.tar.gz>. On
+2002-01-24, Sam writes: "Arial Armenian font is free for
+non-commercial use, so it is OK to use under GPL license."
+
+ Armenian (U+0530-U+058F)
+
+
+* Mohamed Ishan <ishan AT mitf.f2s.com>
+
+Mohamed Ishan has started a Thaana Unicode Project
+<http://thaana.sourceforge.net/> and among other things created a
+couple of Thaana fonts, available under FDL or BDF license.
+
+ Thaana (U+0780-U+07BF)
+
+
+* Sushant Kumar Dash <sushant AT writeme.com> (*)
+
+Sushant Dash has created a font in his mother tongue, Oriya. As he
+states on his web page <http://members.tripod.com/~sushantdash/>:
+"Please feel free to foreword this mail to your Oriya friends. No
+copyright law is applied for this font. It is totally free!!! Feel
+free to modify this using any font editing tools. This is designed for
+people like me, who are away from Orissa and want to write letters
+home using Computers, but suffer due to unavailability of Oriya
+fonts.(Or the cost of the available packages are too much)."
+
+ Oriya (U+0B00-U+0B7F)
+
+
+* Harsh Kumar <harshkumar AT vsnl.com>
+
+Harsh Kumar has started BharatBhasha <http://www.bharatbhasha.net/> -
+an effort to provide "FREE software, Tutorial, Source Codes
+etc. available for working in Hindi, Marathi, Gujarati, Gurmukhi and
+Bangla. You can type text, write Web pages or develop Indian Languages
+Applications on Windows and on Linux. We also offer FREE help to
+users, enthusiasts and software developers for their work in Indian
+languages."
+
+ Devanagari (U+0900-U+097F)
+ Bengali (U+0980-U+09FF)
+ Gurmukhi (U+0A00-U+0A7F)
+ Gujarati (U+0A80-U+0AFF)
+
+
+* Prasad A. Chodavarapu <chprasad AT hotmail.com>
+
+Prasad A. Chodavarapu created Tikkana, a Telugu font available in Type
+1 and TrueType format on <http://chaitanya.bhaavana.net/fonts/>.
+Tikkana exceeds the Unicode Telugu range with some composite glyphs.
+Available under the GNU General Public License.
+
+ Telugu (U+0C00-U+0C7F)
+
+
+* Frans Velthuis <velthuis AT rc.rug.nl> and Anshuman Pandey
+ <apandey AT u.washington.edu>
+
+In 1991, Frans Velthuis from the Groningen University, The
+Netherlands, released a Devanagari font as Metafont source, available
+under the terms of GNU GPL. Later, Anshuman Pandey from the Washington
+University, Seattle, USA, took over the maintenance of font. Fonts can
+be found on CTAN, <ftp://ftp.dante.de/tex-archive/language/devanagari/>. I
+converted the font to Type 1 format using Péter Szabó's TeXtrace
+program <http://www.inf.bme.hu/~pts/textrace/> and removed some
+redundant control points with PfaEdit.
+
+ Devanagari (U+0900-U+097F)
+
+
+* Hardip Singh Pannu <HSPannu AT aol.com>
+
+In 1991, Hardip Singh Pannu has created a free Gurmukhi TrueType font,
+available as regular, bold, oblique and bold oblique form. Its license
+says "Please remember that these fonts are copyrighted (by me) and are
+for non-profit use only."
+
+ Gurmukhi (U+0A00-U+0A7F)
+
+
+* Jeroen Hellingman <jehe AT kabelfoon.nl>
+
+Jeroen Hellingman created a set of Malayalam metafonts in 1994, and a
+set of Oriya metafonts in 1996. Malayalam fonts were created as
+uniform stroke only, while Oriya metafonts exist in both uniform and
+modulated stroke. From private communication: "It is my intention to
+release the fonts under GPL, but not all copies around have this
+notice on them." Metafonts can be found on CTAN,
+<ftp://ftp.dante.de/tex-archive/language/oriya/> and
+<ftp://ftp.dante.de/tex-archive/language/malayalam/>.
+
+ Oriya (U+0B00-U+0B7F)
+ Malayalam (U+0D00-U+0D7F)
+
+
+* Thomas Ridgeway <> (*)
+
+Thomas Ridgeway, then at the Humanities And Arts Computing Center,
+Washington University, Seattle, USA, (now defunct), created a Tamil
+metafont in 1990. Anshuman Pandey from the same university took over
+the maintenance of font. Fonts can be found at CTAN,
+<ftp://ftp.dante.de/tex-archive/language/tamil/wntamil/>.
+
+ Tamil (U+0B80-U+0BFF)
+
+
+* Berhanu Beyene <1beyene AT informatik.uni-hamburg.de>,
+ Prof. Dr. Manfred Kudlek <kudlek AT informatik.uni-hamburg.de>, Olaf
+ Kummer <kummer AT informatik.uni-hamburg.de>, and Jochen Metzinger <?>
+
+Beyene, Kudlek, Kummer and Metzinger from the Theoretical Foundations
+of Computer Science, University of Hamburg, prepared a set of Ethiopic
+metafonts, found on
+<ftp://ftp.dante.de/tex-archive/language/ethiopia/ethiop/>. They also
+maintain home page on the Ethiopic font project,
+<http://www.informatik.uni-hamburg.de/TGI/mitarbeiter/wimis/kummer/ethiop_eng.html>,
+and can be reached at <ethiop AT informatik.uni-hamburg.de>. The current
+version of fonts is 0.7 (1998), and they are released under GNU GPL. I
+converted the fonts to Type 1 format using Péter Szabó's TeXtrace-A
+program <http://www.inf.bme.hu/~pts/textrace/> and removed some
+redundant control points with PfaEdit.
+
+ Ethiopic (U+1200-U+137F)
+
+
+* Maxim Iorsh <iorsh AT users.sourceforge.net>
+
+In 2002, Maxim Iorsh started the Culmus project, aiming at providing
+Hebrew-speaking Linux and Unix community with a basic collection of
+Hebrew fonts for X Windows. The fonts are visually compatible with
+URW++ Century Schoolbook L, URW++ Nimbus Sans L and URW++ Nimbus Mono
+L families, respectively, and are released under GNU GPL license. See
+also <http://culmus.sourceforge.net/>.
+
+ Hebrew (U+0590-U+05FF)
+
+
+* Panayotis Katsaloulis <panayotis AT panayotis.com>
+
+Panayotis Katsaloulis helped fixing Greek accents in the Greek
+Extended area.
+
+ Greek Extended (U+1F00-U+1FFF)
+
+
+* Vyacheslav Dikonov <sdiconov AT mail.ru>
+
+Vyacheslav Dikonov made a Braille unicode font that could be merged
+with the UCS fonts to fill the 2800-28FF range completely. (uniform
+scaling is possible to adapt it to any cell size). He also contributed
+a free syriac font, whose glyphs (about half of them) are borrowed
+from the "Carlo Ator" font freely downloadable from
+<http://www.aacf.asso.fr/>. Vyacheslav also filled in a few missing
+spots in the U+2000-U+27FF area, e.g. the box drawing section, sets of
+subscript and superscript digits and capital Roman numbers.
+
+ Syriac (U+0700-U+074A)
+ Box Drawing (U+2500-U+257F)
+ Braille (U+2800-U+28FF)
+
+
+* M.S. Sridhar <mssridhar AT vsnl.com>
+
+M/S Cyberscape Multimedia Limited, Mumbai, developers of Akruti
+Software for Indian Languages (http://www.akruti.com/), have released
+a set of TTF fonts for nine Indian scripts (Devanagari, Gujarati,
+Telugu, Tamil, Malayalam, Kannada, Bengali, Oriya, and Gurumukhi)
+under the GNU General Public License (GPL). You can download the fonts
+from the Free Software Foundation of India WWW site
+(http://www.gnu.org.in/akruti-fonts/) or from the Akruti website.
+
+For any further information or assistance regarding these fonts,
+please contact mssridhar AT vsnl.com.
+
+ Devanagari (U+0900-U+097F)
+ Bengali (U+0980-U+09FF)
+ Gurmukhi (U+0A00-U+0A7F)
+ Gujarati (U+0A80-U+0AFF)
+ Oriya (U+0B00-U+0B7F)
+ Tamil (U+0B80-U+0BFF)
+ Telugu (U+0C00-U+0C7F)
+ Kannada (U+0C80-U+0CFF)
+ Malayalam (U+0D00-U+0D7F)
+
+
+* DMS Electronics, The Sri Lanka Tipitaka Project, and Noah Levitt
+ <nlevitt AT columbia.edu>
+
+Noah Levitt found out that the Sinhalese fonts available on the site
+<http://www.metta.lk/fonts/> are released under GNU GPL, or,
+precisely, "Public Domain under GNU Licence Produced by DMS
+Electronics for The Sri Lanka Tipitaka Project" (taken from the font
+comment), and took the effort of recoding the font to Unicode.
+
+ Sinhala (U+0D80-U+0DFF)
+
+
+* Daniel Shurovich Chirkov <dansh AT chirkov.com>
+
+Dan Chirkov updated the FreeSerif font with the missing Cyrillic
+glyphs needed for conformance to Unicode 3.2. The effort is part of
+the Slavjanskij package for Mac OS X,
+<http://www.versiontracker.com/dyn/moreinfo/macosx/18680>.
+
+ Cyrillic (U+0400-U+04FF)
+
+
+* Denis Jacquerye <moyogo AT gmail.com>
+
+Denis Jacquerye added new glyphs and corrected existing ones in the
+Latin Extended-B and IPA Extensions ranges.
+
+ Latin Extended-B (U+0180-U+024F)
+ IPA Extensions (U+0250-U+02AF)
+
+
+* K.H. Hussain <hussain AT kfri.org> and R. Chitrajan
+
+`Rachana' in Malayalam means `to write', `to create'. Rachana Akshara
+Vedi, a team of socially committed information technology
+professionals and philologists, has applied developments in computer
+technology and desktop publishing to resurrect the Malayalam language
+from the disorder, fragmentation and degeneration it had suffered
+since the attempt to adapt the Malayalam script for using with a
+regular mechanical typewriter, which took place in
+1967-69. K.H. Hussein at the Kerala Forest Research Institute has
+released "Rachana Normal" fonts with approximately 900 glyphs required
+to typeset traditional Malayalam. R. Chitrajan apparently encoded the
+glyphs in the OpenType table.
+
+ Malayalam (U+0D00-U+0D7F)
+
+
+* Solaiman Karim <solaiman AT ekushey.org>
+
+ Bengali (U+0980-U+09FF)
+
+Solaiman Karim has developed several OpenType Bangla fonts and
+released them under GNU GPL on www.ekushey.org.
+
+
+* Sonali Sonania <sonalisonania AT gmail.com> and Monika Shah
+ <monikapatira AT gmail.com>
+
+ Devanagari (U+0900-U+097F)
+ Gujarati (U+0A80-U+0AFF)
+
+Glyphs were drawn by Cyberscape Multimedia Ltd., #101,Mahalakshmi
+Mansion 21st Main 22nd "A" Cross Banashankari 2nd stage Banglore
+560070, India. Converted to OTF by IndicTrans Team, Powai, Mumbai,
+lead by Prof. Jitendra Shah. Maintained by Monika Shah and Sonali
+Sonania of janabhaaratii Team, C-DAC, Mumbai. This font is released
+under GPL by Dr. Alka Irani and Prof Jitendra Shah, janabhaaratii
+Team, C-DAC, Mumabi. janabhaaratii is localisation project at C-DAC
+Mumbai (formerly National Centre for Software Technology); funded by
+TDIL, Govt. of India. Contact:monika_shah AT lycos.com,
+sonalisonania AT yahoo.com, jitendras AT vsnl.com, alka AT ncst.ernet.in.
+website: www.janabhaaratii.org.in.
+
+
+* Pravin Satpute <pravin_ind21 AT hotmail.com>, Bageshri Salvi
+ <sbagrshri AT yahoo.co.in>, Rahul Bhalerao <rahul_pb_india AT
+ yahoo.com> and Sandeep Shedmake <surgs2k47 AT yahoo.co.in>
+
+ Devanagari (U+0900-U+097F)
+ Gujarati (U+0A80-U+0AFF)
+ Oriya (U+0B00-U+0B7F)
+ Malayalam (U+0D00-U+0D7F)
+ Tamil (U+0B80-U+0BFF)
+
+In December 2005 the team at www.gnowledge.org released a set of two
+Unicode pan-Indic fonts: "Samyak" and "Samyak Sans". "Samyak" font
+belongs to serif style and is an original work of the team; "Samyak
+Sans" font belongs to sans serif style and is actually a compilation
+of already released Indic fonts (Gargi, Padma, Mukti, Utkal, Akruti
+and ThendralUni). Both fonts are based on Unicode standard. You can
+download the font files (released under GNU/GPL License) from
+http://www.gnowledge.org/Gnoware/localization/font.htm
+
+
+* Kulbir Singh Thind
+
+ Gurmukhi (U+0A00-U+0A7F)
+
+Dr. Kulbir Singh Thind designed a set of Gurmukhi Unicode fonts,
+AnmolUni and AnmolUni-Bold, which are available under the terms of GNU
+Generel Public Licens from the Punjabu Computing Resource Center,
+http://guca.sourceforge.net/typography/fonts/anmoluni/.
+
+
+* Gia Shervashidze <giasher AT telenet.ge>
+
+ Georgian (U+10A0-U+10FF)
+
+Starting in mid-1990s, Gia Shervashidze designed many
+Unicode-compliant Georgian fonts: Times New Roman Georgian, Arial
+Georgian, Courier New Georgian. His work on Georgian localization can
+be reached at http://www.gia.ge/.
+
+
+* Primož Peterlin <primoz.peterlin AT biofiz.mf.uni-lj.si>
+
+Primož Peterlin filled in missing glyphs here and there (e.g. Latin
+Extended-B and IPA Extensions ranges in the FreeMono familiy), and
+created the following UCS blocks:
+
+ Latin Extended-B (U+0180-U+024F)
+ IPA Extensions (U+0250-U+02AF)
+ Arrows (U+2190-U+21FF)
+ Box Drawing (U+2500-U+257F)
+ Block Elements (U+2580-U+259F)
+ Geometrical Shapes (U+25A0-U+25FF)
+
+* Mark Williamson
+
+Made the MPH 2 Damase font, from which
+ Hanunóo
+ Buginese
+ Tai Le
+ Ugaritic
+ Old Persian
+
+* Jacob Poon
+
+Submitted a very thorough survey of glyph problems and other suggestions.
+
+* Alexey Kryukov made the TemporaLCGUni fonts, based on the URW++ fonts,
+ from which most of the FreeSerif Cyrillic, and some of the Greek, is drawn.
+ He also provided valuable direction about Cyrillic and Greed typesetting.
+
+Notes:
+
+*: The glyph collection looks license-compatible, but its author has
+ not yet replied and agreed on his/her work being used in part of
+ this glyph collection.
+
+--------------------------------------------------------------------------
+$Id: CREDITS,v 1.17 2008/08/30 09:31:54 Stevan_White Exp $
diff --git a/game/fonts/FreeSans.ttf b/game/fonts/FreeSans/FreeSans.ttf
index a4c41697..a4c41697 100644
--- a/game/fonts/FreeSans.ttf
+++ b/game/fonts/FreeSans/FreeSans.ttf
Binary files differ
diff --git a/game/fonts/FreeSansBold.ttf b/game/fonts/FreeSans/FreeSansBold.ttf
index 15511674..15511674 100644
--- a/game/fonts/FreeSansBold.ttf
+++ b/game/fonts/FreeSans/FreeSansBold.ttf
Binary files differ
diff --git a/game/fonts/FreeSans/README b/game/fonts/FreeSans/README
new file mode 100644
index 00000000..96e4a4db
--- /dev/null
+++ b/game/fonts/FreeSans/README
@@ -0,0 +1,108 @@
+-*-text-*-
+ GNU FreeFont
+
+The GNU FreeFont project aims to provide a useful set of free scalable
+(i.e., OpenType) fonts covering as much as possible of the ISO 10646/Unicode
+UCS (Universal Character Set).
+
+Statement of Purpose
+--------------------
+
+The practical reason for putting glyphs together in a single font face is
+to conveniently mix symbols and characters from different writing systems,
+without having to switch fonts.
+
+Coverage
+--------
+
+FreeFont covers the following character sets
+
+* ISO 8859 parts 1-15
+* CEN MES-3 European Unicode Subset
+ http://www.evertype.com/standards/iso10646/pdf/cwa13873.pdf
+* IBM/Microsoft code pages 437, 850, 852, 1250, 1252 and more
+* Microsoft/Adobe Windows Glyph List 4 (WGL4)
+ http://www.microsoft.com/typography/otspec/WGL4.htm
+* KOI8-R and KOI8-RU
+* DEC VT100 graphics symbols
+* International Phonetic Alphabet
+* Arabic, Hebrew, Armenian, Georgian, Ethiopian and Thai alphabets,
+ including Arabic presentation forms A/B
+* mathematical symbols, including the whole TeX repertoire of symbols
+* APL symbols
+ etc.
+
+Editing
+-------
+
+The free outline font editor, George Williams's FontForge
+<http://fontforge.sourceforge.net/> is used for editing the fonts.
+
+Design Issues
+-------------
+
+Which font shapes should be made? Historical style terms like Renaissance
+or Baroque letterforms cannot be applied beyond Latin/Cyrillic/Greek
+scripts to any greater extent than Kufi or Nashki can be applied beyond
+Arabic script; "italic" is really only meaningful for Latin letters.
+
+However, most modern writing systems have typographic formulations for
+contrasting uniform and modulated character stroke widths, and have some
+history with "oblique", faces. Since the advent of the typewriter, most
+have developed a typographic style with uniform-width characters.
+
+Accordingly, the FreeFont family has one monospaced - FreeMono - and two
+proportional faces (one with uniform stroke - FreeSans - and one with
+modulated stroke - FreeSerif).
+
+To make text from different writing systems look good side-by-side, each
+FreeFont face is meant to contain characters of similar style and weight.
+
+Licensing
+---------
+
+Free UCS scalable fonts 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.
+
+The fonts are distributed in the hope that they 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; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+As a special exception, if you create a document which uses this font, and
+embed this font or unaltered portions of this font into the document, this
+font does not by itself cause the resulting document to be covered by the
+GNU General Public License. This exception does not however invalidate any
+other reasons why the document might be covered by the GNU General Public
+License. If you modify this font, you may extend this exception to your
+version of the font, but you are not obligated to do so. If you do not
+wish to do so, delete this exception statement from your version.
+
+
+Files and their suffixes
+------------------------
+
+The files with .sfd (Spline Font Database) are in FontForge's native format.
+Please use these if you plan to modify the font files.
+
+TrueType fonts for immediate consumption are the files with the .ttf
+(TrueType Font) suffix. These are ready to use in Xwindows based
+systems using FreeType, on Mac OS, and on older Windows systems.
+
+OpenType fonts (with suffix .otf) are for use in Windows Vista.
+Note that although they can be installed on Linux, but many applications
+in Linux still don't support them.
+
+
+--------------------------------------------------------------------------
+Primoz Peterlin, <primoz.peterlin@biofiz.mf.uni-lj.si>
+Steve White <stevan.white@googlemail.com>
+
+Free UCS scalable fonts: http://savannah.gnu.org/projects/freefont/
+$Id: README,v 1.5 2008/08/30 09:30:09 Stevan_White Exp $
diff --git a/game/fonts/Vera.ttf b/game/fonts/Vera.ttf
deleted file mode 100644
index 58cd6b5e..00000000
--- a/game/fonts/Vera.ttf
+++ /dev/null
Binary files differ
diff --git a/game/fonts/VeraBd.ttf b/game/fonts/VeraBd.ttf
deleted file mode 100644
index 51d6111d..00000000
--- a/game/fonts/VeraBd.ttf
+++ /dev/null
Binary files differ
diff --git a/game/fonts/bold/eurostar_regular_bold.dat b/game/fonts/bold/eurostar_regular_bold.dat
deleted file mode 100644
index 1b2023e2..00000000
--- a/game/fonts/bold/eurostar_regular_bold.dat
+++ /dev/null
Binary files differ
diff --git a/game/fonts/bold/eurostar_regular_bold.png b/game/fonts/bold/eurostar_regular_bold.png
deleted file mode 100644
index f2732e44..00000000
--- a/game/fonts/bold/eurostar_regular_bold.png
+++ /dev/null
Binary files differ
diff --git a/game/fonts/fonts.ini b/game/fonts/fonts.ini
index 6abd7366..a705d665 100755
--- a/game/fonts/fonts.ini
+++ b/game/fonts/fonts.ini
@@ -1,11 +1,11 @@
-[Normal]
-File=normal/eurostar_regular.png
-
-[Bold]
-File=bold/eurostar_regular_bold.png
-
-[Outline1]
-File=outline1/outline1.png
-
-[Outline2]
-File=outline2/outline2.png
+[Normal]
+File=FreeSans/FreeSans.ttf
+
+[Bold]
+File=FreeSans/FreeSansBold.ttf
+
+[Outline1]
+File=DejaVu/DejaVuSans-Bold.ttf
+
+[Outline2]
+File=FreeSans/FreeSansBold.ttf
diff --git a/game/fonts/fontsTTF.ini b/game/fonts/fontsTTF.ini
deleted file mode 100644
index 839258b2..00000000
--- a/game/fonts/fontsTTF.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[Normal]
-File=FreeSans.ttf
-
-[Bold]
-File=FreeSansBold.ttf
-
-[Outline1]
-File=FreeSansBold.ttf
-
-[Outline2]
-File=Vera.ttf
diff --git a/game/fonts/normal/eurostar_regular.dat b/game/fonts/normal/eurostar_regular.dat
deleted file mode 100644
index f44ae7d8..00000000
--- a/game/fonts/normal/eurostar_regular.dat
+++ /dev/null
Binary files differ
diff --git a/game/fonts/normal/eurostar_regular.png b/game/fonts/normal/eurostar_regular.png
deleted file mode 100644
index 21ef5ac4..00000000
--- a/game/fonts/normal/eurostar_regular.png
+++ /dev/null
Binary files differ
diff --git a/game/fonts/outline1/outline1.dat b/game/fonts/outline1/outline1.dat
deleted file mode 100644
index ea9f2484..00000000
--- a/game/fonts/outline1/outline1.dat
+++ /dev/null
Binary files differ
diff --git a/game/fonts/outline1/outline1.png b/game/fonts/outline1/outline1.png
deleted file mode 100644
index a1af3cd2..00000000
--- a/game/fonts/outline1/outline1.png
+++ /dev/null
Binary files differ
diff --git a/game/fonts/outline2/outline2.dat b/game/fonts/outline2/outline2.dat
deleted file mode 100644
index 062f1629..00000000
--- a/game/fonts/outline2/outline2.dat
+++ /dev/null
Binary files differ
diff --git a/game/fonts/outline2/outline2.png b/game/fonts/outline2/outline2.png
deleted file mode 100644
index 9677d379..00000000
--- a/game/fonts/outline2/outline2.png
+++ /dev/null
Binary files differ
diff --git a/game/languages/Catalan.ini b/game/languages/Catalan.ini
index 3319a271..9208b9bd 100644
--- a/game/languages/Catalan.ini
+++ b/game/languages/Catalan.ini
@@ -1,393 +1,393 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Carregant...
-
-SING_CHOOSE_MODE=Triar mode
-SING_SING=cantar
-SING_SING_DESC=joc ràpid: cantar un solo o un duet
-
-SING_MULTI=festa
-SING_MULTI_DESC=cantar en mode festa
-
-SING_TOOLS=eines
-
-SING_STATS=estadístiques
-SING_STATS_DESC=veure estadístiques
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=crea les teves propies cançons
-
-SING_GAME_OPTIONS=opcions de joc
-SING_GAME_OPTIONS_DESC=canviar preferències de joc
-
-SING_EXIT=sortir
-SING_EXIT_DESC=sortir del joc
-
-SING_OPTIONS=opcions
-SING_OPTIONS_DESC=canviar preferències
-SING_OPTIONS_WHEREAMI=Opcions
-
-SING_OPTIONS_GAME=joc
-SING_OPTIONS_GRAPHICS=gràfics
-SING_OPTIONS_SOUND=so
-SING_OPTIONS_LYRICS=lletres
-SING_OPTIONS_THEMES=aparença
-SING_OPTIONS_RECORD=gravar
-SING_OPTIONS_ADVANCED=avançat
-SING_OPTIONS_EXIT=enrere
-
-SING_OPTIONS_GAME_WHEREAMI=Opcions de joc
-SING_OPTIONS_GAME_DESC=opcions generals del joc
-SING_OPTIONS_GAME_PLAYERS=Jugadors
-SING_OPTIONS_GAME_DIFFICULTY=Dificultat
-SING_OPTIONS_GAME_LANGUAGE=Idioma
-SING_OPTIONS_GAME_TABS=Pestanyes
-SING_OPTIONS_GAME_SORTING=Ordenació
-SING_OPTIONS_GAME_DEBUG=Debug
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Opcions Gràfiques
-SING_OPTIONS_GRAPHICS_DESC=configurar gràfics
-SING_OPTIONS_GRAPHICS_RESOLUTION=Resolucị
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Pantalla complerta
-SING_OPTIONS_GRAPHICS_DEPTH=Profunditat
-SING_OPTIONS_GRAPHICS_VISUALIZER=Visualització
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscil·loscopi
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de línia
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Mida pel·lícula
-
-SING_OPTIONS_SOUND_WHEREAMI=Opcions de so
-SING_OPTIONS_SOUND_DESC=configurar so
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Reproducció del micro
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Música de fons
-SING_OPTIONS_SOUND_MIC_BOOST=Ampli Micro
-SING_OPTIONS_SOUND_CLICK_ASSIST=Assistència Click
-SING_OPTIONS_SOUND_BEAT_CLICK=Clic de ritme
-SING_OPTIONS_SOUND_THRESHOLD=Llindar
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mode dos jugadors
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Volum previsualitzar
-SING_OPTIONS_SOUND_PREVIEWFADING=Fos previsualitzar
-
-SING_OPTIONS_LYRICS_WHEREAMI=Opcions Lletra
-SING_OPTIONS_LYRICS_DESC=configuració de lletres
-SING_OPTIONS_LYRICS_FONT=Font
-SING_OPTIONS_LYRICS_EFFECT=Efecte
-SING_OPTIONS_LYRICS_SOLMIZATION=Solfeig
-SING_OPTIONS_LYRICS_NOTELINES=Pentagrama
-
-SING_OPTIONS_THEMES_WHEREAMI=Options d'Aparença
-SING_OPTIONS_THEMES_DESC=Configuració d'aparença
-SING_OPTIONS_THEMES_THEME=Aparença
-SING_OPTIONS_THEMES_SKIN=Pell
-SING_OPTIONS_THEMES_COLOR=Color
-
-SING_OPTIONS_RECORD_WHEREAMI=Opcions de micro
-SING_OPTIONS_RECORD_DESC=configuració del micro
-SING_OPTIONS_RECORD_CARD=Tarjeta de so
-SING_OPTIONS_RECORD_INPUT=Entrada
-SING_OPTIONS_RECORD_CHANNEL=Canal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Opcions Avançades
-SING_OPTIONS_ADVANCED_DESC=opcions avançades
-SING_OPTIONS_ADVANCED_EFFECTSING=Efectes de cantar
-SING_OPTIONS_ADVANCED_SCREENFADE=Fos de pantalla
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animació càrrega
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Prequnta abans d'esborrar
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de línia
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Quantes vegades cantada
-SING_OPTIONS_ADVANCED_ONSONGCLICK=després de triar cançó
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Menú Automàtic de festa
-SING_EDIT=Editor
-SING_EDIT_MENU_DESCRIPTION=crea cançons
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importar text de fitxer midi
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=tornar
-SING_EDIT_BUTTON_CONVERT=Importar
-SING_EDIT_BUTTON_EXIT=enrere
-SING_EDIT_NAVIGATE=navegar
-SING_EDIT_SELECT=triar
-SING_EDIT_EXIT=enrere
-
-
-SING_LEGEND_SELECT=seleccionar
-SING_LEGEND_NAVIGATE=navegar
-SING_LEGEND_CONTINUE=continuar
-SING_LEGEND_ESC=enrere
-
-SING_PLAYER_DESC=entrar nom de jugador/s
-SING_PLAYER_WHEREAMI=Nom dels jugadors
-SING_PLAYER_ENTER_NAME=introduir nom
-
-SING_DIFFICULTY_DESC=triar dificultat
-SING_DIFFICULTY_WHEREAMI=Dificultat
-SING_DIFFICULTY_CONTINUE=a selecció de cançó
-SING_EASY=Fàcil
-SING_MEDIUM=Mitjà
-SING_HARD=Difícil
-
-SING_SONG_SELECTION_DESC=triar cançó
-SING_SONG_SELECTION_WHEREAMI=Selecció de cançons
-SING_SONG_SELECTION_GOTO=Anar a ..
-SING_SONG_SELECTION=selecció de cançons
-SING_SONG_SELECTION_MENU=menú
-SING_SONG_SELECTION_PLAYLIST=llista
-SING_SONGS_IN_CAT=Cançons
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TEMPS
-SING_TOTAL=total
-SING_MODE=cantar sol
-SING_NOTES=notes
-SING_GOLDEN_NOTES=notes daurades
-SING_PHRASE_BONUS=bonus de línia
-
-SING_MENU=Menú principal
-
-SONG_SCORE=puntuació cançó
-SONG_SCORE_WHEREAMI=Puntuació
-
-SING_SCORE_TONE_DEAF=Sense oïda
-SING_SCORE_AMATEUR=Novell
-SING_SCORE_WANNABE=Aficionat
-SING_SCORE_HOPEFUL=Esperançador
-SING_SCORE_RISING_STAR=Futura estrella
-SING_SCORE_LEAD_SINGER=Bon cantant
-SING_SCORE_SUPERSTAR=Estrella
-SING_SCORE_ULTRASTAR=Super estrella
-
-SING_TOP_5_CHARTS=millors 5 jugadors
-SING_TOP_5_CHARTS_WHEREAMI=millors 5
-SING_TOP_5_CHARTS_CONTINUE=a selecció de cançó
-
-POPUP_PERFECT=perfecte!
-POPUP_AWESOME=genial!
-POPUP_GREAT=molt bo!
-POPUP_GOOD=esta bé!
-POPUP_NOTBAD=pots millorar!
-POPUP_BAD=malament!
-POPUP_POOR=pobre!
-POPUP_AWFUL=boo fora!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= i
-
-SONG_MENU_NAME_MAIN=menú de cançons
-SONG_MENU_PLAY=Cantar
-SONG_MENU_CHANGEPLAYERS=Canviar jugadors
-SONG_MENU_EDIT=Editar
-SONG_MENU_MODI=Cantar un Modi
-SONG_MENU_CANCEL=Cancel·lar
-
-SONG_MENU_NAME_PLAYLIST=Menú de cançons
-SONG_MENU_PLAYLIST_ADD=Afegir Cançó
-SONG_MENU_PLAYLIST_DEL=Esborrar Cançó
-
-SONG_MENU_NAME_PLAYLIST_ADD=Afegir Song
-SONG_MENU_PLAYLIST_ADD_NEW=a nova llista
-SONG_MENU_PLAYLIST_ADD_EXISTING=a llista existent
-SONG_MENU_PLAYLIST_NOEXISTING=No hi ha llistes
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nova llista
-SONG_MENU_PLAYLIST_NEW_CREATE=Crear
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Sense nom
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Segur que vols esborrar?
-SONG_MENU_YES=Si
-SONG_MENU_NO=No
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Obrir llista
-SONG_MENU_PLAYLIST_LOAD=obrir
-SONG_MENU_PLAYLIST_DELCURRENT=esborrar llista
-
-SONG_MENU_NAME_PLAYLIST_DEL=Esborrar llista?
-
-SONG_MENU_NAME_PARTY_MAIN=Menú festa
-SONG_MENU_JOKER=Comodí
-
-SONG_MENU_NAME_PARTY_JOKER=utilitzar comodí
-
-SONG_JUMPTO_DESC=buscar cançó
-SONG_JUMPTO_TYPE_DESC=Buscar:
-SONG_JUMPTO_TYPE1=Tot
-SONG_JUMPTO_TYPE2=Títol
-SONG_JUMPTO_TYPE3=Artista
-SONG_JUMPTO_SONGSFOUND=%d Cançons trobades
-SONG_JUMPTO_NOSONGSFOUND=No s'han trobat cançons
-SONG_JUMPTO_HELP=Introduir text a cercar
-SONG_JUMPTO_CATTEXT=Cercant: %s
-
-PARTY_MODE=mode festa
-PARTY_DIFFICULTY=Dificultat
-PARTY_PLAYLIST=Mode llista
-PARTY_PLAYLIST_ALL=Tot
-PARTY_PLAYLIST_CATEGORY=Directori
-PARTY_PLAYLIST_PLAYLIST=llista
-PARTY_ROUNDS=Rondes
-PARTY_TEAMS=Equips
-PARTY_TEAMS_PLAYER1=Player Team1
-PARTY_TEAMS_PLAYER2=Player Team2
-PARTY_TEAMS_PLAYER3=Player Team3
-
-PARTY_LEGEND_CONTINUE=continuar
-
-PARTY_OPTIONS_DESC=opcions mode festa
-PARTY_OPTIONS_WHEREAMI=Opcions Festa
-
-PARTY_PLAYER_DESC=introduïr noms de jugadors i equips
-PARTY_PLAYER_WHEREAMI=Noms
-PARTY_PLAYER_ENTER_NAME=introduïr noms
-PARTY_PLAYER_LEGEND_CONTINUE=iniciar festa
-
-PARTY_ROUND_DESC=següent jugador al micro
-PARTY_ROUND_WHEREAMI=Següent Ronda
-PARTY_ROUND_LEGEND_CONTINUE=iniciar ronda
-
-PARTY_SONG_WHEREAMI=Selecció de cançó mode festa
-PARTY_SONG_LEGEND_CONTINUE=cantar
-PARTY_SONG_MENU=menú festa
-
-PARTY_SCORE_DESC=puntuació de l'última ronda
-PARTY_SCORE_WHEREAMI=Punts mode festa
-
-PARTY_WIN_DESC=guanyador de la festa
-PARTY_WIN_WHEREAMI=Guanyador
-PARTY_WIN_LEGEND_CONTINUE=tornar al menú principal
-
-PARTY_ROUND=Ronda
-PARTY_ROUND_WINNER=Guanyador
-PARTY_NOTPLAYEDYET=no s'ha jugat encara
-PARTY_NOBODY=ningú
-NEXT_ROUND=Següent ronda:
-
-PARTY_DISMISSED=Abandona!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=guanya!
-
-PLUGIN_HDL_NAME=Aguantar la línia
-PLUGIN_HDL_DESC=No baixis de la fletxa a la barra de qualitat
-
-PLUGIN_UNTIL5000_NAME=Fins a 5000
-PLUGIN_UNTIL5000_DESC=El primer a arribar a 5000 punts guanya
-
-PLUGIN_DUELL_NAME=Duel
-PLUGIN_DUELL_DESC=Cantar un duela fins a 10000 punts
-
-PLUGIN_BLIND_NAME=Mode cec
-PLUGIN_BLIND_DESC=Duel sense veure les notes
-
-STAT_MAIN=Estadístiques
-STAT_MAIN_DESC=General
-STAT_MAIN_WHEREAMI=Estadístiques
-
-STAT_OVERVIEW_INTRO=%0:s Estadístiques\nÚltima reinicialització %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Cançons(%3:d amb Video), de les que %1:d ya han sonat i %2:d encara no s'han jugat mai.\n La cançó més popular és %5:s de %4:s.
-STAT_OVERVIEW_PLAYER=Des de l'última reinicialització hi han hagut %0:d jugadors diferents.\n El millor jugador és %1:s amb una mitjana de %2:d Punts.\n %3:s ha fet la màxima puntuació amb %4:d Punts.
-
-STAT_DETAIL=Estadístques
-STAT_DETAIL_WHEREAMI=Estadístiques
-
-STAT_NEXT=Següent pàgina
-STAT_PREV=Pàgina anterior
-STAT_REVERSE=Ordre invers
-STAT_PAGE=%0:d de %1:d Pàgines\n (%2:d de %3:d Entrades)
-
-STAT_DESC_SCORES=Màximes puntuacions
-STAT_DESC_SCORES_REVERSED=Mínimes puntuacions
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Millors cantants
-STAT_DESC_SINGERS_REVERSED=Pitjors cantants
-STAT_FORMAT_SINGERS=%0:s \n Puntuació mitjana: %1:d
-
-STAT_DESC_SONGS=Cançons més populars
-STAT_DESC_SONGS_REVERSED=Cançons menys populars
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx cantades
-
-STAT_DESC_BANDS=Grups més populars
-STAT_DESC_BANDS_REVERSED=Grups menys populars
-STAT_FORMAT_BANDS=%0:s \n %1:dx Cantades
-
-MSG_ERROR_TITLE=Error
-MSG_QUESTION_TITLE=Qüestió
-MSG_QUIT_USDX=Realment vols sortir d'UltraStar?
-MSG_END_PARTY=Realment vols sortir del mode festa?
-ERROR_NO_SONGS=No hi ha cançons
-ERROR_NO_PLUGINS=No hi ha Plugins
-ERROR_CORRUPT_SONG=No es poden carregar les cançons
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=No es pot carregar: Fitxer no trobat
-ERROR_CORRUPT_SONG_NO_NOTES=No es pot carregar: No s'han trobat notes
-ERROR_CORRUPT_SONG_NO_BREAKS=No es pot carregar: No s'han trobat línies
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=Carregant...
+
+SING_CHOOSE_MODE=Triar mode
+SING_SING=cantar
+SING_SING_DESC=joc ràpid: cantar un solo o un duet
+
+SING_MULTI=festa
+SING_MULTI_DESC=cantar en mode festa
+
+SING_TOOLS=eines
+
+SING_STATS=estadístiques
+SING_STATS_DESC=veure estadístiques
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=crea les teves propies cançons
+
+SING_GAME_OPTIONS=opcions de joc
+SING_GAME_OPTIONS_DESC=canviar preferències de joc
+
+SING_EXIT=sortir
+SING_EXIT_DESC=sortir del joc
+
+SING_OPTIONS=opcions
+SING_OPTIONS_DESC=canviar preferències
+SING_OPTIONS_WHEREAMI=Opcions
+
+SING_OPTIONS_GAME=joc
+SING_OPTIONS_GRAPHICS=gràfics
+SING_OPTIONS_SOUND=so
+SING_OPTIONS_LYRICS=lletres
+SING_OPTIONS_THEMES=aparença
+SING_OPTIONS_RECORD=gravar
+SING_OPTIONS_ADVANCED=avançat
+SING_OPTIONS_EXIT=enrere
+
+SING_OPTIONS_GAME_WHEREAMI=Opcions de joc
+SING_OPTIONS_GAME_DESC=opcions generals del joc
+SING_OPTIONS_GAME_PLAYERS=Jugadors
+SING_OPTIONS_GAME_DIFFICULTY=Dificultat
+SING_OPTIONS_GAME_LANGUAGE=Idioma
+SING_OPTIONS_GAME_TABS=Pestanyes
+SING_OPTIONS_GAME_SORTING=Ordenació
+SING_OPTIONS_GAME_DEBUG=Debug
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Opcions Gràfiques
+SING_OPTIONS_GRAPHICS_DESC=configurar gràfics
+SING_OPTIONS_GRAPHICS_RESOLUTION=Resolucị
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Pantalla complerta
+SING_OPTIONS_GRAPHICS_DEPTH=Profunditat
+SING_OPTIONS_GRAPHICS_VISUALIZER=Visualització
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscil·loscopi
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de línia
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Mida pel·lícula
+
+SING_OPTIONS_SOUND_WHEREAMI=Opcions de so
+SING_OPTIONS_SOUND_DESC=configurar so
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Reproducció del micro
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Música de fons
+SING_OPTIONS_SOUND_MIC_BOOST=Ampli Micro
+SING_OPTIONS_SOUND_CLICK_ASSIST=Assistència Click
+SING_OPTIONS_SOUND_BEAT_CLICK=Clic de ritme
+SING_OPTIONS_SOUND_THRESHOLD=Llindar
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mode dos jugadors
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Volum previsualitzar
+SING_OPTIONS_SOUND_PREVIEWFADING=Fos previsualitzar
+
+SING_OPTIONS_LYRICS_WHEREAMI=Opcions Lletra
+SING_OPTIONS_LYRICS_DESC=configuració de lletres
+SING_OPTIONS_LYRICS_FONT=Font
+SING_OPTIONS_LYRICS_EFFECT=Efecte
+SING_OPTIONS_LYRICS_SOLMIZATION=Solfeig
+SING_OPTIONS_LYRICS_NOTELINES=Pentagrama
+
+SING_OPTIONS_THEMES_WHEREAMI=Options d'Aparença
+SING_OPTIONS_THEMES_DESC=Configuració d'aparença
+SING_OPTIONS_THEMES_THEME=Aparença
+SING_OPTIONS_THEMES_SKIN=Pell
+SING_OPTIONS_THEMES_COLOR=Color
+
+SING_OPTIONS_RECORD_WHEREAMI=Opcions de micro
+SING_OPTIONS_RECORD_DESC=configuració del micro
+SING_OPTIONS_RECORD_CARD=Tarjeta de so
+SING_OPTIONS_RECORD_INPUT=Entrada
+SING_OPTIONS_RECORD_CHANNEL=Canal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Opcions Avançades
+SING_OPTIONS_ADVANCED_DESC=opcions avançades
+SING_OPTIONS_ADVANCED_EFFECTSING=Efectes de cantar
+SING_OPTIONS_ADVANCED_SCREENFADE=Fos de pantalla
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animació càrrega
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Prequnta abans d'esborrar
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de línia
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Quantes vegades cantada
+SING_OPTIONS_ADVANCED_ONSONGCLICK=després de triar cançó
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Menú Automàtic de festa
+SING_EDIT=Editor
+SING_EDIT_MENU_DESCRIPTION=crea cançons
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importar text de fitxer midi
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=tornar
+SING_EDIT_BUTTON_CONVERT=Importar
+SING_EDIT_BUTTON_EXIT=enrere
+SING_EDIT_NAVIGATE=navegar
+SING_EDIT_SELECT=triar
+SING_EDIT_EXIT=enrere
+
+
+SING_LEGEND_SELECT=seleccionar
+SING_LEGEND_NAVIGATE=navegar
+SING_LEGEND_CONTINUE=continuar
+SING_LEGEND_ESC=enrere
+
+SING_PLAYER_DESC=entrar nom de jugador/s
+SING_PLAYER_WHEREAMI=Nom dels jugadors
+SING_PLAYER_ENTER_NAME=introduir nom
+
+SING_DIFFICULTY_DESC=triar dificultat
+SING_DIFFICULTY_WHEREAMI=Dificultat
+SING_DIFFICULTY_CONTINUE=a selecció de cançó
+SING_EASY=Fàcil
+SING_MEDIUM=Mitjà
+SING_HARD=Difícil
+
+SING_SONG_SELECTION_DESC=triar cançó
+SING_SONG_SELECTION_WHEREAMI=Selecció de cançons
+SING_SONG_SELECTION_GOTO=Anar a ..
+SING_SONG_SELECTION=selecció de cançons
+SING_SONG_SELECTION_MENU=menú
+SING_SONG_SELECTION_PLAYLIST=llista
+SING_SONGS_IN_CAT=Cançons
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TEMPS
+SING_TOTAL=total
+SING_MODE=cantar sol
+SING_NOTES=notes
+SING_GOLDEN_NOTES=notes daurades
+SING_PHRASE_BONUS=bonus de línia
+
+SING_MENU=Menú principal
+
+SONG_SCORE=puntuació cançó
+SONG_SCORE_WHEREAMI=Puntuació
+
+SING_SCORE_TONE_DEAF=Sense oïda
+SING_SCORE_AMATEUR=Novell
+SING_SCORE_WANNABE=Aficionat
+SING_SCORE_HOPEFUL=Esperançador
+SING_SCORE_RISING_STAR=Futura estrella
+SING_SCORE_LEAD_SINGER=Bon cantant
+SING_SCORE_SUPERSTAR=Estrella
+SING_SCORE_ULTRASTAR=Super estrella
+
+SING_TOP_5_CHARTS=millors 5 jugadors
+SING_TOP_5_CHARTS_WHEREAMI=millors 5
+SING_TOP_5_CHARTS_CONTINUE=a selecció de cançó
+
+POPUP_PERFECT=perfecte!
+POPUP_AWESOME=genial!
+POPUP_GREAT=molt bo!
+POPUP_GOOD=esta bé!
+POPUP_NOTBAD=pots millorar!
+POPUP_BAD=malament!
+POPUP_POOR=pobre!
+POPUP_AWFUL=boo fora!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= i
+
+SONG_MENU_NAME_MAIN=menú de cançons
+SONG_MENU_PLAY=Cantar
+SONG_MENU_CHANGEPLAYERS=Canviar jugadors
+SONG_MENU_EDIT=Editar
+SONG_MENU_MODI=Cantar un Modi
+SONG_MENU_CANCEL=Cancel·lar
+
+SONG_MENU_NAME_PLAYLIST=Menú de cançons
+SONG_MENU_PLAYLIST_ADD=Afegir Cançó
+SONG_MENU_PLAYLIST_DEL=Esborrar Cançó
+
+SONG_MENU_NAME_PLAYLIST_ADD=Afegir Song
+SONG_MENU_PLAYLIST_ADD_NEW=a nova llista
+SONG_MENU_PLAYLIST_ADD_EXISTING=a llista existent
+SONG_MENU_PLAYLIST_NOEXISTING=No hi ha llistes
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nova llista
+SONG_MENU_PLAYLIST_NEW_CREATE=Crear
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Sense nom
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Segur que vols esborrar?
+SONG_MENU_YES=Si
+SONG_MENU_NO=No
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Obrir llista
+SONG_MENU_PLAYLIST_LOAD=obrir
+SONG_MENU_PLAYLIST_DELCURRENT=esborrar llista
+
+SONG_MENU_NAME_PLAYLIST_DEL=Esborrar llista?
+
+SONG_MENU_NAME_PARTY_MAIN=Menú festa
+SONG_MENU_JOKER=Comodí
+
+SONG_MENU_NAME_PARTY_JOKER=utilitzar comodí
+
+SONG_JUMPTO_DESC=buscar cançó
+SONG_JUMPTO_TYPE_DESC=Buscar:
+SONG_JUMPTO_TYPE1=Tot
+SONG_JUMPTO_TYPE2=Títol
+SONG_JUMPTO_TYPE3=Artista
+SONG_JUMPTO_SONGSFOUND=%d Cançons trobades
+SONG_JUMPTO_NOSONGSFOUND=No s'han trobat cançons
+SONG_JUMPTO_HELP=Introduir text a cercar
+SONG_JUMPTO_CATTEXT=Cercant: %s
+
+PARTY_MODE=mode festa
+PARTY_DIFFICULTY=Dificultat
+PARTY_PLAYLIST=Mode llista
+PARTY_PLAYLIST_ALL=Tot
+PARTY_PLAYLIST_CATEGORY=Directori
+PARTY_PLAYLIST_PLAYLIST=llista
+PARTY_ROUNDS=Rondes
+PARTY_TEAMS=Equips
+PARTY_TEAMS_PLAYER1=Player Team1
+PARTY_TEAMS_PLAYER2=Player Team2
+PARTY_TEAMS_PLAYER3=Player Team3
+
+PARTY_LEGEND_CONTINUE=continuar
+
+PARTY_OPTIONS_DESC=opcions mode festa
+PARTY_OPTIONS_WHEREAMI=Opcions Festa
+
+PARTY_PLAYER_DESC=introduïr noms de jugadors i equips
+PARTY_PLAYER_WHEREAMI=Noms
+PARTY_PLAYER_ENTER_NAME=introduïr noms
+PARTY_PLAYER_LEGEND_CONTINUE=iniciar festa
+
+PARTY_ROUND_DESC=següent jugador al micro
+PARTY_ROUND_WHEREAMI=Següent Ronda
+PARTY_ROUND_LEGEND_CONTINUE=iniciar ronda
+
+PARTY_SONG_WHEREAMI=Selecció de cançó mode festa
+PARTY_SONG_LEGEND_CONTINUE=cantar
+PARTY_SONG_MENU=menú festa
+
+PARTY_SCORE_DESC=puntuació de l'última ronda
+PARTY_SCORE_WHEREAMI=Punts mode festa
+
+PARTY_WIN_DESC=guanyador de la festa
+PARTY_WIN_WHEREAMI=Guanyador
+PARTY_WIN_LEGEND_CONTINUE=tornar al menú principal
+
+PARTY_ROUND=Ronda
+PARTY_ROUND_WINNER=Guanyador
+PARTY_NOTPLAYEDYET=no s'ha jugat encara
+PARTY_NOBODY=ningú
+NEXT_ROUND=Següent ronda:
+
+PARTY_DISMISSED=Abandona!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=guanya!
+
+PLUGIN_HDL_NAME=Aguantar la línia
+PLUGIN_HDL_DESC=No baixis de la fletxa a la barra de qualitat
+
+PLUGIN_UNTIL5000_NAME=Fins a 5000
+PLUGIN_UNTIL5000_DESC=El primer a arribar a 5000 punts guanya
+
+PLUGIN_DUELL_NAME=Duel
+PLUGIN_DUELL_DESC=Cantar un duela fins a 10000 punts
+
+PLUGIN_BLIND_NAME=Mode cec
+PLUGIN_BLIND_DESC=Duel sense veure les notes
+
+STAT_MAIN=Estadístiques
+STAT_MAIN_DESC=General
+STAT_MAIN_WHEREAMI=Estadístiques
+
+STAT_OVERVIEW_INTRO=%0:s Estadístiques\nÚltima reinicialització %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Cançons(%3:d amb Video), de les que %1:d ya han sonat i %2:d encara no s'han jugat mai.\n La cançó més popular és %5:s de %4:s.
+STAT_OVERVIEW_PLAYER=Des de l'última reinicialització hi han hagut %0:d jugadors diferents.\n El millor jugador és %1:s amb una mitjana de %2:d Punts.\n %3:s ha fet la màxima puntuació amb %4:d Punts.
+
+STAT_DETAIL=Estadístques
+STAT_DETAIL_WHEREAMI=Estadístiques
+
+STAT_NEXT=Següent pàgina
+STAT_PREV=Pàgina anterior
+STAT_REVERSE=Ordre invers
+STAT_PAGE=%0:d de %1:d Pàgines\n (%2:d de %3:d Entrades)
+
+STAT_DESC_SCORES=Màximes puntuacions
+STAT_DESC_SCORES_REVERSED=Mínimes puntuacions
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Millors cantants
+STAT_DESC_SINGERS_REVERSED=Pitjors cantants
+STAT_FORMAT_SINGERS=%0:s \n Puntuació mitjana: %1:d
+
+STAT_DESC_SONGS=Cançons més populars
+STAT_DESC_SONGS_REVERSED=Cançons menys populars
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx cantades
+
+STAT_DESC_BANDS=Grups més populars
+STAT_DESC_BANDS_REVERSED=Grups menys populars
+STAT_FORMAT_BANDS=%0:s \n %1:dx Cantades
+
+MSG_ERROR_TITLE=Error
+MSG_QUESTION_TITLE=Qüestió
+MSG_QUIT_USDX=Realment vols sortir d'UltraStar?
+MSG_END_PARTY=Realment vols sortir del mode festa?
+ERROR_NO_SONGS=No hi ha cançons
+ERROR_NO_PLUGINS=No hi ha Plugins
+ERROR_CORRUPT_SONG=No es poden carregar les cançons
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=No es pot carregar: Fitxer no trobat
+ERROR_CORRUPT_SONG_NO_NOTES=No es pot carregar: No s'han trobat notes
+ERROR_CORRUPT_SONG_NO_BREAKS=No es pot carregar: No s'han trobat línies
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=No es pot carregar: Error llegint línia %0:d \ No newline at end of file
diff --git a/game/languages/Croatian.ini b/game/languages/Croatian.ini
index 79d01440..f52881c0 100644
--- a/game/languages/Croatian.ini
+++ b/game/languages/Croatian.ini
@@ -1,403 +1,403 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Uèitavanje...
-
-SING_CHOOSE_MODE=Izaberi naèin igre
-SING_SING=pjevaj
-SING_SING_DESC=brza igra: pjevaj solo ili duet
-
-SING_MULTI=party
-SING_MULTI_DESC=pjevaj u party mode-u
-
-SING_TOOLS=alati
-
-SING_STATS=statistika
-SING_STATS_DESC=pogledaj statistiku
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=napravi svoje pjesme
-
-SING_GAME_OPTIONS=opcije igre
-SING_GAME_OPTIONS_DESC=promijeni postavke
-
-SING_EXIT=izlaz
-SING_EXIT_DESC=izlaz iz igre
-
-SING_OPTIONS=opcije
-SING_OPTIONS_DESC=promijeni postavke
-SING_OPTIONS_WHEREAMI=Opcije
-
-SING_OPTIONS_GAME=igra
-SING_OPTIONS_GRAPHICS=video
-SING_OPTIONS_SOUND=audio
-SING_OPTIONS_LYRICS=tekstovi
-SING_OPTIONS_THEMES=teme
-SING_OPTIONS_RECORD=snimanje
-SING_OPTIONS_ADVANCED=ostalo
-SING_OPTIONS_EXIT=natrag
-
-SING_OPTIONS_GAME_WHEREAMI=Opcije Igre
-SING_OPTIONS_GAME_DESC=osnovne opcije igre
-SING_OPTIONS_GAME_PLAYERS=Br. igraèa
-SING_OPTIONS_GAME_DIFFICULTY=Težina
-SING_OPTIONS_GAME_LANGUAGE=Jezik
-SING_OPTIONS_GAME_TABS=Tabovi
-SING_OPTIONS_GAME_SORTING=Sortiranje
-SING_OPTIONS_GAME_DEBUG=Debug
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Opcije Videa
-SING_OPTIONS_GRAPHICS_DESC=video opcije
-SING_OPTIONS_GRAPHICS_RESOLUTION=Rezolucija
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Cijeli ekran
-SING_OPTIONS_GRAPHICS_DEPTH=Dubina boja
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus linije
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Velièina videa
-SING_OPTIONS_GRAPHICS_VISUALIZER=Vizualizacije
-
-SING_OPTIONS_SOUND_WHEREAMI=Opcije Zvuka
-SING_OPTIONS_SOUND_DESC=postavke zvuka
-SING_OPTIONS_SOUND_MIC_BOOST=Mic boost
-SING_OPTIONS_SOUND_CLICK_ASSIST=Pomoæ klikovima
-SING_OPTIONS_SOUND_BEAT_CLICK=Klik na udarce
-SING_OPTIONS_SOUND_THRESHOLD=Threshold
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Igra za dva igraèa
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Glasnoæa prikaza
-SING_OPTIONS_SOUND_PREVIEWFADING=Fade-in vrijeme
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Microphone Playback
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Pozadinska glazba
-
-SING_OPTIONS_LYRICS_WHEREAMI=Opcije Tekstova
-SING_OPTIONS_LYRICS_DESC=postavke tekstova
-SING_OPTIONS_LYRICS_FONT=Font
-SING_OPTIONS_LYRICS_EFFECT=Efekt
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacija
-SING_OPTIONS_LYRICS_NOTELINES=Crtovlje
-
-SING_OPTIONS_THEMES_WHEREAMI=Opcije Tema
-SING_OPTIONS_THEMES_DESC=postavke tema i skinova
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Boja
-
-SING_OPTIONS_RECORD_WHEREAMI=Opcije Snimanja
-SING_OPTIONS_RECORD_DESC=postavke mikrofona
-SING_OPTIONS_RECORD_CARD=Zv. kartica
-SING_OPTIONS_RECORD_INPUT=Ulaz
-SING_OPTIONS_RECORD_CHANNEL=Kanal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Ostale Opcije
-SING_OPTIONS_ADVANCED_DESC=ostale postavke
-SING_OPTIONS_ADVANCED_EFFECTSING=Efekti kod pjevanja
-SING_OPTIONS_ADVANCED_SCREENFADE=Fade-out ekrana
-SING_OPTIONS_ADVANCED_LOADANIMATION=Anim. tijekom uèit.
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Sigurn. pitanja
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus linije
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Zapamti broj pjev.
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Nakon pjesme
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto party meni
-
-SING_EDIT=Editor
-SING_EDIT_MENU_DESCRIPTION=napravi svoje pjesme
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Uèitaj tekst iz midi datoteke
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=natrag
-SING_EDIT_BUTTON_CONVERT=Uèitaj
-SING_EDIT_BUTTON_EXIT=natrag
-SING_EDIT_NAVIGATE=upravljanje
-SING_EDIT_SELECT=odaberi
-SING_EDIT_EXIT=natrag
-
-SING_LEGEND_SELECT=odaberi
-SING_LEGEND_NAVIGATE=navigacija
-SING_LEGEND_CONTINUE=nastavi
-SING_LEGEND_ESC=natrag
-
-SING_PLAYER_DESC=unesi ime igraèa
-SING_PLAYER_WHEREAMI=Imena igraèa
-SING_PLAYER_ENTER_NAME=unesi ime
-
-SING_DIFFICULTY_DESC=odaberi težinu
-SING_DIFFICULTY_WHEREAMI=Težina
-SING_DIFFICULTY_CONTINUE=odabir pjesme
-SING_EASY=Lako
-SING_MEDIUM=Srednje
-SING_HARD=Teško
-
-SING_SONG_SELECTION_DESC=odaberi pjesmu
-SING_SONG_SELECTION_WHEREAMI=Odabir Pjesme
-SING_SONG_SELECTION_GOTO=idi na ..
-SING_SONG_SELECTION=odabir pjesme
-SING_SONG_SELECTION_MENU=meni
-SING_SONG_SELECTION_PLAYLIST=playlista
-SING_SONGS_IN_CAT=Pjesme
-PLAYLIST_CATTEXT=Playlista: %s
-
-SING_TIME=TIME
-SING_TOTAL=ukupno
-SING_MODE=pjevaj solo
-SING_NOTES=note
-SING_GOLDEN_NOTES=zlatne note
-SING_PHRASE_BONUS=bonus
-
-SING_MENU=Glavni Meni
-
-SONG_SCORE=bodovi
-SONG_SCORE_WHEREAMI=Rezultat
-
-SING_SCORE_TONE_DEAF=Bez sluha
-SING_SCORE_AMATEUR=Amater
-SING_SCORE_RISING_STAR=Zvijezda u usponu
-SING_SCORE_LEAD_SINGER=Vodeæi pjevaè
-SING_SCORE_HIT_ARTIST=Hit Artist
-SING_SCORE_SUPERSTAR=Superstar
-SING_SCORE_ULTRASTAR=Ultrastar
-SING_SCORE_WANNABE=Wannabe
-SING_SCORE_HOPEFUL=Pun nade
-
-SING_TOP_5_CHARTS=top 5 Igraèa
-SING_TOP_5_CHARTS_WHEREAMI=top 5
-SING_TOP_5_CHARTS_CONTINUE=odabir pjesme
-
-POPUP_PERFECT=izvanredno!
-POPUP_AWESOME=predivno!
-POPUP_GREAT=odlièno!
-POPUP_GOOD=dobro!
-POPUP_NOTBAD=nije loše!
-POPUP_BAD=loše!
-POPUP_POOR=jadno!
-POPUP_AWFUL=grozno!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= i
-
-SONG_MENU_NAME_MAIN=Kolekcija pjesama
-SONG_MENU_PLAY=Pjevaj
-SONG_MENU_CHANGEPLAYERS=Promijeni igraèe
-SONG_MENU_EDIT=Uredi
-SONG_MENU_MODI=Pjevaj Modi
-SONG_MENU_CANCEL=Poništi
-
-SONG_MENU_NAME_PLAYLIST=Playliste
-SONG_MENU_PLAYLIST_ADD=Dodaj Pjesmu
-SONG_MENU_PLAYLIST_DEL=Izbriši Pjesmu
-
-SONG_MENU_NAME_PLAYLIST_ADD=Dodaj Pjesmu
-SONG_MENU_PLAYLIST_ADD_NEW=na novu playlistu
-SONG_MENU_PLAYLIST_ADD_EXISTING=na postojeæu playlistu
-SONG_MENU_PLAYLIST_NOEXISTING=Nema playlisti.
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nova Playlista
-SONG_MENU_PLAYLIST_NEW_CREATE=Napravi
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Bez imena
-
-SONG_MENU_NAME_PLAYLIST_DEL=Stvarno obrisati?
-SONG_MENU_YES=Da
-SONG_MENU_NO=Ne
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Otvori Playlistu
-SONG_MENU_PLAYLIST_LOAD=otvori
-SONG_MENU_PLAYLIST_DELCURRENT=obriši trenutnu Playlistu
-
-SONG_MENU_NAME_PLAYLIST_DEL=Obriši Playlistu?
-
-SONG_MENU_NAME_PARTY_MAIN=Party Meni
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=iskoristi joker
-
-SONG_JUMPTO_DESC=pretraži pjesme
-SONG_JUMPTO_TYPE_DESC=Traži :
-SONG_JUMPTO_TYPE1=Sve
-SONG_JUMPTO_TYPE2=Naslov
-SONG_JUMPTO_TYPE3=Izvoðaè
-SONG_JUMPTO_SONGSFOUND=%d pjes(a)ma naðeno
-SONG_JUMPTO_NOSONGSFOUND=Niti jedna pjesma nije pronaðena.
-SONG_JUMPTO_HELP=Unesi tekst koji želiš tražiti.
-SONG_JUMPTO_CATTEXT=Traži: %s
-
-PARTY_MODE=party mod
-PARTY_DIFFICULTY=Težina
-PARTY_PLAYLIST=Playlist Mod
-PARTY_PLAYLIST_ALL=Sve pjesme
-PARTY_PLAYLIST_CATEGORY=Folder
-PARTY_PLAYLIST_PLAYLIST=Playliste
-PARTY_ROUNDS=Runde
-PARTY_TEAMS=Br. Timova
-PARTY_TEAMS_PLAYER1=Br. Igraèa - Tim1
-PARTY_TEAMS_PLAYER2=Br. Igraèa - Tim2
-PARTY_TEAMS_PLAYER3=Br. Igraèa - Tim3
-
-PARTY_LEGEND_CONTINUE=nastavi
-
-PARTY_OPTIONS_DESC=postavke za party igru
-PARTY_OPTIONS_WHEREAMI=Party Opcije
-
-PARTY_PLAYER_DESC=unesi imena timova i igraèa!
-PARTY_PLAYER_WHEREAMI=Party Imena
-PARTY_PLAYER_ENTER_NAME=unesi imena
-PARTY_PLAYER_LEGEND_CONTINUE=zapoèni party-igru
-
-PARTY_ROUND_DESC=sljed. igraèi za mikr.
-PARTY_ROUND_WHEREAMI=Party Sljed runda
-PARTY_ROUND_LEGEND_CONTINUE=zapoèni rundu
-
-PARTY_SONG_WHEREAMI=Party Odabir pjesme
-PARTY_SONG_LEGEND_CONTINUE=pjevaj
-PARTY_SONG_MENU=party meni
-
-PARTY_SCORE_DESC=bodovi zadnje runde
-PARTY_SCORE_WHEREAMI=Party Bodovi
-
-PARTY_WIN_DESC=pobjednik party igre
-PARTY_WIN_WHEREAMI=Party Pobjednik
-PARTY_WIN_LEGEND_CONTINUE=natrag na glavni meni
-
-PARTY_ROUND=Runda
-PARTY_ROUND_WINNER=Pobjednik
-PARTY_NOTPLAYEDYET=nije još odigr.
-PARTY_NOBODY=nitko ni
-NEXT_ROUND=Sljed. runda:
-
-PARTY_DISMISSED=Izbacen!
-PARTY_SCORE_WINS=%s je
-PARTY_SCORE_WINS2=pobijedio!
-
-PLUGIN_HDL_NAME=Zadrži liniju
-PLUGIN_HDL_DESC=Nemoj biti gori od pokazivaèa na 'rating' baru.
-
-PLUGIN_UNTIL5000_NAME=Do 5000
-PLUGIN_UNTIL5000_DESC=Pobjeðuje onaj tko prvi doðe do 5000 bodova.
-
-PLUGIN_DUELL_NAME=Dvoboj
-PLUGIN_DUELL_DESC=Pjevaj dvoboj do 10000 bodova.
-
-PLUGIN_TEAMDUELL_NAME=Dvoboj timova
-PLUGIN_TEAMDUELL_DESC=Dodaj mikrofon!
-
-PLUGIN_BLIND_NAME=Slijepi naèin
-PLUGIN_BLIND_DESC=Dvoboj bez gledanja nota.
-
-PLUGIN_BLIND_NOSCORE_NAME=Slijepi naèin 2
-PLUGIN_BLIND_NOSCORE_DESC=Dvoboj bez gledanja nota i bodova.
-
-PLUGIN_MORE1000_NAME=1000 Više
-PLUGIN_MORE1000_DESC=Pjevajte dok jedan od igraèa ne skupi 1000 bod više.
-
-STAT_MAIN=Statistika
-STAT_MAIN_DESC=General
-STAT_MAIN_WHEREAMI=Statistika
-
-STAT_OVERVIEW_INTRO=%0:s Statistika. \n Zadnji reset je bio %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d pjesama (%3:d sa Videom), od èega je %1:d pjesama otpjevano a %2:d nije.\n Najpopularnija pjesma je %5:s od %4:s.
-STAT_OVERVIEW_PLAYER=Od zadnjeg reseta bilo je %0:d razlièitih igraèa.\n Najbolji igraè je %1:s sa prosjekom od %2:d bodova.\n %3:s je napravio/la najveæi rezultat sa %4:d bodova.
-
-STAT_DETAIL=Statistika
-STAT_DETAIL_WHEREAMI=Detaljna statistika
-
-STAT_NEXT=Sljed. strana
-STAT_PREV=Preth. strana
-STAT_REVERSE=Obrnuti redoslijed
-STAT_PAGE=Strana %0:d od %1:d\n (%2:d od %3:d unosa)
-
-STAT_DESC_SCORES=HighScores
-STAT_DESC_SCORES_REVERSED=LowScores
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Najbolji pjevaèi
-STAT_DESC_SINGERS_REVERSED=Najgori pjevaèi
-STAT_FORMAT_SINGERS=%0:s \n Prosjeèni bodovi: %1:d
-
-STAT_DESC_SONGS=Popularne pjesme
-STAT_DESC_SONGS_REVERSED=Nepopularne pjesme
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx otpjevano
-
-STAT_DESC_BANDS=Popularni bendovi
-STAT_DESC_BANDS_REVERSED=Nepopularni bendovi
-STAT_FORMAT_BANDS=%0:s \n %1:dx otpjevano
-
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Pjesma se ne može uèitati: Datoteka nije naðena
-ERROR_CORRUPT_SONG_NO_NOTES=Pjesma se ne može uèitati: Nije naðena niti jedna nota
-ERROR_CORRUPT_SONG_NO_BREAKS=Pjesma se ne može uèitati: Nije naðen niti jedan 'linebreak'
-ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Pjesma se ne može uèitati: Greška u obradi linije %0:d
-
-MSG_ERROR_TITLE=Greška
-MSG_QUESTION_TITLE=Pitanje
-MSG_QUIT_USDX=Napustiti UltraStar?
-MSG_END_PARTY=Napustiti Party igru?
-ERROR_NO_SONGS=Nema uèitanih pjesama
-ERROR_NO_PLUGINS=Nema uèitanih pluginova
-ERROR_CORRUPT_SONG=Pjesma se ne može uèitati. \ No newline at end of file
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=UÄitavanje...
+
+SING_CHOOSE_MODE=Izaberi naÄin igre
+SING_SING=pjevaj
+SING_SING_DESC=brza igra: pjevaj solo ili duet
+
+SING_MULTI=party
+SING_MULTI_DESC=pjevaj u party mode-u
+
+SING_TOOLS=alati
+
+SING_STATS=statistika
+SING_STATS_DESC=pogledaj statistiku
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=napravi svoje pjesme
+
+SING_GAME_OPTIONS=opcije igre
+SING_GAME_OPTIONS_DESC=promijeni postavke
+
+SING_EXIT=izlaz
+SING_EXIT_DESC=izlaz iz igre
+
+SING_OPTIONS=opcije
+SING_OPTIONS_DESC=promijeni postavke
+SING_OPTIONS_WHEREAMI=Opcije
+
+SING_OPTIONS_GAME=igra
+SING_OPTIONS_GRAPHICS=video
+SING_OPTIONS_SOUND=audio
+SING_OPTIONS_LYRICS=tekstovi
+SING_OPTIONS_THEMES=teme
+SING_OPTIONS_RECORD=snimanje
+SING_OPTIONS_ADVANCED=ostalo
+SING_OPTIONS_EXIT=natrag
+
+SING_OPTIONS_GAME_WHEREAMI=Opcije Igre
+SING_OPTIONS_GAME_DESC=osnovne opcije igre
+SING_OPTIONS_GAME_PLAYERS=Br. igraÄa
+SING_OPTIONS_GAME_DIFFICULTY=Težina
+SING_OPTIONS_GAME_LANGUAGE=Jezik
+SING_OPTIONS_GAME_TABS=Tabovi
+SING_OPTIONS_GAME_SORTING=Sortiranje
+SING_OPTIONS_GAME_DEBUG=Debug
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Opcije Videa
+SING_OPTIONS_GRAPHICS_DESC=video opcije
+SING_OPTIONS_GRAPHICS_RESOLUTION=Rezolucija
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Cijeli ekran
+SING_OPTIONS_GRAPHICS_DEPTH=Dubina boja
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus linije
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=VeliÄina videa
+SING_OPTIONS_GRAPHICS_VISUALIZER=Vizualizacije
+
+SING_OPTIONS_SOUND_WHEREAMI=Opcije Zvuka
+SING_OPTIONS_SOUND_DESC=postavke zvuka
+SING_OPTIONS_SOUND_MIC_BOOST=Mic boost
+SING_OPTIONS_SOUND_CLICK_ASSIST=Pomoć klikovima
+SING_OPTIONS_SOUND_BEAT_CLICK=Klik na udarce
+SING_OPTIONS_SOUND_THRESHOLD=Threshold
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Igra za dva igraÄa
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Glasnoća prikaza
+SING_OPTIONS_SOUND_PREVIEWFADING=Fade-in vrijeme
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Microphone Playback
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Pozadinska glazba
+
+SING_OPTIONS_LYRICS_WHEREAMI=Opcije Tekstova
+SING_OPTIONS_LYRICS_DESC=postavke tekstova
+SING_OPTIONS_LYRICS_FONT=Font
+SING_OPTIONS_LYRICS_EFFECT=Efekt
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacija
+SING_OPTIONS_LYRICS_NOTELINES=Crtovlje
+
+SING_OPTIONS_THEMES_WHEREAMI=Opcije Tema
+SING_OPTIONS_THEMES_DESC=postavke tema i skinova
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Boja
+
+SING_OPTIONS_RECORD_WHEREAMI=Opcije Snimanja
+SING_OPTIONS_RECORD_DESC=postavke mikrofona
+SING_OPTIONS_RECORD_CARD=Zv. kartica
+SING_OPTIONS_RECORD_INPUT=Ulaz
+SING_OPTIONS_RECORD_CHANNEL=Kanal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Ostale Opcije
+SING_OPTIONS_ADVANCED_DESC=ostale postavke
+SING_OPTIONS_ADVANCED_EFFECTSING=Efekti kod pjevanja
+SING_OPTIONS_ADVANCED_SCREENFADE=Fade-out ekrana
+SING_OPTIONS_ADVANCED_LOADANIMATION=Anim. tijekom uÄit.
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Sigurn. pitanja
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus linije
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Zapamti broj pjev.
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Nakon pjesme
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto party meni
+
+SING_EDIT=Editor
+SING_EDIT_MENU_DESCRIPTION=napravi svoje pjesme
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=UÄitaj tekst iz midi datoteke
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=natrag
+SING_EDIT_BUTTON_CONVERT=UÄitaj
+SING_EDIT_BUTTON_EXIT=natrag
+SING_EDIT_NAVIGATE=upravljanje
+SING_EDIT_SELECT=odaberi
+SING_EDIT_EXIT=natrag
+
+SING_LEGEND_SELECT=odaberi
+SING_LEGEND_NAVIGATE=navigacija
+SING_LEGEND_CONTINUE=nastavi
+SING_LEGEND_ESC=natrag
+
+SING_PLAYER_DESC=unesi ime igraÄa
+SING_PLAYER_WHEREAMI=Imena igraÄa
+SING_PLAYER_ENTER_NAME=unesi ime
+
+SING_DIFFICULTY_DESC=odaberi težinu
+SING_DIFFICULTY_WHEREAMI=Težina
+SING_DIFFICULTY_CONTINUE=odabir pjesme
+SING_EASY=Lako
+SING_MEDIUM=Srednje
+SING_HARD=Teško
+
+SING_SONG_SELECTION_DESC=odaberi pjesmu
+SING_SONG_SELECTION_WHEREAMI=Odabir Pjesme
+SING_SONG_SELECTION_GOTO=idi na ..
+SING_SONG_SELECTION=odabir pjesme
+SING_SONG_SELECTION_MENU=meni
+SING_SONG_SELECTION_PLAYLIST=playlista
+SING_SONGS_IN_CAT=Pjesme
+PLAYLIST_CATTEXT=Playlista: %s
+
+SING_TIME=TIME
+SING_TOTAL=ukupno
+SING_MODE=pjevaj solo
+SING_NOTES=note
+SING_GOLDEN_NOTES=zlatne note
+SING_PHRASE_BONUS=bonus
+
+SING_MENU=Glavni Meni
+
+SONG_SCORE=bodovi
+SONG_SCORE_WHEREAMI=Rezultat
+
+SING_SCORE_TONE_DEAF=Bez sluha
+SING_SCORE_AMATEUR=Amater
+SING_SCORE_RISING_STAR=Zvijezda u usponu
+SING_SCORE_LEAD_SINGER=Vodeći pjevaÄ
+SING_SCORE_HIT_ARTIST=Hit Artist
+SING_SCORE_SUPERSTAR=Superstar
+SING_SCORE_ULTRASTAR=Ultrastar
+SING_SCORE_WANNABE=Wannabe
+SING_SCORE_HOPEFUL=Pun nade
+
+SING_TOP_5_CHARTS=top 5 IgraÄa
+SING_TOP_5_CHARTS_WHEREAMI=top 5
+SING_TOP_5_CHARTS_CONTINUE=odabir pjesme
+
+POPUP_PERFECT=izvanredno!
+POPUP_AWESOME=predivno!
+POPUP_GREAT=odliÄno!
+POPUP_GOOD=dobro!
+POPUP_NOTBAD=nije loše!
+POPUP_BAD=loše!
+POPUP_POOR=jadno!
+POPUP_AWFUL=grozno!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= i
+
+SONG_MENU_NAME_MAIN=Kolekcija pjesama
+SONG_MENU_PLAY=Pjevaj
+SONG_MENU_CHANGEPLAYERS=Promijeni igraÄe
+SONG_MENU_EDIT=Uredi
+SONG_MENU_MODI=Pjevaj Modi
+SONG_MENU_CANCEL=Poništi
+
+SONG_MENU_NAME_PLAYLIST=Playliste
+SONG_MENU_PLAYLIST_ADD=Dodaj Pjesmu
+SONG_MENU_PLAYLIST_DEL=Izbriši Pjesmu
+
+SONG_MENU_NAME_PLAYLIST_ADD=Dodaj Pjesmu
+SONG_MENU_PLAYLIST_ADD_NEW=na novu playlistu
+SONG_MENU_PLAYLIST_ADD_EXISTING=na postojeću playlistu
+SONG_MENU_PLAYLIST_NOEXISTING=Nema playlisti.
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nova Playlista
+SONG_MENU_PLAYLIST_NEW_CREATE=Napravi
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Bez imena
+
+SONG_MENU_NAME_PLAYLIST_DEL=Stvarno obrisati?
+SONG_MENU_YES=Da
+SONG_MENU_NO=Ne
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Otvori Playlistu
+SONG_MENU_PLAYLIST_LOAD=otvori
+SONG_MENU_PLAYLIST_DELCURRENT=obriši trenutnu Playlistu
+
+SONG_MENU_NAME_PLAYLIST_DEL=Obriši Playlistu?
+
+SONG_MENU_NAME_PARTY_MAIN=Party Meni
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=iskoristi joker
+
+SONG_JUMPTO_DESC=pretraži pjesme
+SONG_JUMPTO_TYPE_DESC=Traži :
+SONG_JUMPTO_TYPE1=Sve
+SONG_JUMPTO_TYPE2=Naslov
+SONG_JUMPTO_TYPE3=IzvoÄ‘aÄ
+SONG_JUMPTO_SONGSFOUND=%d pjes(a)ma nađeno
+SONG_JUMPTO_NOSONGSFOUND=Niti jedna pjesma nije pronađena.
+SONG_JUMPTO_HELP=Unesi tekst koji želiš tražiti.
+SONG_JUMPTO_CATTEXT=Traži: %s
+
+PARTY_MODE=party mod
+PARTY_DIFFICULTY=Težina
+PARTY_PLAYLIST=Playlist Mod
+PARTY_PLAYLIST_ALL=Sve pjesme
+PARTY_PLAYLIST_CATEGORY=Folder
+PARTY_PLAYLIST_PLAYLIST=Playliste
+PARTY_ROUNDS=Runde
+PARTY_TEAMS=Br. Timova
+PARTY_TEAMS_PLAYER1=Br. IgraÄa - Tim1
+PARTY_TEAMS_PLAYER2=Br. IgraÄa - Tim2
+PARTY_TEAMS_PLAYER3=Br. IgraÄa - Tim3
+
+PARTY_LEGEND_CONTINUE=nastavi
+
+PARTY_OPTIONS_DESC=postavke za party igru
+PARTY_OPTIONS_WHEREAMI=Party Opcije
+
+PARTY_PLAYER_DESC=unesi imena timova i igraÄa!
+PARTY_PLAYER_WHEREAMI=Party Imena
+PARTY_PLAYER_ENTER_NAME=unesi imena
+PARTY_PLAYER_LEGEND_CONTINUE=zapoÄni party-igru
+
+PARTY_ROUND_DESC=sljed. igraÄi za mikr.
+PARTY_ROUND_WHEREAMI=Party Sljed runda
+PARTY_ROUND_LEGEND_CONTINUE=zapoÄni rundu
+
+PARTY_SONG_WHEREAMI=Party Odabir pjesme
+PARTY_SONG_LEGEND_CONTINUE=pjevaj
+PARTY_SONG_MENU=party meni
+
+PARTY_SCORE_DESC=bodovi zadnje runde
+PARTY_SCORE_WHEREAMI=Party Bodovi
+
+PARTY_WIN_DESC=pobjednik party igre
+PARTY_WIN_WHEREAMI=Party Pobjednik
+PARTY_WIN_LEGEND_CONTINUE=natrag na glavni meni
+
+PARTY_ROUND=Runda
+PARTY_ROUND_WINNER=Pobjednik
+PARTY_NOTPLAYEDYET=nije još odigr.
+PARTY_NOBODY=nitko ni
+NEXT_ROUND=Sljed. runda:
+
+PARTY_DISMISSED=Izbacen!
+PARTY_SCORE_WINS=%s je
+PARTY_SCORE_WINS2=pobijedio!
+
+PLUGIN_HDL_NAME=Zadrži liniju
+PLUGIN_HDL_DESC=Nemoj biti gori od pokazivaÄa na 'rating' baru.
+
+PLUGIN_UNTIL5000_NAME=Do 5000
+PLUGIN_UNTIL5000_DESC=Pobjeđuje onaj tko prvi dođe do 5000 bodova.
+
+PLUGIN_DUELL_NAME=Dvoboj
+PLUGIN_DUELL_DESC=Pjevaj dvoboj do 10000 bodova.
+
+PLUGIN_TEAMDUELL_NAME=Dvoboj timova
+PLUGIN_TEAMDUELL_DESC=Dodaj mikrofon!
+
+PLUGIN_BLIND_NAME=Slijepi naÄin
+PLUGIN_BLIND_DESC=Dvoboj bez gledanja nota.
+
+PLUGIN_BLIND_NOSCORE_NAME=Slijepi naÄin 2
+PLUGIN_BLIND_NOSCORE_DESC=Dvoboj bez gledanja nota i bodova.
+
+PLUGIN_MORE1000_NAME=1000 Više
+PLUGIN_MORE1000_DESC=Pjevajte dok jedan od igraÄa ne skupi 1000 bod viÅ¡e.
+
+STAT_MAIN=Statistika
+STAT_MAIN_DESC=General
+STAT_MAIN_WHEREAMI=Statistika
+
+STAT_OVERVIEW_INTRO=%0:s Statistika. \n Zadnji reset je bio %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d pjesama (%3:d sa Videom), od Äega je %1:d pjesama otpjevano a %2:d nije.\n Najpopularnija pjesma je %5:s od %4:s.
+STAT_OVERVIEW_PLAYER=Od zadnjeg reseta bilo je %0:d razliÄitih igraÄa.\n Najbolji igraÄ je %1:s sa prosjekom od %2:d bodova.\n %3:s je napravio/la najveći rezultat sa %4:d bodova.
+
+STAT_DETAIL=Statistika
+STAT_DETAIL_WHEREAMI=Detaljna statistika
+
+STAT_NEXT=Sljed. strana
+STAT_PREV=Preth. strana
+STAT_REVERSE=Obrnuti redoslijed
+STAT_PAGE=Strana %0:d od %1:d\n (%2:d od %3:d unosa)
+
+STAT_DESC_SCORES=HighScores
+STAT_DESC_SCORES_REVERSED=LowScores
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Najbolji pjevaÄi
+STAT_DESC_SINGERS_REVERSED=Najgori pjevaÄi
+STAT_FORMAT_SINGERS=%0:s \n ProsjeÄni bodovi: %1:d
+
+STAT_DESC_SONGS=Popularne pjesme
+STAT_DESC_SONGS_REVERSED=Nepopularne pjesme
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx otpjevano
+
+STAT_DESC_BANDS=Popularni bendovi
+STAT_DESC_BANDS_REVERSED=Nepopularni bendovi
+STAT_FORMAT_BANDS=%0:s \n %1:dx otpjevano
+
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Pjesma se ne može uÄitati: Datoteka nije naÄ‘ena
+ERROR_CORRUPT_SONG_NO_NOTES=Pjesma se ne može uÄitati: Nije naÄ‘ena niti jedna nota
+ERROR_CORRUPT_SONG_NO_BREAKS=Pjesma se ne može uÄitati: Nije naÄ‘en niti jedan 'linebreak'
+ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Pjesma se ne može uÄitati: GreÅ¡ka u obradi linije %0:d
+
+MSG_ERROR_TITLE=Greška
+MSG_QUESTION_TITLE=Pitanje
+MSG_QUIT_USDX=Napustiti UltraStar?
+MSG_END_PARTY=Napustiti Party igru?
+ERROR_NO_SONGS=Nema uÄitanih pjesama
+ERROR_NO_PLUGINS=Nema uÄitanih pluginova
+ERROR_CORRUPT_SONG=Pjesma se ne može uÄitati. \ No newline at end of file
diff --git a/game/languages/Dutch.ini b/game/languages/Dutch.ini
index d5920218..df25337d 100644
--- a/game/languages/Dutch.ini
+++ b/game/languages/Dutch.ini
@@ -1,398 +1,398 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Laden...
-
-SING_CHOOSE_MODE=kies mode
-SING_SING=zing
-SING_SING_DESC=snel spelletje: zing een solo of duet
-
-SING_MULTI=party
-SING_MULTI_DESC=zing in party-mode
-
-SING_TOOLS=tools
-
-SING_STATS=stats
-SING_STATS_DESC=bekijk de statistieken
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=Maak je eigen liedje
-
-SING_GAME_OPTIONS=spelopties
-SING_GAME_OPTIONS_DESC=verander de spelopties
-
-SING_EXIT=Stoppen
-SING_EXIT_DESC=stop het spelletje
-
-SING_OPTIONS=opties
-SING_OPTIONS_DESC=Verander de opties
-SING_OPTIONS_WHEREAMI=Opties
-
-SING_OPTIONS_GAME=Spel
-SING_OPTIONS_GRAPHICS=graphics
-SING_OPTIONS_SOUND=Geluid
-SING_OPTIONS_LYRICS=Tekst
-SING_OPTIONS_THEMES=Thema
-SING_OPTIONS_RECORD=Opname
-SING_OPTIONS_ADVANCED=Geavanceerd
-SING_OPTIONS_EXIT=Terug
-
-SING_OPTIONS_GAME_WHEREAMI=Spel Opties
-SING_OPTIONS_GAME_DESC=Algemene spelinstellingen
-SING_OPTIONS_GAME_PLAYERS=Spelers
-SING_OPTIONS_GAME_DIFFICULTY=Moeilijkheidsgraad
-SING_OPTIONS_GAME_LANGUAGE=Taal
-SING_OPTIONS_GAME_TABS=Tabs
-SING_OPTIONS_GAME_SORTING=Sorteren
-SING_OPTIONS_GAME_DEBUG=Debug
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Grafische opties
-SING_OPTIONS_GRAPHICS_DESC=Grafische instellingen
-SING_OPTIONS_GRAPHICS_RESOLUTION=Resolutie
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullscreen
-SING_OPTIONS_GRAPHICS_DEPTH=Diepte
-SING_OPTIONS_GRAPHICS_VISUALIZER=Visualisatie
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscoop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Lijnbonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Video grootte
-
-SING_OPTIONS_SOUND_WHEREAMI=Geluidsopties
-SING_OPTIONS_SOUND_DESC=Geluidsinstellingen
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Microfoon Playback
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Achtergrond Muziek
-SING_OPTIONS_SOUND_MIC_BOOST=Microfoon boost
-SING_OPTIONS_SOUND_CLICK_ASSIST=Klik assistent
-SING_OPTIONS_SOUND_BEAT_CLICK=Beat klik
-SING_OPTIONS_SOUND_THRESHOLD=Drempelwaarde
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Twee spelers mode
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Voorbeeld volume
-SING_OPTIONS_SOUND_PREVIEWFADING=Voorbeeld Faden
-
-SING_OPTIONS_LYRICS_WHEREAMI=Tekst Opties
-SING_OPTIONS_LYRICS_DESC=Tekst instellingen
-SING_OPTIONS_LYRICS_FONT=Lettertype
-SING_OPTIONS_LYRICS_EFFECT=Effecten
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmizatie
-SING_OPTIONS_LYRICS_NOTELINES=Staafjes
-
-SING_OPTIONS_THEMES_WHEREAMI=Thema opties
-SING_OPTIONS_THEMES_DESC=Thema- en skinopties
-SING_OPTIONS_THEMES_THEME=Thema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Kleur
-
-SING_OPTIONS_RECORD_WHEREAMI=Opname opties
-SING_OPTIONS_RECORD_DESC=Microfoon instellingen
-SING_OPTIONS_RECORD_CARD=Geluidskaart
-SING_OPTIONS_RECORD_INPUT=Input
-SING_OPTIONS_RECORD_CHANNEL=Kanaal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Geavanceerde opties
-SING_OPTIONS_ADVANCED_DESC=geavanceerde instellingen
-SING_OPTIONS_ADVANCED_EFFECTSING=Zing effecten
-SING_OPTIONS_ADVANCED_SCREENFADE=Faden
-SING_OPTIONS_ADVANCED_LOADANIMATION=Laad animaties
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Veiligheidsvragen
-SING_OPTIONS_ADVANCED_LINEBONUS=Lijnbonus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Telling
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Selecties na het Liedje
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto PartyMenu
-
-SING_EDIT=Editor
-SING_EDIT_MENU_DESCRIPTION=Maak je eigen liedje
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importeer tekst van midi file
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Terug
-SING_EDIT_BUTTON_CONVERT=Importeer
-SING_EDIT_BUTTON_EXIT=Terug
-
-SING_EDIT_NAVIGATE=Navigeer
-SING_EDIT_SELECT=Selecteer
-SING_EDIT_EXIT=Terug
-
-SING_LEGEND_SELECT=Selecteer
-SING_LEGEND_NAVIGATE=Navigeer
-SING_LEGEND_CONTINUE=Ga Verder
-SING_LEGEND_ESC=Terug
-
-SING_PLAYER_DESC=Kies Namen
-SING_PLAYER_WHEREAMI=Namen
-SING_PLAYER_ENTER_NAME=Kies namen
-
-SING_DIFFICULTY_DESC=selecteer moeilijkheidsgraad
-SING_DIFFICULTY_WHEREAMI=Moeilijkheidsgraad
-SING_DIFFICULTY_CONTINUE=Ga verder
-SING_EASY=Gemakkelijk
-SING_MEDIUM=Gemiddeled
-SING_HARD=Moeilijk
-
-SING_SONG_SELECTION_DESC=Kies je liedje
-SING_SONG_SELECTION_WHEREAMI=Selecteer een liedje
-SING_SONG_SELECTION_GOTO=Ga naar
-SING_SONG_SELECTION=Liedjes Selectie
-SING_SONG_SELECTION_MENU=menu
-SING_SONG_SELECTION_PLAYLIST=playlist
-SING_SONGS_IN_CAT=Liedjes
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TIJD
-SING_TOTAL=totaal
-SING_MODE=zing solo
-SING_NOTES=noten
-SING_GOLDEN_NOTES=gouden noten
-SING_PHRASE_BONUS=lijn bonus
-
-SING_MENU=Hoofd Menu
-
-SONG_SCORE=Score
-SONG_SCORE_WHEREAMI=Score
-
-SING_SCORE_TONE_DEAF=Toondoof
-SING_SCORE_AMATEUR=Amateur
-SING_SCORE_WANNABE=Wannabe
-SING_SCORE_HOPEFUL=Hoopvol
-SING_SCORE_RISING_STAR=Opkomende Ster
-SING_SCORE_LEAD_SINGER=Hoofdzanger
-SING_SCORE_SUPERSTAR=Superster
-SING_SCORE_ULTRASTAR=ULTRASTAR
-
-SING_TOP_5_CHARTS=top 5 Spelers
-SING_TOP_5_CHARTS_WHEREAMI=top 5
-SING_TOP_5_CHARTS_CONTINUE=Ga Verder
-
-POPUP_PERFECT=perfect!
-POPUP_AWESOME=ongelooflijk!
-POPUP_GREAT=fantastisch!
-POPUP_GOOD=goed!
-POPUP_NOTBAD=niet slecht!
-POPUP_BAD=slecht!
-POPUP_POOR=zwak!
-POPUP_AWFUL=pijnlijk!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= en
-
-SONG_MENU_NAME_MAIN=Liedjes Menu
-SONG_MENU_PLAY=Zingen
-SONG_MENU_CHANGEPLAYERS=Verander de spelers
-SONG_MENU_EDIT=Bewerken
-SONG_MENU_MODI=Zing een Mode
-SONG_MENU_CANCEL=Cancel
-
-SONG_MENU_NAME_PLAYLIST=Liedjes Menu
-SONG_MENU_PLAYLIST_ADD=Voeg een liedje toe
-SONG_MENU_PLAYLIST_DEL=Verwijder Liedje
-
-SONG_MENU_NAME_PLAYLIST_ADD=Voeg een liedje toe
-SONG_MENU_PLAYLIST_ADD_NEW=aan een nieuwe Playlist
-SONG_MENU_PLAYLIST_ADD_EXISTING=aan een bestaande playlist
-SONG_MENU_PLAYLIST_NOEXISTING=Geen playlist beschikbaar
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nieuwe Playlist
-SONG_MENU_PLAYLIST_NEW_CREATE=Maak aan
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Zonder naam
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Wil je dit echt verwijderen?
-SONG_MENU_YES=Ja
-SONG_MENU_NO=Nee
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Open Playlist
-SONG_MENU_PLAYLIST_LOAD=open
-SONG_MENU_PLAYLIST_DELCURRENT=Verwijder huidige Playlist
-
-SONG_MENU_NAME_PLAYLIST_DEL=Verwijder de Playlist?
-
-SONG_MENU_NAME_PARTY_MAIN=Party Menu
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=Joker inzetten?
-
-SONG_JUMPTO_DESC=Zoek liedje
-SONG_JUMPTO_TYPE_DESC=Zoek naar:
-SONG_JUMPTO_TYPE1=Alles
-SONG_JUMPTO_TYPE2=Titel
-SONG_JUMPTO_TYPE3=Artiest
-SONG_JUMPTO_SONGSFOUND=%d Liedje(s) gevonden
-SONG_JUMPTO_NOSONGSFOUND=Niks gevonden
-SONG_JUMPTO_HELP=Typ waarnaar moet gezocht worden
-SONG_JUMPTO_CATTEXT=Zoek naar: %s
-
-PARTY_MODE=party mode
-PARTY_DIFFICULTY=Moeilijkheidsgraad
-PARTY_PLAYLIST=Playlist Mode
-PARTY_PLAYLIST_ALL=Alle liedjes
-PARTY_PLAYLIST_CATEGORY=Map
-PARTY_PLAYLIST_PLAYLIST=Playlist
-PARTY_ROUNDS=Rondes
-PARTY_TEAMS=Teams
-PARTY_TEAMS_PLAYER1=Speler Team1
-PARTY_TEAMS_PLAYER2=Speler Team2
-PARTY_TEAMS_PLAYER3=Speler Team3
-
-PARTY_LEGEND_CONTINUE=Ga Verder
-
-PARTY_OPTIONS_DESC=Instellingen voor het Partyspelletje
-PARTY_OPTIONS_WHEREAMI=Party Opties
-
-PARTY_PLAYER_DESC=Kies Speler en Teamnamen
-PARTY_PLAYER_WHEREAMI=Party Namen
-PARTY_PLAYER_ENTER_NAME=Kies de namen
-PARTY_PLAYER_LEGEND_CONTINUE=start partyspelletje
-
-PARTY_ROUND_DESC=Volgende spelers aan de Microfoon
-PARTY_ROUND_WHEREAMI=Party Volgende ronde
-PARTY_ROUND_LEGEND_CONTINUE=start de ronde
-
-PARTY_SONG_WHEREAMI=Party Song-Selectie
-PARTY_SONG_LEGEND_CONTINUE=Zing
-PARTY_SONG_MENU=partymenu
-
-PARTY_SCORE_DESC=score van de laatste ronde
-PARTY_SCORE_WHEREAMI=Partypunten
-
-PARTY_WIN_DESC=winnaar van de party-game
-PARTY_WIN_WHEREAMI=Party Winnaar
-PARTY_WIN_LEGEND_CONTINUE=Terug naar het hoofdmenu
-
-PARTY_ROUND=Ronde
-PARTY_ROUND_WINNER=Winnaar
-PARTY_NOTPLAYEDYET=Nog niet gespeeld
-PARTY_NOBODY=niemand
-NEXT_ROUND=Volgende Ronde:
-
-PARTY_DISMISSED=Uitgeschakeld!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=overwinningen!
-
-PLUGIN_HDL_NAME=Hold the Line
-PLUGIN_HDL_DESC=Zing niet slechter dan het pijltje aangeeft!
-
-PLUGIN_UNTIL5000_NAME=Tot 5000
-PLUGIN_UNTIL5000_DESC=De eerste aan 5000 wint.
-
-PLUGIN_DUELL_NAME=Duel
-PLUGIN_DUELL_DESC=Zing een duel to 10000 punten.
-
-PLUGIN_TEAMDUELL_NAME=Team Duel
-PLUGIN_TEAMDUELL_DESC=Geef de microfoon door!
-
-PLUGIN_BLIND_NAME=Blinde Mode
-PLUGIN_BLIND_DESC=Duel zonder de noten te zien.
-
-STAT_MAIN=Statistieken
-STAT_MAIN_DESC=Algemeen
-STAT_MAIN_WHEREAMI=Statistieken
-
-STAT_OVERVIEW_INTRO=%0:s Statistieken. \n Laatst gereset op %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Liedjes(%3:d met Video), waarvan %1:d al gespeeld zijn en %2:d nog niet.\n Het populairste liedje is %5:s van %4:s.
-STAT_OVERVIEW_PLAYER=Sinds de laatste reset waren er %0:d verschillende spelers.\n De beste speler is %1:s met een gemiddelde score van %2:d punten.\n %3:s had de hoogste score met %4:d punten.
-
-STAT_DETAIL=Statistieken
-STAT_DETAIL_WHEREAMI=Gedetailleerde statistieken
-
-STAT_NEXT=Volgende Pagina
-STAT_PREV=Vorige Pagina
-STAT_REVERSE=Omgekeerde Volgorde
-STAT_PAGE=Pagina %0:d van de %1:d Paginas\n (%2:d van de %3:d scores)
-
-STAT_DESC_SCORES=Topscore
-STAT_DESC_SCORES_REVERSED=Laagste scores
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Beste Spelers
-STAT_DESC_SINGERS_REVERSED=Slechtste Spelers
-STAT_FORMAT_SINGERS=%0:s \n Gemiddlede score: %1:d
-
-STAT_DESC_SONGS=Populairste liedje
-STAT_DESC_SONGS_REVERSED=Minst populaire liedjes
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx gezongen
-
-STAT_DESC_BANDS=Populairste Artiesten
-STAT_DESC_BANDS_REVERSED=Minst populaire artiesten
-STAT_FORMAT_BANDS=%0:s \n %1:dx gezongen
-
-MSG_ERROR_TITLE=Error
-MSG_QUESTION_TITLE=Vraag
-MSG_QUIT_USDX=Uit met de pret?
-MSG_END_PARTY=Stoppen met de Party?
-ERROR_NO_SONGS=Geen liedjes geladen
-ERROR_NO_PLUGINS=Geen plugins geladen
-ERROR_CORRUPT_SONG=Liedje kon niet geladen worden
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Liedje kon niet geladen worden: File niet gevonden
-ERROR_CORRUPT_SONG_NO_NOTES=Liedje kon niet geladen worden: Geen noten gevonden
-ERROR_CORRUPT_SONG_NO_BREAKS=Liedje kon niet geladen worden: Geen linebreaks gevonden
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=Laden...
+
+SING_CHOOSE_MODE=kies mode
+SING_SING=zing
+SING_SING_DESC=snel spelletje: zing een solo of duet
+
+SING_MULTI=party
+SING_MULTI_DESC=zing in party-mode
+
+SING_TOOLS=tools
+
+SING_STATS=stats
+SING_STATS_DESC=bekijk de statistieken
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=Maak je eigen liedje
+
+SING_GAME_OPTIONS=spelopties
+SING_GAME_OPTIONS_DESC=verander de spelopties
+
+SING_EXIT=Stoppen
+SING_EXIT_DESC=stop het spelletje
+
+SING_OPTIONS=opties
+SING_OPTIONS_DESC=Verander de opties
+SING_OPTIONS_WHEREAMI=Opties
+
+SING_OPTIONS_GAME=Spel
+SING_OPTIONS_GRAPHICS=graphics
+SING_OPTIONS_SOUND=Geluid
+SING_OPTIONS_LYRICS=Tekst
+SING_OPTIONS_THEMES=Thema
+SING_OPTIONS_RECORD=Opname
+SING_OPTIONS_ADVANCED=Geavanceerd
+SING_OPTIONS_EXIT=Terug
+
+SING_OPTIONS_GAME_WHEREAMI=Spel Opties
+SING_OPTIONS_GAME_DESC=Algemene spelinstellingen
+SING_OPTIONS_GAME_PLAYERS=Spelers
+SING_OPTIONS_GAME_DIFFICULTY=Moeilijkheidsgraad
+SING_OPTIONS_GAME_LANGUAGE=Taal
+SING_OPTIONS_GAME_TABS=Tabs
+SING_OPTIONS_GAME_SORTING=Sorteren
+SING_OPTIONS_GAME_DEBUG=Debug
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Grafische opties
+SING_OPTIONS_GRAPHICS_DESC=Grafische instellingen
+SING_OPTIONS_GRAPHICS_RESOLUTION=Resolutie
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullscreen
+SING_OPTIONS_GRAPHICS_DEPTH=Diepte
+SING_OPTIONS_GRAPHICS_VISUALIZER=Visualisatie
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscoop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Lijnbonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Video grootte
+
+SING_OPTIONS_SOUND_WHEREAMI=Geluidsopties
+SING_OPTIONS_SOUND_DESC=Geluidsinstellingen
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Microfoon Playback
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Achtergrond Muziek
+SING_OPTIONS_SOUND_MIC_BOOST=Microfoon boost
+SING_OPTIONS_SOUND_CLICK_ASSIST=Klik assistent
+SING_OPTIONS_SOUND_BEAT_CLICK=Beat klik
+SING_OPTIONS_SOUND_THRESHOLD=Drempelwaarde
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Twee spelers mode
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Voorbeeld volume
+SING_OPTIONS_SOUND_PREVIEWFADING=Voorbeeld Faden
+
+SING_OPTIONS_LYRICS_WHEREAMI=Tekst Opties
+SING_OPTIONS_LYRICS_DESC=Tekst instellingen
+SING_OPTIONS_LYRICS_FONT=Lettertype
+SING_OPTIONS_LYRICS_EFFECT=Effecten
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmizatie
+SING_OPTIONS_LYRICS_NOTELINES=Staafjes
+
+SING_OPTIONS_THEMES_WHEREAMI=Thema opties
+SING_OPTIONS_THEMES_DESC=Thema- en skinopties
+SING_OPTIONS_THEMES_THEME=Thema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Kleur
+
+SING_OPTIONS_RECORD_WHEREAMI=Opname opties
+SING_OPTIONS_RECORD_DESC=Microfoon instellingen
+SING_OPTIONS_RECORD_CARD=Geluidskaart
+SING_OPTIONS_RECORD_INPUT=Input
+SING_OPTIONS_RECORD_CHANNEL=Kanaal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Geavanceerde opties
+SING_OPTIONS_ADVANCED_DESC=geavanceerde instellingen
+SING_OPTIONS_ADVANCED_EFFECTSING=Zing effecten
+SING_OPTIONS_ADVANCED_SCREENFADE=Faden
+SING_OPTIONS_ADVANCED_LOADANIMATION=Laad animaties
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Veiligheidsvragen
+SING_OPTIONS_ADVANCED_LINEBONUS=Lijnbonus
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Telling
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Selecties na het Liedje
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto PartyMenu
+
+SING_EDIT=Editor
+SING_EDIT_MENU_DESCRIPTION=Maak je eigen liedje
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importeer tekst van midi file
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Terug
+SING_EDIT_BUTTON_CONVERT=Importeer
+SING_EDIT_BUTTON_EXIT=Terug
+
+SING_EDIT_NAVIGATE=Navigeer
+SING_EDIT_SELECT=Selecteer
+SING_EDIT_EXIT=Terug
+
+SING_LEGEND_SELECT=Selecteer
+SING_LEGEND_NAVIGATE=Navigeer
+SING_LEGEND_CONTINUE=Ga Verder
+SING_LEGEND_ESC=Terug
+
+SING_PLAYER_DESC=Kies Namen
+SING_PLAYER_WHEREAMI=Namen
+SING_PLAYER_ENTER_NAME=Kies namen
+
+SING_DIFFICULTY_DESC=selecteer moeilijkheidsgraad
+SING_DIFFICULTY_WHEREAMI=Moeilijkheidsgraad
+SING_DIFFICULTY_CONTINUE=Ga verder
+SING_EASY=Gemakkelijk
+SING_MEDIUM=Gemiddeled
+SING_HARD=Moeilijk
+
+SING_SONG_SELECTION_DESC=Kies je liedje
+SING_SONG_SELECTION_WHEREAMI=Selecteer een liedje
+SING_SONG_SELECTION_GOTO=Ga naar
+SING_SONG_SELECTION=Liedjes Selectie
+SING_SONG_SELECTION_MENU=menu
+SING_SONG_SELECTION_PLAYLIST=playlist
+SING_SONGS_IN_CAT=Liedjes
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TIJD
+SING_TOTAL=totaal
+SING_MODE=zing solo
+SING_NOTES=noten
+SING_GOLDEN_NOTES=gouden noten
+SING_PHRASE_BONUS=lijn bonus
+
+SING_MENU=Hoofd Menu
+
+SONG_SCORE=Score
+SONG_SCORE_WHEREAMI=Score
+
+SING_SCORE_TONE_DEAF=Toondoof
+SING_SCORE_AMATEUR=Amateur
+SING_SCORE_WANNABE=Wannabe
+SING_SCORE_HOPEFUL=Hoopvol
+SING_SCORE_RISING_STAR=Opkomende Ster
+SING_SCORE_LEAD_SINGER=Hoofdzanger
+SING_SCORE_SUPERSTAR=Superster
+SING_SCORE_ULTRASTAR=ULTRASTAR
+
+SING_TOP_5_CHARTS=top 5 Spelers
+SING_TOP_5_CHARTS_WHEREAMI=top 5
+SING_TOP_5_CHARTS_CONTINUE=Ga Verder
+
+POPUP_PERFECT=perfect!
+POPUP_AWESOME=ongelooflijk!
+POPUP_GREAT=fantastisch!
+POPUP_GOOD=goed!
+POPUP_NOTBAD=niet slecht!
+POPUP_BAD=slecht!
+POPUP_POOR=zwak!
+POPUP_AWFUL=pijnlijk!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= en
+
+SONG_MENU_NAME_MAIN=Liedjes Menu
+SONG_MENU_PLAY=Zingen
+SONG_MENU_CHANGEPLAYERS=Verander de spelers
+SONG_MENU_EDIT=Bewerken
+SONG_MENU_MODI=Zing een Mode
+SONG_MENU_CANCEL=Cancel
+
+SONG_MENU_NAME_PLAYLIST=Liedjes Menu
+SONG_MENU_PLAYLIST_ADD=Voeg een liedje toe
+SONG_MENU_PLAYLIST_DEL=Verwijder Liedje
+
+SONG_MENU_NAME_PLAYLIST_ADD=Voeg een liedje toe
+SONG_MENU_PLAYLIST_ADD_NEW=aan een nieuwe Playlist
+SONG_MENU_PLAYLIST_ADD_EXISTING=aan een bestaande playlist
+SONG_MENU_PLAYLIST_NOEXISTING=Geen playlist beschikbaar
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nieuwe Playlist
+SONG_MENU_PLAYLIST_NEW_CREATE=Maak aan
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Zonder naam
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Wil je dit echt verwijderen?
+SONG_MENU_YES=Ja
+SONG_MENU_NO=Nee
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Open Playlist
+SONG_MENU_PLAYLIST_LOAD=open
+SONG_MENU_PLAYLIST_DELCURRENT=Verwijder huidige Playlist
+
+SONG_MENU_NAME_PLAYLIST_DEL=Verwijder de Playlist?
+
+SONG_MENU_NAME_PARTY_MAIN=Party Menu
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=Joker inzetten?
+
+SONG_JUMPTO_DESC=Zoek liedje
+SONG_JUMPTO_TYPE_DESC=Zoek naar:
+SONG_JUMPTO_TYPE1=Alles
+SONG_JUMPTO_TYPE2=Titel
+SONG_JUMPTO_TYPE3=Artiest
+SONG_JUMPTO_SONGSFOUND=%d Liedje(s) gevonden
+SONG_JUMPTO_NOSONGSFOUND=Niks gevonden
+SONG_JUMPTO_HELP=Typ waarnaar moet gezocht worden
+SONG_JUMPTO_CATTEXT=Zoek naar: %s
+
+PARTY_MODE=party mode
+PARTY_DIFFICULTY=Moeilijkheidsgraad
+PARTY_PLAYLIST=Playlist Mode
+PARTY_PLAYLIST_ALL=Alle liedjes
+PARTY_PLAYLIST_CATEGORY=Map
+PARTY_PLAYLIST_PLAYLIST=Playlist
+PARTY_ROUNDS=Rondes
+PARTY_TEAMS=Teams
+PARTY_TEAMS_PLAYER1=Speler Team1
+PARTY_TEAMS_PLAYER2=Speler Team2
+PARTY_TEAMS_PLAYER3=Speler Team3
+
+PARTY_LEGEND_CONTINUE=Ga Verder
+
+PARTY_OPTIONS_DESC=Instellingen voor het Partyspelletje
+PARTY_OPTIONS_WHEREAMI=Party Opties
+
+PARTY_PLAYER_DESC=Kies Speler en Teamnamen
+PARTY_PLAYER_WHEREAMI=Party Namen
+PARTY_PLAYER_ENTER_NAME=Kies de namen
+PARTY_PLAYER_LEGEND_CONTINUE=start partyspelletje
+
+PARTY_ROUND_DESC=Volgende spelers aan de Microfoon
+PARTY_ROUND_WHEREAMI=Party Volgende ronde
+PARTY_ROUND_LEGEND_CONTINUE=start de ronde
+
+PARTY_SONG_WHEREAMI=Party Song-Selectie
+PARTY_SONG_LEGEND_CONTINUE=Zing
+PARTY_SONG_MENU=partymenu
+
+PARTY_SCORE_DESC=score van de laatste ronde
+PARTY_SCORE_WHEREAMI=Partypunten
+
+PARTY_WIN_DESC=winnaar van de party-game
+PARTY_WIN_WHEREAMI=Party Winnaar
+PARTY_WIN_LEGEND_CONTINUE=Terug naar het hoofdmenu
+
+PARTY_ROUND=Ronde
+PARTY_ROUND_WINNER=Winnaar
+PARTY_NOTPLAYEDYET=Nog niet gespeeld
+PARTY_NOBODY=niemand
+NEXT_ROUND=Volgende Ronde:
+
+PARTY_DISMISSED=Uitgeschakeld!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=overwinningen!
+
+PLUGIN_HDL_NAME=Hold the Line
+PLUGIN_HDL_DESC=Zing niet slechter dan het pijltje aangeeft!
+
+PLUGIN_UNTIL5000_NAME=Tot 5000
+PLUGIN_UNTIL5000_DESC=De eerste aan 5000 wint.
+
+PLUGIN_DUELL_NAME=Duel
+PLUGIN_DUELL_DESC=Zing een duel to 10000 punten.
+
+PLUGIN_TEAMDUELL_NAME=Team Duel
+PLUGIN_TEAMDUELL_DESC=Geef de microfoon door!
+
+PLUGIN_BLIND_NAME=Blinde Mode
+PLUGIN_BLIND_DESC=Duel zonder de noten te zien.
+
+STAT_MAIN=Statistieken
+STAT_MAIN_DESC=Algemeen
+STAT_MAIN_WHEREAMI=Statistieken
+
+STAT_OVERVIEW_INTRO=%0:s Statistieken. \n Laatst gereset op %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Liedjes(%3:d met Video), waarvan %1:d al gespeeld zijn en %2:d nog niet.\n Het populairste liedje is %5:s van %4:s.
+STAT_OVERVIEW_PLAYER=Sinds de laatste reset waren er %0:d verschillende spelers.\n De beste speler is %1:s met een gemiddelde score van %2:d punten.\n %3:s had de hoogste score met %4:d punten.
+
+STAT_DETAIL=Statistieken
+STAT_DETAIL_WHEREAMI=Gedetailleerde statistieken
+
+STAT_NEXT=Volgende Pagina
+STAT_PREV=Vorige Pagina
+STAT_REVERSE=Omgekeerde Volgorde
+STAT_PAGE=Pagina %0:d van de %1:d Paginas\n (%2:d van de %3:d scores)
+
+STAT_DESC_SCORES=Topscore
+STAT_DESC_SCORES_REVERSED=Laagste scores
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Beste Spelers
+STAT_DESC_SINGERS_REVERSED=Slechtste Spelers
+STAT_FORMAT_SINGERS=%0:s \n Gemiddlede score: %1:d
+
+STAT_DESC_SONGS=Populairste liedje
+STAT_DESC_SONGS_REVERSED=Minst populaire liedjes
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx gezongen
+
+STAT_DESC_BANDS=Populairste Artiesten
+STAT_DESC_BANDS_REVERSED=Minst populaire artiesten
+STAT_FORMAT_BANDS=%0:s \n %1:dx gezongen
+
+MSG_ERROR_TITLE=Error
+MSG_QUESTION_TITLE=Vraag
+MSG_QUIT_USDX=Uit met de pret?
+MSG_END_PARTY=Stoppen met de Party?
+ERROR_NO_SONGS=Geen liedjes geladen
+ERROR_NO_PLUGINS=Geen plugins geladen
+ERROR_CORRUPT_SONG=Liedje kon niet geladen worden
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Liedje kon niet geladen worden: File niet gevonden
+ERROR_CORRUPT_SONG_NO_NOTES=Liedje kon niet geladen worden: Geen noten gevonden
+ERROR_CORRUPT_SONG_NO_BREAKS=Liedje kon niet geladen worden: Geen linebreaks gevonden
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Liedje kon niet geladen worden: Probleem met regel %0:d \ No newline at end of file
diff --git a/game/languages/English.ini b/game/languages/English.ini
index 412f36c0..9053328e 100644
--- a/game/languages/English.ini
+++ b/game/languages/English.ini
@@ -1,4 +1,4 @@
-[Text]
+[Text]
OPTION_VALUE_CATALAN=Catalan
OPTION_VALUE_CROATIAN=Croatian
OPTION_VALUE_DUTCH=Dutch
@@ -385,10 +385,22 @@ STAT_DESC_BANDS=Most popular Bands
STAT_DESC_BANDS_REVERSED=Least popular Bands
STAT_FORMAT_BANDS=%0:s \n %1:dx Sung
+SCREENSHOT_SAVED=Screenshot saved
+SCREENSHOT_FAILED=Couldn''t save screenshot
+
+INFO_FILE_SAVED=File saved
+ERROR_SAVE_FILE_FAILED=Couldn''t save file
+ERROR_FILE_NOT_FOUND=File not found
+
+ENCODING_ERROR_ASK_FOR_UTF8=Cannot save changes in current encoding. Convert to UTF-8?
+EDITOR_ERROR_NO_TRACK_SELECTED=No track selected
+
MSG_ERROR_TITLE=Error
+MSG_INFO_TITLE=Information
MSG_QUESTION_TITLE=Question
MSG_QUIT_USDX=Really leave UltraStar?
-MSG_END_PARTY=Really end Party Mode?
+MSG_END_PARTY=Really leave Party Mode?
+
ERROR_NO_SONGS=No Songs loaded
ERROR_NO_PLUGINS=No Plugins loaded
ERROR_CORRUPT_SONG=Song could not be loaded.
diff --git a/game/languages/Euskara.ini b/game/languages/Euskara.ini
index 5bbd76cf..43d7af2f 100644
--- a/game/languages/Euskara.ini
+++ b/game/languages/Euskara.ini
@@ -1,398 +1,398 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Kargatzen...
-
-SING_CHOOSE_MODE=Aukeratu
-SING_SING=Abestu
-SING_SING_DESC=Abestu: bakarka edo binaka
-
-SING_MULTI=Taldea
-SING_MULTI_DESC=Taldean abestu
-
-SING_TOOLS=Tresnak
-
-SING_STATS=Estatistikak
-SING_STATS_DESC=Estatistikak ikusi
-
-SING_EDITOR=Editorea
-SING_EDITOR_DESC=Zure kantuak sortu
-
-SING_GAME_OPTIONS=Hobespenak
-SING_GAME_OPTIONS_DESC=Jokoaren hobespenak aldatu
-
-SING_EXIT=Irten
-SING_EXIT_DESC=Jokotik irten
-
-SING_OPTIONS=Hobespenak
-SING_OPTIONS_DESC=Aukerak aldatu
-SING_OPTIONS_WHEREAMI=Hobespenak
-
-SING_OPTIONS_GAME=Jokoa
-SING_OPTIONS_GRAPHICS=Grafikoak
-SING_OPTIONS_SOUND=Soinua
-SING_OPTIONS_LYRICS=Letrak
-SING_OPTIONS_THEMES=Gaiak
-SING_OPTIONS_RECORD=Grabazioa
-SING_OPTIONS_ADVANCED=Aurreratuak
-SING_OPTIONS_EXIT=Itzuli
-
-SING_OPTIONS_GAME_WHEREAMI=Jokoaren hobespenak
-SING_OPTIONS_GAME_DESC=Jokoaren hobespen orokorrak
-SING_OPTIONS_GAME_PLAYERS=Jokalariak
-SING_OPTIONS_GAME_DIFFICULTY=Zailtasuna
-SING_OPTIONS_GAME_LANGUAGE=Hizkuntza
-SING_OPTIONS_GAME_TABS=Etiketak
-SING_OPTIONS_GAME_SORTING=Sailkapena
-SING_OPTIONS_GAME_DEBUG=Araztu
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Grafikoen hobespenak
-SING_OPTIONS_GRAPHICS_DESC=Grafikoen hobespenak
-SING_OPTIONS_GRAPHICS_RESOLUTION=Erresoluzioa
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Pantaila osoa
-SING_OPTIONS_GRAPHICS_DEPTH=Kolore kalitatea
-SING_OPTIONS_GRAPHICS_VISUALIZER=Bistaratzeak
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osziloskopioa
-SING_OPTIONS_GRAPHICS_LINEBONUS=Lerro Bonusa
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Bideo tamaina
-
-SING_OPTIONS_SOUND_WHEREAMI=Soinu hobespenak
-SING_OPTIONS_SOUND_DESC=Soinu hobespenak
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Mikrofono playback-a
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Atzeko soinua
-SING_OPTIONS_SOUND_MIC_BOOST=Mikrofonoa indartu
-SING_OPTIONS_SOUND_CLICK_ASSIST=Noten laguntza
-SING_OPTIONS_SOUND_BEAT_CLICK=Kolpeen laguntza
-SING_OPTIONS_SOUND_THRESHOLD=Arintzea
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Bi jokalari modua
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Bolumena aurreikusi
-SING_OPTIONS_SOUND_PREVIEWFADING=Desagerpena aurreikusi
-
-SING_OPTIONS_LYRICS_WHEREAMI=Letren hobespenak
-SING_OPTIONS_LYRICS_DESC=Letren hobespenak
-SING_OPTIONS_LYRICS_FONT=Letra-mota
-SING_OPTIONS_LYRICS_EFFECT=Efektua
-SING_OPTIONS_LYRICS_SOLMIZATION=Solfeoa
-SING_OPTIONS_LYRICS_NOTELINES=Pentagramak
-
-SING_OPTIONS_THEMES_WHEREAMI=Gaien hobespenak
-SING_OPTIONS_THEMES_DESC=Gaien eta azalen hobespenak
-SING_OPTIONS_THEMES_THEME=Gaia
-SING_OPTIONS_THEMES_SKIN=Azala
-SING_OPTIONS_THEMES_COLOR=Kolorea
-
-SING_OPTIONS_RECORD_WHEREAMI=Grabazioaren hobespenak
-SING_OPTIONS_RECORD_DESC=Mikrofonoaren hobespenak
-SING_OPTIONS_RECORD_CARD=Soinu-txartela
-SING_OPTIONS_RECORD_INPUT=Sarrera
-SING_OPTIONS_RECORD_CHANNEL=Kanala
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Hobespen aurreratuak
-SING_OPTIONS_ADVANCED_DESC=Hobespen aurreratuak
-SING_OPTIONS_ADVANCED_EFFECTSING=Kantu efektuak
-SING_OPTIONS_ADVANCED_SCREENFADE=Pantaila desagertu
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animazioa kargatzerakoan
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Ziurtasun galderak
-SING_OPTIONS_ADVANCED_LINEBONUS=Lerro bonusa
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Aukeratu ondoren
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Talde menu auto
-
-SING_EDIT=Editorea
-SING_EDIT_MENU_DESCRIPTION=Zure kantuak sortu
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Testua inportatu MIDI fitxategiatik
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Itzuli
-SING_EDIT_BUTTON_CONVERT=Inportatu
-SING_EDIT_BUTTON_EXIT=Itzuli
-
-SING_EDIT_NAVIGATE=Nabigatu
-SING_EDIT_SELECT=Aukeratu
-SING_EDIT_EXIT=Itzuli
-
-SING_LEGEND_SELECT=Hautatu
-SING_LEGEND_NAVIGATE=Nabigatu
-SING_LEGEND_CONTINUE=Jarraitu
-SING_LEGEND_ESC=Itzuli
-
-SING_PLAYER_DESC=Jokalarien izenak sartu
-SING_PLAYER_WHEREAMI=Jokalarien izenak
-SING_PLAYER_ENTER_NAME=Izenak idatzi
-
-SING_DIFFICULTY_DESC=Zailtasuna aukeratu
-SING_DIFFICULTY_WHEREAMI=Zailtasuna
-SING_DIFFICULTY_CONTINUE=Abestia aukeratu
-SING_EASY=Erraza
-SING_MEDIUM=Bitartekoa
-SING_HARD=Zaila
-
-SING_SONG_SELECTION_DESC=Abestia aukeratu
-SING_SONG_SELECTION_WHEREAMI=Abestia aukeratu
-SING_SONG_SELECTION_GOTO=... joan
-SING_SONG_SELECTION=Abestia aukeratu
-SING_SONG_SELECTION_MENU=Menu
-SING_SONG_SELECTION_PLAYLIST=Zerrenda
-SING_SONGS_IN_CAT=Abestiak
-PLAYLIST_CATTEXT=Zerrenda: %s
-
-SING_TIME=Denbora
-SING_TOTAL=Guztira
-SING_MODE=Bakarka abestu
-SING_NOTES=Notak
-SING_GOLDEN_NOTES=Urrezko notak
-SING_PHRASE_BONUS=Lerro bonusa
-
-SING_MENU=Menu nagusia
-
-SONG_SCORE=Puntuazioa
-SONG_SCORE_WHEREAMI=Puntuazioa
-
-SING_SCORE_TONE_DEAF=Desafinatua
-SING_SCORE_AMATEUR=Amateur
-SING_SCORE_WANNABE=Etorkizuneko Izarra
-SING_SCORE_HOPEFUL=Hautagaia
-SING_SCORE_RISING_STAR=Hobetuz Zoaz
-SING_SCORE_LEAD_SINGER=Kantari Handia
-SING_SCORE_SUPERSTAR=SuperStar
-SING_SCORE_ULTRASTAR=UltraStar
-
-SING_TOP_5_CHARTS=5 hoberenak
-SING_TOP_5_CHARTS_WHEREAMI=5 hoberenak
-SING_TOP_5_CHARTS_CONTINUE=Abestia aukeratu
-
-POPUP_PERFECT=Bikain!
-POPUP_AWESOME=Txundigarri!
-POPUP_GREAT=Sekulakoa!
-POPUP_GOOD=Ongi!
-POPUP_NOTBAD=Ez dago gaizki!
-POPUP_BAD=Gaizki!
-POPUP_POOR=Eskas!
-POPUP_AWFUL=Penagarri!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= eta
-
-SONG_MENU_NAME_MAIN=Menua
-SONG_MENU_PLAY=Abestu
-SONG_MENU_CHANGEPLAYERS=Jokalariak aukeratu
-SONG_MENU_EDIT=Editorera bidali
-SONG_MENU_MODI=Modi bat abestu
-SONG_MENU_CANCEL=Itzuli
-
-SONG_MENU_NAME_PLAYLIST=Menua
-SONG_MENU_PLAYLIST_ADD=Zerrendara gehitu
-SONG_MENU_PLAYLIST_DEL=Zerrendatik ezabatu
-
-SONG_MENU_NAME_PLAYLIST_ADD=Abestia gehitu
-SONG_MENU_PLAYLIST_ADD_NEW=Zerrenda berrira
-SONG_MENU_PLAYLIST_ADD_EXISTING=Zerrendara
-SONG_MENU_PLAYLIST_NOEXISTING=Ez dago zerrendarik
-
-SONG_MENU_NAME_PLAYLIST_NEW=Zerrenda berria
-SONG_MENU_PLAYLIST_NEW_CREATE=Sortu
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Izengabea
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Ezabatu?
-SONG_MENU_YES=Bai
-SONG_MENU_NO=Ez
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Zerrenda ireki
-SONG_MENU_PLAYLIST_LOAD=Ireki
-SONG_MENU_PLAYLIST_DELCURRENT=Zerrenda hau ezabatu
-
-SONG_MENU_NAME_PLAYLIST_DEL=Zerrenda ezabatu?
-
-SONG_MENU_NAME_PARTY_MAIN=Talde menua
-SONG_MENU_JOKER=Komodina
-
-SONG_MENU_NAME_PARTY_JOKER=Komodina erabili
-
-SONG_JUMPTO_DESC=Bilatu
-SONG_JUMPTO_TYPE_DESC=Bilatu:
-SONG_JUMPTO_TYPE1=Guztia
-SONG_JUMPTO_TYPE2=Titulua
-SONG_JUMPTO_TYPE3=Artista
-SONG_JUMPTO_SONGSFOUND=%d kantu aurkituta
-SONG_JUMPTO_NOSONGSFOUND=Ez dago kanturik
-SONG_JUMPTO_HELP=Hitz gakoak idatzi
-SONG_JUMPTO_CATTEXT=Bilatu: %s
-
-PARTY_MODE=Taldean Abestu
-PARTY_DIFFICULTY=Zailtasuna
-PARTY_PLAYLIST=Abestiak
-PARTY_PLAYLIST_ALL=Guztiak
-PARTY_PLAYLIST_CATEGORY=Karpeta
-PARTY_PLAYLIST_PLAYLIST=Zerrenda
-PARTY_ROUNDS=Errondak
-PARTY_TEAMS=Taldeak
-PARTY_TEAMS_PLAYER1=Jokalariak 1.an
-PARTY_TEAMS_PLAYER2=Jokalariak 2.an
-PARTY_TEAMS_PLAYER3=Jokalariak 3.an
-
-PARTY_LEGEND_CONTINUE=Jarraitu
-
-PARTY_OPTIONS_DESC=Taldean jokatzeko aukerak
-PARTY_OPTIONS_WHEREAMI=Taldeko hobespenak
-
-PARTY_PLAYER_DESC=Jokalarien eta taldeen izenak
-PARTY_PLAYER_WHEREAMI=Taldeen izenak
-PARTY_PLAYER_ENTER_NAME=Izenak idatzi
-PARTY_PLAYER_LEGEND_CONTINUE=Jokoa hasi
-
-PARTY_ROUND_DESC=Hurrengoa mikrofonora
-PARTY_ROUND_WHEREAMI=Hurrengo erronda
-PARTY_ROUND_LEGEND_CONTINUE=Erronda hasi
-
-PARTY_SONG_WHEREAMI=Talde Abestia aukeratu
-PARTY_SONG_LEGEND_CONTINUE=Abestu
-PARTY_SONG_MENU=Talde menua
-
-PARTY_SCORE_DESC=Azken Errondako puntuazioa
-PARTY_SCORE_WHEREAMI=Talde puntuazioa
-
-PARTY_WIN_DESC=Talde irabazlea
-PARTY_WIN_WHEREAMI=Talde jokoaren irabazlea
-PARTY_WIN_LEGEND_CONTINUE=Menu nagusira itzuli
-
-PARTY_ROUND=Erronda
-PARTY_ROUND_WINNER=Irabazlea
-PARTY_NOTPLAYEDYET=Jokatu gabe
-PARTY_NOBODY=Inor
-NEXT_ROUND=Hurrengo erronda:
-
-PARTY_DISMISSED=Galdu duzu!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=irabazi du!
-
-PLUGIN_HDL_NAME=Eutsi goiari
-PLUGIN_HDL_DESC=Ez jaitsi markatutako puntuazio mailatik.
-
-PLUGIN_UNTIL5000_NAME=5000 arte
-PLUGIN_UNTIL5000_DESC=Azkarrena 5000 puntu lortzen irabazten du.
-
-PLUGIN_DUELL_NAME=Duelua
-PLUGIN_DUELL_DESC=Duelua 10.000 punturarte.
-
-PLUGIN_TEAMDUELL_NAME=Talde duelua
-PLUGIN_TEAMDUELL_DESC=Mikrofonoa pasa!
-
-PLUGIN_BLIND_NAME=Itsuan
-PLUGIN_BLIND_DESC=Duelua notak ikusi gabe.
-
-STAT_MAIN=Estatistikak
-STAT_MAIN_DESC=Orokorrak
-STAT_MAIN_WHEREAMI=Estatistikak
-
-STAT_OVERVIEW_INTRO=%0:s estatistikak. \n Azken aldiz ezabatutak %3:dko %2:.2daren %1:.2dan
-STAT_OVERVIEW_SONG=%0:d abesti daude (%3:d bideoarekin), hauetatik %1:d dagoeneko abestu dira, %2:d oraindik ez dira abestu.\n Gehien abestu den kantua %5:s da, %4:s-ena.
-STAT_OVERVIEW_PLAYER=Azken aldiz ezabatu zirenetik, %0:d jokalari desberdin egon dira.\n Jokalari hoberena %1:s da %2:dko batezbesteko puntuazioarekin.\n %3:s puntuaziorik altuena lortu zuen, %4:d puntu.
-
-STAT_DETAIL=Estatistikak
-STAT_DETAIL_WHEREAMI=Estatistika zehatzak
-
-STAT_NEXT=Hurrengo orria
-STAT_PREV=Aurreko orria
-STAT_REVERSE=Ordena alderanztu
-STAT_PAGE=Seite %0:d orri %1:dtik \n (%2:d sarrera %3:dtik)
-
-STAT_DESC_SCORES=Puntuazio onenak
-STAT_DESC_SCORES_REVERSED=Puntuazio txarrenak
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Jokalari onenak
-STAT_DESC_SINGERS_REVERSED=Jokalari txarrenak
-STAT_FORMAT_SINGERS=%0:s \n Batezbesteko puntuazioa: %1:d
-
-STAT_DESC_SONGS=Abesti ospetsuak
-STAT_DESC_SONGS_REVERSED=Abesti ez ospetsuak
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx aldiz abestuta
-
-STAT_DESC_BANDS=Talde ospetsuak
-STAT_DESC_BANDS_REVERSED=Talde ez ospetsuak
-STAT_FORMAT_BANDS=%0:s \n %1:dx aldiz abestuta
-
-MSG_ERROR_TITLE=Hutsa
-MSG_QUESTION_TITLE=Galdera
-MSG_QUIT_USDX=Ziur zaude irten nahi duzula?
-MSG_END_PARTY=Ziur zaude talde jokoa bukatu nahi duzula?
-ERROR_NO_SONGS=Ez dago abestirik
-ERROR_NO_PLUGINS=Ez dago pluginik
-ERROR_CORRUPT_SONG=Ezin da abestia kargatu
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Ezin da abestia kargatu: Fitxategia falta da
-ERROR_CORRUPT_SONG_NO_NOTES=Ezin da abestia kargatu: Ez daude notak
-ERROR_CORRUPT_SONG_NO_BREAKS=Ezin da abestia kargatu: Ez daude lerro jauziak
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=Kargatzen...
+
+SING_CHOOSE_MODE=Aukeratu
+SING_SING=Abestu
+SING_SING_DESC=Abestu: bakarka edo binaka
+
+SING_MULTI=Taldea
+SING_MULTI_DESC=Taldean abestu
+
+SING_TOOLS=Tresnak
+
+SING_STATS=Estatistikak
+SING_STATS_DESC=Estatistikak ikusi
+
+SING_EDITOR=Editorea
+SING_EDITOR_DESC=Zure kantuak sortu
+
+SING_GAME_OPTIONS=Hobespenak
+SING_GAME_OPTIONS_DESC=Jokoaren hobespenak aldatu
+
+SING_EXIT=Irten
+SING_EXIT_DESC=Jokotik irten
+
+SING_OPTIONS=Hobespenak
+SING_OPTIONS_DESC=Aukerak aldatu
+SING_OPTIONS_WHEREAMI=Hobespenak
+
+SING_OPTIONS_GAME=Jokoa
+SING_OPTIONS_GRAPHICS=Grafikoak
+SING_OPTIONS_SOUND=Soinua
+SING_OPTIONS_LYRICS=Letrak
+SING_OPTIONS_THEMES=Gaiak
+SING_OPTIONS_RECORD=Grabazioa
+SING_OPTIONS_ADVANCED=Aurreratuak
+SING_OPTIONS_EXIT=Itzuli
+
+SING_OPTIONS_GAME_WHEREAMI=Jokoaren hobespenak
+SING_OPTIONS_GAME_DESC=Jokoaren hobespen orokorrak
+SING_OPTIONS_GAME_PLAYERS=Jokalariak
+SING_OPTIONS_GAME_DIFFICULTY=Zailtasuna
+SING_OPTIONS_GAME_LANGUAGE=Hizkuntza
+SING_OPTIONS_GAME_TABS=Etiketak
+SING_OPTIONS_GAME_SORTING=Sailkapena
+SING_OPTIONS_GAME_DEBUG=Araztu
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Grafikoen hobespenak
+SING_OPTIONS_GRAPHICS_DESC=Grafikoen hobespenak
+SING_OPTIONS_GRAPHICS_RESOLUTION=Erresoluzioa
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Pantaila osoa
+SING_OPTIONS_GRAPHICS_DEPTH=Kolore kalitatea
+SING_OPTIONS_GRAPHICS_VISUALIZER=Bistaratzeak
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osziloskopioa
+SING_OPTIONS_GRAPHICS_LINEBONUS=Lerro Bonusa
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Bideo tamaina
+
+SING_OPTIONS_SOUND_WHEREAMI=Soinu hobespenak
+SING_OPTIONS_SOUND_DESC=Soinu hobespenak
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Mikrofono playback-a
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Atzeko soinua
+SING_OPTIONS_SOUND_MIC_BOOST=Mikrofonoa indartu
+SING_OPTIONS_SOUND_CLICK_ASSIST=Noten laguntza
+SING_OPTIONS_SOUND_BEAT_CLICK=Kolpeen laguntza
+SING_OPTIONS_SOUND_THRESHOLD=Arintzea
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Bi jokalari modua
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Bolumena aurreikusi
+SING_OPTIONS_SOUND_PREVIEWFADING=Desagerpena aurreikusi
+
+SING_OPTIONS_LYRICS_WHEREAMI=Letren hobespenak
+SING_OPTIONS_LYRICS_DESC=Letren hobespenak
+SING_OPTIONS_LYRICS_FONT=Letra-mota
+SING_OPTIONS_LYRICS_EFFECT=Efektua
+SING_OPTIONS_LYRICS_SOLMIZATION=Solfeoa
+SING_OPTIONS_LYRICS_NOTELINES=Pentagramak
+
+SING_OPTIONS_THEMES_WHEREAMI=Gaien hobespenak
+SING_OPTIONS_THEMES_DESC=Gaien eta azalen hobespenak
+SING_OPTIONS_THEMES_THEME=Gaia
+SING_OPTIONS_THEMES_SKIN=Azala
+SING_OPTIONS_THEMES_COLOR=Kolorea
+
+SING_OPTIONS_RECORD_WHEREAMI=Grabazioaren hobespenak
+SING_OPTIONS_RECORD_DESC=Mikrofonoaren hobespenak
+SING_OPTIONS_RECORD_CARD=Soinu-txartela
+SING_OPTIONS_RECORD_INPUT=Sarrera
+SING_OPTIONS_RECORD_CHANNEL=Kanala
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Hobespen aurreratuak
+SING_OPTIONS_ADVANCED_DESC=Hobespen aurreratuak
+SING_OPTIONS_ADVANCED_EFFECTSING=Kantu efektuak
+SING_OPTIONS_ADVANCED_SCREENFADE=Pantaila desagertu
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animazioa kargatzerakoan
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Ziurtasun galderak
+SING_OPTIONS_ADVANCED_LINEBONUS=Lerro bonusa
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Aukeratu ondoren
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Talde menu auto
+
+SING_EDIT=Editorea
+SING_EDIT_MENU_DESCRIPTION=Zure kantuak sortu
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Testua inportatu MIDI fitxategiatik
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Itzuli
+SING_EDIT_BUTTON_CONVERT=Inportatu
+SING_EDIT_BUTTON_EXIT=Itzuli
+
+SING_EDIT_NAVIGATE=Nabigatu
+SING_EDIT_SELECT=Aukeratu
+SING_EDIT_EXIT=Itzuli
+
+SING_LEGEND_SELECT=Hautatu
+SING_LEGEND_NAVIGATE=Nabigatu
+SING_LEGEND_CONTINUE=Jarraitu
+SING_LEGEND_ESC=Itzuli
+
+SING_PLAYER_DESC=Jokalarien izenak sartu
+SING_PLAYER_WHEREAMI=Jokalarien izenak
+SING_PLAYER_ENTER_NAME=Izenak idatzi
+
+SING_DIFFICULTY_DESC=Zailtasuna aukeratu
+SING_DIFFICULTY_WHEREAMI=Zailtasuna
+SING_DIFFICULTY_CONTINUE=Abestia aukeratu
+SING_EASY=Erraza
+SING_MEDIUM=Bitartekoa
+SING_HARD=Zaila
+
+SING_SONG_SELECTION_DESC=Abestia aukeratu
+SING_SONG_SELECTION_WHEREAMI=Abestia aukeratu
+SING_SONG_SELECTION_GOTO=... joan
+SING_SONG_SELECTION=Abestia aukeratu
+SING_SONG_SELECTION_MENU=Menu
+SING_SONG_SELECTION_PLAYLIST=Zerrenda
+SING_SONGS_IN_CAT=Abestiak
+PLAYLIST_CATTEXT=Zerrenda: %s
+
+SING_TIME=Denbora
+SING_TOTAL=Guztira
+SING_MODE=Bakarka abestu
+SING_NOTES=Notak
+SING_GOLDEN_NOTES=Urrezko notak
+SING_PHRASE_BONUS=Lerro bonusa
+
+SING_MENU=Menu nagusia
+
+SONG_SCORE=Puntuazioa
+SONG_SCORE_WHEREAMI=Puntuazioa
+
+SING_SCORE_TONE_DEAF=Desafinatua
+SING_SCORE_AMATEUR=Amateur
+SING_SCORE_WANNABE=Etorkizuneko Izarra
+SING_SCORE_HOPEFUL=Hautagaia
+SING_SCORE_RISING_STAR=Hobetuz Zoaz
+SING_SCORE_LEAD_SINGER=Kantari Handia
+SING_SCORE_SUPERSTAR=SuperStar
+SING_SCORE_ULTRASTAR=UltraStar
+
+SING_TOP_5_CHARTS=5 hoberenak
+SING_TOP_5_CHARTS_WHEREAMI=5 hoberenak
+SING_TOP_5_CHARTS_CONTINUE=Abestia aukeratu
+
+POPUP_PERFECT=Bikain!
+POPUP_AWESOME=Txundigarri!
+POPUP_GREAT=Sekulakoa!
+POPUP_GOOD=Ongi!
+POPUP_NOTBAD=Ez dago gaizki!
+POPUP_BAD=Gaizki!
+POPUP_POOR=Eskas!
+POPUP_AWFUL=Penagarri!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= eta
+
+SONG_MENU_NAME_MAIN=Menua
+SONG_MENU_PLAY=Abestu
+SONG_MENU_CHANGEPLAYERS=Jokalariak aukeratu
+SONG_MENU_EDIT=Editorera bidali
+SONG_MENU_MODI=Modi bat abestu
+SONG_MENU_CANCEL=Itzuli
+
+SONG_MENU_NAME_PLAYLIST=Menua
+SONG_MENU_PLAYLIST_ADD=Zerrendara gehitu
+SONG_MENU_PLAYLIST_DEL=Zerrendatik ezabatu
+
+SONG_MENU_NAME_PLAYLIST_ADD=Abestia gehitu
+SONG_MENU_PLAYLIST_ADD_NEW=Zerrenda berrira
+SONG_MENU_PLAYLIST_ADD_EXISTING=Zerrendara
+SONG_MENU_PLAYLIST_NOEXISTING=Ez dago zerrendarik
+
+SONG_MENU_NAME_PLAYLIST_NEW=Zerrenda berria
+SONG_MENU_PLAYLIST_NEW_CREATE=Sortu
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Izengabea
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Ezabatu?
+SONG_MENU_YES=Bai
+SONG_MENU_NO=Ez
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Zerrenda ireki
+SONG_MENU_PLAYLIST_LOAD=Ireki
+SONG_MENU_PLAYLIST_DELCURRENT=Zerrenda hau ezabatu
+
+SONG_MENU_NAME_PLAYLIST_DEL=Zerrenda ezabatu?
+
+SONG_MENU_NAME_PARTY_MAIN=Talde menua
+SONG_MENU_JOKER=Komodina
+
+SONG_MENU_NAME_PARTY_JOKER=Komodina erabili
+
+SONG_JUMPTO_DESC=Bilatu
+SONG_JUMPTO_TYPE_DESC=Bilatu:
+SONG_JUMPTO_TYPE1=Guztia
+SONG_JUMPTO_TYPE2=Titulua
+SONG_JUMPTO_TYPE3=Artista
+SONG_JUMPTO_SONGSFOUND=%d kantu aurkituta
+SONG_JUMPTO_NOSONGSFOUND=Ez dago kanturik
+SONG_JUMPTO_HELP=Hitz gakoak idatzi
+SONG_JUMPTO_CATTEXT=Bilatu: %s
+
+PARTY_MODE=Taldean Abestu
+PARTY_DIFFICULTY=Zailtasuna
+PARTY_PLAYLIST=Abestiak
+PARTY_PLAYLIST_ALL=Guztiak
+PARTY_PLAYLIST_CATEGORY=Karpeta
+PARTY_PLAYLIST_PLAYLIST=Zerrenda
+PARTY_ROUNDS=Errondak
+PARTY_TEAMS=Taldeak
+PARTY_TEAMS_PLAYER1=Jokalariak 1.an
+PARTY_TEAMS_PLAYER2=Jokalariak 2.an
+PARTY_TEAMS_PLAYER3=Jokalariak 3.an
+
+PARTY_LEGEND_CONTINUE=Jarraitu
+
+PARTY_OPTIONS_DESC=Taldean jokatzeko aukerak
+PARTY_OPTIONS_WHEREAMI=Taldeko hobespenak
+
+PARTY_PLAYER_DESC=Jokalarien eta taldeen izenak
+PARTY_PLAYER_WHEREAMI=Taldeen izenak
+PARTY_PLAYER_ENTER_NAME=Izenak idatzi
+PARTY_PLAYER_LEGEND_CONTINUE=Jokoa hasi
+
+PARTY_ROUND_DESC=Hurrengoa mikrofonora
+PARTY_ROUND_WHEREAMI=Hurrengo erronda
+PARTY_ROUND_LEGEND_CONTINUE=Erronda hasi
+
+PARTY_SONG_WHEREAMI=Talde Abestia aukeratu
+PARTY_SONG_LEGEND_CONTINUE=Abestu
+PARTY_SONG_MENU=Talde menua
+
+PARTY_SCORE_DESC=Azken Errondako puntuazioa
+PARTY_SCORE_WHEREAMI=Talde puntuazioa
+
+PARTY_WIN_DESC=Talde irabazlea
+PARTY_WIN_WHEREAMI=Talde jokoaren irabazlea
+PARTY_WIN_LEGEND_CONTINUE=Menu nagusira itzuli
+
+PARTY_ROUND=Erronda
+PARTY_ROUND_WINNER=Irabazlea
+PARTY_NOTPLAYEDYET=Jokatu gabe
+PARTY_NOBODY=Inor
+NEXT_ROUND=Hurrengo erronda:
+
+PARTY_DISMISSED=Galdu duzu!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=irabazi du!
+
+PLUGIN_HDL_NAME=Eutsi goiari
+PLUGIN_HDL_DESC=Ez jaitsi markatutako puntuazio mailatik.
+
+PLUGIN_UNTIL5000_NAME=5000 arte
+PLUGIN_UNTIL5000_DESC=Azkarrena 5000 puntu lortzen irabazten du.
+
+PLUGIN_DUELL_NAME=Duelua
+PLUGIN_DUELL_DESC=Duelua 10.000 punturarte.
+
+PLUGIN_TEAMDUELL_NAME=Talde duelua
+PLUGIN_TEAMDUELL_DESC=Mikrofonoa pasa!
+
+PLUGIN_BLIND_NAME=Itsuan
+PLUGIN_BLIND_DESC=Duelua notak ikusi gabe.
+
+STAT_MAIN=Estatistikak
+STAT_MAIN_DESC=Orokorrak
+STAT_MAIN_WHEREAMI=Estatistikak
+
+STAT_OVERVIEW_INTRO=%0:s estatistikak. \n Azken aldiz ezabatutak %3:dko %2:.2daren %1:.2dan
+STAT_OVERVIEW_SONG=%0:d abesti daude (%3:d bideoarekin), hauetatik %1:d dagoeneko abestu dira, %2:d oraindik ez dira abestu.\n Gehien abestu den kantua %5:s da, %4:s-ena.
+STAT_OVERVIEW_PLAYER=Azken aldiz ezabatu zirenetik, %0:d jokalari desberdin egon dira.\n Jokalari hoberena %1:s da %2:dko batezbesteko puntuazioarekin.\n %3:s puntuaziorik altuena lortu zuen, %4:d puntu.
+
+STAT_DETAIL=Estatistikak
+STAT_DETAIL_WHEREAMI=Estatistika zehatzak
+
+STAT_NEXT=Hurrengo orria
+STAT_PREV=Aurreko orria
+STAT_REVERSE=Ordena alderanztu
+STAT_PAGE=Seite %0:d orri %1:dtik \n (%2:d sarrera %3:dtik)
+
+STAT_DESC_SCORES=Puntuazio onenak
+STAT_DESC_SCORES_REVERSED=Puntuazio txarrenak
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Jokalari onenak
+STAT_DESC_SINGERS_REVERSED=Jokalari txarrenak
+STAT_FORMAT_SINGERS=%0:s \n Batezbesteko puntuazioa: %1:d
+
+STAT_DESC_SONGS=Abesti ospetsuak
+STAT_DESC_SONGS_REVERSED=Abesti ez ospetsuak
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx aldiz abestuta
+
+STAT_DESC_BANDS=Talde ospetsuak
+STAT_DESC_BANDS_REVERSED=Talde ez ospetsuak
+STAT_FORMAT_BANDS=%0:s \n %1:dx aldiz abestuta
+
+MSG_ERROR_TITLE=Hutsa
+MSG_QUESTION_TITLE=Galdera
+MSG_QUIT_USDX=Ziur zaude irten nahi duzula?
+MSG_END_PARTY=Ziur zaude talde jokoa bukatu nahi duzula?
+ERROR_NO_SONGS=Ez dago abestirik
+ERROR_NO_PLUGINS=Ez dago pluginik
+ERROR_CORRUPT_SONG=Ezin da abestia kargatu
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Ezin da abestia kargatu: Fitxategia falta da
+ERROR_CORRUPT_SONG_NO_NOTES=Ezin da abestia kargatu: Ez daude notak
+ERROR_CORRUPT_SONG_NO_BREAKS=Ezin da abestia kargatu: Ez daude lerro jauziak
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Ezin da abestia kargatu: Okerra %0:d lerroan \ No newline at end of file
diff --git a/game/languages/Finnish.ini b/game/languages/Finnish.ini
index 7f5c9742..defdb4f0 100644
--- a/game/languages/Finnish.ini
+++ b/game/languages/Finnish.ini
@@ -1,4 +1,4 @@
-[Text]
+[Text]
OPTION_VALUE_CATALAN=Catalan
OPTION_VALUE_CROATIAN=Croatian
OPTION_VALUE_DUTCH=Dutch
@@ -87,7 +87,7 @@ SING_MULTI_DESC=Oletko valmis joukkuetaistoon?
SING_TOOLS=asetukset
SING_STATS=tilastot
-SING_STATS_DESC=näytä tilastot
+SING_STATS_DESC=näytä tilastot
SING_EDITOR=kappale-editori
SING_EDITOR_DESC=luo omia kappaleita
@@ -104,11 +104,11 @@ SING_OPTIONS_WHEREAMI=Asetukset
SING_OPTIONS_GAME=peli
SING_OPTIONS_GRAPHICS=grafiikka
-SING_OPTIONS_SOUND=ääni
+SING_OPTIONS_SOUND=ääni
SING_OPTIONS_LYRICS=lyriikat
SING_OPTIONS_THEMES=ulkoasut
-SING_OPTIONS_RECORD=äänitys
-SING_OPTIONS_ADVANCED=lisäasetukset
+SING_OPTIONS_RECORD=äänitys
+SING_OPTIONS_ADVANCED=lisäasetukset
SING_OPTIONS_EXIT=takaisin
SING_OPTIONS_GAME_WHEREAMI=Peliasetukset
@@ -124,15 +124,15 @@ SING_OPTIONS_GRAPHICS_WHEREAMI=Grafiikka-asetukset
SING_OPTIONS_GRAPHICS_DESC=grafiikka-asetukset
SING_OPTIONS_GRAPHICS_RESOLUTION=Resoluutio
SING_OPTIONS_GRAPHICS_FULLSCREEN=Koko ruutu
-SING_OPTIONS_GRAPHICS_DEPTH=Värisyvyys
+SING_OPTIONS_GRAPHICS_DEPTH=Värisyvyys
SING_OPTIONS_GRAPHICS_VISUALIZER=Visualisointi
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Värähtelijä
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Värähtelijä
SING_OPTIONS_GRAPHICS_LINEBONUS=Viivabonukset
SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Videon koko
-SING_OPTIONS_SOUND_WHEREAMI=Ääniasetukset
-SING_OPTIONS_SOUND_DESC=ääniasetukset
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Oma ääni kuuluvissa
+SING_OPTIONS_SOUND_WHEREAMI=Ääniasetukset
+SING_OPTIONS_SOUND_DESC=ääniasetukset
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Oma ääni kuuluvissa
SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Taustamusiikki
SING_OPTIONS_SOUND_MIC_BOOST=Mikin voimakkuus
SING_OPTIONS_SOUND_CLICK_ASSIST=Klikkausapu
@@ -153,23 +153,23 @@ SING_OPTIONS_THEMES_WHEREAMI=Ulkoasu-asetukset
SING_OPTIONS_THEMES_DESC=ulkoasu-asetukset
SING_OPTIONS_THEMES_THEME=Ulkoasu
SING_OPTIONS_THEMES_SKIN=Tausta
-SING_OPTIONS_THEMES_COLOR=Väri
+SING_OPTIONS_THEMES_COLOR=Väri
-SING_OPTIONS_RECORD_WHEREAMI=Äänitys-asetukset
+SING_OPTIONS_RECORD_WHEREAMI=Äänitys-asetukset
SING_OPTIONS_RECORD_DESC=mikrofonin asetukset
-SING_OPTIONS_RECORD_CARD=Äänikortti
-SING_OPTIONS_RECORD_INPUT=Sisääntulo
+SING_OPTIONS_RECORD_CARD=Äänikortti
+SING_OPTIONS_RECORD_INPUT=Sisääntulo
SING_OPTIONS_RECORD_CHANNEL=Kanava
-SING_OPTIONS_ADVANCED_WHEREAMI=Lisäasetukset
-SING_OPTIONS_ADVANCED_DESC=lisäasetukset
+SING_OPTIONS_ADVANCED_WHEREAMI=Lisäasetukset
+SING_OPTIONS_ADVANCED_DESC=lisäasetukset
SING_OPTIONS_ADVANCED_EFFECTSING=Kappaletehosteet
SING_OPTIONS_ADVANCED_SCREENFADE=Ruudun feidaus
SING_OPTIONS_ADVANCED_LOADANIMATION=Latausanimaatio
SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Poiston vahvistus
SING_OPTIONS_ADVANCED_LINEBONUS=Rivibonus
SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Kappaleen jälkeen
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Kappaleen jälkeen
SING_OPTIONS_ADVANCED_PARTYPOPUP=Autom. bilevalikko
SING_EDIT=kappale-editori
@@ -189,9 +189,9 @@ SING_LEGEND_NAVIGATE=liiku
SING_LEGEND_CONTINUE=jatka
SING_LEGEND_ESC=takaisin
-SING_PLAYER_DESC=syötä pelaajan nimi
+SING_PLAYER_DESC=syötä pelaajan nimi
SING_PLAYER_WHEREAMI=Pelaajien nimet
-SING_PLAYER_ENTER_NAME=syötä nimi
+SING_PLAYER_ENTER_NAME=syötä nimi
SING_DIFFICULTY_DESC=valitse vaikeustaso
SING_DIFFICULTY_WHEREAMI=Vaikeustaso
@@ -210,34 +210,34 @@ SING_SONGS_IN_CAT=kappaletta
PLAYLIST_CATTEXT=Soittolista: %s
SING_TIME=KESTO
-SING_TOTAL=yhteensä
+SING_TOTAL=yhteensä
SING_MODE=laula soolo
SING_NOTES=nuotit
SING_GOLDEN_NOTES=kultanuotit
SING_PHRASE_BONUS=rivibonus
-SING_MENU=Päävalikko
+SING_MENU=Päävalikko
SONG_SCORE=kappaleen pisteet
SONG_SCORE_WHEREAMI=Pisteet
-SING_SCORE_TONE_DEAF=Sävelkorvaton
-SING_SCORE_AMATEUR=Amatööri
+SING_SCORE_TONE_DEAF=Sävelkorvaton
+SING_SCORE_AMATEUR=Amatööri
SING_SCORE_WANNABE=Wannabe
-SING_SCORE_HOPEFUL=Toiveita herättävä
-SING_SCORE_RISING_STAR=Nouseva tähti
-SING_SCORE_LEAD_SINGER=Päälaulaja
-SING_SCORE_SUPERSTAR=Supertähti
-SING_SCORE_ULTRASTAR=Ultratähti
+SING_SCORE_HOPEFUL=Toiveita herättävä
+SING_SCORE_RISING_STAR=Nouseva tähti
+SING_SCORE_LEAD_SINGER=Päälaulaja
+SING_SCORE_SUPERSTAR=Supertähti
+SING_SCORE_ULTRASTAR=Ultratähti
SING_TOP_5_CHARTS=top 5 pelaajat
SING_TOP_5_CHARTS_WHEREAMI=top 5
SING_TOP_5_CHARTS_CONTINUE=kappalevalintaan
-POPUP_PERFECT=täydellistä!
+POPUP_PERFECT=täydellistä!
POPUP_AWESOME=loistavaa!
POPUP_GREAT=mahtavaa!
-POPUP_GOOD=hyvä!
+POPUP_GOOD=hyvä!
POPUP_NOTBAD=menettelee!
POPUP_BAD=huonoa!
POPUP_POOR=heikkoa!
@@ -254,20 +254,20 @@ SONG_MENU_MODI=Laula muunneltu kappale
SONG_MENU_CANCEL=Peruuta
SONG_MENU_NAME_PLAYLIST=Kappalevalikko
-SONG_MENU_PLAYLIST_ADD=Lisää kappale
+SONG_MENU_PLAYLIST_ADD=Lisää kappale
SONG_MENU_PLAYLIST_DEL=Poista kappale
-SONG_MENU_NAME_PLAYLIST_ADD=Lisää kappale
+SONG_MENU_NAME_PLAYLIST_ADD=Lisää kappale
SONG_MENU_PLAYLIST_ADD_NEW=uuteen soittolistaan
SONG_MENU_PLAYLIST_ADD_EXISTING=luotuun soittolistaan
SONG_MENU_PLAYLIST_NOEXISTING=Soittolistaa ei saatavilla
SONG_MENU_NAME_PLAYLIST_NEW=Uusi soittolista
SONG_MENU_PLAYLIST_NEW_CREATE=Luo
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Nimetön
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Nimetön
SONG_MENU_NAME_PLAYLIST_DELITEM=Vahvista poisto?
-SONG_MENU_YES=Kyllä
+SONG_MENU_YES=Kyllä
SONG_MENU_NO=Ei
SONG_MENU_NAME_PLAYLIST_LOAD=Avaa soittolista
@@ -279,16 +279,16 @@ SONG_MENU_NAME_PLAYLIST_DEL=Poista soittolista?
SONG_MENU_NAME_PARTY_MAIN=Bilevalikko
SONG_MENU_JOKER=Jokeri
-SONG_MENU_NAME_PARTY_JOKER=käytä jokeri
+SONG_MENU_NAME_PARTY_JOKER=käytä jokeri
SONG_JUMPTO_DESC=etsi kappale
SONG_JUMPTO_TYPE_DESC=Etsi:
SONG_JUMPTO_TYPE1=Kaikki
SONG_JUMPTO_TYPE2=Nimen mukaan
SONG_JUMPTO_TYPE3=Artistin mukaan
-SONG_JUMPTO_SONGSFOUND=Löytyi %d kappaletta
-SONG_JUMPTO_NOSONGSFOUND=Kappaletta ei löytynyt
-SONG_JUMPTO_HELP=Syötä hakuteksti
+SONG_JUMPTO_SONGSFOUND=Löytyi %d kappaletta
+SONG_JUMPTO_NOSONGSFOUND=Kappaletta ei löytynyt
+SONG_JUMPTO_HELP=Syötä hakuteksti
SONG_JUMPTO_CATTEXT=Etsi: %s
PARTY_MODE=biletila
@@ -308,9 +308,9 @@ PARTY_LEGEND_CONTINUE=jatka
PARTY_OPTIONS_DESC=bilepelin asetukset
PARTY_OPTIONS_WHEREAMI=Bile-asetukset
-PARTY_PLAYER_DESC=Syötä pelaajien ja joukkueiden nimet!
+PARTY_PLAYER_DESC=Syötä pelaajien ja joukkueiden nimet!
PARTY_PLAYER_WHEREAMI=Bilepelaajien nimet
-PARTY_PLAYER_ENTER_NAME=syötä nimet
+PARTY_PLAYER_ENTER_NAME=syötä nimet
PARTY_PLAYER_LEGEND_CONTINUE=aloita bileet
PARTY_ROUND_DESC=seuraavat pelaajat mikkeihin
@@ -326,7 +326,7 @@ PARTY_SCORE_WHEREAMI=Bilepisteet
PARTY_WIN_DESC=bilepelin voittaja
PARTY_WIN_WHEREAMI=Bilepelin voittaja
-PARTY_WIN_LEGEND_CONTINUE=takaisin päävalikkoon
+PARTY_WIN_LEGEND_CONTINUE=takaisin päävalikkoon
PARTY_ROUND=Kierros
PARTY_ROUND_WINNER=Voittaja
@@ -338,28 +338,28 @@ PARTY_DISMISSED=Diskattu!
PARTY_SCORE_WINS=%s
PARTY_SCORE_WINS2=voittaa!
-PLUGIN_HDL_NAME=Pidä pintasi!
-PLUGIN_HDL_DESC=Älä putoa palkin alapuolelle.
+PLUGIN_HDL_NAME=Pidä pintasi!
+PLUGIN_HDL_DESC=Älä putoa palkin alapuolelle.
PLUGIN_UNTIL5000_NAME=Viistonnia
-PLUGIN_UNTIL5000_DESC=Ensimmäisenä 5000 pistettä saanut voittaa.
+PLUGIN_UNTIL5000_DESC=Ensimmäisenä 5000 pistettä saanut voittaa.
PLUGIN_DUELL_NAME=Kymppitonni
PLUGIN_DUELL_DESC=Kaksintaistelu 10000 pisteeseen.
PLUGIN_TEAMDUELL_NAME=Mikit kiertoon!
-PLUGIN_TEAMDUELL_DESC=Mikki kiertää joukkueen sisällä... Varaudu siis laulamaan!
+PLUGIN_TEAMDUELL_DESC=Mikki kiertää joukkueen sisällä... Varaudu siis laulamaan!
PLUGIN_BLIND_NAME=Sokkona
-PLUGIN_BLIND_DESC=Et näe nuotteja.
+PLUGIN_BLIND_DESC=Et näe nuotteja.
STAT_MAIN=Tilastot
STAT_MAIN_DESC=Yleiset
STAT_MAIN_WHEREAMI=Tilasto
STAT_OVERVIEW_INTRO=%0:s \n Pelattu viimeksi %1:.2d.%2:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d kappaletta(%3:d musiikkivideota), joista %1:d pelattu ja %2:d joita ei vielä kokeiltu.\n Suosituin kappale: %4:s :n %5:s
-STAT_OVERVIEW_PLAYER=Viimeksi %0:d eri pelaajaa,\n joista paras oli %1:s keskipisteillä %2:d pistettä.\n %3:s sai korkeimmat pisteet, %4:d pistettä.
+STAT_OVERVIEW_SONG=%0:d kappaletta(%3:d musiikkivideota), joista %1:d pelattu ja %2:d joita ei vielä kokeiltu.\n Suosituin kappale: %4:s :n %5:s
+STAT_OVERVIEW_PLAYER=Viimeksi %0:d eri pelaajaa,\n joista paras oli %1:s keskipisteillä %2:d pistettä.\n %3:s sai korkeimmat pisteet, %4:d pistettä.
STAT_DETAIL=Tilasto
STAT_DETAIL_WHEREAMI=Yksityiskohtainen tilasto
@@ -378,11 +378,11 @@ STAT_DESC_SINGERS_REVERSED=Huonoimmat laulajat
STAT_FORMAT_SINGERS=%0:s \n Keskipisteet: %1:d
STAT_DESC_SONGS=Suosituimmat biisit
-STAT_DESC_SONGS_REVERSED=Vähiten lauletut biisit
+STAT_DESC_SONGS_REVERSED=Vähiten lauletut biisit
STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx laulettu
-STAT_DESC_BANDS=Suosituimmat bändit
-STAT_DESC_BANDS_REVERSED=Vähiten lauletut bändit
+STAT_DESC_BANDS=Suosituimmat bändit
+STAT_DESC_BANDS_REVERSED=Vähiten lauletut bändit
STAT_FORMAT_BANDS=%0:s \n %1:dx laulettu
MSG_ERROR_TITLE=Virhe
@@ -390,9 +390,9 @@ MSG_QUESTION_TITLE= o_0
MSG_QUIT_USDX=Poistutaanko UltraStarista?
MSG_END_PARTY=Poistutaanko biletilasta?
ERROR_NO_SONGS=Kappaleita ei saatavilla
-ERROR_NO_PLUGINS=Lisäosia ei saatavilla
+ERROR_NO_PLUGINS=Lisäosia ei saatavilla
ERROR_CORRUPT_SONG=Kappaletta ei voi ladata.
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Kappaletta ei voi ladata: Tiedostoa ei löytynyt
-ERROR_CORRUPT_SONG_NO_NOTES=Kappaletta ei voi ladata: Nuotteja ei löytynyt
-ERROR_CORRUPT_SONG_NO_BREAKS=Kappaletta ei voi ladata: Rivikatko(j)a ei löytynyt
-ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Kappaletta ei voi ladata: Virhe txt:n rivillä %0:d \ No newline at end of file
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Kappaletta ei voi ladata: Tiedostoa ei löytynyt
+ERROR_CORRUPT_SONG_NO_NOTES=Kappaletta ei voi ladata: Nuotteja ei löytynyt
+ERROR_CORRUPT_SONG_NO_BREAKS=Kappaletta ei voi ladata: Rivikatko(j)a ei löytynyt
+ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Kappaletta ei voi ladata: Virhe txt:n rivillä %0:d \ No newline at end of file
diff --git a/game/languages/French.ini b/game/languages/French.ini
index 1f675994..5d39d51d 100644
--- a/game/languages/French.ini
+++ b/game/languages/French.ini
@@ -1,398 +1,398 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Chargement...
-
-SING_CHOOSE_MODE=Choisir un mode
-SING_SING=Solo
-SING_SING_DESC=Chanter
-
-SING_MULTI=Multi
-SING_MULTI_DESC=Chanter à plusieurs
-
-SING_TOOLS=Outils
-
-SING_STATS=Statistiques
-SING_STATS_DESC=Consulter les statistiques
-
-SING_EDITOR=Éditeur
-SING_EDITOR_DESC=Créer vos propre chansons
-
-SING_GAME_OPTIONS=Options
-SING_GAME_OPTIONS_DESC=Modifier les paramètres du jeu
-
-SING_EXIT=Quitter
-SING_EXIT_DESC=Quitter le jeu
-
-SING_OPTIONS=Options
-SING_OPTIONS_DESC=Changer les paramètres
-SING_OPTIONS_WHEREAMI=Options
-
-SING_OPTIONS_GAME=Jeu
-SING_OPTIONS_GRAPHICS=Graphismes
-SING_OPTIONS_SOUND=Audio
-SING_OPTIONS_LYRICS=Paroles
-SING_OPTIONS_THEMES=Thèmes
-SING_OPTIONS_RECORD=Micros
-SING_OPTIONS_ADVANCED=Avancé
-SING_OPTIONS_EXIT=Retour
-
-SING_OPTIONS_GAME_WHEREAMI=Options de jeu
-SING_OPTIONS_GAME_DESC=Options générales de jeu
-SING_OPTIONS_GAME_PLAYERS=Joueurs
-SING_OPTIONS_GAME_DIFFICULTY=Difficulté
-SING_OPTIONS_GAME_LANGUAGE=Langue
-SING_OPTIONS_GAME_TABS=Dossier
-SING_OPTIONS_GAME_SORTING=Tri
-SING_OPTIONS_GAME_DEBUG=Débogage
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Options graphiques
-SING_OPTIONS_GRAPHICS_DESC=Paramètres des graphismes
-SING_OPTIONS_GRAPHICS_RESOLUTION=Résolution
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Plein écran
-SING_OPTIONS_GRAPHICS_DEPTH=Couleurs
-SING_OPTIONS_GRAPHICS_VISUALIZER=Visualization
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscope
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de phrases
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Taille vidéo
-
-SING_OPTIONS_SOUND_WHEREAMI=Options de son
-SING_OPTIONS_SOUND_DESC=Paramètres de son
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Entendre le micro
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Musique de fond
-SING_OPTIONS_SOUND_MIC_BOOST=Amplif. mic.
-SING_OPTIONS_SOUND_CLICK_ASSIST=Clics d'aide
-SING_OPTIONS_SOUND_BEAT_CLICK=Métronome
-SING_OPTIONS_SOUND_THRESHOLD=Suppression bruit
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mode 2 joueurs
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Prévis. volume
-SING_OPTIONS_SOUND_PREVIEWFADING=Prévis. baisse
-
-SING_OPTIONS_LYRICS_WHEREAMI=Options de paroles
-SING_OPTIONS_LYRICS_DESC=Paramètres de paroles
-SING_OPTIONS_LYRICS_FONT=Caractères
-SING_OPTIONS_LYRICS_EFFECT=Effet
-SING_OPTIONS_LYRICS_SOLMIZATION=Afficher gamme
-SING_OPTIONS_LYRICS_NOTELINES=Barres
-
-SING_OPTIONS_THEMES_WHEREAMI=Options des thèmes
-SING_OPTIONS_THEMES_DESC=Paramètres des thèmes
-SING_OPTIONS_THEMES_THEME=Thèmes
-SING_OPTIONS_THEMES_SKIN=Aspect
-SING_OPTIONS_THEMES_COLOR=Couleur
-
-SING_OPTIONS_RECORD_WHEREAMI=Options d'enregistrement
-SING_OPTIONS_RECORD_DESC=Paramètres des micros
-SING_OPTIONS_RECORD_CARD=Carte son
-SING_OPTIONS_RECORD_INPUT=Entrée
-SING_OPTIONS_RECORD_CHANNEL=Canal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Options avancées
-SING_OPTIONS_ADVANCED_DESC=Paramètres avancés
-SING_OPTIONS_ADVANCED_EFFECTSING=Effet de chant
-SING_OPTIONS_ADVANCED_SCREENFADE=Fondu écran
-SING_OPTIONS_ADVANCED_LOADANIMATION=Charge animation
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Confirm sup.
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de phrases
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Compteur de titres chantés
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Choix ap. chanson
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Menu multi auto
-
-SING_EDIT=Éditeur
-SING_EDIT_MENU_DESCRIPTION=Créer vos propre chansons
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importer texte à une dossier de midi file
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Retour
-SING_EDIT_BUTTON_CONVERT=Importer
-SING_EDIT_BUTTON_EXIT=Retour
-
-SING_EDIT_NAVIGATE=Naviguer
-SING_EDIT_SELECT=Valider
-SING_EDIT_EXIT=Retour
-
-SING_LEGEND_SELECT=Valider
-SING_LEGEND_NAVIGATE=Naviguer
-SING_LEGEND_CONTINUE=Valider
-SING_LEGEND_ESC=Retour
-
-SING_PLAYER_DESC=Entrer le nom du joueur
-SING_PLAYER_WHEREAMI=Nom du joueur
-SING_PLAYER_ENTER_NAME=Modifier
-
-SING_DIFFICULTY_DESC=Choisir le niveau de difficulté
-SING_DIFFICULTY_WHEREAMI=Difficulté
-SING_DIFFICULTY_CONTINUE=Valider
-SING_EASY=Facile
-SING_MEDIUM=Moyen
-SING_HARD=Difficile
-
-SING_SONG_SELECTION_DESC=Choisir une chanson
-SING_SONG_SELECTION_WHEREAMI=Sélection du titre
-SING_SONG_SELECTION_GOTO=Atteindre
-SING_SONG_SELECTION=Choix de chanson
-SING_SONG_SELECTION_MENU=Menu
-SING_SONG_SELECTION_PLAYLIST=Playlist
-SING_SONGS_IN_CAT=Chansons
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TEMPS
-SING_TOTAL=Total
-SING_MODE=Mode
-SING_NOTES=Notes
-SING_GOLDEN_NOTES=Notes en or
-SING_PHRASE_BONUS=Bonus de phrases
-
-SING_MENU=Menu principal
-
-SONG_SCORE=Score
-SONG_SCORE_WHEREAMI=Points
-
-SING_SCORE_TONE_DEAF=Casserole
-SING_SCORE_AMATEUR=Amateur
-SING_SCORE_WANNABE=Aspirant chanteur
-SING_SCORE_HOPEFUL=Espoir
-SING_SCORE_RISING_STAR=Star en herbe
-SING_SCORE_LEAD_SINGER=Artiste
-SING_SCORE_SUPERSTAR=Superstar
-SING_SCORE_ULTRASTAR=Ultrastar
-
-SING_TOP_5_CHARTS=Top 5
-SING_TOP_5_CHARTS_WHEREAMI=Meilleurs joueurs
-SING_TOP_5_CHARTS_CONTINUE=Continuer
-
-POPUP_PERFECT=Parfait !
-POPUP_AWESOME=Cool !
-POPUP_GREAT=Grandiose !
-POPUP_GOOD=Bien !
-POPUP_NOTBAD=O.K. !
-POPUP_BAD=Pas terrible !
-POPUP_POOR=Mauvais !
-POPUP_AWFUL=Nul !
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= et
-
-SONG_MENU_NAME_MAIN=Menu
-SONG_MENU_PLAY=Chanter
-SONG_MENU_CHANGEPLAYERS=Changer de joueur
-SONG_MENU_EDIT=Éditeur
-SONG_MENU_MODI=Chanter un mode
-SONG_MENU_CANCEL=Annuler
-
-SONG_MENU_NAME_PLAYLIST=Menu
-SONG_MENU_PLAYLIST_ADD=Ajouter une chanson
-SONG_MENU_PLAYLIST_DEL=Supprimer la chanson
-
-SONG_MENU_NAME_PLAYLIST_ADD=Ajouter chanson
-SONG_MENU_PLAYLIST_ADD_NEW=À la nouvelle playlist
-SONG_MENU_PLAYLIST_ADD_EXISTING=Ajouter à la playlist
-SONG_MENU_PLAYLIST_NOEXISTING=Pas de playlist
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nouvelle playlist
-SONG_MENU_PLAYLIST_NEW_CREATE=Créer
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Sans-nom
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Supprimer ?
-SONG_MENU_YES=Oui
-SONG_MENU_NO=Non
-
-SONG_MENU_NAME_PLAYLIST_DEL=Supprimer la playlist ?
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Ouvrir une playlist
-SONG_MENU_PLAYLIST_LOAD=Ouvrir
-SONG_MENU_PLAYLIST_DELCURRENT=Supprimer la playlist actuel
-
-SONG_MENU_NAME_PARTY_MAIN=Menu
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=Joker
-
-SONG_JUMPTO_DESC=Rechercher
-SONG_JUMPTO_TYPE_DESC=Recherche :
-SONG_JUMPTO_TYPE1=Tout
-SONG_JUMPTO_TYPE2=Titre
-SONG_JUMPTO_TYPE3=Artiste
-SONG_JUMPTO_SONGSFOUND=%d Chanson(s) trouvée(s)
-SONG_JUMPTO_NOSONGSFOUND=Aucune chanson trouvée
-SONG_JUMPTO_HELP=Entrer le texte à rechercher
-SONG_JUMPTO_CATTEXT=Recherche: %s
-
-PARTY_MODE=Mode multi
-PARTY_DIFFICULTY=Difficulté
-PARTY_PLAYLIST=Playlist
-PARTY_PLAYLIST_ALL=Toutes les chansons
-PARTY_PLAYLIST_CATEGORY=Dossier
-PARTY_PLAYLIST_PLAYLIST=Playlist
-PARTY_ROUNDS=Nbre manches
-PARTY_TEAMS=Nbre équipes
-PARTY_TEAMS_PLAYER1=Joueur(s) équipe 1
-PARTY_TEAMS_PLAYER2=Joueur(s) équipe 2
-PARTY_TEAMS_PLAYER3=Joueur(s) équipe 3
-
-PARTY_LEGEND_CONTINUE=Suivant
-
-PARTY_OPTIONS_DESC=Paramètres du mode multi
-PARTY_OPTIONS_WHEREAMI=Options du mode multi
-
-PARTY_PLAYER_DESC=Entrer le nom des équipes et des joueurs
-PARTY_PLAYER_WHEREAMI=Mode multi: Equipes
-PARTY_PLAYER_ENTER_NAME=Modifier
-PARTY_PLAYER_LEGEND_CONTINUE=Valider
-
-PARTY_ROUND_DESC=Joueurs suivants à vos micros !
-PARTY_ROUND_WHEREAMI=Mode multi: Manche suivante
-PARTY_ROUND_LEGEND_CONTINUE=Commencer
-
-PARTY_SONG_WHEREAMI=Mode multi: Choix de la chanson
-PARTY_SONG_LEGEND_CONTINUE=Chanter
-PARTY_SONG_MENU=Menu
-
-PARTY_SCORE_DESC=Score de la manche
-PARTY_SCORE_WHEREAMI=Mode multi: Score
-
-PARTY_WIN_DESC=Gagnant de la partie
-PARTY_WIN_WHEREAMI=Mode multi: Gagnant
-PARTY_WIN_LEGEND_CONTINUE=Retour au menu principal
-
-PARTY_ROUND=Manche
-PARTY_ROUND_WINNER=Gagnant
-PARTY_NOTPLAYEDYET=-
-PARTY_NOBODY=Personne ne
-NEXT_ROUND=Manche suivante:
-
-PARTY_DISMISSED=Rétrogradé
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=l'emporte !
-
-PLUGIN_HDL_NAME=Tiens la barre
-PLUGIN_HDL_DESC=Maintiens la jauge dans le secteur indiqué
-
-PLUGIN_UNTIL5000_NAME=A 5000
-PLUGIN_UNTIL5000_DESC=Le 1er qui atteint 5000 points remporte la manche
-
-PLUGIN_DUELL_NAME=Duel
-PLUGIN_DUELL_DESC=Le meilleur score remporte la manche
-
-PLUGIN_TEAMDUELL_NAME=Duel par équipe
-PLUGIN_TEAMDUELL_DESC=Passes le micro!
-
-PLUGIN_BLIND_NAME=A l'aveugle
-PLUGIN_BLIND_DESC=Obtiens le meilleur score sans regarder l'écran.
-
-STAT_MAIN=Statistiques
-STAT_MAIN_DESC=Général
-STAT_MAIN_WHEREAMI=Statistiques
-
-STAT_OVERVIEW_INTRO=Statistiques d'%0:s \n Dernière réinitialisation le %1:.2d.%2:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d chansons (%3:d avec vidéo)\n%1:d ont déjà été chantées une fois, %2:d pas encore. \n\n La chanson la plus chantée est %5:s de %4:s.
-STAT_OVERVIEW_PLAYER=%0:d joueurs différents ont chantés depuis la dernière réinitialisation . \n\n Le meilleur joueur est %1:s avec %2:d points. \n Meilleur score, %4:d, atteint par %3:s.
-
-STAT_DETAIL=Statistiques
-STAT_DETAIL_WHEREAMI=Statistiques détaillées
-
-STAT_NEXT=Page suiv.
-STAT_PREV=Page préc.
-STAT_REVERSE=Inverser
-STAT_PAGE=Page %0:d de %1:d \n (%2:d entrées sur %3:d)
-
-STAT_DESC_SCORES=Score
-STAT_DESC_SCORES_REVERSED=Pires scores
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Chanteurs
-STAT_DESC_SINGERS_REVERSED=Pires chanteurs
-STAT_FORMAT_SINGERS=%0:s \n Score moyen: %1:d
-
-STAT_DESC_SONGS=Chansons
-STAT_DESC_SONGS_REVERSED=Chansons impopulaires
-STAT_FORMAT_SONGS=%0:s - %1:s \n Chanté %2:dx
-
-STAT_DESC_BANDS=Artistes
-STAT_DESC_BANDS_REVERSED=Artistes impopulaires
-STAT_FORMAT_BANDS=%0:s \n Chansons chantées: %1:d
-
-MSG_ERROR_TITLE=Erreur
-MSG_QUESTION_TITLE=Confirmation
-MSG_QUIT_USDX=Quitter le jeu ?
-MSG_END_PARTY=Quitter la partie ?
-ERROR_NO_SONGS=Aucune chanson.
-ERROR_NO_PLUGINS=Aucun plugin.
-ERROR_CORRUPT_SONG=Impossible de charger la chanson.
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Chargement impossible: Fichier non trouvé
-ERROR_CORRUPT_SONG_NO_NOTES=Chargement impossible: Pas de partition trouvée
-ERROR_CORRUPT_SONG_NO_BREAKS=Chargement impossible: Saut de ligne introuvable
-ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Chargement impossible: Erreur analyseur à la ligne %0:d \ No newline at end of file
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=Chargement...
+
+SING_CHOOSE_MODE=Choisir un mode
+SING_SING=Solo
+SING_SING_DESC=Chanter
+
+SING_MULTI=Multi
+SING_MULTI_DESC=Chanter à plusieurs
+
+SING_TOOLS=Outils
+
+SING_STATS=Statistiques
+SING_STATS_DESC=Consulter les statistiques
+
+SING_EDITOR=Éditeur
+SING_EDITOR_DESC=Créer vos propre chansons
+
+SING_GAME_OPTIONS=Options
+SING_GAME_OPTIONS_DESC=Modifier les paramètres du jeu
+
+SING_EXIT=Quitter
+SING_EXIT_DESC=Quitter le jeu
+
+SING_OPTIONS=Options
+SING_OPTIONS_DESC=Changer les paramètres
+SING_OPTIONS_WHEREAMI=Options
+
+SING_OPTIONS_GAME=Jeu
+SING_OPTIONS_GRAPHICS=Graphismes
+SING_OPTIONS_SOUND=Audio
+SING_OPTIONS_LYRICS=Paroles
+SING_OPTIONS_THEMES=Thèmes
+SING_OPTIONS_RECORD=Micros
+SING_OPTIONS_ADVANCED=Avancé
+SING_OPTIONS_EXIT=Retour
+
+SING_OPTIONS_GAME_WHEREAMI=Options de jeu
+SING_OPTIONS_GAME_DESC=Options générales de jeu
+SING_OPTIONS_GAME_PLAYERS=Joueurs
+SING_OPTIONS_GAME_DIFFICULTY=Difficulté
+SING_OPTIONS_GAME_LANGUAGE=Langue
+SING_OPTIONS_GAME_TABS=Dossier
+SING_OPTIONS_GAME_SORTING=Tri
+SING_OPTIONS_GAME_DEBUG=Débogage
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Options graphiques
+SING_OPTIONS_GRAPHICS_DESC=Paramètres des graphismes
+SING_OPTIONS_GRAPHICS_RESOLUTION=Résolution
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Plein écran
+SING_OPTIONS_GRAPHICS_DEPTH=Couleurs
+SING_OPTIONS_GRAPHICS_VISUALIZER=Visualization
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscope
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de phrases
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Taille vidéo
+
+SING_OPTIONS_SOUND_WHEREAMI=Options de son
+SING_OPTIONS_SOUND_DESC=Paramètres de son
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Entendre le micro
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Musique de fond
+SING_OPTIONS_SOUND_MIC_BOOST=Amplif. mic.
+SING_OPTIONS_SOUND_CLICK_ASSIST=Clics d'aide
+SING_OPTIONS_SOUND_BEAT_CLICK=Métronome
+SING_OPTIONS_SOUND_THRESHOLD=Suppression bruit
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mode 2 joueurs
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Prévis. volume
+SING_OPTIONS_SOUND_PREVIEWFADING=Prévis. baisse
+
+SING_OPTIONS_LYRICS_WHEREAMI=Options de paroles
+SING_OPTIONS_LYRICS_DESC=Paramètres de paroles
+SING_OPTIONS_LYRICS_FONT=Caractères
+SING_OPTIONS_LYRICS_EFFECT=Effet
+SING_OPTIONS_LYRICS_SOLMIZATION=Afficher gamme
+SING_OPTIONS_LYRICS_NOTELINES=Barres
+
+SING_OPTIONS_THEMES_WHEREAMI=Options des thèmes
+SING_OPTIONS_THEMES_DESC=Paramètres des thèmes
+SING_OPTIONS_THEMES_THEME=Thèmes
+SING_OPTIONS_THEMES_SKIN=Aspect
+SING_OPTIONS_THEMES_COLOR=Couleur
+
+SING_OPTIONS_RECORD_WHEREAMI=Options d'enregistrement
+SING_OPTIONS_RECORD_DESC=Paramètres des micros
+SING_OPTIONS_RECORD_CARD=Carte son
+SING_OPTIONS_RECORD_INPUT=Entrée
+SING_OPTIONS_RECORD_CHANNEL=Canal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Options avancées
+SING_OPTIONS_ADVANCED_DESC=Paramètres avancés
+SING_OPTIONS_ADVANCED_EFFECTSING=Effet de chant
+SING_OPTIONS_ADVANCED_SCREENFADE=Fondu écran
+SING_OPTIONS_ADVANCED_LOADANIMATION=Charge animation
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Confirm sup.
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de phrases
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Compteur de titres chantés
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Choix ap. chanson
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Menu multi auto
+
+SING_EDIT=Éditeur
+SING_EDIT_MENU_DESCRIPTION=Créer vos propre chansons
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importer texte à une dossier de midi file
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Retour
+SING_EDIT_BUTTON_CONVERT=Importer
+SING_EDIT_BUTTON_EXIT=Retour
+
+SING_EDIT_NAVIGATE=Naviguer
+SING_EDIT_SELECT=Valider
+SING_EDIT_EXIT=Retour
+
+SING_LEGEND_SELECT=Valider
+SING_LEGEND_NAVIGATE=Naviguer
+SING_LEGEND_CONTINUE=Valider
+SING_LEGEND_ESC=Retour
+
+SING_PLAYER_DESC=Entrer le nom du joueur
+SING_PLAYER_WHEREAMI=Nom du joueur
+SING_PLAYER_ENTER_NAME=Modifier
+
+SING_DIFFICULTY_DESC=Choisir le niveau de difficulté
+SING_DIFFICULTY_WHEREAMI=Difficulté
+SING_DIFFICULTY_CONTINUE=Valider
+SING_EASY=Facile
+SING_MEDIUM=Moyen
+SING_HARD=Difficile
+
+SING_SONG_SELECTION_DESC=Choisir une chanson
+SING_SONG_SELECTION_WHEREAMI=Sélection du titre
+SING_SONG_SELECTION_GOTO=Atteindre
+SING_SONG_SELECTION=Choix de chanson
+SING_SONG_SELECTION_MENU=Menu
+SING_SONG_SELECTION_PLAYLIST=Playlist
+SING_SONGS_IN_CAT=Chansons
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TEMPS
+SING_TOTAL=Total
+SING_MODE=Mode
+SING_NOTES=Notes
+SING_GOLDEN_NOTES=Notes en or
+SING_PHRASE_BONUS=Bonus de phrases
+
+SING_MENU=Menu principal
+
+SONG_SCORE=Score
+SONG_SCORE_WHEREAMI=Points
+
+SING_SCORE_TONE_DEAF=Casserole
+SING_SCORE_AMATEUR=Amateur
+SING_SCORE_WANNABE=Aspirant chanteur
+SING_SCORE_HOPEFUL=Espoir
+SING_SCORE_RISING_STAR=Star en herbe
+SING_SCORE_LEAD_SINGER=Artiste
+SING_SCORE_SUPERSTAR=Superstar
+SING_SCORE_ULTRASTAR=Ultrastar
+
+SING_TOP_5_CHARTS=Top 5
+SING_TOP_5_CHARTS_WHEREAMI=Meilleurs joueurs
+SING_TOP_5_CHARTS_CONTINUE=Continuer
+
+POPUP_PERFECT=Parfait !
+POPUP_AWESOME=Cool !
+POPUP_GREAT=Grandiose !
+POPUP_GOOD=Bien !
+POPUP_NOTBAD=O.K. !
+POPUP_BAD=Pas terrible !
+POPUP_POOR=Mauvais !
+POPUP_AWFUL=Nul !
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= et
+
+SONG_MENU_NAME_MAIN=Menu
+SONG_MENU_PLAY=Chanter
+SONG_MENU_CHANGEPLAYERS=Changer de joueur
+SONG_MENU_EDIT=Éditeur
+SONG_MENU_MODI=Chanter un mode
+SONG_MENU_CANCEL=Annuler
+
+SONG_MENU_NAME_PLAYLIST=Menu
+SONG_MENU_PLAYLIST_ADD=Ajouter une chanson
+SONG_MENU_PLAYLIST_DEL=Supprimer la chanson
+
+SONG_MENU_NAME_PLAYLIST_ADD=Ajouter chanson
+SONG_MENU_PLAYLIST_ADD_NEW=À la nouvelle playlist
+SONG_MENU_PLAYLIST_ADD_EXISTING=Ajouter à la playlist
+SONG_MENU_PLAYLIST_NOEXISTING=Pas de playlist
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nouvelle playlist
+SONG_MENU_PLAYLIST_NEW_CREATE=Créer
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Sans-nom
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Supprimer ?
+SONG_MENU_YES=Oui
+SONG_MENU_NO=Non
+
+SONG_MENU_NAME_PLAYLIST_DEL=Supprimer la playlist ?
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Ouvrir une playlist
+SONG_MENU_PLAYLIST_LOAD=Ouvrir
+SONG_MENU_PLAYLIST_DELCURRENT=Supprimer la playlist actuel
+
+SONG_MENU_NAME_PARTY_MAIN=Menu
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=Joker
+
+SONG_JUMPTO_DESC=Rechercher
+SONG_JUMPTO_TYPE_DESC=Recherche :
+SONG_JUMPTO_TYPE1=Tout
+SONG_JUMPTO_TYPE2=Titre
+SONG_JUMPTO_TYPE3=Artiste
+SONG_JUMPTO_SONGSFOUND=%d Chanson(s) trouvée(s)
+SONG_JUMPTO_NOSONGSFOUND=Aucune chanson trouvée
+SONG_JUMPTO_HELP=Entrer le texte à rechercher
+SONG_JUMPTO_CATTEXT=Recherche: %s
+
+PARTY_MODE=Mode multi
+PARTY_DIFFICULTY=Difficulté
+PARTY_PLAYLIST=Playlist
+PARTY_PLAYLIST_ALL=Toutes les chansons
+PARTY_PLAYLIST_CATEGORY=Dossier
+PARTY_PLAYLIST_PLAYLIST=Playlist
+PARTY_ROUNDS=Nbre manches
+PARTY_TEAMS=Nbre équipes
+PARTY_TEAMS_PLAYER1=Joueur(s) équipe 1
+PARTY_TEAMS_PLAYER2=Joueur(s) équipe 2
+PARTY_TEAMS_PLAYER3=Joueur(s) équipe 3
+
+PARTY_LEGEND_CONTINUE=Suivant
+
+PARTY_OPTIONS_DESC=Paramètres du mode multi
+PARTY_OPTIONS_WHEREAMI=Options du mode multi
+
+PARTY_PLAYER_DESC=Entrer le nom des équipes et des joueurs
+PARTY_PLAYER_WHEREAMI=Mode multi: Equipes
+PARTY_PLAYER_ENTER_NAME=Modifier
+PARTY_PLAYER_LEGEND_CONTINUE=Valider
+
+PARTY_ROUND_DESC=Joueurs suivants à vos micros !
+PARTY_ROUND_WHEREAMI=Mode multi: Manche suivante
+PARTY_ROUND_LEGEND_CONTINUE=Commencer
+
+PARTY_SONG_WHEREAMI=Mode multi: Choix de la chanson
+PARTY_SONG_LEGEND_CONTINUE=Chanter
+PARTY_SONG_MENU=Menu
+
+PARTY_SCORE_DESC=Score de la manche
+PARTY_SCORE_WHEREAMI=Mode multi: Score
+
+PARTY_WIN_DESC=Gagnant de la partie
+PARTY_WIN_WHEREAMI=Mode multi: Gagnant
+PARTY_WIN_LEGEND_CONTINUE=Retour au menu principal
+
+PARTY_ROUND=Manche
+PARTY_ROUND_WINNER=Gagnant
+PARTY_NOTPLAYEDYET=-
+PARTY_NOBODY=Personne ne
+NEXT_ROUND=Manche suivante:
+
+PARTY_DISMISSED=Rétrogradé
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=l'emporte !
+
+PLUGIN_HDL_NAME=Tiens la barre
+PLUGIN_HDL_DESC=Maintiens la jauge dans le secteur indiqué
+
+PLUGIN_UNTIL5000_NAME=A 5000
+PLUGIN_UNTIL5000_DESC=Le 1er qui atteint 5000 points remporte la manche
+
+PLUGIN_DUELL_NAME=Duel
+PLUGIN_DUELL_DESC=Le meilleur score remporte la manche
+
+PLUGIN_TEAMDUELL_NAME=Duel par équipe
+PLUGIN_TEAMDUELL_DESC=Passes le micro!
+
+PLUGIN_BLIND_NAME=A l'aveugle
+PLUGIN_BLIND_DESC=Obtiens le meilleur score sans regarder l'écran.
+
+STAT_MAIN=Statistiques
+STAT_MAIN_DESC=Général
+STAT_MAIN_WHEREAMI=Statistiques
+
+STAT_OVERVIEW_INTRO=Statistiques d'%0:s \n Dernière réinitialisation le %1:.2d.%2:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d chansons (%3:d avec vidéo)\n%1:d ont déjà été chantées une fois, %2:d pas encore. \n\n La chanson la plus chantée est %5:s de %4:s.
+STAT_OVERVIEW_PLAYER=%0:d joueurs différents ont chantés depuis la dernière réinitialisation . \n\n Le meilleur joueur est %1:s avec %2:d points. \n Meilleur score, %4:d, atteint par %3:s.
+
+STAT_DETAIL=Statistiques
+STAT_DETAIL_WHEREAMI=Statistiques détaillées
+
+STAT_NEXT=Page suiv.
+STAT_PREV=Page préc.
+STAT_REVERSE=Inverser
+STAT_PAGE=Page %0:d de %1:d \n (%2:d entrées sur %3:d)
+
+STAT_DESC_SCORES=Score
+STAT_DESC_SCORES_REVERSED=Pires scores
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Chanteurs
+STAT_DESC_SINGERS_REVERSED=Pires chanteurs
+STAT_FORMAT_SINGERS=%0:s \n Score moyen: %1:d
+
+STAT_DESC_SONGS=Chansons
+STAT_DESC_SONGS_REVERSED=Chansons impopulaires
+STAT_FORMAT_SONGS=%0:s - %1:s \n Chanté %2:dx
+
+STAT_DESC_BANDS=Artistes
+STAT_DESC_BANDS_REVERSED=Artistes impopulaires
+STAT_FORMAT_BANDS=%0:s \n Chansons chantées: %1:d
+
+MSG_ERROR_TITLE=Erreur
+MSG_QUESTION_TITLE=Confirmation
+MSG_QUIT_USDX=Quitter le jeu ?
+MSG_END_PARTY=Quitter la partie ?
+ERROR_NO_SONGS=Aucune chanson.
+ERROR_NO_PLUGINS=Aucun plugin.
+ERROR_CORRUPT_SONG=Impossible de charger la chanson.
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Chargement impossible: Fichier non trouvé
+ERROR_CORRUPT_SONG_NO_NOTES=Chargement impossible: Pas de partition trouvée
+ERROR_CORRUPT_SONG_NO_BREAKS=Chargement impossible: Saut de ligne introuvable
+ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Chargement impossible: Erreur analyseur à la ligne %0:d \ No newline at end of file
diff --git a/game/languages/German.ini b/game/languages/German.ini
index a97732b5..7b29c494 100644
--- a/game/languages/German.ini
+++ b/game/languages/German.ini
@@ -1,11 +1,11 @@
-[Text]
+[Text]
OPTION_VALUE_CATALAN=Katalanisch
OPTION_VALUE_CROATIAN=Kroatisch
-OPTION_VALUE_DUTCH=Niederländisch
+OPTION_VALUE_DUTCH=Niederländisch
OPTION_VALUE_ENGLISH=Englisch
OPTION_VALUE_EUSKARA=Baskisch
OPTION_VALUE_FINNISH=Finnisch
-OPTION_VALUE_FRENCH=Französisch
+OPTION_VALUE_FRENCH=Französisch
OPTION_VALUE_GERMAN=Deutsch
OPTION_VALUE_GREEK=Griechisch
OPTION_VALUE_ITALIAN=Italienisch
@@ -27,9 +27,9 @@ OPTION_VALUE_GENRE=Genre
OPTION_VALUE_LANGUAGE=Sprache
OPTION_VALUE_FOLDER=Ordner
OPTION_VALUE_TITLE=Titel
-OPTION_VALUE_ARTIST=Künstler
+OPTION_VALUE_ARTIST=Künstler
OPTION_VALUE_TITLE2=Titel2
-OPTION_VALUE_ARTIST2=Künstler2
+OPTION_VALUE_ARTIST2=Künstler2
OPTION_VALUE_WHENNOVIDEO=Wenn kein Video
@@ -49,17 +49,17 @@ OPTION_VALUE_OLINE1=OLine1
OPTION_VALUE_OLINE2=OLine2
OPTION_VALUE_SIMPLE=Einfach
-OPTION_VALUE_ZOOM=Vergrössern
+OPTION_VALUE_ZOOM=Vergrössern
OPTION_VALUE_SLIDE=Rutschen
OPTION_VALUE_BALL=Ball
OPTION_VALUE_SHIFT=Schieben
-OPTION_VALUE_EURO=Europäisch
+OPTION_VALUE_EURO=Europäisch
OPTION_VALUE_JAPAN=Japanisch
OPTION_VALUE_AMERICAN=Amerikanisch
OPTION_VALUE_BLUE=Blau
-OPTION_VALUE_GREEN=Grün
+OPTION_VALUE_GREEN=Grün
OPTION_VALUE_PINK=Lila
OPTION_VALUE_RED=Rot
OPTION_VALUE_VIOLET=Violett
@@ -69,15 +69,15 @@ OPTION_VALUE_BROWN=Braun
OPTION_VALUE_BLACK=Schwarz
OPTION_VALUE_SING=Singen
-OPTION_VALUE_SELECT_PLAYERS=Spieler auswählen
-OPTION_VALUE_OPEN_MENU=Menu öffnen
+OPTION_VALUE_SELECT_PLAYERS=Spieler auswählen
+OPTION_VALUE_OPEN_MENU=Menu öffnen
OPTION_VALUE_HARDWARE_CURSOR=Hardware Zeiger
OPTION_VALUE_SOFTWARE_CURSOR=Software Zeiger
-SING_LOADING=Lädt...
+SING_LOADING=Lädt...
-SING_CHOOSE_MODE=Modus wählen
+SING_CHOOSE_MODE=Modus wählen
SING_SING=Singen
SING_SING_DESC=Singen
@@ -93,13 +93,13 @@ SING_EDITOR=Editor
SING_EDITOR_DESC=Erstelle deinen eigenen Song
SING_GAME_OPTIONS=Spieloptionen
-SING_GAME_OPTIONS_DESC=Verändere die Spieleinstellungen
+SING_GAME_OPTIONS_DESC=Verändere die Spieleinstellungen
SING_EXIT=Beenden
SING_EXIT_DESC=Spiel verlassen
SING_OPTIONS=Optionen
-SING_OPTIONS_DESC=Einstellungen verändern
+SING_OPTIONS_DESC=Einstellungen verändern
SING_OPTIONS_WHEREAMI=Optionen
SING_OPTIONS_GAME=Spiel
@@ -109,7 +109,7 @@ SING_OPTIONS_LYRICS=Lyrics
SING_OPTIONS_THEMES=Design
SING_OPTIONS_RECORD=Aufnahme
SING_OPTIONS_ADVANCED=Erweitert
-SING_OPTIONS_EXIT=zurück
+SING_OPTIONS_EXIT=zurück
SING_OPTIONS_GAME_WHEREAMI=Spieloptionen
SING_OPTIONS_GAME_DESC=Allgemeine Spieleinstellungen
@@ -122,13 +122,13 @@ SING_OPTIONS_GAME_DEBUG=Debug
SING_OPTIONS_GRAPHICS_WHEREAMI=Grafikoptionen
SING_OPTIONS_GRAPHICS_DESC=Grafikeinstellungen
-SING_OPTIONS_GRAPHICS_RESOLUTION=Auflösung
+SING_OPTIONS_GRAPHICS_RESOLUTION=Auflösung
SING_OPTIONS_GRAPHICS_FULLSCREEN=Vollbild
SING_OPTIONS_GRAPHICS_DEPTH=Farbtiefe
SING_OPTIONS_GRAPHICS_VISUALIZER=Visualisierung
SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oszilloskop
SING_OPTIONS_GRAPHICS_LINEBONUS=Phrasenbonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Videogröße
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Videogröße
SING_OPTIONS_SOUND_WHEREAMI=Soundoptionen
SING_OPTIONS_SOUND_DESC=Soundeinstellungen
@@ -143,7 +143,7 @@ SING_OPTIONS_SOUND_PREVIEWVOLUME=Vorschau Lautst.
SING_OPTIONS_SOUND_PREVIEWFADING=Vorschau Fading
SING_OPTIONS_LYRICS_WHEREAMI=Lyricsoptionen
-SING_OPTIONS_LYRICS_DESC=Einstellungen für die Lyrics
+SING_OPTIONS_LYRICS_DESC=Einstellungen für die Lyrics
SING_OPTIONS_LYRICS_FONT=Schriftart
SING_OPTIONS_LYRICS_EFFECT=Effekt
SING_OPTIONS_LYRICS_SOLMIZATION=Solmisation
@@ -168,43 +168,43 @@ SING_OPTIONS_ADVANCED_SCREENFADE=Bildschirm-Fade
SING_OPTIONS_ADVANCED_LOADANIMATION=Lade-Animation
SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Sicherheitsabfr.
SING_OPTIONS_ADVANCED_LINEBONUS=Phrasenbonus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Wie oft gesungen mitzählen
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Wie oft gesungen mitzählen
SING_OPTIONS_ADVANCED_ONSONGCLICK=Nach Songauswahl
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto Party-Menü
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto Party-Menü
SING_EDIT=Editor
SING_EDIT_MENU_DESCRIPTION=Erstelle deinen eigenen Song
SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Midi/Kar-Datei in Text exportieren
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=zurück
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=zurück
SING_EDIT_BUTTON_CONVERT=Importieren
-SING_EDIT_BUTTON_EXIT=zurück
+SING_EDIT_BUTTON_EXIT=zurück
SING_EDIT_NAVIGATE=Navigieren
-SING_EDIT_SELECT=Auswählen
-SING_EDIT_EXIT=zurück
+SING_EDIT_SELECT=Auswählen
+SING_EDIT_EXIT=zurück
-SING_LEGEND_SELECT=Auswählen
+SING_LEGEND_SELECT=Auswählen
SING_LEGEND_NAVIGATE=Navigieren
SING_LEGEND_CONTINUE=Weiter
-SING_LEGEND_ESC=zurück
+SING_LEGEND_ESC=zurück
SING_PLAYER_DESC=Spielernamen eingeben.
SING_PLAYER_WHEREAMI=Spielernamen
SING_PLAYER_ENTER_NAME=Namen eingeben
-SING_DIFFICULTY_DESC=Schwierigkeitsgrad auswählen
+SING_DIFFICULTY_DESC=Schwierigkeitsgrad auswählen
SING_DIFFICULTY_WHEREAMI=Schwierigkeitsgrad
SING_DIFFICULTY_CONTINUE=zur Song-Auswahl
SING_EASY=Einfach
SING_MEDIUM=Mittel
SING_HARD=Schwierig
-SING_SONG_SELECTION_DESC=Wähle deinen Song
+SING_SONG_SELECTION_DESC=Wähle deinen Song
SING_SONG_SELECTION_WHEREAMI=Song-Auswahl
SING_SONG_SELECTION_GOTO=Gehe zu ..
SING_SONG_SELECTION=Song-Auswahl
-SING_SONG_SELECTION_MENU=Menü
+SING_SONG_SELECTION_MENU=Menü
SING_SONG_SELECTION_PLAYLIST=Playlist
SING_SONGS_IN_CAT=Songs
PLAYLIST_CATTEXT=Playlist: %s
@@ -216,17 +216,17 @@ SING_NOTES=Noten
SING_GOLDEN_NOTES=Goldener Ton
SING_PHRASE_BONUS=Phrasenbonus
-SING_MENU=Hauptmenü
+SING_MENU=Hauptmenü
SONG_SCORE=Songpunktzahl
SONG_SCORE_WHEREAMI=Punkte
-SING_SCORE_TONE_DEAF=Nichtskönner
+SING_SCORE_TONE_DEAF=Nichtskönner
SING_SCORE_AMATEUR=Amateur
-SING_SCORE_WANNABE=Möchtegern
+SING_SCORE_WANNABE=Möchtegern
SING_SCORE_HOPEFUL=Fortgeschritten
SING_SCORE_RISING_STAR=Sternchen
-SING_SCORE_LEAD_SINGER=Hit-Künstler
+SING_SCORE_LEAD_SINGER=Hit-Künstler
SING_SCORE_SUPERSTAR=Superstar
SING_SCORE_ULTRASTAR=UltraStar
@@ -246,18 +246,18 @@ POPUP_AWFUL=Grausam!
IMPLODE_GLUE1=,
IMPLODE_GLUE2= und
-SONG_MENU_NAME_MAIN=Menü
+SONG_MENU_NAME_MAIN=Menü
SONG_MENU_PLAY=Singen
SONG_MENU_CHANGEPLAYERS=Spieler wechseln
SONG_MENU_EDIT=Editor
SONG_MENU_MODI=Einen Modus singen
SONG_MENU_CANCEL=Abbrechen
-SONG_MENU_NAME_PLAYLIST=Menü
-SONG_MENU_PLAYLIST_ADD=Song hinzufügen
-SONG_MENU_PLAYLIST_DEL=Song löschen
+SONG_MENU_NAME_PLAYLIST=Menü
+SONG_MENU_PLAYLIST_ADD=Song hinzufügen
+SONG_MENU_PLAYLIST_DEL=Song löschen
-SONG_MENU_NAME_PLAYLIST_ADD=Song hinzufügen
+SONG_MENU_NAME_PLAYLIST_ADD=Song hinzufügen
SONG_MENU_PLAYLIST_ADD_NEW=Zu neuer Playlist
SONG_MENU_PLAYLIST_ADD_EXISTING=Zu bestehender Playlist
SONG_MENU_PLAYLIST_NOEXISTING=Keine Playlist vorhanden
@@ -266,17 +266,17 @@ SONG_MENU_NAME_PLAYLIST_NEW=Neue Playlist
SONG_MENU_PLAYLIST_NEW_CREATE=Erstellen
SONG_MENU_PLAYLIST_NEW_UNNAMED=Unbenannt
-SONG_MENU_NAME_PLAYLIST_DELITEM=Wirklich löschen?
+SONG_MENU_NAME_PLAYLIST_DELITEM=Wirklich löschen?
SONG_MENU_YES=Ja
SONG_MENU_NO=Nein
-SONG_MENU_NAME_PLAYLIST_LOAD=Playlist öffnen
-SONG_MENU_PLAYLIST_LOAD=öffnen
-SONG_MENU_PLAYLIST_DELCURRENT=Aktuelle Playlist löschen
+SONG_MENU_NAME_PLAYLIST_LOAD=Playlist öffnen
+SONG_MENU_PLAYLIST_LOAD=öffnen
+SONG_MENU_PLAYLIST_DELCURRENT=Aktuelle Playlist löschen
-SONG_MENU_NAME_PLAYLIST_DEL=Playlist löschen?
+SONG_MENU_NAME_PLAYLIST_DEL=Playlist löschen?
-SONG_MENU_NAME_PARTY_MAIN=Party-Menü
+SONG_MENU_NAME_PARTY_MAIN=Party-Menü
SONG_MENU_JOKER=Joker
SONG_MENU_NAME_PARTY_JOKER=Joker einsetzen
@@ -305,7 +305,7 @@ PARTY_TEAMS_PLAYER3=Spieler Team 3
PARTY_LEGEND_CONTINUE=weiter
-PARTY_OPTIONS_DESC=Einstellungen für das Partyspiel.
+PARTY_OPTIONS_DESC=Einstellungen für das Partyspiel.
PARTY_OPTIONS_WHEREAMI=Party Optionen
PARTY_PLAYER_DESC=Team- und Spielernamen eingeben.
@@ -313,26 +313,26 @@ PARTY_PLAYER_WHEREAMI=Party Spielernamen
PARTY_PLAYER_ENTER_NAME=Namen eingeben
PARTY_PLAYER_LEGEND_CONTINUE=Partyspiel starten
-PARTY_ROUND_DESC=Die nächsten Spieler an die Mikros!
-PARTY_ROUND_WHEREAMI=Party nächste Runde
+PARTY_ROUND_DESC=Die nächsten Spieler an die Mikros!
+PARTY_ROUND_WHEREAMI=Party nächste Runde
PARTY_ROUND_LEGEND_CONTINUE=Runde starten
PARTY_SONG_WHEREAMI=Party Song-Auswahl
PARTY_SONG_LEGEND_CONTINUE=Singen
-PARTY_SONG_MENU=Party-Menü
+PARTY_SONG_MENU=Party-Menü
PARTY_SCORE_DESC=Punkte der letzten Runde.
PARTY_SCORE_WHEREAMI=Party Punkte
PARTY_WIN_DESC=Gewinner des Partyspiels.
PARTY_WIN_WHEREAMI=Party Gewinner
-PARTY_WIN_LEGEND_CONTINUE=Zurück zum Hauptmenü
+PARTY_WIN_LEGEND_CONTINUE=Zurück zum Hauptmenü
PARTY_ROUND=Runde
PARTY_ROUND_WINNER=Sieger
PARTY_NOTPLAYEDYET=Noch nicht gespielt
PARTY_NOBODY=Niemand
-NEXT_ROUND=Nächste Runde:
+NEXT_ROUND=Nächste Runde:
PARTY_DISMISSED=Ausgeschieden!
PARTY_SCORE_WINS=%s
@@ -345,36 +345,36 @@ PLUGIN_UNTIL5000_NAME=Bis 5000
PLUGIN_UNTIL5000_DESC=Wer zuerst 5000 Punkte hat, gewinnt.
PLUGIN_DUELL_NAME=Duell
-PLUGIN_DUELL_DESC=Normales Spiel. Höchste Punktzahl gewinnt.
+PLUGIN_DUELL_DESC=Normales Spiel. Höchste Punktzahl gewinnt.
PLUGIN_TEAMDUELL_NAME=Teamsingen
PLUGIN_TEAMDUELL_DESC=Gib das Mikro weiter!
-PLUGIN_BLIND_NAME=Blind Mode
-PLUGIN_BLIND_DESC=Erreiche blind die höchste Punktzahl.
+PLUGIN_BLIND_NAME=Blind Modus
+PLUGIN_BLIND_DESC=Erreiche blind die höchste Punktzahl.
STAT_MAIN=Statistiken
STAT_MAIN_DESC=Allgemein
STAT_MAIN_WHEREAMI=Statistiken
STAT_OVERVIEW_INTRO=%0:s Statistiken. \n Letzter Reset am %1:.2d.%2:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Songs(%3:d mit Video), davon wurden %1:d schon einmal gesungen und %2:d noch nicht. \n Der am häufigsten gesungene Song ist %5:s von %4:s.
-STAT_OVERVIEW_PLAYER=Seit dem letzten Reset haben %0:d verschiedene Spieler gesungen. \n Der beste Spieler ist %1:s mit %2:d Punkten. \n Die höchste Punktzahl, %4:d, wurde von %3:s erreicht.
+STAT_OVERVIEW_SONG=%0:d Songs(%3:d mit Video), davon wurden %1:d schon einmal gesungen und %2:d noch nicht. \n Der am häufigsten gesungene Song ist %5:s von %4:s.
+STAT_OVERVIEW_PLAYER=Seit dem letzten Reset haben %0:d verschiedene Spieler gesungen. \n Der beste Spieler ist %1:s mit %2:d Punkten. \n Die höchste Punktzahl, %4:d, wurde von %3:s erreicht.
STAT_DETAIL=Statistiken
STAT_DETAIL_WHEREAMI=Detaillierte Statistiken
-STAT_NEXT=Nächste Seite
+STAT_NEXT=Nächste Seite
STAT_PREV=Vorherige Seite
STAT_REVERSE=Umkehren
-STAT_PAGE=Seite %0:d von %1:d \n (%2:d von %3:d Einträgen)
+STAT_PAGE=Seite %0:d von %1:d \n (%2:d von %3:d Einträgen)
STAT_DESC_SCORES=Highscores
STAT_DESC_SCORES_REVERSED=Lowscores
STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-STAT_DESC_SINGERS=Beste Sänger
-STAT_DESC_SINGERS_REVERSED=Schlechteste Sänger
+STAT_DESC_SINGERS=Beste Sänger
+STAT_DESC_SINGERS_REVERSED=Schlechteste Sänger
STAT_FORMAT_SINGERS=%0:s \n Durchschnittliche Punktzahl: %1:d
STAT_DESC_SONGS=Beliebteste Songs
@@ -385,10 +385,22 @@ STAT_DESC_BANDS=Beliebteste Bands
STAT_DESC_BANDS_REVERSED=Unbeliebteste Bands
STAT_FORMAT_BANDS=%0:s \n Gesungene Songs: %1:d
+SCREENSHOT_SAVED=Bildschirmfoto gesichert
+SCREENSHOT_FAILED=Konnte Bildschirmfoto nicht sichern
+
+INFO_FILE_SAVED=Datei gesichert
+ERROR_SAVE_FILE_FAILED=Konnte Datei nicht sichern
+ERROR_FILE_NOT_FOUND=Datei nicht gefunden
+
+ENCODING_ERROR_ASK_FOR_UTF8=Änderungen können nicht in der aktuellen Kodierung gesichert werden. Nach UTF-8 konvertieren?
+EDITOR_ERROR_NO_TRACK_SELECTED=Keine Spur ausgewählt
+
MSG_ERROR_TITLE=Fehler
+MSG_INFO_TITLE=Information
MSG_QUESTION_TITLE=Frage
-MSG_QUIT_USDX=UltraStar wirklich verlassen?
-MSG_END_PARTY=Party-Modus beenden?
+MSG_QUIT_USDX=UltraStar wirklich beenden?
+MSG_END_PARTY=Party-Modus wirklich beenden?
+
ERROR_NO_SONGS=Keine Songs vorhanden.
ERROR_NO_PLUGINS=Keine Plugins vorhanden.
ERROR_CORRUPT_SONG=Song konnte nicht geladen werden.
diff --git a/game/languages/Greek.ini b/game/languages/Greek.ini
index 0a73ee1b..a07b1932 100644
--- a/game/languages/Greek.ini
+++ b/game/languages/Greek.ini
@@ -1,399 +1,399 @@
-;Leo 21
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Öüñôùíåé...
-
-SING_CHOOSE_MODE=ÅðéëïãÞ ôñüðïõ ðáé÷íéäéïý
-SING_SING=Ôñáãïýäçóôå
-SING_SING_DESC=ÃñÞãïñï ðáé÷íßäé: ÔñáãïõäÞóôå óïëï Þ íôïõÝôï
-
-SING_MULTI="ÐÜñôõ"
-SING_MULTI_DESC=ÔñáãïõäÞóôå óå ðáé÷íßäé "ÐÜñôõ"
-
-SING_TOOLS=Åñãáëåßá
-
-SING_STATS=ÓôáôéóôéêÜ
-SING_STATS_DESC=Äåßôå ôá óôáôéóôéêÜ
-
-SING_EDITOR=Äçìéïõñãßá
-SING_EDITOR_DESC=ÖôéÜîôå ôï äéêü óáò ôñáãïýäé
-
-SING_GAME_OPTIONS=ÅðéëïãÝò ðáé÷íéäéïý
-SING_GAME_OPTIONS_DESC=ÁëëÜîôå ôéò åðéëïãÝò ôïõ ðáé÷íéäéïý
-
-SING_EXIT=¸îïäïò
-SING_EXIT_DESC=¸îïäïò áðï ôï ðáé÷íßäé
-
-SING_OPTIONS=ÅðéëïãÝò
-SING_OPTIONS_DESC=ÁëëÜîôå ôéò åðéëïãÝò
-SING_OPTIONS_WHEREAMI=ÅðéëïãÝò
-
-SING_OPTIONS_GAME=Ðáé÷íßäé
-SING_OPTIONS_GRAPHICS=ÃñáöéêÜ
-SING_OPTIONS_SOUND=¹÷ïò
-SING_OPTIONS_LYRICS=Óôß÷ïé
-SING_OPTIONS_THEMES=ÈÝìáôá
-SING_OPTIONS_RECORD=Ç÷ïãñÜöçóç
-SING_OPTIONS_ADVANCED=Ãéá ðñï÷ùñçìÝíïõò
-SING_OPTIONS_EXIT=Ðßóù
-
-SING_OPTIONS_GAME_WHEREAMI=ÅðéëïãÝò ðáé÷íéäéïý
-SING_OPTIONS_GAME_DESC=Êýñéåò åðéëïãÝò ðáé÷íéäéïý
-SING_OPTIONS_GAME_PLAYERS=Ðáß÷ôåò
-SING_OPTIONS_GAME_DIFFICULTY=Äõóêïëßá
-SING_OPTIONS_GAME_LANGUAGE=Ãëþóóá
-SING_OPTIONS_GAME_TABS=ÅôéêÝôåò
-SING_OPTIONS_GAME_SORTING=Ôáîéíüìéóç
-SING_OPTIONS_GAME_DEBUG=Áðïóõìöüñçóç
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=ÅðéëïãÝò ãñáöéêþí
-SING_OPTIONS_GRAPHICS_DESC=Ñõèìßóåéò ãñáöéêþí
-SING_OPTIONS_GRAPHICS_RESOLUTION=ÁíÜëõóç
-SING_OPTIONS_GRAPHICS_FULLSCREEN=ÐëÞñçò ïèüíç
-SING_OPTIONS_GRAPHICS_DEPTH=ÂÜèïò
-SING_OPTIONS_GRAPHICS_VISUALIZER=Êéíïýìåíï öüíôï
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Ïóêéëïóêüðéï
-SING_OPTIONS_GRAPHICS_LINEBONUS=Ìðüíïõò ãñáììÞò
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=ÌÝãåèïò âßíôåï
-
-SING_OPTIONS_SOUND_WHEREAMI=ÅðéëïãÝò Þ÷ïõ
-SING_OPTIONS_SOUND_DESC=ÅðéëïãÝò Þ÷ïõ
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=¹÷ïò ìéêñïöþíïõ
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=ÌïõóéêÞ óôï ìåíïý
-SING_OPTIONS_SOUND_MIC_BOOST=Éó÷ýò ìéêñïöþíïõ
-SING_OPTIONS_SOUND_CLICK_ASSIST=ÂïÞèåéá ìå êëßê
-SING_OPTIONS_SOUND_BEAT_CLICK=ÂïÞèåéá ñõèìïý
-SING_OPTIONS_SOUND_THRESHOLD=Åõáéóèçóßá ìéêñïöþíïõ
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Ìå äýï ðáß÷ôåò
-SING_OPTIONS_SOUND_PREVIEWVOLUME=¸íôáóç ðñïåðéóêüðéóçò
-SING_OPTIONS_SOUND_PREVIEWFADING=ÓâÞóéìï ðñïåðéóêüðéóçò
-
-SING_OPTIONS_LYRICS_WHEREAMI=ÅðéëïãÝò óôß÷ùí
-SING_OPTIONS_LYRICS_DESC=Ñõèìßóéåò óôß÷ùí
-SING_OPTIONS_LYRICS_FONT=ÃñáììáôïóåéñÜ
-SING_OPTIONS_LYRICS_EFFECT=ÅöÝ
-SING_OPTIONS_LYRICS_SOLMIZATION=ÅìöÜíéóç íüôáò áíôß óôß÷ùí
-SING_OPTIONS_LYRICS_NOTELINES=ÐåíôÜãñáììï
-
-SING_OPTIONS_THEMES_WHEREAMI=ÅðéëïãÝò èåìÜôùí
-SING_OPTIONS_THEMES_DESC=Ñõèìßóåéò èåìÜôùí
-SING_OPTIONS_THEMES_THEME=ÈÝìá
-SING_OPTIONS_THEMES_SKIN=ÌïñöÞ èÝìáôïò
-SING_OPTIONS_THEMES_COLOR=×ñþìá
-
-SING_OPTIONS_RECORD_WHEREAMI=ÅðéëïãÝò ìéêñïöþíïõ
-SING_OPTIONS_RECORD_DESC=Ñõèìßóåéò ìéêñïöþíïõ
-SING_OPTIONS_RECORD_CARD=ÊÜñôá Þ÷ïõ
-SING_OPTIONS_RECORD_INPUT=ÅðéëïãÞ ìéêñïöþíïõ
-SING_OPTIONS_RECORD_CHANNEL=ÊáíÜëé
-
-SING_OPTIONS_ADVANCED_WHEREAMI=ÅðéëïãÝò ãéá ðñï÷ùñçìÝíïõò
-SING_OPTIONS_ADVANCED_DESC=Ñõèìßóåéò ãéá ðñï÷ùñçìÝíïõò
-SING_OPTIONS_ADVANCED_EFFECTSING=ÅöÝ ôñáãïõäéïý
-SING_OPTIONS_ADVANCED_SCREENFADE=ÓâÞóéìï åéêüíáò
-SING_OPTIONS_ADVANCED_LOADANIMATION=Öüñôùóç êéíïýìåíùí åéêüíùí
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=ÅñùôÞóåéò áóöáëåßáò
-SING_OPTIONS_ADVANCED_LINEBONUS=Ìðüíïõò ãñáììÞò
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=ÌåôÜ áðï ôçí åðéëïãÞ ôñáãïõäéïý
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Áõôüìáôï ìåíïý "ÐÜñôõ"
-
-SING_EDIT=Äçìéïõñãßá
-SING_EDIT_MENU_DESCRIPTION=ÖôéÜîôå ôï äéêü óáò ôñáãïýäé
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=ÅéóáãùãÞ áñ÷åßïõ êåéìÝíïõ
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Ðßóù
-SING_EDIT_BUTTON_CONVERT=ÅéóáãùãÞ
-SING_EDIT_BUTTON_EXIT=Ðßóù
-
-SING_EDIT_NAVIGATE=ÅîåñÝõíçóç
-SING_EDIT_SELECT=ÅðÝëåîå
-SING_EDIT_EXIT=Ðßóù
-
-SING_LEGEND_SELECT=ÅðÝëåîå
-SING_LEGEND_NAVIGATE=ÅîåñÝõíçóç
-SING_LEGEND_CONTINUE=ÓõíÝ÷éóå
-SING_LEGEND_ESC=Ðßóù
-
-SING_PLAYER_DESC=ÃñÜøå ïíüìá(ôá) ðáé÷ô-ç/ùí
-SING_PLAYER_WHEREAMI=Ïíüìáôá ðáé÷ôþí
-SING_PLAYER_ENTER_NAME=ÃñÜøå üíïìá
-
-SING_DIFFICULTY_DESC=ÄéÜëåîå äõóêïëßá
-SING_DIFFICULTY_WHEREAMI=Äõóêïëßá
-SING_DIFFICULTY_CONTINUE=Óôçí åðéëïãÞ ôñáãïõäéïý
-SING_EASY=Åýêïëï
-SING_MEDIUM=ÌÝôñéï
-SING_HARD=Äýóêïëï
-
-SING_SONG_SELECTION_DESC=ÄéÜëåîå ôñáãïýäé
-SING_SONG_SELECTION_WHEREAMI=ÅðéëïãÞ ôñáãïõäéïý
-SING_SONG_SELECTION_GOTO=ÐÞãáéíå óå...
-SING_SONG_SELECTION=ÅðéëïãÞ ôñáãïõäéïõ
-SING_SONG_SELECTION_MENU=Ìåíïý
-SING_SONG_SELECTION_PLAYLIST=Ëßóôá
-SING_SONGS_IN_CAT=Ôñáãïýäéá
-PLAYLIST_CATTEXT=Ëßóôá: %s
-
-SING_TIME=×ñüíïò
-SING_TOTAL=Óýíïëï
-SING_MODE=Ôñáãïýäá óüëï
-SING_NOTES=Íüôåò
-SING_GOLDEN_NOTES=×ñõóÝò íüôåò
-SING_PHRASE_BONUS=Ìðüíïõò ãñáììÞò
-
-SING_MENU=Êýñéï ìåíïý
-
-SONG_SCORE=Âáèìïëïãßá ôñáãïõäéïý
-SONG_SCORE_WHEREAMI=Âáèìïëïãßá
-
-SING_SCORE_TONE_DEAF=Êáêïöùíßî
-SING_SCORE_AMATEUR=Áñ÷Üñéïò
-SING_SCORE_WANNABE=Ôï èÝëåé...
-SING_SCORE_HOPEFUL=Åëðéäïöüñïò
-SING_SCORE_RISING_STAR=Áíåñ÷üìåíï áóôÝñé
-SING_SCORE_LEAD_SINGER=Åðáããåëìáôßáò
-SING_SCORE_SUPERSTAR=Óïýðåñóôáñ
-SING_SCORE_ULTRASTAR=Áðüëõôïò óôáñ
-
-SING_TOP_5_CHARTS=Ïé êáëýôåñïé 5 ðáß÷ôåò
-SING_TOP_5_CHARTS_WHEREAMI=Ôïð 5
-SING_TOP_5_CHARTS_CONTINUE=Óôçí åðéëïãÞ ôñáãïõäéïý
-
-POPUP_PERFECT=ÔÝëåéá!
-POPUP_AWESOME=ÖáíôáóôéêÜ!
-POPUP_GREAT=Ðïëý êáëÜ!
-POPUP_GOOD=ÊáëÜ!
-POPUP_NOTBAD=Ï÷é Üó÷çìá!
-POPUP_BAD=¢ó÷çìá!
-POPUP_POOR=ðïëý Üó÷çìá!
-POPUP_AWFUL=Áðáßóéá!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= êáé
-
-SONG_MENU_NAME_MAIN=Ìåíïý ôñáãïõäéþí
-SONG_MENU_PLAY=ÔñáãïõäÞóôå
-SONG_MENU_CHANGEPLAYERS=ÁëëÜîôå ðáß÷ôåò
-SONG_MENU_EDIT=Åðåîåñãáóßá
-SONG_MENU_MODI=ÔñáãïõäÞóôå ìéÜ ôñïðïðïßçóç
-SONG_MENU_CANCEL=Áêýñùóç
-
-SONG_MENU_NAME_PLAYLIST=Ìåíïý ôñáãïõäéïý
-SONG_MENU_PLAYLIST_ADD=Ðñüóèåóå ôñáãïýäé
-SONG_MENU_PLAYLIST_DEL=ÄéÝãñáøå ôñáãïýäé
-
-SONG_MENU_NAME_PLAYLIST_ADD=Ðñüóèåóå ôñáãïýäé
-SONG_MENU_PLAYLIST_ADD_NEW=Óå íÝá ëßóôá
-SONG_MENU_PLAYLIST_ADD_EXISTING=Óå õðÜñ÷ïõóá ëßóôá
-SONG_MENU_PLAYLIST_NOEXISTING=Äåí õðÜñ÷åé äéáèÝóéìç ëßóôá
-
-SONG_MENU_NAME_PLAYLIST_NEW=ÍÝá ëßóôá
-SONG_MENU_PLAYLIST_NEW_CREATE=Öôéáîå íÝá
-SONG_MENU_PLAYLIST_NEW_UNNAMED=×ùñßò üíïìá
-
-SONG_MENU_NAME_PLAYLIST_DEL=ÄéáãñáöÞ?
-SONG_MENU_YES=Íáé
-SONG_MENU_NO=¼÷é
-
-SONG_MENU_NAME_PLAYLIST_LOAD=¢íïéîå ìéá ëßóôá
-SONG_MENU_PLAYLIST_LOAD=¢íïéîå
-SONG_MENU_PLAYLIST_DELCURRENT=ÄéÝãñáøå áõôÞ ôç ëßóôá
-
-SONG_MENU_NAME_PLAYLIST_DEL=ÄéáãñáöÞ ëßóôáò?
-
-SONG_MENU_NAME_PARTY_MAIN=Ìåíïý "ÐÜñôõ"
-SONG_MENU_JOKER=ÌðáëáíôÝñ
-
-SONG_MENU_NAME_PARTY_JOKER=ÅðéëïãÞ ìðáëáíôÝñ
-
-SONG_JUMPTO_DESC=ØÜîå ôñáãïýäé
-SONG_JUMPTO_TYPE_DESC=ØÜîå ãéá:
-SONG_JUMPTO_TYPE1=¼ëá
-SONG_JUMPTO_TYPE2=Ôßôëïò
-SONG_JUMPTO_TYPE3=ÊáëëéôÝ÷íçò
-SONG_JUMPTO_SONGSFOUND=%d Ôñáãïýäé(á) âñÝèçêáí
-SONG_JUMPTO_NOSONGSFOUND=Äåí âñÝèçêå ôñáãïýäé
-SONG_JUMPTO_HELP=ÃñÜøå êåßìåíï ãéá áíáæÞôçóç
-SONG_JUMPTO_CATTEXT=ÁíáæÞôçóç ãéá: %s
-
-PARTY_MODE=Åßäïò ðáé÷íéäéïý "ÐÜñôõ"
-PARTY_DIFFICULTY=Äõóêïëßá
-PARTY_PLAYLIST=Ðáßîå ìå ìßá ëßóôá
-PARTY_PLAYLIST_ALL=¼ëá ôá ôñáãïýäéá
-PARTY_PLAYLIST_CATEGORY=ÖÜêåëïò
-PARTY_PLAYLIST_PLAYLIST=Ëßóôá
-PARTY_ROUNDS=Ãýñïé
-PARTY_TEAMS=ÏìÜäåò
-PARTY_TEAMS_PLAYER1=Ðáß÷ôçò ïìÜäá1
-PARTY_TEAMS_PLAYER2=Ðáß÷ôçò ïìÜäá2
-PARTY_TEAMS_PLAYER3=Ðáß÷ôçò ïìÜäá3
-
-PARTY_LEGEND_CONTINUE=ÓõíÝ÷åéá
-
-PARTY_OPTIONS_DESC=ÅðéëïãÝò ãéá ôï ðáé÷íßäé "ÐÜñôõ"
-PARTY_OPTIONS_WHEREAMI=ÅðéëïãÝò "ÐÜñôõ"
-
-PARTY_PLAYER_DESC=ÃñÜøå ïíüìáôá ðáé÷ôþí êáé ïìÜäùí
-PARTY_PLAYER_WHEREAMI=Ïíüìáôá "ÐÜñôõ"
-PARTY_PLAYER_ENTER_NAME=ÃñÜøå ïíüìáôá
-PARTY_PLAYER_LEGEND_CONTINUE=Îåêßíá ôï ðáé÷íßäé "ÐÜñôõ"
-
-PARTY_ROUND_DESC=Åðüìåíïé ðáß÷ôåò
-PARTY_ROUND_WHEREAMI=Åðüìåíïò ãýñïò "ÐÜñôõ"
-PARTY_ROUND_LEGEND_CONTINUE=Îåêßíá ôï ãýñï
-
-PARTY_SONG_WHEREAMI=ÅðéëïãÞ ôñáãïõäéïý "ÐÜñôõ"
-PARTY_SONG_LEGEND_CONTINUE=ÔñáãïõäÞóôå
-PARTY_SONG_MENU=Ìåíïý "ÐÜñôõ"
-
-PARTY_SCORE_DESC=Âáèìïëïãßá ôåëåõôáßïõ ãýñïõ
-PARTY_SCORE_WHEREAMI=Âáèìïß "ÐÜñôõ"
-
-PARTY_WIN_DESC=ÍéêçôÞò ôïõ ðáé÷íéäéïý "ÐÜñôõ"
-PARTY_WIN_WHEREAMI=ÍéêçôÞò "ÐÜñôõ"
-PARTY_WIN_LEGEND_CONTINUE=ÅðéóôñïöÞ óôï êýñéï ìåíïý
-
-PARTY_ROUND=Ãýñïò
-PARTY_ROUND_WINNER=ÍéêçôÞò
-PARTY_NOTPLAYEDYET=Äåí ðáß÷ôçêå áêüìç
-PARTY_NOBODY=Êáíåßò
-NEXT_ROUND=Åðüìåíïò Ãýñïò:
-
-PARTY_DISMISSED=ÁðïâïëÞ!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=Íßêçóå!
-
-PLUGIN_HDL_NAME=Ìåßíå ðÜíù áðü ôç ìðÜñá!
-PLUGIN_HDL_DESC=Ìåßíå ðÜíù áðü ôç ìðÜñá ðïõ åìöáíßæåôáé
-
-PLUGIN_UNTIL5000_NAME=ÌÝ÷ñé 5000 ðüíôïõò
-PLUGIN_UNTIL5000_DESC=¼ðïéïò öôÜóåé ôïõò 5000 ðüíôïõò êåñäßæåé
-
-PLUGIN_DUELL_NAME=Ìïíïìá÷ßá
-PLUGIN_DUELL_DESC=ÔñáãïõäÞóôå óå ìïíïìá÷ßá ìÝ÷ñé ôïõò 10000 ðüíôïõò
-
-PLUGIN_TEAMDUELL_NAME=Ìïíïìá÷ßá ïìÜäùí
-PLUGIN_TEAMDUELL_DESC=Äþóå ôï ìéêñüöùíï!
-
-PLUGIN_BLIND_NAME=Óôá ôõöëÜ
-PLUGIN_BLIND_DESC=Ìïíïìá÷ßá ÷ùñßò íá âëÝðåôå ôéò íüôåò
-
-STAT_MAIN=ÓôáôéóôéêÜ
-STAT_MAIN_DESC=Êýñéá
-STAT_MAIN_WHEREAMI=ÓôáôéóôéêÜ
-
-STAT_OVERVIEW_INTRO=%0:s ÓôáôéóôéêÜ. \n Ôåëåõôáßá Ýîïäïò óôßò %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d ôñáãïýäéá(%3:d ìå âßíôåï), Üðï ôá ïðïßá %1:d Ý÷ïõí ðáé÷ôåß Þäç êáé %2:d äåí Ý÷ïõí ðáé÷ôåß áêüìç.\n Ôï ðéï äçìïöéëÝò ôñáãïýäé åßíáé %5:s áðü %4:s.
-STAT_OVERVIEW_PLAYER=Áðü ôï ôåëåõôáßï óâÞóéìï õðÜñ÷åé-ïõí %0:d ðáß÷ôçò-åò .\n Ï êáëýôåñïò ðáß÷ôçò åßíáé %1:s ìå ìÝóï üñï âáèìïëïãßáò %2:d âáèìïýò.\n %3:s Ýêáíå ôç ìåãáëýôåñç âáèìïëïãßá ìå %4:d âáèìïýò.
-
-STAT_DETAIL=ÓôáôéóôéêÜ
-STAT_DETAIL_WHEREAMI=ËåðôïìåñÞ óôáôéóôéêÜ
-
-STAT_NEXT=Åðüìåíç Óåëßäá
-STAT_PREV=Ðñïçãïýìåíç óåëßäá
-STAT_REVERSE=Áíôßóôñïöá
-STAT_PAGE=Seite %0:d áðü %1:d óåëßäåò\n (%2:d of %3:d åéóáãùãÝò)
-
-STAT_DESC_SCORES=Õøçëüôåñåò Âáèìïëïãßåò
-STAT_DESC_SCORES_REVERSED=×áìçëüôåñåò âáèìïëïãßåò
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Êáëýôåñïé ôñáãïõäéóôÝò
-STAT_DESC_SINGERS_REVERSED=×åéñüôåñïé ôñáãïõäéóôÝò
-STAT_FORMAT_SINGERS=%0:s \n ÌÝóïò üñïò âáèìïëïãßáò: %1:d
-
-STAT_DESC_SONGS=Ðéï äçìïöéëÞ ôñáãïýäéá
-STAT_DESC_SONGS_REVERSED=Ëéãüôåñï äçìïöéëÞ ôñáãïýäéá
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx ôñáãïõäÞèçêáí
-
-STAT_DESC_BANDS=Ðéï äçìïöéëÞò ìðÜíôåò
-STAT_DESC_BANDS_REVERSED=Ëéãüôåñï äçìïöéëÞò ìðÜíôåò
-STAT_FORMAT_BANDS=%0:s \n %1:dx ôñáãïõäÞèçêáí
-
-MSG_ERROR_TITLE=ÓöÜëìá
-MSG_QUESTION_TITLE=Åñþôçóç
-MSG_QUIT_USDX=¸îïäïò áðü ôï ðáé÷íßäé?
-MSG_END_PARTY=¸îïäïò áðï ôï ðáé÷íßäé "ÐÜñôõ"?
-ERROR_NO_SONGS=Äåí öïñôþèçêáí ôñáãïýäéá
-ERROR_NO_PLUGINS=Äåí öïñôþèçêáí âïçèçôéêÝò åöáñìïãÝò
-ERROR_CORRUPT_SONG=Ôá ôñáãïýäéá äåí Þôáí äõíáôü íá öïñôþóïõí
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Ôï ôñáãïýäé äåí Þôáí äõíáôü íá öïñôþóåé: Ôï áñ÷åßï äåí âñÝèçêå
-ERROR_CORRUPT_SONG_NO_NOTES=Ôï ôñáãïýäé äåí Þôáí äõíáôü íá öïñôþóåé: Äåí âñÝèçêáí íüôåò
-ERROR_CORRUPT_SONG_NO_BREAKS=Ôï ôñáãïýäé äåí Þôáí äõíáôü íá öïñôþóåé: Äåí âñÝèçêáí êåíÜ áíÜìåóá óôéò íüôåò
-ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Ôï ôñáãïýäé äåí Þôáí äõíáôü íá öïñôþóåé: ËÜèïò óôçí åðéêüëçóç ôçò ãñáììÞò %0:d \ No newline at end of file
+;Leo 21
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=ΦόÏτωνει...
+
+SING_CHOOSE_MODE=Επιλογή Ï„Ïόπου παιχνιδιοÏ
+SING_SING=ΤÏαγοÏδηστε
+SING_SING_DESC=ΓÏήγοÏο παιχνίδι: ΤÏαγουδήστε σολο ή ντουέτο
+
+SING_MULTI="ΠάÏÏ„Ï…"
+SING_MULTI_DESC=ΤÏαγουδήστε σε παιχνίδι "ΠάÏÏ„Ï…"
+
+SING_TOOLS=ΕÏγαλεία
+
+SING_STATS=Στατιστικά
+SING_STATS_DESC=Δείτε τα στατιστικά
+
+SING_EDITOR=ΔημιουÏγία
+SING_EDITOR_DESC=Φτιάξτε το δικό σας Ï„ÏαγοÏδι
+
+SING_GAME_OPTIONS=Επιλογές παιχνιδιοÏ
+SING_GAME_OPTIONS_DESC=Αλλάξτε τις επιλογές του παιχνιδιοÏ
+
+SING_EXIT=Έξοδος
+SING_EXIT_DESC=Έξοδος απο το παιχνίδι
+
+SING_OPTIONS=Επιλογές
+SING_OPTIONS_DESC=Αλλάξτε τις επιλογές
+SING_OPTIONS_WHEREAMI=Επιλογές
+
+SING_OPTIONS_GAME=Παιχνίδι
+SING_OPTIONS_GRAPHICS=ΓÏαφικά
+SING_OPTIONS_SOUND=Ήχος
+SING_OPTIONS_LYRICS=Στίχοι
+SING_OPTIONS_THEMES=Θέματα
+SING_OPTIONS_RECORD=ΗχογÏάφηση
+SING_OPTIONS_ADVANCED=Για Ï€ÏοχωÏημένους
+SING_OPTIONS_EXIT=Πίσω
+
+SING_OPTIONS_GAME_WHEREAMI=Επιλογές παιχνιδιοÏ
+SING_OPTIONS_GAME_DESC=ΚÏÏιες επιλογές παιχνιδιοÏ
+SING_OPTIONS_GAME_PLAYERS=Παίχτες
+SING_OPTIONS_GAME_DIFFICULTY=Δυσκολία
+SING_OPTIONS_GAME_LANGUAGE=Γλώσσα
+SING_OPTIONS_GAME_TABS=Ετικέτες
+SING_OPTIONS_GAME_SORTING=Ταξινόμιση
+SING_OPTIONS_GAME_DEBUG=ΑποσυμφόÏηση
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Επιλογές γÏαφικών
+SING_OPTIONS_GRAPHICS_DESC=Ρυθμίσεις γÏαφικών
+SING_OPTIONS_GRAPHICS_RESOLUTION=Ανάλυση
+SING_OPTIONS_GRAPHICS_FULLSCREEN=ΠλήÏης οθόνη
+SING_OPTIONS_GRAPHICS_DEPTH=Βάθος
+SING_OPTIONS_GRAPHICS_VISUALIZER=ΚινοÏμενο φόντο
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Οσκιλοσκόπιο
+SING_OPTIONS_GRAPHICS_LINEBONUS=Μπόνους γÏαμμής
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Μέγεθος βίντεο
+
+SING_OPTIONS_SOUND_WHEREAMI=Επιλογές ήχου
+SING_OPTIONS_SOUND_DESC=Επιλογές ήχου
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Ήχος μικÏοφώνου
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Μουσική στο μενοÏ
+SING_OPTIONS_SOUND_MIC_BOOST=ΙσχÏÏ‚ μικÏοφώνου
+SING_OPTIONS_SOUND_CLICK_ASSIST=Βοήθεια με κλίκ
+SING_OPTIONS_SOUND_BEAT_CLICK=Βοήθεια ÏυθμοÏ
+SING_OPTIONS_SOUND_THRESHOLD=Ευαισθησία μικÏοφώνου
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Με δÏο παίχτες
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Ένταση Ï€Ïοεπισκόπισης
+SING_OPTIONS_SOUND_PREVIEWFADING=Σβήσιμο Ï€Ïοεπισκόπισης
+
+SING_OPTIONS_LYRICS_WHEREAMI=Επιλογές στίχων
+SING_OPTIONS_LYRICS_DESC=Ρυθμίσιες στίχων
+SING_OPTIONS_LYRICS_FONT=ΓÏαμματοσειÏά
+SING_OPTIONS_LYRICS_EFFECT=Εφέ
+SING_OPTIONS_LYRICS_SOLMIZATION=Εμφάνιση νότας αντί στίχων
+SING_OPTIONS_LYRICS_NOTELINES=ΠεντάγÏαμμο
+
+SING_OPTIONS_THEMES_WHEREAMI=Επιλογές θεμάτων
+SING_OPTIONS_THEMES_DESC=Ρυθμίσεις θεμάτων
+SING_OPTIONS_THEMES_THEME=Θέμα
+SING_OPTIONS_THEMES_SKIN=ΜοÏφή θέματος
+SING_OPTIONS_THEMES_COLOR=ΧÏώμα
+
+SING_OPTIONS_RECORD_WHEREAMI=Επιλογές μικÏοφώνου
+SING_OPTIONS_RECORD_DESC=Ρυθμίσεις μικÏοφώνου
+SING_OPTIONS_RECORD_CARD=ΚάÏτα ήχου
+SING_OPTIONS_RECORD_INPUT=Επιλογή μικÏοφώνου
+SING_OPTIONS_RECORD_CHANNEL=Κανάλι
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Επιλογές για Ï€ÏοχωÏημένους
+SING_OPTIONS_ADVANCED_DESC=Ρυθμίσεις για Ï€ÏοχωÏημένους
+SING_OPTIONS_ADVANCED_EFFECTSING=Εφέ Ï„ÏαγουδιοÏ
+SING_OPTIONS_ADVANCED_SCREENFADE=Σβήσιμο εικόνας
+SING_OPTIONS_ADVANCED_LOADANIMATION=ΦόÏτωση κινοÏμενων εικόνων
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=ΕÏωτήσεις ασφαλείας
+SING_OPTIONS_ADVANCED_LINEBONUS=Μπόνους γÏαμμής
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Μετά απο την επιλογή Ï„ÏαγουδιοÏ
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Αυτόματο Î¼ÎµÎ½Î¿Ï "ΠάÏÏ„Ï…"
+
+SING_EDIT=ΔημιουÏγία
+SING_EDIT_MENU_DESCRIPTION=Φτιάξτε το δικό σας Ï„ÏαγοÏδι
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Εισαγωγή αÏχείου κειμένου
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Πίσω
+SING_EDIT_BUTTON_CONVERT=Εισαγωγή
+SING_EDIT_BUTTON_EXIT=Πίσω
+
+SING_EDIT_NAVIGATE=ΕξεÏέυνηση
+SING_EDIT_SELECT=Επέλεξε
+SING_EDIT_EXIT=Πίσω
+
+SING_LEGEND_SELECT=Επέλεξε
+SING_LEGEND_NAVIGATE=ΕξεÏέυνηση
+SING_LEGEND_CONTINUE=Συνέχισε
+SING_LEGEND_ESC=Πίσω
+
+SING_PLAYER_DESC=ΓÏάψε ονόμα(τα) παιχτ-η/ων
+SING_PLAYER_WHEREAMI=Ονόματα παιχτών
+SING_PLAYER_ENTER_NAME=ΓÏάψε όνομα
+
+SING_DIFFICULTY_DESC=Διάλεξε δυσκολία
+SING_DIFFICULTY_WHEREAMI=Δυσκολία
+SING_DIFFICULTY_CONTINUE=Στην επιλογή Ï„ÏαγουδιοÏ
+SING_EASY=ΕÏκολο
+SING_MEDIUM=ΜέτÏιο
+SING_HARD=ΔÏσκολο
+
+SING_SONG_SELECTION_DESC=Διάλεξε Ï„ÏαγοÏδι
+SING_SONG_SELECTION_WHEREAMI=Επιλογή Ï„ÏαγουδιοÏ
+SING_SONG_SELECTION_GOTO=Πήγαινε σε...
+SING_SONG_SELECTION=Επιλογή Ï„Ïαγουδιου
+SING_SONG_SELECTION_MENU=ΜενοÏ
+SING_SONG_SELECTION_PLAYLIST=Λίστα
+SING_SONGS_IN_CAT=ΤÏαγοÏδια
+PLAYLIST_CATTEXT=Λίστα: %s
+
+SING_TIME=ΧÏόνος
+SING_TOTAL=ΣÏνολο
+SING_MODE=ΤÏαγοÏδα σόλο
+SING_NOTES=Îότες
+SING_GOLDEN_NOTES=ΧÏυσές νότες
+SING_PHRASE_BONUS=Μπόνους γÏαμμής
+
+SING_MENU=ΚÏÏιο μενοÏ
+
+SONG_SCORE=Βαθμολογία Ï„ÏαγουδιοÏ
+SONG_SCORE_WHEREAMI=Βαθμολογία
+
+SING_SCORE_TONE_DEAF=Κακοφωνίξ
+SING_SCORE_AMATEUR=ΑÏχάÏιος
+SING_SCORE_WANNABE=Το θέλει...
+SING_SCORE_HOPEFUL=ΕλπιδοφόÏος
+SING_SCORE_RISING_STAR=ΑνεÏχόμενο αστέÏι
+SING_SCORE_LEAD_SINGER=Επαγγελματίας
+SING_SCORE_SUPERSTAR=ΣοÏπεÏσταÏ
+SING_SCORE_ULTRASTAR=Απόλυτος σταÏ
+
+SING_TOP_5_CHARTS=Οι καλÏτεÏοι 5 παίχτες
+SING_TOP_5_CHARTS_WHEREAMI=Τοπ 5
+SING_TOP_5_CHARTS_CONTINUE=Στην επιλογή Ï„ÏαγουδιοÏ
+
+POPUP_PERFECT=Τέλεια!
+POPUP_AWESOME=Φανταστικά!
+POPUP_GREAT=Î Î¿Î»Ï ÎºÎ±Î»Î¬!
+POPUP_GOOD=Καλά!
+POPUP_NOTBAD=Οχι άσχημα!
+POPUP_BAD=Άσχημα!
+POPUP_POOR=Ï€Î¿Î»Ï Î¬ÏƒÏ‡Î·Î¼Î±!
+POPUP_AWFUL=Απαίσια!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= και
+
+SONG_MENU_NAME_MAIN=ÎœÎµÎ½Î¿Ï Ï„Ïαγουδιών
+SONG_MENU_PLAY=ΤÏαγουδήστε
+SONG_MENU_CHANGEPLAYERS=Αλλάξτε παίχτες
+SONG_MENU_EDIT=ΕπεξεÏγασία
+SONG_MENU_MODI=ΤÏαγουδήστε μιά Ï„Ïοποποίηση
+SONG_MENU_CANCEL=ΑκÏÏωση
+
+SONG_MENU_NAME_PLAYLIST=ÎœÎµÎ½Î¿Ï Ï„ÏαγουδιοÏ
+SONG_MENU_PLAYLIST_ADD=ΠÏόσθεσε Ï„ÏαγοÏδι
+SONG_MENU_PLAYLIST_DEL=ΔιέγÏαψε Ï„ÏαγοÏδι
+
+SONG_MENU_NAME_PLAYLIST_ADD=ΠÏόσθεσε Ï„ÏαγοÏδι
+SONG_MENU_PLAYLIST_ADD_NEW=Σε νέα λίστα
+SONG_MENU_PLAYLIST_ADD_EXISTING=Σε υπάÏχουσα λίστα
+SONG_MENU_PLAYLIST_NOEXISTING=Δεν υπάÏχει διαθέσιμη λίστα
+
+SONG_MENU_NAME_PLAYLIST_NEW=Îέα λίστα
+SONG_MENU_PLAYLIST_NEW_CREATE=Φτιαξε νέα
+SONG_MENU_PLAYLIST_NEW_UNNAMED=ΧωÏίς όνομα
+
+SONG_MENU_NAME_PLAYLIST_DEL=ΔιαγÏαφή?
+SONG_MENU_YES=Îαι
+SONG_MENU_NO=Όχι
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Άνοιξε μια λίστα
+SONG_MENU_PLAYLIST_LOAD=Άνοιξε
+SONG_MENU_PLAYLIST_DELCURRENT=ΔιέγÏαψε αυτή τη λίστα
+
+SONG_MENU_NAME_PLAYLIST_DEL=ΔιαγÏαφή λίστας?
+
+SONG_MENU_NAME_PARTY_MAIN=ÎœÎµÎ½Î¿Ï "ΠάÏÏ„Ï…"
+SONG_MENU_JOKER=ΜπαλαντέÏ
+
+SONG_MENU_NAME_PARTY_JOKER=Επιλογή μπαλαντέÏ
+
+SONG_JUMPTO_DESC=Ψάξε Ï„ÏαγοÏδι
+SONG_JUMPTO_TYPE_DESC=Ψάξε για:
+SONG_JUMPTO_TYPE1=Όλα
+SONG_JUMPTO_TYPE2=Τίτλος
+SONG_JUMPTO_TYPE3=Καλλιτέχνης
+SONG_JUMPTO_SONGSFOUND=%d ΤÏαγοÏδι(α) βÏέθηκαν
+SONG_JUMPTO_NOSONGSFOUND=Δεν βÏέθηκε Ï„ÏαγοÏδι
+SONG_JUMPTO_HELP=ΓÏάψε κείμενο για αναζήτηση
+SONG_JUMPTO_CATTEXT=Αναζήτηση για: %s
+
+PARTY_MODE=Είδος Ï€Î±Î¹Ï‡Î½Î¹Î´Î¹Î¿Ï "ΠάÏÏ„Ï…"
+PARTY_DIFFICULTY=Δυσκολία
+PARTY_PLAYLIST=Παίξε με μία λίστα
+PARTY_PLAYLIST_ALL=Όλα τα Ï„ÏαγοÏδια
+PARTY_PLAYLIST_CATEGORY=Φάκελος
+PARTY_PLAYLIST_PLAYLIST=Λίστα
+PARTY_ROUNDS=ΓÏÏοι
+PARTY_TEAMS=Ομάδες
+PARTY_TEAMS_PLAYER1=Παίχτης ομάδα1
+PARTY_TEAMS_PLAYER2=Παίχτης ομάδα2
+PARTY_TEAMS_PLAYER3=Παίχτης ομάδα3
+
+PARTY_LEGEND_CONTINUE=Συνέχεια
+
+PARTY_OPTIONS_DESC=Επιλογές για το παιχνίδι "ΠάÏÏ„Ï…"
+PARTY_OPTIONS_WHEREAMI=Επιλογές "ΠάÏÏ„Ï…"
+
+PARTY_PLAYER_DESC=ΓÏάψε ονόματα παιχτών και ομάδων
+PARTY_PLAYER_WHEREAMI=Ονόματα "ΠάÏÏ„Ï…"
+PARTY_PLAYER_ENTER_NAME=ΓÏάψε ονόματα
+PARTY_PLAYER_LEGEND_CONTINUE=Ξεκίνα το παιχνίδι "ΠάÏÏ„Ï…"
+
+PARTY_ROUND_DESC=Επόμενοι παίχτες
+PARTY_ROUND_WHEREAMI=Επόμενος γÏÏος "ΠάÏÏ„Ï…"
+PARTY_ROUND_LEGEND_CONTINUE=Ξεκίνα το γÏÏο
+
+PARTY_SONG_WHEREAMI=Επιλογή Ï„ÏÎ±Î³Î¿Ï…Î´Î¹Î¿Ï "ΠάÏÏ„Ï…"
+PARTY_SONG_LEGEND_CONTINUE=ΤÏαγουδήστε
+PARTY_SONG_MENU=ÎœÎµÎ½Î¿Ï "ΠάÏÏ„Ï…"
+
+PARTY_SCORE_DESC=Βαθμολογία τελευταίου γÏÏου
+PARTY_SCORE_WHEREAMI=Βαθμοί "ΠάÏÏ„Ï…"
+
+PARTY_WIN_DESC=Îικητής του Ï€Î±Î¹Ï‡Î½Î¹Î´Î¹Î¿Ï "ΠάÏÏ„Ï…"
+PARTY_WIN_WHEREAMI=Îικητής "ΠάÏÏ„Ï…"
+PARTY_WIN_LEGEND_CONTINUE=ΕπιστÏοφή στο κÏÏιο μενοÏ
+
+PARTY_ROUND=ΓÏÏος
+PARTY_ROUND_WINNER=Îικητής
+PARTY_NOTPLAYEDYET=Δεν παίχτηκε ακόμη
+PARTY_NOBODY=Κανείς
+NEXT_ROUND=Επόμενος ΓÏÏος:
+
+PARTY_DISMISSED=Αποβολή!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=Îίκησε!
+
+PLUGIN_HDL_NAME=Μείνε πάνω από τη μπάÏα!
+PLUGIN_HDL_DESC=Μείνε πάνω από τη μπάÏα που εμφανίζεται
+
+PLUGIN_UNTIL5000_NAME=ΜέχÏι 5000 πόντους
+PLUGIN_UNTIL5000_DESC=Όποιος φτάσει τους 5000 πόντους κεÏδίζει
+
+PLUGIN_DUELL_NAME=Μονομαχία
+PLUGIN_DUELL_DESC=ΤÏαγουδήστε σε μονομαχία μέχÏι τους 10000 πόντους
+
+PLUGIN_TEAMDUELL_NAME=Μονομαχία ομάδων
+PLUGIN_TEAMDUELL_DESC=Δώσε το μικÏόφωνο!
+
+PLUGIN_BLIND_NAME=Στα τυφλά
+PLUGIN_BLIND_DESC=Μονομαχία χωÏίς να βλέπετε τις νότες
+
+STAT_MAIN=Στατιστικά
+STAT_MAIN_DESC=ΚÏÏια
+STAT_MAIN_WHEREAMI=Στατιστικά
+
+STAT_OVERVIEW_INTRO=%0:s Στατιστικά. \n Τελευταία έξοδος στίς %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Ï„ÏαγοÏδια(%3:d με βίντεο), άπο τα οποία %1:d έχουν παιχτεί ήδη και %2:d δεν έχουν παιχτεί ακόμη.\n Το πιο δημοφιλές Ï„ÏαγοÏδι είναι %5:s από %4:s.
+STAT_OVERVIEW_PLAYER=Από το τελευταίο σβήσιμο υπάÏχει-ουν %0:d παίχτης-ες .\n Ο καλÏτεÏος παίχτης είναι %1:s με μέσο ÏŒÏο βαθμολογίας %2:d βαθμοÏÏ‚.\n %3:s έκανε τη μεγαλÏτεÏη βαθμολογία με %4:d βαθμοÏÏ‚.
+
+STAT_DETAIL=Στατιστικά
+STAT_DETAIL_WHEREAMI=ΛεπτομεÏή στατιστικά
+
+STAT_NEXT=Επόμενη Σελίδα
+STAT_PREV=ΠÏοηγοÏμενη σελίδα
+STAT_REVERSE=ΑντίστÏοφα
+STAT_PAGE=Seite %0:d από %1:d σελίδες\n (%2:d of %3:d εισαγωγές)
+
+STAT_DESC_SCORES=ΥψηλότεÏες Βαθμολογίες
+STAT_DESC_SCORES_REVERSED=ΧαμηλότεÏες βαθμολογίες
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=ΚαλÏτεÏοι Ï„Ïαγουδιστές
+STAT_DESC_SINGERS_REVERSED=ΧειÏότεÏοι Ï„Ïαγουδιστές
+STAT_FORMAT_SINGERS=%0:s \n Μέσος ÏŒÏος βαθμολογίας: %1:d
+
+STAT_DESC_SONGS=Πιο δημοφιλή Ï„ÏαγοÏδια
+STAT_DESC_SONGS_REVERSED=ΛιγότεÏο δημοφιλή Ï„ÏαγοÏδια
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx Ï„Ïαγουδήθηκαν
+
+STAT_DESC_BANDS=Πιο δημοφιλής μπάντες
+STAT_DESC_BANDS_REVERSED=ΛιγότεÏο δημοφιλής μπάντες
+STAT_FORMAT_BANDS=%0:s \n %1:dx Ï„Ïαγουδήθηκαν
+
+MSG_ERROR_TITLE=Σφάλμα
+MSG_QUESTION_TITLE=ΕÏώτηση
+MSG_QUIT_USDX=Έξοδος από το παιχνίδι?
+MSG_END_PARTY=Έξοδος απο το παιχνίδι "ΠάÏÏ„Ï…"?
+ERROR_NO_SONGS=Δεν φοÏτώθηκαν Ï„ÏαγοÏδια
+ERROR_NO_PLUGINS=Δεν φοÏτώθηκαν βοηθητικές εφαÏμογές
+ERROR_CORRUPT_SONG=Τα Ï„ÏαγοÏδια δεν ήταν δυνατό να φοÏτώσουν
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Το Ï„ÏαγοÏδι δεν ήταν δυνατό να φοÏτώσει: Το αÏχείο δεν βÏέθηκε
+ERROR_CORRUPT_SONG_NO_NOTES=Το Ï„ÏαγοÏδι δεν ήταν δυνατό να φοÏτώσει: Δεν βÏέθηκαν νότες
+ERROR_CORRUPT_SONG_NO_BREAKS=Το Ï„ÏαγοÏδι δεν ήταν δυνατό να φοÏτώσει: Δεν βÏέθηκαν κενά ανάμεσα στις νότες
+ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Το Ï„ÏαγοÏδι δεν ήταν δυνατό να φοÏτώσει: Λάθος στην επικόληση της γÏαμμής %0:d \ No newline at end of file
diff --git a/game/languages/Italian.ini b/game/languages/Italian.ini
index 8368794c..2282899c 100644
--- a/game/languages/Italian.ini
+++ b/game/languages/Italian.ini
@@ -1,4 +1,4 @@
-[Text]
+[Text]
OPTION_VALUE_CATALAN=Catalan
OPTION_VALUE_CROATIAN=Croatian
OPTION_VALUE_DUTCH=Dutch
@@ -77,12 +77,12 @@ OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
SING_LOADING=Caricamento...
-SING_CHOOSE_MODE=scegli modalità
+SING_CHOOSE_MODE=scegli modalità
SING_SING=canta
SING_SING_DESC=quick game: canta da solo o duetta
SING_MULTI=party
-SING_MULTI_DESC=canta in modalità party
+SING_MULTI_DESC=canta in modalità party
SING_TOOLS=strumenti
@@ -114,7 +114,7 @@ SING_OPTIONS_EXIT=indietro
SING_OPTIONS_GAME_WHEREAMI=Impostazioni Gioco
SING_OPTIONS_GAME_DESC=impostazioni generali di gioco
SING_OPTIONS_GAME_PLAYERS=Giocatori
-SING_OPTIONS_GAME_DIFFICULTY=Difficultà
+SING_OPTIONS_GAME_DIFFICULTY=Difficultà
SING_OPTIONS_GAME_LANGUAGE=Lingua
SING_OPTIONS_GAME_TABS=Schede
SING_OPTIONS_GAME_SORTING=Ordinamento
@@ -124,7 +124,7 @@ SING_OPTIONS_GRAPHICS_WHEREAMI=Impostazioni Grafica
SING_OPTIONS_GRAPHICS_DESC=impostazioni grafica
SING_OPTIONS_GRAPHICS_RESOLUTION=Risoluzione
SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullscreen
-SING_OPTIONS_GRAPHICS_DEPTH=Profondità
+SING_OPTIONS_GRAPHICS_DEPTH=Profondità
SING_OPTIONS_GRAPHICS_VISUALIZER=Visualizzazioni
SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscopio
SING_OPTIONS_GRAPHICS_LINEBONUS=Linee Bonus
@@ -138,7 +138,7 @@ SING_OPTIONS_SOUND_MIC_BOOST=Potenzia microfono
SING_OPTIONS_SOUND_CLICK_ASSIST=Click di Assistenza
SING_OPTIONS_SOUND_BEAT_CLICK=Click di Beat
SING_OPTIONS_SOUND_THRESHOLD=Soglia
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Modalità due giocatori
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Modalità due giocatori
SING_OPTIONS_SOUND_PREVIEWVOLUME=Volume Anteprima
SING_OPTIONS_SOUND_PREVIEWFADING=Fading Anteprima
@@ -193,8 +193,8 @@ SING_PLAYER_DESC=inserisci nome/i giocatore/i
SING_PLAYER_WHEREAMI=Nomi giocatori
SING_PLAYER_ENTER_NAME=inserisci nome
-SING_DIFFICULTY_DESC=seleziona difficoltà
-SING_DIFFICULTY_WHEREAMI=Difficultà
+SING_DIFFICULTY_DESC=seleziona difficoltà
+SING_DIFFICULTY_WHEREAMI=Difficultà
SING_DIFFICULTY_CONTINUE=per cantare seleziona
SING_EASY=Facile
SING_MEDIUM=Media
@@ -267,7 +267,7 @@ SONG_MENU_PLAYLIST_NEW_CREATE=Crea
SONG_MENU_PLAYLIST_NEW_UNNAMED=Senza Nome
SONG_MENU_NAME_PLAYLIST_DELITEM=Vuoi davvero eliminare?
-SONG_MENU_YES=Sì
+SONG_MENU_YES=Sì
SONG_MENU_NO=No
SONG_MENU_NAME_PLAYLIST_LOAD=Apri Playlist
@@ -291,9 +291,9 @@ SONG_JUMPTO_NOSONGSFOUND=Nessuna Canzone trovata
SONG_JUMPTO_HELP=Scrivi il Testo da Cercare:
SONG_JUMPTO_CATTEXT=Cerca per: %s
-PARTY_MODE=modalità party
-PARTY_DIFFICULTY=Difficultà
-PARTY_PLAYLIST=Modalità Playlist
+PARTY_MODE=modalità party
+PARTY_DIFFICULTY=Difficultà
+PARTY_PLAYLIST=Modalità Playlist
PARTY_PLAYLIST_ALL=Tutte le Canzoni
PARTY_PLAYLIST_CATEGORY=Cartella
PARTY_PLAYLIST_PLAYLIST=Playlist
@@ -350,7 +350,7 @@ PLUGIN_DUELL_DESC=Canta in duello fino a 10000 punti.
PLUGIN_TEAMDUELL_NAME=Duello a Team
PLUGIN_TEAMDUELL_DESC=Passa il Microfono!
-PLUGIN_BLIND_NAME=Modalità Ceca
+PLUGIN_BLIND_NAME=Modalità Ceca
PLUGIN_BLIND_DESC=Duella senza vedere le note.
STAT_MAIN=Statistiche
@@ -358,8 +358,8 @@ STAT_MAIN_DESC=Generale
STAT_MAIN_WHEREAMI=Statistiche
STAT_OVERVIEW_INTRO=%0:s Statistiche. \n Ultimo Azzeramento a %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Canzoni(%3:d con Video), delle quali %1:d sono state già cantate e %2:d non lo sono ancora state.\n La Canzone più popolare è %5:s di %4:s.
-STAT_OVERVIEW_PLAYER=Dall''ultimo Azzeramente c''è/ci sono stato/i %0:d Giocatore/i differente/i.\n Il migliore Giocatore è %1:s con un Punteggio medio di %2:d Punti.\n %3:s ha fatto il Punteggio pià alto con %4:d Punti.
+STAT_OVERVIEW_SONG=%0:d Canzoni(%3:d con Video), delle quali %1:d sono state già cantate e %2:d non lo sono ancora state.\n La Canzone più popolare è %5:s di %4:s.
+STAT_OVERVIEW_PLAYER=Dall''ultimo Azzeramente c''è/ci sono stato/i %0:d Giocatore/i differente/i.\n Il migliore Giocatore è %1:s con un Punteggio medio di %2:d Punti.\n %3:s ha fatto il Punteggio pià alto con %4:d Punti.
STAT_DETAIL=Statistiche
STAT_DETAIL_WHEREAMI=Dettagli Statistiche
@@ -377,21 +377,21 @@ STAT_DESC_SINGERS=Cantanti Migliori
STAT_DESC_SINGERS_REVERSED=Cantanti Peggiori
STAT_FORMAT_SINGERS=%0:s \n Punteggio Medio: %1:d
-STAT_DESC_SONGS=La Canzone più popolare
+STAT_DESC_SONGS=La Canzone più popolare
STAT_DESC_SONGS_REVERSED=La Canzone meno popolare
STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx Cantate
-STAT_DESC_BANDS=Le Bands più popolari
+STAT_DESC_BANDS=Le Bands più popolari
STAT_DESC_BANDS_REVERSED=Le Bands meno popolari
STAT_FORMAT_BANDS=%0:s \n %1:dx Cantate
MSG_ERROR_TITLE=Errore
MSG_QUESTION_TITLE=Domanda
MSG_QUIT_USDX=Vuoi davvero uscire da UltraStar?
-MSG_END_PARTY=Vuoi davvero terminare la Modalità Party?
+MSG_END_PARTY=Vuoi davvero terminare la Modalità Party?
ERROR_NO_SONGS=Nessuna Canzone caricata
ERROR_NO_PLUGINS=Nessun Plugin caricato
-ERROR_CORRUPT_SONG=La canzone non è stata caricata.
+ERROR_CORRUPT_SONG=La canzone non è stata caricata.
ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Impossibile aprire la canzone: File non trovato
ERROR_CORRUPT_SONG_NO_NOTES=Impossibile aprire la canzone: Nessuna nota trovata
ERROR_CORRUPT_SONG_NO_BREAKS=Impossibile aprire la canzone: Nessuna interruzione di linea trovata
diff --git a/game/languages/Japanese.ini b/game/languages/Japanese.ini
index 76d41ef2..98221adf 100644
--- a/game/languages/Japanese.ini
+++ b/game/languages/Japanese.ini
Binary files differ
diff --git a/game/languages/Portuguese.ini b/game/languages/Portuguese.ini
index 9fe91d3b..08149355 100644
--- a/game/languages/Portuguese.ini
+++ b/game/languages/Portuguese.ini
@@ -1,398 +1,398 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=A Ler...
-
-SING_CHOOSE_MODE=Escolha o Modo
-SING_SING=Cantar
-SING_SING_DESC=Jogo Rápido: cantar a Solo ou em Dueto
-
-SING_MULTI=Festa
-SING_MULTI_DESC=Cantar em Modo Festa
-
-SING_TOOLS=Ferramentas
-
-SING_STATS=Estatísticas
-SING_STATS_DESC=Ver Estatísticas
-
-SING_EDITOR=Editor
-SING_EDITOR_DESC=Criar canção
-
-SING_GAME_OPTIONS=Opções de Jogo
-SING_GAME_OPTIONS_DESC=Alterar configurações de Jogo
-
-SING_EXIT=Sair
-SING_EXIT_DESC=Sair do Jogo
-
-SING_OPTIONS=Opções
-SING_OPTIONS_DESC=Alterar configurações
-SING_OPTIONS_WHEREAMI=Opções
-
-SING_OPTIONS_GAME=Jogo
-SING_OPTIONS_GRAPHICS=Gráficos
-SING_OPTIONS_SOUND=Som
-SING_OPTIONS_LYRICS=Letras
-SING_OPTIONS_THEMES=Temas
-SING_OPTIONS_RECORD=Gravação
-SING_OPTIONS_ADVANCED=Avançado
-SING_OPTIONS_EXIT=Voltar
-
-SING_OPTIONS_GAME_WHEREAMI=Opções de Jogo
-SING_OPTIONS_GAME_DESC=Configurações Gerais do Jogo
-SING_OPTIONS_GAME_PLAYERS=Jogadores
-SING_OPTIONS_GAME_DIFFICULTY=Dificuldade
-SING_OPTIONS_GAME_LANGUAGE=Idioma
-SING_OPTIONS_GAME_TABS=Subpastas
-SING_OPTIONS_GAME_SORTING=Ordenação
-SING_OPTIONS_GAME_DEBUG=Modo Debug
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Opção de Gráficos
-SING_OPTIONS_GRAPHICS_DESC=Configuração dos Gráficos
-SING_OPTIONS_GRAPHICS_RESOLUTION=Resolução
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Ecrã Total
-SING_OPTIONS_GRAPHICS_DEPTH=Profundidade
-SING_OPTIONS_GRAPHICS_VISUALIZER=Visualizador
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloscópio
-SING_OPTIONS_GRAPHICS_LINEBONUS=Linha Bonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Tamanho do Vídeo
-
-SING_OPTIONS_SOUND_WHEREAMI=Opções de Som
-SING_OPTIONS_SOUND_DESC=Configuração do Som
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Playback Microfone
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Música de Fundo
-SING_OPTIONS_SOUND_MIC_BOOST=Microfone Boost
-SING_OPTIONS_SOUND_CLICK_ASSIST=Click de Ajuda
-SING_OPTIONS_SOUND_BEAT_CLICK=Click de Batida
-SING_OPTIONS_SOUND_THRESHOLD=Threshold
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Modo de dois jogadores
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Preview Volume
-SING_OPTIONS_SOUND_PREVIEWFADING=Preview Fading
-
-SING_OPTIONS_LYRICS_WHEREAMI=Opções de Letras
-SING_OPTIONS_LYRICS_DESC=Configuração de Letras
-SING_OPTIONS_LYRICS_FONT=Fonte
-SING_OPTIONS_LYRICS_EFFECT=Efeitos
-SING_OPTIONS_LYRICS_SOLMIZATION=Solfejo
-SING_OPTIONS_LYRICS_NOTELINES=Pauta
-
-SING_OPTIONS_THEMES_WHEREAMI=Opção de Tema
-SING_OPTIONS_THEMES_DESC=Configuração de tema e skin
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Côr
-
-SING_OPTIONS_RECORD_WHEREAMI=Opções de Gravação
-SING_OPTIONS_RECORD_DESC=Configuração do Microfone
-SING_OPTIONS_RECORD_CARD=Placa de Som
-SING_OPTIONS_RECORD_INPUT=Entrada
-SING_OPTIONS_RECORD_CHANNEL=Canal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Opções Avançadas
-SING_OPTIONS_ADVANCED_DESC=Outras Opções
-SING_OPTIONS_ADVANCED_EFFECTSING=Efeitos
-SING_OPTIONS_ADVANCED_SCREENFADE=Fade do Ecrã
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animação
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Segurança
-SING_OPTIONS_ADVANCED_LINEBONUS=Linha de Bónus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Escolha da Canção
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Menu de Festa
-
-SING_EDIT=Editor
-SING_EDIT_MENU_DESCRIPTION=Cria a tua própria canção
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importar texto de um arquivo MIDI
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Voltar
-SING_EDIT_BUTTON_CONVERT=Importar
-SING_EDIT_BUTTON_EXIT=Voltar
-
-SING_EDIT_NAVIGATE=Navegar
-SING_EDIT_SELECT=Seleccionar
-SING_EDIT_EXIT=Voltar
-
-SING_LEGEND_SELECT=Seleccionar
-SING_LEGEND_NAVIGATE=Navegar
-SING_LEGEND_CONTINUE=Continuar
-SING_LEGEND_ESC=Voltar
-
-SING_PLAYER_DESC=Introduza o(s) nome(s) do(s) jogador(es)
-SING_PLAYER_WHEREAMI=Nome dos Jogadores
-SING_PLAYER_ENTER_NAME=Introduzir Nome
-
-SING_DIFFICULTY_DESC=Nível de Dificuldade
-SING_DIFFICULTY_WHEREAMI=Dificuldade
-SING_DIFFICULTY_CONTINUE=para a escolha da canção
-SING_EASY=Fácil
-SING_MEDIUM=Médio
-SING_HARD=Difícil
-
-SING_SONG_SELECTION_DESC=Escolha a canção
-SING_SONG_SELECTION_WHEREAMI=Selecção da Canção
-SING_SONG_SELECTION_GOTO=Ir para ..
-SING_SONG_SELECTION=Selecção da Canção
-SING_SONG_SELECTION_MENU=Menu
-SING_SONG_SELECTION_PLAYLIST=Playlist
-SING_SONGS_IN_CAT=Canções
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TEMPO
-SING_TOTAL=Total
-SING_MODE=Cantar a Solo
-SING_NOTES=Notas
-SING_GOLDEN_NOTES=Notas de Ouro
-SING_PHRASE_BONUS=Linha de Bónus
-
-SING_MENU=Menu Principal
-
-SONG_SCORE=Pontuação da Canção
-SONG_SCORE_WHEREAMI=Pontuação
-
-SING_SCORE_TONE_DEAF=Ouvido Mouco
-SING_SCORE_AMATEUR=Amador
-SING_SCORE_WANNABE=Promessa
-SING_SCORE_HOPEFUL=Artista
-SING_SCORE_RISING_STAR=Estrela em Ascenção
-SING_SCORE_LEAD_SINGER=Cantor Principal
-SING_SCORE_SUPERSTAR=SuperStar
-SING_SCORE_ULTRASTAR=UltraStar
-
-SING_TOP_5_CHARTS=5 Melhores Jogadores
-SING_TOP_5_CHARTS_WHEREAMI=Top 5
-SING_TOP_5_CHARTS_CONTINUE=para a escolha da Canção
-
-POPUP_PERFECT=Perfeito!
-POPUP_AWESOME=Fantástico!
-POPUP_GREAT=Óptimo!
-POPUP_GOOD=Bom!
-POPUP_NOTBAD=Nada Mal!
-POPUP_BAD=Mau!
-POPUP_POOR=Péssimo!
-POPUP_AWFUL=Horrível!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= e
-
-SONG_MENU_NAME_MAIN=Menu de canções
-SONG_MENU_PLAY=Cantar
-SONG_MENU_CHANGEPLAYERS=Mudar Jogadores
-SONG_MENU_EDIT=Editar
-SONG_MENU_MODI=Cantar uma Modi
-SONG_MENU_CANCEL=Cancelar
-
-SONG_MENU_NAME_PLAYLIST=Menu de Canções
-SONG_MENU_PLAYLIST_ADD=Adicionar Canção
-SONG_MENU_PLAYLIST_DEL=Apagar Canção
-
-SONG_MENU_NAME_PLAYLIST_ADD=Adicionar Canção
-SONG_MENU_PLAYLIST_ADD_NEW=a uma nova playlist
-SONG_MENU_PLAYLIST_ADD_EXISTING=a uma playlist existente
-SONG_MENU_PLAYLIST_NOEXISTING=Sem playlist disponível
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nova Playlist
-SONG_MENU_PLAYLIST_NEW_CREATE=Criar
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Sem nome
-
-SONG_MENU_NAME_PLAYLIST_DEL=Apagar mesmo?
-SONG_MENU_YES=Sim
-SONG_MENU_NO=Não
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Abrir Playlist
-SONG_MENU_PLAYLIST_LOAD=abrir
-SONG_MENU_PLAYLIST_DELCURRENT=apagar Playlist actual
-
-SONG_MENU_NAME_PLAYLIST_DEL=Apagar Playlist?
-
-SONG_MENU_NAME_PARTY_MAIN=Menu de Festa
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=Usar Joker
-
-SONG_JUMPTO_DESC=Procurar
-SONG_JUMPTO_TYPE_DESC=Procurar por:
-SONG_JUMPTO_TYPE1=Todos
-SONG_JUMPTO_TYPE2=Título
-SONG_JUMPTO_TYPE3=Artista
-SONG_JUMPTO_SONGSFOUND=%d Música(s) encontrada(s)
-SONG_JUMPTO_NOSONGSFOUND=Nenhuma Canção encontrada
-SONG_JUMPTO_HELP=Escreva para procurar
-SONG_JUMPTO_CATTEXT=Procurar por: %s
-
-PARTY_MODE=Modo Festa
-PARTY_DIFFICULTY=Dificuldade
-PARTY_PLAYLIST=Modo Playlist
-PARTY_PLAYLIST_ALL=Todas as Canções
-PARTY_PLAYLIST_CATEGORY=Directório
-PARTY_PLAYLIST_PLAYLIST=Playlist
-PARTY_ROUNDS=Rondas
-PARTY_TEAMS=Equipas
-PARTY_TEAMS_PLAYER1=Jogador Equipa1
-PARTY_TEAMS_PLAYER2=Jogador Equipa2
-PARTY_TEAMS_PLAYER3=Jogador Equipa3
-
-PARTY_LEGEND_CONTINUE=Continuar
-
-PARTY_OPTIONS_DESC=Configurações para o Modo Festa
-PARTY_OPTIONS_WHEREAMI=Opções de Festa
-
-PARTY_PLAYER_DESC=Inserir nomes de jogadores e equipas
-PARTY_PLAYER_WHEREAMI=Nomes de Festa
-PARTY_PLAYER_ENTER_NAME=Inserir nomes
-PARTY_PLAYER_LEGEND_CONTINUE=Iniciar Festa
-
-PARTY_ROUND_DESC=Jogadores seguintes para os microfones
-PARTY_ROUND_WHEREAMI=Ronda seguinte
-PARTY_ROUND_LEGEND_CONTINUE=Inicio da Ronda
-
-PARTY_SONG_WHEREAMI=Escolha da Canção
-PARTY_SONG_LEGEND_CONTINUE=Cantar
-PARTY_SONG_MENU=Menu Festa
-
-PARTY_SCORE_DESC=Pontuação da última ronda
-PARTY_SCORE_WHEREAMI=Pontos da Festa
-
-PARTY_WIN_DESC=Vencedor do Jogo Festa
-PARTY_WIN_WHEREAMI=Vencedor da Festa
-PARTY_WIN_LEGEND_CONTINUE=Voltar ao Menu Principal
-
-PARTY_ROUND=Ronda
-PARTY_ROUND_WINNER=Vencedor
-PARTY_NOTPLAYEDYET=Não tocada
-PARTY_NOBODY=Ninguém
-NEXT_ROUND=Ronda seguinte:
-
-PARTY_DISMISSED=Dispensado!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=Ganhou!
-
-PLUGIN_HDL_NAME=Manter a linha
-PLUGIN_HDL_DESC=Não piorar o ponteiro que é mostrado na barra de pontuação
-
-PLUGIN_UNTIL5000_NAME=Até 5000
-PLUGIN_UNTIL5000_DESC=Quem obter primeiro 5000 pontos ganha a partida
-
-PLUGIN_DUELL_NAME=Duelo
-PLUGIN_DUELL_DESC=Fazer um Duelo até aos 10000 pontos.
-
-PLUGIN_TEAMDUELL_NAME=Duelo de equipa
-PLUGIN_TEAMDUELL_DESC=Passa o Microfone!
-
-PLUGIN_BLIND_NAME=Modo Cego
-PLUGIN_BLIND_DESC=Duelo sem ver as notas.
-
-STAT_MAIN=Estatísticas
-STAT_MAIN_DESC=Geral
-STAT_MAIN_WHEREAMI=Estatísticas
-
-STAT_OVERVIEW_INTRO=%0:s Estatisticas. \n Último Reset a %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Canções(%3:d com Video), das quais %1:d já tocaram e %2:d ainda não tocaram.\n A Canção mais popular é %5:s de %4:s.
-STAT_OVERVIEW_PLAYER=Desde o último Reset houve %0:d Jogador(es) diferente(s).\n O Melhor Jogador é %1:s com a Pontuação Média de %2:d Pontos.\n %3:s teve a Pontuação mais alta com %4:d Pontos.
-
-STAT_DETAIL=Estatísticas
-STAT_DETAIL_WHEREAMI=Estatísticas Detalhadas
-
-STAT_NEXT=Página Seguinte
-STAT_PREV=Página Anterior
-STAT_REVERSE=Ordem Inversa
-STAT_PAGE=%0:d de %1:d Páginas\n (%2:d de %3:d Entradas)
-
-STAT_DESC_SCORES=Pontuções Altas
-STAT_DESC_SCORES_REVERSED=Pontuações Baixas
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Top Cantores
-STAT_DESC_SINGERS_REVERSED=Piores Cantores
-STAT_FORMAT_SINGERS=%0:s \n Pontuação Média: %1:d
-
-STAT_DESC_SONGS=Top Canções
-STAT_DESC_SONGS_REVERSED=Canções Menos Populares
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx Cantaram
-
-STAT_DESC_BANDS=Top Bandas
-STAT_DESC_BANDS_REVERSED=Bandas Menos Populares
-STAT_FORMAT_BANDS=%0:s \n %1:dx Cantaram
-
-MSG_ERROR_TITLE=Erro
-MSG_QUESTION_TITLE=Questão
-MSG_QUIT_USDX=Deseja mesmo sair do UltraStar?
-MSG_END_PARTY=Deseja mesmo terminar o Modo Festa?
-ERROR_NO_SONGS=Nenhuma Canção lida
-ERROR_NO_PLUGINS=Nenhum Plugin lido
-ERROR_CORRUPT_SONG=Canção não pôde ser lida!
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=A canção não foi encontrada!
-ERROR_CORRUPT_SONG_NO_NOTES=A canção não tem notas!
-ERROR_CORRUPT_SONG_NO_BREAKS=A canção não tem quebras de linha!
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=A Ler...
+
+SING_CHOOSE_MODE=Escolha o Modo
+SING_SING=Cantar
+SING_SING_DESC=Jogo Rápido: cantar a Solo ou em Dueto
+
+SING_MULTI=Festa
+SING_MULTI_DESC=Cantar em Modo Festa
+
+SING_TOOLS=Ferramentas
+
+SING_STATS=Estatísticas
+SING_STATS_DESC=Ver Estatísticas
+
+SING_EDITOR=Editor
+SING_EDITOR_DESC=Criar canção
+
+SING_GAME_OPTIONS=Opções de Jogo
+SING_GAME_OPTIONS_DESC=Alterar configurações de Jogo
+
+SING_EXIT=Sair
+SING_EXIT_DESC=Sair do Jogo
+
+SING_OPTIONS=Opções
+SING_OPTIONS_DESC=Alterar configurações
+SING_OPTIONS_WHEREAMI=Opções
+
+SING_OPTIONS_GAME=Jogo
+SING_OPTIONS_GRAPHICS=Gráficos
+SING_OPTIONS_SOUND=Som
+SING_OPTIONS_LYRICS=Letras
+SING_OPTIONS_THEMES=Temas
+SING_OPTIONS_RECORD=Gravação
+SING_OPTIONS_ADVANCED=Avançado
+SING_OPTIONS_EXIT=Voltar
+
+SING_OPTIONS_GAME_WHEREAMI=Opções de Jogo
+SING_OPTIONS_GAME_DESC=Configurações Gerais do Jogo
+SING_OPTIONS_GAME_PLAYERS=Jogadores
+SING_OPTIONS_GAME_DIFFICULTY=Dificuldade
+SING_OPTIONS_GAME_LANGUAGE=Idioma
+SING_OPTIONS_GAME_TABS=Subpastas
+SING_OPTIONS_GAME_SORTING=Ordenação
+SING_OPTIONS_GAME_DEBUG=Modo Debug
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Opção de Gráficos
+SING_OPTIONS_GRAPHICS_DESC=Configuração dos Gráficos
+SING_OPTIONS_GRAPHICS_RESOLUTION=Resolução
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Ecrã Total
+SING_OPTIONS_GRAPHICS_DEPTH=Profundidade
+SING_OPTIONS_GRAPHICS_VISUALIZER=Visualizador
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloscópio
+SING_OPTIONS_GRAPHICS_LINEBONUS=Linha Bonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Tamanho do Vídeo
+
+SING_OPTIONS_SOUND_WHEREAMI=Opções de Som
+SING_OPTIONS_SOUND_DESC=Configuração do Som
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Playback Microfone
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Música de Fundo
+SING_OPTIONS_SOUND_MIC_BOOST=Microfone Boost
+SING_OPTIONS_SOUND_CLICK_ASSIST=Click de Ajuda
+SING_OPTIONS_SOUND_BEAT_CLICK=Click de Batida
+SING_OPTIONS_SOUND_THRESHOLD=Threshold
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Modo de dois jogadores
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Preview Volume
+SING_OPTIONS_SOUND_PREVIEWFADING=Preview Fading
+
+SING_OPTIONS_LYRICS_WHEREAMI=Opções de Letras
+SING_OPTIONS_LYRICS_DESC=Configuração de Letras
+SING_OPTIONS_LYRICS_FONT=Fonte
+SING_OPTIONS_LYRICS_EFFECT=Efeitos
+SING_OPTIONS_LYRICS_SOLMIZATION=Solfejo
+SING_OPTIONS_LYRICS_NOTELINES=Pauta
+
+SING_OPTIONS_THEMES_WHEREAMI=Opção de Tema
+SING_OPTIONS_THEMES_DESC=Configuração de tema e skin
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Côr
+
+SING_OPTIONS_RECORD_WHEREAMI=Opções de Gravação
+SING_OPTIONS_RECORD_DESC=Configuração do Microfone
+SING_OPTIONS_RECORD_CARD=Placa de Som
+SING_OPTIONS_RECORD_INPUT=Entrada
+SING_OPTIONS_RECORD_CHANNEL=Canal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Opções Avançadas
+SING_OPTIONS_ADVANCED_DESC=Outras Opções
+SING_OPTIONS_ADVANCED_EFFECTSING=Efeitos
+SING_OPTIONS_ADVANCED_SCREENFADE=Fade do Ecrã
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animação
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Segurança
+SING_OPTIONS_ADVANCED_LINEBONUS=Linha de Bónus
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Escolha da Canção
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Menu de Festa
+
+SING_EDIT=Editor
+SING_EDIT_MENU_DESCRIPTION=Cria a tua própria canção
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importar texto de um arquivo MIDI
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Voltar
+SING_EDIT_BUTTON_CONVERT=Importar
+SING_EDIT_BUTTON_EXIT=Voltar
+
+SING_EDIT_NAVIGATE=Navegar
+SING_EDIT_SELECT=Seleccionar
+SING_EDIT_EXIT=Voltar
+
+SING_LEGEND_SELECT=Seleccionar
+SING_LEGEND_NAVIGATE=Navegar
+SING_LEGEND_CONTINUE=Continuar
+SING_LEGEND_ESC=Voltar
+
+SING_PLAYER_DESC=Introduza o(s) nome(s) do(s) jogador(es)
+SING_PLAYER_WHEREAMI=Nome dos Jogadores
+SING_PLAYER_ENTER_NAME=Introduzir Nome
+
+SING_DIFFICULTY_DESC=Nível de Dificuldade
+SING_DIFFICULTY_WHEREAMI=Dificuldade
+SING_DIFFICULTY_CONTINUE=para a escolha da canção
+SING_EASY=Fácil
+SING_MEDIUM=Médio
+SING_HARD=Difícil
+
+SING_SONG_SELECTION_DESC=Escolha a canção
+SING_SONG_SELECTION_WHEREAMI=Selecção da Canção
+SING_SONG_SELECTION_GOTO=Ir para ..
+SING_SONG_SELECTION=Selecção da Canção
+SING_SONG_SELECTION_MENU=Menu
+SING_SONG_SELECTION_PLAYLIST=Playlist
+SING_SONGS_IN_CAT=Canções
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TEMPO
+SING_TOTAL=Total
+SING_MODE=Cantar a Solo
+SING_NOTES=Notas
+SING_GOLDEN_NOTES=Notas de Ouro
+SING_PHRASE_BONUS=Linha de Bónus
+
+SING_MENU=Menu Principal
+
+SONG_SCORE=Pontuação da Canção
+SONG_SCORE_WHEREAMI=Pontuação
+
+SING_SCORE_TONE_DEAF=Ouvido Mouco
+SING_SCORE_AMATEUR=Amador
+SING_SCORE_WANNABE=Promessa
+SING_SCORE_HOPEFUL=Artista
+SING_SCORE_RISING_STAR=Estrela em Ascenção
+SING_SCORE_LEAD_SINGER=Cantor Principal
+SING_SCORE_SUPERSTAR=SuperStar
+SING_SCORE_ULTRASTAR=UltraStar
+
+SING_TOP_5_CHARTS=5 Melhores Jogadores
+SING_TOP_5_CHARTS_WHEREAMI=Top 5
+SING_TOP_5_CHARTS_CONTINUE=para a escolha da Canção
+
+POPUP_PERFECT=Perfeito!
+POPUP_AWESOME=Fantástico!
+POPUP_GREAT=Óptimo!
+POPUP_GOOD=Bom!
+POPUP_NOTBAD=Nada Mal!
+POPUP_BAD=Mau!
+POPUP_POOR=Péssimo!
+POPUP_AWFUL=Horrível!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= e
+
+SONG_MENU_NAME_MAIN=Menu de canções
+SONG_MENU_PLAY=Cantar
+SONG_MENU_CHANGEPLAYERS=Mudar Jogadores
+SONG_MENU_EDIT=Editar
+SONG_MENU_MODI=Cantar uma Modi
+SONG_MENU_CANCEL=Cancelar
+
+SONG_MENU_NAME_PLAYLIST=Menu de Canções
+SONG_MENU_PLAYLIST_ADD=Adicionar Canção
+SONG_MENU_PLAYLIST_DEL=Apagar Canção
+
+SONG_MENU_NAME_PLAYLIST_ADD=Adicionar Canção
+SONG_MENU_PLAYLIST_ADD_NEW=a uma nova playlist
+SONG_MENU_PLAYLIST_ADD_EXISTING=a uma playlist existente
+SONG_MENU_PLAYLIST_NOEXISTING=Sem playlist disponível
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nova Playlist
+SONG_MENU_PLAYLIST_NEW_CREATE=Criar
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Sem nome
+
+SONG_MENU_NAME_PLAYLIST_DEL=Apagar mesmo?
+SONG_MENU_YES=Sim
+SONG_MENU_NO=Não
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Abrir Playlist
+SONG_MENU_PLAYLIST_LOAD=abrir
+SONG_MENU_PLAYLIST_DELCURRENT=apagar Playlist actual
+
+SONG_MENU_NAME_PLAYLIST_DEL=Apagar Playlist?
+
+SONG_MENU_NAME_PARTY_MAIN=Menu de Festa
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=Usar Joker
+
+SONG_JUMPTO_DESC=Procurar
+SONG_JUMPTO_TYPE_DESC=Procurar por:
+SONG_JUMPTO_TYPE1=Todos
+SONG_JUMPTO_TYPE2=Título
+SONG_JUMPTO_TYPE3=Artista
+SONG_JUMPTO_SONGSFOUND=%d Música(s) encontrada(s)
+SONG_JUMPTO_NOSONGSFOUND=Nenhuma Canção encontrada
+SONG_JUMPTO_HELP=Escreva para procurar
+SONG_JUMPTO_CATTEXT=Procurar por: %s
+
+PARTY_MODE=Modo Festa
+PARTY_DIFFICULTY=Dificuldade
+PARTY_PLAYLIST=Modo Playlist
+PARTY_PLAYLIST_ALL=Todas as Canções
+PARTY_PLAYLIST_CATEGORY=Directório
+PARTY_PLAYLIST_PLAYLIST=Playlist
+PARTY_ROUNDS=Rondas
+PARTY_TEAMS=Equipas
+PARTY_TEAMS_PLAYER1=Jogador Equipa1
+PARTY_TEAMS_PLAYER2=Jogador Equipa2
+PARTY_TEAMS_PLAYER3=Jogador Equipa3
+
+PARTY_LEGEND_CONTINUE=Continuar
+
+PARTY_OPTIONS_DESC=Configurações para o Modo Festa
+PARTY_OPTIONS_WHEREAMI=Opções de Festa
+
+PARTY_PLAYER_DESC=Inserir nomes de jogadores e equipas
+PARTY_PLAYER_WHEREAMI=Nomes de Festa
+PARTY_PLAYER_ENTER_NAME=Inserir nomes
+PARTY_PLAYER_LEGEND_CONTINUE=Iniciar Festa
+
+PARTY_ROUND_DESC=Jogadores seguintes para os microfones
+PARTY_ROUND_WHEREAMI=Ronda seguinte
+PARTY_ROUND_LEGEND_CONTINUE=Inicio da Ronda
+
+PARTY_SONG_WHEREAMI=Escolha da Canção
+PARTY_SONG_LEGEND_CONTINUE=Cantar
+PARTY_SONG_MENU=Menu Festa
+
+PARTY_SCORE_DESC=Pontuação da última ronda
+PARTY_SCORE_WHEREAMI=Pontos da Festa
+
+PARTY_WIN_DESC=Vencedor do Jogo Festa
+PARTY_WIN_WHEREAMI=Vencedor da Festa
+PARTY_WIN_LEGEND_CONTINUE=Voltar ao Menu Principal
+
+PARTY_ROUND=Ronda
+PARTY_ROUND_WINNER=Vencedor
+PARTY_NOTPLAYEDYET=Não tocada
+PARTY_NOBODY=Ninguém
+NEXT_ROUND=Ronda seguinte:
+
+PARTY_DISMISSED=Dispensado!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=Ganhou!
+
+PLUGIN_HDL_NAME=Manter a linha
+PLUGIN_HDL_DESC=Não piorar o ponteiro que é mostrado na barra de pontuação
+
+PLUGIN_UNTIL5000_NAME=Até 5000
+PLUGIN_UNTIL5000_DESC=Quem obter primeiro 5000 pontos ganha a partida
+
+PLUGIN_DUELL_NAME=Duelo
+PLUGIN_DUELL_DESC=Fazer um Duelo até aos 10000 pontos.
+
+PLUGIN_TEAMDUELL_NAME=Duelo de equipa
+PLUGIN_TEAMDUELL_DESC=Passa o Microfone!
+
+PLUGIN_BLIND_NAME=Modo Cego
+PLUGIN_BLIND_DESC=Duelo sem ver as notas.
+
+STAT_MAIN=Estatísticas
+STAT_MAIN_DESC=Geral
+STAT_MAIN_WHEREAMI=Estatísticas
+
+STAT_OVERVIEW_INTRO=%0:s Estatisticas. \n Último Reset a %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Canções(%3:d com Video), das quais %1:d já tocaram e %2:d ainda não tocaram.\n A Canção mais popular é %5:s de %4:s.
+STAT_OVERVIEW_PLAYER=Desde o último Reset houve %0:d Jogador(es) diferente(s).\n O Melhor Jogador é %1:s com a Pontuação Média de %2:d Pontos.\n %3:s teve a Pontuação mais alta com %4:d Pontos.
+
+STAT_DETAIL=Estatísticas
+STAT_DETAIL_WHEREAMI=Estatísticas Detalhadas
+
+STAT_NEXT=Página Seguinte
+STAT_PREV=Página Anterior
+STAT_REVERSE=Ordem Inversa
+STAT_PAGE=%0:d de %1:d Páginas\n (%2:d de %3:d Entradas)
+
+STAT_DESC_SCORES=Pontuções Altas
+STAT_DESC_SCORES_REVERSED=Pontuações Baixas
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Top Cantores
+STAT_DESC_SINGERS_REVERSED=Piores Cantores
+STAT_FORMAT_SINGERS=%0:s \n Pontuação Média: %1:d
+
+STAT_DESC_SONGS=Top Canções
+STAT_DESC_SONGS_REVERSED=Canções Menos Populares
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx Cantaram
+
+STAT_DESC_BANDS=Top Bandas
+STAT_DESC_BANDS_REVERSED=Bandas Menos Populares
+STAT_FORMAT_BANDS=%0:s \n %1:dx Cantaram
+
+MSG_ERROR_TITLE=Erro
+MSG_QUESTION_TITLE=Questão
+MSG_QUIT_USDX=Deseja mesmo sair do UltraStar?
+MSG_END_PARTY=Deseja mesmo terminar o Modo Festa?
+ERROR_NO_SONGS=Nenhuma Canção lida
+ERROR_NO_PLUGINS=Nenhum Plugin lido
+ERROR_CORRUPT_SONG=Canção não pôde ser lida!
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=A canção não foi encontrada!
+ERROR_CORRUPT_SONG_NO_NOTES=A canção não tem notas!
+ERROR_CORRUPT_SONG_NO_BREAKS=A canção não tem quebras de linha!
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Erro durante o parsing da linha %0:d \ No newline at end of file
diff --git a/game/languages/Spanish.ini b/game/languages/Spanish.ini
index 5ab4bf59..4f2154c4 100644
--- a/game/languages/Spanish.ini
+++ b/game/languages/Spanish.ini
@@ -1,398 +1,398 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Cargando...
-
-SING_CHOOSE_MODE=elige modo
-SING_SING=Cantar
-SING_SING_DESC=Juego rápido: cantar solo o dueto
-
-SING_MULTI=Grupo
-SING_MULTI_DESC=cantar en modo grupo
-
-SING_TOOLS=Utilidades
-
-SING_STATS=Estadísticas
-SING_STATS_DESC=Ver las estadísticas
-
-SING_EDITOR=Editor
-SING_EDITOR_DESC=Crea tu propia canción
-
-SING_GAME_OPTIONS=Opciones
-SING_GAME_OPTIONS_DESC=Cambia las opciones del juego
-
-SING_EXIT=Salir
-SING_EXIT_DESC=Salir del juego
-
-SING_OPTIONS=Opciones
-SING_OPTIONS_DESC=Cambia las opciones
-SING_OPTIONS_WHEREAMI=Opciones
-
-SING_OPTIONS_GAME=Juego
-SING_OPTIONS_GRAPHICS=Gráficos
-SING_OPTIONS_SOUND=Sonido
-SING_OPTIONS_LYRICS=Letras
-SING_OPTIONS_THEMES=Temas
-SING_OPTIONS_RECORD=Grabar
-SING_OPTIONS_ADVANCED=Avanzado
-SING_OPTIONS_EXIT=Atrás
-
-SING_OPTIONS_GAME_WHEREAMI=Opciones del juego
-SING_OPTIONS_GAME_DESC=Ajustes generales del juego
-SING_OPTIONS_GAME_PLAYERS=Jugadores
-SING_OPTIONS_GAME_DIFFICULTY=Dificultad
-SING_OPTIONS_GAME_LANGUAGE=Idioma
-SING_OPTIONS_GAME_TABS=Etiquetas
-SING_OPTIONS_GAME_SORTING=Clasificar por
-SING_OPTIONS_GAME_DEBUG=Modo depuración
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Opciones gráficas
-SING_OPTIONS_GRAPHICS_DESC=Opciones gráficas
-SING_OPTIONS_GRAPHICS_RESOLUTION=Resolución
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Pantalla completa
-SING_OPTIONS_GRAPHICS_DEPTH=Profundidad de color
-SING_OPTIONS_GRAPHICS_VISUALIZER=Visualización
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloscopio
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de línea
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Tamaño del vídeo
-
-SING_OPTIONS_SOUND_WHEREAMI=Opciones de sonido
-SING_OPTIONS_SOUND_DESC=Opciones de sonido
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Playback del micrófono
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Música de fondo
-SING_OPTIONS_SOUND_MIC_BOOST=Potenciar micrófono
-SING_OPTIONS_SOUND_CLICK_ASSIST=Asistente de notas
-SING_OPTIONS_SOUND_BEAT_CLICK=Asistente de golpes
-SING_OPTIONS_SOUND_THRESHOLD=Umbral
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Modo dos jugadores
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Volumen de avance
-SING_OPTIONS_SOUND_PREVIEWFADING=Desvanecimiento
-
-SING_OPTIONS_LYRICS_WHEREAMI=Opciones de letras
-SING_OPTIONS_LYRICS_DESC=Opciones de letras
-SING_OPTIONS_LYRICS_FONT=Tipo de letra
-SING_OPTIONS_LYRICS_EFFECT=Efecto
-SING_OPTIONS_LYRICS_SOLMIZATION=Solfeo
-SING_OPTIONS_LYRICS_NOTELINES=Pentagramas
-
-SING_OPTIONS_THEMES_WHEREAMI=Opciones de temas
-SING_OPTIONS_THEMES_DESC=Opciones de temas
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Piel
-SING_OPTIONS_THEMES_COLOR=Color
-
-SING_OPTIONS_RECORD_WHEREAMI=Opciones de grabación
-SING_OPTIONS_RECORD_DESC=Opciones de micrófono
-SING_OPTIONS_RECORD_CARD=Tarjeta de sonido
-SING_OPTIONS_RECORD_INPUT=Entrada
-SING_OPTIONS_RECORD_CHANNEL=Canal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Opciones avanzadas
-SING_OPTIONS_ADVANCED_DESC=Opciones avanzadas
-SING_OPTIONS_ADVANCED_EFFECTSING=Efectos al cantar
-SING_OPTIONS_ADVANCED_SCREENFADE=Desvanecimiento
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animación de carga
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Preguntas de seguridad
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de línea
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Al seleccionar canción
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto menú de grupo
-
-SING_EDIT=Editor
-SING_EDIT_MENU_DESCRIPTION=Crear tu propia canción
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importar texto desde archivo midi
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Atrás
-SING_EDIT_BUTTON_CONVERT=Importar
-SING_EDIT_BUTTON_EXIT=Atrás
-
-SING_EDIT_NAVIGATE=Navegar
-SING_EDIT_SELECT=Seleccionar
-SING_EDIT_EXIT=Atrás
-
-SING_LEGEND_SELECT=Seleccionar
-SING_LEGEND_NAVIGATE=Navegar
-SING_LEGEND_CONTINUE=Continuar
-SING_LEGEND_ESC=Atrás
-
-SING_PLAYER_DESC=Nombre(s) de jugador(es)
-SING_PLAYER_WHEREAMI=Nombre(s) de jugador(es)
-SING_PLAYER_ENTER_NAME=Escribe el nombre
-
-SING_DIFFICULTY_DESC=Selecciona la dificultad
-SING_DIFFICULTY_WHEREAMI=Dificultad
-SING_DIFFICULTY_CONTINUE=Selección de canción
-SING_EASY=Fácil
-SING_MEDIUM=Normal
-SING_HARD=Difícil
-
-SING_SONG_SELECTION_DESC=Elige tu canción
-SING_SONG_SELECTION_WHEREAMI=Selección de canción
-SING_SONG_SELECTION_GOTO=Ir a...
-SING_SONG_SELECTION=Selección de canción
-SING_SONG_SELECTION_MENU=Menú
-SING_SONG_SELECTION_PLAYLIST=Lista de canciones
-SING_SONGS_IN_CAT=Canciones
-PLAYLIST_CATTEXT=Lista de canciones: %s
-
-SING_TIME=TIEMPO
-SING_TOTAL=Total
-SING_MODE=Solo
-SING_NOTES=Notas
-SING_GOLDEN_NOTES=Notas doradas
-SING_PHRASE_BONUS=Bonus de línea
-
-SING_MENU=Menú principal
-
-SONG_SCORE=Puntuación
-SONG_SCORE_WHEREAMI=Puntuación
-
-SING_SCORE_TONE_DEAF=Sin oído
-SING_SCORE_AMATEUR=Aficionado
-SING_SCORE_WANNABE=Aspirante
-SING_SCORE_HOPEFUL=Promesa
-SING_SCORE_RISING_STAR=Prometes
-SING_SCORE_LEAD_SINGER=Artista
-SING_SCORE_SUPERSTAR=Superestrella
-SING_SCORE_ULTRASTAR=Ultraestrella
-
-SING_TOP_5_CHARTS=Los 5 mejores
-SING_TOP_5_CHARTS_WHEREAMI=Los 5 mejores
-SING_TOP_5_CHARTS_CONTINUE=A selección de canción
-
-POPUP_PERFECT=¡Perfecto!
-POPUP_AWESOME=¡Asombroso!
-POPUP_GREAT=¡Genial!
-POPUP_GOOD=¡Bien!
-POPUP_NOTBAD=¡No está mal!
-POPUP_BAD=¡Mal!
-POPUP_POOR=¡Pésimo!
-POPUP_AWFUL=¡Horrible!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= y
-
-SONG_MENU_NAME_MAIN=Menú canciones
-SONG_MENU_PLAY=Cantar
-SONG_MENU_CHANGEPLAYERS=Escoger jugadores
-SONG_MENU_EDIT=Editar
-SONG_MENU_MODI=Cantar una Modi
-SONG_MENU_CANCEL=Cancelar
-
-SONG_MENU_NAME_PLAYLIST=Menú canciones
-SONG_MENU_PLAYLIST_ADD=Añadir canción
-SONG_MENU_PLAYLIST_DEL=Borrar canción
-
-SONG_MENU_NAME_PLAYLIST_ADD=Añadir canción
-SONG_MENU_PLAYLIST_ADD_NEW=A nueva lista de canciones
-SONG_MENU_PLAYLIST_ADD_EXISTING=A lista existente
-SONG_MENU_PLAYLIST_NOEXISTING=No hay listas de canciones
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nueva lista de canciones
-SONG_MENU_PLAYLIST_NEW_CREATE=Crear
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Sin nombre
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=¿Borrar?
-SONG_MENU_YES=Sí
-SONG_MENU_NO=No
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Abrir lista
-SONG_MENU_PLAYLIST_LOAD=Abrir
-SONG_MENU_PLAYLIST_DELCURRENT=Borrar la lista actual
-
-SONG_MENU_NAME_PLAYLIST_DEL=¿Borrar la lista?
-
-SONG_MENU_NAME_PARTY_MAIN=Menú grupo
-SONG_MENU_JOKER=Aleatorio
-
-SONG_MENU_NAME_PARTY_JOKER=Aleatorio
-
-SONG_JUMPTO_DESC=Buscar canción
-SONG_JUMPTO_TYPE_DESC=Buscar por:
-SONG_JUMPTO_TYPE1=Todo
-SONG_JUMPTO_TYPE2=Título
-SONG_JUMPTO_TYPE3=Artista
-SONG_JUMPTO_SONGSFOUND=%d canción(es) encontrada(s)
-SONG_JUMPTO_NOSONGSFOUND=No se han encontrado canciones
-SONG_JUMPTO_HELP=Escribe el texto a buscar
-SONG_JUMPTO_CATTEXT=Buscar por: %s
-
-PARTY_MODE=Modo grupo
-PARTY_DIFFICULTY=Dificultad
-PARTY_PLAYLIST=Modo lista
-PARTY_PLAYLIST_ALL=Todas las canciones
-PARTY_PLAYLIST_CATEGORY=Carpeta
-PARTY_PLAYLIST_PLAYLIST=Lista de canciones
-PARTY_ROUNDS=Rondas
-PARTY_TEAMS=Equipos
-PARTY_TEAMS_PLAYER1=Miembros del equipo 1
-PARTY_TEAMS_PLAYER2=Miembros del equipo 2
-PARTY_TEAMS_PLAYER3=Miembros del equipo 3
-
-PARTY_LEGEND_CONTINUE=Continuar
-
-PARTY_OPTIONS_DESC=Opciones del modo grupo
-PARTY_OPTIONS_WHEREAMI=Opciones del modo grupo
-
-PARTY_PLAYER_DESC=¡Escribe los nombres de jugadores y equipos!
-PARTY_PLAYER_WHEREAMI=Nombre de los equipos
-PARTY_PLAYER_ENTER_NAME=Escribe los nombres
-PARTY_PLAYER_LEGEND_CONTINUE=Empezar
-
-PARTY_ROUND_DESC=Siguientes jugadores
-PARTY_ROUND_WHEREAMI=Siguiente ronda
-PARTY_ROUND_LEGEND_CONTINUE=Iniciar ronda
-
-PARTY_SONG_WHEREAMI=Selección de canción
-PARTY_SONG_LEGEND_CONTINUE=Cantar
-PARTY_SONG_MENU=Menú grupo
-
-PARTY_SCORE_DESC=Puntuación de la última ronda
-PARTY_SCORE_WHEREAMI=Puntuación
-
-PARTY_WIN_DESC=Equipo ganador
-PARTY_WIN_WHEREAMI=Ganador
-PARTY_WIN_LEGEND_CONTINUE=Al menú principal
-
-PARTY_ROUND=Ronda
-PARTY_ROUND_WINNER=Ganador
-PARTY_NOTPLAYEDYET=Aún no jugado
-PARTY_NOBODY=Nadie
-NEXT_ROUND=Siguiente ronda:
-
-PARTY_DISMISSED=¡Perdió!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=¡Ganó!
-
-PLUGIN_HDL_NAME=Mantén la línea
-PLUGIN_HDL_DESC=No bajes tu puntuación de lo indicado en pantalla
-
-PLUGIN_UNTIL5000_NAME=Hasta 5000
-PLUGIN_UNTIL5000_DESC=Gana quien obtenga 5000 puntos.
-
-PLUGIN_DUELL_NAME=Duelo
-PLUGIN_DUELL_DESC=Canta un duelo hasta 10000 puntos.
-
-PLUGIN_TEAMDUELL_NAME=Duelo de equipos
-PLUGIN_TEAMDUELL_DESC=¡Pasa el micro!
-
-PLUGIN_BLIND_NAME=Modo a ciegas
-PLUGIN_BLIND_DESC=Duelo sin ver las notas.
-
-STAT_MAIN=Estadísticas
-STAT_MAIN_DESC=General
-STAT_MAIN_WHEREAMI=Estadísticas
-
-STAT_OVERVIEW_INTRO=%0:s Estadísticas. \n Último reinicio el %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Canciones(%3:d con vídeo), de las cuales %1:d han sido cantadas y %2:d aún no.\n La canción más popular es %5:s de %4:s.
-STAT_OVERVIEW_PLAYER=Hay registrados %0:d jugador(es) diferente(s).\n El mejor es %1:s con una puntuación promedio de %2:d puntos.\n %3:s ha hecho la mejor puntuación con %4:d puntos.
-
-STAT_DETAIL=Estadísticas
-STAT_DETAIL_WHEREAMI=Estadísticas detalladas
-
-STAT_NEXT=Siguiente
-STAT_PREV=Anterior
-STAT_REVERSE=Invertir el orden
-STAT_PAGE=Página %0:d de %1:d \n (%2:d de %3:d entradas)
-
-STAT_DESC_SCORES=Mejores puntuaciones
-STAT_DESC_SCORES_REVERSED=Peores puntuaciones
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Mejores cantantes
-STAT_DESC_SINGERS_REVERSED=Peores cantantes
-STAT_FORMAT_SINGERS=%0:s \n Puntuación media: %1:d
-
-STAT_DESC_SONGS=Canciones más populares
-STAT_DESC_SONGS_REVERSED=Canciones menos populares
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx veces cantada
-
-STAT_DESC_BANDS=Grupos más populares
-STAT_DESC_BANDS_REVERSED=Grupos menos populares
-STAT_FORMAT_BANDS=%0:s \n %1:dx veces cantado
-
-MSG_ERROR_TITLE=Error
-MSG_QUESTION_TITLE=Pregunta
-MSG_QUIT_USDX=¿Seguro que quieres salir?
-MSG_END_PARTY=¿Seguro que quieres salir del modo grupo?
-ERROR_NO_SONGS=Sin canciones
-ERROR_NO_PLUGINS=Sin plugins
-ERROR_CORRUPT_SONG=Imposible cargar la canción.
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Imposible cargar la canción: Archivo no encontrado
-ERROR_CORRUPT_SONG_NO_NOTES=Imposible cargar la canción: No se encuentran notas
-ERROR_CORRUPT_SONG_NO_BREAKS=Imposible cargar la canción: No se encuentran interrupciones de línea
-ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Imposible cargar la canción: Error durante el parsing de la línea %0:d \ No newline at end of file
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=Cargando...
+
+SING_CHOOSE_MODE=elige modo
+SING_SING=Cantar
+SING_SING_DESC=Juego rápido: cantar solo o dueto
+
+SING_MULTI=Grupo
+SING_MULTI_DESC=cantar en modo grupo
+
+SING_TOOLS=Utilidades
+
+SING_STATS=Estadísticas
+SING_STATS_DESC=Ver las estadísticas
+
+SING_EDITOR=Editor
+SING_EDITOR_DESC=Crea tu propia canción
+
+SING_GAME_OPTIONS=Opciones
+SING_GAME_OPTIONS_DESC=Cambia las opciones del juego
+
+SING_EXIT=Salir
+SING_EXIT_DESC=Salir del juego
+
+SING_OPTIONS=Opciones
+SING_OPTIONS_DESC=Cambia las opciones
+SING_OPTIONS_WHEREAMI=Opciones
+
+SING_OPTIONS_GAME=Juego
+SING_OPTIONS_GRAPHICS=Gráficos
+SING_OPTIONS_SOUND=Sonido
+SING_OPTIONS_LYRICS=Letras
+SING_OPTIONS_THEMES=Temas
+SING_OPTIONS_RECORD=Grabar
+SING_OPTIONS_ADVANCED=Avanzado
+SING_OPTIONS_EXIT=Atrás
+
+SING_OPTIONS_GAME_WHEREAMI=Opciones del juego
+SING_OPTIONS_GAME_DESC=Ajustes generales del juego
+SING_OPTIONS_GAME_PLAYERS=Jugadores
+SING_OPTIONS_GAME_DIFFICULTY=Dificultad
+SING_OPTIONS_GAME_LANGUAGE=Idioma
+SING_OPTIONS_GAME_TABS=Etiquetas
+SING_OPTIONS_GAME_SORTING=Clasificar por
+SING_OPTIONS_GAME_DEBUG=Modo depuración
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Opciones gráficas
+SING_OPTIONS_GRAPHICS_DESC=Opciones gráficas
+SING_OPTIONS_GRAPHICS_RESOLUTION=Resolución
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Pantalla completa
+SING_OPTIONS_GRAPHICS_DEPTH=Profundidad de color
+SING_OPTIONS_GRAPHICS_VISUALIZER=Visualización
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloscopio
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de línea
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Tamaño del vídeo
+
+SING_OPTIONS_SOUND_WHEREAMI=Opciones de sonido
+SING_OPTIONS_SOUND_DESC=Opciones de sonido
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Playback del micrófono
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Música de fondo
+SING_OPTIONS_SOUND_MIC_BOOST=Potenciar micrófono
+SING_OPTIONS_SOUND_CLICK_ASSIST=Asistente de notas
+SING_OPTIONS_SOUND_BEAT_CLICK=Asistente de golpes
+SING_OPTIONS_SOUND_THRESHOLD=Umbral
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Modo dos jugadores
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Volumen de avance
+SING_OPTIONS_SOUND_PREVIEWFADING=Desvanecimiento
+
+SING_OPTIONS_LYRICS_WHEREAMI=Opciones de letras
+SING_OPTIONS_LYRICS_DESC=Opciones de letras
+SING_OPTIONS_LYRICS_FONT=Tipo de letra
+SING_OPTIONS_LYRICS_EFFECT=Efecto
+SING_OPTIONS_LYRICS_SOLMIZATION=Solfeo
+SING_OPTIONS_LYRICS_NOTELINES=Pentagramas
+
+SING_OPTIONS_THEMES_WHEREAMI=Opciones de temas
+SING_OPTIONS_THEMES_DESC=Opciones de temas
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Piel
+SING_OPTIONS_THEMES_COLOR=Color
+
+SING_OPTIONS_RECORD_WHEREAMI=Opciones de grabación
+SING_OPTIONS_RECORD_DESC=Opciones de micrófono
+SING_OPTIONS_RECORD_CARD=Tarjeta de sonido
+SING_OPTIONS_RECORD_INPUT=Entrada
+SING_OPTIONS_RECORD_CHANNEL=Canal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Opciones avanzadas
+SING_OPTIONS_ADVANCED_DESC=Opciones avanzadas
+SING_OPTIONS_ADVANCED_EFFECTSING=Efectos al cantar
+SING_OPTIONS_ADVANCED_SCREENFADE=Desvanecimiento
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animación de carga
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Preguntas de seguridad
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de línea
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Al seleccionar canción
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto menú de grupo
+
+SING_EDIT=Editor
+SING_EDIT_MENU_DESCRIPTION=Crear tu propia canción
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importar texto desde archivo midi
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Atrás
+SING_EDIT_BUTTON_CONVERT=Importar
+SING_EDIT_BUTTON_EXIT=Atrás
+
+SING_EDIT_NAVIGATE=Navegar
+SING_EDIT_SELECT=Seleccionar
+SING_EDIT_EXIT=Atrás
+
+SING_LEGEND_SELECT=Seleccionar
+SING_LEGEND_NAVIGATE=Navegar
+SING_LEGEND_CONTINUE=Continuar
+SING_LEGEND_ESC=Atrás
+
+SING_PLAYER_DESC=Nombre(s) de jugador(es)
+SING_PLAYER_WHEREAMI=Nombre(s) de jugador(es)
+SING_PLAYER_ENTER_NAME=Escribe el nombre
+
+SING_DIFFICULTY_DESC=Selecciona la dificultad
+SING_DIFFICULTY_WHEREAMI=Dificultad
+SING_DIFFICULTY_CONTINUE=Selección de canción
+SING_EASY=Fácil
+SING_MEDIUM=Normal
+SING_HARD=Difícil
+
+SING_SONG_SELECTION_DESC=Elige tu canción
+SING_SONG_SELECTION_WHEREAMI=Selección de canción
+SING_SONG_SELECTION_GOTO=Ir a...
+SING_SONG_SELECTION=Selección de canción
+SING_SONG_SELECTION_MENU=Menú
+SING_SONG_SELECTION_PLAYLIST=Lista de canciones
+SING_SONGS_IN_CAT=Canciones
+PLAYLIST_CATTEXT=Lista de canciones: %s
+
+SING_TIME=TIEMPO
+SING_TOTAL=Total
+SING_MODE=Solo
+SING_NOTES=Notas
+SING_GOLDEN_NOTES=Notas doradas
+SING_PHRASE_BONUS=Bonus de línea
+
+SING_MENU=Menú principal
+
+SONG_SCORE=Puntuación
+SONG_SCORE_WHEREAMI=Puntuación
+
+SING_SCORE_TONE_DEAF=Sin oído
+SING_SCORE_AMATEUR=Aficionado
+SING_SCORE_WANNABE=Aspirante
+SING_SCORE_HOPEFUL=Promesa
+SING_SCORE_RISING_STAR=Prometes
+SING_SCORE_LEAD_SINGER=Artista
+SING_SCORE_SUPERSTAR=Superestrella
+SING_SCORE_ULTRASTAR=Ultraestrella
+
+SING_TOP_5_CHARTS=Los 5 mejores
+SING_TOP_5_CHARTS_WHEREAMI=Los 5 mejores
+SING_TOP_5_CHARTS_CONTINUE=A selección de canción
+
+POPUP_PERFECT=¡Perfecto!
+POPUP_AWESOME=¡Asombroso!
+POPUP_GREAT=¡Genial!
+POPUP_GOOD=¡Bien!
+POPUP_NOTBAD=¡No está mal!
+POPUP_BAD=¡Mal!
+POPUP_POOR=¡Pésimo!
+POPUP_AWFUL=¡Horrible!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= y
+
+SONG_MENU_NAME_MAIN=Menú canciones
+SONG_MENU_PLAY=Cantar
+SONG_MENU_CHANGEPLAYERS=Escoger jugadores
+SONG_MENU_EDIT=Editar
+SONG_MENU_MODI=Cantar una Modi
+SONG_MENU_CANCEL=Cancelar
+
+SONG_MENU_NAME_PLAYLIST=Menú canciones
+SONG_MENU_PLAYLIST_ADD=Añadir canción
+SONG_MENU_PLAYLIST_DEL=Borrar canción
+
+SONG_MENU_NAME_PLAYLIST_ADD=Añadir canción
+SONG_MENU_PLAYLIST_ADD_NEW=A nueva lista de canciones
+SONG_MENU_PLAYLIST_ADD_EXISTING=A lista existente
+SONG_MENU_PLAYLIST_NOEXISTING=No hay listas de canciones
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nueva lista de canciones
+SONG_MENU_PLAYLIST_NEW_CREATE=Crear
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Sin nombre
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=¿Borrar?
+SONG_MENU_YES=Sí
+SONG_MENU_NO=No
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Abrir lista
+SONG_MENU_PLAYLIST_LOAD=Abrir
+SONG_MENU_PLAYLIST_DELCURRENT=Borrar la lista actual
+
+SONG_MENU_NAME_PLAYLIST_DEL=¿Borrar la lista?
+
+SONG_MENU_NAME_PARTY_MAIN=Menú grupo
+SONG_MENU_JOKER=Aleatorio
+
+SONG_MENU_NAME_PARTY_JOKER=Aleatorio
+
+SONG_JUMPTO_DESC=Buscar canción
+SONG_JUMPTO_TYPE_DESC=Buscar por:
+SONG_JUMPTO_TYPE1=Todo
+SONG_JUMPTO_TYPE2=Título
+SONG_JUMPTO_TYPE3=Artista
+SONG_JUMPTO_SONGSFOUND=%d canción(es) encontrada(s)
+SONG_JUMPTO_NOSONGSFOUND=No se han encontrado canciones
+SONG_JUMPTO_HELP=Escribe el texto a buscar
+SONG_JUMPTO_CATTEXT=Buscar por: %s
+
+PARTY_MODE=Modo grupo
+PARTY_DIFFICULTY=Dificultad
+PARTY_PLAYLIST=Modo lista
+PARTY_PLAYLIST_ALL=Todas las canciones
+PARTY_PLAYLIST_CATEGORY=Carpeta
+PARTY_PLAYLIST_PLAYLIST=Lista de canciones
+PARTY_ROUNDS=Rondas
+PARTY_TEAMS=Equipos
+PARTY_TEAMS_PLAYER1=Miembros del equipo 1
+PARTY_TEAMS_PLAYER2=Miembros del equipo 2
+PARTY_TEAMS_PLAYER3=Miembros del equipo 3
+
+PARTY_LEGEND_CONTINUE=Continuar
+
+PARTY_OPTIONS_DESC=Opciones del modo grupo
+PARTY_OPTIONS_WHEREAMI=Opciones del modo grupo
+
+PARTY_PLAYER_DESC=¡Escribe los nombres de jugadores y equipos!
+PARTY_PLAYER_WHEREAMI=Nombre de los equipos
+PARTY_PLAYER_ENTER_NAME=Escribe los nombres
+PARTY_PLAYER_LEGEND_CONTINUE=Empezar
+
+PARTY_ROUND_DESC=Siguientes jugadores
+PARTY_ROUND_WHEREAMI=Siguiente ronda
+PARTY_ROUND_LEGEND_CONTINUE=Iniciar ronda
+
+PARTY_SONG_WHEREAMI=Selección de canción
+PARTY_SONG_LEGEND_CONTINUE=Cantar
+PARTY_SONG_MENU=Menú grupo
+
+PARTY_SCORE_DESC=Puntuación de la última ronda
+PARTY_SCORE_WHEREAMI=Puntuación
+
+PARTY_WIN_DESC=Equipo ganador
+PARTY_WIN_WHEREAMI=Ganador
+PARTY_WIN_LEGEND_CONTINUE=Al menú principal
+
+PARTY_ROUND=Ronda
+PARTY_ROUND_WINNER=Ganador
+PARTY_NOTPLAYEDYET=Aún no jugado
+PARTY_NOBODY=Nadie
+NEXT_ROUND=Siguiente ronda:
+
+PARTY_DISMISSED=¡Perdió!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=¡Ganó!
+
+PLUGIN_HDL_NAME=Mantén la línea
+PLUGIN_HDL_DESC=No bajes tu puntuación de lo indicado en pantalla
+
+PLUGIN_UNTIL5000_NAME=Hasta 5000
+PLUGIN_UNTIL5000_DESC=Gana quien obtenga 5000 puntos.
+
+PLUGIN_DUELL_NAME=Duelo
+PLUGIN_DUELL_DESC=Canta un duelo hasta 10000 puntos.
+
+PLUGIN_TEAMDUELL_NAME=Duelo de equipos
+PLUGIN_TEAMDUELL_DESC=¡Pasa el micro!
+
+PLUGIN_BLIND_NAME=Modo a ciegas
+PLUGIN_BLIND_DESC=Duelo sin ver las notas.
+
+STAT_MAIN=Estadísticas
+STAT_MAIN_DESC=General
+STAT_MAIN_WHEREAMI=Estadísticas
+
+STAT_OVERVIEW_INTRO=%0:s Estadísticas. \n Último reinicio el %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Canciones(%3:d con vídeo), de las cuales %1:d han sido cantadas y %2:d aún no.\n La canción más popular es %5:s de %4:s.
+STAT_OVERVIEW_PLAYER=Hay registrados %0:d jugador(es) diferente(s).\n El mejor es %1:s con una puntuación promedio de %2:d puntos.\n %3:s ha hecho la mejor puntuación con %4:d puntos.
+
+STAT_DETAIL=Estadísticas
+STAT_DETAIL_WHEREAMI=Estadísticas detalladas
+
+STAT_NEXT=Siguiente
+STAT_PREV=Anterior
+STAT_REVERSE=Invertir el orden
+STAT_PAGE=Página %0:d de %1:d \n (%2:d de %3:d entradas)
+
+STAT_DESC_SCORES=Mejores puntuaciones
+STAT_DESC_SCORES_REVERSED=Peores puntuaciones
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Mejores cantantes
+STAT_DESC_SINGERS_REVERSED=Peores cantantes
+STAT_FORMAT_SINGERS=%0:s \n Puntuación media: %1:d
+
+STAT_DESC_SONGS=Canciones más populares
+STAT_DESC_SONGS_REVERSED=Canciones menos populares
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx veces cantada
+
+STAT_DESC_BANDS=Grupos más populares
+STAT_DESC_BANDS_REVERSED=Grupos menos populares
+STAT_FORMAT_BANDS=%0:s \n %1:dx veces cantado
+
+MSG_ERROR_TITLE=Error
+MSG_QUESTION_TITLE=Pregunta
+MSG_QUIT_USDX=¿Seguro que quieres salir?
+MSG_END_PARTY=¿Seguro que quieres salir del modo grupo?
+ERROR_NO_SONGS=Sin canciones
+ERROR_NO_PLUGINS=Sin plugins
+ERROR_CORRUPT_SONG=Imposible cargar la canción.
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Imposible cargar la canción: Archivo no encontrado
+ERROR_CORRUPT_SONG_NO_NOTES=Imposible cargar la canción: No se encuentran notas
+ERROR_CORRUPT_SONG_NO_BREAKS=Imposible cargar la canción: No se encuentran interrupciones de línea
+ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Imposible cargar la canción: Error durante el parsing de la línea %0:d \ No newline at end of file
diff --git a/game/languages/Swedish.ini b/game/languages/Swedish.ini
index afe35d12..fa4e54d0 100644
--- a/game/languages/Swedish.ini
+++ b/game/languages/Swedish.ini
@@ -1,397 +1,397 @@
-[Text]
-OPTION_VALUE_CATALAN=Catalan
-OPTION_VALUE_CROATIAN=Croatian
-OPTION_VALUE_DUTCH=Dutch
-OPTION_VALUE_ENGLISH=English
-OPTION_VALUE_EUSKARA=Euskara
-OPTION_VALUE_FINNISH=Finnish
-OPTION_VALUE_FRENCH=French
-OPTION_VALUE_GERMAN=German
-OPTION_VALUE_GREEK=Greek
-OPTION_VALUE_ITALIAN=Italian
-OPTION_VALUE_JAPANESE=Japanese
-OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
-OPTION_VALUE_PORTUGUESE=Portuguese
-OPTION_VALUE_SPANISH=Spanish
-OPTION_VALUE_SWEDISH=Swedish
-
-OPTION_VALUE_EASY=Easy
-OPTION_VALUE_MEDIUM=Medium
-OPTION_VALUE_HARD=Hard
-
-OPTION_VALUE_ON=On
-OPTION_VALUE_OFF=Off
-
-OPTION_VALUE_EDITION=Edition
-OPTION_VALUE_GENRE=Genre
-OPTION_VALUE_LANGUAGE=Language
-OPTION_VALUE_FOLDER=Folder
-OPTION_VALUE_TITLE=Title
-OPTION_VALUE_ARTIST=Artist
-OPTION_VALUE_TITLE2=Title2
-OPTION_VALUE_ARTIST2=Artist2
-
-OPTION_VALUE_WHENNOVIDEO=When No Video
-
-OPTION_VALUE_SMALL=Small
-OPTION_VALUE_BIG=Big
-
-OPTION_VALUE_HALF=Half
-OPTION_VALUE_FULL_VID=Full (Video)
-OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
-
-OPTION_VALUE_AUTO=Auto
-OPTION_VALUE_SEC=Second
-OPTION_VALUE_SECS=Seconds
-
-OPTION_VALUE_PLAIN=Plain
-OPTION_VALUE_OLINE1=OLine1
-OPTION_VALUE_OLINE2=OLine2
-
-OPTION_VALUE_SIMPLE=Simple
-OPTION_VALUE_ZOOM=Zoom
-OPTION_VALUE_SLIDE=Slide
-OPTION_VALUE_BALL=Ball
-OPTION_VALUE_SHIFT=Shift
-
-OPTION_VALUE_EURO=Euro
-OPTION_VALUE_JAPAN=Japan
-OPTION_VALUE_AMERICAN=American
-
-OPTION_VALUE_BLUE=Blue
-OPTION_VALUE_GREEN=Green
-OPTION_VALUE_PINK=Pink
-OPTION_VALUE_RED=Red
-OPTION_VALUE_VIOLET=Violet
-OPTION_VALUE_ORANGE=Orange
-OPTION_VALUE_YELLOW=Yellow
-OPTION_VALUE_BROWN=Brown
-OPTION_VALUE_BLACK=Black
-
-OPTION_VALUE_SING=Sing
-OPTION_VALUE_SELECT_PLAYERS=Select Players
-OPTION_VALUE_OPEN_MENU=Open Menu
-
-OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
-OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
-
-SING_LOADING=Laddar...
-
-SING_CHOOSE_MODE=välj läge
-SING_SING=sjung
-SING_SING_DESC=snabbspel: sjung solo eller duett
-
-SING_MULTI=party
-SING_MULTI_DESC=sjung i partyläge
-
-SING_TOOLS=verktyg
-
-SING_STATS=statistik
-SING_STATS_DESC=kolla statistiken
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=skapa din egen låt
-
-SING_GAME_OPTIONS=spelinställningar
-SING_GAME_OPTIONS_DESC=ändra spelets inställningar
-
-SING_EXIT=avsluta
-SING_EXIT_DESC=sluta spela
-
-SING_OPTIONS=inställningar
-SING_OPTIONS_DESC=ändra inställningar
-SING_OPTIONS_WHEREAMI=Inställningar
-
-SING_OPTIONS_GAME=spel
-SING_OPTIONS_GRAPHICS=grafik
-SING_OPTIONS_SOUND=ljud
-SING_OPTIONS_LYRICS=text
-SING_OPTIONS_THEMES=teman
-SING_OPTIONS_RECORD=inspelning
-SING_OPTIONS_ADVANCED=avancerat
-SING_OPTIONS_EXIT=tillbaka
-
-SING_OPTIONS_GAME_WHEREAMI=Inställningar Spel
-SING_OPTIONS_GAME_DESC=vanliga spelinställningar
-SING_OPTIONS_GAME_PLAYERS=Spelare
-SING_OPTIONS_GAME_DIFFICULTY=Svårighetsnivå
-SING_OPTIONS_GAME_LANGUAGE=Språk
-SING_OPTIONS_GAME_TABS=Tabbar
-SING_OPTIONS_GAME_SORTING=Sortering
-SING_OPTIONS_GAME_DEBUG=Debuggning
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Inställningar Grafik
-SING_OPTIONS_GRAPHICS_DESC=grafikinställningar
-SING_OPTIONS_GRAPHICS_RESOLUTION=Upplösning
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullskärm
-SING_OPTIONS_GRAPHICS_DEPTH=Färgdjup
-SING_OPTIONS_GRAPHICS_VISUALIZER=Visualisering
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloskåp
-SING_OPTIONS_GRAPHICS_LINEBONUS=Radbonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Filmstorlek
-
-SING_OPTIONS_SOUND_WHEREAMI=Inställningar Ljud
-SING_OPTIONS_SOUND_DESC=ljudinställningar
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Mikrofonuppspelning
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Bakgrundsmusik
-SING_OPTIONS_SOUND_MIC_BOOST=Mikrofonförstärkning
-SING_OPTIONS_SOUND_CLICK_ASSIST=Hjälpljud
-SING_OPTIONS_SOUND_BEAT_CLICK=Taktljud
-SING_OPTIONS_SOUND_THRESHOLD=Ljudtröskel
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Tvåspelarläge
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Volym i låtvalsmenyn
-SING_OPTIONS_SOUND_PREVIEWFADING=Toning i låtvalsmenyn
-
-SING_OPTIONS_LYRICS_WHEREAMI=Inställningar Text
-SING_OPTIONS_LYRICS_DESC=sångtextinställningar
-SING_OPTIONS_LYRICS_FONT=Typsnitt
-SING_OPTIONS_LYRICS_EFFECT=Effekt
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmisation
-SING_OPTIONS_LYRICS_NOTELINES=Notlinjer
-
-SING_OPTIONS_THEMES_WHEREAMI=Inställningar Teman
-SING_OPTIONS_THEMES_DESC=temainställningar
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Färg
-
-SING_OPTIONS_RECORD_WHEREAMI=Inställningar Inspelning
-SING_OPTIONS_RECORD_DESC=Mikrofoninställningar
-SING_OPTIONS_RECORD_CARD=Ljudkort
-SING_OPTIONS_RECORD_INPUT=Ingång
-SING_OPTIONS_RECORD_CHANNEL=Kanal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Inställningar Avancerat
-SING_OPTIONS_ADVANCED_DESC=Avancerade inställningar
-SING_OPTIONS_ADVANCED_EFFECTSING=Sångeffekter
-SING_OPTIONS_ADVANCED_SCREENFADE=Skärmtoning
-SING_OPTIONS_ADVANCED_LOADANIMATION=Laddningsanimering
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Säkerhetsfråga
-SING_OPTIONS_ADVANCED_LINEBONUS=Radbonus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Vid Låtval
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Automatisk Partymeny
-
-SING_EDIT=Editor
-SING_EDIT_MENU_DESCRIPTION=skapa din egen låt
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importera text från midifil
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=tillbaka
-SING_EDIT_BUTTON_CONVERT=Importera
-SING_EDIT_BUTTON_EXIT=tillbaka
-
-SING_EDIT_NAVIGATE=navigera
-SING_EDIT_SELECT=välj
-SING_EDIT_EXIT=tillbaka
-
-SING_LEGEND_SELECT=välj
-SING_LEGEND_NAVIGATE=navigera
-SING_LEGEND_CONTINUE=fortsätt
-SING_LEGEND_ESC=tillbaka
-
-SING_PLAYER_DESC=skriv in spelarnamn
-SING_PLAYER_WHEREAMI=Spelarnamn
-SING_PLAYER_ENTER_NAME=skriv namn
-
-SING_DIFFICULTY_DESC=välj svårighetsnivå
-SING_DIFFICULTY_WHEREAMI=Svårighetsnivå
-SING_DIFFICULTY_CONTINUE=till låtval
-SING_EASY=Lätt
-SING_MEDIUM=Normal
-SING_HARD=Svår
-
-SING_SONG_SELECTION_DESC=välj din låt
-SING_SONG_SELECTION_WHEREAMI=Låtval
-SING_SONG_SELECTION_GOTO=gå till...
-SING_SONG_SELECTION=Låtval
-SING_SONG_SELECTION_MENU=meny
-SING_SONG_SELECTION_PLAYLIST=spellista
-SING_SONGS_IN_CAT=Låtar
-PLAYLIST_CATTEXT=Spellista: %s
-
-SING_TIME=TID
-SING_TOTAL=totalt
-SING_MODE=sjung solo
-SING_NOTES=toner
-SING_GOLDEN_NOTES=gyllene toner
-SING_PHRASE_BONUS=radbonus
-
-SING_MENU=Huvudmeny
-
-SONG_SCORE=Låtpoäng
-SONG_SCORE_WHEREAMI=Poäng
-
-SING_SCORE_TONE_DEAF=Tondöv
-SING_SCORE_AMATEUR=Amatör
-SING_SCORE_WANNABE=Wannabe
-SING_SCORE_HOPEFUL=Potential
-SING_SCORE_RISING_STAR=Stigande stjärna
-SING_SCORE_LEAD_SINGER=Hitartist
-SING_SCORE_SUPERSTAR=Superstjärna
-SING_SCORE_ULTRASTAR=Ultrastar!
-
-SING_TOP_5_CHARTS=topp 5 Spelare
-SING_TOP_5_CHARTS_WHEREAMI=topp 5
-SING_TOP_5_CHARTS_CONTINUE=till låtval
-
-POPUP_PERFECT=perfekt!
-POPUP_AWESOME=storartat!
-POPUP_GREAT=riktigt bra!
-POPUP_GOOD=bra!
-POPUP_NOTBAD=godkänt!
-POPUP_BAD=dåligt!
-POPUP_POOR=uselt!
-POPUP_AWFUL=avskyvärt!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= och
-
-SONG_MENU_NAME_MAIN=låtmeny
-SONG_MENU_PLAY=Sjung
-SONG_MENU_CHANGEPLAYERS=Ändra spelare
-SONG_MENU_EDIT=Redigera
-SONG_MENU_MODI=Sjung en mod
-SONG_MENU_CANCEL=Ångra
-
-SONG_MENU_NAME_PLAYLIST=Låtmeny
-SONG_MENU_PLAYLIST_ADD=Lägg till låt
-SONG_MENU_PLAYLIST_DEL=Ta bort låt
-
-SONG_MENU_NAME_PLAYLIST_ADD=Lägg till låt
-SONG_MENU_PLAYLIST_ADD_NEW=till ny spellista
-SONG_MENU_PLAYLIST_ADD_EXISTING=till exsisterande spellista
-SONG_MENU_PLAYLIST_NOEXISTING=Ingen spellista tillgänglig
-
-SONG_MENU_NAME_PLAYLIST_NEW=Ny spellista
-SONG_MENU_PLAYLIST_NEW_CREATE=Skapa
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Namnlös
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Vill du verkligen bort?
-SONG_MENU_YES=Ja
-SONG_MENU_NO=Nej
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Öppna spellista
-SONG_MENU_PLAYLIST_LOAD=öppna
-SONG_MENU_PLAYLIST_DELCURRENT=ta bort nuvarande spellista
-
-SONG_MENU_NAME_PLAYLIST_DEL=Ta bort spellista?
-
-SONG_MENU_NAME_PARTY_MAIN=Partymeny
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=ta joker
-
-SONG_JUMPTO_DESC=sök låt
-SONG_JUMPTO_TYPE_DESC=Sök efter:
-SONG_JUMPTO_TYPE1=Alla
-SONG_JUMPTO_TYPE2=Titel
-SONG_JUMPTO_TYPE3=Artist
-SONG_JUMPTO_SONGSFOUND=%d Låt(ar) hittade
-SONG_JUMPTO_NOSONGSFOUND=Ingen låt hittad
-SONG_JUMPTO_HELP=Skriv text att söka efter
-SONG_JUMPTO_CATTEXT=Sök efter: %s
-
-PARTY_MODE=partyläge
-PARTY_DIFFICULTY=Svårighetsnivå
-PARTY_PLAYLIST=Spellistläge
-PARTY_PLAYLIST_ALL=Alla låtar
-PARTY_PLAYLIST_CATEGORY=Mapp
-PARTY_PLAYLIST_PLAYLIST=Spellista
-PARTY_ROUNDS=Omgångar
-PARTY_TEAMS=Lag
-PARTY_TEAMS_PLAYER1=Spelare Lag1
-PARTY_TEAMS_PLAYER2=Spelare Lag2
-PARTY_TEAMS_PLAYER3=Spelare Lag3
-
-PARTY_LEGEND_CONTINUE=fortsätt
-
-PARTY_OPTIONS_DESC=inställningar för partyspel
-PARTY_OPTIONS_WHEREAMI=Partyinställningar
-
-PARTY_PLAYER_DESC=skriv spelar- och lagnamn!
-PARTY_PLAYER_WHEREAMI=Partynamn
-PARTY_PLAYER_ENTER_NAME=skriv namn
-PARTY_PLAYER_LEGEND_CONTINUE=starta partyspel
-
-PARTY_ROUND_DESC=nästa spelare till mikrofonerna
-PARTY_ROUND_WHEREAMI=Party Nästa omgång
-PARTY_ROUND_LEGEND_CONTINUE=starta omgång
-
-PARTY_SONG_WHEREAMI=Party Låtval
-PARTY_SONG_LEGEND_CONTINUE=sjung
-PARTY_SONG_MENU=partymeny
-
-PARTY_SCORE_DESC=poäng från förra omgången
-PARTY_SCORE_WHEREAMI=Partypoäng
-
-PARTY_WIN_DESC=vinnare av partyspelet
-PARTY_WIN_WHEREAMI=Partyvinnare
-PARTY_WIN_LEGEND_CONTINUE=tillbaka till huvudmenyn
-
-PARTY_ROUND=Omgång
-PARTY_ROUND_WINNER=Vinnare
-PARTY_NOTPLAYEDYET=inte spelad än
-PARTY_NOBODY=ingen
-NEXT_ROUND=Nästa runda:
-
-PARTY_DISMISSED=Avbröt!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=vann!
-
-PLUGIN_HDL_NAME=Håll god ton
-PLUGIN_HDL_DESC=Bli inte sämre än vad markeringen på omdömesmätaren visar.
-PLUGIN_UNTIL5000_NAME=Till 5000
-PLUGIN_UNTIL5000_DESC=Den som först får 5000 poäng vinner matchen.
-
-PLUGIN_DUELL_NAME=Duell
-PLUGIN_DUELL_DESC=Sjung en duett till 10000 poäng.
-
-PLUGIN_TEAMDUELL_NAME=Lagduell
-PLUGIN_TEAMDUELL_DESC=Skicka micken!
-
-PLUGIN_BLIND_NAME=Blindläge
-PLUGIN_BLIND_DESC=Duell utan att se tonerna.
-
-STAT_MAIN=Statistik
-STAT_MAIN_DESC=Allmänn
-STAT_MAIN_WHEREAMI=Statistik
-
-STAT_OVERVIEW_INTRO=%0:s Statistik. \n Senast återställd %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Låtar(%3:d med Video), varav %1:d redan har spelats och %2:d inte har spelats än.\n Den mest populära låten är %5:s med %4:s.
-STAT_OVERVIEW_PLAYER=Sedan den senaste återställningen har %0:d olika spelare sjungit.\n Den bästa spelaren är %1:s med ett genomsnitt på %2:d poäng.\n %3:s har sjungit bäst med %4:d poäng.
-
-STAT_DETAIL=Statistik
-STAT_DETAIL_WHEREAMI=Detaljerad statistik
-
-STAT_NEXT=Nästa sida
-STAT_PREV=Föregående sida
-STAT_REVERSE=Omvänd ordning
-STAT_PAGE=Sida %0:d av %1:d sidor\n (%2:d av %3:d poster)
-
-STAT_DESC_SCORES=Högsta resultat
-STAT_DESC_SCORES_REVERSED=Lägsta resultat
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Bästa sångare
-STAT_DESC_SINGERS_REVERSED=Sämsta sångare
-STAT_FORMAT_SINGERS=%0:s \n genomsnittlig poäng: %1:d
-
-STAT_DESC_SONGS=Populäraste låtarna
-STAT_DESC_SONGS_REVERSED=Minst populära låtarna
-STAT_FORMAT_SONGS=%0:s - %1:s \n Sjungen %2:dx gånger
-
-STAT_DESC_BANDS=Populäraste artisterna
-STAT_DESC_BANDS_REVERSED=Minst populära artisterna
-STAT_FORMAT_BANDS=%0:s \n %1:dx sjungna
-
-MSG_ERROR_TITLE=Fel
-MSG_QUESTION_TITLE=Fråga
-MSG_QUIT_USDX=Vill du verkligen avsluta UltraStar?
-MSG_END_PARTY=Vill du verkligen avsluta partyläge?
-ERROR_NO_SONGS=Inga låtar laddade
-ERROR_NO_PLUGINS=Inga insticksprogram laddade
-ERROR_CORRUPT_SONG=Låten kunde inte laddas.
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Låten kunde inte laddas: Filen kunde inte hittas
-ERROR_CORRUPT_SONG_NO_NOTES=Låten kunde inte laddas: Kan inte hitta toner
-ERROR_CORRUPT_SONG_NO_BREAKS=Låten kunde inte laddas: Kan inte hitta radbrytningar
-ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Låten kunde inte laddas: Fel på rad %0:d \ No newline at end of file
+[Text]
+OPTION_VALUE_CATALAN=Catalan
+OPTION_VALUE_CROATIAN=Croatian
+OPTION_VALUE_DUTCH=Dutch
+OPTION_VALUE_ENGLISH=English
+OPTION_VALUE_EUSKARA=Euskara
+OPTION_VALUE_FINNISH=Finnish
+OPTION_VALUE_FRENCH=French
+OPTION_VALUE_GERMAN=German
+OPTION_VALUE_GREEK=Greek
+OPTION_VALUE_ITALIAN=Italian
+OPTION_VALUE_JAPANESE=Japanese
+OPTION_VALUE_LUXEMBOURGISH=Luxembourgish
+OPTION_VALUE_PORTUGUESE=Portuguese
+OPTION_VALUE_SPANISH=Spanish
+OPTION_VALUE_SWEDISH=Swedish
+
+OPTION_VALUE_EASY=Easy
+OPTION_VALUE_MEDIUM=Medium
+OPTION_VALUE_HARD=Hard
+
+OPTION_VALUE_ON=On
+OPTION_VALUE_OFF=Off
+
+OPTION_VALUE_EDITION=Edition
+OPTION_VALUE_GENRE=Genre
+OPTION_VALUE_LANGUAGE=Language
+OPTION_VALUE_FOLDER=Folder
+OPTION_VALUE_TITLE=Title
+OPTION_VALUE_ARTIST=Artist
+OPTION_VALUE_TITLE2=Title2
+OPTION_VALUE_ARTIST2=Artist2
+
+OPTION_VALUE_WHENNOVIDEO=When No Video
+
+OPTION_VALUE_SMALL=Small
+OPTION_VALUE_BIG=Big
+
+OPTION_VALUE_HALF=Half
+OPTION_VALUE_FULL_VID=Full (Video)
+OPTION_VALUE_FULL_VID_BG=Full (BG & Video)
+
+OPTION_VALUE_AUTO=Auto
+OPTION_VALUE_SEC=Second
+OPTION_VALUE_SECS=Seconds
+
+OPTION_VALUE_PLAIN=Plain
+OPTION_VALUE_OLINE1=OLine1
+OPTION_VALUE_OLINE2=OLine2
+
+OPTION_VALUE_SIMPLE=Simple
+OPTION_VALUE_ZOOM=Zoom
+OPTION_VALUE_SLIDE=Slide
+OPTION_VALUE_BALL=Ball
+OPTION_VALUE_SHIFT=Shift
+
+OPTION_VALUE_EURO=Euro
+OPTION_VALUE_JAPAN=Japan
+OPTION_VALUE_AMERICAN=American
+
+OPTION_VALUE_BLUE=Blue
+OPTION_VALUE_GREEN=Green
+OPTION_VALUE_PINK=Pink
+OPTION_VALUE_RED=Red
+OPTION_VALUE_VIOLET=Violet
+OPTION_VALUE_ORANGE=Orange
+OPTION_VALUE_YELLOW=Yellow
+OPTION_VALUE_BROWN=Brown
+OPTION_VALUE_BLACK=Black
+
+OPTION_VALUE_SING=Sing
+OPTION_VALUE_SELECT_PLAYERS=Select Players
+OPTION_VALUE_OPEN_MENU=Open Menu
+
+OPTION_VALUE_HARDWARE_CURSOR=Hardware Cursor
+OPTION_VALUE_SOFTWARE_CURSOR=Software Cursor
+
+SING_LOADING=Laddar...
+
+SING_CHOOSE_MODE=välj läge
+SING_SING=sjung
+SING_SING_DESC=snabbspel: sjung solo eller duett
+
+SING_MULTI=party
+SING_MULTI_DESC=sjung i partyläge
+
+SING_TOOLS=verktyg
+
+SING_STATS=statistik
+SING_STATS_DESC=kolla statistiken
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=skapa din egen låt
+
+SING_GAME_OPTIONS=spelinställningar
+SING_GAME_OPTIONS_DESC=ändra spelets inställningar
+
+SING_EXIT=avsluta
+SING_EXIT_DESC=sluta spela
+
+SING_OPTIONS=inställningar
+SING_OPTIONS_DESC=ändra inställningar
+SING_OPTIONS_WHEREAMI=Inställningar
+
+SING_OPTIONS_GAME=spel
+SING_OPTIONS_GRAPHICS=grafik
+SING_OPTIONS_SOUND=ljud
+SING_OPTIONS_LYRICS=text
+SING_OPTIONS_THEMES=teman
+SING_OPTIONS_RECORD=inspelning
+SING_OPTIONS_ADVANCED=avancerat
+SING_OPTIONS_EXIT=tillbaka
+
+SING_OPTIONS_GAME_WHEREAMI=Inställningar Spel
+SING_OPTIONS_GAME_DESC=vanliga spelinställningar
+SING_OPTIONS_GAME_PLAYERS=Spelare
+SING_OPTIONS_GAME_DIFFICULTY=Svårighetsnivå
+SING_OPTIONS_GAME_LANGUAGE=Språk
+SING_OPTIONS_GAME_TABS=Tabbar
+SING_OPTIONS_GAME_SORTING=Sortering
+SING_OPTIONS_GAME_DEBUG=Debuggning
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Inställningar Grafik
+SING_OPTIONS_GRAPHICS_DESC=grafikinställningar
+SING_OPTIONS_GRAPHICS_RESOLUTION=Upplösning
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullskärm
+SING_OPTIONS_GRAPHICS_DEPTH=Färgdjup
+SING_OPTIONS_GRAPHICS_VISUALIZER=Visualisering
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloskåp
+SING_OPTIONS_GRAPHICS_LINEBONUS=Radbonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Filmstorlek
+
+SING_OPTIONS_SOUND_WHEREAMI=Inställningar Ljud
+SING_OPTIONS_SOUND_DESC=ljudinställningar
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Mikrofonuppspelning
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Bakgrundsmusik
+SING_OPTIONS_SOUND_MIC_BOOST=Mikrofonförstärkning
+SING_OPTIONS_SOUND_CLICK_ASSIST=Hjälpljud
+SING_OPTIONS_SOUND_BEAT_CLICK=Taktljud
+SING_OPTIONS_SOUND_THRESHOLD=Ljudtröskel
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Tvåspelarläge
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Volym i låtvalsmenyn
+SING_OPTIONS_SOUND_PREVIEWFADING=Toning i låtvalsmenyn
+
+SING_OPTIONS_LYRICS_WHEREAMI=Inställningar Text
+SING_OPTIONS_LYRICS_DESC=sångtextinställningar
+SING_OPTIONS_LYRICS_FONT=Typsnitt
+SING_OPTIONS_LYRICS_EFFECT=Effekt
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmisation
+SING_OPTIONS_LYRICS_NOTELINES=Notlinjer
+
+SING_OPTIONS_THEMES_WHEREAMI=Inställningar Teman
+SING_OPTIONS_THEMES_DESC=temainställningar
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Färg
+
+SING_OPTIONS_RECORD_WHEREAMI=Inställningar Inspelning
+SING_OPTIONS_RECORD_DESC=Mikrofoninställningar
+SING_OPTIONS_RECORD_CARD=Ljudkort
+SING_OPTIONS_RECORD_INPUT=Ingång
+SING_OPTIONS_RECORD_CHANNEL=Kanal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Inställningar Avancerat
+SING_OPTIONS_ADVANCED_DESC=Avancerade inställningar
+SING_OPTIONS_ADVANCED_EFFECTSING=SÃ¥ngeffekter
+SING_OPTIONS_ADVANCED_SCREENFADE=Skärmtoning
+SING_OPTIONS_ADVANCED_LOADANIMATION=Laddningsanimering
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Säkerhetsfråga
+SING_OPTIONS_ADVANCED_LINEBONUS=Radbonus
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Vid LÃ¥tval
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Automatisk Partymeny
+
+SING_EDIT=Editor
+SING_EDIT_MENU_DESCRIPTION=skapa din egen låt
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importera text från midifil
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=tillbaka
+SING_EDIT_BUTTON_CONVERT=Importera
+SING_EDIT_BUTTON_EXIT=tillbaka
+
+SING_EDIT_NAVIGATE=navigera
+SING_EDIT_SELECT=välj
+SING_EDIT_EXIT=tillbaka
+
+SING_LEGEND_SELECT=välj
+SING_LEGEND_NAVIGATE=navigera
+SING_LEGEND_CONTINUE=fortsätt
+SING_LEGEND_ESC=tillbaka
+
+SING_PLAYER_DESC=skriv in spelarnamn
+SING_PLAYER_WHEREAMI=Spelarnamn
+SING_PLAYER_ENTER_NAME=skriv namn
+
+SING_DIFFICULTY_DESC=välj svårighetsnivå
+SING_DIFFICULTY_WHEREAMI=Svårighetsnivå
+SING_DIFFICULTY_CONTINUE=till låtval
+SING_EASY=Lätt
+SING_MEDIUM=Normal
+SING_HARD=Svår
+
+SING_SONG_SELECTION_DESC=välj din låt
+SING_SONG_SELECTION_WHEREAMI=LÃ¥tval
+SING_SONG_SELECTION_GOTO=gå till...
+SING_SONG_SELECTION=LÃ¥tval
+SING_SONG_SELECTION_MENU=meny
+SING_SONG_SELECTION_PLAYLIST=spellista
+SING_SONGS_IN_CAT=LÃ¥tar
+PLAYLIST_CATTEXT=Spellista: %s
+
+SING_TIME=TID
+SING_TOTAL=totalt
+SING_MODE=sjung solo
+SING_NOTES=toner
+SING_GOLDEN_NOTES=gyllene toner
+SING_PHRASE_BONUS=radbonus
+
+SING_MENU=Huvudmeny
+
+SONG_SCORE=Låtpoäng
+SONG_SCORE_WHEREAMI=Poäng
+
+SING_SCORE_TONE_DEAF=Tondöv
+SING_SCORE_AMATEUR=Amatör
+SING_SCORE_WANNABE=Wannabe
+SING_SCORE_HOPEFUL=Potential
+SING_SCORE_RISING_STAR=Stigande stjärna
+SING_SCORE_LEAD_SINGER=Hitartist
+SING_SCORE_SUPERSTAR=Superstjärna
+SING_SCORE_ULTRASTAR=Ultrastar!
+
+SING_TOP_5_CHARTS=topp 5 Spelare
+SING_TOP_5_CHARTS_WHEREAMI=topp 5
+SING_TOP_5_CHARTS_CONTINUE=till låtval
+
+POPUP_PERFECT=perfekt!
+POPUP_AWESOME=storartat!
+POPUP_GREAT=riktigt bra!
+POPUP_GOOD=bra!
+POPUP_NOTBAD=godkänt!
+POPUP_BAD=dåligt!
+POPUP_POOR=uselt!
+POPUP_AWFUL=avskyvärt!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= och
+
+SONG_MENU_NAME_MAIN=låtmeny
+SONG_MENU_PLAY=Sjung
+SONG_MENU_CHANGEPLAYERS=Ändra spelare
+SONG_MENU_EDIT=Redigera
+SONG_MENU_MODI=Sjung en mod
+SONG_MENU_CANCEL=Ã…ngra
+
+SONG_MENU_NAME_PLAYLIST=LÃ¥tmeny
+SONG_MENU_PLAYLIST_ADD=Lägg till låt
+SONG_MENU_PLAYLIST_DEL=Ta bort låt
+
+SONG_MENU_NAME_PLAYLIST_ADD=Lägg till låt
+SONG_MENU_PLAYLIST_ADD_NEW=till ny spellista
+SONG_MENU_PLAYLIST_ADD_EXISTING=till exsisterande spellista
+SONG_MENU_PLAYLIST_NOEXISTING=Ingen spellista tillgänglig
+
+SONG_MENU_NAME_PLAYLIST_NEW=Ny spellista
+SONG_MENU_PLAYLIST_NEW_CREATE=Skapa
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Namnlös
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Vill du verkligen bort?
+SONG_MENU_YES=Ja
+SONG_MENU_NO=Nej
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Öppna spellista
+SONG_MENU_PLAYLIST_LOAD=öppna
+SONG_MENU_PLAYLIST_DELCURRENT=ta bort nuvarande spellista
+
+SONG_MENU_NAME_PLAYLIST_DEL=Ta bort spellista?
+
+SONG_MENU_NAME_PARTY_MAIN=Partymeny
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=ta joker
+
+SONG_JUMPTO_DESC=sök låt
+SONG_JUMPTO_TYPE_DESC=Sök efter:
+SONG_JUMPTO_TYPE1=Alla
+SONG_JUMPTO_TYPE2=Titel
+SONG_JUMPTO_TYPE3=Artist
+SONG_JUMPTO_SONGSFOUND=%d LÃ¥t(ar) hittade
+SONG_JUMPTO_NOSONGSFOUND=Ingen låt hittad
+SONG_JUMPTO_HELP=Skriv text att söka efter
+SONG_JUMPTO_CATTEXT=Sök efter: %s
+
+PARTY_MODE=partyläge
+PARTY_DIFFICULTY=Svårighetsnivå
+PARTY_PLAYLIST=Spellistläge
+PARTY_PLAYLIST_ALL=Alla låtar
+PARTY_PLAYLIST_CATEGORY=Mapp
+PARTY_PLAYLIST_PLAYLIST=Spellista
+PARTY_ROUNDS=Omgångar
+PARTY_TEAMS=Lag
+PARTY_TEAMS_PLAYER1=Spelare Lag1
+PARTY_TEAMS_PLAYER2=Spelare Lag2
+PARTY_TEAMS_PLAYER3=Spelare Lag3
+
+PARTY_LEGEND_CONTINUE=fortsätt
+
+PARTY_OPTIONS_DESC=inställningar för partyspel
+PARTY_OPTIONS_WHEREAMI=Partyinställningar
+
+PARTY_PLAYER_DESC=skriv spelar- och lagnamn!
+PARTY_PLAYER_WHEREAMI=Partynamn
+PARTY_PLAYER_ENTER_NAME=skriv namn
+PARTY_PLAYER_LEGEND_CONTINUE=starta partyspel
+
+PARTY_ROUND_DESC=nästa spelare till mikrofonerna
+PARTY_ROUND_WHEREAMI=Party Nästa omgång
+PARTY_ROUND_LEGEND_CONTINUE=starta omgång
+
+PARTY_SONG_WHEREAMI=Party LÃ¥tval
+PARTY_SONG_LEGEND_CONTINUE=sjung
+PARTY_SONG_MENU=partymeny
+
+PARTY_SCORE_DESC=poäng från förra omgången
+PARTY_SCORE_WHEREAMI=Partypoäng
+
+PARTY_WIN_DESC=vinnare av partyspelet
+PARTY_WIN_WHEREAMI=Partyvinnare
+PARTY_WIN_LEGEND_CONTINUE=tillbaka till huvudmenyn
+
+PARTY_ROUND=Omgång
+PARTY_ROUND_WINNER=Vinnare
+PARTY_NOTPLAYEDYET=inte spelad än
+PARTY_NOBODY=ingen
+NEXT_ROUND=Nästa runda:
+
+PARTY_DISMISSED=Avbröt!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=vann!
+
+PLUGIN_HDL_NAME=HÃ¥ll god ton
+PLUGIN_HDL_DESC=Bli inte sämre än vad markeringen på omdömesmätaren visar.
+PLUGIN_UNTIL5000_NAME=Till 5000
+PLUGIN_UNTIL5000_DESC=Den som först får 5000 poäng vinner matchen.
+
+PLUGIN_DUELL_NAME=Duell
+PLUGIN_DUELL_DESC=Sjung en duett till 10000 poäng.
+
+PLUGIN_TEAMDUELL_NAME=Lagduell
+PLUGIN_TEAMDUELL_DESC=Skicka micken!
+
+PLUGIN_BLIND_NAME=Blindläge
+PLUGIN_BLIND_DESC=Duell utan att se tonerna.
+
+STAT_MAIN=Statistik
+STAT_MAIN_DESC=Allmänn
+STAT_MAIN_WHEREAMI=Statistik
+
+STAT_OVERVIEW_INTRO=%0:s Statistik. \n Senast återställd %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Låtar(%3:d med Video), varav %1:d redan har spelats och %2:d inte har spelats än.\n Den mest populära låten är %5:s med %4:s.
+STAT_OVERVIEW_PLAYER=Sedan den senaste återställningen har %0:d olika spelare sjungit.\n Den bästa spelaren är %1:s med ett genomsnitt på %2:d poäng.\n %3:s har sjungit bäst med %4:d poäng.
+
+STAT_DETAIL=Statistik
+STAT_DETAIL_WHEREAMI=Detaljerad statistik
+
+STAT_NEXT=Nästa sida
+STAT_PREV=Föregående sida
+STAT_REVERSE=Omvänd ordning
+STAT_PAGE=Sida %0:d av %1:d sidor\n (%2:d av %3:d poster)
+
+STAT_DESC_SCORES=Högsta resultat
+STAT_DESC_SCORES_REVERSED=Lägsta resultat
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Bästa sångare
+STAT_DESC_SINGERS_REVERSED=Sämsta sångare
+STAT_FORMAT_SINGERS=%0:s \n genomsnittlig poäng: %1:d
+
+STAT_DESC_SONGS=Populäraste låtarna
+STAT_DESC_SONGS_REVERSED=Minst populära låtarna
+STAT_FORMAT_SONGS=%0:s - %1:s \n Sjungen %2:dx gånger
+
+STAT_DESC_BANDS=Populäraste artisterna
+STAT_DESC_BANDS_REVERSED=Minst populära artisterna
+STAT_FORMAT_BANDS=%0:s \n %1:dx sjungna
+
+MSG_ERROR_TITLE=Fel
+MSG_QUESTION_TITLE=Fråga
+MSG_QUIT_USDX=Vill du verkligen avsluta UltraStar?
+MSG_END_PARTY=Vill du verkligen avsluta partyläge?
+ERROR_NO_SONGS=Inga låtar laddade
+ERROR_NO_PLUGINS=Inga insticksprogram laddade
+ERROR_CORRUPT_SONG=LÃ¥ten kunde inte laddas.
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=LÃ¥ten kunde inte laddas: Filen kunde inte hittas
+ERROR_CORRUPT_SONG_NO_NOTES=LÃ¥ten kunde inte laddas: Kan inte hitta toner
+ERROR_CORRUPT_SONG_NO_BREAKS=LÃ¥ten kunde inte laddas: Kan inte hitta radbrytningar
+ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Låten kunde inte laddas: Fel på rad %0:d \ No newline at end of file
diff --git a/game/languages/convert.sh b/game/languages/convert.sh
new file mode 100755
index 00000000..328efcda
--- /dev/null
+++ b/game/languages/convert.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# See: http://www.microsoft.com/resources/msdn/goglobal/default.mspx?OS=Windows%20Vista
+
+function convertUTF8 {
+ if [ ! -f $2.ini ]; then
+ echo "skip $2.ini: does not exist"
+ return
+ fi
+
+ # UTF-8 BOM (0xEF 0xBB 0xBF)
+ BOM=`echo -n -e "\0357\0273\0277"`
+ HEADER=`head -c3 $2.ini`
+ if [ $HEADER != $BOM ]; then
+ echo "Convert $2.ini from $1 to UTF8"
+ echo -n $BOM >$2.tmp
+ iconv -f $1 -t UTF-8 $2.ini >>$2.tmp
+ mv $2.tmp $2.ini
+ else
+ echo "skip $2.ini: already UTF8"
+ fi
+}
+
+#convertUTF8 UTF8 Catalan
+convertUTF8 CP1252 French
+convertUTF8 CP1252 Italian
+convertUTF8 CP1252 Spanish
+convertUTF8 CP1250 Croatian
+convertUTF8 CP1252 Euskara
+convertUTF8 CP1252 German
+#convertUTF8 UCS-2LE Japanese
+convertUTF8 CP1252 Swedish
+convertUTF8 CP1252 Dutch
+convertUTF8 CP1252 Finnish
+convertUTF8 CP1253 Greek
+convertUTF8 CP1252 Portuguese
+
+convertUTF8 CP1252 Danish
+convertUTF8 CP1252 Norwegian
+#convertUTF8 CP1251 Serbian
+convertUTF8 CP1250 Serbian
+convertUTF8 CP1250 Slovenian
+convertUTF8 CP1250 Polish
+convertUTF8 CP1250 Slovak
diff --git a/game/languages/old/Danish.ini b/game/languages/old/Danish.ini
index a9871a65..39d0379d 100644
--- a/game/languages/old/Danish.ini
+++ b/game/languages/old/Danish.ini
@@ -1,297 +1,297 @@
-[Text]
-SING_LOADING=Loader...
-
-SING_CHOOSE_MODE=Vælg modus
-SING_SING=Syng
-SING_SING_DESC=Hurtigt spil: Syng solo eller duet
-
-SING_MULTI=Fest
-SING_MULTI_DESC=Syng i fest modus
-
-SING_TOOLS=Værktøjer
-
-SING_STATS=stats
-SING_STATS_DESC=Se statestikker
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=Lav dine egne sange
-SING_GAME_OPTIONS=Spil Indstillinger
-SING_GAME_OPTIONS_DESC=Ændre spil Indstillinger
-
-SING_EXIT=Forlad
-SING_EXIT_DESC=Forlad spillet
-
-SING_OPTIONS=Indstillinger
-SING_OPTIONS_DESC=Ændre Instillinger
-SING_OPTIONS_WHEREAMI=Indstillinger
-
-SING_OPTIONS_GAME=Spil
-SING_OPTIONS_GRAPHICS=Grafik
-SING_OPTIONS_SOUND=Lyd
-SING_OPTIONS_LYRICS=Tekster
-SING_OPTIONS_THEMES=Temaer
-SING_OPTIONS_RECORD=Optag
-SING_OPTIONS_ADVANCED=Advanceret
-SING_OPTIONS_EXIT=Tilbage
-
-SING_OPTIONS_GAME_WHEREAMI=Spil Indstillinger
-SING_OPTIONS_GAME_DESC=Generelle Spil Indstillinger
-SING_OPTIONS_GAME_PLAYERS=Spillere
-SING_OPTIONS_GAME_DIFFICULTY=Sværhedsgrad
-SING_OPTIONS_GAME_LANGUAGE=Sprog
-SING_OPTIONS_GAME_TABS=Tabs
-SING_OPTIONS_GAME_SORTING=Sorting
-SING_OPTIONS_GAME_DEBUG=Debug
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Grafik Indstillinger
-SING_OPTIONS_GRAPHICS_DESC=Grafik Indstillinger
-SING_OPTIONS_GRAPHICS_RESOLUTION=Opløsning
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Fuldskærm
-SING_OPTIONS_GRAPHICS_DEPTH=Farve dybte
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloskop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Linie Bonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Film Størrelse
-
-SING_OPTIONS_SOUND_WHEREAMI=Lyd Indstillinger
-SING_OPTIONS_SOUND_DESC=Lyd Indstillinger
-SING_OPTIONS_SOUND_MIC_BOOST=Mikrofon Boost
-SING_OPTIONS_SOUND_CLICK_ASSIST=Click assist
-SING_OPTIONS_SOUND_BEAT_CLICK=Beat click
-SING_OPTIONS_SOUND_THRESHOLD=Tærskel
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=2 Spiller modus
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Frosmag Volume
-SING_OPTIONS_SOUND_PREVIEWFADING=Forsmag Fader
-
-SING_OPTIONS_LYRICS_WHEREAMI=Tekst Indstillinger
-SING_OPTIONS_LYRICS_DESC=Tekst Indstillinger
-SING_OPTIONS_LYRICS_FONT=Tekst Type
-SING_OPTIONS_LYRICS_EFFECT=Effekt
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmization
-
-SING_OPTIONS_THEMES_WHEREAMI=Tema Indstillinger
-SING_OPTIONS_THEMES_DESC=Tema og Skin Indstillinger
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Farve
-
-SING_OPTIONS_RECORD_WHEREAMI=Optagelses Indstillinger
-SING_OPTIONS_RECORD_DESC=Mikrofon Indstillinger
-SING_OPTIONS_RECORD_CARD=Lydkort
-SING_OPTIONS_RECORD_INPUT=Input
-SING_OPTIONS_RECORD_CHANNEL=Kanal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Advancerede Indstillinger
-SING_OPTIONS_ADVANCED_DESC=Advancerede Indstillinger
-SING_OPTIONS_ADVANCED_EFFECTSING=Sang Effekter
-SING_OPTIONS_ADVANCED_SCREENFADE=Skærm Fading
-SING_OPTIONS_ADVANCED_LOADANIMATION=Load Animation
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Savety Questions
-SING_OPTIONS_ADVANCED_LINEBONUS=Linie Bonus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Efter sang valg
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto Festmodus
-
-SING_LEGEND_SELECT=Vælg
-SING_LEGEND_NAVIGATE=Naviger
-SING_LEGEND_CONTINUE=Fortsæt
-SING_LEGEND_ESC=Tilbage
-
-SING_PLAYER_DESC=Skriv Spiller Navn/e
-SING_PLAYER_WHEREAMI=Spiller Navne
-SING_PLAYER_ENTER_NAME=Skriv navn
-
-SING_DIFFICULTY_DESC=Vælg Sværhedsgrad
-SING_DIFFICULTY_WHEREAMI=Sværhedsgrad
-SING_DIFFICULTY_CONTINUE=Til sang valg
-SING_EASY=Let
-SING_MEDIUM=Normal
-SING_HARD=Svær
-
-SING_SONG_SELECTION_DESC=Vælg Din Sang
-SING_SONG_SELECTION_WHEREAMI=Sang Valg
-SING_SONG_SELECTION_GOTO=Gå Til ..
-SING_SONG_SELECTION=Sang Valg
-SING_SONG_SELECTION_MENU=Menu
-SING_SONG_SELECTION_PLAYLIST=Afspilningsliste
-SING_SONGS_IN_CAT=Songs
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TID
-SING_TOTAL=Total
-SING_MODE=Syng Solo
-SING_NOTES=Noder
-SING_GOLDEN_NOTES=Gyldne Noder
-SING_PHRASE_BONUS=Linie Bonus
-
-SING_MENU=Hoved Menu
-
-SONG_SCORE=Sang score
-SONG_SCORE_WHEREAMI=Score
-
-SING_SCORE_TONE_DEAF=Tone Døv!
-SING_SCORE_AMATEUR=Amatør!
-SING_SCORE_RISING_STAR=Aspirende Stjerne
-SING_SCORE_LEAD_SINGER=Forsanger
-SING_SCORE_HIT_ARTIST=Etableret Stjerne
-SING_SCORE_SUPERSTAR=Super Stjerne
-SING_SCORE_ULTRASTAR=Ultra Stjerne
-
-SING_TOP_5_CHARTS=Top 5 Spillere
-SING_TOP_5_CHARTS_WHEREAMI=Top 5
-SING_TOP_5_CHARTS_CONTINUE=Til Sang Valg
-
-POPUP_PERFECT=Perfekt!
-POPUP_AWESOME=Utroligt!
-POPUP_GREAT=Meget Godt!
-POPUP_GOOD=Godt!
-POPUP_NOTBAD=Ikke dårligt!
-POPUP_BAD=Dårligt!
-POPUP_POOR=Meget Dårligt!
-POPUP_AWFUL=Ringe!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= og
-
-SONG_MENU_NAME_MAIN=Sang Menu
-SONG_MENU_PLAY=Syng
-SONG_MENU_CHANGEPLAYERS=Skift Spillere
-SONG_MENU_EDIT=Ændre
-SONG_MENU_MODI=Sing a Modi
-SONG_MENU_CANCEL=Annuller
-
-SONG_MENU_NAME_PLAYLIST=Sang Menu
-SONG_MENU_PLAYLIST_ADD=Tilføj Sang
-SONG_MENU_PLAYLIST_DEL=Slet Sang
-
-SONG_MENU_NAME_PLAYLIST_ADD=Tilføj Song
-SONG_MENU_PLAYLIST_ADD_NEW=Til Ny Afspilningsliste
-SONG_MENU_PLAYLIST_ADD_EXISTING=Til Eksisterende Afspilningsliste
-SONG_MENU_PLAYLIST_NOEXISTING=Ingen Tilgængelige Afspilningslister
-
-SONG_MENU_NAME_PLAYLIST_NEW=Ny Afspilningsliste
-SONG_MENU_PLAYLIST_NEW_CREATE=Skab
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Unavngiven
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Vil Du Virkelig Slette?
-SONG_MENU_YES=Ja
-SONG_MENU_NO=Nej
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Åben Afspilningsliste
-SONG_MENU_PLAYLIST_LOAD=Åben
-SONG_MENU_PLAYLIST_DELCURRENT=Slet Nuværende Afspilningsliste
-
-SONG_MENU_NAME_PLAYLIST_DEL=Slet Afspilningslisten?
-
-SONG_MENU_NAME_PARTY_MAIN=Fest Menu
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=Brug Jokeren
-
-SONG_JUMPTO_DESC=Søg Sang
-SONG_JUMPTO_TYPE_DESC=Søg Efter:
-SONG_JUMPTO_TYPE1=Alle
-SONG_JUMPTO_TYPE2=Titel
-SONG_JUMPTO_TYPE3=Kunstner
-SONG_JUMPTO_SONGSFOUND=%d Sang(e) fundet!
-SONG_JUMPTO_NOSONGSFOUND=Ingen Sange Fundet
-SONG_JUMPTO_HELP=Skriv Teksten Du Vil Søge Efter
-SONG_JUMPTO_CATTEXT=Søg Efter: %s
-
-PARTY_MODE=Fest modus
-PARTY_DIFFICULTY=Sværhedsgrad
-PARTY_PLAYLIST=Afspilningsliste modus
-PARTY_PLAYLIST_ALL=Alle sange
-PARTY_PLAYLIST_CATEGORY=Mappe
-PARTY_PLAYLIST_PLAYLIST=Afspilningsliste
-PARTY_ROUNDS=Runder
-PARTY_TEAMS=Teams
-PARTY_TEAMS_PLAYER1=Spiller Team 1
-PARTY_TEAMS_PLAYER2=Spiller Team 2
-PARTY_TEAMS_PLAYER3=Spiller Team 3
-
-PARTY_LEGEND_CONTINUE=Fortsæt
-
-PARTY_OPTIONS_DESC=Indstillinger for Fest spil
-PARTY_OPTIONS_WHEREAMI=Fest Indstillinger
-
-PARTY_PLAYER_DESC=Skriv Spiller of Team Navn!
-PARTY_PLAYER_WHEREAMI=Fest navne
-PARTY_PLAYER_ENTER_NAME=Skriv Navne
-PARTY_PLAYER_LEGEND_CONTINUE=Start Fest Spil
-
-PARTY_ROUND_DESC=Næste spillere til mikrofonerne
-PARTY_ROUND_WHEREAMI=Fest Næste runde
-PARTY_ROUND_LEGEND_CONTINUE=Start runde
-
-PARTY_SONG_WHEREAMI=Fest Sang-Valg
-PARTY_SONG_LEGEND_CONTINUE=Syng
-PARTY_SONG_MENU=Fest menu
-
-PARTY_SCORE_DESC=Sidste Rundes Score
-PARTY_SCORE_WHEREAMI=Fest Point
-
-PARTY_WIN_DESC=Vinderen Af Fest Spillet
-PARTY_WIN_WHEREAMI=Fest Vinder
-PARTY_WIN_LEGEND_CONTINUE=Tilbage til Hoved Menuen
-
-PARTY_ROUND=Runde
-PARTY_ROUND_WINNER=vinder
-PARTY_NOTPLAYEDYET=Ikke spillet endnu
-PARTY_NOBODY=Ingen
-NEXT_ROUND=Næste Runde:
-
-PARTY_DISMISSED=Afsluttet!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=Vinder!
-
-PLUGIN_HDL_NAME=Hold Linien
-PLUGIN_HDL_DESC=Få ikke værrer end pilen på skalaen peger på
-
-PLUGIN_UNTIL5000_NAME=Until 5000
-PLUGIN_UNTIL5000_DESC=Hvem får 5000 point først vinder the kampen.
-
-PLUGIN_DUELL_NAME=Duell
-PLUGIN_DUELL_DESC=Syng en duel intil 10000 point.
-
-PLUGIN_BLIND_NAME=Blind Modus
-PLUGIN_BLIND_DESC=Duel med usynlige noder.
-
-STAT_MAIN=Statestikker
-STAT_MAIN_DESC=Generelle
-STAT_MAIN_WHEREAMI=Statestikker
-
-STAT_OVERVIEW_INTRO=%0:s Statistics. \n Last Reset at %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Songs(%3:d with Video), whereof %1:d already were played and %2:d were not played yet.\n The most popular Song is %5:s from %4:s.
-STAT_OVERVIEW_PLAYER=Since the last Reset there were/was %0:d different Player(s).\n The best Player is %1:s with an average Score of %2:d Points.\n %3:s did the highest Score with %4:d Points.
-
-STAT_DETAIL=Statestikker
-STAT_DETAIL_WHEREAMI=Detaljerede Statestikker
-
-STAT_NEXT=Næste Side
-STAT_PREV=Tidligere Side
-STAT_REVERSE=Omvendt Orden
-STAT_PAGE=Seite %0:d of %1:d Pages\n (%2:d of %3:d Entrys)
-
-STAT_DESC_SCORES=HighScore
-STAT_DESC_SCORES_REVERSED=LowScore
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Bedste Sangere
-STAT_DESC_SINGERS_REVERSED=Værste Sangere
-STAT_FORMAT_SINGERS=%0:s \n Average Score: %1:d
-
-STAT_DESC_SONGS=Mest Populære Sange
-STAT_DESC_SONGS_REVERSED=Mindst Populære Sange
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx sung
-
-STAT_DESC_BANDS=Mest Populære Bands
-STAT_DESC_BANDS_REVERSED=Mindst Populære Bands
-STAT_FORMAT_BANDS=%0:s \n %1:dx Sung
-
-MSG_ERROR_TITLE=Fejl
-MSG_QUESTION_TITLE=Spørgsmål
-MSG_QUIT_USDX=Vil du virkelig forlade UltraStar?
-MSG_END_PARTY=Vil du virkelig forlade fest Modus?
-ERROR_NO_SONGS=Ingen Sange hentet
-ERROR_NO_PLUGINS=Igen Plugins hentet
+[Text]
+SING_LOADING=Loader...
+
+SING_CHOOSE_MODE=Vælg modus
+SING_SING=Syng
+SING_SING_DESC=Hurtigt spil: Syng solo eller duet
+
+SING_MULTI=Fest
+SING_MULTI_DESC=Syng i fest modus
+
+SING_TOOLS=Værktøjer
+
+SING_STATS=stats
+SING_STATS_DESC=Se statestikker
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=Lav dine egne sange
+SING_GAME_OPTIONS=Spil Indstillinger
+SING_GAME_OPTIONS_DESC=Ændre spil Indstillinger
+
+SING_EXIT=Forlad
+SING_EXIT_DESC=Forlad spillet
+
+SING_OPTIONS=Indstillinger
+SING_OPTIONS_DESC=Ændre Instillinger
+SING_OPTIONS_WHEREAMI=Indstillinger
+
+SING_OPTIONS_GAME=Spil
+SING_OPTIONS_GRAPHICS=Grafik
+SING_OPTIONS_SOUND=Lyd
+SING_OPTIONS_LYRICS=Tekster
+SING_OPTIONS_THEMES=Temaer
+SING_OPTIONS_RECORD=Optag
+SING_OPTIONS_ADVANCED=Advanceret
+SING_OPTIONS_EXIT=Tilbage
+
+SING_OPTIONS_GAME_WHEREAMI=Spil Indstillinger
+SING_OPTIONS_GAME_DESC=Generelle Spil Indstillinger
+SING_OPTIONS_GAME_PLAYERS=Spillere
+SING_OPTIONS_GAME_DIFFICULTY=Sværhedsgrad
+SING_OPTIONS_GAME_LANGUAGE=Sprog
+SING_OPTIONS_GAME_TABS=Tabs
+SING_OPTIONS_GAME_SORTING=Sorting
+SING_OPTIONS_GAME_DEBUG=Debug
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Grafik Indstillinger
+SING_OPTIONS_GRAPHICS_DESC=Grafik Indstillinger
+SING_OPTIONS_GRAPHICS_RESOLUTION=Opløsning
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Fuldskærm
+SING_OPTIONS_GRAPHICS_DEPTH=Farve dybte
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloskop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Linie Bonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Film Størrelse
+
+SING_OPTIONS_SOUND_WHEREAMI=Lyd Indstillinger
+SING_OPTIONS_SOUND_DESC=Lyd Indstillinger
+SING_OPTIONS_SOUND_MIC_BOOST=Mikrofon Boost
+SING_OPTIONS_SOUND_CLICK_ASSIST=Click assist
+SING_OPTIONS_SOUND_BEAT_CLICK=Beat click
+SING_OPTIONS_SOUND_THRESHOLD=Tærskel
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=2 Spiller modus
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Frosmag Volume
+SING_OPTIONS_SOUND_PREVIEWFADING=Forsmag Fader
+
+SING_OPTIONS_LYRICS_WHEREAMI=Tekst Indstillinger
+SING_OPTIONS_LYRICS_DESC=Tekst Indstillinger
+SING_OPTIONS_LYRICS_FONT=Tekst Type
+SING_OPTIONS_LYRICS_EFFECT=Effekt
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmization
+
+SING_OPTIONS_THEMES_WHEREAMI=Tema Indstillinger
+SING_OPTIONS_THEMES_DESC=Tema og Skin Indstillinger
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Farve
+
+SING_OPTIONS_RECORD_WHEREAMI=Optagelses Indstillinger
+SING_OPTIONS_RECORD_DESC=Mikrofon Indstillinger
+SING_OPTIONS_RECORD_CARD=Lydkort
+SING_OPTIONS_RECORD_INPUT=Input
+SING_OPTIONS_RECORD_CHANNEL=Kanal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Advancerede Indstillinger
+SING_OPTIONS_ADVANCED_DESC=Advancerede Indstillinger
+SING_OPTIONS_ADVANCED_EFFECTSING=Sang Effekter
+SING_OPTIONS_ADVANCED_SCREENFADE=Skærm Fading
+SING_OPTIONS_ADVANCED_LOADANIMATION=Load Animation
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Savety Questions
+SING_OPTIONS_ADVANCED_LINEBONUS=Linie Bonus
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Efter sang valg
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto Festmodus
+
+SING_LEGEND_SELECT=Vælg
+SING_LEGEND_NAVIGATE=Naviger
+SING_LEGEND_CONTINUE=Fortsæt
+SING_LEGEND_ESC=Tilbage
+
+SING_PLAYER_DESC=Skriv Spiller Navn/e
+SING_PLAYER_WHEREAMI=Spiller Navne
+SING_PLAYER_ENTER_NAME=Skriv navn
+
+SING_DIFFICULTY_DESC=Vælg Sværhedsgrad
+SING_DIFFICULTY_WHEREAMI=Sværhedsgrad
+SING_DIFFICULTY_CONTINUE=Til sang valg
+SING_EASY=Let
+SING_MEDIUM=Normal
+SING_HARD=Svær
+
+SING_SONG_SELECTION_DESC=Vælg Din Sang
+SING_SONG_SELECTION_WHEREAMI=Sang Valg
+SING_SONG_SELECTION_GOTO=Gå Til ..
+SING_SONG_SELECTION=Sang Valg
+SING_SONG_SELECTION_MENU=Menu
+SING_SONG_SELECTION_PLAYLIST=Afspilningsliste
+SING_SONGS_IN_CAT=Songs
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TID
+SING_TOTAL=Total
+SING_MODE=Syng Solo
+SING_NOTES=Noder
+SING_GOLDEN_NOTES=Gyldne Noder
+SING_PHRASE_BONUS=Linie Bonus
+
+SING_MENU=Hoved Menu
+
+SONG_SCORE=Sang score
+SONG_SCORE_WHEREAMI=Score
+
+SING_SCORE_TONE_DEAF=Tone Døv!
+SING_SCORE_AMATEUR=Amatør!
+SING_SCORE_RISING_STAR=Aspirende Stjerne
+SING_SCORE_LEAD_SINGER=Forsanger
+SING_SCORE_HIT_ARTIST=Etableret Stjerne
+SING_SCORE_SUPERSTAR=Super Stjerne
+SING_SCORE_ULTRASTAR=Ultra Stjerne
+
+SING_TOP_5_CHARTS=Top 5 Spillere
+SING_TOP_5_CHARTS_WHEREAMI=Top 5
+SING_TOP_5_CHARTS_CONTINUE=Til Sang Valg
+
+POPUP_PERFECT=Perfekt!
+POPUP_AWESOME=Utroligt!
+POPUP_GREAT=Meget Godt!
+POPUP_GOOD=Godt!
+POPUP_NOTBAD=Ikke dårligt!
+POPUP_BAD=Dårligt!
+POPUP_POOR=Meget Dårligt!
+POPUP_AWFUL=Ringe!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= og
+
+SONG_MENU_NAME_MAIN=Sang Menu
+SONG_MENU_PLAY=Syng
+SONG_MENU_CHANGEPLAYERS=Skift Spillere
+SONG_MENU_EDIT=Ændre
+SONG_MENU_MODI=Sing a Modi
+SONG_MENU_CANCEL=Annuller
+
+SONG_MENU_NAME_PLAYLIST=Sang Menu
+SONG_MENU_PLAYLIST_ADD=Tilføj Sang
+SONG_MENU_PLAYLIST_DEL=Slet Sang
+
+SONG_MENU_NAME_PLAYLIST_ADD=Tilføj Song
+SONG_MENU_PLAYLIST_ADD_NEW=Til Ny Afspilningsliste
+SONG_MENU_PLAYLIST_ADD_EXISTING=Til Eksisterende Afspilningsliste
+SONG_MENU_PLAYLIST_NOEXISTING=Ingen Tilgængelige Afspilningslister
+
+SONG_MENU_NAME_PLAYLIST_NEW=Ny Afspilningsliste
+SONG_MENU_PLAYLIST_NEW_CREATE=Skab
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Unavngiven
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Vil Du Virkelig Slette?
+SONG_MENU_YES=Ja
+SONG_MENU_NO=Nej
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Åben Afspilningsliste
+SONG_MENU_PLAYLIST_LOAD=Åben
+SONG_MENU_PLAYLIST_DELCURRENT=Slet Nuværende Afspilningsliste
+
+SONG_MENU_NAME_PLAYLIST_DEL=Slet Afspilningslisten?
+
+SONG_MENU_NAME_PARTY_MAIN=Fest Menu
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=Brug Jokeren
+
+SONG_JUMPTO_DESC=Søg Sang
+SONG_JUMPTO_TYPE_DESC=Søg Efter:
+SONG_JUMPTO_TYPE1=Alle
+SONG_JUMPTO_TYPE2=Titel
+SONG_JUMPTO_TYPE3=Kunstner
+SONG_JUMPTO_SONGSFOUND=%d Sang(e) fundet!
+SONG_JUMPTO_NOSONGSFOUND=Ingen Sange Fundet
+SONG_JUMPTO_HELP=Skriv Teksten Du Vil Søge Efter
+SONG_JUMPTO_CATTEXT=Søg Efter: %s
+
+PARTY_MODE=Fest modus
+PARTY_DIFFICULTY=Sværhedsgrad
+PARTY_PLAYLIST=Afspilningsliste modus
+PARTY_PLAYLIST_ALL=Alle sange
+PARTY_PLAYLIST_CATEGORY=Mappe
+PARTY_PLAYLIST_PLAYLIST=Afspilningsliste
+PARTY_ROUNDS=Runder
+PARTY_TEAMS=Teams
+PARTY_TEAMS_PLAYER1=Spiller Team 1
+PARTY_TEAMS_PLAYER2=Spiller Team 2
+PARTY_TEAMS_PLAYER3=Spiller Team 3
+
+PARTY_LEGEND_CONTINUE=Fortsæt
+
+PARTY_OPTIONS_DESC=Indstillinger for Fest spil
+PARTY_OPTIONS_WHEREAMI=Fest Indstillinger
+
+PARTY_PLAYER_DESC=Skriv Spiller of Team Navn!
+PARTY_PLAYER_WHEREAMI=Fest navne
+PARTY_PLAYER_ENTER_NAME=Skriv Navne
+PARTY_PLAYER_LEGEND_CONTINUE=Start Fest Spil
+
+PARTY_ROUND_DESC=Næste spillere til mikrofonerne
+PARTY_ROUND_WHEREAMI=Fest Næste runde
+PARTY_ROUND_LEGEND_CONTINUE=Start runde
+
+PARTY_SONG_WHEREAMI=Fest Sang-Valg
+PARTY_SONG_LEGEND_CONTINUE=Syng
+PARTY_SONG_MENU=Fest menu
+
+PARTY_SCORE_DESC=Sidste Rundes Score
+PARTY_SCORE_WHEREAMI=Fest Point
+
+PARTY_WIN_DESC=Vinderen Af Fest Spillet
+PARTY_WIN_WHEREAMI=Fest Vinder
+PARTY_WIN_LEGEND_CONTINUE=Tilbage til Hoved Menuen
+
+PARTY_ROUND=Runde
+PARTY_ROUND_WINNER=vinder
+PARTY_NOTPLAYEDYET=Ikke spillet endnu
+PARTY_NOBODY=Ingen
+NEXT_ROUND=Næste Runde:
+
+PARTY_DISMISSED=Afsluttet!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=Vinder!
+
+PLUGIN_HDL_NAME=Hold Linien
+PLUGIN_HDL_DESC=Få ikke værrer end pilen på skalaen peger på
+
+PLUGIN_UNTIL5000_NAME=Until 5000
+PLUGIN_UNTIL5000_DESC=Hvem får 5000 point først vinder the kampen.
+
+PLUGIN_DUELL_NAME=Duell
+PLUGIN_DUELL_DESC=Syng en duel intil 10000 point.
+
+PLUGIN_BLIND_NAME=Blind Modus
+PLUGIN_BLIND_DESC=Duel med usynlige noder.
+
+STAT_MAIN=Statestikker
+STAT_MAIN_DESC=Generelle
+STAT_MAIN_WHEREAMI=Statestikker
+
+STAT_OVERVIEW_INTRO=%0:s Statistics. \n Last Reset at %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Songs(%3:d with Video), whereof %1:d already were played and %2:d were not played yet.\n The most popular Song is %5:s from %4:s.
+STAT_OVERVIEW_PLAYER=Since the last Reset there were/was %0:d different Player(s).\n The best Player is %1:s with an average Score of %2:d Points.\n %3:s did the highest Score with %4:d Points.
+
+STAT_DETAIL=Statestikker
+STAT_DETAIL_WHEREAMI=Detaljerede Statestikker
+
+STAT_NEXT=Næste Side
+STAT_PREV=Tidligere Side
+STAT_REVERSE=Omvendt Orden
+STAT_PAGE=Seite %0:d of %1:d Pages\n (%2:d of %3:d Entrys)
+
+STAT_DESC_SCORES=HighScore
+STAT_DESC_SCORES_REVERSED=LowScore
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Bedste Sangere
+STAT_DESC_SINGERS_REVERSED=Værste Sangere
+STAT_FORMAT_SINGERS=%0:s \n Average Score: %1:d
+
+STAT_DESC_SONGS=Mest Populære Sange
+STAT_DESC_SONGS_REVERSED=Mindst Populære Sange
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx sung
+
+STAT_DESC_BANDS=Mest Populære Bands
+STAT_DESC_BANDS_REVERSED=Mindst Populære Bands
+STAT_FORMAT_BANDS=%0:s \n %1:dx Sung
+
+MSG_ERROR_TITLE=Fejl
+MSG_QUESTION_TITLE=Spørgsmål
+MSG_QUIT_USDX=Vil du virkelig forlade UltraStar?
+MSG_END_PARTY=Vil du virkelig forlade fest Modus?
+ERROR_NO_SONGS=Ingen Sange hentet
+ERROR_NO_PLUGINS=Igen Plugins hentet
ERROR_CORRUPT_SONG=Sangen kunne ikke hentes. \ No newline at end of file
diff --git a/game/languages/old/French.ini b/game/languages/old/French.ini
index 41403934..8a841fab 100644
--- a/game/languages/old/French.ini
+++ b/game/languages/old/French.ini
@@ -1,310 +1,310 @@
-[Text]
-SING_LOADING=Chargement...
-
-SING_CHOOSE_MODE=Choisir un mode
-SING_SING=Solo
-SING_SING_DESC=Chanter
-
-SING_MULTI=Multi
-SING_MULTI_DESC=Chanter à plusieurs
-
-SING_TOOLS=Outils
-
-SING_STATS=Statistiques
-SING_STATS_DESC=Consulter les statistiques
-
-SING_EDITOR=Éditeur
-SING_EDITOR_DESC=Créer vos propre chansons
-
-SING_GAME_OPTIONS=Options
-SING_GAME_OPTIONS_DESC=Modifier les paramètres du jeu
-
-SING_EXIT=Quitter
-SING_EXIT_DESC=Quitter le jeu
-
-SING_OPTIONS=Options
-SING_OPTIONS_DESC=Changer les paramètres
-SING_OPTIONS_WHEREAMI=Options
-
-SING_OPTIONS_GAME=Jeu
-SING_OPTIONS_GRAPHICS=Graphismes
-SING_OPTIONS_SOUND=Audio
-SING_OPTIONS_LYRICS=Paroles
-SING_OPTIONS_THEMES=Thèmes
-SING_OPTIONS_RECORD=Micros
-SING_OPTIONS_ADVANCED=Avancé
-SING_OPTIONS_EXIT=Retour
-
-SING_OPTIONS_GAME_WHEREAMI=Options de jeu
-SING_OPTIONS_GAME_DESC=Options générales de jeu
-SING_OPTIONS_GAME_PLAYERS=Joueurs
-SING_OPTIONS_GAME_DIFFICULTY=Difficulté
-SING_OPTIONS_GAME_LANGUAGE=Langue
-SING_OPTIONS_GAME_TABS=Dossier
-SING_OPTIONS_GAME_SORTING=Tri
-SING_OPTIONS_GAME_DEBUG=Débogage
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Options graphiques
-SING_OPTIONS_GRAPHICS_DESC=Paramètres des graphismes
-SING_OPTIONS_GRAPHICS_RESOLUTION=Résolution
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Plein écran
-SING_OPTIONS_GRAPHICS_DEPTH=Couleurs
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscope
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de phrases
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Taille vidéo
-
-SING_OPTIONS_SOUND_WHEREAMI=Options de son
-SING_OPTIONS_SOUND_DESC=Paramètres de son
-SING_OPTIONS_SOUND_MIC_BOOST=Amplif. mic.
-SING_OPTIONS_SOUND_CLICK_ASSIST=Clics d'aide
-SING_OPTIONS_SOUND_BEAT_CLICK=Métronome
-SING_OPTIONS_SOUND_THRESHOLD=Suppression bruit
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mode 2 joueurs
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Prévis. volume
-SING_OPTIONS_SOUND_PREVIEWFADING=Prévis. baisse
-
-SING_OPTIONS_LYRICS_WHEREAMI=Options de paroles
-SING_OPTIONS_LYRICS_DESC=Paramètres de paroles
-SING_OPTIONS_LYRICS_FONT=Caractères
-SING_OPTIONS_LYRICS_EFFECT=Effet
-SING_OPTIONS_LYRICS_SOLMIZATION=Afficher gamme
-
-SING_OPTIONS_THEMES_WHEREAMI=Options des thèmes
-SING_OPTIONS_THEMES_DESC=Paramètres des thèmes
-SING_OPTIONS_THEMES_THEME=Thèmes
-SING_OPTIONS_THEMES_SKIN=Aspect
-SING_OPTIONS_THEMES_COLOR=Couleur
-
-SING_OPTIONS_RECORD_WHEREAMI=Options d'enregistrement
-SING_OPTIONS_RECORD_DESC=Paramètres des micros
-SING_OPTIONS_RECORD_CARD=Carte son
-SING_OPTIONS_RECORD_INPUT=Entrée
-SING_OPTIONS_RECORD_CHANNEL=Canal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Options avancées
-SING_OPTIONS_ADVANCED_DESC=Paramètres avancés
-SING_OPTIONS_ADVANCED_EFFECTSING=Effet de chant
-SING_OPTIONS_ADVANCED_SCREENFADE=Fondu écran
-SING_OPTIONS_ADVANCED_LOADANIMATION=Charge animation
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Confirm sup.
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de phrases
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Compteur de titres chantés
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Choix ap. chanson
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Menu multi auto
-
-SING_EDIT=Éditeur
-SING_EDIT_MENU_DESCRIPTION=Créer vos propre chansons
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importer texte à une dossier de midi file
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Retour
-SING_EDIT_BUTTON_CONVERT=Importer
-SING_EDIT_BUTTON_EXIT=Retour
-
-SING_EDIT_NAVIGATE=Naviguer
-SING_EDIT_SELECT=Valider
-SING_EDIT_EXIT=Retour
-
-SING_LEGEND_SELECT=Valider
-SING_LEGEND_NAVIGATE=Naviguer
-SING_LEGEND_CONTINUE=Valider
-SING_LEGEND_ESC=Retour
-
-SING_PLAYER_DESC=Entrer le nom du joueur
-SING_PLAYER_WHEREAMI=Nom du joueur
-SING_PLAYER_ENTER_NAME=Modifier
-
-SING_DIFFICULTY_DESC=Choisir le niveau de difficulté
-SING_DIFFICULTY_WHEREAMI=Difficulté
-SING_DIFFICULTY_CONTINUE=Valider
-SING_EASY=Facile
-SING_MEDIUM=Moyen
-SING_HARD=Difficile
-
-SING_SONG_SELECTION_DESC=Choisir une chanson
-SING_SONG_SELECTION_WHEREAMI=Sélection du titre
-SING_SONG_SELECTION_GOTO=Atteindre
-SING_SONG_SELECTION=Choix de chanson
-SING_SONG_SELECTION_MENU=Menu
-SING_SONG_SELECTION_PLAYLIST=Playlist
-SING_SONGS_IN_CAT=Chansons
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TEMPS
-SING_TOTAL=Total
-SING_MODE=Mode
-SING_NOTES=Notes
-SING_GOLDEN_NOTES=Notes en or
-SING_PHRASE_BONUS=Bonus de phrases
-
-SING_MENU=Menu principal
-
-SONG_SCORE=Score
-SONG_SCORE_WHEREAMI=Points
-
-SING_SCORE_TONE_DEAF=Casserole
-SING_SCORE_AMATEUR=Amateur
-SING_SCORE_RISING_STAR=Star en herbe
-SING_SCORE_LEAD_SINGER=Artiste
-SING_SCORE_HIT_ARTIST=Révélation
-SING_SCORE_SUPERSTAR=Superstar
-SING_SCORE_ULTRASTAR=Ultrastar
-
-SING_TOP_5_CHARTS=Top 5
-SING_TOP_5_CHARTS_WHEREAMI=Meilleurs joueurs
-SING_TOP_5_CHARTS_CONTINUE=Continuer
-
-POPUP_PERFECT=Parfait !
-POPUP_AWESOME=Cool !
-POPUP_GREAT=Grandiose !
-POPUP_GOOD=Bien !
-POPUP_NOTBAD=O.K. !
-POPUP_BAD=Pas terrible !
-POPUP_POOR=Mauvais !
-POPUP_AWFUL=Nul !
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= et
-
-SONG_MENU_NAME_MAIN=Menu
-SONG_MENU_PLAY=Chanter
-SONG_MENU_CHANGEPLAYERS=Changer de joueur
-SONG_MENU_EDIT=Éditeur
-SONG_MENU_MODI=Chanter un mode
-SONG_MENU_CANCEL=Annuler
-
-SONG_MENU_NAME_PLAYLIST=Menu
-SONG_MENU_PLAYLIST_ADD=Ajouter une chanson
-SONG_MENU_PLAYLIST_DEL=Supprimer la chanson
-
-SONG_MENU_NAME_PLAYLIST_ADD=Ajouter chanson
-SONG_MENU_PLAYLIST_ADD_NEW=À la nouvelle playlist
-SONG_MENU_PLAYLIST_ADD_EXISTING=Ajouter à la playlist
-SONG_MENU_PLAYLIST_NOEXISTING=Pas de playlist
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nouvelle playlist
-SONG_MENU_PLAYLIST_NEW_CREATE=Créer
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Sans-nom
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Supprimer ?
-SONG_MENU_YES=Oui
-SONG_MENU_NO=Non
-
-SONG_MENU_NAME_PLAYLIST_DEL=Supprimer la playlist ?
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Ouvrir une playlist
-SONG_MENU_PLAYLIST_LOAD=Ouvrir
-SONG_MENU_PLAYLIST_DELCURRENT=Supprimer la playlist actuel
-
-SONG_MENU_NAME_PARTY_MAIN=Menu
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=Joker
-
-SONG_JUMPTO_DESC=Rechercher
-SONG_JUMPTO_TYPE_DESC=Recherche :
-SONG_JUMPTO_TYPE1=Tout
-SONG_JUMPTO_TYPE2=Titre
-SONG_JUMPTO_TYPE3=Artiste
-SONG_JUMPTO_SONGSFOUND=%d Chanson(s) trouvée(s)
-SONG_JUMPTO_NOSONGSFOUND=Aucune chanson trouvée
-SONG_JUMPTO_HELP=Entrer le texte à rechercher
-SONG_JUMPTO_CATTEXT=Recherche: %s
-
-PARTY_MODE=Mode multi
-PARTY_DIFFICULTY=Difficulté
-PARTY_PLAYLIST=Playlist
-PARTY_PLAYLIST_ALL=Toutes les chansons
-PARTY_PLAYLIST_CATEGORY=Dossier
-PARTY_PLAYLIST_PLAYLIST=Playlist
-PARTY_ROUNDS=Nbre manches
-PARTY_TEAMS=Nbre équipes
-PARTY_TEAMS_PLAYER1=Joueur(s) équipe 1
-PARTY_TEAMS_PLAYER2=Joueur(s) équipe 2
-PARTY_TEAMS_PLAYER3=Joueur(s) équipe 3
-
-PARTY_LEGEND_CONTINUE=Suivant
-
-PARTY_OPTIONS_DESC=Paramètres du mode multi
-PARTY_OPTIONS_WHEREAMI=Options du mode multi
-
-PARTY_PLAYER_DESC=Entrer le nom des équipes et des joueurs
-PARTY_PLAYER_WHEREAMI=Mode multi: Equipes
-PARTY_PLAYER_ENTER_NAME=Modifier
-PARTY_PLAYER_LEGEND_CONTINUE=Valider
-
-PARTY_ROUND_DESC=Joueurs suivants à vos micros !
-PARTY_ROUND_WHEREAMI=Mode multi: Manche suivante
-PARTY_ROUND_LEGEND_CONTINUE=Commencer
-
-PARTY_SONG_WHEREAMI=Mode multi: Choix de la chanson
-PARTY_SONG_LEGEND_CONTINUE=Chanter
-PARTY_SONG_MENU=Menu
-
-PARTY_SCORE_DESC=Score de la manche
-PARTY_SCORE_WHEREAMI=Mode multi: Score
-
-PARTY_WIN_DESC=Gagnant de la partie
-PARTY_WIN_WHEREAMI=Mode multi: Gagnant
-PARTY_WIN_LEGEND_CONTINUE=Retour au menu principal
-
-PARTY_ROUND=Manche
-PARTY_ROUND_WINNER=Gagnant
-PARTY_NOTPLAYEDYET=-
-PARTY_NOBODY=Personne ne
-NEXT_ROUND=Manche suivante:
-
-PARTY_DISMISSED=Rétrogradé
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=l'emporte !
-
-PLUGIN_HDL_NAME=Tiens la barre
-PLUGIN_HDL_DESC=Maintiens la jauge dans le secteur indiqué
-
-PLUGIN_UNTIL5000_NAME=A 5000
-PLUGIN_UNTIL5000_DESC=Le 1er qui atteint 5000 points remporte la manche
-
-PLUGIN_DUELL_NAME=Duel
-PLUGIN_DUELL_DESC=Le meilleur score remporte la manche
-
-PLUGIN_BLIND_NAME=A l'aveugle
-PLUGIN_BLIND_DESC=Obtiens le meilleur score sans regarder l'écran.
-
-STAT_MAIN=Statistiques
-STAT_MAIN_DESC=Général
-STAT_MAIN_WHEREAMI=Statistiques
-
-STAT_OVERVIEW_INTRO=Statistiques d'%0:s \n Dernière réinitialisation le %1:.2d.%2:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d chansons (%3:d avec vidéo)\n%1:d ont déjà été chantées une fois, %2:d pas encore. \n\n La chanson la plus chantée est %5:s de %4:s.
-STAT_OVERVIEW_PLAYER=%0:d joueurs différents ont chantés depuis la dernière réinitialisation . \n\n Le meilleur joueur est %1:s avec %2:d points. \n Meilleur score, %4:d, atteint par %3:s.
-
-STAT_DETAIL=Statistiques
-STAT_DETAIL_WHEREAMI=Statistiques détaillées
-
-STAT_NEXT=Page suiv.
-STAT_PREV=Page préc.
-STAT_REVERSE=Inverser
-STAT_PAGE=Page %0:d de %1:d \n (%2:d entrées sur %3:d)
-
-STAT_DESC_SCORES=Score
-STAT_DESC_SCORES_REVERSED=Pires scores
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Chanteurs
-STAT_DESC_SINGERS_REVERSED=Pires chanteurs
-STAT_FORMAT_SINGERS=%0:s \n Score moyen: %1:d
-
-STAT_DESC_SONGS=Chansons
-STAT_DESC_SONGS_REVERSED=Chansons impopulaires
-STAT_FORMAT_SONGS=%0:s - %1:s \n Chanté %2:dx
-
-STAT_DESC_BANDS=Artistes
-STAT_DESC_BANDS_REVERSED=Artistes impopulaires
-STAT_FORMAT_BANDS=%0:s \n Chansons chantées: %1:d
-
-MSG_ERROR_TITLE=Erreur
-MSG_QUESTION_TITLE=Confirmation
-MSG_QUIT_USDX=Quitter le jeu ?
-MSG_END_PARTY=Quitter la partie ?
-ERROR_NO_SONGS=Aucune chanson.
-ERROR_NO_PLUGINS=Aucun plugin.
+[Text]
+SING_LOADING=Chargement...
+
+SING_CHOOSE_MODE=Choisir un mode
+SING_SING=Solo
+SING_SING_DESC=Chanter
+
+SING_MULTI=Multi
+SING_MULTI_DESC=Chanter à plusieurs
+
+SING_TOOLS=Outils
+
+SING_STATS=Statistiques
+SING_STATS_DESC=Consulter les statistiques
+
+SING_EDITOR=Éditeur
+SING_EDITOR_DESC=Créer vos propre chansons
+
+SING_GAME_OPTIONS=Options
+SING_GAME_OPTIONS_DESC=Modifier les paramètres du jeu
+
+SING_EXIT=Quitter
+SING_EXIT_DESC=Quitter le jeu
+
+SING_OPTIONS=Options
+SING_OPTIONS_DESC=Changer les paramètres
+SING_OPTIONS_WHEREAMI=Options
+
+SING_OPTIONS_GAME=Jeu
+SING_OPTIONS_GRAPHICS=Graphismes
+SING_OPTIONS_SOUND=Audio
+SING_OPTIONS_LYRICS=Paroles
+SING_OPTIONS_THEMES=Thèmes
+SING_OPTIONS_RECORD=Micros
+SING_OPTIONS_ADVANCED=Avancé
+SING_OPTIONS_EXIT=Retour
+
+SING_OPTIONS_GAME_WHEREAMI=Options de jeu
+SING_OPTIONS_GAME_DESC=Options générales de jeu
+SING_OPTIONS_GAME_PLAYERS=Joueurs
+SING_OPTIONS_GAME_DIFFICULTY=Difficulté
+SING_OPTIONS_GAME_LANGUAGE=Langue
+SING_OPTIONS_GAME_TABS=Dossier
+SING_OPTIONS_GAME_SORTING=Tri
+SING_OPTIONS_GAME_DEBUG=Débogage
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Options graphiques
+SING_OPTIONS_GRAPHICS_DESC=Paramètres des graphismes
+SING_OPTIONS_GRAPHICS_RESOLUTION=Résolution
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Plein écran
+SING_OPTIONS_GRAPHICS_DEPTH=Couleurs
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloscope
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus de phrases
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Taille vidéo
+
+SING_OPTIONS_SOUND_WHEREAMI=Options de son
+SING_OPTIONS_SOUND_DESC=Paramètres de son
+SING_OPTIONS_SOUND_MIC_BOOST=Amplif. mic.
+SING_OPTIONS_SOUND_CLICK_ASSIST=Clics d'aide
+SING_OPTIONS_SOUND_BEAT_CLICK=Métronome
+SING_OPTIONS_SOUND_THRESHOLD=Suppression bruit
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mode 2 joueurs
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Prévis. volume
+SING_OPTIONS_SOUND_PREVIEWFADING=Prévis. baisse
+
+SING_OPTIONS_LYRICS_WHEREAMI=Options de paroles
+SING_OPTIONS_LYRICS_DESC=Paramètres de paroles
+SING_OPTIONS_LYRICS_FONT=Caractères
+SING_OPTIONS_LYRICS_EFFECT=Effet
+SING_OPTIONS_LYRICS_SOLMIZATION=Afficher gamme
+
+SING_OPTIONS_THEMES_WHEREAMI=Options des thèmes
+SING_OPTIONS_THEMES_DESC=Paramètres des thèmes
+SING_OPTIONS_THEMES_THEME=Thèmes
+SING_OPTIONS_THEMES_SKIN=Aspect
+SING_OPTIONS_THEMES_COLOR=Couleur
+
+SING_OPTIONS_RECORD_WHEREAMI=Options d'enregistrement
+SING_OPTIONS_RECORD_DESC=Paramètres des micros
+SING_OPTIONS_RECORD_CARD=Carte son
+SING_OPTIONS_RECORD_INPUT=Entrée
+SING_OPTIONS_RECORD_CHANNEL=Canal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Options avancées
+SING_OPTIONS_ADVANCED_DESC=Paramètres avancés
+SING_OPTIONS_ADVANCED_EFFECTSING=Effet de chant
+SING_OPTIONS_ADVANCED_SCREENFADE=Fondu écran
+SING_OPTIONS_ADVANCED_LOADANIMATION=Charge animation
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Confirm sup.
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus de phrases
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Compteur de titres chantés
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Choix ap. chanson
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Menu multi auto
+
+SING_EDIT=Éditeur
+SING_EDIT_MENU_DESCRIPTION=Créer vos propre chansons
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Importer texte à une dossier de midi file
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Retour
+SING_EDIT_BUTTON_CONVERT=Importer
+SING_EDIT_BUTTON_EXIT=Retour
+
+SING_EDIT_NAVIGATE=Naviguer
+SING_EDIT_SELECT=Valider
+SING_EDIT_EXIT=Retour
+
+SING_LEGEND_SELECT=Valider
+SING_LEGEND_NAVIGATE=Naviguer
+SING_LEGEND_CONTINUE=Valider
+SING_LEGEND_ESC=Retour
+
+SING_PLAYER_DESC=Entrer le nom du joueur
+SING_PLAYER_WHEREAMI=Nom du joueur
+SING_PLAYER_ENTER_NAME=Modifier
+
+SING_DIFFICULTY_DESC=Choisir le niveau de difficulté
+SING_DIFFICULTY_WHEREAMI=Difficulté
+SING_DIFFICULTY_CONTINUE=Valider
+SING_EASY=Facile
+SING_MEDIUM=Moyen
+SING_HARD=Difficile
+
+SING_SONG_SELECTION_DESC=Choisir une chanson
+SING_SONG_SELECTION_WHEREAMI=Sélection du titre
+SING_SONG_SELECTION_GOTO=Atteindre
+SING_SONG_SELECTION=Choix de chanson
+SING_SONG_SELECTION_MENU=Menu
+SING_SONG_SELECTION_PLAYLIST=Playlist
+SING_SONGS_IN_CAT=Chansons
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TEMPS
+SING_TOTAL=Total
+SING_MODE=Mode
+SING_NOTES=Notes
+SING_GOLDEN_NOTES=Notes en or
+SING_PHRASE_BONUS=Bonus de phrases
+
+SING_MENU=Menu principal
+
+SONG_SCORE=Score
+SONG_SCORE_WHEREAMI=Points
+
+SING_SCORE_TONE_DEAF=Casserole
+SING_SCORE_AMATEUR=Amateur
+SING_SCORE_RISING_STAR=Star en herbe
+SING_SCORE_LEAD_SINGER=Artiste
+SING_SCORE_HIT_ARTIST=Révélation
+SING_SCORE_SUPERSTAR=Superstar
+SING_SCORE_ULTRASTAR=Ultrastar
+
+SING_TOP_5_CHARTS=Top 5
+SING_TOP_5_CHARTS_WHEREAMI=Meilleurs joueurs
+SING_TOP_5_CHARTS_CONTINUE=Continuer
+
+POPUP_PERFECT=Parfait !
+POPUP_AWESOME=Cool !
+POPUP_GREAT=Grandiose !
+POPUP_GOOD=Bien !
+POPUP_NOTBAD=O.K. !
+POPUP_BAD=Pas terrible !
+POPUP_POOR=Mauvais !
+POPUP_AWFUL=Nul !
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= et
+
+SONG_MENU_NAME_MAIN=Menu
+SONG_MENU_PLAY=Chanter
+SONG_MENU_CHANGEPLAYERS=Changer de joueur
+SONG_MENU_EDIT=Éditeur
+SONG_MENU_MODI=Chanter un mode
+SONG_MENU_CANCEL=Annuler
+
+SONG_MENU_NAME_PLAYLIST=Menu
+SONG_MENU_PLAYLIST_ADD=Ajouter une chanson
+SONG_MENU_PLAYLIST_DEL=Supprimer la chanson
+
+SONG_MENU_NAME_PLAYLIST_ADD=Ajouter chanson
+SONG_MENU_PLAYLIST_ADD_NEW=À la nouvelle playlist
+SONG_MENU_PLAYLIST_ADD_EXISTING=Ajouter à la playlist
+SONG_MENU_PLAYLIST_NOEXISTING=Pas de playlist
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nouvelle playlist
+SONG_MENU_PLAYLIST_NEW_CREATE=Créer
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Sans-nom
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Supprimer ?
+SONG_MENU_YES=Oui
+SONG_MENU_NO=Non
+
+SONG_MENU_NAME_PLAYLIST_DEL=Supprimer la playlist ?
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Ouvrir une playlist
+SONG_MENU_PLAYLIST_LOAD=Ouvrir
+SONG_MENU_PLAYLIST_DELCURRENT=Supprimer la playlist actuel
+
+SONG_MENU_NAME_PARTY_MAIN=Menu
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=Joker
+
+SONG_JUMPTO_DESC=Rechercher
+SONG_JUMPTO_TYPE_DESC=Recherche :
+SONG_JUMPTO_TYPE1=Tout
+SONG_JUMPTO_TYPE2=Titre
+SONG_JUMPTO_TYPE3=Artiste
+SONG_JUMPTO_SONGSFOUND=%d Chanson(s) trouvée(s)
+SONG_JUMPTO_NOSONGSFOUND=Aucune chanson trouvée
+SONG_JUMPTO_HELP=Entrer le texte à rechercher
+SONG_JUMPTO_CATTEXT=Recherche: %s
+
+PARTY_MODE=Mode multi
+PARTY_DIFFICULTY=Difficulté
+PARTY_PLAYLIST=Playlist
+PARTY_PLAYLIST_ALL=Toutes les chansons
+PARTY_PLAYLIST_CATEGORY=Dossier
+PARTY_PLAYLIST_PLAYLIST=Playlist
+PARTY_ROUNDS=Nbre manches
+PARTY_TEAMS=Nbre équipes
+PARTY_TEAMS_PLAYER1=Joueur(s) équipe 1
+PARTY_TEAMS_PLAYER2=Joueur(s) équipe 2
+PARTY_TEAMS_PLAYER3=Joueur(s) équipe 3
+
+PARTY_LEGEND_CONTINUE=Suivant
+
+PARTY_OPTIONS_DESC=Paramètres du mode multi
+PARTY_OPTIONS_WHEREAMI=Options du mode multi
+
+PARTY_PLAYER_DESC=Entrer le nom des équipes et des joueurs
+PARTY_PLAYER_WHEREAMI=Mode multi: Equipes
+PARTY_PLAYER_ENTER_NAME=Modifier
+PARTY_PLAYER_LEGEND_CONTINUE=Valider
+
+PARTY_ROUND_DESC=Joueurs suivants à vos micros !
+PARTY_ROUND_WHEREAMI=Mode multi: Manche suivante
+PARTY_ROUND_LEGEND_CONTINUE=Commencer
+
+PARTY_SONG_WHEREAMI=Mode multi: Choix de la chanson
+PARTY_SONG_LEGEND_CONTINUE=Chanter
+PARTY_SONG_MENU=Menu
+
+PARTY_SCORE_DESC=Score de la manche
+PARTY_SCORE_WHEREAMI=Mode multi: Score
+
+PARTY_WIN_DESC=Gagnant de la partie
+PARTY_WIN_WHEREAMI=Mode multi: Gagnant
+PARTY_WIN_LEGEND_CONTINUE=Retour au menu principal
+
+PARTY_ROUND=Manche
+PARTY_ROUND_WINNER=Gagnant
+PARTY_NOTPLAYEDYET=-
+PARTY_NOBODY=Personne ne
+NEXT_ROUND=Manche suivante:
+
+PARTY_DISMISSED=Rétrogradé
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=l'emporte !
+
+PLUGIN_HDL_NAME=Tiens la barre
+PLUGIN_HDL_DESC=Maintiens la jauge dans le secteur indiqué
+
+PLUGIN_UNTIL5000_NAME=A 5000
+PLUGIN_UNTIL5000_DESC=Le 1er qui atteint 5000 points remporte la manche
+
+PLUGIN_DUELL_NAME=Duel
+PLUGIN_DUELL_DESC=Le meilleur score remporte la manche
+
+PLUGIN_BLIND_NAME=A l'aveugle
+PLUGIN_BLIND_DESC=Obtiens le meilleur score sans regarder l'écran.
+
+STAT_MAIN=Statistiques
+STAT_MAIN_DESC=Général
+STAT_MAIN_WHEREAMI=Statistiques
+
+STAT_OVERVIEW_INTRO=Statistiques d'%0:s \n Dernière réinitialisation le %1:.2d.%2:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d chansons (%3:d avec vidéo)\n%1:d ont déjà été chantées une fois, %2:d pas encore. \n\n La chanson la plus chantée est %5:s de %4:s.
+STAT_OVERVIEW_PLAYER=%0:d joueurs différents ont chantés depuis la dernière réinitialisation . \n\n Le meilleur joueur est %1:s avec %2:d points. \n Meilleur score, %4:d, atteint par %3:s.
+
+STAT_DETAIL=Statistiques
+STAT_DETAIL_WHEREAMI=Statistiques détaillées
+
+STAT_NEXT=Page suiv.
+STAT_PREV=Page préc.
+STAT_REVERSE=Inverser
+STAT_PAGE=Page %0:d de %1:d \n (%2:d entrées sur %3:d)
+
+STAT_DESC_SCORES=Score
+STAT_DESC_SCORES_REVERSED=Pires scores
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Chanteurs
+STAT_DESC_SINGERS_REVERSED=Pires chanteurs
+STAT_FORMAT_SINGERS=%0:s \n Score moyen: %1:d
+
+STAT_DESC_SONGS=Chansons
+STAT_DESC_SONGS_REVERSED=Chansons impopulaires
+STAT_FORMAT_SONGS=%0:s - %1:s \n Chanté %2:dx
+
+STAT_DESC_BANDS=Artistes
+STAT_DESC_BANDS_REVERSED=Artistes impopulaires
+STAT_FORMAT_BANDS=%0:s \n Chansons chantées: %1:d
+
+MSG_ERROR_TITLE=Erreur
+MSG_QUESTION_TITLE=Confirmation
+MSG_QUIT_USDX=Quitter le jeu ?
+MSG_END_PARTY=Quitter la partie ?
+ERROR_NO_SONGS=Aucune chanson.
+ERROR_NO_PLUGINS=Aucun plugin.
ERROR_CORRUPT_SONG=Impossible de charger la chanson. \ No newline at end of file
diff --git a/game/languages/old/Norwegian.ini b/game/languages/old/Norwegian.ini
index c585691f..ddd97322 100644
--- a/game/languages/old/Norwegian.ini
+++ b/game/languages/old/Norwegian.ini
@@ -1,297 +1,297 @@
-[Text]
-SING_LOADING=Laster...
-
-SING_CHOOSE_MODE=velg modus
-SING_SING=syng
-SING_SING_DESC=hurtigspill: syng solo eller duett
-
-SING_MULTI=party
-SING_MULTI_DESC=syng i party-modus
-
-SING_TOOLS=verktøy
-
-SING_STATS=statistikk
-SING_STATS_DESC=vis statistikk
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=lag dine egne sanger
-
-SING_GAME_OPTIONS=spillinnstillinger
-SING_GAME_OPTIONS_DESC=endre spillinstillinger
-SING_EXIT=avslutt
-SING_EXIT_DESC=avslutt spillet
-
-SING_OPTIONS=innstillinger
-SING_OPTIONS_DESC=endre innstillinger
-SING_OPTIONS_WHEREAMI=Innstillinger
-
-SING_OPTIONS_GAME=spill
-SING_OPTIONS_GRAPHICS=grafikk
-SING_OPTIONS_SOUND=lyd
-SING_OPTIONS_LYRICS=tekst
-SING_OPTIONS_THEMES=utseende
-SING_OPTIONS_RECORD=opptak
-SING_OPTIONS_ADVANCED=avansert
-SING_OPTIONS_EXIT=tilbake
-
-SING_OPTIONS_GAME_WHEREAMI=Innstillinger Spill
-SING_OPTIONS_GAME_DESC=hovedspillinnstillinger
-SING_OPTIONS_GAME_PLAYERS=Spillere
-SING_OPTIONS_GAME_DIFFICULTY=Vanskelighet
-SING_OPTIONS_GAME_LANGUAGE=Språk
-SING_OPTIONS_GAME_TABS=Mappeinndeling
-SING_OPTIONS_GAME_SORTING=Sortering
-SING_OPTIONS_GAME_DEBUG=Feilsøking
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Innstillinger Grafikk
-SING_OPTIONS_GRAPHICS_DESC=Grafiske innstillinger
-SING_OPTIONS_GRAPHICS_RESOLUTION=Oppløsning
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullskjerm
-SING_OPTIONS_GRAPHICS_DEPTH=Fargedybde
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloskop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Linjebonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Filmstørrelse
-
-SING_OPTIONS_SOUND_WHEREAMI=Innstillinger Lyd
-SING_OPTIONS_SOUND_DESC=lydinnstillinger
-SING_OPTIONS_SOUND_MIC_BOOST=Mikrofon-gain
-SING_OPTIONS_SOUND_CLICK_ASSIST=Klikke-assistanse
-SING_OPTIONS_SOUND_BEAT_CLICK=Beat-klikk
-SING_OPTIONS_SOUND_THRESHOLD=Toleransegrense
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Tospiller-modus
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Preview-volum
-SING_OPTIONS_SOUND_PREVIEWFADING=Preview-fading
-
-SING_OPTIONS_LYRICS_WHEREAMI=Innstillinger Tekst
-SING_OPTIONS_LYRICS_DESC=tekstinnstillinger
-SING_OPTIONS_LYRICS_FONT=Fonter
-SING_OPTIONS_LYRICS_EFFECT=Effekter
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmisasjon
-
-SING_OPTIONS_THEMES_WHEREAMI=Innstillinger Utseende
-SING_OPTIONS_THEMES_DESC=tema og skin-innstillinger
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Farge
-
-SING_OPTIONS_RECORD_WHEREAMI=Innstillinger Opptak
-SING_OPTIONS_RECORD_DESC=mikrofoninnstillinger
-SING_OPTIONS_RECORD_CARD=Lydkort
-SING_OPTIONS_RECORD_INPUT=Input
-SING_OPTIONS_RECORD_CHANNEL=Kanal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Innstillinger Avansert
-SING_OPTIONS_ADVANCED_DESC=avanserte innstillinger
-SING_OPTIONS_ADVANCED_EFFECTSING=Sangeffekter
-SING_OPTIONS_ADVANCED_SCREENFADE=Skjermfading
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animasjonslasting
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Sikkerhetsspørsmål
-SING_OPTIONS_ADVANCED_LINEBONUS=Linjebonus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Etter sang:
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto partymeny
-
-SING_LEGEND_SELECT=velg
-SING_LEGEND_NAVIGATE=naviger
-SING_LEGEND_CONTINUE=fortsett
-SING_LEGEND_ESC=tilbake
-
-SING_PLAYER_DESC=velg spillernavn
-SING_PLAYER_WHEREAMI=Spillernavn
-SING_PLAYER_ENTER_NAME=velg navn
-
-SING_DIFFICULTY_DESC=velg vanskelighetsgrad
-SING_DIFFICULTY_WHEREAMI=Vanskelighet
-SING_DIFFICULTY_CONTINUE=til sangvalg
-SING_EASY=Lett
-SING_MEDIUM=Moderat
-SING_HARD=Vanskelig
-
-SING_SONG_SELECTION_DESC=velg sang
-SING_SONG_SELECTION_WHEREAMI=Sangvalg
-SING_SONG_SELECTION_GOTO=gå til ..
-SING_SONG_SELECTION=Sangvalg
-SING_SONG_SELECTION_MENU=meny
-SING_SONG_SELECTION_PLAYLIST=spilleliste
-SING_SONGS_IN_CAT=Sanger
-PLAYLIST_CATTEXT=Spilleliste: %s
-
-SING_TIME=TID
-SING_TOTAL=total
-SING_MODE=syng solo
-SING_NOTES=toner
-SING_GOLDEN_NOTES=gyldne noter
-SING_PHRASE_BONUS=linjebonus
-
-SING_MENU=Hovedmeny
-
-SONG_SCORE=sangscore
-SONG_SCORE_WHEREAMI=Score
-
-SING_SCORE_TONE_DEAF=Tonedøv
-SING_SCORE_AMATEUR=Amatør
-SING_SCORE_RISING_STAR=Stigende stjerne
-SING_SCORE_LEAD_SINGER=Toppvokalist
-SING_SCORE_HIT_ARTIST=Hitartist
-SING_SCORE_SUPERSTAR=Superstjerne
-SING_SCORE_ULTRASTAR=Ultrastjerne
-
-SING_TOP_5_CHARTS=topp 5 spillere
-SING_TOP_5_CHARTS_WHEREAMI=topp 5
-SING_TOP_5_CHARTS_CONTINUE=til sangvalg
-
-POPUP_PERFECT=perfekt!
-POPUP_AWESOME=fantastisk!
-POPUP_GREAT=kjempebra!
-POPUP_GOOD=bra!
-POPUP_NOTBAD=brukbart!
-POPUP_BAD=dårlig!
-POPUP_POOR=elendig!
-POPUP_AWFUL=grusomt!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= og
-
-SONG_MENU_NAME_MAIN=sangmeny
-SONG_MENU_PLAY=Syng
-SONG_MENU_CHANGEPLAYERS=Endre spillere
-SONG_MENU_EDIT=Endre
-SONG_MENU_MODI=Syng en modus
-SONG_MENU_CANCEL=AVbryt
-
-SONG_MENU_NAME_PLAYLIST=Sangmeny
-SONG_MENU_PLAYLIST_ADD=Legg til sang
-SONG_MENU_PLAYLIST_DEL=Ta bort sang
-
-SONG_MENU_NAME_PLAYLIST_ADD=Legg til sang
-SONG_MENU_PLAYLIST_ADD_NEW=til ny spilleliste
-SONG_MENU_PLAYLIST_ADD_EXISTING=til eksisterende spilleliste
-SONG_MENU_PLAYLIST_NOEXISTING=ingen spilleliste eksisterer
-
-SONG_MENU_NAME_PLAYLIST_NEW=Ny spilleliste
-SONG_MENU_PLAYLIST_NEW_CREATE=Opprett
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Uten navn
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Virkelig slette?
-SONG_MENU_YES=Ja
-SONG_MENU_NO=Nei
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Åpne spilleliste
-SONG_MENU_PLAYLIST_LOAD=åpne
-SONG_MENU_PLAYLIST_DELCURRENT=slett nåværende spilleliste
-
-SONG_MENU_NAME_PLAYLIST_DEL=Slett spilleliste?
-
-SONG_MENU_NAME_PARTY_MAIN=Partymeny
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=bruk joker
-
-SONG_JUMPTO_DESC=søk etter sang
-SONG_JUMPTO_TYPE_DESC=Søk etter:
-SONG_JUMPTO_TYPE1=Alt
-SONG_JUMPTO_TYPE2=Tittel
-SONG_JUMPTO_TYPE3=Artist
-SONG_JUMPTO_SONGSFOUND=%d Sang(er) funnet
-SONG_JUMPTO_NOSONGSFOUND=Ingen funnet
-SONG_JUMPTO_HELP=Skriv inn tekst å lete etter
-SONG_JUMPTO_CATTEXT=Søk etter: %s
-
-PARTY_MODE=Partymodus
-PARTY_DIFFICULTY=Vanskelighetsgrad
-PARTY_PLAYLIST=Spilleliste-modus
-PARTY_PLAYLIST_ALL=Alle sanger
-PARTY_PLAYLIST_CATEGORY=Mappe
-PARTY_PLAYLIST_PLAYLIST=Spillelist
-PARTY_ROUNDS=Runder
-PARTY_TEAMS=Lag
-PARTY_TEAMS_PLAYER1=Spiller Lag1
-PARTY_TEAMS_PLAYER2=Spiller Lag2
-PARTY_TEAMS_PLAYER3=Spiller Lag3
-
-PARTY_LEGEND_CONTINUE=Fortsett
-
-PARTY_OPTIONS_DESC=Innstillinger for party-spillet
-PARTY_OPTIONS_WHEREAMI=Party-innstillinger
-
-PARTY_PLAYER_DESC=skriv spiller- og lagnavn!
-PARTY_PLAYER_WHEREAMI=Party-navn
-PARTY_PLAYER_ENTER_NAME=skriv navn
-PARTY_PLAYER_LEGEND_CONTINUE=start party-game
-
-PARTY_ROUND_DESC=neste spillere til mikrofonene
-PARTY_ROUND_WHEREAMI=Party neste runde
-PARTY_ROUND_LEGEND_CONTINUE=start runden
-
-PARTY_SONG_WHEREAMI=Party sangvalg
-PARTY_SONG_LEGEND_CONTINUE=syng
-PARTY_SONG_MENU=partymeny
-
-PARTY_SCORE_DESC=Siste rundes poengsum
-PARTY_SCORE_WHEREAMI=Partypoeng
-
-PARTY_WIN_DESC=vinner av partyspillet
-PARTY_WIN_WHEREAMI=Party-vinner
-PARTY_WIN_LEGEND_CONTINUE=tilbake til hovedmenyen
-
-PARTY_ROUND=Runde
-PARTY_ROUND_WINNER=Vinner
-PARTY_NOTPLAYEDYET=Ikke spilt ennå
-PARTY_NOBODY=ingen
-NEXT_ROUND=Neste runde:
-
-PARTY_DISMISSED=Avbrutt!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=Vinner!
-
-PLUGIN_HDL_NAME=Hold linja
-PLUGIN_HDL_DESC=Ikke syng dårligere enn hva markøren på statuslinja viser.
-
-PLUGIN_UNTIL5000_NAME=Først til 5000
-PLUGIN_UNTIL5000_DESC=Førstemann til 5000 poeng vinner.
-
-PLUGIN_DUELL_NAME=Duell
-PLUGIN_DUELL_DESC=Syng en duell - først til 10000.
-
-PLUGIN_BLIND_NAME=Blindemodus
-PLUGIN_BLIND_DESC=Duell der notene ikke vises
-
-STAT_MAIN=Statistikk
-STAT_MAIN_DESC=Hoved
-STAT_MAIN_WHEREAMI=Statistikk
-
-STAT_OVERVIEW_INTRO=%0:s Statistikk. \n Siste avslutning ved %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Sanger(%3:d med video), hvorav %1:d allerede har vært sunget og %2:d ennå ikke har vært sunget.\n Den mest populære sangen er %5:s av %4:s.
-STAT_OVERVIEW_PLAYER=Siden den siste avlutningen var det %0:d ulike spillere.\n Den beste spilleren er %1:s med en gjennomsnitts-score på %2:d poeng.\n %3:s fikk høyeste score med %4:d poeng.
-
-STAT_DETAIL=Statistikk
-STAT_DETAIL_WHEREAMI=Detaljert statistikk
-
-STAT_NEXT=Neste side
-STAT_PREV=Forrige side
-STAT_REVERSE=Bytt rekkefølge
-STAT_PAGE=Side %0:d av %1:d Sider\n (%2:d av %3:d )
-
-STAT_DESC_SCORES=Toppscore
-STAT_DESC_SCORES_REVERSED=Bunnscore
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Beste sangere
-STAT_DESC_SINGERS_REVERSED=Dårligste sangere
-STAT_FORMAT_SINGERS=%0:s \n Gjennomsnitts-score: %1:d
-
-STAT_DESC_SONGS=Mest populære sang
-STAT_DESC_SONGS_REVERSED=Minst populære sang
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx sunget
-
-STAT_DESC_BANDS=Mest populære artist
-STAT_DESC_BANDS_REVERSED=Minst populære artist
-STAT_FORMAT_BANDS=%0:s \n %1:dx Sunget
-
-MSG_ERROR_TITLE=Feil
-MSG_QUESTION_TITLE=Spørsmål
-MSG_QUIT_USDX=Vil du virkelig avslutte UltraStar?
-MSG_END_PARTY=Vil du virkelig forlate party-modusen?
-ERROR_NO_SONGS=Ingen sanger lastet
-ERROR_NO_PLUGINS=Ingen plug-ins lastet
+[Text]
+SING_LOADING=Laster...
+
+SING_CHOOSE_MODE=velg modus
+SING_SING=syng
+SING_SING_DESC=hurtigspill: syng solo eller duett
+
+SING_MULTI=party
+SING_MULTI_DESC=syng i party-modus
+
+SING_TOOLS=verktøy
+
+SING_STATS=statistikk
+SING_STATS_DESC=vis statistikk
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=lag dine egne sanger
+
+SING_GAME_OPTIONS=spillinnstillinger
+SING_GAME_OPTIONS_DESC=endre spillinstillinger
+SING_EXIT=avslutt
+SING_EXIT_DESC=avslutt spillet
+
+SING_OPTIONS=innstillinger
+SING_OPTIONS_DESC=endre innstillinger
+SING_OPTIONS_WHEREAMI=Innstillinger
+
+SING_OPTIONS_GAME=spill
+SING_OPTIONS_GRAPHICS=grafikk
+SING_OPTIONS_SOUND=lyd
+SING_OPTIONS_LYRICS=tekst
+SING_OPTIONS_THEMES=utseende
+SING_OPTIONS_RECORD=opptak
+SING_OPTIONS_ADVANCED=avansert
+SING_OPTIONS_EXIT=tilbake
+
+SING_OPTIONS_GAME_WHEREAMI=Innstillinger Spill
+SING_OPTIONS_GAME_DESC=hovedspillinnstillinger
+SING_OPTIONS_GAME_PLAYERS=Spillere
+SING_OPTIONS_GAME_DIFFICULTY=Vanskelighet
+SING_OPTIONS_GAME_LANGUAGE=Språk
+SING_OPTIONS_GAME_TABS=Mappeinndeling
+SING_OPTIONS_GAME_SORTING=Sortering
+SING_OPTIONS_GAME_DEBUG=Feilsøking
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Innstillinger Grafikk
+SING_OPTIONS_GRAPHICS_DESC=Grafiske innstillinger
+SING_OPTIONS_GRAPHICS_RESOLUTION=Oppløsning
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Fullskjerm
+SING_OPTIONS_GRAPHICS_DEPTH=Fargedybde
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Oscilloskop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Linjebonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Filmstørrelse
+
+SING_OPTIONS_SOUND_WHEREAMI=Innstillinger Lyd
+SING_OPTIONS_SOUND_DESC=lydinnstillinger
+SING_OPTIONS_SOUND_MIC_BOOST=Mikrofon-gain
+SING_OPTIONS_SOUND_CLICK_ASSIST=Klikke-assistanse
+SING_OPTIONS_SOUND_BEAT_CLICK=Beat-klikk
+SING_OPTIONS_SOUND_THRESHOLD=Toleransegrense
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Tospiller-modus
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Preview-volum
+SING_OPTIONS_SOUND_PREVIEWFADING=Preview-fading
+
+SING_OPTIONS_LYRICS_WHEREAMI=Innstillinger Tekst
+SING_OPTIONS_LYRICS_DESC=tekstinnstillinger
+SING_OPTIONS_LYRICS_FONT=Fonter
+SING_OPTIONS_LYRICS_EFFECT=Effekter
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmisasjon
+
+SING_OPTIONS_THEMES_WHEREAMI=Innstillinger Utseende
+SING_OPTIONS_THEMES_DESC=tema og skin-innstillinger
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Farge
+
+SING_OPTIONS_RECORD_WHEREAMI=Innstillinger Opptak
+SING_OPTIONS_RECORD_DESC=mikrofoninnstillinger
+SING_OPTIONS_RECORD_CARD=Lydkort
+SING_OPTIONS_RECORD_INPUT=Input
+SING_OPTIONS_RECORD_CHANNEL=Kanal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Innstillinger Avansert
+SING_OPTIONS_ADVANCED_DESC=avanserte innstillinger
+SING_OPTIONS_ADVANCED_EFFECTSING=Sangeffekter
+SING_OPTIONS_ADVANCED_SCREENFADE=Skjermfading
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animasjonslasting
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Sikkerhetsspørsmål
+SING_OPTIONS_ADVANCED_LINEBONUS=Linjebonus
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Etter sang:
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto partymeny
+
+SING_LEGEND_SELECT=velg
+SING_LEGEND_NAVIGATE=naviger
+SING_LEGEND_CONTINUE=fortsett
+SING_LEGEND_ESC=tilbake
+
+SING_PLAYER_DESC=velg spillernavn
+SING_PLAYER_WHEREAMI=Spillernavn
+SING_PLAYER_ENTER_NAME=velg navn
+
+SING_DIFFICULTY_DESC=velg vanskelighetsgrad
+SING_DIFFICULTY_WHEREAMI=Vanskelighet
+SING_DIFFICULTY_CONTINUE=til sangvalg
+SING_EASY=Lett
+SING_MEDIUM=Moderat
+SING_HARD=Vanskelig
+
+SING_SONG_SELECTION_DESC=velg sang
+SING_SONG_SELECTION_WHEREAMI=Sangvalg
+SING_SONG_SELECTION_GOTO=gå til ..
+SING_SONG_SELECTION=Sangvalg
+SING_SONG_SELECTION_MENU=meny
+SING_SONG_SELECTION_PLAYLIST=spilleliste
+SING_SONGS_IN_CAT=Sanger
+PLAYLIST_CATTEXT=Spilleliste: %s
+
+SING_TIME=TID
+SING_TOTAL=total
+SING_MODE=syng solo
+SING_NOTES=toner
+SING_GOLDEN_NOTES=gyldne noter
+SING_PHRASE_BONUS=linjebonus
+
+SING_MENU=Hovedmeny
+
+SONG_SCORE=sangscore
+SONG_SCORE_WHEREAMI=Score
+
+SING_SCORE_TONE_DEAF=Tonedøv
+SING_SCORE_AMATEUR=Amatør
+SING_SCORE_RISING_STAR=Stigende stjerne
+SING_SCORE_LEAD_SINGER=Toppvokalist
+SING_SCORE_HIT_ARTIST=Hitartist
+SING_SCORE_SUPERSTAR=Superstjerne
+SING_SCORE_ULTRASTAR=Ultrastjerne
+
+SING_TOP_5_CHARTS=topp 5 spillere
+SING_TOP_5_CHARTS_WHEREAMI=topp 5
+SING_TOP_5_CHARTS_CONTINUE=til sangvalg
+
+POPUP_PERFECT=perfekt!
+POPUP_AWESOME=fantastisk!
+POPUP_GREAT=kjempebra!
+POPUP_GOOD=bra!
+POPUP_NOTBAD=brukbart!
+POPUP_BAD=dårlig!
+POPUP_POOR=elendig!
+POPUP_AWFUL=grusomt!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= og
+
+SONG_MENU_NAME_MAIN=sangmeny
+SONG_MENU_PLAY=Syng
+SONG_MENU_CHANGEPLAYERS=Endre spillere
+SONG_MENU_EDIT=Endre
+SONG_MENU_MODI=Syng en modus
+SONG_MENU_CANCEL=AVbryt
+
+SONG_MENU_NAME_PLAYLIST=Sangmeny
+SONG_MENU_PLAYLIST_ADD=Legg til sang
+SONG_MENU_PLAYLIST_DEL=Ta bort sang
+
+SONG_MENU_NAME_PLAYLIST_ADD=Legg til sang
+SONG_MENU_PLAYLIST_ADD_NEW=til ny spilleliste
+SONG_MENU_PLAYLIST_ADD_EXISTING=til eksisterende spilleliste
+SONG_MENU_PLAYLIST_NOEXISTING=ingen spilleliste eksisterer
+
+SONG_MENU_NAME_PLAYLIST_NEW=Ny spilleliste
+SONG_MENU_PLAYLIST_NEW_CREATE=Opprett
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Uten navn
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Virkelig slette?
+SONG_MENU_YES=Ja
+SONG_MENU_NO=Nei
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Åpne spilleliste
+SONG_MENU_PLAYLIST_LOAD=åpne
+SONG_MENU_PLAYLIST_DELCURRENT=slett nåværende spilleliste
+
+SONG_MENU_NAME_PLAYLIST_DEL=Slett spilleliste?
+
+SONG_MENU_NAME_PARTY_MAIN=Partymeny
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=bruk joker
+
+SONG_JUMPTO_DESC=søk etter sang
+SONG_JUMPTO_TYPE_DESC=Søk etter:
+SONG_JUMPTO_TYPE1=Alt
+SONG_JUMPTO_TYPE2=Tittel
+SONG_JUMPTO_TYPE3=Artist
+SONG_JUMPTO_SONGSFOUND=%d Sang(er) funnet
+SONG_JUMPTO_NOSONGSFOUND=Ingen funnet
+SONG_JUMPTO_HELP=Skriv inn tekst å lete etter
+SONG_JUMPTO_CATTEXT=Søk etter: %s
+
+PARTY_MODE=Partymodus
+PARTY_DIFFICULTY=Vanskelighetsgrad
+PARTY_PLAYLIST=Spilleliste-modus
+PARTY_PLAYLIST_ALL=Alle sanger
+PARTY_PLAYLIST_CATEGORY=Mappe
+PARTY_PLAYLIST_PLAYLIST=Spillelist
+PARTY_ROUNDS=Runder
+PARTY_TEAMS=Lag
+PARTY_TEAMS_PLAYER1=Spiller Lag1
+PARTY_TEAMS_PLAYER2=Spiller Lag2
+PARTY_TEAMS_PLAYER3=Spiller Lag3
+
+PARTY_LEGEND_CONTINUE=Fortsett
+
+PARTY_OPTIONS_DESC=Innstillinger for party-spillet
+PARTY_OPTIONS_WHEREAMI=Party-innstillinger
+
+PARTY_PLAYER_DESC=skriv spiller- og lagnavn!
+PARTY_PLAYER_WHEREAMI=Party-navn
+PARTY_PLAYER_ENTER_NAME=skriv navn
+PARTY_PLAYER_LEGEND_CONTINUE=start party-game
+
+PARTY_ROUND_DESC=neste spillere til mikrofonene
+PARTY_ROUND_WHEREAMI=Party neste runde
+PARTY_ROUND_LEGEND_CONTINUE=start runden
+
+PARTY_SONG_WHEREAMI=Party sangvalg
+PARTY_SONG_LEGEND_CONTINUE=syng
+PARTY_SONG_MENU=partymeny
+
+PARTY_SCORE_DESC=Siste rundes poengsum
+PARTY_SCORE_WHEREAMI=Partypoeng
+
+PARTY_WIN_DESC=vinner av partyspillet
+PARTY_WIN_WHEREAMI=Party-vinner
+PARTY_WIN_LEGEND_CONTINUE=tilbake til hovedmenyen
+
+PARTY_ROUND=Runde
+PARTY_ROUND_WINNER=Vinner
+PARTY_NOTPLAYEDYET=Ikke spilt ennå
+PARTY_NOBODY=ingen
+NEXT_ROUND=Neste runde:
+
+PARTY_DISMISSED=Avbrutt!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=Vinner!
+
+PLUGIN_HDL_NAME=Hold linja
+PLUGIN_HDL_DESC=Ikke syng dårligere enn hva markøren på statuslinja viser.
+
+PLUGIN_UNTIL5000_NAME=Først til 5000
+PLUGIN_UNTIL5000_DESC=Førstemann til 5000 poeng vinner.
+
+PLUGIN_DUELL_NAME=Duell
+PLUGIN_DUELL_DESC=Syng en duell - først til 10000.
+
+PLUGIN_BLIND_NAME=Blindemodus
+PLUGIN_BLIND_DESC=Duell der notene ikke vises
+
+STAT_MAIN=Statistikk
+STAT_MAIN_DESC=Hoved
+STAT_MAIN_WHEREAMI=Statistikk
+
+STAT_OVERVIEW_INTRO=%0:s Statistikk. \n Siste avslutning ved %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Sanger(%3:d med video), hvorav %1:d allerede har vært sunget og %2:d ennå ikke har vært sunget.\n Den mest populære sangen er %5:s av %4:s.
+STAT_OVERVIEW_PLAYER=Siden den siste avlutningen var det %0:d ulike spillere.\n Den beste spilleren er %1:s med en gjennomsnitts-score på %2:d poeng.\n %3:s fikk høyeste score med %4:d poeng.
+
+STAT_DETAIL=Statistikk
+STAT_DETAIL_WHEREAMI=Detaljert statistikk
+
+STAT_NEXT=Neste side
+STAT_PREV=Forrige side
+STAT_REVERSE=Bytt rekkefølge
+STAT_PAGE=Side %0:d av %1:d Sider\n (%2:d av %3:d )
+
+STAT_DESC_SCORES=Toppscore
+STAT_DESC_SCORES_REVERSED=Bunnscore
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Beste sangere
+STAT_DESC_SINGERS_REVERSED=Dårligste sangere
+STAT_FORMAT_SINGERS=%0:s \n Gjennomsnitts-score: %1:d
+
+STAT_DESC_SONGS=Mest populære sang
+STAT_DESC_SONGS_REVERSED=Minst populære sang
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx sunget
+
+STAT_DESC_BANDS=Mest populære artist
+STAT_DESC_BANDS_REVERSED=Minst populære artist
+STAT_FORMAT_BANDS=%0:s \n %1:dx Sunget
+
+MSG_ERROR_TITLE=Feil
+MSG_QUESTION_TITLE=Spørsmål
+MSG_QUIT_USDX=Vil du virkelig avslutte UltraStar?
+MSG_END_PARTY=Vil du virkelig forlate party-modusen?
+ERROR_NO_SONGS=Ingen sanger lastet
+ERROR_NO_PLUGINS=Ingen plug-ins lastet
ERROR_CORRUPT_SONG=Sangen kunne ikke lastes \ No newline at end of file
diff --git a/game/languages/old/Polish.ini b/game/languages/old/Polish.ini
index 51faa616..74ced1d0 100644
--- a/game/languages/old/Polish.ini
+++ b/game/languages/old/Polish.ini
@@ -1,304 +1,304 @@
-[Text]
-SING_LOADING=Wczytywanie...
-
-SING_CHOOSE_MODE=wybierz tryb
-SING_SING=œpiewaj
-SING_SING_DESC=œpiewaj solo lub w kilka osób
-
-SING_MULTI=impreza
-SING_MULTI_DESC=rozkrêæ imprezê!
-
-SING_TOOLS=narzêdzia
-
-SING_STATS=statystyki
-SING_STATS_DESC=zobacz statystyki
-
-SING_EDITOR=edytor
-SING_EDITOR_DESC=stwórz w³asne piosenki
-
-SING_GAME_OPTIONS=opcje
-SING_GAME_OPTIONS_DESC=zmieñ ustawienia
-
-SING_EXIT=wyjœcie
-SING_EXIT_DESC=wyjdŸ z gry
-
-SING_OPTIONS=opcje
-SING_OPTIONS_DESC=zmieñ ustawienia
-SING_OPTIONS_WHEREAMI=Opcje
-
-SING_OPTIONS_GAME=gra
-SING_OPTIONS_GRAPHICS=grafika
-SING_OPTIONS_SOUND=dŸwiêk
-SING_OPTIONS_LYRICS=s³owa
-SING_OPTIONS_THEMES=tematy
-SING_OPTIONS_RECORD=nagrywanie
-SING_OPTIONS_ADVANCED=zaawansowane
-SING_OPTIONS_EXIT=wstecz
-
-SING_OPTIONS_GAME_WHEREAMI=Opcje Gra
-SING_OPTIONS_GAME_DESC=opcje gry
-SING_OPTIONS_GAME_PLAYERS=IloϾ graczy
-SING_OPTIONS_GAME_DIFFICULTY=Poziom trudnoœci
-SING_OPTIONS_GAME_LANGUAGE=Jêzyk
-SING_OPTIONS_GAME_TABS=Zak³adki
-SING_OPTIONS_GAME_SORTING=Sortowanie
-SING_OPTIONS_GAME_DEBUG=Debug
-
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Opcje Grafika
-SING_OPTIONS_GAME_DESC=opcje gry
-SING_OPTIONS_GAME_PLAYERS=IloϾ graczy
-SING_OPTIONS_GAME_DIFFICULTY=Poziom trudnoœci
-SING_OPTIONS_GAME_LANGUAGE=Jêzyk
-SING_OPTIONS_GAME_TABS=Zak³adki
-SING_OPTIONS_GAME_SORTING=Sortowanie
-SING_OPTIONS_GAME_DEBUG=Debug
-
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus Linii
-
-SING_OPTIONS_SOUND_WHEREAMI=Opcje DŸwiêk
-SING_OPTIONS_SOUND_DESC=opcje dŸwiêku
-SING_OPTIONS_SOUND_MIC_BOOST=Podbicie mikrofonu
-SING_OPTIONS_SOUND_CLICK_ASSIST=Pomoc klikniêciami
-SING_OPTIONS_SOUND_BEAT_CLICK=Klikniêcia w rytm
-SING_OPTIONS_SOUND_THRESHOLD=Próg
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Tryb dwóch graczy
-SING_OPTIONS_SOUND_PREVIEWVOLUME=G³oœnoœæ w podgl¹dzie
-SING_OPTIONS_SOUND_PREVIEWFADING=Zanikanie w podgl¹dzie
-
-SING_OPTIONS_LYRICS_WHEREAMI=Opcje S³owa
-SING_OPTIONS_LYRICS_DESC=opcje s³ów
-SING_OPTIONS_LYRICS_FONT=Czcionka
-SING_OPTIONS_LYRICS_EFFECT=Efekt
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacja
-
-SING_OPTIONS_THEMES_WHEREAMI=Options Tematy
-SING_OPTIONS_THEMES_DESC=opcje tematów
-SING_OPTIONS_THEMES_THEME=Temat
-SING_OPTIONS_THEMES_SKIN=Skóra
-SING_OPTIONS_THEMES_COLOR=Kolor
-
-SING_OPTIONS_RECORD_WHEREAMI=Opcje Nagrywanie
-SING_OPTIONS_RECORD_DESC=opcje nagrywania
-SING_OPTIONS_RECORD_CARD=Karta dŸwiêkowa
-SING_OPTIONS_RECORD_INPUT=Wejœcie
-SING_OPTIONS_RECORD_CHANNEL=Kana³
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Opcje Zaawansowane
-SING_OPTIONS_ADVANCED_DESC=ustawienia zaawansowane
-SING_OPTIONS_ADVANCED_EFFECTSING=Efekty specjalne
-SING_OPTIONS_ADVANCED_SCREENFADE=Przenikanie
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animacja ³adowania
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Pytania przy wyjœciu
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus Linii
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Licznik
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Po wyborze piosenki
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto Menu Imprezy
-
-SING_LEGEND_SELECT=wybierz
-SING_LEGEND_NAVIGATE=nawigacja
-SING_LEGEND_CONTINUE=dalej
-SING_LEGEND_ESC=wstecz
-
-SING_PLAYER_DESC=wprowadŸ imiê gracza
-SING_PLAYER_WHEREAMI=Imiê
-SING_PLAYER_ENTER_NAME=wpisz imiê
-
-SING_DIFFICULTY_DESC=wybierz poziom trudnoœci
-SING_DIFFICULTY_WHEREAMI=Poziom
-SING_DIFFICULTY_CONTINUE=do wyboru piosenki
-SING_EASY=³atwo
-SING_MEDIUM=œrednio
-SING_HARD=trudno
-
-SING_SONG_SELECTION_DESC=wybierz piosenkê
-SING_SONG_SELECTION_WHEREAMI=Wybór Piosenki
-SING_SONG_SELECTION_GOTO=idŸ do...
-SING_SONG_SELECTION=wybór piosenki
-SING_SONG_SELECTION_MENU=menu
-SING_SONG_SELECTION_PLAYLIST=playlista
-SING_SONGS_IN_CAT=Piosenki
-PLAYLIST_CATTEXT=Playlista: %s
-
-SING_TIME=CZAS
-SING_TOTAL=³¹cznie
-SING_MODE=œpiew solo
-SING_NOTES=nuty
-SING_GOLDEN_NOTES=z³ote nuty
-SING_PHRASE_BONUS=Bonus Linii
-
-SING_MENU=Menu G³ówne
-
-SONG_SCORE=wynik
-SONG_SCORE_WHEREAMI=Wynik
-
-SING_SCORE_TONE_DEAF=G³uche nuty
-SING_SCORE_AMATEUR=Amator
-SING_SCORE_RISING_STAR=Wschodz¹ca gwiazda
-SING_SCORE_LEAD_SINGER=Niez³y grajek
-SING_SCORE_HIT_ARTIST=Wielki Artysta
-SING_SCORE_SUPERSTAR=Supergwiazda
-SING_SCORE_ULTRASTAR=Ultrastar
-
-SING_TOP_5_CHARTS=lista 5 najlepszych
-SING_TOP_5_CHARTS_WHEREAMI=top 5
-SING_TOP_5_CHARTS_CONTINUE=do wyboru piosenki
-
-POPUP_PERFECT=idealnie!
-POPUP_AWESOME=niesamowicie!
-POPUP_GREAT=œwietnie!
-POPUP_GOOD=dobrze!
-POPUP_NOTBAD=nieŸle!
-POPUP_BAD=Ÿle!
-POPUP_POOR=s³abo!
-POPUP_AWFUL=okropnie!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= oraz
-
-SONG_MENU_NAME_MAIN=menu piosenki
-SONG_MENU_PLAY=Œpiewaj
-SONG_MENU_CHANGEPLAYERS=Zmieñ graczy
-SONG_MENU_EDIT=Edytuj
-SONG_MENU_MODI=Œpiewaj Modi
-SONG_MENU_CANCEL=Anuluj
-
-SONG_MENU_NAME_PLAYLIST=Menu Piosenki
-SONG_MENU_PLAYLIST_ADD=Dodaj piosenkê
-SONG_MENU_PLAYLIST_DEL=Usuñ piosenkê
-
-SONG_MENU_NAME_PLAYLIST_ADD=Dodaj piosenkê
-SONG_MENU_PLAYLIST_ADD_NEW=do nowej playlisty
-SONG_MENU_PLAYLIST_ADD_EXISTING=do istniej¹cej playlisty
-SONG_MENU_PLAYLIST_NOEXISTING=Brak playlist
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nowa Playlista
-SONG_MENU_PLAYLIST_NEW_CREATE=Stwórz
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Bez nazwy
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Usun¹æ?
-SONG_MENU_YES=Tak
-SONG_MENU_NO=Nie
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Otwórz Playlistê
-SONG_MENU_PLAYLIST_LOAD=otwórz
-SONG_MENU_PLAYLIST_DELCURRENT=usuñ tê playlistê
-
-SONG_MENU_NAME_PLAYLIST_DEL=Usun¹æ playlistê?
-
-SONG_MENU_NAME_PARTY_MAIN=Menu Imprezy
-SONG_MENU_JOKER=Jokera
-
-SONG_MENU_NAME_PARTY_JOKER=weŸ jokera
-
-SONG_JUMPTO_DESC=szukaj
-SONG_JUMPTO_TYPE_DESC=Szukaj:
-SONG_JUMPTO_TYPE1=Wszêdzie
-SONG_JUMPTO_TYPE2=Tytu³
-SONG_JUMPTO_TYPE3=Wykonawca
-SONG_JUMPTO_SONGSFOUND=Znaleziono %d utworów
-SONG_JUMPTO_NOSONGSFOUND=Nic nie znaleziono
-SONG_JUMPTO_HELP=Wpisz tekst do wyszukania
-SONG_JUMPTO_CATTEXT=Szukaj: %s
-
-PARTY_MODE=tryb imprezy
-PARTY_DIFFICULTY=Poziom
-PARTY_PLAYLIST=Tryb playlisty
-PARTY_PLAYLIST_ALL=Wszystko
-PARTY_PLAYLIST_CATEGORY=Folder
-PARTY_PLAYLIST_PLAYLIST=Playlista
-PARTY_ROUNDS=Rundy
-PARTY_TEAMS=Dru¿yny
-PARTY_TEAMS_PLAYER1=Dru¿yna 1
-PARTY_TEAMS_PLAYER2=Dru¿yna 2
-PARTY_TEAMS_PLAYER3=Dru¿yna 3
-
-PARTY_LEGEND_CONTINUE=dalej
-
-PARTY_OPTIONS_DESC=ustawienia trybu imprezy
-PARTY_OPTIONS_WHEREAMI=Impreza - Ustawienia
-
-PARTY_PLAYER_DESC=wpisz nazwy graczy i dru¿yn
-PARTY_PLAYER_WHEREAMI=Nazwy dru¿yn
-PARTY_PLAYER_ENTER_NAME=wpisz nazwy
-PARTY_PLAYER_LEGEND_CONTINUE=start!
-
-PARTY_ROUND_DESC=nastêpni do mikrofonów
-PARTY_ROUND_WHEREAMI=Nastêpna Runda
-PARTY_ROUND_LEGEND_CONTINUE=rozpocznij rundê
-
-PARTY_SONG_WHEREAMI=Wybór piosenki
-PARTY_SONG_LEGEND_CONTINUE=œpiewaj
-PARTY_SONG_MENU=menu
-
-PARTY_SCORE_DESC=wynik ostatniej rundy
-PARTY_SCORE_WHEREAMI=Punkty
-
-PARTY_WIN_DESC=zwyciêzca gry
-PARTY_WIN_WHEREAMI=Zwyciêzca
-PARTY_WIN_LEGEND_CONTINUE=do menu g³ównego
-
-PARTY_ROUND=Runda
-PARTY_ROUND_WINNER=Zwyciêzca
-PARTY_NOTPLAYEDYET=jeszcze nie gra³
-PARTY_NOBODY=nikt
-NEXT_ROUND=Nastêpna runda:
-
-PARTY_DISMISSED=Odpada!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=wygrywa!
-
-PLUGIN_HDL_NAME=Trzymaj liniê
-PLUGIN_HDL_DESC=Œpiewaj lepiej ni¿ linia na wykresie.
-
-PLUGIN_UNTIL5000_NAME=Do 5000
-PLUGIN_UNTIL5000_DESC=Wygrywa ten, kto pierwszy uzyska 5000 punktów.
-
-PLUGIN_DUELL_NAME=Pojedynek
-PLUGIN_DUELL_DESC=Œpiewacie w pojedynku do 10000 punktów.
-
-PLUGIN_TEAMDUELL_NAME=Team Duell
-PLUGIN_TEAMDUELL_DESC=Pass The Mic!
-
-PLUGIN_BLIND_NAME=Œlepiec
-PLUGIN_BLIND_DESC=Pojedynek, w którym nie widzicie nut.
-
-STAT_MAIN=Statystyki
-STAT_MAIN_DESC=Ogólne
-STAT_MAIN_WHEREAMI=Statystyki
-
-STAT_OVERVIEW_INTRO=Statystyki dla: %0:d. \n Ostatnio resetowane: %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Piosenek (%3:d z filmem), z czego %1:d by³o granych a %2:d jeszcze nie.\n Najpopularniejsz¹ piosenk¹ jest %5:s z %4:s.
-STAT_OVERVIEW_PLAYER=Od ostatniego resetu:%0:d ró¿nych graczy.\n Najlepszym graczem jest %1:s ze œrednim wynikiem %2:d punktów.\n %3:s ustanowi³ rekord wynikiem %4:d punktów.
-
-STAT_DETAIL=Statystyki
-STAT_DETAIL_WHEREAMI=Statystyki szczegó³owe
-
-STAT_NEXT=Nastêpna strona
-STAT_PREV=Poprzednia strona
-STAT_REVERSE=Odwróæ kolejnoœæ
-STAT_PAGE=Strona %0:d z %1:d \n (%2:d of %3:d wpisów)
-
-STAT_DESC_SCORES=Najwy¿sze wyniki
-STAT_DESC_SCORES_REVERSED=Najni¿sze wyniki
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Najlepsi
-STAT_DESC_SINGERS_REVERSED=Najgorsi
-STAT_FORMAT_SINGERS=%0:s \n Œredni wynik: %1:d
-
-STAT_DESC_SONGS=Najpopularniejsze piosenki
-STAT_DESC_SONGS_REVERSED=Najmniej popularne piosenki
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx œpiewane
-
-STAT_DESC_BANDS=Najpopularniejsi wykonawcy
-STAT_DESC_BANDS_REVERSED=Najmniej popularni wykonawcy
-STAT_FORMAT_BANDS=%0:s \n %1:dx œpiewani
-
-MSG_ERROR_TITLE=B³¹d
-MSG_QUESTION_TITLE=Pytanie
-MSG_QUIT_USDX=Na pewno chcesz wyjϾ?
-MSG_END_PARTY=Na pewno chcesz zakoñczyæ tryb imprezy?
-ERROR_NO_SONGS=Brak piosenek
-ERROR_NO_PLUGINS=Brak wtyczek
+[Text]
+SING_LOADING=Wczytywanie...
+
+SING_CHOOSE_MODE=wybierz tryb
+SING_SING=œpiewaj
+SING_SING_DESC=œpiewaj solo lub w kilka osób
+
+SING_MULTI=impreza
+SING_MULTI_DESC=rozkrêæ imprezê!
+
+SING_TOOLS=narzêdzia
+
+SING_STATS=statystyki
+SING_STATS_DESC=zobacz statystyki
+
+SING_EDITOR=edytor
+SING_EDITOR_DESC=stwórz w³asne piosenki
+
+SING_GAME_OPTIONS=opcje
+SING_GAME_OPTIONS_DESC=zmieñ ustawienia
+
+SING_EXIT=wyjœcie
+SING_EXIT_DESC=wyjdŸ z gry
+
+SING_OPTIONS=opcje
+SING_OPTIONS_DESC=zmieñ ustawienia
+SING_OPTIONS_WHEREAMI=Opcje
+
+SING_OPTIONS_GAME=gra
+SING_OPTIONS_GRAPHICS=grafika
+SING_OPTIONS_SOUND=dŸwiêk
+SING_OPTIONS_LYRICS=s³owa
+SING_OPTIONS_THEMES=tematy
+SING_OPTIONS_RECORD=nagrywanie
+SING_OPTIONS_ADVANCED=zaawansowane
+SING_OPTIONS_EXIT=wstecz
+
+SING_OPTIONS_GAME_WHEREAMI=Opcje Gra
+SING_OPTIONS_GAME_DESC=opcje gry
+SING_OPTIONS_GAME_PLAYERS=IloϾ graczy
+SING_OPTIONS_GAME_DIFFICULTY=Poziom trudnoœci
+SING_OPTIONS_GAME_LANGUAGE=Jêzyk
+SING_OPTIONS_GAME_TABS=Zak³adki
+SING_OPTIONS_GAME_SORTING=Sortowanie
+SING_OPTIONS_GAME_DEBUG=Debug
+
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Opcje Grafika
+SING_OPTIONS_GAME_DESC=opcje gry
+SING_OPTIONS_GAME_PLAYERS=IloϾ graczy
+SING_OPTIONS_GAME_DIFFICULTY=Poziom trudnoœci
+SING_OPTIONS_GAME_LANGUAGE=Jêzyk
+SING_OPTIONS_GAME_TABS=Zak³adki
+SING_OPTIONS_GAME_SORTING=Sortowanie
+SING_OPTIONS_GAME_DEBUG=Debug
+
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus Linii
+
+SING_OPTIONS_SOUND_WHEREAMI=Opcje DŸwiêk
+SING_OPTIONS_SOUND_DESC=opcje dŸwiêku
+SING_OPTIONS_SOUND_MIC_BOOST=Podbicie mikrofonu
+SING_OPTIONS_SOUND_CLICK_ASSIST=Pomoc klikniêciami
+SING_OPTIONS_SOUND_BEAT_CLICK=Klikniêcia w rytm
+SING_OPTIONS_SOUND_THRESHOLD=Próg
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Tryb dwóch graczy
+SING_OPTIONS_SOUND_PREVIEWVOLUME=G³oœnoœæ w podgl¹dzie
+SING_OPTIONS_SOUND_PREVIEWFADING=Zanikanie w podgl¹dzie
+
+SING_OPTIONS_LYRICS_WHEREAMI=Opcje S³owa
+SING_OPTIONS_LYRICS_DESC=opcje s³ów
+SING_OPTIONS_LYRICS_FONT=Czcionka
+SING_OPTIONS_LYRICS_EFFECT=Efekt
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacja
+
+SING_OPTIONS_THEMES_WHEREAMI=Options Tematy
+SING_OPTIONS_THEMES_DESC=opcje tematów
+SING_OPTIONS_THEMES_THEME=Temat
+SING_OPTIONS_THEMES_SKIN=Skóra
+SING_OPTIONS_THEMES_COLOR=Kolor
+
+SING_OPTIONS_RECORD_WHEREAMI=Opcje Nagrywanie
+SING_OPTIONS_RECORD_DESC=opcje nagrywania
+SING_OPTIONS_RECORD_CARD=Karta dŸwiêkowa
+SING_OPTIONS_RECORD_INPUT=Wejœcie
+SING_OPTIONS_RECORD_CHANNEL=Kana³
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Opcje Zaawansowane
+SING_OPTIONS_ADVANCED_DESC=ustawienia zaawansowane
+SING_OPTIONS_ADVANCED_EFFECTSING=Efekty specjalne
+SING_OPTIONS_ADVANCED_SCREENFADE=Przenikanie
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animacja ³adowania
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Pytania przy wyjœciu
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus Linii
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=Licznik
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Po wyborze piosenki
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto Menu Imprezy
+
+SING_LEGEND_SELECT=wybierz
+SING_LEGEND_NAVIGATE=nawigacja
+SING_LEGEND_CONTINUE=dalej
+SING_LEGEND_ESC=wstecz
+
+SING_PLAYER_DESC=wprowadŸ imiê gracza
+SING_PLAYER_WHEREAMI=Imiê
+SING_PLAYER_ENTER_NAME=wpisz imiê
+
+SING_DIFFICULTY_DESC=wybierz poziom trudnoœci
+SING_DIFFICULTY_WHEREAMI=Poziom
+SING_DIFFICULTY_CONTINUE=do wyboru piosenki
+SING_EASY=³atwo
+SING_MEDIUM=œrednio
+SING_HARD=trudno
+
+SING_SONG_SELECTION_DESC=wybierz piosenkê
+SING_SONG_SELECTION_WHEREAMI=Wybór Piosenki
+SING_SONG_SELECTION_GOTO=idŸ do...
+SING_SONG_SELECTION=wybór piosenki
+SING_SONG_SELECTION_MENU=menu
+SING_SONG_SELECTION_PLAYLIST=playlista
+SING_SONGS_IN_CAT=Piosenki
+PLAYLIST_CATTEXT=Playlista: %s
+
+SING_TIME=CZAS
+SING_TOTAL=³¹cznie
+SING_MODE=œpiew solo
+SING_NOTES=nuty
+SING_GOLDEN_NOTES=z³ote nuty
+SING_PHRASE_BONUS=Bonus Linii
+
+SING_MENU=Menu G³ówne
+
+SONG_SCORE=wynik
+SONG_SCORE_WHEREAMI=Wynik
+
+SING_SCORE_TONE_DEAF=G³uche nuty
+SING_SCORE_AMATEUR=Amator
+SING_SCORE_RISING_STAR=Wschodz¹ca gwiazda
+SING_SCORE_LEAD_SINGER=Niez³y grajek
+SING_SCORE_HIT_ARTIST=Wielki Artysta
+SING_SCORE_SUPERSTAR=Supergwiazda
+SING_SCORE_ULTRASTAR=Ultrastar
+
+SING_TOP_5_CHARTS=lista 5 najlepszych
+SING_TOP_5_CHARTS_WHEREAMI=top 5
+SING_TOP_5_CHARTS_CONTINUE=do wyboru piosenki
+
+POPUP_PERFECT=idealnie!
+POPUP_AWESOME=niesamowicie!
+POPUP_GREAT=œwietnie!
+POPUP_GOOD=dobrze!
+POPUP_NOTBAD=nieŸle!
+POPUP_BAD=Ÿle!
+POPUP_POOR=s³abo!
+POPUP_AWFUL=okropnie!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= oraz
+
+SONG_MENU_NAME_MAIN=menu piosenki
+SONG_MENU_PLAY=Œpiewaj
+SONG_MENU_CHANGEPLAYERS=Zmieñ graczy
+SONG_MENU_EDIT=Edytuj
+SONG_MENU_MODI=Œpiewaj Modi
+SONG_MENU_CANCEL=Anuluj
+
+SONG_MENU_NAME_PLAYLIST=Menu Piosenki
+SONG_MENU_PLAYLIST_ADD=Dodaj piosenkê
+SONG_MENU_PLAYLIST_DEL=Usuñ piosenkê
+
+SONG_MENU_NAME_PLAYLIST_ADD=Dodaj piosenkê
+SONG_MENU_PLAYLIST_ADD_NEW=do nowej playlisty
+SONG_MENU_PLAYLIST_ADD_EXISTING=do istniej¹cej playlisty
+SONG_MENU_PLAYLIST_NOEXISTING=Brak playlist
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nowa Playlista
+SONG_MENU_PLAYLIST_NEW_CREATE=Stwórz
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Bez nazwy
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Usun¹æ?
+SONG_MENU_YES=Tak
+SONG_MENU_NO=Nie
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Otwórz Playlistê
+SONG_MENU_PLAYLIST_LOAD=otwórz
+SONG_MENU_PLAYLIST_DELCURRENT=usuñ tê playlistê
+
+SONG_MENU_NAME_PLAYLIST_DEL=Usun¹æ playlistê?
+
+SONG_MENU_NAME_PARTY_MAIN=Menu Imprezy
+SONG_MENU_JOKER=Jokera
+
+SONG_MENU_NAME_PARTY_JOKER=weŸ jokera
+
+SONG_JUMPTO_DESC=szukaj
+SONG_JUMPTO_TYPE_DESC=Szukaj:
+SONG_JUMPTO_TYPE1=Wszêdzie
+SONG_JUMPTO_TYPE2=Tytu³
+SONG_JUMPTO_TYPE3=Wykonawca
+SONG_JUMPTO_SONGSFOUND=Znaleziono %d utworów
+SONG_JUMPTO_NOSONGSFOUND=Nic nie znaleziono
+SONG_JUMPTO_HELP=Wpisz tekst do wyszukania
+SONG_JUMPTO_CATTEXT=Szukaj: %s
+
+PARTY_MODE=tryb imprezy
+PARTY_DIFFICULTY=Poziom
+PARTY_PLAYLIST=Tryb playlisty
+PARTY_PLAYLIST_ALL=Wszystko
+PARTY_PLAYLIST_CATEGORY=Folder
+PARTY_PLAYLIST_PLAYLIST=Playlista
+PARTY_ROUNDS=Rundy
+PARTY_TEAMS=Dru¿yny
+PARTY_TEAMS_PLAYER1=Dru¿yna 1
+PARTY_TEAMS_PLAYER2=Dru¿yna 2
+PARTY_TEAMS_PLAYER3=Dru¿yna 3
+
+PARTY_LEGEND_CONTINUE=dalej
+
+PARTY_OPTIONS_DESC=ustawienia trybu imprezy
+PARTY_OPTIONS_WHEREAMI=Impreza - Ustawienia
+
+PARTY_PLAYER_DESC=wpisz nazwy graczy i dru¿yn
+PARTY_PLAYER_WHEREAMI=Nazwy dru¿yn
+PARTY_PLAYER_ENTER_NAME=wpisz nazwy
+PARTY_PLAYER_LEGEND_CONTINUE=start!
+
+PARTY_ROUND_DESC=nastêpni do mikrofonów
+PARTY_ROUND_WHEREAMI=Nastêpna Runda
+PARTY_ROUND_LEGEND_CONTINUE=rozpocznij rundê
+
+PARTY_SONG_WHEREAMI=Wybór piosenki
+PARTY_SONG_LEGEND_CONTINUE=œpiewaj
+PARTY_SONG_MENU=menu
+
+PARTY_SCORE_DESC=wynik ostatniej rundy
+PARTY_SCORE_WHEREAMI=Punkty
+
+PARTY_WIN_DESC=zwyciêzca gry
+PARTY_WIN_WHEREAMI=Zwyciêzca
+PARTY_WIN_LEGEND_CONTINUE=do menu g³ównego
+
+PARTY_ROUND=Runda
+PARTY_ROUND_WINNER=Zwyciêzca
+PARTY_NOTPLAYEDYET=jeszcze nie gra³
+PARTY_NOBODY=nikt
+NEXT_ROUND=Nastêpna runda:
+
+PARTY_DISMISSED=Odpada!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=wygrywa!
+
+PLUGIN_HDL_NAME=Trzymaj liniê
+PLUGIN_HDL_DESC=Œpiewaj lepiej ni¿ linia na wykresie.
+
+PLUGIN_UNTIL5000_NAME=Do 5000
+PLUGIN_UNTIL5000_DESC=Wygrywa ten, kto pierwszy uzyska 5000 punktów.
+
+PLUGIN_DUELL_NAME=Pojedynek
+PLUGIN_DUELL_DESC=Œpiewacie w pojedynku do 10000 punktów.
+
+PLUGIN_TEAMDUELL_NAME=Team Duell
+PLUGIN_TEAMDUELL_DESC=Pass The Mic!
+
+PLUGIN_BLIND_NAME=Œlepiec
+PLUGIN_BLIND_DESC=Pojedynek, w którym nie widzicie nut.
+
+STAT_MAIN=Statystyki
+STAT_MAIN_DESC=Ogólne
+STAT_MAIN_WHEREAMI=Statystyki
+
+STAT_OVERVIEW_INTRO=Statystyki dla: %0:d. \n Ostatnio resetowane: %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Piosenek (%3:d z filmem), z czego %1:d by³o granych a %2:d jeszcze nie.\n Najpopularniejsz¹ piosenk¹ jest %5:s z %4:s.
+STAT_OVERVIEW_PLAYER=Od ostatniego resetu:%0:d ró¿nych graczy.\n Najlepszym graczem jest %1:s ze œrednim wynikiem %2:d punktów.\n %3:s ustanowi³ rekord wynikiem %4:d punktów.
+
+STAT_DETAIL=Statystyki
+STAT_DETAIL_WHEREAMI=Statystyki szczegó³owe
+
+STAT_NEXT=Nastêpna strona
+STAT_PREV=Poprzednia strona
+STAT_REVERSE=Odwróæ kolejnoœæ
+STAT_PAGE=Strona %0:d z %1:d \n (%2:d of %3:d wpisów)
+
+STAT_DESC_SCORES=Najwy¿sze wyniki
+STAT_DESC_SCORES_REVERSED=Najni¿sze wyniki
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Najlepsi
+STAT_DESC_SINGERS_REVERSED=Najgorsi
+STAT_FORMAT_SINGERS=%0:s \n Œredni wynik: %1:d
+
+STAT_DESC_SONGS=Najpopularniejsze piosenki
+STAT_DESC_SONGS_REVERSED=Najmniej popularne piosenki
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx œpiewane
+
+STAT_DESC_BANDS=Najpopularniejsi wykonawcy
+STAT_DESC_BANDS_REVERSED=Najmniej popularni wykonawcy
+STAT_FORMAT_BANDS=%0:s \n %1:dx œpiewani
+
+MSG_ERROR_TITLE=B³¹d
+MSG_QUESTION_TITLE=Pytanie
+MSG_QUIT_USDX=Na pewno chcesz wyjϾ?
+MSG_END_PARTY=Na pewno chcesz zakoñczyæ tryb imprezy?
+ERROR_NO_SONGS=Brak piosenek
+ERROR_NO_PLUGINS=Brak wtyczek
ERROR_CORRUPT_SONG=Piosenka nie mog³a zostaæ za³adowana. \ No newline at end of file
diff --git a/game/languages/old/Serbian.ini b/game/languages/old/Serbian.ini
index b680eb44..1896c6de 100644
--- a/game/languages/old/Serbian.ini
+++ b/game/languages/old/Serbian.ini
@@ -1,298 +1,298 @@
-[Text]
-SING_LOADING=Ucitava se...
-
-SING_CHOOSE_MODE=izaberi mod
-SING_SING=pevaj
-SING_SING_DESC=brza igra: pevaj solo ili u duetu
-
-SING_MULTI=tim
-SING_MULTI_DESC=pevaj u timskom modu
-
-SING_TOOLS=alati
-
-SING_STATS=statistike
-SING_STATS_DESC=pogledaj statistike
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=napravi svoje pesme
-
-SING_GAME_OPTIONS=oprcije igre
-SING_GAME_OPTIONS_DESC=promeni podesavanja igre
-
-SING_EXIT=izlaz
-SING_EXIT_DESC=izadji iz igre
-
-SING_OPTIONS=opcije
-SING_OPTIONS_DESC=promeni podesavanja
-SING_OPTIONS_WHEREAMI=Opcije
-
-SING_OPTIONS_GAME=igra
-SING_OPTIONS_GRAPHICS=grafika
-SING_OPTIONS_SOUND=zvuk
-SING_OPTIONS_LYRICS=lirike
-SING_OPTIONS_THEMES=teme
-SING_OPTIONS_RECORD=snimanje
-SING_OPTIONS_ADVANCED=ostalo
-SING_OPTIONS_EXIT=nazad
-
-SING_OPTIONS_GAME_WHEREAMI=Opcije Igra
-SING_OPTIONS_GAME_DESC=opsta podesavanja igre
-SING_OPTIONS_GAME_PLAYERS=Igraci
-SING_OPTIONS_GAME_DIFFICULTY=Tezina
-SING_OPTIONS_GAME_LANGUAGE=Jezik
-SING_OPTIONS_GAME_TABS=Tabovi
-SING_OPTIONS_GAME_SORTING=Sortiranje
-SING_OPTIONS_GAME_DEBUG=Dibagiranje
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Opcije Grafika
-SING_OPTIONS_GRAPHICS_DESC=graficka podesavanja
-SING_OPTIONS_GRAPHICS_RESOLUTION=Rezolucija
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Pun Ekran
-SING_OPTIONS_GRAPHICS_DEPTH=Boje
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus Linija
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Velicina Videa
-
-SING_OPTIONS_SOUND_WHEREAMI=Opcije Zvuk
-SING_OPTIONS_SOUND_DESC=podesavanja zvuka
-SING_OPTIONS_SOUND_MIC_BOOST=Pojacanje mikrofona
-SING_OPTIONS_SOUND_CLICK_ASSIST=Click assist
-SING_OPTIONS_SOUND_BEAT_CLICK=Beat click
-SING_OPTIONS_SOUND_THRESHOLD=Stepen Cujnosti
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mod za dva igraca
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Provera jacine tona
-SING_OPTIONS_SOUND_PREVIEWFADING=Provera pomracenja
-
-SING_OPTIONS_LYRICS_WHEREAMI=Opcije Lirike
-SING_OPTIONS_LYRICS_DESC=Podesavanja lirika
-SING_OPTIONS_LYRICS_FONT=Font
-SING_OPTIONS_LYRICS_EFFECT=Efekti
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacija
-
-SING_OPTIONS_THEMES_WHEREAMI=Opcije Teme
-SING_OPTIONS_THEMES_DESC=podesavanja teme i skina
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Skin
-SING_OPTIONS_THEMES_COLOR=Boja
-
-SING_OPTIONS_RECORD_WHEREAMI=Opcije Snimanje
-SING_OPTIONS_RECORD_DESC=podesavanja mikrofona
-SING_OPTIONS_RECORD_CARD=Zvucna Kartica
-SING_OPTIONS_RECORD_INPUT=Ulaz
-SING_OPTIONS_RECORD_CHANNEL=Kanal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Opcije Ostalo
-SING_OPTIONS_ADVANCED_DESC=ostala podesavanja
-SING_OPTIONS_ADVANCED_EFFECTSING=Efekti Pevanja
-SING_OPTIONS_ADVANCED_SCREENFADE=Pomracenje Ekrana
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animacija Ucitavanja
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Bezbednosna Pitanja
-SING_OPTIONS_ADVANCED_LINEBONUS=Linijski Bonus
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Posle Odabira Pesme
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Automatski Timski Meni
-
-SING_LEGEND_SELECT=izaberi
-SING_LEGEND_NAVIGATE=biraj
-SING_LEGEND_CONTINUE=nastavi
-SING_LEGEND_ESC=nazad
-
-SING_PLAYER_DESC=unesi ime igraca
-SING_PLAYER_WHEREAMI=Imenaigraca
-SING_PLAYER_ENTER_NAME=unesi ime
-
-SING_DIFFICULTY_DESC=izaberi tezinu
-SING_DIFFICULTY_WHEREAMI=Tezina
-SING_DIFFICULTY_CONTINUE=do odabira pesme
-SING_EASY=Lako
-SING_MEDIUM=Normalno
-SING_HARD=Tesko
-
-SING_SONG_SELECTION_DESC=izaberi svoju pesmu
-SING_SONG_SELECTION_WHEREAMI=Izbor Pesme
-SING_SONG_SELECTION_GOTO=idi na...
-SING_SONG_SELECTION=izbor pesme
-SING_SONG_SELECTION_MENU=meni
-SING_SONG_SELECTION_PLAYLIST=lista pesama
-SING_SONGS_IN_CAT=Pesme
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=TIME
-SING_TOTAL=total
-SING_MODE=pevaj solo
-SING_NOTES=note
-SING_GOLDEN_NOTES=zlatne note
-SING_PHRASE_BONUS=linijski bonus
-
-SING_MENU=Glavni Meni
-
-SONG_SCORE=rezultat pesme
-SONG_SCORE_WHEREAMI=Rezultat
-
-SING_SCORE_TONE_DEAF=Antitalenat
-SING_SCORE_AMATEUR=Amater
-SING_SCORE_RISING_STAR=Zvezda U Usponu
-SING_SCORE_LEAD_SINGER=Solista
-SING_SCORE_HIT_ARTIST=Hit Pevac
-SING_SCORE_SUPERSTAR=SuperZvezda
-SING_SCORE_ULTRASTAR=UltraZvezda
-
-SING_TOP_5_CHARTS=najboljih 5 Igraca
-SING_TOP_5_CHARTS_WHEREAMI=najboljih pet
-SING_TOP_5_CHARTS_CONTINUE=do izbora pesme
-
-POPUP_PERFECT=savrseno!
-POPUP_AWESOME=odlicno!
-POPUP_GREAT=sjajno!
-POPUP_GOOD=dobro!
-POPUP_NOTBAD=nije lose!
-POPUP_BAD=lose!
-POPUP_POOR=jedno!
-POPUP_AWFUL=grozno!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= i
-
-SONG_MENU_NAME_MAIN=meni pesme
-SONG_MENU_PLAY=Pevaj
-SONG_MENU_CHANGEPLAYERS=Promeni Igrace
-SONG_MENU_EDIT=Edituj
-SONG_MENU_MODI=Pevaj Modi
-SONG_MENU_CANCEL=Nazad
-
-SONG_MENU_NAME_PLAYLIST=Meni Pesme
-SONG_MENU_PLAYLIST_ADD=Dodaj Pesmu
-SONG_MENU_PLAYLIST_DEL=Obrisi Pesmu
-
-SONG_MENU_NAME_PLAYLIST_ADD=Dodaj Pesmu
-SONG_MENU_PLAYLIST_ADD_NEW=na novu listu
-SONG_MENU_PLAYLIST_ADD_EXISTING=na postojecu listu
-SONG_MENU_PLAYLIST_NOEXISTING=Nema dostupnih lista
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nova Lista
-SONG_MENU_PLAYLIST_NEW_CREATE=Napravi
-SONG_MENU_PLAYLIST_NEW_UNNAMED=BezNaziva
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Zaista Obrisati?
-SONG_MENU_YES=Da
-SONG_MENU_NO=Ne
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Otvori Listu
-SONG_MENU_PLAYLIST_LOAD=otvori
-SONG_MENU_PLAYLIST_DELCURRENT=obrisi Trenutnu Listu
-
-SONG_MENU_NAME_PLAYLIST_DEL=Obrisi listu?
-
-SONG_MENU_NAME_PARTY_MAIN=Timski Meni
-SONG_MENU_JOKER=Dzoker
-
-SONG_MENU_NAME_PARTY_JOKER=uzmi dzokera
-
-SONG_JUMPTO_DESC=trazi pesmu
-SONG_JUMPTO_TYPE_DESC=Trazi:
-SONG_JUMPTO_TYPE1=Sve
-SONG_JUMPTO_TYPE2=Naziv
-SONG_JUMPTO_TYPE3=Izvodjac
-SONG_JUMPTO_SONGSFOUND=%d Pesma(pesama) nadjeno
-SONG_JUMPTO_NOSONGSFOUND=Nema nadjenih pesama
-SONG_JUMPTO_HELP=Upisi tekst koji trazis
-SONG_JUMPTO_CATTEXT=Search for: %s
-
-PARTY_MODE=timski mod
-PARTY_DIFFICULTY=Tezina
-PARTY_PLAYLIST=Mod Liste Pesama
-PARTY_PLAYLIST_ALL=Sve Pesme
-PARTY_PLAYLIST_CATEGORY=Direktorijum
-PARTY_PLAYLIST_PLAYLIST=Lista Pesama
-PARTY_ROUNDS=Runde
-PARTY_TEAMS=Timovi
-PARTY_TEAMS_PLAYER1=Igrac Tim1
-PARTY_TEAMS_PLAYER2=Igrac Tim2
-PARTY_TEAMS_PLAYER3=Igrac Tim3
-
-PARTY_LEGEND_CONTINUE=nastavi
-
-PARTY_OPTIONS_DESC=podesavanja za timsku igru
-PARTY_OPTIONS_WHEREAMI=Timske Opcije
-
-PARTY_PLAYER_DESC=unesi imena igraca i timova!
-PARTY_PLAYER_WHEREAMI=Imena Timova
-PARTY_PLAYER_ENTER_NAME=unesi imena
-PARTY_PLAYER_LEGEND_CONTINUE=zapocni timsku igru
-
-PARTY_ROUND_DESC=sledeci igraci za mikrofonom
-PARTY_ROUND_WHEREAMI=Timska Sledeca Runda
-PARTY_ROUND_LEGEND_CONTINUE=pocni rundu
-
-PARTY_SONG_WHEREAMI=Timski Izbor Pesama
-PARTY_SONG_LEGEND_CONTINUE=povaj
-PARTY_SONG_MENU=timski meni
-
-PARTY_SCORE_DESC=rezultat poslednje runde
-PARTY_SCORE_WHEREAMI=Timski Poeni
-
-PARTY_WIN_DESC=pobednik timske igre
-PARTY_WIN_WHEREAMI=Timski Pobednik
-PARTY_WIN_LEGEND_CONTINUE=nazad u glavni meni
-
-PARTY_ROUND=Runda
-PARTY_ROUND_WINNER=Pobednik
-PARTY_NOTPLAYEDYET=nije jos igrao
-PARTY_NOBODY=niko
-NEXT_ROUND=Sledeca runda:
-
-PARTY_DISMISSED=Otpusten!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=Pobedio!
-
-PLUGIN_HDL_NAME=Drzi liniju
-PLUGIN_HDL_DESC=Ne budi losiji nego sto ti strelica pokazuje.
-
-PLUGIN_UNTIL5000_NAME=Do 5000
-PLUGIN_UNTIL5000_DESC=Ko stigne prvi do 5000 poena pobedjuje.
-
-PLUGIN_DUELL_NAME=Duel
-PLUGIN_DUELL_DESC=Pevaj duel do 10000 poena.
-
-PLUGIN_BLIND_NAME=Slepi Mod
-PLUGIN_BLIND_DESC=Duel bez gledanja nota.
-
-STAT_MAIN=Statistike
-STAT_MAIN_DESC=Generalne
-STAT_MAIN_WHEREAMI=Statistike
-
-STAT_OVERVIEW_INTRO=%0:s Statistike. \n Poslednji reset bio je %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Pesme(%3:d sa Videom), gde su %1:d vec igrane i %2:d nisu jos igrane.\n Najpopularnija pesma je %5:s sa %4:s.
-STAT_OVERVIEW_PLAYER=Od poslednjeg reseta bilo je %0:d razlicitih igraca.\n Najbolji igrac je %1:s sa prosecnim rezultatom od %2:d poena.\n %3:s je imao najveci rezultat sa %4:d poena.
-
-STAT_DETAIL=Statistike
-STAT_DETAIL_WHEREAMI=Detalji Statistike
-
-STAT_NEXT=Sledeca Strana
-STAT_PREV=Prethodna Strana
-STAT_REVERSE=Obrnuti Redosled
-STAT_PAGE=Seite %0:d of %1:d strana\n (%2:d od %3:d unosa)
-
-STAT_DESC_SCORES=NajboljiRezultati
-STAT_DESC_SCORES_REVERSED=NajgoriRezultati
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Najbolji Pevaci
-STAT_DESC_SINGERS_REVERSED=Najgori Pevaci
-STAT_FORMAT_SINGERS=%0:s \n Prosecan Rezultat: %1:d
-
-STAT_DESC_SONGS=Najpopularnije Pesme
-STAT_DESC_SONGS_REVERSED=Najmanje Popularne Pesme
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx pevano
-
-STAT_DESC_BANDS=Najpopularniji Bendovi
-STAT_DESC_BANDS_REVERSED=Najmanje Popularni Bendovi
-STAT_FORMAT_BANDS=%0:s \n %1:dx Pevano
-
-MSG_ERROR_TITLE=Greska
-MSG_QUESTION_TITLE=Pitanje
-MSG_QUIT_USDX=Stvarno napustate UltraStar?
-MSG_END_PARTY=Stvarno napustate Timski Mod?
-ERROR_NO_SONGS=Nema ucitanih pesama
-ERROR_NO_PLUGINS=Nema ucitanih plugin-ova
+[Text]
+SING_LOADING=Ucitava se...
+
+SING_CHOOSE_MODE=izaberi mod
+SING_SING=pevaj
+SING_SING_DESC=brza igra: pevaj solo ili u duetu
+
+SING_MULTI=tim
+SING_MULTI_DESC=pevaj u timskom modu
+
+SING_TOOLS=alati
+
+SING_STATS=statistike
+SING_STATS_DESC=pogledaj statistike
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=napravi svoje pesme
+
+SING_GAME_OPTIONS=oprcije igre
+SING_GAME_OPTIONS_DESC=promeni podesavanja igre
+
+SING_EXIT=izlaz
+SING_EXIT_DESC=izadji iz igre
+
+SING_OPTIONS=opcije
+SING_OPTIONS_DESC=promeni podesavanja
+SING_OPTIONS_WHEREAMI=Opcije
+
+SING_OPTIONS_GAME=igra
+SING_OPTIONS_GRAPHICS=grafika
+SING_OPTIONS_SOUND=zvuk
+SING_OPTIONS_LYRICS=lirike
+SING_OPTIONS_THEMES=teme
+SING_OPTIONS_RECORD=snimanje
+SING_OPTIONS_ADVANCED=ostalo
+SING_OPTIONS_EXIT=nazad
+
+SING_OPTIONS_GAME_WHEREAMI=Opcije Igra
+SING_OPTIONS_GAME_DESC=opsta podesavanja igre
+SING_OPTIONS_GAME_PLAYERS=Igraci
+SING_OPTIONS_GAME_DIFFICULTY=Tezina
+SING_OPTIONS_GAME_LANGUAGE=Jezik
+SING_OPTIONS_GAME_TABS=Tabovi
+SING_OPTIONS_GAME_SORTING=Sortiranje
+SING_OPTIONS_GAME_DEBUG=Dibagiranje
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Opcije Grafika
+SING_OPTIONS_GRAPHICS_DESC=graficka podesavanja
+SING_OPTIONS_GRAPHICS_RESOLUTION=Rezolucija
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Pun Ekran
+SING_OPTIONS_GRAPHICS_DEPTH=Boje
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Bonus Linija
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Velicina Videa
+
+SING_OPTIONS_SOUND_WHEREAMI=Opcije Zvuk
+SING_OPTIONS_SOUND_DESC=podesavanja zvuka
+SING_OPTIONS_SOUND_MIC_BOOST=Pojacanje mikrofona
+SING_OPTIONS_SOUND_CLICK_ASSIST=Click assist
+SING_OPTIONS_SOUND_BEAT_CLICK=Beat click
+SING_OPTIONS_SOUND_THRESHOLD=Stepen Cujnosti
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mod za dva igraca
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Provera jacine tona
+SING_OPTIONS_SOUND_PREVIEWFADING=Provera pomracenja
+
+SING_OPTIONS_LYRICS_WHEREAMI=Opcije Lirike
+SING_OPTIONS_LYRICS_DESC=Podesavanja lirika
+SING_OPTIONS_LYRICS_FONT=Font
+SING_OPTIONS_LYRICS_EFFECT=Efekti
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacija
+
+SING_OPTIONS_THEMES_WHEREAMI=Opcije Teme
+SING_OPTIONS_THEMES_DESC=podesavanja teme i skina
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Skin
+SING_OPTIONS_THEMES_COLOR=Boja
+
+SING_OPTIONS_RECORD_WHEREAMI=Opcije Snimanje
+SING_OPTIONS_RECORD_DESC=podesavanja mikrofona
+SING_OPTIONS_RECORD_CARD=Zvucna Kartica
+SING_OPTIONS_RECORD_INPUT=Ulaz
+SING_OPTIONS_RECORD_CHANNEL=Kanal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Opcije Ostalo
+SING_OPTIONS_ADVANCED_DESC=ostala podesavanja
+SING_OPTIONS_ADVANCED_EFFECTSING=Efekti Pevanja
+SING_OPTIONS_ADVANCED_SCREENFADE=Pomracenje Ekrana
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animacija Ucitavanja
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Bezbednosna Pitanja
+SING_OPTIONS_ADVANCED_LINEBONUS=Linijski Bonus
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Posle Odabira Pesme
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Automatski Timski Meni
+
+SING_LEGEND_SELECT=izaberi
+SING_LEGEND_NAVIGATE=biraj
+SING_LEGEND_CONTINUE=nastavi
+SING_LEGEND_ESC=nazad
+
+SING_PLAYER_DESC=unesi ime igraca
+SING_PLAYER_WHEREAMI=Imenaigraca
+SING_PLAYER_ENTER_NAME=unesi ime
+
+SING_DIFFICULTY_DESC=izaberi tezinu
+SING_DIFFICULTY_WHEREAMI=Tezina
+SING_DIFFICULTY_CONTINUE=do odabira pesme
+SING_EASY=Lako
+SING_MEDIUM=Normalno
+SING_HARD=Tesko
+
+SING_SONG_SELECTION_DESC=izaberi svoju pesmu
+SING_SONG_SELECTION_WHEREAMI=Izbor Pesme
+SING_SONG_SELECTION_GOTO=idi na...
+SING_SONG_SELECTION=izbor pesme
+SING_SONG_SELECTION_MENU=meni
+SING_SONG_SELECTION_PLAYLIST=lista pesama
+SING_SONGS_IN_CAT=Pesme
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=TIME
+SING_TOTAL=total
+SING_MODE=pevaj solo
+SING_NOTES=note
+SING_GOLDEN_NOTES=zlatne note
+SING_PHRASE_BONUS=linijski bonus
+
+SING_MENU=Glavni Meni
+
+SONG_SCORE=rezultat pesme
+SONG_SCORE_WHEREAMI=Rezultat
+
+SING_SCORE_TONE_DEAF=Antitalenat
+SING_SCORE_AMATEUR=Amater
+SING_SCORE_RISING_STAR=Zvezda U Usponu
+SING_SCORE_LEAD_SINGER=Solista
+SING_SCORE_HIT_ARTIST=Hit Pevac
+SING_SCORE_SUPERSTAR=SuperZvezda
+SING_SCORE_ULTRASTAR=UltraZvezda
+
+SING_TOP_5_CHARTS=najboljih 5 Igraca
+SING_TOP_5_CHARTS_WHEREAMI=najboljih pet
+SING_TOP_5_CHARTS_CONTINUE=do izbora pesme
+
+POPUP_PERFECT=savrseno!
+POPUP_AWESOME=odlicno!
+POPUP_GREAT=sjajno!
+POPUP_GOOD=dobro!
+POPUP_NOTBAD=nije lose!
+POPUP_BAD=lose!
+POPUP_POOR=jedno!
+POPUP_AWFUL=grozno!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= i
+
+SONG_MENU_NAME_MAIN=meni pesme
+SONG_MENU_PLAY=Pevaj
+SONG_MENU_CHANGEPLAYERS=Promeni Igrace
+SONG_MENU_EDIT=Edituj
+SONG_MENU_MODI=Pevaj Modi
+SONG_MENU_CANCEL=Nazad
+
+SONG_MENU_NAME_PLAYLIST=Meni Pesme
+SONG_MENU_PLAYLIST_ADD=Dodaj Pesmu
+SONG_MENU_PLAYLIST_DEL=Obrisi Pesmu
+
+SONG_MENU_NAME_PLAYLIST_ADD=Dodaj Pesmu
+SONG_MENU_PLAYLIST_ADD_NEW=na novu listu
+SONG_MENU_PLAYLIST_ADD_EXISTING=na postojecu listu
+SONG_MENU_PLAYLIST_NOEXISTING=Nema dostupnih lista
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nova Lista
+SONG_MENU_PLAYLIST_NEW_CREATE=Napravi
+SONG_MENU_PLAYLIST_NEW_UNNAMED=BezNaziva
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Zaista Obrisati?
+SONG_MENU_YES=Da
+SONG_MENU_NO=Ne
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Otvori Listu
+SONG_MENU_PLAYLIST_LOAD=otvori
+SONG_MENU_PLAYLIST_DELCURRENT=obrisi Trenutnu Listu
+
+SONG_MENU_NAME_PLAYLIST_DEL=Obrisi listu?
+
+SONG_MENU_NAME_PARTY_MAIN=Timski Meni
+SONG_MENU_JOKER=Dzoker
+
+SONG_MENU_NAME_PARTY_JOKER=uzmi dzokera
+
+SONG_JUMPTO_DESC=trazi pesmu
+SONG_JUMPTO_TYPE_DESC=Trazi:
+SONG_JUMPTO_TYPE1=Sve
+SONG_JUMPTO_TYPE2=Naziv
+SONG_JUMPTO_TYPE3=Izvodjac
+SONG_JUMPTO_SONGSFOUND=%d Pesma(pesama) nadjeno
+SONG_JUMPTO_NOSONGSFOUND=Nema nadjenih pesama
+SONG_JUMPTO_HELP=Upisi tekst koji trazis
+SONG_JUMPTO_CATTEXT=Search for: %s
+
+PARTY_MODE=timski mod
+PARTY_DIFFICULTY=Tezina
+PARTY_PLAYLIST=Mod Liste Pesama
+PARTY_PLAYLIST_ALL=Sve Pesme
+PARTY_PLAYLIST_CATEGORY=Direktorijum
+PARTY_PLAYLIST_PLAYLIST=Lista Pesama
+PARTY_ROUNDS=Runde
+PARTY_TEAMS=Timovi
+PARTY_TEAMS_PLAYER1=Igrac Tim1
+PARTY_TEAMS_PLAYER2=Igrac Tim2
+PARTY_TEAMS_PLAYER3=Igrac Tim3
+
+PARTY_LEGEND_CONTINUE=nastavi
+
+PARTY_OPTIONS_DESC=podesavanja za timsku igru
+PARTY_OPTIONS_WHEREAMI=Timske Opcije
+
+PARTY_PLAYER_DESC=unesi imena igraca i timova!
+PARTY_PLAYER_WHEREAMI=Imena Timova
+PARTY_PLAYER_ENTER_NAME=unesi imena
+PARTY_PLAYER_LEGEND_CONTINUE=zapocni timsku igru
+
+PARTY_ROUND_DESC=sledeci igraci za mikrofonom
+PARTY_ROUND_WHEREAMI=Timska Sledeca Runda
+PARTY_ROUND_LEGEND_CONTINUE=pocni rundu
+
+PARTY_SONG_WHEREAMI=Timski Izbor Pesama
+PARTY_SONG_LEGEND_CONTINUE=povaj
+PARTY_SONG_MENU=timski meni
+
+PARTY_SCORE_DESC=rezultat poslednje runde
+PARTY_SCORE_WHEREAMI=Timski Poeni
+
+PARTY_WIN_DESC=pobednik timske igre
+PARTY_WIN_WHEREAMI=Timski Pobednik
+PARTY_WIN_LEGEND_CONTINUE=nazad u glavni meni
+
+PARTY_ROUND=Runda
+PARTY_ROUND_WINNER=Pobednik
+PARTY_NOTPLAYEDYET=nije jos igrao
+PARTY_NOBODY=niko
+NEXT_ROUND=Sledeca runda:
+
+PARTY_DISMISSED=Otpusten!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=Pobedio!
+
+PLUGIN_HDL_NAME=Drzi liniju
+PLUGIN_HDL_DESC=Ne budi losiji nego sto ti strelica pokazuje.
+
+PLUGIN_UNTIL5000_NAME=Do 5000
+PLUGIN_UNTIL5000_DESC=Ko stigne prvi do 5000 poena pobedjuje.
+
+PLUGIN_DUELL_NAME=Duel
+PLUGIN_DUELL_DESC=Pevaj duel do 10000 poena.
+
+PLUGIN_BLIND_NAME=Slepi Mod
+PLUGIN_BLIND_DESC=Duel bez gledanja nota.
+
+STAT_MAIN=Statistike
+STAT_MAIN_DESC=Generalne
+STAT_MAIN_WHEREAMI=Statistike
+
+STAT_OVERVIEW_INTRO=%0:s Statistike. \n Poslednji reset bio je %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Pesme(%3:d sa Videom), gde su %1:d vec igrane i %2:d nisu jos igrane.\n Najpopularnija pesma je %5:s sa %4:s.
+STAT_OVERVIEW_PLAYER=Od poslednjeg reseta bilo je %0:d razlicitih igraca.\n Najbolji igrac je %1:s sa prosecnim rezultatom od %2:d poena.\n %3:s je imao najveci rezultat sa %4:d poena.
+
+STAT_DETAIL=Statistike
+STAT_DETAIL_WHEREAMI=Detalji Statistike
+
+STAT_NEXT=Sledeca Strana
+STAT_PREV=Prethodna Strana
+STAT_REVERSE=Obrnuti Redosled
+STAT_PAGE=Seite %0:d of %1:d strana\n (%2:d od %3:d unosa)
+
+STAT_DESC_SCORES=NajboljiRezultati
+STAT_DESC_SCORES_REVERSED=NajgoriRezultati
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Najbolji Pevaci
+STAT_DESC_SINGERS_REVERSED=Najgori Pevaci
+STAT_FORMAT_SINGERS=%0:s \n Prosecan Rezultat: %1:d
+
+STAT_DESC_SONGS=Najpopularnije Pesme
+STAT_DESC_SONGS_REVERSED=Najmanje Popularne Pesme
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx pevano
+
+STAT_DESC_BANDS=Najpopularniji Bendovi
+STAT_DESC_BANDS_REVERSED=Najmanje Popularni Bendovi
+STAT_FORMAT_BANDS=%0:s \n %1:dx Pevano
+
+MSG_ERROR_TITLE=Greska
+MSG_QUESTION_TITLE=Pitanje
+MSG_QUIT_USDX=Stvarno napustate UltraStar?
+MSG_END_PARTY=Stvarno napustate Timski Mod?
+ERROR_NO_SONGS=Nema ucitanih pesama
+ERROR_NO_PLUGINS=Nema ucitanih plugin-ova
ERROR_CORRUPT_SONG=Pesma se ne moze ucitati. \ No newline at end of file
diff --git a/game/languages/old/Slovak.ini b/game/languages/old/Slovak.ini
index 2e7ae87b..c7a7fb2e 100644
--- a/game/languages/old/Slovak.ini
+++ b/game/languages/old/Slovak.ini
@@ -1,301 +1,301 @@
-[Text]
-SING_LOADING=... nahráva sa hra !
-
-SING_CHOOSE_MODE=vyberte si z možností
-SING_SING=Hra
-SING_SING_DESC=sólo alebo duet
-
-SING_MULTI=Párty
-SING_MULTI_DESC=párty-mód
-
-SING_TOOLS=Nástroje
-
-SING_STATS=štatistika
-SING_STATS_DESC=zobrazi štatistiku
-
-SING_EDITOR=editor
-SING_EDITOR_DESC=vytvorte si vlastnú skladbu
-
-SING_GAME_OPTIONS=nastavenia
-SING_GAME_OPTIONS_DESC=nastavenia hry
-
-SING_EXIT=Koniec
-SING_EXIT_DESC=návrat do systému
-
-SING_OPTIONS=nastavenia
-SING_OPTIONS_DESC=zmeni nastavenia
-SING_OPTIONS_WHEREAMI=Nastavenia
-
-SING_OPTIONS_GAME=hra
-SING_OPTIONS_GRAPHICS=grafika
-SING_OPTIONS_SOUND=zvuk
-SING_OPTIONS_LYRICS=text
-SING_OPTIONS_THEMES=témy
-SING_OPTIONS_RECORD=mikrofón
-SING_OPTIONS_ADVANCED=iné
-SING_OPTIONS_EXIT=spä
-
-SING_OPTIONS_GAME_WHEREAMI=Nastavenia hry
-SING_OPTIONS_GAME_DESC=všeobecné nastavenia
-SING_OPTIONS_GAME_PLAYERS=Poèet hráèov
-SING_OPTIONS_GAME_DIFFICULTY=Obtiažnos
-SING_OPTIONS_GAME_LANGUAGE=Jazyk
-SING_OPTIONS_GAME_TABS=Kategórie
-SING_OPTIONS_GAME_SORTING=Zoradenie
-SING_OPTIONS_GAME_DEBUG=Debug mód
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Grafika
-SING_OPTIONS_GRAPHICS_DESC=nastavenie grafických detailov
-SING_OPTIONS_GRAPHICS_RESOLUTION=Rozlíšenie
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Celá obrazovka
-SING_OPTIONS_GRAPHICS_DEPTH=Far. håbka
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Èiarový Bonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Zobrazenie videa
-
-SING_OPTIONS_SOUND_WHEREAMI=Zvuk
-SING_OPTIONS_SOUND_DESC=nastavenie zvuku
-SING_OPTIONS_SOUND_MIC_BOOST=Zosilnenie mikrof.
-SING_OPTIONS_SOUND_CLICK_ASSIST=Pomocný klik
-SING_OPTIONS_SOUND_BEAT_CLICK=Rytmický klik
-SING_OPTIONS_SOUND_THRESHOLD=Prah poèute¾.
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mód dvoch hráèov
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Náh¾ad(volume)
-SING_OPTIONS_SOUND_PREVIEWFADING=Prechod skladieb
-
-SING_OPTIONS_LYRICS_WHEREAMI=Text
-SING_OPTIONS_LYRICS_DESC=nastavenia zobrazovania textov piesní
-SING_OPTIONS_LYRICS_FONT=Písmo
-SING_OPTIONS_LYRICS_EFFECT=Efekt zvýraznenia
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmizácia
-
-SING_OPTIONS_THEMES_WHEREAMI=Témy
-SING_OPTIONS_THEMES_DESC=zmena témy
-SING_OPTIONS_THEMES_THEME=Téma
-SING_OPTIONS_THEMES_SKIN=Vzh¾ad
-SING_OPTIONS_THEMES_COLOR=Farba
-
-SING_OPTIONS_RECORD_WHEREAMI=Mikrofón
-SING_OPTIONS_RECORD_DESC=nastavenie mikrofónu
-SING_OPTIONS_RECORD_CARD=Zvuková karta
-SING_OPTIONS_RECORD_INPUT=Vstup
-SING_OPTIONS_RECORD_CHANNEL=Kanál
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Iné
-SING_OPTIONS_ADVANCED_DESC=rozširujúce nastavenia
-SING_OPTIONS_ADVANCED_EFFECTSING=Efekty pri speve
-SING_OPTIONS_ADVANCED_SCREENFADE=Jemný prechod
-SING_OPTIONS_ADVANCED_LOADANIMATION=Animácia loading(u)
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Potvrdzovanie
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus za riadok
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Po zvolení skladby
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto PartyMenu
-
-SING_LEGEND_SELECT=výber
-SING_LEGEND_NAVIGATE=navigácia
-SING_LEGEND_CONTINUE=pokraèova
-SING_LEGEND_ESC=spä
-
-SING_PLAYER_DESC=zadajte meno hráèa(ov)
-SING_PLAYER_WHEREAMI=Mená hráèov
-SING_PLAYER_ENTER_NAME=zadávanie mena
-
-SING_DIFFICULTY_DESC=Vyberte obtiažnos
-SING_DIFFICULTY_WHEREAMI=Obtiažnos
-SING_DIFFICULTY_CONTINUE=pokraèova
-SING_EASY=¼ahká
-SING_MEDIUM=Stredná
-SING_HARD=ažká
-
-SING_SONG_SELECTION_DESC=Vyberte skladbu
-SING_SONG_SELECTION_WHEREAMI=výber skladby
-SING_SONG_SELECTION_GOTO=choï na ..
-SING_SONG_SELECTION=výber skladby
-SING_SONG_SELECTION_MENU=menu
-SING_SONG_SELECTION_PLAYLIST=playlist
-SING_SONGS_IN_CAT=Skladba
-PLAYLIST_CATTEXT=Playlist: %s
-
-SING_TIME=Èas
-SING_TOTAL=celkovo
-SING_MODE=spieva sólo
-SING_NOTES=noty
-SING_GOLDEN_NOTES=zlaté noty
-SING_PHRASE_BONUS=bonus za riadok
-
-SING_MENU=Hlavné Menu
-
-SONG_SCORE=hodnotenie
-SONG_SCORE_WHEREAMI=Skóre
-
-SING_SCORE_TONE_DEAF=Antitalent
-SING_SCORE_AMATEUR=Amatér
-SING_SCORE_RISING_STAR=Vychádzajúca hviezda
-SING_SCORE_LEAD_SINGER=Spevák
-SING_SCORE_HIT_ARTIST=Star
-SING_SCORE_SUPERSTAR=Superstar
-SING_SCORE_ULTRASTAR=Ultrastar
-
-SING_TOP_5_CHARTS=najlepších 5
-SING_TOP_5_CHARTS_WHEREAMI=top 5
-SING_TOP_5_CHARTS_CONTINUE=pre výber skladby
-
-POPUP_PERFECT=neskutoèné!
-POPUP_AWESOME=paráda!
-POPUP_GREAT=super!
-POPUP_GOOD=dobré!
-POPUP_NOTBAD=nie zlé!
-POPUP_BAD=zle!
-POPUP_POOR=bieda!
-POPUP_AWFUL=otrasné!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= a
-
-SONG_MENU_NAME_MAIN=Výber hudby
-SONG_MENU_PLAY=Štart
-SONG_MENU_CHANGEPLAYERS=Iný hráè
-SONG_MENU_EDIT=Uprav
-SONG_MENU_MODI=Sing a Modi
-SONG_MENU_CANCEL=Zruši
-
-SONG_MENU_NAME_PLAYLIST=Skladby
-SONG_MENU_PLAYLIST_ADD=Pridaj skladbu
-SONG_MENU_PLAYLIST_DEL=Zmaž skladbu
-
-SONG_MENU_NAME_PLAYLIST_ADD=Pridaj Skladbu
-SONG_MENU_PLAYLIST_ADD_NEW=do nového playlistu
-SONG_MENU_PLAYLIST_ADD_EXISTING=do existujúceho playlistu
-SONG_MENU_PLAYLIST_NOEXISTING=Nie je dostupný žiadny playlist
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nový Playlist
-SONG_MENU_PLAYLIST_NEW_CREATE=Vytvor
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Bez mena
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Skutoène Zmaza ?
-SONG_MENU_YES=Áno
-SONG_MENU_NO=Nie
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Naèítaj Playlist
-SONG_MENU_PLAYLIST_LOAD=naèítaj
-SONG_MENU_PLAYLIST_DELCURRENT=zmaž tento Playlist
-
-SONG_MENU_NAME_PLAYLIST_DEL=Zmaza Playlist?
-
-SONG_MENU_NAME_PARTY_MAIN=Party Menu
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=použi jokera
-
-SONG_JUMPTO_DESC=h¾adaj skladbu
-SONG_JUMPTO_TYPE_DESC=h¾adaj:
-SONG_JUMPTO_TYPE1=všade
-SONG_JUMPTO_TYPE2=v názve skladby
-SONG_JUMPTO_TYPE3=v mene autora
-SONG_JUMPTO_SONGSFOUND=%d skladieb vyhovuje filtru
-SONG_JUMPTO_NOSONGSFOUND=Žiadna skladba
-SONG_JUMPTO_HELP=Napíš k¾úèové slovo pre h¾adanie
-SONG_JUMPTO_CATTEXT=H¾adaj: %s
-
-PARTY_MODE=párty mód
-PARTY_DIFFICULTY=Obtiažnos
-PARTY_PLAYLIST=Skladby z playlistu
-PARTY_PLAYLIST_ALL=Všetky skladby
-PARTY_PLAYLIST_CATEGORY=Kategória
-PARTY_PLAYLIST_PLAYLIST=Playlist
-PARTY_ROUNDS=Poèet kôl
-PARTY_TEAMS=Poèet tímov
-PARTY_TEAMS_PLAYER1=Hráèov v Tíme 1
-PARTY_TEAMS_PLAYER2=Hráèov v Tíme 2
-PARTY_TEAMS_PLAYER3=Hráèov v Tíme 3
-
-PARTY_LEGEND_CONTINUE=pokraèova
-
-PARTY_OPTIONS_DESC=nastavenia pre párty-mód
-PARTY_OPTIONS_WHEREAMI=Párty nastavenia
-
-PARTY_PLAYER_DESC=Zadajte mená tímov a hráèov!
-PARTY_PLAYER_WHEREAMI=Párty mená
-PARTY_PLAYER_ENTER_NAME=zadajte mená
-PARTY_PLAYER_LEGEND_CONTINUE=Pokraèova
-
-PARTY_ROUND_DESC=párty pre hráèov
-PARTY_ROUND_WHEREAMI=List párty disciplín
-PARTY_ROUND_LEGEND_CONTINUE=Štart disciplíny
-
-PARTY_SONG_WHEREAMI=Párty - Výver Skladby
-PARTY_SONG_LEGEND_CONTINUE=Štart
-PARTY_SONG_MENU=party menu
-
-PARTY_SCORE_DESC=skóre posledného kola
-PARTY_SCORE_WHEREAMI=Párty skóre
-
-PARTY_WIN_DESC=Víaz párty
-PARTY_WIN_WHEREAMI=Stupeò víazov
-PARTY_WIN_LEGEND_CONTINUE=spä do hlavného menu
-
-PARTY_ROUND=Kolo
-PARTY_ROUND_WINNER=Víaz
-PARTY_NOTPLAYEDYET=nehralo
-PARTY_NOBODY=ani jedno družstvo
-NEXT_ROUND=Ïalšie kolo:
-
-PARTY_DISMISSED=Ukonèené !
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=víaz tohto kola
-
-PLUGIN_HDL_NAME=Superstar
-PLUGIN_HDL_DESC=nesmieš klesnú pod hranicu ukazovate¾a úspešnosti
-
-PLUGIN_UNTIL5000_NAME=Po 5000
-PLUGIN_UNTIL5000_DESC=kto prvý získa 5000 bodov sa stane víazom
-
-PLUGIN_DUELL_NAME=Duel
-PLUGIN_DUELL_DESC=spievaj, kým nedosiahneš 10000 bodov
-
-PLUGIN_TEAMDUELL_NAME=Duel Tímov
-PLUGIN_TEAMDUELL_DESC=každý hráè sa vystrieda za mikrofónom
-
-PLUGIN_BLIND_NAME=Slepý
-PLUGIN_BLIND_DESC=neuvidíš noty pre hlas
-
-STAT_MAIN=Štatistika
-STAT_MAIN_DESC=Všeobecne
-STAT_MAIN_WHEREAMI=Štatistiky
-
-STAT_OVERVIEW_INTRO=%0:s štatistika \n Štatistika od %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=SKLADBY \n Celkove: %0:d z toho %3:d s videom\n Poèet už hraných: %1:d \n Poèet nehraných: %2:d \n Najhranejšia skladba: %5:s od %4:s
-STAT_OVERVIEW_PLAYER=HRÁÈI \n Celkove: %0:d rôznych hráèov.\n Najlepší hráè: %1:s (%2:d - priemer bodov)\n Najvyššie skóre: %3:s (%4:d bodov)
-
-STAT_DETAIL=Štatistiky
-STAT_DETAIL_WHEREAMI=Podrobná štatistika
-
-STAT_NEXT=Ïalšia strana
-STAT_PREV=Predošlá strana
-STAT_REVERSE=Otoè poradie
-STAT_PAGE=%0:d. z %1:d strán\n (%2:d z %3:d položiek)
-
-STAT_DESC_SCORES=Najvyššie skóre
-STAT_DESC_SCORES_REVERSED=Najhoršie skóre
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Najlepší speváci
-STAT_DESC_SINGERS_REVERSED=Najhorší speváci
-STAT_FORMAT_SINGERS=%0:s \n Priemer skóre: %1:d
-
-STAT_DESC_SONGS=Najhranejšie skladby
-STAT_DESC_SONGS_REVERSED=Najmenej hrané skladby
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx spievaná
-
-STAT_DESC_BANDS=Najhranejšia kapela
-STAT_DESC_BANDS_REVERSED=Najmenej hraná kapela
-STAT_FORMAT_BANDS=%0:s \n %1:dx spievaná
-
-MSG_ERROR_TITLE=Chyba
-MSG_QUESTION_TITLE=Otázka
-MSG_QUIT_USDX=Skutoène chcete skonèi UltraStar?
-MSG_END_PARTY=Skutoène chcete skonèit Párty Mód ?
-ERROR_NO_SONGS=Žiadna skladba
-ERROR_NO_PLUGINS=Žiadny zásuvný modul
-ERROR_CORRUPT_SONG=Skladbu sa nepodarilo nahra.
+[Text]
+SING_LOADING=... nahráva sa hra !
+
+SING_CHOOSE_MODE=vyberte si z možností
+SING_SING=Hra
+SING_SING_DESC=sólo alebo duet
+
+SING_MULTI=Párty
+SING_MULTI_DESC=párty-mód
+
+SING_TOOLS=Nástroje
+
+SING_STATS=štatistika
+SING_STATS_DESC=zobrazi štatistiku
+
+SING_EDITOR=editor
+SING_EDITOR_DESC=vytvorte si vlastnú skladbu
+
+SING_GAME_OPTIONS=nastavenia
+SING_GAME_OPTIONS_DESC=nastavenia hry
+
+SING_EXIT=Koniec
+SING_EXIT_DESC=návrat do systému
+
+SING_OPTIONS=nastavenia
+SING_OPTIONS_DESC=zmeni nastavenia
+SING_OPTIONS_WHEREAMI=Nastavenia
+
+SING_OPTIONS_GAME=hra
+SING_OPTIONS_GRAPHICS=grafika
+SING_OPTIONS_SOUND=zvuk
+SING_OPTIONS_LYRICS=text
+SING_OPTIONS_THEMES=témy
+SING_OPTIONS_RECORD=mikrofón
+SING_OPTIONS_ADVANCED=iné
+SING_OPTIONS_EXIT=spä
+
+SING_OPTIONS_GAME_WHEREAMI=Nastavenia hry
+SING_OPTIONS_GAME_DESC=všeobecné nastavenia
+SING_OPTIONS_GAME_PLAYERS=Poèet hráèov
+SING_OPTIONS_GAME_DIFFICULTY=Obtiažnos
+SING_OPTIONS_GAME_LANGUAGE=Jazyk
+SING_OPTIONS_GAME_TABS=Kategórie
+SING_OPTIONS_GAME_SORTING=Zoradenie
+SING_OPTIONS_GAME_DEBUG=Debug mód
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Grafika
+SING_OPTIONS_GRAPHICS_DESC=nastavenie grafických detailov
+SING_OPTIONS_GRAPHICS_RESOLUTION=Rozlíšenie
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Celá obrazovka
+SING_OPTIONS_GRAPHICS_DEPTH=Far. håbka
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Èiarový Bonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Zobrazenie videa
+
+SING_OPTIONS_SOUND_WHEREAMI=Zvuk
+SING_OPTIONS_SOUND_DESC=nastavenie zvuku
+SING_OPTIONS_SOUND_MIC_BOOST=Zosilnenie mikrof.
+SING_OPTIONS_SOUND_CLICK_ASSIST=Pomocný klik
+SING_OPTIONS_SOUND_BEAT_CLICK=Rytmický klik
+SING_OPTIONS_SOUND_THRESHOLD=Prah poèute¾.
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Mód dvoch hráèov
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Náh¾ad(volume)
+SING_OPTIONS_SOUND_PREVIEWFADING=Prechod skladieb
+
+SING_OPTIONS_LYRICS_WHEREAMI=Text
+SING_OPTIONS_LYRICS_DESC=nastavenia zobrazovania textov piesní
+SING_OPTIONS_LYRICS_FONT=Písmo
+SING_OPTIONS_LYRICS_EFFECT=Efekt zvýraznenia
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmizácia
+
+SING_OPTIONS_THEMES_WHEREAMI=Témy
+SING_OPTIONS_THEMES_DESC=zmena témy
+SING_OPTIONS_THEMES_THEME=Téma
+SING_OPTIONS_THEMES_SKIN=Vzh¾ad
+SING_OPTIONS_THEMES_COLOR=Farba
+
+SING_OPTIONS_RECORD_WHEREAMI=Mikrofón
+SING_OPTIONS_RECORD_DESC=nastavenie mikrofónu
+SING_OPTIONS_RECORD_CARD=Zvuková karta
+SING_OPTIONS_RECORD_INPUT=Vstup
+SING_OPTIONS_RECORD_CHANNEL=Kanál
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Iné
+SING_OPTIONS_ADVANCED_DESC=rozširujúce nastavenia
+SING_OPTIONS_ADVANCED_EFFECTSING=Efekty pri speve
+SING_OPTIONS_ADVANCED_SCREENFADE=Jemný prechod
+SING_OPTIONS_ADVANCED_LOADANIMATION=Animácia loading(u)
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Potvrdzovanie
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus za riadok
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Po zvolení skladby
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Auto PartyMenu
+
+SING_LEGEND_SELECT=výber
+SING_LEGEND_NAVIGATE=navigácia
+SING_LEGEND_CONTINUE=pokraèova
+SING_LEGEND_ESC=spä
+
+SING_PLAYER_DESC=zadajte meno hráèa(ov)
+SING_PLAYER_WHEREAMI=Mená hráèov
+SING_PLAYER_ENTER_NAME=zadávanie mena
+
+SING_DIFFICULTY_DESC=Vyberte obtiažnos
+SING_DIFFICULTY_WHEREAMI=Obtiažnos
+SING_DIFFICULTY_CONTINUE=pokraèova
+SING_EASY=¼ahká
+SING_MEDIUM=Stredná
+SING_HARD=ažká
+
+SING_SONG_SELECTION_DESC=Vyberte skladbu
+SING_SONG_SELECTION_WHEREAMI=výber skladby
+SING_SONG_SELECTION_GOTO=choï na ..
+SING_SONG_SELECTION=výber skladby
+SING_SONG_SELECTION_MENU=menu
+SING_SONG_SELECTION_PLAYLIST=playlist
+SING_SONGS_IN_CAT=Skladba
+PLAYLIST_CATTEXT=Playlist: %s
+
+SING_TIME=Èas
+SING_TOTAL=celkovo
+SING_MODE=spieva sólo
+SING_NOTES=noty
+SING_GOLDEN_NOTES=zlaté noty
+SING_PHRASE_BONUS=bonus za riadok
+
+SING_MENU=Hlavné Menu
+
+SONG_SCORE=hodnotenie
+SONG_SCORE_WHEREAMI=Skóre
+
+SING_SCORE_TONE_DEAF=Antitalent
+SING_SCORE_AMATEUR=Amatér
+SING_SCORE_RISING_STAR=Vychádzajúca hviezda
+SING_SCORE_LEAD_SINGER=Spevák
+SING_SCORE_HIT_ARTIST=Star
+SING_SCORE_SUPERSTAR=Superstar
+SING_SCORE_ULTRASTAR=Ultrastar
+
+SING_TOP_5_CHARTS=najlepších 5
+SING_TOP_5_CHARTS_WHEREAMI=top 5
+SING_TOP_5_CHARTS_CONTINUE=pre výber skladby
+
+POPUP_PERFECT=neskutoèné!
+POPUP_AWESOME=paráda!
+POPUP_GREAT=super!
+POPUP_GOOD=dobré!
+POPUP_NOTBAD=nie zlé!
+POPUP_BAD=zle!
+POPUP_POOR=bieda!
+POPUP_AWFUL=otrasné!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= a
+
+SONG_MENU_NAME_MAIN=Výber hudby
+SONG_MENU_PLAY=Štart
+SONG_MENU_CHANGEPLAYERS=Iný hráè
+SONG_MENU_EDIT=Uprav
+SONG_MENU_MODI=Sing a Modi
+SONG_MENU_CANCEL=Zruši
+
+SONG_MENU_NAME_PLAYLIST=Skladby
+SONG_MENU_PLAYLIST_ADD=Pridaj skladbu
+SONG_MENU_PLAYLIST_DEL=Zmaž skladbu
+
+SONG_MENU_NAME_PLAYLIST_ADD=Pridaj Skladbu
+SONG_MENU_PLAYLIST_ADD_NEW=do nového playlistu
+SONG_MENU_PLAYLIST_ADD_EXISTING=do existujúceho playlistu
+SONG_MENU_PLAYLIST_NOEXISTING=Nie je dostupný žiadny playlist
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nový Playlist
+SONG_MENU_PLAYLIST_NEW_CREATE=Vytvor
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Bez mena
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Skutoène Zmaza ?
+SONG_MENU_YES=Áno
+SONG_MENU_NO=Nie
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Naèítaj Playlist
+SONG_MENU_PLAYLIST_LOAD=naèítaj
+SONG_MENU_PLAYLIST_DELCURRENT=zmaž tento Playlist
+
+SONG_MENU_NAME_PLAYLIST_DEL=Zmaza Playlist?
+
+SONG_MENU_NAME_PARTY_MAIN=Party Menu
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=použi jokera
+
+SONG_JUMPTO_DESC=h¾adaj skladbu
+SONG_JUMPTO_TYPE_DESC=h¾adaj:
+SONG_JUMPTO_TYPE1=všade
+SONG_JUMPTO_TYPE2=v názve skladby
+SONG_JUMPTO_TYPE3=v mene autora
+SONG_JUMPTO_SONGSFOUND=%d skladieb vyhovuje filtru
+SONG_JUMPTO_NOSONGSFOUND=Žiadna skladba
+SONG_JUMPTO_HELP=Napíš k¾úèové slovo pre h¾adanie
+SONG_JUMPTO_CATTEXT=H¾adaj: %s
+
+PARTY_MODE=párty mód
+PARTY_DIFFICULTY=Obtiažnos
+PARTY_PLAYLIST=Skladby z playlistu
+PARTY_PLAYLIST_ALL=Všetky skladby
+PARTY_PLAYLIST_CATEGORY=Kategória
+PARTY_PLAYLIST_PLAYLIST=Playlist
+PARTY_ROUNDS=Poèet kôl
+PARTY_TEAMS=Poèet tímov
+PARTY_TEAMS_PLAYER1=Hráèov v Tíme 1
+PARTY_TEAMS_PLAYER2=Hráèov v Tíme 2
+PARTY_TEAMS_PLAYER3=Hráèov v Tíme 3
+
+PARTY_LEGEND_CONTINUE=pokraèova
+
+PARTY_OPTIONS_DESC=nastavenia pre párty-mód
+PARTY_OPTIONS_WHEREAMI=Párty nastavenia
+
+PARTY_PLAYER_DESC=Zadajte mená tímov a hráèov!
+PARTY_PLAYER_WHEREAMI=Párty mená
+PARTY_PLAYER_ENTER_NAME=zadajte mená
+PARTY_PLAYER_LEGEND_CONTINUE=Pokraèova
+
+PARTY_ROUND_DESC=párty pre hráèov
+PARTY_ROUND_WHEREAMI=List párty disciplín
+PARTY_ROUND_LEGEND_CONTINUE=Štart disciplíny
+
+PARTY_SONG_WHEREAMI=Párty - Výver Skladby
+PARTY_SONG_LEGEND_CONTINUE=Štart
+PARTY_SONG_MENU=party menu
+
+PARTY_SCORE_DESC=skóre posledného kola
+PARTY_SCORE_WHEREAMI=Párty skóre
+
+PARTY_WIN_DESC=Víaz párty
+PARTY_WIN_WHEREAMI=Stupeò víazov
+PARTY_WIN_LEGEND_CONTINUE=spä do hlavného menu
+
+PARTY_ROUND=Kolo
+PARTY_ROUND_WINNER=Víaz
+PARTY_NOTPLAYEDYET=nehralo
+PARTY_NOBODY=ani jedno družstvo
+NEXT_ROUND=Ïalšie kolo:
+
+PARTY_DISMISSED=Ukonèené !
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=víaz tohto kola
+
+PLUGIN_HDL_NAME=Superstar
+PLUGIN_HDL_DESC=nesmieš klesnú pod hranicu ukazovate¾a úspešnosti
+
+PLUGIN_UNTIL5000_NAME=Po 5000
+PLUGIN_UNTIL5000_DESC=kto prvý získa 5000 bodov sa stane víazom
+
+PLUGIN_DUELL_NAME=Duel
+PLUGIN_DUELL_DESC=spievaj, kým nedosiahneš 10000 bodov
+
+PLUGIN_TEAMDUELL_NAME=Duel Tímov
+PLUGIN_TEAMDUELL_DESC=každý hráè sa vystrieda za mikrofónom
+
+PLUGIN_BLIND_NAME=Slepý
+PLUGIN_BLIND_DESC=neuvidíš noty pre hlas
+
+STAT_MAIN=Štatistika
+STAT_MAIN_DESC=Všeobecne
+STAT_MAIN_WHEREAMI=Štatistiky
+
+STAT_OVERVIEW_INTRO=%0:s štatistika \n Štatistika od %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=SKLADBY \n Celkove: %0:d z toho %3:d s videom\n Poèet už hraných: %1:d \n Poèet nehraných: %2:d \n Najhranejšia skladba: %5:s od %4:s
+STAT_OVERVIEW_PLAYER=HRÁÈI \n Celkove: %0:d rôznych hráèov.\n Najlepší hráè: %1:s (%2:d - priemer bodov)\n Najvyššie skóre: %3:s (%4:d bodov)
+
+STAT_DETAIL=Štatistiky
+STAT_DETAIL_WHEREAMI=Podrobná štatistika
+
+STAT_NEXT=Ïalšia strana
+STAT_PREV=Predošlá strana
+STAT_REVERSE=Otoè poradie
+STAT_PAGE=%0:d. z %1:d strán\n (%2:d z %3:d položiek)
+
+STAT_DESC_SCORES=Najvyššie skóre
+STAT_DESC_SCORES_REVERSED=Najhoršie skóre
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Najlepší speváci
+STAT_DESC_SINGERS_REVERSED=Najhorší speváci
+STAT_FORMAT_SINGERS=%0:s \n Priemer skóre: %1:d
+
+STAT_DESC_SONGS=Najhranejšie skladby
+STAT_DESC_SONGS_REVERSED=Najmenej hrané skladby
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx spievaná
+
+STAT_DESC_BANDS=Najhranejšia kapela
+STAT_DESC_BANDS_REVERSED=Najmenej hraná kapela
+STAT_FORMAT_BANDS=%0:s \n %1:dx spievaná
+
+MSG_ERROR_TITLE=Chyba
+MSG_QUESTION_TITLE=Otázka
+MSG_QUIT_USDX=Skutoène chcete skonèi UltraStar?
+MSG_END_PARTY=Skutoène chcete skonèit Párty Mód ?
+ERROR_NO_SONGS=Žiadna skladba
+ERROR_NO_PLUGINS=Žiadny zásuvný modul
+ERROR_CORRUPT_SONG=Skladbu sa nepodarilo nahra.
diff --git a/game/languages/old/Slovenian.ini b/game/languages/old/Slovenian.ini
index b1a76d4f..2fd50c9d 100644
--- a/game/languages/old/Slovenian.ini
+++ b/game/languages/old/Slovenian.ini
@@ -1,322 +1,322 @@
-[Text]
-SING_LOADING=Nalaganje...
-
-SING_CHOOSE_MODE=izberi nacin
-SING_SING=poj
-SING_SING_DESC=poj sam ali v duetu
-
-SING_MULTI=zabava
-SING_MULTI_DESC=poj v nacinu zabave
-
-SING_TOOLS=orodja
-
-SING_STATS=statistika
-SING_STATS_DESC=poglej statistiko
-
-SING_EDITOR=urednik
-SING_EDITOR_DESC=izdelaj svoje pesmi
-
-SING_GAME_OPTIONS=nastavitve igre
-SING_GAME_OPTIONS_DESC=spremeni nastavitve igre
-
-SING_EXIT=izhod
-SING_EXIT_DESC=izhod iz igre
-
-SING_OPTIONS=nastavitve
-SING_OPTIONS_DESC=spremeni nastavitve
-SING_OPTIONS_WHEREAMI=Nastavitve
-
-SING_OPTIONS_GAME=igra
-SING_OPTIONS_GRAPHICS=izgled
-SING_OPTIONS_SOUND=zvok
-SING_OPTIONS_LYRICS=besedilo
-SING_OPTIONS_THEMES=tema
-SING_OPTIONS_RECORD=snemanje
-SING_OPTIONS_ADVANCED=napredno
-SING_OPTIONS_EXIT=nazaj
-
-SING_OPTIONS_GAME_WHEREAMI=Nastavitve Igre
-SING_OPTIONS_GAME_DESC=osnovne nastavitve
-SING_OPTIONS_GAME_PLAYERS=Igralci
-SING_OPTIONS_GAME_DIFFICULTY=Težavnost
-SING_OPTIONS_GAME_LANGUAGE=Jezik
-SING_OPTIONS_GAME_TABS=Mape
-SING_OPTIONS_GAME_SORTING=Sortiranje
-SING_OPTIONS_GAME_DEBUG=Odpravljanje hrošcev
-
-SING_OPTIONS_GRAPHICS_WHEREAMI=Nastavitve prikaza
-SING_OPTIONS_GRAPHICS_DESC=nastavitve prikaza
-SING_OPTIONS_GRAPHICS_RESOLUTION=Locljivost
-SING_OPTIONS_GRAPHICS_FULLSCREEN=Celozaslonski nacin
-SING_OPTIONS_GRAPHICS_DEPTH=Globina
-SING_OPTIONS_GRAPHICS_VISUALIZER=Vizualizacija
-SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
-SING_OPTIONS_GRAPHICS_LINEBONUS=Vrsticni bonus
-SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Velikost videa
-
-SING_OPTIONS_SOUND_WHEREAMI=Nastavitve zvoka
-SING_OPTIONS_SOUND_DESC=nastavitve zvoka
-SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Mikrofonski Playback
-SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Glasbena podlaga
-SING_OPTIONS_SOUND_MIC_BOOST=Ojacitev mikrofona
-SING_OPTIONS_SOUND_CLICK_ASSIST=Asistent klikanja
-SING_OPTIONS_SOUND_BEAT_CLICK=Klikanje po ritmu
-SING_OPTIONS_SOUND_THRESHOLD=Prag
-SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Nacin za dva igralca
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Glasnost predogleda
-SING_OPTIONS_SOUND_PREVIEWFADING=narašcanje glasnosti
-
-SING_OPTIONS_LYRICS_WHEREAMI=Nastavitve besedila
-SING_OPTIONS_LYRICS_DESC=nastavitve besedila
-SING_OPTIONS_LYRICS_FONT=Pisava
-SING_OPTIONS_LYRICS_EFFECT=Ucinek
-SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacija
-SING_OPTIONS_LYRICS_NOTELINES=Notno crtovje
-
-SING_OPTIONS_THEMES_WHEREAMI=Nastavitve tem
-SING_OPTIONS_THEMES_DESC=nastavitve teme
-SING_OPTIONS_THEMES_THEME=Tema
-SING_OPTIONS_THEMES_SKIN=Izgled
-SING_OPTIONS_THEMES_COLOR=Barva
-
-SING_OPTIONS_RECORD_WHEREAMI=Nastavitve snemanja
-SING_OPTIONS_RECORD_DESC=nastavitve mikrofona
-SING_OPTIONS_RECORD_CARD=Vir zvoka
-SING_OPTIONS_RECORD_INPUT=Vhod
-SING_OPTIONS_RECORD_CHANNEL=Kanal
-
-SING_OPTIONS_ADVANCED_WHEREAMI=Napredne nastavitve
-SING_OPTIONS_ADVANCED_DESC=Napredne nastavitve
-SING_OPTIONS_ADVANCED_EFFECTSING=Pevski efekt
-SING_OPTIONS_ADVANCED_SCREENFADE=Zamegljevanje prikaza
-SING_OPTIONS_ADVANCED_LOADANIMATION=Zacetna animacija
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Zašcitno vprašanje
-SING_OPTIONS_ADVANCED_LINEBONUS=Bonus za vrstico
-SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
-SING_OPTIONS_ADVANCED_ONSONGCLICK=Po izboru pesmi
-SING_OPTIONS_ADVANCED_PARTYPOPUP=Samodejni nacin Zabava
-
-SING_EDIT=Urednik
-SING_EDIT_MENU_DESCRIPTION=Izdelaj lastno pesem
-
-SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Izvozi besedilo iz midi datoteke
-SING_EDIT_BUTTON_DESCRIPTION_EXIT=Nazaj
-SING_EDIT_BUTTON_CONVERT=Uvozi
-SING_EDIT_BUTTON_EXIT=Nazaj
-
-SING_EDIT_NAVIGATE=Navigacija
-SING_EDIT_SELECT=Izberi
-SING_EDIT_EXIT=Nazaj
-
-SING_LEGEND_SELECT=izberi
-SING_LEGEND_NAVIGATE=premik
-SING_LEGEND_CONTINUE=nadaljuj
-SING_LEGEND_ESC=nazaj
-
-SING_PLAYER_DESC=vpiši imena igralcev
-SING_PLAYER_WHEREAMI=Imena igralcev
-SING_PLAYER_ENTER_NAME=vnesi ime
-
-SING_DIFFICULTY_DESC=izberi težavnost
-SING_DIFFICULTY_WHEREAMI=Težavnost
-SING_DIFFICULTY_CONTINUE=k izbiri pesmi
-SING_EASY=Enostavno
-SING_MEDIUM=Srednje
-SING_HARD=Težko
-
-SING_SONG_SELECTION_DESC=izberi svojo pesem
-SING_SONG_SELECTION_WHEREAMI=Izbira pesmi
-SING_SONG_SELECTION_GOTO=pojdi na...
-SING_SONG_SELECTION=izbira pesmi
-SING_SONG_SELECTION_MENU=meni
-SING_SONG_SELECTION_PLAYLIST=seznam predvajanja
-SING_SONGS_IN_CAT=Pesmi
-PLAYLIST_CATTEXT=Lista: %s
-
-SING_TIME=CAS
-SING_TOTAL=skupaj
-SING_MODE=Petje
-SING_NOTES=note
-SING_GOLDEN_NOTES=zlate note
-SING_PHRASE_BONUS=bonus za vrstico
-
-SING_MENU=Glavni meni
-
-SONG_SCORE=rezultat petja
-SONG_SCORE_WHEREAMI=Rezultat
-
-SING_SCORE_TONE_DEAF=Gluhonem
-SING_SCORE_AMATEUR=Amater
-SING_SCORE_WANNABE=Igralec
-SING_SCORE_HOPEFUL=Nadebudnež
-SING_SCORE_RISING_STAR=Vzhajajoca zvezda
-SING_SCORE_LEAD_SINGER=Vodilni pevec
-SING_SCORE_SUPERSTAR=Superzvezda
-SING_SCORE_ULTRASTAR=Ultrazvezda
-
-SING_TOP_5_CHARTS=najboljših 5 pevcev
-SING_TOP_5_CHARTS_WHEREAMI=najboljših 5
-SING_TOP_5_CHARTS_CONTINUE=k izbiri pesmi
-
-POPUP_PERFECT=popolno!
-POPUP_AWESOME=odlicno!
-POPUP_GREAT=zelo dobro!
-POPUP_GOOD=dobro!
-POPUP_NOTBAD=ni slabo!
-POPUP_BAD=slabo!
-POPUP_POOR=zelo slabo!
-POPUP_AWFUL=obupno!
-
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= in
-
-SONG_MENU_NAME_MAIN=meni pesmi
-SONG_MENU_PLAY=Poj
-SONG_MENU_CHANGEPLAYERS=Spremeni igralca
-SONG_MENU_EDIT=Uredi
-SONG_MENU_MODI=Poj "a Modi"
-SONG_MENU_CANCEL=Preklici
-
-SONG_MENU_NAME_PLAYLIST=Meni Pesem
-SONG_MENU_PLAYLIST_ADD=Dodaj pesem
-SONG_MENU_PLAYLIST_DEL=Izbriši pesem
-
-SONG_MENU_NAME_PLAYLIST_ADD=Dodaj pesem
-SONG_MENU_PLAYLIST_ADD_NEW=dodaj nov seznam
-SONG_MENU_PLAYLIST_ADD_EXISTING=dodaj shranjen seznam
-SONG_MENU_PLAYLIST_NOEXISTING=Ni seznamov
-
-SONG_MENU_NAME_PLAYLIST_NEW=Nov seznam
-SONG_MENU_PLAYLIST_NEW_CREATE=Ustvari
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Neimenovan
-
-SONG_MENU_NAME_PLAYLIST_DELITEM=Res izbrišem?
-SONG_MENU_YES=Da
-SONG_MENU_NO=Ne
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Odpri seznam
-SONG_MENU_PLAYLIST_LOAD=odpri
-SONG_MENU_PLAYLIST_DELCURRENT=izbriši trenuten seznam
-
-SONG_MENU_NAME_PLAYLIST_DEL=Izbrišem seznam?
-
-SONG_MENU_NAME_PARTY_MAIN=Meni Zabava
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=izkoristi jokerja
-
-SONG_JUMPTO_DESC=poišci pesem
-SONG_JUMPTO_TYPE_DESC=Isci po:
-SONG_JUMPTO_TYPE1=Vse
-SONG_JUMPTO_TYPE2=Naslov
-SONG_JUMPTO_TYPE3=Avtor
-SONG_JUMPTO_SONGSFOUND=%d pesmi najdenih
-SONG_JUMPTO_NOSONGSFOUND=Ne najdem
-SONG_JUMPTO_HELP=Vpiši besedilo za iskanje
-SONG_JUMPTO_CATTEXT=Išci po: %s
-
-PARTY_MODE=zabava
-PARTY_DIFFICULTY=Težavnost
-PARTY_PLAYLIST=Izbor
-PARTY_PLAYLIST_ALL=Vse pesmi
-PARTY_PLAYLIST_CATEGORY=Mapa
-PARTY_PLAYLIST_PLAYLIST=Seznam
-PARTY_ROUNDS=Število rund
-PARTY_TEAMS=Ekipe
-PARTY_TEAMS_PLAYER1=Igralec Ekipa1
-PARTY_TEAMS_PLAYER2=Igralec Ekipa2
-PARTY_TEAMS_PLAYER3=Igralec Ekipa3
-
-PARTY_LEGEND_CONTINUE=nadaljuj
-
-PARTY_OPTIONS_DESC=nastavitve za nacin zabave
-PARTY_OPTIONS_WHEREAMI=nastavitve zabave
-
-PARTY_PLAYER_DESC=vpiši igralce in imena ekip!
-PARTY_PLAYER_WHEREAMI=Imena
-PARTY_PLAYER_ENTER_NAME=vpiši imena
-PARTY_PLAYER_LEGEND_CONTINUE=zacni zabavo
-
-PARTY_ROUND_DESC=naslednji igralec k mikrofonu
-PARTY_ROUND_WHEREAMI=Naslednja runda
-PARTY_ROUND_LEGEND_CONTINUE=zacni rundo
-
-PARTY_SONG_WHEREAMI=Izbor pesmi - Zabava
-PARTY_SONG_LEGEND_CONTINUE=poj
-PARTY_SONG_MENU=meni Zabava
-
-PARTY_SCORE_DESC=tocke zadnje runde
-PARTY_SCORE_WHEREAMI=Tocke v zabavi
-
-PARTY_WIN_DESC=Zmagovalec
-PARTY_WIN_WHEREAMI=Zmagovalec
-PARTY_WIN_LEGEND_CONTINUE=nazaj k glavnemu meniju
-
-PARTY_ROUND=Runda
-PARTY_ROUND_WINNER=Zmagovalec
-PARTY_NOTPLAYEDYET=neizvedeno
-PARTY_NOBODY=nobeden
-NEXT_ROUND=Naslednja runda:
-
-PARTY_DISMISSED=Zakljucena!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=zmaga!
-
-PLUGIN_HDL_NAME=Zdrži nivo
-PLUGIN_HDL_DESC=Ne poj slabše, kot kaže kazalnik na števcu za ocenjevanje.
-
-PLUGIN_UNTIL5000_NAME=Do 5000
-PLUGIN_UNTIL5000_DESC=Kdor prvi doseže 5000 tock, zmaga.
-
-PLUGIN_DUELL_NAME=Dvoboj
-PLUGIN_DUELL_DESC=Tekmovanje do 10000 tock.
-
-PLUGIN_TEAMDUELL_NAME=Ekipni dvoboj
-PLUGIN_TEAMDUELL_DESC=Podaj mikrofon!
-
-PLUGIN_BLIND_NAME=Slepi dvoboj
-PLUGIN_BLIND_DESC=Dvoboj brez prikaza not.
-
-STAT_MAIN=Statika
-STAT_MAIN_DESC=Splošno
-STAT_MAIN_WHEREAMI=Statistika
-
-STAT_OVERVIEW_INTRO=%0:s Statistika. \n Nazadnje ponastavljeno %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Pesmi(%3:d z videom), od katerih je bilo %1:d že zapetih in %2:d ne.\n Najbolj priljubljena pesem je %5:s od %4:s.
-STAT_OVERVIEW_PLAYER=Od zadnje ponastavitve statistike je igro igralo %0:d igralcev.\n Najboljši/a je %1:s s povprecnim rezultatom %2:d tock.\n %3:s je dosegel/la najboljši rezultat s %4:d tockami.
-
-STAT_DETAIL=Statistika
-STAT_DETAIL_WHEREAMI=Podrobna statistika
-
-STAT_NEXT=Naslednja stran
-STAT_PREV=Prejšnja stran
-STAT_REVERSE=Obratni vrstni red
-STAT_PAGE=Stran %0:d od %1:d strani\n (%2:d od %3:d zapisov)
-
-STAT_DESC_SCORES=Najboljši rezultati
-STAT_DESC_SCORES_REVERSED=Najslabši rezultati
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Najboljši igralec
-STAT_DESC_SINGERS_REVERSED=Najslabši igralec
-STAT_FORMAT_SINGERS=%0:s \n povprecni rezultat: %1:d
-
-STAT_DESC_SONGS=Najbolj popularne pesmi
-STAT_DESC_SONGS_REVERSED=Najmanj popularne pesmi
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx igrano
-
-STAT_DESC_BANDS=Najbolj popularen izvajalec
-STAT_DESC_BANDS_REVERSED=Najmanj popularen izvajalec
-STAT_FORMAT_BANDS=%0:s \n %1:dx igrano
-
-MSG_ERROR_TITLE=Napaka
-MSG_QUESTION_TITLE=Vprašanje
-MSG_QUIT_USDX=Želite zapustiti Ultrastar?
-MSG_END_PARTY=Koncam zabavo?
-ERROR_NO_SONGS=Ni pesmi: Naloži jih v mapo Songs
-ERROR_NO_PLUGINS=Ni vkljuckov
-ERROR_CORRUPT_SONG=Ne morem naložiti pesmi.
-ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Ne morem naložiti pesmi: Ne najdem datoteke
-ERROR_CORRUPT_SONG_NO_NOTES=Ne morem naloziti pesmi: Ne najdem not.
-ERROR_CORRUPT_SONG_NO_BREAKS=Ne morem naložiti pesmi: Ne najdem prelomov vrstic.
+[Text]
+SING_LOADING=Nalaganje...
+
+SING_CHOOSE_MODE=izberi nacin
+SING_SING=poj
+SING_SING_DESC=poj sam ali v duetu
+
+SING_MULTI=zabava
+SING_MULTI_DESC=poj v nacinu zabave
+
+SING_TOOLS=orodja
+
+SING_STATS=statistika
+SING_STATS_DESC=poglej statistiko
+
+SING_EDITOR=urednik
+SING_EDITOR_DESC=izdelaj svoje pesmi
+
+SING_GAME_OPTIONS=nastavitve igre
+SING_GAME_OPTIONS_DESC=spremeni nastavitve igre
+
+SING_EXIT=izhod
+SING_EXIT_DESC=izhod iz igre
+
+SING_OPTIONS=nastavitve
+SING_OPTIONS_DESC=spremeni nastavitve
+SING_OPTIONS_WHEREAMI=Nastavitve
+
+SING_OPTIONS_GAME=igra
+SING_OPTIONS_GRAPHICS=izgled
+SING_OPTIONS_SOUND=zvok
+SING_OPTIONS_LYRICS=besedilo
+SING_OPTIONS_THEMES=tema
+SING_OPTIONS_RECORD=snemanje
+SING_OPTIONS_ADVANCED=napredno
+SING_OPTIONS_EXIT=nazaj
+
+SING_OPTIONS_GAME_WHEREAMI=Nastavitve Igre
+SING_OPTIONS_GAME_DESC=osnovne nastavitve
+SING_OPTIONS_GAME_PLAYERS=Igralci
+SING_OPTIONS_GAME_DIFFICULTY=Težavnost
+SING_OPTIONS_GAME_LANGUAGE=Jezik
+SING_OPTIONS_GAME_TABS=Mape
+SING_OPTIONS_GAME_SORTING=Sortiranje
+SING_OPTIONS_GAME_DEBUG=Odpravljanje hrošcev
+
+SING_OPTIONS_GRAPHICS_WHEREAMI=Nastavitve prikaza
+SING_OPTIONS_GRAPHICS_DESC=nastavitve prikaza
+SING_OPTIONS_GRAPHICS_RESOLUTION=Locljivost
+SING_OPTIONS_GRAPHICS_FULLSCREEN=Celozaslonski nacin
+SING_OPTIONS_GRAPHICS_DEPTH=Globina
+SING_OPTIONS_GRAPHICS_VISUALIZER=Vizualizacija
+SING_OPTIONS_GRAPHICS_OSCILLOSCOPE=Osciloskop
+SING_OPTIONS_GRAPHICS_LINEBONUS=Vrsticni bonus
+SING_OPTIONS_GRAPHICS_MOVIE_SIZE=Velikost videa
+
+SING_OPTIONS_SOUND_WHEREAMI=Nastavitve zvoka
+SING_OPTIONS_SOUND_DESC=nastavitve zvoka
+SING_OPTIONS_SOUND_VOICEPASSTHROUGH=Mikrofonski Playback
+SING_OPTIONS_SOUND_BACKGROUNDMUSIC=Glasbena podlaga
+SING_OPTIONS_SOUND_MIC_BOOST=Ojacitev mikrofona
+SING_OPTIONS_SOUND_CLICK_ASSIST=Asistent klikanja
+SING_OPTIONS_SOUND_BEAT_CLICK=Klikanje po ritmu
+SING_OPTIONS_SOUND_THRESHOLD=Prag
+SING_OPTIONS_SOUND_TWO_PLAYERS_MODE=Nacin za dva igralca
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Glasnost predogleda
+SING_OPTIONS_SOUND_PREVIEWFADING=narašcanje glasnosti
+
+SING_OPTIONS_LYRICS_WHEREAMI=Nastavitve besedila
+SING_OPTIONS_LYRICS_DESC=nastavitve besedila
+SING_OPTIONS_LYRICS_FONT=Pisava
+SING_OPTIONS_LYRICS_EFFECT=Ucinek
+SING_OPTIONS_LYRICS_SOLMIZATION=Solmizacija
+SING_OPTIONS_LYRICS_NOTELINES=Notno crtovje
+
+SING_OPTIONS_THEMES_WHEREAMI=Nastavitve tem
+SING_OPTIONS_THEMES_DESC=nastavitve teme
+SING_OPTIONS_THEMES_THEME=Tema
+SING_OPTIONS_THEMES_SKIN=Izgled
+SING_OPTIONS_THEMES_COLOR=Barva
+
+SING_OPTIONS_RECORD_WHEREAMI=Nastavitve snemanja
+SING_OPTIONS_RECORD_DESC=nastavitve mikrofona
+SING_OPTIONS_RECORD_CARD=Vir zvoka
+SING_OPTIONS_RECORD_INPUT=Vhod
+SING_OPTIONS_RECORD_CHANNEL=Kanal
+
+SING_OPTIONS_ADVANCED_WHEREAMI=Napredne nastavitve
+SING_OPTIONS_ADVANCED_DESC=Napredne nastavitve
+SING_OPTIONS_ADVANCED_EFFECTSING=Pevski efekt
+SING_OPTIONS_ADVANCED_SCREENFADE=Zamegljevanje prikaza
+SING_OPTIONS_ADVANCED_LOADANIMATION=Zacetna animacija
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Zašcitno vprašanje
+SING_OPTIONS_ADVANCED_LINEBONUS=Bonus za vrstico
+SING_OPTIONS_ADVANCED_COUNT_HOW_OFTEN_SUNG=
+SING_OPTIONS_ADVANCED_ONSONGCLICK=Po izboru pesmi
+SING_OPTIONS_ADVANCED_PARTYPOPUP=Samodejni nacin Zabava
+
+SING_EDIT=Urednik
+SING_EDIT_MENU_DESCRIPTION=Izdelaj lastno pesem
+
+SING_EDIT_BUTTON_DESCRIPTION_CONVERT=Izvozi besedilo iz midi datoteke
+SING_EDIT_BUTTON_DESCRIPTION_EXIT=Nazaj
+SING_EDIT_BUTTON_CONVERT=Uvozi
+SING_EDIT_BUTTON_EXIT=Nazaj
+
+SING_EDIT_NAVIGATE=Navigacija
+SING_EDIT_SELECT=Izberi
+SING_EDIT_EXIT=Nazaj
+
+SING_LEGEND_SELECT=izberi
+SING_LEGEND_NAVIGATE=premik
+SING_LEGEND_CONTINUE=nadaljuj
+SING_LEGEND_ESC=nazaj
+
+SING_PLAYER_DESC=vpiši imena igralcev
+SING_PLAYER_WHEREAMI=Imena igralcev
+SING_PLAYER_ENTER_NAME=vnesi ime
+
+SING_DIFFICULTY_DESC=izberi težavnost
+SING_DIFFICULTY_WHEREAMI=Težavnost
+SING_DIFFICULTY_CONTINUE=k izbiri pesmi
+SING_EASY=Enostavno
+SING_MEDIUM=Srednje
+SING_HARD=Težko
+
+SING_SONG_SELECTION_DESC=izberi svojo pesem
+SING_SONG_SELECTION_WHEREAMI=Izbira pesmi
+SING_SONG_SELECTION_GOTO=pojdi na...
+SING_SONG_SELECTION=izbira pesmi
+SING_SONG_SELECTION_MENU=meni
+SING_SONG_SELECTION_PLAYLIST=seznam predvajanja
+SING_SONGS_IN_CAT=Pesmi
+PLAYLIST_CATTEXT=Lista: %s
+
+SING_TIME=CAS
+SING_TOTAL=skupaj
+SING_MODE=Petje
+SING_NOTES=note
+SING_GOLDEN_NOTES=zlate note
+SING_PHRASE_BONUS=bonus za vrstico
+
+SING_MENU=Glavni meni
+
+SONG_SCORE=rezultat petja
+SONG_SCORE_WHEREAMI=Rezultat
+
+SING_SCORE_TONE_DEAF=Gluhonem
+SING_SCORE_AMATEUR=Amater
+SING_SCORE_WANNABE=Igralec
+SING_SCORE_HOPEFUL=Nadebudnež
+SING_SCORE_RISING_STAR=Vzhajajoca zvezda
+SING_SCORE_LEAD_SINGER=Vodilni pevec
+SING_SCORE_SUPERSTAR=Superzvezda
+SING_SCORE_ULTRASTAR=Ultrazvezda
+
+SING_TOP_5_CHARTS=najboljših 5 pevcev
+SING_TOP_5_CHARTS_WHEREAMI=najboljših 5
+SING_TOP_5_CHARTS_CONTINUE=k izbiri pesmi
+
+POPUP_PERFECT=popolno!
+POPUP_AWESOME=odlicno!
+POPUP_GREAT=zelo dobro!
+POPUP_GOOD=dobro!
+POPUP_NOTBAD=ni slabo!
+POPUP_BAD=slabo!
+POPUP_POOR=zelo slabo!
+POPUP_AWFUL=obupno!
+
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= in
+
+SONG_MENU_NAME_MAIN=meni pesmi
+SONG_MENU_PLAY=Poj
+SONG_MENU_CHANGEPLAYERS=Spremeni igralca
+SONG_MENU_EDIT=Uredi
+SONG_MENU_MODI=Poj "a Modi"
+SONG_MENU_CANCEL=Preklici
+
+SONG_MENU_NAME_PLAYLIST=Meni Pesem
+SONG_MENU_PLAYLIST_ADD=Dodaj pesem
+SONG_MENU_PLAYLIST_DEL=Izbriši pesem
+
+SONG_MENU_NAME_PLAYLIST_ADD=Dodaj pesem
+SONG_MENU_PLAYLIST_ADD_NEW=dodaj nov seznam
+SONG_MENU_PLAYLIST_ADD_EXISTING=dodaj shranjen seznam
+SONG_MENU_PLAYLIST_NOEXISTING=Ni seznamov
+
+SONG_MENU_NAME_PLAYLIST_NEW=Nov seznam
+SONG_MENU_PLAYLIST_NEW_CREATE=Ustvari
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Neimenovan
+
+SONG_MENU_NAME_PLAYLIST_DELITEM=Res izbrišem?
+SONG_MENU_YES=Da
+SONG_MENU_NO=Ne
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Odpri seznam
+SONG_MENU_PLAYLIST_LOAD=odpri
+SONG_MENU_PLAYLIST_DELCURRENT=izbriši trenuten seznam
+
+SONG_MENU_NAME_PLAYLIST_DEL=Izbrišem seznam?
+
+SONG_MENU_NAME_PARTY_MAIN=Meni Zabava
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=izkoristi jokerja
+
+SONG_JUMPTO_DESC=poišci pesem
+SONG_JUMPTO_TYPE_DESC=Isci po:
+SONG_JUMPTO_TYPE1=Vse
+SONG_JUMPTO_TYPE2=Naslov
+SONG_JUMPTO_TYPE3=Avtor
+SONG_JUMPTO_SONGSFOUND=%d pesmi najdenih
+SONG_JUMPTO_NOSONGSFOUND=Ne najdem
+SONG_JUMPTO_HELP=Vpiši besedilo za iskanje
+SONG_JUMPTO_CATTEXT=Išci po: %s
+
+PARTY_MODE=zabava
+PARTY_DIFFICULTY=Težavnost
+PARTY_PLAYLIST=Izbor
+PARTY_PLAYLIST_ALL=Vse pesmi
+PARTY_PLAYLIST_CATEGORY=Mapa
+PARTY_PLAYLIST_PLAYLIST=Seznam
+PARTY_ROUNDS=Število rund
+PARTY_TEAMS=Ekipe
+PARTY_TEAMS_PLAYER1=Igralec Ekipa1
+PARTY_TEAMS_PLAYER2=Igralec Ekipa2
+PARTY_TEAMS_PLAYER3=Igralec Ekipa3
+
+PARTY_LEGEND_CONTINUE=nadaljuj
+
+PARTY_OPTIONS_DESC=nastavitve za nacin zabave
+PARTY_OPTIONS_WHEREAMI=nastavitve zabave
+
+PARTY_PLAYER_DESC=vpiši igralce in imena ekip!
+PARTY_PLAYER_WHEREAMI=Imena
+PARTY_PLAYER_ENTER_NAME=vpiši imena
+PARTY_PLAYER_LEGEND_CONTINUE=zacni zabavo
+
+PARTY_ROUND_DESC=naslednji igralec k mikrofonu
+PARTY_ROUND_WHEREAMI=Naslednja runda
+PARTY_ROUND_LEGEND_CONTINUE=zacni rundo
+
+PARTY_SONG_WHEREAMI=Izbor pesmi - Zabava
+PARTY_SONG_LEGEND_CONTINUE=poj
+PARTY_SONG_MENU=meni Zabava
+
+PARTY_SCORE_DESC=tocke zadnje runde
+PARTY_SCORE_WHEREAMI=Tocke v zabavi
+
+PARTY_WIN_DESC=Zmagovalec
+PARTY_WIN_WHEREAMI=Zmagovalec
+PARTY_WIN_LEGEND_CONTINUE=nazaj k glavnemu meniju
+
+PARTY_ROUND=Runda
+PARTY_ROUND_WINNER=Zmagovalec
+PARTY_NOTPLAYEDYET=neizvedeno
+PARTY_NOBODY=nobeden
+NEXT_ROUND=Naslednja runda:
+
+PARTY_DISMISSED=Zakljucena!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=zmaga!
+
+PLUGIN_HDL_NAME=Zdrži nivo
+PLUGIN_HDL_DESC=Ne poj slabše, kot kaže kazalnik na števcu za ocenjevanje.
+
+PLUGIN_UNTIL5000_NAME=Do 5000
+PLUGIN_UNTIL5000_DESC=Kdor prvi doseže 5000 tock, zmaga.
+
+PLUGIN_DUELL_NAME=Dvoboj
+PLUGIN_DUELL_DESC=Tekmovanje do 10000 tock.
+
+PLUGIN_TEAMDUELL_NAME=Ekipni dvoboj
+PLUGIN_TEAMDUELL_DESC=Podaj mikrofon!
+
+PLUGIN_BLIND_NAME=Slepi dvoboj
+PLUGIN_BLIND_DESC=Dvoboj brez prikaza not.
+
+STAT_MAIN=Statika
+STAT_MAIN_DESC=Splošno
+STAT_MAIN_WHEREAMI=Statistika
+
+STAT_OVERVIEW_INTRO=%0:s Statistika. \n Nazadnje ponastavljeno %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Pesmi(%3:d z videom), od katerih je bilo %1:d že zapetih in %2:d ne.\n Najbolj priljubljena pesem je %5:s od %4:s.
+STAT_OVERVIEW_PLAYER=Od zadnje ponastavitve statistike je igro igralo %0:d igralcev.\n Najboljši/a je %1:s s povprecnim rezultatom %2:d tock.\n %3:s je dosegel/la najboljši rezultat s %4:d tockami.
+
+STAT_DETAIL=Statistika
+STAT_DETAIL_WHEREAMI=Podrobna statistika
+
+STAT_NEXT=Naslednja stran
+STAT_PREV=Prejšnja stran
+STAT_REVERSE=Obratni vrstni red
+STAT_PAGE=Stran %0:d od %1:d strani\n (%2:d od %3:d zapisov)
+
+STAT_DESC_SCORES=Najboljši rezultati
+STAT_DESC_SCORES_REVERSED=Najslabši rezultati
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Najboljši igralec
+STAT_DESC_SINGERS_REVERSED=Najslabši igralec
+STAT_FORMAT_SINGERS=%0:s \n povprecni rezultat: %1:d
+
+STAT_DESC_SONGS=Najbolj popularne pesmi
+STAT_DESC_SONGS_REVERSED=Najmanj popularne pesmi
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx igrano
+
+STAT_DESC_BANDS=Najbolj popularen izvajalec
+STAT_DESC_BANDS_REVERSED=Najmanj popularen izvajalec
+STAT_FORMAT_BANDS=%0:s \n %1:dx igrano
+
+MSG_ERROR_TITLE=Napaka
+MSG_QUESTION_TITLE=Vprašanje
+MSG_QUIT_USDX=Želite zapustiti Ultrastar?
+MSG_END_PARTY=Koncam zabavo?
+ERROR_NO_SONGS=Ni pesmi: Naloži jih v mapo Songs
+ERROR_NO_PLUGINS=Ni vkljuckov
+ERROR_CORRUPT_SONG=Ne morem naložiti pesmi.
+ERROR_CORRUPT_SONG_FILE_NOT_FOUND=Ne morem naložiti pesmi: Ne najdem datoteke
+ERROR_CORRUPT_SONG_NO_NOTES=Ne morem naloziti pesmi: Ne najdem not.
+ERROR_CORRUPT_SONG_NO_BREAKS=Ne morem naložiti pesmi: Ne najdem prelomov vrstic.
ERROR_CORRUPT_SONG_UNKNOWN_IN_LINE=Ne morem naložiti pesmi: Napaka v parsanju vrstice %0:d \ No newline at end of file
diff --git a/game/languages/old/readme.txt b/game/languages/old/readme.txt
index eb2bd1c0..83ba6cd6 100644
--- a/game/languages/old/readme.txt
+++ b/game/languages/old/readme.txt
@@ -1,286 +1,286 @@
-.o0 Ultrastar Deluxe in your language 0o.
-
------------------------
- Table of Contents
------------------------
-1. Introduction
-2. Statistic wildcards
-3. Texts to add
-
------------------------
-1. Introduction:
------------------------
-To translate USD to a new language, take the English language file, or another one that is up to date and edit the texts behind the equal mark(=).
-
------------------------
-2. Statistic Wild-Cards:
------------------------
-Here are some informations about the wildcards in the language texts for the statistic screens (STAT_...):
-Information that will replace the wildcards:
-
-STAT_OVERVIEW_INTRO:
- Format:
- %0:d Ultrastar Version
- %1:d Day of Reset (A1)
- %2:d Month of Reset (A2)
- %3:d Year of Reset (A3)
-
-STAT_OVERVIEW_SONG:
- Format:
- %0:d Count Songs (A1)
- %1:d Count of Sung Songs (A2)
- %2:d Count of UnSung Songs
- %3:d Count of Songs with Video (A3)
- %4:s Name of the most popular Song
-
-STAT_OVERVIEW_PLAYER:
- Format:
- %0:d Count Players (A1)
- %1:s Best Player (Result)
- %2:d Best Players Score
- %3:s Best Score Player (Result2)
- %4:d Best Score
-
-STAT_FORMAT_SCORES:
- Format:
- %0:s Singer
- %1:d Score
- %2:s Difficulty
- %3:s Song Artist
- %4:s Song Title
-
-STAT_FORMAT_SINGERS:
- Format:
- %0:s Singer
- %1:d Average Score
-
-
-STAT_FORMAT_SONGS:
- Format:
- %0:s Artist
- %1:s Title
- %2:d Times Sung
-
-STAT_FORMAT_BANDS:
- Format:
- %0:s Artist Name
- %1:d Times Sung
-
-Some further explanations about the wildcards:
-%x:[.y]z
-
-Where X is the number of the wildcard,
-Y is optional, it is the number of digits for deciaml numbers (Z=d). So, if y is 2 there and the number is only 0 to 9 there will be a zero added in front of the number.
-z can be d for numbers and s for texts
-
-For the date thing in STAT_OVERVIEW_INTRO you may use %1:.2d for the day and %2:.2d for the month.
-
------------------------
-3. Texts to Add:
------------------------
-To port a language file from Ultrastar 0.5.2 or higher add the following texts to the end of the file:
-
-#Main Screen
-SING_MENU=Main Menu
-
-SING_MULTI=party
-SING_MULTI_DESC=Sing in PartyMode
-
-SING_TOOLS=Tools
-
-SING_STATS=stats
-SING_STATS_DESC=View the Statistics
-
-#Sound Options Screen
-SING_OPTIONS_SOUND_PREVIEWVOLUME=Preview Volume
-SING_OPTIONS_SOUND_PREVIEWFADING=Preview Fading
-
-#Advanced Options Screen
-SING_OPTIONS_ADVANCED=advanced
-SING_OPTIONS_ADVANCED_DESC=advanced options
-SING_OPTIONS_ADVANCED_EFFECTSING=Singscreen effects
-SING_OPTIONS_ADVANCED_SCREENFADE=Screen Fading
-SING_OPTIONS_ADVANCED_LOADANIMATION=Load Animation
-SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Savety Questions
-SING_OPTIONS_ADVANCED_LINEBONUS=Line Bonus
-SING_OPTIONS_ADVANCED_ONSONGCLICK=after SongSelection
-
-#Ratings at the Score Screen
-SING_SCORE_TONE_DEAF=Tone Deaf
-SING_SCORE_AMATEUR=Amateur
-SING_SCORE_RISING_STAR=Rising Star
-SING_SCORE_LEAD_SINGER=Lead Singer
-SING_SCORE_HIT_ARTIST=Hit Artist
-SING_SCORE_SUPERSTAR=Superstar
-SING_SCORE_ULTRASTAR=Ultrastar
-
-#Line Bonus PopUps
-POPUP_PERFECT=perfect!
-POPUP_AWESOME=awesome!
-POPUP_GREAT=great!
-POPUP_GOOD=good!
-POPUP_NOTBAD=not bad!
-POPUP_BAD=bad!
-POPUP_POOR=poor!
-POPUP_AWFUL=awful!
-
-#To connect strings with, e.g.: He, you and I
-IMPLODE_GLUE1=,
-IMPLODE_GLUE2= and
-
-#Song Screen Legend
-PLAYLIST_CATTEXT=Playlist: %s
-
-#Text for the legend bar at the bottom
-SING_LEGEND_CONTINUE=Continue
-
-#Texts of the menu that appears when M is pressed at the song selection
-SONG_MENU_NAME_MAIN=Song Menu
-SONG_MENU_PLAY=Sing
-SONG_MENU_EDIT=Edit
-SONG_MENU_MODI=Sing a Modi
-SONG_MENU_CHANGEPLAYERS=Change Players
-SONG_MENU_CANCEL=Cancel
-
-#Playlist Menu
-SONG_MENU_NAME_MAIN=song menu
-SONG_MENU_PLAY=Sing
-SONG_MENU_CHANGEPLAYERS=Change Players
-SONG_MENU_EDIT=Edit
-SONG_MENU_MODI=Sing a Modi
-SONG_MENU_CANCEL=Cancel
-
-SONG_MENU_NAME_PLAYLIST=Song Menu
-SONG_MENU_PLAYLIST_ADD=Add Song
-SONG_MENU_PLAYLIST_DEL=Delete Song
-
-SONG_MENU_NAME_PLAYLIST_ADD=Add Song
-SONG_MENU_PLAYLIST_ADD_NEW=to new playlist
-SONG_MENU_PLAYLIST_ADD_EXISTING=to exiting playlist
-SONG_MENU_PLAYLIST_NOEXISTING=No playlist available
-
-SONG_MENU_NAME_PLAYLIST_NEW=New Playlist
-SONG_MENU_PLAYLIST_NEW_CREATE=Create
-SONG_MENU_PLAYLIST_NEW_UNNAMED=Unnamed
-
-SONG_MENU_NAME_PLAYLIST_DEL=Really Delete?
-SONG_MENU_YES=Yes
-SONG_MENU_NO=No
-
-SONG_MENU_NAME_PLAYLIST_LOAD=Open Playlist
-SONG_MENU_PLAYLIST_LOAD=open
-SONG_MENU_PLAYLIST_DELCURRENT=delete current Playlist
-
-SONG_MENU_NAME_PLAYLIST_DEL=Delete Playlist?
-
-#Menu Party Modus
-SONG_MENU_NAME_PARTY_MAIN=Menu
-SONG_MENU_JOKER=Joker
-
-SONG_MENU_NAME_PARTY_JOKER=take Joker
-
-#Texts of the jump to window
-SONG_JUMPTO_DESC=Jump to Song
-SONG_JUMPTO_TYPE_DESC=Search for:
-SONG_JUMPTO_TYPE1=All
-SONG_JUMPTO_TYPE2=Title
-SONG_JUMPTO_TYPE3=Artist
-SONG_JUMPTO_SONGSFOUND=%d Song(s) found
-SONG_JUMPTO_NOSONGSFOUND=No Song found
-SONG_JUMPTO_HELP=Type Text to Search for
-SONG_JUMPTO_CATTEXT=Search for: %s
-
-#Texts for Party Mode
-PARTY_MODE=party mode
-PARTY_DIFFICULTY=Difficulty
-PARTY_PLAYLIST=Playlist Mode
-PARTY_PLAYLIST_ALL=All songs
-PARTY_PLAYLIST_CATEGORY=Folder
-PARTY_PLAYLIST_PLAYLIST=Playlist
-PARTY_ROUNDS=Rounds
-PARTY_TEAMS=Teams
-PARTY_TEAMS_PLAYER1=Player Team1
-PARTY_TEAMS_PLAYER2=Player Team2
-PARTY_TEAMS_PLAYER3=Player Team3
-PARTY_LEGEND_CONTINUE=continue
-PARTY_OPTIONS_DESC=settings for the party-game
-PARTY_OPTIONS_WHEREAMI=Party Options
-PARTY_PLAYER_DESC=enter player- and teamnames!
-PARTY_PLAYER_WHEREAMI=Party Names
-PARTY_PLAYER_ENTER_NAME=enter names
-PARTY_PLAYER_LEGEND_CONTINUE=start party-game
-PARTY_SONG_WHEREAMI=Party Song-Selection
-PARTY_SONG_LEGEND_CONTINUE=sing
-PARTY_SONG_MENU=party menu
-PARTY_ROUND_DESC=next players to the mics
-PARTY_ROUND_WHEREAMI=Party Next Round
-PARTY_ROUND_LEGEND_CONTINUE=start round
-PARTY_SCORE_DESC=score of the last round
-PARTY_SCORE_WHEREAMI=Party Points
-PARTY_WIN_DESC=winner of the party-game
-PARTY_WIN_WHEREAMI=Party Winner
-PARTY_WIN_LEGEND_CONTINUE=back to main-menu
-PARTY_ROUND=Round
-PARTY_ROUND_WINNER=Winner
-PARTY_NOTPLAYEDYET=not played yet
-PARTY_NOBODY=nobody
-NEXT_ROUND=Next round:
-PARTY_DISMISSED=Dismissed!
-PARTY_SCORE_WINS=%s
-PARTY_SCORE_WINS2=wins!
-PARTY_SONG_WHEREAMI=Party Song-Selection
-PARTY_SONG_LEGEND_CONTINUE=Party-Menu
-
-#Texts describing Plugins or Modi
-PLUGIN_HDL_NAME=Hold the Line
-PLUGIN_HDL_DESC=Don't get worse than the pointer at the rating bar shows you.
-PLUGIN_UNTIL5000_NAME=Until 5000
-PLUGIN_UNTIL5000_DESC=Who gets 5000 points first wins the match.
-PLUGIN_DUELL_NAME=Duell
-PLUGIN_DUELL_DESC=Sing a duell until 10000 points.
-PLUGIN_BLIND_NAME=Blind Mode
-PLUGIN_BLIND_DESC=Duell without seeing the notes.
-PLUGIN_TEAMDUELL_NAME=Team Duell
-PLUGIN_TEAMDUELL_DESC=Pass The Mic!
-
-#Statistics Screen
-#For more info about the format strings look at the source code (UScreenStatMain)
-STAT_MAIN=Statistics
-STAT_MAIN_DESC=General
-STAT_MAIN_WHEREAMI=Statistics
-
-STAT_OVERVIEW_INTRO=%0:s Statistics. \n Last Reset at %2:.2d.%1:.2d.%3:d
-STAT_OVERVIEW_SONG=%0:d Songs(%3:d with Video), whereof %1:d already were played and %2:d were not played yet.\n The most popular Song is %5:s from %4:s.
-STAT_OVERVIEW_PLAYER=Since the last Reset there were/was %0:d different Player(s).\n The Best Player is %1:s with an average Score of %2:d Points.\n %3:s did the highest Score with %4:d Points.
-
-#Stat Detail Screen
-STAT_DETAIL=Statistics
-STAT_DETAIL_WHEREAMI=Detail Statistics
-
-STAT_NEXT=Next Page
-STAT_PREV=Previous Page
-STAT_REVERSE=Reverse Order
-STAT_PAGE=Seite %0:d of %1:d Pages\n (%2:d of %3:d Entrys)
-
-STAT_DESC_SCORES=HighScores
-STAT_DESC_SCORES_REVERSED=LowScores
-STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
-
-STAT_DESC_SINGERS=Best Singers
-STAT_DESC_SINGERS_REVERSED=Worst Singers
-STAT_FORMAT_SINGERS=%0:s \n Average Score: %1:d
-
-STAT_DESC_SONGS=Most popular Songs
-STAT_DESC_SONGS_REVERSED=Least popular Songs
-STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx sung
-
-STAT_DESC_BANDS=Most popular Bands
-STAT_DESC_BANDS_REVERSED=Least popular Bands
-STAT_FORMAT_BANDS=%0:s \n %1:dx Sung
-
-#Messages for Popup Message Boxes
-MSG_QUESTION_TITLE=Chicken Out
-MSG_QUIT_USDX=Really leave\n\nUltraStar?
-MSG_END_PARTY=Really end\n\nParty Mode?
-ERROR_NO_SONGS=Error: \n No Songs \n loaded
+.o0 Ultrastar Deluxe in your language 0o.
+
+-----------------------
+ Table of Contents
+-----------------------
+1. Introduction
+2. Statistic wildcards
+3. Texts to add
+
+-----------------------
+1. Introduction:
+-----------------------
+To translate USD to a new language, take the English language file, or another one that is up to date and edit the texts behind the equal mark(=).
+
+-----------------------
+2. Statistic Wild-Cards:
+-----------------------
+Here are some informations about the wildcards in the language texts for the statistic screens (STAT_...):
+Information that will replace the wildcards:
+
+STAT_OVERVIEW_INTRO:
+ Format:
+ %0:d Ultrastar Version
+ %1:d Day of Reset (A1)
+ %2:d Month of Reset (A2)
+ %3:d Year of Reset (A3)
+
+STAT_OVERVIEW_SONG:
+ Format:
+ %0:d Count Songs (A1)
+ %1:d Count of Sung Songs (A2)
+ %2:d Count of UnSung Songs
+ %3:d Count of Songs with Video (A3)
+ %4:s Name of the most popular Song
+
+STAT_OVERVIEW_PLAYER:
+ Format:
+ %0:d Count Players (A1)
+ %1:s Best Player (Result)
+ %2:d Best Players Score
+ %3:s Best Score Player (Result2)
+ %4:d Best Score
+
+STAT_FORMAT_SCORES:
+ Format:
+ %0:s Singer
+ %1:d Score
+ %2:s Difficulty
+ %3:s Song Artist
+ %4:s Song Title
+
+STAT_FORMAT_SINGERS:
+ Format:
+ %0:s Singer
+ %1:d Average Score
+
+
+STAT_FORMAT_SONGS:
+ Format:
+ %0:s Artist
+ %1:s Title
+ %2:d Times Sung
+
+STAT_FORMAT_BANDS:
+ Format:
+ %0:s Artist Name
+ %1:d Times Sung
+
+Some further explanations about the wildcards:
+%x:[.y]z
+
+Where X is the number of the wildcard,
+Y is optional, it is the number of digits for deciaml numbers (Z=d). So, if y is 2 there and the number is only 0 to 9 there will be a zero added in front of the number.
+z can be d for numbers and s for texts
+
+For the date thing in STAT_OVERVIEW_INTRO you may use %1:.2d for the day and %2:.2d for the month.
+
+-----------------------
+3. Texts to Add:
+-----------------------
+To port a language file from Ultrastar 0.5.2 or higher add the following texts to the end of the file:
+
+#Main Screen
+SING_MENU=Main Menu
+
+SING_MULTI=party
+SING_MULTI_DESC=Sing in PartyMode
+
+SING_TOOLS=Tools
+
+SING_STATS=stats
+SING_STATS_DESC=View the Statistics
+
+#Sound Options Screen
+SING_OPTIONS_SOUND_PREVIEWVOLUME=Preview Volume
+SING_OPTIONS_SOUND_PREVIEWFADING=Preview Fading
+
+#Advanced Options Screen
+SING_OPTIONS_ADVANCED=advanced
+SING_OPTIONS_ADVANCED_DESC=advanced options
+SING_OPTIONS_ADVANCED_EFFECTSING=Singscreen effects
+SING_OPTIONS_ADVANCED_SCREENFADE=Screen Fading
+SING_OPTIONS_ADVANCED_LOADANIMATION=Load Animation
+SING_OPTIONS_ADVANCED_ASKBEFOREDEL=Savety Questions
+SING_OPTIONS_ADVANCED_LINEBONUS=Line Bonus
+SING_OPTIONS_ADVANCED_ONSONGCLICK=after SongSelection
+
+#Ratings at the Score Screen
+SING_SCORE_TONE_DEAF=Tone Deaf
+SING_SCORE_AMATEUR=Amateur
+SING_SCORE_RISING_STAR=Rising Star
+SING_SCORE_LEAD_SINGER=Lead Singer
+SING_SCORE_HIT_ARTIST=Hit Artist
+SING_SCORE_SUPERSTAR=Superstar
+SING_SCORE_ULTRASTAR=Ultrastar
+
+#Line Bonus PopUps
+POPUP_PERFECT=perfect!
+POPUP_AWESOME=awesome!
+POPUP_GREAT=great!
+POPUP_GOOD=good!
+POPUP_NOTBAD=not bad!
+POPUP_BAD=bad!
+POPUP_POOR=poor!
+POPUP_AWFUL=awful!
+
+#To connect strings with, e.g.: He, you and I
+IMPLODE_GLUE1=,
+IMPLODE_GLUE2= and
+
+#Song Screen Legend
+PLAYLIST_CATTEXT=Playlist: %s
+
+#Text for the legend bar at the bottom
+SING_LEGEND_CONTINUE=Continue
+
+#Texts of the menu that appears when M is pressed at the song selection
+SONG_MENU_NAME_MAIN=Song Menu
+SONG_MENU_PLAY=Sing
+SONG_MENU_EDIT=Edit
+SONG_MENU_MODI=Sing a Modi
+SONG_MENU_CHANGEPLAYERS=Change Players
+SONG_MENU_CANCEL=Cancel
+
+#Playlist Menu
+SONG_MENU_NAME_MAIN=song menu
+SONG_MENU_PLAY=Sing
+SONG_MENU_CHANGEPLAYERS=Change Players
+SONG_MENU_EDIT=Edit
+SONG_MENU_MODI=Sing a Modi
+SONG_MENU_CANCEL=Cancel
+
+SONG_MENU_NAME_PLAYLIST=Song Menu
+SONG_MENU_PLAYLIST_ADD=Add Song
+SONG_MENU_PLAYLIST_DEL=Delete Song
+
+SONG_MENU_NAME_PLAYLIST_ADD=Add Song
+SONG_MENU_PLAYLIST_ADD_NEW=to new playlist
+SONG_MENU_PLAYLIST_ADD_EXISTING=to exiting playlist
+SONG_MENU_PLAYLIST_NOEXISTING=No playlist available
+
+SONG_MENU_NAME_PLAYLIST_NEW=New Playlist
+SONG_MENU_PLAYLIST_NEW_CREATE=Create
+SONG_MENU_PLAYLIST_NEW_UNNAMED=Unnamed
+
+SONG_MENU_NAME_PLAYLIST_DEL=Really Delete?
+SONG_MENU_YES=Yes
+SONG_MENU_NO=No
+
+SONG_MENU_NAME_PLAYLIST_LOAD=Open Playlist
+SONG_MENU_PLAYLIST_LOAD=open
+SONG_MENU_PLAYLIST_DELCURRENT=delete current Playlist
+
+SONG_MENU_NAME_PLAYLIST_DEL=Delete Playlist?
+
+#Menu Party Modus
+SONG_MENU_NAME_PARTY_MAIN=Menu
+SONG_MENU_JOKER=Joker
+
+SONG_MENU_NAME_PARTY_JOKER=take Joker
+
+#Texts of the jump to window
+SONG_JUMPTO_DESC=Jump to Song
+SONG_JUMPTO_TYPE_DESC=Search for:
+SONG_JUMPTO_TYPE1=All
+SONG_JUMPTO_TYPE2=Title
+SONG_JUMPTO_TYPE3=Artist
+SONG_JUMPTO_SONGSFOUND=%d Song(s) found
+SONG_JUMPTO_NOSONGSFOUND=No Song found
+SONG_JUMPTO_HELP=Type Text to Search for
+SONG_JUMPTO_CATTEXT=Search for: %s
+
+#Texts for Party Mode
+PARTY_MODE=party mode
+PARTY_DIFFICULTY=Difficulty
+PARTY_PLAYLIST=Playlist Mode
+PARTY_PLAYLIST_ALL=All songs
+PARTY_PLAYLIST_CATEGORY=Folder
+PARTY_PLAYLIST_PLAYLIST=Playlist
+PARTY_ROUNDS=Rounds
+PARTY_TEAMS=Teams
+PARTY_TEAMS_PLAYER1=Player Team1
+PARTY_TEAMS_PLAYER2=Player Team2
+PARTY_TEAMS_PLAYER3=Player Team3
+PARTY_LEGEND_CONTINUE=continue
+PARTY_OPTIONS_DESC=settings for the party-game
+PARTY_OPTIONS_WHEREAMI=Party Options
+PARTY_PLAYER_DESC=enter player- and teamnames!
+PARTY_PLAYER_WHEREAMI=Party Names
+PARTY_PLAYER_ENTER_NAME=enter names
+PARTY_PLAYER_LEGEND_CONTINUE=start party-game
+PARTY_SONG_WHEREAMI=Party Song-Selection
+PARTY_SONG_LEGEND_CONTINUE=sing
+PARTY_SONG_MENU=party menu
+PARTY_ROUND_DESC=next players to the mics
+PARTY_ROUND_WHEREAMI=Party Next Round
+PARTY_ROUND_LEGEND_CONTINUE=start round
+PARTY_SCORE_DESC=score of the last round
+PARTY_SCORE_WHEREAMI=Party Points
+PARTY_WIN_DESC=winner of the party-game
+PARTY_WIN_WHEREAMI=Party Winner
+PARTY_WIN_LEGEND_CONTINUE=back to main-menu
+PARTY_ROUND=Round
+PARTY_ROUND_WINNER=Winner
+PARTY_NOTPLAYEDYET=not played yet
+PARTY_NOBODY=nobody
+NEXT_ROUND=Next round:
+PARTY_DISMISSED=Dismissed!
+PARTY_SCORE_WINS=%s
+PARTY_SCORE_WINS2=wins!
+PARTY_SONG_WHEREAMI=Party Song-Selection
+PARTY_SONG_LEGEND_CONTINUE=Party-Menu
+
+#Texts describing Plugins or Modi
+PLUGIN_HDL_NAME=Hold the Line
+PLUGIN_HDL_DESC=Don't get worse than the pointer at the rating bar shows you.
+PLUGIN_UNTIL5000_NAME=Until 5000
+PLUGIN_UNTIL5000_DESC=Who gets 5000 points first wins the match.
+PLUGIN_DUELL_NAME=Duell
+PLUGIN_DUELL_DESC=Sing a duell until 10000 points.
+PLUGIN_BLIND_NAME=Blind Mode
+PLUGIN_BLIND_DESC=Duell without seeing the notes.
+PLUGIN_TEAMDUELL_NAME=Team Duell
+PLUGIN_TEAMDUELL_DESC=Pass The Mic!
+
+#Statistics Screen
+#For more info about the format strings look at the source code (UScreenStatMain)
+STAT_MAIN=Statistics
+STAT_MAIN_DESC=General
+STAT_MAIN_WHEREAMI=Statistics
+
+STAT_OVERVIEW_INTRO=%0:s Statistics. \n Last Reset at %2:.2d.%1:.2d.%3:d
+STAT_OVERVIEW_SONG=%0:d Songs(%3:d with Video), whereof %1:d already were played and %2:d were not played yet.\n The most popular Song is %5:s from %4:s.
+STAT_OVERVIEW_PLAYER=Since the last Reset there were/was %0:d different Player(s).\n The Best Player is %1:s with an average Score of %2:d Points.\n %3:s did the highest Score with %4:d Points.
+
+#Stat Detail Screen
+STAT_DETAIL=Statistics
+STAT_DETAIL_WHEREAMI=Detail Statistics
+
+STAT_NEXT=Next Page
+STAT_PREV=Previous Page
+STAT_REVERSE=Reverse Order
+STAT_PAGE=Seite %0:d of %1:d Pages\n (%2:d of %3:d Entrys)
+
+STAT_DESC_SCORES=HighScores
+STAT_DESC_SCORES_REVERSED=LowScores
+STAT_FORMAT_SCORES=%0:s - %1:d [%2:s] \n (%3:s - %4:s)
+
+STAT_DESC_SINGERS=Best Singers
+STAT_DESC_SINGERS_REVERSED=Worst Singers
+STAT_FORMAT_SINGERS=%0:s \n Average Score: %1:d
+
+STAT_DESC_SONGS=Most popular Songs
+STAT_DESC_SONGS_REVERSED=Least popular Songs
+STAT_FORMAT_SONGS=%0:s - %1:s \n %2:dx sung
+
+STAT_DESC_BANDS=Most popular Bands
+STAT_DESC_BANDS_REVERSED=Least popular Bands
+STAT_FORMAT_BANDS=%0:s \n %1:dx Sung
+
+#Messages for Popup Message Boxes
+MSG_QUESTION_TITLE=Chicken Out
+MSG_QUIT_USDX=Really leave\n\nUltraStar?
+MSG_END_PARTY=Really end\n\nParty Mode?
+ERROR_NO_SONGS=Error: \n No Songs \n loaded
ERROR_NO_PLUGINS=Error: \n No Plugins \n loaded \ No newline at end of file
diff --git a/game/themes/Deluxe/Ocean.ini b/game/themes/Deluxe/Ocean.ini
index bdc90979..d18c7a60 100644
--- a/game/themes/Deluxe/Ocean.ini
+++ b/game/themes/Deluxe/Ocean.ini
@@ -9,32 +9,12 @@ Name=Ocean
Color=Blue
[Textures]
-/**
- * Interface
- */
-interface_selectbg_search = interface/selectbg_search.png
-interface_dialog_background = interface/dialog_background.png
-
-Cursor = interface/cursor.png
-Cursor_Pressed = interface/cursor_pressed.png
-
-/**
- * Icons
- */
-icon_song_menu = icon/song_menu.png
-icon_song_search = icon/song_search.png
-icon_song_video = icon/song_video.png
-
-
# # # M A I N # # #
Button = [main]button.png
ButtonF = [main]buttonf.jpg
MainBar = [main]mainBar.png
SelectBG = [main]selectbg.png
-Select_ArrowLeft = interface/select_arrow_left.png
-Select_ArrowRight = interface/select_arrow_right.png
-
#Backgrounds
LoadingBG = [bg-load]blue.jpg
MainBG = [bg-video]_ocean.avi
@@ -48,16 +28,18 @@ PartyBG = [bg-video]_ocean.avi
#Icons on screen
SongCD = [icon]cd.png
MainIcon = [icon]main.png
+MainSearch = [icon]search.png
IconOption = [icon]options.png
IconEdit = [icon]options.png
+IconSongMenu = [icon]songmenu.png
ScoreIcon = [icon]score.png
PartyIcon = [icon]party.png
StatIcon = [icon]stats.png
+VideoIcon = [icon]video.png
IconError = [icon]error.png
IconQuestion = [icon]question.png
-
# # # S O N G S E L E C E T # # #
SongSelection1 = [main]songSelection1.png
SongSelection2 = [main]songSelection2.png
@@ -94,12 +76,11 @@ P = [sing]p.png
#Pointer for lyrics
Ball = [sing]LyricsBall.png
-
# # # S C O R E / T O P 5 # # #
ScoreBox = [score]box.png
-ScoreGlassBox = [score]glass_box.png
+ScoreGlassBox = [score]glass_box.png
ScoreLevel = [score]level.png
-ScoreLevelRound = [score]levelRound.png
+ScoreLevelRound = [score]levelround.png
ScoreLevel_Dark = [score]level_dark.png
ScoreLevel_Dark_Round = [score]level_dark_round.png
@@ -139,7 +120,6 @@ Rating_6 = [score]rating_6.png
Rating_7 = [score]rating_7.png
# thank you girls and guys!!!
-
# # # P A R T Y # # #
Joker =[party]Joker.png
PartyPlayerButton =[party]playerButton.png
@@ -161,7 +141,6 @@ PartyWinDeco1 =[party]winDecoration.png
PartyWinDeco2 =[party]winDecoration.png
PartyWinDeco3 =[party]winDecoration.png
-
# # # S T A T S # # #
StatMainBG1 = [stat]mainBG1.png
StatMainBG2 = [stat]mainBG2.png
@@ -186,6 +165,7 @@ Leiste2 = [special]bar2.png
JumpToBG = [menu]jumpToBg.png
SongMenuBG = [menu]songMenuBg.png
SongMenuSelectBG = [menu]songMenuSelectBg.png
+PopUpBG = [menu]popUpBG.png
# # # N O T E S # # #
@@ -214,7 +194,6 @@ Rectangle = [helper]rectangle.jpg
ButtonFade = [helper]buttonFade.png
BGFade = [special]bg_fade.png
-
# # # D U E T # # #
LyricIcon_P1 = [sing.player1]lyric_active.png
LyricIconD_P1 = [sing.player1]lyric_inactive.png
@@ -227,4 +206,4 @@ LyricIconD_P4 = [sing.player4]lyric_inactive.png
LyricIcon_P5 = [sing.player5]lyric_active.png
LyricIconD_P5 = [sing.player5]lyric_inactive.png
LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png \ No newline at end of file
+LyricIconD_P6 = [sing.player6]lyric_inactive.png
diff --git a/installerdependencies/documents/license.txt b/installerdependencies/documents/license.txt
index 4964fc70..66f35b98 100644
--- a/installerdependencies/documents/license.txt
+++ b/installerdependencies/documents/license.txt
@@ -1,125 +1,125 @@
-The GNU General Public License (GPL)
-Version 2, June 1991
-Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Everyone is permitted to copy and distribute verbatim copies
-of this license document, but changing it is not allowed.
-
-Preamble
-
-The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification follow.
-
-TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
-
-1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
-
-c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
-
-This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
-
-9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
-
-NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-END OF TERMS AND CONDITIONS
-
-How to Apply These Terms to Your New Programs
-
-If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
-
-To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
-
-one line to give the program's name and a brief idea of what it does.
-Copyright (C)
-
-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; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
-
-Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
-
-Yoyodyne, Inc., hereby disclaims all copyright interest
-in the program `Gnomovision' (which makes passes at compilers)
-written by James Hacker.
-
-signature of Ty Coon, 1 April 1989
-Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
+The GNU General Public License (GPL)
+Version 2, June 1991
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+one line to give the program's name and a brief idea of what it does.
+Copyright (C)
+
+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; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright interest
+in the program `Gnomovision' (which makes passes at compilers)
+written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
diff --git a/plugins/Don't_Get_Worse/Hold_The_Line.bdsproj b/plugins/Don't_Get_Worse/Hold_The_Line.bdsproj
deleted file mode 100644
index 8694fb50..00000000
--- a/plugins/Don't_Get_Worse/Hold_The_Line.bdsproj
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<BorlandProject>
- <PersonalityInfo>
- <Option>
- <Option Name="Personality">Delphi.Personality</Option>
- <Option Name="ProjectType">VCLApplication</Option>
- <Option Name="Version">1.0</Option>
- <Option Name="GUID">{06A9B812-7EBB-46A7-A56A-6DE18E64E79D}</Option>
- </Option>
- </PersonalityInfo>
- <Delphi.Personality>
- <Source>
- <Source Name="MainSource">Hold_The_Line.dpr</Source>
- </Source>
- <FileVersion>
- <FileVersion Name="Version">7.0</FileVersion>
- </FileVersion>
- <Compiler>
- <Compiler Name="A">8</Compiler>
- <Compiler Name="B">0</Compiler>
- <Compiler Name="C">1</Compiler>
- <Compiler Name="D">1</Compiler>
- <Compiler Name="E">0</Compiler>
- <Compiler Name="F">0</Compiler>
- <Compiler Name="G">1</Compiler>
- <Compiler Name="H">1</Compiler>
- <Compiler Name="I">1</Compiler>
- <Compiler Name="J">0</Compiler>
- <Compiler Name="K">0</Compiler>
- <Compiler Name="L">1</Compiler>
- <Compiler Name="M">0</Compiler>
- <Compiler Name="N">1</Compiler>
- <Compiler Name="O">1</Compiler>
- <Compiler Name="P">1</Compiler>
- <Compiler Name="Q">0</Compiler>
- <Compiler Name="R">0</Compiler>
- <Compiler Name="S">0</Compiler>
- <Compiler Name="T">0</Compiler>
- <Compiler Name="U">0</Compiler>
- <Compiler Name="V">1</Compiler>
- <Compiler Name="W">0</Compiler>
- <Compiler Name="X">1</Compiler>
- <Compiler Name="Y">1</Compiler>
- <Compiler Name="Z">1</Compiler>
- <Compiler Name="ShowHints">True</Compiler>
- <Compiler Name="ShowWarnings">True</Compiler>
- <Compiler Name="UnitAliases">WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;</Compiler>
- <Compiler Name="NamespacePrefix"></Compiler>
- <Compiler Name="GenerateDocumentation">False</Compiler>
- <Compiler Name="DefaultNamespace"></Compiler>
- <Compiler Name="SymbolDeprecated">True</Compiler>
- <Compiler Name="SymbolLibrary">True</Compiler>
- <Compiler Name="SymbolPlatform">True</Compiler>
- <Compiler Name="SymbolExperimental">True</Compiler>
- <Compiler Name="UnitLibrary">True</Compiler>
- <Compiler Name="UnitPlatform">True</Compiler>
- <Compiler Name="UnitDeprecated">True</Compiler>
- <Compiler Name="UnitExperimental">True</Compiler>
- <Compiler Name="HResultCompat">True</Compiler>
- <Compiler Name="HidingMember">True</Compiler>
- <Compiler Name="HiddenVirtual">True</Compiler>
- <Compiler Name="Garbage">True</Compiler>
- <Compiler Name="BoundsError">True</Compiler>
- <Compiler Name="ZeroNilCompat">True</Compiler>
- <Compiler Name="StringConstTruncated">True</Compiler>
- <Compiler Name="ForLoopVarVarPar">True</Compiler>
- <Compiler Name="TypedConstVarPar">True</Compiler>
- <Compiler Name="AsgToTypedConst">True</Compiler>
- <Compiler Name="CaseLabelRange">True</Compiler>
- <Compiler Name="ForVariable">True</Compiler>
- <Compiler Name="ConstructingAbstract">True</Compiler>
- <Compiler Name="ComparisonFalse">True</Compiler>
- <Compiler Name="ComparisonTrue">True</Compiler>
- <Compiler Name="ComparingSignedUnsigned">True</Compiler>
- <Compiler Name="CombiningSignedUnsigned">True</Compiler>
- <Compiler Name="UnsupportedConstruct">True</Compiler>
- <Compiler Name="FileOpen">True</Compiler>
- <Compiler Name="FileOpenUnitSrc">True</Compiler>
- <Compiler Name="BadGlobalSymbol">True</Compiler>
- <Compiler Name="DuplicateConstructorDestructor">True</Compiler>
- <Compiler Name="InvalidDirective">True</Compiler>
- <Compiler Name="PackageNoLink">True</Compiler>
- <Compiler Name="PackageThreadVar">True</Compiler>
- <Compiler Name="ImplicitImport">True</Compiler>
- <Compiler Name="HPPEMITIgnored">True</Compiler>
- <Compiler Name="NoRetVal">True</Compiler>
- <Compiler Name="UseBeforeDef">True</Compiler>
- <Compiler Name="ForLoopVarUndef">True</Compiler>
- <Compiler Name="UnitNameMismatch">True</Compiler>
- <Compiler Name="NoCFGFileFound">True</Compiler>
- <Compiler Name="ImplicitVariants">True</Compiler>
- <Compiler Name="UnicodeToLocale">True</Compiler>
- <Compiler Name="LocaleToUnicode">True</Compiler>
- <Compiler Name="ImagebaseMultiple">True</Compiler>
- <Compiler Name="SuspiciousTypecast">True</Compiler>
- <Compiler Name="PrivatePropAccessor">True</Compiler>
- <Compiler Name="UnsafeType">False</Compiler>
- <Compiler Name="UnsafeCode">False</Compiler>
- <Compiler Name="UnsafeCast">False</Compiler>
- <Compiler Name="OptionTruncated">True</Compiler>
- <Compiler Name="WideCharReduced">True</Compiler>
- <Compiler Name="DuplicatesIgnored">True</Compiler>
- <Compiler Name="UnitInitSeq">True</Compiler>
- <Compiler Name="LocalPInvoke">True</Compiler>
- <Compiler Name="MessageDirective">True</Compiler>
- <Compiler Name="CodePage"></Compiler>
- </Compiler>
- <Linker>
- <Linker Name="MapFile">0</Linker>
- <Linker Name="OutputObjs">0</Linker>
- <Linker Name="GenerateHpps">False</Linker>
- <Linker Name="ConsoleApp">1</Linker>
- <Linker Name="DebugInfo">False</Linker>
- <Linker Name="RemoteSymbols">False</Linker>
- <Linker Name="GenerateDRC">False</Linker>
- <Linker Name="MinStackSize">16384</Linker>
- <Linker Name="MaxStackSize">1048576</Linker>
- <Linker Name="ImageBase">4194304</Linker>
- <Linker Name="ExeDescription"></Linker>
- </Linker>
- <Directories>
- <Directories Name="OutputDir"></Directories>
- <Directories Name="UnitOutputDir"></Directories>
- <Directories Name="PackageDLLOutputDir"></Directories>
- <Directories Name="PackageDCPOutputDir"></Directories>
- <Directories Name="SearchPath">..\..\src\lib\JEDI-SDL\SDL\Pas</Directories>
- <Directories Name="Packages"></Directories>
- <Directories Name="Conditionals"></Directories>
- <Directories Name="DebugSourceDirs"></Directories>
- <Directories Name="UsePackages">False</Directories>
- </Directories>
- <Parameters>
- <Parameters Name="RunParams"></Parameters>
- <Parameters Name="HostApplication"></Parameters>
- <Parameters Name="Launcher"></Parameters>
- <Parameters Name="UseLauncher">False</Parameters>
- <Parameters Name="DebugCWD"></Parameters>
- <Parameters Name="Debug Symbols Search Path"></Parameters>
- <Parameters Name="LoadAllSymbols">True</Parameters>
- <Parameters Name="LoadUnspecifiedSymbols">False</Parameters>
- </Parameters>
- <Language>
- <Language Name="ActiveLang"></Language>
- <Language Name="ProjectLang">$00000000</Language>
- <Language Name="RootDir"></Language>
- </Language>
- <VersionInfo>
- <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
- <VersionInfo Name="AutoIncBuild">False</VersionInfo>
- <VersionInfo Name="MajorVer">1</VersionInfo>
- <VersionInfo Name="MinorVer">0</VersionInfo>
- <VersionInfo Name="Release">0</VersionInfo>
- <VersionInfo Name="Build">0</VersionInfo>
- <VersionInfo Name="Debug">False</VersionInfo>
- <VersionInfo Name="PreRelease">False</VersionInfo>
- <VersionInfo Name="Special">False</VersionInfo>
- <VersionInfo Name="Private">False</VersionInfo>
- <VersionInfo Name="DLL">False</VersionInfo>
- <VersionInfo Name="Locale">1031</VersionInfo>
- <VersionInfo Name="CodePage">1252</VersionInfo>
- </VersionInfo>
- <VersionInfoKeys>
- <VersionInfoKeys Name="CompanyName"></VersionInfoKeys>
- <VersionInfoKeys Name="FileDescription"></VersionInfoKeys>
- <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
- <VersionInfoKeys Name="InternalName"></VersionInfoKeys>
- <VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys>
- <VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys>
- <VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys>
- <VersionInfoKeys Name="ProductName"></VersionInfoKeys>
- <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
- <VersionInfoKeys Name="Comments"></VersionInfoKeys>
- </VersionInfoKeys>
- </Delphi.Personality>
-</BorlandProject>
diff --git a/plugins/Don't_Get_Worse/Hold_The_Line.lpi b/plugins/Don't_Get_Worse/Hold_The_Line.lpi
deleted file mode 100644
index bb21d5d9..00000000
--- a/plugins/Don't_Get_Worse/Hold_The_Line.lpi
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0"?>
-<CONFIG>
- <ProjectOptions>
- <PathDelim Value="\"/>
- <Version Value="6"/>
- <General>
- <Flags>
- <MainUnitHasUsesSectionForAllUnits Value="False"/>
- <MainUnitHasCreateFormStatements Value="False"/>
- <MainUnitHasTitleStatement Value="False"/>
- </Flags>
- <MainUnit Value="0"/>
- <TargetFileExt Value=".exe"/>
- <Title Value="Hold_The_Line"/>
- <ActiveEditorIndexAtStart Value="2"/>
- </General>
- <VersionInfo>
- <ProjectVersion Value=""/>
- <Language Value=""/>
- <CharSet Value=""/>
- </VersionInfo>
- <PublishOptions>
- <Version Value="2"/>
- <IgnoreBinaries Value="False"/>
- <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
- <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
- </PublishOptions>
- <RunParams>
- <local>
- <FormatVersion Value="1"/>
- <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
- </local>
- </RunParams>
- <Units Count="4">
- <Unit0>
- <Filename Value="Hold_The_Line.dpr"/>
- <IsPartOfProject Value="True"/>
- <UnitName Value="Hold_The_Line"/>
- <CursorPos X="22" Y="1"/>
- <TopLine Value="1"/>
- <EditorIndex Value="0"/>
- <UsageCount Value="20"/>
- <Loaded Value="True"/>
- </Unit0>
- <Unit1>
- <Filename Value="..\SDK\StrUtils.pas"/>
- <UnitName Value="StrUtils"/>
- <CursorPos X="4" Y="13"/>
- <TopLine Value="1"/>
- <EditorIndex Value="2"/>
- <UsageCount Value="10"/>
- <Loaded Value="True"/>
- </Unit1>
- <Unit2>
- <Filename Value="..\..\src\lib\JEDI-SDL\OpenGL\Pas\gl.pas"/>
- <UnitName Value="gl"/>
- <CursorPos X="1" Y="1"/>
- <TopLine Value="1"/>
- <UsageCount Value="10"/>
- </Unit2>
- <Unit3>
- <Filename Value="..\SDK\ModiSDK.pas"/>
- <UnitName Value="ModiSDK"/>
- <CursorPos X="1" Y="8"/>
- <TopLine Value="1"/>
- <EditorIndex Value="1"/>
- <UsageCount Value="10"/>
- <Loaded Value="True"/>
- </Unit3>
- </Units>
- <JumpHistory Count="1" HistoryIndex="0">
- <Position1>
- <Filename Value="..\SDK\StrUtils.pas"/>
- <Caret Line="1" Column="1" TopLine="1"/>
- </Position1>
- </JumpHistory>
- </ProjectOptions>
- <CompilerOptions>
- <Version Value="8"/>
- <PathDelim Value="\"/>
- <SearchPaths>
- <IncludeFiles Value="..\..\src\lib\JEDI-SDL\SDL\Pas\"/>
- </SearchPaths>
- <Parsing>
- <SyntaxOptions>
- <CStyleOperator Value="False"/>
- </SyntaxOptions>
- </Parsing>
- <Linking>
- <Options>
- <ExecutableType Value="Library"/>
- </Options>
- </Linking>
- <Other>
- <CompilerPath Value="$(CompPath)"/>
- </Other>
- </CompilerOptions>
- <Debugging>
- <Exceptions Count="2">
- <Item1>
- <Name Value="ECodetoolError"/>
- </Item1>
- <Item2>
- <Name Value="EFOpenError"/>
- </Item2>
- </Exceptions>
- </Debugging>
-</CONFIG>
diff --git a/src/Makefile.in b/src/Makefile.in
index 3d4b6def..06e62c43 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -122,7 +122,7 @@ endif
LIBS ?= @LIBS@
LDFLAGS ?= @LDFLAGS@
-linkflags := $(sort $(LDFLAGS) $(LIBS))
+linkflags := -L/usr/lib $(sort $(LDFLAGS) $(LIBS))
ifneq ($(linkflags),)
PLINKFLAGS := -k"$(linkflags)"
endif
diff --git a/src/base/TextGL.pas b/src/base/TextGL.pas
index c8de4e28..7fe98d29 100644
--- a/src/base/TextGL.pas
+++ b/src/base/TextGL.pas
@@ -33,170 +33,101 @@ interface
{$I switches.inc}
-// as long as the transition to freetype is not finished
-// use the old implementation
-{$IFDEF UseFreetype}
- {$INCLUDE TextGLFreetype.pas}
-{$ELSE}
uses
gl,
+ glext,
SDL,
+ Classes,
UTexture,
+ UFont,
+ UPath,
ULog;
+type
+ PGLFont = ^TGLFont;
+ TGLFont = record
+ Font: TScalableFont;
+ X, Y, Z: real;
+ end;
+
+var
+ Fonts: array of TGLFont;
+ ActFont: integer;
+
procedure BuildFont; // build our bitmap font
procedure KillFont; // delete the font
-function glTextWidth(const text: string): real; // returns text width
-procedure glPrint(const text: string); // custom GL "Print" routine
+function glTextWidth(const text: UTF8String): real; // returns text width
+procedure glPrint(const text: UTF8String); // custom GL "Print" routine
procedure ResetFont(); // reset font settings of active font
procedure SetFontPos(X, Y: real); // sets X and Y
procedure SetFontZ(Z: real); // sets Z
procedure SetFontSize(Size: real);
procedure SetFontStyle(Style: integer); // sets active font style (normal, bold, etc)
procedure SetFontItalic(Enable: boolean); // sets italic type letter (works for all fonts)
-procedure SetFontAspectW(Aspect: real);
procedure SetFontReflection(Enable:boolean;Spacing: real); // enables/disables text reflection
-//function NextPowerOfTwo(Value: integer): integer;
-// Checks if the ttf exists, if yes then a SDL_ttf is returned
-//function LoadFont(FileName: PAnsiChar; PointSize: integer):PTTF_Font;
-// Does the renderstuff, color is in $ffeecc style
-//function RenderText(font: PTTF_Font; Text:PAnsiChar; Color: Cardinal):PSDL_Surface;
-
-type
- TTextGL = record
- X: real;
- Y: real;
- Z: real;
- Text: string;
- Size: real;
- ColR: real;
- ColG: real;
- ColB: real;
- end;
-
- PFont = ^TFont;
- TFont = record
- Tex: TTexture;
- Width: array[0..255] of byte;
- AspectW: real;
- Centered: boolean;
- Outline: real;
- Italic: boolean;
- Reflection: boolean;
- ReflectionSpacing: real;
- end;
-
-
-var
- Fonts: array of TFont;
- ActFont: integer;
-
-
implementation
uses
- Classes,
+ UTextEncoding,
SysUtils,
IniFiles,
UCommon,
- UGraphic,
UMain,
- UPath;
-
-var
- // Colours for the reflection
- TempColor: array[0..3] of GLfloat;
+ UPathUtils;
-{**
- * Load font info.
- * FontFile is the name of the image (.png) not the data (.dat) file
- *}
-procedure LoadFontInfo(FontID: integer; const FontFile: string);
+function FindFontFile(FontIni: TCustomIniFile; Font: string): IPath;
var
- Stream: TFileStream;
- DatFile: string;
+ Filename: IPath;
begin
- DatFile := ChangeFileExt(FontFile, '.dat');
- FillChar(Fonts[FontID].Width[0], Length(Fonts[FontID].Width), 0);
-
- Stream := nil;
- try
- Stream := TFileStream.Create(DatFile, fmOpenRead);
- Stream.Read(Fonts[FontID].Width, 256);
- except
- Log.LogError('Error while reading font['+ inttostr(FontID) +']', 'LoadFontInfo');
- end;
- Stream.Free;
+ Filename := Path(FontIni.ReadString(Font, 'File', ''));
+ Result := FontPath.Append(Filename);
+ // if path does not exist, try as an absolute path
+ if (not Result.IsFile) then
+ Result := Filename;
end;
-// Builds bitmap fonts
procedure BuildFont;
var
- Count: integer;
FontIni: TMemIniFile;
- FontFile: string; // filename of the image (with .png/... ending)
+ FontFile: IPath;
begin
ActFont := 0;
SetLength(Fonts, 4);
- FontIni := TMemIniFile.Create(FontPath + 'fonts.ini');
-
- // Normal
-
- FontFile := FontPath + FontIni.ReadString('Normal', 'File', '');
-
- Fonts[0].Tex := Texture.LoadTexture(true, FontFile, TEXTURE_TYPE_TRANSPARENT, 0);
- Fonts[0].Tex.H := 30;
- Fonts[0].AspectW := 0.9;
- Fonts[0].Outline := 0;
-
- LoadFontInfo(0, FontFile);
-
- // Bold
-
- FontFile := FontPath + FontIni.ReadString('Bold', 'File', '');
-
- Fonts[1].Tex := Texture.LoadTexture(true, FontFile, TEXTURE_TYPE_TRANSPARENT, 0);
- Fonts[1].Tex.H := 30;
- Fonts[1].AspectW := 1;
- Fonts[1].Outline := 0;
+ FontIni := TMemIniFile.Create(FontPath.Append('fonts.ini').ToNative);
- LoadFontInfo(1, FontFile);
- for Count := 0 to 255 do
- Fonts[1].Width[Count] := Fonts[1].Width[Count] div 2;
-
- // Outline1
-
- FontFile := FontPath + FontIni.ReadString('Outline1', 'File', '');
-
- Fonts[2].Tex := Texture.LoadTexture(true, FontFile, TEXTURE_TYPE_TRANSPARENT, 0);
- Fonts[2].Tex.H := 30;
- Fonts[2].AspectW := 0.95;
- Fonts[2].Outline := 5;
-
- LoadFontInfo(2, FontFile);
- for Count := 0 to 255 do
- Fonts[2].Width[Count] := Fonts[2].Width[Count] div 2 + 2;
+ try
- // Outline2
+ // Normal
+ FontFile := FindFontFile(FontIni, 'Normal');
+ Fonts[0].Font := TFTScalableFont.Create(FontFile, 64);
+ //Fonts[0].Font.GlyphSpacing := 1.4;
+ //Fonts[0].Font.Aspect := 1.2;
- FontFile := FontPath + FontIni.ReadString('Outline2', 'File', '');
+ // Bold
+ FontFile := FindFontFile(FontIni, 'Bold');
+ Fonts[1].Font := TFTScalableFont.Create(FontFile, 64);
- Fonts[3].Tex := Texture.LoadTexture(true, FontFile, TEXTURE_TYPE_TRANSPARENT, 0);
- Fonts[3].Tex.H := 30;
- Fonts[3].AspectW := 0.95;
- Fonts[3].Outline := 4;
+ // Outline1
+ FontFile := FindFontFile(FontIni, 'Outline1');
+ Fonts[2].Font := TFTScalableOutlineFont.Create(FontFile, 64, 0.06);
+ //TFTScalableOutlineFont(Fonts[2].Font).SetOutlineColor(0.3, 0.3, 0.3);
- LoadFontInfo(3, FontFile);
- for Count := 0 to 255 do
- Fonts[3].Width[Count] := Fonts[3].Width[Count] + 1;
+ // Outline2
+ FontFile := FindFontFile(FontIni, 'Outline2');
+ Fonts[3].Font := TFTScalableOutlineFont.Create(FontFile, 64, 0.08);
+ except
+ on E: Exception do
+ Log.LogCritical(E.Message, 'BuildFont');
+ end;
// close ini-file
FontIni.Free;
end;
+
// Deletes the font
procedure KillFont;
begin
@@ -204,133 +135,31 @@ begin
//glDeleteLists(..., 256);
end;
-function glTextWidth(const text: string): real;
+function glTextWidth(const text: UTF8String): real;
var
- Letter: char;
- i: integer;
- Font: PFont;
+ Bounds: TBoundsDbl;
begin
- Result := 0;
- Font := @Fonts[ActFont];
-
- for i := 1 to Length(text) do
- begin
- Letter := Text[i];
- Result := Result + Font.Width[Ord(Letter)] * Font.Tex.H / 30 * Font.AspectW;
- end;
-
- if ((Result > 0) and Font.Italic) then
- Result := Result + 12 * Font.Tex.H / 60 * Font.AspectW;
-end;
-
-procedure glPrintLetter(Letter: char);
-var
- TexX, TexY: real;
- TexR, TexB: real;
- TexHeight: real;
- FWidth: real;
- PL, PT: real;
- PR, PB: real;
- XItal: real; // X shift for italic type letter
- ReflectionSpacing: real; // Distance of the reflection
- Font: PFont;
- Tex: PTexture;
-begin
- Font := @Fonts[ActFont];
- Tex := @Font.Tex;
-
- FWidth := Font.Width[Ord(Letter)];
-
- Tex.W := FWidth * (Tex.H/30) * Font.AspectW;
-
- // set texture positions
- TexX := (ord(Letter) mod 16) * 1/16 + 1/32 - FWidth/1024 - Font.Outline/1024;
- TexY := (ord(Letter) div 16) * 1/16 + 2/1024;
- TexR := (ord(Letter) mod 16) * 1/16 + 1/32 + FWidth/1024 + Font.Outline/1024;
- TexB := (1 + ord(Letter) div 16) * 1/16 - 2/1024;
-
- TexHeight := TexB - TexY;
-
- // set vector positions
- PL := Tex.X - Font.Outline * (Tex.H/30) * Font.AspectW /2;
- PT := Tex.Y;
- PR := PL + Tex.W + Font.Outline * (Tex.H/30) * Font.AspectW;
- PB := PT + Tex.H;
-
- if (not Font.Italic) then
- XItal := 0
- else
- XItal := 12;
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, Tex.TexNum);
-
- glBegin(GL_QUADS);
- glTexCoord2f(TexX, TexY); glVertex2f(PL+XItal, PT);
- glTexCoord2f(TexX, TexB); glVertex2f(PL, PB);
- glTexCoord2f(TexR, TexB); glVertex2f(PR, PB);
- glTexCoord2f(TexR, TexY); glVertex2f(PR+XItal, PT);
- glEnd;
-
- // <mog> Reflection
- // Yes it would make sense to put this in an extra procedure,
- // but this works, doesn't take much lines, and is almost lightweight
- if Font.Reflection then
- begin
- ReflectionSpacing := Font.ReflectionSpacing + Tex.H/2;
-
- glDepthRange(0, 10);
- glDepthFunc(GL_LEQUAL);
- glEnable(GL_DEPTH_TEST);
-
- glBegin(GL_QUADS);
- glColor4f(TempColor[0], TempColor[1], TempColor[2], 0);
- glTexCoord2f(TexX, TexY + TexHeight/2);
- glVertex3f(PL, PB + ReflectionSpacing - Tex.H/2, Tex.z);
-
- glColor4f(TempColor[0], TempColor[1], TempColor[2], Tex.Alpha-0.3);
- glTexCoord2f(TexX, TexB );
- glVertex3f(PL + XItal, PT + ReflectionSpacing, Tex.z);
-
- glTexCoord2f(TexR, TexB );
- glVertex3f(PR + XItal, PT + ReflectionSpacing, Tex.z);
-
- glColor4f(TempColor[0], TempColor[1], TempColor[2], 0);
- glTexCoord2f(TexR, TexY + TexHeight/2);
- glVertex3f(PR, PB + ReflectionSpacing - Tex.H/2, Tex.z);
- glEnd;
-
- glDisable(GL_DEPTH_TEST);
- end; // reflection
-
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
-
- Tex.X := Tex.X + Tex.W;
-
- //write the colour back
- glColor4fv(@TempColor);
+ Bounds := Fonts[ActFont].Font.BBox(Text, true);
+ Result := Bounds.Right - Bounds.Left;
end;
// Custom GL "Print" Routine
-procedure glPrint(const Text: string);
+procedure glPrint(const Text: UTF8String);
var
- Pos: integer;
+ GLFont: PGLFont;
begin
// if there is no text do nothing
if (Text = '') then
Exit;
- //Save the actual color and alpha (for reflection)
- glGetFloatv(GL_CURRENT_COLOR, @TempColor);
+ GLFont := @Fonts[ActFont];
- for Pos := 1 to Length(Text) do
- begin
- glPrintLetter(Text[Pos]);
- end;
+ glPushMatrix();
+ // set font position
+ glTranslatef(GLFont.X, GLFont.Y + GLFont.Font.Ascender, GLFont.Z);
+ // draw string
+ GLFont.Font.Print(Text);
+ glPopMatrix();
end;
procedure ResetFont();
@@ -343,18 +172,18 @@ end;
procedure SetFontPos(X, Y: real);
begin
- Fonts[ActFont].Tex.X := X;
- Fonts[ActFont].Tex.Y := Y;
+ Fonts[ActFont].X := X;
+ Fonts[ActFont].Y := Y;
end;
procedure SetFontZ(Z: real);
begin
- Fonts[ActFont].Tex.Z := Z;
+ Fonts[ActFont].Z := Z;
end;
procedure SetFontSize(Size: real);
begin
- Fonts[ActFont].Tex.H := Size;
+ Fonts[ActFont].Font.Height := Size;
end;
procedure SetFontStyle(Style: integer);
@@ -364,21 +193,19 @@ end;
procedure SetFontItalic(Enable: boolean);
begin
- Fonts[ActFont].Italic := Enable;
-end;
-
-procedure SetFontAspectW(Aspect: real);
-begin
- Fonts[ActFont].AspectW := Aspect;
+ if (Enable) then
+ Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style + [Italic]
+ else
+ Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style - [Italic]
end;
procedure SetFontReflection(Enable: boolean; Spacing: real);
begin
- Fonts[ActFont].Reflection := Enable;
- Fonts[ActFont].ReflectionSpacing := Spacing;
+ if (Enable) then
+ Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style + [Reflect]
+ else
+ Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style - [Reflect];
+ Fonts[ActFont].Font.ReflectionSpacing := Spacing - Fonts[ActFont].Font.Descender;
end;
end.
-
-{$ENDIF}
-
diff --git a/src/base/TextGLFreetype.pas b/src/base/TextGLFreetype.pas
deleted file mode 100644
index 61b26693..00000000
--- a/src/base/TextGLFreetype.pas
+++ /dev/null
@@ -1,222 +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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/TextGL.pas $
- * $Id: TextGL.pas 1483 2008-10-28 19:01:20Z tobigun $
- *}
-
-(*
-unit TextGL;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-*)
-
-uses
- gl,
- glext,
- SDL,
- UTexture,
- UFont,
- Classes,
- ULog;
-
-type
- PGLFont = ^TGLFont;
- TGLFont = record
- Font: TScalableFont;
- X, Y, Z: real;
- end;
-
-var
- Fonts: array of TGLFont;
- ActFont: integer;
-
-procedure BuildFont; // build our bitmap font
-procedure KillFont; // delete the font
-function glTextWidth(const text: string): real; // returns text width
-procedure glPrint(const text: string); // custom GL "Print" routine
-procedure ResetFont(); // reset font settings of active font
-procedure SetFontPos(X, Y: real); // sets X and Y
-procedure SetFontZ(Z: real); // sets Z
-procedure SetFontSize(Size: real);
-procedure SetFontStyle(Style: integer); // sets active font style (normal, bold, etc)
-procedure SetFontItalic(Enable: boolean); // sets italic type letter (works for all fonts)
-procedure SetFontReflection(Enable:boolean;Spacing: real); // enables/disables text reflection
-
-implementation
-
-uses
- UMain,
- UCommon,
- UTextEncoding,
- SysUtils,
- IniFiles;
-
-function FindFontFile(FontIni: TCustomIniFile; Font: string): string;
-var
- Filename: string;
-begin
- Filename := FontIni.ReadString(Font, 'File', '');
- Result := FontPath + Filename;
- // if path does not exist, try as an absolute path
- if (not FileExists(Result)) then
- Result := Filename;
-end;
-
-procedure BuildFont;
-var
- FontIni: TMemIniFile;
- //BitmapFont: TBitmapFont;
- FontFile: string;
-begin
- ActFont := 0;
-
- SetLength(Fonts, 4);
- FontIni := TMemIniFile.Create(FontPath + 'fontsTTF.ini');
- //FontIni := TMemIniFile.Create(FontPath + 'fonts.ini');
-
- try
-
- // Normal
- FontFile := FindFontFile(FontIni, 'Normal');
- Fonts[0].Font := TFTScalableFont.Create(FontFile, 64);
- //Fonts[0].Font.GlyphSpacing := 1.4;
- //Fonts[0].Font.Aspect := 1.2;
-
- {
- BitmapFont := TBitmapFont.Create(FontFile, 0, 19, 35, -10);
- BitmapFont.CorrectWidths(2, 0);
- Fonts[0].Font := TScalableFont.Create(BitmapFont, false);
- }
-
- //Fonts[0].Font.Aspect := 0.9;
-
- // Bold
- FontFile := FindFontFile(FontIni, 'Bold');
- Fonts[1].Font := TFTScalableFont.Create(FontFile, 64);
-
- // Outline1
- FontFile := FindFontFile(FontIni, 'Outline1');
- Fonts[2].Font := TFTScalableOutlineFont.Create(FontFile, 64, 0.06);
- //TFTScalableOutlineFont(Fonts[2].Font).SetOutlineColor(0.3, 0.3, 0.3);
-
- // Outline2
- FontFile := FindFontFile(FontIni, 'Outline2');
- Fonts[3].Font := TFTScalableOutlineFont.Create(FontFile, 64, 0.08);
-
- except on E: Exception do
- Log.LogCritical(E.Message, 'BuildFont');
- end;
-
- // close ini-file
- FontIni.Free;
-end;
-
-
-// Deletes the font
-procedure KillFont;
-begin
- // delete all characters
- //glDeleteLists(..., 256);
-end;
-
-function glTextWidth(const text: string): real;
-var
- Bounds: TBoundsDbl;
-begin
- // FIXME: remove conversion
- Bounds := Fonts[ActFont].Font.BBox(RecodeString(Text, encCP1252), true);
- Result := Bounds.Right - Bounds.Left;
-end;
-
-// Custom GL "Print" Routine
-procedure glPrint(const Text: string);
-var
- GLFont: PGLFont;
-begin
- // if there is no text do nothing
- if (Text = '') then
- Exit;
-
- GLFont := @Fonts[ActFont];
-
- glPushMatrix();
- // set font position
- glTranslatef(GLFont.X, GLFont.Y + GLFont.Font.Ascender, GLFont.Z);
- // draw string
- // FIXME: remove conversion
- GLFont.Font.Print(RecodeString(Text, encCP1252));
- glPopMatrix();
-end;
-
-procedure ResetFont();
-begin
- SetFontPos(0, 0);
- SetFontZ(0);
- SetFontItalic(False);
- SetFontReflection(False, 0);
-end;
-
-procedure SetFontPos(X, Y: real);
-begin
- Fonts[ActFont].X := X;
- Fonts[ActFont].Y := Y;
-end;
-
-procedure SetFontZ(Z: real);
-begin
- Fonts[ActFont].Z := Z;
-end;
-
-procedure SetFontSize(Size: real);
-begin
- Fonts[ActFont].Font.Height := Size;
-end;
-
-procedure SetFontStyle(Style: integer);
-begin
- ActFont := Style;
-end;
-
-procedure SetFontItalic(Enable: boolean);
-begin
- if (Enable) then
- Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style + [Italic]
- else
- Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style - [Italic]
-end;
-
-procedure SetFontReflection(Enable: boolean; Spacing: real);
-begin
- if (Enable) then
- Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style + [Reflect]
- else
- Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style - [Reflect];
- Fonts[ActFont].Font.ReflectionSpacing := Spacing - Fonts[ActFont].Font.Descender;
-end;
-
-end.
diff --git a/src/base/UBeatTimer.pas b/src/base/UBeatTimer.pas
index 2983fdee..310a49cd 100644
--- a/src/base/UBeatTimer.pas
+++ b/src/base/UBeatTimer.pas
@@ -1,170 +1,170 @@
-{* 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/base/USingNotes.pas $
- * $Id: USingNotes.pas 1406 2008-09-23 21:43:52Z k-m_schindler $
- *}
-
-unit UBeatTimer;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- UTime;
-
-type
- (**
- * TLyricsState contains all information concerning the
- * state of the lyrics, e.g. the current beat or duration of the lyrics.
- *)
- TLyricsState = class
- private
- Timer: TRelativeTimer; // keeps track of the current time
- public
- OldBeat: integer; // previous discovered beat
- CurrentBeat: integer; // current beat (rounded)
- MidBeat: real; // current beat (float)
-
- // now we use this for super synchronization!
- // only used when analyzing voice
- // TODO: change ...D to ...Detect(ed)
- OldBeatD: integer; // previous discovered beat
- CurrentBeatD: integer; // current discovered beat (rounded)
- MidBeatD: real; // current discovered beat (float)
-
- // we use this for audible clicks
- // TODO: Change ...C to ...Click
- OldBeatC: integer; // previous discovered beat
- CurrentBeatC: integer;
- MidBeatC: real; // like CurrentBeatC
-
- OldLine: integer; // previous displayed sentence
-
- StartTime: real; // time till start of lyrics (= Gap)
- TotalTime: real; // total song time
-
- constructor Create();
- procedure Pause();
- procedure Resume();
-
- procedure Reset();
- procedure UpdateBeats();
-
- (**
- * current song time (in seconds) used as base-timer for lyrics etc.
- *)
- function GetCurrentTime(): real;
- procedure SetCurrentTime(Time: real);
- end;
-
-implementation
-uses UNote, Math;
-
-
-constructor TLyricsState.Create();
-begin
- // create a triggered timer, so we can Pause() it, set the time
- // and Resume() it afterwards for better synching.
- Timer := TRelativeTimer.Create(true);
-
- // reset state
- Reset();
-end;
-
-procedure TLyricsState.Pause();
-begin
- Timer.Pause();
-end;
-
-procedure TLyricsState.Resume();
-begin
- Timer.Resume();
-end;
-
-procedure TLyricsState.SetCurrentTime(Time: real);
-begin
- // do not start the timer (if not started already),
- // after setting the current time
- Timer.SetTime(Time, false);
-end;
-
-function TLyricsState.GetCurrentTime(): real;
-begin
- Result := Timer.GetTime();
-end;
-
-(**
- * Resets the timer and state of the lyrics.
- * The timer will be stopped afterwards so you have to call Resume()
- * to start the lyrics timer.
- *)
-procedure TLyricsState.Reset();
-begin
- Pause();
- SetCurrentTime(0);
-
- StartTime := 0;
- TotalTime := 0;
-
- OldBeat := -1;
- MidBeat := -1;
- CurrentBeat := -1;
-
- OldBeatC := -1;
- MidBeatC := -1;
- CurrentBeatC := -1;
-
- OldBeatD := -1;
- MidBeatD := -1;
- CurrentBeatD := -1;
-end;
-
-(**
- * Updates the beat information (CurrentBeat/MidBeat/...) according to the
- * current lyric time.
- *)
-procedure TLyricsState.UpdateBeats();
-var
- CurLyricsTime: real;
-begin
- CurLyricsTime := GetCurrentTime();
-
- OldBeat := CurrentBeat;
- MidBeat := GetMidBeat(CurLyricsTime - StartTime / 1000);
- CurrentBeat := Floor(MidBeat);
-
- OldBeatC := CurrentBeatC;
- MidBeatC := GetMidBeat(CurLyricsTime - StartTime / 1000);
- CurrentBeatC := Floor(MidBeatC);
-
- OldBeatD := CurrentBeatD;
- // MidBeatD = MidBeat with additional GAP
- MidBeatD := -0.5 + GetMidBeat(CurLyricsTime - (StartTime + 120 + 20) / 1000);
- CurrentBeatD := Floor(MidBeatD);
-end;
-
+{* 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 UBeatTimer;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ UTime;
+
+type
+ (**
+ * TLyricsState contains all information concerning the
+ * state of the lyrics, e.g. the current beat or duration of the lyrics.
+ *)
+ TLyricsState = class
+ private
+ Timer: TRelativeTimer; // keeps track of the current time
+ public
+ OldBeat: integer; // previous discovered beat
+ CurrentBeat: integer; // current beat (rounded)
+ MidBeat: real; // current beat (float)
+
+ // now we use this for super synchronization!
+ // only used when analyzing voice
+ // TODO: change ...D to ...Detect(ed)
+ OldBeatD: integer; // previous discovered beat
+ CurrentBeatD: integer; // current discovered beat (rounded)
+ MidBeatD: real; // current discovered beat (float)
+
+ // we use this for audible clicks
+ // TODO: Change ...C to ...Click
+ OldBeatC: integer; // previous discovered beat
+ CurrentBeatC: integer;
+ MidBeatC: real; // like CurrentBeatC
+
+ OldLine: integer; // previous displayed sentence
+
+ StartTime: real; // time till start of lyrics (= Gap)
+ TotalTime: real; // total song time
+
+ constructor Create();
+ procedure Pause();
+ procedure Resume();
+
+ procedure Reset();
+ procedure UpdateBeats();
+
+ (**
+ * current song time (in seconds) used as base-timer for lyrics etc.
+ *)
+ function GetCurrentTime(): real;
+ procedure SetCurrentTime(Time: real);
+ end;
+
+implementation
+uses UNote, Math;
+
+
+constructor TLyricsState.Create();
+begin
+ // create a triggered timer, so we can Pause() it, set the time
+ // and Resume() it afterwards for better synching.
+ Timer := TRelativeTimer.Create(true);
+
+ // reset state
+ Reset();
+end;
+
+procedure TLyricsState.Pause();
+begin
+ Timer.Pause();
+end;
+
+procedure TLyricsState.Resume();
+begin
+ Timer.Resume();
+end;
+
+procedure TLyricsState.SetCurrentTime(Time: real);
+begin
+ // do not start the timer (if not started already),
+ // after setting the current time
+ Timer.SetTime(Time, false);
+end;
+
+function TLyricsState.GetCurrentTime(): real;
+begin
+ Result := Timer.GetTime();
+end;
+
+(**
+ * Resets the timer and state of the lyrics.
+ * The timer will be stopped afterwards so you have to call Resume()
+ * to start the lyrics timer.
+ *)
+procedure TLyricsState.Reset();
+begin
+ Pause();
+ SetCurrentTime(0);
+
+ StartTime := 0;
+ TotalTime := 0;
+
+ OldBeat := -1;
+ MidBeat := -1;
+ CurrentBeat := -1;
+
+ OldBeatC := -1;
+ MidBeatC := -1;
+ CurrentBeatC := -1;
+
+ OldBeatD := -1;
+ MidBeatD := -1;
+ CurrentBeatD := -1;
+end;
+
+(**
+ * Updates the beat information (CurrentBeat/MidBeat/...) according to the
+ * current lyric time.
+ *)
+procedure TLyricsState.UpdateBeats();
+var
+ CurLyricsTime: real;
+begin
+ CurLyricsTime := GetCurrentTime();
+
+ OldBeat := CurrentBeat;
+ MidBeat := GetMidBeat(CurLyricsTime - StartTime / 1000);
+ CurrentBeat := Floor(MidBeat);
+
+ OldBeatC := CurrentBeatC;
+ MidBeatC := GetMidBeat(CurLyricsTime - StartTime / 1000);
+ CurrentBeatC := Floor(MidBeatC);
+
+ OldBeatD := CurrentBeatD;
+ // MidBeatD = MidBeat with additional GAP
+ MidBeatD := -0.5 + GetMidBeat(CurLyricsTime - (StartTime + 120 + 20) / 1000);
+ CurrentBeatD := Floor(MidBeatD);
+end;
+
end. \ No newline at end of file
diff --git a/src/base/UCatCovers.pas b/src/base/UCatCovers.pas
index 6ef81b68..6e004b22 100644
--- a/src/base/UCatCovers.pas
+++ b/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,10 +64,11 @@ uses
IniFiles,
SysUtils,
Classes,
- // UFiles,
+ UFilesystem,
ULog,
UMain,
- UPath;
+ UUnicodeUtils,
+ UPathUtils;
constructor TCatCovers.Create;
begin
@@ -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/src/base/UCommandLine.pas b/src/base/UCommandLine.pas
index 281a480d..ac0db2c2 100644
--- a/src/base/UCommandLine.pas
+++ b/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/src/base/UCommon.pas b/src/base/UCommon.pas
index d729b6dd..fa0faf3c 100644
--- a/src/base/UCommon.pas
+++ b/src/base/UCommon.pas
@@ -39,9 +39,28 @@ uses
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF}
- sdl,
UConfig,
- ULog;
+ ULog,
+ UPath;
+
+type
+ TStringDynArray = array of string;
+
+const
+ SepWhitespace = [#9, #10, #13, ' ']; // tab, lf, cr, space
+
+{**
+ * Splits a string into pieces separated by Separators.
+ * MaxCount specifies the max. number of pieces. If it is <= 0 the number is
+ * not limited. If > 0 the last array element will hold the rest of the string
+ * (with leading separators removed).
+ *
+ * Examples:
+ * SplitString(' split me now ', 0) -> ['split', 'me', 'now']
+ * SplitString(' split me now ', 1) -> ['split', 'me now']
+ *}
+function SplitString(const Str: string; MaxCount: integer = 0; Separators: TSysCharSet = SepWhitespace): TStringDynArray;
+
type
TMessageType = (mtInfo, mtError);
@@ -50,43 +69,19 @@ procedure ShowMessage(const msg: string; msgType: TMessageType = mtInfo);
procedure ConsoleWriteLn(const msg: string);
-function RWopsFromStream(Stream: TStream): PSDL_RWops;
-
{$IFDEF FPC}
function RandomRange(aMin: integer; aMax: integer): integer;
{$ENDIF}
-function StringReplaceW(text: WideString; search, rep: WideChar): WideString;
-function AdaptFilePaths(const aPath: WideString): WideString;
-
procedure DisableFloatingPointExceptions();
procedure SetDefaultNumericLocale();
procedure RestoreNumericLocale();
{$IFNDEF MSWINDOWS}
- procedure ZeroMemory(Destination: pointer; Length: dword);
- function MakeLong(a, b: word): longint;
- (*
- #define LOBYTE(a) (BYTE)(a)
- #define HIBYTE(a) (BYTE)((a)>>8)
- #define LOWORD(a) (WORD)(a)
- #define HIWORD(a) (WORD)((a)>>16)
- #define MAKEWORD(a,b) (WORD)(((a)&0xff)|((b)<<8))
- *)
+procedure ZeroMemory(Destination: pointer; Length: dword);
+function MakeLong(a, b: word): longint;
{$ENDIF}
-function FileExistsInsensitive(var FileName: string): boolean;
-
-(*
- * Character classes
- *)
-
-function IsAlphaChar(ch: WideChar): boolean;
-function IsNumericChar(ch: WideChar): boolean;
-function IsAlphaNumericChar(ch: WideChar): boolean;
-function IsPunctuationChar(ch: WideChar): boolean;
-function IsControlChar(ch: WideChar): boolean;
-
// A stable alternative to TList.Sort() (use TList.Sort() if applicable, see below)
procedure MergeSort(List: TList; CompareFunc: TListSortCompare);
@@ -101,8 +96,63 @@ uses
{$IFDEF Delphi}
Dialogs,
{$ENDIF}
- UMain;
+ sdl,
+ UFilesystem,
+ UMain,
+ UUnicodeUtils;
+
+function SplitString(const Str: string; MaxCount: integer; Separators: TSysCharSet): TStringDynArray;
+
+ {*
+ * Adds Str[StartPos..Endpos-1] to the result array.
+ *}
+ procedure AddSplit(StartPos, EndPos: integer);
+ begin
+ SetLength(Result, Length(Result)+1);
+ Result[High(Result)] := Copy(Str, StartPos, EndPos-StartPos);
+ end;
+var
+ I: integer;
+ Start: integer;
+ Last: integer;
+begin
+ Start := 0;
+ SetLength(Result, 0);
+
+ for I := 1 to Length(Str) do
+ begin
+ if (Str[I] in Separators) then
+ begin
+ // end of component found
+ if (Start > 0) then
+ begin
+ AddSplit(Start, I);
+ Start := 0;
+ end;
+ end
+ else if (Start = 0) then
+ begin
+ // mark beginning of component
+ Start := I;
+ // check if this is the last component
+ if (Length(Result) = MaxCount-1) then
+ begin
+ // find last non-separator char
+ Last := Length(Str);
+ while (Str[Last] in Separators) do
+ Dec(Last);
+ // add component up to last non-separator
+ AddSplit(Start, Last);
+ Exit;
+ end;
+ end;
+ end;
+
+ // last component
+ if (Start > 0) then
+ AddSplit(Start, Length(Str)+1);
+end;
// data used by the ...Locale() functions
{$IF Defined(Linux) or Defined(FreeBSD)}
@@ -224,39 +274,6 @@ begin
exOverflow, exUnderflow, exPrecision]);
end;
-function StringReplaceW(text: WideString; search, rep: WideChar): WideString;
-var
- iPos: integer;
-// sTemp: WideString;
-begin
-(*
- result := text;
- iPos := Pos(search, result);
- while (iPos > 0) do
- begin
- sTemp := copy(result, iPos + length(search), length(result));
- result := copy(result, 1, iPos - 1) + rep + sTEmp;
- iPos := Pos(search, result);
- end;
-*)
- result := text;
-
- if search = rep then
- exit;
-
- for iPos := 1 to length(result) do
- begin
- if result[iPos] = search then
- result[iPos] := rep;
- end;
-end;
-
-function AdaptFilePaths(const aPath: WideString): WideString;
-begin
- result := StringReplaceW(aPath, '\', PathDelim);//, [rfReplaceAll]);
-end;
-
-
{$IFNDEF MSWINDOWS}
procedure ZeroMemory(Destination: pointer; Length: dword);
begin
@@ -268,135 +285,8 @@ begin
Result := (LongInt(B) shl 16) + A;
end;
-(*
-function QueryPerformanceCounter(lpPerformanceCount:TLARGEINTEGER): Bool;
-
- // From http://en.wikipedia.org/wiki/RDTSC
- function RDTSC: Int64; register;
- asm
- rdtsc
- end;
-
-begin
- // Use clock_gettime(CLOCK_REALTIME, ...) here (but not from the libc unit)
- lpPerformanceCount := RDTSC();
- result := true;
-end;
-
-function QueryPerformanceFrequency(lpFrequency:TLARGEINTEGER):Bool;
-begin
- // clock_getres(CLOCK_REALTIME, ...)
- lpFrequency := 0;
- result := true;
-end;
-*)
{$ENDIF}
-// Checks if a regular files or directory with the given name exists.
-// The comparison is case insensitive.
-function FileExistsInsensitive(var FileName: string): boolean;
-var
- FilePath, LocalFileName: string;
- SearchInfo: TSearchRec;
-begin
-{$IF Defined(Linux) or Defined(FreeBSD)}
- // speed up standard case
- if FileExists(FileName) then
- begin
- Result := true;
- exit;
- end;
-
- Result := false;
-
- FilePath := ExtractFilePath(FileName);
- if (FindFirst(FilePath + '*', faAnyFile, SearchInfo) = 0) then
- begin
- LocalFileName := ExtractFileName(FileName);
- repeat
- if (AnsiSameText(LocalFileName, SearchInfo.Name)) then
- begin
- FileName := FilePath + SearchInfo.Name;
- Result := true;
- break;
- end;
- until (FindNext(SearchInfo) <> 0);
- end;
- FindClose(SearchInfo);
-{$ELSE}
- // Windows and Mac OS X do not have case sensitive file systems
- Result := FileExists(FileName);
-{$IFEND}
-end;
-
-// +++++++++++++++++++++ helpers for RWOpsFromStream() +++++++++++++++
-function SdlStreamSeek(context: PSDL_RWops; offset: integer; whence: integer): integer; cdecl;
-var
- stream: TStream;
- origin: word;
-begin
- stream := TStream(context.unknown);
- if (stream = nil) then
- raise EInvalidContainer.Create('SDLStreamSeek on nil');
- case whence of
- 0 : origin := soFromBeginning; // Offset is from the beginning of the resource. Seek moves to the position Offset. Offset must be >= 0.
- 1 : origin := soFromCurrent; // Offset is from the current position in the resource. Seek moves to Position + Offset.
- 2 : origin := soFromEnd;
- else
- origin := soFromBeginning; // just in case
- end;
- Result := stream.Seek(offset, origin);
-end;
-
-function SdlStreamRead(context: PSDL_RWops; Ptr: pointer; size: integer; maxnum: integer): integer; cdecl;
-var
- stream: TStream;
-begin
- stream := TStream(context.unknown);
- if (stream = nil) then
- raise EInvalidContainer.Create('SDLStreamRead on nil');
- try
- Result := stream.read(Ptr^, Size * maxnum) div size;
- except
- Result := -1;
- end;
-end;
-
-function SDLStreamClose(context: PSDL_RWops): integer; cdecl;
-var
- stream: TStream;
-begin
- stream := TStream(context.unknown);
- if (stream = nil) then
- raise EInvalidContainer.Create('SDLStreamClose on nil');
- stream.Free;
- Result := 1;
-end;
-// -----------------------------------------------
-
-(*
- * Creates an SDL_RWops handle from a TStream.
- * The stream and RWops must be freed by the user after usage.
- * Use SDL_FreeRW(...) to free the RWops data-struct.
- *)
-function RWopsFromStream(Stream: TStream): PSDL_RWops;
-begin
- Result := SDL_AllocRW();
- if (Result = nil) then
- Exit;
-
- // set RW-callbacks
- with Result^ do
- begin
- unknown := TUnknown(Stream);
- seek := SDLStreamSeek;
- read := SDLStreamRead;
- write := nil;
- close := SDLStreamClose;
- type_ := 2;
- end;
-end;
-
{$IFDEF FPC}
function RandomRange(aMin: integer; aMax: integer): integer;
begin
@@ -541,59 +431,6 @@ begin
{$IFEND}
end;
-function IsAlphaChar(ch: WideChar): boolean;
-begin
- // TODO: add chars > 255 when unicode-fonts work?
- case ch of
- 'A'..'Z', // A-Z
- 'a'..'z', // a-z
- #170,#181,#186,
- #192..#214,
- #216..#246,
- #248..#255:
- Result := true;
- else
- Result := false;
- end;
-end;
-
-function IsNumericChar(ch: WideChar): boolean;
-begin
- case ch of
- '0'..'9':
- Result := true;
- else
- Result := false;
- end;
-end;
-
-function IsAlphaNumericChar(ch: WideChar): boolean;
-begin
- Result := (IsAlphaChar(ch) or IsNumericChar(ch));
-end;
-
-function IsPunctuationChar(ch: WideChar): boolean;
-begin
- // TODO: add chars outside of Latin1 basic (0..127)?
- case ch of
- ' '..'/',':'..'@','['..'`','{'..'~':
- Result := true;
- else
- Result := false;
- end;
-end;
-
-function IsControlChar(ch: WideChar): boolean;
-begin
- case ch of
- #0..#31,
- #127..#159:
- Result := true;
- else
- Result := false;
- end;
-end;
-
(*
* Recursive part of the MergeSort algorithm.
* OutList will be either InList or TempList and will be swapped in each
diff --git a/src/base/UConfig.pas b/src/base/UConfig.pas
index 1214f36f..f6dc69a5 100644
--- a/src/base/UConfig.pas
+++ b/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/src/base/UCovers.pas b/src/base/UCovers.pas
index a1705674..6c7c9e48 100644
--- a/src/base/UCovers.pas
+++ b/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;
@@ -111,7 +112,7 @@ uses
DateUtils;
const
- COVERDB_FILENAME = 'cover.db';
+ COVERDB_FILENAME: UTF8String = 'cover.db';
COVERDB_VERSION = 01; // 0.1
COVER_TBL = 'Cover';
COVER_THUMBNAIL_TBL = 'CoverThumbnail';
@@ -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: string;
+ Filename: IPath;
begin
- Filename := UTF8Encode(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);
@@ -384,6 +385,9 @@ begin
end
else
begin
+ // FillChar() does not decrement the ref-count of ref-counted fields
+ // -> reset Name field manually
+ Result.Name := nil;
FillChar(Result, SizeOf(TTexture), 0);
end;
except on E: Exception do
@@ -403,7 +407,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 +421,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/src/base/UDLLManager.pas b/src/base/UDLLManager.pas
index 3faa15bf..d5bb1480 100644
--- a/src/base/UDLLManager.pas
+++ b/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;
@@ -92,7 +94,7 @@ uses
{$ELSE}
dynlibs,
{$ENDIF}
- UPath,
+ UPathUtils,
ULog,
SysUtils;
@@ -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));
+
+ FileInfo := Iter.Next;
- 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);
+ 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/src/base/UDataBase.pas b/src/base/UDataBase.pas
index 227db653..bdcbd30f 100644
--- a/src/base/UDataBase.pas
+++ b/src/base/UDataBase.pas
@@ -36,18 +36,19 @@ interface
uses
Classes,
SQLiteTable3,
+ UPath,
USong,
USongs;
//--------------------
-//DataBaseSystem - Class including all DB Methods
+//DataBaseSystem - Class including all DB methods
//--------------------
type
TStatType = (
- stBestScores, // Best Scores
- stBestSingers, // Best Singers
- stMostSungSong, // Most sung Songs
- stMostPopBand // Most popular Band
+ stBestScores, // Best scores
+ stBestSingers, // Best singers
+ stMostSungSong, // Most sung songs
+ stMostPopBand // Most popular band
);
// abstract super-class for statistic results
@@ -58,29 +59,29 @@ type
TStatResultBestScores = class(TStatResult)
public
- Singer: WideString;
+ Singer: UTF8String;
Score: word;
Difficulty: byte;
- SongArtist: WideString;
- SongTitle: WideString;
+ SongArtist: UTF8String;
+ SongTitle: UTF8String;
end;
TStatResultBestSingers = class(TStatResult)
public
- Player: WideString;
+ Player: UTF8String;
AverageScore: word;
end;
TStatResultMostSungSong = class(TStatResult)
public
- Artist: WideString;
- Title: WideString;
+ Artist: UTF8String;
+ Title: UTF8String;
TimesSung: word;
end;
TStatResultMostPopBand = class(TStatResult)
public
- ArtistName: WideString;
+ ArtistName: UTF8String;
TimesSungTot: word;
end;
@@ -88,18 +89,18 @@ 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: WideString; Score: integer);
+ procedure AddScore(Song: TSong; Level: integer; const Name: UTF8String; Score: integer);
procedure WriteScore(Song: TSong);
function GetStats(Typ: TStatType; Count: byte; Page: cardinal; Reversed: boolean): TList;
@@ -131,49 +132,49 @@ const
cUS_Statistics_Info = 'us_statistics_info';
(**
- * Opens Database and Create Tables if not Exist
+ * Open database and create tables if they do not exist
*)
-procedure TDataBaseSystem.Init(const Filename: string);
+procedure TDataBaseSystem.Init(const Filename: IPath);
var
Version: integer;
- finalizeConvertion: boolean;
+ finalizeConversion: boolean;
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);
+ // open database
+ ScoreDB := TSQLiteDatabase.Create(Filename.ToUTF8);
fFilename := Filename;
Version := GetVersion();
- //Adds Table cUS_Statistics_Info
- //Happens from Convertion 1.01 -> 1.1
+ // add Table cUS_Statistics_Info
+ // needed in the conversion from 1.01 to 1.1
if not ScoreDB.TableExists(cUS_Statistics_Info) then
begin
- Log.LogInfo('Outdated song-database file found - Missing Table"'+cUS_Statistics_Info+'"', 'TDataBaseSystem.Init');
- ScoreDB.ExecSQL('CREATE TABLE IF NOT EXISTS ['+cUS_Statistics_Info+'] (' +
+ Log.LogInfo('Outdated song database found - missing table"' + cUS_Statistics_Info + '"', 'TDataBaseSystem.Init');
+ ScoreDB.ExecSQL('CREATE TABLE IF NOT EXISTS [' + cUS_Statistics_Info + '] (' +
'[ResetTime] INTEGER' +
');');
// insert creation timestamp
- ScoreDB.ExecSQL(Format('INSERT INTO ['+cUS_Statistics_Info+'] ' +
+ ScoreDB.ExecSQL(Format('INSERT INTO [' + cUS_Statistics_Info + '] ' +
'([ResetTime]) VALUES(%d);',
[DateTimeToUnix(Now())]));
end;
- //Converts data of 1.01 -> 1.1
- //Part #1 - prearrangement
- finalizeConvertion := false;
+ // convert data from 1.01 to 1.1
+ // part #1 - prearrangement
+ finalizeConversion := false;
if (Version = 0) AND ScoreDB.TableExists('US_Scores') then
begin
- //Rename old Tables - to be able to insert new table-structures
+ // rename old tables - to be able to insert new table structures
ScoreDB.ExecSQL('ALTER TABLE US_Scores RENAME TO us_scores_101;');
ScoreDB.ExecSQL('ALTER TABLE US_Songs RENAME TO us_songs_101;');
- finalizeConvertion := true; //means: convertion has to be done!
+ finalizeConversion := true; // means: conversion has to be done!
end;
// Set version number after creation
@@ -187,14 +188,14 @@ begin
// types are used (especially FieldAsInteger). Also take care to write the
// types in upper-case letters although SQLite does not care about this -
// SQLiteTable3 is very sensitive in this regard.
- ScoreDB.ExecSQL('CREATE TABLE IF NOT EXISTS ['+cUS_Scores+'] (' +
+ ScoreDB.ExecSQL('CREATE TABLE IF NOT EXISTS [' + cUS_Scores + '] (' +
'[SongID] INTEGER NOT NULL, ' +
'[Difficulty] INTEGER NOT NULL, ' +
'[Player] TEXT NOT NULL, ' +
'[Score] INTEGER NOT NULL' +
');');
- ScoreDB.ExecSQL('CREATE TABLE IF NOT EXISTS ['+cUS_Songs+'] (' +
+ ScoreDB.ExecSQL('CREATE TABLE IF NOT EXISTS [' + cUS_Songs + '] (' +
'[ID] INTEGER PRIMARY KEY, ' +
'[Artist] TEXT NOT NULL, ' +
'[Title] TEXT NOT NULL, ' +
@@ -202,25 +203,25 @@ begin
'[Rating] INTEGER NULL' +
');');
- //Converts data of 1.01 -> 1.1
- //Part #2 - accomplishment
- if finalizeConvertion then
+ // convert data from 1.01 to 1.1
+ // part #2 - accomplishment
+ if finalizeConversion then
begin
- Log.LogInfo('Outdated song-database file found - Began Converting from V1.01 to V1.1', 'TDataBaseSystem.Init');
- //insert old values in new db-schemes (/tables)
- ScoreDB.ExecSQL('INSERT INTO '+cUS_Scores+' SELECT SongID, Difficulty, Player, Score FROM us_scores_101;');
- ScoreDB.ExecSQL('INSERT INTO '+cUS_Songs+' SELECT ID, Artist, Title, TimesPlayed, ''NULL'' FROM us_songs_101;');
+ Log.LogInfo('Outdated song database found - begin conversion from V1.01 to V1.1', 'TDataBaseSystem.Init');
+ // insert old values into new db-schemes (/tables)
+ ScoreDB.ExecSQL('INSERT INTO ' + cUS_Scores + ' SELECT SongID, Difficulty, Player, Score FROM us_scores_101;');
+ ScoreDB.ExecSQL('INSERT INTO ' + cUS_Songs + ' SELECT ID, Artist, Title, TimesPlayed, ''NULL'' FROM us_songs_101;');
//now drop old tables
ScoreDB.ExecSQL('DROP TABLE us_scores_101;');
ScoreDB.ExecSQL('DROP TABLE us_songs_101;');
end;
- //Adds Column Rating to cUS_Songs
- //Just for the users of Nightly-Builds and all Developers!
+ // add column rating to cUS_Songs
+ // just for users of nightly builds and developers!
if not ScoreDB.ContainsColumn(cUS_Songs, 'Rating') then
begin
- Log.LogInfo('Outdated song-database file found - Adding Column Rating to "'+cUS_Songs+'"', 'TDataBaseSystem.Init');
- ScoreDB.ExecSQL('ALTER TABLE '+cUS_Songs+' ADD COLUMN Rating INTEGER NULL');
+ Log.LogInfo('Outdated song database found - adding column rating to "' + cUS_Songs + '"', 'TDataBaseSystem.Init');
+ ScoreDB.ExecSQL('ALTER TABLE ' + cUS_Songs + ' ADD COLUMN Rating INTEGER NULL');
end;
except
@@ -259,13 +260,13 @@ begin
try
// Search Song in DB
TableData := ScoreDB.GetUniTable(
- 'SELECT [Difficulty], [Player], [Score] FROM ['+cUS_Scores+'] ' +
+ 'SELECT [Difficulty], [Player], [Score] FROM [' + cUS_Scores + '] ' +
'WHERE [SongID] = (' +
- 'SELECT [ID] FROM ['+cUS_Songs+'] ' +
+ 'SELECT [ID] FROM [' + cUS_Songs + '] ' +
'WHERE [Artist] = ? AND [Title] = ? ' +
'LIMIT 1) ' +
'ORDER BY [Score] DESC LIMIT 15',
- [UTF8Encode(Song.Artist), UTF8Encode(Song.Title)]);
+ [Song.Artist, Song.Title]);
// Empty Old Scores
SetLength(Song.Score[0], 0);
@@ -283,7 +284,7 @@ begin
SetLength(Song.Score[Difficulty], Length(Song.Score[Difficulty]) + 1);
Song.Score[Difficulty, High(Song.Score[Difficulty])].Name :=
- UTF8Decode(TableData.FieldByName['Player']);
+ TableData.FieldByName['Player'];
Song.Score[Difficulty, High(Song.Score[Difficulty])].Score :=
TableData.FieldAsInteger(TableData.FieldIndex['Score']);
end;
@@ -305,7 +306,7 @@ end;
(**
* Adds one new score to DB
*)
-procedure TDataBaseSystem.AddScore(Song: TSong; Level: integer; const Name: WideString; Score: integer);
+procedure TDataBaseSystem.AddScore(Song: TSong; Level: integer; const Name: UTF8String; Score: integer);
var
ID: integer;
TableData: TSQLiteTable;
@@ -322,35 +323,35 @@ begin
try
ID := ScoreDB.GetTableValue(
- 'SELECT [ID] FROM ['+cUS_Songs+'] ' +
+ 'SELECT [ID] FROM [' + cUS_Songs + '] ' +
'WHERE [Artist] = ? AND [Title] = ?',
- [UTF8Encode(Song.Artist), UTF8Encode(Song.Title)]);
+ [Song.Artist, Song.Title]);
if (ID = 0) then
begin
// Create song if it does not exist
ScoreDB.ExecSQL(
- 'INSERT INTO ['+cUS_Songs+'] ' +
+ 'INSERT INTO [' + cUS_Songs + '] ' +
'([ID], [Artist], [Title], [TimesPlayed]) VALUES ' +
'(NULL, ?, ?, 0);',
- [UTF8Encode(Song.Artist), UTF8Encode(Song.Title)]);
+ [Song.Artist, Song.Title]);
// Get song-ID
ID := ScoreDB.GetLastInsertRowID();
end;
// Create new entry
ScoreDB.ExecSQL(
- 'INSERT INTO ['+cUS_Scores+'] ' +
+ 'INSERT INTO [' + cUS_Scores + '] ' +
'([SongID] ,[Difficulty], [Player], [Score]) VALUES ' +
'(?, ?, ?, ?);',
- [ID, Level, UTF8Encode(Name), Score]);
+ [ID, Level, Name, Score]);
// Delete last position when there are more than 5 entrys.
// Fixes crash when there are > 5 ScoreEntrys
// Note: GetUniTable is not applicable here, as the results are used while
// table entries are deleted.
TableData := ScoreDB.GetTable(
- 'SELECT [Player], [Score] FROM ['+cUS_Scores+'] ' +
+ 'SELECT [Player], [Score] FROM [' + cUS_Scores + '] ' +
'WHERE [SongID] = ' + InttoStr(ID) + ' AND ' +
- '[Difficulty] = ' + InttoStr(Level) +' ' +
+ '[Difficulty] = ' + InttoStr(Level) + ' ' +
'ORDER BY [Score] DESC LIMIT -1 OFFSET 5');
while (not TableData.EOF) do
@@ -360,7 +361,7 @@ begin
// an automatic cast of this field to the TEXT type (although it might even
// work that way).
ScoreDB.ExecSQL(
- 'DELETE FROM ['+cUS_Scores+'] ' +
+ 'DELETE FROM [' + cUS_Scores + '] ' +
'WHERE [SongID] = ' + InttoStr(ID) + ' AND ' +
'[Difficulty] = ' + InttoStr(Level) +' AND ' +
'[Player] = ? AND ' +
@@ -378,8 +379,8 @@ begin
end;
(**
- * Not needed with new System.
- * Used for increment played count
+ * Not needed with new system.
+ * Used to increment played count
*)
procedure TDataBaseSystem.WriteScore(Song: TSong);
begin
@@ -389,10 +390,10 @@ begin
try
// Increase TimesPlayed
ScoreDB.ExecSQL(
- 'UPDATE ['+cUS_Songs+'] ' +
+ 'UPDATE [' + cUS_Songs + '] ' +
'SET [TimesPlayed] = [TimesPlayed] + 1 ' +
'WHERE [Title] = ? AND [Artist] = ?;',
- [UTF8Encode(Song.Title), UTF8Encode(Song.Artist)]);
+ [Song.Title, Song.Artist]);
except on E: Exception do
Log.LogError(E.Message, 'TDataBaseSystem.WriteScore');
end;
@@ -420,19 +421,19 @@ begin
// Create query
case Typ of
stBestScores: begin
- Query := 'SELECT [Player], [Difficulty], [Score], [Artist], [Title] FROM ['+cUS_Scores+'] ' +
- 'INNER JOIN ['+cUS_Songs+'] ON ([SongID] = [ID]) ORDER BY [Score]';
+ Query := 'SELECT [Player], [Difficulty], [Score], [Artist], [Title] FROM [' + cUS_Scores + '] ' +
+ 'INNER JOIN [' + cUS_Songs + '] ON ([SongID] = [ID]) ORDER BY [Score]';
end;
stBestSingers: begin
- Query := 'SELECT [Player], ROUND(AVG([Score])) FROM ['+cUS_Scores+'] ' +
+ Query := 'SELECT [Player], ROUND(AVG([Score])) FROM [' + cUS_Scores + '] ' +
'GROUP BY [Player] ORDER BY AVG([Score])';
end;
stMostSungSong: begin
- Query := 'SELECT [Artist], [Title], [TimesPlayed] FROM ['+cUS_Songs+'] ' +
+ Query := 'SELECT [Artist], [Title], [TimesPlayed] FROM [' + cUS_Songs + '] ' +
'ORDER BY [TimesPlayed]';
end;
stMostPopBand: begin
- Query := 'SELECT [Artist], SUM([TimesPlayed]) FROM ['+cUS_Songs+'] ' +
+ Query := 'SELECT [Artist], SUM([TimesPlayed]) FROM [' + cUS_Songs + '] ' +
'GROUP BY [Artist] ORDER BY SUM([TimesPlayed])';
end;
end;
@@ -465,18 +466,18 @@ begin
Stat := TStatResultBestScores.Create;
with TStatResultBestScores(Stat) do
begin
- Singer := UTF8Decode(TableData.Fields[0]);
+ Singer := TableData.Fields[0];
Difficulty := TableData.FieldAsInteger(1);
Score := TableData.FieldAsInteger(2);
- SongArtist := UTF8Decode(TableData.Fields[3]);
- SongTitle := UTF8Decode(TableData.Fields[4]);
+ SongArtist := TableData.Fields[3];
+ SongTitle := TableData.Fields[4];
end;
end;
stBestSingers: begin
Stat := TStatResultBestSingers.Create;
with TStatResultBestSingers(Stat) do
begin
- Player := UTF8Decode(TableData.Fields[0]);
+ Player := TableData.Fields[0];
AverageScore := TableData.FieldAsInteger(1);
end;
end;
@@ -484,8 +485,8 @@ begin
Stat := TStatResultMostSungSong.Create;
with TStatResultMostSungSong(Stat) do
begin
- Artist := UTF8Decode(TableData.Fields[0]);
- Title := UTF8Decode(TableData.Fields[1]);
+ Artist := TableData.Fields[0];
+ Title := TableData.Fields[1];
TimesSung := TableData.FieldAsInteger(2);
end;
end;
@@ -493,7 +494,7 @@ begin
Stat := TStatResultMostPopBand.Create;
with TStatResultMostPopBand(Stat) do
begin
- ArtistName := UTF8Decode(TableData.Fields[0]);
+ ArtistName := TableData.Fields[0];
TimesSungTot := TableData.FieldAsInteger(1);
end;
end
@@ -524,7 +525,7 @@ end;
(**
* Gets total number of entrys for a stats query
*)
-function TDataBaseSystem.GetTotalEntrys(Typ: TStatType): cardinal;
+function TDataBaseSystem.GetTotalEntrys(Typ: TStatType): cardinal;
var
Query: string;
begin
@@ -537,13 +538,13 @@ begin
// Create query
case Typ of
stBestScores:
- Query := 'SELECT COUNT([SongID]) FROM ['+cUS_Scores+'];';
+ Query := 'SELECT COUNT([SongID]) FROM [' + cUS_Scores + '];';
stBestSingers:
- Query := 'SELECT COUNT(DISTINCT [Player]) FROM ['+cUS_Scores+'];';
+ Query := 'SELECT COUNT(DISTINCT [Player]) FROM [' + cUS_Scores + '];';
stMostSungSong:
- Query := 'SELECT COUNT([ID]) FROM ['+cUS_Songs+'];';
+ Query := 'SELECT COUNT([ID]) FROM [' + cUS_Songs + '];';
stMostPopBand:
- Query := 'SELECT COUNT(DISTINCT [Artist]) FROM ['+cUS_Songs+'];';
+ Query := 'SELECT COUNT(DISTINCT [Artist]) FROM [' + cUS_Songs + '];';
end;
Result := ScoreDB.GetTableValue(Query);
@@ -566,7 +567,7 @@ begin
Exit;
try
- Query := 'SELECT [ResetTime] FROM ['+cUS_Statistics_Info+'];';
+ Query := 'SELECT [ResetTime] FROM [' + cUS_Statistics_Info + '];';
Result := UnixToDateTime(ScoreDB.GetTableValue(Query));
except on E: Exception do
Log.LogError(E.Message, 'TDataBaseSystem.GetStatReset');
diff --git a/src/base/UEditorLyrics.pas b/src/base/UEditorLyrics.pas
index ef9d8dd6..0eacd1f9 100644
--- a/src/base/UEditorLyrics.pas
+++ b/src/base/UEditorLyrics.pas
@@ -74,7 +74,7 @@ type
procedure SetSize(Value: real);
procedure SetSelected(Value: integer);
procedure SetFontStyle(Value: integer);
- procedure AddWord(Text: string);
+ procedure AddWord(Text: UTF8String);
procedure Refresh;
public
ColR: real;
@@ -179,7 +179,7 @@ begin
FontStyleI := Value;
end;
-procedure TEditorLyrics.AddWord(Text: string);
+procedure TEditorLyrics.AddWord(Text: UTF8String);
var
WordNum: integer;
begin
diff --git a/src/base/UFiles.pas b/src/base/UFiles.pas
index 0495dfbb..a46d4e0d 100644
--- a/src/base/UFiles.pas
+++ b/src/base/UFiles.pas
@@ -34,24 +34,23 @@ interface
uses
SysUtils,
+ Classes,
ULog,
UMusic,
USongs,
- USong;
+ USong,
+ UPath;
procedure ResetSingTemp;
-function SaveSong(Song: TSong; Lines: TLines; Name: string; Relative: boolean): boolean;
+type
+ TSaveSongResult = (ssrOK, ssrFileError, ssrEncodingError);
-var
- SongFile: TextFile; // all procedures in this unit operates on this file
- FileLineNo: integer; //Line which is readed at Last, for error reporting
-
- // variables available for all procedures
- Base : array[0..1] of integer;
- Rel : array[0..1] of integer;
- Mult : integer = 1;
- MultBPM : integer = 4;
+{**
+ * 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: IPath; Relative: boolean): TSaveSongResult;
implementation
@@ -59,7 +58,9 @@ uses
TextGL,
UIni,
UNote,
- UPlatform;
+ UPlatform,
+ UUnicodeUtils,
+ UTextEncoding;
//--------------------
// Resets the temporary Sentence Arrays for each Player and some other Variables
@@ -77,101 +78,112 @@ begin
Player[Count].LengthNote := 0;
Player[Count].HighNote := -1;
end;
-
- (* FIXME
- //Reset Path and Filename Values to Prevent Errors in Editor
- if assigned( CurrentSong ) then
- begin
- SetLength(CurrentSong.BPM, 0);
- CurrentSong.Path := '';
- CurrentSong.FileName := '';
- end;
- *)
-
-// CurrentSong := nil;
end;
-
//--------------------
// Saves a Song
//--------------------
-function SaveSong(Song: TSong; Lines: TLines; Name: string; Relative: boolean): boolean;
+function SaveSong(const Song: TSong; const Lines: TLines; const Name: IPath; Relative: boolean): TSaveSongResult;
var
C: integer;
N: integer;
- S: string;
+ S: AnsiString;
B: integer;
- RelativeSubTime: integer;
- NoteState: String;
+ RelativeSubTime: integer;
+ NoteState: AnsiString;
+ SongFile: TTextFileStream;
+
+ function EncodeToken(const Str: UTF8String): RawByteString;
+ var
+ Success: boolean;
+ begin
+ Success := EncodeStringUTF8(Str, Result, Song.Encoding);
+ if (not Success) then
+ SaveSong := ssrEncodingError;
+ end;
begin
-// Relative := true; // override (idea - use shift+S to save with relative)
- AssignFile(SongFile, Name);
- Rewrite(SongFile);
-
- Writeln(SongFile, '#TITLE:' + Song.Title + '');
- Writeln(SongFile, '#ARTIST:' + Song.Artist);
-
- if Song.Creator <> '' then Writeln(SongFile, '#CREATOR:' + Song.Creator);
- if Song.Edition <> 'Unknown' then Writeln(SongFile, '#EDITION:' + Song.Edition);
- if Song.Genre <> 'Unknown' then Writeln(SongFile, '#GENRE:' + Song.Genre);
- if Song.Language <> 'Unknown' then Writeln(SongFile, '#LANGUAGE:' + Song.Language);
-
- Writeln(SongFile, '#MP3:' + Song.Mp3);
-
- if Song.Cover <> '' then Writeln(SongFile, '#COVER:' + Song.Cover);
- if Song.Background <> '' then Writeln(SongFile, '#BACKGROUND:' + Song.Background);
- if Song.Video <> '' then Writeln(SongFile, '#VIDEO:' + Song.Video);
- 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');
-
- Writeln(SongFile, '#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
- Writeln(SongFile, '#GAP:' + FloatToStr(Song.GAP));
-
- RelativeSubTime := 0;
- for B := 1 to High(CurrentSong.BPM) do
- Writeln(SongFile, 'B ' + FloatToStr(CurrentSong.BPM[B].StartBeat) + ' ' + FloatToStr(CurrentSong.BPM[B].BPM/4));
-
- for C := 0 to Lines.High do begin
- for N := 0 to Lines.Line[C].HighNote do begin
- 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) + ' ' + Text;
-
-
- Writeln(SongFile, S);
- end; // with
- end; // N
-
- if C < Lines.High then begin // don't write end of last sentence
- 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;
- Writeln(SongFile, S);
+ // Relative := true; // override (idea - use shift+S to save with relative)
+ Result := ssrOK;
+
+ try
+ SongFile := TMemTextFileStream.Create(Name, fmCreate);
+ try
+ if (Song.Encoding = encUTF8) then
+ SongFile.WriteString(UTF8_BOM);
+
+ SongFile.WriteLine('#ENCODING:' + EncodingName(Song.Encoding));
+ SongFile.WriteLine('#TITLE:' + EncodeToken(Song.Title));
+ SongFile.WriteLine('#ARTIST:' + EncodeToken(Song.Artist));
+
+ 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));
+
+ 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));
+
+ 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');
+
+ SongFile.WriteLine('#BPM:' + FloatToStr(Song.BPM[0].BPM / 4));
+ SongFile.WriteLine('#GAP:' + FloatToStr(Song.GAP));
+
+ 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
+ for N := 0 to Lines.Line[C].HighNote do
+ begin
+ 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
+ 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;
+ end; // C
+
+ SongFile.WriteLine('E');
+ finally
+ SongFile.Free;
end;
-
- end; // C
-
-
- Writeln(SongFile, 'E');
- CloseFile(SongFile);
-
- Result := true;
+ except
+ Result := ssrFileError;
+ end;
end;
end.
+
diff --git a/src/base/UFilesystem.pas b/src/base/UFilesystem.pas
new file mode 100644
index 00000000..d4972df5
--- /dev/null
+++ b/src/base/UFilesystem.pas
@@ -0,0 +1,692 @@
+{* 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 UFilesystem;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ SysUtils,
+ Classes,
+ {$IFDEF MSWINDOWS}
+ Windows,
+ TntSysUtils,
+ {$ENDIF}
+ UPath;
+
+type
+ {$IFDEF MSWINDOWS}
+ TSytemSearchRec = TSearchRecW;
+ {$ELSE}
+ TSytemSearchRec = TSearchRec;
+ {$ENDIF}
+
+ TFileInfo = record
+ Time: integer; // timestamp
+ Size: int64; // file size (byte)
+ Attr: integer; // file attributes
+ Name: IPath; // basename with extension
+ end;
+
+ {**
+ * Iterates through the search results retrieved by FileFind().
+ * Example usage:
+ * while(Iter.HasNext()) do
+ * SearchRec := Iter.Next();
+ *}
+ IFileIterator = interface
+ function HasNext(): boolean;
+ function Next(): TFileInfo;
+ end;
+
+ {**
+ * Wrapper for SysUtils file functions.
+ * For documentation and examples, check the SysUtils equivalent.
+ *}
+ IFileSystem = interface
+ function ExpandFileName(const FileName: IPath): IPath;
+ function FileCreate(const FileName: IPath): THandle;
+ function DirectoryCreate(const Dir: IPath): boolean;
+ function FileOpen(const FileName: IPath; Mode: longword): THandle;
+ function FileAge(const FileName: IPath): integer; overload;
+ function FileAge(const FileName: IPath; out FileDateTime: TDateTime): boolean; overload;
+
+ function DirectoryExists(const Name: IPath): boolean;
+
+ {**
+ * On Windows: returns true only for files (not directories)
+ * On Apple/Unix: returns true for all kind of files (even directories)
+ * @seealso SysUtils.FileExists()
+ *}
+ function FileExists(const Name: IPath): boolean;
+
+ function FileGetAttr(const FileName: IPath): Cardinal;
+ function FileSetAttr(const FileName: IPath; Attr: integer): boolean;
+ function FileIsReadOnly(const FileName: IPath): boolean;
+ function FileSetReadOnly(const FileName: IPath; ReadOnly: boolean): boolean;
+ function FileIsAbsolute(const FileName: IPath): boolean;
+ function ForceDirectories(const Dir: IPath): boolean;
+ function RenameFile(const OldName, NewName: IPath): boolean;
+ function DeleteFile(const FileName: IPath): boolean;
+ function RemoveDir(const Dir: IPath): boolean;
+
+ {**
+ * Copies file Source to Target. If FailIfExists is true, the file is not
+ * copied if it already exists.
+ * Returns true if the file was successfully copied.
+ *}
+ function CopyFile(const Source, Target: IPath; FailIfExists: boolean): boolean;
+
+ function ExtractFileDrive(const FileName: IPath): IPath;
+ function ExtractFilePath(const FileName: IPath): IPath;
+ function ExtractFileDir(const FileName: IPath): IPath;
+ function ExtractFileName(const FileName: IPath): IPath;
+ function ExtractFileExt(const FileName: IPath): IPath;
+ function ExtractRelativePath(const BaseName: IPath; const FileName: IPath): IPath;
+
+ function ChangeFileExt(const FileName: IPath; const Extension: IPath): IPath;
+
+ function IncludeTrailingPathDelimiter(const FileName: IPath): IPath;
+ function ExcludeTrailingPathDelimiter(const FileName: IPath): IPath;
+
+ {**
+ * Searches for a file with filename Name in the directories given in DirList.
+ *}
+ function FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+
+ {**
+ * More convenient version of FindFirst/Next/Close with iterator support.
+ *}
+ function FileFind(const FilePattern: IPath; Attr: integer): IFileIterator;
+
+ {**
+ * Old style search functions. Use FileFind() instead.
+ *}
+ function FindFirst(const FilePattern: IPath; Attr: integer; var F: TSytemSearchRec): integer;
+ function FindNext(var F: TSytemSearchRec): integer;
+ procedure FindClose(var F: TSytemSearchRec);
+
+ function GetCurrentDir: IPath;
+ function SetCurrentDir(const Dir: IPath): boolean;
+
+ {**
+ * Returns true if the filesystem is case-sensitive.
+ *}
+ function IsCaseSensitive(): boolean;
+ end;
+
+ function FileSystem(): IFileSystem;
+
+implementation
+
+type
+ TFileSystemImpl = class(TInterfacedObject, IFileSystem)
+ public
+ function ExpandFileName(const FileName: IPath): IPath;
+ function FileCreate(const FileName: IPath): THandle;
+ function DirectoryCreate(const Dir: IPath): boolean;
+ function FileOpen(const FileName: IPath; Mode: longword): THandle;
+ function FileAge(const FileName: IPath): integer; overload;
+ function FileAge(const FileName: IPath; out FileDateTime: TDateTime): boolean; overload;
+ function DirectoryExists(const Name: IPath): boolean;
+ function FileExists(const Name: IPath): boolean;
+ function FileGetAttr(const FileName: IPath): Cardinal;
+ function FileSetAttr(const FileName: IPath; Attr: integer): boolean;
+ function FileIsReadOnly(const FileName: IPath): boolean;
+ function FileSetReadOnly(const FileName: IPath; ReadOnly: boolean): boolean;
+ function FileIsAbsolute(const FileName: IPath): boolean;
+ function ForceDirectories(const Dir: IPath): boolean;
+ function RenameFile(const OldName, NewName: IPath): boolean;
+ function DeleteFile(const FileName: IPath): boolean;
+ function RemoveDir(const Dir: IPath): boolean;
+ function CopyFile(const Source, Target: IPath; FailIfExists: boolean): boolean;
+
+ function ExtractFileDrive(const FileName: IPath): IPath;
+ function ExtractFilePath(const FileName: IPath): IPath;
+ function ExtractFileDir(const FileName: IPath): IPath;
+ function ExtractFileName(const FileName: IPath): IPath;
+ function ExtractFileExt(const FileName: IPath): IPath;
+ function ExtractRelativePath(const BaseName: IPath; const FileName: IPath): IPath;
+ function ChangeFileExt(const FileName: IPath; const Extension: IPath): IPath;
+ function IncludeTrailingPathDelimiter(const FileName: IPath): IPath;
+ function ExcludeTrailingPathDelimiter(const FileName: IPath): IPath;
+
+ function FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+ function FileFind(const FilePattern: IPath; Attr: integer): IFileIterator;
+
+ function FindFirst(const FilePattern: IPath; Attr: integer; var F: TSytemSearchRec): integer;
+ function FindNext(var F: TSytemSearchRec): integer;
+ procedure FindClose(var F: TSytemSearchRec);
+
+ function GetCurrentDir: IPath;
+ function SetCurrentDir(const Dir: IPath): boolean;
+
+ function IsCaseSensitive(): boolean;
+ end;
+
+ TFileIterator = class(TInterfacedObject, IFileIterator)
+ private
+ fHasNext: boolean;
+ fSearchRec: TSytemSearchRec;
+ public
+ constructor Create(const FilePattern: IPath; Attr: integer);
+ destructor Destroy(); override;
+
+ function HasNext(): boolean;
+ function Next(): TFileInfo;
+ end;
+
+
+var
+ FileSystem_Singleton: IFileSystem;
+
+function FileSystem(): IFileSystem;
+begin
+ Result := FileSystem_Singleton;
+end;
+
+function TFileSystemImpl.FileFind(const FilePattern: IPath; Attr: integer): IFileIterator;
+begin
+ Result := TFileIterator.Create(FilePattern, Attr);
+end;
+
+function TFileSystemImpl.IsCaseSensitive(): boolean;
+begin
+ // Windows and Mac OS X do not have case sensitive file systems
+ {$IF Defined(MSWINDOWS) or Defined(DARWIN)}
+ Result := false;
+ {$ELSE}
+ Result := true;
+ {$IFEND}
+end;
+
+function TFileSystemImpl.FileIsAbsolute(const FileName: IPath): boolean;
+var
+ NameStr: UTF8String;
+begin
+ Result := true;
+ NameStr := FileName.ToUTF8();
+
+ {$IFDEF MSWINDOWS}
+ // check if drive is given 'C:...'
+ if (FileName.GetDrive().ToUTF8 <> '') then
+ Exit;
+ // check if path starts with '\\'
+ if (Length(NameStr) >= 2) and
+ (NameStr[1] = PathDelim) and (NameStr[2] = PathDelim) then
+ Exit;
+ {$ELSE} // Unix based systems
+ // check if root dir given '/...'
+ if (Length(NameStr) >= 1) and (NameStr[1] = PathDelim) then
+ Exit;
+ {$ENDIF}
+
+ Result := false;
+end;
+
+{$IFDEF MSWINDOWS}
+
+function TFileSystemImpl.ExpandFileName(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExpandFileName(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.FileCreate(const FileName: IPath): THandle;
+begin
+ Result := WideFileCreate(FileName.ToWide());
+end;
+
+function TFileSystemImpl.DirectoryCreate(const Dir: IPath): boolean;
+begin
+ Result := WideCreateDir(Dir.ToWide());
+end;
+
+function TFileSystemImpl.FileOpen(const FileName: IPath; Mode: longword): THandle;
+begin
+ Result := WideFileOpen(FileName.ToWide(), Mode);
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath): integer;
+begin
+ Result := WideFileAge(FileName.ToWide());
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath; out FileDateTime: TDateTime): boolean;
+begin
+ Result := WideFileAge(FileName.ToWide(), FileDateTime);
+end;
+
+function TFileSystemImpl.DirectoryExists(const Name: IPath): boolean;
+begin
+ Result := WideDirectoryExists(Name.ToWide());
+end;
+
+function TFileSystemImpl.FileExists(const Name: IPath): boolean;
+begin
+ Result := WideFileExists(Name.ToWide());
+end;
+
+function TFileSystemImpl.FileGetAttr(const FileName: IPath): Cardinal;
+begin
+ Result := WideFileGetAttr(FileName.ToWide());
+end;
+
+function TFileSystemImpl.FileSetAttr(const FileName: IPath; Attr: integer): boolean;
+begin
+ Result := WideFileSetAttr(FileName.ToWide(), Attr);
+end;
+
+function TFileSystemImpl.FileIsReadOnly(const FileName: IPath): boolean;
+begin
+ Result := WideFileIsReadOnly(FileName.ToWide());
+end;
+
+function TFileSystemImpl.FileSetReadOnly(const FileName: IPath; ReadOnly: boolean): boolean;
+begin
+ Result := WideFileSetReadOnly(FileName.ToWide(), ReadOnly);
+end;
+
+function TFileSystemImpl.ForceDirectories(const Dir: IPath): boolean;
+begin
+ Result := WideForceDirectories(Dir.ToWide());
+end;
+
+function TFileSystemImpl.FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+var
+ I: integer;
+ DirListStr: WideString;
+begin
+ DirListStr := '';
+ for I := 0 to High(DirList) do
+ begin
+ if (I > 0) then
+ DirListStr := DirListStr + PathSep;
+ DirListStr := DirListStr + DirList[I].ToWide();
+ end;
+ Result := Path(WideFileSearch(Name.ToWide(), DirListStr));
+end;
+
+function TFileSystemImpl.RenameFile(const OldName, NewName: IPath): boolean;
+begin
+ Result := WideRenameFile(OldName.ToWide(), NewName.ToWide());
+end;
+
+function TFileSystemImpl.DeleteFile(const FileName: IPath): boolean;
+begin
+ Result := WideDeleteFile(FileName.ToWide());
+end;
+
+function TFileSystemImpl.RemoveDir(const Dir: IPath): boolean;
+begin
+ Result := WideRemoveDir(Dir.ToWide());
+end;
+
+function TFileSystemImpl.CopyFile(const Source, Target: IPath; FailIfExists: boolean): boolean;
+begin
+ Result := WideCopyFile(Source.ToWide(), Target.ToWide(), FailIfExists);
+end;
+
+function TFileSystemImpl.ExtractFileDrive(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExtractFileDrive(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ExtractFilePath(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExtractFilePath(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ExtractFileDir(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExtractFileDir(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ExtractFileName(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExtractFileName(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ExtractFileExt(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExtractFileExt(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ExtractRelativePath(const BaseName: IPath; const FileName: IPath): IPath;
+begin
+ Result := Path(WideExtractRelativePath(BaseName.ToWide(), FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ChangeFileExt(const FileName: IPath; const Extension: IPath): IPath;
+begin
+ Result := Path(WideChangeFileExt(FileName.ToWide(), Extension.ToWide()));
+end;
+
+function TFileSystemImpl.IncludeTrailingPathDelimiter(const FileName: IPath): IPath;
+begin
+ Result := Path(WideIncludeTrailingPathDelimiter(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.ExcludeTrailingPathDelimiter(const FileName: IPath): IPath;
+begin
+ Result := Path(WideExcludeTrailingPathDelimiter(FileName.ToWide()));
+end;
+
+function TFileSystemImpl.FindFirst(const FilePattern: IPath; Attr: integer; var F: TSytemSearchRec): integer;
+begin
+ Result := WideFindFirst(FilePattern.ToWide(), Attr, F);
+end;
+
+function TFileSystemImpl.FindNext(var F: TSytemSearchRec): integer;
+begin
+ Result := WideFindNext(F);
+end;
+
+procedure TFileSystemImpl.FindClose(var F: TSytemSearchRec);
+begin
+ WideFindClose(F);
+end;
+
+function TFileSystemImpl.GetCurrentDir: IPath;
+begin
+ Result := Path(WideGetCurrentDir());
+end;
+
+function TFileSystemImpl.SetCurrentDir(const Dir: IPath): boolean;
+begin
+ Result := WideSetCurrentDir(Dir.ToWide());
+end;
+
+{$ELSE} // UNIX
+
+function TFileSystemImpl.ExpandFileName(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExpandFileName(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.FileCreate(const FileName: IPath): THandle;
+begin
+ Result := SysUtils.FileCreate(FileName.ToNative());
+end;
+
+function TFileSystemImpl.DirectoryCreate(const Dir: IPath): boolean;
+begin
+ Result := SysUtils.CreateDir(Dir.ToNative());
+end;
+
+function TFileSystemImpl.FileOpen(const FileName: IPath; Mode: longword): THandle;
+begin
+ Result := SysUtils.FileOpen(FileName.ToNative(), Mode);
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath): integer;
+begin
+ Result := SysUtils.FileAge(FileName.ToNative());
+end;
+
+function TFileSystemImpl.FileAge(const FileName: IPath; out FileDateTime: TDateTime): boolean;
+var
+ FileDate: integer;
+begin
+ FileDate := SysUtils.FileAge(FileName.ToNative());
+ Result := (FileDate <> -1);
+ if (Result) then
+ FileDateTime := FileDateToDateTime(FileDate);
+end;
+
+function TFileSystemImpl.DirectoryExists(const Name: IPath): boolean;
+begin
+ Result := SysUtils.DirectoryExists(Name.ToNative());
+end;
+
+function TFileSystemImpl.FileExists(const Name: IPath): boolean;
+begin
+ Result := SysUtils.FileExists(Name.ToNative());
+end;
+
+function TFileSystemImpl.FileGetAttr(const FileName: IPath): Cardinal;
+begin
+ Result := SysUtils.FileGetAttr(FileName.ToNative());
+end;
+
+function TFileSystemImpl.FileSetAttr(const FileName: IPath; Attr: integer): boolean;
+begin
+ Result := (SysUtils.FileSetAttr(FileName.ToNative(), Attr) = 0);
+end;
+
+function TFileSystemImpl.FileIsReadOnly(const FileName: IPath): boolean;
+begin
+ Result := SysUtils.FileIsReadOnly(FileName.ToNative());
+end;
+
+function TFileSystemImpl.FileSetReadOnly(const FileName: IPath; ReadOnly: boolean): boolean;
+begin
+ Result := (SysUtils.FileSetAttr(FileName.ToNative(), faReadOnly) = 0);
+end;
+
+function TFileSystemImpl.ForceDirectories(const Dir: IPath): boolean;
+begin
+ Result := SysUtils.ForceDirectories(Dir.ToNative());
+end;
+
+function TFileSystemImpl.FileSearch(const Name: IPath; DirList: array of IPath): IPath;
+var
+ I: integer;
+ DirListStr: AnsiString;
+begin
+ DirListStr := '';
+ for I := 0 to High(DirList) do
+ begin
+ if (I > 0) then
+ DirListStr := DirListStr + PathSep;
+ DirListStr := DirListStr + DirList[I].ToNative();
+ end;
+ Result := Path(SysUtils.FileSearch(Name.ToNative(), DirListStr));
+end;
+
+function TFileSystemImpl.RenameFile(const OldName, NewName: IPath): boolean;
+begin
+ Result := SysUtils.RenameFile(OldName.ToNative(), NewName.ToNative());
+end;
+
+function TFileSystemImpl.DeleteFile(const FileName: IPath): boolean;
+begin
+ Result := SysUtils.DeleteFile(FileName.ToNative());
+end;
+
+function TFileSystemImpl.RemoveDir(const Dir: IPath): boolean;
+begin
+ Result := SysUtils.RemoveDir(Dir.ToNative());
+end;
+
+function TFileSystemImpl.CopyFile(const Source, Target: IPath; 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.ToNative(), fmOpenRead);
+ TargetFile := TFileStream.Create(Target.ToNative(), 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;
+
+function TFileSystemImpl.ExtractFileDrive(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExtractFileDrive(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ExtractFilePath(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExtractFilePath(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ExtractFileDir(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExtractFileDir(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ExtractFileName(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExtractFileName(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ExtractFileExt(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExtractFileExt(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ExtractRelativePath(const BaseName: IPath; const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExtractRelativePath(BaseName.ToNative(), FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ChangeFileExt(const FileName: IPath; const Extension: IPath): IPath;
+begin
+ Result := Path(SysUtils.ChangeFileExt(FileName.ToNative(), Extension.ToNative()));
+end;
+
+function TFileSystemImpl.IncludeTrailingPathDelimiter(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.IncludeTrailingPathDelimiter(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.ExcludeTrailingPathDelimiter(const FileName: IPath): IPath;
+begin
+ Result := Path(SysUtils.ExcludeTrailingPathDelimiter(FileName.ToNative()));
+end;
+
+function TFileSystemImpl.FindFirst(const FilePattern: IPath; Attr: integer; var F: TSytemSearchRec): integer;
+begin
+ Result := SysUtils.FindFirst(FilePattern.ToNative(), Attr, F);
+end;
+
+function TFileSystemImpl.FindNext(var F: TSytemSearchRec): integer;
+begin
+ Result := SysUtils.FindNext(F);
+end;
+
+procedure TFileSystemImpl.FindClose(var F: TSytemSearchRec);
+begin
+ SysUtils.FindClose(F);
+end;
+
+function TFileSystemImpl.GetCurrentDir: IPath;
+begin
+ Result := Path(SysUtils.GetCurrentDir());
+end;
+
+function TFileSystemImpl.SetCurrentDir(const Dir: IPath): boolean;
+begin
+ Result := SysUtils.SetCurrentDir(Dir.ToNative());
+end;
+
+{$ENDIF}
+
+
+{ TFileIterator }
+
+constructor TFileIterator.Create(const FilePattern: IPath; Attr: integer);
+begin
+ inherited Create();
+ fHasNext := (FileSystem.FindFirst(FilePattern, Attr, fSearchRec) = 0);
+end;
+
+destructor TFileIterator.Destroy();
+begin
+ FileSystem.FindClose(fSearchRec);
+ inherited;
+end;
+
+function TFileIterator.HasNext(): boolean;
+begin
+ Result := fHasNext;
+end;
+
+function TFileIterator.Next(): TFileInfo;
+begin
+ if (not fHasNext) then
+ begin
+ // Note: do not use FillChar() on records with ref-counted fields
+ Result.Time := 0;
+ Result.Size := 0;
+ Result.Attr := 0;
+ Result.Name := nil;
+ Exit;
+ end;
+
+ Result.Time := fSearchRec.Time;
+ Result.Size := fSearchRec.Size;
+ Result.Attr := fSearchRec.Attr;
+ Result.Name := Path(fSearchRec.Name);
+
+ // fetch next entry
+ fHasNext := (FileSystem.FindNext(fSearchRec) = 0);
+end;
+
+
+initialization
+ FileSystem_Singleton := TFileSystemImpl.Create;
+
+finalization
+ FileSystem_Singleton := nil;
+
+end.
diff --git a/src/base/UFont.pas b/src/base/UFont.pas
index a72bca21..72409ac1 100644
--- a/src/base/UFont.pas
+++ b/src/base/UFont.pas
@@ -47,12 +47,14 @@ uses
glext,
glu,
sdl,
+ Math,
+ Classes,
+ SysUtils,
+ UUnicodeUtils,
{$IFDEF BITMAP_FONT}
UTexture,
{$ENDIF}
- Math,
- Classes,
- SysUtils;
+ UPath;
type
@@ -60,7 +62,7 @@ type
TGLubyteArray = array[0 .. (MaxInt div SizeOf(GLubyte))-1] of GLubyte;
TGLubyteDynArray = array of GLubyte;
- TWideStringArray = array of WideString;
+ TUCS4StringArray = array of UCS4String;
TGLColor = packed record
case byte of
@@ -126,34 +128,34 @@ type
{**
* Splits lines in Text seperated by newline (char-code #13).
- * @param Text UTF-8 encoded string
- * @param Lines splitted WideString lines
+ * @param Text UCS-4 encoded string
+ * @param Lines splitted UCS4String lines
*}
- procedure SplitLines(const Text: UTF8String; var Lines: TWideStringArray);
+ procedure SplitLines(const Text: UCS4String; var Lines: TUCS4StringArray);
{**
- * Print an array of WideStrings. Each array-item is a line of text.
+ * Print an array of UCS4Strings. Each array-item is a line of text.
* Lines of text are seperated by the line-spacing.
* This is the base function for all text drawing.
*}
- procedure Print(const Text: TWideStringArray); overload; virtual;
+ procedure Print(const Text: TUCS4StringArray); overload; virtual;
{**
* Draws an underline.
*}
- procedure DrawUnderline(const Text: WideString); virtual;
+ procedure DrawUnderline(const Text: UCS4String); virtual;
{**
* Renders (one) line of text.
*}
- procedure Render(const Text: WideString); virtual; abstract;
+ procedure Render(const Text: UCS4String); virtual; abstract;
{**
* Returns the bounds of text-lines contained in Text.
* @param(Advance if true the right bound is set to the advance instead
* of the minimal right bound.)
*}
- function BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl; overload; virtual; abstract;
+ function BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl; overload; virtual; abstract;
{**
* Resets all user settings to default values.
@@ -188,9 +190,11 @@ type
{**
* Prints a text.
*}
+ procedure Print(const Text: UCS4String); overload;
+ {** UTF-16 version of @link(Print) }
procedure Print(const Text: WideString); overload;
{** UTF-8 version of @link(Print) }
- procedure Print(const Text: string); overload;
+ procedure Print(const Text: UTF8String); overload;
{**
* Calculates the bounding box (width and height) around Text.
@@ -203,6 +207,8 @@ type
* bigger than the text's width as it additionally contains the advance
* and glyph-spacing of the last character.
*}
+ function BBox(const Text: UCS4String; Advance: boolean = true): TBoundsDbl; overload;
+ {** UTF-16 version of @link(BBox) }
function BBox(const Text: WideString; Advance: boolean = true): TBoundsDbl; overload;
{** UTF-8 version of @link(BBox) }
function BBox(const Text: UTF8String; Advance: boolean = true): TBoundsDbl; overload;
@@ -249,9 +255,9 @@ type
/// Mipmap fonts (size[level+1] = size[level]/2)
fMipmapFonts: array[0..cMaxMipmapLevel] of TFont;
- procedure Render(const Text: WideString); override;
- procedure Print(const Text: TWideStringArray); override;
- function BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl; override;
+ procedure Render(const Text: UCS4String); override;
+ procedure Print(const Text: TUCS4StringArray); override;
+ function BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl; override;
{**
* Callback called for creation of each mipmap font.
@@ -322,7 +328,7 @@ type
{**
* Table for storage of max. 256 glyphs.
- * Used for the second cache level. Indexed by the LSB of the WideChar
+ * Used for the second cache level. Indexed by the LSB of the UCS4Char
* char-code.
*}
PGlyphTable = ^TGlyphTable;
@@ -332,7 +338,7 @@ type
* Cache for glyphs of a single font.
* The cached glyphs are stored inside a hash-list.
* Hashing is performed in two steps:
- * 1. the least significant byte (LSB) of the WideChar character code
+ * 1. the least significant byte (LSB) of the UCS4Char character code
* is removed (shr 8) and the result (we call it BaseCode here) looked up in
* the hash-list.
* 2. Each entry of the hash-list contains a table with max. 256 entries.
@@ -359,22 +365,22 @@ type
* Add glyph Glyph with char-code ch to the cache.
* @returns @true on success, @false otherwise
*}
- function AddGlyph(ch: WideChar; const Glyph: TGlyph): boolean;
+ function AddGlyph(ch: UCS4Char; const Glyph: TGlyph): boolean;
{**
* Removes the glyph with char-code ch from the cache.
*}
- procedure DeleteGlyph(ch: WideChar);
+ procedure DeleteGlyph(ch: UCS4Char);
{**
* Removes the glyph with char-code ch from the cache.
*}
- function GetGlyph(ch: WideChar): TGlyph;
+ function GetGlyph(ch: UCS4Char): TGlyph;
{**
* Checks if a glyph with char-code ch is cached.
*}
- function HasGlyph(ch: WideChar): boolean;
+ function HasGlyph(ch: UCS4Char): boolean;
{**
* Remove and free all cached glyphs. If KeepBaseSet is set to
@@ -408,13 +414,13 @@ type
* Retrieves a cached glyph with char-code ch from cache.
* If the glyph is not already cached, it is loaded with LoadGlyph().
*}
- function GetGlyph(ch: WideChar): TGlyph;
+ function GetGlyph(ch: UCS4Char): TGlyph;
{**
* Callback to create (load) a glyph with char-code ch.
* Implemented by subclasses.
*}
- function LoadGlyph(ch: WideChar): TGlyph; virtual; abstract;
+ function LoadGlyph(ch: UCS4Char): TGlyph; virtual; abstract;
public
constructor Create();
@@ -436,6 +442,7 @@ type
*}
TFTGlyph = class(TGlyph)
private
+ fCharCode: UCS4Char; //**< Char code
fCharIndex: FT_UInt; //**< Freetype specific char-index (<> char-code)
fDisplayList: GLuint; //**< Display-list ID
fTexture: GLuint; //**< Texture ID
@@ -458,7 +465,7 @@ type
* The bitmap must be 2* pixels wider and higher than the
* original glyph's bitmap with the latter centered in it.
*}
- procedure Extrude(var TexBuffer: TGLubyteDynArray; Outset: single);
+ procedure StrokeBorder(var Glyph: FT_Glyph);
{**
* Creates an OpenGL texture (and display list) for the glyph.
@@ -477,7 +484,7 @@ type
* Creates a glyph with char-code ch from font Font.
* @param LoadFlags flags passed to FT_Load_Glyph()
*}
- constructor Create(Font: TFTFont; ch: WideChar; Outset: single;
+ constructor Create(Font: TFTFont; ch: UCS4Char; Outset: single;
LoadFlags: FT_Int32);
destructor Destroy(); override;
@@ -490,6 +497,8 @@ type
property CharIndex: FT_UInt read fCharIndex;
end;
+ TFontPart = ( fpNone, fpInner, fpOutline );
+
{**
* Freetype font class.
*}
@@ -498,19 +507,20 @@ type
procedure ResetIntern();
protected
- fFilename: string; //**< 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
fLoadFlags: FT_Int32; //**< FT glpyh load-flags
fFontUnitScale: TPositionDbl; //**< FT font-units to pixel ratio
fUseDisplayLists: boolean; //**< true: use display-lists, false: direct drawing
+ fPart: TFontPart; //**< indicates the part of an outline font
{** @seealso TCachedFont.LoadGlyph }
- function LoadGlyph(ch: WideChar): TGlyph; override;
+ function LoadGlyph(ch: UCS4Char): TGlyph; override;
- procedure Render(const Text: WideString); override;
- function BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl; override;
+ procedure Render(const Text: UCS4String); override;
+ function BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl; override;
function GetHeight(): single; override;
function GetAscender(): single; override;
@@ -528,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: string;
+ constructor Create(const Filename: IPath;
Size: integer; Outset: single = 0.0;
LoadFlags: FT_Int32 = FT_LOAD_DEFAULT);
@@ -558,7 +568,7 @@ type
* The extrusion in pixels is Size*OutsetAmount
* (0.0 -> no extrusion, 0.1 -> 10%).
*}
- constructor Create(const Filename: string;
+ constructor Create(const Filename: IPath;
Size: integer; OutsetAmount: single = 0.0;
UseMipmaps: boolean = true);
@@ -576,7 +586,7 @@ type
*}
TFTOutlineFont = class(TFont)
private
- fFilename: string;
+ fFilename: IPath;
fSize: integer;
fOutset: single;
fInnerFont, fOutlineFont: TFTFont;
@@ -585,9 +595,9 @@ type
procedure ResetIntern();
protected
- procedure DrawUnderline(const Text: WideString); override;
- procedure Render(const Text: WideString); override;
- function BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl; override;
+ procedure DrawUnderline(const Text: UCS4String); override;
+ procedure Render(const Text: UCS4String); override;
+ function BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl; override;
function GetHeight(): single; override;
function GetAscender(): single; override;
@@ -603,7 +613,7 @@ type
procedure SetReflectionPass(Enable: boolean); override;
public
- constructor Create(const Filename: string;
+ constructor Create(const Filename: IPath;
Size: integer; Outset: single;
LoadFlags: FT_Int32 = FT_LOAD_DEFAULT);
destructor Destroy; override;
@@ -637,7 +647,7 @@ type
function CreateMipmap(Level: integer; Scale: single): TFont; override;
public
- constructor Create(const Filename: string;
+ constructor Create(const Filename: IPath;
Size: integer; OutsetAmount: single;
UseMipmaps: boolean = true);
@@ -672,18 +682,18 @@ type
procedure ResetIntern();
- procedure RenderChar(ch: WideChar; var AdvanceX: real);
+ procedure RenderChar(ch: UCS4Char; var AdvanceX: real);
{**
* Load font widths from an info file.
* @param InfoFile the name of the info (.dat) file
* @raises Exception if the file is corrupted
*}
- procedure LoadFontInfo(const InfoFile: string);
+ procedure LoadFontInfo(const InfoFile: IPath);
protected
- procedure Render(const Text: WideString); override;
- function BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl; override;
+ procedure Render(const Text: UCS4String); override;
+ function BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl; override;
function GetHeight(): single; override;
function GetAscender(): single; override;
@@ -699,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: string; Outline: integer;
+ constructor Create(const Filename: IPath; Outline: integer;
Baseline, Ascender, Descender: integer);
destructor Destroy(); override;
@@ -801,37 +811,61 @@ begin
ResetIntern();
end;
-procedure TFont.SplitLines(const Text: UTF8String; var Lines: TWideStringArray);
+procedure TFont.SplitLines(const Text: UCS4String; var Lines: TUCS4StringArray);
var
- LineList: TStringList;
- LineIndex: integer;
+ CharIndex: integer;
+ LineStart: integer;
+ LineLength: integer;
+ EOT: boolean; // End-Of-Text
begin
- // split lines on newline (there is no WideString version of ExtractStrings)
- LineList := TStringList.Create();
- ExtractStrings([#13], [], PChar(Text), LineList);
+ // split lines on newline
+ SetLength(Lines, 0);
+ EOT := false;
+ LineStart := 0;
+
+ for CharIndex := 0 to High(Text) do
+ begin
+ // check for end of text (UCS4Strings are zero-terminated)
+ if (CharIndex = High(Text)) then
+ EOT := true;
+
+ // check for newline (carriage return (#13)) or end of text
+ if (Text[CharIndex] = 13) or EOT then
+ begin
+ LineLength := CharIndex - LineStart;
+ // check if last character was a newline
+ if (EOT and (LineLength = 0)) then
+ Break;
- // create an array of WideStrins from the UTF-8 string-list
- SetLength(Lines, LineList.Count);
- for LineIndex := 0 to LineList.Count-1 do
- Lines[LineIndex] := UTF8Decode(LineList[LineIndex]);
- LineList.Free();
+ // copy line (even if LineLength is 0)
+ SetLength(Lines, Length(Lines)+1);
+ Lines[High(Lines)] := UCS4Copy(Text, LineStart, LineLength);
+
+ LineStart := CharIndex+1;
+ end;
+ end;
end;
-function TFont.BBox(const Text: UTF8String; Advance: boolean): TBoundsDbl;
+function TFont.BBox(const Text: UCS4String; Advance: boolean): TBoundsDbl;
var
- LineArray: TWideStringArray;
+ LineArray: TUCS4StringArray;
begin
SplitLines(Text, LineArray);
Result := BBox(LineArray, Advance);
SetLength(LineArray, 0);
end;
+function TFont.BBox(const Text: UTF8String; Advance: boolean): TBoundsDbl;
+begin
+ Result := BBox(UTF8Decode(Text), Advance);
+end;
+
function TFont.BBox(const Text: WideString; Advance: boolean): TBoundsDbl;
begin
- Result := BBox(UTF8Encode(Text), Advance);
+ Result := BBox(WideStringToUCS4String(Text), Advance);
end;
-procedure TFont.Print(const Text: TWideStringArray);
+procedure TFont.Print(const Text: TUCS4StringArray);
var
LineIndex: integer;
begin
@@ -912,21 +946,26 @@ begin
glPopAttrib();
end;
-procedure TFont.Print(const Text: string);
+procedure TFont.Print(const Text: UCS4String);
var
- LineArray: TWideStringArray;
+ LineArray: TUCS4StringArray;
begin
SplitLines(Text, LineArray);
Print(LineArray);
SetLength(LineArray, 0);
end;
+procedure TFont.Print(const Text: UTF8String);
+begin
+ Print(UTF8Decode(Text));
+end;
+
procedure TFont.Print(const Text: WideString);
begin
- Print(UTF8Encode(Text));
+ Print(WideStringToUCS4String(Text));
end;
-procedure TFont.DrawUnderline(const Text: WideString);
+procedure TFont.DrawUnderline(const Text: UCS4String);
var
UnderlineY1, UnderlineY2: single;
Bounds: TBoundsDbl;
@@ -1194,7 +1233,7 @@ begin
glScalef(MipmapScale, MipmapScale, 0);
end;
-procedure TScalableFont.Print(const Text: TWideStringArray);
+procedure TScalableFont.Print(const Text: TUCS4StringArray);
begin
glPushMatrix();
@@ -1210,12 +1249,12 @@ begin
glPopMatrix();
end;
-procedure TScalableFont.Render(const Text: WideString);
+procedure TScalableFont.Render(const Text: UCS4String);
begin
Assert(false, 'Unused TScalableFont.Render() was called');
end;
-function TScalableFont.BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl;
+function TScalableFont.BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl;
begin
Result := fBaseFont.BBox(Text, Advance);
Result.Left := Result.Left * fScale * fAspect;
@@ -1346,7 +1385,7 @@ begin
inherited;
end;
-function TCachedFont.GetGlyph(ch: WideChar): TGlyph;
+function TCachedFont.GetGlyph(ch: UCS4Char): TGlyph;
begin
Result := fCache.GetGlyph(ch);
if (Result = nil) then
@@ -1368,11 +1407,11 @@ end;
*}
constructor TFTFont.Create(
- const Filename: string;
+ const Filename: IPath;
Size: integer; Outset: single;
LoadFlags: FT_Int32);
var
- i: WideChar;
+ ch: UCS4Char;
begin
inherited Create();
@@ -1381,10 +1420,11 @@ begin
fOutset := Outset;
fLoadFlags := LoadFlags;
fUseDisplayLists := true;
+ 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
@@ -1400,8 +1440,8 @@ begin
ResetIntern();
// pre-cache some commonly used glyphs (' ' - '~')
- for i := #32 to #126 do
- fCache.AddGlyph(i, TFTGlyph.Create(Self, i, Outset, LoadFlags));
+ for ch := 32 to 126 do
+ fCache.AddGlyph(ch, TFTGlyph.Create(Self, ch, Outset, LoadFlags));
end;
destructor TFTFont.Destroy();
@@ -1424,15 +1464,15 @@ begin
ResetIntern();
end;
-function TFTFont.LoadGlyph(ch: WideChar): TGlyph;
+function TFTFont.LoadGlyph(ch: UCS4Char): TGlyph;
begin
Result := TFTGlyph.Create(Self, ch, Outset, fLoadFlags);
end;
-function TFTFont.BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl;
+function TFTFont.BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl;
var
Glyph, PrevGlyph: TFTGlyph;
- TextLine: WideString;
+ TextLine: UCS4String;
LineYOffset: single;
LineIndex, CharIndex: integer;
LineBounds: TBoundsDbl;
@@ -1462,7 +1502,7 @@ begin
LineBounds.Top := 0;
// for each glyph image, compute its bounding box
- for CharIndex := 1 to Length(TextLine) do
+ for CharIndex := 0 to LengthUCS4(TextLine)-1 do
begin
Glyph := TFTGlyph(GetGlyph(TextLine[CharIndex]));
if (Glyph <> nil) then
@@ -1480,9 +1520,9 @@ begin
LineBounds.Left := LineBounds.Right + Glyph.Bounds.Left;
// update right bound
- if (CharIndex < Length(TextLine)) or // not the last character
- (TextLine[CharIndex] = ' ') or // on space char (Bounds.Right = 0)
- Advance then // or in advance mode
+ if (CharIndex < LengthUCS4(TextLine)-1) or // not the last character
+ (TextLine[CharIndex] = Ord(' ')) or // on space char (Bounds.Right = 0)
+ Advance then // or in advance mode
begin
// add advance and glyph spacing
LineBounds.Right := LineBounds.Right + Glyph.Advance.x + GlyphSpacing
@@ -1534,13 +1574,13 @@ begin
end;
// if left or bottom bound was not set, set them to 0
- if (Result.Left = Infinity) then
+ if (IsInfinite(Result.Left)) then
Result.Left := 0.0;
- if (Result.Bottom = Infinity) then
+ if (IsInfinite(Result.Bottom)) then
Result.Bottom := 0.0;
end;
-procedure TFTFont.Render(const Text: WideString);
+procedure TFTFont.Render(const Text: UCS4String);
var
CharIndex: integer;
Glyph, PrevGlyph: TFTGlyph;
@@ -1550,7 +1590,7 @@ begin
PrevGlyph := nil;
// draw current line
- for CharIndex := 1 to Length(Text) do
+ for CharIndex := 0 to LengthUCS4(Text)-1 do
begin
Glyph := TFTGlyph(GetGlyph(Text[CharIndex]));
if (Assigned(Glyph)) then
@@ -1606,7 +1646,7 @@ end;
* TFTScalableFont
*}
-constructor TFTScalableFont.Create(const Filename: string;
+constructor TFTScalableFont.Create(const Filename: IPath;
Size: integer; OutsetAmount: single;
UseMipmaps: boolean);
var
@@ -1662,7 +1702,7 @@ end;
*}
constructor TFTOutlineFont.Create(
- const Filename: string;
+ const Filename: IPath;
Size: integer; Outset: single;
LoadFlags: FT_Int32);
begin
@@ -1673,7 +1713,9 @@ begin
fOutset := Outset;
fInnerFont := TFTFont.Create(Filename, Size, 0.0, LoadFlags);
+ fInnerFont.fPart := fpInner;
fOutlineFont := TFTFont.Create(Filename, Size, Outset, LoadFlags);
+ fOutlineFont.fPart := fpOutline;
ResetIntern();
end;
@@ -1705,7 +1747,7 @@ begin
ResetIntern();
end;
-procedure TFTOutlineFont.DrawUnderline(const Text: WideString);
+procedure TFTOutlineFont.DrawUnderline(const Text: UCS4String);
var
CurrentColor: TGLColor;
OutlineColor: TGLColor;
@@ -1730,7 +1772,7 @@ begin
glPopMatrix();
end;
-procedure TFTOutlineFont.Render(const Text: WideString);
+procedure TFTOutlineFont.Render(const Text: UCS4String);
var
CurrentColor: TGLColor;
OutlineColor: TGLColor;
@@ -1770,7 +1812,7 @@ begin
fInnerFont.FlushCache(KeepBaseSet);
end;
-function TFTOutlineFont.BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl;
+function TFTOutlineFont.BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl;
begin
Result := fOutlineFont.BBox(Text, Advance);
end;
@@ -1852,7 +1894,7 @@ end;
*}
constructor TFTScalableOutlineFont.Create(
- const Filename: string;
+ const Filename: IPath;
Size: integer; OutsetAmount: single;
UseMipmaps: boolean);
var
@@ -1935,82 +1977,113 @@ const
*}
cTexSmoothBorder = 1;
-procedure TFTGlyph.Extrude(var TexBuffer: TGLubyteDynArray; Outset: single);
+procedure TFTGlyph.StrokeBorder(var Glyph: FT_Glyph);
+var
+ Outline: PFT_Outline;
+ OuterStroker, InnerStroker: FT_Stroker;
+ OuterNumPoints, InnerNumPoints, GlyphNumPoints: FT_UInt;
+ OuterNumContours, InnerNumContours, GlyphNumContours: FT_UInt;
+ OuterBorder, InnerBorder: FT_StrokerBorder;
+ OutlineFlags: FT_Int;
+ UseStencil: boolean;
+begin
+ // It is possible to extrude the borders of a glyph with FT_Glyph_Stroke
+ // but it will extrude the border to the outside and the inside of a glyph
+ // although we just want to extrude to the outside.
+ // FT_Glyph_StrokeBorder extrudes to the outside but also fills the interior
+ // (this is what we need for bold fonts).
+ // In both cases the inner font and outline font (border) will overlap.
+ // Normally this does not matter but it does if alpha blending is active.
+ // In this case if e.g. the inner color is set to white, the outline to red
+ // and alpha to 0.5 the inner part will not be white it will be pink.
+
+ InnerStroker := nil;
+ OuterStroker := nil;
+
+ // If we are to create the interior of an outlined font (fInner = true)
+ // we have to create two borders:
+ // - one extruded to the outside by fOutset pixels and
+ // - one extruded to the inside by almost 0 zero pixels.
+ // The second one is used as a stencil for the first one, clearing the
+ // interiour of the glyph.
+ // The stencil is not needed to create bold fonts.
+ UseStencil := (fFont.fPart = fpInner);
+
+ Outline := @FT_OutlineGlyph(Glyph).outline;
+
+ OuterBorder := FT_Outline_GetOutsideBorder(Outline);
+ if (OuterBorder = FT_STROKER_BORDER_LEFT) then
+ InnerBorder := FT_STROKER_BORDER_RIGHT
+ else
+ InnerBorder := FT_STROKER_BORDER_LEFT;
+
+ { extrude outer border }
+
+ if (FT_Stroker_New(Glyph.library_, OuterStroker) <> 0) then
+ raise Exception.Create('FT_Stroker_New failed!');
+ FT_Stroker_Set(
+ OuterStroker,
+ Round(fOutset * 64),
+ FT_STROKER_LINECAP_ROUND,
+ FT_STROKER_LINEJOIN_BEVEL,
+ 0);
+
+ // similar to FT_Glyph_StrokeBorder(inner = FT_FALSE) but it is possible to
+ // use FT_Stroker_ExportBorder() afterwards to combine inner and outer borders
+ if (FT_Stroker_ParseOutline(OuterStroker, Outline, FT_FALSE) <> 0) then
+ raise Exception.Create('FT_Stroker_ParseOutline failed!');
- procedure SetToMax(var Val1: GLubyte; Val2: GLubyte); {$IFDEF HasInline}inline;{$ENDIF}
+ FT_Stroker_GetBorderCounts(OuterStroker, OuterBorder, OuterNumPoints, OuterNumContours);
+
+ { extrude inner border (= stencil) }
+
+ if (UseStencil) then
begin
- if (Val1 < Val2) then
- Val1 := Val2;
+ if (FT_Stroker_New(Glyph.library_, InnerStroker) <> 0) then
+ raise Exception.Create('FT_Stroker_New failed!');
+ FT_Stroker_Set(
+ InnerStroker,
+ 63, // extrude at most one pixel to avoid a black border
+ FT_STROKER_LINECAP_ROUND,
+ FT_STROKER_LINEJOIN_BEVEL,
+ 0);
+
+ if (FT_Stroker_ParseOutline(InnerStroker, Outline, FT_FALSE) <> 0) then
+ raise Exception.Create('FT_Stroker_ParseOutline failed!');
+
+ FT_Stroker_GetBorderCounts(InnerStroker, InnerBorder, InnerNumPoints, InnerNumContours);
+ end else begin
+ InnerNumPoints := 0;
+ InnerNumContours := 0;
end;
-var
- I, X, Y: integer;
- SrcBuffer,TmpBuffer: TGLubyteDynArray;
- TexLine, TexLinePrev, TexLineNext: PGLubyteArray;
- SrcLine: PGLubyteArray;
- AlphaScale: single;
- Value, ValueNeigh, ValueDiag: GLubyte;
-const
- // square-root of 2 used for diagonal neighbor pixels
- cSqrt2 = 1.4142;
- // number of ignored pixels on each edge of the bitmap. Consists of:
- // - border used for font smoothing and
- // - outer (extruded) bitmap pixel (because it is just written but never read)
- cBorder = cTexSmoothBorder + 1;
-begin
- // allocate memory for temporary buffer
- SetLength(SrcBuffer, Length(TexBuffer));
- FillChar(SrcBuffer[0], Length(TexBuffer), 0);
-
- // extrude pixel by pixel
- for I := 1 to Ceil(Outset) do
- begin
- // swap arrays
- TmpBuffer := TexBuffer;
- TexBuffer := SrcBuffer;
- SrcBuffer := TmpBuffer;
-
- // as long as we add an entire pixel of outset, use a solid color.
- // If the fractional part is reached blend, e.g. outline=3.2 -> 3 solid
- // pixels and one blended with alpha=0.2.
- // For the fractional part I = Ceil(Outset) is always true.
- if (I <= Outset) then
- AlphaScale := 1
- else
- AlphaScale := Outset - Trunc(Outset);
-
- // copy data to the expanded bitmap.
- for Y := cBorder to fTexSize.Height - 2*cBorder do
- begin
- TexLine := @TexBuffer[Y*fTexSize.Width];
- TexLinePrev := @TexBuffer[(Y-1)*fTexSize.Width];
- TexLineNext := @TexBuffer[(Y+1)*fTexSize.Width];
- SrcLine := @SrcBuffer[Y*fTexSize.Width];
+ { combine borders (subtract: OuterBorder - InnerBorder) }
- // expand current line's pixels
- for X := cBorder to fTexSize.Width - 2*cBorder do
- begin
- Value := SrcLine[X];
- ValueNeigh := Round(Value * AlphaScale);
- ValueDiag := Round(ValueNeigh / cSqrt2);
+ GlyphNumPoints := InnerNumPoints + OuterNumPoints;
+ GlyphNumContours := InnerNumContours + OuterNumContours;
- SetToMax(TexLine[X], Value);
- SetToMax(TexLine[X-1], ValueNeigh);
- SetToMax(TexLine[X+1], ValueNeigh);
+ // save flags before deletion (TODO: set them on the resulting outline)
+ OutlineFlags := Outline.flags;
- SetToMax(TexLinePrev[X], ValueNeigh);
- SetToMax(TexLinePrev[X-1], ValueDiag);
- SetToMax(TexLinePrev[X+1], ValueDiag);
+ // resize glyph outline to hold inner and outer border
+ FT_Outline_Done(Glyph.Library_, Outline);
+ if (FT_Outline_New(Glyph.Library_, GlyphNumPoints, GlyphNumContours, Outline) <> 0) then
+ raise Exception.Create('FT_Outline_New failed!');
- SetToMax(TexLineNext[X], ValueNeigh);
- SetToMax(TexLineNext[X-1], ValueDiag);
- SetToMax(TexLineNext[X+1], ValueDiag);
- end;
- end;
- end;
+ Outline.n_points := 0;
+ Outline.n_contours := 0;
- TmpBuffer := nil;
- SetLength(SrcBuffer, 0);
+ // add points to outline. The inner-border is used as a stencil.
+ FT_Stroker_ExportBorder(OuterStroker, OuterBorder, Outline);
+ if (UseStencil) then
+ FT_Stroker_ExportBorder(InnerStroker, InnerBorder, Outline);
+ if (FT_Outline_Check(outline) <> 0) then
+ raise Exception.Create('FT_Stroker_ExportBorder failed!');
+
+ if (InnerStroker <> nil) then
+ FT_Stroker_Done(InnerStroker);
+ if (OuterStroker <> nil) then
+ FT_Stroker_Done(OuterStroker);
end;
procedure TFTGlyph.CreateTexture(LoadFlags: FT_Int32);
@@ -2033,6 +2106,9 @@ begin
if (FT_Get_Glyph(fFont.Face^.glyph, Glyph) <> 0) then
raise Exception.Create('FT_Get_Glyph failed');
+ if (fOutset > 0) then
+ StrokeBorder(Glyph);
+
// store scaled advance width/height in glyph-object
fAdvance.X := fFont.Face^.glyph^.advance.x / 64 + fOutset*2;
fAdvance.Y := fFont.Face^.glyph^.advance.y / 64 + fOutset*2;
@@ -2114,9 +2190,6 @@ begin
end;
end;
- if (fOutset > 0) then
- Extrude(TexBuffer, fOutset);
-
// allocate resources for textures and display lists
glGenTextures(1, @fTexture);
@@ -2151,13 +2224,14 @@ begin
FT_Done_Glyph(Glyph);
end;
-constructor TFTGlyph.Create(Font: TFTFont; ch: WideChar; Outset: single;
+constructor TFTGlyph.Create(Font: TFTFont; ch: UCS4Char; Outset: single;
LoadFlags: FT_Int32);
begin
inherited Create();
fFont := Font;
fOutset := Outset;
+ fCharCode := ch;
// get the Freetype char-index (use default UNICODE charmap)
fCharIndex := FT_Get_Char_Index(Font.fFace, FT_ULONG(ch));
@@ -2336,7 +2410,7 @@ begin
InsertPos := fHash.Count;
end;
-function TGlyphCache.AddGlyph(ch: WideChar; const Glyph: TGlyph): boolean;
+function TGlyphCache.AddGlyph(ch: UCS4Char; const Glyph: TGlyph): boolean;
var
BaseCode: cardinal;
GlyphCode: integer;
@@ -2346,7 +2420,7 @@ var
begin
Result := false;
- BaseCode := cardinal(ch) shr 8;
+ BaseCode := Ord(ch) shr 8;
GlyphTable := FindGlyphTable(BaseCode, InsertPos);
if (GlyphTable = nil) then
begin
@@ -2356,7 +2430,7 @@ begin
end;
// get glyph table offset
- GlyphCode := cardinal(ch) and $FF;
+ GlyphCode := Ord(ch) and $FF;
// insert glyph into table if not present
if (GlyphTable[GlyphCode] = nil) then
begin
@@ -2365,19 +2439,19 @@ begin
end;
end;
-procedure TGlyphCache.DeleteGlyph(ch: WideChar);
+procedure TGlyphCache.DeleteGlyph(ch: UCS4Char);
var
Table: PGlyphTable;
TableIndex, GlyphIndex: integer;
TableEmpty: boolean;
begin
// find table
- Table := FindGlyphTable(cardinal(ch) shr 8, TableIndex);
+ Table := FindGlyphTable(Ord(ch) shr 8, TableIndex);
if (Table = nil) then
Exit;
// find glyph
- GlyphIndex := cardinal(ch) and $FF;
+ GlyphIndex := Ord(ch) and $FF;
if (Table[GlyphIndex] <> nil) then
begin
// destroy glyph
@@ -2402,19 +2476,19 @@ begin
end;
end;
-function TGlyphCache.GetGlyph(ch: WideChar): TGlyph;
+function TGlyphCache.GetGlyph(ch: UCS4Char): TGlyph;
var
InsertPos: integer;
Table: PGlyphTable;
begin
- Table := FindGlyphTable(cardinal(ch) shr 8, InsertPos);
+ Table := FindGlyphTable(Ord(ch) shr 8, InsertPos);
if (Table = nil) then
Result := nil
else
- Result := Table[cardinal(ch) and $FF];
+ Result := Table[Ord(ch) and $FF];
end;
-function TGlyphCache.HasGlyph(ch: WideChar): boolean;
+function TGlyphCache.HasGlyph(ch: UCS4Char): boolean;
begin
Result := (GetGlyph(ch) <> nil);
end;
@@ -2482,7 +2556,7 @@ end;
* TBitmapFont
*}
-constructor TBitmapFont.Create(const Filename: string; Outline: integer;
+constructor TBitmapFont.Create(const Filename: IPath; Outline: integer;
Baseline, Ascender, Descender: integer);
begin
inherited Create();
@@ -2494,7 +2568,7 @@ begin
fAscender := Ascender;
fDescender := Descender;
- LoadFontInfo(ChangeFileExt(Filename, '.dat'));
+ LoadFontInfo(Filename.SetExtension('.dat'));
ResetIntern();
end;
@@ -2524,27 +2598,27 @@ begin
fWidths[Count] := Round(fWidths[Count] * WidthMult) + WidthAdd;
end;
-procedure TBitmapFont.LoadFontInfo(const InfoFile: string);
+procedure TBitmapFont.LoadFontInfo(const InfoFile: IPath);
var
- Stream: TFileStream;
+ Stream: TStream;
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;
-function TBitmapFont.BBox(const Text: TWideStringArray; Advance: boolean): TBoundsDbl;
+function TBitmapFont.BBox(const Text: TUCS4StringArray; Advance: boolean): TBoundsDbl;
var
LineIndex, CharIndex: integer;
CharCode: cardinal;
- Line: WideString;
+ Line: UCS4String;
LineWidth: double;
begin
Result.Left := 0;
@@ -2556,7 +2630,7 @@ begin
begin
Line := Text[LineIndex];
LineWidth := 0;
- for CharIndex := 1 to Length(Line) do
+ for CharIndex := 0 to LengthUCS4(Line)-1 do
begin
CharCode := Ord(Line[CharIndex]);
if (CharCode < Length(fWidths)) then
@@ -2567,7 +2641,7 @@ begin
end;
end;
-procedure TBitmapFont.RenderChar(ch: WideChar; var AdvanceX: real);
+procedure TBitmapFont.RenderChar(ch: UCS4Char; var AdvanceX: real);
var
TexX, TexY: real;
TexR, TexB: real;
@@ -2659,20 +2733,20 @@ begin
AdvanceX := AdvanceX + GlyphWidth;
end;
-procedure TBitmapFont.Render(const Text: WideString);
+procedure TBitmapFont.Render(const Text: UCS4String);
var
CharIndex: integer;
AdvanceX: real;
begin
// if there is no text do nothing
- if (Text = '') then
+ if (Text = nil) or (Text[0] = 0) then
Exit;
//Save the current color and alpha (for reflection)
glGetFloatv(GL_CURRENT_COLOR, @fTempColor);
AdvanceX := 0;
- for CharIndex := 1 to Length(Text) do
+ for CharIndex := 0 to LengthUCS4(Text)-1 do
begin
RenderChar(Text[CharIndex], AdvanceX);
end;
diff --git a/src/base/UGraphic.pas b/src/base/UGraphic.pas
index a2456a13..7738e010 100644
--- a/src/base/UGraphic.pas
+++ b/src/base/UGraphic.pas
@@ -150,6 +150,7 @@ var
//popup mod
ScreenPopupCheck: TScreenPopupCheck;
ScreenPopupError: TScreenPopupError;
+ ScreenPopupInfo: TScreenPopupInfo;
//Notes
Tex_Left: array[0..6] of TTexture; //rename to tex_note_left
@@ -281,7 +282,7 @@ uses
UIni,
UDisplay,
UCommandLine,
- UPath;
+ UPathUtils;
procedure LoadFontTextures;
begin
@@ -362,7 +363,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;
@@ -411,14 +412,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;
@@ -433,23 +434,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');
@@ -486,9 +487,9 @@ 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);
+ SDL_WM_SetIcon(Icon, nil);
SDL_WM_SetCaption(PChar(Title), nil);
@@ -689,7 +690,7 @@ end;
procedure LoadLoadingScreen;
begin
ScreenLoading := TScreenLoading.Create;
- ScreenLoading.onShow;
+ ScreenLoading.OnShow;
Display.CurrentScreen := @ScreenLoading;
@@ -704,7 +705,7 @@ end;
procedure LoadScreens;
begin
{ ScreenLoading := TScreenLoading.Create;
- ScreenLoading.onShow;
+ ScreenLoading.OnShow;
Display.CurrentScreen := @ScreenLoading;
ScreenLoading.Draw;
Display.Draw;
@@ -765,6 +766,8 @@ begin
Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Popup (Check)', 3); Log.BenchmarkStart(3);
ScreenPopupError := TScreenPopupError.Create;
Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Popup (Error)', 3); Log.BenchmarkStart(3);
+ ScreenPopupInfo := TScreenPopupInfo.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Popup (Info)', 3); Log.BenchmarkStart(3);
ScreenPartyNewRound := TScreenPartyNewRound.Create;
Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyNewRound', 3); Log.BenchmarkStart(3);
ScreenPartyScore := TScreenPartyScore.Create;
@@ -816,6 +819,7 @@ begin
ScreenSongJumpto.Destroy;
ScreenPopupCheck.Destroy;
ScreenPopupError.Destroy;
+ ScreenPopupInfo.Destroy;
ScreenPartyNewRound.Destroy;
ScreenPartyScore.Destroy;
ScreenPartyWin.Destroy;
diff --git a/src/base/UImage.pas b/src/base/UImage.pas
index 6b0c509e..1866316e 100644
--- a/src/base/UImage.pas
+++ b/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
@@ -181,6 +182,7 @@ uses
zlib,
sdl_image,
sdlutils,
+ sdlstreams,
UCommon,
ULog;
@@ -282,26 +284,26 @@ end;
procedure user_read_data(png_ptr: png_structp; data: png_bytep; length: png_size_t); cdecl;
var
- inFile: TFileStream;
+ inFile: TStream;
begin
- inFile := TFileStream(png_get_io_ptr(png_ptr));
+ inFile := TStream(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: TStream;
begin
- outFile := TFileStream(png_get_io_ptr(png_ptr));
+ outFile := TStream(png_get_io_ptr(png_ptr));
outFile.Write(data^, length);
end;
procedure user_flush_data(png_ptr: png_structp); cdecl;
//var
-// outFile: TFileStream;
+// outFile: TStream;
begin
// binary files are flushed automatically, Flush() works with Text-files only
- //outFile := TFileStream(png_get_io_ptr(png_ptr));
+ //outFile := TStream(png_get_io_ptr(png_ptr));
//outFile.Flush();
end;
@@ -323,11 +325,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: TStream;
row: integer;
rowData: array of png_bytep;
// rowStride: integer;
@@ -339,9 +341,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 +502,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: TStream;
FileInfo: BITMAPINFOHEADER;
FileHeader: BITMAPFILEHEADER;
Converted: boolean;
@@ -513,9 +515,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 +581,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,18 +599,19 @@ 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;
BitmapInfo: TBitmapInfo;
Jpeg: TJpegImage;
row: integer;
+ FileStream: TBinaryFileStream;
{$ELSE}
- cinfo: jpeg_compress_struct;
- jerr : jpeg_error_mgr;
- jpgFile: TFileStream;
- rowPtr: array[0..0] of JSAMPROW;
+ cinfo: jpeg_compress_struct;
+ jerr : jpeg_error_mgr;
+ jpgFile: TBinaryFileStream;
+ rowPtr: array[0..0] of JSAMPROW;
{$ENDIF}
converted: boolean;
begin
@@ -669,19 +672,32 @@ begin
SDL_UnlockSurface(Surface);
// assign Bitmap to JPEG and store the latter
- Jpeg := TJPEGImage.Create;
- Jpeg.Assign(Bitmap);
- Bitmap.Free;
- Jpeg.CompressionQuality := Quality;
try
- // compress image (don't forget this line, otherwise it won't be compressed)
- Jpeg.Compress();
- Jpeg.SaveToFile(FileName);
+ // init with nil so Free() will not fail if an exception occurs
+ Jpeg := nil;
+ Bitmap := nil;
+ FileStream := nil;
+
+ try
+ Jpeg := TJPEGImage.Create;
+ Jpeg.Assign(Bitmap);
+
+ // compress image (don't forget this line, otherwise it won't be compressed)
+ Jpeg.CompressionQuality := Quality;
+ Jpeg.Compress();
+
+ // Note: FileStream needed for unicode filename support
+ FileStream := TBinaryFileStream.Create(Filename, fmCreate);
+ Jpeg.SaveToStream(FileStream);
+ finally
+ FileStream.Free;
+ Bitmap.Free;
+ Jpeg.Free;
+ end;
except
- Log.LogError('Could not save file: "' + FileName + '"', 'WriteJPGImage');
+ Log.LogError('Could not save file: "' + FileName.ToNative + '"', 'WriteJPGImage');
Exit;
end;
- Jpeg.Free;
{$ELSE}
// based on example.pas in FPC's packages/base/pasjpeg directory
@@ -703,9 +719,9 @@ begin
// open file for writing
try
- jpgFile := TFileStream.Create(FileName, fmCreate);
+ jpgFile := TBinaryFileStream.Create(FileName, fmCreate);
except
- Log.LogError('Could not open file: "' + FileName + '"', 'WriteJPGImage');
+ Log.LogError('Could not open file: "' + FileName.ToNative + '"', 'WriteJPGImage');
Exit;
end;
@@ -763,27 +779,29 @@ 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;
+ FileStream: TBinaryFileStream;
+ SDLStream: PSDL_RWops;
begin
- Result := nil;
-
- // FileExistsInsensitive() requires a var-arg
- FilenameFound := Filename;
+ Result := nil;
- // 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));
+ SDLStream := SDLStreamSetup(TBinaryFileStream.Create(FilenameCaseAdj, fmOpenRead));
+ Result := IMG_Load_RW(SDLStream, 1);
+ // Note: TBinaryFileStream is freed by SDLStream. SDLStream by IMG_Load_RW().
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/src/base/UIni.pas b/src/base/UIni.pas
index f92ea7c3..a3bc1876 100644
--- a/src/base/UIni.pas
+++ b/src/base/UIni.pas
@@ -37,7 +37,10 @@ uses
Classes,
IniFiles,
SysUtils,
- ULog;
+ ULog,
+ UTextEncoding,
+ UFilesystem,
+ UPath;
type
// TInputDeviceConfig stores the configuration for an input device.
@@ -70,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 TranslateOptionValues;
@@ -85,14 +87,14 @@ type
procedure LoadScreenModes(IniFile: TCustomIniFile);
public
- Name: array[0..11] of string;
+ Name: array[0..11] of UTF8String;
// Templates for Names Mod
- NameTeam: array[0..2] of string;
- NameTemplate: array[0..11] of string;
+ NameTeam: array[0..2] of UTF8String;
+ NameTemplate: array[0..11] of UTF8String;
//Filename of the opened iniFile
- Filename: string;
+ Filename: IPath;
// Game
Players: integer;
@@ -165,19 +167,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,132 +189,132 @@ 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');
var
- ILanguageTranslated: array of string;
+ ILanguageTranslated: array of UTF8String;
- IDifficultyTranslated: array[0..2] of string = ('Easy', 'Medium', 'Hard');
- ITabsTranslated: array[0..1] of string = ('Off', 'On');
+ IDifficultyTranslated: array[0..2] of UTF8String = ('Easy', 'Medium', 'Hard');
+ ITabsTranslated: array[0..1] of UTF8String = ('Off', 'On');
- ISortingTranslated: array[0..7] of string = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2');
+ ISortingTranslated: array[0..7] of UTF8String = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2');
- IDebugTranslated: array[0..1] of string = ('Off', 'On');
+ IDebugTranslated: array[0..1] of UTF8String = ('Off', 'On');
- IFullScreenTranslated: array[0..1] of string = ('Off', 'On');
- IVisualizerTranslated: array[0..2] of string = ('Off', 'WhenNoVideo','On');
+ IFullScreenTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IVisualizerTranslated: array[0..2] of UTF8String = ('Off', 'WhenNoVideo','On');
- IBackgroundMusicTranslated: array[0..1] of string = ('Off', 'On');
- ISingWindowTranslated: array[0..1] of string = ('Small', 'Big');
+ IBackgroundMusicTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ ISingWindowTranslated: array[0..1] of UTF8String = ('Small', 'Big');
//SingBar Mod
- IOscilloscopeTranslated: array[0..1] of string = ('Off', 'On');
+ IOscilloscopeTranslated: array[0..1] of UTF8String = ('Off', 'On');
- ISpectrumTranslated: array[0..1] of string = ('Off', 'On');
- ISpectrographTranslated: array[0..1] of string = ('Off', 'On');
- IMovieSizeTranslated: array[0..2] of string = ('Half', 'Full [Vid]', 'Full [BG+Vid]');
+ ISpectrumTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ ISpectrographTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IMovieSizeTranslated: array[0..2] of UTF8String = ('Half', 'Full [Vid]', 'Full [BG+Vid]');
- IClickAssistTranslated: array[0..1] of string = ('Off', 'On');
- IBeatClickTranslated: array[0..1] of string = ('Off', 'On');
- ISavePlaybackTranslated: array[0..1] of string = ('Off', 'On');
+ IClickAssistTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IBeatClickTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ ISavePlaybackTranslated: array[0..1] of UTF8String = ('Off', 'On');
- IVoicePassthroughTranslated: array[0..1] of string = ('Off', 'On');
+ IVoicePassthroughTranslated: array[0..1] of UTF8String = ('Off', 'On');
//Song Preview
- IPreviewVolumeTranslated: array[0..10] of string = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%');
+ IPreviewVolumeTranslated: array[0..10] of UTF8String = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%');
- IAudioOutputBufferSizeTranslated: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
+ IAudioOutputBufferSizeTranslated: array[0..9] of UTF8String = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
- IAudioInputBufferSizeTranslated: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
+ IAudioInputBufferSizeTranslated: array[0..9] of UTF8String = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536');
- IPreviewFadingTranslated: array[0..5] of string = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs');
+ IPreviewFadingTranslated: array[0..5] of UTF8String = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs');
- ILyricsFontTranslated: array[0..2] of string = ('Plain', 'OLine1', 'OLine2');
- ILyricsEffectTranslated: array[0..4] of string = ('Simple', 'Zoom', 'Slide', 'Ball', 'Shift');
- ISolmizationTranslated: array[0..3] of string = ('Off', 'Euro', 'Jap', 'American');
- INoteLinesTranslated: array[0..1] of string = ('Off', 'On');
+ ILyricsFontTranslated: array[0..2] of UTF8String = ('Plain', 'OLine1', 'OLine2');
+ ILyricsEffectTranslated: array[0..4] of UTF8String = ('Simple', 'Zoom', 'Slide', 'Ball', 'Shift');
+ ISolmizationTranslated: array[0..3] of UTF8String = ('Off', 'Euro', 'Jap', 'American');
+ INoteLinesTranslated: array[0..1] of UTF8String = ('Off', 'On');
- IColorTranslated: array[0..8] of string = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');
+ IColorTranslated: array[0..8] of UTF8String = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');
// Advanced
- ILoadAnimationTranslated: array[0..1] of string = ('Off', 'On');
- IEffectSingTranslated: array[0..1] of string = ('Off', 'On');
- IScreenFadeTranslated: array[0..1] of string = ('Off', 'On');
- IAskbeforeDelTranslated: array[0..1] of string = ('Off', 'On');
- IOnSongClickTranslated: array[0..2] of string = ('Sing', 'Select Players', 'Open Menu');
- ILineBonusTranslated: array[0..1] of string = ('Off', 'On');
- IPartyPopupTranslated: array[0..1] of string = ('Off', 'On');
+ ILoadAnimationTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IEffectSingTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IScreenFadeTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IAskbeforeDelTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IOnSongClickTranslated: array[0..2] of UTF8String = ('Sing', 'Select Players', 'Open Menu');
+ ILineBonusTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IPartyPopupTranslated: array[0..1] of UTF8String = ('Off', 'On');
- IJoypadTranslated: array[0..1] of string = ('Off', 'On');
- IMouseTranslated: array[0..2] of string = ('Off', 'Hardware Cursor', 'Software Cursor');
+ IJoypadTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IMouseTranslated: array[0..2] of UTF8String = ('Off', 'Hardware Cursor', 'Software Cursor');
// Recording options
- IChannelPlayerTranslated: array[0..6] of string = ('Off', '1', '2', '3', '4', '5', '6');
- IMicBoostTranslated: array[0..3] of string = ('Off', '+6dB', '+12dB', '+18dB');
+ IChannelPlayerTranslated: array[0..6] of UTF8String = ('Off', '1', '2', '3', '4', '5', '6');
+ IMicBoostTranslated: array[0..3] of UTF8String = ('Off', '+6dB', '+12dB', '+18dB');
implementation
@@ -323,9 +325,10 @@ uses
ULanguage,
UPlatform,
UMain,
- UPath,
URecord,
- USkins;
+ USkins,
+ UPathUtils,
+ UUnicodeUtils;
(**
* Translate and set the values of options, which need translation.
@@ -524,14 +527,6 @@ begin
end;
(**
- * 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.
*)
@@ -581,7 +576,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;
@@ -605,7 +600,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;
@@ -718,9 +713,9 @@ begin
// Load song-paths
for I := 0 to PathStrings.Count-1 do
begin
- if (AnsiStartsText('SongDir', PathStrings[I])) then
+ if (Pos('SONGDIR', UpperCase(PathStrings[I])) = 1) then
begin
- AddSongPath(IniFile.ReadString('Directories', PathStrings[I], ''));
+ AddSongPath(Path(IniFile.ReadString('Directories', PathStrings[I], '')));
end;
end;
@@ -733,18 +728,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
@@ -753,12 +753,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
@@ -779,7 +778,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
@@ -888,19 +887,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
@@ -1042,13 +1037,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]);
@@ -1188,17 +1183,17 @@ 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 := 1 to 12 do
- IniFile.WriteString('Name', 'P' + IntToStr(I), Name[I-1]);
- for I := 1 to 3 do
- IniFile.WriteString('NameTeam', 'T' + IntToStr(I), NameTeam[I-1]);
- for I := 1 to 12 do
- IniFile.WriteString('NameTemplate', 'Name' + IntToStr(I), NameTemplate[I-1]);
+ for I := 0 to High(Name) do
+ IniFile.WriteString('Name', 'P' + IntToStr(I+1), Name[I]);
+ for I := 0 to High(NameTeam) do
+ IniFile.WriteString('NameTeam', 'T' + IntToStr(I+1), NameTeam[I]);
+ for I := 0 to High(NameTemplate) do
+ IniFile.WriteString('NameTemplate', 'Name' + IntToStr(I+1), NameTemplate[I]);
IniFile.Free;
end;
@@ -1208,9 +1203,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/src/base/ULanguage.pas b/src/base/ULanguage.pas
index 80926774..5f8a2692 100644
--- a/src/base/ULanguage.pas
+++ b/src/base/ULanguage.pas
@@ -33,33 +33,41 @@ interface
{$I switches.inc}
+uses
+ UUnicodeUtils;
+
type
TLanguageEntry = record
- ID: string;
- Text: string;
+ ID: AnsiString; //**< identifier (ASCII)
+ Text: UTF8String; //**< translation (UTF-8)
end;
TLanguageList = record
- Name: string;
- {FileName: string; }
+ Name: AnsiString; //**< language name (ASCII)
end;
+ TLanguageEntryArray = array of TLanguageEntry;
+
TLanguage = class
- public
- Entry: array of TLanguageEntry; //Entrys of Chosen Language
- EntryDefault: array of TLanguageEntry; //Entrys of Standard Language
- EntryConst: array of TLanguageEntry; //Constant Entrys e.g. Version
- Implode_Glue1, Implode_Glue2: String;
- public
+ private
List: array of TLanguageList;
- constructor Create;
+ Entry: TLanguageEntryArray; //**< Entrys of Chosen Language
+ EntryDefault: TLanguageEntryArray; //**< Entrys of Standard Language
+ EntryConst: TLanguageEntryArray; //**< Constant Entrys e.g. Version
+
+ Implode_Glue1, Implode_Glue2: UTF8String;
+
procedure LoadList;
- function Translate(Text: String): String;
- procedure ChangeLanguage(Language: String);
- procedure AddConst(ID, Text: String);
- procedure ChangeConst(ID, Text: String);
- function Implode(Pieces: Array of String): String;
+ function FindID(const ID: AnsiString; const EntryList: TLanguageEntryArray): integer;
+
+ public
+ constructor Create;
+ function Translate(const Text: RawByteString): UTF8String;
+ procedure ChangeLanguage(const Language: AnsiString);
+ procedure AddConst(const ID: AnsiString; const Text: UTF8String);
+ procedure ChangeConst(const ID: AnsiString; const Text: UTF8String);
+ function Implode(const Pieces: array of UTF8String): UTF8String;
end;
var
@@ -69,20 +77,18 @@ implementation
uses
UMain,
- // UFiles,
UIni,
IniFiles,
Classes,
SysUtils,
- {$IFDEF win32}
- Windows,
- {$ENDIF}
ULog,
- UPath;
+ UPath,
+ UFilesystem,
+ UPathUtils;
-//----------
-//Create - Construct Class then LoadList + Standard Language + Set Standard Implode Glues
-//----------
+{**
+ * LoadList, set default language, set standard implode glues
+ *}
constructor TLanguage.Create;
var
I, J: Integer;
@@ -108,7 +114,7 @@ begin
ChangeLanguage('English');
SetLength(EntryDefault, Length(Entry));
- for J := low(Entry) to high(Entry) do
+ for J := 0 to high(Entry) do
EntryDefault[J] := Entry[J];
SetLength(Entry, 0);
@@ -123,42 +129,44 @@ begin
end;
-//----------
-//LoadList - Parse the Language Dir searching Translations
-//----------
+{**
+ * Parse the Language Dir searching Translations
+ *}
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, '');
+ IniInfo := Iter.Next;
+
+ LangName := IniInfo.Name.SetExtension('').ToUTF8;
- List[High(List)].Name := SR.Name;
- ILanguage[High(ILanguage)] := SR.Name;
+ SetLength(List, Length(List)+1);
+ List[High(List)].Name := LangName;
- until FindNext(SR) <> 0;
- SysUtils.FindClose(SR);
- end; // if FindFirst
+ SetLength(ILanguage, Length(ILanguage)+1);
+ ILanguage[High(ILanguage)] := LangName;
+ end;
end;
-//----------
-//ChangeLanguage - Load the specified LanguageFile
-//----------
-procedure TLanguage.ChangeLanguage(Language: String);
+{**
+ * Load the specified LanguageFile
+ *}
+procedure TLanguage.ChangeLanguage(const Language: AnsiString);
var
- IniFile: TIniFile;
+ IniFile: TUnicodeMemIniFile;
E: integer; // entry
S: TStringList;
begin
SetLength(Entry, 0);
- IniFile := TIniFile.Create(LanguagesPath + Language + '.ini');
+ IniFile := TUnicodeMemIniFile.Create(LanguagesPath.Append(Language + '.ini'));
S := TStringList.Create;
IniFile.ReadSectionValues('Text', S);
@@ -178,57 +186,84 @@ begin
IniFile.Free;
end;
-//----------
-//Translate - Translate the Text
-//----------
-Function TLanguage.Translate(Text: String): String;
+{**
+ * Find the index of ID an array of language entries.
+ * @returns the index on success, -1 otherwise.
+ *}
+function TLanguage.FindID(const ID: AnsiString; const EntryList: TLanguageEntryArray): integer;
var
- E: integer; // entry
+ Index: integer;
begin
+ for Index := 0 to High(EntryList) do
+ begin
+ if ID = EntryList[Index].ID then
+ begin
+ Result := Index;
+ Exit;
+ end;
+ end;
+ Result := -1;
+end;
+
+{**
+ * Translate the Text.
+ * If Text is an ID, text will be translated according to the current language
+ * setting. If Text is not a known ID, it will be returned as is.
+ * @param Text either an ID or an UTF-8 encoded string
+ *}
+function TLanguage.Translate(const Text: RawByteString): UTF8String;
+var
+ E: integer; // entry
+ ID: AnsiString;
+ EntryIndex: integer;
+begin
+ // fallback result in case Text is not a known ID
Result := Text;
- Text := Uppercase(Result);
+
+ // normalize ID case
+ ID := UpperCase(Text);
+
+ // Check if ID exists
//Const Mod
- for E := 0 to high(EntryConst) do
- if Text = EntryConst[E].ID then
- begin
- Result := EntryConst[E].Text;
- exit;
- end;
- //Const Mod End
+ EntryIndex := FindID(ID, EntryConst);
+ if (EntryIndex >= 0) then
+ begin
+ Result := EntryConst[EntryIndex].Text;
+ Exit;
+ end;
- for E := 0 to high(Entry) do
- if Text = Entry[E].ID then
- begin
- Result := Entry[E].Text;
- exit;
- end;
+ EntryIndex := FindID(ID, Entry);
+ if (EntryIndex >= 0) then
+ begin
+ Result := Entry[EntryIndex].Text;
+ Exit;
+ end;
//Standard Language (If a Language File is Incomplete)
//Then use Standard Language
- for E := low(EntryDefault) to high(EntryDefault) do
- if Text = EntryDefault[E].ID then
- begin
- Result := EntryDefault[E].Text;
- Break;
- end;
- //Standard Language END
+ EntryIndex := FindID(ID, EntryDefault);
+ if (EntryIndex >= 0) then
+ begin
+ Result := EntryDefault[EntryIndex].Text;
+ Exit;
+ end;
end;
-//----------
-//AddConst - Add a Constant ID that will be Translated but not Loaded from the LanguageFile
-//----------
-procedure TLanguage.AddConst (ID, Text: String);
+{**
+ * Add a Constant ID that will be Translated but not Loaded from the LanguageFile
+ *}
+procedure TLanguage.AddConst(const ID: AnsiString; const Text: UTF8String);
begin
SetLength (EntryConst, Length(EntryConst) + 1);
EntryConst[high(EntryConst)].ID := ID;
EntryConst[high(EntryConst)].Text := Text;
end;
-//----------
-//ChangeConst - Change a Constant Value by ID
-//----------
-procedure TLanguage.ChangeConst(ID, Text: String);
+{**
+ * Change a Constant Value by ID
+ *}
+procedure TLanguage.ChangeConst(const ID: AnsiString; const Text: UTF8String);
var
I: Integer;
begin
@@ -242,16 +277,16 @@ begin
end;
end;
-//----------
-//Implode - Connect an Array of Strings with ' and ' or ', ' to one String
-//----------
-function TLanguage.Implode(Pieces: Array of String): String;
+{**
+ * Connect an array of strings with ' and ' or ', ' to one string
+ *}
+function TLanguage.Implode(const Pieces: array of UTF8String): UTF8String;
var
I: Integer;
begin
Result := '';
//Go through Pieces
- for I := low(Pieces) to high(Pieces) do
+ for I := 0 to high(Pieces) do
begin
//Add Value
Result := Result + Pieces[I];
diff --git a/src/base/ULog.pas b/src/base/ULog.pas
index a872729a..e4ff4862 100644
--- a/src/base/ULog.pas
+++ b/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
@@ -115,7 +116,7 @@ type
// voice
procedure LogVoice(SoundNr: integer);
// buffer
- procedure LogBuffer(const buf : Pointer; const bufLength : Integer; const filename : string);
+ procedure LogBuffer(const buf : Pointer; const bufLength : Integer; const filename : IPath);
end;
procedure DebugWriteln(const aString: String);
@@ -133,7 +134,7 @@ uses
UTime,
UCommon,
UCommandLine,
- UPath;
+ UPathUtils;
(*
* Write to console if in debug mode (Thread-safe).
@@ -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);
@@ -420,21 +420,19 @@ begin
FS.Free;
end;
-procedure TLog.LogBuffer(const buf: Pointer; const bufLength: Integer; const filename: string);
+procedure TLog.LogBuffer(const buf: Pointer; const bufLength: Integer; const filename: IPath);
var
- f : TFileStream;
+ f : TBinaryFileStream;
begin
- f := nil;
-
try
- f := TFileStream.Create( filename, fmCreate);
- f.Write( buf^, bufLength);
- f.Free;
- except
- on e : Exception do begin
- Log.LogError('TLog.LogBuffer: Failed to log buffer into file "' + filename + '". ErrMsg: ' + e.Message);
+ f := TBinaryFileStream.Create( filename, fmCreate);
+ try
+ f.Write( buf^, bufLength);
+ finally
f.Free;
end;
+ except on e : Exception do
+ Log.LogError('TLog.LogBuffer: Failed to log buffer into file "' + filename.ToNative + '". ErrMsg: ' + e.Message);
end;
end;
diff --git a/src/base/ULyrics.pas b/src/base/ULyrics.pas
index 82982981..3f62db9c 100644
--- a/src/base/ULyrics.pas
+++ b/src/base/ULyrics.pas
@@ -52,14 +52,14 @@ type
Width: real; // width
Start: cardinal; // start of the word in quarters (beats)
Length: cardinal; // length of the word in quarters
- Text: string; // text
+ Text: UTF8String; // text
Freestyle: boolean; // is freestyle?
end;
TLyricWordArray = array of TLyricWord;
TLyricLine = class
public
- Text: string; // text
+ Text: UTF8String; // text
Width: real; // width
Height: real; // height
Words: TLyricWordArray; // words in this line
diff --git a/src/base/UMain.pas b/src/base/UMain.pas
index 33eca888..b8ddf346 100644
--- a/src/base/UMain.pas
+++ b/src/base/UMain.pas
@@ -80,7 +80,7 @@ uses
UJoystick,
ULanguage,
ULog,
- UPath,
+ UPathUtils,
UPlaylist,
UMusic,
UBeatTimer,
@@ -190,7 +190,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);
@@ -246,10 +246,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);
@@ -353,11 +353,9 @@ begin
CountMidTime;
Delay := Floor(1000 / MAX_FPS - 1000 * TimeMid);
- //Log.LogError ('MainLoop', 'Delay: ' + intToStr(Delay));
if Delay >= 1 then
SDL_Delay(Delay); // dynamic, maximum is 100 fps
- //Log.LogError ('MainLoop', 'Delay: ok ' + intToStr(Delay));
CountSkipTime;
@@ -433,6 +431,8 @@ begin
if (ScreenPopupError <> nil) and (ScreenPopupError.Visible) then
done := not ScreenPopupError.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
+ else if (ScreenPopupInfo <> nil) and (ScreenPopupInfo.Visible) then
+ done := not ScreenPopupInfo.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
else if (ScreenPopupCheck <> nil) and (ScreenPopupCheck.Visible) then
done := not ScreenPopupCheck.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
else
@@ -462,6 +462,16 @@ begin
end;
SDL_KEYDOWN:
begin
+ // translate CTRL-A (ASCII 1) - CTRL-Z (ASCII 26) to correct charcodes.
+ // keysyms (SDLK_A, ...) could be used instead but they ignore the
+ // current key mapping (if 'a' is pressed on a French keyboard the
+ // .unicode field will be 'a' and .sym SDLK_Q).
+ // IMPORTANT: if CTRL is pressed with a key different than 'A'-'Z' SDL
+ // will set .unicode to 0. There is no possibility to obtain a
+ // translated charcode. Use keysyms instead.
+ //if (Event.key.keysym.unicode in [1 .. 26]) then
+ // Event.key.keysym.unicode := Ord('A') + Event.key.keysym.unicode - 1;
+
// remap the "keypad enter" key to the "standard enter" key
if (Event.key.keysym.sym = SDLK_KP_ENTER) then
Event.key.keysym.sym := SDLK_RETURN;
@@ -496,13 +506,15 @@ begin
// if there is a visible popup then let it handle input instead of underlying screen
// shoud be done in a way to be sure the topmost popup has preference (maybe error, then check)
else if (ScreenPopupError <> nil) and (ScreenPopupError.Visible) then
- Done := not ScreenPopupError.ParseInput(Event.key.keysym.sym, WideChar(Event.key.keysym.unicode), true)
+ Done := not ScreenPopupError.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
+ else if (ScreenPopupInfo <> nil) and (ScreenPopupInfo.Visible) then
+ Done := not ScreenPopupInfo.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
else if (ScreenPopupCheck <> nil) and (ScreenPopupCheck.Visible) then
- Done := not ScreenPopupCheck.ParseInput(Event.key.keysym.sym, WideChar(Event.key.keysym.unicode), true)
+ Done := not ScreenPopupCheck.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
else
begin
// check if screen wants to exit
- Done := not Display.CurrentScreen^.ParseInput(Event.key.keysym.sym, WideChar(Event.key.keysym.unicode), true);
+ Done := not Display.CurrentScreen^.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true);
// if screen wants to exit
if Done then
diff --git a/src/base/UMusic.pas b/src/base/UMusic.pas
index 19c54bee..5d816c9a 100644
--- a/src/base/UMusic.pas
+++ b/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);
@@ -62,7 +63,7 @@ type
Start: integer; // beat the fragment starts at
Length: integer; // length in beats
Tone: integer; // full range tone
- Text: string; // text assigned to this fragment (a syllable, word, etc.)
+ Text: UTF8String; // text assigned to this fragment (a syllable, word, etc.)
NoteType: TNoteType; // note-type: golden-note/freestyle etc.
end;
@@ -73,7 +74,7 @@ type
PLine = ^TLine;
TLine = record
Start: integer; // the start beat of this line (<> start beat of the first note of this line)
- Lyric: string;
+ Lyric: UTF8String;
//LyricWidth: real; // @deprecated: width of the line in pixels.
// Do not use this as the width is not correct.
// Use TLyricsEngine.GetUpperLine().Width instead.
@@ -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;
@@ -400,13 +401,13 @@ type
(*
IVideoDecoder = Interface( IGenericDecoder )
['{2F184B2B-FE69-44D5-9031-0A2462391DCA}']
- function Open(const Filename: string): TVideoDecodeStream;
+ function Open(const Filename: IPath): TVideoDecodeStream;
end;
*)
IAudioDecoder = Interface( IGenericDecoder )
['{AB47B1B6-2AA9-4410-BF8C-EC79561B5478}']
- function Open(const Filename: string): TAudioDecodeStream;
+ function Open(const Filename: IPath): TAudioDecodeStream;
end;
IAudioInput = Interface
@@ -456,7 +457,7 @@ const
SOUNDID_CLICK = 5;
LAST_SOUNDID = SOUNDID_CLICK;
- BaseSoundFilenames: array[0..LAST_SOUNDID] of string = (
+ BaseSoundFilenames: array[0..LAST_SOUNDID] of IPath = (
'%SOUNDPATH%/Common start.mp3', // Start
'%SOUNDPATH%/Common back.mp3', // Back
'%SOUNDPATH%/menu swoosh.mp3', // Swoosh
@@ -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;
@@ -533,7 +534,7 @@ uses
UCommandLine,
URecord,
ULog,
- UPath;
+ UPathUtils;
var
DefaultVideoPlayback : IVideoPlayback;
@@ -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/src/base/UNote.pas b/src/base/UNote.pas
index 6da4cf07..8e5b709a 100644
--- a/src/base/UNote.pas
+++ b/src/base/UNote.pas
@@ -19,8 +19,8 @@
* 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/base/UNote.pas $
- * $Id: UNote.pas 1626 2009-03-07 19:53:00Z k-m_schindler $
+ * $URL$
+ * $Id$
*}
unit UNote;
@@ -61,7 +61,7 @@ type
PPLayer = ^TPlayer;
TPlayer = record
- Name: string;
+ Name: UTF8String;
// Index in Teaminfo record
TeamID: byte;
@@ -129,7 +129,7 @@ uses
UCommon,
UGraphic,
UGraphicClasses,
- UPath,
+ UPathUtils,
UPlatform,
UThemes;
diff --git a/src/base/UParty.pas b/src/base/UParty.pas
index 615418f1..52eb5a05 100644
--- a/src/base/UParty.pas
+++ b/src/base/UParty.pas
@@ -71,7 +71,7 @@ type
procedure StartRound;
procedure EndRound;
function GetTeamOrder: TeamOrderArray;
- function GetWinnerString(Round: byte): string;
+ function GetWinnerString(Round: byte): UTF8String;
end;
var
@@ -352,9 +352,9 @@ end;
//----------
//GetWinnerString - Get string with WinnerTeam Name, when there is more than one Winner than Connect with and or ,
//----------
-function TPartySession.GetWinnerString(Round: byte): string;
+function TPartySession.GetWinnerString(Round: byte): UTF8String;
var
- Winners: array of string;
+ Winners: array of UTF8String;
I: integer;
begin
Result := Language.Translate('PARTY_NOBODY');
diff --git a/src/base/UPath.pas b/src/base/UPath.pas
index 2316ac02..03bd82eb 100644
--- a/src/base/UPath.pas
+++ b/src/base/UPath.pas
@@ -19,170 +19,1395 @@
* 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/base/UPath.pas $
- * $Id: UPath.pas 1624 2009-03-06 23:45:10Z k-m_schindler $
+ * $URL$
+ * $Id$
*}
unit UPath;
-interface
-
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
+interface
+
uses
SysUtils,
- Classes;
-
-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;
-procedure InitializePaths;
-procedure AddSongPath(const Path: string);
+ Classes,
+ IniFiles,
+ {$IFDEF MSWINDOWS}
+ TntClasses,
+ {$ENDIF}
+ UConfig,
+ UUnicodeUtils;
+
+type
+ IPath = interface;
+
+ {**
+ * TUnicodeMemoryStream
+ *}
+ TUnicodeMemoryStream = class(TMemoryStream)
+ public
+ procedure LoadFromFile(const FileName: IPath);
+ procedure SaveToFile(const FileName: IPath);
+ end;
+
+ {**
+ * Unicode capable IniFile implementation.
+ * TMemIniFile and TIniFile are not able to handle INI-files with
+ * an UTF-8 BOM. This implementation checks if an UTF-8 BOM exists
+ * and removes it from the internal string-list.
+ * UTF8Encoded is set accordingly.
+ *}
+ TUnicodeMemIniFile = class(TMemIniFile)
+ private
+ FFilename: IPath;
+ FUTF8Encoded: boolean;
+ public
+ constructor Create(const FileName: IPath; UTF8Encoded: boolean = false); reintroduce;
+ procedure UpdateFile; override;
+ property UTF8Encoded: boolean READ FUTF8Encoded WRITE FUTF8Encoded;
+ end;
+
+ {**
+ * TBinaryFileStream (inherited from THandleStream)
+ *}
+ {$IFDEF MSWINDOWS}
+ TBinaryFileStream = class(TTntFileStream)
+ {$ELSE}
+ TBinaryFileStream = class(TFileStream)
+ {$ENDIF}
+ public
+ {**
+ * @seealso TFileStream.Create for valid Mode parameters
+ *}
+ constructor Create(const FileName: IPath; Mode: word);
+ end;
+
+ {**
+ * TTextFileStream
+ *}
+ TTextFileStream = class(TStream)
+ protected
+ fLineBreak: RawByteString;
+ fFilename: IPath;
+ fMode: word;
+
+ function ReadLine(var Success: boolean): RawByteString; overload; virtual; abstract;
+ public
+ constructor Create(Filename: IPath; Mode: word);
+
+ function ReadString(): RawByteString; virtual; abstract;
+ function ReadLine(var Line: UTF8String): boolean; overload;
+ function ReadLine(var Line: AnsiString): boolean; overload;
+
+ procedure WriteString(const Str: RawByteString); virtual;
+ procedure WriteLine(const Line: RawByteString); virtual;
+
+ property LineBreak: RawByteString read fLineBreak write fLineBreak;
+ property Filename: IPath read fFilename;
+ end;
+
+ {**
+ * TMemTextStream
+ *}
+ TMemTextFileStream = class(TTextFileStream)
+ private
+ fStream: TMemoryStream;
+ protected
+ function GetSize: int64; override;
+
+ {**
+ * Copies fStream.Memory from StartPos to EndPos-1 to the result string;
+ *}
+ function CopyMemString(StartPos: int64; EndPos: int64): RawByteString;
+ public
+ constructor Create(Filename: IPath; Mode: word);
+ destructor Destroy(); override;
+
+ function Read(var Buffer; Count: longint): longint; override;
+ function Write(const Buffer; Count: longint): longint; override;
+ function Seek(Offset: longint; Origin: word): longint; override;
+ function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override;
+
+ function ReadLine(var Success: boolean): RawByteString; override;
+ function ReadString(): RawByteString; override;
+ end;
+
+ {**
+ TUnicodeIniStream = class()
+ 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;
+
+ {**
+ * An IPath represents a filename, a directory or a filesystem path in general.
+ * It hides some of the operating system's specifics like path delimiters
+ * and encodings and provides an easy to use interface to handle them.
+ * Internally all paths are stored with the same path delimiter (PathDelim)
+ * and encoding (UTF-8). The transformation is already done AT THE CREATION of
+ * the IPath and hence calls to e.g. IPath.Equal() will not distinguish between
+ * Unix and Windows style paths.
+ *
+ * Create new paths with one of the Path() functions.
+ * If you need a string representation use IPath.ToNative/ToUTF8/ToWide.
+ * Note that due to the path-delimiter and encoding transformation the string
+ * might have changed. Path('one\test/path').ToUTF8() might return 'one/test/path'.
+ *
+ * It is recommended to use an IPath as long as possible without a string
+ * conversion (IPath.To...()). The whole Delphi (< 2009) and FPC RTL is ANSI
+ * only on Windows. If you would use for example FileExists(MyPath.ToNative)
+ * it would not find a file which contains characters that are not in the
+ * current locale. Same applies to AssignFile(), TFileStream.Create() and
+ * everything else in the RTL that expects a filename.
+ * As a rule of thumb: NEVER use any of the Delphi/FPC RTL filename functions
+ * if the filename parameter is not of a UTF8String or WideString type.
+ *
+ * If you need to open a file use TBinaryStream or TFileStream instead. Many
+ * of the RTL classes offer a LoadFromStream() method so ANSI Open() methods
+ * can be workaround.
+ *
+ * If there is only a ANSI and no IPath/UTF-8/WideString version and you cannot
+ * even pass a stream instead of a filename be aware that even if you know that
+ * a filename is ASCII only, subdirectories in an absolute path might contain
+ * some non-ASCII characters (for example the user's name) and hence might
+ * fail (if the characters are not in the current locale).
+ * It is rare but it happens.
+ *
+ * IMPORTANT:
+ * This interface needs the cwstring unit on Unix (Max OS X / Linux) systems.
+ * Cwstring functions (WideUpperCase, ...) cannot be used by external threads
+ * as FPC uses Thread-Local-Storage for the implementation. As a result do not
+ * call IPath stuff by external threads (e.g. in C callbacks or by SDL-threads).
+ *}
+ 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)
+ * is used. If it is set to false the (more) portable '/' delimiter will used.
+ *}
+ function ToUTF8(UseNativeDelim: boolean = true): UTF8String;
+
+ {**
+ * Returns the path as an UTF-16 encoded string.
+ * If UseNativeDelim is set to true, the native path delimiter ('\' on win32)
+ * is used. If it is set to false the delimiter will be '/'.
+ *}
+ function ToWide(UseNativeDelim: boolean = true): WideString;
+
+ {**
+ * Returns the path with the system's native encoding and path delimiter.
+ * Win32: ANSI (use the UTF-16 version IPath.ToWide() whenever possible)
+ * Mac: UTF8
+ * Unix: UTF8 or ANSI according to LC_CTYPE
+ *}
+ function ToNative(): RawByteString;
+
+ {**
+ * Note: File must be closed with FileClose(Handle) after usage
+ * @seealso SysUtils.FileOpen()
+ *}
+ function Open(Mode: longword): THandle;
+
+ {** @seealso SysUtils.ExtractFileDrive() *}
+ function GetDrive(): IPath;
+
+ {** @seealso SysUtils.ExtractFilePath() *}
+ function GetPath(): IPath;
+
+ {** @seealso SysUtils.ExtractFileDir() *}
+ function GetDir(): IPath;
+
+ {** @seealso SysUtils.ExtractFileName() *}
+ function GetName(): IPath;
+
+ {** @seealso SysUtils.ExtractFileExtension() *}
+ function GetExtension(): IPath;
+
+ {**
+ * Returns a copy of the path with the extension changed to Extension.
+ * The file itself is not changed, use Rename() for this task.
+ * @seealso SysUtils.ChangeFileExt()
+ *}
+ 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.
+ * Note that the basename must be terminated with a path delimiter
+ * otherwise the last path component will be ignored.
+ * @seealso SysUtils.ExtractRelativePath()
+ *}
+ function GetRelativePath(const BaseName: IPath): IPath;
+
+ {** @seealso SysUtils.ExpandFileName() *}
+ function GetAbsolutePath(): IPath;
+
+ {**
+ * Returns the concatenation of this path with Child. If this path does not
+ * 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; 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. Path delimiters are not removed from
+ * components.
+ * Example: C:\test\my\dir -> ['C:\', 'test\', 'my\', 'dir']
+ *}
+ function SplitDirs(): IPathDynArray;
+
+ {**
+ * Returns the parent directory or PATH_NONE if none exists.
+ *}
+ function GetParent(): IPath;
+
+ {**
+ * Checks if this path is a subdir of or file inside Parent.
+ * If Direct is true this path must be a direct child.
+ * Example: C:\test\file is a direct child of C:\test and a child of C:\
+ *}
+ function IsChildOf(const Parent: IPath; Direct: boolean): boolean;
+
+ {**
+ * Adjusts the case of the path on case senstitive filesystems.
+ * If the path does not exist or the filesystem is case insensitive
+ * the original path will be returned. Otherwise a corrected copy.
+ *}
+ function AdjustCase(AdjustAllLevels: boolean): IPath;
+
+ {** @seealso SysUtils.IncludeTrailingPathDelimiter() *}
+ function AppendPathDelim(): IPath;
+
+ {** @seealso SysUtils.ExcludeTrailingPathDelimiter() *}
+ function RemovePathDelim(): IPath;
+
+ function Exists(): boolean;
+ function IsFile(): boolean;
+ function IsDirectory(): boolean;
+ function IsAbsolute(): boolean;
+ function GetFileAge(): integer; overload;
+ function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
+ function GetAttr(): cardinal;
+ function SetAttr(Attr: Integer): boolean;
+ function IsReadOnly(): boolean;
+ 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; 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
+ * not found. Use IFileSystem.FileFind() instead if you want to use
+ * wildcards.
+ * @seealso SysUtils.FileSearch()
+ *}
+ function FileSearch(const DirList: IPath): IPath;
+
+ {** File must be closed with FileClose(Handle) after usage }
+ function CreateFile(): THandle;
+ function DeleteFile(): boolean;
+ function CreateDirectory(Force: boolean = false): boolean;
+ function DeleteEmptyDir(): boolean;
+ function Rename(const NewName: IPath): boolean;
+ function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
+
+ // TODO: Dirwatch stuff
+ // AddFileChangeListener(Listener: TFileChangeListener);
+
+ {**
+ * Internal string representation. For debugging only.
+ *}
+ function GetIntern: UTF8String;
+ property Intern: UTF8String READ GetIntern;
+ end;
+
+{**
+ * Creates a new path with the given pathname. PathName can be either in UTF8
+ * or the local encoding.
+ * Notes:
+ * - 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; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
+
+{**
+ * Creates a new path with the given UTF-16 pathname.
+ *}
+function Path(const PathName: WideString; DelimOption: TPathDelimOption = pdKeep): IPath; overload;
+
+{**
+ * Returns a singleton for Path('').
+ *}
+function PATH_NONE(): IPath;
implementation
uses
- StrUtils,
- UPlatform,
- UCommandLine,
- ULog;
+ RTLConsts,
+ UTextEncoding,
+ UFilesystem;
+
+{*
+ * Due to a compiler bug in FPC <= 2.2.4 reference counting does not work
+ * properly with interfaces (see http://bugs.freepascal.org/view.php?id=14019).
+ *
+ * There are two (probably more) scenarios causes a program to crash:
+ *
+ * 1. Assume we execute Path('fail').GetParent().ToUTF8(). The compiler will
+ * internally create a temporary variable to hold the result of Path('fail').
+ * This temporary var is then passed as Self to GetParent(). Unfortunately FPC
+ * does already decrement the ref-count of the temporary var at the end of the
+ * call to Path('fail') and the ref-count drops to zero and the temp object
+ * is destroyed as FPC erroneously assumes that the temp is not used anymore.
+ * As a result the Self variable in GetParent() will be invalid, the same
+ * applies to TPathImpl.fName which reference count dropped to zero when the
+ * temp was destroyed. Hence GetParent() will likely crash.
+ * If it does not, ToUTF8() will either return some random string
+ * (e.g. '' or stupid stuff like 'fhwkjehdk') or crash.
+ * Either way the result of ToUTF8() is messed up.
+ * This scenario applies whenever a function (or method) is called that returns
+ * an interfaced object (e.g. an IPath) and the result is used without storing
+ * a reference to it in a (temporary) variable first.
+ *
+ * Tmp := Path('fail'); Tmp2 := Tmp.GetParent(); Tmp2.ToUTF8();
+ *
+ * will not crash but is very impractical and error-prone. Note that Tmp2 cannot
+ * be replaced with Tmp (see scenario 2).
+ *
+ * 2. Another situation this bug will ruin our lives is when a variable to an
+ * interfaced object is used at the left and right side of an assignment as in:
+ * MyPath := MyPath.GetParent()
+ *
+ * Although the bug is already fixed in the FPC development version 2.3.1
+ * it will take quite some time till the next FPC release (> 2.2.4) in which
+ * this issue is fixed.
+ *
+ * To workaround this bug we use some very simple and stupid kind of garbage
+ * collection. New IPaths are stored in an IInterfaceList (call it GarbaegeList)
+ * to artificially increase the ref-count of the newly created object.
+ * This keeps the object alive when FPC's temporary variable comes to the end
+ * of its lifetime and the object's ref-count is decremented
+ * (and is now 1 instead of 0).
+ * Later on, the object is either garbage or referenced by another variable.
+ *
+ * Look at
+ * MyPath := Path('SomeDir/SubDir').GetParent()
+ *
+ * (1) The result of Path('SomeDir/SubDir') is garbage as it is not used anymore.
+ * (2) The result of GetParent() is referenced by MyPath
+ * Object (1) has a reference count of 1 (as it is only referenced by the
+ * GarbageList). Object (2) is referenced twice (MyPath + GarbageList).
+ * When the reference to (2) is finally stored in MyPath we can safely remove
+ * (1) and (2) from the GarbageList so (1) will be freed and the ref-count of
+ * (2) will be decremented to 1.
+ *
+ * As we do not know when it is safe to remove an object from the GarbageList
+ * we assume that there are max. GarbageMaxCount IPath elements created until
+ * the execution of the expression is performed and a reference to the resulting
+ * object is assigned to a variable so all temps can be safely deleted.
+ *
+ * Worst-case scenarios are recursive calls or calls with large call stacks with
+ * functions that return an IPath. Also keep in mind that multiple threads might
+ * be executing such functions at the same time.
+ * A reasonable count might be a max. of 20.000 elements. With an average length
+ * of 40 UTF8 chars (maybe 60 byte with class info, pointer etc.) per IPath
+ * this will consume ~1.2MB.
+ *}
+{$IFDEF FPC}
+{$IF FPC_VERSION_INT <= 002002004} // <= 2.2.4
+ {$DEFINE HAVE_REFCNTBUG}
+{$IFEND}
+{$ENDIF}
+
+{$IFDEF HAVE_REFCNTBUG}
+const
+ // when GarbageList.Count reaches GarbageMaxCount the oldest references in
+ // GarbageList will be deleted until GarbageList.Count equals GarbageAfterCleanCount.
+ GarbageMaxCount = 20000;
+ GarbageAfterCleanCount = GarbageMaxCount-1000;
+
+var
+ GarbageList: IInterfaceList;
+{$ENDIF}
+
+type
+ TPathImpl = class(TInterfacedObject, IPath)
+ private
+ fName: UTF8String; //<** internal filename string, always UTF8 with PathDelim
+
+ {**
+ * Unifies the filename. Path-delimiters are replaced by '/'.
+ *}
+ procedure Unify(DelimOption: TPathDelimOption);
+
+ {**
+ * Returns a copy of fName with path delimiters changed to '/'.
+ *}
+ function GetPortableString(): UTF8String;
+
+ procedure AssertRefCount; {$IFDEF HasInline}inline;{$ENDIF}
+
+ public
+ constructor Create(const Name: UTF8String; DelimOption: TPathDelimOption);
+ destructor Destroy(); override;
+
+ function ToUTF8(UseNativeDelim: boolean): UTF8String;
+ function ToWide(UseNativeDelim: boolean): WideString;
+ function ToNative(): RawByteString;
+
+ function Open(Mode: longword): THandle;
+
+ function GetDrive(): IPath;
+ function GetPath(): IPath;
+ function GetDir(): IPath;
+ function GetName(): IPath;
+ function GetExtension(): 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; 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 AppendPathDelim(): IPath;
+ function RemovePathDelim(): IPath;
+
+ function GetFileAge(): integer; overload;
+ function GetFileAge(out FileDateTime: TDateTime): boolean; overload;
+ function Exists(): boolean;
+ function IsFile(): boolean;
+ function IsDirectory(): boolean;
+ function IsAbsolute(): boolean;
+ function GetAttr(): cardinal;
+ 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;
+ function DeleteFile(): boolean;
+ function CreateDirectory(Force: boolean): boolean;
+ function DeleteEmptyDir(): boolean;
+ function Rename(const NewName: IPath): boolean;
+ function CopyFile(const Target: IPath; FailIfExists: boolean): boolean;
+
+ function GetIntern(): UTF8String;
+ end;
+
+function Path(const PathName: RawByteString; DelimOption: TPathDelimOption): IPath;
+begin
+ if (IsUTF8String(PathName)) then
+ Result := TPathImpl.Create(PathName, DelimOption)
+ else if (IsNativeUTF8()) then
+ Result := PATH_NONE
+ else
+ Result := TPathImpl.Create(AnsiToUtf8(PathName), DelimOption);
+end;
+
+function Path(const PathName: WideString; DelimOption: TPathDelimOption): IPath;
+begin
+ Result := TPathImpl.Create(UTF8Encode(PathName), DelimOption);
+end;
+
+
+
+procedure TPathImpl.AssertRefCount;
+begin
+ {$IFDEF HAVE_REFCNTBUG}
+ if (FRefCount <= 0) then
+ raise Exception.Create('RefCount error: ' + IntToStr(FRefCount));
+ {$ENDIF}
+end;
+
+constructor TPathImpl.Create(const Name: UTF8String; DelimOption: TPathDelimOption);
+begin
+ inherited Create();
+ fName := Name;
+ Unify(DelimOption);
+ {$IFDEF HAVE_REFCNTBUG}
+ GarbageList.Lock;
+ if (GarbageList.Count >= GarbageMaxCount) then
+ begin
+ while (GarbageList.Count > GarbageAfterCleanCount) do
+ GarbageList.Delete(0);
+ end;
+ GarbageList.Add(Self);
+ GarbageList.Unlock;
+ {$ENDIF}
+end;
+
+destructor TPathImpl.Destroy();
+begin
+ inherited;
+end;
+
+procedure TPathImpl.Unify(DelimOption: TPathDelimOption);
+var
+ I: integer;
+begin
+ // convert all path delimiters to native ones
+ for I := 1 to Length(fName) do
+ 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;
+var
+ I: integer;
+begin
+ Result := fName;
+ if (PathDelim = '/') then
+ Exit;
+
+ for I := 1 to Length(Result) do
+ begin
+ if (Result[I] = PathDelim) then
+ Result[I] := '/';
+ end;
+end;
+
+function TPathImpl.ToUTF8(UseNativeDelim: boolean): UTF8String;
+begin
+ AssertRefCount;
+
+ if (UseNativeDelim) then
+ Result := fName
+ else
+ Result := GetPortableString();
+end;
+
+function TPathImpl.ToWide(UseNativeDelim: boolean): WideString;
+begin
+ if (UseNativeDelim) then
+ Result := UTF8Decode(fName)
+ else
+ Result := UTF8Decode(GetPortableString());
+end;
+
+function TPathImpl.ToNative(): RawByteString;
+begin
+ if (IsNativeUTF8()) then
+ Result := fName
+ else
+ Result := Utf8ToAnsi(fName);
+end;
+
+function TPathImpl.GetDrive(): IPath;
+begin
+ AssertRefCount;
+ Result := FileSystem.ExtractFileDrive(Self);
+end;
+
+function TPathImpl.GetPath(): IPath;
+begin
+ AssertRefCount;
+ Result := FileSystem.ExtractFilePath(Self);
+end;
+
+function TPathImpl.GetDir(): IPath;
+begin
+ AssertRefCount;
+ Result := FileSystem.ExtractFileDir(Self);
+end;
+
+function TPathImpl.GetName(): IPath;
+begin
+ AssertRefCount;
+ Result := FileSystem.ExtractFileName(Self);
+end;
+
+function TPathImpl.GetExtension(): IPath;
+begin
+ AssertRefCount;
+ Result := FileSystem.ExtractFileExt(Self);
+end;
+
+function TPathImpl.SetExtension(const Extension: IPath): IPath;
+begin
+ AssertRefCount;
+ 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;
+ Result := FileSystem.ExtractRelativePath(BaseName, Self);
+end;
+
+function TPathImpl.GetAbsolutePath(): IPath;
+begin
+ AssertRefCount;
+ Result := FileSystem.ExpandFileName(Self);
+end;
+
+function TPathImpl.GetParent(): IPath;
+var
+ CurPath, ParentPath: IPath;
+begin
+ AssertRefCount;
+
+ Result := PATH_NONE;
+
+ CurPath := Self.RemovePathDelim();
+ // check if current path has a parent (no further '/')
+ if (Pos(PathDelim, CurPath.ToUTF8()) = 0) then
+ Exit;
+
+ // set new path and check if it has changed to avoid endless loops
+ // e.g. with invalid paths like '/C:' (GetPath() uses ':' as delimiter too)
+ // on delphi/win32
+ ParentPath := CurPath.GetPath();
+ if (ParentPath.ToUTF8 = CurPath.ToUTF8) then
+ Exit;
+
+ Result := ParentPath;
+end;
+
+function TPathImpl.SplitDirs(): IPathDynArray;
+var
+ CurPath: IPath;
+ Components: array of IPath;
+ CurPathStr: UTF8String;
+ DelimPos: integer;
+ I: integer;
+begin
+ SetLength(Result, 0);
+
+ if (Length(Self.ToUTF8(true)) = 0) then
+ Exit;
+
+ CurPath := Self;
+ SetLength(Components, 0);
+ repeat
+ SetLength(Components, Length(Components)+1);
+
+ CurPathStr := CurPath.ToUTF8();
+ DelimPos := LastDelimiter(PathDelim, SysUtils.ExcludeTrailingPathDelimiter(CurPathStr));
+ Components[High(Components)] := Path(Copy(CurPathStr, DelimPos+1, Length(CurPathStr)));
+
+ CurPath := CurPath.GetParent();
+ until (CurPath = PATH_NONE);
+
+ // reverse list
+ SetLength(Result, Length(Components));
+ for I := 0 to High(Components) do
+ Result[I] := Components[High(Components)-I];
+end;
+
+function TPathImpl.Append(const Child: IPath; DelimOption: TPathDelimOption): IPath;
+var
+ TmpResult: IPath;
+begin
+ AssertRefCount;
+
+ if (fName = '') then
+ TmpResult := Child
+ else
+ 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
+ AssertRefCount;
+ Result := Append(Path(Child), DelimOption);
+end;
+
+function TPathImpl.Append(const Child: WideString; DelimOption: TPathDelimOption): IPath;
+begin
+ AssertRefCount;
+ Result := Append(Path(Child), DelimOption);
+end;
+
+function TPathImpl.Equals(const Other: IPath; IgnoreCase: boolean): boolean;
+var
+ SelfPath, OtherPath: UTF8String;
+begin
+ 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;
-procedure AddSpecialPath(var PathList: TStringList; const Path: string);
+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
- Index: integer;
- PathAbs, OldPathAbs: string;
+ SelfPath, ParentPath: UTF8String;
begin
- if (PathList = nil) then
- PathList := TStringList.Create;
+ Result := false;
+
+ if (Direct) then
+ begin
+ SelfPath := Self.GetParent().GetAbsolutePath().AppendPathDelim().ToUTF8();
+ ParentPath := Parent.GetAbsolutePath().AppendPathDelim().ToUTF8();
+
+ // simply check if this paths parent path (SelfPath) equals ParentPath
+ Result := (SelfPath = ParentPath);
+ end
+ else
+ begin
+ SelfPath := Self.GetAbsolutePath().AppendPathDelim().ToUTF8();
+ ParentPath := Parent.GetAbsolutePath().AppendPathDelim().ToUTF8();
- if (Path = '') or not ForceDirectories(Path) then
+ if (Length(SelfPath) <= Length(ParentPath)) then
+ Exit;
+
+ // check if ParentPath is a substring of SelfPath
+ if (FileSystem.IsCaseSensitive()) then
+ Result := (StrLComp(PAnsiChar(SelfPath), PAnsiChar(ParentPath), Length(ParentPath)) = 0)
+ else
+ Result := (StrLIComp(PAnsiChar(SelfPath), PAnsiChar(ParentPath), Length(ParentPath)) = 0)
+ end;
+end;
+
+function AdjustCaseRecursive(CurPath: IPath; AdjustAllLevels: boolean): IPath;
+var
+ OldParent, AdjustedParent: IPath;
+ LocalName: IPath;
+ PathFound: IPath;
+ PathWithAdjParent: IPath;
+ SearchInfo: TFileInfo;
+ FileIter: IFileIterator;
+ Pattern: IPath;
+begin
+ // if case-sensitive path exists there is no need to adjust case
+ if (CurPath.Exists()) then
+ begin
+ Result := CurPath;
Exit;
+ end;
+
+ LocalName := CurPath.RemovePathDelim().GetName();
- PathAbs := IncludeTrailingPathDelimiter(ExpandFileName(Path));
+ // try to adjust parent
+ OldParent := CurPath.GetParent();
+ if (OldParent <> PATH_NONE) then
+ begin
+ if (not AdjustAllLevels) then
+ begin
+ AdjustedParent := OldParent;
+ end
+ else
+ begin
+ AdjustedParent := AdjustCaseRecursive(OldParent, AdjustAllLevels);
+ if (AdjustedParent = nil) then
+ begin
+ // parent path was not found case-insensitive
+ Result := nil;
+ Exit;
+ end;
- // check if path or a part of the path was already added
- for Index := 0 to PathList.Count-1 do
+ // check if the path with adjusted parent can be found now
+ PathWithAdjParent := AdjustedParent.Append(LocalName);
+ if (PathWithAdjParent.Exists()) then
+ begin
+ Result := PathWithAdjParent;
+ Exit;
+ end;
+ end;
+ Pattern := AdjustedParent.Append(Path('*'));
+ end
+ else // path has no parent
begin
- OldPathAbs := IncludeTrailingPathDelimiter(ExpandFileName(PathList[Index]));
- // 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
+ // the top path can either be absolute or relative
+ if (CurPath.IsAbsolute) then
begin
- // ignore the new path
+ // the only absolute directory at Unix without a parent is root ('/')
+ // and hence does not need to be adjusted
+ Result := CurPath;
Exit;
end;
+ // this is a relative path, search in the current working dir
+ AdjustedParent := nil;
+ Pattern := Path('*');
+ end;
- // check if a previously added directory is a sub-directory of the new one.
- if (AnsiStartsText(PathAbs, OldPathAbs)) then
+ // compare name with all files in the current directory case-insensitive
+ FileIter := FileSystem.FileFind(Pattern, faAnyFile);
+ while (FileIter.HasNext()) do
+ begin
+ SearchInfo := FileIter.Next();
+ PathFound := SearchInfo.Name;
+ if (CompareText(LocalName.ToUTF8, PathFound.ToUTF8) = 0) then
begin
- // replace the old with the new one.
- PathList[Index] := PathAbs;
+ if (AdjustedParent <> nil) then
+ Result := AdjustedParent.Append(PathFound)
+ else
+ Result := PathFound;
Exit;
end;
end;
- PathList.Add(PathAbs);
+ // no matching file found
+ Result := nil;
end;
-procedure AddSongPath(const Path: string);
+function TPathImpl.AdjustCase(AdjustAllLevels: boolean): IPath;
begin
- AddSpecialPath(SongPaths, Path);
+ AssertRefCount;
+
+ Result := Self;
+
+ if (FileSystem.IsCaseSensitive) then
+ begin
+ Result := AdjustCaseRecursive(Self, AdjustAllLevels);
+ if (Result = nil) then
+ Result := Self;
+ end;
end;
-procedure AddCoverPath(const Path: string);
+function TPathImpl.AppendPathDelim(): IPath;
begin
- AddSpecialPath(CoverPaths, Path);
+ AssertRefCount;
+ Result := FileSystem.IncludeTrailingPathDelimiter(Self);
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 TPathImpl.RemovePathDelim(): IPath;
begin
- Result := false;
+ AssertRefCount;
+ Result := FileSystem.ExcludeTrailingPathDelimiter(Self);
+end;
- if (RequestedPath = '') then
- Exit;
+function TPathImpl.CreateFile(): THandle;
+begin
+ Result := FileSystem.FileCreate(Self);
+end;
+
+function TPathImpl.CreateDirectory(Force: boolean): boolean;
+begin
+ if (Force) then
+ Result := FileSystem.ForceDirectories(Self)
+ else
+ Result := FileSystem.DirectoryCreate(Self);
+end;
+
+function TPathImpl.Open(Mode: longword): THandle;
+begin
+ Result := FileSystem.FileOpen(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
+ // note the different specifications of FileExists() on Win32 <> Unix
+ {$IFDEF MSWINDOWS}
+ Result := IsFile() or IsDirectory();
+ {$ELSE}
+ Result := FileSystem.FileExists(Self);
+ {$ENDIF}
+end;
+
+function TPathImpl.IsFile(): boolean;
+begin
+ // note the different specifications of FileExists() on Win32 <> Unix
+ {$IFDEF MSWINDOWS}
+ Result := FileSystem.FileExists(Self);
+ {$ELSE}
+ Result := Exists() and not IsDirectory();
+ {$ENDIF}
+end;
+
+function TPathImpl.IsDirectory(): boolean;
+begin
+ Result := FileSystem.DirectoryExists(Self);
+end;
+
+function TPathImpl.IsAbsolute(): boolean;
+begin
+ AssertRefCount;
+ Result := FileSystem.FileIsReadOnly(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.IsUnset(): boolean;
+begin
+ Result := (fName = '');
+end;
+
+function TPathImpl.IsSet(): boolean;
+begin
+ Result := (fName <> '');
+end;
+
+function TPathImpl.FileSearch(const DirList: IPath): IPath;
+begin
+ AssertRefCount;
+ 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;
+
+function TPathImpl.GetIntern(): UTF8String;
+begin
+ Result := fName;
+end;
+
+
+{ 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;
- // Make sure the directory exists
- if (not ForceDirectories(RequestedPath)) then
+{ TTextStream }
+
+constructor TTextFileStream.Create(Filename: IPath; Mode: word);
+begin
+ inherited Create();
+ fMode := Mode;
+ fFilename := Filename;
+ fLineBreak := sLineBreak;
+end;
+
+function TTextFileStream.ReadLine(var Line: UTF8String): boolean;
+begin
+ Line := ReadLine(Result);
+end;
+
+function TTextFileStream.ReadLine(var Line: AnsiString): boolean;
+begin
+ Line := ReadLine(Result);
+end;
+
+procedure TTextFileStream.WriteString(const Str: RawByteString);
+begin
+ WriteBuffer(Str[1], Length(Str));
+end;
+
+procedure TTextFileStream.WriteLine(const Line: RawByteString);
+begin
+ WriteBuffer(Line[1], Length(Line));
+ WriteBuffer(fLineBreak[1], Length(fLineBreak));
+end;
+
+{ TMemTextStream }
+
+constructor TMemTextFileStream.Create(Filename: IPath; Mode: word);
+var
+ FileStream: TBinaryFileStream;
+begin
+ inherited Create(Filename, Mode);
+
+ fStream := TMemoryStream.Create();
+
+ // load data to memory in read mode
+ if ((Mode and 3) in [fmOpenRead, fmOpenReadWrite]) then
begin
- PathResult := '';
- Exit;
+ FileStream := TBinaryFileStream.Create(Filename, fmOpenRead);
+ try
+ fStream.LoadFromStream(FileStream);
+ finally
+ FileStream.Free;
+ end;
+ end
+ // check if file exists for write-mode
+ else if ((Mode and 3) = fmOpenWrite) and (not Filename.IsFile) then
+ begin
+ raise EFOpenError.CreateResFmt(@SFOpenError,
+ [FileName.GetAbsolutePath.ToNative]);
+ end;
+end;
+
+destructor TMemTextFileStream.Destroy();
+var
+ FileStream: TBinaryFileStream;
+ SaveMode: word;
+begin
+ // save changes in write mode (= not read-only mode)
+ if ((fMode and 3) <> fmOpenRead) then
+ begin
+ if (fMode = fmCreate) then
+ SaveMode := fmCreate
+ else
+ SaveMode := fmOpenWrite;
+ FileStream := TBinaryFileStream.Create(fFilename, SaveMode);
+ try
+ fStream.SaveToStream(FileStream);
+ finally
+ FileStream.Free;
+ end;
end;
- PathResult := IncludeTrailingPathDelimiter(RequestedPath);
+ fStream.Free;
+ inherited;
+end;
+
+function TMemTextFileStream.GetSize: int64;
+begin
+ Result := fStream.Size;
+end;
+
+function TMemTextFileStream.Read(var Buffer; Count: longint): longint;
+begin
+ Result := fStream.Read(Buffer, Count);
+end;
+
+function TMemTextFileStream.Write(const Buffer; Count: longint): longint;
+begin
+ Result := fStream.Write(Buffer, Count);
+end;
- if (NeedsWritePermission) and
- (FileIsReadOnly(RequestedPath)) then
+function TMemTextFileStream.Seek(Offset: longint; Origin: word): longint;
+begin
+ Result := fStream.Seek(Offset, Origin);
+end;
+
+function TMemTextFileStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64;
+begin
+ Result := fStream.Seek(Offset, Origin);
+end;
+
+function TMemTextFileStream.CopyMemString(StartPos: int64; EndPos: int64): RawByteString;
+var
+ LineLength: cardinal;
+ Temp: RawByteString;
+begin
+ LineLength := EndPos - StartPos;
+ if (LineLength > 0) then
begin
- Exit;
+ // set string length to line-length (+ zero-terminator)
+ SetLength(Temp, LineLength);
+ StrLCopy(PAnsiChar(Temp),
+ @PAnsiChar(fStream.Memory)[StartPos],
+ LineLength);
+ Result := Temp;
+ end
+ else
+ begin
+ Result := '';
+ end;
+end;
+
+function TMemTextFileStream.ReadString(): RawByteString;
+var
+ TextPtr: PAnsiChar;
+ CurPos, StartPos, FileSize: int64;
+begin
+ TextPtr := PAnsiChar(fStream.Memory);
+ CurPos := Position;
+ FileSize := Size;
+ StartPos := -1;
+
+ while (CurPos < FileSize) do
+ begin
+ // check for whitespace (tab, lf, cr, space)
+ if (TextPtr[CurPos] in [#9, #10, #13, ' ']) then
+ begin
+ // check if we are at the end of a string
+ if (StartPos > -1) then
+ Break;
+ end
+ else if (StartPos = -1) then // start of string found
+ begin
+ StartPos := CurPos;
+ end;
+ Inc(CurPos);
end;
- Result := true;
+ if (StartPos = -1) then
+ Result := ''
+ else
+ begin
+ Result := CopyMemString(StartPos, CurPos);
+ fStream.Position := CurPos;
+ end;
end;
-(**
- * Function sets all absolute paths e.g. song path and makes sure the directorys exist
- *)
-procedure InitializePaths;
+{*
+ * Implementation of ReadLine(). We need separate versions for UTF8String
+ * and AnsiString as "var" parameter types have to fit exactly.
+ * To avoid a var-parameter here, the internal version the Line parameter is
+ * used as return value.
+ *}
+function TMemTextFileStream.ReadLine(var Success: boolean): RawByteString;
+var
+ TextPtr: PAnsiChar;
+ CurPos, FileSize: int64;
begin
- // Log directory (must be writable)
- if (not FindPath(LogPath, Platform.GetLogPath, true)) then
+ TextPtr := PAnsiChar(fStream.Memory);
+ CurPos := fStream.Position;
+ FileSize := Size;
+
+ // check for EOF
+ if (CurPos >= FileSize) then
begin
- Log.FileOutputEnabled := false;
- Log.LogWarn('Log directory "'+ Platform.GetLogPath +'" not available', 'InitializePaths');
+ Result := '';
+ Success := false;
+ Exit;
+ end;
+
+ Success := true;
+
+ while (CurPos < FileSize) do
+ begin
+ if (TextPtr[CurPos] in [#10, #13]) then
+ begin
+ // copy text line
+ Result := CopyMemString(fStream.Position, CurPos);
+
+ // handle windows style #13#10 (\r\n) newlines
+ if (TextPtr[CurPos] = #13) and
+ (CurPos+1 < FileSize) and
+ (TextPtr[CurPos+1] = #10) then
+ begin
+ Inc(CurPos);
+ end;
+
+ // update stream pos
+ fStream.Position := CurPos+1;
+
+ Exit;
+ end;
+ Inc(CurPos);
+ end;
+
+ Result := CopyMemString(fStream.Position, CurPos);
+ fStream.Position := FileSize;
+end;
+
+{ TUnicodeMemoryStream }
+
+procedure TUnicodeMemoryStream.LoadFromFile(const FileName: IPath);
+var
+ Stream: TStream;
+begin
+ Stream := TBinaryFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(Stream);
+ finally
+ Stream.Free;
end;
+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);
+procedure TUnicodeMemoryStream.SaveToFile(const FileName: IPath);
+var
+ Stream: TStream;
+begin
+ Stream := TBinaryFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+{ TUnicodeMemIniFile }
- // Playlists are not shared as we need one directory to write too
- FindPath(PlaylistPath, Platform.GetGameUserPath + 'playlists', true);
+constructor TUnicodeMemIniFile.Create(const FileName: IPath; UTF8Encoded: boolean);
+var
+ List: TStringList;
+ Stream: TBinaryFileStream;
+ BOMBuf: array[0..2] of AnsiChar;
+begin
+ inherited Create('');
+ FFilename := FileName;
+ FUTF8Encoded := UTF8Encoded;
- // Screenshot directory (must be writable)
- if (not FindPath(ScreenshotsPath, Platform.GetGameUserPath + 'screenshots', true)) then
+ if FileName.Exists() then
begin
- Log.LogWarn('Screenshot directory "'+ Platform.GetGameUserPath +'" not available', 'InitializePaths');
+ List := nil;
+ Stream := nil;
+ try
+ List := TStringList.Create;
+ Stream := TBinaryFileStream.Create(FileName, fmOpenRead);
+ if (Stream.Read(BOMBuf[0], SizeOf(BOMBuf)) = 3) and
+ (CompareMem(PChar(UTF8_BOM), @BomBuf, Length(UTF8_BOM))) then
+ begin
+ // truncate BOM
+ FUTF8Encoded := true;
+ end
+ else
+ begin
+ // rewind file
+ Stream.Seek(0, soBeginning);
+ end;
+ List.LoadFromStream(Stream);
+ SetStrings(List);
+ finally
+ Stream.Free;
+ List.Free;
+ end;
end;
+end;
- // Add song paths
- AddSongPath(Params.SongPath);
- AddSongPath(Platform.GetGameSharedPath + 'songs');
- AddSongPath(Platform.GetGameUserPath + 'songs');
+procedure TUnicodeMemIniFile.UpdateFile;
+var
+ List: TStringList;
+ Stream: TBinaryFileStream;
+begin
+ List := nil;
+ Stream := nil;
+ try
+ List := TStringList.Create;
+ GetStrings(List);
+ Stream := TBinaryFileStream.Create(FFileName, fmCreate);
+ if UTF8Encoded then
+ Stream.Write(UTF8_BOM, Length(UTF8_BOM));
+ List.SaveToStream(Stream);
+ finally
+ List.Free;
+ Stream.Free;
+ end;
+end;
- // Add category cover paths
- AddCoverPath(Platform.GetGameSharedPath + 'covers');
- AddCoverPath(Platform.GetGameUserPath + 'covers');
+
+var
+ PATH_NONE_Singelton: IPath;
+
+function PATH_NONE(): IPath;
+begin
+ Result := PATH_NONE_Singelton;
end;
+initialization
+ {$IFDEF HAVE_REFCNTBUG}
+ GarbageList := TInterfaceList.Create();
+ GarbageList.Capacity := GarbageMaxCount;
+ {$ENDIF}
+ PATH_NONE_Singelton := Path('');
+
+finalization
+ PATH_NONE_Singelton := nil;
+
end.
diff --git a/src/base/UPathUtils.pas b/src/base/UPathUtils.pas
new file mode 100644
index 00000000..c2bcdd4b
--- /dev/null
+++ b/src/base/UPathUtils.pas
@@ -0,0 +1,196 @@
+{* 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 UPathUtils;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ SysUtils,
+ Classes,
+ UPath;
+
+var
+ // Absolute Paths
+ 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: IPath);
+
+implementation
+
+uses
+ StrUtils,
+ UPlatform,
+ UCommandLine,
+ ULog;
+
+procedure AddSpecialPath(var PathList: IInterfaceList; const Path: IPath);
+var
+ Index: integer;
+ PathAbs, PathTmp: IPath;
+ OldPath, OldPathAbs, OldPathTmp: IPath;
+begin
+ if (PathList = nil) then
+ PathList := TInterfaceList.Create;
+
+ if Path.Equals(PATH_NONE) or not Path.CreateDirectory(true) then
+ Exit;
+
+ 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
+ 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 (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 (PathAbs.IsChildOf(OldPathAbs, false)) then
+ begin
+ // replace the old with the new one.
+ PathList[Index] := PathAbs;
+ Exit;
+ end;
+ end;
+
+ PathList.Add(PathAbs);
+end;
+
+procedure AddSongPath(const Path: IPath);
+begin
+ AddSpecialPath(SongPaths, Path);
+end;
+
+procedure AddCoverPath(const Path: IPath);
+begin
+ AddSpecialPath(CoverPaths, Path);
+end;
+
+(**
+ * Initialize a path variable
+ * After setting paths, make sure that paths exist
+ *)
+function FindPath(
+ out PathResult: IPath;
+ const RequestedPath: IPath;
+ NeedsWritePermission: boolean): boolean;
+begin
+ Result := false;
+
+ if (RequestedPath.Equals(PATH_NONE)) then
+ Exit;
+
+ // Make sure the directory exists
+ if (not RequestedPath.CreateDirectory(true)) then
+ begin
+ PathResult := PATH_NONE;
+ Exit;
+ end;
+
+ PathResult := RequestedPath.AppendPathDelim();
+
+ if (NeedsWritePermission) and RequestedPath.IsReadOnly() then
+ Exit;
+
+ Result := true;
+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.ToNative +'" not available', 'InitializePaths');
+ end;
+
+ 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, UserPath.Append('playlists'), true);
+
+ // Screenshot directory (must be writable)
+ if (not FindPath(ScreenshotsPath, UserPath.Append('screenshots'), true)) then
+ begin
+ Log.LogWarn('Screenshot directory "'+ UserPath.ToNative +'" not available', 'InitializePaths');
+ end;
+
+ // Add song paths
+ AddSongPath(Params.SongPath);
+ AddSongPath(SharedPath.Append('songs'));
+ AddSongPath(UserPath.Append('songs'));
+
+ // Add category cover paths
+ AddCoverPath(SharedPath.Append('covers'));
+ AddCoverPath(UserPath.Append('covers'));
+end;
+
+end.
diff --git a/src/base/UPlatform.pas b/src/base/UPlatform.pas
index 6f13481c..11c67fa7 100644
--- a/src/base/UPlatform.pas
+++ b/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/src/base/UPlatformLinux.pas b/src/base/UPlatformLinux.pas
index 30499a97..693facaa 100644
--- a/src/base/UPlatformLinux.pas
+++ b/src/base/UPlatformLinux.pas
@@ -36,7 +36,8 @@ interface
uses
Classes,
UPlatform,
- UConfig;
+ UConfig,
+ UPath;
type
TPlatformLinux = class(TPlatform)
@@ -44,15 +45,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 +59,7 @@ implementation
uses
UCommandLine,
BaseUnix,
- {$IF FPC_VERSION_INT >= 2002002}
pwd,
- {$IFEND}
SysUtils,
ULog;
@@ -88,114 +85,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;
- Entry : Longint;
- 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/src/base/UPlatformMacOSX.pas b/src/base/UPlatformMacOSX.pas
index 96e4bc63..1dc0014a 100644
--- a/src/base/UPlatformMacOSX.pas
+++ b/src/base/UPlatformMacOSX.pas
@@ -36,7 +36,9 @@ interface
uses
Classes,
ULog,
- UPlatform;
+ UPlatform,
+ UFilesystem,
+ UPath;
type
{**
@@ -93,19 +95,21 @@ 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).
*}
procedure CreateUserFolders();
+ function GetHomeDir(): IPath;
+
public
{**
* Init simply calls @link(CreateUserFolders), which in turn scans the
@@ -116,37 +120,30 @@ 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
uses
- SysUtils,
- BaseUnix;
+ SysUtils;
procedure TPlatformMacOSX.Init;
begin
@@ -154,178 +151,129 @@ begin
end;
procedure TPlatformMacOSX.CreateUserFolders();
-const
- // used to construct the @link(UserPathName)
- PathName: string = '/Library/Application Support/UltraStarDeluxe';
var
- RelativePath: string;
+ RelativePath: IPath;
// BaseDir contains the path to the folder, where a search is performed.
// It is set to the entries in @link(DirectoryList) one after the other.
- BaseDir: string;
+ BaseDir: IPath;
// OldBaseDir contains the path to the folder, where the search started.
// It is used to return to it, when the search is completed in all folders.
- OldBaseDir: string;
- // This record contains the result of a file search with FindFirst or FindNext
- SearchInfo: TSearchRec;
+ OldBaseDir: IPath;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
+ CurPath: IPath;
// These two lists contain all folder and file names found
// within the folder @link(BaseDir).
- DirectoryList, FileList: TStringList;
+ DirectoryList, FileList: IInterfaceList;
// DirectoryIsFinished contains the index of the folder in @link(DirectoryList),
// which is the last one completely searched. Later folders are still to be
// searched for additional files and folders.
DirectoryIsFinished: longint;
- Counter: longint;
+ I: longint;
// These three are for creating directories, due to possible symlinks
CreatedDirectory: boolean;
FileAttrs: integer;
- DirectoryPath: string;
-
- UserPathName: string;
+ DirectoryPath: IPath;
+ UserPath: IPath;
+ SrcFile, TgtFile: IPath;
begin
// Get the current folder and save it in OldBaseDir for returning to it, when
// finished.
- GetDir(0, OldBaseDir);
+ OldBaseDir := FileSystem.GetCurrentDir();
- // UltraStarDeluxe.app/Contents contains all the default files and
- // folders.
- BaseDir := OldBaseDir + '/UltraStarDeluxe.app/Contents';
- ChDir(BaseDir);
+ // UltraStarDeluxe.app/Contents contains all the default files and folders.
+ BaseDir := OldBaseDir.Append('UltraStarDeluxe.app/Contents');
+ FileSystem.SetCurrentDir(BaseDir);
- // Right now, only $HOME/Library/Application Support/UltraStarDeluxe
- // is used.
- UserPathName := GetEnvironmentVariable('HOME') + PathName;
+ // Right now, only $HOME/Library/Application Support/UltraStarDeluxe is used.
+ UserPath := GetGameUserPath();
DirectoryIsFinished := 0;
- DirectoryList := TStringList.Create();
- FileList := TStringList.Create();
- DirectoryList.Add('.');
+ // replace with IInterfaceList
+ DirectoryList := TInterfaceList.Create();
+ FileList := TInterfaceList.Create();
+ DirectoryList.Add(Path('.'));
// create the folder and file lists
repeat
-
- RelativePath := DirectoryList[DirectoryIsFinished];
- ChDir(BaseDir + '/' + RelativePath);
- if (FindFirst('*', faAnyFile, SearchInfo) = 0) then
+ RelativePath := (DirectoryList[DirectoryIsFinished] as IPath);
+ FileSystem.SetCurrentDir(BaseDir.Append(RelativePath));
+ Iter := FileSystem.FileFind(Path('*'), faAnyFile);
+ while (Iter.HasNext) do
begin
- repeat
- if DirectoryExists(SearchInfo.Name) then
- begin
- if (SearchInfo.Name <> '.') and (SearchInfo.Name <> '..') then
- DirectoryList.Add(RelativePath + '/' + SearchInfo.Name);
- end
- else
- Filelist.Add(RelativePath + '/' + SearchInfo.Name);
- until (FindNext(SearchInfo) <> 0);
+ FileInfo := Iter.Next;
+ CurPath := FileInfo.Name;
+ if CurPath.IsDirectory() then
+ begin
+ if (not CurPath.Equals('.')) and (not CurPath.Equals('..')) then
+ DirectoryList.Add(RelativePath.Append(CurPath));
+ end
+ else
+ Filelist.Add(RelativePath.Append(CurPath));
end;
- FindClose(SearchInfo);
Inc(DirectoryIsFinished);
until (DirectoryIsFinished = DirectoryList.Count);
// create missing folders
- ForceDirectories(UserPathName); // should not be necessary since (UserPathName+'/.') is created.
- for Counter := 0 to DirectoryList.Count-1 do
+ UserPath.CreateDirectory(true); // should not be necessary since (UserPathName+'/.') is created.
+ for I := 0 to DirectoryList.Count-1 do
begin
- DirectoryPath := UserPathName + '/' + DirectoryList[Counter];
- CreatedDirectory := ForceDirectories(DirectoryPath);
- FileAttrs := FileGetAttr(DirectoryPath);
- // Don't know how to analyse the target of the link.
+ CurPath := DirectoryList[I] as IPath;
+ DirectoryPath := UserPath.Append(CurPath);
+ CreatedDirectory := DirectoryPath.CreateDirectory();
+ FileAttrs := DirectoryPath.GetAttr();
+ // Maybe analyse the target of the link with FpReadlink().
// Let's assume the symlink is pointing to an existing directory.
if (not CreatedDirectory) and (FileAttrs and faSymLink > 0) then
- Log.LogError('Failed to create the folder "'+ UserPathName + '/' + DirectoryList[Counter] +'"',
+ Log.LogError('Failed to create the folder "'+ DirectoryPath.ToNative +'"',
'TPlatformMacOSX.CreateUserFolders');
end;
- DirectoryList.Free();
// copy missing files
- for Counter := 0 to Filelist.Count-1 do
+ for I := 0 to Filelist.Count-1 do
begin
- CopyFile(BaseDir + '/' + Filelist[Counter],
- UserPathName + '/' + Filelist[Counter], true);
+ CurPath := Filelist[I] as IPath;
+ SrcFile := BaseDir.Append(CurPath);
+ TgtFile := UserPath.Append(CurPath);
+ SrcFile.CopyFile(TgtFile, true);
end;
- FileList.Free();
// go back to the initial folder
- ChDir(OldBaseDir);
+ FileSystem.SetCurrentDir(OldBaseDir);
end;
-function TPlatformMacOSX.GetBundlePath: WideString;
-var
- i, pos : integer;
+function TPlatformMacOSX.GetBundlePath: 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;
+ Result := GetExecutionDir().GetParent().GetParent();
end;
-function TPlatformMacOSX.GetApplicationSupportPath: WideString;
+function TPlatformMacOSX.GetApplicationSupportPath: IPath;
const
- PathName : string = '/Library/Application Support/UltraStarDeluxe';
+ PathName: string = 'Library/Application Support/UltraStarDeluxe';
begin
- Result := GetEnvironmentVariable('HOME') + PathName + '/';
+ Result := GetHomeDir().Append(PathName, pdAppend);
end;
-function TPlatformMacOSX.GetLogPath: WideString;
+function TPlatformMacOSX.GetHomeDir(): IPath;
begin
- Result := GetApplicationSupportPath + 'Logs';
+ Result := Path(GetEnvironmentVariable('HOME'));
end;
-function TPlatformMacOSX.GetGameSharedPath: WideString;
+function TPlatformMacOSX.GetLogPath: IPath;
begin
- Result := GetApplicationSupportPath;
+ Result := GetApplicationSupportPath.Append('Logs');
end;
-function TPlatformMacOSX.GetGameUserPath: WideString;
+function TPlatformMacOSX.GetGameSharedPath: IPath;
begin
Result := GetApplicationSupportPath;
end;
-function TPlatformMacOSX.DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray;
-var
- i : integer;
- TheDir : pdir;
- ADirent : pDirent;
- lAttrib : integer;
+function TPlatformMacOSX.GetGameUserPath: IPath;
begin
- i := 0;
- Filter := LowerCase(Filter);
-
- TheDir := FPOpenDir(Dir);
- if Assigned(TheDir) then
- 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);
+ Result := GetApplicationSupportPath;
end;
end.
diff --git a/src/base/UPlatformWindows.pas b/src/base/UPlatformWindows.pas
index e198958a..a0372dad 100644
--- a/src/base/UPlatformWindows.pas
+++ b/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,95 +61,6 @@ 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;
-begin
- with F do
- begin
- while FindData.dwFileAttributes and ExcludeAttr <> 0 do
-{$IFDEF Delphi}
- if not FindNextFileW(FindHandle, FindData) then
-{$ELSE}
- if not FindNextFileW(FindHandle, @FindData) then
-{$ENDIF}
- begin
- Result := GetLastError;
- Exit;
- end;
- FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
- FileTimeToDosDateTime(LocalFileTime, LongRec(Time).Hi, LongRec(Time).Lo);
- Size := FindData.nFileSizeLow;
- Attr := FindData.dwFileAttributes;
- Name := FindData.cFileName;
- end;
- Result := 0;
-end;
-
-function DirectoryExistsW(const Directory: widestring): Boolean;
-var
- Code: Integer;
-begin
- Code := GetFileAttributesW(PWideChar(Directory));
- Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
-end;
-
//------------------------------
//Start more than One Time Prevention
//------------------------------
@@ -180,41 +89,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 +99,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/src/base/UPlaylist.pas b/src/base/UPlaylist.pas
index 419ce687..03ae2ffb 100644
--- a/src/base/UPlaylist.pas
+++ b/src/base/UPlaylist.pas
@@ -34,21 +34,23 @@ interface
{$I switches.inc}
uses
+ Classes,
USong,
- UPath;
+ UPath,
+ UPathUtils;
type
TPlaylistItem = record
- Artist: String;
- Title: String;
+ Artist: UTF8String;
+ Title: UTF8String;
SongID: Integer;
end;
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; 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(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; 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: String): 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 := TMemTextFileStream.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 := TMemTextFileStream.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(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
@@ -390,7 +392,7 @@ begin
begin
ScreenSong.UnLoadDetailedCover;
ScreenSong.HideCatTL;
- CatSongs.SetFilter('', 0);
+ CatSongs.SetFilter('', fltAll);
ScreenSong.Interaction := 0;
ScreenSong.FixSelected;
ScreenSong.ChangeMusic;
@@ -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/src/base/USkins.pas b/src/base/USkins.pas
index a4722d95..6ef5c596 100644
--- a/src/base/USkins.pas
+++ b/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,
- UPath;
+ 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/src/base/USong.pas b/src/base/USong.pas
index 57f78a27..d2043a93 100644
--- a/src/base/USong.pas
+++ b/src/base/USong.pas
@@ -56,7 +56,11 @@ uses
PseudoThread,
{$ENDIF}
UCatCovers,
- UXMLSong;
+ UXMLSong,
+ UUnicodeUtils,
+ UTextEncoding,
+ UFilesystem,
+ UPath;
type
@@ -68,42 +72,54 @@ type
end;
TScore = record
- Name: WideString;
+ Name: UTF8String;
Score: integer;
- Length: string;
end;
TSong = class
+ private
FileLineNo : integer; // line, which is read last, for error reporting
- procedure ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string);
+ function DecodeFilename(Filename: RawByteString): IPath;
+ function Solmizate(Note: integer; Type_: integer): string;
+ 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;
- public
- Path: WideString;
- Folder: WideString; // for sorting by folder
- fFileName,
- FileName: WideString;
+ function ParseLyricStringParam(const Line: RawByteString; var LinePos: integer): RawByteString;
+ function ParseLyricIntParam(const Line: RawByteString; var LinePos: integer): integer;
+ function ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): real;
+ function ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar;
+ function ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString;
+
+ function ReadTXTHeader(SongFile: TTextFileStream): 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)
+ FileName: IPath; // just name component of file (only set if file was found)
+
+ // filenames
+ Cover: IPath;
+ Mp3: IPath;
+ Background: IPath;
+ Video: IPath;
+
// sorting methods
- //Category: array of WideString; // TODO: do we need this?
- Genre: WideString;
- Edition: WideString;
- Language: WideString;
+ Genre: UTF8String;
+ Edition: UTF8String;
+ Language: UTF8String;
- Title: WideString;
- Artist: WideString;
+ Title: UTF8String;
+ Artist: UTF8String;
- Text: WideString;
- Creator: WideString;
+ Creator: UTF8String;
- Cover: WideString;
CoverTex: TTexture;
- Mp3: WideString;
- Background: WideString;
- Video: WideString;
+
VideoGAP: real;
NotesGAP: integer;
Start: real; // in seconds
@@ -113,6 +129,8 @@ type
BPM: array of TBPM;
GAP: real; // in miliseconds
+ Encoding: TEncoding;
+
Score: array[0..2] of array of TScore;
// these are used when sorting is enabled
@@ -122,20 +140,18 @@ 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
-
Base : array[0..1] of integer;
Rel : array[0..1] of integer;
Mult : integer;
MultBPM : integer;
- LastError: String;
+ LastError: AnsiString;
function GetErrorLineNo: integer;
property ErrorLineNo: integer read GetErrorLineNo;
- constructor Create (); overload;
- constructor Create ( const aFileName : WideString ); overload;
+ constructor Create(); overload;
+ constructor Create(const aFileName : IPath); overload;
function LoadSong: boolean;
function LoadXMLSong: boolean;
function Analyse(): boolean;
@@ -149,67 +165,74 @@ uses
StrUtils,
TextGL,
UIni,
- UPath,
+ UPathUtils,
UMusic, //needed for Lines
UNote; //needed for Player
+const
+ // use USDX < 1.1 encoding for backward compatibility
+ DEFAULT_ENCODING = encCP1252;
+
constructor TSong.Create();
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
@@ -218,45 +241,178 @@ 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.DecodeFilename(Filename: RawByteString): IPath;
+begin
+ Result := UPath.Path(DecodeStringUTF8(Filename, Encoding));
+end;
+
+type
+ EUSDXParseException = class(Exception);
+
+{**
+ * Parses the Line string starting from LinePos for a parameter.
+ * Leading whitespace is trimmed, same applies to the first trailing whitespace.
+ * After the call LinePos will point to the position after the first trailing
+ * whitespace.
+ *
+ * Raises an EUSDXParseException if no string was found.
+ *
+ * Example:
+ * ParseLyricParam(Line:'Param0 Param1 Param2', LinePos:8, ...)
+ * -> Param:'Param1', LinePos:16 (= start of 'Param2')
+ *}
+function TSong.ParseLyricStringParam(const Line: RawByteString; var LinePos: integer): RawByteString;
+var
+ Start: integer;
+ OldLinePos: integer;
+const
+ Whitespace = [#9, ' '];
+begin
+ OldLinePos := LinePos;
+
+ Start := 0;
+ while (LinePos <= Length(Line)) do
+ begin
+ if (Line[LinePos] in Whitespace) then
+ begin
+ // check for end of param
+ if (Start > 0) then
+ Break;
+ end
+ // check for beginning of param
+ else if (Start = 0) then
+ begin
+ Start := LinePos;
+ end;
+ Inc(LinePos);
+ end;
+
+ // check if param was found
+ if (Start = 0) then
+ begin
+ LinePos := OldLinePos;
+ raise EUSDXParseException.Create('String expected');
+ end
+ else
+ begin
+ // copy param without trailing whitespace
+ Result := Copy(Line, Start, LinePos-Start);
+ // skip first trailing whitespace (if not at EOL)
+ if (LinePos <= Length(Line)) then
+ Inc(LinePos);
+ end;
+end;
+
+function TSong.ParseLyricIntParam(const Line: RawByteString; var LinePos: integer): integer;
+var
+ Str: RawByteString;
+ OldLinePos: integer;
+begin
+ OldLinePos := LinePos;
+ Str := ParseLyricStringParam(Line, LinePos);
+ try
+ Result := StrToInt(Str);
+ except // on EConvertError
+ LinePos := OldLinePos;
+ raise EUSDXParseException.Create('Integer expected');
end;
end;
-{function TSong.LoadSong(): boolean;
+function TSong.ParseLyricFloatParam(const Line: RawByteString; var LinePos: integer): real;
+var
+ Str: RawByteString;
+ OldLinePos: integer;
+begin
+ OldLinePos := LinePos;
+ Str := ParseLyricStringParam(Line, LinePos);
+ try
+ Result := StrToFloat(Str);
+ except // on EConvertError
+ LinePos := OldLinePos;
+ raise EUSDXParseException.Create('Float expected');
+ end;
+end;
+
+function TSong.ParseLyricCharParam(const Line: RawByteString; var LinePos: integer): AnsiChar;
+var
+ Str: RawByteString;
+ OldLinePos: integer;
begin
+ OldLinePos := LinePos;
+ Str := ParseLyricStringParam(Line, LinePos);
+ if (Length(Str) <> 1) then
+ begin
+ LinePos := OldLinePos;
+ raise EUSDXParseException.Create('Character expected');
+ end;
+ Result := Str[1];
+end;
-end; }
+{**
+ * Returns the rest of the line from LinePos as lyric text.
+ * Leading and trailing whitespace is not trimmed.
+ *}
+function TSong.ParseLyricText(const Line: RawByteString; var LinePos: integer): RawByteString;
+begin
+ if (LinePos > Length(Line)) then
+ Result := ''
+ else
+ begin
+ Result := Copy(Line, LinePos, Length(Line)-LinePos+1);
+ LinePos := Length(Line)+1;
+ end;
+end;
//Load TXT Song
function TSong.LoadSong(): boolean;
-
var
- TempC: char;
- Text: string;
- CP: integer; // Current Player (0 or 1)
+ CurLine: RawByteString;
+ LinePos: integer;
Count: integer;
Both: boolean;
- Param1: integer;
- Param2: integer;
- Param3: integer;
- ParamS: string;
- I: integer;
+ Param0: AnsiChar;
+ Param1: integer;
+ Param2: integer;
+ Param3: integer;
+ ParamLyric: UTF8String;
+
+ I: integer;
+ NotesFound: boolean;
+ SongFile: 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
Mult := 1; // accuracy of measurement of note
Rel[0] := 0;
- CP := 0;
Both := false;
if Length(Player) = 2 then
@@ -264,156 +420,155 @@ begin
try
// Open song file for reading.....
- FileMode := fmOpenRead;
- AssignFile(SongFile, fFileName);
- Reset(SongFile);
-
- //Clear old Song Header
- if (self.Path = '') then
- self.Path := ExtractFilePath(FileName);
-
- if (self.FileName = '') then
- self.Filename := ExtractFileName(FileName);
-
- FileLineNo := 0;
- //Search for Note Begining
- repeat
- ReadLn(SongFile, Text);
- Inc(FileLineNo);
+ SongFile := TMemTextFileStream.Create(FileNamePath, fmOpenRead);
+ try
+ //Search for Note Beginning
+ FileLineNo := 0;
+ NotesFound := false;
+ while (SongFile.ReadLine(CurLine)) do
+ begin
+ Inc(FileLineNo);
+ if (Length(CurLine) > 0) and (CurLine[1] in [':', 'F', '*']) then
+ begin
+ NotesFound := true;
+ Break;
+ end;
+ end;
- if (EoF(SongFile)) then
+ if (not NotesFound) then
begin //Song File Corrupted - No Notes
- CloseFile(SongFile);
- Log.LogError('Could not load txt File, no Notes found: ' + FileName);
+ Log.LogError('Could not load txt File, no notes found: ' + FileNamePath.ToNative);
LastError := 'ERROR_CORRUPT_SONG_NO_NOTES';
Exit;
end;
- Read(SongFile, TempC);
- until ((TempC = ':') or (TempC = 'F') or (TempC = '*'));
-
- SetLength(Lines, 2);
- for Count := 0 to High(Lines) do
- begin
- Lines[Count].High := 0;
- Lines[Count].Number := 1;
- Lines[Count].Current := 0;
- Lines[Count].Resolution := self.Resolution;
- Lines[Count].NotesGAP := self.NotesGAP;
- Lines[Count].ScoreValue := 0;
- //Add first line and set some standard values to fields
- //see procedure NewSentence for further explantation
- //concerning most of these values
- SetLength(Lines[Count].Line, 1);
- Lines[Count].Line[0].HighNote := -1;
- Lines[Count].Line[0].LastLine := false;
- Lines[Count].Line[0].BaseNote := High(Integer);
- Lines[Count].Line[0].TotalNotes := 0;
- end;
-
- while (TempC <> 'E') and (not EOF(SongFile)) do
- begin
-
- if (TempC = ':') or (TempC = '*') or (TempC = 'F') then
+ SetLength(Lines, 2);
+ for Count := 0 to High(Lines) do
begin
- // read notes
- Read(SongFile, Param1);
- Read(SongFile, Param2);
- Read(SongFile, Param3);
- Read(SongFile, ParamS);
-
- //Check for ZeroNote
- if Param2 = 0 then
- Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!')
- else
- begin
- // add notes
- if not Both then
- // P1
- ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS)
- else
- begin
- // P1 + P2
- ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS);
- ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS);
- end;
- end; //Zeronote check
- end // if
-
- else if TempC = '-' then
- begin
- // reads sentence
- Read(SongFile, Param1);
- if self.Relative then
- Read(SongFile, Param2); // read one more data for relative system
-
- // new sentence
- if not Both then
- // P1
- NewSentence(0, (Param1 + Rel[0]) * Mult, Param2)
- else
- begin
- // P1 + P2
- NewSentence(0, (Param1 + Rel[0]) * Mult, Param2);
- NewSentence(1, (Param1 + Rel[1]) * Mult, Param2);
- end;
- end // if
+ Lines[Count].High := 0;
+ Lines[Count].Number := 1;
+ Lines[Count].Current := 0;
+ Lines[Count].Resolution := self.Resolution;
+ Lines[Count].NotesGAP := self.NotesGAP;
+ Lines[Count].ScoreValue := 0;
+
+ //Add first line and set some standard values to fields
+ //see procedure NewSentence for further explantation
+ //concerning most of these values
+ SetLength(Lines[Count].Line, 1);
+ Lines[Count].Line[0].HighNote := -1;
+ Lines[Count].Line[0].LastLine := false;
+ Lines[Count].Line[0].BaseNote := High(Integer);
+ Lines[Count].Line[0].TotalNotes := 0;
+ end;
- else if TempC = 'B' then
+ while true do
begin
- SetLength(self.BPM, Length(self.BPM) + 1);
- Read(SongFile, self.BPM[High(self.BPM)].StartBeat);
- self.BPM[High(self.BPM)].StartBeat := self.BPM[High(self.BPM)].StartBeat + Rel[0];
+ LinePos := 0;
- Read(SongFile, Text);
- self.BPM[High(self.BPM)].BPM := StrToFloat(Text);
- self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM;
- end;
+ Param0 := ParseLyricCharParam(CurLine, LinePos);
+ if (Param0 = 'E') then
+ begin
+ Break
+ end
+ else if (Param0 in [':', '*', 'F']) then
+ begin
+ // read notes
+ Param1 := ParseLyricIntParam(CurLine, LinePos);
+ Param2 := ParseLyricIntParam(CurLine, LinePos);
+ Param3 := ParseLyricIntParam(CurLine, LinePos);
+ ParamLyric := ParseLyricText(CurLine, LinePos);
+
+ //Check for ZeroNote
+ if Param2 = 0 then
+ Log.LogError('Found zero-length note at "'+Param0+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamLyric+'" -> Note ignored!')
+ else
+ begin
+ // add notes
+ if not Both then
+ // P1
+ ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric)
+ else
+ begin
+ // P1 + P2
+ ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric);
+ ParseNote(1, Param0, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamLyric);
+ end;
+ end; //Zeronote check
+ end // if
+
+ else if Param0 = '-' then
+ begin
+ // reads sentence
+ Param1 := ParseLyricIntParam(CurLine, LinePos);
+ if self.Relative then
+ Param2 := ParseLyricIntParam(CurLine, LinePos); // read one more data for relative system
+
+ // new sentence
+ if not Both then
+ // P1
+ NewSentence(0, (Param1 + Rel[0]) * Mult, Param2)
+ else
+ begin
+ // P1 + P2
+ NewSentence(0, (Param1 + Rel[0]) * Mult, Param2);
+ NewSentence(1, (Param1 + Rel[1]) * Mult, Param2);
+ end;
+ end // if
- ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32)
+ else if Param0 = 'B' then
+ begin
+ SetLength(self.BPM, Length(self.BPM) + 1);
+ self.BPM[High(self.BPM)].StartBeat := ParseLyricFloatParam(CurLine, LinePos);
+ self.BPM[High(self.BPM)].StartBeat := self.BPM[High(self.BPM)].StartBeat + Rel[0];
- Read(SongFile, TempC);
- Inc(FileLineNo);
- end; // while}
+ self.BPM[High(self.BPM)].BPM := ParseLyricFloatParam(CurLine, LinePos);
+ self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM;
+ end;
- CloseFile(SongFile);
+ // Read next line in File
+ if (not SongFile.ReadLine(CurLine)) then
+ Break;
- for I := 0 to High(Lines) do
+ Inc(FileLineNo);
+ end; // while
+ finally
+ SongFile.Free;
+ end;
+ except
+ on E: Exception do
begin
- if ((Both) or (I = 0)) then
- 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 + '"');
- exit;
- end;
-
- if (Lines[I].Line[Lines[I].High].HighNote < 0) then
- begin
- SetLength(Lines[I].Line, Lines[I].Number - 1);
- Lines[I].High := Lines[I].High - 1;
- Lines[I].Number := Lines[I].Number - 1;
- Log.LogError('Error loading Song, sentence w/o note found in last line before E: ' + Filename);
- end;
- end;
+ Log.LogError(Format('Error loading file: "%s" in line %d,%d: %s',
+ [FileNamePath.ToNative, FileLineNo, LinePos, E.Message]));
+ Exit;
end;
+ end;
- for Count := 0 to High(Lines) do
+ for I := 0 to High(Lines) do
+ begin
+ if ((Both) or (I = 0)) then
begin
- if (High(Lines[Count].Line) >= 0) then
- Lines[Count].Line[High(Lines[Count].Line)].LastLine := true;
- end;
- except
- try
- CloseFile(SongFile);
- except
+ if (Length(Lines[I].Line) < 2) then
+ begin
+ LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS';
+ Log.LogError('Error loading file: Can''t find any linebreaks in "' + FileNamePath.ToNative + '"');
+ exit;
+ end;
+ if (Lines[I].Line[Lines[I].High].HighNote < 0) then
+ begin
+ SetLength(Lines[I].Line, Lines[I].Number - 1);
+ Lines[I].High := Lines[I].High - 1;
+ Lines[I].Number := Lines[I].Number - 1;
+ Log.LogError('Error loading Song, sentence w/o note found in last line before E: ' + FileNamePath.ToNative);
+ end;
end;
+ end;
- LastError := 'ERROR_CORRUPT_SONG_ERROR_IN_LINE';
- Log.LogError('Error Loading File: "' + fFileName + '" in Line ' + inttostr(FileLineNo));
- exit;
+ for Count := 0 to High(Lines) do
+ begin
+ if (High(Lines[Count].Line) >= 0) then
+ Lines[Count].Line[High(Lines[Count].Line)].LastLine := true;
end;
Result := true;
@@ -421,11 +576,7 @@ end;
//Load XML Song
function TSong.LoadXMLSong(): boolean;
-
var
- //TempC: char;
- Text: string;
- CP: integer; // Current Player (0 or 1)
Count: integer;
Both: boolean;
Param1: integer;
@@ -438,14 +589,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;
@@ -454,7 +606,6 @@ begin
Lines[0].ScoreValue := 0;
self.Relative := false;
Rel[0] := 0;
- CP := 0;
Both := false;
if Length(Player) = 2 then
@@ -484,7 +635,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');
@@ -551,7 +702,7 @@ begin
end
else
begin
- Log.LogError('Could not parse Inputfile: ' + Path + PathDelim + FileName);
+ Log.LogError('Could not parse inputfile: ' + FileNamePath.ToNative);
exit;
end;
@@ -563,14 +714,11 @@ begin
Result := true;
end;
-function TSong.ReadXMLHeader(const aFileName : WideString): boolean;
-
+function TSong.ReadXMLHeader(const aFileName : IPath): boolean;
var
- //Line, Identifier, Value: string;
- //Temp : word;
Done : byte;
Parser : TParser;
-
+ FileNamePath: IPath;
begin
Result := true;
Done := 0;
@@ -579,7 +727,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
@@ -598,9 +747,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
@@ -621,16 +770,16 @@ 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
// Video Gap
- // self.VideoGAP := song_StrtoFloat( Value )
+ // self.VideoGAP := StrtoFloatI18n( Value )
//Genre Sorting
self.Genre := Parser.SongInfo.Header.Genre;
@@ -645,7 +794,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;
@@ -654,220 +803,260 @@ 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;
-
- function song_StrtoFloat( aValue : string ) : extended;
-
- var
- lValue : string;
-
- begin
- lValue := aValue;
-
- if (Pos(',', lValue) <> 0) then
- lValue[Pos(',', lValue)] := '.';
-
- Result := StrToFloatDef(lValue, 0);
- end;
-
+{**
+ * "International" StrToFloat variant. Uses either ',' or '.' as decimal
+ * separator.
+ *}
+function StrToFloatI18n(const Value: string): extended;
var
- Line, Identifier, Value: string;
- Temp : word;
- Done : byte;
+ TempValue : string;
+begin
+ TempValue := Value;
+ if (Pos(',', TempValue) <> 0) then
+ TempValue[Pos(',', TempValue)] := '.';
+ Result := StrToFloatDef(TempValue, 0);
+end;
+function TSong.ReadTXTHeader(SongFile: TTextFileStream): boolean;
+var
+ Line, Identifier: string;
+ Value: string;
+ SepPos: integer; // separator position
+ Done: byte; // bit-vector of mandatory fields
+ EncFile: IPath; // encoded filename
+ FullFileName: string;
begin
Result := true;
Done := 0;
- //Read first Line
- ReadLn (SongFile, Line);
+ FullFileName := Path.Append(Filename).ToNative;
+ //Read first Line
+ SongFile.ReadLine(Line);
if (Length(Line) <= 0) then
begin
- Log.LogError('File Starts with Empty Line: ' + aFileName);
+ Log.LogError('File starts with empty line: ' + FullFileName,
+ 'TSong.ReadTXTHeader');
Result := false;
Exit;
end;
+ // check if file begins with a UTF-8 BOM, if so set encoding to UTF-8
+ if (CheckReplaceUTF8BOM(Line)) then
+ Encoding := encUTF8;
+
//Read Lines while Line starts with # or its empty
while (Length(Line) = 0) or (Line[1] = '#') do
begin
//Increase Line Number
Inc (FileLineNo);
- Temp := Pos(':', Line);
+ SepPos := Pos(':', Line);
- //Line has a Seperator-> Headerline
- if (Temp <> 0) then
- begin
- //Read Identifier and Value
- Identifier := Uppercase(Trim(Copy(Line, 2, Temp - 2))); //Uppercase is for Case Insensitive Checks
- Value := Trim(Copy(Line, Temp + 1,Length(Line) - Temp));
+ //Line has no Seperator, ignore non header field
+ if (SepPos = 0) then
+ Continue;
- //Check the Identifier (If Value is given)
- if (Length(Value) <> 0) then
- begin
- //-----------
- //Required Attributes
- //-----------
-
- {$IFDEF UTF8_FILENAMES}
- if ((Identifier = 'MP3') or (Identifier = 'BACKGROUND') or (Identifier = 'COVER') or (Identifier = 'VIDEO')) then
- Value := Utf8Encode(Value);
- {$ENDIF}
+ //Read Identifier and Value
+ Identifier := UpperCase(Trim(Copy(Line, 2, SepPos - 2))); //Uppercase is for Case Insensitive Checks
+ Value := Trim(Copy(Line, SepPos + 1, Length(Line) - SepPos));
- //Title
- if (Identifier = 'TITLE') then
- begin
- self.Title := Value;
-
- //Add Title Flag to Done
- Done := Done or 1;
- end
+ //Check the Identifier (If Value is given)
+ if (Length(Value) = 0) then
+ begin
+ Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName,
+ 'TSong.ReadTXTHeader');
+ end
+ else
+ begin
+
+ //-----------
+ //Required Attributes
+ //-----------
- //Artist
- else if (Identifier = 'ARTIST') then
- begin
- self.Artist := Value;
+ if (Identifier = 'TITLE') then
+ begin
+ DecodeStringUTF8(Value, Title, Encoding);
+ //Add Title Flag to Done
+ Done := Done or 1;
+ end
- //Add Artist Flag to Done
- Done := Done or 2;
- end
+ else if (Identifier = 'ARTIST') then
+ begin
+ DecodeStringUTF8(Value, Artist, Encoding);
+ //Add Artist Flag to Done
+ Done := Done or 2;
+ end
- //MP3 File //Test if Exists
- else if (Identifier = 'MP3') and (FileExists(self.Path + Value)) then
+ //MP3 File
+ else if (Identifier = 'MP3') then
+ begin
+ EncFile := DecodeFilename(Value);
+ if (Self.Path.Append(EncFile).IsFile) then
begin
- self.Mp3 := Value;
+ self.Mp3 := EncFile;
//Add Mp3 Flag to Done
Done := Done or 4;
- end
+ end;
+ end
- //Beats per Minute
- else if (Identifier = 'BPM') then
- begin
- SetLength(self.BPM, 1);
- self.BPM[0].StartBeat := 0;
+ //Beats per Minute
+ else if (Identifier = 'BPM') then
+ begin
+ SetLength(self.BPM, 1);
+ self.BPM[0].StartBeat := 0;
- self.BPM[0].BPM := song_StrtoFloat( Value ) * Mult * MultBPM;
+ self.BPM[0].BPM := StrToFloatI18n( Value ) * Mult * MultBPM;
- if self.BPM[0].BPM <> 0 then
- begin
- //Add BPM Flag to Done
- Done := Done or 8;
- end;
- end
+ if self.BPM[0].BPM <> 0 then
+ begin
+ //Add BPM Flag to Done
+ Done := Done or 8;
+ end;
+ end
- //---------
- //Additional Header Information
- //---------
+ //---------
+ //Additional Header Information
+ //---------
- // Gap
- else if (Identifier = 'GAP') then
- self.GAP := song_StrtoFloat( Value )
+ // Gap
+ else if (Identifier = 'GAP') then
+ begin
+ self.GAP := StrToFloatI18n(Value);
+ end
- //Cover Picture
- else if (Identifier = 'COVER') then
- self.Cover := Value
+ //Cover Picture
+ else if (Identifier = 'COVER') then
+ begin
+ self.Cover := DecodeFilename(Value);
+ end
- //Background Picture
- else if (Identifier = 'BACKGROUND') then
- self.Background := Value
+ //Background Picture
+ else if (Identifier = 'BACKGROUND') then
+ begin
+ self.Background := DecodeFilename(Value);
+ end
- // Video File
- else if (Identifier = 'VIDEO') then
- begin
- if (FileExists(self.Path + Value)) then
- self.Video := Value
- else
- Log.LogError('Can''t find Video File in Song: ' + aFileName);
- end
+ // Video File
+ else if (Identifier = 'VIDEO') then
+ begin
+ EncFile := DecodeFilename(Value);
+ if (self.Path.Append(EncFile).IsFile) then
+ self.Video := EncFile
+ else
+ Log.LogError('Can''t find video file in song: ' + FullFileName);
+ end
- // Video Gap
- else if (Identifier = 'VIDEOGAP') then
- self.VideoGAP := song_StrtoFloat( Value )
+ // Video Gap
+ else if (Identifier = 'VIDEOGAP') then
+ begin
+ self.VideoGAP := StrToFloatI18n( Value )
+ end
- //Genre Sorting
- else if (Identifier = 'GENRE') then
- self.Genre := Value
+ //Genre Sorting
+ else if (Identifier = 'GENRE') then
+ begin
+ DecodeStringUTF8(Value, Genre, Encoding)
+ end
- //Edition Sorting
- else if (Identifier = 'EDITION') then
- self.Edition := Value
+ //Edition Sorting
+ else if (Identifier = 'EDITION') then
+ begin
+ DecodeStringUTF8(Value, Edition, Encoding)
+ end
- //Creator Tag
- else if (Identifier = 'CREATOR') then
- self.Creator := Value
+ //Creator Tag
+ else if (Identifier = 'CREATOR') then
+ begin
+ DecodeStringUTF8(Value, Creator, Encoding)
+ end
+
+ //Language Sorting
+ else if (Identifier = 'LANGUAGE') then
+ begin
+ DecodeStringUTF8(Value, Language, Encoding)
+ end
- //Language Sorting
- else if (Identifier = 'LANGUAGE') then
- self.Language := Value
+ // Song Start
+ else if (Identifier = 'START') then
+ begin
+ self.Start := StrToFloatI18n( Value )
+ end
- // Song Start
- else if (Identifier = 'START') then
- self.Start := song_StrtoFloat( Value )
+ // Song Ending
+ else if (Identifier = 'END') then
+ begin
+ TryStrtoInt(Value, self.Finish)
+ end
- // Song Ending
- else if (Identifier = 'END') then
- TryStrtoInt(Value, self.Finish)
+ // Resolution
+ else if (Identifier = 'RESOLUTION') then
+ begin
+ TryStrtoInt(Value, self.Resolution)
+ end
- // Resolution
- else if (Identifier = 'RESOLUTION') then
- TryStrtoInt(Value, self.Resolution)
+ // Notes Gap
+ else if (Identifier = 'NOTESGAP') then
+ begin
+ TryStrtoInt(Value, self.NotesGAP)
+ end
- // Notes Gap
- else if (Identifier = 'NOTESGAP') then
- TryStrtoInt(Value, self.NotesGAP)
- // Relative Notes
- else if (Identifier = 'RELATIVE') and (uppercase(Value) = 'YES') then
+ // Relative Notes
+ else if (Identifier = 'RELATIVE') then
+ begin
+ if (UpperCase(Value) = 'YES') then
self.Relative := true;
+ end
+ // File encoding
+ else if (Identifier = 'ENCODING') then
+ begin
+ self.Encoding := ParseEncoding(Value, DEFAULT_ENCODING);
end;
- end;
+
+ end; // End check for non-empty Value
- if not EOF(SongFile) then
- ReadLn (SongFile, Line)
- else
+ // read next line
+ if (not SongFile.ReadLine(Line)) then
begin
Result := false;
- Log.LogError('File Incomplete or not Ultrastar TxT (A): ' + aFileName);
- break;
+ Log.LogError('File incomplete or not Ultrastar txt (A): ' + FullFileName);
+ Break;
end;
+ end; // while
- end;
-
- if self.Cover = '' then
- self.Cover := platform.FindSongFile(Path, '*[CO].jpg');
+ if self.Cover.IsUnset then
+ self.Cover := FindSongFile(Path, '*[CO].jpg');
//Check if all Required Values are given
if (Done <> 15) then
begin
Result := false;
if (Done and 8) = 0 then //No BPM Flag
- Log.LogError('BPM Tag Missing: ' + self.FileName)
+ Log.LogError('BPM tag missing: ' + FullFileName)
else if (Done and 4) = 0 then //No MP3 Flag
- Log.LogError('MP3 Tag/File Missing: ' + self.FileName)
+ Log.LogError('MP3 tag/file missing: ' + FullFileName)
else if (Done and 2) = 0 then //No Artist Flag
- Log.LogError('Artist Tag Missing: ' + self.FileName)
+ Log.LogError('Artist tag missing: ' + FullFileName)
else if (Done and 1) = 0 then //No Title Flag
- Log.LogError('Title Tag Missing: ' + self.FileName)
+ Log.LogError('Title tag missing: ' + FullFileName)
else //unknown Error
- Log.LogError('File Incomplete or not Ultrastar TxT (B - '+ inttostr(Done) +'): ' + aFileName);
+ Log.LogError('File incomplete or not Ultrastar txt (B - '+ inttostr(Done) +'): ' + FullFileName);
end;
-
end;
function TSong.GetErrorLineNo: integer;
@@ -878,47 +1067,52 @@ begin
Result := -1;
end;
-procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: string);
-
+function TSong.Solmizate(Note: integer; Type_: integer): string;
begin
- case Ini.Solmization of
+ case (Type_) of
1: // european
begin
- case (NoteP mod 12) of
- 0..1: LyricS := ' do ';
- 2..3: LyricS := ' re ';
- 4: LyricS := ' mi ';
- 5..6: LyricS := ' fa ';
- 7..8: LyricS := ' sol ';
- 9..10: LyricS := ' la ';
- 11: LyricS := ' si ';
+ case (Note mod 12) of
+ 0..1: Result := ' do ';
+ 2..3: Result := ' re ';
+ 4: Result := ' mi ';
+ 5..6: Result := ' fa ';
+ 7..8: Result := ' sol ';
+ 9..10: Result := ' la ';
+ 11: Result := ' si ';
end;
end;
2: // japanese
begin
- case (NoteP mod 12) of
- 0..1: LyricS := ' do ';
- 2..3: LyricS := ' re ';
- 4: LyricS := ' mi ';
- 5..6: LyricS := ' fa ';
- 7..8: LyricS := ' so ';
- 9..10: LyricS := ' la ';
- 11: LyricS := ' shi ';
+ case (Note mod 12) of
+ 0..1: Result := ' do ';
+ 2..3: Result := ' re ';
+ 4: Result := ' mi ';
+ 5..6: Result := ' fa ';
+ 7..8: Result := ' so ';
+ 9..10: Result := ' la ';
+ 11: Result := ' shi ';
end;
end;
3: // american
begin
- case (NoteP mod 12) of
- 0..1: LyricS := ' do ';
- 2..3: LyricS := ' re ';
- 4: LyricS := ' mi ';
- 5..6: LyricS := ' fa ';
- 7..8: LyricS := ' sol ';
- 9..10: LyricS := ' la ';
- 11: LyricS := ' ti ';
+ case (Note mod 12) of
+ 0..1: Result := ' do ';
+ 2..3: Result := ' re ';
+ 4: Result := ' mi ';
+ 5..6: Result := ' fa ';
+ 7..8: Result := ' sol ';
+ 9..10: Result := ' la ';
+ 11: Result := ' ti ';
end;
end;
end; // case
+end;
+
+procedure TSong.ParseNote(LineNumber: integer; TypeP: char; StartP, DurationP, NoteP: integer; LyricS: UTF8String);
+begin
+ if (Ini.Solmization <> 0) then
+ LyricS := Solmizate(NoteP, Ini.Solmization);
with Lines[LineNumber].Line[Lines[LineNumber].High] do
begin
@@ -956,14 +1150,7 @@ begin
if Note[HighNote].Tone < BaseNote then
BaseNote := Note[HighNote].Tone;
- //delete the space that seperates the notes pitch from its lyrics
- //it is left in the LyricS string because Read("some ordinal type") will
- //set the files pointer to the first whitespace character after the
- //ordinal string. Trim is no solution because it would cut the spaces
- //that seperate the words of the lyrics, too.
- Delete(LyricS, 1, 1);
-
- Note[HighNote].Text := LyricS;
+ DecodeStringUTF8(LyricS, Note[HighNote].Text, Encoding);
Lyric := Lyric + Note[HighNote].Text;
End_ := Note[HighNote].Start + Note[HighNote].Length;
@@ -971,10 +1158,8 @@ begin
end;
procedure TSong.NewSentence(LineNumberP: integer; Param1, Param2: integer);
-
var
I: integer;
-
begin
if (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then
@@ -985,7 +1170,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;
@@ -1012,8 +1198,7 @@ begin
Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := false;
end;
-procedure TSong.clear();
-
+procedure TSong.Clear();
begin
//Main Information
Title := '';
@@ -1024,22 +1209,21 @@ begin
Edition := 'Unknown';
Language := 'Unknown'; //Language Patch
+ // set to default encoding
+ Encoding := DEFAULT_ENCODING;
+
//Required Information
- Mp3 := '';
- {$IFDEF FPC}
- setlength( BPM, 0 );
- {$ELSE}
- BPM := nil;
- {$ENDIF}
+ Mp3 := PATH_NONE;
+ SetLength(BPM, 0);
GAP := 0;
Start := 0;
Finish := 0;
//Additional Information
- Background := '';
- Cover := '';
- Video := '';
+ Background := PATH_NONE;
+ Cover := PATH_NONE;
+ Video := PATH_NONE;
VideoGAP := 0;
NotesGAP := 0;
Resolution := 4;
@@ -1049,7 +1233,8 @@ begin
end;
function TSong.Analyse(): boolean;
-
+var
+ SongFile: TTextFileStream;
begin
Result := false;
@@ -1057,20 +1242,15 @@ begin
FileLineNo := 0;
//Open File and set File Pointer to the beginning
- AssignFile(SongFile, self.Path + self.FileName);
-
+ SongFile := TMemTextFileStream.Create(Self.Path.Append(Self.FileName), fmOpenRead);
try
- Reset(SongFile);
-
//Clear old Song Header
- self.clear;
+ Self.clear;
//Read Header
- Result := self.ReadTxTHeader( FileName )
-
- //And Close File
+ Result := Self.ReadTxTHeader(SongFile)
finally
- CloseFile(SongFile);
+ SongFile.Free;
end;
end;
diff --git a/src/base/USongs.pas b/src/base/USongs.pas
index c4871f18..49b84425 100644
--- a/src/base/USongs.pas
+++ b/src/base/USongs.pas
@@ -40,32 +40,35 @@ 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;
type
+ TSongFilter = (
+ fltAll,
+ fltTitle,
+ fltArtist
+ );
TBPM = record
BPM: real;
@@ -73,11 +76,13 @@ type
end;
TScore = record
- Name: widestring;
+ Name: UTF8String;
Score: integer;
Length: string;
end;
+ TPathDynArray = array of IPath;
+
{$IFDEF USE_PSEUDO_THREAD}
TSongs = class(TPseudoThread)
{$ELSE}
@@ -102,11 +107,11 @@ 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 FindFilesByExtension(const Dir: IPath; const Ext: IPath; Recursive: Boolean; var Files: TPathDynArray);
+ 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;
@@ -128,7 +133,7 @@ type
function VisibleSongs: integer; // returns number of visible songs (for tabs)
function VisibleIndex(Index: integer): integer; // returns visible song index (skips invisible)
- function SetFilter(FilterStr: string; const fType: byte): cardinal;
+ function SetFilter(FilterStr: UTF8String; Filter: TSongFilter): cardinal;
end;
var
@@ -156,9 +161,12 @@ uses
UCovers,
UFiles,
UGraphic,
+ UMain,
UIni,
- UPath,
- UNote;
+ UPathUtils,
+ UNote,
+ UFilesystem,
+ UUnicodeUtils;
constructor TSongs.Create();
begin
@@ -232,7 +240,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;
@@ -264,84 +272,92 @@ 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.FindFilesByExtension(const Dir: IPath; const Ext: IPath; Recursive: Boolean; var Files: TPathDynArray);
var
- i: integer;
- Files: TDirectoryEntryArray;
- lSong: TSong;
+ Iter: IFileIterator;
+ FileInfo: TFileInfo;
+ FileName: IPath;
begin
-
- try
- Files := Platform.DirectoryFindFiles(Dir, '.txt', true)
- except
- Log.LogError('Couldn''t deal with directory/file: ' + Dir + ' in TSongs.BrowseTXTFiles')
- end;
-
- for i := 0 to Length(Files) - 1 do
+ // search for all files and directories
+ Iter := FileSystem.FileFind(Dir.Append('*'), faAnyFile);
+ while (Iter.HasNext) do
begin
- if Files[i].IsDirectory then
+ FileInfo := Iter.Next;
+ FileName := FileInfo.Name;
+ if ((FileInfo.Attr and faDirectory) <> 0) then
begin
- BrowseTXTFiles(Dir + Files[i].Name + PathDelim); //Recursive Call
+ if Recursive and (not FileName.Equals('.')) and (not FileName.Equals('..')) then
+ FindFilesByExtension(Dir.Append(FileName), Ext, true, Files);
end
else
begin
- lSong := TSong.create(Dir + Files[i].Name);
-
- if lSong.Analyse then
- SongList.add(lSong)
- else
+ if (Ext.Equals(FileName.GetExtension(), true)) then
begin
- Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".');
- freeandnil(lSong);
+ SetLength(Files, Length(Files)+1);
+ Files[High(Files)] := Dir.Append(FileName);
end;
-
end;
end;
- SetLength(Files, 0);
-
end;
-procedure TSongs.BrowseXMLFiles(Dir: widestring);
+procedure TSongs.BrowseTXTFiles(Dir: IPath);
var
- i: integer;
- Files: TDirectoryEntryArray;
- lSong: TSong;
+ I: integer;
+ Files: TPathDynArray;
+ Song: TSong;
+ Extension: IPath;
begin
+ SetLength(Files, 0);
+ Extension := Path('.txt');
+ FindFilesByExtension(Dir, Extension, true, Files);
- try
- Files := Platform.DirectoryFindFiles(Dir, '.xml', true)
- except
- Log.LogError('Couldn''t deal with directory/file: ' + Dir + ' in TSongs.BrowseXMLFiles')
- end;
-
- for i := 0 to Length(Files) - 1 do
+ for I := 0 to High(Files) do
begin
- if Files[i].IsDirectory then
- begin
- BrowseXMLFiles(Dir + Files[i].Name + PathDelim); // Recursive Call
- end
+ Song := TSong.Create(Files[I]);
+
+ if Song.Analyse then
+ SongList.Add(Song)
else
begin
- lSong := TSong.create(Dir + Files[i].Name);
+ Log.LogError('AnalyseFile failed for "' + Files[I].ToNative + '".');
+ FreeAndNil(Song);
+ end;
+ end;
- if lSong.AnalyseXML then
- SongList.add(lSong)
- else
- begin
- Log.LogError('AnalyseFile failed for "' + Files[i].Name + '".');
- freeandnil(lSong);
- end;
+ SetLength(Files, 0);
+end;
+
+procedure TSongs.BrowseXMLFiles(Dir: IPath);
+var
+ I: integer;
+ Files: TPathDynArray;
+ Song: TSong;
+ Extension: IPath;
+begin
+ SetLength(Files, 0);
+ Extension := Path('.xml');
+ FindFilesByExtension(Dir, Extension, true, Files);
+
+ for I := 0 to High(Files) do
+ begin
+ Song := TSong.Create(Files[I]);
+ if Song.AnalyseXML then
+ SongList.Add(Song)
+ else
+ begin
+ Log.LogError('AnalyseFile failed for "' + Files[I].ToNative + '".');
+ FreeAndNil(Song);
end;
end;
- SetLength(Files, 0);
+ SetLength(Files, 0);
end;
(*
@@ -350,32 +366,32 @@ end;
function CompareByEdition(Song1, Song2: Pointer): integer;
begin
- Result := CompareText(TSong(Song1).Edition, TSong(Song2).Edition);
+ Result := UTF8CompareText(TSong(Song1).Edition, TSong(Song2).Edition);
end;
function CompareByGenre(Song1, Song2: Pointer): integer;
begin
- Result := CompareText(TSong(Song1).Genre, TSong(Song2).Genre);
+ Result := UTF8CompareText(TSong(Song1).Genre, TSong(Song2).Genre);
end;
function CompareByTitle(Song1, Song2: Pointer): integer;
begin
- Result := CompareText(TSong(Song1).Title, TSong(Song2).Title);
+ Result := UTF8CompareText(TSong(Song1).Title, TSong(Song2).Title);
end;
function CompareByArtist(Song1, Song2: Pointer): integer;
begin
- Result := CompareText(TSong(Song1).Artist, TSong(Song2).Artist);
+ Result := UTF8CompareText(TSong(Song1).Artist, TSong(Song2).Artist);
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;
begin
- Result := CompareText(TSong(Song1).Language, TSong(Song2).Language);
+ Result := UTF8CompareText(TSong(Song1).Language, TSong(Song2).Language);
end;
procedure TSongs.Sort(Order: integer);
@@ -412,18 +428,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
@@ -469,14 +473,14 @@ procedure TCatSongs.Refresh;
var
SongIndex: integer;
CurSong: TSong;
- CatIndex: integer; // index of current song in Song
- Letter: char; // current letter for sorting using letter
- CurCategory: string; // current edition for sorting using edition, genre etc.
- Order: integer; // number used for ordernum
- LetterTmp: char;
- CatNumber: integer; // Number of Song in Category
-
- procedure AddCategoryButton(const CategoryName: string);
+ CatIndex: integer; // index of current song in Song
+ Letter: UCS4Char; // current letter for sorting using letter
+ CurCategory: UTF8String; // current edition for sorting using edition, genre etc.
+ Order: integer; // number used for ordernum
+ LetterTmp: UCS4Char;
+ CatNumber: integer; // Number of Song in Category
+
+ procedure AddCategoryButton(const CategoryName: UTF8String);
var
PrevCatBtnIndex: integer;
begin
@@ -511,7 +515,7 @@ begin
// Note: do NOT set Letter to ' ', otherwise no category-button will be
// created for songs beginning with ' ' if songs of this category exist.
// TODO: trim song-properties so ' ' will not occur as first chararcter.
- Letter := #0;
+ Letter := 0;
// clear song-list
for SongIndex := 0 to Songs.SongList.Count - 1 do
@@ -530,91 +534,110 @@ begin
// if tabs are on, add section buttons for each new section
if (Ini.Tabs = 1) then
begin
- if (Ini.Sorting = sEdition) and
- (CompareText(CurCategory, CurSong.Edition) <> 0) then
- begin
- CurCategory := CurSong.Edition;
-
- // add Category Button
- AddCategoryButton(CurCategory);
- end
-
- else if (Ini.Sorting = sGenre) and
- (CompareText(CurCategory, CurSong.Genre) <> 0) then
- begin
- CurCategory := CurSong.Genre;
- // add Genre Button
- AddCategoryButton(CurCategory);
- end
-
- else if (Ini.Sorting = sLanguage) and
- (CompareText(CurCategory, CurSong.Language) <> 0) then
- begin
- CurCategory := CurSong.Language;
- // add Language Button
- AddCategoryButton(CurCategory);
- end
+ case (Ini.Sorting) of
+ sEdition: begin
+ if (CompareText(CurCategory, CurSong.Edition) <> 0) then
+ begin
+ CurCategory := CurSong.Edition;
+
+ // add Category Button
+ AddCategoryButton(CurCategory);
+ end;
+ end;
- else if (Ini.Sorting = sTitle) and
- (Length(CurSong.Title) >= 1) and
- (Letter <> UpperCase(CurSong.Title)[1]) then
- begin
- Letter := Uppercase(CurSong.Title)[1];
- // add a letter Category Button
- AddCategoryButton(Letter);
- end
+ sGenre: begin
+ if (CompareText(CurCategory, CurSong.Genre) <> 0) then
+ begin
+ CurCategory := CurSong.Genre;
+ // add Genre Button
+ AddCategoryButton(CurCategory);
+ end;
+ end;
- else if (Ini.Sorting = sArtist) and
- (Length(CurSong.Artist) >= 1) and
- (Letter <> UpperCase(CurSong.Artist)[1]) then
- begin
- Letter := UpperCase(CurSong.Artist)[1];
- // add a letter Category Button
- AddCategoryButton(Letter);
- end
+ sLanguage: begin
+ if (CompareText(CurCategory, CurSong.Language) <> 0) then
+ begin
+ CurCategory := CurSong.Language;
+ // add Language Button
+ AddCategoryButton(CurCategory);
+ end
+ end;
- else if (Ini.Sorting = sFolder) and
- (CompareText(CurCategory, CurSong.Folder) <> 0) then
- begin
- CurCategory := CurSong.Folder;
- // add folder tab
- AddCategoryButton(CurCategory);
- end
+ sTitle: begin
+ if (Length(CurSong.Title) >= 1) then
+ begin
+ LetterTmp := UCS4UpperCase(UTF8ToUCS4String(CurSong.Title)[0]);
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
+ end;
- else if (Ini.Sorting = sTitle2) and
- (Length(CurSong.Title) >= 1) then
- begin
- // pack all numbers into a category named '#'
- if (CurSong.Title[1] >= '0') and (CurSong.Title[1] <= '9') then
- LetterTmp := '#'
- else
- LetterTmp := UpperCase(CurSong.Title)[1];
+ sArtist: begin
+ if (Length(CurSong.Artist) >= 1) then
+ begin
+ LetterTmp := UCS4UpperCase(UTF8ToUCS4String(CurSong.Artist)[0]);
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
+ end;
- if (Letter <> LetterTmp) then
- begin
- Letter := LetterTmp;
- // add a letter Category Button
- AddCategoryButton(Letter);
+ sFolder: begin
+ if (UTF8CompareText(CurCategory, CurSong.Folder) <> 0) then
+ begin
+ CurCategory := CurSong.Folder;
+ // add folder tab
+ AddCategoryButton(CurCategory);
+ end;
end;
- end
- else if (Ini.Sorting = sArtist2) and
- (Length(CurSong.Artist)>=1) then
- begin
- // pack all numbers into a category named '#'
- if (CurSong.Artist[1] >= '0') and (CurSong.Artist[1] <= '9') then
- LetterTmp := '#'
- else
- LetterTmp := UpperCase(CurSong.Artist)[1];
+ sTitle2: begin
+ if (Length(CurSong.Title) >= 1) then
+ begin
+ LetterTmp := UTF8ToUCS4String(CurSong.Title)[0];
+ // pack all numbers into a category named '#'
+ if (LetterTmp in [Ord('0') .. Ord('9')]) then
+ LetterTmp := Ord('#')
+ else
+ LetterTmp := UCS4UpperCase(LetterTmp);
+
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
+ end;
- if (Letter <> LetterTmp) then
- begin
- Letter := LetterTmp;
- // add a letter Category Button
- AddCategoryButton(Letter);
+ sArtist2: begin
+ if (Length(CurSong.Artist) >= 1) then
+ begin
+ LetterTmp := UTF8ToUCS4String(CurSong.Artist)[0];
+ // pack all numbers into a category named '#'
+ if (LetterTmp in [Ord('0') .. Ord('9')]) then
+ LetterTmp := Ord('#')
+ else
+ LetterTmp := UCS4UpperCase(LetterTmp);
+
+ if (Letter <> LetterTmp) then
+ begin
+ Letter := LetterTmp;
+ // add a letter Category Button
+ AddCategoryButton(UCS4ToUTF8String(Letter));
+ end;
+ end;
end;
- end;
- end;
+
+ end; // case (Ini.Sorting)
+ end; // if (Ini.Tabs = 1)
CatIndex := Length(Song);
SetLength(Song, CatIndex+1);
@@ -761,58 +784,58 @@ begin
end;
end;
-function TCatSongs.SetFilter(FilterStr: string; const fType: byte): cardinal;
+function TCatSongs.SetFilter(FilterStr: UTF8String; Filter: TSongFilter): cardinal;
var
I, J: integer;
- cString: string;
- SearchStr: array of string;
+ TmpString: UTF8String;
+ WordArray: array of UTF8String;
begin
-{
- fType: 0: All
- 1: Title
- 2: Artist
-}
FilterStr := Trim(FilterStr);
- if FilterStr<>'' then
+ if (FilterStr <> '') then
begin
Result := 0;
- // Create Search Array
- SetLength(SearchStr, 1);
+
+ // initialize word array
+ SetLength(WordArray, 1);
+
+ // Copy words to SearchStr
I := Pos(' ', FilterStr);
while (I <> 0) do
begin
- SetLength(SearchStr, Length(SearchStr) + 1);
- cString := Copy(FilterStr, 1, I - 1);
- if (cString <> ' ') and (cString <> '') then
- SearchStr[High(SearchStr) - 1] := cString;
- Delete (FilterStr, 1, I);
+ WordArray[High(WordArray)] := Copy(FilterStr, 1, I-1);
+ SetLength(WordArray, Length(WordArray) + 1);
- I := Pos (' ', FilterStr);
+ FilterStr := TrimLeft(Copy(FilterStr, I+1, Length(FilterStr)-I));
+ I := Pos(' ', FilterStr);
end;
- // Copy last Word
- if (FilterStr <> ' ') and (FilterStr <> '') then
- SearchStr[High(SearchStr)] := FilterStr;
+
+ // Copy last word
+ WordArray[High(WordArray)] := FilterStr;
for I := 0 to High(Song) do
begin
if not Song[i].Main then
begin
- case fType of
- 0: cString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder;
- 1: cString := Song[I].Title;
- 2: cString := Song[I].Artist;
+ case Filter of
+ fltAll:
+ TmpString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder;
+ fltTitle:
+ TmpString := Song[I].Title;
+ fltArtist:
+ TmpString := Song[I].Artist;
end;
- Song[i].Visible:=true;
- // Look for every Searched Word
- for J := 0 to High(SearchStr) do
+ Song[i].Visible := true;
+ // Look for every searched word
+ for J := 0 to High(WordArray) do
begin
- Song[i].Visible := Song[i].Visible and AnsiContainsText(cString, SearchStr[J])
+ Song[i].Visible := Song[i].Visible and
+ UTF8ContainsText(TmpString, WordArray[J])
end;
if Song[i].Visible then
Inc(Result);
end
else
- Song[i].Visible:=false;
+ Song[i].Visible := false;
end;
CatNumShow := -2;
end
@@ -820,7 +843,7 @@ begin
begin
for i := 0 to High(Song) do
begin
- Song[i].Visible := (Ini.Tabs=1) = Song[i].Main;
+ Song[i].Visible := (Ini.Tabs = 1) = Song[i].Main;
CatNumShow := -1;
end;
Result := 0;
diff --git a/src/base/UTextEncoding.pas b/src/base/UTextEncoding.pas
index 6eec8eec..bb3d0f1a 100644
--- a/src/base/UTextEncoding.pas
+++ b/src/base/UTextEncoding.pas
@@ -19,8 +19,8 @@
* 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 $
+ * $URL$
+ * $Id$
*}
unit UTextEncoding;
@@ -34,114 +34,206 @@ interface
{$I switches.inc}
uses
- SysUtils;
+ SysUtils,
+ UUnicodeUtils;
type
- TEncoding = (encCP1250, encCP1252, encUTF8, encNative);
+ 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)
+ );
-function RecodeString(const Src: string; SrcEncoding: TEncoding): WideString;
+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
- TConversionTable = array[0..127] of WideChar;
+ 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
- // Windows-1250 Central/Eastern Europe (used by Ultrastar)
- CP1250Table: TConversionTable = (
- { $80 }
- #$20AC, #0, #$201A, #0, #$201E, #$2026, #$2020, #$2021,
- #0, #$2030, #$0160, #$2039, #$015A, #$0164, #$017D, #$0179,
- { $90 }
- #0, #$2018, #$2019, #$201C, #$201D, #$2022, #$2013, #$2014,
- #0, #$2122, #$0161, #$203A, #$015B, #$0165, #$017E, #$017A,
- { $A0 }
- #$00A0, #$02C7, #$02D8, #$0141, #$00A4, #$0104, #$00A6, #$00A7,
- #$00A8, #$00A9, #$015E, #$00AB, #$00AC, #$00AD, #$00AE, #$017B,
- { $B0 }
- #$00B0, #$00B1, #$02DB, #$0142, #$00B4, #$00B5, #$00B6, #$00B7,
- #$00B8, #$0105, #$015F, #$00BB, #$013D, #$02DD, #$013E, #$017C,
- { $C0 }
- #$0154, #$00C1, #$00C2, #$0102, #$00C4, #$0139, #$0106, #$00C7,
- #$010C, #$00C9, #$0118, #$00CB, #$011A, #$00CD, #$00CE, #$010E,
- { $D0 }
- #$0110, #$0143, #$0147, #$00D3, #$00D4, #$0150, #$00D6, #$00D7,
- #$0158, #$016E, #$00DA, #$0170, #$00DC, #$00DD, #$0162, #$00DF,
- { $E0 }
- #$0155, #$00E1, #$00E2, #$0103, #$00E4, #$013A, #$0107, #$00E7,
- #$010D, #$00E9, #$0119, #$00EB, #$011B, #$00ED, #$00EE, #$010F,
- { $F0 }
- #$0111, #$0144, #$0148, #$00F3, #$00F4, #$0151, #$00F6, #$00F7,
- #$0159, #$016F, #$00FA, #$0171, #$00FC, #$00FD, #$0163, #$02D9
- );
+ ERROR_CHAR = '?';
- // Windows-1252 Western Europe (used by UltraStar Deluxe < 1.1)
- CP1252Table: TConversionTable = (
- { $80 }
- #$20AC, #0, #$201A, #$0192, #$201E, #$2026, #$2020, #$2021,
- #$02C6, #$2030, #$0160, #$2039, #$0152, #0, #$017D, #0,
- { $90 }
- #0, #$2018, #$2019, #$201C, #$201D, #$2022, #$2013, #$2014,
- #$02DC, #$2122, #$0161, #$203A, #$0153, #0, #$017E, #$0178,
- { $A0 }
- #$00A0, #$00A1, #$00A2, #$00A3, #$00A4, #$00A5, #$00A6, #$00A7,
- #$00A8, #$00A9, #$00AA, #$00AB, #$00AC, #$00AD, #$00AE, #$00AF,
- { $B0 }
- #$00B0, #$00B1, #$00B2, #$00B3, #$00B4, #$00B5, #$00B6, #$00B7,
- #$00B8, #$00B9, #$00BA, #$00BB, #$00BC, #$00BD, #$00BE, #$00BF,
- { $C0 }
- #$00C0, #$00C1, #$00C2, #$00C3, #$00C4, #$00C5, #$00C6, #$00C7,
- #$00C8, #$00C9, #$00CA, #$00CB, #$00CC, #$00CD, #$00CE, #$00CF,
- { $D0 }
- #$00D0, #$00D1, #$00D2, #$00D3, #$00D4, #$00D5, #$00D6, #$00D7,
- #$00D8, #$00D9, #$00DA, #$00DB, #$00DC, #$00DD, #$00DE, #$00DF,
- { $E0 }
- #$00E0, #$00E1, #$00E2, #$00E3, #$00E4, #$00E5, #$00E6, #$00E7,
- #$00E8, #$00E9, #$00EA, #$00EB, #$00EC, #$00ED, #$00EE, #$00EF,
- { $F0 }
- #$00F0, #$00F1, #$00F2, #$00F3, #$00F4, #$00F5, #$00F6, #$00F7,
- #$00F8, #$00F9, #$00FA, #$00FB, #$00FC, #$00FD, #$00FE, #$00FF
- );
+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 Convert(const Src: string; const Table: TConversionTable): WideString;
+function TSingleByteEncoder.Decode(const InStr: RawByteString; out OutStr: UCS4String): boolean;
var
- SrcPos, DstPos: integer;
+ I: integer;
begin
- SetLength(Result, Length(Src));
- DstPos := 1;
- for SrcPos := 1 to Length(Src) do
+ SetLength(OutStr, Length(InStr)+1);
+ Result := true;
+ for I := 1 to Length(InStr) do
begin
- if (Src[SrcPos] < #128) then
- begin
- // copy ASCII char
- Result[DstPos] := Src[SrcPos];
- Inc(DstPos);
- end
- else
+ 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
- // look-up char
- Result[DstPos] := Table[Ord(Src[SrcPos]) - 128];
- // ignore invalid characters
- if (Result[DstPos] <> #0) then
- Inc(DstPos);
+ Result := Encoding;
+ Exit;
end;
end;
- SetLength(Result, DstPos-1);
+ Result := Default;
end;
-function RecodeString(const Src: string; SrcEncoding: TEncoding): WideString;
+function EncodingName(Encoding: TEncoding): AnsiString;
begin
- case SrcEncoding of
- encCP1250:
- Result := Convert(Src, CP1250Table);
- encCP1252:
- Result := Convert(Src, CP1252Table);
- encUTF8:
- Result := UTF8Decode(Src);
- encNative:
- Result := UTF8Decode(AnsiToUtf8(Src));
- end;
+ 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/src/base/UTexture.pas b/src/base/UTexture.pas
index 97f244fe..e477dbb1 100644
--- a/src/base/UTexture.pas
+++ b/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;
@@ -197,7 +198,7 @@ begin
for TextureIndex := 0 to High(Texture) do
begin
CurrentTexture := @Texture[TextureIndex];
- if (CurrentTexture.Name = Name) and
+ if (CurrentTexture.Name.Equals(Name)) and
(CurrentTexture.Typ = Typ) then
begin
// colorized textures must match in their color too
@@ -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/src/base/UThemes.pas b/src/base/UThemes.pas
index 3fd77853..c1a26927 100644
--- a/src/base/UThemes.pas
+++ b/src/base/UThemes.pas
@@ -34,11 +34,12 @@ interface
{$I switches.inc}
uses
- ULog,
IniFiles,
SysUtils,
Classes,
- UTexture;
+ ULog,
+ UTexture,
+ UPath;
type
TRGB = record
@@ -112,7 +113,7 @@ type
Font: integer;
Size: integer;
Align: integer;
- Text: string;
+ Text: UTF8String;
//Reflection
Reflection: boolean;
ReflectionSpacing: real;
@@ -182,7 +183,7 @@ type
showArrows:boolean;
oneItemOnly:boolean;
- Text: string;
+ Text: UTF8String;
ColR, ColG, ColB, Int: real;
DColR, DColG, DColB, DInt: real;
TColR, TColG, TColB, TInt: real;
@@ -236,8 +237,8 @@ type
TextDescription: TThemeText;
TextDescriptionLong: TThemeText;
- Description: array[0..5] of string;
- DescriptionLong: array[0..5] of string;
+ Description: array[0..5] of UTF8String;
+ DescriptionLong: array[0..5] of UTF8String;
end;
TThemeName = class(TThemeBasic)
@@ -354,7 +355,7 @@ type
TextP3RScore: TThemeText;
//Linebonus Translations
- LineBonusText: array [0..8] of string;
+ LineBonusText: array [0..8] of UTF8String;
//Pause Popup
PausePopUp: TThemeStatic;
@@ -421,7 +422,7 @@ type
ButtonExit: TThemeButton;
TextDescription: TThemeText;
- Description: array[0..7] of string;
+ Description: array[0..7] of UTF8String;
end;
TThemeOptionsGame = class(TThemeBasic)
@@ -496,8 +497,8 @@ type
TextDescription: TThemeText;
TextDescriptionLong: TThemeText;
- Description: array[0..5] of string;
- DescriptionLong: array[0..5] of string;
+ Description: array[0..5] of UTF8string;
+ DescriptionLong: array[0..5] of UTF8string;
end;
//Error- and Check-Popup
@@ -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
@@ -700,15 +701,15 @@ type
TextPage: TThemeText;
TextList: AThemeText;
- Description: array[0..3] of string;
- DescriptionR: array[0..3] of string;
- FormatStr: array[0..3] of string;
- PageStr: string;
+ Description: array[0..3] of UTF8String;
+ DescriptionR: array[0..3] of UTF8String;
+ FormatStr: array[0..3] of UTF8String;
+ PageStr: UTF8String;
end;
//Playlist Translations
TThemePlaylist = record
- CatText: string;
+ CatText: UTF8String;
end;
TTheme = class
@@ -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/src/base/UUnicodeUtils.pas b/src/base/UUnicodeUtils.pas
new file mode 100644
index 00000000..37b53a67
--- /dev/null
+++ b/src/base/UUnicodeUtils.pas
@@ -0,0 +1,670 @@
+{* 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 UUnicodeUtils;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+uses
+{$IFDEF MSWINDOWS}
+ Windows,
+{$ENDIF}
+ StrUtils,
+ SysUtils;
+
+type
+ // String with unknown encoding. Introduced with Delphi 2009 and maybe soon
+ // with FPC.
+ RawByteString = AnsiString;
+
+{**
+ * Returns true if the system uses UTF-8 as default string type
+ * (filesystem or API calls).
+ * This is always true on Mac OS X and always false on Win32. On Unix it depends
+ * on the LC_CTYPE setting.
+ * Do not use AnsiToUTF8() or UTF8ToAnsi() if this function returns true.
+ *}
+function IsNativeUTF8(): boolean;
+
+(*
+ * Character classes
+ *)
+
+function IsAlphaChar(ch: WideChar): boolean; overload;
+function IsAlphaChar(ch: UCS4Char): boolean; overload;
+
+function IsNumericChar(ch: WideChar): boolean; overload;
+function IsNumericChar(ch: UCS4Char): boolean; overload;
+
+function IsAlphaNumericChar(ch: WideChar): boolean; overload;
+function IsAlphaNumericChar(ch: UCS4Char): boolean; overload;
+
+function IsPunctuationChar(ch: WideChar): boolean; overload;
+function IsPunctuationChar(ch: UCS4Char): boolean; overload;
+
+function IsControlChar(ch: WideChar): boolean; overload;
+function IsControlChar(ch: UCS4Char): boolean; overload;
+
+function IsPrintableChar(ch: WideChar): boolean; overload;
+function IsPrintableChar(ch: UCS4Char): boolean; overload;
+
+{**
+ * Checks if the given string is a valid UTF-8 string.
+ * If an ANSI encoded string (with char codes >= 128) is passed, the
+ * function will most probably return false, as most ANSI strings sequences
+ * are illegal in UTF-8.
+ *}
+function IsUTF8String(const str: RawByteString): boolean;
+
+{**
+ * Iterates over an UTF-8 encoded string.
+ * StrPtr will be increased to the beginning of the next character on each
+ * call.
+ * Results true if the given string starts with an UTF-8 encoded char.
+ *}
+function NextCharUTF8(var StrPtr: PAnsiChar; out Ch: UCS4Char): boolean;
+
+{**
+ * Deletes Count chars (not bytes) beginning at char- (not byte-) position Index.
+ * Index values start with 1.
+ *}
+procedure UTF8Delete(var Str: UTF8String; Index: Integer; Count: Integer);
+procedure UCS4Delete(var Str: UCS4String; Index: Integer; Count: Integer);
+
+{**
+ * Checks if the string is composed of ASCII characters.
+ *}
+function IsASCIIString(const str: RawByteString): boolean;
+
+{*
+ * String format conversion
+ *}
+
+function UTF8ToUCS4String(const str: UTF8String): UCS4String;
+function UCS4ToUTF8String(const str: UCS4String): UTF8String; overload;
+function UCS4ToUTF8String(ch: UCS4Char): UTF8String; overload;
+
+{**
+ * Returns the number of characters (not bytes) in string str.
+ *}
+function LengthUTF8(const str: UTF8String): integer;
+
+{**
+ * Returns the length of an UCS4String. Note that Length(UCS4String) returns
+ * the length+1 as UCS4Strings are zero-terminated.
+ *}
+function LengthUCS4(const str: UCS4String): integer;
+
+{** @seealso WideCompareStr *}
+function UTF8CompareStr(const S1, S2: UTF8String): integer;
+{** @seealso WideCompareText *}
+function UTF8CompareText(const S1, S2: UTF8String): integer;
+
+function UTF8StartsText(const SubText, Text: UTF8String): boolean;
+
+function UTF8ContainsStr(const Text, SubText: UTF8String): boolean;
+function UTF8ContainsText(const Text, SubText: UTF8String): boolean;
+
+{** @seealso WideUpperCase *}
+function UTF8UpperCase(const str: UTF8String): UTF8String;
+{** @seealso WideCompareText *}
+function UTF8LowerCase(const str: UTF8String): UTF8String;
+
+{**
+ * Converts a UCS-4 char ch to its upper-case representation.
+ *}
+function UCS4UpperCase(ch: UCS4Char): UCS4Char; overload;
+
+{**
+ * Converts a UCS-4 string str to its upper-case representation.
+ *}
+function UCS4UpperCase(const str: UCS4String): UCS4String; overload;
+
+{**
+ * Converts a UCS4Char to an UCS4String.
+ * Note that UCS4Strings are zero-terminated dynamic arrays.
+ *}
+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;
+
+{**
+ * Copies a segment of str starting with Index (0-based) with Count characters.
+ * Note: Do not use Copy() to copy UCS4Strings as the result will not contain
+ * a trailing #0 character and hence is invalid.
+ *}
+function UCS4Copy(const str: UCS4String; Index: Integer = 0; Count: Integer = -1): UCS4String;
+
+(*
+ * Converts a WideString to its upper- or lower-case representation.
+ * Wrapper for WideUpper/LowerCase. Needed because some plattforms have
+ * problems with unicode support.
+ *
+ * Note that characters in UTF-16 might consist of one or two WideChar valus
+ * (see surrogates). So instead of using WideStringUpperCase(ch)[1] for single
+ * character access, convert to UCS-4 where each character is represented by
+ * one UCS4Char.
+ *)
+function WideStringUpperCase(const str: WideString) : WideString; overload;
+function WideStringUpperCase(ch: WideChar): WideString; overload;
+function WideStringLowerCase(const str: WideString): WideString; overload;
+function WideStringLowerCase(ch: WideChar): WideString; overload;
+
+function WideStringReplaceChar(const text: WideString; search, rep: WideChar): WideString;
+
+implementation
+
+{$IFDEF UNIX}
+{$IFNDEF DARWIN}
+const
+ LC_CTYPE = 0;
+
+function setlocale(category: integer; locale: PChar): PChar; cdecl; external 'c';
+{$ENDIF}
+{$ENDIF}
+
+var
+ NativeUTF8: boolean;
+
+procedure InitUnicodeUtils();
+{$IFDEF UNIX}
+{$IFNDEF DARWIN}
+var
+ localeName: PChar;
+{$ENDIF}
+{$ENDIF}
+begin
+ {$IF Defined(DARWIN)}
+ NativeUTF8 := true;
+ {$ELSEIF Defined(MSWindows)}
+ NativeUTF8 := false;
+ {$ELSEIF Defined(UNIX)}
+ // check if locale name contains UTF8 or UTF-8
+ localeName := setlocale(LC_CTYPE, nil);
+ NativeUTF8 := Pos('UTF8', UpperCase(AnsiReplaceStr(localeName, '-', ''))) > 0;
+ {$ELSE}
+ raise Exception.Create('Unknown system');
+ {$IFEND}
+end;
+
+function IsNativeUTF8(): boolean;
+begin
+ Result := NativeUTF8;
+end;
+
+function IsAlphaChar(ch: WideChar): boolean;
+begin
+ {$IFDEF MSWINDOWS}
+ Result := IsCharAlphaW(ch);
+ {$ELSE}
+ // TODO: add chars > 255 (or replace with libxml2 functions?)
+ case ch of
+ 'A'..'Z', // A-Z
+ 'a'..'z', // a-z
+ #170,#181,#186,
+ #192..#214,
+ #216..#246,
+ #248..#255:
+ Result := true;
+ else
+ Result := false;
+ end;
+ {$ENDIF}
+end;
+
+function IsAlphaChar(ch: UCS4Char): boolean;
+begin
+ Result := IsAlphaChar(WideChar(Ord(ch)));
+end;
+
+function IsNumericChar(ch: WideChar): boolean;
+begin
+ // TODO: replace with libxml2 functions?
+ // ignore non-arabic numerals as we do not want to handle them
+ case ch of
+ '0'..'9':
+ Result := true;
+ else
+ Result := false;
+ end;
+end;
+
+function IsNumericChar(ch: UCS4Char): boolean;
+begin
+ Result := IsNumericChar(WideChar(Ord(ch)));
+end;
+
+function IsAlphaNumericChar(ch: WideChar): boolean;
+begin
+ Result := (IsAlphaChar(ch) or IsNumericChar(ch));
+end;
+
+function IsAlphaNumericChar(ch: UCS4Char): boolean;
+begin
+ Result := (IsAlphaChar(ch) or IsNumericChar(ch));
+end;
+
+function IsPunctuationChar(ch: WideChar): boolean;
+begin
+ // TODO: add chars > 255 (or replace with libxml2 functions?)
+ case ch of
+ ' '..'/',':'..'@','['..'`','{'..'~',
+ #160..#191,#215,#247:
+ Result := true;
+ else
+ Result := false;
+ end;
+end;
+
+function IsPunctuationChar(ch: UCS4Char): boolean;
+begin
+ Result := IsPunctuationChar(WideChar(Ord(ch)));
+end;
+
+function IsControlChar(ch: WideChar): boolean;
+begin
+ case ch of
+ #0..#31,
+ #127..#159:
+ Result := true;
+ else
+ Result := false;
+ end;
+end;
+
+function IsControlChar(ch: UCS4Char): boolean;
+begin
+ Result := IsControlChar(WideChar(Ord(ch)));
+end;
+
+function IsPrintableChar(ch: WideChar): boolean;
+begin
+ Result := not IsControlChar(ch);
+end;
+
+function IsPrintableChar(ch: UCS4Char): boolean;
+begin
+ Result := IsPrintableChar(WideChar(Ord(ch)));
+end;
+
+
+function NextCharUTF8(var StrPtr: PAnsiChar; out Ch: UCS4Char): boolean;
+
+ // find the most significant zero bit (Result: [7..-1])
+ function FindZeroMSB(b: byte): integer;
+ var
+ Mask: byte;
+ begin
+ Mask := $80;
+ Result := 7;
+ while (b and Mask <> 0) do
+ begin
+ Mask := Mask shr 1;
+ Dec(Result);
+ end;
+ end;
+
+var
+ ZeroBit: integer;
+ SeqCount: integer; // number of trailing bytes to follow
+const
+ Mask: array[1..3] of byte = ($1F, $0F, $07);
+begin
+ Result := false;
+ SeqCount := 0;
+ Ch := 0;
+
+ while (StrPtr^ <> #0) do
+ begin
+ if (StrPtr^ < #128) then
+ begin
+ // check that no more trailing bytes are expected
+ if (SeqCount = 0) then
+ begin
+ Ch := Ord(StrPtr^);
+ Inc(StrPtr);
+ Result := true;
+ end;
+ Break;
+ end
+ else
+ begin
+ ZeroBit := FindZeroMSB(Ord(StrPtr^));
+ // trailing byte expected
+ if (SeqCount > 0) then
+ begin
+ // check if trailing byte has pattern 10xxxxxx
+ if (ZeroBit <> 6) then
+ begin
+ Inc(StrPtr);
+ Break;
+ end;
+
+ Dec(SeqCount);
+ Ch := (Ch shl 6) or (Ord(StrPtr^) and $3F);
+
+ // check if char is finished
+ if (SeqCount = 0) then
+ begin
+ Inc(StrPtr);
+ Result := true;
+ Break;
+ end;
+ end
+ else // leading byte expected
+ begin
+ // check if pattern is one of 110xxxxx/1110xxxx/11110xxx
+ if (ZeroBit > 5) or (ZeroBit < 3) then
+ begin
+ Inc(StrPtr);
+ Break;
+ end;
+ // calculate number of trailing bytes (1, 2 or 3)
+ SeqCount := 6 - ZeroBit;
+ // extract first part of char
+ Ch := Ord(StrPtr^) and Mask[SeqCount];
+ end;
+ end;
+
+ Inc(StrPtr);
+ end;
+
+ if (not Result) then
+ Ch := Ord('?');
+end;
+
+function IsUTF8String(const str: RawByteString): boolean;
+var
+ Ch: UCS4Char;
+ StrPtr: PAnsiChar;
+begin
+ Result := true;
+ StrPtr := PChar(str);
+ while (StrPtr^ <> #0) do
+ begin
+ if (not NextCharUTF8(StrPtr, Ch)) then
+ begin
+ Result := false;
+ Exit;
+ end;
+ end;
+end;
+
+function IsASCIIString(const str: RawByteString): boolean;
+var
+ I: integer;
+begin
+ for I := 1 to Length(str) do
+ begin
+ if (str[I] >= #128) then
+ begin
+ Result := false;
+ Exit;
+ end;
+ end;
+ Result := true;
+end;
+
+
+function UTF8ToUCS4String(const str: UTF8String): UCS4String;
+begin
+ Result := WideStringToUCS4String(UTF8Decode(str));
+end;
+
+function UCS4ToUTF8String(const str: UCS4String): UTF8String;
+begin
+ Result := UTF8Encode(UCS4StringToWideString(str));
+end;
+
+function UCS4ToUTF8String(ch: UCS4Char): UTF8String;
+begin
+ Result := UCS4ToUTF8String(UCS4CharToString(ch));
+end;
+
+function LengthUTF8(const str: UTF8String): integer;
+begin
+ Result := LengthUCS4(UTF8ToUCS4String(str));
+end;
+
+function LengthUCS4(const str: UCS4String): integer;
+begin
+ Result := High(str);
+ if (Result = -1) then
+ Result := 0;
+end;
+
+function UTF8CompareStr(const S1, S2: UTF8String): integer;
+begin
+ Result := WideCompareStr(UTF8Decode(S1), UTF8Decode(S2));
+end;
+
+function UTF8CompareText(const S1, S2: UTF8String): integer;
+begin
+ Result := WideCompareText(UTF8Decode(S1), UTF8Decode(S2));
+end;
+
+function UTF8StartsStr(const SubText, Text: UTF8String): boolean;
+begin
+ // TODO: use WideSameStr (slower but handles different representations of the same char)?
+ Result := (Pos(SubText, Text) = 1);
+end;
+
+function UTF8StartsText(const SubText, Text: UTF8String): boolean;
+begin
+ // TODO: use WideSameText (slower but handles different representations of the same char)?
+ Result := (Pos(UTF8UpperCase(SubText), UTF8UpperCase(Text)) = 1);
+end;
+
+function UTF8ContainsStr(const Text, SubText: UTF8String): boolean;
+begin
+ Result := Pos(SubText, Text) > 0;
+end;
+
+function UTF8ContainsText(const Text, SubText: UTF8String): boolean;
+begin
+ Result := Pos(UTF8UpperCase(SubText), UTF8UpperCase(Text)) > 0;
+end;
+
+function UTF8UpperCase(const str: UTF8String): UTF8String;
+begin
+ Result := UTF8Encode(WideStringUpperCase(UTF8Decode(str)));
+end;
+
+function UTF8LowerCase(const str: UTF8String): UTF8String;
+begin
+ Result := UTF8Encode(WideStringLowerCase(UTF8Decode(str)));
+end;
+
+function UCS4UpperCase(ch: UCS4Char): UCS4Char;
+begin
+ Result := UCS4UpperCase(UCS4CharToString(ch))[0];
+end;
+
+function UCS4UpperCase(const str: UCS4String): UCS4String;
+begin
+ // convert to upper-case as WideString and convert result back to UCS-4
+ Result := WideStringToUCS4String(
+ WideStringUpperCase(
+ UCS4StringToWideString(str)));
+end;
+
+function UCS4CharToString(ch: UCS4Char): UCS4String;
+begin
+ SetLength(Result, 2);
+ Result[0] := ch;
+ 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));
+end;
+
+function UCS4Copy(const str: UCS4String; Index: Integer; Count: Integer): UCS4String;
+var
+ I: integer;
+ MaxCount: integer;
+begin
+ // calculate max. copy count
+ MaxCount := LengthUCS4(str)-Index;
+ if (MaxCount < 0) then
+ MaxCount := 0;
+ // adjust copy count
+ if (Count > MaxCount) or (Count < 0) then
+ Count := MaxCount;
+
+ // copy (and add zero terminator)
+ SetLength(Result, Count + 1);
+ for I := 0 to Count-1 do
+ Result[I] := str[Index+I];
+ Result[Count] := 0;
+end;
+
+procedure UTF8Delete(var Str: UTF8String; Index: Integer; Count: Integer);
+var
+ StrUCS4: UCS4String;
+begin
+ StrUCS4 := UTF8ToUCS4String(str);
+ UCS4Delete(StrUCS4, Index-1, Count);
+ Str := UCS4ToUTF8String(StrUCS4);
+end;
+
+procedure UCS4Delete(var Str: UCS4String; Index: Integer; Count: Integer);
+var
+ Len: integer;
+ OldStr: UCS4String;
+ I: integer;
+begin
+ Len := LengthUCS4(Str);
+ if (Count <= 0) or (Index < 0) or (Index >= Len) then
+ Exit;
+ if (Index + Count > Len) then
+ Count := Len-Index;
+
+ OldStr := Str;
+ SetLength(Str, Len-Count+1);
+ for I := 0 to Index-1 do
+ Str[I] := OldStr[I];
+ for I := Index+Count to Len-1 do
+ Str[I-Count] := OldStr[I];
+ Str[High(Str)] := 0;
+end;
+
+function WideStringUpperCase(ch: WideChar): WideString;
+begin
+ // If WideChar #0 is converted to a WideString in Delphi, a string with
+ // length 1 and a single char #0 is returned. In FPC an empty (length=0)
+ // string will be returned. This will crash, if a non printable key was
+ // pressed, its char code (#0) is translated to upper-case and the the first
+ // character is accessed with Result[1].
+ // We cannot catch this error in the WideString parameter variant as the string
+ // has length 0 already.
+
+ // Force min. string length of 1
+ if (ch = #0) then
+ Result := #0
+ else
+ Result := WideStringUpperCase(WideString(ch));
+end;
+
+function WideStringUpperCase(const str: WideString): WideString;
+begin
+ // On Linux and MacOSX the cwstring unit is necessary for Unicode function-calls.
+ // Otherwise you will get an EIntOverflow exception (thrown by unimplementedwidestring()).
+ // The Unicode manager cwstring does not work with MacOSX at the moment because
+ // of missing references to iconv.
+ // Note: Should be fixed now
+
+ {.$IFNDEF DARWIN}
+ {.$IFDEF NOIGNORE}
+ Result := WideUpperCase(str)
+ {.$ELSE}
+ //Result := UTF8Decode(UpperCase(UTF8Encode(str)));
+ {.$ENDIF}
+end;
+
+function WideStringLowerCase(ch: WideChar): WideString;
+begin
+ // see WideStringUpperCase
+ if (ch = #0) then
+ Result := #0
+ else
+ Result := WideStringLowerCase(WideString(ch));
+end;
+
+function WideStringLowerCase(const str: WideString): WideString;
+begin
+ // see WideStringUpperCase
+ Result := WideLowerCase(str)
+end;
+
+function WideStringReplaceChar(const text: WideString; search, rep: WideChar): WideString;
+var
+ iPos : integer;
+// sTemp : WideString;
+begin
+(*
+ result := text;
+ iPos := Pos(search, result);
+ while (iPos > 0) do
+ begin
+ sTemp := copy(result, iPos + length(search), length(result));
+ result := copy(result, 1, iPos - 1) + rep + sTEmp;
+ iPos := Pos(search, result);
+ end;
+*)
+ result := text;
+
+ if search = rep then
+ exit;
+
+ for iPos := 1 to length(result) do
+ begin
+ if result[iPos] = search then
+ result[iPos] := rep;
+ end;
+end;
+
+initialization
+ InitUnicodeUtils;
+
+end.
diff --git a/src/base/UXMLSong.pas b/src/base/UXMLSong.pas
index 58b48789..e9751eba 100644
--- a/src/base/UXMLSong.pas
+++ b/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,24 @@ 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
Result := False;
- if FileExists(Filename) then
+ if Filename.IsFile() then
begin
- SSFile := TStringList.Create;
+ ErrorMessage := 'Can''t open melody.xml file';
+ SSFile := TStringList.Create;
+ FileStream := TBinaryFileStream.Create(Filename, fmOpenRead);
try
- ErrorMessage := 'Can''t open melody.xml file';
- SSFile.LoadFromFile(Filename);
+ SSFile.LoadFromStream(FileStream);
+
ErrorMessage := '';
Result := True;
+
I := 0;
SongInfo.CountSentences := 0;
@@ -153,7 +163,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]);
@@ -162,21 +172,24 @@ begin
finally
SSFile.Free;
+ FileStream.Free;
end;
end;
end;
-Function TParser.ParseSongHeader (const Filename: String): Boolean;
-var I: Integer;
+function TParser.ParseSongHeader (const Filename: IPath): Boolean;
+var
+ I: Integer;
+ Stream: TBinaryFileStream;
begin
Result := False;
- if FileExists(Filename) then
+
+ if Filename.IsFile() then
begin
SSFile := TStringList.Create;
- SSFile.Clear;
-
+ Stream := TBinaryFileStream.Create(Filename, fmOpenRead);
try
- SSFile.LoadFromFile(Filename);
+ SSFile.LoadFromStream(Stream);
If (SSFile.Count > 0) then
begin
@@ -207,6 +220,7 @@ begin
finally
SSFile.Free;
+ Stream.Free;
end;
end
else
@@ -569,18 +583,20 @@ begin
Result := true;
end;
-Function TParser.ParseConfigforEdition(const Filename: String): String;
+Function TParser.ParseConfigForEdition(const Filename: IPath): String;
var
txt: TStringlist;
+ Stream: TBinaryFileStream;
I: Integer;
J, K: Integer;
S: String;
begin
Result := '';
- txt := TStringlist.Create;
- try
- txt.LoadFromFile(Filename);
+ Stream := TBinaryFileStream.Create(Filename, fmOpenRead);
+ try
+ txt := TStringlist.Create;
+ txt.LoadFromStream(Stream);
For I := 0 to txt.Count-1 do
begin
S := Trim(txt.Strings[I]);
@@ -600,6 +616,7 @@ begin
Edition := Result;
finally
txt.Free;
+ Stream.Free;
end;
end;
diff --git a/src/encoding/CP1250.inc b/src/encoding/CP1250.inc
new file mode 100644
index 00000000..5628156e
--- /dev/null
+++ b/src/encoding/CP1250.inc
@@ -0,0 +1,236 @@
+{* 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$
+ *}
+
+{*
+ * Windows-1250 Central/Eastern Europe
+ * (used by Ultrastar)
+ *}
+
+type
+ TEncoderCP1250 = class(TSingleByteEncoder)
+ public
+ function GetName(): AnsiString; override;
+ function DecodeChar(InChr: AnsiChar; out OutChr: UCS4Char): boolean; override;
+ function EncodeChar(InChr: UCS4Char; out OutChr: AnsiChar): boolean; override;
+ end;
+
+function TEncoderCP1250.GetName(): AnsiString;
+begin
+ Result := 'CP1250';
+end;
+
+const
+ // Positions marked as #0 are invalid.
+ CP1250Table: array[128..255] of UCS4Char = (
+ { $80 }
+ $20AC, 0, $201A, 0, $201E, $2026, $2020, $2021,
+ 0, $2030, $0160, $2039, $015A, $0164, $017D, $0179,
+ { $90 }
+ 0, $2018, $2019, $201C, $201D, $2022, $2013, $2014,
+ 0, $2122, $0161, $203A, $015B, $0165, $017E, $017A,
+ { $A0 }
+ $00A0, $02C7, $02D8, $0141, $00A4, $0104, $00A6, $00A7,
+ $00A8, $00A9, $015E, $00AB, $00AC, $00AD, $00AE, $017B,
+ { $B0 }
+ $00B0, $00B1, $02DB, $0142, $00B4, $00B5, $00B6, $00B7,
+ $00B8, $0105, $015F, $00BB, $013D, $02DD, $013E, $017C,
+ { $C0 }
+ $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7,
+ $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E,
+ { $D0 }
+ $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7,
+ $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF,
+ { $E0 }
+ $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7,
+ $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F,
+ { $F0 }
+ $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7,
+ $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9
+ );
+
+function TEncoderCP1250.DecodeChar(InChr: AnsiChar; out OutChr: UCS4Char): boolean;
+begin
+ Result := true;
+ if (InChr < #128) then
+ OutChr := UCS4Char(Ord(InChr)) // use Ord() to avoid automatic conversion
+ else
+ begin
+ OutChr := CP1250Table[Ord(InChr)];
+ if (OutChr = 0) then
+ begin
+ Result := false;
+ OutChr := Ord(ERROR_CHAR);
+ end;
+ end;
+end;
+
+function TEncoderCP1250.EncodeChar(InChr: UCS4Char; out OutChr: AnsiChar): boolean;
+begin
+ if (InChr < 128) then
+ begin
+ OutChr := AnsiChar(Ord(InChr));
+ Result := true;
+ end
+ else
+ begin
+ case InChr of
+ $20AC: OutChr := #128;
+ // invalid: #129
+ $201A: OutChr := #130;
+ // invalid: #131
+ $201E: OutChr := #132;
+ $2026: OutChr := #133;
+ $2020: OutChr := #134;
+ $2021: OutChr := #135;
+ // invalid: #136
+ $2030: OutChr := #137;
+ $0160: OutChr := #138;
+ $2039: OutChr := #139;
+ $015A: OutChr := #140;
+ $0164: OutChr := #141;
+ $017D: OutChr := #142;
+ $0179: OutChr := #143;
+ // invalid: #144
+ $2018: OutChr := #145;
+ $2019: OutChr := #146;
+ $201C: OutChr := #147;
+ $201D: OutChr := #148;
+ $2022: OutChr := #149;
+ $2013: OutChr := #150;
+ $2014: OutChr := #151;
+ // invalid: #152
+ $2122: OutChr := #153;
+ $0161: OutChr := #154;
+ $203A: OutChr := #155;
+ $015B: OutChr := #156;
+ $0165: OutChr := #157;
+ $017E: OutChr := #158;
+ $017A: OutChr := #159;
+ $00A0: OutChr := #160;
+ $02C7: OutChr := #161;
+ $02D8: OutChr := #162;
+ $0141: OutChr := #163;
+ $00A4: OutChr := #164;
+ $0104: OutChr := #165;
+ $00A6: OutChr := #166;
+ $00A7: OutChr := #167;
+ $00A8: OutChr := #168;
+ $00A9: OutChr := #169;
+ $015E: OutChr := #170;
+ $00AB: OutChr := #171;
+ $00AC: OutChr := #172;
+ $00AD: OutChr := #173;
+ $00AE: OutChr := #174;
+ $017B: OutChr := #175;
+ $00B0: OutChr := #176;
+ $00B1: OutChr := #177;
+ $02DB: OutChr := #178;
+ $0142: OutChr := #179;
+ $00B4: OutChr := #180;
+ $00B5: OutChr := #181;
+ $00B6: OutChr := #182;
+ $00B7: OutChr := #183;
+ $00B8: OutChr := #184;
+ $0105: OutChr := #185;
+ $015F: OutChr := #186;
+ $00BB: OutChr := #187;
+ $013D: OutChr := #188;
+ $02DD: OutChr := #189;
+ $013E: OutChr := #190;
+ $017C: OutChr := #191;
+ $0154: OutChr := #192;
+ $00C1: OutChr := #193;
+ $00C2: OutChr := #194;
+ $0102: OutChr := #195;
+ $00C4: OutChr := #196;
+ $0139: OutChr := #197;
+ $0106: OutChr := #198;
+ $00C7: OutChr := #199;
+ $010C: OutChr := #200;
+ $00C9: OutChr := #201;
+ $0118: OutChr := #202;
+ $00CB: OutChr := #203;
+ $011A: OutChr := #204;
+ $00CD: OutChr := #205;
+ $00CE: OutChr := #206;
+ $010E: OutChr := #207;
+ $0110: OutChr := #208;
+ $0143: OutChr := #209;
+ $0147: OutChr := #210;
+ $00D3: OutChr := #211;
+ $00D4: OutChr := #212;
+ $0150: OutChr := #213;
+ $00D6: OutChr := #214;
+ $00D7: OutChr := #215;
+ $0158: OutChr := #216;
+ $016E: OutChr := #217;
+ $00DA: OutChr := #218;
+ $0170: OutChr := #219;
+ $00DC: OutChr := #220;
+ $00DD: OutChr := #221;
+ $0162: OutChr := #222;
+ $00DF: OutChr := #223;
+ $0155: OutChr := #224;
+ $00E1: OutChr := #225;
+ $00E2: OutChr := #226;
+ $0103: OutChr := #227;
+ $00E4: OutChr := #228;
+ $013A: OutChr := #229;
+ $0107: OutChr := #230;
+ $00E7: OutChr := #231;
+ $010D: OutChr := #232;
+ $00E9: OutChr := #233;
+ $0119: OutChr := #234;
+ $00EB: OutChr := #235;
+ $011B: OutChr := #236;
+ $00ED: OutChr := #237;
+ $00EE: OutChr := #238;
+ $010F: OutChr := #239;
+ $0111: OutChr := #240;
+ $0144: OutChr := #241;
+ $0148: OutChr := #242;
+ $00F3: OutChr := #243;
+ $00F4: OutChr := #244;
+ $0151: OutChr := #245;
+ $00F6: OutChr := #246;
+ $00F7: OutChr := #247;
+ $0159: OutChr := #248;
+ $016F: OutChr := #249;
+ $00FA: OutChr := #250;
+ $0171: OutChr := #251;
+ $00FC: OutChr := #252;
+ $00FD: OutChr := #253;
+ $0163: OutChr := #254;
+ $02D9: OutChr := #255;
+ else begin
+ OutChr := ERROR_CHAR;
+ Result := false;
+ Exit;
+ end;
+ end;
+ Result := true;
+ end;
+end;
+
diff --git a/src/encoding/CP1252.inc b/src/encoding/CP1252.inc
new file mode 100644
index 00000000..f7d3f8ea
--- /dev/null
+++ b/src/encoding/CP1252.inc
@@ -0,0 +1,122 @@
+{* 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$
+ *}
+
+{*
+ * Windows-1252 Western Europe
+ * (used by UltraStar Deluxe < 1.1)
+ *}
+
+type
+ TEncoderCP1252 = class(TSingleByteEncoder)
+ public
+ function GetName(): AnsiString; override;
+ function DecodeChar(InChr: AnsiChar; out OutChr: UCS4Char): boolean; override;
+ function EncodeChar(InChr: UCS4Char; out OutChr: AnsiChar): boolean; override;
+ end;
+
+function TEncoderCP1252.GetName(): AnsiString;
+begin
+ Result := 'CP1252';
+end;
+
+const
+ // Positions marked as #0 are invalid.
+ CP1252Table: array[128..159] of UCS4Char = (
+ { $80 }
+ $20AC, 0, $201A, $0192, $201E, $2026, $2020, $2021,
+ $02C6, $2030, $0160, $2039, $0152, 0, $017D, 0,
+ { $90 }
+ 0, $2018, $2019, $201C, $201D, $2022, $2013, $2014,
+ $02DC, $2122, $0161, $203A, $0153, 0, $017E, $0178
+ );
+
+function TEncoderCP1252.DecodeChar(InChr: AnsiChar; out OutChr: UCS4Char): boolean;
+begin
+ Result := true;
+ if (InChr < #128) or (InChr >= #160) then
+ OutChr := UCS4Char(Ord(InChr)) // use Ord() to avoid automatic conversion
+ else
+ begin
+ OutChr := CP1252Table[Ord(InChr)];
+ if (OutChr = 0) then
+ begin
+ Result := false;
+ OutChr := Ord(ERROR_CHAR);
+ end;
+ end;
+end;
+
+function TEncoderCP1252.EncodeChar(InChr: UCS4Char; out OutChr: AnsiChar): boolean;
+begin
+ if (InChr < 128) or ((InChr >= 160) and (InChr <= 255)) then
+ begin
+ OutChr := AnsiChar(Ord(InChr));
+ Result := true;
+ end
+ else
+ begin
+ case InChr of
+ $20AC: OutChr := #128;
+ // invalid: #129
+ $201A: OutChr := #130;
+ $0192: OutChr := #131;
+ $201E: OutChr := #132;
+ $2026: OutChr := #133;
+ $2020: OutChr := #134;
+ $2021: OutChr := #135;
+ $02C6: OutChr := #136;
+ $2030: OutChr := #137;
+ $0160: OutChr := #138;
+ $2039: OutChr := #139;
+ $0152: OutChr := #140;
+ // invalid: #141
+ $017D: OutChr := #142;
+ // invalid: #143
+ // invalid: #144
+ $2018: OutChr := #145;
+ $2019: OutChr := #146;
+ $201C: OutChr := #147;
+ $201D: OutChr := #148;
+ $2022: OutChr := #149;
+ $2013: OutChr := #150;
+ $2014: OutChr := #151;
+ $02DC: OutChr := #152;
+ $2122: OutChr := #153;
+ $0161: OutChr := #154;
+ $203A: OutChr := #155;
+ $0153: OutChr := #156;
+ // invalid: #157
+ $017E: OutChr := #158;
+ $0178: OutChr := #159;
+ else begin
+ OutChr := ERROR_CHAR;
+ Result := false;
+ Exit;
+ end;
+ end;
+ Result := true;
+ end;
+end;
+
diff --git a/src/encoding/Locale.inc b/src/encoding/Locale.inc
new file mode 100644
index 00000000..a3cdcebc
--- /dev/null
+++ b/src/encoding/Locale.inc
@@ -0,0 +1,55 @@
+{* 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$
+ *}
+
+{*
+ * Locale
+ *}
+
+type
+ TEncoderLocale = class(TEncoder)
+ public
+ function GetName(): AnsiString; override;
+ function Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean; override;
+ function Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean; override;
+ end;
+
+function TEncoderLocale.GetName(): AnsiString;
+begin
+ Result := 'LOCALE';
+end;
+
+function TEncoderLocale.Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean;
+begin
+ OutStr := WideStringToUCS4String(InStr); // use implicit conversion
+ Result := true;
+end;
+
+function TEncoderLocale.Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean;
+begin
+ OutStr := UCS4StringToWideString(InStr); // use implicit conversion
+ // any way to check for errors?
+ Result := true;
+end;
+
diff --git a/src/encoding/UTF8.inc b/src/encoding/UTF8.inc
new file mode 100644
index 00000000..43eacfbd
--- /dev/null
+++ b/src/encoding/UTF8.inc
@@ -0,0 +1,70 @@
+{* 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$
+ *}
+
+{*
+ * UTF-8
+ *}
+
+type
+ TEncoderUTF8 = class(TEncoder)
+ public
+ function GetName(): AnsiString; override;
+ function Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean; override;
+ function Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean; override;
+ end;
+
+function TEncoderUTF8.GetName(): AnsiString;
+begin
+ Result := 'UTF8';
+end;
+
+function TEncoderUTF8.Decode(const InStr: AnsiString; out OutStr: UCS4String): boolean;
+var
+ I: integer;
+ StrPtr: PAnsiChar;
+begin
+ // UTF8Decode() may crash with FPC < 2.2.2 if the input string is not UTF-8
+ // encoded. Newer versions do not crash but do not signal errors either.
+ // So let's implement this stuff again.
+ Result := true;
+ SetLength(OutStr, Length(InStr)+1);
+ I := 0;
+ StrPtr := PChar(InStr);
+ while (StrPtr^ <> #0) do
+ begin
+ if (not NextCharUTF8(StrPtr, OutStr[I])) then
+ Result := false;;
+ Inc(I);
+ end;
+ SetLength(OutStr, I+1);
+ OutStr[High(OutStr)] := 0;
+end;
+
+function TEncoderUTF8.Encode(const InStr: UCS4String; out OutStr: AnsiString): boolean;
+begin
+ OutStr := UCS4ToUTF8String(InStr);
+ Result := true;
+end;
+
diff --git a/src/lib/FreeImage/FreeBitmap.pas b/src/lib/FreeImage/FreeBitmap.pas
index 4e5f50a4..d32fb5cb 100644
--- a/src/lib/FreeImage/FreeBitmap.pas
+++ b/src/lib/FreeImage/FreeBitmap.pas
@@ -33,7 +33,7 @@ unit FreeBitmap;
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
interface
diff --git a/src/lib/SQLite/SQLite3.pas b/src/lib/SQLite/SQLite3.pas
index 9537606c..7b7207c4 100644
--- a/src/lib/SQLite/SQLite3.pas
+++ b/src/lib/SQLite/SQLite3.pas
@@ -10,7 +10,7 @@ unit SQLite3;
{$IFDEF FPC}
{$MODE DELPHI}
- {$H+} (* use AnsiString *)
+ {$H+} (* use long strings *)
{$PACKENUM 4} (* use 4-byte enums *)
{$PACKRECORDS C} (* C/C++-compatible record packing *)
{$ELSE}
diff --git a/src/lib/TntUnicodeControls/License.txt b/src/lib/TntUnicodeControls/License.txt
new file mode 100644
index 00000000..8ac7f75b
--- /dev/null
+++ b/src/lib/TntUnicodeControls/License.txt
@@ -0,0 +1,11 @@
+TntWare Delphi Unicode Controls
+ http://www.tntware.com/delphicontrols/unicode/
+
+Copyright (c) 2002-2007, Troy Wolbrink (www.tntware.com)
+
+License
+Redistribution and use in binary forms, with or without modification, are permitted. Redistribution and use in source forms, with or without modification, are permitted provided that the redistributions of source code retain the above copyright.
+
+Disclaimer
+This software is provided by the author "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
+
diff --git a/src/lib/TntUnicodeControls/Readme.txt b/src/lib/TntUnicodeControls/Readme.txt
new file mode 100644
index 00000000..a2d8f799
--- /dev/null
+++ b/src/lib/TntUnicodeControls/Readme.txt
@@ -0,0 +1,53 @@
+ ** Tnt Delphi UNICODE Controls Project **
+
+Website: http://tnt.ccci.org/delphi_unicode_controls/
+Email: troy.wolbrink@ccci.org
+
+These controls are provided as-is, with no implied warranty. They are freely available for you to use in your own projects. Please let me know if you have found them helpful. Also, please let me know if you find any bugs or other areas of needed improvement.
+
+
+---Delphi Installation--------------------------
+
+The most simple way to install these components is by opening the appropriate design package in Delphi and clicking on the big "Install" button. For instance, Delphi 5's design package is TntUnicodeVcl_D50.dpk.
+
+For BCB 2006 and newer, open the appropriate design package in the packages\bcbx\ folder using the Delphi personality. After compiling and installing, you should be able to use the components in both the Delphi and BCB personality. Remember to set the library path in menu "Tools->Options" for both the C++ Builder and the Delphi.
+
+
+---A note on fonts----------------------
+
+The default TFont uses "MS Sans Serif" which doesn't work well with most non-ANSI characters. I'd recommend using a TrueType font such as "Tahoma" if it is installed on the machine. To make TFont use a different font like "Tahoma" add this to the first line in the project:
+
+ Graphics.DefFontData.Name := 'Tahoma';
+
+You might have to include "Graphics" in the file's uses clauses. Furthermore, adding this line of code to the project will cause the changed setting to only be applied at runtime, not at design time. To make a designtime change, you'd have to add this line to the initialization section of a unit in a design package.
+
+Regarding the IDE, I use GExperts to change the font of the Object Inspector. The Wide String List editor uses the font used by the object inspector.
+
+Also keep in mind that the font used by certain message boxes come from that set by Windows' Display properties.
+
+
+---Background----------------------------
+
+Designing software for an international audience, I've always wanted to write a full UNICODE application. My approach so far, has been to write Unicode on the inside, and MBCS on the outside. This has always been frustrating, because (even on Windows NT/2000/XP which provide native Unicode window controls) the WideStrings inside my application and databases were always confined to an ANSI VCL. And, since the VCL was designed to wrap the low-level Windows details, why shouldn't the VCL hide the fact that sometimes native Unicode controls are not possible on the given version of Windows. I believe the VCL should be written with a Unicode interface, even if it must (at times) deal with an ANSI operating system. For example, TEdit should expose Text as a WideString, even if it has to convert the WideString to an AnsiString on the Windows 9X platform.
+
+In the past, the ANSI VCL may have made a little sense, considering that there were many more users of Windows 9X, than Windows NT. There would have been some performance penalty to use WideStrings on the Windows 9X platform. But with the faster computers of today, and with more people using platforms such as Windows 2000 and Windows XP, the ANSI VCL just doesn't make sense anymore. In fact, having to use the the ANSI VCL on Windows NT/2000/XP is slower because of the constant conversion to and from UNICODE inside Windows.
+
+My coding signature is Tnt. I will use this to denote my classes from others.
+
+For more information about me: <http://home.ccci.org/wolbrink/>
+Some of my software projects (all written in Delphi).
+ TntMPD (contact manager for missionaries)
+ <http://www.tntmpd.com/>
+ Jesus Film Screen Saver
+ <http://home.ccci.org/wolbrink/screensaver.htm>
+ ActiveX SCR control
+ <http://tnt.ccci.org/download/activex_scr/ActiveXSCR.exe>
+
+---Design Goals----------------------------
+
+I want the controls to work on Windows 95, 98, ME, NT, 2000, XP, etc. I want a single EXE for all platforms. Of course, full UNICODE support is only truly available on NT/2000/XP. In other words, the controls should automatically scale to take advantage of native Unicode support when possible.
+
+I want the controls to inherit from the Delphi VCL. I want to reuse as much code as possible. For the most part this makes sense. The only sticky part is where text messages get passed around. But I believe I've gotten past this through strategic subclassing at various points in the message flow chain. To give a rough comparison of why this is so important, check out the following chart which compares the lines of code in the VCL for a given control (4,397 in all), and the lines of code required in my descendent controls (655 in all). Besides saving lines of code, I get the advantage of automatically inheriting new features as new versions of Delphi come out. One such example is the AlphaBlending feature in the Delphi 6 TForm. Even though I use Delphi 5 now, I won't have to add any code to get this new feature.
+
+---More Interesting Information----------------------------
+Case Study: Porting an MFC Application to Unicode: It looks like the FrontPage 2002 team did the roughly the same thing to MFC as what I'm doing to the VCL. They did this with the same goal in mind: to support Unicode as much as possible depending on the support offered by Windows. Another goal was "Don’t abandon MFC; don’t rewrite app". Because they still want to support Windows 9X using the same worldwide EXE used everywhere. They couldn't just compile with the _UNICODE directive. They had to start with the ANSI MFC, strategically subclassing window procedures at just the right places. Hmmm... sounds familiar. \ No newline at end of file
diff --git a/src/lib/TntUnicodeControls/TntClasses.pas b/src/lib/TntUnicodeControls/TntClasses.pas
new file mode 100644
index 00000000..be043421
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntClasses.pas
@@ -0,0 +1,1799 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntClasses;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+interface
+
+{ TODO: Consider: TTntRegIniFile, TTntMemIniFile (consider if UTF8 fits into this solution). }
+
+{***********************************************}
+{ WideChar-streaming implemented by Maël Hörz }
+{***********************************************}
+
+uses
+ Classes, SysUtils, Windows,
+ {$IFNDEF COMPILER_10_UP}
+ TntWideStrings,
+ {$ELSE}
+ WideStrings,
+ {$ENDIF}
+ ActiveX, Contnrs;
+
+// ......... introduced .........
+type
+ TTntStreamCharSet = (csAnsi, csUnicode, csUnicodeSwapped, csUtf8);
+
+function AutoDetectCharacterSet(Stream: TStream): TTntStreamCharSet;
+
+//---------------------------------------------------------------------------------------------
+// Tnt - Classes
+//---------------------------------------------------------------------------------------------
+
+{TNT-WARN ExtractStrings}
+{TNT-WARN LineStart}
+{TNT-WARN TStringStream} // TODO: Implement a TWideStringStream
+
+// A potential implementation of TWideStringStream can be found at:
+// http://kdsxml.cvs.sourceforge.net/kdsxml/Global/KDSClasses.pas?revision=1.10&view=markup
+
+procedure TntPersistent_AfterInherited_DefineProperties(Filer: TFiler; Instance: TPersistent);
+
+type
+{TNT-WARN TFileStream}
+ TTntFileStream = class(THandleStream)
+ public
+ constructor Create(const FileName: WideString; Mode: Word);
+ destructor Destroy; override;
+ end;
+
+{TNT-WARN TMemoryStream}
+ TTntMemoryStream = class(TMemoryStream{TNT-ALLOW TMemoryStream})
+ public
+ procedure LoadFromFile(const FileName: WideString);
+ procedure SaveToFile(const FileName: WideString);
+ end;
+
+{TNT-WARN TResourceStream}
+ TTntResourceStream = class(TCustomMemoryStream)
+ private
+ HResInfo: HRSRC;
+ HGlobal: THandle;
+ procedure Initialize(Instance: THandle; Name, ResType: PWideChar);
+ public
+ constructor Create(Instance: THandle; const ResName: WideString; ResType: PWideChar);
+ constructor CreateFromID(Instance: THandle; ResID: Word; ResType: PWideChar);
+ destructor Destroy; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ procedure SaveToFile(const FileName: WideString);
+ end;
+
+ TTntStrings = class;
+
+{TNT-WARN TAnsiStrings}
+ TAnsiStrings{TNT-ALLOW TAnsiStrings} = class(TStrings{TNT-ALLOW TStrings})
+ public
+ procedure LoadFromFile(const FileName: WideString); reintroduce;
+ procedure SaveToFile(const FileName: WideString); reintroduce;
+ procedure LoadFromFileEx(const FileName: WideString; CodePage: Cardinal);
+ procedure SaveToFileEx(const FileName: WideString; CodePage: Cardinal);
+ procedure LoadFromStreamEx(Stream: TStream; CodePage: Cardinal); virtual; abstract;
+ procedure SaveToStreamEx(Stream: TStream; CodePage: Cardinal); virtual; abstract;
+ end;
+
+ TAnsiStringsForWideStringsAdapter = class(TAnsiStrings{TNT-ALLOW TAnsiStrings})
+ private
+ FWideStrings: TTntStrings;
+ FAdapterCodePage: Cardinal;
+ protected
+ function Get(Index: Integer): AnsiString; override;
+ procedure Put(Index: Integer; const S: AnsiString); override;
+ function GetCount: Integer; override;
+ function GetObject(Index: Integer): TObject; override;
+ procedure PutObject(Index: Integer; AObject: TObject); override;
+ procedure SetUpdateState(Updating: Boolean); override;
+ function AdapterCodePage: Cardinal; dynamic;
+ public
+ constructor Create(AWideStrings: TTntStrings; _AdapterCodePage: Cardinal = 0);
+ procedure Clear; override;
+ procedure Delete(Index: Integer); override;
+ procedure Insert(Index: Integer; const S: AnsiString); override;
+ procedure LoadFromStreamEx(Stream: TStream; CodePage: Cardinal); override;
+ procedure SaveToStreamEx(Stream: TStream; CodePage: Cardinal); override;
+ end;
+
+{TNT-WARN TStrings}
+ TTntStrings = class(TWideStrings)
+ private
+ FLastFileCharSet: TTntStreamCharSet;
+ FAnsiStrings: TAnsiStrings{TNT-ALLOW TAnsiStrings};
+ procedure SetAnsiStrings(const Value: TAnsiStrings{TNT-ALLOW TAnsiStrings});
+ procedure ReadData(Reader: TReader);
+ procedure ReadDataUTF7(Reader: TReader);
+ procedure ReadDataUTF8(Reader: TReader);
+ procedure WriteDataUTF7(Writer: TWriter);
+ protected
+ procedure DefineProperties(Filer: TFiler); override;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ procedure LoadFromFile(const FileName: WideString); override;
+ procedure LoadFromStream(Stream: TStream); override;
+ procedure LoadFromStream_BOM(Stream: TStream; WithBOM: Boolean); virtual;
+
+ procedure SaveToFile(const FileName: WideString); override;
+ procedure SaveToStream(Stream: TStream); override;
+ procedure SaveToStream_BOM(Stream: TStream; WithBOM: Boolean); virtual;
+
+ property LastFileCharSet: TTntStreamCharSet read FLastFileCharSet;
+ published
+ property AnsiStrings: TAnsiStrings{TNT-ALLOW TAnsiStrings} read FAnsiStrings write SetAnsiStrings stored False;
+ end;
+
+{ TTntStringList class }
+
+ TTntStringList = class;
+ TWideStringListSortCompare = function(List: TTntStringList; Index1, Index2: Integer): Integer;
+
+{TNT-WARN TStringList}
+ TTntStringList = class(TTntStrings)
+ private
+ FUpdating: Boolean;
+ FList: PWideStringItemList;
+ FCount: Integer;
+ FCapacity: Integer;
+ FSorted: Boolean;
+ FDuplicates: TDuplicates;
+ FCaseSensitive: Boolean;
+ FOnChange: TNotifyEvent;
+ FOnChanging: TNotifyEvent;
+ procedure ExchangeItems(Index1, Index2: Integer);
+ procedure Grow;
+ procedure QuickSort(L, R: Integer; SCompare: TWideStringListSortCompare);
+ procedure SetSorted(Value: Boolean);
+ procedure SetCaseSensitive(const Value: Boolean);
+ protected
+ procedure Changed; virtual;
+ procedure Changing; virtual;
+ function Get(Index: Integer): WideString; override;
+ function GetCapacity: Integer; override;
+ function GetCount: Integer; override;
+ function GetObject(Index: Integer): TObject; override;
+ procedure Put(Index: Integer; const S: WideString); override;
+ procedure PutObject(Index: Integer; AObject: TObject); override;
+ procedure SetCapacity(NewCapacity: Integer); override;
+ procedure SetUpdateState(Updating: Boolean); override;
+ function CompareStrings(const S1, S2: WideString): Integer; override;
+ procedure InsertItem(Index: Integer; const S: WideString; AObject: TObject); virtual;
+ public
+ destructor Destroy; override;
+ function Add(const S: WideString): Integer; override;
+ function AddObject(const S: WideString; AObject: TObject): Integer; override;
+ procedure Clear; override;
+ procedure Delete(Index: Integer); override;
+ procedure Exchange(Index1, Index2: Integer); override;
+ function Find(const S: WideString; var Index: Integer): Boolean; virtual;
+ function IndexOf(const S: WideString): Integer; override;
+ function IndexOfName(const Name: WideString): Integer; override;
+ procedure Insert(Index: Integer; const S: WideString); override;
+ procedure InsertObject(Index: Integer; const S: WideString;
+ AObject: TObject); override;
+ procedure Sort; virtual;
+ procedure CustomSort(Compare: TWideStringListSortCompare); virtual;
+ property Duplicates: TDuplicates read FDuplicates write FDuplicates;
+ property Sorted: Boolean read FSorted write SetSorted;
+ property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
+ end;
+
+// ......... introduced .........
+type
+ TListTargetCompare = function (Item, Target: Pointer): Integer;
+
+function FindSortedListByTarget(List: TList; TargetCompare: TListTargetCompare;
+ Target: Pointer; var Index: Integer): Boolean;
+
+function ClassIsRegistered(const clsid: TCLSID): Boolean;
+
+var
+ RuntimeUTFStreaming: Boolean;
+
+type
+ TBufferedAnsiString = class(TObject)
+ private
+ FStringBuffer: AnsiString;
+ LastWriteIndex: Integer;
+ public
+ procedure Clear;
+ procedure AddChar(const wc: AnsiChar);
+ procedure AddString(const s: AnsiString);
+ procedure AddBuffer(Buff: PAnsiChar; Chars: Integer);
+ function Value: AnsiString;
+ function BuffPtr: PAnsiChar;
+ end;
+
+ TBufferedWideString = class(TObject)
+ private
+ FStringBuffer: WideString;
+ LastWriteIndex: Integer;
+ public
+ procedure Clear;
+ procedure AddChar(const wc: WideChar);
+ procedure AddString(const s: WideString);
+ procedure AddBuffer(Buff: PWideChar; Chars: Integer);
+ function Value: WideString;
+ function BuffPtr: PWideChar;
+ end;
+
+ TBufferedStreamReader = class(TStream)
+ private
+ FStream: TStream;
+ FStreamSize: Integer;
+ FBuffer: array of Byte;
+ FBufferSize: Integer;
+ FBufferStartPosition: Integer;
+ FVirtualPosition: Integer;
+ procedure UpdateBufferFromPosition(StartPos: Integer);
+ public
+ constructor Create(Stream: TStream; BufferSize: Integer = 1024);
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ end;
+
+// "synced" wide string
+type TSetAnsiStrEvent = procedure(const Value: AnsiString) of object;
+function GetSyncedWideString(var WideStr: WideString; const AnsiStr: AnsiString): WideString;
+procedure SetSyncedWideString(const Value: WideString; var WideStr: WideString;
+ const AnsiStr: AnsiString; SetAnsiStr: TSetAnsiStrEvent);
+
+type
+ TWideComponentHelper = class(TComponent)
+ private
+ FComponent: TComponent;
+ protected
+ procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ constructor CreateHelper(AOwner: TComponent; ComponentHelperList: TComponentList);
+ end;
+
+function FindWideComponentHelper(ComponentHelperList: TComponentList; Component: TComponent): TWideComponentHelper;
+
+implementation
+
+uses
+ RTLConsts, ComObj, Math,
+ Registry, TypInfo, TntSystem, TntSysUtils;
+
+{ TntPersistent }
+
+//===========================================================================
+// The Delphi 5 Classes.pas never supported the streaming of WideStrings.
+// The Delphi 6 Classes.pas supports WideString streaming. But it's too bad that
+// the Delphi 6 IDE doesn't use the updated Classes.pas. Switching between Form/Text
+// mode corrupts extended characters in WideStrings even under Delphi 6.
+// Delphi 7 seems to finally get right. But let's keep the UTF7 support at design time
+// to enable sharing source code with previous versions of Delphi.
+//
+// The purpose of this solution is to store WideString properties which contain
+// non-ASCII chars in the form of UTF7 under the old property name + '_UTF7'.
+//
+// Special thanks go to Francisco Leong for helping to develop this solution.
+//
+
+{ TTntWideStringPropertyFiler }
+type
+ TTntWideStringPropertyFiler = class
+ private
+ FInstance: TPersistent;
+ FPropInfo: PPropInfo;
+ procedure ReadDataUTF8(Reader: TReader);
+ procedure ReadDataUTF7(Reader: TReader);
+ procedure WriteDataUTF7(Writer: TWriter);
+ public
+ procedure DefineProperties(Filer: TFiler; Instance: TPersistent; PropName: AnsiString);
+ end;
+
+function ReaderNeedsUtfHelp(Reader: TReader): Boolean;
+begin
+ if Reader.Owner = nil then
+ Result := False { designtime - visual form inheritance ancestor }
+ else if csDesigning in Reader.Owner.ComponentState then
+ {$IFDEF COMPILER_7_UP}
+ Result := False { Delphi 7+: designtime - doesn't need UTF help. }
+ {$ELSE}
+ Result := True { Delphi 6: designtime - always needs UTF help. }
+ {$ENDIF}
+ else
+ Result := RuntimeUTFStreaming; { runtime }
+end;
+
+procedure TTntWideStringPropertyFiler.ReadDataUTF8(Reader: TReader);
+begin
+ if ReaderNeedsUtfHelp(Reader) then
+ SetWideStrProp(FInstance, FPropInfo, UTF8ToWideString(Reader.ReadString))
+ else
+ Reader.ReadString; { do nothing with Result }
+end;
+
+procedure TTntWideStringPropertyFiler.ReadDataUTF7(Reader: TReader);
+begin
+ if ReaderNeedsUtfHelp(Reader) then
+ SetWideStrProp(FInstance, FPropInfo, UTF7ToWideString(Reader.ReadString))
+ else
+ Reader.ReadString; { do nothing with Result }
+end;
+
+procedure TTntWideStringPropertyFiler.WriteDataUTF7(Writer: TWriter);
+begin
+ Writer.WriteString(WideStringToUTF7(GetWideStrProp(FInstance, FPropInfo)));
+end;
+
+procedure TTntWideStringPropertyFiler.DefineProperties(Filer: TFiler; Instance: TPersistent;
+ PropName: AnsiString);
+
+ {$IFNDEF COMPILER_7_UP}
+ function HasData: Boolean;
+ var
+ CurrPropValue: WideString;
+ begin
+ // must be stored
+ Result := IsStoredProp(Instance, FPropInfo);
+ if Result
+ and (Filer.Ancestor <> nil)
+ and (GetPropInfo(Filer.Ancestor, PropName, [tkWString]) <> nil) then
+ begin
+ // must be different than ancestor
+ CurrPropValue := GetWideStrProp(Instance, FPropInfo);
+ Result := CurrPropValue <> GetWideStrProp(Filer.Ancestor, GetPropInfo(Filer.Ancestor, PropName));
+ end;
+ if Result then begin
+ // must be non-blank and different than UTF8 (implies all ASCII <= 127)
+ CurrPropValue := GetWideStrProp(Instance, FPropInfo);
+ Result := (CurrPropValue <> '') and (WideStringToUTF8(CurrPropValue) <> CurrPropValue);
+ end;
+ end;
+ {$ENDIF}
+
+begin
+ FInstance := Instance;
+ FPropInfo := GetPropInfo(Instance, PropName, [tkWString]);
+ if FPropInfo <> nil then begin
+ // must be published (and of type WideString)
+ Filer.DefineProperty(PropName + 'W', ReadDataUTF8, nil, False);
+ {$IFDEF COMPILER_7_UP}
+ Filer.DefineProperty(PropName + '_UTF7', ReadDataUTF7, WriteDataUTF7, False);
+ {$ELSE}
+ Filer.DefineProperty(PropName + '_UTF7', ReadDataUTF7, WriteDataUTF7, HasData);
+ {$ENDIF}
+ end;
+ FInstance := nil;
+ FPropInfo := nil;
+end;
+
+{ TTntWideCharPropertyFiler }
+type
+ TTntWideCharPropertyFiler = class
+ private
+ FInstance: TPersistent;
+ FPropInfo: PPropInfo;
+ {$IFNDEF COMPILER_9_UP}
+ FWriter: TWriter;
+ procedure GetLookupInfo(var Ancestor: TPersistent;
+ var Root, LookupRoot, RootAncestor: TComponent);
+ {$ENDIF}
+ procedure ReadData_W(Reader: TReader);
+ procedure ReadDataUTF7(Reader: TReader);
+ procedure WriteData_W(Writer: TWriter);
+ function ReadChar(Reader: TReader): WideChar;
+ public
+ procedure DefineProperties(Filer: TFiler; Instance: TPersistent; PropName: AnsiString);
+ end;
+
+{$IFNDEF COMPILER_9_UP}
+type
+ TGetLookupInfoEvent = procedure(var Ancestor: TPersistent;
+ var Root, LookupRoot, RootAncestor: TComponent) of object;
+
+function AncestorIsValid(Ancestor: TPersistent; Root, RootAncestor: TComponent): Boolean;
+begin
+ Result := (Ancestor <> nil) and (RootAncestor <> nil) and
+ Root.InheritsFrom(RootAncestor.ClassType);
+end;
+
+function IsDefaultOrdPropertyValue(Instance: TObject; PropInfo: PPropInfo;
+ OnGetLookupInfo: TGetLookupInfoEvent): Boolean;
+var
+ Ancestor: TPersistent;
+ LookupRoot: TComponent;
+ RootAncestor: TComponent;
+ Root: TComponent;
+ AncestorValid: Boolean;
+ Value: Longint;
+ Default: LongInt;
+begin
+ Ancestor := nil;
+ Root := nil;
+ LookupRoot := nil;
+ RootAncestor := nil;
+
+ if Assigned(OnGetLookupInfo) then
+ OnGetLookupInfo(Ancestor, Root, LookupRoot, RootAncestor);
+
+ AncestorValid := AncestorIsValid(Ancestor, Root, RootAncestor);
+
+ Result := True;
+ if (PropInfo^.GetProc <> nil) and (PropInfo^.SetProc <> nil) then
+ begin
+ Value := GetOrdProp(Instance, PropInfo);
+ if AncestorValid then
+ Result := Value = GetOrdProp(Ancestor, PropInfo)
+ else
+ begin
+ Default := PPropInfo(PropInfo)^.Default;
+ Result := (Default <> LongInt($80000000)) and (Value = Default);
+ end;
+ end;
+end;
+
+procedure TTntWideCharPropertyFiler.GetLookupInfo(var Ancestor: TPersistent;
+ var Root, LookupRoot, RootAncestor: TComponent);
+begin
+ Ancestor := FWriter.Ancestor;
+ Root := FWriter.Root;
+ LookupRoot := FWriter.LookupRoot;
+ RootAncestor := FWriter.RootAncestor;
+end;
+{$ENDIF}
+
+function TTntWideCharPropertyFiler.ReadChar(Reader: TReader): WideChar;
+var
+ Temp: WideString;
+begin
+ case Reader.NextValue of
+ vaWString:
+ Temp := Reader.ReadWideString;
+ vaString:
+ Temp := Reader.ReadString;
+ else
+ raise EReadError.Create(SInvalidPropertyValue);
+ end;
+
+ if Length(Temp) > 1 then
+ raise EReadError.Create(SInvalidPropertyValue);
+ Result := Temp[1];
+end;
+
+procedure TTntWideCharPropertyFiler.ReadData_W(Reader: TReader);
+begin
+ SetOrdProp(FInstance, FPropInfo, Ord(ReadChar(Reader)));
+end;
+
+procedure TTntWideCharPropertyFiler.ReadDataUTF7(Reader: TReader);
+var
+ S: WideString;
+begin
+ S := UTF7ToWideString(Reader.ReadString);
+ if S = '' then
+ SetOrdProp(FInstance, FPropInfo, 0)
+ else
+ SetOrdProp(FInstance, FPropInfo, Ord(S[1]))
+end;
+
+type TAccessWriter = class(TWriter);
+
+procedure TTntWideCharPropertyFiler.WriteData_W(Writer: TWriter);
+var
+ L: Integer;
+ Temp: WideString;
+begin
+ Temp := WideChar(GetOrdProp(FInstance, FPropInfo));
+
+ {$IFNDEF FPC}
+ TAccessWriter(Writer).WriteValue(vaWString);
+ {$ELSE}
+ TAccessWriter(Writer).Write(vaWString, SizeOf(vaWString));
+ {$ENDIF}
+ L := Length(Temp);
+ Writer.Write(L, SizeOf(Integer));
+ Writer.Write(Pointer(@Temp[1])^, L * 2);
+end;
+
+procedure TTntWideCharPropertyFiler.DefineProperties(Filer: TFiler;
+ Instance: TPersistent; PropName: AnsiString);
+
+ {$IFNDEF COMPILER_9_UP}
+ function HasData: Boolean;
+ var
+ CurrPropValue: Integer;
+ begin
+ // must be stored
+ Result := IsStoredProp(Instance, FPropInfo);
+ if Result and (Filer.Ancestor <> nil) and
+ (GetPropInfo(Filer.Ancestor, PropName, [tkWChar]) <> nil) then
+ begin
+ // must be different than ancestor
+ CurrPropValue := GetOrdProp(Instance, FPropInfo);
+ Result := CurrPropValue <> GetOrdProp(Filer.Ancestor, GetPropInfo(Filer.Ancestor, PropName));
+ end;
+ if Result and (Filer is TWriter) then
+ begin
+ FWriter := TWriter(Filer);
+ Result := not IsDefaultOrdPropertyValue(Instance, FPropInfo, GetLookupInfo);
+ end;
+ end;
+ {$ENDIF}
+
+begin
+ FInstance := Instance;
+ FPropInfo := GetPropInfo(Instance, PropName, [tkWChar]);
+ if FPropInfo <> nil then
+ begin
+ // must be published (and of type WideChar)
+ {$IFDEF COMPILER_9_UP}
+ Filer.DefineProperty(PropName + 'W', ReadData_W, WriteData_W, False);
+ {$ELSE}
+ Filer.DefineProperty(PropName + 'W', ReadData_W, WriteData_W, HasData);
+ {$ENDIF}
+ Filer.DefineProperty(PropName + '_UTF7', ReadDataUTF7, nil, False);
+ end;
+ FInstance := nil;
+ FPropInfo := nil;
+end;
+
+procedure TntPersistent_AfterInherited_DefineProperties(Filer: TFiler; Instance: TPersistent);
+var
+ I, Count: Integer;
+ PropInfo: PPropInfo;
+ PropList: PPropList;
+ WideStringFiler: TTntWideStringPropertyFiler;
+ WideCharFiler: TTntWideCharPropertyFiler;
+begin
+ Count := GetTypeData(Instance.ClassInfo)^.PropCount;
+ if Count > 0 then
+ begin
+ WideStringFiler := TTntWideStringPropertyFiler.Create;
+ try
+ WideCharFiler := TTntWideCharPropertyFiler.Create;
+ try
+ GetMem(PropList, Count * SizeOf(Pointer));
+ try
+ GetPropInfos(Instance.ClassInfo, PropList);
+ for I := 0 to Count - 1 do
+ begin
+ PropInfo := PropList^[I];
+ if (PropInfo = nil) then
+ break;
+ if (PropInfo.PropType^.Kind = tkWString) then
+ WideStringFiler.DefineProperties(Filer, Instance, PropInfo.Name)
+ else if (PropInfo.PropType^.Kind = tkWChar) then
+ WideCharFiler.DefineProperties(Filer, Instance, PropInfo.Name)
+ end;
+ finally
+ FreeMem(PropList, Count * SizeOf(Pointer));
+ end;
+ finally
+ WideCharFiler.Free;
+ end;
+ finally
+ WideStringFiler.Free;
+ end;
+ end;
+end;
+
+{ TTntFileStream }
+
+{$IFDEF FPC}
+ {$DEFINE HAS_SFCREATEERROREX}
+{$ENDIF}
+{$IFDEF DELPHI_7_UP}
+ {$DEFINE HAS_SFCREATEERROREX}
+{$ENDIF}
+
+constructor TTntFileStream.Create(const FileName: WideString; Mode: Word);
+var
+ CreateHandle: Integer;
+ {$IFDEF HAS_SFCREATEERROREX}
+ ErrorMessage: WideString;
+ {$ENDIF}
+begin
+ if Mode = fmCreate then
+ begin
+ CreateHandle := WideFileCreate(FileName);
+ if CreateHandle < 0 then begin
+ {$IFDEF HAS_SFCREATEERROREX}
+ ErrorMessage := WideSysErrorMessage(GetLastError);
+ raise EFCreateError.CreateFmt(SFCreateErrorEx, [WideExpandFileName(FileName), ErrorMessage]);
+ {$ELSE}
+ raise EFCreateError.CreateFmt(SFCreateError, [WideExpandFileName(FileName)]);
+ {$ENDIF}
+ end;
+ end else
+ begin
+ CreateHandle := WideFileOpen(FileName, Mode);
+ if CreateHandle < 0 then begin
+ {$IFDEF HAS_SFCREATEERROREX}
+ ErrorMessage := WideSysErrorMessage(GetLastError);
+ raise EFOpenError.CreateFmt(SFOpenErrorEx, [WideExpandFileName(FileName), ErrorMessage]);
+ {$ELSE}
+ raise EFOpenError.CreateFmt(SFOpenError, [WideExpandFileName(FileName)]);
+ {$ENDIF}
+ end;
+ end;
+ inherited Create(CreateHandle);
+end;
+
+destructor TTntFileStream.Destroy;
+begin
+ if Handle >= 0 then FileClose(Handle);
+end;
+
+{ TTntMemoryStream }
+
+procedure TTntMemoryStream.LoadFromFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TTntMemoryStream.SaveToFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+{ TTntResourceStream }
+
+constructor TTntResourceStream.Create(Instance: THandle; const ResName: WideString;
+ ResType: PWideChar);
+begin
+ inherited Create;
+ Initialize(Instance, PWideChar(ResName), ResType);
+end;
+
+constructor TTntResourceStream.CreateFromID(Instance: THandle; ResID: Word;
+ ResType: PWideChar);
+begin
+ inherited Create;
+ Initialize(Instance, PWideChar(ResID), ResType);
+end;
+
+procedure TTntResourceStream.Initialize(Instance: THandle; Name, ResType: PWideChar);
+
+ procedure Error;
+ begin
+ raise EResNotFound.CreateFmt(SResNotFound, [Name]);
+ end;
+
+begin
+ HResInfo := FindResourceW(Instance, Name, ResType);
+ if HResInfo = 0 then Error;
+ HGlobal := LoadResource(Instance, HResInfo);
+ if HGlobal = 0 then Error;
+ SetPointer(LockResource(HGlobal), SizeOfResource(Instance, HResInfo));
+end;
+
+destructor TTntResourceStream.Destroy;
+begin
+ UnlockResource(HGlobal);
+ FreeResource(HGlobal); { Technically this is not necessary (MS KB #193678) }
+ inherited Destroy;
+end;
+
+function TTntResourceStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ raise EStreamError.CreateRes(PResStringRec(@SCantWriteResourceStreamError));
+end;
+
+procedure TTntResourceStream.SaveToFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+{ TAnsiStrings }
+
+procedure TAnsiStrings{TNT-ALLOW TAnsiStrings}.LoadFromFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TAnsiStrings{TNT-ALLOW TAnsiStrings}.SaveToFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TAnsiStrings{TNT-ALLOW TAnsiStrings}.LoadFromFileEx(const FileName: WideString; CodePage: Cardinal);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStreamEx(Stream, CodePage);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TAnsiStrings{TNT-ALLOW TAnsiStrings}.SaveToFileEx(const FileName: WideString; CodePage: Cardinal);
+var
+ Stream: TStream;
+ Utf8BomPtr: PAnsiChar;
+begin
+ Stream := TTntFileStream.Create(FileName, fmCreate);
+ try
+ if (CodePage = CP_UTF8) then
+ begin
+ Utf8BomPtr := PAnsiChar(UTF8_BOM);
+ Stream.WriteBuffer(Utf8BomPtr^, Length(UTF8_BOM));
+ end;
+ SaveToStreamEx(Stream, CodePage);
+ finally
+ Stream.Free;
+ end;
+end;
+
+{ TAnsiStringsForWideStringsAdapter }
+
+constructor TAnsiStringsForWideStringsAdapter.Create(AWideStrings: TTntStrings; _AdapterCodePage: Cardinal);
+begin
+ inherited Create;
+ FWideStrings := AWideStrings;
+ FAdapterCodePage := _AdapterCodePage;
+end;
+
+function TAnsiStringsForWideStringsAdapter.AdapterCodePage: Cardinal;
+begin
+ if FAdapterCodePage = 0 then
+ Result := TntSystem.DefaultSystemCodePage
+ else
+ Result := FAdapterCodePage;
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.Clear;
+begin
+ FWideStrings.Clear;
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.Delete(Index: Integer);
+begin
+ FWideStrings.Delete(Index);
+end;
+
+function TAnsiStringsForWideStringsAdapter.Get(Index: Integer): AnsiString;
+begin
+ Result := WideStringToStringEx(FWideStrings.Get(Index), AdapterCodePage);
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.Put(Index: Integer; const S: AnsiString);
+begin
+ FWideStrings.Put(Index, StringToWideStringEx(S, AdapterCodePage));
+end;
+
+function TAnsiStringsForWideStringsAdapter.GetCount: Integer;
+begin
+ Result := FWideStrings.GetCount;
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.Insert(Index: Integer; const S: AnsiString);
+begin
+ FWideStrings.Insert(Index, StringToWideStringEx(S, AdapterCodePage));
+end;
+
+function TAnsiStringsForWideStringsAdapter.GetObject(Index: Integer): TObject;
+begin
+ Result := FWideStrings.GetObject(Index);
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.PutObject(Index: Integer; AObject: TObject);
+begin
+ FWideStrings.PutObject(Index, AObject);
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.SetUpdateState(Updating: Boolean);
+begin
+ FWideStrings.SetUpdateState(Updating);
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.LoadFromStreamEx(Stream: TStream; CodePage: Cardinal);
+var
+ Size: Integer;
+ S: AnsiString;
+begin
+ BeginUpdate;
+ try
+ Size := Stream.Size - Stream.Position;
+ SetString(S, nil, Size);
+ Stream.Read(Pointer(S)^, Size);
+ FWideStrings.SetTextStr(StringToWideStringEx(S, CodePage));
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TAnsiStringsForWideStringsAdapter.SaveToStreamEx(Stream: TStream; CodePage: Cardinal);
+var
+ S: AnsiString;
+begin
+ S := WideStringToStringEx(FWideStrings.GetTextStr, CodePage);
+ Stream.WriteBuffer(Pointer(S)^, Length(S));
+end;
+
+{ TTntStrings }
+
+constructor TTntStrings.Create;
+begin
+ inherited;
+ FAnsiStrings := TAnsiStringsForWideStringsAdapter.Create(Self);
+ FLastFileCharSet := csUnicode;
+end;
+
+destructor TTntStrings.Destroy;
+begin
+ FreeAndNil(FAnsiStrings);
+ inherited;
+end;
+
+procedure TTntStrings.SetAnsiStrings(const Value: TAnsiStrings{TNT-ALLOW TAnsiStrings});
+begin
+ FAnsiStrings.Assign(Value);
+end;
+
+procedure TTntStrings.DefineProperties(Filer: TFiler);
+
+ {$IFNDEF COMPILER_7_UP}
+ function DoWrite: Boolean;
+ begin
+ if Filer.Ancestor <> nil then
+ begin
+ Result := True;
+ if Filer.Ancestor is TWideStrings then
+ Result := not Equals(TWideStrings(Filer.Ancestor))
+ end
+ else Result := Count > 0;
+ end;
+
+ function DoWriteAsUTF7: Boolean;
+ var
+ i: integer;
+ begin
+ Result := False;
+ for i := 0 to Count - 1 do begin
+ if (Strings[i] <> '') and (WideStringToUTF8(Strings[i]) <> Strings[i]) then begin
+ Result := True;
+ break; { found a string with non-ASCII chars (> 127) }
+ end;
+ end;
+ end;
+ {$ENDIF}
+
+begin
+ inherited DefineProperties(Filer); { Handles main 'Strings' property.' }
+ Filer.DefineProperty('WideStrings', ReadData, nil, False);
+ Filer.DefineProperty('WideStringsW', ReadDataUTF8, nil, False);
+ {$IFDEF COMPILER_7_UP}
+ Filer.DefineProperty('WideStrings_UTF7', ReadDataUTF7, WriteDataUTF7, False);
+ {$ELSE}
+ Filer.DefineProperty('WideStrings_UTF7', ReadDataUTF7, WriteDataUTF7, DoWrite and DoWriteAsUTF7);
+ {$ENDIF}
+end;
+
+procedure TTntStrings.LoadFromFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ FLastFileCharSet := AutoDetectCharacterSet(Stream);
+ Stream.Position := 0;
+ LoadFromStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TTntStrings.LoadFromStream(Stream: TStream);
+begin
+ LoadFromStream_BOM(Stream, True);
+end;
+
+procedure TTntStrings.LoadFromStream_BOM(Stream: TStream; WithBOM: Boolean);
+var
+ DataLeft: Integer;
+ StreamCharSet: TTntStreamCharSet;
+ SW: WideString;
+ SA: AnsiString;
+begin
+ BeginUpdate;
+ try
+ if WithBOM then
+ StreamCharSet := AutoDetectCharacterSet(Stream)
+ else
+ StreamCharSet := csUnicode;
+ DataLeft := Stream.Size - Stream.Position;
+ if (StreamCharSet in [csUnicode, csUnicodeSwapped]) then
+ begin
+ // BOM indicates Unicode text stream
+ if DataLeft < SizeOf(WideChar) then
+ SW := ''
+ else begin
+ SetLength(SW, DataLeft div SizeOf(WideChar));
+ Stream.Read(PWideChar(SW)^, DataLeft);
+ if StreamCharSet = csUnicodeSwapped then
+ StrSwapByteOrder(PWideChar(SW));
+ end;
+ SetTextStr(SW);
+ end
+ else if StreamCharSet = csUtf8 then
+ begin
+ // BOM indicates UTF-8 text stream
+ SetLength(SA, DataLeft div SizeOf(AnsiChar));
+ Stream.Read(PAnsiChar(SA)^, DataLeft);
+ SetTextStr(UTF8ToWideString(SA));
+ end
+ else
+ begin
+ // without byte order mark it is assumed that we are loading ANSI text
+ SetLength(SA, DataLeft div SizeOf(AnsiChar));
+ Stream.Read(PAnsiChar(SA)^, DataLeft);
+ SetTextStr(SA);
+ end;
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TTntStrings.ReadData(Reader: TReader);
+begin
+ if Reader.NextValue in [vaString, vaLString] then
+ SetTextStr(Reader.ReadString) {JCL compatiblity}
+ else if Reader.NextValue = vaWString then
+ SetTextStr(Reader.ReadWideString) {JCL compatiblity}
+ else begin
+ BeginUpdate;
+ try
+ Clear;
+ Reader.ReadListBegin;
+ while not Reader.EndOfList do
+ if Reader.NextValue in [vaString, vaLString] then
+ Add(Reader.ReadString) {TStrings compatiblity}
+ else
+ Add(Reader.ReadWideString);
+ Reader.ReadListEnd;
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+procedure TTntStrings.ReadDataUTF7(Reader: TReader);
+begin
+ Reader.ReadListBegin;
+ if ReaderNeedsUtfHelp(Reader) then
+ begin
+ BeginUpdate;
+ try
+ Clear;
+ while not Reader.EndOfList do
+ Add(UTF7ToWideString(Reader.ReadString))
+ finally
+ EndUpdate;
+ end;
+ end else begin
+ while not Reader.EndOfList do
+ Reader.ReadString; { do nothing with Result }
+ end;
+ Reader.ReadListEnd;
+end;
+
+procedure TTntStrings.ReadDataUTF8(Reader: TReader);
+begin
+ Reader.ReadListBegin;
+ if ReaderNeedsUtfHelp(Reader)
+ or (Count = 0){ Legacy support where 'WideStrings' was never written in lieu of WideStringsW }
+ then begin
+ BeginUpdate;
+ try
+ Clear;
+ while not Reader.EndOfList do
+ Add(UTF8ToWideString(Reader.ReadString))
+ finally
+ EndUpdate;
+ end;
+ end else begin
+ while not Reader.EndOfList do
+ Reader.ReadString; { do nothing with Result }
+ end;
+ Reader.ReadListEnd;
+end;
+
+procedure TTntStrings.SaveToFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TTntStrings.SaveToStream(Stream: TStream);
+begin
+ SaveToStream_BOM(Stream, True);
+end;
+
+procedure TTntStrings.SaveToStream_BOM(Stream: TStream; WithBOM: Boolean);
+// Saves the currently loaded text into the given stream.
+// WithBOM determines whether to write a byte order mark or not.
+var
+ SW: WideString;
+ BOM: WideChar;
+begin
+ if WithBOM then begin
+ BOM := UNICODE_BOM;
+ Stream.WriteBuffer(BOM, SizeOf(WideChar));
+ end;
+ SW := GetTextStr;
+ Stream.WriteBuffer(PWideChar(SW)^, Length(SW) * SizeOf(WideChar));
+end;
+
+procedure TTntStrings.WriteDataUTF7(Writer: TWriter);
+var
+ I: Integer;
+begin
+ Writer.WriteListBegin;
+ for I := 0 to Count-1 do
+ Writer.WriteString(WideStringToUTF7(Get(I)));
+ Writer.WriteListEnd;
+end;
+
+{ TTntStringList }
+
+destructor TTntStringList.Destroy;
+begin
+ FOnChange := nil;
+ FOnChanging := nil;
+ inherited Destroy;
+ if FCount <> 0 then Finalize(FList^[0], FCount);
+ FCount := 0;
+ SetCapacity(0);
+end;
+
+function TTntStringList.Add(const S: WideString): Integer;
+begin
+ Result := AddObject(S, nil);
+end;
+
+function TTntStringList.AddObject(const S: WideString; AObject: TObject): Integer;
+begin
+ if not Sorted then
+ Result := FCount
+ else
+ if Find(S, Result) then
+ case Duplicates of
+ dupIgnore: Exit;
+ dupError: Error(PResStringRec(@SDuplicateString), 0);
+ end;
+ InsertItem(Result, S, AObject);
+end;
+
+procedure TTntStringList.Changed;
+begin
+ if (not FUpdating) and Assigned(FOnChange) then
+ FOnChange(Self);
+end;
+
+procedure TTntStringList.Changing;
+begin
+ if (not FUpdating) and Assigned(FOnChanging) then
+ FOnChanging(Self);
+end;
+
+procedure TTntStringList.Clear;
+begin
+ if FCount <> 0 then
+ begin
+ Changing;
+ Finalize(FList^[0], FCount);
+ FCount := 0;
+ SetCapacity(0);
+ Changed;
+ end;
+end;
+
+procedure TTntStringList.Delete(Index: Integer);
+begin
+ if (Index < 0) or (Index >= FCount) then Error(PResStringRec(@SListIndexError), Index);
+ Changing;
+ Finalize(FList^[Index]);
+ Dec(FCount);
+ if Index < FCount then
+ System.Move(FList^[Index + 1], FList^[Index],
+ (FCount - Index) * SizeOf(TWideStringItem));
+ Changed;
+end;
+
+procedure TTntStringList.Exchange(Index1, Index2: Integer);
+begin
+ if (Index1 < 0) or (Index1 >= FCount) then Error(PResStringRec(@SListIndexError), Index1);
+ if (Index2 < 0) or (Index2 >= FCount) then Error(PResStringRec(@SListIndexError), Index2);
+ Changing;
+ ExchangeItems(Index1, Index2);
+ Changed;
+end;
+
+procedure TTntStringList.ExchangeItems(Index1, Index2: Integer);
+var
+ Temp: Integer;
+ Item1, Item2: PWideStringItem;
+begin
+ Item1 := @FList^[Index1];
+ Item2 := @FList^[Index2];
+ Temp := Integer(Item1^.FString);
+ Integer(Item1^.FString) := Integer(Item2^.FString);
+ Integer(Item2^.FString) := Temp;
+ Temp := Integer(Item1^.FObject);
+ Integer(Item1^.FObject) := Integer(Item2^.FObject);
+ Integer(Item2^.FObject) := Temp;
+end;
+
+function TTntStringList.Find(const S: WideString; var Index: Integer): Boolean;
+var
+ L, H, I, C: Integer;
+begin
+ Result := False;
+ L := 0;
+ H := FCount - 1;
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ C := CompareStrings(FList^[I].FString, S);
+ if C < 0 then L := I + 1 else
+ begin
+ H := I - 1;
+ if C = 0 then
+ begin
+ Result := True;
+ if Duplicates <> dupAccept then L := I;
+ end;
+ end;
+ end;
+ Index := L;
+end;
+
+function TTntStringList.Get(Index: Integer): WideString;
+begin
+ if (Index < 0) or (Index >= FCount) then Error(PResStringRec(@SListIndexError), Index);
+ Result := FList^[Index].FString;
+end;
+
+function TTntStringList.GetCapacity: Integer;
+begin
+ Result := FCapacity;
+end;
+
+function TTntStringList.GetCount: Integer;
+begin
+ Result := FCount;
+end;
+
+function TTntStringList.GetObject(Index: Integer): TObject;
+begin
+ if (Index < 0) or (Index >= FCount) then Error(PResStringRec(@SListIndexError), Index);
+ Result := FList^[Index].FObject;
+end;
+
+procedure TTntStringList.Grow;
+var
+ Delta: Integer;
+begin
+ if FCapacity > 64 then Delta := FCapacity div 4 else
+ if FCapacity > 8 then Delta := 16 else
+ Delta := 4;
+ SetCapacity(FCapacity + Delta);
+end;
+
+function TTntStringList.IndexOf(const S: WideString): Integer;
+begin
+ if not Sorted then Result := inherited IndexOf(S) else
+ if not Find(S, Result) then Result := -1;
+end;
+
+function TTntStringList.IndexOfName(const Name: WideString): Integer;
+var
+ NameKey: WideString;
+begin
+ if not Sorted then
+ Result := inherited IndexOfName(Name)
+ else begin
+ // use sort to find index more quickly
+ NameKey := Name + NameValueSeparator;
+ Find(NameKey, Result);
+ if (Result < 0) or (Result > Count - 1) then
+ Result := -1
+ else if CompareStrings(NameKey, Copy(Strings[Result], 1, Length(NameKey))) <> 0 then
+ Result := -1
+ end;
+end;
+
+procedure TTntStringList.Insert(Index: Integer; const S: WideString);
+begin
+ InsertObject(Index, S, nil);
+end;
+
+procedure TTntStringList.InsertObject(Index: Integer; const S: WideString;
+ AObject: TObject);
+begin
+ if Sorted then Error(PResStringRec(@SSortedListError), 0);
+ if (Index < 0) or (Index > FCount) then Error(PResStringRec(@SListIndexError), Index);
+ InsertItem(Index, S, AObject);
+end;
+
+procedure TTntStringList.InsertItem(Index: Integer; const S: WideString; AObject: TObject);
+begin
+ Changing;
+ if FCount = FCapacity then Grow;
+ if Index < FCount then
+ System.Move(FList^[Index], FList^[Index + 1],
+ (FCount - Index) * SizeOf(TWideStringItem));
+ with FList^[Index] do
+ begin
+ Pointer(FString) := nil;
+ FObject := AObject;
+ FString := S;
+ end;
+ Inc(FCount);
+ Changed;
+end;
+
+procedure TTntStringList.Put(Index: Integer; const S: WideString);
+begin
+ if Sorted then Error(PResStringRec(@SSortedListError), 0);
+ if (Index < 0) or (Index >= FCount) then Error(PResStringRec(@SListIndexError), Index);
+ Changing;
+ FList^[Index].FString := S;
+ Changed;
+end;
+
+procedure TTntStringList.PutObject(Index: Integer; AObject: TObject);
+begin
+ if (Index < 0) or (Index >= FCount) then Error(PResStringRec(@SListIndexError), Index);
+ Changing;
+ FList^[Index].FObject := AObject;
+ Changed;
+end;
+
+procedure TTntStringList.QuickSort(L, R: Integer; SCompare: TWideStringListSortCompare);
+var
+ I, J, P: Integer;
+begin
+ repeat
+ I := L;
+ J := R;
+ P := (L + R) shr 1;
+ repeat
+ while SCompare(Self, I, P) < 0 do Inc(I);
+ while SCompare(Self, J, P) > 0 do Dec(J);
+ if I <= J then
+ begin
+ ExchangeItems(I, J);
+ if P = I then
+ P := J
+ else if P = J then
+ P := I;
+ Inc(I);
+ Dec(J);
+ end;
+ until I > J;
+ if L < J then QuickSort(L, J, SCompare);
+ L := I;
+ until I >= R;
+end;
+
+procedure TTntStringList.SetCapacity(NewCapacity: Integer);
+begin
+ ReallocMem(FList, NewCapacity * SizeOf(TWideStringItem));
+ FCapacity := NewCapacity;
+end;
+
+procedure TTntStringList.SetSorted(Value: Boolean);
+begin
+ if FSorted <> Value then
+ begin
+ if Value then Sort;
+ FSorted := Value;
+ end;
+end;
+
+procedure TTntStringList.SetUpdateState(Updating: Boolean);
+begin
+ FUpdating := Updating;
+ if Updating then Changing else Changed;
+end;
+
+function WideStringListCompareStrings(List: TTntStringList; Index1, Index2: Integer): Integer;
+begin
+ Result := List.CompareStrings(List.FList^[Index1].FString,
+ List.FList^[Index2].FString);
+end;
+
+procedure TTntStringList.Sort;
+begin
+ CustomSort(WideStringListCompareStrings);
+end;
+
+procedure TTntStringList.CustomSort(Compare: TWideStringListSortCompare);
+begin
+ if not Sorted and (FCount > 1) then
+ begin
+ Changing;
+ QuickSort(0, FCount - 1, Compare);
+ Changed;
+ end;
+end;
+
+function TTntStringList.CompareStrings(const S1, S2: WideString): Integer;
+begin
+ if CaseSensitive then
+ Result := WideCompareStr(S1, S2)
+ else
+ Result := WideCompareText(S1, S2);
+end;
+
+procedure TTntStringList.SetCaseSensitive(const Value: Boolean);
+begin
+ if Value <> FCaseSensitive then
+ begin
+ FCaseSensitive := Value;
+ if Sorted then Sort;
+ end;
+end;
+
+//------------------------- TntClasses introduced procs ----------------------------------
+
+function AutoDetectCharacterSet(Stream: TStream): TTntStreamCharSet;
+var
+ ByteOrderMark: WideChar;
+ BytesRead: Integer;
+ Utf8Test: array[0..2] of AnsiChar;
+begin
+ // Byte Order Mark
+ ByteOrderMark := #0;
+ if (Stream.Size - Stream.Position) >= SizeOf(ByteOrderMark) then begin
+ BytesRead := Stream.Read(ByteOrderMark, SizeOf(ByteOrderMark));
+ if (ByteOrderMark <> UNICODE_BOM) and (ByteOrderMark <> UNICODE_BOM_SWAPPED) then begin
+ ByteOrderMark := #0;
+ Stream.Seek(-BytesRead, soFromCurrent);
+ if (Stream.Size - Stream.Position) >= Length(Utf8Test) * SizeOf(AnsiChar) then begin
+ BytesRead := Stream.Read(Utf8Test[0], Length(Utf8Test) * SizeOf(AnsiChar));
+ if Utf8Test <> UTF8_BOM then
+ Stream.Seek(-BytesRead, soFromCurrent);
+ end;
+ end;
+ end;
+ // Test Byte Order Mark
+ if ByteOrderMark = UNICODE_BOM then
+ Result := csUnicode
+ else if ByteOrderMark = UNICODE_BOM_SWAPPED then
+ Result := csUnicodeSwapped
+ else if Utf8Test = UTF8_BOM then
+ Result := csUtf8
+ else
+ Result := csAnsi;
+end;
+
+function FindSortedListByTarget(List: TList; TargetCompare: TListTargetCompare;
+ Target: Pointer; var Index: Integer): Boolean;
+var
+ L, H, I, C: Integer;
+begin
+ Result := False;
+ L := 0;
+ H := List.Count - 1;
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ C := TargetCompare(List[i], Target);
+ if C < 0 then L := I + 1 else
+ begin
+ H := I - 1;
+ if C = 0 then
+ begin
+ Result := True;
+ L := I;
+ end;
+ end;
+ end;
+ Index := L;
+end;
+
+function ClassIsRegistered(const clsid: TCLSID): Boolean;
+var
+ OleStr: POleStr;
+ Reg: TRegIniFile;
+ Key, Filename: WideString;
+begin
+ // First, check to see if there is a ProgID. This will tell if the
+ // control is registered on the machine. No ProgID, control won't run
+ Result := ProgIDFromCLSID(clsid, OleStr) = S_OK;
+ if not Result then Exit; //Bail as soon as anything goes wrong.
+
+ // Next, make sure that the file is actually there by rooting it out
+ // of the registry
+ Key := WideFormat('\SOFTWARE\Classes\CLSID\%s', [GUIDToString(clsid)]);
+ Reg := TRegIniFile.Create;
+ try
+ Reg.RootKey := HKEY_LOCAL_MACHINE;
+ Result := Reg.OpenKeyReadOnly(Key);
+ if not Result then Exit; // Bail as soon as anything goes wrong.
+
+ FileName := Reg.ReadString('InProcServer32', '', EmptyStr);
+ if (Filename = EmptyStr) then // try another key for the file name
+ begin
+ FileName := Reg.ReadString('InProcServer', '', EmptyStr);
+ end;
+ Result := Filename <> EmptyStr;
+ if not Result then Exit;
+ Result := WideFileExists(Filename);
+ finally
+ Reg.Free;
+ end;
+end;
+
+{ TBufferedAnsiString }
+
+procedure TBufferedAnsiString.Clear;
+begin
+ LastWriteIndex := 0;
+ if Length(FStringBuffer) > 0 then
+ FillChar(FStringBuffer[1], Length(FStringBuffer) * SizeOf(AnsiChar), 0);
+end;
+
+procedure TBufferedAnsiString.AddChar(const wc: AnsiChar);
+const
+ MIN_GROW_SIZE = 32;
+ MAX_GROW_SIZE = 256;
+var
+ GrowSize: Integer;
+begin
+ Inc(LastWriteIndex);
+ if LastWriteIndex > Length(FStringBuffer) then begin
+ GrowSize := Max(MIN_GROW_SIZE, Length(FStringBuffer));
+ GrowSize := Min(GrowSize, MAX_GROW_SIZE);
+ SetLength(FStringBuffer, Length(FStringBuffer) + GrowSize);
+ FillChar(FStringBuffer[LastWriteIndex], GrowSize * SizeOf(AnsiChar), 0);
+ end;
+ FStringBuffer[LastWriteIndex] := wc;
+end;
+
+procedure TBufferedAnsiString.AddString(const s: AnsiString);
+var
+ LenS: Integer;
+ BlockSize: Integer;
+ AllocSize: Integer;
+begin
+ LenS := Length(s);
+ if LenS > 0 then begin
+ Inc(LastWriteIndex);
+ if LastWriteIndex + LenS - 1 > Length(FStringBuffer) then begin
+ // determine optimum new allocation size
+ BlockSize := Length(FStringBuffer) div 2;
+ if BlockSize < 8 then
+ BlockSize := 8;
+ AllocSize := ((LenS div BlockSize) + 1) * BlockSize;
+ // realloc buffer
+ SetLength(FStringBuffer, Length(FStringBuffer) + AllocSize);
+ FillChar(FStringBuffer[Length(FStringBuffer) - AllocSize + 1], AllocSize * SizeOf(AnsiChar), 0);
+ end;
+ CopyMemory(@FStringBuffer[LastWriteIndex], @s[1], LenS * SizeOf(AnsiChar));
+ Inc(LastWriteIndex, LenS - 1);
+ end;
+end;
+
+procedure TBufferedAnsiString.AddBuffer(Buff: PAnsiChar; Chars: Integer);
+var
+ i: integer;
+begin
+ for i := 1 to Chars do begin
+ if Buff^ = #0 then
+ break;
+ AddChar(Buff^);
+ Inc(Buff);
+ end;
+end;
+
+function TBufferedAnsiString.Value: AnsiString;
+begin
+ Result := PAnsiChar(FStringBuffer);
+end;
+
+function TBufferedAnsiString.BuffPtr: PAnsiChar;
+begin
+ Result := PAnsiChar(FStringBuffer);
+end;
+
+{ TBufferedWideString }
+
+procedure TBufferedWideString.Clear;
+begin
+ LastWriteIndex := 0;
+ if Length(FStringBuffer) > 0 then
+ FillChar(FStringBuffer[1], Length(FStringBuffer) * SizeOf(WideChar), 0);
+end;
+
+procedure TBufferedWideString.AddChar(const wc: WideChar);
+const
+ MIN_GROW_SIZE = 32;
+ MAX_GROW_SIZE = 256;
+var
+ GrowSize: Integer;
+begin
+ Inc(LastWriteIndex);
+ if LastWriteIndex > Length(FStringBuffer) then begin
+ GrowSize := Max(MIN_GROW_SIZE, Length(FStringBuffer));
+ GrowSize := Min(GrowSize, MAX_GROW_SIZE);
+ SetLength(FStringBuffer, Length(FStringBuffer) + GrowSize);
+ FillChar(FStringBuffer[LastWriteIndex], GrowSize * SizeOf(WideChar), 0);
+ end;
+ FStringBuffer[LastWriteIndex] := wc;
+end;
+
+procedure TBufferedWideString.AddString(const s: WideString);
+var
+ i: integer;
+begin
+ for i := 1 to Length(s) do
+ AddChar(s[i]);
+end;
+
+procedure TBufferedWideString.AddBuffer(Buff: PWideChar; Chars: Integer);
+var
+ i: integer;
+begin
+ for i := 1 to Chars do begin
+ if Buff^ = #0 then
+ break;
+ AddChar(Buff^);
+ Inc(Buff);
+ end;
+end;
+
+function TBufferedWideString.Value: WideString;
+begin
+ Result := PWideChar(FStringBuffer);
+end;
+
+function TBufferedWideString.BuffPtr: PWideChar;
+begin
+ Result := PWideChar(FStringBuffer);
+end;
+
+{ TBufferedStreamReader }
+
+constructor TBufferedStreamReader.Create(Stream: TStream; BufferSize: Integer = 1024);
+begin
+ // init stream
+ FStream := Stream;
+ FStreamSize := Stream.Size;
+ // init buffer
+ FBufferSize := BufferSize;
+ SetLength(FBuffer, BufferSize);
+ FBufferStartPosition := -FBufferSize; { out of any useful range }
+ // init virtual position
+ FVirtualPosition := 0;
+end;
+
+function TBufferedStreamReader.Seek(Offset: Integer; Origin: Word): Longint;
+begin
+ case Origin of
+ soFromBeginning: FVirtualPosition := Offset;
+ soFromCurrent: Inc(FVirtualPosition, Offset);
+ soFromEnd: FVirtualPosition := FStreamSize + Offset;
+ end;
+ Result := FVirtualPosition;
+end;
+
+procedure TBufferedStreamReader.UpdateBufferFromPosition(StartPos: Integer);
+begin
+ try
+ FStream.Position := StartPos;
+ FStream.Read(FBuffer[0], FBufferSize);
+ FBufferStartPosition := StartPos;
+ except
+ FBufferStartPosition := -FBufferSize; { out of any useful range }
+ raise;
+ end;
+end;
+
+function TBufferedStreamReader.Read(var Buffer; Count: Integer): Longint;
+var
+ BytesLeft: Integer;
+ FirstBufferRead: Integer;
+ StreamDirectRead: Integer;
+ Buf: PAnsiChar;
+begin
+ if (FVirtualPosition >= 0) and (Count >= 0) then
+ begin
+ Result := FStreamSize - FVirtualPosition;
+ if Result > 0 then
+ begin
+ if Result > Count then
+ Result := Count;
+
+ Buf := @Buffer;
+ BytesLeft := Result;
+
+ // try to read what is left in buffer
+ FirstBufferRead := FBufferStartPosition + FBufferSize - FVirtualPosition;
+ if (FirstBufferRead < 0) or (FirstBufferRead > FBufferSize) then
+ FirstBufferRead := 0;
+ FirstBufferRead := Min(FirstBufferRead, Result);
+ if FirstBufferRead > 0 then begin
+ Move(FBuffer[FVirtualPosition - FBufferStartPosition], Buf[0], FirstBufferRead);
+ Dec(BytesLeft, FirstBufferRead);
+ end;
+
+ if BytesLeft > 0 then begin
+ // The first read in buffer was not enough
+ StreamDirectRead := (BytesLeft div FBufferSize) * FBufferSize;
+ FStream.Position := FVirtualPosition + FirstBufferRead;
+ FStream.Read(Buf[FirstBufferRead], StreamDirectRead);
+ Dec(BytesLeft, StreamDirectRead);
+
+ if BytesLeft > 0 then begin
+ // update buffer, and read what is left
+ UpdateBufferFromPosition(FStream.Position);
+ Move(FBuffer[0], Buf[FirstBufferRead + StreamDirectRead], BytesLeft);
+ end;
+ end;
+
+ Inc(FVirtualPosition, Result);
+ Exit;
+ end;
+ end;
+ Result := 0;
+end;
+
+function TBufferedStreamReader.Write(const Buffer; Count: Integer): Longint;
+begin
+ raise ETntInternalError.Create('Internal Error: class can not write.');
+ Result := 0;
+end;
+
+//-------- synced wide string -----------------
+
+function GetSyncedWideString(var WideStr: WideString; const AnsiStr: AnsiString): WideString;
+begin
+ if AnsiString(WideStr) <> (AnsiStr) then begin
+ WideStr := AnsiStr; {AnsiStr changed. Keep WideStr in sync.}
+ end;
+ Result := WideStr;
+end;
+
+procedure SetSyncedWideString(const Value: WideString; var WideStr: WideString;
+ const AnsiStr: AnsiString; SetAnsiStr: TSetAnsiStrEvent);
+begin
+ if Value <> GetSyncedWideString(WideStr, AnsiStr) then
+ begin
+ if (not WideSameStr(Value, AnsiString(Value))) {unicode chars lost in conversion}
+ and (AnsiStr = AnsiString(Value)) {AnsiStr is not going to change}
+ then begin
+ SetAnsiStr(''); {force the change}
+ end;
+ WideStr := Value;
+ SetAnsiStr(Value);
+ end;
+end;
+
+{ TWideComponentHelper }
+
+function CompareComponentHelperToTarget(Item, Target: Pointer): Integer;
+begin
+ if PtrUInt(TWideComponentHelper(Item).FComponent) < PtrUInt(Target) then
+ Result := -1
+ else if PtrUInt(TWideComponentHelper(Item).FComponent) > PtrUInt(Target) then
+ Result := 1
+ else
+ Result := 0;
+end;
+
+function FindWideComponentHelperIndex(ComponentHelperList: TComponentList; Component: TComponent; var Index: Integer): Boolean;
+begin
+ // find Component in sorted wide caption list (list is sorted by TWideComponentHelper.FComponent)
+ Result := FindSortedListByTarget(ComponentHelperList, CompareComponentHelperToTarget, Component, Index);
+end;
+
+constructor TWideComponentHelper.Create(AOwner: TComponent);
+begin
+ raise ETntInternalError.Create('TNT Internal Error: TWideComponentHelper.Create should never be encountered.');
+end;
+
+constructor TWideComponentHelper.CreateHelper(AOwner: TComponent; ComponentHelperList: TComponentList);
+var
+ Index: Integer;
+begin
+ // don't use direct ownership for memory management
+ inherited Create(nil);
+ FComponent := AOwner;
+ FComponent.FreeNotification(Self);
+
+ // insert into list according to sort
+ FindWideComponentHelperIndex(ComponentHelperList, FComponent, Index);
+ ComponentHelperList.Insert(Index, Self);
+end;
+
+procedure TWideComponentHelper.Notification(AComponent: TComponent; Operation: TOperation);
+begin
+ inherited;
+ if (AComponent = FComponent) and (Operation = opRemove) then begin
+ FComponent := nil;
+ Free;
+ end;
+end;
+
+function FindWideComponentHelper(ComponentHelperList: TComponentList; Component: TComponent): TWideComponentHelper;
+var
+ Index: integer;
+begin
+ if FindWideComponentHelperIndex(ComponentHelperList, Component, Index) then begin
+ Result := TWideComponentHelper(ComponentHelperList[Index]);
+ Assert(Result.FComponent = Component, 'TNT Internal Error: FindWideComponentHelperIndex failed.');
+ end else
+ Result := nil;
+end;
+
+initialization
+ RuntimeUTFStreaming := False; { Delphi 6 and higher don't need UTF help at runtime. }
+
+end.
diff --git a/src/lib/TntUnicodeControls/TntCompilers.inc b/src/lib/TntUnicodeControls/TntCompilers.inc
new file mode 100644
index 00000000..06f4d9ab
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntCompilers.inc
@@ -0,0 +1,378 @@
+//----------------------------------------------------------------------------------------------------------------------
+// Include file to determine which compiler is currently being used to build the project/component.
+// This file uses ideas from Brad Stowers DFS.inc file (www.delphifreestuff.com).
+//
+// Portions created by Mike Lischke are Copyright
+// (C) 1999-2002 Dipl. Ing. Mike Lischke. All Rights Reserved.
+//----------------------------------------------------------------------------------------------------------------------
+// The following symbols are defined:
+//
+// COMPILER_1 : Kylix/Delphi/BCB 1.x is the compiler.
+// COMPILER_1_UP : Kylix/Delphi/BCB 1.x or higher is the compiler.
+// COMPILER_2 : Kylix/Delphi 2.x or BCB 1.x is the compiler.
+// COMPILER_2_UP : Kylix/Delphi 2.x or higher, or BCB 1.x or higher is the compiler.
+// COMPILER_3 : Kylix/Delphi/BCB 3.x is the compiler.
+// COMPILER_3_UP : Kylix/Delphi/BCB 3.x or higher is the compiler.
+// COMPILER_4 : Kylix/Delphi/BCB 4.x is the compiler.
+// COMPILER_4_UP : Kylix/Delphi/BCB 4.x or higher is the compiler.
+// COMPILER_5 : Kylix/Delphi/BCB 5.x is the compiler.
+// COMPILER_5_UP : Kylix/Delphi/BCB 5.x or higher is the compiler.
+// COMPILER_6 : Kylix/Delphi/BCB 6.x is the compiler.
+// COMPILER_6_UP : Kylix/Delphi/BCB 6.x or higher is the compiler.
+// COMPILER_7 : Kylix/Delphi/BCB 7.x is the compiler.
+// COMPILER_7_UP : Kylix/Delphi/BCB 7.x or higher is the compiler.
+//
+// Only defined if Windows is the target:
+// CPPB : Any version of BCB is being used.
+// CPPB_1 : BCB v1.x is being used.
+// CPPB_3 : BCB v3.x is being used.
+// CPPB_3_UP : BCB v3.x or higher is being used.
+// CPPB_4 : BCB v4.x is being used.
+// CPPB_4_UP : BCB v4.x or higher is being used.
+// CPPB_5 : BCB v5.x is being used.
+// CPPB_5_UP : BCB v5.x or higher is being used.
+// CPPB_6 : BCB v6.x is being used.
+// CPPB_6_UP : BCB v6.x or higher is being used.
+//
+// Only defined if Windows is the target:
+// DELPHI : Any version of Delphi is being used.
+// DELPHI_1 : Delphi v1.x is being used.
+// DELPHI_2 : Delphi v2.x is being used.
+// DELPHI_2_UP : Delphi v2.x or higher is being used.
+// DELPHI_3 : Delphi v3.x is being used.
+// DELPHI_3_UP : Delphi v3.x or higher is being used.
+// DELPHI_4 : Delphi v4.x is being used.
+// DELPHI_4_UP : Delphi v4.x or higher is being used.
+// DELPHI_5 : Delphi v5.x is being used.
+// DELPHI_5_UP : Delphi v5.x or higher is being used.
+// DELPHI_6 : Delphi v6.x is being used.
+// DELPHI_6_UP : Delphi v6.x or higher is being used.
+// DELPHI_7 : Delphi v7.x is being used.
+// DELPHI_7_UP : Delphi v7.x or higher is being used.
+//
+// Only defined if Linux is the target:
+// KYLIX : Any version of Kylix is being used.
+// KYLIX_1 : Kylix 1.x is being used.
+// KYLIX_1_UP : Kylix 1.x or higher is being used.
+// KYLIX_2 : Kylix 2.x is being used.
+// KYLIX_2_UP : Kylix 2.x or higher is being used.
+// KYLIX_3 : Kylix 3.x is being used.
+// KYLIX_3_UP : Kylix 3.x or higher is being used.
+//
+// Only defined if Linux is the target:
+// QT_CLX : Trolltech's QT library is being used.
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ifdef Win32}
+
+ {$ifdef VER180}
+ {$define COMPILER_10}
+ {$define DELPHI}
+ {$define DELPHI_10}
+ {$endif}
+
+ {$ifdef VER170}
+ {$define COMPILER_9}
+ {$define DELPHI}
+ {$define DELPHI_9}
+ {$endif}
+
+ {$ifdef VER150}
+ {$define COMPILER_7}
+ {$define DELPHI}
+ {$define DELPHI_7}
+ {$endif}
+
+ {$ifdef VER140}
+ {$define COMPILER_6}
+ {$ifdef BCB}
+ {$define CPPB}
+ {$define CPPB_6}
+ {$else}
+ {$define DELPHI}
+ {$define DELPHI_6}
+ {$endif}
+ {$endif}
+
+ {$ifdef VER130}
+ {$define COMPILER_5}
+ {$ifdef BCB}
+ {$define CPPB}
+ {$define CPPB_5}
+ {$else}
+ {$define DELPHI}
+ {$define DELPHI_5}
+ {$endif}
+ {$endif}
+
+ {$ifdef VER125}
+ {$define COMPILER_4}
+ {$define CPPB}
+ {$define CPPB_4}
+ {$endif}
+
+ {$ifdef VER120}
+ {$define COMPILER_4}
+ {$define DELPHI}
+ {$define DELPHI_4}
+ {$endif}
+
+ {$ifdef VER110}
+ {$define COMPILER_3}
+ {$define CPPB}
+ {$define CPPB_3}
+ {$endif}
+
+ {$ifdef VER100}
+ {$define COMPILER_3}
+ {$define DELPHI}
+ {$define DELPHI_3}
+ {$endif}
+
+ {$ifdef VER93}
+ {$define COMPILER_2} // C++ Builder v1 compiler is really v2
+ {$define CPPB}
+ {$define CPPB_1}
+ {$endif}
+
+ {$ifdef VER90}
+ {$define COMPILER_2}
+ {$define DELPHI}
+ {$define DELPHI_2}
+ {$endif}
+
+ {$ifdef VER80}
+ {$define COMPILER_1}
+ {$define DELPHI}
+ {$define DELPHI_1}
+ {$endif}
+
+ {$ifdef FPC}
+ {.$define DELPHI}
+ {$endif}
+
+ {$ifdef DELPHI_2}
+ {$define DELPHI_2_UP}
+ {$endif}
+
+ {$ifdef DELPHI_3}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$endif}
+
+ {$ifdef DELPHI_4}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$endif}
+
+ {$ifdef DELPHI_5}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$endif}
+
+ {$ifdef DELPHI_6}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$define DELPHI_6_UP}
+ {$endif}
+
+ {$ifdef DELPHI_7}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$define DELPHI_6_UP}
+ {$define DELPHI_7_UP}
+ {$endif}
+
+ {$ifdef DELPHI_9}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$define DELPHI_6_UP}
+ {$define DELPHI_7_UP}
+ {$define DELPHI_9_UP}
+ {$endif}
+
+ {$ifdef DELPHI_10}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$define DELPHI_6_UP}
+ {$define DELPHI_7_UP}
+ {$define DELPHI_9_UP}
+ {$define DELPHI_10_UP}
+ {$endif}
+
+ {$ifdef CPPB_3}
+ {$define CPPB_3_UP}
+ {$endif}
+
+ {$ifdef CPPB_4}
+ {$define CPPB_3_UP}
+ {$define CPPB_4_UP}
+ {$endif}
+
+ {$ifdef CPPB_5}
+ {$define CPPB_3_UP}
+ {$define CPPB_4_UP}
+ {$define CPPB_5_UP}
+ {$endif}
+
+ {$ifdef CPPB_6}
+ {$define CPPB_3_UP}
+ {$define CPPB_4_UP}
+ {$define CPPB_5_UP}
+ {$define CPPB_6_UP}
+ {$endif}
+
+ {$ifdef CPPB_3_UP}
+ // C++ Builder requires this if you use Delphi components in run-time packages.
+ {$ObjExportAll On}
+ {$endif}
+
+{$else (not Windows)}
+ // Linux is the target
+ {$define QT_CLX}
+
+ {$define KYLIX}
+ {$define KYLIX_1}
+ {$define KYLIX_1_UP}
+
+ {$ifdef VER150}
+ {$define COMPILER_7}
+ {$define KYLIX_3}
+ {$endif}
+
+ {$ifdef VER140}
+ {$define COMPILER_6}
+ {$define KYLIX_2}
+ {$endif}
+
+ {$ifdef KYLIX_2}
+ {$define KYLIX_2_UP}
+ {$endif}
+
+ {$ifdef KYLIX_3}
+ {$define KYLIX_2_UP}
+ {$define KYLIX_3_UP}
+ {$endif}
+
+{$endif}
+
+// Compiler defines common to all platforms.
+{$ifdef COMPILER_1}
+ {$define COMPILER_1_UP}
+{$endif}
+
+{$ifdef COMPILER_2}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+{$endif}
+
+{$ifdef COMPILER_3}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+{$endif}
+
+{$ifdef COMPILER_4}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+{$endif}
+
+{$ifdef COMPILER_5}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+{$endif}
+
+{$ifdef COMPILER_6}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+ {$define COMPILER_6_UP}
+{$endif}
+
+{$ifdef COMPILER_7}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+ {$define COMPILER_6_UP}
+ {$define COMPILER_7_UP}
+{$endif}
+
+{$ifdef COMPILER_9}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+ {$define COMPILER_6_UP}
+ {$define COMPILER_7_UP}
+ {$define COMPILER_9_UP}
+{$endif}
+
+{$ifdef COMPILER_10}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+ {$define COMPILER_6_UP}
+ {$define COMPILER_7_UP}
+ {$define COMPILER_9_UP}
+ {$define COMPILER_10_UP}
+{$endif}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ALIGN ON}
+{$BOOLEVAL OFF}
+
+{$ifdef COMPILER_7_UP}
+ {$define THEME_7_UP} { Allows experimental theme support on pre-Delphi 7. }
+{$endif}
+
+{$IFDEF COMPILER_6_UP}
+{$WARN SYMBOL_PLATFORM OFF} { We are going to use Win32 specific symbols! }
+{$ENDIF}
+
+{$IFDEF COMPILER_7_UP}
+{$IFDEF FPC}
+ {$DEFINE UNSAFE_WARNINGS_OFF}
+{$ENDIF}
+{$ENDIF}
+
+{$IFDEF UNSAFE_WARNINGS_OFF}
+{$WARN UNSAFE_CODE OFF} { We are not going to be "safe"! }
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$ENDIF}
+
+{$IFDEF FPC}
+{$HINTS OFF}
+{$ENDIF}
+
+{$IFNDEF FPC}
+ // Delphi system function overrides might (not tested) cause problems on
+ // CPUs with code protection (NX-bit). So disable by default.
+ {.$DEFINE USE_SYSTEM_OVERRIDES}
+{$ENDIF}
+
+
diff --git a/src/lib/TntUnicodeControls/TntFormatStrUtils.pas b/src/lib/TntUnicodeControls/TntFormatStrUtils.pas
new file mode 100644
index 00000000..c6b65082
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntFormatStrUtils.pas
@@ -0,0 +1,521 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntFormatStrUtils;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+interface
+
+// this unit provides functions to work with format strings
+
+uses
+ TntSysUtils;
+
+function GetCanonicalFormatStr(const _FormatString: WideString): WideString;
+
+{$IFNDEF FPC}
+{$IFNDEF COMPILER_9_UP}
+function ReplaceFloatingArgumentsInFormatString(const _FormatString: WideString;
+ const Args: array of const
+ {$IFDEF COMPILER_7_UP}; FormatSettings: PFormatSettings{$ENDIF}): WideString;
+{$ENDIF}
+{$ENDIF}
+procedure CompareFormatStrings(FormatStr1, FormatStr2: WideString);
+function FormatStringsAreCompatible(FormatStr1, FormatStr2: WideString): Boolean;
+
+type
+ EFormatSpecError = class(ETntGeneralError);
+
+implementation
+
+uses
+ SysUtils, Math, TntClasses;
+
+resourcestring
+ SInvalidFormatSpecifier = 'Invalid Format Specifier: %s';
+ SMismatchedArgumentTypes = 'Argument types for index %d do not match. (%s <> %s)';
+ SMismatchedArgumentCounts = 'Number of format specifiers do not match.';
+
+type
+ TFormatSpecifierType = (fstInteger, fstFloating, fstPointer, fstString);
+
+function GetFormatSpecifierType(const FormatSpecifier: WideString): TFormatSpecifierType;
+var
+ LastChar: WideChar;
+begin
+ LastChar := TntWideLastChar(FormatSpecifier);
+ case LastChar of
+ 'd', 'D', 'u', 'U', 'x', 'X':
+ result := fstInteger;
+ 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'N', 'm', 'M':
+ result := fstFloating;
+ 'p', 'P':
+ result := fstPointer;
+ 's', 'S':
+ result := fstString
+ else
+ raise ETntInternalError.CreateFmt('Internal Error: Unexpected format type (%s)', [LastChar]);
+ end;
+end;
+
+type
+ TFormatStrParser = class(TObject)
+ private
+ ParsedString: TBufferedWideString;
+ PFormatString: PWideChar;
+ LastIndex: Integer;
+ ExplicitCount: Integer;
+ ImplicitCount: Integer;
+ procedure RaiseInvalidFormatSpecifier;
+ function ParseChar(c: WideChar): Boolean;
+ procedure ForceParseChar(c: WideChar);
+ function ParseDigit: Boolean;
+ function ParseInteger: Boolean;
+ procedure ForceParseType;
+ function PeekDigit: Boolean;
+ function PeekIndexSpecifier(out Index: Integer): Boolean;
+ public
+ constructor Create(const _FormatString: WideString);
+ destructor Destroy; override;
+ function ParseFormatSpecifier: Boolean;
+ end;
+
+constructor TFormatStrParser.Create(const _FormatString: WideString);
+begin
+ inherited Create;
+ PFormatString := PWideChar(_FormatString);
+ ExplicitCount := 0;
+ ImplicitCount := 0;
+ LastIndex := -1;
+ ParsedString := TBufferedWideString.Create;
+end;
+
+destructor TFormatStrParser.Destroy;
+begin
+ FreeAndNil(ParsedString);
+ inherited;
+end;
+
+procedure TFormatStrParser.RaiseInvalidFormatSpecifier;
+begin
+ raise EFormatSpecError.CreateFmt(SInvalidFormatSpecifier, [ParsedString.Value + PFormatString]);
+end;
+
+function TFormatStrParser.ParseChar(c: WideChar): Boolean;
+begin
+ result := False;
+ if PFormatString^ = c then begin
+ result := True;
+ ParsedString.AddChar(c);
+ Inc(PFormatString);
+ end;
+end;
+
+procedure TFormatStrParser.ForceParseChar(c: WideChar);
+begin
+ if not ParseChar(c) then
+ RaiseInvalidFormatSpecifier;
+end;
+
+function TFormatStrParser.PeekDigit: Boolean;
+begin
+ result := False;
+ if (PFormatString^ <> #0)
+ and (PFormatString^ >= '0')
+ and (PFormatString^ <= '9') then
+ result := True;
+end;
+
+function TFormatStrParser.ParseDigit: Boolean;
+begin
+ result := False;
+ if PeekDigit then begin
+ result := True;
+ ForceParseChar(PFormatString^);
+ end;
+end;
+
+function TFormatStrParser.ParseInteger: Boolean;
+const
+ MAX_INT_DIGITS = 6;
+var
+ digitcount: integer;
+begin
+ digitcount := 0;
+ While ParseDigit do begin
+ inc(digitcount);
+ end;
+ result := (digitcount > 0);
+ if digitcount > MAX_INT_DIGITS then
+ RaiseInvalidFormatSpecifier;
+end;
+
+procedure TFormatStrParser.ForceParseType;
+begin
+ if PFormatString^ = #0 then
+ RaiseInvalidFormatSpecifier;
+
+ case PFormatString^ of
+ 'd', 'u', 'x', 'e', 'f', 'g', 'n', 'm', 'p', 's',
+ 'D', 'U', 'X', 'E', 'F', 'G', 'N', 'M', 'P', 'S':
+ begin
+ // do nothing
+ end
+ else
+ RaiseInvalidFormatSpecifier;
+ end;
+ ForceParseChar(PFormatString^);
+end;
+
+function TFormatStrParser.PeekIndexSpecifier(out Index: Integer): Boolean;
+var
+ SaveParsedString: WideString;
+ SaveFormatString: PWideChar;
+begin
+ SaveParsedString := ParsedString.Value;
+ SaveFormatString := PFormatString;
+ try
+ ParsedString.Clear;
+ Result := False;
+ Index := -1;
+ if ParseInteger then begin
+ Index := StrToInt(ParsedString.Value);
+ if ParseChar(':') then
+ Result := True;
+ end;
+ finally
+ ParsedString.Clear;
+ ParsedString.AddString(SaveParsedString);
+ PFormatString := SaveFormatString;
+ end;
+end;
+
+function TFormatStrParser.ParseFormatSpecifier: Boolean;
+var
+ ExplicitIndex: Integer;
+begin
+ Result := False;
+ // Parse entire format specifier
+ ForceParseChar('%');
+ if (PFormatString^ <> #0)
+ and (not ParseChar(' '))
+ and (not ParseChar('%')) then begin
+ if PeekIndexSpecifier(ExplicitIndex) then begin
+ Inc(ExplicitCount);
+ LastIndex := Max(LastIndex, ExplicitIndex);
+ end else begin
+ Inc(ImplicitCount);
+ Inc(LastIndex);
+ ParsedString.AddString(IntToStr(LastIndex));
+ ParsedString.AddChar(':');
+ end;
+ if ParseChar('*') then
+ begin
+ Inc(ImplicitCount);
+ Inc(LastIndex);
+ ParseChar(':');
+ end else if ParseInteger then
+ ParseChar(':');
+ ParseChar('-');
+ if ParseChar('*') then begin
+ Inc(ImplicitCount);
+ Inc(LastIndex);
+ end else
+ ParseInteger;
+ if ParseChar('.') then begin
+ if not ParseChar('*') then
+ ParseInteger;
+ end;
+ ForceParseType;
+ Result := True;
+ end;
+end;
+
+//-----------------------------------
+
+function GetCanonicalFormatStr(const _FormatString: WideString): WideString;
+var
+ PosSpec: Integer;
+begin
+ with TFormatStrParser.Create(_FormatString) do
+ try
+ // loop until no more '%'
+ PosSpec := Pos('%', PFormatString);
+ While PosSpec <> 0 do begin
+ try
+ // delete everything up until '%'
+ ParsedString.AddBuffer(PFormatString, PosSpec - 1);
+ Inc(PFormatString, PosSpec - 1);
+ // parse format specifier
+ ParseFormatSpecifier;
+ finally
+ PosSpec := Pos('%', PFormatString);
+ end;
+ end;
+ if ((ExplicitCount = 0) and (ImplicitCount = 1)) {simple expression}
+ or ((ExplicitCount > 0) and (ImplicitCount = 0)) {nothing converted} then
+ result := _FormatString {original}
+ else
+ result := ParsedString.Value + PFormatString;
+ finally
+ Free;
+ end;
+end;
+
+{$IFNDEF FPC}
+{$IFNDEF COMPILER_9_UP}
+function ReplaceFloatingArgumentsInFormatString(const _FormatString: WideString;
+ const Args: array of const
+ {$IFDEF COMPILER_7_UP}; FormatSettings: PFormatSettings{$ENDIF}): WideString;
+{ This function replaces floating point format specifiers with their actual formatted values.
+ It also adds index specifiers so that the other format specifiers don't lose their place.
+ The reason for this is that WideFormat doesn't correctly format floating point specifiers.
+ See QC#4254. }
+var
+ Parser: TFormatStrParser;
+ PosSpec: Integer;
+ Output: TBufferedWideString;
+begin
+ Output := TBufferedWideString.Create;
+ try
+ Parser := TFormatStrParser.Create(_FormatString);
+ with Parser do
+ try
+ // loop until no more '%'
+ PosSpec := Pos('%', PFormatString);
+ While PosSpec <> 0 do begin
+ try
+ // delete everything up until '%'
+ Output.AddBuffer(PFormatString, PosSpec - 1);
+ Inc(PFormatString, PosSpec - 1);
+ // parse format specifier
+ ParsedString.Clear;
+ if (not ParseFormatSpecifier)
+ or (GetFormatSpecifierType(ParsedString.Value) <> fstFloating) then
+ Output.AddBuffer(ParsedString.BuffPtr, MaxInt)
+ {$IFDEF COMPILER_7_UP}
+ else if Assigned(FormatSettings) then
+ Output.AddString(Format{TNT-ALLOW Format}(ParsedString.Value, Args, FormatSettings^))
+ {$ENDIF}
+ else
+ Output.AddString(Format{TNT-ALLOW Format}(ParsedString.Value, Args));
+ finally
+ PosSpec := Pos('%', PFormatString);
+ end;
+ end;
+ Output.AddString(PFormatString);
+ finally
+ Free;
+ end;
+ Result := Output.Value;
+ finally
+ Output.Free;
+ end;
+end;
+{$ENDIF}
+{$ENDIF}
+
+procedure GetFormatArgs(const _FormatString: WideString; FormatArgs: TTntStrings);
+var
+ PosSpec: Integer;
+begin
+ with TFormatStrParser.Create(_FormatString) do
+ try
+ FormatArgs.Clear;
+ // loop until no more '%'
+ PosSpec := Pos('%', PFormatString);
+ While PosSpec <> 0 do begin
+ try
+ // delete everything up until '%'
+ Inc(PFormatString, PosSpec - 1);
+ // add format specifier to list
+ ParsedString.Clear;
+ if ParseFormatSpecifier then
+ FormatArgs.Add(ParsedString.Value);
+ finally
+ PosSpec := Pos('%', PFormatString);
+ end;
+ end;
+ finally
+ Free;
+ end;
+end;
+
+function GetExplicitIndex(const FormatSpecifier: WideString): Integer;
+var
+ IndexStr: WideString;
+ PosColon: Integer;
+begin
+ result := -1;
+ PosColon := Pos(':', FormatSpecifier);
+ if PosColon <> 0 then begin
+ IndexStr := Copy(FormatSpecifier, 2, PosColon - 2);
+ result := StrToInt(IndexStr);
+ end;
+end;
+
+function GetMaxIndex(FormatArgs: TTntStrings): Integer;
+var
+ i: integer;
+ RunningIndex: Integer;
+ ExplicitIndex: Integer;
+begin
+ result := -1;
+ RunningIndex := -1;
+ for i := 0 to FormatArgs.Count - 1 do begin
+ ExplicitIndex := GetExplicitIndex(FormatArgs[i]);
+ if ExplicitIndex <> -1 then
+ RunningIndex := ExplicitIndex
+ else
+ inc(RunningIndex);
+ result := Max(result, RunningIndex);
+ end;
+end;
+
+function FormatSpecToObject(SpecType: TFormatSpecifierType): TObject;
+begin
+ {$IFNDEF FPC}
+ Result := TObject(SpecType);
+ {$ELSE}
+ Result := Pointer(SpecType);
+ {$ENDIF}
+end;
+
+procedure UpdateTypeList(FormatArgs, TypeList: TTntStrings);
+var
+ i: integer;
+ f: WideString;
+ SpecType: TFormatSpecifierType;
+ ExplicitIndex: Integer;
+ MaxIndex: Integer;
+ RunningIndex: Integer;
+begin
+ // set count of TypeList to accomodate maximum index
+ MaxIndex := GetMaxIndex(FormatArgs);
+ TypeList.Clear;
+ for i := 0 to MaxIndex do
+ TypeList.Add('');
+
+ // for each arg...
+ RunningIndex := -1;
+ for i := 0 to FormatArgs.Count - 1 do begin
+ f := FormatArgs[i];
+ ExplicitIndex := GetExplicitIndex(f);
+ SpecType := GetFormatSpecifierType(f);
+
+ // determine running arg index
+ if ExplicitIndex <> -1 then
+ RunningIndex := ExplicitIndex
+ else
+ inc(RunningIndex);
+
+ if TypeList[RunningIndex] <> '' then begin
+ // already exists in list, check for compatibility
+ if TypeList.Objects[RunningIndex] <> FormatSpecToObject(SpecType) then
+ raise EFormatSpecError.CreateFmt(SMismatchedArgumentTypes,
+ [RunningIndex, TypeList[RunningIndex], f]);
+ end else begin
+ // not in list so update it
+ TypeList[RunningIndex] := f;
+ TypeList.Objects[RunningIndex] := FormatSpecToObject(SpecType);
+ end;
+ end;
+end;
+
+procedure CompareFormatStrings(FormatStr1, FormatStr2: WideString);
+var
+ ArgList1: TTntStringList;
+ ArgList2: TTntStringList;
+ TypeList1: TTntStringList;
+ TypeList2: TTntStringList;
+ i: integer;
+begin
+ ArgList1 := nil;
+ ArgList2 := nil;
+ TypeList1 := nil;
+ TypeList2 := nil;
+ try
+ ArgList1 := TTntStringList.Create;
+ ArgList2 := TTntStringList.Create;
+ TypeList1 := TTntStringList.Create;
+ TypeList2 := TTntStringList.Create;
+
+ GetFormatArgs(FormatStr1, ArgList1);
+ UpdateTypeList(ArgList1, TypeList1);
+
+ GetFormatArgs(FormatStr2, ArgList2);
+ UpdateTypeList(ArgList2, TypeList2);
+
+ if TypeList1.Count <> TypeList2.Count then
+ raise EFormatSpecError.Create(SMismatchedArgumentCounts + CRLF + CRLF + '> ' + FormatStr1 + CRLF + '> ' + FormatStr2);
+
+ for i := 0 to TypeList1.Count - 1 do begin
+ if TypeList1.Objects[i] <> TypeList2.Objects[i] then begin
+ raise EFormatSpecError.CreateFmt(SMismatchedArgumentTypes,
+ [i, TypeList1[i], TypeList2[i]]);
+ end;
+ end;
+
+ finally
+ ArgList1.Free;
+ ArgList2.Free;
+ TypeList1.Free;
+ TypeList2.Free;
+ end;
+end;
+
+function FormatStringsAreCompatible(FormatStr1, FormatStr2: WideString): Boolean;
+var
+ ArgList1: TTntStringList;
+ ArgList2: TTntStringList;
+ TypeList1: TTntStringList;
+ TypeList2: TTntStringList;
+ i: integer;
+begin
+ ArgList1 := nil;
+ ArgList2 := nil;
+ TypeList1 := nil;
+ TypeList2 := nil;
+ try
+ ArgList1 := TTntStringList.Create;
+ ArgList2 := TTntStringList.Create;
+ TypeList1 := TTntStringList.Create;
+ TypeList2 := TTntStringList.Create;
+
+ GetFormatArgs(FormatStr1, ArgList1);
+ UpdateTypeList(ArgList1, TypeList1);
+
+ GetFormatArgs(FormatStr2, ArgList2);
+ UpdateTypeList(ArgList2, TypeList2);
+
+ Result := (TypeList1.Count = TypeList2.Count);
+ if Result then begin
+ for i := 0 to TypeList1.Count - 1 do begin
+ if TypeList1.Objects[i] <> TypeList2.Objects[i] then begin
+ Result := False;
+ break;
+ end;
+ end;
+ end;
+ finally
+ ArgList1.Free;
+ ArgList2.Free;
+ TypeList1.Free;
+ TypeList2.Free;
+ end;
+end;
+
+end.
diff --git a/src/lib/TntUnicodeControls/TntSysUtils.pas b/src/lib/TntUnicodeControls/TntSysUtils.pas
new file mode 100644
index 00000000..b7cf2467
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntSysUtils.pas
@@ -0,0 +1,1753 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntSysUtils;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+interface
+
+{ TODO: Consider: more filename functions from SysUtils }
+{ TODO: Consider: string functions from StrUtils. }
+
+uses
+ Types, SysUtils, Windows, TntWindows;
+
+//---------------------------------------------------------------------------------------------
+// Tnt - Types
+//---------------------------------------------------------------------------------------------
+
+// ......... introduced .........
+type
+ // The user of the application did something plainly wrong.
+ ETntUserError = class(Exception);
+ // A general error occured. (ie. file didn't exist, server didn't return data, etc.)
+ ETntGeneralError = class(Exception);
+ // Like Assert(). An error occured that should never have happened, send me a bug report now!
+ ETntInternalError = class(Exception);
+
+{$IFNDEF FPC}
+type
+ PtrInt = LongInt;
+ PtrUInt = LongWord;
+{$ENDIF}
+
+//---------------------------------------------------------------------------------------------
+// Tnt - SysUtils
+//---------------------------------------------------------------------------------------------
+
+// ......... SBCS and MBCS functions with WideString replacements in SysUtils.pas .........
+
+{TNT-WARN CompareStr} {TNT-WARN AnsiCompareStr}
+{TNT-WARN SameStr} {TNT-WARN AnsiSameStr}
+{TNT-WARN SameText} {TNT-WARN AnsiSameText}
+{TNT-WARN CompareText} {TNT-WARN AnsiCompareText}
+{TNT-WARN UpperCase} {TNT-WARN AnsiUpperCase}
+{TNT-WARN LowerCase} {TNT-WARN AnsiLowerCase}
+
+{TNT-WARN AnsiPos} { --> Pos() supports WideString. }
+{TNT-WARN FmtStr}
+{TNT-WARN Format}
+{TNT-WARN FormatBuf}
+
+// ......... MBCS Byte Type Procs .........
+
+{TNT-WARN ByteType}
+{TNT-WARN StrByteType}
+{TNT-WARN ByteToCharIndex}
+{TNT-WARN ByteToCharLen}
+{TNT-WARN CharToByteIndex}
+{TNT-WARN CharToByteLen}
+
+// ........ null-terminated string functions .........
+
+{TNT-WARN StrEnd}
+{TNT-WARN StrLen}
+{TNT-WARN StrLCopy}
+{TNT-WARN StrCopy}
+{TNT-WARN StrECopy}
+{TNT-WARN StrPLCopy}
+{TNT-WARN StrPCopy}
+{TNT-WARN StrLComp}
+{TNT-WARN AnsiStrLComp}
+{TNT-WARN StrComp}
+{TNT-WARN AnsiStrComp}
+{TNT-WARN StrLIComp}
+{TNT-WARN AnsiStrLIComp}
+{TNT-WARN StrIComp}
+{TNT-WARN AnsiStrIComp}
+{TNT-WARN StrLower}
+{TNT-WARN AnsiStrLower}
+{TNT-WARN StrUpper}
+{TNT-WARN AnsiStrUpper}
+{TNT-WARN StrPos}
+{TNT-WARN AnsiStrPos}
+{TNT-WARN StrScan}
+{TNT-WARN AnsiStrScan}
+{TNT-WARN StrRScan}
+{TNT-WARN AnsiStrRScan}
+{TNT-WARN StrLCat}
+{TNT-WARN StrCat}
+{TNT-WARN StrMove}
+{TNT-WARN StrPas}
+{TNT-WARN StrAlloc}
+{TNT-WARN StrBufSize}
+{TNT-WARN StrNew}
+{TNT-WARN StrDispose}
+
+{TNT-WARN AnsiExtractQuotedStr}
+{TNT-WARN AnsiLastChar}
+{TNT-WARN AnsiStrLastChar}
+{TNT-WARN QuotedStr}
+{TNT-WARN AnsiQuotedStr}
+{TNT-WARN AnsiDequotedStr}
+
+// ........ string functions .........
+
+{$IFNDEF FPC}
+{$IFNDEF COMPILER_9_UP}
+ //
+ // pre-Delphi 9 issues w/ WideFormatBuf, WideFmtStr and WideFormat
+ //
+
+ {$IFDEF COMPILER_7_UP}
+ type
+ PFormatSettings = ^TFormatSettings;
+ {$ENDIF}
+
+ // SysUtils.WideFormatBuf doesn't correctly handle numeric specifiers.
+ function Tnt_WideFormatBuf(var Buffer; BufLen: Cardinal; const FormatStr;
+ FmtLen: Cardinal; const Args: array of const): Cardinal; {$IFDEF COMPILER_7_UP} overload; {$ENDIF}
+
+ {$IFDEF COMPILER_7_UP}
+ function Tnt_WideFormatBuf(var Buffer; BufLen: Cardinal; const FormatStr;
+ FmtLen: Cardinal; const Args: array of const;
+ const FormatSettings: TFormatSettings): Cardinal; overload;
+ {$ENDIF}
+
+ // SysUtils.WideFmtStr doesn't handle string lengths > 4096.
+ procedure Tnt_WideFmtStr(var Result: WideString; const FormatStr: WideString;
+ const Args: array of const); {$IFDEF COMPILER_7_UP} overload; {$ENDIF}
+
+ {$IFDEF COMPILER_7_UP}
+ procedure Tnt_WideFmtStr(var Result: WideString; const FormatStr: WideString;
+ const Args: array of const; const FormatSettings: TFormatSettings); overload;
+ {$ENDIF}
+
+ {----------------------------------------------------------------------------------------
+ Without the FormatSettings parameter, Tnt_WideFormat is *NOT* necessary...
+ TntSystem.InstallTntSystemUpdates([tsFixWideFormat]);
+ will fix WideFormat as well as WideFmtStr.
+ ----------------------------------------------------------------------------------------}
+ function Tnt_WideFormat(const FormatStr: WideString; const Args: array of const): WideString; {$IFDEF COMPILER_7_UP} overload; {$ENDIF}
+
+ {$IFDEF COMPILER_7_UP}
+ function Tnt_WideFormat(const FormatStr: WideString; const Args: array of const;
+ const FormatSettings: TFormatSettings): WideString; overload;
+ {$ENDIF}
+
+{$ENDIF}
+{$ENDIF}
+
+{TNT-WARN WideUpperCase} // SysUtils.WideUpperCase is broken on Win9x for D6, D7, D9.
+function Tnt_WideUpperCase(const S: WideString): WideString;
+{TNT-WARN WideLowerCase} // SysUtils.WideLowerCase is broken on Win9x for D6, D7, D9.
+function Tnt_WideLowerCase(const S: WideString): WideString;
+
+function TntWideLastChar(const S: WideString): WideChar;
+
+{TNT-WARN StringReplace}
+{TNT-WARN WideStringReplace} // <-- WideStrUtils.WideStringReplace uses SysUtils.WideUpperCase which is broken on Win9x.
+function Tnt_WideStringReplace(const S, OldPattern, NewPattern: WideString;
+ Flags: TReplaceFlags; WholeWord: Boolean = False): WideString;
+
+{TNT-WARN AdjustLineBreaks}
+type TTntTextLineBreakStyle = (tlbsLF, tlbsCRLF, tlbsCR);
+function TntAdjustLineBreaksLength(const S: WideString; Style: TTntTextLineBreakStyle = tlbsCRLF): Integer;
+function TntAdjustLineBreaks(const S: WideString; Style: TTntTextLineBreakStyle = tlbsCRLF): WideString;
+
+{TNT-WARN WrapText}
+function WideWrapText(const Line, BreakStr: WideString; const BreakChars: TSysCharSet;
+ MaxCol: Integer): WideString; overload;
+function WideWrapText(const Line: WideString; MaxCol: Integer): WideString; overload;
+
+// ........ filename manipulation .........
+
+{TNT-WARN SameFileName} // doesn't apply to Unicode filenames, use WideSameText
+{TNT-WARN AnsiCompareFileName} // doesn't apply to Unicode filenames, use WideCompareText
+{TNT-WARN AnsiLowerCaseFileName} // doesn't apply to Unicode filenames, use WideLowerCase
+{TNT-WARN AnsiUpperCaseFileName} // doesn't apply to Unicode filenames, use WideUpperCase
+
+{TNT-WARN IncludeTrailingBackslash}
+function WideIncludeTrailingBackslash(const S: WideString): WideString;
+{TNT-WARN IncludeTrailingPathDelimiter}
+function WideIncludeTrailingPathDelimiter(const S: WideString): WideString;
+{TNT-WARN ExcludeTrailingBackslash}
+function WideExcludeTrailingBackslash(const S: WideString): WideString;
+{TNT-WARN ExcludeTrailingPathDelimiter}
+function WideExcludeTrailingPathDelimiter(const S: WideString): WideString;
+{TNT-WARN IsDelimiter}
+function WideIsDelimiter(const Delimiters, S: WideString; Index: Integer): Boolean;
+{TNT-WARN IsPathDelimiter}
+function WideIsPathDelimiter(const S: WideString; Index: Integer): Boolean;
+{TNT-WARN LastDelimiter}
+function WideLastDelimiter(const Delimiters, S: WideString): Integer;
+{TNT-WARN ChangeFileExt}
+function WideChangeFileExt(const FileName, Extension: WideString): WideString;
+{TNT-WARN ExtractFilePath}
+function WideExtractFilePath(const FileName: WideString): WideString;
+{TNT-WARN ExtractFileDir}
+function WideExtractFileDir(const FileName: WideString): WideString;
+{TNT-WARN ExtractFileDrive}
+function WideExtractFileDrive(const FileName: WideString): WideString;
+{TNT-WARN ExtractFileName}
+function WideExtractFileName(const FileName: WideString): WideString;
+{TNT-WARN ExtractFileExt}
+function WideExtractFileExt(const FileName: WideString): WideString;
+{TNT-WARN ExtractRelativePath}
+function WideExtractRelativePath(const BaseName, DestName: WideString): WideString;
+
+// ........ file management routines .........
+
+{TNT-WARN ExpandFileName}
+function WideExpandFileName(const FileName: WideString): WideString;
+{TNT-WARN ExtractShortPathName}
+function WideExtractShortPathName(const FileName: WideString): WideString;
+{TNT-WARN FileCreate}
+function WideFileCreate(const FileName: WideString): Integer;
+{TNT-WARN FileOpen}
+function WideFileOpen(const FileName: WideString; Mode: LongWord): Integer;
+{TNT-WARN FileAge}
+function WideFileAge(const FileName: WideString): Integer; overload;
+function WideFileAge(const FileName: WideString; out FileDateTime: TDateTime): Boolean; overload;
+{TNT-WARN DirectoryExists}
+function WideDirectoryExists(const Name: WideString): Boolean;
+{TNT-WARN FileExists}
+function WideFileExists(const Name: WideString): Boolean;
+{TNT-WARN FileGetAttr}
+function WideFileGetAttr(const FileName: WideString): Cardinal;
+{TNT-WARN FileSetAttr}
+function WideFileSetAttr(const FileName: WideString; Attr: Integer): Boolean;
+{TNT-WARN FileIsReadOnly}
+function WideFileIsReadOnly(const FileName: WideString): Boolean;
+{TNT-WARN FileSetReadOnly}
+function WideFileSetReadOnly(const FileName: WideString; ReadOnly: Boolean): Boolean;
+{TNT-WARN ForceDirectories}
+function WideForceDirectories(Dir: WideString): Boolean;
+{TNT-WARN FileSearch}
+function WideFileSearch(const Name, DirList: WideString): WideString;
+{TNT-WARN RenameFile}
+function WideRenameFile(const OldName, NewName: WideString): Boolean;
+{TNT-WARN DeleteFile}
+function WideDeleteFile(const FileName: WideString): Boolean;
+{TNT-WARN CopyFile}
+function WideCopyFile(const FromFile, ToFile: WideString; FailIfExists: Boolean): Boolean;
+
+
+{TNT-WARN TFileName}
+type
+ TWideFileName = type WideString;
+
+{TNT-WARN TSearchRec} // <-- FindFile - warning on TSearchRec is all that is necessary
+type
+ TSearchRecW = record
+ Time: Integer;
+ Size: Int64;
+ Attr: Integer;
+ Name: TWideFileName;
+ ExcludeAttr: Integer;
+ FindHandle: THandle;
+ FindData: TWin32FindDataW;
+ end;
+function WideFindFirst(const Path: WideString; Attr: Integer; var F: TSearchRecW): Integer;
+function WideFindNext(var F: TSearchRecW): Integer;
+procedure WideFindClose(var F: TSearchRecW);
+
+{TNT-WARN CreateDir}
+function WideCreateDir(const Dir: WideString): Boolean;
+{TNT-WARN RemoveDir}
+function WideRemoveDir(const Dir: WideString): Boolean;
+{TNT-WARN GetCurrentDir}
+function WideGetCurrentDir: WideString;
+{TNT-WARN SetCurrentDir}
+function WideSetCurrentDir(const Dir: WideString): Boolean;
+
+
+// ........ date/time functions .........
+
+{TNT-WARN TryStrToDateTime}
+function TntTryStrToDateTime(Str: WideString; out DateTime: TDateTime): Boolean;
+{TNT-WARN TryStrToDate}
+function TntTryStrToDate(Str: WideString; out DateTime: TDateTime): Boolean;
+{TNT-WARN TryStrToTime}
+function TntTryStrToTime(Str: WideString; out DateTime: TDateTime): Boolean;
+
+{ introduced }
+function ValidDateTimeStr(Str: WideString): Boolean;
+function ValidDateStr(Str: WideString): Boolean;
+function ValidTimeStr(Str: WideString): Boolean;
+
+{TNT-WARN StrToDateTime}
+function TntStrToDateTime(Str: WideString): TDateTime;
+{TNT-WARN StrToDate}
+function TntStrToDate(Str: WideString): TDateTime;
+{TNT-WARN StrToTime}
+function TntStrToTime(Str: WideString): TDateTime;
+{TNT-WARN StrToDateTimeDef}
+function TntStrToDateTimeDef(Str: WideString; Default: TDateTime): TDateTime;
+{TNT-WARN StrToDateDef}
+function TntStrToDateDef(Str: WideString; Default: TDateTime): TDateTime;
+{TNT-WARN StrToTimeDef}
+function TntStrToTimeDef(Str: WideString; Default: TDateTime): TDateTime;
+
+{TNT-WARN CurrToStr}
+{TNT-WARN CurrToStrF}
+function TntCurrToStr(Value: Currency; lpFormat: PCurrencyFmtW = nil): WideString;
+{TNT-WARN StrToCurr}
+function TntStrToCurr(const S: WideString): Currency;
+{TNT-WARN StrToCurrDef}
+function ValidCurrencyStr(const S: WideString): Boolean;
+function TntStrToCurrDef(const S: WideString; const Default: Currency): Currency;
+function GetDefaultCurrencyFmt: TCurrencyFmtW;
+
+// ........ misc functions .........
+
+{TNT-WARN GetLocaleStr}
+function WideGetLocaleStr(LocaleID: LCID; LocaleType: Integer; const Default: WideString): WideString;
+{TNT-WARN SysErrorMessage}
+function WideSysErrorMessage(ErrorCode: Integer): WideString;
+
+// ......... introduced .........
+
+function WideLibraryErrorMessage(const LibName: WideString; Dll: THandle; ErrorCode: Integer): WideString;
+
+const
+ CR = WideChar(#13);
+ LF = WideChar(#10);
+ CRLF = WideString(#13#10);
+ WideLineSeparator = WideChar($2028);
+
+var
+ Win32PlatformIsUnicode: Boolean;
+ Win32PlatformIsXP: Boolean;
+ Win32PlatformIs2003: Boolean;
+ Win32PlatformIsVista: Boolean;
+
+{$IFNDEF FPC}
+{$IFNDEF COMPILER_7_UP}
+function CheckWin32Version(AMajor: Integer; AMinor: Integer = 0): Boolean;
+{$ENDIF}
+{$ENDIF}
+function WinCheckH(RetVal: Cardinal): Cardinal;
+function WinCheckFileH(RetVal: Cardinal): Cardinal;
+function WinCheckP(RetVal: Pointer): Pointer;
+
+function WideGetModuleFileName(Instance: HModule): WideString;
+function WideSafeLoadLibrary(const Filename: Widestring;
+ ErrorMode: UINT = SEM_NOOPENFILEERRORBOX): HMODULE;
+{$IFNDEF FPC}
+function WideLoadPackage(const Name: Widestring): HMODULE;
+{$ENDIF}
+
+function IsWideCharUpper(WC: WideChar): Boolean;
+function IsWideCharLower(WC: WideChar): Boolean;
+function IsWideCharDigit(WC: WideChar): Boolean;
+function IsWideCharSpace(WC: WideChar): Boolean;
+function IsWideCharPunct(WC: WideChar): Boolean;
+function IsWideCharCntrl(WC: WideChar): Boolean;
+function IsWideCharBlank(WC: WideChar): Boolean;
+function IsWideCharXDigit(WC: WideChar): Boolean;
+function IsWideCharAlpha(WC: WideChar): Boolean;
+function IsWideCharAlphaNumeric(WC: WideChar): Boolean;
+
+function WideTextPos(const SubStr, S: WideString): Integer;
+
+function ExtractStringArrayStr(P: PWideChar): WideString;
+function ExtractStringFromStringArray(var P: PWideChar; Separator: WideChar = #0): WideString;
+function ExtractStringsFromStringArray(P: PWideChar; Separator: WideChar = #0): TWideStringDynArray;
+
+function IsWideCharMappableToAnsi(const WC: WideChar): Boolean;
+function IsWideStringMappableToAnsi(const WS: WideString): Boolean;
+function IsRTF(const Value: WideString): Boolean;
+
+function ENG_US_FloatToStr(Value: Extended): WideString;
+function ENG_US_StrToFloat(const S: WideString): Extended;
+
+//---------------------------------------------------------------------------------------------
+// Tnt - Variants
+//---------------------------------------------------------------------------------------------
+
+// ........ Variants.pas has WideString versions of these functions .........
+{TNT-WARN VarToStr}
+{TNT-WARN VarToStrDef}
+
+var
+ _SettingChangeTime: Cardinal;
+
+implementation
+
+uses
+ ActiveX, ComObj, SysConst,
+ {$IFDEF COMPILER_9_UP} WideStrUtils, {$ENDIF} TntWideStrUtils,
+ TntSystem, TntFormatStrUtils;
+
+//---------------------------------------------------------------------------------------------
+// Tnt - SysUtils
+//---------------------------------------------------------------------------------------------
+
+{$IFNDEF FPC}
+{$IFNDEF COMPILER_9_UP}
+
+ function _Tnt_WideFormatBuf(var Buffer; BufLen: Cardinal; const FormatStr;
+ FmtLen: Cardinal; const Args: array of const
+ {$IFDEF COMPILER_7_UP}; const FormatSettings: PFormatSettings {$ENDIF}): Cardinal;
+ var
+ OldFormat: WideString;
+ NewFormat: WideString;
+ begin
+ SetString(OldFormat, PWideChar(@FormatStr), FmtLen);
+ { The reason for this is that WideFormat doesn't correctly format floating point specifiers.
+ See QC#4254. }
+ NewFormat := ReplaceFloatingArgumentsInFormatString(OldFormat, Args{$IFDEF COMPILER_7_UP}, FormatSettings{$ENDIF});
+ {$IFDEF COMPILER_7_UP}
+ if FormatSettings <> nil then
+ Result := WideFormatBuf(Buffer, BufLen, Pointer(NewFormat)^,
+ Length(NewFormat), Args, FormatSettings^)
+ else
+ {$ENDIF}
+ Result := WideFormatBuf(Buffer, BufLen, Pointer(NewFormat)^,
+ Length(NewFormat), Args);
+ end;
+
+ function Tnt_WideFormatBuf(var Buffer; BufLen: Cardinal; const FormatStr;
+ FmtLen: Cardinal; const Args: array of const): Cardinal;
+ begin
+ Result := _Tnt_WideFormatBuf(Buffer, BufLen, FormatStr, FmtLen, Args{$IFDEF COMPILER_7_UP}, nil{$ENDIF});
+ end;
+
+ {$IFDEF COMPILER_7_UP}
+ function Tnt_WideFormatBuf(var Buffer; BufLen: Cardinal; const FormatStr;
+ FmtLen: Cardinal; const Args: array of const; const FormatSettings: TFormatSettings): Cardinal;
+ begin
+ Result := _Tnt_WideFormatBuf(Buffer, BufLen, FormatStr, FmtLen, Args, @FormatSettings);
+ end;
+ {$ENDIF}
+
+ procedure _Tnt_WideFmtStr(var Result: WideString; const FormatStr: WideString;
+ const Args: array of const{$IFDEF COMPILER_7_UP}; const FormatSettings: PFormatSettings{$ENDIF});
+ var
+ Len, BufLen: Integer;
+ Buffer: array[0..4095] of WideChar;
+ begin
+ BufLen := Length(Buffer); // Fixes buffer overwrite issue. (See QC #4703, #4744)
+ if Length(FormatStr) < (Length(Buffer) - (Length(Buffer) div 4)) then
+ Len := _Tnt_WideFormatBuf(Buffer, Length(Buffer) - 1, Pointer(FormatStr)^,
+ Length(FormatStr), Args{$IFDEF COMPILER_7_UP}, FormatSettings{$ENDIF})
+ else
+ begin
+ BufLen := Length(FormatStr);
+ Len := BufLen;
+ end;
+ if Len >= BufLen - 1 then
+ begin
+ while Len >= BufLen - 1 do
+ begin
+ Inc(BufLen, BufLen);
+ Result := ''; // prevent copying of existing data, for speed
+ SetLength(Result, BufLen);
+ Len := _Tnt_WideFormatBuf(Pointer(Result)^, BufLen - 1, Pointer(FormatStr)^,
+ Length(FormatStr), Args{$IFDEF COMPILER_7_UP}, FormatSettings{$ENDIF});
+ end;
+ SetLength(Result, Len);
+ end
+ else
+ SetString(Result, Buffer, Len);
+ end;
+
+ procedure Tnt_WideFmtStr(var Result: WideString; const FormatStr: WideString;
+ const Args: array of const);
+ begin
+ _Tnt_WideFmtStr(Result, FormatStr, Args{$IFDEF COMPILER_7_UP}, nil{$ENDIF});
+ end;
+
+ {$IFDEF COMPILER_7_UP}
+ procedure Tnt_WideFmtStr(var Result: WideString; const FormatStr: WideString;
+ const Args: array of const; const FormatSettings: TFormatSettings);
+ begin
+ _Tnt_WideFmtStr(Result, FormatStr, Args, @FormatSettings);
+ end;
+ {$ENDIF}
+
+ {----------------------------------------------------------------------------------------
+ Without the FormatSettings parameter, Tnt_WideFormat is *NOT* necessary...
+ TntSystem.InstallTntSystemUpdates([tsFixWideFormat]);
+ will fix WideFormat as well as WideFmtStr.
+ ----------------------------------------------------------------------------------------}
+ function Tnt_WideFormat(const FormatStr: WideString; const Args: array of const): WideString;
+ begin
+ Tnt_WideFmtStr(Result, FormatStr, Args);
+ end;
+
+ {$IFDEF COMPILER_7_UP}
+ function Tnt_WideFormat(const FormatStr: WideString; const Args: array of const;
+ const FormatSettings: TFormatSettings): WideString;
+ begin
+ Tnt_WideFmtStr(Result, FormatStr, Args, FormatSettings);
+ end;
+ {$ENDIF}
+
+{$ENDIF}
+{$ENDIF FPC}
+
+function Tnt_WideUpperCase(const S: WideString): WideString;
+begin
+ {$IFNDEF FPC}
+ {$IFNDEF COMPILER_10_UP}
+ {$DEFINE WIDEUPPERCASE_BROKEN}
+ {$ENDIF}
+ {$ENDIF}
+ {$IFDEF WIDEUPPERCASE_BROKEN}
+ { SysUtils.WideUpperCase is broken for Win9x. }
+ Result := S;
+ if Length(Result) > 0 then
+ Tnt_CharUpperBuffW(PWideChar(Result), Length(Result));
+ {$ELSE}
+ Result := SysUtils.WideUpperCase{TNT-ALLOW WideUpperCase}(S);
+ {$ENDIF}
+end;
+
+function Tnt_WideLowerCase(const S: WideString): WideString;
+begin
+ {$IFNDEF FPC}
+ {$IFNDEF COMPILER_10_UP}
+ {$DEFINE WIDELOWERCASE_BROKEN}
+ {$ENDIF}
+ {$ENDIF}
+ {$IFDEF WIDELOWERCASE_BROKEN}
+ { SysUtils.WideLowerCase is broken for Win9x. }
+ Result := S;
+ if Length(Result) > 0 then
+ Tnt_CharLowerBuffW(PWideChar(Result), Length(Result));
+ {$ELSE}
+ Result := SysUtils.WideLowerCase{TNT-ALLOW WideLowerCase}(S);
+ {$ENDIF}
+end;
+
+function TntWideLastChar(const S: WideString): WideChar;
+var
+ P: PWideChar;
+begin
+ P := WideLastChar(S);
+ if P = nil then
+ Result := #0
+ else
+ Result := P^;
+end;
+
+function Tnt_WideStringReplace(const S, OldPattern, NewPattern: WideString;
+ Flags: TReplaceFlags; WholeWord: Boolean = False): WideString;
+
+ function IsWordSeparator(WC: WideChar): Boolean;
+ begin
+ Result := (WC = WideChar(#0))
+ or IsWideCharSpace(WC)
+ or IsWideCharPunct(WC);
+ end;
+
+var
+ SearchStr, Patt, NewStr: WideString;
+ Offset: Integer;
+ PrevChar, NextChar: WideChar;
+begin
+ if rfIgnoreCase in Flags then
+ begin
+ SearchStr := Tnt_WideUpperCase(S);
+ Patt := Tnt_WideUpperCase(OldPattern);
+ end else
+ begin
+ SearchStr := S;
+ Patt := OldPattern;
+ end;
+ NewStr := S;
+ Result := '';
+ while SearchStr <> '' do
+ begin
+ Offset := Pos(Patt, SearchStr);
+ if Offset = 0 then
+ begin
+ Result := Result + NewStr;
+ Break;
+ end; // done
+
+ if (WholeWord) then
+ begin
+ if (Offset = 1) then
+ PrevChar := TntWideLastChar(Result)
+ else
+ PrevChar := NewStr[Offset - 1];
+
+ if Offset + Length(OldPattern) <= Length(NewStr) then
+ NextChar := NewStr[Offset + Length(OldPattern)]
+ else
+ NextChar := WideChar(#0);
+
+ if (not IsWordSeparator(PrevChar))
+ or (not IsWordSeparator(NextChar)) then
+ begin
+ Result := Result + Copy(NewStr, 1, Offset + Length(OldPattern) - 1);
+ NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
+ SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
+ continue;
+ end;
+ end;
+
+ Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
+ NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
+ if not (rfReplaceAll in Flags) then
+ begin
+ Result := Result + NewStr;
+ Break;
+ end;
+ SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
+ end;
+end;
+
+function TntAdjustLineBreaksLength(const S: WideString; Style: TTntTextLineBreakStyle = tlbsCRLF): Integer;
+var
+ Source, SourceEnd: PWideChar;
+begin
+ Source := Pointer(S);
+ SourceEnd := Source + Length(S);
+ Result := Length(S);
+ while Source < SourceEnd do
+ begin
+ case Source^ of
+ #10, WideLineSeparator:
+ if Style = tlbsCRLF then
+ Inc(Result);
+ #13:
+ if Style = tlbsCRLF then
+ if Source[1] = #10 then
+ Inc(Source)
+ else
+ Inc(Result)
+ else
+ if Source[1] = #10 then
+ Dec(Result);
+ end;
+ Inc(Source);
+ end;
+end;
+
+function TntAdjustLineBreaks(const S: WideString; Style: TTntTextLineBreakStyle = tlbsCRLF): WideString;
+var
+ Source, SourceEnd, Dest: PWideChar;
+ DestLen: Integer;
+begin
+ Source := Pointer(S);
+ SourceEnd := Source + Length(S);
+ DestLen := TntAdjustLineBreaksLength(S, Style);
+ SetString(Result, nil, DestLen);
+ Dest := Pointer(Result);
+ while Source < SourceEnd do begin
+ case Source^ of
+ #10, WideLineSeparator:
+ begin
+ if Style in [tlbsCRLF, tlbsCR] then
+ begin
+ Dest^ := #13;
+ Inc(Dest);
+ end;
+ if Style in [tlbsCRLF, tlbsLF] then
+ begin
+ Dest^ := #10;
+ Inc(Dest);
+ end;
+ Inc(Source);
+ end;
+ #13:
+ begin
+ if Style in [tlbsCRLF, tlbsCR] then
+ begin
+ Dest^ := #13;
+ Inc(Dest);
+ end;
+ if Style in [tlbsCRLF, tlbsLF] then
+ begin
+ Dest^ := #10;
+ Inc(Dest);
+ end;
+ Inc(Source);
+ if Source^ = #10 then Inc(Source);
+ end;
+ else
+ Dest^ := Source^;
+ Inc(Dest);
+ Inc(Source);
+ end;
+ end;
+end;
+
+function WideWrapText(const Line, BreakStr: WideString; const BreakChars: TSysCharSet;
+ MaxCol: Integer): WideString;
+
+ function WideCharIn(C: WideChar; SysCharSet: TSysCharSet): Boolean;
+ begin
+ Result := (C <= High(AnsiChar)) and (AnsiChar(C) in SysCharSet);
+ end;
+
+const
+ QuoteChars = ['''', '"'];
+var
+ Col, Pos: Integer;
+ LinePos, LineLen: Integer;
+ BreakLen, BreakPos: Integer;
+ QuoteChar, CurChar: WideChar;
+ ExistingBreak: Boolean;
+begin
+ Col := 1;
+ Pos := 1;
+ LinePos := 1;
+ BreakPos := 0;
+ QuoteChar := ' ';
+ ExistingBreak := False;
+ LineLen := Length(Line);
+ BreakLen := Length(BreakStr);
+ Result := '';
+ while Pos <= LineLen do
+ begin
+ CurChar := Line[Pos];
+ if CurChar = BreakStr[1] then
+ begin
+ if QuoteChar = ' ' then
+ begin
+ ExistingBreak := WideSameText(BreakStr, Copy(Line, Pos, BreakLen));
+ if ExistingBreak then
+ begin
+ Inc(Pos, BreakLen-1);
+ BreakPos := Pos;
+ end;
+ end
+ end
+ else if WideCharIn(CurChar, BreakChars) then
+ begin
+ if QuoteChar = ' ' then BreakPos := Pos
+ end
+ else if WideCharIn(CurChar, QuoteChars) then
+ begin
+ if CurChar = QuoteChar then
+ QuoteChar := ' '
+ else if QuoteChar = ' ' then
+ QuoteChar := CurChar;
+ end;
+ Inc(Pos);
+ Inc(Col);
+ if not (WideCharIn(QuoteChar, QuoteChars)) and (ExistingBreak or
+ ((Col > MaxCol) and (BreakPos > LinePos))) then
+ begin
+ Col := Pos - BreakPos;
+ Result := Result + Copy(Line, LinePos, BreakPos - LinePos + 1);
+ if not (WideCharIn(CurChar, QuoteChars)) then
+ while Pos <= LineLen do
+ begin
+ if WideCharIn(Line[Pos], BreakChars) then
+ Inc(Pos)
+ else if Copy(Line, Pos, Length(sLineBreak)) = sLineBreak then
+ Inc(Pos, Length(sLineBreak))
+ else
+ break;
+ end;
+ if not ExistingBreak and (Pos < LineLen) then
+ Result := Result + BreakStr;
+ Inc(BreakPos);
+ LinePos := BreakPos;
+ ExistingBreak := False;
+ end;
+ end;
+ Result := Result + Copy(Line, LinePos, MaxInt);
+end;
+
+function WideWrapText(const Line: WideString; MaxCol: Integer): WideString;
+begin
+ Result := WideWrapText(Line, sLineBreak, [' ', '-', #9], MaxCol); { do not localize }
+end;
+
+function WideIncludeTrailingBackslash(const S: WideString): WideString;
+begin
+ Result := WideIncludeTrailingPathDelimiter(S);
+end;
+
+function WideIncludeTrailingPathDelimiter(const S: WideString): WideString;
+begin
+ Result := S;
+ if not WideIsPathDelimiter(Result, Length(Result)) then Result := Result + PathDelim;
+end;
+
+function WideExcludeTrailingBackslash(const S: WideString): WideString;
+begin
+ Result := WideExcludeTrailingPathDelimiter(S);
+end;
+
+function WideExcludeTrailingPathDelimiter(const S: WideString): WideString;
+begin
+ Result := S;
+ if WideIsPathDelimiter(Result, Length(Result)) then
+ SetLength(Result, Length(Result)-1);
+end;
+
+function WideIsDelimiter(const Delimiters, S: WideString; Index: Integer): Boolean;
+begin
+ Result := False;
+ if (Index <= 0) or (Index > Length(S)) then exit;
+ Result := WStrScan(PWideChar(Delimiters), S[Index]) <> nil;
+end;
+
+function WideIsPathDelimiter(const S: WideString; Index: Integer): Boolean;
+begin
+ Result := (Index > 0) and (Index <= Length(S)) and (S[Index] = PathDelim);
+end;
+
+function WideLastDelimiter(const Delimiters, S: WideString): Integer;
+var
+ P: PWideChar;
+begin
+ Result := Length(S);
+ P := PWideChar(Delimiters);
+ while Result > 0 do
+ begin
+ if (S[Result] <> #0) and (WStrScan(P, S[Result]) <> nil) then
+ Exit;
+ Dec(Result);
+ end;
+end;
+
+function WideChangeFileExt(const FileName, Extension: WideString): WideString;
+var
+ I: Integer;
+begin
+ I := WideLastDelimiter('.\:',Filename);
+ if (I = 0) or (FileName[I] <> '.') then I := MaxInt;
+ Result := Copy(FileName, 1, I - 1) + Extension;
+end;
+
+function WideExtractFilePath(const FileName: WideString): WideString;
+var
+ I: Integer;
+begin
+ I := WideLastDelimiter('\:', FileName);
+ Result := Copy(FileName, 1, I);
+end;
+
+function WideExtractFileDir(const FileName: WideString): WideString;
+var
+ I: Integer;
+begin
+ I := WideLastDelimiter(DriveDelim + PathDelim,Filename);
+ if (I > 1) and (FileName[I] = PathDelim) and
+ (not (FileName[I - 1] in [WideChar(PathDelim), WideChar(DriveDelim)])) then Dec(I);
+ Result := Copy(FileName, 1, I);
+end;
+
+function WideExtractFileDrive(const FileName: WideString): WideString;
+var
+ I, J: Integer;
+begin
+ if (Length(FileName) >= 2) and (FileName[2] = DriveDelim) then
+ Result := Copy(FileName, 1, 2)
+ else if (Length(FileName) >= 2) and (FileName[1] = PathDelim) and
+ (FileName[2] = PathDelim) then
+ begin
+ J := 0;
+ I := 3;
+ While (I < Length(FileName)) and (J < 2) do
+ begin
+ if FileName[I] = PathDelim then Inc(J);
+ if J < 2 then Inc(I);
+ end;
+ if FileName[I] = PathDelim then Dec(I);
+ Result := Copy(FileName, 1, I);
+ end else Result := '';
+end;
+
+function WideExtractFileName(const FileName: WideString): WideString;
+var
+ I: Integer;
+begin
+ I := WideLastDelimiter('\:', FileName);
+ Result := Copy(FileName, I + 1, MaxInt);
+end;
+
+function WideExtractFileExt(const FileName: WideString): WideString;
+var
+ I: Integer;
+begin
+ I := WideLastDelimiter('.\:', FileName);
+ if (I > 0) and (FileName[I] = '.') then
+ Result := Copy(FileName, I, MaxInt) else
+ Result := '';
+end;
+
+function WideExtractRelativePath(const BaseName, DestName: WideString): WideString;
+var
+ BasePath, DestPath: WideString;
+ BaseLead, DestLead: PWideChar;
+ BasePtr, DestPtr: PWideChar;
+
+ function WideExtractFilePathNoDrive(const FileName: WideString): WideString;
+ begin
+ Result := WideExtractFilePath(FileName);
+ Delete(Result, 1, Length(WideExtractFileDrive(FileName)));
+ end;
+
+ function Next(var Lead: PWideChar): PWideChar;
+ begin
+ Result := Lead;
+ if Result = nil then Exit;
+ Lead := WStrScan(Lead, PathDelim);
+ if Lead <> nil then
+ begin
+ Lead^ := #0;
+ Inc(Lead);
+ end;
+ end;
+
+begin
+ if WideSameText(WideExtractFileDrive(BaseName), WideExtractFileDrive(DestName)) then
+ begin
+ BasePath := WideExtractFilePathNoDrive(BaseName);
+ DestPath := WideExtractFilePathNoDrive(DestName);
+ BaseLead := Pointer(BasePath);
+ BasePtr := Next(BaseLead);
+ DestLead := Pointer(DestPath);
+ DestPtr := Next(DestLead);
+ while (BasePtr <> nil) and (DestPtr <> nil) and WideSameText(BasePtr, DestPtr) do
+ begin
+ BasePtr := Next(BaseLead);
+ DestPtr := Next(DestLead);
+ end;
+ Result := '';
+ while BaseLead <> nil do
+ begin
+ Result := Result + '..' + PathDelim; { Do not localize }
+ Next(BaseLead);
+ end;
+ if (DestPtr <> nil) and (DestPtr^ <> #0) then
+ Result := Result + DestPtr + PathDelim;
+ if DestLead <> nil then
+ Result := Result + DestLead; // destlead already has a trailing backslash
+ Result := Result + WideExtractFileName(DestName);
+ end
+ else
+ Result := DestName;
+end;
+
+function WideExpandFileName(const FileName: WideString): WideString;
+var
+ FName: PWideChar;
+ Buffer: array[0..MAX_PATH - 1] of WideChar;
+begin
+ SetString(Result, Buffer, Tnt_GetFullPathNameW(PWideChar(FileName), MAX_PATH, Buffer, FName));
+end;
+
+function WideExtractShortPathName(const FileName: WideString): WideString;
+var
+ Buffer: array[0..MAX_PATH - 1] of WideChar;
+begin
+ SetString(Result, Buffer, Tnt_GetShortPathNameW(PWideChar(FileName), Buffer, MAX_PATH));
+end;
+
+function WideFileCreate(const FileName: WideString): Integer;
+begin
+ Result := Integer(Tnt_CreateFileW(PWideChar(FileName), GENERIC_READ or GENERIC_WRITE,
+ 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0))
+end;
+
+function WideFileOpen(const FileName: WideString; Mode: LongWord): Integer;
+const
+ AccessMode: array[0..2] of LongWord = (
+ GENERIC_READ,
+ GENERIC_WRITE,
+ GENERIC_READ or GENERIC_WRITE);
+ ShareMode: array[0..4] of LongWord = (
+ 0,
+ 0,
+ FILE_SHARE_READ,
+ FILE_SHARE_WRITE,
+ FILE_SHARE_READ or FILE_SHARE_WRITE);
+begin
+ Result := Integer(Tnt_CreateFileW(PWideChar(FileName), AccessMode[Mode and 3],
+ ShareMode[(Mode and $F0) shr 4], nil, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0));
+end;
+
+function WideFileAge(const FileName: WideString): Integer;
+var
+ Handle: THandle;
+ FindData: TWin32FindDataW;
+ LocalFileTime: TFileTime;
+begin
+ Handle := Tnt_FindFirstFileW(PWideChar(FileName), FindData);
+ if Handle <> INVALID_HANDLE_VALUE then
+ begin
+ Windows.FindClose(Handle);
+ if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
+ begin
+ FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
+ if FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi, LongRec(Result).Lo) then
+ Exit
+ end;
+ end;
+ Result := -1;
+end;
+
+function WideFileAge(const FileName: WideString; out FileDateTime: TDateTime): Boolean;
+var
+ Handle: THandle;
+ FindData: TWin32FindDataW;
+ LSystemTime: TSystemTime;
+ LocalFileTime: TFileTime;
+begin
+ Result := False;
+ Handle := Tnt_FindFirstFileW(PWideChar(FileName), FindData);
+ if Handle <> INVALID_HANDLE_VALUE then
+ begin
+ Windows.FindClose(Handle);
+ if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
+ begin
+ Result := True;
+ FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
+ FileTimeToSystemTime(LocalFileTime, LSystemTime);
+ with LSystemTime do
+ FileDateTime := EncodeDate(wYear, wMonth, wDay) +
+ EncodeTime(wHour, wMinute, wSecond, wMilliSeconds);
+ end;
+ end;
+end;
+
+function WideDirectoryExists(const Name: WideString): Boolean;
+var
+ Code: Cardinal;
+begin
+ Code := WideFileGetAttr(Name);
+ Result := (Code <> INVALID_FILE_ATTRIBUTES) and ((FILE_ATTRIBUTE_DIRECTORY and Code) <> 0);
+end;
+
+function WideFileExists(const Name: WideString): Boolean;
+var
+ Code: Cardinal;
+begin
+ Code := WideFileGetAttr(Name);
+ Result := (Code <> INVALID_FILE_ATTRIBUTES) and ((FILE_ATTRIBUTE_DIRECTORY and Code) = 0);
+end;
+
+function WideFileGetAttr(const FileName: WideString): Cardinal;
+begin
+ Result := Tnt_GetFileAttributesW(PWideChar(FileName));
+end;
+
+function WideFileSetAttr(const FileName: WideString; Attr: Integer): Boolean;
+begin
+ Result := Tnt_SetFileAttributesW(PWideChar(FileName), Attr)
+end;
+
+function WideFileIsReadOnly(const FileName: WideString): Boolean;
+begin
+ Result := (Tnt_GetFileAttributesW(PWideChar(FileName)) and faReadOnly) <> 0;
+end;
+
+function WideFileSetReadOnly(const FileName: WideString; ReadOnly: Boolean): Boolean;
+var
+ Flags: Integer;
+begin
+ Result := False;
+ Flags := Tnt_GetFileAttributesW(PWideChar(FileName));
+ if Flags = -1 then Exit;
+ if ReadOnly then
+ Flags := Flags or faReadOnly
+ else
+ Flags := Flags and not faReadOnly;
+ Result := Tnt_SetFileAttributesW(PWideChar(FileName), Flags);
+end;
+
+function WideForceDirectories(Dir: WideString): Boolean;
+begin
+ Result := True;
+ if Length(Dir) = 0 then
+ raise ETntGeneralError.Create(
+ {$IFNDEF FPC} SCannotCreateDir {$ELSE} SCannotCreateEmptyDir {$ENDIF});
+ Dir := WideExcludeTrailingBackslash(Dir);
+ if (Length(Dir) < 3) or WideDirectoryExists(Dir)
+ or (WideExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
+ Result := WideForceDirectories(WideExtractFilePath(Dir));
+ if Result then
+ Result := Tnt_CreateDirectoryW(PWideChar(Dir), nil)
+end;
+
+function WideFileSearch(const Name, DirList: WideString): WideString;
+var
+ I, P, L: Integer;
+ C: WideChar;
+begin
+ Result := Name;
+ P := 1;
+ L := Length(DirList);
+ while True do
+ begin
+ if WideFileExists(Result) then Exit;
+ while (P <= L) and (DirList[P] = PathSep) do Inc(P);
+ if P > L then Break;
+ I := P;
+ while (P <= L) and (DirList[P] <> PathSep) do
+ Inc(P);
+ Result := Copy(DirList, I, P - I);
+ C := TntWideLastChar(Result);
+ if (C <> DriveDelim) and (C <> PathDelim) then
+ Result := Result + PathDelim;
+ Result := Result + Name;
+ end;
+ Result := '';
+end;
+
+function WideRenameFile(const OldName, NewName: WideString): Boolean;
+begin
+ Result := Tnt_MoveFileW(PWideChar(OldName), PWideChar(NewName))
+end;
+
+function WideDeleteFile(const FileName: WideString): Boolean;
+begin
+ Result := Tnt_DeleteFileW(PWideChar(FileName))
+end;
+
+function WideCopyFile(const FromFile, ToFile: WideString; FailIfExists: Boolean): Boolean;
+begin
+ Result := Tnt_CopyFileW(PWideChar(FromFile), PWideChar(ToFile), FailIfExists)
+end;
+
+function _WideFindMatchingFile(var F: TSearchRecW): Integer;
+var
+ LocalFileTime: TFileTime;
+begin
+ with F do
+ begin
+ while FindData.dwFileAttributes and ExcludeAttr <> 0 do
+ if not Tnt_FindNextFileW(FindHandle, FindData) then
+ begin
+ Result := GetLastError;
+ Exit;
+ end;
+ FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
+ FileTimeToDosDateTime(LocalFileTime, LongRec(Time).Hi, LongRec(Time).Lo);
+ Size := (Int64(FindData.nFileSizeHigh) shl 32) + FindData.nFileSizeLow;
+ Attr := FindData.dwFileAttributes;
+ Name := FindData.cFileName;
+ end;
+ Result := 0;
+end;
+
+function WideFindFirst(const Path: WideString; Attr: Integer; var F: TSearchRecW): Integer;
+const
+ faSpecial = faHidden or faSysFile {$IFNDEF COMPILER_9_UP} or faVolumeID {$ENDIF} or faDirectory;
+begin
+ F.ExcludeAttr := not Attr and faSpecial;
+ F.FindHandle := Tnt_FindFirstFileW(PWideChar(Path), F.FindData);
+ if F.FindHandle <> INVALID_HANDLE_VALUE then
+ begin
+ Result := _WideFindMatchingFile(F);
+ if Result <> 0 then WideFindClose(F);
+ end else
+ Result := GetLastError;
+end;
+
+function WideFindNext(var F: TSearchRecW): Integer;
+begin
+ if Tnt_FindNextFileW(F.FindHandle, F.FindData) then
+ Result := _WideFindMatchingFile(F) else
+ Result := GetLastError;
+end;
+
+procedure WideFindClose(var F: TSearchRecW);
+begin
+ if F.FindHandle <> INVALID_HANDLE_VALUE then
+ begin
+ Windows.FindClose(F.FindHandle);
+ F.FindHandle := INVALID_HANDLE_VALUE;
+ end;
+end;
+
+function WideCreateDir(const Dir: WideString): Boolean;
+begin
+ Result := Tnt_CreateDirectoryW(PWideChar(Dir), nil);
+end;
+
+function WideRemoveDir(const Dir: WideString): Boolean;
+begin
+ Result := Tnt_RemoveDirectoryW(PWideChar(Dir));
+end;
+
+function WideGetCurrentDir: WideString;
+begin
+ SetLength(Result, MAX_PATH);
+ Tnt_GetCurrentDirectoryW(MAX_PATH, PWideChar(Result));
+ Result := PWideChar(Result);
+end;
+
+function WideSetCurrentDir(const Dir: WideString): Boolean;
+begin
+ Result := Tnt_SetCurrentDirectoryW(PWideChar(Dir));
+end;
+
+//=============================================================================================
+//== DATE/TIME STRING PARSING ================================================================
+//=============================================================================================
+
+{$IFDEF FPC}
+const
+ VAR_TIMEVALUEONLY = 1;
+ VAR_DATEVALUEONLY = 2;
+{$ENDIF}
+
+function _IntTryStrToDateTime(Str: WideString; Flags: Integer; out DateTime: TDateTime): HResult;
+begin
+ Result := VarDateFromStr(
+ {$IFDEF FPC} POLECHAR(Str) {$ELSE} Str {$ENDIF},
+ GetThreadLocale, Flags, Double(DateTime));
+ if (not Succeeded(Result)) then begin
+ if (Flags = VAR_TIMEVALUEONLY)
+ and SysUtils.TryStrToTime{TNT-ALLOW TryStrToTime}(Str, DateTime) then
+ Result := S_OK // SysUtils seems confident (works for date = "dd.MM.yy" and time = "H.mm.ss")
+ else if (Flags = VAR_DATEVALUEONLY)
+ and SysUtils.TryStrToDate{TNT-ALLOW TryStrToDate}(Str, DateTime) then
+ Result := S_OK // SysUtils seems confident
+ else if (Flags = 0)
+ and SysUtils.TryStrToDateTime{TNT-ALLOW TryStrToDateTime}(Str, DateTime) then
+ Result := S_OK // SysUtils seems confident
+ end;
+end;
+
+function TntTryStrToDateTime(Str: WideString; out DateTime: TDateTime): Boolean;
+begin
+ Result := Succeeded(_IntTryStrToDateTime(Str, 0, DateTime));
+end;
+
+function TntTryStrToDate(Str: WideString; out DateTime: TDateTime): Boolean;
+begin
+ Result := Succeeded(_IntTryStrToDateTime(Str, VAR_DATEVALUEONLY, DateTime));
+end;
+
+function TntTryStrToTime(Str: WideString; out DateTime: TDateTime): Boolean;
+begin
+ Result := Succeeded(_IntTryStrToDateTime(Str, VAR_TIMEVALUEONLY, DateTime));
+end;
+
+function ValidDateTimeStr(Str: WideString): Boolean;
+var
+ Temp: TDateTime;
+begin
+ Result := Succeeded(_IntTryStrToDateTime(Str, 0, Temp));
+end;
+
+function ValidDateStr(Str: WideString): Boolean;
+var
+ Temp: TDateTime;
+begin
+ Result := Succeeded(_IntTryStrToDateTime(Str, VAR_DATEVALUEONLY, Temp));
+end;
+
+function ValidTimeStr(Str: WideString): Boolean;
+var
+ Temp: TDateTime;
+begin
+ Result := Succeeded(_IntTryStrToDateTime(Str, VAR_TIMEVALUEONLY, Temp));
+end;
+
+function TntStrToDateTimeDef(Str: WideString; Default: TDateTime): TDateTime;
+begin
+ if not TntTryStrToDateTime(Str, Result) then
+ Result := Default;
+end;
+
+function TntStrToDateDef(Str: WideString; Default: TDateTime): TDateTime;
+begin
+ if not TntTryStrToDate(Str, Result) then
+ Result := Default;
+end;
+
+function TntStrToTimeDef(Str: WideString; Default: TDateTime): TDateTime;
+begin
+ if not TntTryStrToTime(Str, Result) then
+ Result := Default;
+end;
+
+function _IntStrToDateTime(Str: WideString; Flags: Integer; ErrorFormatStr: WideString): TDateTime;
+begin
+ try
+ OleCheck(_IntTryStrToDateTime(Str, Flags, Result));
+ except
+ on E: Exception do begin
+ E.Message := E.Message + CRLF + WideFormat(ErrorFormatStr, [Str]);
+ raise EConvertError.Create(E.Message);
+ end;
+ end;
+end;
+
+function TntStrToDateTime(Str: WideString): TDateTime;
+begin
+ Result := _IntStrToDateTime(Str, 0, SInvalidDateTime);
+end;
+
+function TntStrToDate(Str: WideString): TDateTime;
+begin
+ Result := _IntStrToDateTime(Str, VAR_DATEVALUEONLY,
+ {$IFNDEF FPC} SInvalidDate {$ELSE} SInvalidDateTime {$ENDIF});
+end;
+
+function TntStrToTime(Str: WideString): TDateTime;
+begin
+ Result := _IntStrToDateTime(Str, VAR_TIMEVALUEONLY,
+ {$IFNDEF FPC} SInvalidTime {$ELSE} SInvalidDateTime {$ENDIF});
+end;
+
+//=============================================================================================
+//== CURRENCY STRING PARSING =================================================================
+//=============================================================================================
+
+function TntCurrToStr(Value: Currency; lpFormat: PCurrencyFmtW = nil): WideString;
+const
+ MAX_BUFF_SIZE = 64; // can a currency string actually be larger?
+var
+ ValueStr: WideString;
+begin
+ // format lpValue using ENG-US settings
+ ValueStr := ENG_US_FloatToStr(Value);
+ // get currency format
+ SetLength(Result, MAX_BUFF_SIZE);
+ if 0 = Tnt_GetCurrencyFormatW(GetThreadLocale, 0, PWideChar(ValueStr),
+ lpFormat, PWideChar(Result), Length(Result))
+ then begin
+ RaiseLastOSError;
+ end;
+ Result := PWideChar(Result);
+end;
+
+function TntStrToCurr(const S: WideString): Currency;
+begin
+ try
+ OleCheck(VarCyFromStr(
+ {$IFDEF FPC} POLECHAR(S) {$ELSE} S {$ENDIF},
+ GetThreadLocale, 0, Result));
+ except
+ on E: Exception do begin
+ E.Message := E.Message + CRLF + WideFormat(SInvalidCurrency, [S]);
+ raise EConvertError.Create(E.Message);
+ end;
+ end;
+end;
+
+function ValidCurrencyStr(const S: WideString): Boolean;
+var
+ Dummy: Currency;
+begin
+ Result := Succeeded(VarCyFromStr(
+ {$IFDEF FPC} POLECHAR(S) {$ELSE} S {$ENDIF},
+ GetThreadLocale, 0, Dummy));
+end;
+
+function TntStrToCurrDef(const S: WideString; const Default: Currency): Currency;
+begin
+ if not Succeeded(VarCyFromStr(
+ {$IFDEF FPC} POLECHAR(S) {$ELSE} S {$ENDIF},
+ GetThreadLocale, 0, Result)) then
+ Result := Default;
+end;
+
+threadvar
+ Currency_DecimalSep: WideString;
+ Currency_ThousandSep: WideString;
+ Currency_CurrencySymbol: WideString;
+
+function GetDefaultCurrencyFmt: TCurrencyFmtW;
+begin
+ ZeroMemory(@Result, SizeOf(Result));
+ Result.NumDigits := StrToIntDef(WideGetLocaleStr(GetThreadLocale, LOCALE_ICURRDIGITS, '2'), 2);
+ Result.LeadingZero := StrToIntDef(WideGetLocaleStr(GetThreadLocale, LOCALE_ILZERO, '1'), 1);
+ Result.Grouping := StrToIntDef(Copy(WideGetLocaleStr(GetThreadLocale, LOCALE_SMONGROUPING, '3;0'), 1, 1), 3);
+ Currency_DecimalSep := WideGetLocaleStr(GetThreadLocale, LOCALE_SMONDECIMALSEP, '.');
+ Result.lpDecimalSep := {$IFNDEF FPC} PWideChar(Currency_DecimalSep)
+ {$ELSE} LPTSTR(PWideChar(Currency_DecimalSep)) {$ENDIF};
+ Currency_ThousandSep := WideGetLocaleStr(GetThreadLocale, LOCALE_SMONTHOUSANDSEP, ',');
+ Result.lpThousandSep := {$IFNDEF FPC} PWideChar(Currency_ThousandSep)
+ {$ELSE} LPTSTR(PWideChar(Currency_ThousandSep)) {$ENDIF};
+ Result.NegativeOrder := StrToIntDef(WideGetLocaleStr(GetThreadLocale, LOCALE_INEGCURR, '0'), 0);
+ Result.PositiveOrder := StrToIntDef(WideGetLocaleStr(GetThreadLocale, LOCALE_ICURRENCY, '0'), 0);
+ Currency_CurrencySymbol := WideGetLocaleStr(GetThreadLocale, LOCALE_SCURRENCY, '');
+ Result.lpCurrencySymbol := {$IFNDEF FPC} PWideChar(Currency_CurrencySymbol)
+ {$ELSE} LPTSTR(PWideChar(Currency_CurrencySymbol)) {$ENDIF};
+end;
+
+//=============================================================================================
+
+{$IFDEF FPC}
+function GetLocaleStr(Locale, LocaleType: Integer; const Default: string): string;
+var
+ L: Integer;
+ Buffer: array[0..255] of Char;
+begin
+ L := GetLocaleInfo(Locale, LocaleType, Buffer, SizeOf(Buffer));
+ if L > 0 then SetString(Result, Buffer, L - 1) else Result := Default;
+end;
+{$ENDIF}
+
+function WideGetLocaleStr(LocaleID: LCID; LocaleType: Integer; const Default: WideString): WideString;
+var
+ L: Integer;
+begin
+ if (not Win32PlatformIsUnicode) then
+ Result := GetLocaleStr{TNT-ALLOW GetLocaleStr}(LocaleID, LocaleType, Default)
+ else begin
+ SetLength(Result, 255);
+ L := GetLocaleInfoW(LocaleID, LocaleType, PWideChar(Result), Length(Result));
+ if L > 0 then
+ SetLength(Result, L - 1)
+ else
+ Result := Default;
+ end;
+end;
+
+function WideSysErrorMessage(ErrorCode: Integer): WideString;
+begin
+ Result := WideLibraryErrorMessage('system', 0, ErrorCode);
+end;
+
+function WideLibraryErrorMessage(const LibName: WideString; Dll: THandle; ErrorCode: Integer): WideString;
+var
+ Len: Integer;
+ AnsiResult: AnsiString;
+ Flags: Cardinal;
+begin
+ Flags := FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY;
+ if Dll <> 0 then
+ Flags := Flags or FORMAT_MESSAGE_FROM_HMODULE;
+ if Win32PlatformIsUnicode then begin
+ SetLength(Result, 256);
+ Len := FormatMessageW(Flags, Pointer(Dll), ErrorCode, 0, PWideChar(Result), Length(Result), nil);
+ SetLength(Result, Len);
+ end else begin
+ SetLength(AnsiResult, 256);
+ Len := FormatMessageA(Flags, Pointer(Dll), ErrorCode, 0, PAnsiChar(AnsiResult), Length(AnsiResult), nil);
+ SetLength(AnsiResult, Len);
+ Result := AnsiResult;
+ end;
+ if Trim(Result) = '' then
+ Result := WideFormat('Unspecified error (%d) from %s.', [ErrorCode, LibName]);
+end;
+
+{$IFNDEF COMPILER_7_UP}
+function CheckWin32Version(AMajor: Integer; AMinor: Integer = 0): Boolean;
+begin
+ Result := (Win32MajorVersion > AMajor) or
+ ((Win32MajorVersion = AMajor) and
+ (Win32MinorVersion >= AMinor));
+end;
+{$ENDIF}
+
+function WinCheckH(RetVal: Cardinal): Cardinal;
+begin
+ if RetVal = 0 then RaiseLastOSError;
+ Result := RetVal;
+end;
+
+function WinCheckFileH(RetVal: Cardinal): Cardinal;
+begin
+ if RetVal = INVALID_HANDLE_VALUE then RaiseLastOSError;
+ Result := RetVal;
+end;
+
+function WinCheckP(RetVal: Pointer): Pointer;
+begin
+ if RetVal = nil then RaiseLastOSError;
+ Result := RetVal;
+end;
+
+function WideGetModuleFileName(Instance: HModule): WideString;
+begin
+ SetLength(Result, MAX_PATH);
+ WinCheckH(Tnt_GetModuleFileNameW(Instance, PWideChar(Result), Length(Result)));
+ Result := PWideChar(Result)
+end;
+
+function WideSafeLoadLibrary(const Filename: Widestring; ErrorMode: UINT): HMODULE;
+var
+ OldMode: UINT;
+ FPUControlWord: Word;
+begin
+ OldMode := SetErrorMode(ErrorMode);
+ try
+ asm
+ FNSTCW FPUControlWord
+ end;
+ try
+ Result := Tnt_LoadLibraryW(PWideChar(Filename));
+ finally
+ asm
+ FNCLEX
+ FLDCW FPUControlWord
+ end;
+ end;
+ finally
+ SetErrorMode(OldMode);
+ end;
+end;
+
+{$IFNDEF FPC}
+function WideLoadPackage(const Name: Widestring): HMODULE;
+begin
+ Result := WideSafeLoadLibrary(Name);
+ if Result = 0 then
+ begin
+ raise EPackageError.CreateFmt(sErrorLoadingPackage, [Name, WideSysErrorMessage(GetLastError)]);
+ end;
+ try
+ InitializePackage(Result);
+ except
+ FreeLibrary(Result);
+ raise;
+ end;
+end;
+{$ENDIF}
+
+function _WideCharType(WC: WideChar; dwInfoType: Cardinal): Word;
+begin
+ Win32Check(Tnt_GetStringTypeExW(GetThreadLocale, dwInfoType, PWideChar(@WC), 1, Result))
+end;
+
+function IsWideCharUpper(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_UPPER) <> 0;
+end;
+
+function IsWideCharLower(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_LOWER) <> 0;
+end;
+
+function IsWideCharDigit(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_DIGIT) <> 0;
+end;
+
+function IsWideCharSpace(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_SPACE) <> 0;
+end;
+
+function IsWideCharPunct(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_PUNCT) <> 0;
+end;
+
+function IsWideCharCntrl(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_CNTRL) <> 0;
+end;
+
+function IsWideCharBlank(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_BLANK) <> 0;
+end;
+
+function IsWideCharXDigit(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_XDIGIT) <> 0;
+end;
+
+function IsWideCharAlpha(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and C1_ALPHA) <> 0;
+end;
+
+function IsWideCharAlphaNumeric(WC: WideChar): Boolean;
+begin
+ Result := (_WideCharType(WC, CT_CTYPE1) and (C1_ALPHA + C1_DIGIT)) <> 0;
+end;
+
+function WideTextPos(const SubStr, S: WideString): Integer;
+begin
+ Result := Pos(Tnt_WideUpperCase(SubStr), Tnt_WideUpperCase(S));
+end;
+
+function FindDoubleTerminator(P: PWideChar): PWideChar;
+begin
+ Result := P;
+ while True do begin
+ Result := WStrScan(Result, #0);
+ Inc(Result);
+ if Result^ = #0 then begin
+ Dec(Result);
+ break;
+ end;
+ end;
+end;
+
+function ExtractStringArrayStr(P: PWideChar): WideString;
+var
+ PEnd: PWideChar;
+begin
+ PEnd := FindDoubleTerminator(P);
+ Inc(PEnd, 2); // move past #0#0
+ SetString(Result, P, PEnd - P);
+end;
+
+function ExtractStringFromStringArray(var P: PWideChar; Separator: WideChar = #0): WideString;
+var
+ Start: PWideChar;
+begin
+ Start := P;
+ P := WStrScan(Start, Separator);
+ if P = nil then begin
+ Result := Start;
+ P := WStrEnd(Start);
+ end else begin
+ SetString(Result, Start, P - Start);
+ Inc(P);
+ end;
+end;
+
+function ExtractStringsFromStringArray(P: PWideChar; Separator: WideChar = #0): TWideStringDynArray;
+const
+ GROW_COUNT = 256;
+var
+ Count: Integer;
+ Item: WideString;
+begin
+ Count := 0;
+ SetLength(Result, GROW_COUNT);
+ Item := ExtractStringFromStringArray(P, Separator);
+ While Item <> '' do begin
+ if Count > High(Result) then
+ SetLength(Result, Length(Result) + GROW_COUNT);
+ Result[Count] := Item;
+ Inc(Count);
+ Item := ExtractStringFromStringArray(P, Separator);
+ end;
+ SetLength(Result, Count);
+end;
+
+function IsWideCharMappableToAnsi(const WC: WideChar): Boolean;
+var
+ UsedDefaultChar: BOOL;
+begin
+ WideCharToMultiByte(DefaultSystemCodePage, 0, PWideChar(@WC), 1, nil, 0, nil, @UsedDefaultChar);
+ Result := not UsedDefaultChar;
+end;
+
+function IsWideStringMappableToAnsi(const WS: WideString): Boolean;
+var
+ UsedDefaultChar: BOOL;
+begin
+ WideCharToMultiByte(DefaultSystemCodePage, 0, PWideChar(WS), Length(WS), nil, 0, nil, @UsedDefaultChar);
+ Result := not UsedDefaultChar;
+end;
+
+function IsRTF(const Value: WideString): Boolean;
+const
+ RTF_BEGIN_1 = WideString('{\RTF');
+ RTF_BEGIN_2 = WideString('{URTF');
+begin
+ Result := (WideTextPos(RTF_BEGIN_1, Value) = 1)
+ or (WideTextPos(RTF_BEGIN_2, Value) = 1);
+end;
+
+{$IFDEF COMPILER_7_UP}
+var
+ Cached_ENG_US_FormatSettings: TFormatSettings;
+ Cached_ENG_US_FormatSettings_Time: Cardinal;
+
+function ENG_US_FormatSettings: TFormatSettings;
+begin
+ if Cached_ENG_US_FormatSettings_Time = _SettingChangeTime then
+ Result := Cached_ENG_US_FormatSettings
+ else begin
+ GetLocaleFormatSettings(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)), Result);
+ Result.DecimalSeparator := '.'; // ignore overrides
+ Cached_ENG_US_FormatSettings := Result;
+ Cached_ENG_US_FormatSettings_Time := _SettingChangeTime;
+ end;
+ end;
+
+function ENG_US_FloatToStr(Value: Extended): WideString;
+begin
+ Result := FloatToStr(Value, ENG_US_FormatSettings);
+end;
+
+function ENG_US_StrToFloat(const S: WideString): Extended;
+begin
+ if not TextToFloat(PAnsiChar(AnsiString(S)), Result, fvExtended, ENG_US_FormatSettings) then
+ Result := StrToFloat(S); // try using native format
+end;
+
+{$ELSE}
+
+function ENG_US_FloatToStr(Value: Extended): WideString;
+var
+ SaveDecimalSep: AnsiChar;
+begin
+ SaveDecimalSep := SysUtils.DecimalSeparator;
+ try
+ SysUtils.DecimalSeparator := '.';
+ Result := FloatToStr(Value);
+ finally
+ SysUtils.DecimalSeparator := SaveDecimalSep;
+ end;
+end;
+
+function ENG_US_StrToFloat(const S: WideString): Extended;
+var
+ SaveDecimalSep: AnsiChar;
+begin
+ try
+ SaveDecimalSep := SysUtils.DecimalSeparator;
+ try
+ SysUtils.DecimalSeparator := '.';
+ Result := StrToFloat(S);
+ finally
+ SysUtils.DecimalSeparator := SaveDecimalSep;
+ end;
+ except
+ if SysUtils.DecimalSeparator <> '.' then
+ Result := StrToFloat(S) // try using native format
+ else
+ raise;
+ end;
+end;
+{$ENDIF}
+
+//---------------------------------------------------------------------------------------------
+// Tnt - Variants
+//---------------------------------------------------------------------------------------------
+
+initialization
+ Win32PlatformIsUnicode := (Win32Platform = VER_PLATFORM_WIN32_NT);
+ Win32PlatformIsXP := ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))
+ or (Win32MajorVersion > 5);
+ Win32PlatformIs2003 := ((Win32MajorVersion = 5) and (Win32MinorVersion >= 2))
+ or (Win32MajorVersion > 5);
+ Win32PlatformIsVista := (Win32MajorVersion >= 6);
+
+finalization
+ Currency_DecimalSep := ''; {make memory sleuth happy}
+ Currency_ThousandSep := ''; {make memory sleuth happy}
+ Currency_CurrencySymbol := ''; {make memory sleuth happy}
+
+end.
diff --git a/src/lib/TntUnicodeControls/TntSystem.pas b/src/lib/TntUnicodeControls/TntSystem.pas
new file mode 100644
index 00000000..e613ce0c
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntSystem.pas
@@ -0,0 +1,1427 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntSystem;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+{*****************************************************************************}
+{ Special thanks go to Francisco Leong for originating the design for }
+{ WideString-enabled resourcestrings. }
+{*****************************************************************************}
+
+interface
+
+uses
+ Windows;
+
+// These functions should not be used by Delphi code since conversions are implicit.
+{TNT-WARN WideCharToString}
+{TNT-WARN WideCharLenToString}
+{TNT-WARN WideCharToStrVar}
+{TNT-WARN WideCharLenToStrVar}
+{TNT-WARN StringToWideChar}
+
+// ................ ANSI TYPES ................
+{TNT-WARN Char}
+{TNT-WARN PChar}
+{TNT-WARN String}
+
+{TNT-WARN CP_ACP} // <-- use DefaultSystemCodePage
+function DefaultSystemCodePage: Cardinal; // implicitly used when converting AnsiString <--> WideString.
+
+{$IFNDEF FPC}
+var
+ WideCustomLoadResString: function(ResStringRec: PResStringRec; var Value: WideString): Boolean;
+{$ENDIF}
+
+{TNT-WARN LoadResString}
+function WideLoadResString(ResStringRec: PResStringRec): WideString;
+{TNT-WARN ParamCount}
+function WideParamCount: Integer;
+{TNT-WARN ParamStr}
+function WideParamStr(Index: Integer): WideString;
+
+// ......... introduced .........
+
+const
+ { Each Unicode stream should begin with the code U+FEFF, }
+ { which the standard defines as the *byte order mark*. }
+ UNICODE_BOM = WideChar($FEFF);
+ UNICODE_BOM_SWAPPED = WideChar($FFFE);
+ UTF8_BOM = AnsiString(#$EF#$BB#$BF);
+
+function WideStringToUTF8(const S: WideString): AnsiString;
+function UTF8ToWideString(const S: AnsiString): WideString;
+
+function WideStringToUTF7(const W: WideString): AnsiString;
+function UTF7ToWideString(const S: AnsiString): WideString;
+
+function StringToWideStringEx(const S: AnsiString; CodePage: Cardinal): WideString;
+function WideStringToStringEx(const WS: WideString; CodePage: Cardinal): AnsiString;
+
+function UCS2ToWideString(const Value: AnsiString): WideString;
+function WideStringToUCS2(const Value: WideString): AnsiString;
+
+function CharSetToCodePage(ciCharset: UINT): Cardinal;
+function LCIDToCodePage(ALcid: LCID): Cardinal;
+function KeyboardCodePage: Cardinal;
+function KeyUnicode(CharCode: Word): WideChar;
+
+procedure StrSwapByteOrder(Str: PWideChar);
+
+{$IFDEF USE_SYSTEM_OVERRIDES}
+
+type
+ TTntSystemUpdate =
+ (tsWideResourceStrings
+ {$IFNDEF COMPILER_9_UP}, tsFixImplicitCodePage, tsFixWideStrConcat, tsFixWideFormat {$ENDIF}
+ );
+ TTntSystemUpdateSet = set of TTntSystemUpdate;
+
+const
+ AllTntSystemUpdates = [Low(TTntSystemUpdate)..High(TTntSystemUpdate)];
+
+procedure InstallTntSystemUpdates(Updates: TTntSystemUpdateSet = AllTntSystemUpdates);
+
+{$ENDIF USE_SYSTEM_OVERRIDES}
+
+implementation
+
+uses
+ SysUtils, Variants, TntWindows, TntSysUtils;
+
+var
+ GDefaultSystemCodePage: Cardinal;
+
+function DefaultSystemCodePage: Cardinal;
+begin
+ Result := GDefaultSystemCodePage;
+end;
+
+{$IFDEF USE_SYSTEM_OVERRIDES}
+var
+ IsDebugging: Boolean;
+{$ENDIF USE_SYSTEM_OVERRIDES}
+
+function WideLoadResStringDetect(ResStringRec: PResStringRec): WideString;
+var
+ PCustom: PAnsiChar;
+begin
+ // custom string pointer
+ PCustom := PAnsiChar(ResStringRec); { I would like to use PWideChar, but this would break legacy code. }
+ if (StrLen{TNT-ALLOW StrLen}(PCustom) > Cardinal(Length(UTF8_BOM)))
+ and CompareMem(PCustom, PAnsiChar(UTF8_BOM), Length(UTF8_BOM)) then
+ // detected UTF8
+ Result := UTF8ToWideString(PAnsiChar(PCustom + Length(UTF8_BOM)))
+ else
+ // normal
+ Result := PCustom;
+end;
+
+{$IFNDEF FPC}
+
+function WideLoadResString(ResStringRec: PResStringRec): WideString;
+const
+ MAX_RES_STRING_SIZE = 4097; { MSDN documents this as the maximum size of a string in table. }
+var
+ Buffer: array [0..MAX_RES_STRING_SIZE] of WideChar; { Buffer leaves room for null terminator. }
+begin
+ if Assigned(WideCustomLoadResString) and WideCustomLoadResString(ResStringRec, Result) then
+ exit; { a custom resourcestring has been loaded. }
+
+ if ResStringRec = nil then
+ Result := ''
+ else if ResStringRec.Identifier < 64*1024 then
+ SetString(Result, Buffer,
+ Tnt_LoadStringW(FindResourceHInstance(ResStringRec.Module^),
+ ResStringRec.Identifier, Buffer, MAX_RES_STRING_SIZE))
+ else begin
+ Result := WideLoadResStringDetect(ResStringRec);
+ end;
+end;
+
+{$ELSE}
+
+function WideLoadResString(ResStringRec: PResStringRec): WideString;
+begin
+ Result := WideLoadResStringDetect(ResStringRec);
+end;
+
+{$ENDIF}
+
+function WideGetParamStr(P: PWideChar; var Param: WideString): PWideChar;
+var
+ i, Len: Integer;
+ Start, S, Q: PWideChar;
+begin
+ while True do
+ begin
+ while (P[0] <> #0) and (P[0] <= ' ') do
+ Inc(P);
+ if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
+ end;
+ Len := 0;
+ Start := P;
+ while P[0] > ' ' do
+ begin
+ if P[0] = '"' then
+ begin
+ Inc(P);
+ while (P[0] <> #0) and (P[0] <> '"') do
+ begin
+ Q := P + 1;
+ Inc(Len, Q - P);
+ P := Q;
+ end;
+ if P[0] <> #0 then
+ Inc(P);
+ end
+ else
+ begin
+ Q := P + 1;
+ Inc(Len, Q - P);
+ P := Q;
+ end;
+ end;
+
+ SetLength(Param, Len);
+
+ P := Start;
+ S := PWideChar(Param);
+ i := 0;
+ while P[0] > ' ' do
+ begin
+ if P[0] = '"' then
+ begin
+ Inc(P);
+ while (P[0] <> #0) and (P[0] <> '"') do
+ begin
+ Q := P + 1;
+ while P < Q do
+ begin
+ S[i] := P^;
+ Inc(P);
+ Inc(i);
+ end;
+ end;
+ if P[0] <> #0 then Inc(P);
+ end
+ else
+ begin
+ Q := P + 1;
+ while P < Q do
+ begin
+ S[i] := P^;
+ Inc(P);
+ Inc(i);
+ end;
+ end;
+ end;
+
+ Result := P;
+end;
+
+function WideParamCount: Integer;
+var
+ P: PWideChar;
+ S: WideString;
+begin
+ P := WideGetParamStr(GetCommandLineW, S);
+ Result := 0;
+ while True do
+ begin
+ P := WideGetParamStr(P, S);
+ if S = '' then Break;
+ Inc(Result);
+ end;
+end;
+
+function WideParamStr(Index: Integer): WideString;
+var
+ P: PWideChar;
+begin
+ if Index = 0 then
+ Result := WideGetModuleFileName(0)
+ else
+ begin
+ P := GetCommandLineW;
+ while True do
+ begin
+ P := WideGetParamStr(P, Result);
+ if (Index = 0) or (Result = '') then Break;
+ Dec(Index);
+ end;
+ end;
+end;
+
+function WideStringToUTF8(const S: WideString): AnsiString;
+begin
+ Result := UTF8Encode(S);
+end;
+
+function UTF8ToWideString(const S: AnsiString): WideString;
+begin
+ Result := UTF8Decode(S);
+end;
+
+ { ======================================================================= }
+ { Original File: ConvertUTF7.c }
+ { Author: David B. Goldsmith }
+ { Copyright (C) 1994, 1996 Taligent, Inc. All rights reserved. }
+ { }
+ { This code is copyrighted. Under the copyright laws, this code may not }
+ { be copied, in whole or part, without prior written consent of Taligent. }
+ { }
+ { Taligent grants the right to use this code as long as this ENTIRE }
+ { copyright notice is reproduced in the code. The code is provided }
+ { AS-IS, AND TALIGENT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR }
+ { IMPLIED, INCLUDING, BUT NOT LIMITED TO IMPLIED WARRANTIES OF }
+ { MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT }
+ { WILL TALIGENT BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, }
+ { WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS }
+ { INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY }
+ { LOSS) ARISING OUT OF THE USE OR INABILITY TO USE THIS CODE, EVEN }
+ { IF TALIGENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. }
+ { BECAUSE SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF }
+ { LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE }
+ { LIMITATION MAY NOT APPLY TO YOU. }
+ { }
+ { RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the }
+ { government is subject to restrictions as set forth in subparagraph }
+ { (c)(l)(ii) of the Rights in Technical Data and Computer Software }
+ { clause at DFARS 252.227-7013 and FAR 52.227-19. }
+ { }
+ { This code may be protected by one or more U.S. and International }
+ { Patents. }
+ { }
+ { TRADEMARKS: Taligent and the Taligent Design Mark are registered }
+ { trademarks of Taligent, Inc. }
+ { ======================================================================= }
+
+type UCS2 = Word;
+
+const
+ _base64: AnsiString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+ _direct: AnsiString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789''(),-./:?';
+ _optional: AnsiString = '!"#$%&*;<=>@[]^_`{|}';
+ _spaces: AnsiString = #9#13#10#32;
+
+var
+ base64: PAnsiChar;
+ invbase64: array[0..127] of SmallInt;
+ direct: PAnsiChar;
+ optional: PAnsiChar;
+ spaces: PAnsiChar;
+ mustshiftsafe: array[0..127] of AnsiChar;
+ mustshiftopt: array[0..127] of AnsiChar;
+
+var
+ needtables: Boolean = True;
+
+procedure Initialize_UTF7_Data;
+begin
+ base64 := PAnsiChar(_base64);
+ direct := PAnsiChar(_direct);
+ optional := PAnsiChar(_optional);
+ spaces := PAnsiChar(_spaces);
+end;
+
+procedure tabinit;
+var
+ i: Integer;
+ limit: Integer;
+begin
+ i := 0;
+ while (i < 128) do
+ begin
+ mustshiftopt[i] := #1;
+ mustshiftsafe[i] := #1;
+ invbase64[i] := -1;
+ Inc(i);
+ end { For };
+ limit := Length(_Direct);
+ i := 0;
+ while (i < limit) do
+ begin
+ mustshiftopt[Integer(direct[i])] := #0;
+ mustshiftsafe[Integer(direct[i])] := #0;
+ Inc(i);
+ end { For };
+ limit := Length(_Spaces);
+ i := 0;
+ while (i < limit) do
+ begin
+ mustshiftopt[Integer(spaces[i])] := #0;
+ mustshiftsafe[Integer(spaces[i])] := #0;
+ Inc(i);
+ end { For };
+ limit := Length(_Optional);
+ i := 0;
+ while (i < limit) do
+ begin
+ mustshiftopt[Integer(optional[i])] := #0;
+ Inc(i);
+ end { For };
+ limit := Length(_Base64);
+ i := 0;
+ while (i < limit) do
+ begin
+ invbase64[Integer(base64[i])] := i;
+ Inc(i);
+ end { For };
+ needtables := False;
+end; { tabinit }
+
+function WRITE_N_BITS(x: UCS2; n: Integer; var BITbuffer: Cardinal; var bufferbits: Integer): Integer;
+begin
+ BITbuffer := BITbuffer or (x and (not (-1 shl n))) shl (32 - n - bufferbits);
+ bufferbits := bufferbits + n;
+ Result := bufferbits;
+end; { WRITE_N_BITS }
+
+function READ_N_BITS(n: Integer; var BITbuffer: Cardinal; var bufferbits: Integer): UCS2;
+var
+ buffertemp: Cardinal;
+begin
+ buffertemp := BITbuffer shr (32 - n);
+ BITbuffer := BITbuffer shl n;
+ bufferbits := bufferbits - n;
+ Result := UCS2(buffertemp);
+end; { READ_N_BITS }
+
+function ConvertUCS2toUTF7(var sourceStart: PWideChar; sourceEnd: PWideChar;
+ var targetStart: PAnsiChar; targetEnd: PAnsiChar; optional: Boolean;
+ verbose: Boolean): Integer;
+var
+ r: UCS2;
+ target: PAnsiChar;
+ source: PWideChar;
+ BITbuffer: Cardinal;
+ bufferbits: Integer;
+ shifted: Boolean;
+ needshift: Boolean;
+ done: Boolean;
+ mustshift: PAnsiChar;
+begin
+ Initialize_UTF7_Data;
+ Result := 0;
+ BITbuffer := 0;
+ bufferbits := 0;
+ shifted := False;
+ source := sourceStart;
+ target := targetStart;
+ r := 0;
+ if needtables then
+ tabinit;
+ if optional then
+ mustshift := @mustshiftopt[0]
+ else
+ mustshift := @mustshiftsafe[0];
+ repeat
+ done := source >= sourceEnd;
+ if not Done then
+ begin
+ r := Word(source^);
+ Inc(Source);
+ end { If };
+ needshift := (not done) and ((r > $7F) or (mustshift[r] <> #0));
+ if needshift and (not shifted) then
+ begin
+ if (Target >= TargetEnd) then
+ begin
+ Result := 2;
+ break;
+ end { If };
+ target^ := '+';
+ Inc(target);
+ { Special case handling of the SHIFT_IN character }
+ if (r = UCS2('+')) then
+ begin
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ break;
+ end;
+ target^ := '-';
+ Inc(target);
+ end
+ else
+ shifted := True;
+ end { If };
+ if shifted then
+ begin
+ { Either write the character to the bit buffer, or pad }
+ { the bit buffer out to a full base64 character. }
+ { }
+ if needshift then
+ WRITE_N_BITS(r, 16, BITbuffer, bufferbits)
+ else
+ WRITE_N_BITS(0, (6 - (bufferbits mod 6)) mod 6, BITbuffer,
+ bufferbits);
+ { Flush out as many full base64 characters as possible }
+ { from the bit buffer. }
+ { }
+ while (target < targetEnd) and (bufferbits >= 6) do
+ begin
+ Target^ := base64[READ_N_BITS(6, BITbuffer, bufferbits)];
+ Inc(Target);
+ end { While };
+ if (bufferbits >= 6) then
+ begin
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ break;
+ end { If };
+ end { If };
+ if (not needshift) then
+ begin
+ { Write the explicit shift out character if }
+ { 1) The caller has requested we always do it, or }
+ { 2) The directly encoded character is in the }
+ { base64 set, or }
+ { 3) The directly encoded character is SHIFT_OUT. }
+ { }
+ if verbose or ((not done) and ((invbase64[r] >= 0) or (r =
+ Integer('-')))) then
+ begin
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ Break;
+ end { If };
+ Target^ := '-';
+ Inc(Target);
+ end { If };
+ shifted := False;
+ end { If };
+ { The character can be directly encoded as ASCII. }
+ end { If };
+ if (not needshift) and (not done) then
+ begin
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ break;
+ end { If };
+ Target^ := AnsiChar(r);
+ Inc(Target);
+ end { If };
+ until (done);
+ sourceStart := source;
+ targetStart := target;
+end; { ConvertUCS2toUTF7 }
+
+function ConvertUTF7toUCS2(var sourceStart: PAnsiChar; sourceEnd: PAnsiChar;
+ var targetStart: PWideChar; targetEnd: PWideChar): Integer;
+var
+ target: PWideChar { Register };
+ source: PAnsiChar { Register };
+ BITbuffer: Cardinal { & "Address Of" Used };
+ bufferbits: Integer { & "Address Of" Used };
+ shifted: Boolean { Used In Boolean Context };
+ first: Boolean { Used In Boolean Context };
+ wroteone: Boolean;
+ base64EOF: Boolean;
+ base64value: Integer;
+ done: Boolean;
+ c: UCS2;
+ prevc: UCS2;
+ junk: UCS2 { Used In Boolean Context };
+begin
+ Initialize_UTF7_Data;
+ Result := 0;
+ BITbuffer := 0;
+ bufferbits := 0;
+ shifted := False;
+ first := False;
+ wroteone := False;
+ source := sourceStart;
+ target := targetStart;
+ c := 0;
+ if needtables then
+ tabinit;
+ repeat
+ { read an ASCII character c }
+ done := Source >= SourceEnd;
+ if (not done) then
+ begin
+ c := Word(Source^);
+ Inc(Source);
+ end { If };
+ if shifted then
+ begin
+ { We're done with a base64 string if we hit EOF, it's not a valid }
+ { ASCII character, or it's not in the base64 set. }
+ { }
+ base64value := invbase64[c];
+ base64EOF := (done or (c > $7F)) or (base64value < 0);
+ if base64EOF then
+ begin
+ shifted := False;
+ { If the character causing us to drop out was SHIFT_IN or }
+ { SHIFT_OUT, it may be a special escape for SHIFT_IN. The }
+ { test for SHIFT_IN is not necessary, but allows an alternate }
+ { form of UTF-7 where SHIFT_IN is escaped by SHIFT_IN. This }
+ { only works for some values of SHIFT_IN. }
+ { }
+ if ((not done) and ((c = Integer('+')) or (c = Integer('-')))) then
+ begin
+ { get another character c }
+ prevc := c;
+ Done := Source >= SourceEnd;
+ if (not Done) then
+ begin
+ c := Word(Source^);
+ Inc(Source);
+ { If no base64 characters were encountered, and the }
+ { character terminating the shift sequence was }
+ { SHIFT_OUT, then it's a special escape for SHIFT_IN. }
+ { }
+ end;
+ if first and (prevc = Integer('-')) then
+ begin
+ { write SHIFT_IN unicode }
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ break;
+ end { If };
+ Target^ := WideChar('+');
+ Inc(Target);
+ end
+ else
+ begin
+ if (not wroteone) then
+ begin
+ Result := 1;
+ end { If };
+ end { Else };
+ ;
+ end { If }
+ else
+ begin
+ if (not wroteone) then
+ begin
+ Result := 1;
+ end { If };
+ end { Else };
+ end { If }
+ else
+ begin
+ { Add another 6 bits of base64 to the bit buffer. }
+ WRITE_N_BITS(base64value, 6, BITbuffer,
+ bufferbits);
+ first := False;
+ end { Else };
+ { Extract as many full 16 bit characters as possible from the }
+ { bit buffer. }
+ { }
+ while (bufferbits >= 16) and (target < targetEnd) do
+ begin
+ { write a unicode }
+ Target^ := WideChar(READ_N_BITS(16, BITbuffer, bufferbits));
+ Inc(Target);
+ wroteone := True;
+ end { While };
+ if (bufferbits >= 16) then
+ begin
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ Break;
+ end;
+ end { If };
+ if (base64EOF) then
+ begin
+ junk := READ_N_BITS(bufferbits, BITbuffer, bufferbits);
+ if (junk <> 0) then
+ begin
+ Result := 1;
+ end { If };
+ end { If };
+ end { If };
+ if (not shifted) and (not done) then
+ begin
+ if (c = Integer('+')) then
+ begin
+ shifted := True;
+ first := True;
+ wroteone := False;
+ end { If }
+ else
+ begin
+ { It must be a directly encoded character. }
+ if (c > $7F) then
+ begin
+ Result := 1;
+ end { If };
+ if (target >= targetEnd) then
+ begin
+ Result := 2;
+ break;
+ end { If };
+ Target^ := WideChar(c);
+ Inc(Target);
+ end { Else };
+ end { If };
+ until (done);
+ sourceStart := source;
+ targetStart := target;
+end; { ConvertUTF7toUCS2 }
+
+ {*****************************************************************************}
+ { Thanks to Francisco Leong for providing the Pascal conversion of }
+ { ConvertUTF7.c (by David B. Goldsmith) }
+ {*****************************************************************************}
+
+resourcestring
+ SBufferOverflow = 'Buffer overflow';
+ SInvalidUTF7 = 'Invalid UTF7';
+
+function WideStringToUTF7(const W: WideString): AnsiString;
+var
+ SourceStart, SourceEnd: PWideChar;
+ TargetStart, TargetEnd: PAnsiChar;
+begin
+ if W = '' then
+ Result := ''
+ else
+ begin
+ SetLength(Result, Length(W) * 7); // Assume worst case
+ SourceStart := PWideChar(@W[1]);
+ SourceEnd := PWideChar(@W[Length(W)]) + 1;
+ TargetStart := PAnsiChar(@Result[1]);
+ TargetEnd := PAnsiChar(@Result[Length(Result)]) + 1;
+ if ConvertUCS2toUTF7(SourceStart, SourceEnd, TargetStart,
+ TargetEnd, True, False) <> 0
+ then
+ raise ETntInternalError.Create(SBufferOverflow);
+ SetLength(Result, TargetStart - PAnsiChar(@Result[1]));
+ end;
+end;
+
+function UTF7ToWideString(const S: AnsiString): WideString;
+var
+ SourceStart, SourceEnd: PAnsiChar;
+ TargetStart, TargetEnd: PWideChar;
+begin
+ if (S = '') then
+ Result := ''
+ else
+ begin
+ SetLength(Result, Length(S)); // Assume Worst case
+ SourceStart := PAnsiChar(@S[1]);
+ SourceEnd := PAnsiChar(@S[Length(S)]) + 1;
+ TargetStart := PWideChar(@Result[1]);
+ TargetEnd := PWideChar(@Result[Length(Result)]) + 1;
+ case ConvertUTF7toUCS2(SourceStart, SourceEnd, TargetStart,
+ TargetEnd) of
+ 1: raise ETntGeneralError.Create(SInvalidUTF7);
+ 2: raise ETntInternalError.Create(SBufferOverflow);
+ end;
+ SetLength(Result, TargetStart - PWideChar(@Result[1]));
+ end;
+end;
+
+function StringToWideStringEx(const S: AnsiString; CodePage: Cardinal): WideString;
+var
+ InputLength,
+ OutputLength: Integer;
+begin
+ if CodePage = CP_UTF7 then
+ Result := UTF7ToWideString(S) // CP_UTF7 not supported on Windows 95
+ else if CodePage = CP_UTF8 then
+ Result := UTF8ToWideString(S) // CP_UTF8 not supported on Windows 95
+ else begin
+ InputLength := Length(S);
+ OutputLength := MultiByteToWideChar(CodePage, 0, PAnsiChar(S), InputLength, nil, 0);
+ SetLength(Result, OutputLength);
+ MultiByteToWideChar(CodePage, 0, PAnsiChar(S), InputLength, PWideChar(Result), OutputLength);
+ end;
+end;
+
+function WideStringToStringEx(const WS: WideString; CodePage: Cardinal): AnsiString;
+var
+ InputLength,
+ OutputLength: Integer;
+begin
+ if CodePage = CP_UTF7 then
+ Result := WideStringToUTF7(WS) // CP_UTF7 not supported on Windows 95
+ else if CodePage = CP_UTF8 then
+ Result := WideStringToUTF8(WS) // CP_UTF8 not supported on Windows 95
+ else begin
+ InputLength := Length(WS);
+ OutputLength := WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, nil, 0, nil, nil);
+ SetLength(Result, OutputLength);
+ WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, PAnsiChar(Result), OutputLength, nil, nil);
+ end;
+end;
+
+function UCS2ToWideString(const Value: AnsiString): WideString;
+begin
+ if Length(Value) = 0 then
+ Result := ''
+ else
+ SetString(Result, PWideChar(@Value[1]), Length(Value) div SizeOf(WideChar))
+end;
+
+function WideStringToUCS2(const Value: WideString): AnsiString;
+begin
+ if Length(Value) = 0 then
+ Result := ''
+ else
+ SetString(Result, PAnsiChar(@Value[1]), Length(Value) * SizeOf(WideChar))
+end;
+
+{ Windows.pas doesn't declare TranslateCharsetInfo() correctly. }
+function TranslateCharsetInfo(lpSrc: PDWORD; var lpCs: TCharsetInfo; dwFlags: DWORD): BOOL; stdcall; external gdi32 name 'TranslateCharsetInfo';
+
+function CharSetToCodePage(ciCharset: UINT): Cardinal;
+var
+ C: TCharsetInfo;
+begin
+ Win32Check(TranslateCharsetInfo(PDWORD(ciCharset), C, TCI_SRCCHARSET));
+ Result := C.ciACP
+end;
+
+function LCIDToCodePage(ALcid: LCID): Cardinal;
+var
+ Buf: array[0..6] of AnsiChar;
+begin
+ GetLocaleInfo(ALcid, LOCALE_IDefaultAnsiCodePage, Buf, 6);
+ Result := StrToIntDef(Buf, GetACP);
+end;
+
+function KeyboardCodePage: Cardinal;
+begin
+ Result := LCIDToCodePage(GetKeyboardLayout(0) and $FFFF);
+end;
+
+function KeyUnicode(CharCode: Word): WideChar;
+var
+ AChar: AnsiChar;
+begin
+ // converts the given character (as it comes with a WM_CHAR message) into its
+ // corresponding Unicode character depending on the active keyboard layout
+ if CharCode <= Word(High(AnsiChar)) then begin
+ AChar := AnsiChar(CharCode);
+ MultiByteToWideChar(KeyboardCodePage, MB_USEGLYPHCHARS, @AChar, 1, @Result, 1);
+ end else
+ Result := WideChar(CharCode);
+end;
+
+procedure StrSwapByteOrder(Str: PWideChar);
+var
+ P: PWord;
+begin
+ P := PWord(Str);
+ While (P^ <> 0) do begin
+ P^ := MakeWord(HiByte(P^), LoByte(P^));
+ Inc(P);
+ end;
+end;
+
+{$IFDEF USE_SYSTEM_OVERRIDES}
+
+//--------------------------------------------------------------------
+// LoadResString()
+//
+// This system function is used to retrieve a resourcestring and
+// return the result as an AnsiString. If we believe that the result
+// is only a temporary value, and that it will be immediately
+// assigned to a WideString or a Variant, then we will save the
+// Unicode result as well as a reference to the original Ansi string.
+// WStrFromPCharLen() or VarFromLStr() will return this saved
+// Unicode string if it appears to receive the most recent result
+// of LoadResString.
+//--------------------------------------------------------------------
+
+
+ //===========================================================================================
+ //
+ // function CodeMatchesPatternForUnicode(...);
+ //
+ // GIVEN: SomeWideString := SSomeResString; { WideString := resourcestring }
+ //
+ // Delphi will compile this statement into the following:
+ // -------------------------------------------------
+ // TempAnsiString := LoadResString(@SSomeResString);
+ // LINE 1: lea edx,[SomeTempAnsiString]
+ // LINE 2: mov eax,[@SomeResString]
+ // LINE 3: call LoadResString
+ //
+ // WStrFromLStr(SomeWideString, TempAnsiString); { SomeWideString := TempAnsiString }
+ // LINE 4: mov edx,[SomeTempAnsiString]
+ // LINE 5: mov/lea eax [@SomeWideString]
+ // LINE 6: call @WStrFromLStr
+ // -------------------------------------------------
+ //
+ // The order in which the parameters are prepared for WStrFromLStr (ie LINE 4 & 5) is
+ // reversed when assigning a non-temporary AnsiString to a WideString.
+ //
+ // This code, for example, results in LINE 4 and LINE 5 being swapped.
+ //
+ // SomeAnsiString := SSomeResString;
+ // SomeWideString := SomeAnsiString;
+ //
+ // Since we know the "signature" used by the compiler, we can detect this pattern.
+ // If we believe it is only temporary, we can save the Unicode results for later
+ // retrieval from WStrFromLStr.
+ //
+ // One final note: When assigning a resourcestring to a Variant, the same patterns exist.
+ //===========================================================================================
+
+function CodeMatchesPatternForUnicode(PLine4: PAnsiChar): Boolean;
+const
+ SIZEOF_OPCODE = 1 {byte};
+ MOV_16_OPCODE = AnsiChar($8B); { we'll assume operand size is 16 bits }
+ MOV_32_OPCODE = AnsiChar($B8); { we'll assume operand size is 32 bits }
+ LEA_OPCODE = AnsiChar($8D); { operand size can be 16 or 40 bits }
+ CALL_OPCODE = AnsiChar($E8); { assumed operand size is 32 bits }
+ BREAK_OPCODE = AnsiChar($CC); {in a breakpoint}
+var
+ PLine1: PAnsiChar;
+ PLine2: PAnsiChar;
+ PLine3: PAnsiChar;
+ DataSize: Integer; // bytes in first LEA operand
+begin
+ Result := False;
+
+ PLine3 := PLine4 - SizeOf(CALL_OPCODE) - 4;
+ PLine2 := PLine3 - SizeOf(MOV_32_OPCODE) - 4;
+
+ // figure PLine1 and operand size
+ DataSize := 2; { try 16 bit operand for line 1 }
+ PLine1 := PLine2 - DataSize - SizeOf(LEA_OPCODE);
+ if (PLine1^ <> LEA_OPCODE) and (not (IsDebugging and (PLine1^ = BREAK_OPCODE))) then
+ begin
+ DataSize := 5; { try 40 bit operand for line 1 }
+ PLine1 := PLine2 - DataSize - SizeOf(LEA_OPCODE);
+ end;
+ if (PLine1^ = LEA_OPCODE) or (IsDebugging and (PLine1^ = BREAK_OPCODE)) then
+ begin
+ if CompareMem(PLine1 + SIZEOF_OPCODE, PLine4 + SIZEOF_OPCODE, DataSize) then
+ begin
+ // After this check, it seems to match the WideString <- (temp) AnsiString pattern
+ Result := True; // It is probably OK. (The side effects of being wrong aren't very bad.)
+ end;
+ end;
+end;
+
+threadvar
+ PLastResString: PAnsiChar;
+ LastResStringValue: AnsiString;
+ LastWideResString: WideString;
+
+procedure FreeTntSystemThreadVars;
+begin
+ LastResStringValue := '';
+ LastWideResString := '';
+end;
+
+procedure Custom_System_EndThread(ExitCode: Integer);
+begin
+ FreeTntSystemThreadVars;
+ {$IFDEF COMPILER_10_UP}
+ if Assigned(SystemThreadEndProc) then
+ SystemThreadEndProc(ExitCode);
+ {$ENDIF}
+ ExitThread(ExitCode);
+end;
+
+function Custom_System_LoadResString(ResStringRec: PResStringRec): AnsiString;
+var
+ ReturnAddr: Pointer;
+begin
+ // get return address
+ asm
+ PUSH ECX
+ MOV ECX, [EBP + 4]
+ MOV ReturnAddr, ECX
+ POP ECX
+ end;
+ // check calling code pattern
+ if CodeMatchesPatternForUnicode(ReturnAddr) then begin
+ // result will probably be assigned to an intermediate AnsiString
+ // on its way to either a WideString or Variant.
+ LastWideResString := WideLoadResString(ResStringRec);
+ Result := LastWideResString;
+ LastResStringValue := Result;
+ if Result = '' then
+ PLastResString := nil
+ else
+ PLastResString := PAnsiChar(Result);
+ end else begin
+ // result will probably be assigned to an actual AnsiString variable.
+ PLastResString := nil;
+ Result := WideLoadResString(ResStringRec);
+ end;
+end;
+
+//--------------------------------------------------------------------
+// WStrFromPCharLen()
+//
+// This system function is used to assign an AnsiString to a WideString.
+// It has been modified to assign Unicode results from LoadResString.
+// Another purpose of this function is to specify the code page.
+//--------------------------------------------------------------------
+
+procedure Custom_System_WStrFromPCharLen(var Dest: WideString; Source: PAnsiChar; Length: Integer);
+var
+ DestLen: Integer;
+ Buffer: array[0..2047] of WideChar;
+ Local_PLastResString: Pointer;
+begin
+ Local_PLastResString := PLastResString;
+ if (Local_PLastResString <> nil)
+ and (Local_PLastResString = Source)
+ and (System.Length(LastResStringValue) = Length)
+ and (LastResStringValue = Source) then begin
+ // use last unicode resource string
+ PLastResString := nil; { clear for further use }
+ Dest := LastWideResString;
+ end else begin
+ if Local_PLastResString <> nil then
+ PLastResString := nil; { clear for further use }
+ if Length <= 0 then
+ begin
+ Dest := '';
+ Exit;
+ end;
+ if Length + 1 < High(Buffer) then
+ begin
+ DestLen := MultiByteToWideChar(DefaultSystemCodePage, 0, Source, Length, Buffer,
+ High(Buffer));
+ if DestLen > 0 then
+ begin
+ SetLength(Dest, DestLen);
+ Move(Pointer(@Buffer[0])^, Pointer(Dest)^, DestLen * SizeOf(WideChar));
+ Exit;
+ end;
+ end;
+ DestLen := (Length + 1);
+ SetLength(Dest, DestLen); // overallocate, trim later
+ DestLen := MultiByteToWideChar(DefaultSystemCodePage, 0, Source, Length, Pointer(Dest),
+ DestLen);
+ if DestLen < 0 then
+ DestLen := 0;
+ SetLength(Dest, DestLen);
+ end;
+end;
+
+{$IFNDEF COMPILER_9_UP}
+
+//--------------------------------------------------------------------
+// LStrFromPWCharLen()
+//
+// This system function is used to assign an WideString to an AnsiString.
+// It has not been modified from its original purpose other than to specify the code page.
+//--------------------------------------------------------------------
+
+procedure Custom_System_LStrFromPWCharLen(var Dest: AnsiString; Source: PWideChar; Length: Integer);
+var
+ DestLen: Integer;
+ Buffer: array[0..4095] of AnsiChar;
+begin
+ if Length <= 0 then
+ begin
+ Dest := '';
+ Exit;
+ end;
+ if Length + 1 < (High(Buffer) div sizeof(WideChar)) then
+ begin
+ DestLen := WideCharToMultiByte(DefaultSystemCodePage, 0, Source,
+ Length, Buffer, High(Buffer),
+ nil, nil);
+ if DestLen >= 0 then
+ begin
+ SetLength(Dest, DestLen);
+ Move(Pointer(@Buffer[0])^, PAnsiChar(Dest)^, DestLen);
+ Exit;
+ end;
+ end;
+
+ DestLen := (Length + 1) * sizeof(WideChar);
+ SetLength(Dest, DestLen); // overallocate, trim later
+ DestLen := WideCharToMultiByte(DefaultSystemCodePage, 0, Source, Length, Pointer(Dest), DestLen,
+ nil, nil);
+ if DestLen < 0 then
+ DestLen := 0;
+ SetLength(Dest, DestLen);
+end;
+
+//--------------------------------------------------------------------
+// WStrToString()
+//
+// This system function is used to assign an WideString to an short string.
+// It has not been modified from its original purpose other than to specify the code page.
+//--------------------------------------------------------------------
+
+procedure Custom_System_WStrToString(Dest: PShortString; const Source: WideString; MaxLen: Integer);
+var
+ SourceLen, DestLen: Integer;
+ Buffer: array[0..511] of AnsiChar;
+begin
+ if MaxLen > 255 then MaxLen := 255;
+ SourceLen := Length(Source);
+ if SourceLen >= MaxLen then SourceLen := MaxLen;
+ if SourceLen = 0 then
+ DestLen := 0
+ else begin
+ DestLen := WideCharToMultiByte(DefaultSystemCodePage, 0, Pointer(Source), SourceLen,
+ Buffer, SizeOf(Buffer), nil, nil);
+ if DestLen > MaxLen then DestLen := MaxLen;
+ end;
+ Dest^[0] := Chr(DestLen);
+ if DestLen > 0 then Move(Buffer, Dest^[1], DestLen);
+end;
+
+{$ENDIF}
+
+//--------------------------------------------------------------------
+// VarFromLStr()
+//
+// This system function is used to assign an AnsiString to a Variant.
+// It has been modified to assign Unicode results from LoadResString.
+//--------------------------------------------------------------------
+
+procedure Custom_System_VarFromLStr(var V: TVarData; const Value: AnsiString);
+const
+ varDeepData = $BFE8;
+var
+ Local_PLastResString: Pointer;
+begin
+ if (V.VType and varDeepData) <> 0 then
+ VarClear(PVariant(@V)^);
+
+ Local_PLastResString := PLastResString;
+ if (Local_PLastResString <> nil)
+ and (Local_PLastResString = PAnsiChar(Value))
+ and (LastResStringValue = Value) then begin
+ // use last unicode resource string
+ PLastResString := nil; { clear for further use }
+ V.VOleStr := nil;
+ V.VType := varOleStr;
+ WideString(Pointer(V.VOleStr)) := Copy(LastWideResString, 1, MaxInt);
+ end else begin
+ if Local_PLastResString <> nil then
+ PLastResString := nil; { clear for further use }
+ V.VString := nil;
+ V.VType := varString;
+ AnsiString(V.VString) := Value;
+ end;
+end;
+
+{$IFNDEF COMPILER_9_UP}
+
+//--------------------------------------------------------------------
+// WStrCat3() A := B + C;
+//
+// This system function is used to concatenate two strings into one result.
+// This function is added because A := '' + '' doesn't necessarily result in A = '';
+//--------------------------------------------------------------------
+
+procedure Custom_System_WStrCat3(var Dest: WideString; const Source1, Source2: WideString);
+
+ function NewWideString(CharLength: Longint): Pointer;
+ var
+ _NewWideString: function(CharLength: Longint): Pointer;
+ begin
+ asm
+ PUSH ECX
+ MOV ECX, offset System.@NewWideString;
+ MOV _NewWideString, ECX
+ POP ECX
+ end;
+ Result := _NewWideString(CharLength);
+ end;
+
+ procedure WStrSet(var S: WideString; P: PWideChar);
+ var
+ Temp: Pointer;
+ begin
+ Temp := Pointer(InterlockedExchange(Integer(S), Integer(P)));
+ if Temp <> nil then
+ WideString(Temp) := '';
+ end;
+
+var
+ Source1Len, Source2Len: Integer;
+ NewStr: PWideChar;
+begin
+ Source1Len := Length(Source1);
+ Source2Len := Length(Source2);
+ if (Source1Len <> 0) or (Source2Len <> 0) then
+ begin
+ NewStr := NewWideString(Source1Len + Source2Len);
+ Move(Pointer(Source1)^, Pointer(NewStr)^, Source1Len * sizeof(WideChar));
+ Move(Pointer(Source2)^, NewStr[Source1Len], Source2Len * sizeof(WideChar));
+ WStrSet(Dest, NewStr);
+ end else
+ Dest := '';
+end;
+
+{$ENDIF}
+
+//--------------------------------------------------------------------
+// System proc replacements
+//--------------------------------------------------------------------
+
+type
+ POverwrittenData = ^TOverwrittenData;
+ TOverwrittenData = record
+ Location: Pointer;
+ OldCode: array[0..6] of Byte;
+ end;
+
+procedure OverwriteProcedure(OldProcedure, NewProcedure: pointer; Data: POverwrittenData = nil);
+{ OverwriteProcedure originally from Igor Siticov }
+{ Modified by Jacques Garcia Vazquez }
+var
+ x: PAnsiChar;
+ y: integer;
+ ov2, ov: cardinal;
+ p: pointer;
+begin
+ if Assigned(Data) and (Data.Location <> nil) then
+ exit; { procedure already overwritten }
+
+ // need six bytes in place of 5
+ x := PAnsiChar(OldProcedure);
+ if not VirtualProtect(Pointer(x), 6, PAGE_EXECUTE_READWRITE, @ov) then
+ RaiseLastOSError;
+
+ // if a jump is present then a redirect is found
+ // $FF25 = jmp dword ptr [xxx]
+ // This redirect is normally present in bpl files, but not in exe files
+ p := OldProcedure;
+
+ if Word(p^) = $25FF then
+ begin
+ Inc(Integer(p), 2); // skip the jump
+ // get the jump address p^ and dereference it p^^
+ p := Pointer(Pointer(p^)^);
+
+ // release the memory
+ if not VirtualProtect(Pointer(x), 6, ov, @ov2) then
+ RaiseLastOSError;
+
+ // re protect the correct one
+ x := PAnsiChar(p);
+ if not VirtualProtect(Pointer(x), 6, PAGE_EXECUTE_READWRITE, @ov) then
+ RaiseLastOSError;
+ end;
+
+ if Assigned(Data) then
+ begin
+ Move(x^, Data.OldCode, 6);
+ { Assign Location last so that Location <> nil only if OldCode is properly initialized. }
+ Data.Location := x;
+ end;
+
+ x[0] := AnsiChar($E9);
+ y := integer(NewProcedure) - integer(p) - 5;
+ x[1] := AnsiChar(y and 255);
+ x[2] := AnsiChar((y shr 8) and 255);
+ x[3] := AnsiChar((y shr 16) and 255);
+ x[4] := AnsiChar((y shr 24) and 255);
+
+ if not VirtualProtect(Pointer(x), 6, ov, @ov2) then
+ RaiseLastOSError;
+end;
+
+procedure RestoreProcedure(OriginalProc: Pointer; Data: TOverwrittenData);
+var
+ ov, ov2: Cardinal;
+begin
+ if Data.Location <> nil then begin
+ if not VirtualProtect(Data.Location, 6, PAGE_EXECUTE_READWRITE, @ov) then
+ RaiseLastOSError;
+ Move(Data.OldCode, Data.Location^, 6);
+ if not VirtualProtect(Data.Location, 6, ov, @ov2) then
+ RaiseLastOSError;
+ end;
+end;
+
+function Addr_System_EndThread: Pointer;
+begin
+ Result := @System.EndThread;
+end;
+
+function Addr_System_LoadResString: Pointer;
+begin
+ Result := @System.LoadResString{TNT-ALLOW LoadResString};
+end;
+
+function Addr_System_WStrFromPCharLen: Pointer;
+asm
+ mov eax, offset System.@WStrFromPCharLen;
+end;
+
+{$IFNDEF COMPILER_9_UP}
+function Addr_System_LStrFromPWCharLen: Pointer;
+asm
+ mov eax, offset System.@LStrFromPWCharLen;
+end;
+
+function Addr_System_WStrToString: Pointer;
+asm
+ mov eax, offset System.@WStrToString;
+end;
+{$ENDIF}
+
+function Addr_System_VarFromLStr: Pointer;
+asm
+ mov eax, offset System.@VarFromLStr;
+end;
+
+function Addr_System_WStrCat3: Pointer;
+asm
+ mov eax, offset System.@WStrCat3;
+end;
+
+var
+ System_EndThread_Code,
+ System_LoadResString_Code,
+ System_WStrFromPCharLen_Code,
+ {$IFNDEF COMPILER_9_UP}
+ System_LStrFromPWCharLen_Code,
+ System_WStrToString_Code,
+ {$ENDIF}
+ System_VarFromLStr_Code
+ {$IFNDEF COMPILER_9_UP}
+ ,
+ System_WStrCat3_Code,
+ SysUtils_WideFmtStr_Code
+ {$ENDIF}
+ : TOverwrittenData;
+
+procedure InstallEndThreadOverride;
+begin
+ OverwriteProcedure(Addr_System_EndThread, @Custom_System_EndThread, @System_EndThread_Code);
+end;
+
+procedure InstallStringConversionOverrides;
+begin
+ OverwriteProcedure(Addr_System_WStrFromPCharLen, @Custom_System_WStrFromPCharLen, @System_WStrFromPCharLen_Code);
+ {$IFNDEF COMPILER_9_UP}
+ OverwriteProcedure(Addr_System_LStrFromPWCharLen, @Custom_System_LStrFromPWCharLen, @System_LStrFromPWCharLen_Code);
+ OverwriteProcedure(Addr_System_WStrToString, @Custom_System_WStrToString, @System_WStrToString_Code);
+ {$ENDIF}
+end;
+
+procedure InstallWideResourceStrings;
+begin
+ OverwriteProcedure(Addr_System_LoadResString, @Custom_System_LoadResString, @System_LoadResString_Code);
+ OverwriteProcedure(Addr_System_VarFromLStr, @Custom_System_VarFromLStr, @System_VarFromLStr_Code);
+end;
+
+{$IFNDEF COMPILER_9_UP}
+procedure InstallWideStringConcatenationFix;
+begin
+ OverwriteProcedure(Addr_System_WStrCat3, @Custom_System_WStrCat3, @System_WStrCat3_Code);
+end;
+
+procedure InstallWideFormatFixes;
+begin
+ OverwriteProcedure(@SysUtils.WideFmtStr, @TntSysUtils.Tnt_WideFmtStr, @SysUtils_WideFmtStr_Code);
+end;
+{$ENDIF}
+
+procedure InstallTntSystemUpdates(Updates: TTntSystemUpdateSet = AllTntSystemUpdates);
+begin
+ InstallEndThreadOverride;
+ if tsWideResourceStrings in Updates then begin
+ InstallStringConversionOverrides;
+ InstallWideResourceStrings;
+ end;
+ {$IFNDEF COMPILER_9_UP}
+ if tsFixImplicitCodePage in Updates then begin
+ InstallStringConversionOverrides;
+ { CP_ACP is the code page used by the non-Unicode Windows API. }
+ GDefaultSystemCodePage := CP_ACP{TNT-ALLOW CP_ACP};
+ end;
+ if tsFixWideStrConcat in Updates then begin
+ InstallWideStringConcatenationFix;
+ end;
+ if tsFixWideFormat in Updates then begin
+ InstallWideFormatFixes;
+ end;
+ {$ENDIF}
+end;
+
+{$IFNDEF COMPILER_9_UP}
+var
+ StartupDefaultUserCodePage: Cardinal;
+{$ENDIF}
+
+procedure UninstallSystemOverrides;
+begin
+ RestoreProcedure(Addr_System_EndThread, System_EndThread_Code);
+ // String Conversion
+ RestoreProcedure(Addr_System_WStrFromPCharLen, System_WStrFromPCharLen_Code);
+ {$IFNDEF COMPILER_9_UP}
+ RestoreProcedure(Addr_System_LStrFromPWCharLen, System_LStrFromPWCharLen_Code);
+ RestoreProcedure(Addr_System_WStrToString, System_WStrToString_Code);
+ GDefaultSystemCodePage := StartupDefaultUserCodePage;
+ {$ENDIF}
+ // Wide resourcestring
+ RestoreProcedure(Addr_System_LoadResString, System_LoadResString_Code);
+ RestoreProcedure(Addr_System_VarFromLStr, System_VarFromLStr_Code);
+ {$IFNDEF COMPILER_9_UP}
+ // WideString concat fix
+ RestoreProcedure(Addr_System_WStrCat3, System_WStrCat3_Code);
+ // WideFormat fixes
+ RestoreProcedure(@SysUtils.WideFmtStr, SysUtils_WideFmtStr_Code);
+ {$ENDIF}
+end;
+
+{$ENDIF USE_SYSTEM_OVERRIDES}
+
+initialization
+ {$IFDEF COMPILER_9_UP}
+ {$DEFINE USE_GETACP}
+ {$ENDIF}
+ {$IFDEF FPC}
+ {$DEFINE USE_GETACP}
+ {$ENDIF}
+ {$IFDEF USE_GETACP}
+ GDefaultSystemCodePage := GetACP;
+ {$ELSE}
+ {$IFDEF COMPILER_7_UP}
+ if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 5) then
+ GDefaultSystemCodePage := CP_THREAD_ACP // Win 2K/XP/...
+ else
+ GDefaultSystemCodePage := LCIDToCodePage(GetThreadLocale); // Win NT4/95/98/ME
+ {$ELSE}
+ GDefaultSystemCodePage := CP_ACP{TNT-ALLOW CP_ACP};
+ {$ENDIF}
+ {$ENDIF}
+ {$IFDEF USE_SYSTEM_OVERRIDES}
+ {$IFNDEF COMPILER_9_UP}
+ StartupDefaultUserCodePage := DefaultSystemCodePage;
+ {$ENDIF}
+ IsDebugging := DebugHook > 0;
+ {$ENDIF USE_SYSTEM_OVERRIDES}
+
+finalization
+ {$IFDEF USE_SYSTEM_OVERRIDES}
+ UninstallSystemOverrides;
+ FreeTntSystemThreadVars; { Make MemorySleuth happy. }
+ {$ENDIF USE_SYSTEM_OVERRIDES}
+
+end.
diff --git a/src/lib/TntUnicodeControls/TntWideStrUtils.pas b/src/lib/TntUnicodeControls/TntWideStrUtils.pas
new file mode 100644
index 00000000..99f63aea
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntWideStrUtils.pas
@@ -0,0 +1,455 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntWideStrUtils;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+interface
+
+{ Wide string manipulation functions }
+
+{$IFNDEF COMPILER_9_UP}
+function WStrAlloc(Size: Cardinal): PWideChar;
+function WStrBufSize(const Str: PWideChar): Cardinal;
+{$ENDIF}
+{$IFNDEF COMPILER_10_UP}
+function WStrMove(Dest: PWideChar; const Source: PWideChar; Count: Cardinal): PWideChar;
+{$ENDIF}
+{$IFNDEF COMPILER_9_UP}
+function WStrNew(const Str: PWideChar): PWideChar;
+procedure WStrDispose(Str: PWideChar);
+{$ENDIF}
+//---------------------------------------------------------------------------------------------
+{$IFNDEF COMPILER_9_UP}
+function WStrLen(Str: PWideChar): Cardinal;
+function WStrEnd(Str: PWideChar): PWideChar;
+{$ENDIF}
+{$IFNDEF COMPILER_10_UP}
+function WStrCat(Dest: PWideChar; const Source: PWideChar): PWideChar;
+{$ENDIF}
+{$IFNDEF COMPILER_9_UP}
+function WStrCopy(Dest, Source: PWideChar): PWideChar;
+function WStrLCopy(Dest, Source: PWideChar; MaxLen: Cardinal): PWideChar;
+function WStrPCopy(Dest: PWideChar; const Source: WideString): PWideChar;
+function WStrPLCopy(Dest: PWideChar; const Source: WideString; MaxLen: Cardinal): PWideChar;
+{$ENDIF}
+{$IFNDEF COMPILER_10_UP}
+function WStrScan(const Str: PWideChar; Chr: WideChar): PWideChar;
+// WStrComp and WStrPos were introduced as broken in Delphi 2006, but fixed in Delphi 2006 Update 2
+function WStrComp(Str1, Str2: PWideChar): Integer;
+function WStrPos(Str, SubStr: PWideChar): PWideChar;
+{$ENDIF}
+function Tnt_WStrComp(Str1, Str2: PWideChar): Integer; deprecated;
+function Tnt_WStrPos(Str, SubStr: PWideChar): PWideChar; deprecated;
+
+{ ------------ introduced --------------- }
+function WStrECopy(Dest, Source: PWideChar): PWideChar;
+function WStrLComp(Str1, Str2: PWideChar; MaxLen: Cardinal): Integer;
+function WStrLIComp(Str1, Str2: PWideChar; MaxLen: Cardinal): Integer;
+function WStrIComp(Str1, Str2: PWideChar): Integer;
+function WStrLower(Str: PWideChar): PWideChar;
+function WStrUpper(Str: PWideChar): PWideChar;
+function WStrRScan(const Str: PWideChar; Chr: WideChar): PWideChar;
+function WStrLCat(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar;
+function WStrPas(const Str: PWideChar): WideString;
+
+{ SysUtils.pas } //-------------------------------------------------------------------------
+
+{$IFNDEF COMPILER_10_UP}
+function WideLastChar(const S: WideString): PWideChar;
+function WideQuotedStr(const S: WideString; Quote: WideChar): WideString;
+{$ENDIF}
+{$IFNDEF COMPILER_9_UP}
+function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): Widestring;
+{$ENDIF}
+{$IFNDEF COMPILER_10_UP}
+function WideDequotedStr(const S: WideString; AQuote: WideChar): WideString;
+{$ENDIF}
+
+implementation
+
+uses
+ {$IFDEF COMPILER_9_UP} WideStrUtils, {$ENDIF} Math, Windows, TntWindows;
+
+{$IFNDEF COMPILER_9_UP}
+function WStrAlloc(Size: Cardinal): PWideChar;
+begin
+ Size := SizeOf(Cardinal) + (Size * SizeOf(WideChar));
+ GetMem(Result, Size);
+ PCardinal(Result)^ := Size;
+ Inc(PAnsiChar(Result), SizeOf(Cardinal));
+end;
+
+function WStrBufSize(const Str: PWideChar): Cardinal;
+var
+ P: PWideChar;
+begin
+ P := Str;
+ Dec(PAnsiChar(P), SizeOf(Cardinal));
+ Result := PCardinal(P)^ - SizeOf(Cardinal);
+ Result := Result div SizeOf(WideChar);
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_10_UP}
+function WStrMove(Dest: PWideChar; const Source: PWideChar; Count: Cardinal): PWideChar;
+var
+ Length: Integer;
+begin
+ Result := Dest;
+ Length := Count * SizeOf(WideChar);
+ Move(Source^, Dest^, Length);
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_9_UP}
+function WStrNew(const Str: PWideChar): PWideChar;
+var
+ Size: Cardinal;
+begin
+ if Str = nil then Result := nil else
+ begin
+ Size := WStrLen(Str) + 1;
+ Result := WStrMove(WStrAlloc(Size), Str, Size);
+ end;
+end;
+
+procedure WStrDispose(Str: PWideChar);
+begin
+ if Str <> nil then
+ begin
+ Dec(PAnsiChar(Str), SizeOf(Cardinal));
+ FreeMem(Str, Cardinal(Pointer(Str)^));
+ end;
+end;
+{$ENDIF}
+
+//---------------------------------------------------------------------------------------------
+
+{$IFNDEF COMPILER_9_UP}
+function WStrLen(Str: PWideChar): Cardinal;
+begin
+ Result := WStrEnd(Str) - Str;
+end;
+
+function WStrEnd(Str: PWideChar): PWideChar;
+begin
+ // returns a pointer to the end of a null terminated string
+ Result := Str;
+ While Result^ <> #0 do
+ Inc(Result);
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_10_UP}
+function WStrCat(Dest: PWideChar; const Source: PWideChar): PWideChar;
+begin
+ Result := Dest;
+ WStrCopy(WStrEnd(Dest), Source);
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_9_UP}
+function WStrCopy(Dest, Source: PWideChar): PWideChar;
+begin
+ Result := WStrLCopy(Dest, Source, MaxInt);
+end;
+
+function WStrLCopy(Dest, Source: PWideChar; MaxLen: Cardinal): PWideChar;
+var
+ Count: Cardinal;
+begin
+ // copies a specified maximum number of characters from Source to Dest
+ Result := Dest;
+ Count := 0;
+ While (Count < MaxLen) and (Source^ <> #0) do begin
+ Dest^ := Source^;
+ Inc(Source);
+ Inc(Dest);
+ Inc(Count);
+ end;
+ Dest^ := #0;
+end;
+
+function WStrPCopy(Dest: PWideChar; const Source: WideString): PWideChar;
+begin
+ Result := WStrLCopy(Dest, PWideChar(Source), Length(Source));
+end;
+
+function WStrPLCopy(Dest: PWideChar; const Source: WideString; MaxLen: Cardinal): PWideChar;
+begin
+ Result := WStrLCopy(Dest, PWideChar(Source), MaxLen);
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_10_UP}
+function WStrScan(const Str: PWideChar; Chr: WideChar): PWideChar;
+begin
+ Result := Str;
+ while Result^ <> Chr do
+ begin
+ if Result^ = #0 then
+ begin
+ Result := nil;
+ Exit;
+ end;
+ Inc(Result);
+ end;
+end;
+
+function WStrComp(Str1, Str2: PWideChar): Integer;
+begin
+ Result := WStrLComp(Str1, Str2, MaxInt);
+end;
+
+function WStrPos(Str, SubStr: PWideChar): PWideChar;
+var
+ PSave: PWideChar;
+ P: PWideChar;
+ PSub: PWideChar;
+begin
+ // returns a pointer to the first occurance of SubStr in Str
+ Result := nil;
+ if (Str <> nil) and (Str^ <> #0) and (SubStr <> nil) and (SubStr^ <> #0) then begin
+ P := Str;
+ While P^ <> #0 do begin
+ if P^ = SubStr^ then begin
+ // investigate possibility here
+ PSave := P;
+ PSub := SubStr;
+ While (P^ = PSub^) do begin
+ Inc(P);
+ Inc(PSub);
+ if (PSub^ = #0) then begin
+ Result := PSave;
+ exit; // found a match
+ end;
+ if (P^ = #0) then
+ exit; // no match, hit end of string
+ end;
+ P := PSave;
+ end;
+ Inc(P);
+ end;
+ end;
+end;
+{$ENDIF}
+
+function Tnt_WStrComp(Str1, Str2: PWideChar): Integer; deprecated;
+begin
+ Result := WStrComp(Str1, Str2);
+end;
+
+function Tnt_WStrPos(Str, SubStr: PWideChar): PWideChar; deprecated;
+begin
+ Result := WStrPos(Str, SubStr);
+end;
+
+//------------------------------------------------------------------------------
+
+function WStrECopy(Dest, Source: PWideChar): PWideChar;
+begin
+ Result := WStrEnd(WStrCopy(Dest, Source));
+end;
+
+function WStrComp_EX(Str1, Str2: PWideChar; MaxLen: Cardinal; dwCmpFlags: Cardinal): Integer;
+var
+ Len1, Len2: Integer;
+begin
+ if MaxLen = Cardinal(MaxInt) then begin
+ Len1 := -1;
+ Len2 := -1;
+ end else begin
+ Len1 := Min(WStrLen(Str1), MaxLen);
+ Len2 := Min(WStrLen(Str2), MaxLen);
+ end;
+ Result := Tnt_CompareStringW(GetThreadLocale, dwCmpFlags, Str1, Len1, Str2, Len2) - 2;
+end;
+
+function WStrLComp(Str1, Str2: PWideChar; MaxLen: Cardinal): Integer;
+begin
+ Result := WStrComp_EX(Str1, Str2, MaxLen, 0);
+end;
+
+function WStrLIComp(Str1, Str2: PWideChar; MaxLen: Cardinal): Integer;
+begin
+ Result := WStrComp_EX(Str1, Str2, MaxLen, NORM_IGNORECASE);
+end;
+
+function WStrIComp(Str1, Str2: PWideChar): Integer;
+begin
+ Result := WStrLIComp(Str1, Str2, MaxInt);
+end;
+
+function WStrLower(Str: PWideChar): PWideChar;
+begin
+ Result := Str;
+ Tnt_CharLowerBuffW(Str, WStrLen(Str))
+end;
+
+function WStrUpper(Str: PWideChar): PWideChar;
+begin
+ Result := Str;
+ Tnt_CharUpperBuffW(Str, WStrLen(Str))
+end;
+
+function WStrRScan(const Str: PWideChar; Chr: WideChar): PWideChar;
+var
+ MostRecentFound: PWideChar;
+begin
+ if Chr = #0 then
+ Result := WStrEnd(Str)
+ else
+ begin
+ Result := nil;
+ MostRecentFound := Str;
+ while True do
+ begin
+ while MostRecentFound^ <> Chr do
+ begin
+ if MostRecentFound^ = #0 then
+ Exit;
+ Inc(MostRecentFound);
+ end;
+ Result := MostRecentFound;
+ Inc(MostRecentFound);
+ end;
+ end;
+end;
+
+function WStrLCat(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar;
+begin
+ Result := Dest;
+ WStrLCopy(WStrEnd(Dest), Source, MaxLen - WStrLen(Dest));
+end;
+
+function WStrPas(const Str: PWideChar): WideString;
+begin
+ Result := Str;
+end;
+
+//---------------------------------------------------------------------------------------------
+
+{$IFNDEF COMPILER_10_UP}
+function WideLastChar(const S: WideString): PWideChar;
+begin
+ if S = '' then
+ Result := nil
+ else
+ Result := @S[Length(S)];
+end;
+
+function WideQuotedStr(const S: WideString; Quote: WideChar): WideString;
+var
+ P, Src,
+ Dest: PWideChar;
+ AddCount: Integer;
+begin
+ AddCount := 0;
+ P := WStrScan(PWideChar(S), Quote);
+ while (P <> nil) do
+ begin
+ Inc(P);
+ Inc(AddCount);
+ P := WStrScan(P, Quote);
+ end;
+
+ if AddCount = 0 then
+ Result := Quote + S + Quote
+ else
+ begin
+ SetLength(Result, Length(S) + AddCount + 2);
+ Dest := PWideChar(Result);
+ Dest^ := Quote;
+ Inc(Dest);
+ Src := PWideChar(S);
+ P := WStrScan(Src, Quote);
+ repeat
+ Inc(P);
+ Move(Src^, Dest^, 2 * (P - Src));
+ Inc(Dest, P - Src);
+ Dest^ := Quote;
+ Inc(Dest);
+ Src := P;
+ P := WStrScan(Src, Quote);
+ until P = nil;
+ P := WStrEnd(Src);
+ Move(Src^, Dest^, 2 * (P - Src));
+ Inc(Dest, P - Src);
+ Dest^ := Quote;
+ end;
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_9_UP}
+function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): Widestring;
+var
+ P, Dest: PWideChar;
+ DropCount: Integer;
+begin
+ Result := '';
+ if (Src = nil) or (Src^ <> Quote) then Exit;
+ Inc(Src);
+ DropCount := 1;
+ P := Src;
+ Src := WStrScan(Src, Quote);
+ while Src <> nil do // count adjacent pairs of quote chars
+ begin
+ Inc(Src);
+ if Src^ <> Quote then Break;
+ Inc(Src);
+ Inc(DropCount);
+ Src := WStrScan(Src, Quote);
+ end;
+ if Src = nil then Src := WStrEnd(P);
+ if ((Src - P) <= 1) then Exit;
+ if DropCount = 1 then
+ SetString(Result, P, Src - P - 1)
+ else
+ begin
+ SetLength(Result, Src - P - DropCount);
+ Dest := PWideChar(Result);
+ Src := WStrScan(P, Quote);
+ while Src <> nil do
+ begin
+ Inc(Src);
+ if Src^ <> Quote then Break;
+ Move(P^, Dest^, (Src - P) * SizeOf(WideChar));
+ Inc(Dest, Src - P);
+ Inc(Src);
+ P := Src;
+ Src := WStrScan(Src, Quote);
+ end;
+ if Src = nil then Src := WStrEnd(P);
+ Move(P^, Dest^, (Src - P - 1) * SizeOf(WideChar));
+ end;
+end;
+{$ENDIF}
+
+{$IFNDEF COMPILER_10_UP}
+function WideDequotedStr(const S: WideString; AQuote: WideChar): WideString;
+var
+ LText : PWideChar;
+begin
+ LText := PWideChar(S);
+ Result := WideExtractQuotedStr(LText, AQuote);
+ if Result = '' then
+ Result := S;
+end;
+{$ENDIF}
+
+
+end.
diff --git a/src/lib/TntUnicodeControls/TntWideStrings.pas b/src/lib/TntUnicodeControls/TntWideStrings.pas
new file mode 100644
index 00000000..75132d22
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntWideStrings.pas
@@ -0,0 +1,846 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntWideStrings;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+interface
+
+{$IFDEF COMPILER_10_UP}
+ {$MESSAGE FATAL 'Do not refer to TntWideStrings.pas. It works correctly in Delphi 2006.'}
+{$ENDIF}
+
+uses
+ Classes;
+
+{******************************************************************************}
+{ }
+{ Delphi 2005 introduced TWideStrings in WideStrings.pas. }
+{ Unfortunately, it was not ready for prime time. }
+{ Setting CommaText is not consistent, and it relies on CharNextW }
+{ Which is only available on Windows NT+. }
+{ }
+{******************************************************************************}
+
+type
+ TWideStrings = class;
+
+{ IWideStringsAdapter interface }
+{ Maintains link between TWideStrings and IWideStrings implementations }
+
+ IWideStringsAdapter = interface
+ ['{25FE0E3B-66CB-48AA-B23B-BCFA67E8F5DA}']
+ procedure ReferenceStrings(S: TWideStrings);
+ procedure ReleaseStrings;
+ end;
+
+ TWideStringsEnumerator = class
+ private
+ FIndex: Integer;
+ FStrings: TWideStrings;
+ public
+ constructor Create(AStrings: TWideStrings);
+ function GetCurrent: WideString;
+ function MoveNext: Boolean;
+ property Current: WideString read GetCurrent;
+ end;
+
+{$IFDEF FPC}
+ TStringsDefined = set of (
+ sdDelimiter, sdQuoteChar, sdNameValueSeparator, sdLineBreak,
+ sdStrictDelimiter);
+{$ENDIF}
+
+{$DEFINE NAMEVALUESEPARATOR_RW}
+{$IFNDEF COMPILER_7_UP}
+ {$UNDEF NAMEVALUESEPARATOR_RW}
+{$ENDIF}
+
+{ TWideStrings class }
+
+ TWideStrings = class(TPersistent)
+ private
+ FDefined: TStringsDefined;
+ FDelimiter: WideChar;
+ FQuoteChar: WideChar;
+ {$IFDEF NAMEVALUESEPARATOR_RW}
+ FNameValueSeparator: WideChar;
+ {$ENDIF}
+ FUpdateCount: Integer;
+ FAdapter: IWideStringsAdapter;
+ function GetCommaText: WideString;
+ function GetDelimitedText: WideString;
+ function GetName(Index: Integer): WideString;
+ function GetValue(const Name: WideString): WideString;
+ procedure ReadData(Reader: TReader);
+ procedure SetCommaText(const Value: WideString);
+ procedure SetDelimitedText(const Value: WideString);
+ procedure SetStringsAdapter(const Value: IWideStringsAdapter);
+ procedure SetValue(const Name, Value: WideString);
+ procedure WriteData(Writer: TWriter);
+ function GetDelimiter: WideChar;
+ procedure SetDelimiter(const Value: WideChar);
+ function GetQuoteChar: WideChar;
+ procedure SetQuoteChar(const Value: WideChar);
+ function GetNameValueSeparator: WideChar;
+ {$IFDEF NAMEVALUESEPARATOR_RW}
+ procedure SetNameValueSeparator(const Value: WideChar);
+ {$ENDIF}
+ function GetValueFromIndex(Index: Integer): WideString;
+ procedure SetValueFromIndex(Index: Integer; const Value: WideString);
+ protected
+ procedure AssignTo(Dest: TPersistent); override;
+ procedure DefineProperties(Filer: TFiler); override;
+ procedure Error(const Msg: WideString; Data: Integer); overload;
+ procedure Error(Msg: PResStringRec; Data: Integer); overload;
+ function ExtractName(const S: WideString): WideString;
+ function Get(Index: Integer): WideString; virtual; abstract;
+ function GetCapacity: Integer; virtual;
+ function GetCount: Integer; virtual; abstract;
+ function GetObject(Index: Integer): TObject; virtual;
+ function GetTextStr: WideString; virtual;
+ procedure Put(Index: Integer; const S: WideString); virtual;
+ procedure PutObject(Index: Integer; AObject: TObject); virtual;
+ procedure SetCapacity(NewCapacity: Integer); virtual;
+ procedure SetTextStr(const Value: WideString); virtual;
+ procedure SetUpdateState(Updating: Boolean); virtual;
+ property UpdateCount: Integer read FUpdateCount;
+ function CompareStrings(const S1, S2: WideString): Integer; virtual;
+ public
+ destructor Destroy; override;
+ function Add(const S: WideString): Integer; virtual;
+ function AddObject(const S: WideString; AObject: TObject): Integer; virtual;
+ procedure Append(const S: WideString);
+ procedure AddStrings(Strings: TStrings{TNT-ALLOW TStrings}); overload; virtual;
+ procedure AddStrings(Strings: TWideStrings); overload; virtual;
+ procedure Assign(Source: TPersistent); override;
+ procedure BeginUpdate;
+ procedure Clear; virtual; abstract;
+ procedure Delete(Index: Integer); virtual; abstract;
+ procedure EndUpdate;
+ function Equals(Strings: TWideStrings): Boolean;
+ procedure Exchange(Index1, Index2: Integer); virtual;
+ function GetEnumerator: TWideStringsEnumerator;
+ function GetTextW: PWideChar; virtual;
+ function IndexOf(const S: WideString): Integer; virtual;
+ function IndexOfName(const Name: WideString): Integer; virtual;
+ function IndexOfObject(AObject: TObject): Integer; virtual;
+ procedure Insert(Index: Integer; const S: WideString); virtual; abstract;
+ procedure InsertObject(Index: Integer; const S: WideString;
+ AObject: TObject); virtual;
+ procedure LoadFromFile(const FileName: WideString); virtual;
+ procedure LoadFromStream(Stream: TStream); virtual;
+ procedure Move(CurIndex, NewIndex: Integer); virtual;
+ procedure SaveToFile(const FileName: WideString); virtual;
+ procedure SaveToStream(Stream: TStream); virtual;
+ procedure SetTextW(const Text: PWideChar); virtual;
+ property Capacity: Integer read GetCapacity write SetCapacity;
+ property CommaText: WideString read GetCommaText write SetCommaText;
+ property Count: Integer read GetCount;
+ property Delimiter: WideChar read GetDelimiter write SetDelimiter;
+ property DelimitedText: WideString read GetDelimitedText write SetDelimitedText;
+ property Names[Index: Integer]: WideString read GetName;
+ property Objects[Index: Integer]: TObject read GetObject write PutObject;
+ property QuoteChar: WideChar read GetQuoteChar write SetQuoteChar;
+ property Values[const Name: WideString]: WideString read GetValue write SetValue;
+ property ValueFromIndex[Index: Integer]: WideString read GetValueFromIndex write SetValueFromIndex;
+ property NameValueSeparator: WideChar read GetNameValueSeparator {$IFDEF NAMEVALUESEPARATOR_RW} write SetNameValueSeparator {$ENDIF};
+ property Strings[Index: Integer]: WideString read Get write Put; default;
+ property Text: WideString read GetTextStr write SetTextStr;
+ property StringsAdapter: IWideStringsAdapter read FAdapter write SetStringsAdapter;
+ end;
+
+ PWideStringItem = ^TWideStringItem;
+ TWideStringItem = record
+ FString: WideString;
+ FObject: TObject;
+ end;
+
+ PWideStringItemList = ^TWideStringItemList;
+ TWideStringItemList = array[0..MaxListSize] of TWideStringItem;
+
+implementation
+
+uses
+ Windows, SysUtils, TntSystem, {$IFDEF COMPILER_9_UP} WideStrUtils, {$ELSE} TntWideStrUtils, {$ENDIF}
+ TntSysUtils, TntClasses;
+
+{ TWideStringsEnumerator }
+
+constructor TWideStringsEnumerator.Create(AStrings: TWideStrings);
+begin
+ inherited Create;
+ FIndex := -1;
+ FStrings := AStrings;
+end;
+
+function TWideStringsEnumerator.GetCurrent: WideString;
+begin
+ Result := FStrings[FIndex];
+end;
+
+function TWideStringsEnumerator.MoveNext: Boolean;
+begin
+ Result := FIndex < FStrings.Count - 1;
+ if Result then
+ Inc(FIndex);
+end;
+
+{ TWideStrings }
+
+destructor TWideStrings.Destroy;
+begin
+ StringsAdapter := nil;
+ inherited;
+end;
+
+function TWideStrings.Add(const S: WideString): Integer;
+begin
+ Result := GetCount;
+ Insert(Result, S);
+end;
+
+function TWideStrings.AddObject(const S: WideString; AObject: TObject): Integer;
+begin
+ Result := Add(S);
+ PutObject(Result, AObject);
+end;
+
+procedure TWideStrings.Append(const S: WideString);
+begin
+ Add(S);
+end;
+
+procedure TWideStrings.AddStrings(Strings: TStrings{TNT-ALLOW TStrings});
+var
+ I: Integer;
+begin
+ BeginUpdate;
+ try
+ for I := 0 to Strings.Count - 1 do
+ AddObject(Strings[I], Strings.Objects[I]);
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TWideStrings.AddStrings(Strings: TWideStrings);
+var
+ I: Integer;
+begin
+ BeginUpdate;
+ try
+ for I := 0 to Strings.Count - 1 do
+ AddObject(Strings[I], Strings.Objects[I]);
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TWideStrings.Assign(Source: TPersistent);
+begin
+ if Source is TWideStrings then
+ begin
+ BeginUpdate;
+ try
+ Clear;
+ FDefined := TWideStrings(Source).FDefined;
+ {$IFDEF NAMEVALUESEPARATOR_RW}
+ FNameValueSeparator := TWideStrings(Source).FNameValueSeparator;
+ {$ENDIF}
+ FQuoteChar := TWideStrings(Source).FQuoteChar;
+ FDelimiter := TWideStrings(Source).FDelimiter;
+ AddStrings(TWideStrings(Source));
+ finally
+ EndUpdate;
+ end;
+ end
+ else if Source is TStrings{TNT-ALLOW TStrings} then
+ begin
+ BeginUpdate;
+ try
+ Clear;
+ {$IFDEF NAMEVALUESEPARATOR_RW}
+ FNameValueSeparator := WideChar(TStrings{TNT-ALLOW TStrings}(Source).NameValueSeparator);
+ {$ENDIF}
+ FQuoteChar := WideChar(TStrings{TNT-ALLOW TStrings}(Source).QuoteChar);
+ FDelimiter := WideChar(TStrings{TNT-ALLOW TStrings}(Source).Delimiter);
+ AddStrings(TStrings{TNT-ALLOW TStrings}(Source));
+ finally
+ EndUpdate;
+ end;
+ end
+ else
+ inherited Assign(Source);
+end;
+
+procedure TWideStrings.AssignTo(Dest: TPersistent);
+var
+ I: Integer;
+begin
+ if Dest is TWideStrings then Dest.Assign(Self)
+ else if Dest is TStrings{TNT-ALLOW TStrings} then
+ begin
+ TStrings{TNT-ALLOW TStrings}(Dest).BeginUpdate;
+ try
+ TStrings{TNT-ALLOW TStrings}(Dest).Clear;
+ {$IFDEF NAMEVALUESEPARATOR_RW}
+ TStrings{TNT-ALLOW TStrings}(Dest).NameValueSeparator := AnsiChar(NameValueSeparator);
+ {$ENDIF}
+ TStrings{TNT-ALLOW TStrings}(Dest).QuoteChar := AnsiChar(QuoteChar);
+ TStrings{TNT-ALLOW TStrings}(Dest).Delimiter := AnsiChar(Delimiter);
+ for I := 0 to Count - 1 do
+ TStrings{TNT-ALLOW TStrings}(Dest).AddObject(Strings[I], Objects[I]);
+ finally
+ TStrings{TNT-ALLOW TStrings}(Dest).EndUpdate;
+ end;
+ end
+ else
+ inherited AssignTo(Dest);
+end;
+
+procedure TWideStrings.BeginUpdate;
+begin
+ if FUpdateCount = 0 then SetUpdateState(True);
+ Inc(FUpdateCount);
+end;
+
+procedure TWideStrings.DefineProperties(Filer: TFiler);
+
+ function DoWrite: Boolean;
+ begin
+ if Filer.Ancestor <> nil then
+ begin
+ Result := True;
+ if Filer.Ancestor is TWideStrings then
+ Result := not Equals(TWideStrings(Filer.Ancestor))
+ end
+ else Result := Count > 0;
+ end;
+
+begin
+ Filer.DefineProperty('Strings', ReadData, WriteData, DoWrite);
+end;
+
+procedure TWideStrings.EndUpdate;
+begin
+ Dec(FUpdateCount);
+ if FUpdateCount = 0 then SetUpdateState(False);
+end;
+
+function TWideStrings.Equals(Strings: TWideStrings): Boolean;
+var
+ I, Count: Integer;
+begin
+ Result := False;
+ Count := GetCount;
+ if Count <> Strings.GetCount then Exit;
+ for I := 0 to Count - 1 do if Get(I) <> Strings.Get(I) then Exit;
+ Result := True;
+end;
+
+procedure TWideStrings.Error(const Msg: WideString; Data: Integer);
+
+ function ReturnAddr: Pointer;
+ asm
+ MOV EAX,[EBP+4]
+ end;
+
+begin
+ raise EStringListError.CreateFmt(Msg, [Data]) at ReturnAddr;
+end;
+
+procedure TWideStrings.Error(Msg: PResStringRec; Data: Integer);
+begin
+ Error(WideLoadResString(Msg), Data);
+end;
+
+procedure TWideStrings.Exchange(Index1, Index2: Integer);
+var
+ TempObject: TObject;
+ TempString: WideString;
+begin
+ BeginUpdate;
+ try
+ TempString := Strings[Index1];
+ TempObject := Objects[Index1];
+ Strings[Index1] := Strings[Index2];
+ Objects[Index1] := Objects[Index2];
+ Strings[Index2] := TempString;
+ Objects[Index2] := TempObject;
+ finally
+ EndUpdate;
+ end;
+end;
+
+function TWideStrings.ExtractName(const S: WideString): WideString;
+var
+ P: Integer;
+begin
+ Result := S;
+ P := Pos(NameValueSeparator, Result);
+ if P <> 0 then
+ SetLength(Result, P-1) else
+ SetLength(Result, 0);
+end;
+
+function TWideStrings.GetCapacity: Integer;
+begin // descendents may optionally override/replace this default implementation
+ Result := Count;
+end;
+
+function TWideStrings.GetCommaText: WideString;
+var
+ LOldDefined: TStringsDefined;
+ LOldDelimiter: WideChar;
+ LOldQuoteChar: WideChar;
+begin
+ LOldDefined := FDefined;
+ LOldDelimiter := FDelimiter;
+ LOldQuoteChar := FQuoteChar;
+ Delimiter := ',';
+ QuoteChar := '"';
+ try
+ Result := GetDelimitedText;
+ finally
+ FDelimiter := LOldDelimiter;
+ FQuoteChar := LOldQuoteChar;
+ FDefined := LOldDefined;
+ end;
+end;
+
+function TWideStrings.GetDelimitedText: WideString;
+var
+ S: WideString;
+ P: PWideChar;
+ I, Count: Integer;
+begin
+ Count := GetCount;
+ if (Count = 1) and (Get(0) = '') then
+ Result := WideString(QuoteChar) + QuoteChar
+ else
+ begin
+ Result := '';
+ for I := 0 to Count - 1 do
+ begin
+ S := Get(I);
+ P := PWideChar(S);
+ while not ((P^ in [WideChar(#0)..WideChar(' ')]) or (P^ = QuoteChar) or (P^ = Delimiter)) do
+ Inc(P);
+ if (P^ <> #0) then S := WideQuotedStr(S, QuoteChar);
+ Result := Result + S + Delimiter;
+ end;
+ System.Delete(Result, Length(Result), 1);
+ end;
+end;
+
+function TWideStrings.GetName(Index: Integer): WideString;
+begin
+ Result := ExtractName(Get(Index));
+end;
+
+function TWideStrings.GetObject(Index: Integer): TObject;
+begin
+ Result := nil;
+end;
+
+function TWideStrings.GetEnumerator: TWideStringsEnumerator;
+begin
+ Result := TWideStringsEnumerator.Create(Self);
+end;
+
+function TWideStrings.GetTextW: PWideChar;
+begin
+ Result := WStrNew(PWideChar(GetTextStr));
+end;
+
+function TWideStrings.GetTextStr: WideString;
+var
+ I, L, Size, Count: Integer;
+ P: PWideChar;
+ S, LB: WideString;
+begin
+ Count := GetCount;
+ Size := 0;
+ LB := sLineBreak;
+ for I := 0 to Count - 1 do Inc(Size, Length(Get(I)) + Length(LB));
+ SetString(Result, nil, Size);
+ P := Pointer(Result);
+ for I := 0 to Count - 1 do
+ begin
+ S := Get(I);
+ L := Length(S);
+ if L <> 0 then
+ begin
+ System.Move(Pointer(S)^, P^, L * SizeOf(WideChar));
+ Inc(P, L);
+ end;
+ L := Length(LB);
+ if L <> 0 then
+ begin
+ System.Move(Pointer(LB)^, P^, L * SizeOf(WideChar));
+ Inc(P, L);
+ end;
+ end;
+end;
+
+function TWideStrings.GetValue(const Name: WideString): WideString;
+var
+ I: Integer;
+begin
+ I := IndexOfName(Name);
+ if I >= 0 then
+ Result := Copy(Get(I), Length(Name) + 2, MaxInt) else
+ Result := '';
+end;
+
+function TWideStrings.IndexOf(const S: WideString): Integer;
+begin
+ for Result := 0 to GetCount - 1 do
+ if CompareStrings(Get(Result), S) = 0 then Exit;
+ Result := -1;
+end;
+
+function TWideStrings.IndexOfName(const Name: WideString): Integer;
+var
+ P: Integer;
+ S: WideString;
+begin
+ for Result := 0 to GetCount - 1 do
+ begin
+ S := Get(Result);
+ P := Pos(NameValueSeparator, S);
+ if (P <> 0) and (CompareStrings(Copy(S, 1, P - 1), Name) = 0) then Exit;
+ end;
+ Result := -1;
+end;
+
+function TWideStrings.IndexOfObject(AObject: TObject): Integer;
+begin
+ for Result := 0 to GetCount - 1 do
+ if GetObject(Result) = AObject then Exit;
+ Result := -1;
+end;
+
+procedure TWideStrings.InsertObject(Index: Integer; const S: WideString;
+ AObject: TObject);
+begin
+ Insert(Index, S);
+ PutObject(Index, AObject);
+end;
+
+procedure TWideStrings.LoadFromFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TWideStrings.LoadFromStream(Stream: TStream);
+var
+ Size: Integer;
+ S: WideString;
+begin
+ BeginUpdate;
+ try
+ Size := Stream.Size - Stream.Position;
+ SetString(S, nil, Size div SizeOf(WideChar));
+ Stream.Read(Pointer(S)^, Length(S) * SizeOf(WideChar));
+ SetTextStr(S);
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TWideStrings.Move(CurIndex, NewIndex: Integer);
+var
+ TempObject: TObject;
+ TempString: WideString;
+begin
+ if CurIndex <> NewIndex then
+ begin
+ BeginUpdate;
+ try
+ TempString := Get(CurIndex);
+ TempObject := GetObject(CurIndex);
+ Delete(CurIndex);
+ InsertObject(NewIndex, TempString, TempObject);
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+procedure TWideStrings.Put(Index: Integer; const S: WideString);
+var
+ TempObject: TObject;
+begin
+ TempObject := GetObject(Index);
+ Delete(Index);
+ InsertObject(Index, S, TempObject);
+end;
+
+procedure TWideStrings.PutObject(Index: Integer; AObject: TObject);
+begin
+end;
+
+procedure TWideStrings.ReadData(Reader: TReader);
+begin
+ if Reader.NextValue in [vaString, vaLString] then
+ SetTextStr(Reader.ReadString) {JCL compatiblity}
+ else if Reader.NextValue = vaWString then
+ SetTextStr(Reader.ReadWideString) {JCL compatiblity}
+ else begin
+ BeginUpdate;
+ try
+ Clear;
+ Reader.ReadListBegin;
+ while not Reader.EndOfList do
+ if Reader.NextValue in [vaString, vaLString] then
+ Add(Reader.ReadString) {TStrings compatiblity}
+ else
+ Add(Reader.ReadWideString);
+ Reader.ReadListEnd;
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+procedure TWideStrings.SaveToFile(const FileName: WideString);
+var
+ Stream: TStream;
+begin
+ Stream := TTntFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+procedure TWideStrings.SaveToStream(Stream: TStream);
+var
+ SW: WideString;
+begin
+ SW := GetTextStr;
+ Stream.WriteBuffer(PWideChar(SW)^, Length(SW) * SizeOf(WideChar));
+end;
+
+procedure TWideStrings.SetCapacity(NewCapacity: Integer);
+begin
+ // do nothing - descendents may optionally implement this method
+end;
+
+procedure TWideStrings.SetCommaText(const Value: WideString);
+begin
+ Delimiter := ',';
+ QuoteChar := '"';
+ SetDelimitedText(Value);
+end;
+
+procedure TWideStrings.SetStringsAdapter(const Value: IWideStringsAdapter);
+begin
+ if FAdapter <> nil then FAdapter.ReleaseStrings;
+ FAdapter := Value;
+ if FAdapter <> nil then FAdapter.ReferenceStrings(Self);
+end;
+
+procedure TWideStrings.SetTextW(const Text: PWideChar);
+begin
+ SetTextStr(Text);
+end;
+
+procedure TWideStrings.SetTextStr(const Value: WideString);
+var
+ P, Start: PWideChar;
+ S: WideString;
+begin
+ BeginUpdate;
+ try
+ Clear;
+ P := Pointer(Value);
+ if P <> nil then
+ while P^ <> #0 do
+ begin
+ Start := P;
+ while not (P^ in [WideChar(#0), WideChar(#10), WideChar(#13)]) and (P^ <> WideLineSeparator) do
+ Inc(P);
+ SetString(S, Start, P - Start);
+ Add(S);
+ if P^ = #13 then Inc(P);
+ if P^ = #10 then Inc(P);
+ if P^ = WideLineSeparator then Inc(P);
+ end;
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TWideStrings.SetUpdateState(Updating: Boolean);
+begin
+end;
+
+procedure TWideStrings.SetValue(const Name, Value: WideString);
+var
+ I: Integer;
+begin
+ I := IndexOfName(Name);
+ if Value <> '' then
+ begin
+ if I < 0 then I := Add('');
+ Put(I, Name + NameValueSeparator + Value);
+ end else
+ begin
+ if I >= 0 then Delete(I);
+ end;
+end;
+
+procedure TWideStrings.WriteData(Writer: TWriter);
+var
+ I: Integer;
+begin
+ Writer.WriteListBegin;
+ for I := 0 to Count-1 do begin
+ Writer.WriteWideString(Get(I));
+ end;
+ Writer.WriteListEnd;
+end;
+
+procedure TWideStrings.SetDelimitedText(const Value: WideString);
+var
+ P, P1: PWideChar;
+ S: WideString;
+begin
+ BeginUpdate;
+ try
+ Clear;
+ P := PWideChar(Value);
+ while P^ in [WideChar(#1)..WideChar(' ')] do
+ Inc(P);
+ while P^ <> #0 do
+ begin
+ if P^ = QuoteChar then
+ S := WideExtractQuotedStr(P, QuoteChar)
+ else
+ begin
+ P1 := P;
+ while (P^ > ' ') and (P^ <> Delimiter) do
+ Inc(P);
+ SetString(S, P1, P - P1);
+ end;
+ Add(S);
+ while P^ in [WideChar(#1)..WideChar(' ')] do
+ Inc(P);
+ if P^ = Delimiter then
+ begin
+ P1 := P;
+ Inc(P1);
+ if P1^ = #0 then
+ Add('');
+ repeat
+ Inc(P);
+ until not (P^ in [WideChar(#1)..WideChar(' ')]);
+ end;
+ end;
+ finally
+ EndUpdate;
+ end;
+end;
+
+function TWideStrings.GetDelimiter: WideChar;
+begin
+ if not (sdDelimiter in FDefined) then
+ Delimiter := ',';
+ Result := FDelimiter;
+end;
+
+function TWideStrings.GetQuoteChar: WideChar;
+begin
+ if not (sdQuoteChar in FDefined) then
+ QuoteChar := '"';
+ Result := FQuoteChar;
+end;
+
+procedure TWideStrings.SetDelimiter(const Value: WideChar);
+begin
+ if (FDelimiter <> Value) or not (sdDelimiter in FDefined) then
+ begin
+ Include(FDefined, sdDelimiter);
+ FDelimiter := Value;
+ end
+end;
+
+procedure TWideStrings.SetQuoteChar(const Value: WideChar);
+begin
+ if (FQuoteChar <> Value) or not (sdQuoteChar in FDefined) then
+ begin
+ Include(FDefined, sdQuoteChar);
+ FQuoteChar := Value;
+ end
+end;
+
+function TWideStrings.CompareStrings(const S1, S2: WideString): Integer;
+begin
+ Result := WideCompareText(S1, S2);
+end;
+
+function TWideStrings.GetNameValueSeparator: WideChar;
+begin
+ {$IFDEF NAMEVALUESEPARATOR_RW}
+ if not (sdNameValueSeparator in FDefined) then
+ NameValueSeparator := '=';
+ Result := FNameValueSeparator;
+ {$ELSE}
+ Result := '=';
+ {$ENDIF}
+end;
+
+{$IFDEF NAMEVALUESEPARATOR_RW}
+procedure TWideStrings.SetNameValueSeparator(const Value: WideChar);
+begin
+ if (FNameValueSeparator <> Value) or not (sdNameValueSeparator in FDefined) then
+ begin
+ Include(FDefined, sdNameValueSeparator);
+ FNameValueSeparator := Value;
+ end
+end;
+{$ENDIF}
+
+function TWideStrings.GetValueFromIndex(Index: Integer): WideString;
+begin
+ if Index >= 0 then
+ Result := Copy(Get(Index), Length(Names[Index]) + 2, MaxInt) else
+ Result := '';
+end;
+
+procedure TWideStrings.SetValueFromIndex(Index: Integer; const Value: WideString);
+begin
+ if Value <> '' then
+ begin
+ if Index < 0 then Index := Add('');
+ Put(Index, Names[Index] + NameValueSeparator + Value);
+ end
+ else
+ if Index >= 0 then Delete(Index);
+end;
+
+end.
diff --git a/src/lib/TntUnicodeControls/TntWindows.pas b/src/lib/TntUnicodeControls/TntWindows.pas
new file mode 100644
index 00000000..8fd7ec88
--- /dev/null
+++ b/src/lib/TntUnicodeControls/TntWindows.pas
@@ -0,0 +1,1501 @@
+
+{*****************************************************************************}
+{ }
+{ Tnt Delphi Unicode Controls }
+{ http://www.tntware.com/delphicontrols/unicode/ }
+{ Version: 2.3.0 }
+{ }
+{ Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
+{ }
+{*****************************************************************************}
+
+unit TntWindows;
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$INCLUDE TntCompilers.inc}
+
+interface
+
+uses
+ Windows, ShellApi, ShlObj;
+
+// ......... compatibility
+
+const
+ DT_NOFULLWIDTHCHARBREAK = $00080000;
+
+const
+ INVALID_FILE_ATTRIBUTES = DWORD(-1);
+
+// ................ ANSI TYPES ................
+{TNT-WARN LPSTR}
+{TNT-WARN PLPSTR}
+{TNT-WARN LPCSTR}
+{TNT-WARN LPCTSTR}
+{TNT-WARN LPTSTR}
+
+// ........ EnumResourceTypesW, EnumResourceNamesW and EnumResourceLanguagesW are supposed ....
+// ........ to work on Win95/98/ME but have caused access violations in testing on Win95 ......
+// .. TNT--WARN EnumResourceTypes ..
+// .. TNT--WARN EnumResourceTypesA ..
+// .. TNT--WARN EnumResourceNames ..
+// .. TNT--WARN EnumResourceNamesA ..
+// .. TNT--WARN EnumResourceLanguages ..
+// .. TNT--WARN EnumResourceLanguagesA ..
+
+//------------------------------------------------------------------------------------------
+
+// ......... The Unicode form of these functions are supported on Windows 95/98/ME .........
+{TNT-WARN ExtTextOut}
+{TNT-WARN ExtTextOutA}
+{TNT-WARN Tnt_ExtTextOutW}
+
+{TNT-WARN FindResource}
+{TNT-WARN FindResourceA}
+{TNT-WARN Tnt_FindResourceW}
+
+{TNT-WARN FindResourceEx}
+{TNT-WARN FindResourceExA}
+{TNT-WARN Tnt_FindResourceExW}
+
+{TNT-WARN GetCharWidth}
+{TNT-WARN GetCharWidthA}
+{TNT-WARN Tnt_GetCharWidthW}
+
+{TNT-WARN GetCommandLine}
+{TNT-WARN GetCommandLineA}
+{TNT-WARN Tnt_GetCommandLineW}
+
+{TNT-WARN GetTextExtentPoint}
+{TNT-WARN GetTextExtentPointA}
+{TNT-WARN Tnt_GetTextExtentPointW}
+
+{TNT-WARN GetTextExtentPoint32}
+{TNT-WARN GetTextExtentPoint32A}
+{TNT-WARN Tnt_GetTextExtentPoint32W}
+
+{TNT-WARN lstrcat}
+{TNT-WARN lstrcatA}
+{TNT-WARN Tnt_lstrcatW}
+
+{TNT-WARN lstrcpy}
+{TNT-WARN lstrcpyA}
+{TNT-WARN Tnt_lstrcpyW}
+
+{TNT-WARN lstrlen}
+{TNT-WARN lstrlenA}
+{TNT-WARN Tnt_lstrlenW}
+
+{TNT-WARN MessageBox}
+{TNT-WARN MessageBoxA}
+{TNT-WARN Tnt_MessageBoxW}
+
+{TNT-WARN MessageBoxEx}
+{TNT-WARN MessageBoxExA}
+{TNT-WARN Tnt_MessageBoxExA}
+
+{TNT-WARN TextOut}
+{TNT-WARN TextOutA}
+{TNT-WARN Tnt_TextOutW}
+
+//------------------------------------------------------------------------------------------
+
+{TNT-WARN LOCALE_USER_DEFAULT} // <-- use GetThreadLocale
+{TNT-WARN LOCALE_SYSTEM_DEFAULT} // <-- use GetThreadLocale
+
+//------------------------------------------------------------------------------------------
+// compatiblity
+//------------------------------------------------------------------------------------------
+{$IFNDEF COMPILER_9_UP}
+type
+ {$IFDEF FPC}
+ TStartupInfoA = STARTUPINFO;
+ TStartupInfoW = STARTUPINFO;
+ {$ELSE}
+ TStartupInfoA = _STARTUPINFOA;
+ TStartupInfoW = record
+ cb: DWORD;
+ lpReserved: PWideChar;
+ lpDesktop: PWideChar;
+ lpTitle: PWideChar;
+ dwX: DWORD;
+ dwY: DWORD;
+ dwXSize: DWORD;
+ dwYSize: DWORD;
+ dwXCountChars: DWORD;
+ dwYCountChars: DWORD;
+ dwFillAttribute: DWORD;
+ dwFlags: DWORD;
+ wShowWindow: Word;
+ cbReserved2: Word;
+ lpReserved2: PByte;
+ hStdInput: THandle;
+ hStdOutput: THandle;
+ hStdError: THandle;
+ end;
+ {$ENDIF}
+
+function CreateProcessW{TNT-ALLOW CreateProcessW}(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
+ lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
+ bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
+ lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfoW;
+ var lpProcessInformation: TProcessInformation): BOOL; stdcall; external kernel32 name 'CreateProcessW';
+
+{$ENDIF}
+
+{$IFDEF FPC}
+type
+ TCurrencyFmtA = CURRENCYFMT;
+ TCurrencyFmtW = CURRENCYFMT;
+ PCurrencyFmtA = ^TCurrencyFmtA;
+ PCurrencyFmtW = ^TCurrencyFmtW;
+{$ENDIF}
+
+//------------------------------------------------------------------------------------------
+
+{TNT-WARN SetWindowText}
+{TNT-WARN SetWindowTextA}
+{TNT-WARN SetWindowTextW}
+function Tnt_SetWindowTextW(hWnd: HWND; lpString: PWideChar): BOOL;
+
+{TNT-WARN RemoveDirectory}
+{TNT-WARN RemoveDirectoryA}
+{TNT-WARN RemoveDirectoryW}
+function Tnt_RemoveDirectoryW(lpPathName: PWideChar): BOOL;
+
+{TNT-WARN GetShortPathName}
+{TNT-WARN GetShortPathNameA}
+{TNT-WARN GetShortPathNameW}
+function Tnt_GetShortPathNameW(lpszLongPath: PWideChar; lpszShortPath: PWideChar;
+ cchBuffer: DWORD): DWORD;
+
+{TNT-WARN GetFullPathName}
+{TNT-WARN GetFullPathNameA}
+{TNT-WARN GetFullPathNameW}
+function Tnt_GetFullPathNameW(lpFileName: PWideChar; nBufferLength: DWORD;
+ lpBuffer: PWideChar; var lpFilePart: PWideChar): DWORD;
+
+{TNT-WARN CreateFile}
+{TNT-WARN CreateFileA}
+{TNT-WARN CreateFileW}
+function Tnt_CreateFileW(lpFileName: PWideChar; dwDesiredAccess, dwShareMode: DWORD;
+ lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD;
+ hTemplateFile: THandle): THandle;
+
+{TNT-WARN FindFirstFile}
+{TNT-WARN FindFirstFileA}
+{TNT-WARN FindFirstFileW}
+function Tnt_FindFirstFileW(lpFileName: PWideChar; var lpFindFileData: TWIN32FindDataW): THandle;
+
+{TNT-WARN FindNextFile}
+{TNT-WARN FindNextFileA}
+{TNT-WARN FindNextFileW}
+function Tnt_FindNextFileW(hFindFile: THandle; var lpFindFileData: TWIN32FindDataW): BOOL;
+
+{TNT-WARN GetFileAttributes}
+{TNT-WARN GetFileAttributesA}
+{TNT-WARN GetFileAttributesW}
+function Tnt_GetFileAttributesW(lpFileName: PWideChar): DWORD;
+
+{TNT-WARN SetFileAttributes}
+{TNT-WARN SetFileAttributesA}
+{TNT-WARN SetFileAttributesW}
+function Tnt_SetFileAttributesW(lpFileName: PWideChar; dwFileAttributes: DWORD): BOOL;
+
+{TNT-WARN CreateDirectory}
+{TNT-WARN CreateDirectoryA}
+{TNT-WARN CreateDirectoryW}
+function Tnt_CreateDirectoryW(lpPathName: PWideChar;
+ lpSecurityAttributes: PSecurityAttributes): BOOL;
+
+{TNT-WARN MoveFile}
+{TNT-WARN MoveFileA}
+{TNT-WARN MoveFileW}
+function Tnt_MoveFileW(lpExistingFileName, lpNewFileName: PWideChar): BOOL;
+
+{TNT-WARN CopyFile}
+{TNT-WARN CopyFileA}
+{TNT-WARN CopyFileW}
+function Tnt_CopyFileW(lpExistingFileName, lpNewFileName: PWideChar; bFailIfExists: BOOL): BOOL;
+
+{TNT-WARN DeleteFile}
+{TNT-WARN DeleteFileA}
+{TNT-WARN DeleteFileW}
+function Tnt_DeleteFileW(lpFileName: PWideChar): BOOL;
+
+{TNT-WARN DrawText}
+{TNT-WARN DrawTextA}
+{TNT-WARN DrawTextW}
+function Tnt_DrawTextW(hDC: HDC; lpString: PWideChar; nCount: Integer;
+ var lpRect: TRect; uFormat: UINT): Integer;
+
+{TNT-WARN GetDiskFreeSpace}
+{TNT-WARN GetDiskFreeSpaceA}
+{TNT-WARN GetDiskFreeSpaceW}
+function Tnt_GetDiskFreeSpaceW(lpRootPathName: PWideChar; var lpSectorsPerCluster,
+ lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: DWORD): BOOL;
+
+{TNT-WARN GetVolumeInformation}
+{TNT-WARN GetVolumeInformationA}
+{TNT-WARN GetVolumeInformationW}
+function Tnt_GetVolumeInformationW(lpRootPathName: PWideChar; lpVolumeNameBuffer: PWideChar;
+ nVolumeNameSize: DWORD; lpVolumeSerialNumber: PDWORD;
+ var lpMaximumComponentLength, lpFileSystemFlags: DWORD; lpFileSystemNameBuffer: PWideChar;
+ nFileSystemNameSize: DWORD): BOOL;
+
+{TNT-WARN GetModuleFileName}
+{TNT-WARN GetModuleFileNameA}
+{TNT-WARN GetModuleFileNameW}
+function Tnt_GetModuleFileNameW(hModule: HINST; lpFilename: PWideChar; nSize: DWORD): DWORD;
+
+{TNT-WARN GetTempPath}
+{TNT-WARN GetTempPathA}
+{TNT-WARN GetTempPathW}
+function Tnt_GetTempPathW(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD;
+
+{TNT-WARN GetTempFileName}
+{TNT-WARN GetTempFileNameA}
+{TNT-WARN GetTempFileNameW}
+function Tnt_GetTempFileNameW(lpPathName, lpPrefixString: PWideChar; uUnique: UINT;
+ lpTempFileName: PWideChar): UINT;
+
+{TNT-WARN GetWindowsDirectory}
+{TNT-WARN GetWindowsDirectoryA}
+{TNT-WARN GetWindowsDirectoryW}
+function Tnt_GetWindowsDirectoryW(lpBuffer: PWideChar; uSize: UINT): UINT;
+
+{TNT-WARN GetSystemDirectory}
+{TNT-WARN GetSystemDirectoryA}
+{TNT-WARN GetSystemDirectoryW}
+function Tnt_GetSystemDirectoryW(lpBuffer: PWideChar; uSize: UINT): UINT;
+
+{TNT-WARN GetCurrentDirectory}
+{TNT-WARN GetCurrentDirectoryA}
+{TNT-WARN GetCurrentDirectoryW}
+function Tnt_GetCurrentDirectoryW(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD;
+
+{TNT-WARN SetCurrentDirectory}
+{TNT-WARN SetCurrentDirectoryA}
+{TNT-WARN SetCurrentDirectoryW}
+function Tnt_SetCurrentDirectoryW(lpPathName: PWideChar): BOOL;
+
+{TNT-WARN GetComputerName}
+{TNT-WARN GetComputerNameA}
+{TNT-WARN GetComputerNameW}
+function Tnt_GetComputerNameW(lpBuffer: PWideChar; var nSize: DWORD): BOOL;
+
+{TNT-WARN GetUserName}
+{TNT-WARN GetUserNameA}
+{TNT-WARN GetUserNameW}
+function Tnt_GetUserNameW(lpBuffer: PWideChar; var nSize: DWORD): BOOL;
+
+{TNT-WARN ShellExecute}
+{TNT-WARN ShellExecuteA}
+{TNT-WARN ShellExecuteW}
+function Tnt_ShellExecuteW(hWnd: HWND; Operation, FileName, Parameters,
+ Directory: PWideChar; ShowCmd: Integer): HINST;
+
+{TNT-WARN LoadLibrary}
+{TNT-WARN LoadLibraryA}
+{TNT-WARN LoadLibraryW}
+function Tnt_LoadLibraryW(lpLibFileName: PWideChar): HMODULE;
+
+{TNT-WARN LoadLibraryEx}
+{TNT-WARN LoadLibraryExA}
+{TNT-WARN LoadLibraryExW}
+function Tnt_LoadLibraryExW(lpLibFileName: PWideChar; hFile: THandle; dwFlags: DWORD): HMODULE;
+
+{TNT-WARN CreateProcess}
+{TNT-WARN CreateProcessA}
+{TNT-WARN CreateProcessW}
+function Tnt_CreateProcessW(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
+ lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
+ bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
+ lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfoW;
+ var lpProcessInformation: TProcessInformation): BOOL;
+
+{TNT-WARN GetCurrencyFormat}
+{TNT-WARN GetCurrencyFormatA}
+{TNT-WARN GetCurrencyFormatW}
+function Tnt_GetCurrencyFormatW(Locale: LCID; dwFlags: DWORD; lpValue: PWideChar;
+ lpFormat: PCurrencyFmtW; lpCurrencyStr: PWideChar; cchCurrency: Integer): Integer;
+
+{TNT-WARN CompareString}
+{TNT-WARN CompareStringA}
+{TNT-WARN CompareStringW}
+function Tnt_CompareStringW(Locale: LCID; dwCmpFlags: DWORD; lpString1: PWideChar;
+ cchCount1: Integer; lpString2: PWideChar; cchCount2: Integer): Integer;
+
+{TNT-WARN CharUpper}
+{TNT-WARN CharUpperA}
+{TNT-WARN CharUpperW}
+function Tnt_CharUpperW(lpsz: PWideChar): PWideChar;
+
+{TNT-WARN CharUpperBuff}
+{TNT-WARN CharUpperBuffA}
+{TNT-WARN CharUpperBuffW}
+function Tnt_CharUpperBuffW(lpsz: PWideChar; cchLength: DWORD): DWORD;
+
+{TNT-WARN CharLower}
+{TNT-WARN CharLowerA}
+{TNT-WARN CharLowerW}
+function Tnt_CharLowerW(lpsz: PWideChar): PWideChar;
+
+{TNT-WARN CharLowerBuff}
+{TNT-WARN CharLowerBuffA}
+{TNT-WARN CharLowerBuffW}
+function Tnt_CharLowerBuffW(lpsz: PWideChar; cchLength: DWORD): DWORD;
+
+{TNT-WARN GetStringTypeEx}
+{TNT-WARN GetStringTypeExA}
+{TNT-WARN GetStringTypeExW}
+function Tnt_GetStringTypeExW(Locale: LCID; dwInfoType: DWORD;
+ lpSrcStr: PWideChar; cchSrc: Integer; var lpCharType): BOOL;
+
+{TNT-WARN LoadString}
+{TNT-WARN LoadStringA}
+{TNT-WARN LoadStringW}
+function Tnt_LoadStringW(hInstance: HINST; uID: UINT; lpBuffer: PWideChar; nBufferMax: Integer): Integer;
+
+{$IFDEF FPC}
+type
+ TMenuItemInfoW = TMENUITEMINFO;
+ tagMenuItemINFOW = tagMENUITEMINFO;
+{$ENDIF}
+
+{TNT-WARN InsertMenuItem}
+{TNT-WARN InsertMenuItemA}
+{TNT-WARN InsertMenuItemW}
+function Tnt_InsertMenuItemW(hMenu: HMENU; uItem: DWORD; fByPosition: BOOL; lpmii: tagMenuItemINFOW): BOOL;
+
+{TNT-WARN ExtractIconEx}
+{TNT-WARN ExtractIconExA}
+{TNT-WARN ExtractIconExW}
+function Tnt_ExtractIconExW(lpszFile: PWideChar; nIconIndex: Integer;
+ var phiconLarge, phiconSmall: HICON; nIcons: UINT): UINT;
+
+{TNT-WARN ExtractAssociatedIcon}
+{TNT-WARN ExtractAssociatedIconA}
+{TNT-WARN ExtractAssociatedIconW}
+function Tnt_ExtractAssociatedIconW(hInst: HINST; lpIconPath: PWideChar;
+ var lpiIcon: Word): HICON;
+
+{TNT-WARN GetFileVersionInfoSize}
+{TNT-WARN GetFileVersionInfoSizeA}
+{TNT-WARN GetFileVersionInfoSizeW}
+function Tnt_GetFileVersionInfoSizeW(lptstrFilename: PWideChar; var lpdwHandle: DWORD): DWORD;
+
+{TNT-WARN GetFileVersionInfo}
+{TNT-WARN GetFileVersionInfoA}
+{TNT-WARN GetFileVersionInfoW}
+function Tnt_GetFileVersionInfoW(lptstrFilename: PWideChar; dwHandle, dwLen: DWORD;
+ lpData: Pointer): BOOL;
+
+const
+ VQV_FIXEDFILEINFO = '\';
+ VQV_VARFILEINFO_TRANSLATION = '\VarFileInfo\Translation';
+ VQV_STRINGFILEINFO = '\StringFileInfo';
+
+ VER_COMMENTS = 'Comments';
+ VER_INTERNALNAME = 'InternalName';
+ VER_PRODUCTNAME = 'ProductName';
+ VER_COMPANYNAME = 'CompanyName';
+ VER_LEGALCOPYRIGHT = 'LegalCopyright';
+ VER_PRODUCTVERSION = 'ProductVersion';
+ VER_FILEDESCRIPTION = 'FileDescription';
+ VER_LEGALTRADEMARKS = 'LegalTrademarks';
+ VER_PRIVATEBUILD = 'PrivateBuild';
+ VER_FILEVERSION = 'FileVersion';
+ VER_ORIGINALFILENAME = 'OriginalFilename';
+ VER_SPECIALBUILD = 'SpecialBuild';
+
+{TNT-WARN VerQueryValue}
+{TNT-WARN VerQueryValueA}
+{TNT-WARN VerQueryValueW}
+function Tnt_VerQueryValueW(pBlock: Pointer; lpSubBlock: PWideChar;
+ var lplpBuffer: Pointer; var puLen: UINT): BOOL;
+
+type
+{$IFDEF FPC}
+ PSHNAMEMAPPINGA = ^SHNAMEMAPPINGA;
+ SHNAMEMAPPINGA = record
+ pszOldPath : LPSTR;
+ pszNewPath : LPSTR;
+ cchOldPath : longint;
+ cchNewPath : longint;
+ end;
+
+ PSHNAMEMAPPINGW = ^SHNAMEMAPPINGW;
+ SHNAMEMAPPINGW = record
+ pszOldPath : LPWSTR;
+ pszNewPath : LPWSTR;
+ cchOldPath : longint;
+ cchNewPath : longint;
+ end;
+{$ENDIF}
+
+ TSHNameMappingHeaderA = record
+ cNumOfMappings: Cardinal;
+ lpNM: PSHNAMEMAPPINGA;
+ end;
+ PSHNameMappingHeaderA = ^TSHNameMappingHeaderA;
+
+ TSHNameMappingHeaderW = record
+ cNumOfMappings: Cardinal;
+ lpNM: PSHNAMEMAPPINGW;
+ end;
+ PSHNameMappingHeaderW = ^TSHNameMappingHeaderW;
+
+{TNT-WARN SHFileOperation}
+{TNT-WARN SHFileOperationA}
+{TNT-WARN SHFileOperationW} // <-- no stub on early Windows 95
+function Tnt_SHFileOperationW(var lpFileOp: TSHFileOpStructW): Integer;
+
+{TNT-WARN SHFreeNameMappings}
+procedure Tnt_SHFreeNameMappings(hNameMappings: THandle);
+
+{TNT-WARN SHBrowseForFolder}
+{TNT-WARN SHBrowseForFolderA}
+{TNT-WARN SHBrowseForFolderW} // <-- no stub on early Windows 95
+function Tnt_SHBrowseForFolderW(var lpbi: TBrowseInfoW): PItemIDList;
+
+{TNT-WARN SHGetPathFromIDList}
+{TNT-WARN SHGetPathFromIDListA}
+{TNT-WARN SHGetPathFromIDListW} // <-- no stub on early Windows 95
+function Tnt_SHGetPathFromIDListW(pidl: PItemIDList; pszPath: PWideChar): BOOL;
+
+{TNT-WARN SHGetFileInfo}
+{TNT-WARN SHGetFileInfoA}
+{TNT-WARN SHGetFileInfoW} // <-- no stub on early Windows 95
+function Tnt_SHGetFileInfoW(pszPath: PWideChar; dwFileAttributes: DWORD;
+ var psfi: TSHFileInfoW; cbFileInfo, uFlags: UINT): DWORD;
+
+// ......... introduced .........
+function Tnt_Is_IntResource(ResStr: LPCWSTR): Boolean;
+
+function LANGIDFROMLCID(lcid: LCID): WORD;
+function MAKELANGID(usPrimaryLanguage, usSubLanguage: WORD): WORD;
+function MAKELCID(wLanguageID: WORD; wSortID: WORD = SORT_DEFAULT): LCID;
+function PRIMARYLANGID(lgid: WORD): WORD;
+function SORTIDFROMLCID(lcid: LCID): WORD;
+function SUBLANGID(lgid: WORD): WORD;
+
+implementation
+
+uses
+ SysUtils, Math, TntSysUtils,
+ {$IFDEF COMPILER_9_UP} WideStrUtils, {$ENDIF} TntWideStrUtils;
+
+function _PAnsiCharWithNil(const S: AnsiString): PAnsiChar;
+begin
+ if S = '' then
+ Result := nil {Win9x needs nil for some parameters instead of empty strings}
+ else
+ Result := PAnsiChar(S);
+end;
+
+function _PWideCharWithNil(const S: WideString): PWideChar;
+begin
+ if S = '' then
+ Result := nil {Win9x needs nil for some parameters instead of empty strings}
+ else
+ Result := PWideChar(S);
+end;
+
+function _WStr(lpString: PWideChar; cchCount: Integer): WideString;
+begin
+ if cchCount = -1 then
+ Result := lpString
+ else
+ Result := Copy(WideString(lpString), 1, cchCount);
+end;
+
+procedure _MakeWideWin32FindData(var WideFindData: TWIN32FindDataW; AnsiFindData: TWIN32FindDataA);
+begin
+ CopyMemory(@WideFindData, @AnsiFindData,
+ PtrUInt(@WideFindData.cFileName) - PtrUInt(@WideFindData));
+ WStrPCopy(WideFindData.cFileName, AnsiFindData.cFileName);
+ WStrPCopy(WideFindData.cAlternateFileName, AnsiFindData.cAlternateFileName);
+end;
+
+function Tnt_SetWindowTextW(hWnd: HWND; lpString: PWideChar): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := SetWindowTextW{TNT-ALLOW SetWindowTextW}(hWnd, lpString)
+ else
+ Result := SetWindowTextA{TNT-ALLOW SetWindowTextA}(hWnd, PAnsiChar(AnsiString(lpString)));
+end;
+
+//-----------------------------
+
+type
+ TPathLengthResultOption = (poAllowDirectoryMode, poZeroSmallBuff, poExactCopy, poExactCopySubPaths);
+ TPathLengthResultOptions = set of TPathLengthResultOption;
+
+procedure _ExactStrCopyW(pDest, pSource: PWideChar; Count: Integer);
+var
+ i: integer;
+begin
+ for i := 1 to Count do begin
+ pDest^ := pSource^;
+ Inc(PSource);
+ Inc(pDest);
+ end;
+end;
+
+procedure _ExactCopySubPaths(pDest, pSource: PWideChar; Count: Integer);
+var
+ i: integer;
+ OriginalSource: PWideChar;
+ PNextSlash: PWideChar;
+begin
+ if Count >= 4 then begin
+ OriginalSource := pSource;
+ PNextSlash := WStrScan(pSource, '\');
+ for i := 1 to Count - 1 do begin
+ // determine next path delimiter
+ if pSource > pNextSlash then begin
+ PNextSlash := WStrScan(pSource, '\');
+ end;
+ // leave if no more sub paths
+ if (PNextSlash = nil)
+ or ((pNextSlash - OriginalSource) >= Count) then begin
+ exit;
+ end;
+ // copy char
+ pDest^ := pSource^;
+ Inc(PSource);
+ Inc(pDest);
+ end;
+ end;
+end;
+
+function _HandlePathLengthResult(nBufferLength: DWORD; lpBuffer: PWideChar; const AnsiBuff: AnsiString; Options: TPathLengthResultOptions): Integer;
+var
+ WideBuff: WideString;
+begin
+ WideBuff := AnsiBuff;
+ if nBufferLength > Cardinal(Length(WideBuff)) then begin
+ // normal
+ Result := Length(WideBuff);
+ WStrLCopy(lpBuffer, PWideChar(WideBuff), nBufferLength);
+ end else if (poExactCopy in Options) then begin
+ // exact
+ Result := nBufferLength;
+ _ExactStrCopyW(lpBuffer, PWideChar(WideBuff), nBufferLength);
+ end else begin
+ // other
+ if (poAllowDirectoryMode in Options)
+ and (nBufferLength = Cardinal(Length(WideBuff))) then begin
+ Result := Length(WideBuff) + 1;
+ WStrLCopy(lpBuffer, PWideChar(WideBuff), nBufferLength - 1);
+ end else begin
+ Result := Length(WideBuff) + 1;
+ if (nBufferLength > 0) then begin
+ if (poZeroSmallBuff in Options) then
+ lpBuffer^ := #0
+ else if (poExactCopySubPaths in Options) then
+ _ExactCopySubPaths(lpBuffer, PWideChar(WideBuff), nBufferLength);
+ end;
+ end;
+ end;
+end;
+
+function _HandleStringLengthResult(nBufferLength: DWORD; lpBuffer: PWideChar; const AnsiBuff: AnsiString; Options: TPathLengthResultOptions): Integer;
+var
+ WideBuff: WideString;
+begin
+ WideBuff := AnsiBuff;
+ if nBufferLength >= Cardinal(Length(WideBuff)) then begin
+ // normal
+ Result := Length(WideBuff);
+ WStrLCopy(lpBuffer, PWideChar(WideBuff), nBufferLength);
+ end else if nBufferLength = 0 then
+ Result := Length(WideBuff)
+ else
+ Result := 0;
+end;
+
+//-------------------------------------------
+
+function Tnt_RemoveDirectoryW(lpPathName: PWideChar): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := RemoveDirectoryW{TNT-ALLOW RemoveDirectoryW}(PWideChar(lpPathName))
+ else
+ Result := RemoveDirectoryA{TNT-ALLOW RemoveDirectoryA}(PAnsiChar(AnsiString(lpPathName)));
+end;
+
+function Tnt_GetShortPathNameW(lpszLongPath: PWideChar; lpszShortPath: PWideChar;
+ cchBuffer: DWORD): DWORD;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetShortPathNameW{TNT-ALLOW GetShortPathNameW}(lpszLongPath, lpszShortPath, cchBuffer)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH * 2);
+ SetLength(AnsiBuff, GetShortPathNameA{TNT-ALLOW GetShortPathNameA}(PAnsiChar(AnsiString(lpszLongPath)),
+ PAnsiChar(AnsiBuff), Length(AnsiBuff)));
+ Result := _HandlePathLengthResult(cchBuffer, lpszShortPath, AnsiBuff, [poExactCopySubPaths]);
+ end;
+end;
+
+function Tnt_GetFullPathNameW(lpFileName: PWideChar; nBufferLength: DWORD;
+ lpBuffer: PWideChar; var lpFilePart: PWideChar): DWORD;
+var
+ AnsiBuff: AnsiString;
+ AnsiFilePart: PAnsiChar;
+ AnsiLeadingChars: Integer;
+ WideLeadingChars: Integer;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetFullPathNameW{TNT-ALLOW GetFullPathNameW}(lpFileName, nBufferLength, lpBuffer, lpFilePart)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH * 2);
+ SetLength(AnsiBuff, GetFullPathNameA{TNT-ALLOW GetFullPathNameA}(PAnsiChar(AnsiString(lpFileName)),
+ Length(AnsiBuff), PAnsiChar(AnsiBuff), AnsiFilePart));
+ Result := _HandlePathLengthResult(nBufferLength, lpBuffer, AnsiBuff, [poZeroSmallBuff]);
+ // deal w/ lpFilePart
+ if (AnsiFilePart = nil) or (nBufferLength < Result) then
+ lpFilePart := nil
+ else begin
+ AnsiLeadingChars := AnsiFilePart - PAnsiChar(AnsiBuff);
+ WideLeadingChars := Length(WideString(Copy(AnsiBuff, 1, AnsiLeadingChars)));
+ lpFilePart := lpBuffer + WideLeadingChars;
+ end;
+ end;
+end;
+
+function Tnt_CreateFileW(lpFileName: PWideChar; dwDesiredAccess, dwShareMode: DWORD;
+ lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD;
+ hTemplateFile: THandle): THandle;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CreateFileW{TNT-ALLOW CreateFileW}(lpFileName, dwDesiredAccess, dwShareMode,
+ lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile)
+ else
+ Result := CreateFileA{TNT-ALLOW CreateFileA}(PAnsiChar(AnsiString(lpFileName)), dwDesiredAccess, dwShareMode,
+ lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile)
+end;
+
+function Tnt_FindFirstFileW(lpFileName: PWideChar; var lpFindFileData: TWIN32FindDataW): THandle;
+var
+ Ansi_lpFindFileData: TWIN32FindDataA;
+begin
+ if Win32PlatformIsUnicode then
+ Result := FindFirstFileW{TNT-ALLOW FindFirstFileW}(lpFileName, lpFindFileData)
+ else begin
+ Result := FindFirstFileA{TNT-ALLOW FindFirstFileA}(PAnsiChar(AnsiString(lpFileName)),
+ Ansi_lpFindFileData);
+ if Result <> INVALID_HANDLE_VALUE then
+ _MakeWideWin32FindData(lpFindFileData, Ansi_lpFindFileData);
+ end;
+end;
+
+function Tnt_FindNextFileW(hFindFile: THandle; var lpFindFileData: TWIN32FindDataW): BOOL;
+var
+ Ansi_lpFindFileData: TWIN32FindDataA;
+begin
+ if Win32PlatformIsUnicode then
+ Result := FindNextFileW{TNT-ALLOW FindNextFileW}(hFindFile, lpFindFileData)
+ else begin
+ Result := FindNextFileA{TNT-ALLOW FindNextFileA}(hFindFile, Ansi_lpFindFileData);
+ if Result then
+ _MakeWideWin32FindData(lpFindFileData, Ansi_lpFindFileData);
+ end;
+end;
+
+function Tnt_GetFileAttributesW(lpFileName: PWideChar): DWORD;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetFileAttributesW{TNT-ALLOW GetFileAttributesW}(lpFileName)
+ else
+ Result := GetFileAttributesA{TNT-ALLOW GetFileAttributesA}(PAnsiChar(AnsiString(lpFileName)));
+end;
+
+function Tnt_SetFileAttributesW(lpFileName: PWideChar; dwFileAttributes: DWORD): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := SetFileAttributesW{TNT-ALLOW SetFileAttributesW}(lpFileName, dwFileAttributes)
+ else
+ Result := SetFileAttributesA{TNT-ALLOW SetFileAttributesA}(PAnsiChar(AnsiString(lpFileName)), dwFileAttributes);
+end;
+
+function Tnt_CreateDirectoryW(lpPathName: PWideChar;
+ lpSecurityAttributes: PSecurityAttributes): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CreateDirectoryW{TNT-ALLOW CreateDirectoryW}(lpPathName, lpSecurityAttributes)
+ else
+ Result := CreateDirectoryA{TNT-ALLOW CreateDirectoryA}(PAnsiChar(AnsiString(lpPathName)), lpSecurityAttributes);
+end;
+
+function Tnt_MoveFileW(lpExistingFileName, lpNewFileName: PWideChar): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := MoveFileW{TNT-ALLOW MoveFileW}(lpExistingFileName, lpNewFileName)
+ else
+ Result := MoveFileA{TNT-ALLOW MoveFileA}(PAnsiChar(AnsiString(lpExistingFileName)), PAnsiChar(AnsiString(lpNewFileName)));
+end;
+
+function Tnt_CopyFileW(lpExistingFileName, lpNewFileName: PWideChar; bFailIfExists: BOOL): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CopyFileW{TNT-ALLOW CopyFileW}(lpExistingFileName, lpNewFileName, bFailIfExists)
+ else
+ Result := CopyFileA{TNT-ALLOW CopyFileA}(PAnsiChar(AnsiString(lpExistingFileName)),
+ PAnsiChar(AnsiString(lpNewFileName)), bFailIfExists);
+end;
+
+function Tnt_DeleteFileW(lpFileName: PWideChar): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := DeleteFileW{TNT-ALLOW DeleteFileW}(lpFileName)
+ else
+ Result := DeleteFileA{TNT-ALLOW DeleteFileA}(PAnsiChar(AnsiString(lpFileName)));
+end;
+
+function Tnt_DrawTextW(hDC: HDC; lpString: PWideChar; nCount: Integer;
+ var lpRect: TRect; uFormat: UINT): Integer;
+begin
+ if Win32PlatformIsUnicode then
+ Result := DrawTextW{TNT-ALLOW DrawTextW}(hDC, lpString, nCount, lpRect, uFormat)
+ else
+ Result := DrawTextA{TNT-ALLOW DrawTextA}(hDC,
+ PAnsiChar(AnsiString(_WStr(lpString, nCount))), -1, lpRect, uFormat);
+end;
+
+function Tnt_GetDiskFreeSpaceW(lpRootPathName: PWideChar; var lpSectorsPerCluster,
+ lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: DWORD): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetDiskFreeSpaceW{TNT-ALLOW GetDiskFreeSpaceW}(lpRootPathName,
+ lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters)
+ else
+ Result := GetDiskFreeSpaceA{TNT-ALLOW GetDiskFreeSpaceA}(PAnsiChar(AnsiString(lpRootPathName)),
+ lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters)
+end;
+
+function Tnt_GetVolumeInformationW(lpRootPathName: PWideChar; lpVolumeNameBuffer: PWideChar;
+ nVolumeNameSize: DWORD; lpVolumeSerialNumber: PDWORD;
+ var lpMaximumComponentLength, lpFileSystemFlags: DWORD; lpFileSystemNameBuffer: PWideChar;
+ nFileSystemNameSize: DWORD): BOOL;
+var
+ AnsiFileSystemNameBuffer: AnsiString;
+ AnsiVolumeNameBuffer: AnsiString;
+ AnsiBuffLen: DWORD;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetVolumeInformationW{TNT-ALLOW GetVolumeInformationW}(lpRootPathName, lpVolumeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize)
+ else begin
+ SetLength(AnsiVolumeNameBuffer, MAX_COMPUTERNAME_LENGTH + 1);
+ SetLength(AnsiFileSystemNameBuffer, MAX_COMPUTERNAME_LENGTH + 1);
+ AnsiBuffLen := Length(AnsiFileSystemNameBuffer);
+ Result := GetVolumeInformationA{TNT-ALLOW GetVolumeInformationA}(PAnsiChar(AnsiString(lpRootPathName)), PAnsiChar(AnsiVolumeNameBuffer), AnsiBuffLen, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, PAnsiChar(AnsiFileSystemNameBuffer), AnsiBuffLen);
+ if Result then begin
+ SetLength(AnsiFileSystemNameBuffer, AnsiBuffLen);
+ if (nFileSystemNameSize <= AnsiBuffLen) or (Length(AnsiFileSystemNameBuffer) = 0) then
+ Result := False
+ else begin
+ WStrPLCopy(lpFileSystemNameBuffer, AnsiFileSystemNameBuffer, nFileSystemNameSize);
+ WStrPLCopy(lpVolumeNameBuffer, AnsiVolumeNameBuffer, nVolumeNameSize);
+ end;
+ end;
+ end;
+end;
+
+function Tnt_GetModuleFileNameW(hModule: HINST; lpFilename: PWideChar; nSize: DWORD): DWORD;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetModuleFileNameW{TNT-ALLOW GetModuleFileNameW}(hModule, lpFilename, nSize)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH);
+ SetLength(AnsiBuff, GetModuleFileNameA{TNT-ALLOW GetModuleFileNameA}(hModule, PAnsiChar(AnsiBuff), Length(AnsiBuff)));
+ Result := _HandlePathLengthResult(nSize, lpFilename, AnsiBuff, [poExactCopy]);
+ end;
+end;
+
+function Tnt_GetTempPathW(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetTempPathW{TNT-ALLOW GetTempPathW}(nBufferLength, lpBuffer)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH);
+ SetLength(AnsiBuff, GetTempPathA{TNT-ALLOW GetTempPathA}(Length(AnsiBuff), PAnsiChar(AnsiBuff)));
+ Result := _HandlePathLengthResult(nBufferLength, lpBuffer, AnsiBuff, [poAllowDirectoryMode, poZeroSmallBuff]);
+ end;
+end;
+
+function Tnt_GetTempFileNameW(lpPathName, lpPrefixString: PWideChar; uUnique: UINT;
+ lpTempFileName: PWideChar): UINT;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetTempFileNameW{TNT-ALLOW GetTempFileNameW}(lpPathName, lpPrefixString, uUnique, lpTempFileName)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH);
+ Result := GetTempFileNameA{TNT-ALLOW GetTempFileNameA}(PAnsiChar(AnsiString(lpPathName)), PAnsiChar(lpPrefixString), uUnique, PAnsiChar(AnsiBuff));
+ AnsiBuff := PAnsiChar(AnsiBuff);
+ _HandlePathLengthResult(MAX_PATH, lpTempFileName, AnsiBuff, [poZeroSmallBuff]);
+ end;
+end;
+
+function Tnt_GetWindowsDirectoryW(lpBuffer: PWideChar; uSize: UINT): UINT;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetWindowsDirectoryW{TNT-ALLOW GetWindowsDirectoryW}(lpBuffer, uSize)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH);
+ SetLength(AnsiBuff, GetWindowsDirectoryA{TNT-ALLOW GetWindowsDirectoryA}(PAnsiChar(AnsiBuff), Length(AnsiBuff)));
+ Result := _HandlePathLengthResult(uSize, lpBuffer, AnsiBuff, []);
+ end;
+end;
+
+function Tnt_GetSystemDirectoryW(lpBuffer: PWideChar; uSize: UINT): UINT;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetSystemDirectoryW{TNT-ALLOW GetSystemDirectoryW}(lpBuffer, uSize)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH);
+ SetLength(AnsiBuff, GetSystemDirectoryA{TNT-ALLOW GetSystemDirectoryA}(PAnsiChar(AnsiBuff), Length(AnsiBuff)));
+ Result := _HandlePathLengthResult(uSize, lpBuffer, AnsiBuff, []);
+ end;
+end;
+
+function Tnt_GetCurrentDirectoryW(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetCurrentDirectoryW{TNT-ALLOW GetCurrentDirectoryW}(nBufferLength, lpBuffer)
+ else begin
+ SetLength(AnsiBuff, MAX_PATH);
+ SetLength(AnsiBuff, GetCurrentDirectoryA{TNT-ALLOW GetCurrentDirectoryA}(Length(AnsiBuff), PAnsiChar(AnsiBuff)));
+ Result := _HandlePathLengthResult(nBufferLength, lpBuffer, AnsiBuff, [poAllowDirectoryMode, poZeroSmallBuff]);
+ end;
+end;
+
+function Tnt_SetCurrentDirectoryW(lpPathName: PWideChar): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := SetCurrentDirectoryW{TNT-ALLOW SetCurrentDirectoryW}(lpPathName)
+ else
+ Result := SetCurrentDirectoryA{TNT-ALLOW SetCurrentDirectoryA}(PAnsiChar(AnsiString(lpPathName)));
+end;
+
+function Tnt_GetComputerNameW(lpBuffer: PWideChar; var nSize: DWORD): BOOL;
+var
+ AnsiBuff: AnsiString;
+ AnsiBuffLen: DWORD;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetComputerNameW{TNT-ALLOW GetComputerNameW}(lpBuffer, nSize)
+ else begin
+ SetLength(AnsiBuff, MAX_COMPUTERNAME_LENGTH + 1);
+ AnsiBuffLen := Length(AnsiBuff);
+ Result := GetComputerNameA{TNT-ALLOW GetComputerNameA}(PAnsiChar(AnsiBuff), AnsiBuffLen);
+ if Result then begin
+ SetLength(AnsiBuff, AnsiBuffLen);
+ if (nSize <= AnsiBuffLen) or (Length(AnsiBuff) = 0) then begin
+ nSize := AnsiBuffLen + 1;
+ Result := False;
+ end else begin
+ WStrPLCopy(lpBuffer, AnsiBuff, nSize);
+ nSize := WStrLen(lpBuffer);
+ end;
+ end;
+ end;
+end;
+
+function Tnt_GetUserNameW(lpBuffer: PWideChar; var nSize: DWORD): BOOL;
+var
+ AnsiBuff: AnsiString;
+ AnsiBuffLen: DWORD;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetUserNameW{TNT-ALLOW GetUserNameW}(lpBuffer, nSize)
+ else begin
+ SetLength(AnsiBuff, 255);
+ AnsiBuffLen := Length(AnsiBuff);
+ Result := GetUserNameA{TNT-ALLOW GetUserNameA}(PAnsiChar(AnsiBuff), AnsiBuffLen);
+ if Result then begin
+ SetLength(AnsiBuff, AnsiBuffLen);
+ if (nSize <= AnsiBuffLen) or (Length(AnsiBuff) = 0) then begin
+ nSize := AnsiBuffLen + 1;
+ Result := False;
+ end else begin
+ WStrPLCopy(lpBuffer, AnsiBuff, nSize);
+ nSize := WStrLen(lpBuffer);
+ end;
+ end;
+ end;
+end;
+
+function Tnt_ShellExecuteW(hWnd: HWND; Operation, FileName, Parameters,
+ Directory: PWideChar; ShowCmd: Integer): HINST;
+begin
+ if Win32PlatformIsUnicode then
+ Result := ShellExecuteW{TNT-ALLOW ShellExecuteW}(hWnd, _PWideCharWithNil(WideString(Operation)),
+ FileName, Parameters,
+ Directory, ShowCmd)
+ else begin
+ Result := ShellExecuteA{TNT-ALLOW ShellExecuteA}(hWnd, _PAnsiCharWithNil(AnsiString(Operation)),
+ _PAnsiCharWithNil(AnsiString(FileName)), _PAnsiCharWithNil(AnsiString(Parameters)),
+ _PAnsiCharWithNil(AnsiString(Directory)), ShowCmd)
+ end;
+end;
+
+function Tnt_LoadLibraryW(lpLibFileName: PWideChar): HMODULE;
+begin
+ if Win32PlatformIsUnicode then
+ Result := LoadLibraryW{TNT-ALLOW LoadLibraryW}(lpLibFileName)
+ else
+ Result := LoadLibraryA{TNT-ALLOW LoadLibraryA}(PAnsiChar(AnsiString(lpLibFileName)));
+end;
+
+function Tnt_LoadLibraryExW(lpLibFileName: PWideChar; hFile: THandle; dwFlags: DWORD): HMODULE;
+begin
+ if Win32PlatformIsUnicode then
+ Result := LoadLibraryExW{TNT-ALLOW LoadLibraryExW}(lpLibFileName, hFile, dwFlags)
+ else
+ Result := LoadLibraryExA{TNT-ALLOW LoadLibraryExA}(PAnsiChar(AnsiString(lpLibFileName)), hFile, dwFlags);
+end;
+
+function Tnt_CreateProcessW(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
+ lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
+ bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
+ lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfoW;
+ var lpProcessInformation: TProcessInformation): BOOL;
+var
+ AnsiStartupInfo: TStartupInfoA;
+begin
+ if Win32PlatformIsUnicode then begin
+ Result := CreateProcessW{TNT-ALLOW CreateProcessW}(lpApplicationName, lpCommandLine,
+ lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
+ lpCurrentDirectory, lpStartupInfo, lpProcessInformation)
+ end else begin
+ CopyMemory(@AnsiStartupInfo, @lpStartupInfo, SizeOf(TStartupInfo));
+ AnsiStartupInfo.lpReserved := _PAnsiCharWithNil(AnsiString(lpStartupInfo.lpReserved));
+ AnsiStartupInfo.lpDesktop := _PAnsiCharWithNil(AnsiString(lpStartupInfo.lpDesktop));
+ AnsiStartupInfo.lpTitle := _PAnsiCharWithNil(AnsiString(lpStartupInfo.lpTitle));
+ Result := CreateProcessA{TNT-ALLOW CreateProcessA}(_PAnsiCharWithNil(AnsiString(lpApplicationName)),
+ _PAnsiCharWithNil(AnsiString(lpCommandLine)),
+ lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
+ _PAnsiCharWithNil(AnsiString(lpCurrentDirectory)), AnsiStartupInfo, lpProcessInformation);
+ end;
+end;
+
+function Tnt_GetCurrencyFormatW(Locale: LCID; dwFlags: DWORD; lpValue: PWideChar;
+ lpFormat: PCurrencyFmtW; lpCurrencyStr: PWideChar; cchCurrency: Integer): Integer;
+const
+ MAX_ANSI_BUFF_SIZE = 64; // can a currency string actually be larger?
+var
+ AnsiFormat: TCurrencyFmtA;
+ PAnsiFormat: PCurrencyFmtA;
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetCurrencyFormatW{TNT-ALLOW GetCurrencyFormatW}(Locale, dwFlags, lpValue,
+ {$IFNDEF FPC} lpFormat {$ELSE} PCurrencyFmt(lpFormat) {$ENDIF},
+ lpCurrencyStr, cchCurrency)
+ else begin
+ if lpFormat = nil then
+ PAnsiFormat := nil
+ else begin
+ ZeroMemory(@AnsiFormat, SizeOf(AnsiFormat));
+ AnsiFormat.NumDigits := lpFormat.NumDigits;
+ AnsiFormat.LeadingZero := lpFormat.LeadingZero;
+ AnsiFormat.Grouping := lpFormat.Grouping;
+ AnsiFormat.lpDecimalSep := PAnsiChar(AnsiString(lpFormat.lpDecimalSep));
+ AnsiFormat.lpThousandSep := PAnsiChar(AnsiString(lpFormat.lpThousandSep));
+ AnsiFormat.NegativeOrder := lpFormat.NegativeOrder;
+ AnsiFormat.PositiveOrder := lpFormat.PositiveOrder;
+ AnsiFormat.lpCurrencySymbol := PAnsiChar(AnsiString(lpFormat.lpCurrencySymbol));
+ PAnsiFormat := @AnsiFormat;
+ end;
+ SetLength(AnsiBuff, MAX_ANSI_BUFF_SIZE);
+ SetLength(AnsiBuff, GetCurrencyFormatA{TNT-ALLOW GetCurrencyFormatA}(Locale, dwFlags,
+ PAnsiChar(AnsiString(lpValue)), PAnsiFormat, PAnsiChar(AnsiBuff), MAX_ANSI_BUFF_SIZE));
+ Result := _HandleStringLengthResult(cchCurrency, lpCurrencyStr, AnsiBuff, []);
+ end;
+end;
+
+function Tnt_CompareStringW(Locale: LCID; dwCmpFlags: DWORD; lpString1: PWideChar;
+ cchCount1: Integer; lpString2: PWideChar; cchCount2: Integer): Integer;
+var
+ WideStr1, WideStr2: WideString;
+ AnsiStr1, AnsiStr2: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CompareStringW{TNT-ALLOW CompareStringW}(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2)
+ else begin
+ WideStr1 := _WStr(lpString1, cchCount1);
+ WideStr2 := _WStr(lpString2, cchCount2);
+ if (dwCmpFlags = 0) then begin
+ // binary comparison
+ if WideStr1 < WideStr2 then
+ Result := 1
+ else if WideStr1 = WideStr2 then
+ Result := 2
+ else
+ Result := 3;
+ end else begin
+ AnsiStr1 := WideStr1;
+ AnsiStr2 := WideStr2;
+ Result := CompareStringA{TNT-ALLOW CompareStringA}(Locale, dwCmpFlags,
+ PAnsiChar(AnsiStr1), -1, PAnsiChar(AnsiStr2), -1);
+ end;
+ end;
+end;
+
+function Tnt_CharUpperW(lpsz: PWideChar): PWideChar;
+var
+ AStr: AnsiString;
+ WStr: WideString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CharUpperW{TNT-ALLOW CharUpperW}(lpsz)
+ else begin
+ if HiWord(Cardinal(lpsz)) = 0 then begin
+ // literal char mode
+ Result := lpsz;
+ if IsWideCharMappableToAnsi(WideChar(lpsz)) then begin
+ AStr := WideChar(lpsz); // single character may be more than one byte
+ CharUpperA{TNT-ALLOW CharUpperA}(PAnsiChar(AStr));
+ WStr := AStr; // should always be single wide char
+ if Length(WStr) = 1 then
+ Result := PWideChar(WStr[1]);
+ end
+ end else begin
+ // null-terminated string mode
+ Result := lpsz;
+ while lpsz^ <> #0 do begin
+ lpsz^ := WideChar(Tnt_CharUpperW(PWideChar(lpsz^)));
+ Inc(lpsz);
+ end;
+ end;
+ end;
+end;
+
+function Tnt_CharUpperBuffW(lpsz: PWideChar; cchLength: DWORD): DWORD;
+var
+ i: integer;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CharUpperBuffW{TNT-ALLOW CharUpperBuffW}(lpsz, cchLength)
+ else begin
+ Result := cchLength;
+ for i := 1 to cchLength do begin
+ lpsz^ := WideChar(Tnt_CharUpperW(PWideChar(lpsz^)));
+ Inc(lpsz);
+ end;
+ end;
+end;
+
+function Tnt_CharLowerW(lpsz: PWideChar): PWideChar;
+var
+ AStr: AnsiString;
+ WStr: WideString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CharLowerW{TNT-ALLOW CharLowerW}(lpsz)
+ else begin
+ if HiWord(Cardinal(lpsz)) = 0 then begin
+ // literal char mode
+ Result := lpsz;
+ if IsWideCharMappableToAnsi(WideChar(lpsz)) then begin
+ AStr := WideChar(lpsz); // single character may be more than one byte
+ CharLowerA{TNT-ALLOW CharLowerA}(PAnsiChar(AStr));
+ WStr := AStr; // should always be single wide char
+ if Length(WStr) = 1 then
+ Result := PWideChar(WStr[1]);
+ end
+ end else begin
+ // null-terminated string mode
+ Result := lpsz;
+ while lpsz^ <> #0 do begin
+ lpsz^ := WideChar(Tnt_CharLowerW(PWideChar(lpsz^)));
+ Inc(lpsz);
+ end;
+ end;
+ end;
+end;
+
+function Tnt_CharLowerBuffW(lpsz: PWideChar; cchLength: DWORD): DWORD;
+var
+ i: integer;
+begin
+ if Win32PlatformIsUnicode then
+ Result := CharLowerBuffW{TNT-ALLOW CharLowerBuffW}(lpsz, cchLength)
+ else begin
+ Result := cchLength;
+ for i := 1 to cchLength do begin
+ lpsz^ := WideChar(Tnt_CharLowerW(PWideChar(lpsz^)));
+ Inc(lpsz);
+ end;
+ end;
+end;
+
+function Tnt_GetStringTypeExW(Locale: LCID; dwInfoType: DWORD;
+ lpSrcStr: PWideChar; cchSrc: Integer; var lpCharType): BOOL;
+var
+ AStr: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetStringTypeExW{TNT-ALLOW GetStringTypeExW}(Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType)
+ else begin
+ AStr := _WStr(lpSrcStr, cchSrc);
+ Result := GetStringTypeExA{TNT-ALLOW GetStringTypeExA}(Locale, dwInfoType,
+ PAnsiChar(AStr), -1, lpCharType);
+ end;
+end;
+
+function Win9x_LoadStringW(hInstance: HINST; uID: UINT; lpBuffer: PWideChar; nBufferMax: Integer): Integer;
+// This function originated by the WINE Project.
+// It was translated to Pascal by Francisco Leong.
+// It was further modified by Troy Wolbrink.
+var
+ hmem: HGLOBAL;
+ hrsrc: THandle;
+ p: PWideChar;
+ string_num, i: Integer;
+ block: Integer;
+begin
+ Result := 0;
+ // Netscape v3 fix...
+ if (HIWORD(uID) = $FFFF) then begin
+ uID := UINT(-(Integer(uID)));
+ end;
+ // figure block, string_num
+ block := ((uID shr 4) and $FFFF) + 1; // bits 4 - 19, mask out bits 20 - 31, inc by 1
+ string_num := uID and $000F;
+ // get handle & pointer to string block
+ hrsrc := FindResource{TNT-ALLOW FindResource}(hInstance, MAKEINTRESOURCE(block), RT_STRING);
+ if (hrsrc <> 0) then
+ begin
+ hmem := LoadResource(hInstance, hrsrc);
+ if (hmem <> 0) then
+ begin
+ p := LockResource(hmem);
+ // walk the block to the requested string
+ for i := 0 to string_num - 1 do begin
+ p := p + Integer(p^) + 1;
+ end;
+ Result := Integer(p^); { p points to the length of string }
+ Inc(p); { p now points to the actual string }
+ if (lpBuffer <> nil) and (nBufferMax > 0) then
+ begin
+ Result := min(nBufferMax - 1, Result); { max length to copy }
+ if (Result > 0) then begin
+ CopyMemory(lpBuffer, p, Result * sizeof(WideChar));
+ end;
+ lpBuffer[Result] := WideChar(0); { null terminate }
+ end;
+ end;
+ end;
+end;
+
+function Tnt_LoadStringW(hInstance: HINST; uID: UINT; lpBuffer: PWideChar; nBufferMax: Integer): Integer;
+begin
+ if Win32PlatformIsUnicode then
+ Result := Windows.LoadStringW{TNT-ALLOW LoadStringW}(hInstance, uID, lpBuffer, nBufferMax)
+ else
+ Result := Win9x_LoadStringW(hInstance, uID, lpBuffer, nBufferMax);
+end;
+
+function Tnt_InsertMenuItemW(hMenu: HMENU; uItem: DWORD; fByPosition: BOOL; lpmii: TMenuItemInfoW): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := InsertMenuItemW{TNT-ALLOW InsertMenuItemW}(hMenu, uItem, fByPosition,
+ {$IFDEF FPC}@{$ENDIF}lpmii)
+ else begin
+ TMenuItemInfoA(lpmii).dwTypeData := PAnsiChar(AnsiString(lpmii.dwTypeData));
+ Result := InsertMenuItemA{TNT-ALLOW InsertMenuItemA}(hMenu, uItem, fByPosition,
+ {$IFDEF FPC}@{$ENDIF}TMenuItemInfoA(lpmii));
+ end;
+end;
+
+function Tnt_ExtractIconExW(lpszFile: PWideChar; nIconIndex: Integer;
+ var phiconLarge, phiconSmall: HICON; nIcons: UINT): UINT;
+begin
+ if Win32PlatformIsUnicode then
+ Result := ExtractIconExW{TNT-ALLOW ExtractIconExW}(lpszFile,
+ nIconIndex, phiconLarge, phiconSmall, nIcons)
+ else
+ Result := ExtractIconExA{TNT-ALLOW ExtractIconExA}(PAnsiChar(AnsiString(lpszFile)),
+ nIconIndex, phiconLarge, phiconSmall, nIcons);
+end;
+
+function Tnt_ExtractAssociatedIconW(hInst: HINST; lpIconPath: PWideChar;
+ var lpiIcon: Word): HICON;
+begin
+ if Win32PlatformIsUnicode then
+ Result := ExtractAssociatedIconW{TNT-ALLOW ExtractAssociatedIconW}(hInst,
+ lpIconPath, {$IFDEF FPC}@{$ENDIF}lpiIcon)
+ else
+ Result := ExtractAssociatedIconA{TNT-ALLOW ExtractAssociatedIconA}(hInst,
+ PAnsiChar(AnsiString(lpIconPath)), {$IFDEF FPC}@{$ENDIF}lpiIcon)
+end;
+
+function Tnt_GetFileVersionInfoSizeW(lptstrFilename: PWideChar; var lpdwHandle: DWORD): DWORD;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetFileVersionInfoSizeW{TNT-ALLOW GetFileVersionInfoSizeW}(lptstrFilename, lpdwHandle)
+ else
+ Result := GetFileVersionInfoSizeA{TNT-ALLOW GetFileVersionInfoSizeA}(PAnsiChar(AnsiString(lptstrFilename)), lpdwHandle);
+end;
+
+function Tnt_GetFileVersionInfoW(lptstrFilename: PWideChar; dwHandle, dwLen: DWORD;
+ lpData: Pointer): BOOL;
+begin
+ if Win32PlatformIsUnicode then
+ Result := GetFileVersionInfoW{TNT-ALLOW GetFileVersionInfoW}(lptstrFilename, dwHandle, dwLen, lpData)
+ else
+ Result := GetFileVersionInfoA{TNT-ALLOW GetFileVersionInfoA}(PAnsiChar(AnsiString(lptstrFilename)), dwHandle, dwLen, lpData);
+end;
+
+var
+ Last_VerQueryValue_String: WideString;
+
+function Tnt_VerQueryValueW(pBlock: Pointer; lpSubBlock: PWideChar;
+ var lplpBuffer: Pointer; var puLen: UINT): BOOL;
+var
+ AnsiBuff: AnsiString;
+begin
+ if Win32PlatformIsUnicode then
+ Result := VerQueryValueW{TNT-ALLOW VerQueryValueW}(pBlock, lpSubBlock, lplpBuffer, puLen)
+ else begin
+ Result := VerQueryValueA{TNT-ALLOW VerQueryValueA}(pBlock, PAnsiChar(AnsiString(lpSubBlock)), lplpBuffer, puLen);
+ if WideTextPos(VQV_STRINGFILEINFO, lpSubBlock) <> 1 then
+ else begin
+ { /StringFileInfo, convert ansi result to unicode }
+ SetString(AnsiBuff, PAnsiChar(lplpBuffer), puLen);
+ Last_VerQueryValue_String := AnsiBuff;
+ lplpBuffer := PWideChar(Last_VerQueryValue_String);
+ puLen := Length(Last_VerQueryValue_String);
+ end;
+ end;
+end;
+
+//---------------------------------------------------------------------------------------
+// Wide functions from Shell32.dll should be loaded dynamically (no stub on early Win95)
+//---------------------------------------------------------------------------------------
+
+type
+ TSHFileOperationW = function(var lpFileOp: TSHFileOpStructW): Integer; stdcall;
+ TSHBrowseForFolderW = function(var lpbi: TBrowseInfoW): PItemIDList; stdcall;
+ TSHGetPathFromIDListW = function(pidl: PItemIDList; pszPath: PWideChar): BOOL; stdcall;
+ TSHGetFileInfoW = function(pszPath: PWideChar; dwFileAttributes: DWORD;
+ var psfi: TSHFileInfoW; cbFileInfo, uFlags: UINT): DWORD; stdcall;
+
+var
+ Safe_SHFileOperationW: TSHFileOperationW = nil;
+ Safe_SHBrowseForFolderW: TSHBrowseForFolderW = nil;
+ Safe_SHGetPathFromIDListW: TSHGetPathFromIDListW = nil;
+ Safe_SHGetFileInfoW: TSHGetFileInfoW = nil;
+
+var Shell32DLL: HModule = 0;
+
+procedure LoadWideShell32Procs;
+begin
+ if Shell32DLL = 0 then begin
+ Shell32DLL := WinCheckH(Tnt_LoadLibraryW('shell32.dll'));
+ Safe_SHFileOperationW := WinCheckP(GetProcAddress(Shell32DLL, 'SHFileOperationW'));
+ Safe_SHBrowseForFolderW := WinCheckP(GetProcAddress(Shell32DLL, 'SHBrowseForFolderW'));
+ Safe_SHGetPathFromIDListW := WinCheckP(GetProcAddress(Shell32DLL, 'SHGetPathFromIDListW'));
+ Safe_SHGetFileInfoW := WinCheckP(GetProcAddress(Shell32DLL, 'SHGetFileInfoW'));
+ end;
+end;
+
+function Tnt_SHFileOperationW(var lpFileOp: TSHFileOpStructW): Integer;
+var
+ AnsiFileOp: TSHFileOpStructA;
+ MapCount: Integer;
+ PAnsiMap: PSHNameMappingA;
+ PWideMap: PSHNameMappingW;
+ OldPath: WideString;
+ NewPath: WideString;
+ i: integer;
+begin
+ if Win32PlatformIsUnicode then begin
+ LoadWideShell32Procs;
+ Result := Safe_SHFileOperationW(lpFileOp);
+ end else begin
+ AnsiFileOp := TSHFileOpStructA(lpFileOp);
+ // convert PChar -> PWideChar
+ if lpFileOp.pFrom = nil then
+ AnsiFileOp.pFrom := nil
+ else
+ AnsiFileOp.pFrom := PAnsiChar(AnsiString(ExtractStringArrayStr(lpFileOp.pFrom)));
+ if lpFileOp.pTo = nil then
+ AnsiFileOp.pTo := nil
+ else
+ AnsiFileOp.pTo := PAnsiChar(AnsiString(ExtractStringArrayStr(lpFileOp.pTo)));
+ AnsiFileOp.lpszProgressTitle := PAnsiChar(AnsiString(lpFileOp.lpszProgressTitle));
+ Result := SHFileOperationA{TNT-ALLOW SHFileOperationA}(
+ {$IFDEF FPC}@{$ENDIF}AnsiFileOp);
+ // return struct results
+ lpFileOp.fAnyOperationsAborted := AnsiFileOp.fAnyOperationsAborted;
+ lpFileOp.hNameMappings := nil;
+ if (AnsiFileOp.hNameMappings <> nil)
+ and ((FOF_WANTMAPPINGHANDLE and AnsiFileOp.fFlags) <> 0) then begin
+ // alloc mem
+ MapCount := PSHNameMappingHeaderA(AnsiFileOp.hNameMappings).cNumOfMappings;
+ lpFileOp.hNameMappings :=
+ AllocMem(SizeOf({hNameMappings}Cardinal) + SizeOf(TSHNameMappingW) * MapCount);
+ PSHNameMappingHeaderW(lpFileOp.hNameMappings).cNumOfMappings := MapCount;
+ // init pointers
+ PAnsiMap := PSHNameMappingHeaderA(AnsiFileOp.hNameMappings).lpNM;
+ PWideMap := PSHNameMappingHeaderW(lpFileOp.hNameMappings).lpNM;
+ for i := 1 to MapCount do begin
+ // old path
+ OldPath := Copy(PAnsiMap.pszOldPath, 1, PAnsiMap.cchOldPath);
+ PWideMap.pszOldPath := WStrNew(PWideChar(OldPath));
+ PWideMap.cchOldPath := WStrLen(PWideMap.pszOldPath);
+ // new path
+ NewPath := Copy(PAnsiMap.pszNewPath, 1, PAnsiMap.cchNewPath);
+ PWideMap.pszNewPath := WStrNew(PWideChar(NewPath));
+ PWideMap.cchNewPath := WStrLen(PWideMap.pszNewPath);
+ // next record
+ Inc(PAnsiMap);
+ Inc(PWideMap);
+ end;
+ end;
+ end;
+end;
+
+procedure Tnt_SHFreeNameMappings(hNameMappings: THandle);
+var
+ i: integer;
+ MapCount: Integer;
+ PWideMap: PSHNameMappingW;
+begin
+ if Win32PlatformIsUnicode then
+ SHFreeNameMappings{TNT-ALLOW SHFreeNameMappings}(hNameMappings)
+ else begin
+ // free strings
+ MapCount := PSHNameMappingHeaderW(hNameMappings).cNumOfMappings;
+ PWideMap := PSHNameMappingHeaderW(hNameMappings).lpNM;
+ for i := 1 to MapCount do begin
+ WStrDispose(PWideMap.pszOldPath);
+ WStrDispose(PWideMap.pszNewPath);
+ Inc(PWideMap);
+ end;
+ // free struct
+ FreeMem(Pointer(hNameMappings));
+ end;
+end;
+
+function Tnt_SHBrowseForFolderW(var lpbi: TBrowseInfoW): PItemIDList;
+var
+ AnsiInfo: TBrowseInfoA;
+ AnsiBuffer: array[0..MAX_PATH] of AnsiChar;
+begin
+ if Win32PlatformIsUnicode then begin
+ LoadWideShell32Procs;
+ Result := Safe_SHBrowseForFolderW(lpbi);
+ end else begin
+ AnsiInfo := TBrowseInfoA(lpbi);
+ AnsiInfo.lpszTitle := PAnsiChar(AnsiString(lpbi.lpszTitle));
+ if lpbi.pszDisplayName <> nil then
+ AnsiInfo.pszDisplayName := AnsiBuffer;
+ Result := SHBrowseForFolderA{TNT-ALLOW SHBrowseForFolderA}(
+ {$IFDEF FPC}@{$ENDIF}AnsiInfo);
+ if lpbi.pszDisplayName <> nil then
+ WStrPCopy(lpbi.pszDisplayName, AnsiInfo.pszDisplayName);
+ lpbi.iImage := AnsiInfo.iImage;
+ end;
+end;
+
+function Tnt_SHGetPathFromIDListW(pidl: PItemIDList; pszPath: PWideChar): BOOL;
+var
+ AnsiPath: AnsiString;
+begin
+ if Win32PlatformIsUnicode then begin
+ LoadWideShell32Procs;
+ Result := Safe_SHGetPathFromIDListW(pidl, pszPath);
+ end else begin
+ SetLength(AnsiPath, MAX_PATH);
+ Result := SHGetPathFromIDListA{TNT-ALLOW SHGetPathFromIDListA}(pidl, PAnsiChar(AnsiPath));
+ if Result then
+ WStrPCopy(pszPath, PAnsiChar(AnsiPath))
+ end;
+end;
+
+function Tnt_SHGetFileInfoW(pszPath: PWideChar; dwFileAttributes: DWORD;
+ var psfi: TSHFileInfoW; cbFileInfo, uFlags: UINT): DWORD;
+var
+ SHFileInfoA: TSHFileInfoA;
+begin
+ if Win32PlatformIsUnicode then begin
+ LoadWideShell32Procs;
+ Result := Safe_SHGetFileInfoW(pszPath, dwFileAttributes, psfi, cbFileInfo, uFlags)
+ end else begin
+ Result := SHGetFileInfoA{TNT-ALLOW SHGetFileInfoA}(PAnsiChar(AnsiString(pszPath)),
+ dwFileAttributes, SHFileInfoA, SizeOf(TSHFileInfoA), uFlags);
+ // update pfsi...
+ ZeroMemory(@psfi, SizeOf(TSHFileInfoW));
+ psfi.hIcon := SHFileInfoA.hIcon;
+ psfi.iIcon := SHFileInfoA.iIcon;
+ psfi.dwAttributes := SHFileInfoA.dwAttributes;
+ WStrPLCopy(psfi.szDisplayName, SHFileInfoA.szDisplayName, MAX_PATH);
+ WStrPLCopy(psfi.szTypeName, SHFileInfoA.szTypeName, 80);
+ end;
+end;
+
+
+function Tnt_Is_IntResource(ResStr: LPCWSTR): Boolean;
+begin
+ Result := HiWord(Cardinal(ResStr)) = 0;
+end;
+
+function LANGIDFROMLCID(lcid: LCID): WORD;
+begin
+ Result := LoWord(lcid);
+end;
+
+function MAKELANGID(usPrimaryLanguage, usSubLanguage: WORD): WORD;
+begin
+ Result := (usSubLanguage shl 10) or usPrimaryLanguage;
+end;
+
+function MAKELCID(wLanguageID: WORD; wSortID: WORD = SORT_DEFAULT): LCID;
+begin
+ Result := MakeLong(wLanguageID, wSortID);
+end;
+
+function PRIMARYLANGID(lgid: WORD): WORD;
+begin
+ Result := lgid and $03FF;
+end;
+
+function SORTIDFROMLCID(lcid: LCID): WORD;
+begin
+ Result := HiWord(lcid);
+end;
+
+function SUBLANGID(lgid: WORD): WORD;
+begin
+ Result := lgid shr 10;
+end;
+
+initialization
+
+finalization
+ if Shell32DLL <> 0 then
+ FreeLibrary(Shell32DLL);
+
+end.
diff --git a/src/lib/ctypes/ctypes.pas b/src/lib/ctypes/ctypes.pas
index 6cdf77fc..694552dc 100644
--- a/src/lib/ctypes/ctypes.pas
+++ b/src/lib/ctypes/ctypes.pas
@@ -1,72 +1,72 @@
-{
- This file is part of the Free Pascal run time library.
- Copyright (c) 2004 by Marco van de Voort, member of the
- Free Pascal development team
-
- Implements C types for in header conversions
-
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
-
- 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.
-
-
- **********************************************************************}
-
-unit ctypes;
-
-interface
-
-type
- qword = int64; // Keep h2pas "uses ctypes" headers working with delphi.
-
- { the following type definitions are compiler dependant }
- { and system dependant }
-
- cint8 = shortint; pcint8 = ^cint8;
- cuint8 = byte; pcuint8 = ^cuint8;
- cchar = cint8; pcchar = ^cchar;
- cschar = cint8; pcschar = ^cschar;
- cuchar = cuint8; pcuchar = ^cuchar;
-
- cint16 = smallint; pcint16 = ^cint16;
- cuint16 = word; pcuint16 = ^cuint16;
- cshort = cint16; pcshort = ^cshort;
- csshort = cint16; pcsshort = ^csshort;
- cushort = cuint16; pcushort = ^cushort;
-
- cint32 = longint; pcint32 = ^cint32;
- cuint32 = longword; pcuint32 = ^cuint32;
- cint = cint32; pcint = ^cint; { minimum range is : 32-bit }
- csint = cint32; pcsint = ^csint; { minimum range is : 32-bit }
- cuint = cuint32; pcuint = ^cuint; { minimum range is : 32-bit }
- csigned = cint; pcsigned = ^csigned;
- cunsigned = cuint; pcunsigned = ^cunsigned;
-
- cint64 = int64; pcint64 = ^cint64;
- cuint64 = qword; pcuint64 = ^cuint64;
- clonglong = cint64; pclonglong = ^clonglong;
- cslonglong = cint64; pcslonglong = ^cslonglong;
- culonglong = cuint64; pculonglong = ^culonglong;
-
- cbool = longbool; pcbool = ^cbool;
-
-{$if defined(cpu64) and not(defined(win64) and defined(cpux86_64))}
- clong = int64; pclong = ^clong;
- cslong = int64; pcslong = ^cslong;
- culong = qword; pculong = ^culong;
-{$else}
- clong = longint; pclong = ^clong;
- cslong = longint; pcslong = ^cslong;
- culong = cardinal; pculong = ^culong;
-{$ifend}
-
- cfloat = single; pcfloat = ^cfloat;
- cdouble = double; pcdouble = ^cdouble;
- clongdouble = extended; pclongdouble = ^clongdouble;
-
-implementation
-
-end.
+{
+ This file is part of the Free Pascal run time library.
+ Copyright (c) 2004 by Marco van de Voort, member of the
+ Free Pascal development team
+
+ Implements C types for in header conversions
+
+ See the file COPYING.FPC, included in this distribution,
+ for details about the copyright.
+
+ 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.
+
+
+ **********************************************************************}
+
+unit ctypes;
+
+interface
+
+type
+ qword = int64; // Keep h2pas "uses ctypes" headers working with delphi.
+
+ { the following type definitions are compiler dependant }
+ { and system dependant }
+
+ cint8 = shortint; pcint8 = ^cint8;
+ cuint8 = byte; pcuint8 = ^cuint8;
+ cchar = cint8; pcchar = ^cchar;
+ cschar = cint8; pcschar = ^cschar;
+ cuchar = cuint8; pcuchar = ^cuchar;
+
+ cint16 = smallint; pcint16 = ^cint16;
+ cuint16 = word; pcuint16 = ^cuint16;
+ cshort = cint16; pcshort = ^cshort;
+ csshort = cint16; pcsshort = ^csshort;
+ cushort = cuint16; pcushort = ^cushort;
+
+ cint32 = longint; pcint32 = ^cint32;
+ cuint32 = longword; pcuint32 = ^cuint32;
+ cint = cint32; pcint = ^cint; { minimum range is : 32-bit }
+ csint = cint32; pcsint = ^csint; { minimum range is : 32-bit }
+ cuint = cuint32; pcuint = ^cuint; { minimum range is : 32-bit }
+ csigned = cint; pcsigned = ^csigned;
+ cunsigned = cuint; pcunsigned = ^cunsigned;
+
+ cint64 = int64; pcint64 = ^cint64;
+ cuint64 = qword; pcuint64 = ^cuint64;
+ clonglong = cint64; pclonglong = ^clonglong;
+ cslonglong = cint64; pcslonglong = ^cslonglong;
+ culonglong = cuint64; pculonglong = ^culonglong;
+
+ cbool = longbool; pcbool = ^cbool;
+
+{$if defined(cpu64) and not(defined(win64) and defined(cpux86_64))}
+ clong = int64; pclong = ^clong;
+ cslong = int64; pcslong = ^cslong;
+ culong = qword; pculong = ^culong;
+{$else}
+ clong = longint; pclong = ^clong;
+ cslong = longint; pcslong = ^cslong;
+ culong = cardinal; pculong = ^culong;
+{$ifend}
+
+ cfloat = single; pcfloat = ^cfloat;
+ cdouble = double; pcdouble = ^cdouble;
+ clongdouble = extended; pclongdouble = ^clongdouble;
+
+implementation
+
+end.
diff --git a/src/lib/ffmpeg/avformat.pas b/src/lib/ffmpeg/avformat.pas
index 0ec2c118..e39416a1 100644
--- a/src/lib/ffmpeg/avformat.pas
+++ b/src/lib/ffmpeg/avformat.pas
@@ -1132,7 +1132,7 @@ function av_probe_input_format(pd: PAVProbeData; is_opened: cint): PAVInputForma
* Allocates all the structures needed to read an input stream.
* This does not open the needed codecs for decoding the stream[s].
*)
-function av_open_input_stream(ic_ptr: PAVFormatContext;
+function av_open_input_stream(var ic_ptr: PAVFormatContext;
pb: PByteIOContext; filename: PAnsiChar;
fmt: PAVInputFormat; ap: PAVFormatParameters): cint;
cdecl; external av__format;
diff --git a/src/lib/ffmpeg/avio.pas b/src/lib/ffmpeg/avio.pas
index dc0a330b..c47bb618 100644
--- a/src/lib/ffmpeg/avio.pas
+++ b/src/lib/ffmpeg/avio.pas
@@ -108,14 +108,16 @@ type
name: PAnsiChar;
url_open: function (h: PURLContext; filename: {const} PAnsiChar; flags: cint): cint; cdecl;
url_read: function (h: PURLContext; buf: PByteArray; size: cint): cint; cdecl;
+ {$IF LIBAVFORMAT_VERSION >= 52034001} // 52.34.1
url_read_complete: function (h: PURLContext; buf: PByteArray; size: cint): cint; cdecl;
+ {$IFEND}
url_write: function (h: PURLContext; buf: PByteArray; size: cint): cint; cdecl;
url_seek: function (h: PURLContext; pos: cint64; whence: cint): cint64; cdecl;
url_close: function (h: PURLContext): cint; cdecl;
next: PURLProtocol;
{$IF (LIBAVFORMAT_VERSION >= 52001000) and (LIBAVFORMAT_VERSION < 52004000)} // 52.1.0 .. 52.4.0
- url_read_play: function (h: PURLContext): cint;
- url_read_pause: function (h: PURLContext): cint;
+ url_read_play: function (h: PURLContext): cint; cdecl;
+ url_read_pause: function (h: PURLContext): cint; cdecl;
{$IFEND}
{$IF LIBAVFORMAT_VERSION >= 52004000} // 52.4.0
url_read_pause: function (h: PURLContext; pause: cint): cint; cdecl;
@@ -278,16 +280,19 @@ function av_protocol_next(p: PURLProtocol): PURLProtocol;
(**
* @deprecated Use av_register_protocol() instead.
*)
-function register_protocol (protocol: PURLProtocol): cint;
+function register_protocol(protocol: PURLProtocol): cint;
cdecl; external av__format;
+(** Alias for register_protocol() *)
+function av_register_protocol(protocol: PURLProtocol): cint;
+ cdecl; external av__format name 'register_protocol';
{$ELSE}
-function av_register_protocol (protocol: PURLProtocol): cint;
+function av_register_protocol(protocol: PURLProtocol): cint;
cdecl; external av__format;
{$IFEND}
type
- TReadWriteFunc = function (opaque: Pointer; buf: PByteArray; buf_size: cint): cint; cdecl;
- TSeekFunc = function (opaque: Pointer; offset: cint64; whence: cint): cint64; cdecl;
+ TReadWriteFunc = function(opaque: Pointer; buf: PByteArray; buf_size: cint): cint; cdecl;
+ TSeekFunc = function(opaque: Pointer; offset: cint64; whence: cint): cint64; cdecl;
function init_put_byte(s: PByteIOContext;
buffer: PByteArray;
diff --git a/src/lib/fft/UFFT.pas b/src/lib/fft/UFFT.pas
index 6b094c98..5a056a8c 100644
--- a/src/lib/fft/UFFT.pas
+++ b/src/lib/fft/UFFT.pas
@@ -47,7 +47,7 @@ unit UFFT;
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // Use AnsiString
+ {$H+} // Use long strings
{$ENDIF}
interface
diff --git a/src/lib/freetype/demo/engine-test.bdsproj b/src/lib/freetype/demo/engine-test.bdsproj
index 9547f18f..e5b3e97d 100644
--- a/src/lib/freetype/demo/engine-test.bdsproj
+++ b/src/lib/freetype/demo/engine-test.bdsproj
@@ -27,13 +27,13 @@
<Compiler Name="I">1</Compiler>
<Compiler Name="J">0</Compiler>
<Compiler Name="K">0</Compiler>
- <Compiler Name="L">1</Compiler>
- <Compiler Name="M">0</Compiler>
- <Compiler Name="N">1</Compiler>
- <Compiler Name="O">0</Compiler>
- <Compiler Name="P">1</Compiler>
- <Compiler Name="Q">0</Compiler>
- <Compiler Name="R">0</Compiler>
+ <Compiler Name="L">1</Compiler>
+ <Compiler Name="M">0</Compiler>
+ <Compiler Name="N">1</Compiler>
+ <Compiler Name="O">1</Compiler>
+ <Compiler Name="P">1</Compiler>
+ <Compiler Name="Q">0</Compiler>
+ <Compiler Name="R">0</Compiler>
<Compiler Name="S">0</Compiler>
<Compiler Name="T">0</Compiler>
<Compiler Name="U">0</Compiler>
diff --git a/src/lib/freetype/demo/engine-test.dpr b/src/lib/freetype/demo/engine-test.dpr
index 80177735..bbd7d890 100644
--- a/src/lib/freetype/demo/engine-test.dpr
+++ b/src/lib/freetype/demo/engine-test.dpr
@@ -27,7 +27,9 @@ uses
ctypes in '../../ctypes/ctypes.pas',
{$ENDIF}
FreeType in '../freetype.pas',
- UFont in '../../../base/UFont.pas',
+ UFont in 'UFont.pas',
+ //UFont in '../../../base/UFont.pas',
+ UUnicodeUtils in '../../../base/UUnicodeUtils.pas',
math,
sysutils;
@@ -41,7 +43,7 @@ const
//FONT_FILE = 'C:/Windows/Fonts/Arial.ttf';
//FONT_FILE = 'C:/Windows/Fonts/SimSun.ttf';
//FONT_FILE = 'eurostarregularextended.ttf';
- FONT_FILE = 'FreeSans.ttf';
+ FONT_FILE = '../../../../game/fonts/FreeSans/FreeSans.ttf';
var
OurFont: TScalableFont;
@@ -129,11 +131,11 @@ begin
// Really Nice Perspective Calculations
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
- //OurFont := TFTScalableFont.Create(FONT_FILE, 64);
+ OurFont := TFTScalableFont.Create(FONT_FILE, 64, 0.03);
//OurFont := TFTFont.Create(FONT_FILE, 128);
- OurFont := TFTScalableOutlineFont.Create(FONT_FILE, 64, 0.05);
+ //OurFont := TFTScalableOutlineFont.Create(FONT_FILE, 64, 0.03);
//OurFont.UseKerning := false;
- TFTScalableOutlineFont(OurFont).SetOutlineColor(1, 0, 0);
+ //TFTScalableOutlineFont(OurFont).SetOutlineColor(1, 0, 0, 1);
//OurFont := TOutlineFont.Create(FONT_FILE, 32, 2);
//OurFont.LineSpacing := OurFont.LineSpacing * 0.5;
@@ -183,7 +185,7 @@ begin
//OurFont.SetOutlineColor(0.5, 0.5, 0.5);
//OurFont.ReflectionSpacing := -4;
//OurFont.UseKerning := false;
- OurFont.Height := 64;//cnt2;
+ OurFont.Height := 150;//cnt2;
//OurFont.Reset;
//OurFont.Aspect := 2;
@@ -191,7 +193,7 @@ begin
bounds := OurFont.BBox(msg);
//glRectf(bounds.Left, OurFont.Ascender, bounds.Right, OurFont.Ascender-OurFont.Height);
- glColor3f(1, 1, 1);
+ glColor4f(1, 1, 1, 1);
//OurFont.ReflectionSpacing := 0;
OurFont.Print(msg);
diff --git a/src/lib/freetype/demo/engine-test.lpi b/src/lib/freetype/demo/engine-test.lpi
index 6cbfe1eb..45483a56 100644
--- a/src/lib/freetype/demo/engine-test.lpi
+++ b/src/lib/freetype/demo/engine-test.lpi
@@ -28,14 +28,14 @@
</local>
</RunParams>
<Units Count="16">
- <Unit0>
- <Filename Value="engine-test.dpr"/>
- <IsPartOfProject Value="True"/>
- <CursorPos X="25" Y="135"/>
- <TopLine Value="118"/>
- <EditorIndex Value="0"/>
- <UsageCount Value="72"/>
- <Loaded Value="True"/>
+ <Unit0>
+ <Filename Value="engine-test.dpr"/>
+ <IsPartOfProject Value="True"/>
+ <CursorPos X="18" Y="25"/>
+ <TopLine Value="1"/>
+ <EditorIndex Value="0"/>
+ <UsageCount Value="72"/>
+ <Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="JEDI-SDL\OpenGL\Pas\opengl12.pas"/>
@@ -139,13 +139,22 @@
<UnitName Value="UFont"/>
<CursorPos X="15" Y="1752"/>
<TopLine Value="1734"/>
- <UsageCount Value="10"/>
- </Unit15>
- </Units>
- <JumpHistory Count="0" HistoryIndex="-1"/>
- </ProjectOptions>
- <CompilerOptions>
- <Version Value="8"/>
+ <UsageCount Value="10"/>
+ </Unit15>
+ </Units>
+ <JumpHistory Count="2" HistoryIndex="1">
+ <Position1>
+ <Filename Value="engine-test.dpr"/>
+ <Caret Line="52" Column="10" TopLine="37"/>
+ </Position1>
+ <Position2>
+ <Filename Value="engine-test.dpr"/>
+ <Caret Line="1" Column="1" TopLine="1"/>
+ </Position2>
+ </JumpHistory>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="8"/>
<PathDelim Value="\"/>
<SearchPaths>
<IncludeFiles Value="..\..\JEDI-SDL\SDL\Pas\"/>
diff --git a/src/lib/freetype/freetype.pas b/src/lib/freetype/freetype.pas
index 6a9d2062..6aaa3b59 100644
--- a/src/lib/freetype/freetype.pas
+++ b/src/lib/freetype/freetype.pas
@@ -1,23 +1,42 @@
-//----------------------------------------------------------------------------
-// FreeType2 pascal header
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.4 (Public License)
-// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
-// Pascal Port By: Milan Marusinec alias Milano
-// milan@marusinec.sk
-// http://www.aggpas.org
-// Copyright (c) 2005-2007
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Adapted by the UltraStar Deluxe Team
-//----------------------------------------------------------------------------
+(***************************************************************************)
+(* *)
+(* freetype.h *)
+(* *)
+(* FreeType high-level API and common types (specification only). *)
+(* *)
+(* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by *)
+(* David Turner, Robert Wilhelm, and Werner Lemberg. *)
+(* *)
+(* This file is part of the FreeType project, and may only be used, *)
+(* modified, and distributed under the terms of the FreeType project *)
+(* license, LICENSE.TXT. By continuing to use, modify, or distribute *)
+(* this file you indicate that you have read the license and *)
+(* understand and accept it fully. *)
+(* *)
+(***************************************************************************)
+
+(***************************************************************************)
+(* Initial Pascal port by *)
+(***************************************************************************)
+(* Anti-Grain Geometry - Version 2.4 (Public License) *)
+(* Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) *)
+(* *)
+(* Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3) *)
+(* Pascal Port By: Milan Marusinec alias Milano *)
+(* milan@marusinec.sk *)
+(* http://www.aggpas.org *)
+(* Copyright (c) 2005-2007 *)
+(* *)
+(* Permission to copy, use, modify, sell and distribute this software *)
+(* is granted provided this copyright notice appears in all copies. *)
+(* This software is provided "as is" without express or implied *)
+(* warranty, and with no claim as to its suitability for any purpose. *)
+(* *)
+(***************************************************************************)
+
+(***************************************************************************)
+(* Extended by the UltraStar Deluxe Team *)
+(***************************************************************************)
unit freetype;
@@ -36,7 +55,7 @@ uses
const
{$IF Defined(MSWINDOWS)}
- ft_lib = 'libfreetype-6.dll';
+ ft_lib = 'freetype6.dll';
{$ELSEIF Defined(DARWIN)}
ft_lib = 'libfreetype.dylib';
{$LINKLIB libfreetype}
@@ -45,32 +64,24 @@ const
{$IFEND}
type
- FT_Byte = cuchar;
- FT_Short = csshort;
- FT_UShort = cushort;
- FT_Int = csint;
- FT_UInt = cuint;
- FT_Int16 = cint16;
- FT_UInt16 = cuint16;
- FT_Int32 = cint32;
- FT_UInt32 = cuint32;
- FT_Long = cslong;
- FT_ULong = culong;
-
- FT_Fixed = cslong;
- FT_Pos = cslong;
- FT_Error = cint;
- FT_F26Dot6 = cslong;
- FT_String = cchar;
- FT_Bool = cuchar;
-
- PFT_Byte = ^FT_Byte;
- PFT_Short = ^FT_Short;
- PFT_String = ^FT_String;
-
-
- TByteArray = array [0 .. (MaxInt div SizeOf(byte))-1] of byte;
- PByteArray = ^TByteArray;
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Library *)
+ (* *)
+ (* <Description> *)
+ (* A handle to a FreeType library instance. Each `library' is *)
+ (* completely independent from the others; it is the `root' of a set *)
+ (* of objects like fonts, faces, sizes, etc. *)
+ (* *)
+ (* It also embeds a memory manager (see @FT_Memory), as well as a *)
+ (* scan-line converter object (see @FT_Raster). *)
+ (* *)
+ (* <Note> *)
+ (* Library objects are normally created by @FT_Init_FreeType, and *)
+ (* destroyed with @FT_Done_FreeType. *)
+ (* *)
+ FT_Library = Pointer;
(*************************************************************************)
@@ -290,54 +301,6 @@ const
FT_ENCODING_WANSUNG: FT_Encoding = ('w', 'a', 'n', 's');
FT_ENCODING_JOHAB: FT_Encoding = ('j', 'o', 'h', 'a');
- (*************************************************************************)
- (* *)
- (* <Enum> *)
- (* FT_Glyph_Format *)
- (* *)
- (* <Description> *)
- (* An enumeration type used to describe the format of a given glyph *)
- (* image. Note that this version of FreeType only supports two image *)
- (* formats, even though future font drivers will be able to register *)
- (* their own format. *)
- (* *)
- (* <Values> *)
- (* FT_GLYPH_FORMAT_NONE :: *)
- (* The value 0 is reserved and does describe a glyph format. *)
- (* *)
- (* FT_GLYPH_FORMAT_COMPOSITE :: *)
- (* The glyph image is a composite of several other images. This *)
- (* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to *)
- (* report compound glyphs (like accented characters). *)
- (* *)
- (* FT_GLYPH_FORMAT_BITMAP :: *)
- (* The glyph image is a bitmap, and can be described as an *)
- (* @FT_Bitmap. You generally need to access the `bitmap' field of *)
- (* the @FT_GlyphSlotRec structure to read it. *)
- (* *)
- (* FT_GLYPH_FORMAT_OUTLINE :: *)
- (* The glyph image is a vertorial outline made of line segments *)
- (* and Bezier arcs; it can be described as an @FT_Outline; you *)
- (* generally want to access the `outline' field of the *)
- (* @FT_GlyphSlotRec structure to read it. *)
- (* *)
- (* FT_GLYPH_FORMAT_PLOTTER :: *)
- (* The glyph image is a vectorial path with no inside/outside *)
- (* contours. Some Type 1 fonts, like those in the Hershey family, *)
- (* contain glyphs in this format. These are described as *)
- (* @FT_Outline, but FreeType isn't currently capable of rendering *)
- (* them correctly. *)
- (* *)
-type
- FT_Glyph_Format = array[0..3] of char;
-const
- FT_GLYPH_FORMAT_NONE: FT_Glyph_Format = (#0, #0, #0, #0 );
-
- FT_GLYPH_FORMAT_COMPOSITE: FT_Glyph_Format = ('c', 'o', 'm', 'p' );
- FT_GLYPH_FORMAT_BITMAP: FT_Glyph_Format = ('b', 'i', 't', 's' );
- FT_GLYPH_FORMAT_OUTLINE: FT_Glyph_Format = ('o', 'u', 't', 'l' );
- FT_GLYPH_FORMAT_PLOTTER: FT_Glyph_Format = ('p', 'l', 'o', 't' );
-
(*************************************************************************)
(* *)
@@ -358,7 +321,7 @@ const
const
FT_STYLE_FLAG_ITALIC = 1 shl 0;
FT_STYLE_FLAG_BOLD = 1 shl 1;
-
+
(***************************************************************************
*
@@ -567,7 +530,7 @@ const
(* perform this pass. *)
(* *)
type
- FT_Render_Mode = FT_Int;
+ FT_Render_Mode = cint;
const
FT_RENDER_MODE_NORMAL = 0;
FT_RENDER_MODE_LIGHT = FT_RENDER_MODE_NORMAL + 1;
@@ -579,63 +542,34 @@ const
(*************************************************************************)
(* *)
- (* <Enum> *)
- (* FT_Pixel_Mode *)
+ (* <Type> *)
+ (* FT_GlyphSlot *)
(* *)
(* <Description> *)
- (* An enumeration type used to describe the format of pixels in a *)
- (* given bitmap. Note that additional formats may be added in the *)
- (* future. *)
+ (* A handle to a given `glyph slot'. A slot is a container where it *)
+ (* is possible to load any one of the glyphs contained in its parent *)
+ (* face. *)
(* *)
- (* <Values> *)
- (* FT_PIXEL_MODE_NONE :: *)
- (* Value 0 is reserved. *)
- (* *)
- (* FT_PIXEL_MODE_MONO :: *)
- (* A monochrome bitmap, using 1 bit per pixel. Note that pixels *)
- (* are stored in most-significant order (MSB), which means that *)
- (* the left-most pixel in a byte has value 128. *)
- (* *)
- (* FT_PIXEL_MODE_GRAY :: *)
- (* An 8-bit bitmap, generally used to represent anti-aliased glyph *)
- (* images. Each pixel is stored in one byte. Note that the number *)
- (* of value `gray' levels is stored in the `num_bytes' field of *)
- (* the @FT_Bitmap structure (it generally is 256). *)
- (* *)
- (* FT_PIXEL_MODE_GRAY2 :: *)
- (* A 2-bit/pixel bitmap, used to represent embedded anti-aliased *)
- (* bitmaps in font files according to the OpenType specification. *)
- (* We haven't found a single font using this format, however. *)
- (* *)
- (* FT_PIXEL_MODE_GRAY4 :: *)
- (* A 4-bit/pixel bitmap, used to represent embedded anti-aliased *)
- (* bitmaps in font files according to the OpenType specification. *)
- (* We haven't found a single font using this format, however. *)
- (* *)
- (* FT_PIXEL_MODE_LCD :: *)
- (* An 8-bit bitmap, used to represent RGB or BGR decimated glyph *)
- (* images used for display on LCD displays; the bitmap is three *)
- (* times wider than the original glyph image. See also *)
- (* @FT_RENDER_MODE_LCD. *)
- (* *)
- (* FT_PIXEL_MODE_LCD_V :: *)
- (* An 8-bit bitmap, used to represent RGB or BGR decimated glyph *)
- (* images used for display on rotated LCD displays; the bitmap *)
- (* is three times taller than the original glyph image. See also *)
- (* @FT_RENDER_MODE_LCD_V. *)
+ (* In other words, each time you call @FT_Load_Glyph or *)
+ (* @FT_Load_Char, the slot's content is erased by the new glyph data, *)
+ (* i.e. the glyph's metrics, its image (bitmap or outline), and *)
+ (* other control information. *)
+ (* *)
+ (* <Also> *)
+ (* @FT_GlyphSlotRec details the publicly accessible glyph fields. *)
(* *)
type
- FT_Pixel_Mode = byte;
-const
- FT_PIXEL_MODE_NONE = 0;
- FT_PIXEL_MODE_MONO = FT_PIXEL_MODE_NONE + 1;
- FT_PIXEL_MODE_GRAY = FT_PIXEL_MODE_MONO + 1;
- FT_PIXEL_MODE_GRAY2 = FT_PIXEL_MODE_GRAY + 1;
- FT_PIXEL_MODE_GRAY4 = FT_PIXEL_MODE_GRAY2 + 1;
- FT_PIXEL_MODE_LCD = FT_PIXEL_MODE_GRAY4 + 1;
- FT_PIXEL_MODE_LCD_V = FT_PIXEL_MODE_LCD + 1;
+ FT_GlyphSlot = ^FT_GlyphSlotRec;
- FT_PIXEL_MODE_MAX = FT_PIXEL_MODE_LCD_V + 1; (* do not remove *)
+
+{$DEFINE TYPE_DECL}
+{$I ftconfig.inc}
+{$I fttypes.inc}
+{$I ftimage.inc}
+{$I ftglyph.inc}
+{$I ftstroke.inc}
+{$I ftoutln.inc}
+{$UNDEF TYPE_DECL}
(*************************************************************************)
@@ -674,7 +608,6 @@ const
(* vertAdvance :: *)
(* Advance height for vertical layout. *)
(* *)
-type
FT_Glyph_Metrics = record
width ,
height : FT_Pos;
@@ -759,140 +692,6 @@ type
(*************************************************************************)
(* *)
- (* <Struct> *)
- (* FT_Vector *)
- (* *)
- (* <Description> *)
- (* A simple structure used to store a 2D vector; coordinates are of *)
- (* the FT_Pos type. *)
- (* *)
- (* <Fields> *)
- (* x :: The horizontal coordinate. *)
- (* y :: The vertical coordinate. *)
- (* *)
- PFT_Vector = ^FT_Vector;
- FT_Vector = record
- x ,
- y : FT_Pos;
- end;
-
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_Outline *)
- (* *)
- (* <Description> *)
- (* This structure is used to describe an outline to the scan-line *)
- (* converter. *)
- (* *)
- (* <Fields> *)
- (* n_contours :: The number of contours in the outline. *)
- (* *)
- (* n_points :: The number of points in the outline. *)
- (* *)
- (* points :: A pointer to an array of `n_points' FT_Vector *)
- (* elements, giving the outline's point coordinates. *)
- (* *)
- (* tags :: A pointer to an array of `n_points' chars, giving *)
- (* each outline point's type. If bit 0 is unset, the *)
- (* point is `off' the curve, i.e. a Bezier control *)
- (* point, while it is `on' when set. *)
- (* *)
- (* Bit 1 is meaningful for `off' points only. If set, *)
- (* it indicates a third-order Bezier arc control point; *)
- (* and a second-order control point if unset. *)
- (* *)
- (* contours :: An array of `n_contours' shorts, giving the end *)
- (* point of each contour within the outline. For *)
- (* example, the first contour is defined by the points *)
- (* `0' to `contours[0]', the second one is defined by *)
- (* the points `contours[0]+1' to `contours[1]', etc. *)
- (* *)
- (* flags :: A set of bit flags used to characterize the outline *)
- (* and give hints to the scan-converter and hinter on *)
- (* how to convert/grid-fit it. See FT_Outline_Flags. *)
- (* *)
- PFT_Outline = ^FT_Outline;
- FT_Outline = record
- n_contours : FT_Short;
- n_points : FT_Short;
-
- points : PFT_Vector;
- tags : PChar;
- contours : PFT_Short;
-
- flags : FT_Int;
- end;
-
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_Bitmap *)
- (* *)
- (* <Description> *)
- (* A structure used to describe a bitmap or pixmap to the raster. *)
- (* Note that we now manage pixmaps of various depths through the *)
- (* `pixel_mode' field. *)
- (* *)
- (* <Fields> *)
- (* rows :: The number of bitmap rows. *)
- (* *)
- (* width :: The number of pixels in bitmap row. *)
- (* *)
- (* pitch :: The pitch's absolute value is the number of bytes *)
- (* taken by one bitmap row, including padding. *)
- (* However, the pitch is positive when the bitmap has *)
- (* a `down' flow, and negative when it has an `up' *)
- (* flow. In all cases, the pitch is an offset to add *)
- (* to a bitmap pointer in order to go down one row. *)
- (* *)
- (* buffer :: A typeless pointer to the bitmap buffer. This *)
- (* value should be aligned on 32-bit boundaries in *)
- (* most cases. *)
- (* *)
- (* num_grays :: This field is only used with *)
- (* `FT_PIXEL_MODE_GRAY'; it gives the number of gray *)
- (* levels used in the bitmap. *)
- (* *)
- (* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. *)
- (* See @FT_Pixel_Mode for possible values. *)
- (* *)
- (* palette_mode :: This field is only used with paletted pixel modes; *)
- (* it indicates how the palette is stored. *)
- (* *)
- (* palette :: A typeless pointer to the bitmap palette; only *)
- (* used for paletted pixel modes. *)
- (* *)
- (* <Note> *)
- (* For now, the only pixel mode supported by FreeType are mono and *)
- (* grays. However, drivers might be added in the future to support *)
- (* more `colorful' options. *)
- (* *)
- (* When using pixel modes pal2, pal4 and pal8 with a void `palette' *)
- (* field, a gray pixmap with respectively 4, 16, and 256 levels of *)
- (* gray is assumed. This, in order to be compatible with some *)
- (* embedded bitmap formats defined in the TrueType specification. *)
- (* *)
- (* Note that no font was found presenting such embedded bitmaps, so *)
- (* this is currently completely unhandled by the library. *)
- (* *)
- PFT_Bitmap = ^FT_Bitmap;
- FT_Bitmap = record
- rows ,
- width : FT_Int;
- pitch : FT_Int;
- buffer : PByteArray;
- num_grays : FT_Short;
- pixel_mode ,
- palette_mode : byte;
- palette : pointer;
- end;
-
-
- (*************************************************************************)
- (* *)
(* <Type> *)
(* FT_Face *)
(* *)
@@ -950,184 +749,11 @@ type
PAFT_CharMap = ^FT_CharMap;
AFT_CharMap = array[0..High(Word)] of FT_CharMap;
- (*************************************************************************)
- (* *)
- (* <Type> *)
- (* FT_Library *)
- (* *)
- (* <Description> *)
- (* A handle to a FreeType library instance. Each `library' is *)
- (* completely independent from the others; it is the `root' of a set *)
- (* of objects like fonts, faces, sizes, etc. *)
- (* *)
- (* It also embeds a memory manager (see @FT_Memory), as well as a *)
- (* scan-line converter object (see @FT_Raster). *)
- (* *)
- (* <Note> *)
- (* Library objects are normally created by @FT_Init_FreeType, and *)
- (* destroyed with @FT_Done_FreeType. *)
- (* *)
- FT_Library = ^FT_LibraryRec;
- FT_LibraryRec = record // internal
- end;
- (*************************************************************************)
- (* *)
- (* <Section> *)
- (* glyph_management *)
- (* *)
- (* <Title> *)
- (* Glyph Management *)
- (* *)
- (* <Abstract> *)
- (* Generic interface to manage individual glyph data. *)
- (* *)
- (* <Description> *)
- (* This section contains definitions used to manage glyph data *)
- (* through generic FT_Glyph objects. Each of them can contain a *)
- (* bitmap, a vector outline, or even images in other formats. *)
- (* *)
- (*************************************************************************)
- (* forward declaration to a private type *)
- PFT_Glyph_Class = ^FT_Glyph_Class;
- FT_Glyph_Class = record // internal
- end;
- (*************************************************************************)
- (* *)
- (* <Type> *)
- (* FT_Glyph *)
- (* *)
- (* <Description> *)
- (* Handle to an object used to model generic glyph images. It is a *)
- (* pointer to the @FT_GlyphRec structure and can contain a glyph *)
- (* bitmap or pointer. *)
- (* *)
- (* <Note> *)
- (* Glyph objects are not owned by the library. You must thus release *)
- (* them manually (through @FT_Done_Glyph) _before_ calling *)
- (* @FT_Done_FreeType. *)
- (* *)
- FT_Glyph = ^FT_GlyphRec;
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_GlyphRec *)
- (* *)
- (* <Description> *)
- (* The root glyph structure contains a given glyph image plus its *)
- (* advance width in 16.16 fixed float format. *)
- (* *)
- (* <Fields> *)
- (* library :: A handle to the FreeType library object. *)
- (* *)
- (* clazz :: A pointer to the glyph's class. Private. *)
- (* *)
- (* format :: The format of the glyph's image. *)
- (* *)
- (* advance :: A 16.16 vector that gives the glyph's advance width. *)
- (* *)
- FT_GlyphRec = record
- library_: FT_Library;
- clazz: PFT_Glyph_Class;
- format: FT_Glyph_Format;
- advance: FT_Vector;
- end;
-
-
- (*************************************************************************)
- (* *)
- (* <Type> *)
- (* FT_BitmapGlyph *)
- (* *)
- (* <Description> *)
- (* A handle to an object used to model a bitmap glyph image. This is *)
- (* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. *)
- (* *)
- FT_BitmapGlyph = ^FT_BitmapGlyphRec;
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_BitmapGlyphRec *)
- (* *)
- (* <Description> *)
- (* A structure used for bitmap glyph images. This really is a *)
- (* `sub-class' of `FT_GlyphRec'. *)
- (* *)
- (* <Fields> *)
- (* root :: The root FT_Glyph fields. *)
- (* *)
- (* left :: The left-side bearing, i.e., the horizontal distance *)
- (* from the current pen position to the left border of the *)
- (* glyph bitmap. *)
- (* *)
- (* top :: The top-side bearing, i.e., the vertical distance from *)
- (* the current pen position to the top border of the glyph *)
- (* bitmap. This distance is positive for upwards-y! *)
- (* *)
- (* bitmap :: A descriptor for the bitmap. *)
- (* *)
- (* <Note> *)
- (* You can typecast FT_Glyph to FT_BitmapGlyph if you have *)
- (* glyph->format == FT_GLYPH_FORMAT_BITMAP. This lets you access *)
- (* the bitmap's contents easily. *)
- (* *)
- (* The corresponding pixel buffer is always owned by the BitmapGlyph *)
- (* and is thus created and destroyed with it. *)
- (* *)
- FT_BitmapGlyphRec = record
- root: FT_GlyphRec;
- left: FT_Int;
- top: FT_Int;
- bitmap: FT_Bitmap;
- end;
- (*************************************************************************)
- (* *)
- (* <Type> *)
- (* FT_OutlineGlyph *)
- (* *)
- (* <Description> *)
- (* A handle to an object used to model an outline glyph image. This *)
- (* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. *)
- (* *)
- FT_OutlineGlyph = ^FT_OutlineGlyphRec;
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_OutlineGlyphRec *)
- (* *)
- (* <Description> *)
- (* A structure used for outline (vectorial) glyph images. This *)
- (* really is a `sub-class' of `FT_GlyphRec'. *)
- (* *)
- (* <Fields> *)
- (* root :: The root FT_Glyph fields. *)
- (* *)
- (* outline :: A descriptor for the outline. *)
- (* *)
- (* <Note> *)
- (* You can typecast FT_Glyph to FT_OutlineGlyph if you have *)
- (* glyph->format == FT_GLYPH_FORMAT_OUTLINE. This lets you access *)
- (* the outline's content easily. *)
- (* *)
- (* As the outline is extracted from a glyph slot, its coordinates are *)
- (* expressed normally in 26.6 pixels, unless the flag *)
- (* FT_LOAD_NO_SCALE was used in FT_Load_Glyph() or FT_Load_Char(). *)
- (* *)
- (* The outline's tables are always owned by the object and are *)
- (* destroyed with it. *)
- (* *)
- FT_OutlineGlyphRec = record
- root: FT_GlyphRec;
- outline: FT_Outline;
- end;
-
(*************************************************************************)
(* *)
@@ -1149,101 +775,6 @@ type
(*************************************************************************)
(* *)
- (* <FuncType> *)
- (* FT_Generic_Finalizer *)
- (* *)
- (* <Description> *)
- (* Describes a function used to destroy the `client' data of any *)
- (* FreeType object. See the description of the FT_Generic type for *)
- (* details of usage. *)
- (* *)
- (* <Input> *)
- (* The address of the FreeType object which is under finalization. *)
- (* Its client data is accessed through its `generic' field. *)
- (* *)
- FT_Generic_Finalizer = procedure(AnObject : pointer ); cdecl;
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_Generic *)
- (* *)
- (* <Description> *)
- (* Client applications often need to associate their own data to a *)
- (* variety of FreeType core objects. For example, a text layout API *)
- (* might want to associate a glyph cache to a given size object. *)
- (* *)
- (* Most FreeType object contains a `generic' field, of type *)
- (* FT_Generic, which usage is left to client applications and font *)
- (* servers. *)
- (* *)
- (* It can be used to store a pointer to client-specific data, as well *)
- (* as the address of a `finalizer' function, which will be called by *)
- (* FreeType when the object is destroyed (for example, the previous *)
- (* client example would put the address of the glyph cache destructor *)
- (* in the `finalizer' field). *)
- (* *)
- (* <Fields> *)
- (* data :: A typeless pointer to any client-specified data. This *)
- (* field is completely ignored by the FreeType library. *)
- (* *)
- (* finalizer :: A pointer to a `generic finalizer' function, which *)
- (* will be called when the object is destroyed. If this *)
- (* field is set to NULL, no code will be called. *)
- (* *)
- FT_Generic = record
- data : pointer;
- finalizer : FT_Generic_Finalizer;
- end;
-
- (*************************************************************************)
- (* *)
- (* <Struct> *)
- (* FT_BBox *)
- (* *)
- (* <Description> *)
- (* A structure used to hold an outline's bounding box, i.e., the *)
- (* coordinates of its extrema in the horizontal and vertical *)
- (* directions. *)
- (* *)
- (* <Fields> *)
- (* xMin :: The horizontal minimum (left-most). *)
- (* *)
- (* yMin :: The vertical minimum (bottom-most). *)
- (* *)
- (* xMax :: The horizontal maximum (right-most). *)
- (* *)
- (* yMax :: The vertical maximum (top-most). *)
- (* *)
- PFT_BBox = ^FT_BBox;
- FT_BBox = record
- xMin, yMin : FT_Pos;
- xMax, yMax : FT_Pos;
- end;
-
-
- (*************************************************************************)
- (* *)
- (* <Type> *)
- (* FT_GlyphSlot *)
- (* *)
- (* <Description> *)
- (* A handle to a given `glyph slot'. A slot is a container where it *)
- (* is possible to load any one of the glyphs contained in its parent *)
- (* face. *)
- (* *)
- (* In other words, each time you call @FT_Load_Glyph or *)
- (* @FT_Load_Char, the slot's content is erased by the new glyph data, *)
- (* i.e. the glyph's metrics, its image (bitmap or outline), and *)
- (* other control information. *)
- (* *)
- (* <Also> *)
- (* @FT_GlyphSlotRec details the publicly accessible glyph fields. *)
- (* *)
- FT_GlyphSlot = ^FT_GlyphSlotRec;
-
- (*************************************************************************)
- (* *)
(* <Struct> *)
(* FT_GlyphSlotRec *)
(* *)
@@ -1432,7 +963,7 @@ type
subglyphs : FT_SubGlyph;
control_data : pointer;
- control_len : longint;
+ control_len : clong;
lsb_delta: FT_Pos;
rsb_delta: FT_Pos;
@@ -1497,15 +1028,15 @@ type
(* computations. *)
(* *)
FT_Size_Metrics = record
- x_ppem ,
- y_ppem : FT_UShort;
- x_scale ,
- y_scale : FT_Fixed;
-
- ascender ,
- descender : FT_Pos;
- height : FT_Pos;
- max_advance : FT_Pos;
+ x_ppem, (* horizontal pixels per EM *)
+ y_ppem: FT_UShort; (* vertical pixels per EM *)
+ x_scale, (* scaling values used to convert font *)
+ y_scale: FT_Fixed; (* units to 26.6 fractional pixels *)
+
+ ascender, (* ascender in 26.6 frac. pixels *)
+ descender: FT_Pos; (* descender in 26.6 frac. pixels *)
+ height: FT_Pos; (* text height in 26.6 frac. pixels *)
+ max_advance: FT_Pos; (* max horizontal advance, in 26.6 pixels *)
end;
(*************************************************************************)
@@ -1786,21 +1317,29 @@ type
encoding_id : FT_UShort;
end;
+
+{$I ftconfig.inc}
+{$I fttypes.inc}
+{$I ftimage.inc}
+{$I ftglyph.inc}
+{$I ftstroke.inc}
+{$I ftoutln.inc}
+
+
{ GLOBAL PROCEDURES }
(*************************************************************************)
(* *)
(* @macro: *)
- (* FT_CURVE_TAG ( flag ) *)
+ (* FT_HAS_KERNING( face ) *)
(* *)
- function FT_CURVE_TAG(flag: byte): byte;
-
-const
- FT_CURVE_TAG_ON = 1;
- FT_CURVE_TAG_CONIC = 0;
- FT_CURVE_TAG_CUBIC = 2;
-
+ (* @description: *)
+ (* A macro that returns true whenever a face object contains kerning *)
+ (* data that can be accessed with @FT_Get_Kerning. *)
+ (* *)
+ function FT_HAS_KERNING(face : FT_Face ) : cbool;
+
(*************************************************************************)
(* *)
(* @macro: *)
@@ -1813,16 +1352,6 @@ const
(* *)
function FT_IS_SCALABLE(face : FT_Face ) : cbool;
- (*************************************************************************)
- (* *)
- (* @macro: *)
- (* FT_HAS_KERNING( face ) *)
- (* *)
- (* @description: *)
- (* A macro that returns true whenever a face object contains kerning *)
- (* data that can be accessed with @FT_Get_Kerning. *)
- (* *)
- function FT_HAS_KERNING(face : FT_Face ) : cbool;
(*************************************************************************)
(* *)
@@ -2284,216 +1813,12 @@ const
pixel_height : FT_UInt ) : FT_Error;
cdecl; external ft_lib name 'FT_Set_Pixel_Sizes';
- (*************************************************************************)
- (* *)
- (* <Function> *)
- (* FT_Get_Glyph *)
- (* *)
- (* <Description> *)
- (* A function used to extract a glyph image from a slot. *)
- (* *)
- (* <Input> *)
- (* slot :: A handle to the source glyph slot. *)
- (* *)
- (* <Output> *)
- (* aglyph :: A handle to the glyph object. *)
- (* *)
- (* <Return> *)
- (* FreeType error code. 0 means success. *)
- (* *)
- function FT_Get_Glyph(
- slot: FT_GlyphSlot;
- out aglyph: FT_Glyph ): FT_Error;
- cdecl; external ft_lib name 'FT_Get_Glyph';
-
- (*************************************************************************)
- (* *)
- (* <Enum> *)
- (* FT_Glyph_BBox_Mode *)
- (* *)
- (* <Description> *)
- (* The mode how the values of @FT_Glyph_Get_CBox are returned. *)
- (* *)
- (* <Values> *)
- (* FT_GLYPH_BBOX_UNSCALED :: *)
- (* Return unscaled font units. *)
- (* *)
- (* FT_GLYPH_BBOX_SUBPIXELS :: *)
- (* Return unfitted 26.6 coordinates. *)
- (* *)
- (* FT_GLYPH_BBOX_GRIDFIT :: *)
- (* Return grid-fitted 26.6 coordinates. *)
- (* *)
- (* FT_GLYPH_BBOX_TRUNCATE :: *)
- (* Return coordinates in integer pixels. *)
- (* *)
- (* FT_GLYPH_BBOX_PIXELS :: *)
- (* Return grid-fitted pixel coordinates. *)
- (* *)
-type
- FT_Glyph_BBox_Mode = FT_UInt;
const
- FT_GLYPH_BBOX_UNSCALED = 0;
- FT_GLYPH_BBOX_SUBPIXELS = 0;
- FT_GLYPH_BBOX_GRIDFIT = 1;
- FT_GLYPH_BBOX_TRUNCATE = 2;
- FT_GLYPH_BBOX_PIXELS = 3;
-
- (*************************************************************************)
- (* *)
- (* <Function> *)
- (* FT_Glyph_Get_CBox *)
- (* *)
- (* <Description> *)
- (* Return a glyph's `control box'. The control box encloses all the *)
- (* outline's points, including Bézier control points. Though it *)
- (* coincides with the exact bounding box for most glyphs, it can be *)
- (* slightly larger in some situations (like when rotating an outline *)
- (* which contains Bézier outside arcs). *)
- (* *)
- (* Computing the control box is very fast, while getting the bounding *)
- (* box can take much more time as it needs to walk over all segments *)
- (* and arcs in the outline. To get the latter, you can use the *)
- (* `ftbbox' component which is dedicated to this single task. *)
- (* *)
- (* <Input> *)
- (* glyph :: A handle to the source glyph object. *)
- (* *)
- (* mode :: The mode which indicates how to interpret the returned *)
- (* bounding box values. *)
- (* *)
- (* <Output> *)
- (* acbox :: The glyph coordinate bounding box. Coordinates are *)
- (* expressed in 1/64th of pixels if it is grid-fitted. *)
- (* *)
- (* <Note> *)
- (* Coordinates are relative to the glyph origin, using the Y-upwards *)
- (* convention. *)
- (* *)
- (* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' *)
- (* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font *)
- (* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS *)
- (* is another name for this constant. *)
- (* *)
- (* Note that the maximum coordinates are exclusive, which means that *)
- (* one can compute the width and height of the glyph image (be it in *)
- (* integer or 26.6 pixels) as: *)
- (* *)
- (* { *)
- (* width = bbox.xMax - bbox.xMin; *)
- (* height = bbox.yMax - bbox.yMin; *)
- (* } *)
- (* *)
- (* Note also that for 26.6 coordinates, if `bbox_mode' is set to *)
- (* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, *)
- (* which corresponds to: *)
- (* *)
- (* { *)
- (* bbox.xMin = FLOOR(bbox.xMin); *)
- (* bbox.yMin = FLOOR(bbox.yMin); *)
- (* bbox.xMax = CEILING(bbox.xMax); *)
- (* bbox.yMax = CEILING(bbox.yMax); *)
- (* } *)
- (* *)
- (* To get the bbox in pixel coordinates, set `bbox_mode' to *)
- (* @FT_GLYPH_BBOX_TRUNCATE. *)
- (* *)
- (* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' *)
- (* to @FT_GLYPH_BBOX_PIXELS. *)
- (* *)
- procedure FT_Glyph_Get_CBox( glyph: FT_Glyph;
- bbox_mode: FT_UInt;
- out acbox: FT_BBox );
- cdecl; external ft_lib name 'FT_Glyph_Get_CBox';
-
- (*************************************************************************)
- (* *)
- (* <Function> *)
- (* FT_Glyph_To_Bitmap *)
- (* *)
- (* <Description> *)
- (* Converts a given glyph object to a bitmap glyph object. *)
- (* *)
- (* <InOut> *)
- (* the_glyph :: A pointer to a handle to the target glyph. *)
- (* *)
- (* <Input> *)
- (* render_mode :: An enumeration that describe how the data is *)
- (* rendered. *)
- (* *)
- (* origin :: A pointer to a vector used to translate the glyph *)
- (* image before rendering. Can be 0 (if no *)
- (* translation). The origin is expressed in *)
- (* 26.6 pixels. *)
- (* *)
- (* destroy :: A boolean that indicates that the original glyph *)
- (* image should be destroyed by this function. It is *)
- (* never destroyed in case of error. *)
- (* *)
- (* <Return> *)
- (* FreeType error code. 0 means success. *)
- (* *)
- (* <Note> *)
- (* The glyph image is translated with the `origin' vector before *)
- (* rendering. *)
- (* *)
- (* The first parameter is a pointer to a FT_Glyph handle, that will *)
- (* be replaced by this function. Typically, you would use (omitting *)
- (* error handling): *)
- (* *)
- (* *)
- (* { *)
- (* FT_Glyph glyph; *)
- (* FT_BitmapGlyph glyph_bitmap; *)
- (* *)
- (* *)
- (* // load glyph *)
- (* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); *)
- (* *)
- (* // extract glyph image *)
- (* error = FT_Get_Glyph( face->glyph, &glyph ); *)
- (* *)
- (* // convert to a bitmap (default render mode + destroy old) *)
- (* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) *)
- (* { *)
- (* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_DEFAULT, *)
- (* 0, 1 ); *)
- (* if ( error ) // glyph unchanged *)
- (* ... *)
- (* } *)
- (* *)
- (* // access bitmap content by typecasting *)
- (* glyph_bitmap = (FT_BitmapGlyph)glyph; *)
- (* *)
- (* // do funny stuff with it, like blitting/drawing *)
- (* ... *)
- (* *)
- (* // discard glyph image (bitmap or not) *)
- (* FT_Done_Glyph( glyph ); *)
- (* } *)
- (* *)
- (* *)
- (* This function does nothing if the glyph format isn't scalable. *)
- (* *)
- function FT_Glyph_To_Bitmap(var the_glyph: FT_Glyph;
- render_mode: FT_Render_Mode;
- origin: PFT_Vector;
- destroy: FT_Bool ): FT_Error;
- cdecl; external ft_lib name 'FT_Glyph_To_Bitmap';
+ FT_ANGLE_PI = 180 shl 16;
+ FT_ANGLE_2PI = FT_ANGLE_PI * 2;
+ FT_ANGLE_PI2 = FT_ANGLE_PI div 2;
+ FT_ANGLE_PI4 = FT_ANGLE_PI div 4;
- (*************************************************************************)
- (* *)
- (* <Function> *)
- (* FT_Done_Glyph *)
- (* *)
- (* <Description> *)
- (* Destroys a given glyph. *)
- (* *)
- (* <Input> *)
- (* glyph :: A handle to the target glyph object. *)
- (* *)
- procedure FT_Done_Glyph( glyph: FT_Glyph );
- cdecl; external ft_lib name 'FT_Done_Glyph';
implementation
@@ -2504,17 +1829,17 @@ begin
result := flag and 3;
end;
-{ FT_IS_SCALABLE }
-function FT_IS_SCALABLE(face : FT_Face ) : cbool;
-begin
- result := cbool(face.face_flags and FT_FACE_FLAG_SCALABLE );
-end;
-
{ FT_HAS_KERNING }
function FT_HAS_KERNING(face : FT_Face ) : cbool;
begin
result := cbool(face.face_flags and FT_FACE_FLAG_KERNING );
end;
+{ FT_IS_SCALABLE }
+function FT_IS_SCALABLE(face : FT_Face ) : cbool;
+begin
+ result := cbool(face.face_flags and FT_FACE_FLAG_SCALABLE );
+end;
+
end.
diff --git a/src/lib/freetype/ftconfig.inc b/src/lib/freetype/ftconfig.inc
new file mode 100644
index 00000000..100fb2e0
--- /dev/null
+++ b/src/lib/freetype/ftconfig.inc
@@ -0,0 +1,35 @@
+(***************************************************************************)
+(* *)
+(* ftconfig.h *)
+(* *)
+(* ANSI-specific configuration file (specification only). *)
+(* *)
+(* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007 by *)
+(* David Turner, Robert Wilhelm, and Werner Lemberg. *)
+(* *)
+(* This file is part of the FreeType project, and may only be used, *)
+(* modified, and distributed under the terms of the FreeType project *)
+(* license, LICENSE.TXT. By continuing to use, modify, or distribute *)
+(* this file you indicate that you have read the license and *)
+(* understand and accept it fully. *)
+(* *)
+(***************************************************************************)
+(***************************************************************************)
+(* Pascal port by the UltraStar Deluxe Team *)
+(***************************************************************************)
+
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* IntN types *)
+ (* *)
+ (* Used to guarantee the size of some specific integers. *)
+ (* *)
+ FT_Int16 = cint16;
+ FT_UInt16 = cuint16;
+ FT_Int32 = cint32;
+ FT_UInt32 = cuint32;
+
+{$ENDIF TYPE_DECL}
+
diff --git a/src/lib/freetype/ftglyph.inc b/src/lib/freetype/ftglyph.inc
new file mode 100644
index 00000000..0d4acc99
--- /dev/null
+++ b/src/lib/freetype/ftglyph.inc
@@ -0,0 +1,435 @@
+(***************************************************************************)
+(* *)
+(* ftglyph.h *)
+(* *)
+(* FreeType convenience functions to handle glyphs (specification). *)
+(* *)
+(* Copyright 1996-2001, 2002, 2003, 2006 by *)
+(* David Turner, Robert Wilhelm, and Werner Lemberg. *)
+(* *)
+(* This file is part of the FreeType project, and may only be used, *)
+(* modified, and distributed under the terms of the FreeType project *)
+(* license, LICENSE.TXT. By continuing to use, modify, or distribute *)
+(* this file you indicate that you have read the license and *)
+(* understand and accept it fully. *)
+(* *)
+(***************************************************************************)
+(***************************************************************************)
+(* Pascal port by the UltraStar Deluxe Team *)
+(***************************************************************************)
+
+
+ (*************************************************************************)
+ (* *)
+ (* This file contains the definition of several convenience functions *)
+ (* that can be used by client applications to easily retrieve glyph *)
+ (* bitmaps and outlines from a given face. *)
+ (* *)
+ (* These functions should be optional if you are writing a font server *)
+ (* or text layout engine on top of FreeType. However, they are pretty *)
+ (* handy for many other simple uses of the library. *)
+ (* *)
+ (*************************************************************************)
+
+ (*************************************************************************)
+ (* *)
+ (* <Section> *)
+ (* glyph_management *)
+ (* *)
+ (* <Title> *)
+ (* Glyph Management *)
+ (* *)
+ (* <Abstract> *)
+ (* Generic interface to manage individual glyph data. *)
+ (* *)
+ (* <Description> *)
+ (* This section contains definitions used to manage glyph data *)
+ (* through generic FT_Glyph objects. Each of them can contain a *)
+ (* bitmap, a vector outline, or even images in other formats. *)
+ (* *)
+ (*************************************************************************)
+
+{$IFDEF TYPE_DECL}
+
+ (* forward declaration to a private type *)
+ PFT_Glyph_Class = Pointer;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Glyph *)
+ (* *)
+ (* <Description> *)
+ (* Handle to an object used to model generic glyph images. It is a *)
+ (* pointer to the @FT_GlyphRec structure and can contain a glyph *)
+ (* bitmap or pointer. *)
+ (* *)
+ (* <Note> *)
+ (* Glyph objects are not owned by the library. You must thus release *)
+ (* them manually (through @FT_Done_Glyph) _before_ calling *)
+ (* @FT_Done_FreeType. *)
+ (* *)
+ FT_Glyph = ^FT_GlyphRec;
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_GlyphRec *)
+ (* *)
+ (* <Description> *)
+ (* The root glyph structure contains a given glyph image plus its *)
+ (* advance width in 16.16 fixed float format. *)
+ (* *)
+ (* <Fields> *)
+ (* library :: A handle to the FreeType library object. *)
+ (* *)
+ (* clazz :: A pointer to the glyph's class. Private. *)
+ (* *)
+ (* format :: The format of the glyph's image. *)
+ (* *)
+ (* advance :: A 16.16 vector that gives the glyph's advance width. *)
+ (* *)
+ FT_GlyphRec = record
+ library_: FT_Library;
+ clazz: PFT_Glyph_Class;
+ format: FT_Glyph_Format;
+ advance: FT_Vector;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_BitmapGlyph *)
+ (* *)
+ (* <Description> *)
+ (* A handle to an object used to model a bitmap glyph image. This is *)
+ (* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. *)
+ (* *)
+ FT_BitmapGlyph = ^FT_BitmapGlyphRec;
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_BitmapGlyphRec *)
+ (* *)
+ (* <Description> *)
+ (* A structure used for bitmap glyph images. This really is a *)
+ (* `sub-class' of `FT_GlyphRec'. *)
+ (* *)
+ (* <Fields> *)
+ (* root :: The root FT_Glyph fields. *)
+ (* *)
+ (* left :: The left-side bearing, i.e., the horizontal distance *)
+ (* from the current pen position to the left border of the *)
+ (* glyph bitmap. *)
+ (* *)
+ (* top :: The top-side bearing, i.e., the vertical distance from *)
+ (* the current pen position to the top border of the glyph *)
+ (* bitmap. This distance is positive for upwards-y! *)
+ (* *)
+ (* bitmap :: A descriptor for the bitmap. *)
+ (* *)
+ (* <Note> *)
+ (* You can typecast FT_Glyph to FT_BitmapGlyph if you have *)
+ (* glyph->format == FT_GLYPH_FORMAT_BITMAP. This lets you access *)
+ (* the bitmap's contents easily. *)
+ (* *)
+ (* The corresponding pixel buffer is always owned by the BitmapGlyph *)
+ (* and is thus created and destroyed with it. *)
+ (* *)
+ FT_BitmapGlyphRec = record
+ root: FT_GlyphRec;
+ left: FT_Int;
+ top: FT_Int;
+ bitmap: FT_Bitmap;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_OutlineGlyph *)
+ (* *)
+ (* <Description> *)
+ (* A handle to an object used to model an outline glyph image. This *)
+ (* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. *)
+ (* *)
+ FT_OutlineGlyph = ^FT_OutlineGlyphRec;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_OutlineGlyphRec *)
+ (* *)
+ (* <Description> *)
+ (* A structure used for outline (vectorial) glyph images. This *)
+ (* really is a `sub-class' of `FT_GlyphRec'. *)
+ (* *)
+ (* <Fields> *)
+ (* root :: The root FT_Glyph fields. *)
+ (* *)
+ (* outline :: A descriptor for the outline. *)
+ (* *)
+ (* <Note> *)
+ (* You can typecast FT_Glyph to FT_OutlineGlyph if you have *)
+ (* glyph->format == FT_GLYPH_FORMAT_OUTLINE. This lets you access *)
+ (* the outline's content easily. *)
+ (* *)
+ (* As the outline is extracted from a glyph slot, its coordinates are *)
+ (* expressed normally in 26.6 pixels, unless the flag *)
+ (* FT_LOAD_NO_SCALE was used in FT_Load_Glyph() or FT_Load_Char(). *)
+ (* *)
+ (* The outline's tables are always owned by the object and are *)
+ (* destroyed with it. *)
+ (* *)
+ FT_OutlineGlyphRec = record
+ root: FT_GlyphRec;
+ outline: FT_Outline;
+ end;
+
+{$ELSE TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Get_Glyph *)
+ (* *)
+ (* <Description> *)
+ (* A function used to extract a glyph image from a slot. *)
+ (* *)
+ (* <Input> *)
+ (* slot :: A handle to the source glyph slot. *)
+ (* *)
+ (* <Output> *)
+ (* aglyph :: A handle to the glyph object. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ function FT_Get_Glyph(
+ slot: FT_GlyphSlot;
+ out aglyph: FT_Glyph ): FT_Error;
+ cdecl; external ft_lib name 'FT_Get_Glyph';
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Glyph_Copy *)
+ (* *)
+ (* <Description> *)
+ (* A function used to copy a glyph image. Note that the created *)
+ (* @FT_Glyph object must be released with @FT_Done_Glyph. *)
+ (* *)
+ (* <Input> *)
+ (* source :: A handle to the source glyph object. *)
+ (* *)
+ (* <Output> *)
+ (* target :: A handle to the target glyph object. 0~in case of *)
+ (* error. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0~means success. *)
+ (* *)
+ function FT_Glyph_Copy(source: FT_Glyph;
+ var target: FT_Glyph ): FT_Error;
+ cdecl; external ft_lib name 'FT_Glyph_Copy';
+
+{$ENDIF TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Enum> *)
+ (* FT_Glyph_BBox_Mode *)
+ (* *)
+ (* <Description> *)
+ (* The mode how the values of @FT_Glyph_Get_CBox are returned. *)
+ (* *)
+ (* <Values> *)
+ (* FT_GLYPH_BBOX_UNSCALED :: *)
+ (* Return unscaled font units. *)
+ (* *)
+ (* FT_GLYPH_BBOX_SUBPIXELS :: *)
+ (* Return unfitted 26.6 coordinates. *)
+ (* *)
+ (* FT_GLYPH_BBOX_GRIDFIT :: *)
+ (* Return grid-fitted 26.6 coordinates. *)
+ (* *)
+ (* FT_GLYPH_BBOX_TRUNCATE :: *)
+ (* Return coordinates in integer pixels. *)
+ (* *)
+ (* FT_GLYPH_BBOX_PIXELS :: *)
+ (* Return grid-fitted pixel coordinates. *)
+ (* *)
+ FT_Glyph_BBox_Mode = cint;
+{$ELSE TYPE_DECL}
+const
+ FT_GLYPH_BBOX_UNSCALED = 0;
+ FT_GLYPH_BBOX_SUBPIXELS = 0;
+ FT_GLYPH_BBOX_GRIDFIT = 1;
+ FT_GLYPH_BBOX_TRUNCATE = 2;
+ FT_GLYPH_BBOX_PIXELS = 3;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Glyph_Get_CBox *)
+ (* *)
+ (* <Description> *)
+ (* Return a glyph's `control box'. The control box encloses all the *)
+ (* outline's points, including Bézier control points. Though it *)
+ (* coincides with the exact bounding box for most glyphs, it can be *)
+ (* slightly larger in some situations (like when rotating an outline *)
+ (* which contains Bézier outside arcs). *)
+ (* *)
+ (* Computing the control box is very fast, while getting the bounding *)
+ (* box can take much more time as it needs to walk over all segments *)
+ (* and arcs in the outline. To get the latter, you can use the *)
+ (* `ftbbox' component which is dedicated to this single task. *)
+ (* *)
+ (* <Input> *)
+ (* glyph :: A handle to the source glyph object. *)
+ (* *)
+ (* mode :: The mode which indicates how to interpret the returned *)
+ (* bounding box values. *)
+ (* *)
+ (* <Output> *)
+ (* acbox :: The glyph coordinate bounding box. Coordinates are *)
+ (* expressed in 1/64th of pixels if it is grid-fitted. *)
+ (* *)
+ (* <Note> *)
+ (* Coordinates are relative to the glyph origin, using the Y-upwards *)
+ (* convention. *)
+ (* *)
+ (* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' *)
+ (* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font *)
+ (* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS *)
+ (* is another name for this constant. *)
+ (* *)
+ (* Note that the maximum coordinates are exclusive, which means that *)
+ (* one can compute the width and height of the glyph image (be it in *)
+ (* integer or 26.6 pixels) as: *)
+ (* *)
+ (* { *)
+ (* width = bbox.xMax - bbox.xMin; *)
+ (* height = bbox.yMax - bbox.yMin; *)
+ (* } *)
+ (* *)
+ (* Note also that for 26.6 coordinates, if `bbox_mode' is set to *)
+ (* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, *)
+ (* which corresponds to: *)
+ (* *)
+ (* { *)
+ (* bbox.xMin = FLOOR(bbox.xMin); *)
+ (* bbox.yMin = FLOOR(bbox.yMin); *)
+ (* bbox.xMax = CEILING(bbox.xMax); *)
+ (* bbox.yMax = CEILING(bbox.yMax); *)
+ (* } *)
+ (* *)
+ (* To get the bbox in pixel coordinates, set `bbox_mode' to *)
+ (* @FT_GLYPH_BBOX_TRUNCATE. *)
+ (* *)
+ (* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' *)
+ (* to @FT_GLYPH_BBOX_PIXELS. *)
+ (* *)
+ procedure FT_Glyph_Get_CBox( glyph: FT_Glyph;
+ bbox_mode: FT_UInt;
+ out acbox: FT_BBox );
+ cdecl; external ft_lib name 'FT_Glyph_Get_CBox';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Glyph_To_Bitmap *)
+ (* *)
+ (* <Description> *)
+ (* Converts a given glyph object to a bitmap glyph object. *)
+ (* *)
+ (* <InOut> *)
+ (* the_glyph :: A pointer to a handle to the target glyph. *)
+ (* *)
+ (* <Input> *)
+ (* render_mode :: An enumeration that describe how the data is *)
+ (* rendered. *)
+ (* *)
+ (* origin :: A pointer to a vector used to translate the glyph *)
+ (* image before rendering. Can be 0 (if no *)
+ (* translation). The origin is expressed in *)
+ (* 26.6 pixels. *)
+ (* *)
+ (* destroy :: A boolean that indicates that the original glyph *)
+ (* image should be destroyed by this function. It is *)
+ (* never destroyed in case of error. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ (* <Note> *)
+ (* The glyph image is translated with the `origin' vector before *)
+ (* rendering. *)
+ (* *)
+ (* The first parameter is a pointer to a FT_Glyph handle, that will *)
+ (* be replaced by this function. Typically, you would use (omitting *)
+ (* error handling): *)
+ (* *)
+ (* *)
+ (* { *)
+ (* FT_Glyph glyph; *)
+ (* FT_BitmapGlyph glyph_bitmap; *)
+ (* *)
+ (* *)
+ (* // load glyph *)
+ (* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); *)
+ (* *)
+ (* // extract glyph image *)
+ (* error = FT_Get_Glyph( face->glyph, &glyph ); *)
+ (* *)
+ (* // convert to a bitmap (default render mode + destroy old) *)
+ (* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) *)
+ (* { *)
+ (* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_DEFAULT, *)
+ (* 0, 1 ); *)
+ (* if ( error ) // glyph unchanged *)
+ (* ... *)
+ (* } *)
+ (* *)
+ (* // access bitmap content by typecasting *)
+ (* glyph_bitmap = (FT_BitmapGlyph)glyph; *)
+ (* *)
+ (* // do funny stuff with it, like blitting/drawing *)
+ (* ... *)
+ (* *)
+ (* // discard glyph image (bitmap or not) *)
+ (* FT_Done_Glyph( glyph ); *)
+ (* } *)
+ (* *)
+ (* *)
+ (* This function does nothing if the glyph format isn't scalable. *)
+ (* *)
+ function FT_Glyph_To_Bitmap(var the_glyph: FT_Glyph;
+ render_mode: FT_Render_Mode;
+ origin: PFT_Vector;
+ destroy: FT_Bool ): FT_Error;
+ cdecl; external ft_lib name 'FT_Glyph_To_Bitmap';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Done_Glyph *)
+ (* *)
+ (* <Description> *)
+ (* Destroys a given glyph. *)
+ (* *)
+ (* <Input> *)
+ (* glyph :: A handle to the target glyph object. *)
+ (* *)
+ procedure FT_Done_Glyph( glyph: FT_Glyph );
+ cdecl; external ft_lib name 'FT_Done_Glyph';
+
+{$ENDIF TYPE_DECL}
diff --git a/src/lib/freetype/ftimage.inc b/src/lib/freetype/ftimage.inc
new file mode 100644
index 00000000..9255c422
--- /dev/null
+++ b/src/lib/freetype/ftimage.inc
@@ -0,0 +1,803 @@
+(***************************************************************************)
+(* *)
+(* ftimage.h *)
+(* *)
+(* FreeType glyph image formats and default raster interface *)
+(* (specification). *)
+(* *)
+(* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by *)
+(* David Turner, Robert Wilhelm, and Werner Lemberg. *)
+(* *)
+(* This file is part of the FreeType project, and may only be used, *)
+(* modified, and distributed under the terms of the FreeType project *)
+(* license, LICENSE.TXT. By continuing to use, modify, or distribute *)
+(* this file you indicate that you have read the license and *)
+(* understand and accept it fully. *)
+(* *)
+(***************************************************************************)
+(***************************************************************************)
+(* Pascal port by the UltraStar Deluxe Team *)
+(***************************************************************************)
+
+ (*************************************************************************)
+ (* *)
+ (* Note: A `raster' is simply a scan-line converter, used to render *)
+ (* FT_Outlines into FT_Bitmaps. *)
+ (* *)
+ (*************************************************************************)
+
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Pos *)
+ (* *)
+ (* <Description> *)
+ (* The type FT_Pos is a 32-bit integer used to store vectorial *)
+ (* coordinates. Depending on the context, these can represent *)
+ (* distances in integer font units, or 16,16, or 26.6 fixed float *)
+ (* pixel coordinates. *)
+ (* *)
+ FT_Pos = cslong;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Vector *)
+ (* *)
+ (* <Description> *)
+ (* A simple structure used to store a 2D vector; coordinates are of *)
+ (* the FT_Pos type. *)
+ (* *)
+ (* <Fields> *)
+ (* x :: The horizontal coordinate. *)
+ (* y :: The vertical coordinate. *)
+ (* *)
+ PFT_Vector = ^FT_Vector;
+ FT_Vector = record
+ x ,
+ y : FT_Pos;
+ end;
+
+ PFT_VectorArray = ^FT_VectorArray;
+ FT_VectorArray = array[0 .. (MaxInt div SizeOf(FT_Vector))-1] of FT_Vector;
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_BBox *)
+ (* *)
+ (* <Description> *)
+ (* A structure used to hold an outline's bounding box, i.e., the *)
+ (* coordinates of its extrema in the horizontal and vertical *)
+ (* directions. *)
+ (* *)
+ (* <Fields> *)
+ (* xMin :: The horizontal minimum (left-most). *)
+ (* *)
+ (* yMin :: The vertical minimum (bottom-most). *)
+ (* *)
+ (* xMax :: The horizontal maximum (right-most). *)
+ (* *)
+ (* yMax :: The vertical maximum (top-most). *)
+ (* *)
+ PFT_BBox = ^FT_BBox;
+ FT_BBox = record
+ xMin, yMin : FT_Pos;
+ xMax, yMax : FT_Pos;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Enum> *)
+ (* FT_Pixel_Mode *)
+ (* *)
+ (* <Description> *)
+ (* An enumeration type used to describe the format of pixels in a *)
+ (* given bitmap. Note that additional formats may be added in the *)
+ (* future. *)
+ (* *)
+ (* <Values> *)
+ (* FT_PIXEL_MODE_NONE :: *)
+ (* Value 0 is reserved. *)
+ (* *)
+ (* FT_PIXEL_MODE_MONO :: *)
+ (* A monochrome bitmap, using 1 bit per pixel. Note that pixels *)
+ (* are stored in most-significant order (MSB), which means that *)
+ (* the left-most pixel in a byte has value 128. *)
+ (* *)
+ (* FT_PIXEL_MODE_GRAY :: *)
+ (* An 8-bit bitmap, generally used to represent anti-aliased glyph *)
+ (* images. Each pixel is stored in one byte. Note that the number *)
+ (* of value `gray' levels is stored in the `num_bytes' field of *)
+ (* the @FT_Bitmap structure (it generally is 256). *)
+ (* *)
+ (* FT_PIXEL_MODE_GRAY2 :: *)
+ (* A 2-bit/pixel bitmap, used to represent embedded anti-aliased *)
+ (* bitmaps in font files according to the OpenType specification. *)
+ (* We haven't found a single font using this format, however. *)
+ (* *)
+ (* FT_PIXEL_MODE_GRAY4 :: *)
+ (* A 4-bit/pixel bitmap, used to represent embedded anti-aliased *)
+ (* bitmaps in font files according to the OpenType specification. *)
+ (* We haven't found a single font using this format, however. *)
+ (* *)
+ (* FT_PIXEL_MODE_LCD :: *)
+ (* An 8-bit bitmap, used to represent RGB or BGR decimated glyph *)
+ (* images used for display on LCD displays; the bitmap is three *)
+ (* times wider than the original glyph image. See also *)
+ (* @FT_RENDER_MODE_LCD. *)
+ (* *)
+ (* FT_PIXEL_MODE_LCD_V :: *)
+ (* An 8-bit bitmap, used to represent RGB or BGR decimated glyph *)
+ (* images used for display on rotated LCD displays; the bitmap *)
+ (* is three times taller than the original glyph image. See also *)
+ (* @FT_RENDER_MODE_LCD_V. *)
+ (* *)
+ FT_Pixel_Mode = cint;
+{$ELSE TYPE_DECL}
+const
+ FT_PIXEL_MODE_NONE = 0;
+ FT_PIXEL_MODE_MONO = FT_PIXEL_MODE_NONE + 1;
+ FT_PIXEL_MODE_GRAY = FT_PIXEL_MODE_MONO + 1;
+ FT_PIXEL_MODE_GRAY2 = FT_PIXEL_MODE_GRAY + 1;
+ FT_PIXEL_MODE_GRAY4 = FT_PIXEL_MODE_GRAY2 + 1;
+ FT_PIXEL_MODE_LCD = FT_PIXEL_MODE_GRAY4 + 1;
+ FT_PIXEL_MODE_LCD_V = FT_PIXEL_MODE_LCD + 1;
+
+ FT_PIXEL_MODE_MAX = FT_PIXEL_MODE_LCD_V + 1; (* do not remove *)
+{$ENDIF TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Bitmap *)
+ (* *)
+ (* <Description> *)
+ (* A structure used to describe a bitmap or pixmap to the raster. *)
+ (* Note that we now manage pixmaps of various depths through the *)
+ (* `pixel_mode' field. *)
+ (* *)
+ (* <Fields> *)
+ (* rows :: The number of bitmap rows. *)
+ (* *)
+ (* width :: The number of pixels in bitmap row. *)
+ (* *)
+ (* pitch :: The pitch's absolute value is the number of bytes *)
+ (* taken by one bitmap row, including padding. *)
+ (* However, the pitch is positive when the bitmap has *)
+ (* a `down' flow, and negative when it has an `up' *)
+ (* flow. In all cases, the pitch is an offset to add *)
+ (* to a bitmap pointer in order to go down one row. *)
+ (* *)
+ (* buffer :: A typeless pointer to the bitmap buffer. This *)
+ (* value should be aligned on 32-bit boundaries in *)
+ (* most cases. *)
+ (* *)
+ (* num_grays :: This field is only used with *)
+ (* `FT_PIXEL_MODE_GRAY'; it gives the number of gray *)
+ (* levels used in the bitmap. *)
+ (* *)
+ (* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. *)
+ (* See @FT_Pixel_Mode for possible values. *)
+ (* *)
+ (* palette_mode :: This field is only used with paletted pixel modes; *)
+ (* it indicates how the palette is stored. *)
+ (* *)
+ (* palette :: A typeless pointer to the bitmap palette; only *)
+ (* used for paletted pixel modes. *)
+ (* *)
+ (* <Note> *)
+ (* For now, the only pixel mode supported by FreeType are mono and *)
+ (* grays. However, drivers might be added in the future to support *)
+ (* more `colorful' options. *)
+ (* *)
+ (* When using pixel modes pal2, pal4 and pal8 with a void `palette' *)
+ (* field, a gray pixmap with respectively 4, 16, and 256 levels of *)
+ (* gray is assumed. This, in order to be compatible with some *)
+ (* embedded bitmap formats defined in the TrueType specification. *)
+ (* *)
+ (* Note that no font was found presenting such embedded bitmaps, so *)
+ (* this is currently completely unhandled by the library. *)
+ (* *)
+ PFT_Bitmap = ^FT_Bitmap;
+ FT_Bitmap = record
+ rows: FT_Int;
+ width: FT_Int;
+ pitch: FT_Int;
+ buffer: PByteArray;
+ num_grays: FT_Short;
+ pixel_mode: byte;
+ palette_mode: byte;
+ palette: pointer;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Section> *)
+ (* outline_processing *)
+ (* *)
+ (*************************************************************************)
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Outline *)
+ (* *)
+ (* <Description> *)
+ (* This structure is used to describe an outline to the scan-line *)
+ (* converter. *)
+ (* *)
+ (* <Fields> *)
+ (* n_contours :: The number of contours in the outline. *)
+ (* *)
+ (* n_points :: The number of points in the outline. *)
+ (* *)
+ (* points :: A pointer to an array of `n_points' FT_Vector *)
+ (* elements, giving the outline's point coordinates. *)
+ (* *)
+ (* tags :: A pointer to an array of `n_points' chars, giving *)
+ (* each outline point's type. If bit 0 is unset, the *)
+ (* point is `off' the curve, i.e. a Bezier control *)
+ (* point, while it is `on' when set. *)
+ (* *)
+ (* Bit 1 is meaningful for `off' points only. If set, *)
+ (* it indicates a third-order Bezier arc control point; *)
+ (* and a second-order control point if unset. *)
+ (* *)
+ (* contours :: An array of `n_contours' shorts, giving the end *)
+ (* point of each contour within the outline. For *)
+ (* example, the first contour is defined by the points *)
+ (* `0' to `contours[0]', the second one is defined by *)
+ (* the points `contours[0]+1' to `contours[1]', etc. *)
+ (* *)
+ (* flags :: A set of bit flags used to characterize the outline *)
+ (* and give hints to the scan-converter and hinter on *)
+ (* how to convert/grid-fit it. See FT_Outline_Flags. *)
+ (* *)
+ PFT_Outline = ^FT_Outline;
+ FT_Outline = record
+ n_contours: FT_Short; (* number of contours in glyph *)
+ n_points: FT_Short; (* number of points in the glyph *)
+
+ points: PFT_VectorArray; (* the outline's points *)
+ tags: PByteArray; (* the points flags *)
+ contours: PFT_ShortArray; (* the contour end points *)
+
+ flags: FT_Int; (* outline masks *)
+ end;
+
+{$ELSE TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* @macro: *)
+ (* FT_CURVE_TAG ( flag ) *)
+ (* *)
+ function FT_CURVE_TAG(flag: byte): byte;
+
+const
+ FT_CURVE_TAG_ON = 1;
+ FT_CURVE_TAG_CONIC = 0;
+ FT_CURVE_TAG_CUBIC = 2;
+
+ FT_CURVE_TAG_TOUCH_X = 8; // reserved for the TrueType hinter
+ FT_CURVE_TAG_TOUCH_Y = 16; // reserved for the TrueType hinter
+
+ FT_CURVE_TAG_TOUCH_BOTH = ( FT_CURVE_TAG_TOUCH_X or
+ FT_CURVE_TAG_TOUCH_Y );
+{$ENDIF TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Outline_MoveToFunc *)
+ (* *)
+ (* <Description> *)
+ (* A function pointer type used to describe the signature of a `move *)
+ (* to' function during outline walking/decomposition. *)
+ (* *)
+ (* A `move to' is emitted to start a new contour in an outline. *)
+ (* *)
+ (* <Input> *)
+ (* to :: A pointer to the target point of the `move to'. *)
+ (* *)
+ (* user :: A typeless pointer which is passed from the caller of the *)
+ (* decomposition function. *)
+ (* *)
+ (* <Return> *)
+ (* Error code. 0 means success. *)
+ (* *)
+ FT_Outline_MoveToFunc = function(to_: {const} PFT_Vector;
+ user: Pointer): cint; cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Outline_LineToFunc *)
+ (* *)
+ (* <Description> *)
+ (* A function pointer type used to describe the signature of a `line *)
+ (* to' function during outline walking/decomposition. *)
+ (* *)
+ (* A `line to' is emitted to indicate a segment in the outline. *)
+ (* *)
+ (* <Input> *)
+ (* to :: A pointer to the target point of the `line to'. *)
+ (* *)
+ (* user :: A typeless pointer which is passed from the caller of the *)
+ (* decomposition function. *)
+ (* *)
+ (* <Return> *)
+ (* Error code. 0 means success. *)
+ (* *)
+ FT_Outline_LineToFunc = function(to_: {const} PFT_Vector;
+ user: Pointer): cint; cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Outline_ConicToFunc *)
+ (* *)
+ (* <Description> *)
+ (* A function pointer type use to describe the signature of a `conic *)
+ (* to' function during outline walking/decomposition. *)
+ (* *)
+ (* A `conic to' is emitted to indicate a second-order Bézier arc in *)
+ (* the outline. *)
+ (* *)
+ (* <Input> *)
+ (* control :: An intermediate control point between the last position *)
+ (* and the new target in `to'. *)
+ (* *)
+ (* to :: A pointer to the target end point of the conic arc. *)
+ (* *)
+ (* user :: A typeless pointer which is passed from the caller of *)
+ (* the decomposition function. *)
+ (* *)
+ (* <Return> *)
+ (* Error code. 0 means success. *)
+ (* *)
+ FT_Outline_ConicToFunc = function(control: {const} PFT_Vector;
+ to_: {const} PFT_Vector;
+ user: Pointer): cint; cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Outline_CubicToFunc *)
+ (* *)
+ (* <Description> *)
+ (* A function pointer type used to describe the signature of a `cubic *)
+ (* to' function during outline walking/decomposition. *)
+ (* *)
+ (* A `cubic to' is emitted to indicate a third-order Bézier arc. *)
+ (* *)
+ (* <Input> *)
+ (* control1 :: A pointer to the first Bézier control point. *)
+ (* *)
+ (* control2 :: A pointer to the second Bézier control point. *)
+ (* *)
+ (* to :: A pointer to the target end point. *)
+ (* *)
+ (* user :: A typeless pointer which is passed from the caller of *)
+ (* the decomposition function. *)
+ (* *)
+ (* <Return> *)
+ (* Error code. 0 means success. *)
+ (* *)
+ FT_Outline_CubicToFunc = function( control1: {const} PFT_Vector;
+ control2: {const} PFT_Vector;
+ to_: {const} PFT_Vector;
+ user: Pointer ): cint; cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Outline_Funcs *)
+ (* *)
+ (* <Description> *)
+ (* A structure to hold various function pointers used during outline *)
+ (* decomposition in order to emit segments, conic, and cubic Béziers, *)
+ (* as well as `move to' and `close to' operations. *)
+ (* *)
+ (* <Fields> *)
+ (* move_to :: The `move to' emitter. *)
+ (* *)
+ (* line_to :: The segment emitter. *)
+ (* *)
+ (* conic_to :: The second-order Bézier arc emitter. *)
+ (* *)
+ (* cubic_to :: The third-order Bézier arc emitter. *)
+ (* *)
+ (* shift :: The shift that is applied to coordinates before they *)
+ (* are sent to the emitter. *)
+ (* *)
+ (* delta :: The delta that is applied to coordinates before they *)
+ (* are sent to the emitter, but after the shift. *)
+ (* *)
+ (* <Note> *)
+ (* The point coordinates sent to the emitters are the transformed *)
+ (* version of the original coordinates (this is important for high *)
+ (* accuracy during scan-conversion). The transformation is simple: *)
+ (* *)
+ (* { *)
+ (* x' = (x << shift) - delta *)
+ (* y' = (x << shift) - delta *)
+ (* } *)
+ (* *)
+ (* Set the value of `shift' and `delta' to 0 to get the original *)
+ (* point coordinates. *)
+ (* *)
+ PFT_Outline_Funcs = ^FT_Outline_Funcs;
+ FT_Outline_Funcs = record
+ move_to: FT_Outline_MoveToFunc;
+ line_to: FT_Outline_LineToFunc;
+ conic_to: FT_Outline_ConicToFunc;
+ cubic_to: FT_Outline_CubicToFunc;
+
+ shift: cint;
+ delta: FT_Pos;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Enum> *)
+ (* FT_Glyph_Format *)
+ (* *)
+ (* <Description> *)
+ (* An enumeration type used to describe the format of a given glyph *)
+ (* image. Note that this version of FreeType only supports two image *)
+ (* formats, even though future font drivers will be able to register *)
+ (* their own format. *)
+ (* *)
+ (* <Values> *)
+ (* FT_GLYPH_FORMAT_NONE :: *)
+ (* The value 0 is reserved and does describe a glyph format. *)
+ (* *)
+ (* FT_GLYPH_FORMAT_COMPOSITE :: *)
+ (* The glyph image is a composite of several other images. This *)
+ (* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to *)
+ (* report compound glyphs (like accented characters). *)
+ (* *)
+ (* FT_GLYPH_FORMAT_BITMAP :: *)
+ (* The glyph image is a bitmap, and can be described as an *)
+ (* @FT_Bitmap. You generally need to access the `bitmap' field of *)
+ (* the @FT_GlyphSlotRec structure to read it. *)
+ (* *)
+ (* FT_GLYPH_FORMAT_OUTLINE :: *)
+ (* The glyph image is a vertorial outline made of line segments *)
+ (* and Bezier arcs; it can be described as an @FT_Outline; you *)
+ (* generally want to access the `outline' field of the *)
+ (* @FT_GlyphSlotRec structure to read it. *)
+ (* *)
+ (* FT_GLYPH_FORMAT_PLOTTER :: *)
+ (* The glyph image is a vectorial path with no inside/outside *)
+ (* contours. Some Type 1 fonts, like those in the Hershey family, *)
+ (* contain glyphs in this format. These are described as *)
+ (* @FT_Outline, but FreeType isn't currently capable of rendering *)
+ (* them correctly. *)
+ (* *)
+ FT_Glyph_Format = array[0..3] of char;
+{$ELSE TYPE_DECL}
+const
+ FT_GLYPH_FORMAT_NONE: FT_Glyph_Format = (#0, #0, #0, #0 );
+
+ FT_GLYPH_FORMAT_COMPOSITE: FT_Glyph_Format = ('c', 'o', 'm', 'p' );
+ FT_GLYPH_FORMAT_BITMAP: FT_Glyph_Format = ('b', 'i', 't', 's' );
+ FT_GLYPH_FORMAT_OUTLINE: FT_Glyph_Format = ('o', 'u', 't', 'l' );
+ FT_GLYPH_FORMAT_PLOTTER: FT_Glyph_Format = ('p', 'l', 'o', 't' );
+
+{$ENDIF TYPE_DECL}
+
+ (*************************************************************************)
+ (*************************************************************************)
+ (*************************************************************************)
+ (***** *****)
+ (***** R A S T E R D E F I N I T I O N S *****)
+ (***** *****)
+ (*************************************************************************)
+ (*************************************************************************)
+ (*************************************************************************)
+
+
+ (*************************************************************************)
+ (* *)
+ (* A raster is a scan converter, in charge of rendering an outline into *)
+ (* a a bitmap. This section contains the public API for rasters. *)
+ (* *)
+ (* Note that in FreeType 2, all rasters are now encapsulated within *)
+ (* specific modules called `renderers'. See `freetype/ftrender.h' for *)
+ (* more details on renderers. *)
+ (* *)
+ (*************************************************************************)
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Section> *)
+ (* raster *)
+ (* *)
+ (* <Title> *)
+ (* Scanline Converter *)
+ (* *)
+ (* <Abstract> *)
+ (* How vectorial outlines are converted into bitmaps and pixmaps. *)
+ (* *)
+ (* <Description> *)
+ (* This section contains technical definitions. *)
+ (* *)
+ (*************************************************************************)
+
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Raster *)
+ (* *)
+ (* <Description> *)
+ (* A handle (pointer) to a raster object. Each object can be used *)
+ (* independently to convert an outline into a bitmap or pixmap. *)
+ (* *)
+ FT_Raster = Pointer;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Span *)
+ (* *)
+ (* <Description> *)
+ (* A structure used to model a single span of gray (or black) pixels *)
+ (* when rendering a monochrome or anti-aliased bitmap. *)
+ (* *)
+ (* <Fields> *)
+ (* x :: The span's horizontal start position. *)
+ (* *)
+ (* len :: The span's length in pixels. *)
+ (* *)
+ (* coverage :: The span color/coverage, ranging from 0 (background) *)
+ (* to 255 (foreground). Only used for anti-aliased *)
+ (* rendering. *)
+ (* *)
+ (* <Note> *)
+ (* This structure is used by the span drawing callback type named *)
+ (* @FT_SpanFunc which takes the y-coordinate of the span as a *)
+ (* a parameter. *)
+ (* *)
+ (* The coverage value is always between 0 and 255. *)
+ (* *)
+ PFT_Span = ^FT_Span;
+ FT_Span = record
+ x: cshort;
+ len: cushort;
+ coverage: cuchar;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_SpanFunc *)
+ (* *)
+ (* <Description> *)
+ (* A function used as a call-back by the anti-aliased renderer in *)
+ (* order to let client applications draw themselves the gray pixel *)
+ (* spans on each scan line. *)
+ (* *)
+ (* <Input> *)
+ (* y :: The scanline's y-coordinate. *)
+ (* *)
+ (* count :: The number of spans to draw on this scanline. *)
+ (* *)
+ (* spans :: A table of `count' spans to draw on the scanline. *)
+ (* *)
+ (* user :: User-supplied data that is passed to the callback. *)
+ (* *)
+ (* <Note> *)
+ (* This callback allows client applications to directly render the *)
+ (* gray spans of the anti-aliased bitmap to any kind of surfaces. *)
+ (* *)
+ (* This can be used to write anti-aliased outlines directly to a *)
+ (* given background bitmap, and even perform translucency. *)
+ (* *)
+ (* Note that the `count' field cannot be greater than a fixed value *)
+ (* defined by the `FT_MAX_GRAY_SPANS' configuration macro in *)
+ (* `ftoption.h'. By default, this value is set to 32, which means *)
+ (* that if there are more than 32 spans on a given scanline, the *)
+ (* callback is called several times with the same `y' parameter in *)
+ (* order to draw all callbacks. *)
+ (* *)
+ (* Otherwise, the callback is only called once per scan-line, and *)
+ (* only for those scanlines that do have `gray' pixels on them. *)
+ (* *)
+ FT_SpanFunc = procedure(y: cint;
+ count: cint;
+ spans: {const} PFT_Span;
+ user: Pointer ); cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Raster_BitTest_Func *)
+ (* *)
+ (* <Description> *)
+ (* THIS TYPE IS DEPRECATED. DO NOT USE IT. *)
+ (* *)
+ (* A function used as a call-back by the monochrome scan-converter *)
+ (* to test whether a given target pixel is already set to the drawing *)
+ (* `color'. These tests are crucial to implement drop-out control *)
+ (* per-se the TrueType spec. *)
+ (* *)
+ (* <Input> *)
+ (* y :: The pixel's y-coordinate. *)
+ (* *)
+ (* x :: The pixel's x-coordinate. *)
+ (* *)
+ (* user :: User-supplied data that is passed to the callback. *)
+ (* *)
+ (* <Return> *)
+ (* 1 if the pixel is `set', 0 otherwise. *)
+ (* *)
+ FT_Raster_BitTest_Func = function(y: cint;
+ x: cint;
+ user: Pointer): cint; cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Raster_BitSet_Func *)
+ (* *)
+ (* <Description> *)
+ (* THIS TYPE IS DEPRECATED. DO NOT USE IT. *)
+ (* *)
+ (* A function used as a call-back by the monochrome scan-converter *)
+ (* to set an individual target pixel. This is crucial to implement *)
+ (* drop-out control according to the TrueType specification. *)
+ (* *)
+ (* <Input> *)
+ (* y :: The pixel's y-coordinate. *)
+ (* *)
+ (* x :: The pixel's x-coordinate. *)
+ (* *)
+ (* user :: User-supplied data that is passed to the callback. *)
+ (* *)
+ (* <Return> *)
+ (* 1 if the pixel is `set', 0 otherwise. *)
+ (* *)
+ FT_Raster_BitSet_Func = procedure(y: cint;
+ x: cint;
+ user: Pointer ); cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Enum> *)
+ (* FT_RASTER_FLAG_XXX *)
+ (* *)
+ (* <Description> *)
+ (* A list of bit flag constants as used in the `flags' field of a *)
+ (* @FT_Raster_Params structure. *)
+ (* *)
+ (* <Values> *)
+ (* FT_RASTER_FLAG_DEFAULT :: This value is 0. *)
+ (* *)
+ (* FT_RASTER_FLAG_AA :: This flag is set to indicate that an *)
+ (* anti-aliased glyph image should be *)
+ (* generated. Otherwise, it will be *)
+ (* monochrome (1-bit). *)
+ (* *)
+ (* FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct *)
+ (* rendering. In this mode, client *)
+ (* applications must provide their own span *)
+ (* callback. This lets them directly *)
+ (* draw or compose over an existing bitmap. *)
+ (* If this bit is not set, the target *)
+ (* pixmap's buffer _must_ be zeroed before *)
+ (* rendering. *)
+ (* *)
+ (* Note that for now, direct rendering is *)
+ (* only possible with anti-aliased glyphs. *)
+ (* *)
+ (* FT_RASTER_FLAG_CLIP :: This flag is only used in direct *)
+ (* rendering mode. If set, the output will *)
+ (* be clipped to a box specified in the *)
+ (* `clip_box' field of the *)
+ (* @FT_Raster_Params structure. *)
+ (* *)
+ (* Note that by default, the glyph bitmap *)
+ (* is clipped to the target pixmap, except *)
+ (* in direct rendering mode where all spans *)
+ (* are generated if no clipping box is set. *)
+ (* *)
+{$ELSE TYPE_DECL}
+const
+ FT_RASTER_FLAG_DEFAULT = $0;
+ FT_RASTER_FLAG_AA = $1;
+ FT_RASTER_FLAG_DIRECT = $2;
+ FT_RASTER_FLAG_CLIP = $4;
+
+{$ENDIF TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Raster_Params *)
+ (* *)
+ (* <Description> *)
+ (* A structure to hold the arguments used by a raster's render *)
+ (* function. *)
+ (* *)
+ (* <Fields> *)
+ (* target :: The target bitmap. *)
+ (* *)
+ (* source :: A pointer to the source glyph image (e.g., an *)
+ (* @FT_Outline). *)
+ (* *)
+ (* flags :: The rendering flags. *)
+ (* *)
+ (* gray_spans :: The gray span drawing callback. *)
+ (* *)
+ (* black_spans :: The black span drawing callback. *)
+ (* *)
+ (* bit_test :: The bit test callback. UNIMPLEMENTED! *)
+ (* *)
+ (* bit_set :: The bit set callback. UNIMPLEMENTED! *)
+ (* *)
+ (* user :: User-supplied data that is passed to each drawing *)
+ (* callback. *)
+ (* *)
+ (* clip_box :: An optional clipping box. It is only used in *)
+ (* direct rendering mode. Note that coordinates here *)
+ (* should be expressed in _integer_ pixels (and not in *)
+ (* 26.6 fixed-point units). *)
+ (* *)
+ (* <Note> *)
+ (* An anti-aliased glyph bitmap is drawn if the @FT_RASTER_FLAG_AA *)
+ (* bit flag is set in the `flags' field, otherwise a monochrome *)
+ (* bitmap is generated. *)
+ (* *)
+ (* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the *)
+ (* raster will call the `gray_spans' callback to draw gray pixel *)
+ (* spans, in the case of an aa glyph bitmap, it will call *)
+ (* `black_spans', and `bit_test' and `bit_set' in the case of a *)
+ (* monochrome bitmap. This allows direct composition over a *)
+ (* pre-existing bitmap through user-provided callbacks to perform the *)
+ (* span drawing/composition. *)
+ (* *)
+ (* Note that the `bit_test' and `bit_set' callbacks are required when *)
+ (* rendering a monochrome bitmap, as they are crucial to implement *)
+ (* correct drop-out control as defined in the TrueType specification. *)
+ (* *)
+ PFT_Raster_Params = ^FT_Raster_Params;
+ FT_Raster_Params = record
+ target: {const} PFT_Bitmap;
+ source: {const} Pointer;
+ flags: cint;
+ gray_spans: FT_SpanFunc;
+ black_spans: FT_SpanFunc;
+ bit_test: FT_Raster_BitTest_Func; (* doesn't work! *)
+ bit_set: FT_Raster_BitSet_Func; (* doesn't work! *)
+ user: Pointer;
+ clip_box: FT_BBox;
+ end;
+
+{$ENDIF TYPE_DECL}
+
+
diff --git a/src/lib/freetype/ftoutln.inc b/src/lib/freetype/ftoutln.inc
new file mode 100644
index 00000000..997c6cb3
--- /dev/null
+++ b/src/lib/freetype/ftoutln.inc
@@ -0,0 +1,497 @@
+(***************************************************************************)
+(* *)
+(* ftoutln.h *)
+(* *)
+(* Support for the FT_Outline type used to store glyph shapes of *)
+(* most scalable font formats (specification). *)
+(* *)
+(* Copyright 1996-2001, 2002, 2003, 2005, 2006, 2007 by *)
+(* David Turner, Robert Wilhelm, and Werner Lemberg. *)
+(* *)
+(* This file is part of the FreeType project, and may only be used, *)
+(* modified, and distributed under the terms of the FreeType project *)
+(* license, LICENSE.TXT. By continuing to use, modify, or distribute *)
+(* this file you indicate that you have read the license and *)
+(* understand and accept it fully. *)
+(* *)
+(***************************************************************************)
+(***************************************************************************)
+(* Pascal port by the UltraStar Deluxe Team *)
+(***************************************************************************)
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Section> *)
+ (* outline_processing *)
+ (* *)
+ (* <Title> *)
+ (* Outline Processing *)
+ (* *)
+ (* <Abstract> *)
+ (* Functions to create, transform, and render vectorial glyph images. *)
+ (* *)
+ (* <Description> *)
+ (* This section contains routines used to create and destroy scalable *)
+ (* glyph images known as `outlines'. These can also be measured, *)
+ (* transformed, and converted into bitmaps and pixmaps. *)
+ (* *)
+ (* <Order> *)
+ (* FT_Outline *)
+ (* FT_OUTLINE_FLAGS *)
+ (* FT_Outline_New *)
+ (* FT_Outline_Done *)
+ (* FT_Outline_Copy *)
+ (* FT_Outline_Translate *)
+ (* FT_Outline_Transform *)
+ (* FT_Outline_Embolden *)
+ (* FT_Outline_Reverse *)
+ (* FT_Outline_Check *)
+ (* *)
+ (* FT_Outline_Get_CBox *)
+ (* FT_Outline_Get_BBox *)
+ (* *)
+ (* FT_Outline_Get_Bitmap *)
+ (* FT_Outline_Render *)
+ (* *)
+ (* FT_Outline_Decompose *)
+ (* FT_Outline_Funcs *)
+ (* FT_Outline_MoveTo_Func *)
+ (* FT_Outline_LineTo_Func *)
+ (* FT_Outline_ConicTo_Func *)
+ (* FT_Outline_CubicTo_Func *)
+ (* *)
+ (*************************************************************************)
+
+{$IFNDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Decompose *)
+ (* *)
+ (* <Description> *)
+ (* Walks over an outline's structure to decompose it into individual *)
+ (* segments and Bézier arcs. This function is also able to emit *)
+ (* `move to' and `close to' operations to indicate the start and end *)
+ (* of new contours in the outline. *)
+ (* *)
+ (* <Input> *)
+ (* outline :: A pointer to the source target. *)
+ (* *)
+ (* func_interface :: A table of `emitters', i.e,. function pointers *)
+ (* called during decomposition to indicate path *)
+ (* operations. *)
+ (* *)
+ (* <InOut> *)
+ (* user :: A typeless pointer which is passed to each *)
+ (* emitter during the decomposition. It can be *)
+ (* used to store the state during the *)
+ (* decomposition. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ function FT_Outline_Decompose(
+ outline: PFT_Outline;
+ func_interface: {const} PFT_Outline_Funcs;
+ user: Pointer): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Decompose';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_New *)
+ (* *)
+ (* <Description> *)
+ (* Creates a new outline of a given size. *)
+ (* *)
+ (* <Input> *)
+ (* library :: A handle to the library object from where the *)
+ (* outline is allocated. Note however that the new *)
+ (* outline will *not* necessarily be *freed*, when *)
+ (* destroying the library, by @FT_Done_FreeType. *)
+ (* *)
+ (* numPoints :: The maximal number of points within the outline. *)
+ (* *)
+ (* numContours :: The maximal number of contours within the outline. *)
+ (* *)
+ (* <Output> *)
+ (* anoutline :: A handle to the new outline. NULL in case of *)
+ (* error. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ (* <Note> *)
+ (* The reason why this function takes a `library' parameter is simply *)
+ (* to use the library's memory allocator. *)
+ (* *)
+ function FT_Outline_New(
+ library_: FT_Library;
+ numPoints: FT_UInt;
+ numContours: FT_Int;
+ anoutline: PFT_Outline): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_New';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Done *)
+ (* *)
+ (* <Description> *)
+ (* Destroys an outline created with @FT_Outline_New. *)
+ (* *)
+ (* <Input> *)
+ (* library :: A handle of the library object used to allocate the *)
+ (* outline. *)
+ (* *)
+ (* outline :: A pointer to the outline object to be discarded. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ (* <Note> *)
+ (* If the outline's `owner' field is not set, only the outline *)
+ (* descriptor will be released. *)
+ (* *)
+ (* The reason why this function takes an `library' parameter is *)
+ (* simply to use ft_mem_free(). *)
+ (* *)
+ function FT_Outline_Done(library_: FT_Library;
+ outline: PFT_Outline): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Done';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Check *)
+ (* *)
+ (* <Description> *)
+ (* Check the contents of an outline descriptor. *)
+ (* *)
+ (* <Input> *)
+ (* outline :: A handle to a source outline. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ function FT_Outline_Check( outline: PFT_Outline ): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Check';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Get_CBox *)
+ (* *)
+ (* <Description> *)
+ (* Returns an outline's `control box'. The control box encloses all *)
+ (* the outline's points, including Bézier control points. Though it *)
+ (* coincides with the exact bounding box for most glyphs, it can be *)
+ (* slightly larger in some situations (like when rotating an outline *)
+ (* which contains Bézier outside arcs). *)
+ (* *)
+ (* Computing the control box is very fast, while getting the bounding *)
+ (* box can take much more time as it needs to walk over all segments *)
+ (* and arcs in the outline. To get the latter, you can use the *)
+ (* `ftbbox' component which is dedicated to this single task. *)
+ (* *)
+ (* <Input> *)
+ (* outline :: A pointer to the source outline descriptor. *)
+ (* *)
+ (* <Output> *)
+ (* acbox :: The outline's control box. *)
+ (* *)
+ procedure FT_Outline_Get_CBox(
+ outline: {const} PFT_Outline;
+ acbox: PFT_BBox);
+ cdecl; external ft_lib name 'FT_Outline_Get_CBox';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Translate *)
+ (* *)
+ (* <Description> *)
+ (* Applies a simple translation to the points of an outline. *)
+ (* *)
+ (* <InOut> *)
+ (* outline :: A pointer to the target outline descriptor. *)
+ (* *)
+ (* <Input> *)
+ (* xOffset :: The horizontal offset. *)
+ (* *)
+ (* yOffset :: The vertical offset. *)
+ (* *)
+ procedure FT_Outline_Translate(
+ outline: {const} PFT_Outline;
+ xOffset: FT_Pos;
+ yOffset: FT_Pos);
+ cdecl; external ft_lib name 'FT_Outline_Translate';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Copy *)
+ (* *)
+ (* <Description> *)
+ (* Copies an outline into another one. Both objects must have the *)
+ (* same sizes (number of points & number of contours) when this *)
+ (* function is called. *)
+ (* *)
+ (* <Input> *)
+ (* source :: A handle to the source outline. *)
+ (* *)
+ (* <Output> *)
+ (* target :: A handle to the target outline. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ function FT_Outline_Copy(
+ source: {const} PFT_Outline;
+ target: PFT_Outline): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Copy';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Transform *)
+ (* *)
+ (* <Description> *)
+ (* Applies a simple 2x2 matrix to all of an outline's points. Useful *)
+ (* for applying rotations, slanting, flipping, etc. *)
+ (* *)
+ (* <InOut> *)
+ (* outline :: A pointer to the target outline descriptor. *)
+ (* *)
+ (* <Input> *)
+ (* matrix :: A pointer to the transformation matrix. *)
+ (* *)
+ (* <Note> *)
+ (* You can use @FT_Outline_Translate if you need to translate the *)
+ (* outline's points. *)
+ (* *)
+ procedure FT_Outline_Transform(
+ outline: {const} PFT_Outline;
+ matrix: {const} PFT_Matrix);
+ cdecl; external ft_lib name 'FT_Outline_Transform';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Embolden *)
+ (* *)
+ (* <Description> *)
+ (* Emboldens an outline. The new outline will be at most 4 times *)
+ (* `strength' pixels wider and higher. You may think of the left and *)
+ (* bottom borders as unchanged. *)
+ (* *)
+ (* Negative `strength' values to reduce the outline thickness are *)
+ (* possible also. *)
+ (* *)
+ (* <InOut> *)
+ (* outline :: A handle to the target outline. *)
+ (* *)
+ (* <Input> *)
+ (* strength :: How strong the glyph is emboldened. Expressed in *)
+ (* 26.6 pixel format. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ (* <Note> *)
+ (* The used algorithm to increase or decrease the thickness of the *)
+ (* glyph doesn't change the number of points; this means that certain *)
+ (* situations like acute angles or intersections are sometimes *)
+ (* handled incorrectly. *)
+ (* *)
+ (* Example call: *)
+ (* *)
+ (* { *)
+ (* FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); *)
+ (* if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) *)
+ (* FT_Outline_Embolden( &face->slot->outline, strength ); *)
+ (* } *)
+ (* *)
+ function FT_Outline_Embolden(
+ outline: PFT_Outline;
+ strength: FT_Pos): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Embolden';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Reverse *)
+ (* *)
+ (* <Description> *)
+ (* Reverses the drawing direction of an outline. This is used to *)
+ (* ensure consistent fill conventions for mirrored glyphs. *)
+ (* *)
+ (* <InOut> *)
+ (* outline :: A pointer to the target outline descriptor. *)
+ (* *)
+ (* <Note> *)
+ (* This functions toggles the bit flag @FT_OUTLINE_REVERSE_FILL in *)
+ (* the outline's `flags' field. *)
+ (* *)
+ (* It shouldn't be used by a normal client application, unless it *)
+ (* knows what it is doing. *)
+ (* *)
+ procedure FT_Outline_Reverse( outline: PFT_Outline );
+ cdecl; external ft_lib name 'FT_Outline_Reverse';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Get_Bitmap *)
+ (* *)
+ (* <Description> *)
+ (* Renders an outline within a bitmap. The outline's image is simply *)
+ (* OR-ed to the target bitmap. *)
+ (* *)
+ (* <Input> *)
+ (* library :: A handle to a FreeType library object. *)
+ (* *)
+ (* outline :: A pointer to the source outline descriptor. *)
+ (* *)
+ (* <InOut> *)
+ (* abitmap :: A pointer to the target bitmap descriptor. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ (* <Note> *)
+ (* This function does NOT CREATE the bitmap, it only renders an *)
+ (* outline image within the one you pass to it! *)
+ (* *)
+ (* It will use the raster corresponding to the default glyph format. *)
+ (* *)
+ function FT_Outline_Get_Bitmap(
+ library_: FT_Library;
+ outline: PFT_Outline;
+ abitmap: {const} PFT_Bitmap): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Get_Bitmap';
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Function> *)
+ (* FT_Outline_Render *)
+ (* *)
+ (* <Description> *)
+ (* Renders an outline within a bitmap using the current scan-convert. *)
+ (* This functions uses an @FT_Raster_Params structure as an argument, *)
+ (* allowing advanced features like direct composition, translucency, *)
+ (* etc. *)
+ (* *)
+ (* <Input> *)
+ (* library :: A handle to a FreeType library object. *)
+ (* *)
+ (* outline :: A pointer to the source outline descriptor. *)
+ (* *)
+ (* <InOut> *)
+ (* params :: A pointer to an @FT_Raster_Params structure used to *)
+ (* describe the rendering operation. *)
+ (* *)
+ (* <Return> *)
+ (* FreeType error code. 0 means success. *)
+ (* *)
+ (* <Note> *)
+ (* You should know what you are doing and how @FT_Raster_Params works *)
+ (* to use this function. *)
+ (* *)
+ (* The field `params.source' will be set to `outline' before the scan *)
+ (* converter is called, which means that the value you give to it is *)
+ (* actually ignored. *)
+ (* *)
+ function FT_Outline_Render(
+ library_: FT_Library;
+ outline: PFT_Outline;
+ params: PFT_Raster_Params): FT_Error;
+ cdecl; external ft_lib name 'FT_Outline_Render';
+
+{$ENDIF TYPE_DECL}
+
+ (**************************************************************************
+ *
+ * @enum:
+ * FT_Orientation
+ *
+ * @description:
+ * A list of values used to describe an outline's contour orientation.
+ *
+ * The TrueType and Postscript specifications use different conventions
+ * to determine whether outline contours should be filled or unfilled.
+ *
+ * @values:
+ * FT_ORIENTATION_TRUETYPE ::
+ * According to the TrueType specification, clockwise contours must
+ * be filled, and counter-clockwise ones must be unfilled.
+ *
+ * FT_ORIENTATION_POSTSCRIPT ::
+ * According to the Postscript specification, counter-clockwise contours
+ * must be filled, and clockwise ones must be unfilled.
+ *
+ * FT_ORIENTATION_FILL_RIGHT ::
+ * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to
+ * remember that in TrueType, everything that is to the right of
+ * the drawing direction of a contour must be filled.
+ *
+ * FT_ORIENTATION_FILL_LEFT ::
+ * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to
+ * remember that in Postscript, everything that is to the left of
+ * the drawing direction of a contour must be filled.
+ *
+ * FT_ORIENTATION_NONE ::
+ * The orientation cannot be determined. That is, different parts of
+ * the glyph have different orientation.
+ *
+ *)
+{$IFDEF TYPE_DECL}
+ FT_Orientation = cint;
+{$ELSE TYPE_DECL}
+const
+ FT_ORIENTATION_TRUETYPE = 0;
+ FT_ORIENTATION_POSTSCRIPT = 1;
+ FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE;
+ FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT;
+ FT_ORIENTATION_NONE = FT_ORIENTATION_FILL_LEFT+1;
+
+ (**************************************************************************
+ *
+ * @function:
+ * FT_Outline_Get_Orientation
+ *
+ * @description:
+ * This function analyzes a glyph outline and tries to compute its
+ * fill orientation (see @FT_Orientation). This is done by computing
+ * the direction of each global horizontal and/or vertical extrema
+ * within the outline.
+ *
+ * Note that this will return @FT_ORIENTATION_TRUETYPE for empty
+ * outlines.
+ *
+ * @input:
+ * outline ::
+ * A handle to the source outline.
+ *
+ * @return:
+ * The orientation.
+ *
+ *)
+ function FT_Outline_Get_Orientation( outline: PFT_Outline ): FT_Orientation;
+ cdecl; external ft_lib name 'FT_Outline_Get_Orientation';
+
+{$ENDIF TYPE_DECL}
+
diff --git a/src/lib/freetype/ftstroke.inc b/src/lib/freetype/ftstroke.inc
new file mode 100644
index 00000000..bf8a00ae
--- /dev/null
+++ b/src/lib/freetype/ftstroke.inc
@@ -0,0 +1,711 @@
+{***************************************************************************}
+{* *}
+{* ftstroke.h *}
+{* *}
+{* FreeType path stroker (specification). *}
+{* *}
+{* Copyright 2002, 2003, 2004, 2005, 2006 by *}
+{* David Turner, Robert Wilhelm, and Werner Lemberg. *}
+{* *}
+{* This file is part of the FreeType project, and may only be used, *}
+{* modified, and distributed under the terms of the FreeType project *}
+{* license, LICENSE.TXT. By continuing to use, modify, or distribute *}
+{* this file you indicate that you have read the license and *}
+{* understand and accept it fully. *}
+{* *}
+{***************************************************************************}
+(***************************************************************************)
+(* Pascal port by the UltraStar Deluxe Team *)
+(***************************************************************************)
+
+ {************************************************************************
+ *
+ * @section:
+ * glyph_stroker
+ *
+ * @title:
+ * Glyph Stroker
+ *
+ * @abstract:
+ * Generating bordered and stroked glyphs.
+ *
+ * @description:
+ * This component generates stroked outlines of a given vectorial
+ * glyph. It also allows you to retrieve the `outside' and/or the
+ * `inside' borders of the stroke.
+ *
+ * This can be useful to generate `bordered' glyph, i.e., glyphs
+ * displayed with a coloured (and anti-aliased) border around their
+ * shape.
+ *}
+
+{$IFDEF TYPE_DECL}
+
+ {**************************************************************
+ *
+ * @type:
+ * FT_Stroker
+ *
+ * @description:
+ * Opaque handler to a path stroker object.
+ *}
+ FT_Stroker = Pointer;
+
+
+ {**************************************************************
+ *
+ * @enum:
+ * FT_Stroker_LineJoin
+ *
+ * @description:
+ * These values determine how two joining lines are rendered
+ * in a stroker.
+ *
+ * @values:
+ * FT_STROKER_LINEJOIN_ROUND ::
+ * Used to render rounded line joins. Circular arcs are used
+ * to join two lines smoothly.
+ *
+ * FT_STROKER_LINEJOIN_BEVEL ::
+ * Used to render beveled line joins; i.e., the two joining lines
+ * are extended until they intersect.
+ *
+ * FT_STROKER_LINEJOIN_MITER ::
+ * Same as beveled rendering, except that an additional line
+ * break is added if the angle between the two joining lines
+ * is too closed (this is useful to avoid unpleasant spikes
+ * in beveled rendering).
+ *}
+ FT_Stroker_LineJoin = cint;
+{$ELSE TYPE_DECL}
+const
+ FT_STROKER_LINEJOIN_ROUND = 0;
+ FT_STROKER_LINEJOIN_BEVEL = 1;
+ FT_STROKER_LINEJOIN_MITER = 2;
+
+{$ENDIF TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ {**************************************************************
+ *
+ * @enum:
+ * FT_Stroker_LineCap
+ *
+ * @description:
+ * These values determine how the end of opened sub-paths are
+ * rendered in a stroke.
+ *
+ * @values:
+ * FT_STROKER_LINECAP_BUTT ::
+ * The end of lines is rendered as a full stop on the last
+ * point itself.
+ *
+ * FT_STROKER_LINECAP_ROUND ::
+ * The end of lines is rendered as a half-circle around the
+ * last point.
+ *
+ * FT_STROKER_LINECAP_SQUARE ::
+ * The end of lines is rendered as a square around the
+ * last point.
+ *}
+ FT_Stroker_LineCap = cint;
+{$ELSE TYPE_DECL}
+const
+ FT_STROKER_LINECAP_BUTT = 0;
+ FT_STROKER_LINECAP_ROUND = 1;
+ FT_STROKER_LINECAP_SQUARE = 2;
+
+{$ENDIF TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ {**************************************************************
+ *
+ * @enum:
+ * FT_StrokerBorder
+ *
+ * @description:
+ * These values are used to select a given stroke border
+ * in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder.
+ *
+ * @values:
+ * FT_STROKER_BORDER_LEFT ::
+ * Select the left border, relative to the drawing direction.
+ *
+ * FT_STROKER_BORDER_RIGHT ::
+ * Select the right border, relative to the drawing direction.
+ *
+ * @note:
+ * Applications are generally interested in the `inside' and `outside'
+ * borders. However, there is no direct mapping between these and the
+ * `left' and `right' ones, since this really depends on the glyph's
+ * drawing orientation, which varies between font formats.
+ *
+ * You can however use @FT_Outline_GetInsideBorder and
+ * @FT_Outline_GetOutsideBorder to get these.
+ *}
+ FT_StrokerBorder = cint;
+{$ELSE TYPE_DECL}
+const
+ FT_STROKER_BORDER_LEFT = 0;
+ FT_STROKER_BORDER_RIGHT = 1;
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Outline_GetInsideBorder
+ *
+ * @description:
+ * Retrieve the @FT_StrokerBorder value corresponding to the
+ * `inside' borders of a given outline.
+ *
+ * @input:
+ * outline ::
+ * The source outline handle.
+ *
+ * @return:
+ * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid
+ * outlines.
+ *}
+ function FT_Outline_GetInsideBorder( outline: PFT_Outline ): FT_StrokerBorder;
+ cdecl; external ft_lib name 'FT_Outline_GetInsideBorder';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Outline_GetOutsideBorder
+ *
+ * @description:
+ * Retrieve the @FT_StrokerBorder value corresponding to the
+ * `outside' borders of a given outline.
+ *
+ * @input:
+ * outline ::
+ * The source outline handle.
+ *
+ * @return:
+ * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid
+ * outlines.
+ *}
+ function FT_Outline_GetOutsideBorder( outline: PFT_Outline ): FT_StrokerBorder;
+ cdecl; external ft_lib name 'FT_Outline_GetOutsideBorder';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_New
+ *
+ * @description:
+ * Create a new stroker object.
+ *
+ * @input:
+ * library ::
+ * FreeType library handle.
+ *
+ * @output:
+ * astroker ::
+ * A new stroker object handle. NULL in case of error.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *}
+ function FT_Stroker_New(
+ library_: FT_Library;
+ out astroker: FT_Stroker ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_New';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_Set
+ *
+ * @description:
+ * Reset a stroker object's attributes.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * radius ::
+ * The border radius.
+ *
+ * line_cap ::
+ * The line cap style.
+ *
+ * line_join ::
+ * The line join style.
+ *
+ * miter_limit ::
+ * The miter limit for the FT_STROKER_LINEJOIN_MITER style,
+ * expressed as 16.16 fixed point value.
+ *
+ * @note:
+ * The radius is expressed in the same units that the outline
+ * coordinates.
+ *}
+ procedure FT_Stroker_Set(
+ stroker: FT_Stroker;
+ radius: FT_Fixed;
+ line_cap: FT_Stroker_LineCap;
+ line_join: FT_Stroker_LineJoin;
+ miter_limit: FT_Fixed );
+ cdecl; external ft_lib name 'FT_Stroker_Set';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_Rewind
+ *
+ * @description:
+ * Reset a stroker object without changing its attributes.
+ * You should call this function before beginning a new
+ * series of calls to @FT_Stroker_BeginSubPath or
+ * @FT_Stroker_EndSubPath.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *}
+ procedure FT_Stroker_Rewind( stroker: FT_Stroker );
+ cdecl; external ft_lib name 'FT_Stroker_Rewind';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_ParseOutline
+ *
+ * @description:
+ * A convenience function used to parse a whole outline with
+ * the stroker. The resulting outline(s) can be retrieved
+ * later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * outline ::
+ * The source outline.
+ *
+ * opened ::
+ * A boolean. If 1, the outline is treated as an open path instead
+ * of a closed one.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * If `opened' is 0 (the default), the outline is treated as a closed
+ * path, and the stroker will generate two distinct `border' outlines.
+ *
+ * If `opened' is 1, the outline is processed as an open path, and the
+ * stroker will generate a single `stroke' outline.
+ *
+ * This function calls @FT_Stroker_Rewind automatically.
+ *}
+ function FT_Stroker_ParseOutline(
+ stroker: FT_Stroker;
+ outline: PFT_Outline;
+ opened: FT_Bool): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_ParseOutline';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_BeginSubPath
+ *
+ * @description:
+ * Start a new sub-path in the stroker.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * to ::
+ * A pointer to the start vector.
+ *
+ * open ::
+ * A boolean. If 1, the sub-path is treated as an open one.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * This function is useful when you need to stroke a path that is
+ * not stored as an @FT_Outline object.
+ *}
+ function FT_Stroker_BeginSubPath(
+ stroker: FT_Stroker;
+ to_: PFT_Vector;
+ open: FT_Bool ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_BeginSubPath';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_EndSubPath
+ *
+ * @description:
+ * Close the current sub-path in the stroker.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * You should call this function after @FT_Stroker_BeginSubPath.
+ * If the subpath was not `opened', this function will `draw' a
+ * single line segment to the start position when needed.
+ *}
+ function FT_Stroker_EndSubPath( stroker: FT_Stroker ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_EndSubPath';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_LineTo
+ *
+ * @description:
+ * `Draw' a single line segment in the stroker's current sub-path,
+ * from the last position.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * to ::
+ * A pointer to the destination point.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * You should call this function between @FT_Stroker_BeginSubPath and
+ * @FT_Stroker_EndSubPath.
+ *}
+ function FT_Stroker_LineTo(
+ stroker: FT_Stroker;
+ to_: PFT_Vector ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_LineTo';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_ConicTo
+ *
+ * @description:
+ * `Draw' a single quadratic Bézier in the stroker's current sub-path,
+ * from the last position.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * control ::
+ * A pointer to a Bézier control point.
+ *
+ * to ::
+ * A pointer to the destination point.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * You should call this function between @FT_Stroker_BeginSubPath and
+ * @FT_Stroker_EndSubPath.
+ *}
+ function FT_Stroker_ConicTo(
+ stroker: FT_Stroker;
+ control: PFT_Vector;
+ to_: PFT_Vector ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_ConicTo';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_CubicTo
+ *
+ * @description:
+ * `Draw' a single cubic Bézier in the stroker's current sub-path,
+ * from the last position.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * control1 ::
+ * A pointer to the first Bézier control point.
+ *
+ * control2 ::
+ * A pointer to second Bézier control point.
+ *
+ * to ::
+ * A pointer to the destination point.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * You should call this function between @FT_Stroker_BeginSubPath and
+ * @FT_Stroker_EndSubPath.
+ *}
+ function FT_Stroker_CubicTo(
+ stroker: FT_Stroker;
+ control1: PFT_Vector;
+ control2: PFT_Vector;
+ to_: PFT_Vector ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_CubicTo';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_GetBorderCounts
+ *
+ * @description:
+ * Call this function once you have finished parsing your paths
+ * with the stroker. It will return the number of points and
+ * contours necessary to export one of the `border' or `stroke'
+ * outlines generated by the stroker.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * border ::
+ * The border index.
+ *
+ * @output:
+ * anum_points ::
+ * The number of points.
+ *
+ * anum_contours ::
+ * The number of contours.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * When an outline, or a sub-path, is `closed', the stroker generates
+ * two independent `border' outlines, named `left' and `right'.
+ *
+ * When the outline, or a sub-path, is `opened', the stroker merges
+ * the `border' outlines with caps. The `left' border receives all
+ * points, while the `right' border becomes empty.
+ *
+ * Use the function @FT_Stroker_GetCounts instead if you want to
+ * retrieve the counts associated to both borders.
+ *}
+ function FT_Stroker_GetBorderCounts(
+ stroker: FT_Stroker;
+ border: FT_StrokerBorder;
+ out anum_points: FT_UInt;
+ out anum_contours: FT_UInt ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_GetBorderCounts';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_ExportBorder
+ *
+ * @description:
+ * Call this function after @FT_Stroker_GetBorderCounts to
+ * export the corresponding border to your own @FT_Outline
+ * structure.
+ *
+ * Note that this function will append the border points and
+ * contours to your outline, but will not try to resize its
+ * arrays.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * border ::
+ * The border index.
+ *
+ * outline ::
+ * The target outline handle.
+ *
+ * @note:
+ * Always call this function after @FT_Stroker_GetBorderCounts to
+ * get sure that there is enough room in your @FT_Outline object to
+ * receive all new data.
+ *
+ * When an outline, or a sub-path, is `closed', the stroker generates
+ * two independent `border' outlines, named `left' and `right'
+ *
+ * When the outline, or a sub-path, is `opened', the stroker merges
+ * the `border' outlines with caps. The `left' border receives all
+ * points, while the `right' border becomes empty.
+ *
+ * Use the function @FT_Stroker_Export instead if you want to
+ * retrieve all borders at once.
+ *}
+ procedure FT_Stroker_ExportBorder(
+ stroker: FT_Stroker;
+ border: FT_StrokerBorder;
+ outline: PFT_Outline );
+ cdecl; external ft_lib name 'FT_Stroker_ExportBorder';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_GetCounts
+ *
+ * @description:
+ * Call this function once you have finished parsing your paths
+ * with the stroker. It returns the number of points and
+ * contours necessary to export all points/borders from the stroked
+ * outline/path.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * @output:
+ * anum_points ::
+ * The number of points.
+ *
+ * anum_contours ::
+ * The number of contours.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *}
+ function FT_Stroker_GetCounts(
+ stroker: FT_Stroker;
+ out anum_points: FT_UInt;
+ out anum_contours: FT_UInt ): FT_Error;
+ cdecl; external ft_lib name 'FT_Stroker_GetCounts';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_Export
+ *
+ * @description:
+ * Call this function after @FT_Stroker_GetBorderCounts to
+ * export the all borders to your own @FT_Outline structure.
+ *
+ * Note that this function will append the border points and
+ * contours to your outline, but will not try to resize its
+ * arrays.
+ *
+ * @input:
+ * stroker ::
+ * The target stroker handle.
+ *
+ * outline ::
+ * The target outline handle.
+ *}
+ procedure FT_Stroker_Export(
+ stroker: FT_Stroker;
+ outline: PFT_Outline );
+ cdecl; external ft_lib name 'FT_Stroker_Export';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Stroker_Done
+ *
+ * @description:
+ * Destroy a stroker object.
+ *
+ * @input:
+ * stroker ::
+ * A stroker handle. Can be NULL.
+ *}
+ procedure FT_Stroker_Done( stroker: FT_Stroker );
+ cdecl; external ft_lib name 'FT_Stroker_Done';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Glyph_Stroke
+ *
+ * @description:
+ * Stroke a given outline glyph object with a given stroker.
+ *
+ * @inout:
+ * pglyph ::
+ * Source glyph handle on input, new glyph handle on output.
+ *
+ * @input:
+ * stroker ::
+ * A stroker handle.
+ *
+ * destroy ::
+ * A Boolean. If 1, the source glyph object is destroyed
+ * on success.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * The source glyph is untouched in case of error.
+ *}
+ function FT_Glyph_Stroke(
+ var glyph: FT_Glyph;
+ stroker: FT_Stroker;
+ destroy: FT_Bool ): FT_Error;
+ cdecl; external ft_lib name 'FT_Glyph_Stroke';
+
+
+ {**************************************************************
+ *
+ * @function:
+ * FT_Glyph_StrokeBorder
+ *
+ * @description:
+ * Stroke a given outline glyph object with a given stroker, but
+ * only return either its inside or outside border.
+ *
+ * @inout:
+ * pglyph ::
+ * Source glyph handle on input, new glyph handle on output.
+ *
+ * @input:
+ * stroker ::
+ * A stroker handle.
+ *
+ * inside ::
+ * A Boolean. If 1, return the inside border, otherwise
+ * the outside border.
+ *
+ * destroy ::
+ * A Boolean. If 1, the source glyph object is destroyed
+ * on success.
+ *
+ * @return:
+ * FreeType error code. 0 means success.
+ *
+ * @note:
+ * The source glyph is untouched in case of error.
+ *}
+ function FT_Glyph_StrokeBorder(
+ var glyph: FT_Glyph;
+ stroker: FT_Stroker;
+ inside: FT_Bool;
+ destroy: FT_Bool ): FT_Error;
+ cdecl; external ft_lib name 'FT_Glyph_StrokeBorder';
+
+{$ENDIF TYPE_DECL}
+
diff --git a/src/lib/freetype/fttypes.inc b/src/lib/freetype/fttypes.inc
new file mode 100644
index 00000000..a64432e6
--- /dev/null
+++ b/src/lib/freetype/fttypes.inc
@@ -0,0 +1,311 @@
+(***************************************************************************)
+(* *)
+(* fttypes.h *)
+(* *)
+(* FreeType simple types definitions (specification only). *)
+(* *)
+(* Copyright 1996-2001, 2002, 2004, 2006, 2007 by *)
+(* David Turner, Robert Wilhelm, and Werner Lemberg. *)
+(* *)
+(* This file is part of the FreeType project, and may only be used, *)
+(* modified, and distributed under the terms of the FreeType project *)
+(* license, LICENSE.TXT. By continuing to use, modify, or distribute *)
+(* this file you indicate that you have read the license and *)
+(* understand and accept it fully. *)
+(* *)
+(***************************************************************************)
+(***************************************************************************)
+(* Pascal port by the UltraStar Deluxe Team *)
+(***************************************************************************)
+
+ (*************************************************************************)
+ (* *)
+ (* <Section> *)
+ (* basic_types *)
+ (* *)
+ (* <Title> *)
+ (* Basic Data Types *)
+ (* *)
+ (* <Abstract> *)
+ (* The basic data types defined by the library. *)
+ (* *)
+ (* <Description> *)
+ (* This section contains the basic data types defined by FreeType 2, *)
+ (* ranging from simple scalar types to bitmap descriptors. More *)
+ (* font-specific structures are defined in a different section. *)
+ (* *)
+ (* <Order> *)
+ (* FT_Byte *)
+ (* FT_Bytes *)
+ (* FT_Char *)
+ (* FT_Int *)
+ (* FT_UInt *)
+ (* FT_Short *)
+ (* FT_UShort *)
+ (* FT_Long *)
+ (* FT_ULong *)
+ (* FT_Bool *)
+ (* FT_Offset *)
+ (* FT_PtrDist *)
+ (* FT_String *)
+ (* FT_Tag *)
+ (* FT_Error *)
+ (* FT_Fixed *)
+ (* FT_Pointer *)
+ (* FT_Pos *)
+ (* FT_Vector *)
+ (* FT_BBox *)
+ (* FT_Matrix *)
+ (* FT_FWord *)
+ (* FT_UFWord *)
+ (* FT_F2Dot14 *)
+ (* FT_UnitVector *)
+ (* FT_F26Dot6 *)
+ (* *)
+ (* *)
+ (* FT_Generic *)
+ (* FT_Generic_Finalizer *)
+ (* *)
+ (* FT_Bitmap *)
+ (* FT_Pixel_Mode *)
+ (* FT_Palette_Mode *)
+ (* FT_Glyph_Format *)
+ (* FT_IMAGE_TAG *)
+ (* *)
+ (*************************************************************************)
+
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Bool *)
+ (* *)
+ (* <Description> *)
+ (* A typedef of unsigned char, used for simple booleans. As usual, *)
+ (* values 1 and 0 represent true and false, respectively. *)
+ (* *)
+ FT_Bool = cuchar;
+{$ENDIF TYPE_DECL}
+{$IFNDEF TYPE_DECL}
+const
+ FT_FALSE = 0;
+ FT_TRUE = 1;
+{$ENDIF !TYPE_DECL}
+{$IFDEF TYPE_DECL}
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Byte *)
+ (* *)
+ (* <Description> *)
+ (* A simple typedef for the _unsigned_ char type. *)
+ (* *)
+ FT_Byte = cuchar;
+ PFT_Byte = ^FT_Byte;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_String *)
+ (* *)
+ (* <Description> *)
+ (* A simple typedef for the char type, usually used for strings. *)
+ (* *)
+ FT_String = cchar;
+ PFT_String = ^FT_String;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Short *)
+ (* *)
+ (* <Description> *)
+ (* A typedef for signed short. *)
+ (* *)
+ FT_Short = csshort;
+ PFT_Short = ^FT_Short;
+
+ PFT_ShortArray = ^FT_ShortArray;
+ FT_ShortArray = array[0 .. (MaxInt div SizeOf(FT_Short))-1] of FT_Short;
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_UShort *)
+ (* *)
+ (* <Description> *)
+ (* A typedef for unsigned short. *)
+ (* *)
+ FT_UShort = cushort;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Int *)
+ (* *)
+ (* <Description> *)
+ (* A typedef for the int type. *)
+ (* *)
+ FT_Int = csint;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_UInt *)
+ (* *)
+ (* <Description> *)
+ (* A typedef for the unsigned int type. *)
+ (* *)
+ FT_UInt = cuint;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Long *)
+ (* *)
+ (* <Description> *)
+ (* A typedef for signed long. *)
+ (* *)
+ FT_Long = cslong;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_ULong *)
+ (* *)
+ (* <Description> *)
+ (* A typedef for unsigned long. *)
+ (* *)
+ FT_ULong = culong;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_F26Dot6 *)
+ (* *)
+ (* <Description> *)
+ (* A signed 26.6 fixed float type used for vectorial pixel *)
+ (* coordinates. *)
+ (* *)
+ FT_F26Dot6 = cslong;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Fixed *)
+ (* *)
+ (* <Description> *)
+ (* This type is used to store 16.16 fixed float values, like scaling *)
+ (* values or matrix coefficients. *)
+ (* *)
+ FT_Fixed = cslong;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Type> *)
+ (* FT_Error *)
+ (* *)
+ (* <Description> *)
+ (* The FreeType error code type. A value of 0 is always interpreted *)
+ (* as a successful operation. *)
+ (* *)
+ FT_Error = cint;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Matrix *)
+ (* *)
+ (* <Description> *)
+ (* A simple structure used to store a 2x2 matrix. Coefficients are *)
+ (* in 16.16 fixed float format. The computation performed is: *)
+ (* *)
+ (* { *)
+ (* x' = x*xx + y*xy *)
+ (* y' = x*yx + y*yy *)
+ (* } *)
+ (* *)
+ (* <Fields> *)
+ (* xx :: Matrix coefficient. *)
+ (* *)
+ (* xy :: Matrix coefficient. *)
+ (* *)
+ (* yx :: Matrix coefficient. *)
+ (* *)
+ (* yy :: Matrix coefficient. *)
+ (* *)
+ PFT_Matrix = ^FT_Matrix;
+ FT_Matrix = record
+ xx, xy: FT_Fixed;
+ yx, yy: FT_Fixed;
+ end;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <FuncType> *)
+ (* FT_Generic_Finalizer *)
+ (* *)
+ (* <Description> *)
+ (* Describes a function used to destroy the `client' data of any *)
+ (* FreeType object. See the description of the FT_Generic type for *)
+ (* details of usage. *)
+ (* *)
+ (* <Input> *)
+ (* The address of the FreeType object which is under finalization. *)
+ (* Its client data is accessed through its `generic' field. *)
+ (* *)
+ FT_Generic_Finalizer = procedure(AnObject : pointer ); cdecl;
+
+
+ (*************************************************************************)
+ (* *)
+ (* <Struct> *)
+ (* FT_Generic *)
+ (* *)
+ (* <Description> *)
+ (* Client applications often need to associate their own data to a *)
+ (* variety of FreeType core objects. For example, a text layout API *)
+ (* might want to associate a glyph cache to a given size object. *)
+ (* *)
+ (* Most FreeType object contains a `generic' field, of type *)
+ (* FT_Generic, which usage is left to client applications and font *)
+ (* servers. *)
+ (* *)
+ (* It can be used to store a pointer to client-specific data, as well *)
+ (* as the address of a `finalizer' function, which will be called by *)
+ (* FreeType when the object is destroyed (for example, the previous *)
+ (* client example would put the address of the glyph cache destructor *)
+ (* in the `finalizer' field). *)
+ (* *)
+ (* <Fields> *)
+ (* data :: A typeless pointer to any client-specified data. This *)
+ (* field is completely ignored by the FreeType library. *)
+ (* *)
+ (* finalizer :: A pointer to a `generic finalizer' function, which *)
+ (* will be called when the object is destroyed. If this *)
+ (* field is set to NULL, no code will be called. *)
+ (* *)
+ FT_Generic = record
+ data: pointer;
+ finalizer: FT_Generic_Finalizer;
+ end;
+
+
+ TByteArray = array [0 .. (MaxInt div SizeOf(byte))-1] of byte;
+ PByteArray = ^TByteArray;
+
+{$ENDIF TYPE_DECL}
+
diff --git a/src/lib/lib-info.txt b/src/lib/lib-info.txt
index 59502c7a..0a184568 100644
--- a/src/lib/lib-info.txt
+++ b/src/lib/lib-info.txt
@@ -1,60 +1,60 @@
-bass:
-http://www.un4seen.com/ (2.4.2.1)
-- FPC Mac OS X compatibility fixes
-
-fft:
-translation of audacity's FFT.cpp by hennymcc (maybe replace this with FFTW?)
-
-ffmpeg:
-- http://www.iversenit.dk/dev/ffmpeg-headers/: 2006-10
-- several bugs were fixed
-- many IFDEFS were added to the header to support multiple versions of ffmpeg (starting with end of 2006) and not only one specific version. This is necessary as we cannot control which version is used on linux. We could ship the ffmpeg lib with USDX and link statically but a stripped down ffmpeg is 15MB in size and takes 5 minutes to compile (so static linkage is not a good option).
-- the headers were updated to reflect the changes in the ffmpeg C-headers (http://svn.mplayerhq.hu/ffmpeg/trunk/ and http://svn.mplayerhq.hu/mplayer/trunk/libswscale/)
-
-freeimage:
-- inserted by eddie. Some compatibility fixes for platforms different than mac os x.
-- not used anymore
-
-freetype:
-- based on the AggPas (http://aggpas.org/) headers
-- just a minimal header that contains only some of the freetype functions and types. Some functions and structures/constants/types needed for USDX were added.
-- some comments added
-
-jedi-sdl:
-JEDI-SDL v1.0 Final RC 2 (http://jedi-sdl.pascalgamedevelopment.com/)
-- 64bit compatibility patch (http://sourceforge.net/tracker/index.php?func=detail&aid=1902924&group_id=43805&atid=437446)
-- some Mac OS X patches from freepascal trunk
-- some additional patched (see *.patch)
-
-midi:
-taken from http://www.torry.net/authorsmore.php?id=1615 (TMidiPlayer)
-- FPC (Win32) compatibility fixes
-- Win32 only. Maybe use some timidity stuff under linux.
-
-libpng:
-autocreated H2Pas file taken from freepascal trunk
-- bug fixes (especially H2Pas related stuff like wrong file types)
-- delphi compatibility
-- comments added
-
-portaudio:
-translation of the (patched) audacity C headers by hennymcc.
-See http://audacity.cvs.sourceforge.net/viewvc/audacity/lib-src/portaudio-v19/include/?sortdir=down
-
-portmixer:
-translation of the (patched) audacity C headers by hennymcc.
-- Unlike portaudio portmixer is part of audacity and there is no linux package for it. If we want to use it for linux, we have to link it statically. Unfortunately it requires a patched version of portaudio (which is part of audacity and statically linked to) so we have to statically link portaudio too :(.
-
-projectM:
-translation of the original C++ headers and C-wrapper by hennymcc
-
-samplerate:
-translation of the original C headers by profoX/hennymcc
-
-sqlite:
-taken from http://www.itwriting.com/blog/a-simple-delphi-wrapper-for-sqlite-3
-- slightly patched: see *.patch files for what has been patched (e.g. Binding)
-
-zlib:
-taken from freepascal (slightly patched)
+bass:
+http://www.un4seen.com/ (2.4.2.1)
+- FPC Mac OS X compatibility fixes
+
+fft:
+translation of audacity's FFT.cpp by hennymcc (maybe replace this with FFTW?)
+
+ffmpeg:
+- http://www.iversenit.dk/dev/ffmpeg-headers/: 2006-10
+- several bugs were fixed
+- many IFDEFS were added to the header to support multiple versions of ffmpeg (starting with end of 2006) and not only one specific version. This is necessary as we cannot control which version is used on linux. We could ship the ffmpeg lib with USDX and link statically but a stripped down ffmpeg is 15MB in size and takes 5 minutes to compile (so static linkage is not a good option).
+- the headers were updated to reflect the changes in the ffmpeg C-headers (http://svn.mplayerhq.hu/ffmpeg/trunk/ and http://svn.mplayerhq.hu/mplayer/trunk/libswscale/)
+
+freeimage:
+- inserted by eddie. Some compatibility fixes for platforms different than mac os x.
+- not used anymore
+
+freetype:
+- based on the AggPas (http://aggpas.org/) headers
+- just a minimal header that contains only some of the freetype functions and types. Some functions and structures/constants/types needed for USDX were added.
+- some comments added
+
+jedi-sdl:
+JEDI-SDL v1.0 Final RC 2 (http://jedi-sdl.pascalgamedevelopment.com/)
+- 64bit compatibility patch (http://sourceforge.net/tracker/index.php?func=detail&aid=1902924&group_id=43805&atid=437446)
+- some Mac OS X patches from freepascal trunk
+- some additional patched (see *.patch)
+
+midi:
+taken from http://www.torry.net/authorsmore.php?id=1615 (TMidiPlayer)
+- FPC (Win32) compatibility fixes
+- Win32 only. Maybe use some timidity stuff under linux.
+
+libpng:
+autocreated H2Pas file taken from freepascal trunk
+- bug fixes (especially H2Pas related stuff like wrong file types)
+- delphi compatibility
+- comments added
+
+portaudio:
+translation of the (patched) audacity C headers by hennymcc.
+See http://audacity.cvs.sourceforge.net/viewvc/audacity/lib-src/portaudio-v19/include/?sortdir=down
+
+portmixer:
+translation of the (patched) audacity C headers by hennymcc.
+- Unlike portaudio portmixer is part of audacity and there is no linux package for it. If we want to use it for linux, we have to link it statically. Unfortunately it requires a patched version of portaudio (which is part of audacity and statically linked to) so we have to statically link portaudio too :(.
+
+projectM:
+translation of the original C++ headers and C-wrapper by hennymcc
+
+samplerate:
+translation of the original C headers by profoX/hennymcc
+
+sqlite:
+taken from http://www.itwriting.com/blog/a-simple-delphi-wrapper-for-sqlite-3
+- slightly patched: see *.patch files for what has been patched (e.g. Binding)
+
+zlib:
+taken from freepascal (slightly patched)
- delphi compatibility \ No newline at end of file
diff --git a/src/lib/midi/CIRCBUF.PAS b/src/lib/midi/CIRCBUF.PAS
index 77cb3643..3ceb4c6e 100644
--- a/src/lib/midi/CIRCBUF.PAS
+++ b/src/lib/midi/CIRCBUF.PAS
@@ -23,7 +23,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
Uses
diff --git a/src/lib/midi/DELPHMCB.PAS b/src/lib/midi/DELPHMCB.PAS
index e607627d..ef0d5451 100644
--- a/src/lib/midi/DELPHMCB.PAS
+++ b/src/lib/midi/DELPHMCB.PAS
@@ -13,7 +13,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/midi/MIDIDEFS.PAS b/src/lib/midi/MIDIDEFS.PAS
index fc8eed26..4afe56ef 100644
--- a/src/lib/midi/MIDIDEFS.PAS
+++ b/src/lib/midi/MIDIDEFS.PAS
@@ -13,7 +13,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/midi/MIDITYPE.PAS b/src/lib/midi/MIDITYPE.PAS
index b1ec1bdd..45b50820 100644
--- a/src/lib/midi/MIDITYPE.PAS
+++ b/src/lib/midi/MIDITYPE.PAS
@@ -10,7 +10,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/midi/MidiFile.pas b/src/lib/midi/MidiFile.pas
index 11b1ca0b..acf44c04 100644
--- a/src/lib/midi/MidiFile.pas
+++ b/src/lib/midi/MidiFile.pas
@@ -92,18 +92,18 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
Windows,
- //Forms,
Messages,
Classes,
{$IFDEF FPC}
WinAllocation,
{$ENDIF}
- SysUtils;
+ SysUtils,
+ UPath;
type
TChunkType = (illegal, header, track);
@@ -162,7 +162,7 @@ type
procedure WndProc(var Msg : TMessage);
protected
{ Protected declarations }
- midiFile: file of byte;
+ midiFile: TBinaryFileStream;
chunkType: TChunkType;
chunkLength: integer;
chunkData: PByte;
@@ -177,7 +177,7 @@ type
FBpm: integer;
FBeatsPerMeasure: integer;
FusPerTick: double;
- FFilename: string;
+ FFilename: IPath;
Tracks: TList;
currentTrack: TMidiTrack;
@@ -191,7 +191,7 @@ type
currentPos: Double; // Current Position in ticks
procedure OnTrackReady;
- procedure setFilename(val: string);
+ procedure SetFilename(val: IPath);
procedure ReadChunkHeader;
procedure ReadChunkContent;
procedure ReadChunk;
@@ -221,7 +221,7 @@ type
function Ready: boolean;
published
{ Published declarations }
- property Filename: string read FFilename write setFilename;
+ property Filename: IPath read FFilename write SetFilename;
property NumberOfTracks: integer read numberTracks;
property TicksPerQuarter: integer read deltaTicks;
property FileFormat: TFileFormat read FFileFormat;
@@ -463,7 +463,7 @@ begin
result := Tracks.Items[index];
end;
-procedure TMidifile.setFilename(val: string);
+procedure TMidifile.SetFilename(val: IPath);
begin
FFilename := val;
// ReadFile;
@@ -586,7 +586,7 @@ procedure TMidifile.ReadChunkHeader;
var
theByte: array[0..7] of byte;
begin
- BlockRead(midiFile, theByte, 8);
+ midiFile.Read(theByte[0], 8);
if (theByte[0] = $4D) and (theByte[1] = $54) then
begin
if (theByte[2] = $68) and (theByte[3] = $64) then
@@ -608,7 +608,7 @@ begin
if not (chunkData = nil) then
FreeMem(chunkData);
GetMem(chunkData, chunkLength + 10);
- BlockRead(midiFile, chunkData^, chunkLength);
+ midiFile.Read(chunkData^, chunkLength);
chunkIndex := chunkData;
chunkEnd := PByte(integer(chunkIndex) + integer(chunkLength) - 1);
end;
@@ -848,12 +848,10 @@ begin
Tracks.Clear;
chunkType := illegal;
- AssignFile(midiFile, FFilename);
- FileMode := 0;
- Reset(midiFile);
- while not eof(midiFile) do
+ midiFile := TBinaryFileStream.Create(FFilename, fmOpenRead);
+ while (midiFile.Position < midiFile.Size) do
ReadChunk;
- CloseFile(midiFile);
+ FreeAndNil(midiFile);
numberTracks := Tracks.Count;
end;
diff --git a/src/lib/midi/MidiScope.pas b/src/lib/midi/MidiScope.pas
index 42fc65fc..afc20b0f 100644
--- a/src/lib/midi/MidiScope.pas
+++ b/src/lib/midi/MidiScope.pas
@@ -20,7 +20,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/midi/Midicons.pas b/src/lib/midi/Midicons.pas
index 35dbb5f3..72259beb 100644
--- a/src/lib/midi/Midicons.pas
+++ b/src/lib/midi/Midicons.pas
@@ -11,7 +11,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses Messages;
diff --git a/src/lib/midi/Midiin.pas b/src/lib/midi/Midiin.pas
index 21db0298..66e4f76d 100644
--- a/src/lib/midi/Midiin.pas
+++ b/src/lib/midi/Midiin.pas
@@ -103,7 +103,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/midi/Midiout.pas b/src/lib/midi/Midiout.pas
index 606d0dae..98e6e3fb 100644
--- a/src/lib/midi/Midiout.pas
+++ b/src/lib/midi/Midiout.pas
@@ -98,7 +98,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/other/DirWatch.pas b/src/lib/other/DirWatch.pas
index 9d395840..1e00ec5d 100644
--- a/src/lib/other/DirWatch.pas
+++ b/src/lib/other/DirWatch.pas
@@ -25,7 +25,7 @@ interface
{$IFDEF FPC}
{$MODE Delphi}
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$ENDIF}
uses
diff --git a/src/lib/projectM/projectM.pas b/src/lib/projectM/projectM.pas
index 4adba17d..533cb19b 100644
--- a/src/lib/projectM/projectM.pas
+++ b/src/lib/projectM/projectM.pas
@@ -2,7 +2,7 @@ unit projectM;
{$IFDEF FPC}
{$MODE DELPHI}
- {$H+} (* use AnsiString *)
+ {$H+} (* use long strings *)
{$PACKENUM 4} (* use 4-byte enums *)
{$PACKRECORDS C} (* C/C++-compatible record packing *)
{$ELSE}
diff --git a/src/lib/zlib/zlib.pas b/src/lib/zlib/zlib.pas
index 31d6a68b..8d09313f 100644
--- a/src/lib/zlib/zlib.pas
+++ b/src/lib/zlib/zlib.pas
@@ -14,7 +14,7 @@ interface
{$ifdef FPC}
{$mode objfpc} // Needed for array of const
- {$H+} // use AnsiString
+ {$H+} // use long strings
{$PACKRECORDS C}
{$endif}
diff --git a/src/media/UAudioCore_Bass.pas b/src/media/UAudioCore_Bass.pas
index 12623dc1..197f9760 100644
--- a/src/media/UAudioCore_Bass.pas
+++ b/src/media/UAudioCore_Bass.pas
@@ -44,6 +44,7 @@ type
public
constructor Create();
class function GetInstance(): TAudioCore_Bass;
+ function CheckVersion(): boolean;
function ErrorGetString(): string; overload;
function ErrorGetString(errCode: integer): string; overload;
function ConvertAudioFormatToBASSFlags(Format: TAudioSampleFormat; out Flags: DWORD): boolean;
@@ -56,6 +57,12 @@ uses
UMain,
ULog;
+const
+ // TODO: 2.4.2 is not ABI compatible with older versions
+ // as (BASS_RECORDINFO.driver was removed)
+ //BASS_MIN_REQUIRED_VERSION = $02040201;
+ BASS_MIN_REQUIRED_VERSION = $02000000;
+
var
Instance: TAudioCore_Bass;
@@ -71,6 +78,11 @@ begin
Result := Instance;
end;
+function TAudioCore_Bass.CheckVersion(): boolean;
+begin
+ Result := BASS_GetVersion() >= BASS_MIN_REQUIRED_VERSION;
+end;
+
function TAudioCore_Bass.ErrorGetString(): string;
begin
Result := ErrorGetString(BASS_ErrorGetCode());
diff --git a/src/media/UAudioDecoder_Bass.pas b/src/media/UAudioDecoder_Bass.pas
index 6bbdaeaa..d6d2425a 100644
--- a/src/media/UAudioDecoder_Bass.pas
+++ b/src/media/UAudioDecoder_Bass.pas
@@ -38,11 +38,12 @@ implementation
uses
Classes,
SysUtils,
+ bass,
UMain,
UMusic,
UAudioCore_Bass,
ULog,
- bass;
+ UPath;
type
TBassDecodeStream = class(TAudioDecodeStream)
@@ -75,7 +76,7 @@ type
function InitializeDecoder(): boolean;
function FinalizeDecoder(): boolean;
- function Open(const Filename: string): TAudioDecodeStream;
+ function Open(const Filename: IPath): TAudioDecodeStream;
end;
var
@@ -213,7 +214,10 @@ end;
function TAudioDecoder_Bass.InitializeDecoder(): boolean;
begin
+ Result := false;
BassCore := TAudioCore_Bass.GetInstance();
+ if not BassCore.CheckVersion then
+ Exit;
Result := true;
end;
@@ -222,7 +226,7 @@ begin
Result := true;
end;
-function TAudioDecoder_Bass.Open(const Filename: string): TAudioDecodeStream;
+function TAudioDecoder_Bass.Open(const Filename: IPath): TAudioDecodeStream;
var
Stream: HSTREAM;
ChannelInfo: BASS_CHANNELINFO;
@@ -237,7 +241,14 @@ begin
// TODO: use BASS_STREAM_PRESCAN for accurate seeking in VBR-files?
// disadvantage: seeking will slow down.
- Stream := BASS_StreamCreateFile(False, PAnsiChar(Filename), 0, 0, BASS_STREAM_DECODE);
+
+ {$IFDEF MSWINDOWS}
+ // Windows: Use UTF-16 version
+ Stream := BASS_StreamCreateFile(False, PWideChar(Filename.ToWide), 0, 0, BASS_STREAM_DECODE or BASS_UNICODE);
+ {$ELSE}
+ // Mac OS X: Use UTF8/ANSI version
+ Stream := BASS_StreamCreateFile(False, PAnsiChar(Filename.ToNative), 0, 0, BASS_STREAM_DECODE);
+ {$ENDIF}
if (Stream = 0) then
begin
//Log.LogError(BassCore.ErrorGetString(), 'TAudioDecoder_Bass.Open');
@@ -247,7 +258,7 @@ begin
// check if BASS opened some erroneously recognized file-formats
if BASS_ChannelGetInfo(Stream, channelInfo) then
begin
- fileExt := ExtractFileExt(Filename);
+ fileExt := Filename.GetExtension.ToUTF8;
// BASS opens FLV-files (maybe others too) although it cannot handle them.
// Setting BASS_CONFIG_VERIFY to the max. value (100000) does not help.
if ((fileExt = '.flv') and (channelInfo.ctype = BASS_CTYPE_STREAM_MP1)) then
diff --git a/src/media/UAudioDecoder_FFmpeg.pas b/src/media/UAudioDecoder_FFmpeg.pas
index 97d8a8df..d079afdc 100644
--- a/src/media/UAudioDecoder_FFmpeg.pas
+++ b/src/media/UAudioDecoder_FFmpeg.pas
@@ -56,23 +56,24 @@ interface
implementation
uses
+ SDL, // SDL redefines some base types -> include before SysUtils to ignore them
Classes,
Math,
- UMusic,
- UIni,
- UMain,
+ SysUtils,
avcodec,
avformat,
avutil,
avio,
mathematics, // used for av_rescale_q
rational,
- SDL,
- SysUtils,
+ UMusic,
+ UIni,
+ UMain,
UMediaCore_FFmpeg,
ULog,
UCommon,
- UConfig;
+ UConfig,
+ UPath;
const
MAX_AUDIOQ_SIZE = (5 * 16 * 1024);
@@ -138,7 +139,7 @@ type
AudioBufferSize: integer;
AudioBuffer: PByteArray;
- Filename: string;
+ Filename: IPath;
procedure SetPositionIntern(Time: real; Flush: boolean; Blocking: boolean);
procedure SetEOF(State: boolean); {$IFDEF HasInline}inline;{$ENDIF}
@@ -161,7 +162,7 @@ type
constructor Create();
destructor Destroy(); override;
- function Open(const Filename: string): boolean;
+ function Open(const Filename: IPath): boolean;
procedure Close(); override;
function GetLength(): real; override;
@@ -183,7 +184,7 @@ type
function InitializeDecoder(): boolean;
function FinalizeDecoder(): boolean;
- function Open(const Filename: string): TAudioDecodeStream;
+ function Open(const Filename: IPath): TAudioDecodeStream;
end;
var
@@ -270,7 +271,7 @@ begin
inherited;
end;
-function TFFmpegDecodeStream.Open(const Filename: string): boolean;
+function TFFmpegDecodeStream.Open(const Filename: IPath): boolean;
var
SampleFormat: TAudioSampleFormat;
AVResult: integer;
@@ -280,18 +281,18 @@ begin
Close();
Reset();
- if (not FileExists(Filename)) then
+ if (not Filename.IsFile) then
begin
- Log.LogError('Audio-file does not exist: "' + Filename + '"', 'UAudio_FFmpeg');
+ Log.LogError('Audio-file does not exist: "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Exit;
end;
Self.Filename := Filename;
- // open audio file
- if (av_open_input_file(FormatCtx, PAnsiChar(Filename), nil, 0, nil) <> 0) then
+ // use custom 'ufile' protocol for UTF-8 support
+ if (av_open_input_file(FormatCtx, PAnsiChar('ufile:'+FileName.ToUTF8), nil, 0, nil) <> 0) then
begin
- Log.LogError('av_open_input_file failed: "' + Filename + '"', 'UAudio_FFmpeg');
+ Log.LogError('av_open_input_file failed: "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Exit;
end;
@@ -301,7 +302,7 @@ begin
// retrieve stream information
if (av_find_stream_info(FormatCtx) < 0) then
begin
- Log.LogError('av_find_stream_info failed: "' + Filename + '"', 'UAudio_FFmpeg');
+ Log.LogError('av_find_stream_info failed: "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Close();
Exit;
end;
@@ -310,13 +311,13 @@ begin
FormatCtx^.pb.eof_reached := 0;
{$IFDEF DebugFFmpegDecode}
- dump_format(FormatCtx, 0, PAnsiChar(Filename), 0);
+ dump_format(FormatCtx, 0, PAnsiChar(Filename.ToNative), 0);
{$ENDIF}
AudioStreamIndex := FFmpegCore.FindAudioStreamIndex(FormatCtx);
if (AudioStreamIndex < 0) then
begin
- Log.LogError('FindAudioStreamIndex: No Audio-stream found "' + Filename + '"', 'UAudio_FFmpeg');
+ Log.LogError('FindAudioStreamIndex: No Audio-stream found "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Close();
Exit;
end;
@@ -1117,7 +1118,7 @@ begin
Result := true;
end;
-function TAudioDecoder_FFmpeg.Open(const Filename: string): TAudioDecodeStream;
+function TAudioDecoder_FFmpeg.Open(const Filename: IPath): TAudioDecodeStream;
var
Stream: TFFmpegDecodeStream;
begin
diff --git a/src/media/UAudioInput_Bass.pas b/src/media/UAudioInput_Bass.pas
index ad6c3818..9d4417f1 100644
--- a/src/media/UAudioInput_Bass.pas
+++ b/src/media/UAudioInput_Bass.pas
@@ -489,6 +489,11 @@ end;
function TAudioInput_Bass.InitializeRecord(): boolean;
begin
BassCore := TAudioCore_Bass.GetInstance();
+ if not BassCore.CheckVersion then
+ begin
+ Result := false;
+ Exit;
+ end;
Result := EnumDevices();
end;
diff --git a/src/media/UAudioPlaybackBase.pas b/src/media/UAudioPlaybackBase.pas
index 7d143fdc..de2d5563 100644
--- a/src/media/UAudioPlaybackBase.pas
+++ b/src/media/UAudioPlaybackBase.pas
@@ -34,7 +34,8 @@ interface
{$I switches.inc}
uses
- UMusic;
+ UMusic,
+ UPath;
type
TAudioPlaybackBase = class(TInterfacedObject, IAudioPlayback)
@@ -46,12 +47,12 @@ type
function GetLatency(): double; virtual; abstract;
// open sound or music stream (used by Open() and OpenSound())
- function OpenStream(const Filename: string): TAudioPlaybackStream;
- function OpenDecodeStream(const Filename: string): TAudioDecodeStream;
+ function OpenStream(const Filename: IPath): TAudioPlaybackStream;
+ function OpenDecodeStream(const Filename: IPath): TAudioDecodeStream;
public
function GetName: string; virtual; abstract;
- function Open(const Filename: string): boolean; // true if succeed
+ function Open(const Filename: IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -79,7 +80,7 @@ type
function Length: real;
// Sounds
- function OpenSound(const Filename: string): TAudioPlaybackStream;
+ function OpenSound(const Filename: IPath): TAudioPlaybackStream;
procedure PlaySound(Stream: TAudioPlaybackStream);
procedure StopSound(Stream: TAudioPlaybackStream);
@@ -108,7 +109,7 @@ begin
Result := true;
end;
-function TAudioPlaybackBase.Open(const Filename: string): boolean;
+function TAudioPlaybackBase.Open(const Filename: IPath): boolean;
begin
// free old MusicStream
MusicStream.Free;
@@ -130,7 +131,7 @@ begin
FreeAndNil(MusicStream);
end;
-function TAudioPlaybackBase.OpenDecodeStream(const Filename: String): TAudioDecodeStream;
+function TAudioPlaybackBase.OpenDecodeStream(const Filename: IPath): TAudioDecodeStream;
var
i: integer;
begin
@@ -140,7 +141,7 @@ begin
if (assigned(Result)) then
begin
Log.LogInfo('Using decoder ' + IAudioDecoder(AudioDecoders[i]).GetName() +
- ' for "' + Filename + '"', 'TAudioPlaybackBase.OpenDecodeStream');
+ ' for "' + Filename.ToNative + '"', 'TAudioPlaybackBase.OpenDecodeStream');
Exit;
end;
end;
@@ -157,7 +158,7 @@ begin
SourceStream.Free;
end;
-function TAudioPlaybackBase.OpenStream(const Filename: string): TAudioPlaybackStream;
+function TAudioPlaybackBase.OpenStream(const Filename: IPath): TAudioPlaybackStream;
var
PlaybackStream: TAudioPlaybackStream;
DecodeStream: TAudioDecodeStream;
@@ -169,7 +170,7 @@ begin
DecodeStream := OpenDecodeStream(Filename);
if (not assigned(DecodeStream)) then
begin
- Log.LogStatus('Could not open "' + Filename + '"', 'TAudioPlayback_Bass.OpenStream');
+ Log.LogStatus('Could not open "' + Filename.ToNative + '"', 'TAudioPlayback_Bass.OpenStream');
Exit;
end;
@@ -283,7 +284,7 @@ begin
Result := 0;
end;
-function TAudioPlaybackBase.OpenSound(const Filename: string): TAudioPlaybackStream;
+function TAudioPlaybackBase.OpenSound(const Filename: IPath): TAudioPlaybackStream;
begin
Result := OpenStream(Filename);
end;
diff --git a/src/media/UAudioPlayback_Bass.pas b/src/media/UAudioPlayback_Bass.pas
index 923c1d7b..1d7a44dc 100644
--- a/src/media/UAudioPlayback_Bass.pas
+++ b/src/media/UAudioPlayback_Bass.pas
@@ -684,9 +684,11 @@ end;
function TAudioPlayback_Bass.InitializePlayback(): boolean;
begin
- result := false;
+ Result := false;
BassCore := TAudioCore_Bass.GetInstance();
+ if not BassCore.CheckVersion then
+ Exit;
EnumDevices();
@@ -706,7 +708,7 @@ begin
//BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10);
//BASS_SetConfig(BASS_CONFIG_BUFFER, 100);
- result := true;
+ Result := true;
end;
function TAudioPlayback_Bass.FinalizePlayback(): boolean;
diff --git a/src/media/UMediaCore_FFmpeg.pas b/src/media/UMediaCore_FFmpeg.pas
index 9ad19a5b..b4951fe1 100644
--- a/src/media/UMediaCore_FFmpeg.pas
+++ b/src/media/UMediaCore_FFmpeg.pas
@@ -34,12 +34,16 @@ interface
{$I switches.inc}
uses
- UMusic,
+ Classes,
+ ctypes,
+ sdl,
avcodec,
avformat,
avutil,
+ avio,
+ UMusic,
ULog,
- sdl;
+ UPath;
type
PPacketQueue = ^TPacketQueue;
@@ -97,12 +101,29 @@ implementation
uses
SysUtils;
+function FFmpegStreamOpen(h: PURLContext; filename: PChar; flags: cint): cint; cdecl; forward;
+function FFmpegStreamRead(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl; forward;
+function FFmpegStreamWrite(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl; forward;
+function FFmpegStreamSeek(h: PURLContext; pos: int64; whence: cint): int64; cdecl; forward;
+function FFmpegStreamClose(h: PURLContext): cint; cdecl; forward;
+
+const
+ UTF8FileProtocol: TURLProtocol = (
+ name: 'ufile';
+ url_open: FFmpegStreamOpen;
+ url_read: FFmpegStreamRead;
+ url_write: FFmpegStreamWrite;
+ url_seek: FFmpegStreamSeek;
+ url_close: FFmpegStreamClose;
+ );
+
var
Instance: TMediaCore_FFmpeg;
constructor TMediaCore_FFmpeg.Create();
begin
inherited;
+ av_register_protocol(@UTF8FileProtocol);
AVCodecLock := SDL_CreateMutex();
end;
@@ -220,6 +241,105 @@ begin
Result := true;
end;
+
+{**
+ * UTF-8 Filename wrapper based on:
+ * http://www.mail-archive.com/libav-user@mplayerhq.hu/msg02460.html
+ *}
+
+function FFmpegStreamOpen(h: PURLContext; filename: PChar; flags: cint): cint; cdecl;
+var
+ Stream: TStream;
+ Mode: word;
+ ProtPrefix: string;
+ FilePath: IPath;
+begin
+ // check for protocol prefix ('ufile:') and strip it
+ ProtPrefix := Format('%s:', [UTF8FileProtocol.name]);
+ if (StrLComp(filename, PChar(ProtPrefix), Length(ProtPrefix)) = 0) then
+ begin
+ Inc(filename, Length(ProtPrefix));
+ end;
+
+ FilePath := Path(filename);
+
+ if ((flags and URL_RDWR) <> 0) then
+ Mode := fmCreate
+ else if ((flags and URL_WRONLY) <> 0) then
+ Mode := fmCreate // TODO: fmCreate is Read+Write -> reopen with fmOpenWrite
+ else
+ Mode := fmOpenRead;
+
+ Result := 0;
+
+ try
+ Stream := TBinaryFileStream.Create(FilePath, Mode);
+ h.priv_data := Stream;
+ except
+ Result := AVERROR_NOENT;
+ end;
+end;
+
+function FFmpegStreamRead(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl;
+var
+ Stream: TStream;
+begin
+ Stream := TStream(h.priv_data);
+ if (Stream = nil) then
+ raise EInvalidContainer.Create('FFmpegStreamRead on nil');
+ try
+ Result := Stream.Read(buf[0], size);
+ except
+ Result := -1;
+ end;
+end;
+
+function FFmpegStreamWrite(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl;
+var
+ Stream: TStream;
+begin
+ Stream := TStream(h.priv_data);
+ if (Stream = nil) then
+ raise EInvalidContainer.Create('FFmpegStreamWrite on nil');
+ try
+ Result := Stream.Write(buf[0], size);
+ except
+ Result := -1;
+ end;
+end;
+
+function FFmpegStreamSeek(h: PURLContext; pos: int64; whence: cint): int64; cdecl;
+var
+ Stream : TStream;
+ Origin : TSeekOrigin;
+begin
+ Stream := TStream(h.priv_data);
+ if (Stream = nil) then
+ raise EInvalidContainer.Create('FFmpegStreamSeek on nil');
+ case whence of
+ 0 {SEEK_SET}: Origin := soBeginning;
+ 1 {SEEK_CUR}: Origin := soCurrent;
+ 2 {SEEK_END}: Origin := soEnd;
+ AVSEEK_SIZE: begin
+ Result := Stream.Size;
+ Exit;
+ end
+ else
+ Origin := soBeginning;
+ end;
+ Result := Stream.Seek(pos, Origin);
+end;
+
+function FFmpegStreamClose(h: PURLContext): cint; cdecl;
+var
+ Stream : TStream;
+begin
+ Stream := TStream(h.priv_data);
+ Stream.Free;
+ Result := 0;
+end;
+
+
{ TPacketQueue }
constructor TPacketQueue.Create();
diff --git a/src/media/UMedia_dummy.pas b/src/media/UMedia_dummy.pas
index 7558dd0b..25e94724 100644
--- a/src/media/UMedia_dummy.pas
+++ b/src/media/UMedia_dummy.pas
@@ -36,9 +36,10 @@ interface
implementation
uses
- SysUtils,
- math,
- UMusic;
+ SysUtils,
+ math,
+ UMusic,
+ UPath;
type
TMedia_dummy = class( TInterfacedObject, IVideoPlayback, IVideoVisualization, IAudioPlayback, IAudioInput )
@@ -51,7 +52,7 @@ type
function Init(): boolean;
function Finalize(): boolean;
- function Open(const aFileName : string): boolean; // true if succeed
+ function Open(const aFileName: IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -88,7 +89,7 @@ type
function Finished: boolean;
function Length: real;
- function OpenSound(const Filename: string): TAudioPlaybackStream;
+ function OpenSound(const Filename: IPath): TAudioPlaybackStream;
procedure CloseSound(var PlaybackStream: TAudioPlaybackStream);
procedure PlaySound(stream: TAudioPlaybackStream);
procedure StopSound(stream: TAudioPlaybackStream);
@@ -125,7 +126,7 @@ begin
Result := true;
end;
-function TMedia_dummy.Open(const aFileName : string): boolean; // true if succeed
+function TMedia_dummy.Open(const aFileName : IPath): boolean; // true if succeed
begin
Result := false;
end;
@@ -236,7 +237,7 @@ begin
Result := 60;
end;
-function TMedia_dummy.OpenSound(const Filename: string): TAudioPlaybackStream;
+function TMedia_dummy.OpenSound(const Filename: IPath): TAudioPlaybackStream;
begin
Result := nil;
end;
diff --git a/src/media/UVideo.pas b/src/media/UVideo.pas
index f55690b2..8d441e6c 100644
--- a/src/media/UVideo.pas
+++ b/src/media/UVideo.pas
@@ -69,8 +69,9 @@ type
implementation
uses
+ SysUtils,
+ Math,
SDL,
- textgl,
avcodec,
avformat,
avutil,
@@ -79,17 +80,17 @@ uses
{$IFDEF UseSWScale}
swscale,
{$ENDIF}
- UMediaCore_FFmpeg,
- math,
gl,
glext,
- SysUtils,
+ textgl,
+ UMediaCore_FFmpeg,
UCommon,
UConfig,
ULog,
UMusic,
UGraphicClasses,
- UGraphic;
+ UGraphic,
+ UPath;
const
{$IFDEF PIXEL_FMT_BGR}
@@ -154,7 +155,7 @@ type
function Init(): boolean;
function Finalize: boolean;
- function Open(const aFileName : string): boolean; // true if succeed
+ function Open(const FileName : IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -252,7 +253,7 @@ begin
fAspectCorrection := acoCrop;
end;
-function TVideoPlayback_FFmpeg.Open(const aFileName : string): boolean; // true if succeed
+function TVideoPlayback_FFmpeg.Open(const FileName : IPath): boolean; // true if succeed
var
errnum: Integer;
AudioStreamIndex: integer;
@@ -261,10 +262,11 @@ begin
Reset();
- errnum := av_open_input_file(fFormatContext, PChar(aFileName), nil, 0, nil);
+ // use custom 'ufile' protocol for UTF-8 support
+ errnum := av_open_input_file(fFormatContext, PAnsiChar('ufile:'+FileName.ToUTF8), nil, 0, nil);
if (errnum <> 0) then
begin
- Log.LogError('Failed to open file "'+aFileName+'" ('+FFmpegCore.GetErrorString(errnum)+')');
+ Log.LogError('Failed to open file "'+ FileName.ToNative +'" ('+FFmpegCore.GetErrorString(errnum)+')');
Exit;
end;
@@ -434,7 +436,7 @@ begin
fAVFrame := nil;
fAVFrameRGB := nil;
fFrameBuffer := nil;
-
+
if (fCodecContext <> nil) then
begin
// avcodec_close() is not thread-safe
diff --git a/src/media/UVisualizer.pas b/src/media/UVisualizer.pas
index 37e0268a..b25d68a9 100644
--- a/src/media/UVisualizer.pas
+++ b/src/media/UVisualizer.pas
@@ -77,6 +77,7 @@ uses
UGraphic,
UMain,
UConfig,
+ UPath,
ULog;
{$IF PROJECTM_VERSION < 1000000} // < 1.0
@@ -130,7 +131,7 @@ type
function Init(): boolean;
function Finalize(): boolean;
- function Open(const aFileName : string): boolean; // true if succeed
+ function Open(const aFileName: IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -183,7 +184,7 @@ begin
Result := true;
end;
-function TVideoPlayback_ProjectM.Open(const aFileName : string): boolean; // true if succeed
+function TVideoPlayback_ProjectM.Open(const aFileName: IPath): boolean; // true if succeed
begin
Result := false;
end;
diff --git a/src/menu/UDisplay.pas b/src/menu/UDisplay.pas
index f2eb2ced..6f29d2e1 100644
--- a/src/menu/UDisplay.pas
+++ b/src/menu/UDisplay.pas
@@ -36,10 +36,11 @@ interface
uses
UCommon,
SDL,
- UMenu,
gl,
glu,
- SysUtils;
+ SysUtils,
+ UMenu,
+ UPath;
type
TDisplay = class
@@ -123,7 +124,8 @@ uses
UMain,
UTexture,
UTime,
- UPath;
+ ULanguage,
+ UPathUtils;
constructor TDisplay.Create;
var
@@ -219,6 +221,8 @@ begin
//popup mod
if (ScreenPopupError <> nil) and ScreenPopupError.Visible then
ScreenPopupError.Draw
+ else if (ScreenPopupInfo <> nil) and ScreenPopupInfo.Visible then
+ ScreenPopupInfo.Draw
else if (ScreenPopupCheck <> nil) and ScreenPopupCheck.Visible then
ScreenPopupCheck.Draw;
@@ -268,7 +272,7 @@ begin
// blackscreen-hack
if not BlackScreen then
- NextScreen.onShow;
+ NextScreen.OnShow;
// update fade state
LastFadeTime := SDL_GetTicks();
@@ -328,7 +332,7 @@ begin
NextScreen := nil;
if not BlackScreen then
begin
- CurrentScreen.onShowFinish;
+ CurrentScreen.OnShowFinish;
CurrentScreen.ShowFinish := true;
end
else
@@ -504,49 +508,49 @@ end;
procedure TDisplay.SaveScreenShot;
var
Num: integer;
- FileName: string;
+ FileName: IPath;
+ Prefix: UTF8String;
ScreenData: PChar;
Surface: PSDL_Surface;
Success: boolean;
Align: integer;
RowSize: integer;
begin
-// Exit if Screenshot-path does not exist or read-only
- if (ScreenshotsPath = '') then
+ // Exit if Screenshot-path does not exist or read-only
+ if (ScreenshotsPath.IsUnset) then
Exit;
for Num := 1 to 9999 do
begin
- FileName := IntToStr(Num);
- while Length(FileName) < 4 do
- FileName := '0' + FileName;
- FileName := ScreenshotsPath + 'screenshot' + FileName + '.png';
- if not FileExists(FileName) then
- break
+ // fill prefix to 4 digits with leading '0', e.g. '0001'
+ Prefix := Format('screenshot%.4d', [Num]);
+ FileName := ScreenshotsPath.Append(Prefix + '.png');
+ if not FileName.Exists() then
+ break;
end;
-// we must take the row-alignment (4byte by default) into account
+ // we must take the row-alignment (4byte by default) into account
glGetIntegerv(GL_PACK_ALIGNMENT, @Align);
-// calc aligned row-size
+ // calc aligned row-size
RowSize := ((ScreenW*3 + (Align-1)) div Align) * Align;
GetMem(ScreenData, RowSize * ScreenH);
glReadPixels(0, 0, ScreenW, ScreenH, GL_RGB, GL_UNSIGNED_BYTE, ScreenData);
-// on big endian machines (powerpc) this may need to be changed to
-// Needs to be tests. KaMiSchi Sept 2008
-// in this case one may have to add " glext, " to the list of used units
-// glReadPixels(0, 0, ScreenW, ScreenH, GL_BGR, GL_UNSIGNED_BYTE, ScreenData);
+ // on big endian machines (powerpc) this may need to be changed to
+ // Needs to be tests. KaMiSchi Sept 2008
+ // in this case one may have to add " glext, " to the list of used units
+ // glReadPixels(0, 0, ScreenW, ScreenH, GL_BGR, GL_UNSIGNED_BYTE, ScreenData);
Surface := SDL_CreateRGBSurfaceFrom(
ScreenData, ScreenW, ScreenH, 24, RowSize,
$0000FF, $00FF00, $FF0000, 0);
-// Success := WriteJPGImage(FileName, Surface, 95);
-// Success := WriteBMPImage(FileName, Surface);
+ // Success := WriteJPGImage(FileName, Surface, 95);
+ // Success := WriteBMPImage(FileName, Surface);
Success := WritePNGImage(FileName, Surface);
if Success then
- ScreenPopupError.ShowPopup('Screenshot saved: ' + ExtractFileName(FileName))
+ ScreenPopupInfo.ShowPopup(Format(Language.Translate('SCREENSHOT_SAVED'), [FileName.GetName.ToUTF8()]))
else
- ScreenPopupError.ShowPopup('Screenshot failed');
+ ScreenPopupError.ShowPopup(Language.Translate('SCREENSHOT_FAILED'));
SDL_FreeSurface(Surface);
FreeMem(ScreenData);
@@ -559,7 +563,7 @@ procedure TDisplay.DrawDebugInformation;
var
Ticks: cardinal;
begin
-// Some White Background for information
+ // Some White Background for information
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glColor4f(1, 1, 1, 0.5);
@@ -571,13 +575,13 @@ begin
glEnd;
glDisable(GL_BLEND);
-// set font specs
+ // set font specs
SetFontStyle(0);
SetFontSize(21);
SetFontItalic(false);
glColor4f(0, 0, 0, 1);
-// calculate fps
+ // calculate fps
Ticks := SDL_GetTicks();
if (Ticks >= NextFPSSwap) then
begin
@@ -588,17 +592,17 @@ begin
Inc(FPSCounter);
-// draw text
+ // draw text
-// fps
+ // fps
SetFontPos(695, 0);
glPrint ('FPS: ' + InttoStr(LastFPS));
-// rspeed
+ // rspeed
SetFontPos(695, 13);
glPrint ('RSpeed: ' + InttoStr(Round(1000 * TimeMid)));
-// lasterror
+ // lasterror
SetFontPos(695, 26);
glColor4f(1, 0, 0, 1);
glPrint (OSD_LastError);
diff --git a/src/menu/UMenu.pas b/src/menu/UMenu.pas
index a3f47b3d..7979e28e 100644
--- a/src/menu/UMenu.pas
+++ b/src/menu/UMenu.pas
@@ -38,6 +38,7 @@ uses
Math,
gl,
SDL,
+ UPath,
UMenuBackground,
UMenuButton,
UMenuButtonCollection,
@@ -81,8 +82,6 @@ type
//constructor Create(Back: string; W, H: integer); overload; virtual; // W and H are the number of overlaps
// interaction
- function WideCharUpperCase(wchar: WideChar) : WideString;
- function WideStringUpperCase(wstring: WideString) : WideString;
procedure AddInteraction(Typ, Num: integer);
procedure SetInteraction(Num: integer); virtual;
property Interaction: integer read SelInteraction write SetInteraction;
@@ -98,62 +97,62 @@ type
// static
function AddStatic(ThemeStatic: TThemeStatic): integer; overload;
- function AddStatic(X, Y, W, H: real; const Name: string): integer; overload;
- function AddStatic(X, Y, W, H: real; const Name: string; Typ: TTextureType): integer; overload;
- function AddStatic(X, Y, W, H: real; ColR, ColG, ColB: real; const Name: string; Typ: TTextureType): integer; overload;
- function AddStatic(X, Y, W, H, Z: real; ColR, ColG, ColB: real; const Name: string; Typ: TTextureType): integer; overload;
- function AddStatic(X, Y, W, H: real; ColR, ColG, ColB: real; const Name: string; Typ: TTextureType; Color: integer): integer; overload;
- function AddStatic(X, Y, W, H, Z: real; ColR, ColG, ColB: real; const Name: string; Typ: TTextureType; Color: integer): integer; overload;
- function AddStatic(X, Y, W, H, Z: real; ColR, ColG, ColB: real; TexX1, TexY1, TexX2, TexY2: real; const Name: string; Typ: TTextureType; Color: integer; Reflection: boolean; ReflectionSpacing: real): integer; overload;
+ function AddStatic(X, Y, W, H: real; const TexName: IPath): integer; overload;
+ function AddStatic(X, Y, W, H: real; const TexName: IPath; Typ: TTextureType): integer; overload;
+ function AddStatic(X, Y, W, H: real; ColR, ColG, ColB: real; const TexName: IPath; Typ: TTextureType): integer; overload;
+ function AddStatic(X, Y, W, H, Z: real; ColR, ColG, ColB: real; const TexName: IPath; Typ: TTextureType): integer; overload;
+ function AddStatic(X, Y, W, H: real; ColR, ColG, ColB: real; const TexName: IPath; Typ: TTextureType; Color: integer): integer; overload;
+ function AddStatic(X, Y, W, H, Z: real; ColR, ColG, ColB: real; const TexName: IPath; Typ: TTextureType; Color: integer): integer; overload;
+ function AddStatic(X, Y, W, H, Z: real; ColR, ColG, ColB: real; TexX1, TexY1, TexX2, TexY2: real; const TexName: IPath; Typ: TTextureType; Color: integer; Reflection: boolean; ReflectionSpacing: real): integer; overload;
// text
function AddText(ThemeText: TThemeText): integer; overload;
- function AddText(X, Y: real; const Text_: string): integer; overload;
- function AddText(X, Y: real; Style: integer; Size, ColR, ColG, ColB: real; const Text: string): integer; overload;
- function AddText(X, Y, W: real; Style: integer; Size, ColR, ColG, ColB: real; Align: integer; const Text_: string; Reflection_: boolean; ReflectionSpacing_: real; Z : real): integer; overload;
+ function AddText(X, Y: real; const Text_: UTF8String): integer; overload;
+ function AddText(X, Y: real; Style: integer; Size, ColR, ColG, ColB: real; const Text: UTF8String): integer; overload;
+ function AddText(X, Y, W: real; Style: integer; Size, ColR, ColG, ColB: real; Align: integer; const Text_: UTF8String; Reflection_: boolean; ReflectionSpacing_: real; Z : real): integer; overload;
// button
procedure SetButtonLength(Length: cardinal); //Function that Set Length of Button Array in one Step instead of register new Memory for every Button
function AddButton(ThemeButton: TThemeButton): integer; overload;
- function AddButton(X, Y, W, H: real; const Name: string): integer; overload;
- function AddButton(X, Y, W, H: real; const Name: string; Typ: TTextureType; Reflection: boolean): integer; overload;
- function AddButton(X, Y, W, H, ColR, ColG, ColB, Int, DColR, DColG, DColB, DInt: real; const Name: string; Typ: TTextureType; Reflection: boolean; ReflectionSpacing, DeSelectReflectionSpacing: real): integer; overload;
+ function AddButton(X, Y, W, H: real; const TexName: IPath): integer; overload;
+ function AddButton(X, Y, W, H: real; const TexName: IPath; Typ: TTextureType; Reflection: boolean): integer; overload;
+ function AddButton(X, Y, W, H, ColR, ColG, ColB, Int, DColR, DColG, DColB, DInt: real; const TexName: IPath; Typ: TTextureType; Reflection: boolean; ReflectionSpacing, DeSelectReflectionSpacing: real): integer; overload;
procedure ClearButtons;
- procedure AddButtonText(AddX, AddY: real; const AddText: string); overload;
- procedure AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; const AddText: string); overload;
- procedure AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: string); overload;
- procedure AddButtonText(CustomButton: TButton; AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: string); overload;
+ procedure AddButtonText(AddX, AddY: real; const AddText: UTF8String); overload;
+ procedure AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; const AddText: UTF8String); overload;
+ procedure AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: UTF8String); overload;
+ procedure AddButtonText(CustomButton: TButton; AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: UTF8String); overload;
// select slide
- function AddSelectSlide(ThemeSelectS: TThemeSelectSlide; var Data: integer; Values: array of string): integer; overload;
+ function AddSelectSlide(ThemeSelectS: TThemeSelectSlide; var Data: integer; const Values: array of UTF8String): integer; overload;
function AddSelectSlide(X, Y, W, H, SkipX, SBGW, ColR, ColG, ColB, Int, DColR, DColG, DColB, DInt,
TColR, TColG, TColB, TInt, TDColR, TDColG, TDColB, TDInt,
SBGColR, SBGColG, SBGColB, SBGInt, SBGDColR, SBGDColG, SBGDColB, SBGDInt,
STColR, STColG, STColB, STInt, STDColR, STDColG, STDColB, STDInt: real;
- const Name: string; Typ: TTextureType; const SBGName: string; SBGTyp: TTextureType;
- const Caption: string; var Data: integer): integer; overload;
- procedure AddSelectSlideOption(const AddText: string); overload;
- procedure AddSelectSlideOption(SelectNo: cardinal; const AddText: string); overload;
- procedure UpdateSelectSlideOptions(ThemeSelectSlide: TThemeSelectSlide; SelectNum: integer; Values: array of string; var Data: integer);
+ const TexName: IPath; Typ: TTextureType; const SBGName: IPath; SBGTyp: TTextureType;
+ const Caption: UTF8String; var Data: integer): integer; overload;
+ procedure AddSelectSlideOption(const AddText: UTF8String); overload;
+ procedure AddSelectSlideOption(SelectNo: cardinal; const AddText: UTF8String); overload;
+ procedure UpdateSelectSlideOptions(ThemeSelectSlide: TThemeSelectSlide; SelectNum: integer; const Values: array of UTF8String; var Data: integer);
// function AddWidget(X, Y : UInt16; WidgetSrc : PSDL_Surface): Int16;
// procedure ClearWidgets(MinNumber : Int16);
procedure FadeTo(Screen: PMenu); overload;
procedure FadeTo(Screen: PMenu; aSound: TAudioPlaybackStream); overload;
//popup hack
- procedure CheckFadeTo(Screen: PMenu; msg: string);
+ procedure CheckFadeTo(Screen: PMenu; Msg: UTF8String);
function DrawBG: boolean; virtual;
function DrawFG: boolean; virtual;
function Draw: boolean; virtual;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown : boolean): boolean; virtual;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown : boolean): boolean; virtual;
function ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean; virtual;
function InRegion(X1, Y1, W, H, X, Y: real): boolean;
function InteractAt(X, Y: real): integer;
function CollectionAt(X, Y: real): integer;
- procedure onShow; virtual;
- procedure onShowFinish; virtual;
- procedure onHide; virtual;
+ procedure OnShow; virtual;
+ procedure OnShowFinish; virtual;
+ procedure OnHide; virtual;
procedure SetAnimationProgress(Progress: real); virtual;
@@ -391,7 +390,7 @@ begin
begin
//At first some intelligent try to decide which BG to load
- FileExt := lowercase(ExtractFileExt(Skin.GetTextureFileName(ThemedSettings.Tex)));
+ FileExt := LowerCase(Skin.GetTextureFileName(ThemedSettings.Tex).GetExtension.ToUTF8);
if IsInArray(FileExt, SUPPORTED_EXTS_BACKGROUNDTEXTURE) then
TryBGCreate(TMenuBackgroundTexture)
@@ -599,29 +598,29 @@ begin
ThemeStatic.Typ, $FFFFFF, ThemeStatic.Reflection, ThemeStatic.Reflectionspacing);
end;
-function TMenu.AddStatic(X, Y, W, H: real; const Name: string): integer;
+function TMenu.AddStatic(X, Y, W, H: real; const TexName: IPath): integer;
begin
- Result := AddStatic(X, Y, W, H, Name, TEXTURE_TYPE_PLAIN);
+ Result := AddStatic(X, Y, W, H, TexName, TEXTURE_TYPE_PLAIN);
end;
function TMenu.AddStatic(X, Y, W, H: real;
- ColR, ColG, ColB: real;
- const Name: string;
+ ColR, ColG, ColB: real;
+ const TexName: IPath;
Typ: TTextureType): integer;
begin
- Result := AddStatic(X, Y, W, H, ColR, ColG, ColB, Name, Typ, $FFFFFF);
+ Result := AddStatic(X, Y, W, H, ColR, ColG, ColB, TexName, Typ, $FFFFFF);
end;
function TMenu.AddStatic(X, Y, W, H, Z: real;
- ColR, ColG, ColB: real;
- const Name: string;
+ ColR, ColG, ColB: real;
+ const TexName: IPath;
Typ: TTextureType): integer;
begin
- Result := AddStatic(X, Y, W, H, Z, ColR, ColG, ColB, Name, Typ, $FFFFFF);
+ Result := AddStatic(X, Y, W, H, Z, ColR, ColG, ColB, TexName, Typ, $FFFFFF);
end;
function TMenu.AddStatic(X, Y, W, H: real;
- const Name: string;
+ const TexName: IPath;
Typ: TTextureType): integer;
var
StatNum: integer;
@@ -629,7 +628,7 @@ begin
// adds static
StatNum := Length(Static);
SetLength(Static, StatNum + 1);
- Static[StatNum] := TStatic.Create(Texture.GetTexture(Name, Typ, $FF00FF)); // new skin
+ Static[StatNum] := TStatic.Create(Texture.GetTexture(TexName, Typ, $FF00FF)); // new skin
// configures static
Static[StatNum].Texture.X := X;
@@ -642,26 +641,26 @@ end;
function TMenu.AddStatic(X, Y, W, H: real;
ColR, ColG, ColB: real;
- const Name: string;
+ const TexName: IPath;
Typ: TTextureType;
Color: integer): integer;
begin
- Result := AddStatic(X, Y, W, H, 0, ColR, ColG, ColB, Name, Typ, Color);
+ Result := AddStatic(X, Y, W, H, 0, ColR, ColG, ColB, TexName, Typ, Color);
end;
function TMenu.AddStatic(X, Y, W, H, Z: real;
ColR, ColG, ColB: real;
- const Name: string;
+ const TexName: IPath;
Typ: TTextureType;
Color: integer): integer;
begin
- Result := AddStatic(X, Y, W, H, Z, ColR, ColG, ColB, 0, 0, 1, 1, Name, Typ, Color, false, 0);
+ Result := AddStatic(X, Y, W, H, Z, ColR, ColG, ColB, 0, 0, 1, 1, TexName, Typ, Color, false, 0);
end;
function TMenu.AddStatic(X, Y, W, H, Z: real;
ColR, ColG, ColB: real;
TexX1, TexY1, TexX2, TexY2: real;
- const Name: string;
+ const TexName: IPath;
Typ: TTextureType;
Color: integer;
Reflection: boolean;
@@ -677,11 +676,11 @@ begin
if (Typ = TEXTURE_TYPE_COLORIZED) then
begin
// give encoded color to GetTexture()
- Static[StatNum] := TStatic.Create(Texture.GetTexture(Name, Typ, RGBFloatToInt(ColR, ColG, ColB)));
+ Static[StatNum] := TStatic.Create(Texture.GetTexture(TexName, Typ, RGBFloatToInt(ColR, ColG, ColB)));
end
else
begin
- Static[StatNum] := TStatic.Create(Texture.GetTexture(Name, Typ, Color)); // new skin
+ Static[StatNum] := TStatic.Create(Texture.GetTexture(TexName, Typ, Color)); // new skin
end;
// configures static
@@ -726,7 +725,7 @@ begin
ThemeText.ColR, ThemeText.ColG, ThemeText.ColB, ThemeText.Align, ThemeText.Text, ThemeText.Reflection, ThemeText.ReflectionSpacing, ThemeText.Z);
end;
-function TMenu.AddText(X, Y: real; const Text_: string): integer;
+function TMenu.AddText(X, Y: real; const Text_: UTF8String): integer;
var
TextNum: integer;
begin
@@ -739,20 +738,20 @@ end;
function TMenu.AddText(X, Y: real;
Style: integer;
- Size, ColR, ColG, ColB: real
- ; const Text: string): integer;
+ Size, ColR, ColG, ColB: real;
+ const Text: UTF8String): integer;
begin
Result := AddText(X, Y, 0, Style, Size, ColR, ColG, ColB, 0, Text, false, 0, 0);
end;
function TMenu.AddText(X, Y, W: real;
Style: integer;
- Size, ColR, ColG, ColB: real;
- Align: integer;
- const Text_: string;
- Reflection_: boolean;
- ReflectionSpacing_: real;
- Z : real): integer;
+ Size, ColR, ColG, ColB: real;
+ Align: integer;
+ const Text_: UTF8String;
+ Reflection_: boolean;
+ ReflectionSpacing_: real;
+ Z : real): integer;
var
TextNum: integer;
begin
@@ -843,18 +842,18 @@ begin
Log.LogBenchmark('====> Screen Options32', 6);
end;
-function TMenu.AddButton(X, Y, W, H: real; const Name: string): integer;
+function TMenu.AddButton(X, Y, W, H: real; const TexName: IPath): integer;
begin
- Result := AddButton(X, Y, W, H, Name, TEXTURE_TYPE_PLAIN, false);
+ Result := AddButton(X, Y, W, H, TexName, TEXTURE_TYPE_PLAIN, false);
end;
-function TMenu.AddButton(X, Y, W, H: real; const Name: string; Typ: TTextureType; Reflection: boolean): integer;
+function TMenu.AddButton(X, Y, W, H: real; const TexName: IPath; Typ: TTextureType; Reflection: boolean): integer;
begin
- Result := AddButton(X, Y, W, H, 1, 1, 1, 1, 1, 1, 1, 0.5, Name, TEXTURE_TYPE_PLAIN, Reflection, 15, 15);
+ Result := AddButton(X, Y, W, H, 1, 1, 1, 1, 1, 1, 1, 0.5, TexName, TEXTURE_TYPE_PLAIN, Reflection, 15, 15);
end;
function TMenu.AddButton(X, Y, W, H, ColR, ColG, ColB, Int, DColR, DColG, DColB, DInt: real;
- const Name: string;
+ const TexName: IPath;
Typ: TTextureType;
Reflection: boolean;
ReflectionSpacing, DeSelectReflectionSpacing: real): integer;
@@ -876,12 +875,12 @@ begin
if (Typ = TEXTURE_TYPE_COLORIZED) then
begin
// give encoded color to GetTexture()
- Button[Result] := TButton.Create(Texture.GetTexture(Name, Typ, RGBFloatToInt(ColR, ColG, ColB)),
- Texture.GetTexture(Name, Typ, RGBFloatToInt(DColR, DColG, DColB)));
+ Button[Result] := TButton.Create(Texture.GetTexture(TexName, Typ, RGBFloatToInt(ColR, ColG, ColB)),
+ Texture.GetTexture(TexName, Typ, RGBFloatToInt(DColR, DColG, DColB)));
end
else
begin
- Button[Result] := TButton.Create(Texture.GetTexture(Name, Typ));
+ Button[Result] := TButton.Create(Texture.GetTexture(TexName, Typ));
end;
// configures button
@@ -935,11 +934,11 @@ var
J: integer;
begin
// We don't forget about newly implemented static for nice skin ...
- for J := 0 to Length(Static) - 1 do
+ for J := 0 to High(Static) do
Static[J].Draw;
// ... and slightly implemented menutext unit
- for J := 0 to Length(Text) - 1 do
+ for J := 0 to High(Text) do
Text[J].Draw;
// Draw all ButtonCollections
@@ -947,10 +946,10 @@ begin
ButtonCollection[J].Draw;
// Second, we draw all of our buttons
- for J := 0 to Length(Button) - 1 do
+ for J := 0 to High(Button) do
Button[J].Draw;
- for J := 0 to Length(SelectsS) - 1 do
+ for J := 0 to High(SelectsS) do
SelectsS[J].Draw;
// Third, we draw all our widgets
@@ -1178,21 +1177,41 @@ begin
AudioPlayback.PlaySound( aSound );
end;
+procedure OnSaveEncodingError(Value: boolean; Data: Pointer);
+begin
+ Display.CheckOK := Value;
+ if (Value) then
+ begin
+ //Hack to Finish Singscreen correct on Exit with Q Shortcut
+ if (Display.NextScreenWithCheck = nil) then
+ begin
+ if (Display.CurrentScreen = @ScreenSing) then
+ ScreenSing.Finish
+ else if (Display.CurrentScreen = @ScreenSingModi) then
+ ScreenSingModi.Finish;
+ end;
+ end
+ else
+ begin
+ Display.NextScreenWithCheck := nil;
+ end;
+end;
+
//popup hack
-procedure TMenu.CheckFadeTo(Screen: PMenu; msg: string);
+procedure TMenu.CheckFadeTo(Screen: PMenu; Msg: UTF8String);
begin
Display.Fade := 0;
Display.NextScreenWithCheck := Screen;
Display.CheckOK := false;
- ScreenPopupCheck.ShowPopup(msg);
+ ScreenPopupCheck.ShowPopup(msg, OnSaveEncodingError, nil, false);
end;
-procedure TMenu.AddButtonText(AddX, AddY: real; const AddText: string);
+procedure TMenu.AddButtonText(AddX, AddY: real; const AddText: UTF8String);
begin
AddButtonText(AddX, AddY, 1, 1, 1, AddText);
end;
-procedure TMenu.AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; const AddText: string);
+procedure TMenu.AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; const AddText: UTF8String);
var
Il: integer;
begin
@@ -1208,7 +1227,7 @@ begin
end;
end;
-procedure TMenu.AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: string);
+procedure TMenu.AddButtonText(AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: UTF8String);
var
Il: integer;
begin
@@ -1227,7 +1246,7 @@ begin
end;
end;
-procedure TMenu.AddButtonText(CustomButton: TButton; AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: string);
+procedure TMenu.AddButtonText(CustomButton: TButton; AddX, AddY: real; ColR, ColG, ColB: real; Font: integer; Size: integer; Align: integer; const AddText: UTF8String);
var
Il: integer;
begin
@@ -1246,7 +1265,7 @@ begin
end;
end;
-function TMenu.AddSelectSlide(ThemeSelectS: TThemeSelectSlide; var Data: integer; Values: array of string): integer;
+function TMenu.AddSelectSlide(ThemeSelectS: TThemeSelectSlide; var Data: integer; const Values: array of UTF8String): integer;
var
SO: integer;
begin
@@ -1283,8 +1302,8 @@ function TMenu.AddSelectSlide(X, Y, W, H, SkipX, SBGW, ColR, ColG, ColB, Int, DC
TColR, TColG, TColB, TInt, TDColR, TDColG, TDColB, TDInt,
SBGColR, SBGColG, SBGColB, SBGInt, SBGDColR, SBGDColG, SBGDColB, SBGDInt,
STColR, STColG, STColB, STInt, STDColR, STDColG, STDColB, STDInt: real;
- const Name: string; Typ: TTextureType; const SBGName: string; SBGTyp: TTextureType;
- const Caption: string; var Data: integer): integer;
+ const TexName: IPath; Typ: TTextureType; const SBGName: IPath; SBGTyp: TTextureType;
+ const Caption: UTF8String; var Data: integer): integer;
var
S: integer;
I: integer;
@@ -1294,9 +1313,9 @@ begin
SelectsS[S] := TSelectSlide.Create;
if (Typ = TEXTURE_TYPE_COLORIZED) then
- SelectsS[S].Texture := Texture.GetTexture(Name, Typ, RGBFloatToInt(ColR, ColG, ColB))
+ SelectsS[S].Texture := Texture.GetTexture(TexName, Typ, RGBFloatToInt(ColR, ColG, ColB))
else
- SelectsS[S].Texture := Texture.GetTexture(Name, Typ);
+ SelectsS[S].Texture := Texture.GetTexture(TexName, Typ);
SelectsS[S].X := X;
SelectsS[S].Y := Y;
SelectsS[S].W := W;
@@ -1414,12 +1433,12 @@ begin
Result := S;
end;
-procedure TMenu.AddSelectSlideOption(const AddText: string);
+procedure TMenu.AddSelectSlideOption(const AddText: UTF8String);
begin
AddSelectSlideOption(High(SelectsS), AddText);
end;
-procedure TMenu.AddSelectSlideOption(SelectNo: cardinal; const AddText: string);
+procedure TMenu.AddSelectSlideOption(SelectNo: cardinal; const AddText: UTF8String);
var
SO: integer;
begin
@@ -1435,7 +1454,8 @@ begin
}
end;
-procedure TMenu.UpdateSelectSlideOptions(ThemeSelectSlide: TThemeSelectSlide; SelectNum: integer; Values: array of string; var Data: integer);
+procedure TMenu.UpdateSelectSlideOptions(ThemeSelectSlide: TThemeSelectSlide;
+ SelectNum: integer; const Values: array of UTF8String; var Data: integer);
var
SO: integer;
begin
@@ -1560,7 +1580,7 @@ begin
AddStatic(X+2, Y+2, W-4, H-4, 1, 1, 1, Skin.GetTextureFileName('MainBar'), TEXTURE_TYPE_COLORIZED);
end;
-procedure TMenu.onShow;
+procedure TMenu.OnShow;
begin
// FIXME: this needs some work. First, there should be a variable like
// VideoBackground so we can check whether a video-background is enabled or not.
@@ -1589,57 +1609,18 @@ begin
Background.OnShow;
end;
-procedure TMenu.onShowFinish;
+procedure TMenu.OnShowFinish;
begin
// nothing
end;
-(*
- * Wrapper for WideUpperCase. Needed because some plattforms have problems with
- * unicode support.
- *)
-function TMenu.WideCharUpperCase(wchar: WideChar) : WideString;
-begin
- // On Linux and MacOSX the cwstring unit is necessary for Unicode function-calls.
- // Otherwise you will get an EIntOverflow exception (thrown by unimplementedwidestring()).
- // The Unicode manager cwstring does not work with MacOSX at the moment because
- // of missing references to iconv. So we have to use Ansi... for the moment.
-
- // cwstring crashes in FPC 2.2.2 so do not use the cwstring stuff
- {.$IFNDEF DARWIN}
- {$IFDEF NOIGNORE}
- // The FPC implementation of WideUpperCase returns nil if wchar is #0 (e.g. if an arrow key is pressed)
- if (wchar <> #0) then
- Result := WideUpperCase(wchar)
- else
- Result := #0;
- {$ELSE}
- Result := AnsiUpperCase(wchar)
- {$ENDIF}
-end;
-
-(*
- * Wrapper for WideUpperCase. Needed because some plattforms have problems with
- * unicode support.
- *)
-function TMenu.WideStringUpperCase(wstring: WideString) : WideString;
-begin
- // cwstring crashes in FPC 2.2.2 so do not use the cwstring stuff
- {.$IFNDEF DARWIN}
- {$IFDEF NOIGNORE}
- Result := WideUpperCase(wstring)
- {$ELSE}
- Result := AnsiUpperCase(wstring);
- {$ENDIF}
-end;
-
-procedure TMenu.onHide;
+procedure TMenu.OnHide;
begin
// nothing
Background.OnFinish;
end;
-function TMenu.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TMenu.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
// nothing
Result := true;
@@ -1657,7 +1638,7 @@ begin
if RightMbESC and (MouseButton = SDL_BUTTON_RIGHT) and BtnDown then
begin
//if RightMbESC is set, send ESC keypress
- Result:=ParseInput(SDLK_ESCAPE, #0, true);
+ Result:=ParseInput(SDLK_ESCAPE, 0, true);
end;
nBut := InteractAt(X, Y);
@@ -1669,18 +1650,18 @@ begin
if (MouseButton = SDL_BUTTON_LEFT) and BtnDown then
begin
//click button
- Result:=ParseInput(SDLK_RETURN, #0, true);
+ Result:=ParseInput(SDLK_RETURN, 0, true);
end;
if (Interactions[nBut].Typ = iSelectS) then
begin
//forward/backward in select slide with mousewheel
if (MouseButton = SDL_BUTTON_WHEELDOWN) and BtnDown then
begin
- ParseInput(SDLK_RIGHT, #0, true);
+ ParseInput(SDLK_RIGHT, 0, true);
end;
if (MouseButton = SDL_BUTTON_WHEELUP) and BtnDown then
begin
- ParseInput(SDLK_LEFT, #0, true);
+ ParseInput(SDLK_LEFT, 0, true);
end;
end;
end
diff --git a/src/menu/UMenuBackground.pas b/src/menu/UMenuBackground.pas
index c85f0806..0e2e63a6 100644
--- a/src/menu/UMenuBackground.pas
+++ b/src/menu/UMenuBackground.pas
@@ -1,83 +1,83 @@
-{* 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 UMenuBackground;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- SysUtils,
- UThemes;
-
-//TMenuBackground - abstraction class for MenuBackgrounds
-//this is a class, not an interface because of the constructors
-//and destructors
-//--------
-
-type
- EMenuBackgroundError = class(Exception);
- TMenuBackground = class
- constructor Create(const ThemedSettings: TThemeBackground); virtual;
- procedure OnShow; virtual;
- procedure Draw; virtual;
- procedure OnFinish; virtual;
- destructor Destroy; override;
- end;
- cMenuBackground = class of TMenuBackground;
-
-implementation
-
-constructor TMenuBackground.Create(const ThemedSettings: TThemeBackground);
-begin
- inherited Create;
-end;
-
-destructor TMenuBackground.Destroy;
-begin
- inherited;
-end;
-
-procedure TMenuBackground.OnShow;
-begin
-
-end;
-
-procedure TMenuBackground.OnFinish;
-begin
-
-end;
-
-procedure TMenuBackground.Draw;
-begin
-
-end;
-
-end.
+{* 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 UMenuBackground;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ SysUtils,
+ UThemes;
+
+//TMenuBackground - abstraction class for MenuBackgrounds
+//this is a class, not an interface because of the constructors
+//and destructors
+//--------
+
+type
+ EMenuBackgroundError = class(Exception);
+ TMenuBackground = class
+ constructor Create(const ThemedSettings: TThemeBackground); virtual;
+ procedure OnShow; virtual;
+ procedure Draw; virtual;
+ procedure OnFinish; virtual;
+ destructor Destroy; override;
+ end;
+ cMenuBackground = class of TMenuBackground;
+
+implementation
+
+constructor TMenuBackground.Create(const ThemedSettings: TThemeBackground);
+begin
+ inherited Create;
+end;
+
+destructor TMenuBackground.Destroy;
+begin
+ inherited;
+end;
+
+procedure TMenuBackground.OnShow;
+begin
+
+end;
+
+procedure TMenuBackground.OnFinish;
+begin
+
+end;
+
+procedure TMenuBackground.Draw;
+begin
+
+end;
+
+end.
diff --git a/src/menu/UMenuBackgroundColor.pas b/src/menu/UMenuBackgroundColor.pas
index a5c2a70a..45b58c1e 100644
--- a/src/menu/UMenuBackgroundColor.pas
+++ b/src/menu/UMenuBackgroundColor.pas
@@ -1,73 +1,73 @@
-{* 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 UMenuBackgroundColor;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- UThemes,
- UMenuBackground;
-
-//TMenuBackgroundColor - Background Color
-//--------
-
-type
- TMenuBackgroundColor = class (TMenuBackground)
- private
- Color: TRGB;
- public
- constructor Create(const ThemedSettings: TThemeBackground); override;
- procedure Draw; override;
- end;
-
-implementation
-uses
- gl,
- glext,
- UGraphic;
-
-constructor TMenuBackgroundColor.Create(const ThemedSettings: TThemeBackground);
-begin
- inherited;
- Color := ThemedSettings.Color;
-end;
-
-procedure TMenuBackgroundColor.Draw;
-begin
- if (ScreenAct = 1) then
- begin //just clear once, even when using two screens
- glClearColor(Color.R, Color.G, Color.B, 0);
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
- end;
-end;
-
+{* 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 UMenuBackgroundColor;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ UThemes,
+ UMenuBackground;
+
+//TMenuBackgroundColor - Background Color
+//--------
+
+type
+ TMenuBackgroundColor = class (TMenuBackground)
+ private
+ Color: TRGB;
+ public
+ constructor Create(const ThemedSettings: TThemeBackground); override;
+ procedure Draw; override;
+ end;
+
+implementation
+uses
+ gl,
+ glext,
+ UGraphic;
+
+constructor TMenuBackgroundColor.Create(const ThemedSettings: TThemeBackground);
+begin
+ inherited;
+ Color := ThemedSettings.Color;
+end;
+
+procedure TMenuBackgroundColor.Draw;
+begin
+ if (ScreenAct = 1) then
+ begin //just clear once, even when using two screens
+ glClearColor(Color.R, Color.G, Color.B, 0);
+ glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+ end;
+end;
+
end. \ No newline at end of file
diff --git a/src/menu/UMenuBackgroundFade.pas b/src/menu/UMenuBackgroundFade.pas
index b61a4542..6d877baa 100644
--- a/src/menu/UMenuBackgroundFade.pas
+++ b/src/menu/UMenuBackgroundFade.pas
@@ -1,176 +1,176 @@
-{* 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 UMenuBackgroundFade;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- UThemes,
- UTexture,
- UMenuBackground;
-
-//TMenuBackgroundFade - Background Fade In for Overlay screens
-//--------
-
-type
- TMenuBackgroundFade = class (TMenuBackground)
- private
- Tex: TTexture;
- Color: TRGB;
- Alpha: real;
-
- useTexture: boolean;
-
- FadeTime: cardinal;
- public
- constructor Create(const ThemedSettings: TThemeBackground); override;
- procedure OnShow; override;
- procedure Draw; override;
- destructor Destroy; override;
- end;
-
-const
- FADEINTIME = 1500; //Time the bg fades in
-
-implementation
-uses
- sdl,
- gl,
- glext,
- USkins,
- UCommon,
- UGraphic;
-
-constructor TMenuBackgroundFade.Create(const ThemedSettings: TThemeBackground);
-var
- texFilename: string;
-begin
- inherited;
- FadeTime := 0;
-
- Color := ThemedSettings.Color;
- Alpha := ThemedSettings.Alpha;
- if (Length(ThemedSettings.Tex) > 0) then
- begin
- texFilename := Skin.GetTextureFileName(ThemedSettings.Tex);
- texFilename := AdaptFilePaths(texFilename);
- Tex := Texture.GetTexture(texFilename, TEXTURE_TYPE_PLAIN);
-
- UseTexture := (Tex.TexNum <> 0);
- end
- else
- UseTexture := false;
-
- if (not UseTexture) then
- FreeandNil(Tex);
-end;
-
-destructor TMenuBackgroundFade.Destroy;
-begin
- //Why isn't there any Tex.free method?
- {if UseTexture then
- FreeandNil(Tex); }
- inherited;
-end;
-
-procedure TMenuBackgroundFade.OnShow;
-begin
- FadeTime := SDL_GetTicks;
-end;
-
-procedure TMenuBackgroundFade.Draw;
-var
- Progress: real;
-begin
- if FadeTime = 0 then
- Progress := Alpha
- else
- Progress := Alpha * (SDL_GetTicks - FadeTime) / FADEINTIME;
-
- if Progress > Alpha then
- begin
- FadeTime := 0;
- Progress := Alpha;
- end;
-
- if (UseTexture) then
- begin //Draw Texture to Screen
- if (ScreenAct = 1) then //Clear just once when in dual screen mode
- glClear(GL_DEPTH_BUFFER_BIT);
-
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glColorRGB(Color, Progress);
- glBindTexture(GL_TEXTURE_2D, Tex.TexNum);
-
- glBegin(GL_QUADS);
- glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY1*Tex.TexH);
- glVertex2f(0, 0);
-
- glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY2*Tex.TexH);
- glVertex2f(0, 600);
-
- glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY2*Tex.TexH);
- glVertex2f(800, 600);
-
- glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY1*Tex.TexH);
- glVertex2f(800, 0);
- glEnd;
-
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
- end
- else
- begin //Clear Screen w/ progress Alpha + Color
- if (ScreenAct = 1) then //Clear just once when in dual screen mode
- glClear(GL_DEPTH_BUFFER_BIT);
-
- glDisable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glColorRGB(Color, Progress);
-
- glBegin(GL_QUADS);
- glVertex2f(0, 0);
- glVertex2f(0, 600);
- glVertex2f(800, 600);
- glVertex2f(800, 0);
- glEnd;
-
- glDisable(GL_BLEND);
- end;
-end;
-
-end.
+{* 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 UMenuBackgroundFade;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ UThemes,
+ UTexture,
+ UMenuBackground,
+ UPath;
+
+//TMenuBackgroundFade - Background Fade In for Overlay screens
+//--------
+
+type
+ TMenuBackgroundFade = class (TMenuBackground)
+ private
+ Tex: TTexture;
+ Color: TRGB;
+ Alpha: real;
+
+ useTexture: boolean;
+
+ FadeTime: cardinal;
+ public
+ constructor Create(const ThemedSettings: TThemeBackground); override;
+ procedure OnShow; override;
+ procedure Draw; override;
+ destructor Destroy; override;
+ end;
+
+const
+ FADEINTIME = 1500; //Time the bg fades in
+
+implementation
+uses
+ sdl,
+ gl,
+ glext,
+ USkins,
+ UCommon,
+ UGraphic;
+
+constructor TMenuBackgroundFade.Create(const ThemedSettings: TThemeBackground);
+var
+ texFilename: IPath;
+begin
+ inherited;
+ FadeTime := 0;
+
+ Color := ThemedSettings.Color;
+ Alpha := ThemedSettings.Alpha;
+ if (Length(ThemedSettings.Tex) > 0) then
+ begin
+ texFilename := Skin.GetTextureFileName(ThemedSettings.Tex);
+ Tex := Texture.GetTexture(texFilename, TEXTURE_TYPE_PLAIN);
+
+ UseTexture := (Tex.TexNum <> 0);
+ end
+ else
+ UseTexture := false;
+
+ if (not UseTexture) then
+ FreeandNil(Tex);
+end;
+
+destructor TMenuBackgroundFade.Destroy;
+begin
+ //Why isn't there any Tex.free method?
+ {if UseTexture then
+ FreeandNil(Tex); }
+ inherited;
+end;
+
+procedure TMenuBackgroundFade.OnShow;
+begin
+ FadeTime := SDL_GetTicks;
+end;
+
+procedure TMenuBackgroundFade.Draw;
+var
+ Progress: real;
+begin
+ if FadeTime = 0 then
+ Progress := Alpha
+ else
+ Progress := Alpha * (SDL_GetTicks - FadeTime) / FADEINTIME;
+
+ if Progress > Alpha then
+ begin
+ FadeTime := 0;
+ Progress := Alpha;
+ end;
+
+ if (UseTexture) then
+ begin //Draw Texture to Screen
+ if (ScreenAct = 1) then //Clear just once when in dual screen mode
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glColorRGB(Color, Progress);
+ glBindTexture(GL_TEXTURE_2D, Tex.TexNum);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY1*Tex.TexH);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY2*Tex.TexH);
+ glVertex2f(0, 600);
+
+ glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY2*Tex.TexH);
+ glVertex2f(800, 600);
+
+ glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY1*Tex.TexH);
+ glVertex2f(800, 0);
+ glEnd;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ end
+ else
+ begin //Clear Screen w/ progress Alpha + Color
+ if (ScreenAct = 1) then //Clear just once when in dual screen mode
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glColorRGB(Color, Progress);
+
+ glBegin(GL_QUADS);
+ glVertex2f(0, 0);
+ glVertex2f(0, 600);
+ glVertex2f(800, 600);
+ glVertex2f(800, 0);
+ glEnd;
+
+ glDisable(GL_BLEND);
+ end;
+end;
+
+end.
diff --git a/src/menu/UMenuBackgroundNone.pas b/src/menu/UMenuBackgroundNone.pas
index 1fccc007..c64f3023 100644
--- a/src/menu/UMenuBackgroundNone.pas
+++ b/src/menu/UMenuBackgroundNone.pas
@@ -1,70 +1,70 @@
-{* 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 UMenuBackgroundNone;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- UThemes,
- UMenuBackground;
-
-//TMenuBackgroundNone - Just no Background (e.g. for Overlays)
-//--------
-
-type
- TMenuBackgroundNone = class (TMenuBackground)
- private
-
- public
- constructor Create(const ThemedSettings: TThemeBackground); override;
- procedure Draw; override;
- end;
-
-implementation
-uses
- gl,
- glext,
- UGraphic;
-
-constructor TMenuBackgroundNone.Create(const ThemedSettings: TThemeBackground);
-begin
- inherited;
-end;
-
-procedure TMenuBackgroundNone.Draw;
-begin
- //Do just nothing in here!
- If (ScreenAct = 1) then //Clear just once when in dual screen mode
- glClear(GL_DEPTH_BUFFER_BIT);
-end;
-
+{* 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 UMenuBackgroundNone;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ UThemes,
+ UMenuBackground;
+
+//TMenuBackgroundNone - Just no Background (e.g. for Overlays)
+//--------
+
+type
+ TMenuBackgroundNone = class (TMenuBackground)
+ private
+
+ public
+ constructor Create(const ThemedSettings: TThemeBackground); override;
+ procedure Draw; override;
+ end;
+
+implementation
+uses
+ gl,
+ glext,
+ UGraphic;
+
+constructor TMenuBackgroundNone.Create(const ThemedSettings: TThemeBackground);
+begin
+ inherited;
+end;
+
+procedure TMenuBackgroundNone.Draw;
+begin
+ //Do just nothing in here!
+ If (ScreenAct = 1) then //Clear just once when in dual screen mode
+ glClear(GL_DEPTH_BUFFER_BIT);
+end;
+
end. \ No newline at end of file
diff --git a/src/menu/UMenuBackgroundTexture.pas b/src/menu/UMenuBackgroundTexture.pas
index a1b9e88a..f71637ff 100644
--- a/src/menu/UMenuBackgroundTexture.pas
+++ b/src/menu/UMenuBackgroundTexture.pas
@@ -1,125 +1,126 @@
-{* 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 UMenuBackgroundTexture;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- UThemes,
- UTexture,
- UMenuBackground;
-
-//TMenuBackgroundColor - Background Color
-//--------
-
-type
- TMenuBackgroundTexture = class (TMenuBackground)
- private
- Tex: TTexture;
- Color: TRGB;
- public
- constructor Create(const ThemedSettings: TThemeBackground); override;
- procedure Draw; override;
- destructor Destroy; override;
- end;
-
-const
- SUPPORTED_EXTS_BACKGROUNDTEXTURE: array[0..13] of string = ('.png', '.bmp', '.jpg', '.jpeg', '.gif', '.pnm', '.ppm', '.pgm', '.pbm', '.xpm', '.lbm', '.pcx', '.tga', '.tiff');
-
-implementation
-uses
- USkins,
- UCommon,
- SysUtils,
- gl,
- glext,
- UGraphic;
-
-constructor TMenuBackgroundTexture.Create(const ThemedSettings: TThemeBackground);
-var texFilename: string;
-begin
- inherited;
-
- if (Length(ThemedSettings.Tex) = 0) then
- raise EMenuBackgroundError.Create('TMenuBackgroundTexture: No texture filename present');
-
- Color := ThemedSettings.Color;
-
- texFilename := Skin.GetTextureFileName(ThemedSettings.Tex);
- texFilename := AdaptFilePaths(texFilename);
- Tex := Texture.GetTexture(texFilename, TEXTURE_TYPE_PLAIN);
-
- if (Tex.TexNum = 0) then
- begin
- freeandnil(Tex);
- raise EMenuBackgroundError.Create('TMenuBackgroundTexture: Can''t load texture');
- end;
-end;
-
-destructor TMenuBackgroundTexture.Destroy;
-begin
- //freeandnil(Tex); <- this causes an Access Violation o0
- inherited;
-end;
-
-procedure TMenuBackgroundTexture.Draw;
-begin
- If (ScreenAct = 1) then //Clear just once when in dual screen mode
- glClear(GL_DEPTH_BUFFER_BIT);
-
- glColorRGB(Color);
-
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glBindTexture(GL_TEXTURE_2D, Tex.TexNum);
-
- glBegin(GL_QUADS);
- glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY1*Tex.TexH);
- glVertex2f(0, 0);
-
- glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY2*Tex.TexH);
- glVertex2f(0, 600);
-
- glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY2*Tex.TexH);
- glVertex2f(800, 600);
-
- glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY1*Tex.TexH);
- glVertex2f(800, 0);
- glEnd;
-
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
-end;
-
-end.
+{* 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 UMenuBackgroundTexture;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ UThemes,
+ UTexture,
+ UMenuBackground,
+ UPath;
+
+//TMenuBackgroundColor - Background Color
+//--------
+
+type
+ TMenuBackgroundTexture = class (TMenuBackground)
+ private
+ Tex: TTexture;
+ Color: TRGB;
+ public
+ constructor Create(const ThemedSettings: TThemeBackground); override;
+ procedure Draw; override;
+ destructor Destroy; override;
+ end;
+
+const
+ SUPPORTED_EXTS_BACKGROUNDTEXTURE: array[0..13] of string = ('.png', '.bmp', '.jpg', '.jpeg', '.gif', '.pnm', '.ppm', '.pgm', '.pbm', '.xpm', '.lbm', '.pcx', '.tga', '.tiff');
+
+implementation
+uses
+ USkins,
+ UCommon,
+ SysUtils,
+ gl,
+ glext,
+ UGraphic;
+
+constructor TMenuBackgroundTexture.Create(const ThemedSettings: TThemeBackground);
+var
+ texFilename: IPath;
+begin
+ inherited;
+
+ if (Length(ThemedSettings.Tex) = 0) then
+ raise EMenuBackgroundError.Create('TMenuBackgroundTexture: No texture filename present');
+
+ Color := ThemedSettings.Color;
+
+ texFilename := Skin.GetTextureFileName(ThemedSettings.Tex);
+ Tex := Texture.GetTexture(texFilename, TEXTURE_TYPE_PLAIN);
+
+ if (Tex.TexNum = 0) then
+ begin
+ freeandnil(Tex);
+ raise EMenuBackgroundError.Create('TMenuBackgroundTexture: Can''t load texture');
+ end;
+end;
+
+destructor TMenuBackgroundTexture.Destroy;
+begin
+ //freeandnil(Tex); <- this causes an Access Violation o0
+ inherited;
+end;
+
+procedure TMenuBackgroundTexture.Draw;
+begin
+ If (ScreenAct = 1) then //Clear just once when in dual screen mode
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ glColorRGB(Color);
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glBindTexture(GL_TEXTURE_2D, Tex.TexNum);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY1*Tex.TexH);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(Tex.TexX1*Tex.TexW, Tex.TexY2*Tex.TexH);
+ glVertex2f(0, 600);
+
+ glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY2*Tex.TexH);
+ glVertex2f(800, 600);
+
+ glTexCoord2f(Tex.TexX2*Tex.TexW, Tex.TexY1*Tex.TexH);
+ glVertex2f(800, 0);
+ glEnd;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+end;
+
+end.
diff --git a/src/menu/UMenuBackgroundVideo.pas b/src/menu/UMenuBackgroundVideo.pas
index d1ce0f09..9d265764 100644
--- a/src/menu/UMenuBackgroundVideo.pas
+++ b/src/menu/UMenuBackgroundVideo.pas
@@ -1,204 +1,203 @@
-{* 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 UMenuBackgroundVideo;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses
- UThemes,
- UMenuBackground,
- UVideo;
-
-//TMenuBackgroundColor - Background Color
-//--------
-
-type
- //DefaultBGVideoPlayback = TVideoPlayback_FFmpeg;
-
-{type
- TBGVideoPool = class;
-
- PBGVideoPoolItem = ^TBGVideoPoolItem;
- TBGVideoPoolItem = record
- Parent: TBGVideoPool;
- VideoPlayback = IVideoPlayback;
- ReferenceCounter: cardinal; //Number of Creations
- end;
-
- TBGVideo = class
- private
- myItem: PBGVideoPoolItem;
- public
- constructor Create(Item: PBGVideoPoolItem); override;
-
- function GetVideoPlayback: IVideoPlayback;
- procedure Draw;
-
- destructor Destroy;
- end;
-
- TBGVideoPool = class
- private
- Items: PBGVideoPoolItem;
- public
- constructor Create;
-
- function GetBGVideo(filename: string): TBGVideo;
- procedure RemoveItem(
- procedure FreeAllItems;
-
- destructor Destroy;
- end;
-
-type }
- TMenuBackgroundVideo = class (TMenuBackground)
- private
- fFilename: string;
- public
- constructor Create(const ThemedSettings: TThemeBackground); override;
- procedure OnShow; override;
- procedure Draw; override;
- procedure OnFinish; override;
- destructor Destroy; override;
- end;
-
-{var
- BGVideoPool: TBGVideoPool; }
-const
- SUPPORTED_EXTS_BACKGROUNDVIDEO: array[0..6] of string = ('.avi', '.mov', '.divx', '.mpg', '.mp4', '.mpeg', '.m2v');
-
-implementation
-
-uses
- gl,
- glext,
- UMusic,
- SysUtils,
- UTime,
- USkins,
- UCommon,
- UGraphic;
-
-constructor TMenuBackgroundVideo.Create(const ThemedSettings: TThemeBackground);
-begin
- inherited;
- if (Length(ThemedSettings.Tex) = 0) then
- raise EMenuBackgroundError.Create('TMenuBackgroundVideo: No video filename present');
-
- fFileName := Skin.GetTextureFileName(ThemedSettings.Tex);
- fFileName := AdaptFilePaths( fFileName );
-
- if fileexists(fFilename) AND VideoPlayback.Open( fFileName ) then
- begin
- VideoBGTimer.SetTime(0);
- VideoPlayback.Play;
- end
- else
- raise EMenuBackgroundError.Create('TMenuBackgroundVideo: Can''t load background video: ' + fFilename);
-end;
-
-destructor TMenuBackgroundVideo.Destroy;
-begin
-
-end;
-
-procedure TMenuBackgroundVideo.OnShow;
-begin
- if VideoPlayback.Open( fFileName ) then
- begin
- VideoBGTimer.SetTime(0);
- VideoPlayback.Play;
- end;
-end;
-
-procedure TMenuBackgroundVideo.OnFinish;
-begin
-
-end;
-
-procedure TMenuBackgroundVideo.Draw;
-begin
- If (ScreenAct = 1) then //Clear just once when in dual screen mode
- glClear(GL_DEPTH_BUFFER_BIT);
-
- VideoPlayback.GetFrame(VideoBGTimer.GetTime());
- // FIXME: why do we draw on screen 2? Seems to be wrong.
- VideoPlayback.DrawGL(2);
-end;
-
-// Implementation of TBGVideo
-//--------
-{constructor TBGVideo.Create(Item: PBGVideoPoolItem);
-begin
- myItem := PBGVideoPoolItem;
- Inc(myItem.ReferenceCounter);
-end;
-
-destructor TBGVideo.Destroy;
-begin
- Dec(myItem.ReferenceCounter);
-end;
-
-function TBGVideo.GetVideoPlayback: IVideoPlayback;
-begin
-
-end;
-
-procedure TBGVideo.Draw;
-begin
-
-end;
-
-// Implementation of TBGVideoPool
-//--------
-
-constructor TBGVideoPool.Create;
-begin
-
-end;
-
-destructor TBGVideoPool.Destroy;
-begin
-
-end;
-
-function TBGVideoPool.GetBGVideo(filename: string): TBGVideo;
-begin
-
-end;
-
-procedure TBGVideoPool.FreeAllItems;
-begin
-
-end; }
-
-end.
+{* 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 UMenuBackgroundVideo;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ UThemes,
+ UMenuBackground,
+ UVideo,
+ UPath;
+
+//TMenuBackgroundColor - Background Color
+//--------
+
+type
+ //DefaultBGVideoPlayback = TVideoPlayback_FFmpeg;
+
+{type
+ TBGVideoPool = class;
+
+ PBGVideoPoolItem = ^TBGVideoPoolItem;
+ TBGVideoPoolItem = record
+ Parent: TBGVideoPool;
+ VideoPlayback = IVideoPlayback;
+ ReferenceCounter: cardinal; //Number of Creations
+ end;
+
+ TBGVideo = class
+ private
+ myItem: PBGVideoPoolItem;
+ public
+ constructor Create(Item: PBGVideoPoolItem); override;
+
+ function GetVideoPlayback: IVideoPlayback;
+ procedure Draw;
+
+ destructor Destroy;
+ end;
+
+ TBGVideoPool = class
+ private
+ Items: PBGVideoPoolItem;
+ public
+ constructor Create;
+
+ function GetBGVideo(filename: IPath): TBGVideo;
+ procedure RemoveItem(
+ procedure FreeAllItems;
+
+ destructor Destroy;
+ end;
+
+type }
+ TMenuBackgroundVideo = class (TMenuBackground)
+ private
+ fFilename: IPath;
+ public
+ constructor Create(const ThemedSettings: TThemeBackground); override;
+ procedure OnShow; override;
+ procedure Draw; override;
+ procedure OnFinish; override;
+ destructor Destroy; override;
+ end;
+
+{var
+ BGVideoPool: TBGVideoPool; }
+const
+ SUPPORTED_EXTS_BACKGROUNDVIDEO: array[0..6] of string = ('.avi', '.mov', '.divx', '.mpg', '.mp4', '.mpeg', '.m2v');
+
+implementation
+
+uses
+ gl,
+ glext,
+ UMusic,
+ SysUtils,
+ UTime,
+ USkins,
+ UCommon,
+ UGraphic;
+
+constructor TMenuBackgroundVideo.Create(const ThemedSettings: TThemeBackground);
+begin
+ inherited;
+ if (Length(ThemedSettings.Tex) = 0) then
+ raise EMenuBackgroundError.Create('TMenuBackgroundVideo: No video filename present');
+
+ fFileName := Skin.GetTextureFileName(ThemedSettings.Tex);
+ if fFilename.IsFile and VideoPlayback.Open(fFileName) then
+ begin
+ VideoBGTimer.SetTime(0);
+ VideoPlayback.Play;
+ end
+ else
+ raise EMenuBackgroundError.Create('TMenuBackgroundVideo: Can''t load background video: ' + fFilename.ToNative);
+end;
+
+destructor TMenuBackgroundVideo.Destroy;
+begin
+
+end;
+
+procedure TMenuBackgroundVideo.OnShow;
+begin
+ if VideoPlayback.Open( fFileName ) then
+ begin
+ VideoBGTimer.SetTime(0);
+ VideoPlayback.Play;
+ end;
+end;
+
+procedure TMenuBackgroundVideo.OnFinish;
+begin
+
+end;
+
+procedure TMenuBackgroundVideo.Draw;
+begin
+ If (ScreenAct = 1) then //Clear just once when in dual screen mode
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ VideoPlayback.GetFrame(VideoBGTimer.GetTime());
+ // FIXME: why do we draw on screen 2? Seems to be wrong.
+ VideoPlayback.DrawGL(2);
+end;
+
+// Implementation of TBGVideo
+//--------
+{constructor TBGVideo.Create(Item: PBGVideoPoolItem);
+begin
+ myItem := PBGVideoPoolItem;
+ Inc(myItem.ReferenceCounter);
+end;
+
+destructor TBGVideo.Destroy;
+begin
+ Dec(myItem.ReferenceCounter);
+end;
+
+function TBGVideo.GetVideoPlayback: IVideoPlayback;
+begin
+
+end;
+
+procedure TBGVideo.Draw;
+begin
+
+end;
+
+// Implementation of TBGVideoPool
+//--------
+
+constructor TBGVideoPool.Create;
+begin
+
+end;
+
+destructor TBGVideoPool.Destroy;
+begin
+
+end;
+
+function TBGVideoPool.GetBGVideo(filename: IPath): TBGVideo;
+begin
+
+end;
+
+procedure TBGVideoPool.FreeAllItems;
+begin
+
+end; }
+
+end.
diff --git a/src/menu/UMenuSelectSlide.pas b/src/menu/UMenuSelectSlide.pas
index f9f6bbae..6bc824f4 100644
--- a/src/menu/UMenuSelectSlide.pas
+++ b/src/menu/UMenuSelectSlide.pas
@@ -48,7 +48,7 @@ type
// objects
Text: TText; // Main text describing option
TextOpt: array of TText; // 3 texts in the position of possible options
- TextOptT: array of string; // array of names for possible options
+ TextOptT: array of UTF8String; // array of names for possible options
Texture: TTexture; // Select Texture
TextureSBG: TTexture; // Background Selections Texture
diff --git a/src/menu/UMenuText.pas b/src/menu/UMenuText.pas
index b5507327..276f961b 100644
--- a/src/menu/UMenuText.pas
+++ b/src/menu/UMenuText.pas
@@ -45,8 +45,8 @@ type
TText = class
private
SelectBool: boolean;
- TextString: string;
- TextTiles: array of string;
+ TextString: UTF8String;
+ TextTiles: array of UTF8String;
STicks: cardinal;
SelectBlink: boolean;
@@ -75,22 +75,23 @@ type
procedure SetSelect(Value: boolean);
property Selected: boolean read SelectBool write SetSelect;
- procedure SetText(Value: string);
- property Text: string read TextString write SetText;
+ procedure SetText(Value: UTF8String);
+ property Text: UTF8String read TextString write SetText;
- procedure DeleteLastL; // procedure to delete last letter
+ procedure DeleteLastLetter; //< Deletes the rightmost letter
procedure Draw;
constructor Create; overload;
- constructor Create(X, Y: real; Text: string); overload;
- constructor Create(ParX, ParY, ParW: real; ParStyle: integer; ParSize, ParColR, ParColG, ParColB: real; ParAlign: integer; ParText: string; ParReflection: boolean; ParReflectionSpacing: real; ParZ: real); overload;
+ constructor Create(X, Y: real; const Text: UTF8String); overload;
+ constructor Create(ParX, ParY, ParW: real; ParStyle: integer; ParSize, ParColR, ParColG, ParColB: real; ParAlign: integer; const ParText: UTF8String; ParReflection: boolean; ParReflectionSpacing: real; ParZ: real); overload;
end;
implementation
uses
- StrUtils,
- UGraphic;
+ UGraphic,
+ UUnicodeUtils,
+ StrUtils;
procedure TText.SetSelect(Value: boolean);
begin
@@ -101,7 +102,7 @@ begin
STicks := SDL_GetTicks() div 550;
end;
-procedure TText.SetText(Value: string);
+procedure TText.SetText(Value: UTF8String);
var
NextPos: cardinal; // next pos of a space etc.
LastPos: cardinal; // last pos "
@@ -244,23 +245,15 @@ begin
AddBreak(LastBreak, Length(Value)+1);
end;
-procedure TText.DeleteLastL;
-var
- S: string;
- L: integer;
+procedure TText.DeleteLastLetter;
begin
- S := TextString;
- L := Length(S);
- if (L > 0) then
- SetLength(S, L-1);
-
- SetText(S);
+ SetText(UTF8Copy(TextString, 1, LengthUTF8(TextString)-1));
end;
procedure TText.Draw;
var
X2, Y2: real;
- Text2: string;
+ Text2: UTF8String;
I: integer;
Ticks: cardinal;
begin
@@ -349,19 +342,19 @@ begin
Create(0, 0, '');
end;
-constructor TText.Create(X, Y: real; Text: string);
+constructor TText.Create(X, Y: real; const Text: UTF8String);
begin
Create(X, Y, 0, 0, 30, 0, 0, 0, 0, Text, false, 0, 0);
end;
constructor TText.Create(ParX, ParY, ParW: real;
ParStyle: integer;
- ParSize, ParColR, ParColG, ParColB: real;
- ParAlign: integer;
- ParText: string;
- ParReflection: boolean;
- ParReflectionSpacing: real;
- ParZ: real);
+ ParSize, ParColR, ParColG, ParColB: real;
+ ParAlign: integer;
+ const ParText: UTF8String;
+ ParReflection: boolean;
+ ParReflectionSpacing: real;
+ ParZ: real);
begin
inherited Create;
Alpha := 1;
diff --git a/src/screens/UScreenCredits.pas b/src/screens/UScreenCredits.pas
index def6b7de..b1333b4a 100644
--- a/src/screens/UScreenCredits.pas
+++ b/src/screens/UScreenCredits.pas
@@ -35,15 +35,16 @@ interface
uses
SysUtils,
- UMenu,
SDL,
SDL_Image,
+ gl,
+ UMenu,
UDisplay,
UTexture,
- gl,
UMusic,
UFiles,
UThemes,
+ UPath,
UGraphicClasses;
type
@@ -98,10 +99,10 @@ type
Fadeout: boolean;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function Draw: boolean; override;
- procedure onShow; override;
- procedure onHide; override;
+ procedure OnShow; override;
+ procedure OnHide; override;
procedure DrawCredits;
procedure Draw_FunkyText;
end;
@@ -138,17 +139,17 @@ const
OUTRO_EXD_FILE = 'outro-exit-dark.png';
Timings: array[0..21] of cardinal=(
- 20, // 0 Delay vor Start
+ 20, // 0 Delay before Start
- 149, // 1 Ende erster Intro Zoom
- 155, // 2 Start 2. Action im Intro
- 170, // 3 Ende Separation im Intro
- 271, // 4 Anfang Zoomout im Intro
+ 149, // 1 End first Intro Zoom
+ 155, // 2 Start 2. Action in Intro
+ 170, // 3 End Separation in Intro
+ 271, // 4 beginning Zoomout in Intro
0, // 5 unused
- 261, // 6 Start fade-to-white im Intro
+ 261, // 6 Start fade-to-white in Intro
271, // 7 Start Main Part
- 280, // 8 Start On-Beat-Sternchen Main Part
+ 280, // 8 Start On-Beat-Star Main Part
396, // 9 Start BlindGuard
666, // 10 Start blindy
@@ -162,7 +163,7 @@ const
2826, // 18 Ende Whiteshark
3096, // 19 Start FadeOut Mainscreen
3366, // 20 Ende Credits Tune
- 60); // 21 start flare im intro
+ 60); // 21 start flare in intro
implementation
@@ -176,9 +177,9 @@ uses
Textgl,
ULanguage,
UCommon,
- UPath;
+ UPathUtils;
-function TScreenCredits.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenCredits.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
@@ -204,38 +205,38 @@ end;
constructor TScreenCredits.Create;
var
- CreditsPath: string;
+ CreditsPath: IPath;
begin
inherited Create;
- CreditsPath := ResourcesPath + 'credits/';
-
- credits_bg_tex := Texture.LoadTexture(CreditsPath + CRDTS_BG_FILE, TEXTURE_TYPE_PLAIN, 0);
- credits_bg_ovl := Texture.LoadTexture(CreditsPath + CRDTS_OVL_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
-
- credits_blindguard := Texture.LoadTexture(CreditsPath + CRDTS_blindguard_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_blindy := Texture.LoadTexture(CreditsPath + CRDTS_blindy_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_canni := Texture.LoadTexture(CreditsPath + CRDTS_canni_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_commandio := Texture.LoadTexture(CreditsPath + CRDTS_commandio_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_lazyjoker := Texture.LoadTexture(CreditsPath + CRDTS_lazyjoker_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_mog := Texture.LoadTexture(CreditsPath + CRDTS_mog_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_mota := Texture.LoadTexture(CreditsPath + CRDTS_mota_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_skillmaster := Texture.LoadTexture(CreditsPath + CRDTS_skillmaster_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- credits_whiteshark := Texture.LoadTexture(CreditsPath + CRDTS_whiteshark_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
-
- intro_layer01 := Texture.LoadTexture(CreditsPath + INTRO_L01_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer02 := Texture.LoadTexture(CreditsPath + INTRO_L02_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer03 := Texture.LoadTexture(CreditsPath + INTRO_L03_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer04 := Texture.LoadTexture(CreditsPath + INTRO_L04_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer05 := Texture.LoadTexture(CreditsPath + INTRO_L05_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer06 := Texture.LoadTexture(CreditsPath + INTRO_L06_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer07 := Texture.LoadTexture(CreditsPath + INTRO_L07_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer08 := Texture.LoadTexture(CreditsPath + INTRO_L08_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- intro_layer09 := Texture.LoadTexture(CreditsPath + INTRO_L09_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
-
- outro_bg := Texture.LoadTexture(CreditsPath + OUTRO_BG_FILE, TEXTURE_TYPE_PLAIN, 0);
- outro_esc := Texture.LoadTexture(CreditsPath + OUTRO_ESC_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
- outro_exd := Texture.LoadTexture(CreditsPath + OUTRO_EXD_FILE, TEXTURE_TYPE_TRANSPARENT, 0);
+ CreditsPath := ResourcesPath.Append('credits', pdAppend);
+
+ credits_bg_tex := Texture.LoadTexture(CreditsPath.Append(CRDTS_BG_FILE), TEXTURE_TYPE_PLAIN, 0);
+ credits_bg_ovl := Texture.LoadTexture(CreditsPath.Append(CRDTS_OVL_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+
+ credits_blindguard := Texture.LoadTexture(CreditsPath.Append(CRDTS_blindguard_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_blindy := Texture.LoadTexture(CreditsPath.Append(CRDTS_blindy_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_canni := Texture.LoadTexture(CreditsPath.Append(CRDTS_canni_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_commandio := Texture.LoadTexture(CreditsPath.Append(CRDTS_commandio_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_lazyjoker := Texture.LoadTexture(CreditsPath.Append(CRDTS_lazyjoker_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_mog := Texture.LoadTexture(CreditsPath.Append(CRDTS_mog_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_mota := Texture.LoadTexture(CreditsPath.Append(CRDTS_mota_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_skillmaster := Texture.LoadTexture(CreditsPath.Append(CRDTS_skillmaster_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ credits_whiteshark := Texture.LoadTexture(CreditsPath.Append(CRDTS_whiteshark_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+
+ intro_layer01 := Texture.LoadTexture(CreditsPath.Append(INTRO_L01_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer02 := Texture.LoadTexture(CreditsPath.Append(INTRO_L02_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer03 := Texture.LoadTexture(CreditsPath.Append(INTRO_L03_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer04 := Texture.LoadTexture(CreditsPath.Append(INTRO_L04_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer05 := Texture.LoadTexture(CreditsPath.Append(INTRO_L05_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer06 := Texture.LoadTexture(CreditsPath.Append(INTRO_L06_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer07 := Texture.LoadTexture(CreditsPath.Append(INTRO_L07_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer08 := Texture.LoadTexture(CreditsPath.Append(INTRO_L08_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ intro_layer09 := Texture.LoadTexture(CreditsPath.Append(INTRO_L09_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+
+ outro_bg := Texture.LoadTexture(CreditsPath.Append(OUTRO_BG_FILE), TEXTURE_TYPE_PLAIN, 0);
+ outro_esc := Texture.LoadTexture(CreditsPath.Append(OUTRO_ESC_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
+ outro_exd := Texture.LoadTexture(CreditsPath.Append(OUTRO_EXD_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
CRDTS_Stage:=InitialDelay;
end;
@@ -246,7 +247,7 @@ begin
Draw := true;
end;
-procedure TScreenCredits.onShow;
+procedure TScreenCredits.OnShow;
begin
inherited;
@@ -255,13 +256,13 @@ begin
deluxe_slidein := 0;
Credits_Alpha := 0;
// Music.SetLoop(true); loop loops not, shit
- AudioPlayback.Open(soundpath + 'wome-credits-tune.mp3'); // thank you wetue
+ AudioPlayback.Open(soundpath.Append('wome-credits-tune.mp3')); // thank you wetue
// Music.Play;
CTime := 0;
// setlength(CTime_hold,0);
end;
-procedure TScreenCredits.onHide;
+procedure TScreenCredits.OnHide;
begin
AudioPlayback.Stop;
end;
@@ -1386,7 +1387,7 @@ begin
begin
CTime_hold := 0;
AudioPlayback.Stop;
- AudioPlayback.Open(soundpath + 'credits-outro-tune.mp3');
+ AudioPlayback.Open(SoundPath.Append('credits-outro-tune.mp3'));
AudioPlayback.SetVolume(0.2);
AudioPlayback.SetLoop(true);
AudioPlayback.Play;
diff --git a/src/screens/UScreenEdit.pas b/src/screens/UScreenEdit.pas
index 5112e17a..2111adef 100644
--- a/src/screens/UScreenEdit.pas
+++ b/src/screens/UScreenEdit.pas
@@ -45,8 +45,7 @@ type
TextDescriptionLong: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar;
- PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
procedure InteractNext; override;
procedure InteractPrev; override;
procedure InteractInc; override;
@@ -60,10 +59,10 @@ uses
UGraphic,
UMusic,
USkins,
+ UUnicodeUtils,
SysUtils;
-function TScreenEdit.ParseInput(PressedKey: cardinal; CharCode: WideChar;
- PressedDown: boolean): boolean;
+function TScreenEdit.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
SDL_ModState: word;
begin
@@ -75,8 +74,8 @@ begin
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
diff --git a/src/screens/UScreenEditConvert.pas b/src/screens/UScreenEditConvert.pas
index e4a691cf..b2fb7773 100644
--- a/src/screens/UScreenEditConvert.pas
+++ b/src/screens/UScreenEditConvert.pas
@@ -25,6 +25,29 @@
unit UScreenEditConvert;
+{*
+ * See
+ * MIDI Recommended Practice (RP-017): SMF Lyric Meta Event Definition
+ * http://www.midi.org/techspecs/rp17.php
+ * MIDI Recommended Practice (RP-026): SMF Language and Display Extensions
+ * http://www.midi.org/techspecs/rp26.php
+ * MIDI File Format
+ * http://www.sonicspot.com/guide/midifiles.html
+ * KMIDI File Format
+ * http://gnese.free.fr/Projects/KaraokeTime/Fichiers/karfaq.html
+ * http://journals.rpungin.fotki.com/karaoke/category/midi
+ *
+ * There are two widely spread karaoke formats:
+ * - KMIDI (.kar), an inofficial midi extension by Tune 1000
+ * - Standard Midi files with lyric meta-tags (SMF with lyrics, .mid).
+ *
+ * KMIDI uses two tracks, the first just contains a header (mostly track 2) and
+ * the second the lyrics (track 3). It uses text meta tags for the lyrics.
+ * SMF uses just one track (normally track 1) and uses lyric meta tags for storage.
+ *
+ * Most files are in the KMIDI format. Some Midi files contain both lyric types.
+ *}
+
interface
{$IFDEF FPC}
@@ -45,10 +68,11 @@ uses
USongs,
USong,
UMusic,
- UThemes;
+ UThemes,
+ UPath;
type
- TNote = record
+ TMidiNote = record
Event: integer;
EventType: integer;
Channel: integer;
@@ -56,70 +80,65 @@ type
Len: real;
Data1: integer;
Data2: integer;
- Str: string;
+ Str: UTF8String; // normally ASCII
end;
+ TLyricType = (ltKMIDI, ltSMFLyric);
+
TTrack = record
- Note: array of TNote;
- Name: string;
- Hear: boolean;
- Status: set of (notes, lyrics);
+ Note: array of TMidiNote;
+ Name: UTF8String; // normally ASCII
+ Status: set of (tsNotes, tsLyrics); //< track contains notes, lyrics or both
+ LyricType: set of TLyricType;
+ NoteType: (ntNone, ntAvail);
end;
- TNuta = record
+ TNote = record
Start: integer;
Len: integer;
Tone: integer;
- Lyric: string;
+ Lyric: UTF8String;
NewSentence: boolean;
end;
TArrayTrack = array of TTrack;
TScreenEditConvert = class(TMenu)
- public
- ATrack: TArrayTrack; // actual track
-// Track: TArrayTrack;
- Channel: TArrayTrack;
+ private
+ Tracks: TArrayTrack; // current track
ColR: array[0..100] of real;
ColG: array[0..100] of real;
ColB: array[0..100] of real;
Len: real;
- Sel: integer;
- Selected: boolean;
-// FileName: string;
+ SelTrack: integer; // index of selected track
+ fFileName: IPath;
{$IFDEF UseMIDIPort}
MidiFile: TMidiFile;
- MidiTrack: TMidiTrack;
- MidiEvent: pMidiEvent;
MidiOut: TMidiOutput;
{$ENDIF}
-
- Song: TSong;
- Lines: TLines;
+
BPM: real;
Ticks: real;
- Note: array of TNuta;
+ Note: array of TNote;
- procedure AddLyric(Start: integer; Text: string);
- procedure Extract;
+ procedure AddLyric(Start: integer; LyricType: TLyricType; Text: UTF8String);
+ procedure Extract(out Song: TSong; out Lines: TLines);
{$IFDEF UseMIDIPort}
procedure MidiFile1MidiEvent(event: PMidiEvent);
{$ENDIF}
-
- function SelectedNumber: integer;
+
+ function CountSelectedTracks: integer;
+
+ public
constructor Create; override;
- procedure onShow; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function Draw: boolean; override;
- procedure onHide; override;
+ procedure OnHide; override;
end;
-var
- ConversionFileName: string;
-
implementation
uses
@@ -131,17 +150,42 @@ uses
UGraphic,
UIni,
UMain,
- UPath,
- USkins;
-
-function TScreenEditConvert.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+ UPathUtils,
+ USkins,
+ ULanguage,
+ UTextEncoding,
+ UUnicodeUtils;
+
+const
+ // MIDI/KAR lyrics are specified to be ASCII only.
+ // Assume backward compatible CP1252 encoding.
+ DEFAULT_ENCODING = encCP1252;
+
+const
+ MIDI_EVENTTYPE_NOTEOFF = $8;
+ MIDI_EVENTTYPE_NOTEON = $9;
+ MIDI_EVENTTYPE_META_SYSEX = $F;
+
+ MIDI_EVENT_META = $FF;
+ MIDI_META_TEXT = $1;
+ MIDI_META_LYRICS = $5;
+
+function TScreenEditConvert.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
+{$IFDEF UseMIDIPort}
+var
+ SResult: TSaveSongResult;
+ Playing: boolean;
+ MidiTrack: TMidiTrack;
+ Song: TSong;
+ Lines: TLines;
+{$ENDIF}
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -153,9 +197,10 @@ begin
SDLK_ESCAPE,
SDLK_BACKSPACE :
begin
- {$IFDEF UseMIDIPort}
- MidiFile.StopPlaying;
- {$ENDIF}
+ {$IFDEF UseMIDIPort}
+ if (MidiFile <> nil) then
+ MidiFile.StopPlaying;
+ {$ENDIF}
AudioPlayback.PlaySound(SoundLib.Back);
FadeTo(@ScreenEdit);
end;
@@ -165,70 +210,97 @@ begin
if Interaction = 0 then
begin
AudioPlayback.PlaySound(SoundLib.Start);
+ ScreenOpen.Filename := GamePath.Append('file.mid');
ScreenOpen.BackScreen := @ScreenEditConvert;
FadeTo(@ScreenOpen);
- end;
-
- if Interaction = 1 then
+ end
+ else if Interaction = 1 then
begin
- Selected := false;
- {$IFDEF UseMIDIPort}
- MidiFile.OnMidiEvent := MidiFile1MidiEvent;
-// MidiFile.GoToTime(MidiFile.GetTrackLength div 2);
- MidiFile.StartPlaying;
+ {$IFDEF UseMIDIPort}
+ if (MidiFile <> nil) then
+ begin
+ MidiFile.OnMidiEvent := MidiFile1MidiEvent;
+ //MidiFile.GoToTime(MidiFile.GetTrackLength div 2);
+ MidiFile.StartPlaying;
+ end;
{$ENDIF}
- end;
-
- if Interaction = 2 then
+ end
+ else if Interaction = 2 then
begin
- Selected := true;
{$IFDEF UseMIDIPort}
- MidiFile.OnMidiEvent := nil;
- {$ENDIF}
- {for T := 0 to High(ATrack) do
+ if (MidiFile <> nil) then
begin
- if ATrack[T].Hear then
- begin
- MidiTrack := MidiFile.GetTrack(T);
- MidiTrack.OnMidiEvent := MidiFile1MidiEvent;
- end;
+ MidiFile.OnMidiEvent := nil;
+ MidiFile.StartPlaying;
end;
- MidiFile.StartPlaying;//}
- end;
-
- if Interaction = 3 then
+ {$ENDIF}
+ end
+ else if Interaction = 3 then
begin
- if SelectedNumber > 0 then
+ {$IFDEF UseMIDIPort}
+ if CountSelectedTracks > 0 then
+ begin
+ Extract(Song, Lines);
+ SResult := SaveSong(Song, Lines, fFileName.SetExtension('.txt'),
+ false);
+ FreeAndNil(Song);
+ if (SResult = ssrOK) then
+ ScreenPopupInfo.ShowPopup(Language.Translate('INFO_FILE_SAVED'))
+ else
+ ScreenPopupError.ShowPopup(Language.Translate('ERROR_SAVE_FILE_FAILED'));
+ end
+ else
begin
- Extract;
- SaveSong(Song, Lines, ChangeFileExt(ConversionFileName, '.txt'), false);
+ ScreenPopupError.ShowPopup(Language.Translate('EDITOR_ERROR_NO_TRACK_SELECTED'));
end;
+ {$ENDIF}
end;
end;
SDLK_SPACE:
begin
-// ATrack[Sel].Hear := not ATrack[Sel].Hear;
- if Notes in ATrack[Sel].Status then
+ {$IFDEF UseMIDIPort}
+ if (MidiFile <> nil) then
begin
- ATrack[Sel].Status := ATrack[Sel].Status - [Notes];
- if Lyrics in ATrack[Sel].Status then
- ATrack[Sel].Status := ATrack[Sel].Status - [Lyrics]
- else
- ATrack[Sel].Status := ATrack[Sel].Status + [Lyrics];
- end
- else
- ATrack[Sel].Status := ATrack[Sel].Status + [Notes];
+ if (Tracks[SelTrack].NoteType = ntAvail) and
+ (Tracks[SelTrack].LyricType <> []) then
+ begin
+ if (Tracks[SelTrack].Status = []) then
+ Tracks[SelTrack].Status := [tsNotes]
+ else if (Tracks[SelTrack].Status = [tsNotes]) then
+ Tracks[SelTrack].Status := [tsLyrics]
+ else if (Tracks[SelTrack].Status = [tsLyrics]) then
+ Tracks[SelTrack].Status := [tsNotes, tsLyrics]
+ else if (Tracks[SelTrack].Status = [tsNotes, tsLyrics]) then
+ Tracks[SelTrack].Status := [];
+ end
+ else if (Tracks[SelTrack].NoteType = ntAvail) then
+ begin
+ if (Tracks[SelTrack].Status = []) then
+ Tracks[SelTrack].Status := [tsNotes]
+ else
+ Tracks[SelTrack].Status := [];
+ end
+ else if (Tracks[SelTrack].LyricType <> []) then
+ begin
+ if (Tracks[SelTrack].Status = []) then
+ Tracks[SelTrack].Status := [tsLyrics]
+ else
+ Tracks[SelTrack].Status := [];
+ end;
-{ if Selected then
- begin
- MidiTrack := MidiFile.GetTrack(Sel);
- if Track[Sel].Hear then
+ Playing := (MidiFile.GetCurrentTime > 0);
+ MidiFile.StopPlaying();
+ MidiTrack := MidiFile.GetTrack(SelTrack);
+ if tsNotes in Tracks[SelTrack].Status then
MidiTrack.OnMidiEvent := MidiFile1MidiEvent
else
MidiTrack.OnMidiEvent := nil;
- end;}
+ if (Playing) then
+ MidiFile.ContinuePlaying();
+ end;
+ {$ENDIF}
end;
SDLK_RIGHT:
@@ -243,102 +315,161 @@ begin
SDLK_DOWN:
begin
- Inc(Sel);
- if Sel > High(ATrack) then
- Sel := 0;
+ Inc(SelTrack);
+ if SelTrack > High(Tracks) then
+ SelTrack := 0;
end;
SDLK_UP:
begin
- Dec(Sel);
- if Sel < 0 then
- Sel := High(ATrack);
+ Dec(SelTrack);
+ if SelTrack < 0 then
+ SelTrack := High(Tracks);
end;
end;
end;
end;
-procedure TScreenEditConvert.AddLyric(Start: integer; Text: string);
+procedure TScreenEditConvert.AddLyric(Start: integer; LyricType: TLyricType; Text: UTF8String);
var
N: integer;
begin
- for N := 0 to High(Note) do
+ // find corresponding note
+ N := 0;
+ while (N <= High(Note)) do
begin
if Note[N].Start = Start then
- begin
- // check for new sentece
- if Copy(Text, 1, 1) = '\' then
- Delete(Text, 1, 1);
- if Copy(Text, 1, 1) = '/' then
- begin
- Delete(Text, 1, 1);
- Note[N].NewSentence := true;
- end;
+ Break;
+ Inc(N);
+ end;
- // overwrite lyric od append
- if Note[N].Lyric = '-' then
- Note[N].Lyric := Text
- else
- Note[N].Lyric := Note[N].Lyric + Text;
+ // check if note was found
+ if (N > High(Note)) then
+ Exit;
+
+ // set text
+ if (LyricType = ltKMIDI) then
+ begin
+ // end of paragraph
+ if Copy(Text, 1, 1) = '\' then
+ begin
+ Delete(Text, 1, 1);
+ end
+ // end of line
+ else if Copy(Text, 1, 1) = '/' then
+ begin
+ Delete(Text, 1, 1);
+ Note[N].NewSentence := true;
+ end;
+ end
+ else // SMFLyric
+ begin
+ // Line Feed -> end of paragraph
+ if Copy(Text, 1, 1) = #$0A then
+ begin
+ Delete(Text, 1, 1);
+ end
+ // Carriage Return -> end of line
+ else if Copy(Text, 1, 1) = #$0D then
+ begin
+ Delete(Text, 1, 1);
+ Note[N].NewSentence := true;
end;
end;
+
+ // overwrite lyric or append
+ if Note[N].Lyric = '-' then
+ Note[N].Lyric := Text
+ else
+ Note[N].Lyric := Note[N].Lyric + Text;
end;
-procedure TScreenEditConvert.Extract;
+procedure TScreenEditConvert.Extract(out Song: TSong; out Lines: TLines);
+
var
T: integer;
C: integer;
N: integer;
Nu: integer;
- NoteTemp: TNuta;
+ NoteTemp: TNote;
Move: integer;
Max, Min: integer;
+ LyricType: TLyricType;
+ Text: UTF8String;
begin
// song info
- Song.Title := '';
- Song.Artist := '';
- Song.Mp3 := '';
+ Song := TSong.Create();
+ Song.Clear();
Song.Resolution := 4;
SetLength(Song.BPM, 1);
Song.BPM[0].BPM := BPM*4;
-
SetLength(Note, 0);
// extract notes
- for T := 0 to High(ATrack) do
+ for T := 0 to High(Tracks) do
begin
-// if ATrack[T].Hear then
-// begin
- if Notes in ATrack[T].Status then
+ if tsNotes in Tracks[T].Status then
begin
- for N := 0 to High(ATrack[T].Note) do
+ for N := 0 to High(Tracks[T].Note) do
begin
- if (ATrack[T].Note[N].EventType = 9) and (ATrack[T].Note[N].Data2 > 0) then
+ if (Tracks[T].Note[N].EventType = MIDI_EVENTTYPE_NOTEON) and
+ (Tracks[T].Note[N].Data2 > 0) then
begin
Nu := Length(Note);
SetLength(Note, Nu + 1);
- Note[Nu].Start := Round(ATrack[T].Note[N].Start / Ticks);
- Note[Nu].Len := Round(ATrack[T].Note[N].Len / Ticks);
- Note[Nu].Tone := ATrack[T].Note[N].Data1 - 12*5;
+ Note[Nu].Start := Round(Tracks[T].Note[N].Start / Ticks);
+ Note[Nu].Len := Round(Tracks[T].Note[N].Len / Ticks);
+ Note[Nu].Tone := Tracks[T].Note[N].Data1 - 12*5;
Note[Nu].Lyric := '-';
end;
end;
end;
end;
- // extract lyrics
- for T := 0 to High(ATrack) do
+ // extract lyrics (and artist + title info)
+ for T := 0 to High(Tracks) do
begin
-// if ATrack[T].Hear then
-// begin
- if Lyrics in ATrack[T].Status then
+ if not (tsLyrics in Tracks[T].Status) then
+ Continue;
+
+ for N := 0 to High(Tracks[T].Note) do
begin
- for N := 0 to High(ATrack[T].Note) do
+ if (Tracks[T].Note[N].Event = MIDI_EVENT_META) then
begin
- if (ATrack[T].Note[N].EventType = 15) then
+ // determine and validate lyric meta tag
+ if (ltKMIDI in Tracks[T].LyricType) and
+ (Tracks[T].Note[N].Data1 = MIDI_META_TEXT) then
begin
-// Log.LogStatus('<' + Track[T].Note[N].Str + '>', 'MIDI');
- AddLyric(Round(ATrack[T].Note[N].Start / Ticks), ATrack[T].Note[N].Str);
+ Text := Tracks[T].Note[N].Str;
+
+ // check for meta info
+ if (Length(Text) > 2) and (Text[1] = '@') then
+ begin
+ case Text[2] of
+ 'L': Song.Language := Copy(Text, 3, Length(Text)); // language
+ 'T': begin // title info
+ if (Song.Artist = '') then
+ Song.Artist := Copy(Text, 3, Length(Text))
+ else if (Song.Title = '') then
+ Song.Title := Copy(Text, 3, Length(Text));
+ end;
+ end;
+ Continue;
+ end;
+
+ LyricType := ltKMIDI;
+ end
+ else if (ltSMFLyric in Tracks[T].LyricType) and
+ (Tracks[T].Note[N].Data1 = MIDI_META_LYRICS) then
+ begin
+ LyricType := ltSMFLyric;
+ end
+ else
+ begin
+ // unknown meta event
+ Continue;
end;
+
+ AddLyric(Round(Tracks[T].Note[N].Start / Ticks), LyricType, Tracks[T].Note[N].Str);
end;
end;
end;
@@ -360,8 +491,12 @@ begin
// copy notes
SetLength(Lines.Line, 1);
- Lines.Number := 1;
- Lines.High := 0;
+ Lines.Number := 1;
+ Lines.High := 0;
+ Lines.Current := 0;
+ Lines.Resolution := 0;
+ Lines.NotesGAP := 0;
+ Lines.ScoreValue := 0;
C := 0;
N := 0;
@@ -403,35 +538,37 @@ begin
// create space for new note
SetLength(Lines.Line[C].Note, Length(Lines.Line[C].Note)+1);
+ Inc(Lines.Line[C].HighNote);
// initialize note
Lines.Line[C].Note[N].Start := Note[Nu].Start;
Lines.Line[C].Note[N].Length := Note[Nu].Len;
Lines.Line[C].Note[N].Tone := Note[Nu].Tone;
- Lines.Line[C].Note[N].Text := Note[Nu].Lyric;
- //All Notes are Freestyle when Converted Fix:
+ Lines.Line[C].Note[N].Text := DecodeStringUTF8(Note[Nu].Lyric, DEFAULT_ENCODING);
Lines.Line[C].Note[N].NoteType := ntNormal;
Inc(N);
end;
end;
-function TScreenEditConvert.SelectedNumber: integer;
+function TScreenEditConvert.CountSelectedTracks: integer;
var
T: integer; // track
begin
Result := 0;
- for T := 0 to High(ATrack) do
-// if ATrack[T].Hear then
-// Inc(Result);
- if Notes in ATrack[T].Status then
+ for T := 0 to High(Tracks) do
+ if tsNotes in Tracks[T].Status then
Inc(Result);
end;
{$IFDEF UseMIDIPort}
procedure TScreenEditConvert.MidiFile1MidiEvent(event: PMidiEvent);
begin
-// Log.LogStatus(IntToStr(event.event), 'MIDI');
- MidiOut.PutShort(event.event, event.data1, event.data2);
+ //Log.LogStatus(IntToStr(event.event), 'MIDI');
+ try
+ MidiOut.PutShort(event.event, event.data1, event.data2);
+ except
+ MidiFile.StopPlaying();
+ end;
end;
{$ENDIF}
@@ -442,7 +579,7 @@ begin
inherited Create;
AddButton(40, 20, 100, 40, Skin.GetTextureFileName('ButtonF'));
AddButtonText(15, 5, 0, 0, 0, 'Open');
-// Button[High(Button)].Text[0].Size := 11;
+ //Button[High(Button)].Text[0].Size := 11;
AddButton(160, 20, 100, 40, Skin.GetTextureFileName('ButtonF'));
AddButtonText(25, 5, 0, 0, 0, 'Play');
@@ -453,19 +590,7 @@ begin
AddButton(500, 20, 100, 40, Skin.GetTextureFileName('ButtonF'));
AddButtonText(20, 5, 0, 0, 0, 'Save');
-{ MidiOut := TMidiOutput.Create(nil);
-// MidiOut.Close;
-// MidiOut.DeviceID := 0;
- if Ini.Debug = 1 then
- MidiOut.ProductName := 'Microsoft GS Wavetable SW Synth'; // for my kxproject without midi table
- Log.LogStatus(MidiOut.ProductName, 'MIDI');
- MidiOut.Open;
-// MidiOut.SetVolume(100, 100); // temporary}
-
- ConversionFileName := GamePath + 'file.mid';
- {$IFDEF UseMIDIPort}
- MidiFile := TMidiFile.Create(nil);
- {$ENDIF}
+ fFileName := PATH_NONE;
for P := 0 to 100 do
begin
@@ -476,96 +601,124 @@ begin
end;
-procedure TScreenEditConvert.onShow;
+procedure TScreenEditConvert.OnShow;
var
T: integer; // track
N: integer; // note
- C: integer; // channel
- CN: integer; // channel note
+ {$IFDEF UseMIDIPort}
+ MidiTrack: TMidiTrack;
+ MidiEvent: PMidiEvent;
+ {$ENDIF}
+ FileOpened: boolean;
+ KMIDITrackIndex, SMFTrackIndex: integer;
begin
inherited;
+ Interaction := 0;
+
{$IFDEF UseMIDIPort}
MidiOut := TMidiOutput.Create(nil);
- if Ini.Debug = 1 then
- MidiOut.ProductName := 'Microsoft GS Wavetable SW Synth'; // for my kxproject without midi table
- Log.LogStatus(MidiOut.ProductName, 'MIDI');
+ Log.LogInfo(MidiOut.ProductName, 'MIDI');
MidiOut.Open;
+ MidiFile := nil;
+ SetLength(Tracks, 0);
+
+ // Filename is only <> PATH_NONE if we called the OpenScreen before
+ fFilename := ScreenOpen.Filename;
+ if (fFilename = PATH_NONE) then
+ Exit;
+ ScreenOpen.Filename := PATH_NONE;
- if FileExists(ConversionFileName) then
+ FileOpened := false;
+ if fFileName.Exists then
begin
- MidiFile.Filename := ConversionFileName;
- MidiFile.ReadFile;
+ MidiFile := TMidiFile.Create(nil);
+ MidiFile.Filename := fFileName;
+ try
+ MidiFile.ReadFile;
+ FileOpened := true;
+ except
+ MidiFile.Free;
+ end;
+ end;
- Len := 0;
- Sel := 0;
- BPM := MidiFile.Bpm;
- Ticks := MidiFile.TicksPerQuarter / 4;
+ if (not FileOpened) then
+ begin
+ ScreenPopupError.ShowPopup(Language.Translate('ERROR_FILE_NOT_FOUND'));
+ Exit;
+ end;
-{ for T := 0 to MidiFile.NumberOfTracks-1 do
- begin
- SetLength(Track, Length(Track)+1);
- MidiTrack := MidiFile.GetTrack(T);
- MidiTrack.OnMidiEvent := MidiFile1MidiEvent;
- Track[T].Name := MidiTrack.getName;
+ Len := 0;
+ SelTrack := 0;
+ BPM := MidiFile.Bpm;
+ Ticks := MidiFile.TicksPerQuarter / 4;
- for N := 0 to MidiTrack.getEventCount-1 do
- begin
- SetLength(Track[T].Note, Length(Track[T].Note)+1);
- MidiEvent := MidiTrack.GetEvent(N);
- Track[T].Note[N].Start := MidiEvent.time;
- Track[T].Note[N].Len := MidiEvent.len;
- Track[T].Note[N].Event := MidiEvent.event;
- Track[T].Note[N].EventType := MidiEvent.event div 16;
- Track[T].Note[N].Channel := MidiEvent.event and 15;
- Track[T].Note[N].Data1 := MidiEvent.data1;
- Track[T].Note[N].Data2 := MidiEvent.data2;
- Track[T].Note[N].Str := MidiEvent.str;
-
- if Track[T].Note[N].Start + Track[T].Note[N].Len > Len then
- Len := Track[T].Note[N].Start + Track[T].Note[N].Len;
- end;
- end;}
+ KMIDITrackIndex := -1;
+ SMFTrackIndex := -1;
- SetLength(Channel, 16);
- for T := 0 to 15 do
- begin
- Channel[T].Name := IntToStr(T+1);
- SetLength(Channel[T].Note, 0);
- Channel[T].Status := [];
- end;
+ SetLength(Tracks, MidiFile.NumberOfTracks);
+ for T := 0 to MidiFile.NumberOfTracks-1 do
+ Tracks[T].LyricType := [];
- for T := 0 to MidiFile.NumberOfTracks-1 do
+ for T := 0 to MidiFile.NumberOfTracks-1 do
+ begin
+ MidiTrack := MidiFile.GetTrack(T);
+ MidiTrack.OnMidiEvent := nil;
+ Tracks[T].Name := DecodeStringUTF8(MidiTrack.getName, DEFAULT_ENCODING);
+ Tracks[T].NoteType := ntNone;
+ Tracks[T].Status := [];
+
+ SetLength(Tracks[T].Note, MidiTrack.getEventCount());
+ for N := 0 to MidiTrack.getEventCount-1 do
begin
- MidiTrack := MidiFile.GetTrack(T);
- MidiTrack.OnMidiEvent := MidiFile1MidiEvent;
-
- for N := 0 to MidiTrack.getEventCount-1 do
+ MidiEvent := MidiTrack.GetEvent(N);
+
+ Tracks[T].Note[N].Start := MidiEvent.time;
+ Tracks[T].Note[N].Len := MidiEvent.len;
+ Tracks[T].Note[N].Event := MidiEvent.event;
+ Tracks[T].Note[N].EventType := MidiEvent.event shr 4;
+ Tracks[T].Note[N].Channel := MidiEvent.event and $0F;
+ Tracks[T].Note[N].Data1 := MidiEvent.data1;
+ Tracks[T].Note[N].Data2 := MidiEvent.data2;
+ Tracks[T].Note[N].Str := DecodeStringUTF8(MidiEvent.str, DEFAULT_ENCODING);
+
+ if (Tracks[T].Note[N].Event = MIDI_EVENT_META) then
+ begin
+ case (Tracks[T].Note[N].Data1) of
+ MIDI_META_TEXT: begin
+ // KMIDI lyrics (uses MIDI_META_TEXT events)
+ if (StrLComp(PAnsiChar(Tracks[T].Note[N].Str), '@KMIDI KARAOKE FILE', 19) = 0) and
+ (High(Tracks) >= T+1) then
+ begin
+ // The '@KMIDI ...' mark is in the first track (mostly named 'Soft Karaoke')
+ // but the lyrics are in the second track (named 'Words')
+ Tracks[T+1].LyricType := Tracks[T+1].LyricType + [ltKMIDI];
+ KMIDITrackIndex := T+1;
+ end;
+ end;
+ MIDI_META_LYRICS: begin
+ // lyrics in Standard Midi File format found (uses MIDI_META_LYRICS events)
+ Tracks[T].LyricType := Tracks[T].LyricType + [ltSMFLyric];
+ SMFTrackIndex := T;
+ end;
+ end;
+ end
+ else if (Tracks[T].Note[N].EventType = MIDI_EVENTTYPE_NOTEON) then
begin
- MidiEvent := MidiTrack.GetEvent(N);
- C := MidiEvent.event and 15;
-
- CN := Length(Channel[C].Note);
- SetLength(Channel[C].Note, CN+1);
-
- Channel[C].Note[CN].Start := MidiEvent.time;
- Channel[C].Note[CN].Len := MidiEvent.len;
- Channel[C].Note[CN].Event := MidiEvent.event;
- Channel[C].Note[CN].EventType := MidiEvent.event div 16;
- Channel[C].Note[CN].Channel := MidiEvent.event and 15;
- Channel[C].Note[CN].Data1 := MidiEvent.data1;
- Channel[C].Note[CN].Data2 := MidiEvent.data2;
- Channel[C].Note[CN].Str := MidiEvent.str;
-
- if Channel[C].Note[CN].Start + Channel[C].Note[CN].Len > Len then
- Len := Channel[C].Note[CN].Start + Channel[C].Note[CN].Len;
+ // notes available
+ Tracks[T].NoteType := ntAvail;
end;
- end;
- ATrack := Channel;
+ if Tracks[T].Note[N].Start + Tracks[T].Note[N].Len > Len then
+ Len := Tracks[T].Note[N].Start + Tracks[T].Note[N].Len;
+ end;
end;
- Interaction := 0;
+ // set default lyric track. Prefer KMIDI.
+ if (KMIDITrackIndex > -1) then
+ Tracks[KMIDITrackIndex].Status := Tracks[KMIDITrackIndex].Status + [tsLyrics]
+ else if (SMFTrackIndex > -1) then
+ Tracks[SMFTrackIndex].Status := Tracks[SMFTrackIndex].Status + [tsLyrics];
{$ENDIF}
end;
@@ -578,41 +731,44 @@ var
Y: real;
Height: real;
YSkip: real;
+ TrackName: UTF8String;
begin
// draw static menu
inherited Draw;
Y := 100;
- Height := min(480, 40 * Length(ATrack));
+ Height := min(480, 40 * Length(Tracks));
Bottom := Y + Height;
- if Length(ATrack) = 0 then // prevent crash with uncomplete code.
- begin
- Log.LogDebug ('UScreenEditConvert -> TScreenEditConvert.Draw:', 'Length(ATrack) = 0');
- YSkip := 40;
- end
- else
- YSkip := Height / Length(ATrack);
+ YSkip := Height / Length(Tracks);
- // select
- DrawQuad(10, Y + Sel*YSkip, 780, YSkip, 0.8, 0.8, 0.8);
+ // highlight selected track
+ DrawQuad(10, Y+SelTrack*YSkip, 780, YSkip, 0.8, 0.8, 0.8);
- // selected - now me use Status System
- for Count := 0 to High(ATrack) do
- if ATrack[Count].Hear then
+ // track-selection info
+ for Count := 0 to High(Tracks) do
+ if Tracks[Count].Status <> [] then
DrawQuad(10, Y + Count*YSkip, 50, YSkip, 0.8, 0.3, 0.3);
glColor3f(0, 0, 0);
- for Count := 0 to High(ATrack) do
+ for Count := 0 to High(Tracks) do
begin
- if Notes in ATrack[Count].Status then
+ if Tracks[Count].NoteType = ntAvail then
begin
+ if tsNotes in Tracks[Count].Status then
+ glColor3f(0, 0, 0)
+ else
+ glColor3f(0.7, 0.7, 0.7);
SetFontPos(25, Y + Count*YSkip + 10);
SetFontSize(15);
glPrint('N');
end;
- if Lyrics in ATrack[Count].Status then
+ if Tracks[Count].LyricType <> [] then
begin
+ if tsLyrics in Tracks[Count].Status then
+ glColor3f(0, 0, 0)
+ else
+ glColor3f(0.7, 0.7, 0.7);
SetFontPos(40, Y + Count*YSkip + 10);
SetFontSize(15);
glPrint('L');
@@ -623,51 +779,48 @@ begin
DrawLine( 60, Y, 60, Bottom, 0, 0, 0);
DrawLine(790, Y, 790, Bottom, 0, 0, 0);
- for Count := 0 to Length(ATrack) do
+ for Count := 0 to Length(Tracks) do
DrawLine(10, Y + Count*YSkip, 790, Y + Count*YSkip, 0, 0, 0);
- for Count := 0 to High(ATrack) do
+ for Count := 0 to High(Tracks) do
begin
- SetFontPos(11, Y + 10 + Count*YSkip);
+ SetFontPos(65, Y + Count*YSkip);
SetFontSize(15);
- glPrint(ATrack[Count].Name);
+ glPrint(Tracks[Count].Name);
end;
- for Count := 0 to High(ATrack) do
- for Count2 := 0 to High(ATrack[Count].Note) do
+ for Count := 0 to High(Tracks) do
+ begin
+ for Count2 := 0 to High(Tracks[Count].Note) do
begin
- if ATrack[Count].Note[Count2].EventType = 9 then
- DrawQuad(60 + ATrack[Count].Note[Count2].Start/Len*725,
- Y + (Count+1)*YSkip - ATrack[Count].Note[Count2].Data1*35/127,
- 3,
- 3,
- ColR[Count],
- ColG[Count],
- ColB[Count]);
- if ATrack[Count].Note[Count2].EventType = 15 then
- DrawLine(60 + ATrack[Count].Note[Count2].Start/Len*725,
- Y + 0.75*YSkip + Count*YSkip,
- 60 + ATrack[Count].Note[Count2].Start/Len*725,
- Y + YSkip + Count*YSkip,
- ColR[Count],
- ColG[Count],
- ColB[Count]);
+ if Tracks[Count].Note[Count2].EventType = MIDI_EVENTTYPE_NOTEON then
+ DrawQuad(60 + Tracks[Count].Note[Count2].Start/Len * 725,
+ Y + (Count+1)*YSkip - Tracks[Count].Note[Count2].Data1*35/127,
+ 3, 3,
+ ColR[Count], ColG[Count], ColB[Count]);
+ if Tracks[Count].Note[Count2].EventType = 15 then
+ DrawLine(60 + Tracks[Count].Note[Count2].Start/Len * 725, Y + 0.75 * YSkip + Count*YSkip,
+ 60 + Tracks[Count].Note[Count2].Start/Len * 725, Y + YSkip + Count*YSkip,
+ ColR[Count], ColG[Count], ColB[Count]);
end;
+ end;
// playing line
{$IFDEF UseMIDIPort}
- X := 60 + MidiFile.GetCurrentTime/MidiFile.GetTrackLength*730;
+ if (MidiFile <> nil) then
+ X := 60 + MidiFile.GetCurrentTime/MidiFile.GetTrackLength*730;
{$ENDIF}
DrawLine(X, Y, X, Bottom, 0.3, 0.3, 0.3);
Result := true;
end;
-procedure TScreenEditConvert.onHide;
+procedure TScreenEditConvert.OnHide;
begin
{$IFDEF UseMIDIPort}
+ FreeAndNil(MidiFile);
MidiOut.Close;
- MidiOut.Free;
+ FreeAndNil(MidiOut);
{$ENDIF}
end;
diff --git a/src/screens/UScreenEditHeader.pas b/src/screens/UScreenEditHeader.pas
index ad0fc40a..c581215b 100644
--- a/src/screens/UScreenEditHeader.pas
+++ b/src/screens/UScreenEditHeader.pas
@@ -38,6 +38,7 @@ uses
SDL,
USongs,
USong,
+ UPath,
UThemes;
type
@@ -72,8 +73,8 @@ type
procedure SetRoundButtons;
constructor Create; override;
- procedure onShow; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
{ function Draw: boolean; override;
procedure Finish;}
end;
@@ -86,17 +87,18 @@ uses
SysUtils,
UFiles,
USkins,
- UTexture;
+ UTexture,
+ UUnicodeUtils;
-function TScreenEditHeader.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenEditHeader.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
T: integer;
begin
Result := true;
if (PressedDown) then // Key Down
begin // check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -105,10 +107,10 @@ begin
// check special keys
case PressedKey of
- SDLK_ESCAPE :
+ SDLK_ESCAPE:
begin
-// Music.PlayBack;
-// FadeTo(@MainScreen);
+ //Music.PlayBack;
+ //FadeTo(@MainScreen);
Result := false;
end;
@@ -116,7 +118,7 @@ begin
begin
if Interaction = 1 then
begin
-// Save;
+ //Save;
end;
end;
@@ -159,19 +161,19 @@ begin
T := Interaction - 2 + TextTitle;
if (Interaction >= 2) and (Interaction <= 13) and (Length(Text[T].Text) >= 1) then
begin
- Text[T].DeleteLastL;
+ Text[T].DeleteLastLetter;
SetRoundButtons;
end;
end;
end;
case CharCode of
- #32..#255:
+ 32..255:
begin
if (Interaction >= 2) and (Interaction <= 13) then
begin
Text[Interaction - 2 + TextTitle].Text :=
- Text[Interaction - 2 + TextTitle].Text + CharCode;
+ Text[Interaction - 2 + TextTitle].Text + UCS4ToUTF8String(CharCode);
SetRoundButtons;
end;
end;
@@ -223,18 +225,18 @@ begin
TextGAP := AddText(340, 110 + 13*30, 0, 30, 0, 0, 0, '');
TextBPM := AddText(340, 110 + 14*30, 0, 30, 0, 0, 0, '');
- StaticTitle := AddStatic(130, 115 + 0*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticArtist := AddStatic(130, 115 + 1*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticMp3 := AddStatic(130, 115 + 2*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticBackground := AddStatic(130, 115 + 4*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticVideo := AddStatic(130, 115 + 5*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticVideoGAP := AddStatic(130, 115 + 6*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticRelative := AddStatic(130, 115 + 8*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticResolution := AddStatic(130, 115 + 9*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticNotesGAP := AddStatic(130, 115 + 10*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticStart := AddStatic(130, 115 + 12*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticGAP := AddStatic(130, 115 + 13*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
- StaticBPM := AddStatic(130, 115 + 14*30, 20, 20, 1, 1, 1, 'RoundButton', TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticTitle := AddStatic(130, 115 + 0*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticArtist := AddStatic(130, 115 + 1*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticMp3 := AddStatic(130, 115 + 2*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticBackground := AddStatic(130, 115 + 4*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticVideo := AddStatic(130, 115 + 5*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticVideoGAP := AddStatic(130, 115 + 6*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticRelative := AddStatic(130, 115 + 8*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticResolution := AddStatic(130, 115 + 9*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticNotesGAP := AddStatic(130, 115 + 10*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticStart := AddStatic(130, 115 + 12*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticGAP := AddStatic(130, 115 + 13*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
+ StaticBPM := AddStatic(130, 115 + 14*30, 20, 20, 1, 1, 1, Path('RoundButton'), TEXTURE_TYPE_TRANSPARENT, $FF00FF);
AddInteraction(iText, TextTitle);
AddInteraction(iText, TextArtist);
@@ -250,7 +252,7 @@ begin
AddInteraction(iText, TextBPM);
end;
-procedure TScreenEditHeader.onShow;
+procedure TScreenEditHeader.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenEditSub.pas b/src/screens/UScreenEditSub.pas
index 3e1f3c1c..00e62c16 100644
--- a/src/screens/UScreenEditSub.pas
+++ b/src/screens/UScreenEditSub.pas
@@ -116,11 +116,11 @@ type
Tex_Background: TTexture;
FadeOut: boolean;
constructor Create; override;
- procedure onShow; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- function ParseInputEditText(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+ procedure OnShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ function ParseInputEditText(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
function Draw: boolean; override;
- procedure onHide; override;
+ procedure OnHide; override;
end;
implementation
@@ -130,14 +130,44 @@ uses
UDraw,
UNote,
USkins,
- ULanguage;
+ ULanguage,
+ UTextEncoding,
+ UUnicodeUtils,
+ UPath;
+
+
+procedure OnSaveEncodingError(Value: boolean; Data: Pointer);
+var
+ SResult: TSaveSongResult;
+ FilePath: IPath;
+ Success: boolean;
+begin
+ Success := false;
+ if (Value) then
+ begin
+ CurrentSong.Encoding := encUTF8;
+ FilePath := CurrentSong.Path.Append(CurrentSong.FileName);
+ // create backup file
+ FilePath.CopyFile(Path(FilePath.ToUTF8 + '.ansi.bak'), false);
+ // store in UTF-8 encoding
+ SResult := SaveSong(CurrentSong, Lines[0], FilePath,
+ boolean(Data));
+ Success := (SResult = ssrOK);
+ end;
+
+ if (Success) then
+ ScreenPopupInfo.ShowPopup(Language.Translate('INFO_FILE_SAVED'))
+ else
+ ScreenPopupError.ShowPopup(Language.Translate('ERROR_SAVE_FILE_FAILED'));
+end;
// Method for input parsing. If false is returned, GetNextWindow
// should be checked to know the next window to load;
-function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
SDL_ModState: word;
R: real;
+ SResult: TSaveSongResult;
begin
Result := true;
@@ -152,40 +182,47 @@ begin
+ KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS});
if (PressedDown) then // Key Down
- begin // check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ begin
+ // check normal keys
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
end;
- 'S':
+ Ord('S'):
begin
// Save Song
- if SDL_ModState = KMOD_LSHIFT then
- SaveSong(CurrentSong, Lines[0], CurrentSong.Path + CurrentSong.FileName, true)
+ SResult := SaveSong(CurrentSong, Lines[0], CurrentSong.Path.Append(CurrentSong.FileName),
+ (SDL_ModState = KMOD_LSHIFT));
+ if (SResult = ssrOK) then
+ begin
+ ScreenPopupInfo.ShowPopup(Language.Translate('INFO_FILE_SAVED'));
+ end
+ else if (SResult = ssrEncodingError) then
+ begin
+ ScreenPopupCheck.ShowPopup(Language.Translate('ENCODING_ERROR_ASK_FOR_UTF8'), OnSaveEncodingError,
+ Pointer(SDL_ModState = KMOD_LSHIFT), true);
+ end
else
- SaveSong(CurrentSong, Lines[0], CurrentSong.Path + CurrentSong.FileName, false);
-
- {if SDL_ModState = KMOD_LSHIFT or KMOD_LCTRL + KMOD_LALT then
- // Save Song
- SaveSongDebug(CurrentSong, Lines[0], 'C:\song.asm', false);}
-
+ begin
+ ScreenPopupError.ShowPopup(Language.Translate('ERROR_SAVE_FILE_FAILED'));
+ end;
Exit;
end;
- 'D':
+ Ord('D'):
begin
// Divide lengths by 2
DivideBPM;
Exit;
end;
- 'M':
+ Ord('M'):
begin
// Multiply lengths by 2
MultiplyBPM;
Exit;
end;
- 'C':
+ Ord('C'):
begin
// Capitalize letter at the beginning of line
if SDL_ModState = 0 then
@@ -201,7 +238,7 @@ begin
Exit;
end;
- 'V':
+ Ord('V'):
begin
// Paste text
if SDL_ModState = KMOD_LCTRL then
@@ -217,13 +254,13 @@ begin
CopySentence(CopySrc, Lines[0].Current);
end;
end;
- 'T':
+ Ord('T'):
begin
// Fixes timings between sentences
FixTimings;
Exit;
end;
- 'P':
+ Ord('P'):
begin
if SDL_ModState = 0 then
begin
@@ -269,8 +306,8 @@ begin
Exit;
end;
- // Golden Note Patch
- 'G':
+ // Golden Note
+ Ord('G'):
begin
if (Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType = ntGolden) then
Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntNormal
@@ -280,8 +317,8 @@ begin
Exit;
end;
- // Freestyle Note Patch
- 'F':
+ // Freestyle Note
+ Ord('F'):
begin
if (Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType = ntFreestyle) then
Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntNormal
@@ -580,10 +617,11 @@ begin
// skip to next sentence
if SDL_ModState = 0 then
- begin {$IFDEF UseMIDIPort}
+ begin
+ {$IFDEF UseMIDIPort}
MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127);
PlaySentenceMidi := false;
- {$endif}
+ {$ENDIF}
Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 0;
Inc(Lines[0].Current);
@@ -642,7 +680,7 @@ begin
end; // if
end;
-function TScreenEditSub.ParseInputEditText(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenEditSub.ParseInputEditText(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
SDL_ModState: word;
begin
@@ -653,7 +691,16 @@ begin
+ KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS});
if (PressedDown) then
- begin // Key Down
+ begin
+ // check normal keys
+ if (IsPrintableChar(CharCode)) then
+ begin
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text :=
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text + UCS4ToUTF8String(CharCode);
+ Exit;
+ end;
+
+ // check special keys
case PressedKey of
SDLK_ESCAPE:
@@ -665,15 +712,10 @@ begin
// Exit Text Edit Mode
TextEditMode := false;
end;
- SDLK_0..SDLK_9, SDLK_A..SDLK_Z, SDLK_SPACE, SDLK_MINUS, SDLK_EXCLAIM, SDLK_COMMA, SDLK_SLASH, SDLK_ASTERISK, SDLK_QUESTION, SDLK_QUOTE, SDLK_QUOTEDBL:
- begin
- Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text :=
- Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text + CharCode;
- end;
SDLK_BACKSPACE:
begin
- Delete(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text,
- Length(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text), 1);
+ UTF8Delete(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text,
+ LengthUTF8(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Text), 1);
end;
SDLK_RIGHT:
begin
@@ -758,9 +800,11 @@ var
S: string;
begin
// temporary
-{ for C := 0 to Lines[0].High do
+ {
+ for C := 0 to Lines[0].High do
for N := 0 to Lines[0].Line[C].HighNut do
- Lines[0].Line[C].Note[N].Text := AnsiLowerCase(Lines[0].Line[C].Note[N].Text);}
+ Lines[0].Line[C].Note[N].Text := UTF8LowerCase(Lines[0].Line[C].Note[N].Text);
+ }
for C := 0 to Lines[0].High do
begin
@@ -1085,14 +1129,16 @@ var
N: integer;
NHigh: integer;
begin
-{ C := Lines[0].Current;
+ {
+ C := Lines[0].Current;
for N := Lines[0].Line[C].HighNut downto 1 do
begin
Lines[0].Line[C].Note[N].Text := Lines[0].Line[C].Note[N-1].Text;
end; // for
- Lines[0].Line[C].Note[0].Text := '- ';}
+ Lines[0].Line[C].Note[0].Text := '- ';
+ }
C := Lines[0].Current;
NHigh := Lines[0].Line[C].HighNote;
@@ -1233,21 +1279,24 @@ begin
end;
-procedure TScreenEditSub.onShow;
+procedure TScreenEditSub.OnShow;
+var
+ FileExt: IPath;
begin
inherited;
- Log.LogStatus('Initializing', 'TEditScreen.onShow');
+ Log.LogStatus('Initializing', 'TEditScreen.OnShow');
Lyric := TEditorLyrics.Create;
ResetSingTemp;
try
- //Check if File is XML
- if copy(CurrentSong.FileName,length(CurrentSong.FileName)-3,4) = '.xml' then
- Error := not CurrentSong.LoadXMLSong()
- else
- Error := not CurrentSong.LoadSong();
+ //Check if File is XML
+ FileExt := CurrentSong.FileName.GetExtension;
+ if FileExt.ToUTF8 = '.xml' then
+ Error := not CurrentSong.LoadXMLSong()
+ else
+ Error := not CurrentSong.LoadSong();
except
Error := true;
end;
@@ -1269,12 +1318,12 @@ begin
{$ENDIF}
Text[TextTitle].Text := CurrentSong.Title;
Text[TextArtist].Text := CurrentSong.Artist;
- Text[TextMp3].Text := CurrentSong.Mp3;
+ Text[TextMp3].Text := CurrentSong.Mp3.ToUTF8;
Lines[0].Current := 0;
CurrentNote := 0;
Lines[0].Line[0].Note[0].Color := 1;
- AudioPlayback.Open(CurrentSong.Path + CurrentSong.Mp3);
+ AudioPlayback.Open(CurrentSong.Path.Append(CurrentSong.Mp3));
//Set Down Music Volume for Better hearability of Midi Sounds
//Music.SetVolume(0.4);
@@ -1412,7 +1461,7 @@ begin
Result := true;
end;
-procedure TScreenEditSub.onHide;
+procedure TScreenEditSub.OnHide;
begin
{$IFDEF UseMIDIPort}
MidiOut.Close;
diff --git a/src/screens/UScreenLevel.pas b/src/screens/UScreenLevel.pas
index b41a8535..4d7d8b5e 100644
--- a/src/screens/UScreenLevel.pas
+++ b/src/screens/UScreenLevel.pas
@@ -46,8 +46,8 @@ type
TScreenLevel = class(TMenu)
public
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
end;
@@ -58,16 +58,17 @@ uses
UMain,
UIni,
USong,
- UTexture;
+ UTexture,
+ UUnicodeUtils;
-function TScreenLevel.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenLevel.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -119,7 +120,7 @@ begin
Interaction := 0;
end;
-procedure TScreenLevel.onShow;
+procedure TScreenLevel.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenLoading.pas b/src/screens/UScreenLoading.pas
index ea639ba3..e368f181 100644
--- a/src/screens/UScreenLoading.pas
+++ b/src/screens/UScreenLoading.pas
@@ -43,10 +43,11 @@ uses
type
TScreenLoading = class(TMenu)
public
- Fadeout: boolean;
+ Fadeout: boolean;
+
constructor Create; override;
- procedure onShow; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
end;
implementation
@@ -55,7 +56,7 @@ uses
UGraphic,
UTime;
-function TScreenLoading.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenLoading.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
end;
@@ -69,7 +70,7 @@ begin
Fadeout := false;
end;
-procedure TScreenLoading.onShow;
+procedure TScreenLoading.OnShow;
begin
inherited;
end;
diff --git a/src/screens/UScreenMain.pas b/src/screens/UScreenMain.pas
index a4e6009f..7237eb80 100644
--- a/src/screens/UScreenMain.pas
+++ b/src/screens/UScreenMain.pas
@@ -49,9 +49,9 @@ type
TextDescriptionLong: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: widechar;
+ function ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ procedure OnShow; override;
procedure SetInteraction(Num: integer); override;
procedure SetAnimationProgress(Progress: real); override;
end;
@@ -69,9 +69,10 @@ uses
UParty,
UDLLManager,
UScreenCredits,
- USkins;
+ USkins,
+ UUnicodeUtils;
-function TScreenMain.ParseInput(PressedKey: cardinal; CharCode: widechar;
+function TScreenMain.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean;
var
SDL_ModState: word;
@@ -84,22 +85,19 @@ begin
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
- begin
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'): begin
Result := false;
Exit;
end;
- 'C':
- begin
+ Ord('C'): begin
if (SDL_ModState = KMOD_LALT) then
begin
FadeTo(@ScreenCredits, SoundLib.Start);
Exit;
end;
end;
- 'M':
- begin
+ Ord('M'): begin
if (Ini.Players >= 1) and (Length(DLLMan.Plugins) >= 1) then
begin
FadeTo(@ScreenPartyOptions, SoundLib.Start);
@@ -107,14 +105,12 @@ begin
end;
end;
- 'S':
- begin
+ Ord('S'): begin
FadeTo(@ScreenStatMain, SoundLib.Start);
Exit;
end;
- 'E':
- begin
+ Ord('E'): begin
FadeTo(@ScreenEdit, SoundLib.Start);
Exit;
end;
@@ -172,7 +168,11 @@ begin
//Editor
if Interaction = 3 then
begin
+ {$IFDEF UseMIDIPort}
FadeTo(@ScreenEdit, SoundLib.Start);
+ {$ELSE}
+ ScreenPopupError.ShowPopup(Language.Translate('ERROR_NO_EDITOR'));
+ {$ENDIF}
end;
//Options
@@ -232,7 +232,7 @@ begin
Interaction := 0;
end;
-procedure TScreenMain.onShow;
+procedure TScreenMain.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenName.pas b/src/screens/UScreenName.pas
index d13db170..42af50d7 100644
--- a/src/screens/UScreenName.pas
+++ b/src/screens/UScreenName.pas
@@ -47,8 +47,8 @@ type
public
Goto_SingScreen: boolean; //If true then next Screen in SingScreen
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
end;
@@ -59,9 +59,11 @@ uses
UGraphic,
UIni,
UNote,
- UTexture;
+ UTexture,
+ UUnicodeUtils;
-function TScreenName.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+
+function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
I: integer;
SDL_ModState: word;
@@ -74,10 +76,10 @@ begin
+ KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT);
// check normal keys
- if (IsAlphaNumericChar(CharCode) or
- {(CharCode in [' ','-','_','!',',','<','/','*','?','''','"']))} IsPunctuationChar(CharCode)) then
+ if (IsPrintableChar(CharCode)) then
begin
- Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text + CharCode;
+ Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text +
+ UCS4ToUTF8String(CharCode);
Exit;
end;
@@ -195,7 +197,7 @@ begin
SDLK_BACKSPACE:
begin
- Button[Interaction].Text[0].DeleteLastL;
+ Button[Interaction].Text[0].DeleteLastLetter();
end;
SDLK_ESCAPE :
@@ -248,7 +250,7 @@ begin
Interaction := 0;
end;
-procedure TScreenName.onShow;
+procedure TScreenName.OnShow;
var
I: integer;
begin
diff --git a/src/screens/UScreenOpen.pas b/src/screens/UScreenOpen.pas
index a854e81b..70b883c4 100644
--- a/src/screens/UScreenOpen.pas
+++ b/src/screens/UScreenOpen.pas
@@ -34,10 +34,13 @@ interface
{$I switches.inc}
uses
+ Math,
+ SysUtils,
+ gl,
+ SDL,
+ UPath,
UMenu,
UMusic,
- SDL,
- SysUtils,
UFiles,
UTime,
USongs,
@@ -46,26 +49,31 @@ uses
UTexture,
UMenuText,
ULyrics,
- Math,
- gl,
UThemes;
type
TScreenOpen = class(TMenu)
private
- TextF: array[0..1] of integer;
- TextN: integer;
- public
- Tex_Background: TTexture;
- FadeOut: boolean;
- Path: string;
- BackScreen: pointer;
+ //fTextF: array[0..1] of integer;
+ fTextN: integer; // text-box ID of filename
+ fFilename: IPath;
+ fBackScreen: PMenu;
+
procedure AddBox(X, Y, W, H: real);
+ public
constructor Create; override;
- procedure onShow; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
-// function Draw: boolean; override;
-// procedure Finish;
+ procedure OnShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+
+ {**
+ * Set by the caller to provide a default filename.
+ * Set to the selected filename after calling this screen or to PATH_NONE
+ * if the screen was aborted.
+ * TODO: maybe pass this value with a callback OnValueChanged()
+ *}
+ property Filename: IPath READ fFilename WRITE fFilename;
+ {** The screen that is shown after this screen is closed (set by the caller) *}
+ property BackScreen: PMenu READ fBackScreen WRITE fBackScreen;
end;
implementation
@@ -75,45 +83,41 @@ uses
UDraw,
UMain,
UScreenEditConvert,
- USkins;
+ USkins,
+ UUnicodeUtils;
-function TScreenOpen.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOpen.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then // Key Down
begin
// check normal keys
- case CharCode of
- '0'..'9', 'a'..'z', 'A'..'Z', ' ', '-', '.', ':', '\':
- begin
- if Interaction = 0 then
- begin
- Text[TextN].Text := Text[TextN].Text + CharCode;
- end;
- end;
+ if (IsPrintableChar(CharCode)) then
+ begin
+ if (Interaction = 0) then
+ begin
+ Text[fTextN].Text := Text[fTextN].Text + UCS4ToUTF8String(CharCode);
+ Exit;
+ end;
end;
// check special keys
case PressedKey of
- SDLK_Q:
- begin
- Result := false;
- end;
- 8: // del
+ SDLK_BACKSPACE: // del
begin
if Interaction = 0 then
begin
- Text[TextN].DeleteLastL;
+ Text[fTextN].DeleteLastLetter;
end;
end;
SDLK_ESCAPE:
begin
//Empty Filename and go to last Screen
- ConversionFileName := '';
+ fFileName := PATH_NONE;
AudioPlayback.PlaySound(SoundLib.Back);
- FadeTo(BackScreen);
+ FadeTo(fBackScreen);
end;
SDLK_RETURN:
@@ -121,16 +125,16 @@ begin
if (Interaction = 2) then
begin
//Update Filename and go to last Screen
- ConversionFileName := Text[TextN].Text;
+ fFileName := Path(Text[fTextN].Text);
AudioPlayback.PlaySound(SoundLib.Back);
- FadeTo(BackScreen);
+ FadeTo(fBackScreen);
end
else if (Interaction = 1) then
begin
//Empty Filename and go to last Screen
- ConversionFileName := '';
+ fFileName := PATH_NONE;
AudioPlayback.PlaySound(SoundLib.Back);
- FadeTo(BackScreen);
+ FadeTo(fBackScreen);
end;
end;
@@ -165,21 +169,25 @@ constructor TScreenOpen.Create;
begin
inherited Create;
+ fFilename := PATH_NONE;
+
// line
-{ AddStatic(20, 10, 80, 30, 0, 0, 0, 'MainBar', 'JPG', TEXTURE_TYPE_COLORIZED);
+ {
+ AddStatic(20, 10, 80, 30, 0, 0, 0, 'MainBar', 'JPG', TEXTURE_TYPE_COLORIZED);
AddText(35, 17, 1, 18, 1, 1, 1, 'line');
- TextSentence := AddText(120, 14, 1, 24, 0, 0, 0, '0 / 0');}
+ TextSentence := AddText(120, 14, 1, 24, 0, 0, 0, '0 / 0');
+ }
// file list
-// AddBox(400, 100, 350, 450);
+ //AddBox(400, 100, 350, 450);
-// TextF[0] := AddText(430, 155, 0, 24, 0, 0, 0, 'a');
-// TextF[1] := AddText(430, 180, 0, 24, 0, 0, 0, 'a');
+ //TextF[0] := AddText(430, 155, 0, 24, 0, 0, 0, 'a');
+ //TextF[1] := AddText(430, 180, 0, 24, 0, 0, 0, 'a');
// file name
AddBox(20, 540, 500, 40);
- TextN := AddText(50, 548, 0, 24, 0, 0, 0, ConversionFileName);
- AddInteraction(iText, TextN);
+ fTextN := AddText(50, 548, 0, 24, 0, 0, 0, fFileName.ToUTF8);
+ AddInteraction(iText, fTextN);
// buttons
{AddButton(540, 540, 100, 40, Skin.SkinPath + Skin.ButtonF);
@@ -196,11 +204,12 @@ begin
end;
-procedure TScreenOpen.onShow;
+procedure TScreenOpen.OnShow;
begin
inherited;
Interaction := 0;
+ Text[fTextN].Text := fFilename.ToUTF8();
end;
(*
diff --git a/src/screens/UScreenOptions.pas b/src/screens/UScreenOptions.pas
index a6486075..3a046400 100644
--- a/src/screens/UScreenOptions.pas
+++ b/src/screens/UScreenOptions.pas
@@ -34,9 +34,9 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
SysUtils,
+ UMenu,
UDisplay,
UMusic,
UFiles,
@@ -48,8 +48,8 @@ type
public
TextDescription: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure InteractNext; override;
procedure InteractPrev; override;
procedure InteractNextRow; override;
@@ -60,16 +60,17 @@ type
implementation
uses
- UGraphic;
+ UGraphic,
+ UUnicodeUtils;
-function TScreenOptions.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOptions.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -189,7 +190,7 @@ begin
Interaction := 0;
end;
-procedure TScreenOptions.onShow;
+procedure TScreenOptions.OnShow;
begin
inherited;
end;
diff --git a/src/screens/UScreenOptionsAdvanced.pas b/src/screens/UScreenOptionsAdvanced.pas
index 0fb8153c..7116ad40 100644
--- a/src/screens/UScreenOptionsAdvanced.pas
+++ b/src/screens/UScreenOptionsAdvanced.pas
@@ -34,8 +34,8 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
+ UMenu,
UDisplay,
UMusic,
UFiles,
@@ -46,24 +46,25 @@ type
TScreenOptionsAdvanced = class(TMenu)
public
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
end;
implementation
uses
UGraphic,
+ UUnicodeUtils,
SysUtils;
-function TScreenOptionsAdvanced.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOptionsAdvanced.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -160,7 +161,7 @@ begin
Interaction := 0;
end;
-procedure TScreenOptionsAdvanced.onShow;
+procedure TScreenOptionsAdvanced.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenOptionsGame.pas b/src/screens/UScreenOptionsGame.pas
index 0c152c41..caeaad6e 100644
--- a/src/screens/UScreenOptionsGame.pas
+++ b/src/screens/UScreenOptionsGame.pas
@@ -35,40 +35,39 @@ interface
uses
SDL,
+ UMenu,
UDisplay,
+ UMusic,
UFiles,
UIni,
- UMenu,
- UMusic,
- USongs,
- UThemes;
+ UThemes,
+ USongs;
type
TScreenOptionsGame = class(TMenu)
public
old_Tabs, old_Sorting: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure RefreshSongs;
end;
implementation
uses
- SysUtils,
- UGraphic;
+ UGraphic,
+ UUnicodeUtils,
+ SysUtils;
-function TScreenOptionsGame.ParseInput(PressedKey: cardinal;
- CharCode: WideChar;
- PressedDown: boolean): boolean;
+function TScreenOptionsGame.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if PressedDown then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -166,7 +165,7 @@ begin
ScreenSong.Refresh;
end;
-procedure TScreenOptionsGame.onShow;
+procedure TScreenOptionsGame.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenOptionsGraphics.pas b/src/screens/UScreenOptionsGraphics.pas
index ba1465b2..8ca13f09 100644
--- a/src/screens/UScreenOptionsGraphics.pas
+++ b/src/screens/UScreenOptionsGraphics.pas
@@ -46,8 +46,8 @@ type
TScreenOptionsGraphics = class(TMenu)
public
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
end;
implementation
@@ -55,17 +55,17 @@ implementation
uses
UGraphic,
UMain,
- SysUtils,
- TypInfo;
+ UUnicodeUtils,
+ SysUtils;
-function TScreenOptionsGraphics.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOptionsGraphics.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -162,7 +162,7 @@ begin
end;
-procedure TScreenOptionsGraphics.onShow;
+procedure TScreenOptionsGraphics.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenOptionsLyrics.pas b/src/screens/UScreenOptionsLyrics.pas
index 035b0089..0ef4e2a6 100644
--- a/src/screens/UScreenOptionsLyrics.pas
+++ b/src/screens/UScreenOptionsLyrics.pas
@@ -46,24 +46,25 @@ type
TScreenOptionsLyrics = class(TMenu)
public
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
end;
implementation
uses
UGraphic,
+ UUnicodeUtils,
SysUtils;
-function TScreenOptionsLyrics.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOptionsLyrics.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -137,7 +138,7 @@ begin
end;
-procedure TScreenOptionsLyrics.onShow;
+procedure TScreenOptionsLyrics.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenOptionsRecord.pas b/src/screens/UScreenOptionsRecord.pas
index 7eb2ced7..828c20f6 100644
--- a/src/screens/UScreenOptionsRecord.pas
+++ b/src/screens/UScreenOptionsRecord.pas
@@ -61,8 +61,8 @@ type
PreviewDeviceIndex: integer;
// string arrays for select-slide options
- InputSourceNames: array of string;
- InputDeviceNames: array of string;
+ InputSourceNames: array of UTF8String;
+ InputDeviceNames: array of UTF8String;
// dynamic generated themes for channel select-sliders
SelectSlideChannelTheme: array of TThemeSelectSlide;
@@ -95,9 +95,9 @@ type
public
constructor Create; override;
function Draw: boolean; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
- procedure onHide; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
+ procedure OnHide; override;
end;
const
@@ -126,33 +126,34 @@ uses
UFiles,
UDisplay,
UIni,
+ UUnicodeUtils,
ULog;
-function TScreenOptionsRecord.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOptionsRecord.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
end;
- '+':
+ Ord('+'):
begin
// FIXME: add a nice volume-slider instead
// or at least provide visualization and acceleration if the user holds the key pressed.
ChangeVolume(0.02);
end;
- '-':
+ Ord('-'):
begin
// FIXME: add a nice volume-slider instead
// or at least provide visualization and acceleration if the user holds the key pressed.
ChangeVolume(-0.02);
end;
- 'T':
+ Ord('T'):
begin
if ((SDL_GetModState() and KMOD_SHIFT) <> 0) then
Ini.ThresholdIndex := (Ini.ThresholdIndex + Length(IThresholdVals) - 1) mod Length(IThresholdVals)
@@ -418,7 +419,7 @@ begin
NextVolumePollTime := 0;
end;
-procedure TScreenOptionsRecord.onShow;
+procedure TScreenOptionsRecord.OnShow;
var
ChannelIndex: integer;
begin
@@ -436,7 +437,7 @@ begin
StartPreview();
end;
-procedure TScreenOptionsRecord.onHide;
+procedure TScreenOptionsRecord.OnHide;
var
ChannelIndex: integer;
begin
diff --git a/src/screens/UScreenOptionsSound.pas b/src/screens/UScreenOptionsSound.pas
index aa87ceb4..7556dceb 100644
--- a/src/screens/UScreenOptionsSound.pas
+++ b/src/screens/UScreenOptionsSound.pas
@@ -34,8 +34,8 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
+ UMenu,
UDisplay,
UMusic,
UFiles,
@@ -46,26 +46,27 @@ type
TScreenOptionsSound = class(TMenu)
public
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: widechar;
+ function ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ procedure OnShow; override;
end;
implementation
uses
UGraphic,
+ UUnicodeUtils,
SysUtils;
function TScreenOptionsSound.ParseInput(PressedKey: cardinal;
- CharCode: widechar; PressedDown: boolean): boolean;
+ CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -177,7 +178,7 @@ begin
Interaction := 0;
end;
-procedure TScreenOptionsSound.onShow;
+procedure TScreenOptionsSound.OnShow;
begin
inherited;
Interaction := 0;
diff --git a/src/screens/UScreenOptionsThemes.pas b/src/screens/UScreenOptionsThemes.pas
index 1e7407f1..dca581a2 100644
--- a/src/screens/UScreenOptionsThemes.pas
+++ b/src/screens/UScreenOptionsThemes.pas
@@ -49,8 +49,8 @@ type
public
SkinSelect: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure InteractInc; override;
procedure InteractDec; override;
end;
@@ -61,17 +61,18 @@ uses
SysUtils,
UGraphic,
UMain,
- UPath,
+ UPathUtils,
+ UUnicodeUtils,
USkins;
-function TScreenOptionsThemes.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenOptionsThemes.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -135,7 +136,7 @@ begin
if (SelInteraction = 0) then
begin
Skin.OnThemeChange;
- UpdateSelectSlideOptions (Theme.OptionsThemes.SelectSkin, SkinSelect, ISkin, Ini.SkinNo);
+ UpdateSelectSlideOptions(Theme.OptionsThemes.SelectSkin, SkinSelect, ISkin, Ini.SkinNo);
end;
ReloadTheme();
@@ -178,7 +179,7 @@ begin
AddButtonText(14, 20, Theme.Options.Description[7]);
end;
-procedure TScreenOptionsThemes.onShow;
+procedure TScreenOptionsThemes.OnShow;
begin
inherited;
@@ -187,7 +188,7 @@ end;
procedure TScreenOptionsThemes.ReloadTheme;
begin
- Theme.LoadTheme(ThemePath + ITheme[Ini.Theme] + '.ini', Ini.Color);
+ Theme.LoadTheme(ThemePath.Append(ITheme[Ini.Theme] + '.ini'), Ini.Color);
ScreenOptionsThemes := TScreenOptionsThemes.create();
ScreenOptionsThemes.onshow;
diff --git a/src/screens/UScreenPartyNewRound.pas b/src/screens/UScreenPartyNewRound.pas
index 03a72fa9..c4295502 100644
--- a/src/screens/UScreenPartyNewRound.pas
+++ b/src/screens/UScreenPartyNewRound.pas
@@ -34,12 +34,12 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
+ SysUtils,
+ UMenu,
UDisplay,
UMusic,
UFiles,
- SysUtils,
UThemes;
type
@@ -99,8 +99,8 @@ type
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
end;
@@ -115,16 +115,17 @@ uses
UDLLManager,
ULanguage,
USong,
- ULog;
+ ULog,
+ UUnicodeUtils;
-function TScreenPartyNewRound.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenPartyNewRound.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -215,12 +216,12 @@ begin
LoadFromTheme(Theme.PartyNewRound);
end;
-procedure TScreenPartyNewRound.onShow;
+procedure TScreenPartyNewRound.OnShow;
var
I: integer;
- function GetTeamPlayers(const Num: byte): string;
+ function GetTeamPlayers(const Num: byte): UTF8String;
var
- Players: array of string;
+ Players: array of UTF8String;
J: byte;
begin
if (Num-1 >= PartySession.Teams.NumTeams) then
@@ -229,7 +230,7 @@ var
//Create Players array
SetLength(Players, PartySession.Teams.TeamInfo[Num-1].NumPlayers);
for J := 0 to PartySession.Teams.TeamInfo[Num-1].NumPlayers-1 do
- Players[J] := string(PartySession.Teams.TeamInfo[Num-1].PlayerInfo[J].Name);
+ Players[J] := UTF8String(PartySession.Teams.TeamInfo[Num-1].PlayerInfo[J].Name);
//Implode and Return
Result := Language.Implode(Players);
@@ -364,7 +365,7 @@ begin
if (PartySession.Teams.NumTeams >= 1) then
begin
Text[TextScoreTeam1].Text := InttoStr(PartySession.Teams.TeamInfo[0].Score);
- Text[TextNameTeam1].Text := string(PartySession.Teams.TeamInfo[0].Name);
+ Text[TextNameTeam1].Text := UTF8String(PartySession.Teams.TeamInfo[0].Name);
Text[TextTeam1Players].Text := GetTeamPlayers(1);
Text[TextScoreTeam1].Visible := true;
@@ -385,7 +386,7 @@ begin
if (PartySession.Teams.NumTeams >= 2) then
begin
Text[TextScoreTeam2].Text := InttoStr(PartySession.Teams.TeamInfo[1].Score);
- Text[TextNameTeam2].Text := string(PartySession.Teams.TeamInfo[1].Name);
+ Text[TextNameTeam2].Text := UTF8String(PartySession.Teams.TeamInfo[1].Name);
Text[TextTeam2Players].Text := GetTeamPlayers(2);
Text[TextScoreTeam2].Visible := true;
@@ -406,7 +407,7 @@ begin
if (PartySession.Teams.NumTeams >= 3) then
begin
Text[TextScoreTeam3].Text := InttoStr(PartySession.Teams.TeamInfo[2].Score);
- Text[TextNameTeam3].Text := string(PartySession.Teams.TeamInfo[2].Name);
+ Text[TextNameTeam3].Text := UTF8String(PartySession.Teams.TeamInfo[2].Name);
Text[TextTeam3Players].Text := GetTeamPlayers(3);
Text[TextScoreTeam3].Visible := true;
diff --git a/src/screens/UScreenPartyOptions.pas b/src/screens/UScreenPartyOptions.pas
index 5f7f1d9e..2deffda6 100644
--- a/src/screens/UScreenPartyOptions.pas
+++ b/src/screens/UScreenPartyOptions.pas
@@ -61,20 +61,20 @@ type
NumPlayer1, NumPlayer2, NumPlayer3: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
procedure SetPlaylist2;
end;
var
- IPlaylist: array[0..2] of string;
- IPlaylist2: array of string;
+ IPlaylist: array[0..2] of UTF8String;
+ IPlaylist2: array of UTF8String;
const
- ITeams: array[0..1] of string = ('2', '3');
- IPlayers: array[0..3] of string = ('1', '2', '3', '4');
- IRounds: array[0..5] of string = ('2', '3', '4', '5', '6', '7');
+ ITeams: array[0..1] of UTF8String = ('2', '3');
+ IPlayers: array[0..3] of UTF8String = ('1', '2', '3', '4');
+ IRounds: array[0..5] of UTF8String = ('2', '3', '4', '5', '6', '7');
implementation
@@ -88,9 +88,10 @@ uses
USong,
UDLLManager,
UPlaylist,
- USongs;
+ USongs,
+ UUnicodeUtils;
-function TScreenPartyOptions.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenPartyOptions.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
I, J: integer;
OnlyMultiPlayer: boolean;
@@ -99,8 +100,8 @@ begin
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -239,14 +240,14 @@ begin
//Load Screen From Theme
LoadFromTheme(Theme.PartyOptions);
- SelectLevel := AddSelectSlide (Theme.PartyOptions.SelectLevel, Ini.Difficulty, Theme.ILevel);
- SelectPlayList := AddSelectSlide (Theme.PartyOptions.SelectPlayList, PlayList, IPlaylist);
- SelectPlayList2 := AddSelectSlide (Theme.PartyOptions.SelectPlayList2, PlayList2, IPlaylist2);
- SelectRounds := AddSelectSlide (Theme.PartyOptions.SelectRounds, Rounds, IRounds);
- SelectTeams := AddSelectSlide (Theme.PartyOptions.SelectTeams, NumTeams, ITeams);
- SelectPlayers1 := AddSelectSlide (Theme.PartyOptions.SelectPlayers1, NumPlayer1, IPlayers);
- SelectPlayers2 := AddSelectSlide (Theme.PartyOptions.SelectPlayers2, NumPlayer2, IPlayers);
- SelectPlayers3 := AddSelectSlide (Theme.PartyOptions.SelectPlayers3, NumPlayer3, IPlayers);
+ SelectLevel := AddSelectSlide(Theme.PartyOptions.SelectLevel, Ini.Difficulty, Theme.ILevel);
+ SelectPlayList := AddSelectSlide(Theme.PartyOptions.SelectPlayList, PlayList, IPlaylist);
+ SelectPlayList2 := AddSelectSlide(Theme.PartyOptions.SelectPlayList2, PlayList2, IPlaylist2);
+ SelectRounds := AddSelectSlide(Theme.PartyOptions.SelectRounds, Rounds, IRounds);
+ SelectTeams := AddSelectSlide(Theme.PartyOptions.SelectTeams, NumTeams, ITeams);
+ SelectPlayers1 := AddSelectSlide(Theme.PartyOptions.SelectPlayers1, NumPlayer1, IPlayers);
+ SelectPlayers2 := AddSelectSlide(Theme.PartyOptions.SelectPlayers2, NumPlayer2, IPlayers);
+ SelectPlayers3 := AddSelectSlide(Theme.PartyOptions.SelectPlayers3, NumPlayer3, IPlayers);
Interaction := 0;
@@ -301,7 +302,7 @@ begin
UpdateSelectSlideOptions(Theme.PartyOptions.SelectPlayList2, 2, IPlaylist2, Playlist2);
end;
-procedure TScreenPartyOptions.onShow;
+procedure TScreenPartyOptions.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenPartyPlayer.pas b/src/screens/UScreenPartyPlayer.pas
index c2070fce..887d5202 100644
--- a/src/screens/UScreenPartyPlayer.pas
+++ b/src/screens/UScreenPartyPlayer.pas
@@ -64,8 +64,8 @@ type
Player12Name: cardinal;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
end;
@@ -76,9 +76,10 @@ uses
UMain,
UIni,
UTexture,
- UParty;
+ UParty,
+ UUnicodeUtils;
-function TScreenPartyPlayer.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenPartyPlayer.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
SDL_ModState: word;
I, J: integer;
@@ -107,9 +108,14 @@ begin
begin // Key Down
// check normal keys
case CharCode of
- '0'..'9', 'a'..'z', 'A'..'Z', ' ', '-', '_', '!', ',', '<', '/', '*', '?', '''', '"':
+ Ord('0')..Ord('9'),
+ Ord('a')..Ord('z'),
+ Ord('A')..Ord('Z'),
+ Ord(' '), Ord('-'), Ord('_'), Ord('!'), Ord(','), Ord('<'), Ord('/'),
+ Ord('*'), Ord('?'), Ord(''''), Ord('"'):
begin
- Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text + CharCode;
+ Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text +
+ UCS4ToUTF8String(CharCode);
Exit;
end;
end;
@@ -228,7 +234,7 @@ begin
SDLK_BACKSPACE:
begin
- Button[Interaction].Text[0].DeleteLastL;
+ Button[Interaction].Text[0].DeleteLastLetter;
end;
SDLK_ESCAPE:
@@ -294,7 +300,7 @@ begin
Interaction := 0;
end;
-procedure TScreenPartyPlayer.onShow;
+procedure TScreenPartyPlayer.OnShow;
var
I: integer;
begin
diff --git a/src/screens/UScreenPartyScore.pas b/src/screens/UScreenPartyScore.pas
index 23cf666d..2de240b8 100644
--- a/src/screens/UScreenPartyScore.pas
+++ b/src/screens/UScreenPartyScore.pas
@@ -34,11 +34,11 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
+ SysUtils,
+ UMenu,
UDisplay,
UMusic,
- SysUtils,
UThemes;
type
@@ -69,8 +69,8 @@ type
MaxScore: word;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
end;
@@ -83,16 +83,17 @@ uses
UScreenSingModi,
ULanguage,
UTexture,
- USkins;
+ USkins,
+ UUnicodeUtils;
-function TScreenPartyScore.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenPartyScore.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -165,7 +166,9 @@ begin
DecoColor[0].B := B;
//Load Texture
- Tex := Texture.LoadTexture(pchar(Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.FirstTexture)), Theme.PartyScore.DecoTextures.FirstTyp, Color);
+ Tex := Texture.LoadTexture(
+ Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.FirstTexture),
+ Theme.PartyScore.DecoTextures.FirstTyp, Color);
DecoTex[0] := Tex.TexNum;
//Get Second Color
@@ -176,7 +179,9 @@ begin
DecoColor[1].B := B;
//Load Second Texture
- Tex := Texture.LoadTexture(pchar(Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.SecondTexture)), Theme.PartyScore.DecoTextures.SecondTyp, Color);
+ Tex := Texture.LoadTexture(
+ Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.SecondTexture),
+ Theme.PartyScore.DecoTextures.SecondTyp, Color);
DecoTex[1] := Tex.TexNum;
//Get Third Color
@@ -187,14 +192,16 @@ begin
DecoColor[2].B := B;
//Load Third Texture
- Tex := Texture.LoadTexture(pchar(Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.ThirdTexture)), Theme.PartyScore.DecoTextures.ThirdTyp, Color);
+ Tex := Texture.LoadTexture(
+ Skin.GetTextureFileName(Theme.PartyScore.DecoTextures.ThirdTexture),
+ Theme.PartyScore.DecoTextures.ThirdTyp, Color);
DecoTex[2] := Tex.TexNum;
end;
LoadFromTheme(Theme.PartyScore);
end;
-procedure TScreenPartyScore.onShow;
+procedure TScreenPartyScore.OnShow;
var
I, J: integer;
Placings: array [0..5] of byte;
@@ -238,7 +245,7 @@ begin
if (ScreenSingModi.PlayerInfo.NumPlayers >= 1) then
begin
Text[TextScoreTeam1].Text := InttoStr(ScreenSingModi.PlayerInfo.Playerinfo[0].Score);
- Text[TextNameTeam1].Text := string(ScreenSingModi.TeamInfo.Teaminfo[0].Name);
+ Text[TextNameTeam1].Text := UTF8String(ScreenSingModi.TeamInfo.Teaminfo[0].Name);
//Set Deco Texture
if Theme.PartyScore.DecoTextures.ChangeTextures then
@@ -267,7 +274,7 @@ begin
if (ScreenSingModi.PlayerInfo.NumPlayers >= 2) then
begin
Text[TextScoreTeam2].Text := InttoStr(ScreenSingModi.PlayerInfo.Playerinfo[1].Score);
- Text[TextNameTeam2].Text := string(ScreenSingModi.TeamInfo.Teaminfo[1].Name);
+ Text[TextNameTeam2].Text := UTF8String(ScreenSingModi.TeamInfo.Teaminfo[1].Name);
//Set Deco Texture
if Theme.PartyScore.DecoTextures.ChangeTextures then
@@ -296,7 +303,7 @@ begin
if (ScreenSingModi.PlayerInfo.NumPlayers >= 3) then
begin
Text[TextScoreTeam3].Text := InttoStr(ScreenSingModi.PlayerInfo.Playerinfo[2].Score);
- Text[TextNameTeam3].Text := string(ScreenSingModi.TeamInfo.Teaminfo[2].Name);
+ Text[TextNameTeam3].Text := UTF8String(ScreenSingModi.TeamInfo.Teaminfo[2].Name);
//Set Deco Texture
if Theme.PartyScore.DecoTextures.ChangeTextures then
diff --git a/src/screens/UScreenPartyWin.pas b/src/screens/UScreenPartyWin.pas
index 3c105c7d..afa5ce83 100644
--- a/src/screens/UScreenPartyWin.pas
+++ b/src/screens/UScreenPartyWin.pas
@@ -34,10 +34,11 @@ interface
{$I switches.inc}
uses
+ SDL,
+ SysUtils,
UMenu,
- SDL, UDisplay,
+ UDisplay,
UMusic,
- SysUtils,
UThemes;
type
@@ -61,28 +62,29 @@ type
TextWinner: cardinal;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
end;
implementation
-uses
+uses
UGraphic,
UMain,
UParty,
UScreenSingModi,
- ULanguage;
+ ULanguage,
+ UUnicodeUtils;
-function TScreenPartyWin.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenPartyWin.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -135,7 +137,7 @@ begin
LoadFromTheme(Theme.PartyWin);
end;
-procedure TScreenPartyWin.onShow;
+procedure TScreenPartyWin.OnShow;
var
I: integer;
Placing: TeamOrderArray;
diff --git a/src/screens/UScreenPopup.pas b/src/screens/UScreenPopup.pas
index 7e4671d6..fdf4a69c 100644
--- a/src/screens/UScreenPopup.pas
+++ b/src/screens/UScreenPopup.pas
@@ -34,42 +34,61 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
+ SysUtils,
+ UMenu,
UMusic,
UFiles,
- SysUtils,
UThemes;
type
+ TPopupCheckHandler = procedure(Value: boolean; Data: Pointer);
+
TScreenPopupCheck = class(TMenu)
+ private
+ fHandler: TPopupCheckHandler;
+ fHandlerData: Pointer;
+
public
- Visible: boolean; //Whether the Menu should be Drawn
+ Visible: boolean; // whether the menu should be drawn
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
- procedure ShowPopup(msg: string);
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
+ procedure ShowPopup(const Msg: UTF8String; Handler: TPopupCheckHandler;
+ HandlerData: Pointer; DefaultValue: boolean = false);
function Draw: boolean; override;
end;
type
- TScreenPopupError = class(TMenu)
-{ private
- CurMenu: byte; //Num of the cur. Shown Menu}
+ TScreenPopup = class(TMenu)
+ {
+ private
+ CurMenu: byte; //Num of the cur. Shown Menu
+ }
public
Visible: boolean; //Whether the Menu should be Drawn
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
- procedure onHide; override;
- procedure ShowPopup(msg: string);
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
+ procedure OnHide; override;
+ procedure ShowPopup(const Msg: UTF8String);
function Draw: boolean; override;
end;
+ TScreenPopupError = class(TScreenPopup)
+ public
+ constructor Create;
+ end;
+
+ TScreenPopupInfo = class(TScreenPopup)
+ public
+ constructor Create;
+ end;
+
var
-// ISelections: array of string;
+ //ISelections: array of string;
SelectValue: integer;
implementation
@@ -82,70 +101,57 @@ uses
ULanguage,
UParty,
UPlaylist,
- UDisplay;
+ UDisplay,
+ UUnicodeUtils;
-function TScreenPopupCheck.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+{ TScreenPopupCheck }
+
+function TScreenPopupCheck.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
+var
+ Value: boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
- // check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
- begin
- Result := false;
- Exit;
- end;
- end;
-
// check special keys
case PressedKey of
SDLK_ESCAPE,
SDLK_BACKSPACE :
begin
- Display.CheckOK := false;
- Display.NextScreenWithCheck := NIL;
+ Value := false;
Visible := false;
Result := false;
end;
SDLK_RETURN:
begin
- case Interaction of
- 0: begin
- //Hack to Finish Singscreen correct on Exit with Q Shortcut
- if (Display.NextScreenWithCheck = NIL) then
- begin
- if (Display.CurrentScreen = @ScreenSing) then
- ScreenSing.Finish
- else if (Display.CurrentScreen = @ScreenSingModi) then
- ScreenSingModi.Finish;
- end;
-
- Display.CheckOK := true;
- end;
- 1: begin
- Display.CheckOK := false;
- Display.NextScreenWithCheck := NIL;
- end;
- end;
+ Value := (Interaction = 0);
Visible := false;
Result := false;
end;
- SDLK_DOWN: InteractNext;
- SDLK_UP: InteractPrev;
-
+ SDLK_DOWN: InteractNext;
+ SDLK_UP: InteractPrev;
+
SDLK_RIGHT: InteractNext;
- SDLK_LEFT: InteractPrev;
+ SDLK_LEFT: InteractPrev;
end;
end;
+
+ if (not Result) then
+ begin
+ if (@fHandler <> nil) then
+ fHandler(Value, fHandlerData);
+ end;
end;
constructor TScreenPopupCheck.Create;
begin
inherited Create;
+ fHandler := nil;
+ fHandlerData := nil;
+
AddText(Theme.CheckPopup.TextCheck);
LoadFromTheme(Theme.CheckPopup);
@@ -163,18 +169,24 @@ end;
function TScreenPopupCheck.Draw: boolean;
begin
- Draw:=inherited Draw;
+ Result := inherited Draw;
end;
-procedure TScreenPopupCheck.onShow;
+procedure TScreenPopupCheck.OnShow;
begin
inherited;
end;
-procedure TScreenPopupCheck.ShowPopup(msg: string);
+procedure TScreenPopupCheck.ShowPopup(const Msg: UTF8String; Handler: TPopupCheckHandler;
+ HandlerData: Pointer; DefaultValue: boolean);
begin
- Interaction := 0; //Reset Interaction
+ if (DefaultValue) then
+ Interaction := 0
+ else
+ Interaction := 1;
Visible := true; //Set Visible
+ fHandler := Handler;
+ fHandlerData := HandlerData;
Text[0].Text := Language.Translate(msg);
@@ -187,9 +199,9 @@ begin
Background.OnShow
end;
-// error popup
+{ TScreenPopup }
-function TScreenPopupError.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenPopup.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
@@ -223,7 +235,7 @@ begin
end;
end;
-constructor TScreenPopupError.Create;
+constructor TScreenPopup.Create;
begin
inherited Create;
@@ -238,22 +250,22 @@ begin
Interaction := 0;
end;
-function TScreenPopupError.Draw: boolean;
+function TScreenPopup.Draw: boolean;
begin
Draw := inherited Draw;
end;
-procedure TScreenPopupError.onShow;
+procedure TScreenPopup.OnShow;
begin
inherited;
end;
-procedure TScreenPopupError.onHide;
+procedure TScreenPopup.OnHide;
begin
end;
-procedure TScreenPopupError.ShowPopup(msg: string);
+procedure TScreenPopup.ShowPopup(const Msg: UTF8String);
begin
Interaction := 0; //Reset Interaction
Visible := true; //Set Visible
@@ -277,4 +289,20 @@ begin
Button[0].Text[0].Text := 'OK';
end;
+{ TScreenPopupError }
+
+constructor TScreenPopupError.Create;
+begin
+ inherited;
+ Text[1].Text := Language.Translate('MSG_ERROR_TITLE');
+end;
+
+{ TScreenPopupInfo }
+
+constructor TScreenPopupInfo.Create;
+begin
+ inherited;
+ Text[1].Text := Language.Translate('MSG_INFO_TITLE');
+end;
+
end.
diff --git a/src/screens/UScreenScore.pas b/src/screens/UScreenScore.pas
index a01c7691..ce1b11e5 100644
--- a/src/screens/UScreenScore.pas
+++ b/src/screens/UScreenScore.pas
@@ -128,10 +128,10 @@ type
TextGolden_ActualValue: array[1..6] of integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function ParseMouse(MouseButton: Integer; BtnDown: Boolean; X, Y: integer): boolean; override;
- procedure onShow; override;
- procedure onShowFinish; override;
+ procedure OnShow; override;
+ procedure OnShowFinish; override;
function Draw: boolean; override;
procedure FillPlayer(Item, P: integer);
@@ -158,16 +158,18 @@ uses
UIni,
ULog,
ULanguage,
- UNote;
+ UNote,
+ UUnicodeUtils;
-function TScreenScore.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+
+function TScreenScore.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -197,7 +199,7 @@ begin
Result := True;
if (MouseButton = SDL_BUTTON_LEFT) and BtnDown then begin
//left-click anywhere sends return
- ParseInput(SDLK_RETURN, #0, true);
+ ParseInput(SDLK_RETURN, 0, true);
end;
end;
@@ -261,7 +263,7 @@ begin
end;
-procedure TScreenScore.onShow;
+procedure TScreenScore.OnShow;
var
P: integer; // player
I: integer;
diff --git a/src/screens/UScreenSing.pas b/src/screens/UScreenSing.pas
index 157f7e64..20805737 100644
--- a/src/screens/UScreenSing.pas
+++ b/src/screens/UScreenSing.pas
@@ -35,9 +35,9 @@ interface
uses
SysUtils,
- gl,
SDL,
TextGL,
+ gl,
UFiles,
UGraphicClasses,
UIni,
@@ -49,6 +49,7 @@ uses
USongs,
UTexture,
UThemes,
+ UPath,
UTime;
type
@@ -101,11 +102,11 @@ type
fCurrentVideoPlaybackEngine: IVideoPlayback;
constructor Create; override;
- procedure onShow; override;
- procedure onShowFinish; override;
- procedure onHide; override;
+ procedure OnShow; override;
+ procedure OnShowFinish; override;
+ procedure OnHide; override;
- function ParseInput(PressedKey: cardinal; CharCode: widechar;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean; override;
function Draw: boolean; override;
@@ -127,20 +128,21 @@ uses
UNote,
URecord,
USong,
- UDisplay;
+ UDisplay,
+ UUnicodeUtils;
// method for input parsing. if false is returned, getnextwindow
// should be checked to know the next window to load;
-function TScreenSing.ParseInput(PressedKey: cardinal; CharCode: widechar;
+function TScreenSing.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // key down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
// when not ask before exit then finish now
if (Ini.AskbeforeDel <> 1) then
@@ -152,7 +154,7 @@ begin
Result := false;
Exit;
end;
- 'V': // show visualization
+ Ord('V'): // show visualization
begin
fShowVisualization := not fShowVisualization;
@@ -166,7 +168,7 @@ begin
Exit;
end;
- 'P':
+ Ord('P'):
begin
Pause;
Exit;
@@ -216,6 +218,8 @@ end;
// pause mod
procedure TScreenSing.Pause;
+var
+ VideoFile: IPath;
begin
if (not Paused) then // enable pause
begin
@@ -228,8 +232,8 @@ begin
AudioPlayback.Pause;
// pause video
- if (CurrentSong.Video <> '') and FileExists(CurrentSong.Path +
- CurrentSong.Video) then
+ VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
+ if (CurrentSong.Video.IsSet) and VideoFile.Exists then
fCurrentVideoPlaybackEngine.Pause;
end
@@ -241,8 +245,8 @@ begin
AudioPlayback.Play;
// video
- if (CurrentSong.Video <> '') and FileExists(CurrentSong.Path +
- CurrentSong.Video) then
+ VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
+ if (CurrentSong.Video.IsSet) and VideoFile.Exists then
fCurrentVideoPlaybackEngine.Pause;
Paused := false;
@@ -307,7 +311,7 @@ begin
LyricsSync := TLyricsSyncSource.Create();
end;
-procedure TScreenSing.onShow;
+procedure TScreenSing.OnShow;
var
Index: integer;
V1: boolean;
@@ -317,12 +321,12 @@ var
V2M: boolean;
V3R: boolean;
Color: TRGB;
-
+ VideoFile, BgFile: IPath;
success: boolean;
begin
inherited;
- Log.LogStatus('Begin', 'onShow');
+ Log.LogStatus('Begin', 'OnShow');
FadeOut := false;
// reset video playback engine, to play video clip ...
@@ -423,7 +427,7 @@ begin
// FIXME: bad style, put the try-except into loadsong() and not here
try
// check if file is xml
- if copy(CurrentSong.FileName, length(CurrentSong.FileName) - 3, 4) = '.xml' then
+ if CurrentSong.FileName.GetExtension.ToUTF8 = '.xml' then
success := CurrentSong.LoadXMLSong()
else
success := CurrentSong.LoadSong();
@@ -467,9 +471,10 @@ begin
*}
VideoLoaded := false;
fShowVisualization := false;
- if (CurrentSong.Video <> '') and FileExists(CurrentSong.Path + CurrentSong.Video) then
+ VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
+ if (CurrentSong.Video.IsSet) and VideoFile.IsFile then
begin
- if (fCurrentVideoPlaybackEngine.Open(CurrentSong.Path + CurrentSong.Video)) then
+ if (fCurrentVideoPlaybackEngine.Open(VideoFile)) then
begin
fShowVisualization := false;
fCurrentVideoPlaybackEngine := VideoPlayback;
@@ -482,15 +487,17 @@ begin
{*
* set background to: picture
*}
- if (CurrentSong.Background <> '') and (VideoLoaded = false)
+ if (CurrentSong.Background.IsSet) and (VideoLoaded = false)
and (TVisualizerOption(Ini.VisualizerOption) = voOff) then
+ begin
+ BgFile := CurrentSong.Path.Append(CurrentSong.Background);
try
- Tex_Background := Texture.LoadTexture(CurrentSong.Path + CurrentSong.Background);
+ Tex_Background := Texture.LoadTexture(BgFile);
except
- Log.LogError('Background could not be loaded: ' + CurrentSong.Path +
- CurrentSong.Background);
+ Log.LogError('Background could not be loaded: ' + BgFile.ToNative);
Tex_Background.TexNum := 0;
end
+ end
else
begin
Tex_Background.TexNum := 0;
@@ -622,7 +629,7 @@ begin
if Lines[0].Line[Index].TotalNotes = 0 then
Inc(NumEmptySentences);
- Log.LogStatus('End', 'onShow');
+ Log.LogStatus('End', 'OnShow');
end;
procedure TScreenSing.onShowFinish;
@@ -640,7 +647,7 @@ begin
CountSkipTimeSet;
end;
-procedure TScreenSing.onHide;
+procedure TScreenSing.OnHide;
begin
// background texture
if (Tex_Background.TexNum > 0) then
diff --git a/src/screens/UScreenSingModi.pas b/src/screens/UScreenSingModi.pas
index eeb06004..48d1e9a1 100644
--- a/src/screens/UScreenSingModi.pas
+++ b/src/screens/UScreenSingModi.pas
@@ -47,7 +47,7 @@ uses
ULyrics,
TextGL,
gl,
-
+ UPath,
UThemes,
UScreenSing,
ModiSDK;
@@ -62,16 +62,16 @@ type
TeamInfo: TTeamInfo;
constructor Create; override;
- procedure onShow; override;
+ procedure OnShow; override;
//procedure onShowFinish; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function Draw: boolean; override;
procedure Finish; override;
end;
type
TCustomSoundEntry = record
- Filename : string;
+ Filename : IPath;
Stream : TAudioPlaybackStream;
end;
@@ -108,13 +108,13 @@ uses
UGraphicClasses,
ULanguage,
UNote,
- UPath,
+ UPathUtils,
URecord,
USkins;
// Method for input parsing. If false is returned, GetNextWindow
// should be checked to know the next window to load;
-function TScreenSingModi.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenSingModi.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
@@ -176,7 +176,7 @@ begin
end;
end;
-procedure TScreenSingModi.onShow;
+procedure TScreenSingModi.OnShow;
var
I: integer;
begin
@@ -503,19 +503,20 @@ end;
function LoadTex(const Name: PChar; Typ: TTextureType): TsmallTexture;
var
- Texname, EXT: string;
+ TexName: IPath;
+ Ext: UTF8String;
Tex: TTexture;
begin
//Get texture Name
TexName := Skin.GetTextureFileName(string(Name));
//Get File Typ
- Ext := ExtractFileExt(TexName);
- if (uppercase(Ext) = '.JPG') then
+ Ext := TexName.GetExtension().ToUTF8;
+ if (UpperCase(Ext) = '.JPG') then
Ext := 'JPG'
else
Ext := 'BMP';
- Tex := Texture.LoadTexture(false, PChar(TexName), UTEXTURE.TTextureType(Typ), 0);
+ Tex := Texture.LoadTexture(false, TexName, UTexture.TTextureType(Typ), 0);
Result.TexNum := Tex.TexNum;
Result.W := Tex.W;
@@ -544,20 +545,21 @@ function LoadSound(const Name: PChar): cardinal;
var
Stream: TAudioPlaybackStream;
i: integer;
- Filename: string;
+ Filename: IPath;
+ SoundFile: IPath;
begin
//Search for Sound in already loaded Sounds
- Filename := UpperCase(SoundPath + Name);
+ SoundFile := SoundPath.Append(Name);
for i := 0 to High(CustomSounds) do
begin
- if (UpperCase(CustomSounds[i].Filename) = Filename) then
+ if (SoundFile.Equals(CustomSounds[i].Filename, true)) then
begin
Result := i;
Exit;
end;
end;
- Stream := AudioPlayback.OpenSound(SoundPath + string(Name));
+ Stream := AudioPlayback.OpenSound(SoundFile);
if (Stream = nil) then
begin
Result := 0;
diff --git a/src/screens/UScreenSong.pas b/src/screens/UScreenSong.pas
index fa3c836e..5fa6de39 100644
--- a/src/screens/UScreenSong.pas
+++ b/src/screens/UScreenSong.pas
@@ -38,6 +38,7 @@ uses
SDL,
UCommon,
UDisplay,
+ UPath,
UFiles,
UIni,
ULanguage,
@@ -118,19 +119,19 @@ type
procedure SetScroll4;
procedure SetScroll5;
procedure SetScroll6;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean; override;
function Draw: boolean; override;
procedure GenerateThumbnails();
- procedure onShow; override;
- procedure onHide; override;
+ procedure OnShow; override;
+ procedure OnHide; override;
procedure SelectNext;
procedure SelectPrev;
procedure SkipTo(Target: cardinal);
procedure FixSelected; //Show Wrong Song when Tabs on Fix
procedure FixSelected2; //Show Wrong Song when Tabs on Fix
procedure ShowCatTL(Cat: integer);// Show Cat in Top left
- procedure ShowCatTLCustom(Caption: string);// Show Custom Text in Top left
+ procedure ShowCatTLCustom(Caption: UTF8String);// Show Custom Text in Top left
procedure HideCatTL;// Show Cat in Tob left
procedure Refresh; //Refresh Song Sorting
procedure ChangeMusic;
@@ -164,7 +165,8 @@ uses
UParty,
UPlaylist,
UScreenSongMenu,
- USkins;
+ USkins,
+ UUnicodeUtils;
// ***** Public methods ****** //
@@ -211,7 +213,7 @@ begin
end;
//Show Wrong Song when Tabs on Fix End
-procedure TScreenSong.ShowCatTLCustom(Caption: string);// Show Custom Text in Top left
+procedure TScreenSong.ShowCatTLCustom(Caption: UTF8String);// Show Custom Text in Top left
begin
Text[TextCat].Text := Caption;
Text[TextCat].Visible := true;
@@ -243,12 +245,13 @@ end;
// Method for input parsing. If false is returned, GetNextWindow
// should be checked to know the next window to load;
-function TScreenSong.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenSong.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
I: integer;
I2: integer;
SDL_ModState: word;
- Letter: WideChar;
+ UpperLetter: UCS4Char;
+ TempStr: UTF8String;
begin
Result := true;
@@ -273,9 +276,10 @@ begin
//Jump to Artist/Titel
if ((SDL_ModState and KMOD_LALT <> 0) and (Mode = smNormal)) then
begin
- if (WideCharUpperCase(CharCode)[1] in ([WideChar('A')..WideChar('Z'), WideChar('0') .. WideChar('9')]) ) then
+ UpperLetter := UCS4UpperCase(CharCode);
+
+ if (UpperLetter in ([Ord('A')..Ord('Z'), Ord('0') .. Ord('9')]) ) then
begin
- Letter := WideCharUpperCase(CharCode)[1];
I2 := Length(CatSongs.Song);
//Jump To Titel
@@ -283,18 +287,21 @@ begin
begin
for I := 1 to High(CatSongs.Song) do
begin
- if (CatSongs.Song[(I + Interaction) mod I2].Visible) and
- (Length(CatSongs.Song[(I + Interaction) mod I2].Title)>0) and
- (WideStringUpperCase(CatSongs.Song[(I + Interaction) mod I2].Title)[1] = Letter) then
+ if (CatSongs.Song[(I + Interaction) mod I2].Visible) then
begin
- SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2));
+ TempStr := CatSongs.Song[(I + Interaction) mod I2].Title;
+ if (Length(TempStr) > 0) and
+ (UCS4UpperCase(UTF8ToUCS4String(TempStr)[0]) = UpperLetter) then
+ begin
+ SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2));
- AudioPlayback.PlaySound(SoundLib.Change);
+ AudioPlayback.PlaySound(SoundLib.Change);
- ChangeMusic;
- SetScroll4;
- //Break and Exit
- Exit;
+ ChangeMusic;
+ SetScroll4;
+ //Break and Exit
+ Exit;
+ end;
end;
end;
end
@@ -303,19 +310,22 @@ begin
begin
for I := 1 to High(CatSongs.Song) do
begin
- if (CatSongs.Song[(I + Interaction) mod I2].Visible) and
- (Length(CatSongs.Song[(I + Interaction) mod I2].Artist)>0) and
- (WideStringUpperCase(CatSongs.Song[(I + Interaction) mod I2].Artist)[1] = Letter) then
+ if (CatSongs.Song[(I + Interaction) mod I2].Visible) then
begin
- SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2));
+ TempStr := CatSongs.Song[(I + Interaction) mod I2].Artist;
+ if (Length(TempStr) > 0) and
+ (UCS4UpperCase(UTF8ToUCS4String(TempStr)[0]) = UpperLetter) then
+ begin
+ SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2));
- AudioPlayback.PlaySound(SoundLib.Change);
+ AudioPlayback.PlaySound(SoundLib.Change);
- ChangeMusic;
- SetScroll4;
+ ChangeMusic;
+ SetScroll4;
- //Break and Exit
- Exit;
+ //Break and Exit
+ Exit;
+ end;
end;
end;
end;
@@ -325,14 +335,14 @@ begin
end;
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
end;
- 'M': //Show SongMenu
+ Ord('M'): //Show SongMenu
begin
if (Songs.SongList.Count > 0) then
begin
@@ -342,41 +352,41 @@ begin
begin
if CatSongs.CatNumShow = -3 then
begin
- ScreenSongMenu.onShow;
+ ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Playlist);
end
else
begin
- ScreenSongMenu.onShow;
+ ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Main);
end;
end
else
begin
- ScreenSongMenu.onShow;
+ ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Playlist_Load);
end;
end //Party Mode -> Show Party Menu
else
begin
- ScreenSongMenu.onShow;
+ ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Party_Main);
end;
end;
Exit;
end;
- 'P': //Show Playlist Menu
+ Ord('P'): //Show Playlist Menu
begin
if (Songs.SongList.Count > 0) and (Mode = smNormal) then
begin
- ScreenSongMenu.onShow;
+ ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Playlist_Load);
end;
Exit;
end;
- 'J': //Show Jumpto Menu
+ Ord('J'): //Show Jumpto Menu
begin
if (Songs.SongList.Count > 0) and (Mode = smNormal) then
begin
@@ -385,13 +395,13 @@ begin
Exit;
end;
- 'E':
+ Ord('E'):
begin
OpenEditor;
Exit;
end;
- 'R':
+ Ord('R'):
begin
if (Songs.SongList.Count > 0) and
(Mode = smNormal) then
@@ -515,7 +525,7 @@ begin
if (CatSongs.CatNumShow < -1) then
begin
//Atm: Set Empty Filter
- CatSongs.SetFilter('', 0);
+ CatSongs.SetFilter('', fltAll);
//Show Cat in Top Left Mod
HideCatTL;
@@ -744,18 +754,18 @@ begin
if RightMbESC and (MouseButton = SDL_BUTTON_RIGHT) and BtnDown then
//if RightMbESC is set, send ESC keypress
- Result:=ParseInput(SDLK_ESCAPE, #0, true);
+ Result:=ParseInput(SDLK_ESCAPE, 0, true);
//song scrolling with mousewheel
if (MouseButton = SDL_BUTTON_WHEELDOWN) and BtnDown then
- ParseInput(SDLK_RIGHT, #0, true);
+ ParseInput(SDLK_RIGHT, 0, true);
if (MouseButton = SDL_BUTTON_WHEELUP) and BtnDown then
- ParseInput(SDLK_LEFT, #0, true);
+ ParseInput(SDLK_LEFT, 0, true);
//LMB anywhere starts
if (MouseButton = SDL_BUTTON_LEFT) and BtnDown then
- ParseInput(SDLK_RETURN, #0, true);
+ ParseInput(SDLK_RETURN, 0, true);
end;
constructor TScreenSong.Create;
@@ -833,9 +843,9 @@ var
I: integer;
CoverButtonIndex: integer;
CoverButton: TButton;
- CoverName: string;
CoverTexture: TTexture;
Cover: TCover;
+ CoverFile: IPath;
Song: TSong;
begin
if (Length(CatSongs.Song) <= 0) then
@@ -850,7 +860,7 @@ begin
CoverButton := nil;
// create a clickable cover
- CoverButtonIndex := AddButton(300 + I*250, 140, 200, 200, '', TEXTURE_TYPE_PLAIN, Theme.Song.Cover.Reflections);
+ CoverButtonIndex := AddButton(300 + I*250, 140, 200, 200, PATH_NONE, TEXTURE_TYPE_PLAIN, Theme.Song.Cover.Reflections);
if (CoverButtonIndex > -1) then
CoverButton := Button[CoverButtonIndex];
if (CoverButton = nil) then
@@ -859,18 +869,16 @@ begin
Song := CatSongs.Song[I];
// if cover-image is not found then show 'no cover'
- if (not FileExists(Song.Path + Song.Cover)) then
- Song.Cover := '';
-
- if (Song.Cover = '') then
- CoverName := Skin.GetTextureFileName('SongCover')
- else
- CoverName := Song.Path + Song.Cover;
+ CoverFile := Song.Path.Append(Song.Cover);
+ if (not CoverFile.IsFile()) then
+ Song.Cover := PATH_NONE;
+ if (Song.Cover.IsUnset) then
+ CoverFile := Skin.GetTextureFileName('SongCover');
// load cover and cache its texture
- Cover := Covers.FindCover(CoverName);
+ Cover := Covers.FindCover(CoverFile);
if (Cover = nil) then
- Cover := Covers.AddCover(CoverName);
+ Cover := Covers.AddCover(CoverFile);
// use the cached texture
// TODO: this is a workaround until the new song-loading works.
@@ -910,7 +918,7 @@ begin
end;
// Set visibility of video icon
- Static[VideoIcon].Visible := (CatSongs.Song[Interaction].Video <> '');
+ Static[VideoIcon].Visible := CatSongs.Song[Interaction].Video.IsSet;
// Set texts
Text[TextArtist].Text := CatSongs.Song[Interaction].Artist;
@@ -1399,7 +1407,7 @@ begin
end;
end;
-procedure TScreenSong.onShow;
+procedure TScreenSong.OnShow;
begin
inherited;
{**
@@ -1456,14 +1464,14 @@ begin
SetStatics;
end;
-procedure TScreenSong.onHide;
+procedure TScreenSong.OnHide;
begin
// turn music volume to 100%
AudioPlayback.SetVolume(1.0);
// if preview is deactivated: load musicfile now
if (IPreviewVolumeVals[Ini.PreviewVolume] = 0) then
- AudioPlayback.Open(CatSongs.Song[Interaction].Path + CatSongs.Song[Interaction].Mp3);
+ AudioPlayback.Open(CatSongs.Song[Interaction].Path.Append(CatSongs.Song[Interaction].Mp3));
// if hide then stop music (for party mode popup on exit)
if (Display.NextScreen <> @ScreenSing) and
@@ -1642,7 +1650,7 @@ begin
if not assigned(Song) then
Exit;
- if AudioPlayback.Open(Song.Path + Song.Mp3) then
+ if AudioPlayback.Open(Song.Path.Append(Song.Mp3)) then
begin
AudioPlayback.Position := AudioPlayback.Length / 4;
// set preview volume
diff --git a/src/screens/UScreenSongJumpto.pas b/src/screens/UScreenSongJumpto.pas
index e55a6276..3a199576 100644
--- a/src/screens/UScreenSongJumpto.pas
+++ b/src/screens/UScreenSongJumpto.pas
@@ -34,42 +34,39 @@ interface
{$I switches.inc}
uses
- UMenu,
SDL,
+ SysUtils,
+ UMenu,
UDisplay,
UMusic,
UFiles,
- SysUtils,
+ USongs,
UThemes;
type
TScreenSongJumpto = class(TMenu)
private
//For ChangeMusic
- LastPlayed: integer;
- VisibleBool: boolean;
- public
- VisSongs: integer;
+ fLastPlayed: integer;
+ fVisible: boolean;
+ fSelectType: TSongFilter;
+ fVisSongs: integer;
- constructor Create; override;
+ procedure SetTextFound(Count: Cardinal);
//Visible //Whether the Menu should be Drawn
//Whether the Menu should be Drawn
procedure SetVisible(Value: boolean);
- property Visible: boolean read VisibleBool write SetVisible;
+ public
+ constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
function Draw: boolean; override;
- procedure SetTextFound(const Count: cardinal);
+ property Visible: boolean read fVisible write SetVisible;
end;
-var
- IType: array [0..2] of string;
- SelectType: integer;
-
-
implementation
uses
@@ -79,26 +76,24 @@ uses
UTexture,
ULanguage,
UParty,
- USongs,
UScreenSong,
- ULog;
+ ULog,
+ UUnicodeUtils;
-function TScreenSongJumpto.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenSongJumpto.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case CharCode of
- '0'..'9', 'a'..'z', 'A'..'Z', ' ', '-', '_', '!', ',', '<', '/', '*', '?', '''', '"',
- '[', '{', ';', ':':
- begin
- if Interaction = 0 then
- begin
- Button[0].Text[0].Text := Button[0].Text[0].Text + CharCode;
- SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType));
- end;
- end;
+ if (IsAlphaNumericChar(CharCode) or
+ IsPunctuationChar(CharCode)) then
+ begin
+ if (Interaction = 0) then
+ begin
+ Button[0].Text[0].Text := Button[0].Text[0].Text + UCS4ToUTF8String(CharCode);
+ SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, fSelectType));
+ end;
end;
// check special keys
@@ -107,8 +102,8 @@ begin
begin
if (Interaction = 0) and (Length(Button[0].Text[0].Text) > 0) then
begin
- Button[0].Text[0].DeleteLastL;
- SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType));
+ Button[0].Text[0].DeleteLastLetter();
+ SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, fSelectType));
end;
end;
@@ -117,18 +112,15 @@ begin
begin
Visible := false;
AudioPlayback.PlaySound(SoundLib.Back);
- if (VisSongs = 0) and (Length(Button[0].Text[0].Text) > 0) then
+ if (fVisSongs = 0) and (Length(Button[0].Text[0].Text) > 0) then
begin
ScreenSong.UnLoadDetailedCover;
Button[0].Text[0].Text := '';
- CatSongs.SetFilter('', 0);
+ CatSongs.SetFilter('', fltAll);
SetTextFound(0);
end;
end;
- // Up and Down could be done at the same time,
- // but I don't want to declare variables inside
- // functions like this one, called so many times
SDLK_DOWN:
begin
{SelectNext;
@@ -146,7 +138,7 @@ begin
Interaction := 1;
InteractInc;
if (Length(Button[0].Text[0].Text) > 0) then
- SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType));
+ SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, fSelectType));
Interaction := 0;
end;
SDLK_LEFT:
@@ -154,7 +146,7 @@ begin
Interaction := 1;
InteractDec;
if (Length(Button[0].Text[0].Text) > 0) then
- SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, SelectType));
+ SetTextFound(CatSongs.SetFilter(Button[0].Text[0].Text, fSelectType));
Interaction := 0;
end;
end;
@@ -162,8 +154,6 @@ begin
end;
constructor TScreenSongJumpto.Create;
-//var
-// I: integer; // Auto Removed, Unused Variable
begin
inherited Create;
@@ -175,23 +165,23 @@ begin
if (Length(Button[0].Text) = 0) then
AddButtonText(14, 20, '');
- SelectType := 0;
- AddSelectSlide(Theme.SongJumpto.SelectSlideType, SelectType, Theme.SongJumpto.IType);
+ fSelectType := fltAll;
+ AddSelectSlide(Theme.SongJumpto.SelectSlideType, PInteger(@fSelectType)^, Theme.SongJumpto.IType);
Interaction := 0;
- LastPlayed := 0;
+ fLastPlayed := 0;
end;
procedure TScreenSongJumpto.SetVisible(Value: boolean);
begin
-//If change from unvisible to Visible then OnShow
- if (VisibleBool = false) and (Value = true) then
+//If change from invisible to Visible then OnShow
+ if (fVisible = false) and (Value = true) then
OnShow;
- VisibleBool := Value;
+ fVisible := Value;
end;
-procedure TScreenSongJumpto.onShow;
+procedure TScreenSongJumpto.OnShow;
begin
inherited;
@@ -208,7 +198,7 @@ begin
Interaction := 0;
Button[0].Text[0].Selected := true;
- LastPlayed := ScreenSong.Interaction;
+ fLastPlayed := ScreenSong.Interaction;
end;
function TScreenSongJumpto.Draw: boolean;
@@ -216,7 +206,7 @@ begin
Result := inherited Draw;
end;
-procedure TScreenSongJumpto.SetTextFound(const Count: cardinal);
+procedure TScreenSongJumpto.SetTextFound(Count: cardinal);
begin
if (Count = 0) then
begin
@@ -235,7 +225,7 @@ begin
end;
//Set visSongs
- VisSongs := Count;
+ fVisSongs := Count;
//Fix SongSelection
ScreenSong.Interaction := high(CatSongs.Song);
@@ -243,9 +233,9 @@ begin
ScreenSong.FixSelected;
//Play Correct Music
- if (ScreenSong.Interaction <> LastPlayed) then
+ if (ScreenSong.Interaction <> fLastPlayed) then
begin
- LastPlayed := ScreenSong.Interaction;
+ fLastPlayed := ScreenSong.Interaction;
ScreenSong.ChangeMusic;
end;
diff --git a/src/screens/UScreenSongMenu.pas b/src/screens/UScreenSongMenu.pas
index 0af94a8f..ec893c7a 100644
--- a/src/screens/UScreenSongMenu.pas
+++ b/src/screens/UScreenSongMenu.pas
@@ -50,8 +50,8 @@ type
Visible: boolean; // whether the menu should be drawn
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
function Draw: boolean; override;
procedure MenuShow(sMenu: byte);
procedure HandleReturn;
@@ -73,7 +73,7 @@ const
SM_Party_Joker = 128 or 2;
var
- ISelections: array of string;
+ ISelections: array of UTF8String;
SelectValue: integer;
implementation
@@ -86,9 +86,10 @@ uses
ULanguage,
UParty,
UPlaylist,
- USongs;
+ USongs,
+ UUnicodeUtils;
-function TScreenSongMenu.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenSongMenu.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
@@ -96,27 +97,29 @@ begin
if (CurMenu = SM_Playlist_New) and (Interaction=0) then
begin
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- '0'..'9', 'A'..'Z', ' ', '-', '_', '!', ',', '<', '/', '*', '?', '''', '"':
- begin
- Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text + CharCode;
- exit;
- end;
+ if IsAlphaNumericChar(CharCode) or
+ (CharCode in [Ord(' '), Ord('-'), Ord('_'), Ord('!'),
+ Ord(','), Ord('<'), Ord('/'), Ord('*'),
+ Ord('?'), Ord(''''), Ord('"')]) then
+ begin
+ Button[Interaction].Text[0].Text := Button[Interaction].Text[0].Text +
+ UCS4ToUTF8String(CharCode);
+ exit;
end;
// check special keys
case PressedKey of
SDLK_BACKSPACE:
begin
- Button[Interaction].Text[0].DeleteLastL;
+ Button[Interaction].Text[0].DeleteLastLetter;
exit;
end;
end;
end;
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -223,7 +226,7 @@ begin
Result := inherited Draw;
end;
-procedure TScreenSongMenu.onShow;
+procedure TScreenSongMenu.OnShow;
begin
inherited;
end;
@@ -405,9 +408,9 @@ begin
Button[3].Visible := true;
SelectsS[0].Visible := false;
- Button[0].Text[0].Text := string(PartySession.Teams.Teaminfo[0].Name);
- Button[1].Text[0].Text := string(PartySession.Teams.Teaminfo[1].Name);
- Button[2].Text[0].Text := string(PartySession.Teams.Teaminfo[2].Name);
+ Button[0].Text[0].Text := UTF8String(PartySession.Teams.Teaminfo[0].Name);
+ Button[1].Text[0].Text := UTF8String(PartySession.Teams.Teaminfo[1].Name);
+ Button[2].Text[0].Text := UTF8String(PartySession.Teams.Teaminfo[2].Name);
Button[3].Text[0].Text := Language.Translate('SONG_MENU_CANCEL');
// set right interaction
diff --git a/src/screens/UScreenStatDetail.pas b/src/screens/UScreenStatDetail.pas
index bbbb4a1b..249626b0 100644
--- a/src/screens/UScreenStatDetail.pas
+++ b/src/screens/UScreenStatDetail.pas
@@ -55,8 +55,8 @@ type
TotPages: cardinal;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
procedure SetTitle;
@@ -66,20 +66,21 @@ type
implementation
uses
- UGraphic,
- ULanguage,
Math,
Classes,
- ULog;
+ UGraphic,
+ ULanguage,
+ ULog,
+ UUnicodeUtils;
-function TScreenStatDetail.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenStatDetail.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -178,7 +179,7 @@ begin
Typ := TStatType(0);
end;
-procedure TScreenStatDetail.onShow;
+procedure TScreenStatDetail.OnShow;
begin
inherited;
diff --git a/src/screens/UScreenStatMain.pas b/src/screens/UScreenStatMain.pas
index 2fd91288..204f40cd 100644
--- a/src/screens/UScreenStatMain.pas
+++ b/src/screens/UScreenStatMain.pas
@@ -47,14 +47,14 @@ type
private
//Some Stat Value that don't need to be calculated 2 times
SongsWithVid: cardinal;
- function FormatOverviewIntro(FormatStr: string): string;
- function FormatSongOverview(FormatStr: string): string;
- function FormatPlayerOverview(FormatStr: string): string;
+ function FormatOverviewIntro(FormatStr: UTF8String): UTF8String;
+ function FormatSongOverview(FormatStr: UTF8String): UTF8String;
+ function FormatPlayerOverview(FormatStr: UTF8String): UTF8String;
public
TextOverview: integer;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
- procedure onShow; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
+ procedure OnShow; override;
procedure SetAnimationProgress(Progress: real); override;
procedure SetOverview;
@@ -70,21 +70,17 @@ uses
ULanguage,
UCommon,
Classes,
- {$IFDEF win32}
- windows,
- {$ELSE}
- sysconst,
- {$ENDIF}
- ULog;
-
-function TScreenStatMain.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+ ULog,
+ UUnicodeUtils;
+
+function TScreenStatMain.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -170,11 +166,11 @@ begin
//Set Songs with Vid
SongsWithVid := 0;
for I := 0 to Songs.SongList.Count -1 do
- if (TSong(Songs.SongList[I]).Video <> '') then
+ if (TSong(Songs.SongList[I]).Video.IsSet) then
Inc(SongsWithVid);
end;
-procedure TScreenStatMain.onShow;
+procedure TScreenStatMain.OnShow;
begin
inherited;
@@ -182,7 +178,7 @@ begin
SetOverview;
end;
-function TScreenStatMain.FormatOverviewIntro(FormatStr: string): string;
+function TScreenStatMain.FormatOverviewIntro(FormatStr: UTF8String): UTF8String;
var
Year, Month, Day: word;
begin
@@ -203,10 +199,10 @@ begin
end;
end;
-function TScreenStatMain.FormatSongOverview(FormatStr: string): string;
+function TScreenStatMain.FormatSongOverview(FormatStr: UTF8String): UTF8String;
var
CntSongs, CntSungSongs, CntVidSongs: integer;
- MostPopSongArtist, MostPopSongTitle: string;
+ MostPopSongArtist, MostPopSongTitle: UTF8String;
StatList: TList;
MostSungSong: TStatResultMostSungSong;
begin
@@ -247,12 +243,12 @@ begin
end;
end;
-function TScreenStatMain.FormatPlayerOverview(FormatStr: string): string;
+function TScreenStatMain.FormatPlayerOverview(FormatStr: UTF8String): UTF8String;
var
CntPlayers: integer;
BestScoreStat: TStatResultBestScores;
BestSingerStat: TStatResultBestSingers;
- BestPlayer, BestScorePlayer: string;
+ BestPlayer, BestScorePlayer: UTF8String;
BestPlayerScore, BestScore: integer;
SingerStats, ScoreStats: TList;
begin
@@ -307,7 +303,7 @@ end;
procedure TScreenStatMain.SetOverview;
var
- Overview: string;
+ Overview: UTF8String;
begin
// Format overview
Overview := FormatOverviewIntro(Language.Translate('STAT_OVERVIEW_INTRO')) + '\n \n' +
diff --git a/src/screens/UScreenTop5.pas b/src/screens/UScreenTop5.pas
index 1013a9b5..f9c86643 100644
--- a/src/screens/UScreenTop5.pas
+++ b/src/screens/UScreenTop5.pas
@@ -56,9 +56,9 @@ type
Fadeout: boolean;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean; override;
- procedure onShow; override;
+ procedure OnShow; override;
function Draw: boolean; override;
end;
@@ -67,19 +67,19 @@ implementation
uses
UDataBase,
UGraphic,
+ UMain,
UIni,
- UNote;
+ UNote,
+ UUnicodeUtils;
-function TScreenTop5.ParseInput(PressedKey: cardinal;
- CharCode: WideChar;
- PressedDown: boolean): boolean;
+function TScreenTop5.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if PressedDown then
begin
// check normal keys
- case WideCharUpperCase(CharCode)[1] of
- 'Q':
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
begin
Result := false;
Exit;
@@ -113,7 +113,7 @@ begin
Result := true;
if (MouseButton = SDL_BUTTON_LEFT) and BtnDown then
//left-click anywhere sends return
- ParseInput(SDLK_RETURN, #0, true);
+ ParseInput(SDLK_RETURN, 0, true);
end;
constructor TScreenTop5.Create;
@@ -137,7 +137,7 @@ begin
end;
-procedure TScreenTop5.onShow;
+procedure TScreenTop5.OnShow;
var
I: integer;
PMax: integer;
diff --git a/src/screens/UScreenWelcome.pas b/src/screens/UScreenWelcome.pas
index a00a84e2..4b463613 100644
--- a/src/screens/UScreenWelcome.pas
+++ b/src/screens/UScreenWelcome.pas
@@ -45,9 +45,9 @@ type
Animation: real;
Fadeout: boolean;
constructor Create; override;
- function ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean; override;
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function Draw: boolean; override;
- procedure onShow; override;
+ procedure OnShow; override;
end;
implementation
@@ -58,7 +58,7 @@ uses
USkins,
UTexture;
-function TScreenWelcome.ParseInput(PressedKey: cardinal; CharCode: WideChar; PressedDown: boolean): boolean;
+function TScreenWelcome.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
@@ -91,7 +91,7 @@ begin
Fadeout := false;
end;
-procedure TScreenWelcome.onShow;
+procedure TScreenWelcome.OnShow;
begin
inherited;
diff --git a/src/switches.inc b/src/switches.inc
index 215fe239..55d8e619 100644
--- a/src/switches.inc
+++ b/src/switches.inc
@@ -15,14 +15,30 @@
{$ELSE}
{$DEFINE Delphi}
- // Delphi version numbers (ignore versions released before Delphi 6 as they miss the $IF directive):
- // Delphi 6 (VER140), Delphi 7 (VER150), Delphi 8 (VER160)
- // Delphi 9/2005 (VER170), Delphi 10/2006 (VER180)
+ // Delphi version numbers (ignore Delphi < 7 and Delphi 8 (VER160))
- // the inline-procedure directive was introduced with Delphi 2005
- {$IF not (Defined(VER140) or Defined(VER150) or Defined(VER160))}
+ {$IFDEF VER180} // Delphi 2006 (=10)
+ {$DEFINE DELPHI_10}
+ {$DEFINE DELPHI_7_UP}
+ {$DEFINE DELPHI_9_UP}
+ {$DEFINE DELPHI_10_UP}
+ {$ENDIF}
+
+ {$IFDEF VER170} // Delphi 2005 (=9)
+ {$DEFINE DELPHI_9}
+ {$DEFINE DELPHI_7_UP}
+ {$DEFINE DELPHI_9_UP}
+ {$ENDIF}
+
+ {$IFDEF VER150} // Delphi 7
+ {$DEFINE DELPHI_7}
+ {$DEFINE DELPHI_7_UP}
+ {$ENDIF}
+
+ // inline directive introduced with Delphi 2005
+ {$IFDEF DELPHI_9_UP}
{$DEFINE HasInline}
- {$IFEND}
+ {$ENDIF}
{$ENDIF}
@@ -65,8 +81,6 @@
{$DEFINE CONSOLE}
{$IFEND}
-{.$DEFINE UseFreetype}
-
// audio config
{$IF Defined(HaveBASS)}
{$DEFINE UseBASSPlayback}
@@ -114,4 +128,4 @@
{$DEFINE UsePortaudio}
{$IFEND}
-{$ENDIF PASDOC} \ No newline at end of file
+{$ENDIF PASDOC}
diff --git a/src/ultrastardx.dpr b/src/ultrastardx.dpr
index 11796cfa..0b2ff0bc 100644
--- a/src/ultrastardx.dpr
+++ b/src/ultrastardx.dpr
@@ -50,11 +50,7 @@ uses
{$IFDEF Unix}
cthreads, // THIS MUST be the first used unit in FPC if Threads are used!!
// (see http://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial)
- // cwstring crashes in FPC 2.2.2 so do not use the cwstring stuff
- {.$IFNDEF DARWIN}
- {$IFDEF NOIGNORE}
- cwstring, // Enable Unicode support. MacOSX misses some references to iconv.
- {$ENDIF}
+ cwstring, // Enable Unicode support
{$ENDIF}
{$IFNDEF FPC}
@@ -71,16 +67,12 @@ uses
sdl in 'lib\JEDI-SDL\SDL\Pas\sdl.pas',
sdl_image in 'lib\JEDI-SDL\SDL_Image\Pas\sdl_image.pas',
sdlutils in 'lib\JEDI-SDL\SDL\Pas\sdlutils.pas',
+ sdlstreams in 'lib\JEDI-SDL\SDL\Pas\sdlstreams.pas',
UMediaCore_SDL in 'media\UMediaCore_SDL.pas',
zlib in 'lib\zlib\zlib.pas',
png in 'lib\libpng\png.pas',
-
- {$IFDEF UseFreetype}
freetype in 'lib\freetype\freetype.pas',
- UFont in 'base\UFont.pas',
- UTextEncoding in 'base\UTextEncoding.pas',
- {$ENDIF}
{$IFDEF UseBass}
bass in 'lib\bass\delphi\bass.pas',
@@ -136,10 +128,22 @@ uses
{$IFDEF DARWIN}
PseudoThread in 'macosx\PseudoThread.pas',
{$ENDIF}
-
+
SQLiteTable3 in 'lib\SQLite\SQLiteTable3.pas',
SQLite3 in 'lib\SQLite\SQLite3.pas',
+ {$IFDEF MSWINDOWS}
+ // TntUnicodeControls
+ TntSystem in 'lib\TntUnicodeControls\TntSystem.pas',
+ TntSysUtils in 'lib\TntUnicodeControls\TntSysUtils.pas',
+ TntWindows in 'lib\TntUnicodeControls\TntWindows.pas',
+ TntWideStrUtils in 'lib\TntUnicodeControls\TntWideStrUtils.pas',
+ TntClasses in 'lib\TntUnicodeControls\TntClasses.pas',
+ TntFormatStrUtils in 'lib\TntUnicodeControls\TntFormatStrUtils.pas',
+ {$IFNDEF DELPHI_10_UP} // WideStrings for FPC and Delphi < 2006
+ TntWideStrings in 'lib\TntUnicodeControls\TntWideStrings.pas',
+ {$ENDIF}
+ {$ENDIF}
//------------------------------
//Includes - Menu System
@@ -175,7 +179,6 @@ uses
UDraw in 'base\UDraw.pas',
URecord in 'base\URecord.pas',
UTime in 'base\UTime.pas',
- TextGL in 'base\TextGL.pas',
USong in 'base\USong.pas',
UXMLSong in 'base\UXMLSong.pas',
USongs in 'base\USongs.pas',
@@ -198,10 +201,18 @@ uses
URingBuffer in 'base\URingBuffer.pas',
USingScores in 'base\USingScores.pas',
USingNotes in 'base\USingNotes.pas',
- UPath in 'base\UPath.pas',
+ UPathUtils in 'base\UPathUtils.pas',
UNote in 'base\UNote.pas',
UBeatTimer in 'base\UBeatTimer.pas',
+ TextGL in 'base\TextGL.pas',
+ UUnicodeUtils in 'base\UUnicodeUtils.pas',
+ UFont in 'base\UFont.pas',
+ UTextEncoding in 'base\UTextEncoding.pas',
+
+ UPath in 'base\UPath.pas',
+ UFilesystem in 'base\UFilesystem.pas',
+
//------------------------------
//Includes - Plugin Support
//------------------------------