Skip to content

Commit

Permalink
Fix issue #5: Fix files containing invalid file name characters
Browse files Browse the repository at this point in the history
Some games created with a operating system supporting wider encoding scheme might not extract correctl
on all systems. File paths extracted from the archives are now cleaned before trying to use them
when writing a file.
  • Loading branch information
uuksu committed Apr 22, 2023
1 parent 0f9bb9d commit d3a4ac9
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 12 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Changed in this release

* **Fix wrong output names on UNIX**: Fix files extracted from a RGASSAD going to a wrong directories on a UNIX-like systems because of hardcoded path delimeters. Thank you @tyrone-sudeium for contribution!
* **Fix [issue #5](https://github.com/uuksu/RPGMakerDecrypter/issues/5)**: Some games created with a operating system supporting wider encoding scheme might not extract correctly on all systems. File paths extracted from the archives are now cleaned before trying to use them when writing a file. Thanks @izayoi256 for reporting the issue!
66 changes: 66 additions & 0 deletions RPGMakerDecrypter.Decrypter/ArchiveFileNameUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace RPGMakerDecrypter.Decrypter
{
public static class ArchivedFileNameUtils
{
public static string GetFileName(string name)
{
return GetPathParts(name).Last();
}

public static string GetPlatformSpecificPath(string name)
{
var pathParts = GetPathParts(name);

pathParts = CleanUnicodeCharacters(pathParts);
pathParts = CleanInvalidPathCharacters(pathParts);

return Path.Combine(pathParts);
}

private static string[] GetPathParts(string name)
{
// Paths in RGSSAD file names are always with Windows-style delimeters
return name.Split('\\');
}

private static string[] CleanUnicodeCharacters(string[] pathParts)
{
var cleanedPathParts = new List<string>();
var unicodeConstantRegex = new Regex(@"(?i)\\(u|U)([0-9]|[A-F])([0-9]|[A-F])([0-9]|[A-F])([0-9]|[A-F])");

foreach (var pathPart in pathParts)
{
cleanedPathParts.Add(unicodeConstantRegex.Replace(pathPart, string.Empty));
}

return cleanedPathParts.ToArray();
}

private static string[] CleanInvalidPathCharacters(string[] pathParts)
{
var cleanedPathParts = new List<string>();

foreach (var pathPart in pathParts)
{
var cleanedPathPart = pathPart;

foreach(var invalidFileNameChar in Path.GetInvalidFileNameChars())
{
cleanedPathPart = cleanedPathPart.Replace($"{invalidFileNameChar}", string.Empty);
}

cleanedPathParts.Add(cleanedPathPart);
}

return cleanedPathParts.ToArray();
}
}
}
14 changes: 5 additions & 9 deletions RPGMakerDecrypter.Decrypter/RGSSAD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,13 @@ public void ExtractAllFiles(string outputDirectoryPath, bool overrideExisting =
/// <exception cref="System.Exception">Invalid file path. Archive could be corrupted.</exception>
public void ExtractFile(ArchivedFile archivedFile, string outputDirectoryPath, bool overrideExisting = false, bool createDirectory = true)
{
var platformSpecificArchiveFilePath = ArchivedFileNameUtils.GetPlatformSpecificPath(archivedFile.Name);

string outputPath;

if (createDirectory)
{
// Create output directory if it does not exist
string filePathStr = archivedFile.Name;
if (Path.DirectorySeparatorChar != '\\') {
// On Unix-like systems we need to correct that the path names encoded in RGSSAD always use Windows path delimiters.
filePathStr = filePathStr.Replace('\\', Path.DirectorySeparatorChar);
}
string directoryPath = Path.GetDirectoryName(filePathStr);
string directoryPath = Path.GetDirectoryName(platformSpecificArchiveFilePath);

if (directoryPath == null)
{
Expand All @@ -109,11 +105,11 @@ public void ExtractFile(ArchivedFile archivedFile, string outputDirectoryPath, b
Directory.CreateDirectory(Path.Combine(outputDirectoryPath, directoryPath));
}

outputPath = Path.Combine(outputDirectoryPath, filePathStr);
outputPath = Path.Combine(outputDirectoryPath, platformSpecificArchiveFilePath);
}
else
{
string fileName = archivedFile.Name.Split('\\').Last();
string fileName = Path.GetFileName(platformSpecificArchiveFilePath);
outputPath = Path.Combine(outputDirectoryPath, fileName);
}

Expand Down
4 changes: 2 additions & 2 deletions RPGMakerDecrypter.Gui/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private void archivedFilesListBox_SelectedIndexChanged(object sender, EventArgs

ArchivedFile archivedFile = currentArchive.ArchivedFiles[archivedFilesListBox.SelectedIndex];

fileNameTextBox.Text = archivedFile.Name;
fileNameTextBox.Text = ArchivedFileNameUtils.GetFileName(archivedFile.Name);
sizeTextBox.Text = archivedFile.Size.ToString();

extractFileButton.Enabled = true;
Expand Down Expand Up @@ -176,7 +176,7 @@ private void extractFileButton_Click(object sender, EventArgs e)

ArchivedFile archivedFile = currentArchive.ArchivedFiles[archivedFilesListBox.SelectedIndex];

string fileName = archivedFile.Name.Split('\\').Last();
string fileName = ArchivedFileNameUtils.GetFileName(archivedFile.Name);
string extension = fileName.Split('.').Last();

SaveFileDialog saveFileDialog = new SaveFileDialog();
Expand Down

0 comments on commit d3a4ac9

Please sign in to comment.