Modifying fpl files

Please note: This article is only available in English.
foobar2000 is certainly a really nice music player. The only bad thing is a binary playlist format...

foobar2000 comes with a proprietary playlist format called *.fpl. This format gave the developers a quick and robust starting point. According to official sources a (human-readable) text-format has been discussed, but omitted after realizing the performance drawback. In my opinion this should have been discussed much more before deciding for a binary format.

The issue is not a new one: Adding or removing (or modifying) single entries with the foobar2000 application is easily possible, however, scripting and other possibilities are not integrated. In my case I had a big issue with changed file paths. foobar2000 stores files with an absolute path. This certainly has some advantages:

  • The playlist is location-independent.
  • Resolving the path is not required.

But not everything is gold. The big disadvantage is that every (even little) change in the path of the files (like changing the drive letter) will lead to unplayable files.

Of course there would have been an easy solution. Each file would be stored with a relative path to a base path. The base path would be the (initial) location of the playlist file. The combination of the relative path and the base path would now be the path that is currently stored. If that path is invalid, the relative path (relative to the current position of the playlist file) would be used. So this would work just fine - and it would also save bytes in the playlist file since relative paths are (usually) much shorter than absolute paths.

After this discussion about improving the foobar2000 playlist file format (which is not in my hand), it is time for some coding.

The way that such binary formats are usually build up is a kind of fixed pattern of bytes for certain values. If a value has a variable length then the length has to be saved before saving the content. In case of strings (like a file path), we have an array of chars. Since this array has (usually) a variable size, we need to save the length of this array before we save the array. Therefore extending the length of a file path is much harder than just changing single letters.

In this article I will only change single letters. This requires the least amount of knowledge about the file format and works well with the least amount of tests.

I want to change file paths that start with D:\ to F:\. First we need to check the ASCII table for the specific values. Working with ASCII I prefer to only use hex-numbers. In our case we look for the following combination:

  1. Starting with 0x44 (D)
  2. Now the colon with 0x3A (:)
  3. Ending with 0x5C (\)

We only need to change the first combination to 0x46. I then wrote a short code snippet with the free tool LINQPad:

void Main()
{
	var files = Directory.GetFiles(@"F:\Music\Playlists");
	
	foreach(var file in files)
	{
		var bytes = File.ReadAllBytes(file);
		var modified = false;
		
		for(int i = 2; i < bytes.Length; i++)
		{
			if(bytes[i-2] == 0x44 &&
			   bytes[i-1] == 0x3a &&
			   bytes[i-0] == 0x5c)
			{
				bytes[i-2] = 0x46;
				modified = true;
			}
		}
		
		if(modified)
		{
			File.WriteAllBytes(file, bytes);
			("File " + file + " modified ...").Dump();
		}
	}
}

This snippet reads all files from the given directory (in this directory there are only FPL files - otherwise do NOT use this code snippet, but make sure to only fetch *.fpl files!).

It then goes on to look for the specified combination (this is not very well optimized, but we do not care about performance here). If the combination is found we change the specific part from D to F.

Finally if at least one modification has been done, we overwrite the existing file. Also this is maybe not a good option for you. Please make sure to have a backup of the old files or save the files with a new filename otherwise.

This script works well in case of changing the file path from one state to another, where both states have the same length.

Due to the Windows filesystem it also works if the new path is smaller than the previous, since we can insert values that will be omitted by Windows (multiple backslashes for instance). Please also note that this algorithm is idempotent, i.e. once applied to the files another round on the modified files will result in no changes.

Created . Last updated .

References

Sharing is caring!