private void WriteFiles_Click(object sender, RoutedEventArgs e)
        {
            if (lockTracks)
            {
                return;
            }
            if (MessageBox.Show("Are you sure you want to overwrite the database?", "Confirm Overwrite", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes)
            {
                return;
            }
            if (!File.Exists(dbFile.Text))
            {
                MessageBox.Show("Please select a valid database file.");
                return;
            }
            if (File.GetAttributes(dbFile.Text).HasFlag(FileAttributes.ReadOnly))
            {
                MessageBox.Show("\"" + dbFile.Text + "\" is Read-only.", "Write Failed");
                return;
            }
            if (File.GetAttributes(dbsFile.Text).HasFlag(FileAttributes.ReadOnly))
            {
                MessageBox.Show("\"" + dbsFile.Text + "\" is Read-only.", "Write Failed");
                return;
            }

            bool setDbHidden  = false;
            bool setDbsHidden = false;

            if (File.GetAttributes(dbFile.Text).HasFlag(FileAttributes.Hidden))
            {
                setDbHidden = true;
                File.SetAttributes(dbFile.Text, File.GetAttributes(dbsFile.Text) & ~FileAttributes.Hidden);
            }

            if (File.GetAttributes(dbsFile.Text).HasFlag(FileAttributes.Hidden))
            {
                setDbsHidden = true;
                File.SetAttributes(dbsFile.Text, File.GetAttributes(dbsFile.Text) & ~FileAttributes.Hidden);
            }

            FileStream fs;
            FileStream fsdbs;

            try
            {
                fs = new FileStream(dbFile.Text, FileMode.Create, FileAccess.ReadWrite);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Could not write to \"" + dbFile.Text + "\": " + "\n" + ex.Message);
                return;
            }

            try
            {
                fsdbs = new FileStream(dbsFile.Text, FileMode.Create, FileAccess.ReadWrite);
            }
            catch (Exception ex)
            {
                fs.Close();
                MessageBox.Show("Could not write to \"" + dbsFile.Text + "\": " + "\n" + ex.Message);
                return;
            }

            BinaryWriter bw            = new BinaryWriter(fs);
            BinaryWriter bwdbs         = new BinaryWriter(fsdbs);
            string       userMusicPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Rockstar Games\GTA V\User Music";

            foreach (Track t in tracks)
            {
                byte[] header         = BitConverter.GetBytes(t.ID);
                byte[] header2        = { 0x00, 0x00, 0x00, 0x00 };
                byte[] chunkSeparator = { 0x00 };
                byte[] chunkTitle     = TrackUtilities.StrToPaddedChunk(t.Title, 31, 0x00, Encoding.Default);
                byte[] chunkArtist    = TrackUtilities.StrToPaddedChunk(t.Artist, 31, 0x00, Encoding.Default);
                byte[] duration       = BitConverter.GetBytes((int)t.Duration.TotalMilliseconds);
                byte[] unknown        = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                byte[] footer         = { 0x02, 0x00, 0x00, 0x00 };

                string final_path = t.Path;
                if (final_path.Contains(userMusicPath))
                {
                    final_path = final_path.Insert(userMusicPath.Length, @"\"); //GTA wants a double slash after User Music for some reason
                }
                else
                {
                    final_path = TrackUtilities.GetShortPath(final_path);
                }
                byte[] pathLength = BitConverter.GetBytes(final_path.Length);

                byte[] chunk = header.Concat(header2).Concat(chunkArtist).Concat(chunkSeparator).Concat(chunkTitle).Concat(chunkSeparator).Concat(duration).Concat(unknown).Concat(footer).Concat(pathLength).ToArray();

                bw.Write(chunk);
                bwdbs.Write(Encoding.Unicode.GetBytes(final_path));
            }

            bw.Close();
            bwdbs.Close();
            fs.Close();
            fsdbs.Close();

            if (setDbHidden)
            {
                File.SetAttributes(dbFile.Text, File.GetAttributes(dbFile.Text) | FileAttributes.Hidden);
            }
            if (setDbsHidden)
            {
                File.SetAttributes(dbsFile.Text, File.GetAttributes(dbsFile.Text) | FileAttributes.Hidden);
            }
            MessageBox.Show("Be sure to set the files to read-only prior to launching the game.\n\nAlternatively, disable the \"Auto-scan for Music\" setting in-game.", "Database files written");
        }
        private void LoadButton_Click(object sender, RoutedEventArgs e)
        {
            if (lockTracks)
            {
                return;
            }
            if (!File.Exists(dbFile.Text))
            {
                MessageBox.Show("Please select a valid database file.");
                return;
            }

            if (File.GetAttributes(dbFile.Text).HasFlag(FileAttributes.ReadOnly) && MessageBox.Show("\"" + dbFile.Text + "\" is Read-only! File cannot be modified. Load anyway?", "Warning", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes)
            {
                return;
            }
            if (!File.GetAttributes(dbFile.Text).HasFlag(FileAttributes.ReadOnly) && File.GetAttributes(dbsFile.Text).HasFlag(FileAttributes.ReadOnly) && MessageBox.Show("\"" + dbsFile.Text + "\" is Read-only! File cannot be modified. Load anyway?", "Warning", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes)
            {
                return;
            }
            FileStream fs;
            FileStream fsdbs;

            try
            {
                fs = new FileStream(dbFile.Text, FileMode.Open, FileAccess.Read);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Could not open \"" + dbFile.Text + "\": " + "\n" + ex.Message);
                return;
            }

            try
            {
                fsdbs = new FileStream(dbsFile.Text, FileMode.Open, FileAccess.Read);
            }
            catch (Exception ex)
            {
                fs.Close();
                MessageBox.Show("Could not open \"" + dbsFile.Text + "\": " + "\n" + ex.Message);
                return;
            }

            if (tracks.Count > 0)
            {
                if (MessageBox.Show("Are you sure you want to clear the track list? Any unsaved data will be lost.", "Confirm Clear", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes)
                {
                    return;
                }
                tracks.Clear();
            }

            if (fs.Length % 96 != 0)
            {
                if (MessageBox.Show("\"" + dbsFile.Text + "\" seems to be corrupt (incorrect length). Try to parse anyway?", "Incorrect Length", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes)
                {
                    fs.Close();
                    fsdbs.Close();
                    return;
                }
            }

            BinaryReader br      = new BinaryReader(fs);
            BinaryReader brdbs   = new BinaryReader(fsdbs);
            int          counter = 0;

            while (fs.CanRead && fs.Position < fs.Length)
            {
                if (fs.Length - fs.Position < 96)
                {
                    break;
                }
                byte[] header          = br.ReadBytes(8);
                byte[] chunkArtist     = br.ReadBytes(31);
                byte   chunkSeparator  = br.ReadByte();
                byte[] chunkTitle      = br.ReadBytes(31);
                byte   chunkSeparator2 = br.ReadByte();
                byte[] duration        = br.ReadBytes(4);
                byte[] unknown         = br.ReadBytes(12);
                byte[] footer          = br.ReadBytes(4);
                byte[] pathByteLength  = br.ReadBytes(4);
                int    pathLength      = BitConverter.ToInt32(pathByteLength) * 2;

                string path = Encoding.Unicode.GetString(brdbs.ReadBytes(pathLength));

                string artist = "";
                string title  = "";
                foreach (byte b in chunkArtist)
                {
                    if (b == 0x00)
                    {
                        break;
                    }
                    artist += (char)b;
                }
                foreach (byte b in chunkTitle)
                {
                    if (b == 0x00)
                    {
                        break;
                    }
                    title += (char)b;
                }
                tracks.Add(new Track()
                {
                    ID = counter, Title = title, Artist = artist, ShortPath = TrackUtilities.GetShortPath(path.Replace(@"\\", @"\")), Path = System.IO.Path.GetFullPath(path.Replace(@"\\", @"\")), Duration = TimeSpan.FromMilliseconds(BitConverter.ToInt32(duration))
                });
                counter++;
            }

            br.Close();
            brdbs.Close();
            fs.Close();
            fsdbs.Close();

            ((ListCollectionView)trackList.ItemsSource).Refresh();
            trackList.Items.Refresh();
        }