Zip: Fixed issues with non-UTF8 filenames in zip files
This commit is contained in:
parent
ef63dfa816
commit
0d1e9bbcb3
20 changed files with 334 additions and 212 deletions
|
@ -18,7 +18,7 @@
|
|||
#include "../Utilities/Timer.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/PlatformUtilities.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "HdBuilderPpu.h"
|
||||
#include "HdPpu.h"
|
||||
#include "NsfPpu.h"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "stdafx.h"
|
||||
#include <atomic>
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "RomData.h"
|
||||
|
||||
class Debugger;
|
||||
|
|
|
@ -758,6 +758,7 @@
|
|||
<ClInclude Include="UnRom_94.h" />
|
||||
<ClInclude Include="VideoDecoder.h" />
|
||||
<ClInclude Include="BaseVideoFilter.h" />
|
||||
<ClInclude Include="VirtualFile.h" />
|
||||
<ClInclude Include="VRC1.h" />
|
||||
<ClInclude Include="VRC2_4.h" />
|
||||
<ClInclude Include="VRC3.h" />
|
||||
|
@ -875,6 +876,7 @@
|
|||
<ClCompile Include="VideoRenderer.cpp" />
|
||||
<ClCompile Include="VideoDecoder.cpp" />
|
||||
<ClCompile Include="BaseVideoFilter.cpp" />
|
||||
<ClCompile Include="VirtualFile.cpp" />
|
||||
<ClCompile Include="VsControlManager.cpp" />
|
||||
<ClCompile Include="ScaleFilter.cpp" />
|
||||
<ClCompile Include="VsZapper.cpp" />
|
||||
|
|
|
@ -1240,6 +1240,9 @@
|
|||
<ClInclude Include="LuaScriptingContext.h">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualFile.h">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1503,5 +1506,8 @@
|
|||
<ClCompile Include="HdAudioDevice.cpp">
|
||||
<Filter>HdPacks</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualFile.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,6 +1,6 @@
|
|||
#include <algorithm>
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "HdPackBuilder.h"
|
||||
|
||||
HdPackBuilder* HdPackBuilder::_instance = nullptr;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "HdData.h"
|
||||
#include "../Utilities/ZipReader.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "HdData.h"
|
||||
#include "VirtualFile.h"
|
||||
|
||||
class HdPackLoader
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "../Utilities/stb_vorbis.h"
|
||||
#include "../Utilities/blip_buf.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
class OggReader
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/CRC32.h"
|
||||
#include "../Utilities/sha1.h"
|
||||
#include "../Utilities/ArchiveReader.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "RomLoader.h"
|
||||
#include "iNesLoader.h"
|
||||
#include "FdsLoader.h"
|
||||
|
@ -98,7 +99,7 @@ string RomLoader::FindMatchingRomInFile(string filePath, HashInfo hashInfo)
|
|||
{
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filePath);
|
||||
if(reader) {
|
||||
for(string file : reader->GetFileList({ ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe" })) {
|
||||
for(string file : reader->GetFileList(VirtualFile::RomExtensions)) {
|
||||
RomLoader loader;
|
||||
vector<uint8_t> fileData;
|
||||
if(loader.LoadFile(filePath)) {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "RomData.h"
|
||||
class ArchiveReader;
|
||||
|
||||
class RomLoader
|
||||
{
|
||||
private:
|
||||
RomData _romData;
|
||||
string _filename;
|
||||
private:
|
||||
RomData _romData;
|
||||
string _filename;
|
||||
|
||||
static string FindMatchingRomInFile(string filePath, HashInfo hashInfo);
|
||||
static string FindMatchingRomInFile(string filePath, HashInfo hashInfo);
|
||||
|
||||
public:
|
||||
bool LoadFile(VirtualFile romFile);
|
||||
bool LoadFile(string filename, vector<uint8_t> &fileData);
|
||||
public:
|
||||
bool LoadFile(VirtualFile romFile);
|
||||
bool LoadFile(string filename, vector<uint8_t> &fileData);
|
||||
|
||||
RomData GetRomData();
|
||||
static string FindMatchingRom(vector<string> romFiles, string romFilename, HashInfo hashInfo, bool useFastSearch);
|
||||
RomData GetRomData();
|
||||
static string FindMatchingRom(vector<string> romFiles, string romFilename, HashInfo hashInfo, bool useFastSearch);
|
||||
};
|
||||
|
|
|
@ -215,9 +215,10 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame)
|
|||
|
||||
Console::Pause();
|
||||
try {
|
||||
Console::LoadROM(romPath, patchPath);
|
||||
if(!resetGame) {
|
||||
SaveStateManager::LoadState(stateStream, false);
|
||||
if(Console::LoadROM(romPath, patchPath)) {
|
||||
if(!resetGame) {
|
||||
SaveStateManager::LoadState(stateStream, false);
|
||||
}
|
||||
}
|
||||
} catch(std::exception ex) {
|
||||
Console::GetInstance()->Stop();
|
||||
|
|
160
Core/VirtualFile.cpp
Normal file
160
Core/VirtualFile.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include "VirtualFile.h"
|
||||
#include "../Utilities/sha1.h"
|
||||
#include "../Utilities/ArchiveReader.h"
|
||||
#include "../Utilities/StringUtilities.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/BpsPatcher.h"
|
||||
#include "../Utilities/IpsPatcher.h"
|
||||
#include "../Utilities/UpsPatcher.h"
|
||||
|
||||
const std::initializer_list<string> VirtualFile::RomExtensions = { ".nes", ".fds", ".nsf", ".nsfe", "*.unf", "*.unif" };
|
||||
|
||||
VirtualFile::VirtualFile()
|
||||
{
|
||||
}
|
||||
|
||||
VirtualFile::VirtualFile(const string & archivePath, const string innerFile)
|
||||
{
|
||||
_path = archivePath;
|
||||
_innerFile = innerFile;
|
||||
}
|
||||
|
||||
VirtualFile::VirtualFile(const string & file)
|
||||
{
|
||||
vector<string> tokens = StringUtilities::Split(file, '\x1');
|
||||
_path = tokens[0];
|
||||
if(tokens.size() > 1) {
|
||||
_innerFile = tokens[1];
|
||||
if(tokens.size() > 2) {
|
||||
try {
|
||||
_innerFileIndex = std::stoi(tokens[2]);
|
||||
} catch(std::exception) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFile::VirtualFile(std::istream & input, string filePath)
|
||||
{
|
||||
_path = filePath;
|
||||
FromStream(input, _data);
|
||||
}
|
||||
|
||||
VirtualFile::operator std::string() const
|
||||
{
|
||||
if(_innerFile.empty()) {
|
||||
return _path;
|
||||
} else if(_path.empty()) {
|
||||
throw std::runtime_error("Cannot convert to string");
|
||||
} else {
|
||||
return _path + "\x1" + _innerFile;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualFile::FromStream(std::istream & input, vector<uint8_t>& output)
|
||||
{
|
||||
input.seekg(0, std::ios::end);
|
||||
uint32_t fileSize = (uint32_t)input.tellg();
|
||||
input.seekg(0, std::ios::beg);
|
||||
|
||||
output.resize(fileSize, 0);
|
||||
input.read((char*)output.data(), fileSize);
|
||||
}
|
||||
|
||||
void VirtualFile::LoadFile()
|
||||
{
|
||||
if(_data.size() == 0) {
|
||||
if(!_innerFile.empty()) {
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(_path);
|
||||
if(reader) {
|
||||
if(_innerFileIndex >= 0) {
|
||||
vector<string> filelist = reader->GetFileList(VirtualFile::RomExtensions);
|
||||
if(filelist.size() > _innerFileIndex) {
|
||||
reader->ExtractFile(filelist[_innerFileIndex], _data);
|
||||
}
|
||||
} else {
|
||||
reader->ExtractFile(_innerFile, _data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ifstream input(_path, std::ios::in | std::ios::binary);
|
||||
if(input.good()) {
|
||||
FromStream(input, _data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VirtualFile::IsValid()
|
||||
{
|
||||
LoadFile();
|
||||
return _data.size() > 0;
|
||||
}
|
||||
|
||||
string VirtualFile::GetFilePath()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
string VirtualFile::GetFolderPath()
|
||||
{
|
||||
return FolderUtilities::GetFolderName(_path);
|
||||
}
|
||||
|
||||
string VirtualFile::GetFileName()
|
||||
{
|
||||
return _innerFile.empty() ? FolderUtilities::GetFilename(_path, true) : _innerFile;
|
||||
}
|
||||
|
||||
string VirtualFile::GetSha1Hash()
|
||||
{
|
||||
string hash = SHA1::GetHash(_data);
|
||||
std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool VirtualFile::ReadFile(vector<uint8_t>& out)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() > 0) {
|
||||
out.resize(_data.size(), 0);
|
||||
std::copy(_data.begin(), _data.end(), out.begin());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VirtualFile::ReadFile(std::stringstream & out)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() > 0) {
|
||||
out.write((char*)_data.data(), _data.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VirtualFile::ApplyPatch(VirtualFile & patch)
|
||||
{
|
||||
//Apply patch file
|
||||
bool result = false;
|
||||
if(patch.IsValid() && patch._data.size() >= 5) {
|
||||
vector<uint8_t> patchedData;
|
||||
std::stringstream ss;
|
||||
patch.ReadFile(ss);
|
||||
|
||||
if(memcmp(patch._data.data(), "PATCH", 5) == 0) {
|
||||
result = IpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
} else if(memcmp(patch._data.data(), "UPS1", 4) == 0) {
|
||||
result = UpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
} else if(memcmp(patch._data.data(), "BPS1", 4) == 0) {
|
||||
result = BpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
}
|
||||
if(result) {
|
||||
_data = patchedData;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
37
Core/VirtualFile.h
Normal file
37
Core/VirtualFile.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <sstream>
|
||||
|
||||
class VirtualFile
|
||||
{
|
||||
private:
|
||||
string _path = "";
|
||||
string _innerFile = "";
|
||||
int32_t _innerFileIndex = -1;
|
||||
vector<uint8_t> _data;
|
||||
|
||||
void FromStream(std::istream &input, vector<uint8_t> &output);
|
||||
|
||||
void LoadFile();
|
||||
|
||||
public:
|
||||
static const std::initializer_list<string> RomExtensions;
|
||||
|
||||
VirtualFile();
|
||||
VirtualFile(const string &archivePath, const string innerFile);
|
||||
VirtualFile(const string &file);
|
||||
VirtualFile(std::istream &input, string filePath);
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
bool IsValid();
|
||||
string GetFilePath();
|
||||
string GetFolderPath();
|
||||
string GetFileName();
|
||||
string GetSha1Hash();
|
||||
|
||||
bool ReadFile(vector<uint8_t> &out);
|
||||
bool ReadFile(std::stringstream &out);
|
||||
|
||||
bool ApplyPatch(VirtualFile &patch);
|
||||
};
|
|
@ -11,6 +11,7 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
public string Path { get; set; }
|
||||
public string InnerFile { get; set; }
|
||||
public int InnerFileIndex { get; set; }
|
||||
|
||||
public bool Exists { get { return File.Exists(Path); } }
|
||||
public bool Compressed { get { return !string.IsNullOrWhiteSpace(InnerFile); } }
|
||||
|
@ -20,7 +21,14 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return Path + (Compressed ? ("\x1" + InnerFile) : "");
|
||||
string resPath = Path;
|
||||
if(Compressed) {
|
||||
resPath += "\x1" + InnerFile;
|
||||
if(InnerFileIndex > 0) {
|
||||
resPath += "\x1" + (InnerFileIndex - 1).ToString();
|
||||
}
|
||||
}
|
||||
return resPath;
|
||||
}
|
||||
|
||||
static public implicit operator ResourcePath(string path)
|
||||
|
@ -28,7 +36,8 @@ namespace Mesen.GUI.Forms
|
|||
string[] tokens = path.Split('\x1');
|
||||
return new ResourcePath() {
|
||||
Path = tokens[0],
|
||||
InnerFile = tokens.Length > 1 ? tokens[1] : ""
|
||||
InnerFile = tokens.Length > 1 ? tokens[1] : "",
|
||||
InnerFileIndex = tokens.Length > 2 ? (int.Parse(tokens[2]) + 1) : 0
|
||||
};
|
||||
}
|
||||
|
||||
|
|
2
GUI.NET/Forms/frmSelectRom.Designer.cs
generated
2
GUI.NET/Forms/frmSelectRom.Designer.cs
generated
|
@ -75,7 +75,6 @@
|
|||
this.lstRoms.Size = new System.Drawing.Size(457, 182);
|
||||
this.lstRoms.TabIndex = 1;
|
||||
this.lstRoms.SelectedIndexChanged += new System.EventHandler(this.lstRoms_SelectedIndexChanged);
|
||||
this.lstRoms.DoubleClick += new System.EventHandler(this.lstRoms_DoubleClick);
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
|
@ -99,7 +98,6 @@
|
|||
this.btnOK.TabIndex = 0;
|
||||
this.btnOK.Text = "OK";
|
||||
this.btnOK.UseVisualStyleBackColor = true;
|
||||
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
|
|
|
@ -8,16 +8,17 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static Mesen.GUI.InteropEmu;
|
||||
|
||||
namespace Mesen.GUI.Forms
|
||||
{
|
||||
public partial class frmSelectRom : BaseForm
|
||||
{
|
||||
private List<string> _romFiles;
|
||||
private List<ArchiveRomEntry> _romFiles;
|
||||
private int SelectedIndex { get; set; }
|
||||
private string _previousSearch = "";
|
||||
|
||||
public frmSelectRom(List<string> romFiles)
|
||||
public frmSelectRom(List<ArchiveRomEntry> romFiles)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
@ -56,9 +57,9 @@ namespace Mesen.GUI.Forms
|
|||
if(string.IsNullOrWhiteSpace(_previousSearch)) {
|
||||
lstRoms.Items.AddRange(_romFiles.ToArray());
|
||||
} else {
|
||||
List<string> romsToAdd = new List<string>();
|
||||
foreach(string rom in _romFiles) {
|
||||
if(rom.IndexOf(_previousSearch, StringComparison.InvariantCultureIgnoreCase) >= 0) {
|
||||
List<ArchiveRomEntry> romsToAdd = new List<ArchiveRomEntry>();
|
||||
foreach(ArchiveRomEntry rom in _romFiles) {
|
||||
if(rom.Filename.IndexOf(_previousSearch, StringComparison.InvariantCultureIgnoreCase) >= 0) {
|
||||
romsToAdd.Add(rom);
|
||||
}
|
||||
}
|
||||
|
@ -75,21 +76,28 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
public static bool SelectRom(ref ResourcePath resource)
|
||||
{
|
||||
List<string> archiveRomList = InteropEmu.GetArchiveRomList(resource.Path);
|
||||
List<ArchiveRomEntry> archiveRomList = InteropEmu.GetArchiveRomList(resource.Path);
|
||||
|
||||
if(archiveRomList.Contains(resource.InnerFile)) {
|
||||
if(archiveRomList.Select(entry => entry.Filename).Contains(resource.InnerFile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(archiveRomList.Count > 1) {
|
||||
frmSelectRom frm = new frmSelectRom(archiveRomList);
|
||||
if(frm.ShowDialog(null, Application.OpenForms[0]) == DialogResult.OK) {
|
||||
resource.InnerFile = frm.lstRoms.SelectedItem.ToString();
|
||||
ArchiveRomEntry entry = frm.lstRoms.SelectedItem as ArchiveRomEntry;
|
||||
resource.InnerFile = entry.Filename;
|
||||
if(!entry.IsUtf8) {
|
||||
resource.InnerFileIndex = archiveRomList.IndexOf(entry) + 1;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if(archiveRomList.Count == 1) {
|
||||
resource.InnerFile = archiveRomList[0];
|
||||
resource.InnerFile = archiveRomList[0].Filename;
|
||||
if(!archiveRomList[0].IsUtf8) {
|
||||
resource.InnerFileIndex = 1;
|
||||
}
|
||||
} else {
|
||||
resource.InnerFile = "";
|
||||
}
|
||||
|
@ -97,27 +105,11 @@ namespace Mesen.GUI.Forms
|
|||
return true;
|
||||
}
|
||||
|
||||
void SetSelectedIndex()
|
||||
{
|
||||
this.SelectedIndex = _romFiles.IndexOf(lstRoms.SelectedItem.ToString());
|
||||
this.DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
private void lstRoms_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
btnOK.Enabled = lstRoms.SelectedItems.Count > 0;
|
||||
}
|
||||
|
||||
private void lstRoms_DoubleClick(object sender, EventArgs e)
|
||||
{
|
||||
SetSelectedIndex();
|
||||
}
|
||||
|
||||
private void btnOK_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetSelectedIndex();
|
||||
}
|
||||
|
||||
private void tmrSearch_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if(txtSearch.Text.Trim() != _previousSearch) {
|
||||
|
|
|
@ -32,7 +32,6 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void LoadRecentGame([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath, [MarshalAs(UnmanagedType.I1)]bool resetGame);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "GetArchiveRomList")] private static extern IntPtr GetArchiveRomListWrapper([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename);
|
||||
public static List<string> GetArchiveRomList(string filename) { return new List<string>(PtrToStringUtf8(InteropEmu.GetArchiveRomListWrapper(filename)).Split(new string[] { "[!|!]" }, StringSplitOptions.RemoveEmptyEntries)); }
|
||||
|
||||
[DllImport(DLLPath)] public static extern void SetMousePosition(double x, double y);
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HasZapper();
|
||||
|
@ -671,6 +670,65 @@ namespace Mesen.GUI
|
|||
return new List<string>(PtrToStringUtf8(InteropEmu.GetAudioDevicesWrapper()).Split(new string[1] { "||" }, StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
public class ArchiveRomEntry
|
||||
{
|
||||
public string Filename;
|
||||
public bool IsUtf8;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Filename;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ArchiveRomEntry> GetArchiveRomList(string filename)
|
||||
{
|
||||
//Split the array on the [!|!] delimiter
|
||||
byte[] buffer = PtrToByteArray(InteropEmu.GetArchiveRomListWrapper(filename));
|
||||
List<List<byte>> filenames = new List<List<byte>>();
|
||||
List<byte> filenameBytes = new List<byte>();
|
||||
for(int i = 0; i < buffer.Length - 5; i++) {
|
||||
if(buffer[i] == '[' && buffer[i+1] == '!' && buffer[i+2] == '|' && buffer[i+3] == '!' && buffer[i+4] == ']') {
|
||||
filenames.Add(filenameBytes);
|
||||
filenameBytes = new List<byte>();
|
||||
i+=4;
|
||||
} else {
|
||||
filenameBytes.Add(buffer[i]);
|
||||
}
|
||||
}
|
||||
filenames.Add(filenameBytes);
|
||||
|
||||
List<ArchiveRomEntry> entries = new List<ArchiveRomEntry>();
|
||||
|
||||
//Check whether or not each string is a valid utf8 filename, if not decode it using the system's default encoding.
|
||||
//This is necessary because zip files do not have any rules when it comes to encoding filenames
|
||||
for(int i = 0; i < filenames.Count; i++) {
|
||||
byte[] originalBytes = filenames[i].ToArray();
|
||||
string utf8Filename = Encoding.UTF8.GetString(originalBytes);
|
||||
byte[] convertedBytes = Encoding.UTF8.GetBytes(utf8Filename);
|
||||
bool equal = true;
|
||||
if(originalBytes.Length == convertedBytes.Length) {
|
||||
for(int j = 0; j < convertedBytes.Length; j++) {
|
||||
if(convertedBytes[j] != originalBytes[j]) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
equal = false;
|
||||
}
|
||||
|
||||
if(!equal) {
|
||||
//String doesn't appear to be an utf8 string, use the system's default encoding
|
||||
entries.Add(new ArchiveRomEntry() { Filename = Encoding.Default.GetString(originalBytes), IsUtf8 = false });
|
||||
} else {
|
||||
entries.Add(new ArchiveRomEntry() { Filename = utf8Filename, IsUtf8 = true });
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static byte[] _codeByteArray = new byte[0];
|
||||
private static string PtrToStringUtf8(IntPtr ptr, UInt32 length = 0)
|
||||
{
|
||||
|
@ -705,6 +763,23 @@ namespace Mesen.GUI
|
|||
}
|
||||
}
|
||||
|
||||
private static byte[] PtrToByteArray(IntPtr ptr)
|
||||
{
|
||||
if(ptr == IntPtr.Zero) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
while(System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0) {
|
||||
len++;
|
||||
}
|
||||
|
||||
byte[] array = new byte[len];
|
||||
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public enum ConsoleNotificationType
|
||||
{
|
||||
GameLoaded = 0,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../Core/IRenderingDevice.h"
|
||||
#include "../Core/IAudioDevice.h"
|
||||
#include "../Core/MovieManager.h"
|
||||
#include "../Core/VirtualFile.h"
|
||||
#include "../Core/HdPackBuilder.h"
|
||||
#include "../Utilities/AviWriter.h"
|
||||
#include "../Core/ShortcutKeyHandler.h"
|
||||
|
@ -128,7 +129,7 @@ namespace InteropEmu {
|
|||
std::ostringstream out;
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filename);
|
||||
if(reader) {
|
||||
for(string romName : reader->GetFileList({ ".nes", ".fds", ".nsf", ".nsfe", "*.unf" })) {
|
||||
for(string romName : reader->GetFileList(VirtualFile::RomExtensions)) {
|
||||
out << romName << "[!|!]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -360,7 +360,6 @@
|
|||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="UpsPatcher.h" />
|
||||
<ClInclude Include="UTF8Util.h" />
|
||||
<ClInclude Include="VirtualFile.h" />
|
||||
<ClInclude Include="xBRZ\config.h" />
|
||||
<ClInclude Include="xBRZ\xbrz.h" />
|
||||
<ClInclude Include="ZipReader.h" />
|
||||
|
|
|
@ -158,9 +158,6 @@
|
|||
<ClInclude Include="ArchiveReader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stb_vorbis.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include "sha1.h"
|
||||
#include "ArchiveReader.h"
|
||||
#include "StringUtilities.h"
|
||||
#include "FolderUtilities.h"
|
||||
#include "BpsPatcher.h"
|
||||
#include "IpsPatcher.h"
|
||||
#include "UpsPatcher.h"
|
||||
|
||||
class VirtualFile
|
||||
{
|
||||
private:
|
||||
string _path = "";
|
||||
string _innerFile = "";
|
||||
vector<uint8_t> _data;
|
||||
|
||||
void FromStream(std::istream &input, vector<uint8_t> &output)
|
||||
{
|
||||
input.seekg(0, std::ios::end);
|
||||
uint32_t fileSize = (uint32_t)input.tellg();
|
||||
input.seekg(0, std::ios::beg);
|
||||
|
||||
output.resize(fileSize, 0);
|
||||
input.read((char*)output.data(), fileSize);
|
||||
}
|
||||
|
||||
void LoadFile()
|
||||
{
|
||||
if(_data.size() == 0) {
|
||||
if(!_innerFile.empty()) {
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(_path);
|
||||
if(reader) {
|
||||
reader->ExtractFile(_innerFile, _data);
|
||||
}
|
||||
} else {
|
||||
ifstream input(_path, std::ios::in | std::ios::binary);
|
||||
if(input.good()) {
|
||||
FromStream(input, _data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
VirtualFile()
|
||||
{
|
||||
}
|
||||
|
||||
VirtualFile(const string &archivePath, const string innerFile)
|
||||
{
|
||||
_path = archivePath;
|
||||
_innerFile = innerFile;
|
||||
}
|
||||
|
||||
VirtualFile(const string &file)
|
||||
{
|
||||
vector<string> tokens = StringUtilities::Split(file, '\x1');
|
||||
_path = tokens[0];
|
||||
if(tokens.size() > 1) {
|
||||
_innerFile = tokens[1];
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFile(std::istream &input, string filePath)
|
||||
{
|
||||
_path = filePath;
|
||||
FromStream(input, _data);
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
if(_innerFile.empty()) {
|
||||
return _path;
|
||||
} else if(_path.empty()) {
|
||||
throw std::runtime_error("Cannot convert to string");
|
||||
} else {
|
||||
return _path + "\x1" + _innerFile;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValid()
|
||||
{
|
||||
LoadFile();
|
||||
return _data.size() > 0;
|
||||
}
|
||||
|
||||
string GetFilePath()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
string GetFolderPath()
|
||||
{
|
||||
return FolderUtilities::GetFolderName(_path);
|
||||
}
|
||||
|
||||
string GetFileName()
|
||||
{
|
||||
return _innerFile.empty() ? FolderUtilities::GetFilename(_path, true) : _innerFile;
|
||||
}
|
||||
|
||||
string GetSha1Hash()
|
||||
{
|
||||
string hash = SHA1::GetHash(_data);
|
||||
std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool ReadFile(vector<uint8_t> &out)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() > 0) {
|
||||
out.resize(_data.size(), 0);
|
||||
std::copy(_data.begin(), _data.end(), out.begin());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadFile(std::stringstream &out)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() > 0) {
|
||||
out.write((char*)_data.data(), _data.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ApplyPatch(VirtualFile &patch)
|
||||
{
|
||||
//Apply patch file
|
||||
bool result = false;
|
||||
if(patch.IsValid() && patch._data.size() >= 5 ) {
|
||||
vector<uint8_t> patchedData;
|
||||
std::stringstream ss;
|
||||
patch.ReadFile(ss);
|
||||
|
||||
if(memcmp(patch._data.data(), "PATCH", 5) == 0) {
|
||||
result = IpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
} else if(memcmp(patch._data.data(), "UPS1", 4) == 0) {
|
||||
result = UpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
} else if(memcmp(patch._data.data(), "BPS1", 4) == 0) {
|
||||
result = BpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
}
|
||||
if(result) {
|
||||
_data = patchedData;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue