Easy Freelancer character decoding with C#
I recently spent a couple of hours figuring out how to decode a Freelancer character file using C#. It turns out it's pretty easy, essentially 6 lines of copy-paste code wrapped up as a function that returns the entire decoded file in a string. It isn't really tutorial-type material, but there is one bit that can cause problems if you don't know about it, so I figured it was worth posting.
Code is at the bottom. WARNING! I substituted "<}>" for closing square brackets in the code; change it back or the code won't compile.
The major problem is that .NET makes very bad guesses about FL file content if you try to read them without specifying the encoding as UTF7. The result is garbage.
Other than that, none of this is particularly clever. I trim off the first 4 characters (the "FLS1" header) as I read the data in, and directly turn it into a character array. Then I just un-hash each character using the secret word "Gene" and the character hash outlined by Jor in his flcodec source (which he says he wrote based on algorithm information from Sherlog).
I'm not sure how good performance is, but I read the entire file into memory in 1 step, then write the decoded data to a presized stringbuilder; this theoretically makes it much faster than per-character file reading, but it probably is a bit slower than techniques that skips some content lines, and a bit more memory-intensive than a routine that simply modifies characters in-place in the data array.
<pre><font size=1 face=Courier>public string DecodeCharacter(string filepath)
{
// read the entire raw file as a character array;
// we immediately strip out the FLS1 using Substring(4).
char[<}> data = (new System.IO.StreamReader(filepath, System.Text.Encoding.UTF7)).
ReadToEnd().Substring(4).ToCharArray();
// create a pre-sized stringbuilder.
System.Text.StringBuilder sb =
new System.Text.StringBuilder(data.Length);
char[<}> gene = "Gene".ToCharArray();
for(int i = 0; i < data.GetLength(0); i++)
{
sb.Append((char)(data[i<}> ^ (((gene[i % 4<}> + i) % 256) / 0x80)));
}
return(sb.ToString());
} </font></pre>
Code is at the bottom. WARNING! I substituted "<}>" for closing square brackets in the code; change it back or the code won't compile.
The major problem is that .NET makes very bad guesses about FL file content if you try to read them without specifying the encoding as UTF7. The result is garbage.
Other than that, none of this is particularly clever. I trim off the first 4 characters (the "FLS1" header) as I read the data in, and directly turn it into a character array. Then I just un-hash each character using the secret word "Gene" and the character hash outlined by Jor in his flcodec source (which he says he wrote based on algorithm information from Sherlog).
I'm not sure how good performance is, but I read the entire file into memory in 1 step, then write the decoded data to a presized stringbuilder; this theoretically makes it much faster than per-character file reading, but it probably is a bit slower than techniques that skips some content lines, and a bit more memory-intensive than a routine that simply modifies characters in-place in the data array.
<pre><font size=1 face=Courier>public string DecodeCharacter(string filepath)
{
// read the entire raw file as a character array;
// we immediately strip out the FLS1 using Substring(4).
char[<}> data = (new System.IO.StreamReader(filepath, System.Text.Encoding.UTF7)).
ReadToEnd().Substring(4).ToCharArray();
// create a pre-sized stringbuilder.
System.Text.StringBuilder sb =
new System.Text.StringBuilder(data.Length);
char[<}> gene = "Gene".ToCharArray();
for(int i = 0; i < data.GetLength(0); i++)
{
sb.Append((char)(data[i<}> ^ (((gene[i % 4<}> + i) % 256) / 0x80)));
}
return(sb.ToString());
} </font></pre>