mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
724 lines
18 KiB
C++
724 lines
18 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Nestopia - NES/Famicom emulator written in C++
|
|
//
|
|
// Copyright (C) 2003-2008 Martin Freij
|
|
//
|
|
// This file is part of Nestopia.
|
|
//
|
|
// Nestopia is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Nestopia is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Nestopia; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "NstIoFile.hpp"
|
|
#include "NstIoArchive.hpp"
|
|
#include "NstIoScreen.hpp"
|
|
#include "NstWindowUser.hpp"
|
|
#include "NstResourceString.hpp"
|
|
#include "NstDialogBrowse.hpp"
|
|
#include "NstDialogPaths.hpp"
|
|
#include "NstManagerPaths.hpp"
|
|
#include "NstManagerPathsFilter.hpp"
|
|
|
|
namespace Nestopia
|
|
{
|
|
namespace Managers
|
|
{
|
|
Paths::File::File()
|
|
: type(NONE)
|
|
{
|
|
}
|
|
|
|
Paths::File::~File()
|
|
{
|
|
}
|
|
|
|
Paths::Paths(Emulator& e,const Configuration& cfg,Window::Menu& m)
|
|
:
|
|
Manager ( e, m, this, &Paths::OnEmuEvent, IDM_OPTIONS_PATHS, &Paths::OnMenu ),
|
|
dialog ( new Window::Paths(cfg) )
|
|
{
|
|
recentImageDir = cfg["paths"]["images"]["recent-directory"].Str();
|
|
|
|
UpdateSettings();
|
|
}
|
|
|
|
Paths::~Paths()
|
|
{
|
|
}
|
|
|
|
void Paths::Save(Configuration& cfg) const
|
|
{
|
|
dialog->Save( cfg );
|
|
|
|
if (recentImageDir.DirectoryExists())
|
|
cfg["paths"]["images"]["recent-directory"].Str() = recentImageDir;
|
|
}
|
|
|
|
void Paths::UpdateSettings()
|
|
{
|
|
emulator.WriteProtectCartridge
|
|
(
|
|
dialog->GetSetting(Window::Paths::READONLY_CARTRIDGE)
|
|
);
|
|
}
|
|
|
|
void Paths::OnMenu(uint)
|
|
{
|
|
dialog->Open();
|
|
UpdateSettings();
|
|
}
|
|
|
|
void Paths::OnEmuEvent(const Emulator::Event event,const Emulator::Data data)
|
|
{
|
|
switch (event)
|
|
{
|
|
case Emulator::EVENT_NETPLAY_MODE:
|
|
|
|
menu[IDM_OPTIONS_PATHS].Enable( !data );
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Paths::SaveSlotExportingEnabled() const
|
|
{
|
|
return dialog->GetSetting(Window::Paths::AUTO_EXPORT_STATE_SLOTS);
|
|
}
|
|
|
|
bool Paths::SaveSlotImportingEnabled() const
|
|
{
|
|
return dialog->GetSetting(Window::Paths::AUTO_IMPORT_STATE_SLOTS);
|
|
}
|
|
|
|
bool Paths::AutoLoadCheatsEnabled() const
|
|
{
|
|
return dialog->GetSetting(Window::Paths::CHEATS_AUTO_LOAD);
|
|
}
|
|
|
|
bool Paths::AutoSaveCheatsEnabled() const
|
|
{
|
|
return dialog->GetSetting(Window::Paths::CHEATS_AUTO_SAVE);
|
|
}
|
|
|
|
bool Paths::UseStateCompression() const
|
|
{
|
|
return dialog->GetSetting(Window::Paths::COMPRESS_STATES);
|
|
}
|
|
|
|
bool Paths::BypassPatchValidation() const
|
|
{
|
|
return dialog->GetSetting(Window::Paths::PATCH_BYPASS_VALIDATION);
|
|
}
|
|
|
|
bool Paths::LocateFile(Path& path,const File::Types types) const
|
|
{
|
|
NST_ASSERT( path.File().Length() );
|
|
|
|
static const struct { uint type; wchar_t extension[4]; } lut[19] =
|
|
{
|
|
{ File::INES, L"nes" },
|
|
{ File::UNIF, L"unf" },
|
|
{ File::FDS, L"fds" },
|
|
{ File::NSF, L"nsf" },
|
|
{ File::BATTERY, L"sav" },
|
|
{ File::TAPE, L"tp" },
|
|
{ File::STATE|File::SLOTS, L"nst" },
|
|
{ File::IPS, L"ips" },
|
|
{ File::UPS, L"ups" },
|
|
{ File::MOVIE, L"nsv" },
|
|
{ File::ROM, L"rom" },
|
|
{ File::XML, L"xml" },
|
|
{ File::PALETTE, L"pal" },
|
|
{ File::WAVE, L"wav" },
|
|
{ File::AVI, L"avi" },
|
|
{ File::ARCHIVE, L"zip" },
|
|
{ File::ARCHIVE, L"rar" },
|
|
{ File::ARCHIVE, L"7z" }
|
|
};
|
|
|
|
for (uint i=0; i < 18; ++i)
|
|
{
|
|
if (types( lut[i].type ))
|
|
{
|
|
path.Directory() = GetDefaultDirectory( lut[i].type );
|
|
path.Extension() = lut[i].extension;
|
|
|
|
if (path.FileExists())
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Paths::FindFile(Path& path) const
|
|
{
|
|
NST_ASSERT( path.File().Length() );
|
|
|
|
path.Directory() = Application::Instance::GetExePath().Directory();
|
|
|
|
if (path.FileExists())
|
|
return true;
|
|
|
|
for (uint i=0; i < Window::Paths::NUM_DIRS; ++i)
|
|
{
|
|
path.Directory() = dialog->GetDirectory( static_cast<Window::Paths::Type>(i) );
|
|
|
|
if (path.FileExists())
|
|
return true;
|
|
}
|
|
|
|
path.Directory() = recentImageDir;
|
|
|
|
if (path.FileExists())
|
|
return true;
|
|
|
|
path.Directory().Clear();
|
|
|
|
return false;
|
|
}
|
|
|
|
void Paths::UpdateRecentImageDirectory(const Path& path,const File::Types types) const
|
|
{
|
|
NST_ASSERT( path.Length() );
|
|
|
|
if (types( File::IMAGE ))
|
|
recentImageDir = path.Directory();
|
|
}
|
|
|
|
Path Paths::GetScreenShotPath() const
|
|
{
|
|
Path path;
|
|
|
|
path.Directory() = dialog->GetDirectory( Window::Paths::DIR_SCREENSHOT );
|
|
path.File() = emulator.GetImagePath().Target().File();
|
|
path.Extension().Clear();
|
|
|
|
const uint offset = path.Length() + 1;
|
|
path << L"_xxx." << dialog->GetScreenShotExtension();
|
|
|
|
for (uint i=1; i < 1000; ++i)
|
|
{
|
|
path[offset+0] = '0' + (i / 100);
|
|
path[offset+1] = '0' + (i % 100 / 10);
|
|
path[offset+2] = '0' + (i % 10);
|
|
|
|
if (!path.FileExists())
|
|
break;
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
wcstring Paths::GetDefaultExtension(const File::Types types)
|
|
{
|
|
return
|
|
(
|
|
types( File::INES ) ? L"nes" :
|
|
types( File::UNIF ) ? L"unf" :
|
|
types( File::FDS ) ? L"fds" :
|
|
types( File::NSF ) ? L"nsf" :
|
|
types( File::XML ) ? L"xml" :
|
|
types( File::BATTERY ) ? L"sav" :
|
|
types( File::TAPE ) ? L"tp" :
|
|
types( File::STATE|File::SLOTS ) ? L"nst" :
|
|
types( File::IPS ) ? L"ips" :
|
|
types( File::UPS ) ? L"ups" :
|
|
types( File::MOVIE ) ? L"nsv" :
|
|
types( File::ROM ) ? L"rom" :
|
|
types( File::ROM ) ? L"xml" :
|
|
types( File::PALETTE ) ? L"pal" :
|
|
types( File::WAVE ) ? L"wav" :
|
|
types( File::AVI ) ? L"avi" :
|
|
types( File::ARCHIVE ) ? L"zip" :
|
|
L""
|
|
);
|
|
}
|
|
|
|
const Path Paths::GetDefaultDirectory(const File::Types types) const
|
|
{
|
|
Window::Paths::Type type;
|
|
|
|
if (types( File::IMAGE|File::ROM ))
|
|
{
|
|
if (dialog->GetSetting(Window::Paths::USE_LAST_IMAGE_DIR) && recentImageDir.DirectoryExists())
|
|
return recentImageDir;
|
|
|
|
type = Window::Paths::DIR_IMAGE;
|
|
}
|
|
else if (types( File::STATE|File::SLOTS|File::MOVIE ))
|
|
{
|
|
type = Window::Paths::DIR_STATE;
|
|
}
|
|
else if (types( File::BATTERY|File::TAPE ))
|
|
{
|
|
type = Window::Paths::DIR_SAVE;
|
|
}
|
|
else if (types( File::PATCH ))
|
|
{
|
|
type = Window::Paths::DIR_PATCHES;
|
|
}
|
|
else
|
|
{
|
|
return Application::Instance::GetExePath().Directory();
|
|
}
|
|
|
|
return dialog->GetDirectory( type );
|
|
}
|
|
|
|
bool Paths::CheckFile(Path& path,const File::Types types,const Alert alert,const uint title) const
|
|
{
|
|
NST_ASSERT( types.Word() );
|
|
|
|
try
|
|
{
|
|
if (LoadFromFile( path, NULL, types ))
|
|
return true;
|
|
}
|
|
catch (int ids)
|
|
{
|
|
if (alert == NOISY)
|
|
{
|
|
Window::User::Fail( ids, title );
|
|
}
|
|
else if (alert == STICKY)
|
|
{
|
|
Io::Screen() << Resource::String(title) << ' ' << Resource::String(ids);
|
|
}
|
|
}
|
|
|
|
path.Clear();
|
|
return false;
|
|
}
|
|
|
|
Path Paths::BrowseLoad(const File::Types types,const GenericString dir,const Checking checking) const
|
|
{
|
|
NST_ASSERT( types.Word() );
|
|
|
|
Path path
|
|
(
|
|
Window::Browser::OpenFile
|
|
(
|
|
Filter( types ).Ptr(),
|
|
dir.Length() ? Path(dir) : GetDefaultDirectory( types ),
|
|
GetDefaultExtension( types )
|
|
)
|
|
);
|
|
|
|
if (path.Length())
|
|
{
|
|
UpdateRecentImageDirectory( path, types );
|
|
|
|
if (checking == CHECK_FILE)
|
|
CheckFile( path, types, NOISY );
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
Path Paths::BrowseSave(const File::Types types,const Method method,const GenericString initPath) const
|
|
{
|
|
NST_ASSERT( types.Word() );
|
|
|
|
Path path( initPath );
|
|
|
|
if (path.Directory().Empty())
|
|
path.Directory() = GetDefaultDirectory( types );
|
|
|
|
if (method == SUGGEST && path.File().Empty())
|
|
path.File() = emulator.GetImagePath().Target().File();
|
|
|
|
path.Extension() = GetDefaultExtension( types );
|
|
path = Window::Browser::SaveFile( Filter(types).Ptr(), path );
|
|
|
|
if (path.Length())
|
|
UpdateRecentImageDirectory( path, types );
|
|
|
|
return path;
|
|
}
|
|
|
|
void Paths::FixFile(const File::Type type,Path& path) const
|
|
{
|
|
if (path.File().Length())
|
|
{
|
|
if (path.Directory().Empty())
|
|
path.Directory() = GetDefaultDirectory( type );
|
|
|
|
if (path.Extension().Empty())
|
|
path.Extension() = GetDefaultExtension( type );
|
|
}
|
|
else
|
|
{
|
|
path.Clear();
|
|
}
|
|
}
|
|
|
|
Path Paths::GetSavePath(const Path& image,const File::Type type) const
|
|
{
|
|
NST_ASSERT( image.Length() );
|
|
|
|
Path save;
|
|
|
|
if (type & File::GAME)
|
|
{
|
|
save.Set
|
|
(
|
|
dialog->GetDirectory( (type & File::CARTRIDGE) ? Window::Paths::DIR_SAVE : Window::Paths::DIR_PATCHES ),
|
|
image.Target().File(),
|
|
(type & File::CARTRIDGE) ? L"sav" : L"ups"
|
|
);
|
|
}
|
|
|
|
return save;
|
|
}
|
|
|
|
Path Paths::GetCheatPath() const
|
|
{
|
|
return dialog->GetDirectory( Window::Paths::DIR_CHEATS );
|
|
}
|
|
|
|
Path Paths::GetCheatPath(const Path& image) const
|
|
{
|
|
return Path( dialog->GetDirectory( Window::Paths::DIR_CHEATS ), image.Target().File(), L"xml" );
|
|
}
|
|
|
|
Path Paths::GetPatchPath(const Path& image,const File::Type type) const
|
|
{
|
|
Path patch;
|
|
|
|
if ((type & File::CARTRIDGE) && dialog->GetSetting( Window::Paths::PATCH_AUTO_APPLY ))
|
|
{
|
|
patch.Set( dialog->GetDirectory( Window::Paths::DIR_PATCHES ), image.Target().File(), L"ups" );
|
|
|
|
if (!patch.FileExists())
|
|
patch.Extension() = L"ips";
|
|
}
|
|
|
|
return patch;
|
|
}
|
|
|
|
Path Paths::GetSamplesPath() const
|
|
{
|
|
return dialog->GetDirectory( Window::Paths::DIR_SAMPLES );
|
|
}
|
|
|
|
Paths::File::Type Paths::Load
|
|
(
|
|
File& file,
|
|
const File::Types types,
|
|
const GenericString path,
|
|
const Alert alert
|
|
) const
|
|
{
|
|
if (path.Length())
|
|
{
|
|
file.name = path;
|
|
|
|
if (file.name.Directory().Empty())
|
|
file.name.Directory() = GetDefaultDirectory( types );
|
|
}
|
|
else
|
|
{
|
|
file.name = BrowseLoad( types );
|
|
}
|
|
|
|
if (file.name.Empty() || (alert == QUIETLY && !file.name.FileExists()))
|
|
return File::NONE;
|
|
|
|
try
|
|
{
|
|
Application::Instance::Waiter wait;
|
|
file.type = LoadFromFile( file.name, &file.data, types );
|
|
}
|
|
catch (int ids)
|
|
{
|
|
if (alert == NOISY)
|
|
{
|
|
Window::User::Fail( ids, IDS_TITLE_ERROR );
|
|
}
|
|
else if (alert == STICKY)
|
|
{
|
|
Io::Screen() << Resource::String(IDS_TITLE_ERROR) << ' ' << Resource::String(ids);
|
|
}
|
|
|
|
file.type = File::NONE;
|
|
}
|
|
|
|
if (file.type == File::NONE)
|
|
{
|
|
file.name.Clear();
|
|
file.data.Clear();
|
|
}
|
|
|
|
return file.type;
|
|
}
|
|
|
|
bool Paths::Save
|
|
(
|
|
const void* const data,
|
|
const uint size,
|
|
const File::Type type,
|
|
Path path,
|
|
const Alert alert
|
|
) const
|
|
{
|
|
if (path.Directory().Empty())
|
|
path.Directory() = GetDefaultDirectory( type );
|
|
|
|
try
|
|
{
|
|
Io::File( path, Io::File::DUMP|Io::File::WRITE_THROUGH ).Write( data, size );
|
|
}
|
|
catch (Io::File::Exception ids)
|
|
{
|
|
if (alert == NOISY)
|
|
{
|
|
Window::User::Fail( ids, IDS_TITLE_ERROR );
|
|
}
|
|
else if (alert == STICKY)
|
|
{
|
|
Io::Screen() << Resource::String(IDS_TITLE_ERROR) << ' ' << Resource::String(ids);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Paths::File::Type Paths::LoadFromFile(Path& path,File::Data* const data,const File::Types types)
|
|
{
|
|
NST_ASSERT( path.Length() );
|
|
|
|
const GenericString fileInArchive( path.FileInArchive() );
|
|
GenericString filePath( path );
|
|
|
|
if (fileInArchive.Length())
|
|
filePath = path.Archive();
|
|
|
|
try
|
|
{
|
|
Io::File file( filePath, Io::File::READ|Io::File::EXISTING );
|
|
|
|
const File::Type type = CheckFile( types, file.Peek32(), path.Extension().Id() );
|
|
|
|
if (type == File::NONE)
|
|
throw IDS_FILE_ERR_INVALID;
|
|
|
|
if (type == File::ARCHIVE)
|
|
return LoadFromArchive( Io::Archive(file), path, data, fileInArchive, types );
|
|
|
|
if (fileInArchive.Length())
|
|
throw IDS_FILE_ERR_INVALID;
|
|
|
|
if (data)
|
|
file.Stream() >> *data;
|
|
|
|
return type;
|
|
}
|
|
catch (Io::File::Exception id)
|
|
{
|
|
throw int(id);
|
|
}
|
|
}
|
|
|
|
Paths::File::Type Paths::LoadFromArchive
|
|
(
|
|
const Io::Archive& archive,
|
|
Path& path,
|
|
File::Data* const data,
|
|
const GenericString& fileInArchive,
|
|
const File::Types types
|
|
)
|
|
{
|
|
uint index;
|
|
|
|
if (fileInArchive.Length())
|
|
{
|
|
index = archive.Find( fileInArchive );
|
|
}
|
|
else
|
|
{
|
|
uint count = 0;
|
|
GenericString filter[32];
|
|
|
|
if (types( File::INES )) filter[count++] = L"nes";
|
|
if (types( File::FDS )) filter[count++] = L"fds";
|
|
if (types( File::NSF )) filter[count++] = L"nsf";
|
|
if (types( File::BATTERY )) filter[count++] = L"sav";
|
|
if (types( File::TAPE )) filter[count++] = L"tp";
|
|
if (types( File::STATE )) filter[count++] = L"nst";
|
|
if (types( File::MOVIE )) filter[count++] = L"nsv";
|
|
if (types( File::IPS )) filter[count++] = L"ips";
|
|
if (types( File::UPS )) filter[count++] = L"ups";
|
|
if (types( File::ROM )) filter[count++] = L"rom";
|
|
if (types( File::XML )) filter[count++] = L"xml";
|
|
if (types( File::PALETTE )) filter[count++] = L"pal";
|
|
if (types( File::WAVE )) filter[count++] = L"wav";
|
|
if (types( File::AVI )) filter[count++] = L"avi";
|
|
|
|
if (types( File::UNIF ))
|
|
{
|
|
filter[count++] = L"unf";
|
|
filter[count++] = L"unif";
|
|
}
|
|
|
|
if (types( File::SLOTS ))
|
|
{
|
|
filter[count++] = L"ns1";
|
|
filter[count++] = L"ns2";
|
|
filter[count++] = L"ns3";
|
|
filter[count++] = L"ns4";
|
|
filter[count++] = L"ns5";
|
|
filter[count++] = L"ns6";
|
|
filter[count++] = L"ns7";
|
|
filter[count++] = L"ns8";
|
|
filter[count++] = L"ns9";
|
|
}
|
|
|
|
// If more than one file in the archive let the user choose which to load,
|
|
// non-valid files will be filtered out by named extension detection
|
|
|
|
index = archive.UserSelect( filter, count );
|
|
}
|
|
|
|
if (!index)
|
|
{
|
|
return File::NONE;
|
|
}
|
|
else if (index == Io::Archive::NO_FILES)
|
|
{
|
|
throw IDS_FILE_ERR_NOTHING_IN_ARCHIVE;
|
|
}
|
|
|
|
--index;
|
|
|
|
File::Type type = File::ARCHIVE;
|
|
|
|
if (data)
|
|
{
|
|
data->Resize( archive[index].Size() );
|
|
|
|
if (data->Size() < 4 || !archive[index].Uncompress( data->Ptr() ))
|
|
throw IDS_FILE_ERR_INVALID;
|
|
|
|
type = CheckFile
|
|
(
|
|
types,
|
|
FourCC<>::T( data->Ptr() ),
|
|
archive[index].GetName().Extension().Id()
|
|
);
|
|
|
|
if (type == File::NONE || type == File::ARCHIVE)
|
|
throw IDS_FILE_ERR_INVALID;
|
|
}
|
|
|
|
if (fileInArchive.Empty())
|
|
path << " <" << archive[index].GetName() << '>';
|
|
|
|
return type;
|
|
}
|
|
|
|
Paths::File::Type Paths::CheckFile(const File::Types types,const uint fileId,const uint extensionId)
|
|
{
|
|
File::Type type = File::NONE;
|
|
|
|
switch (fileId)
|
|
{
|
|
case File::ID_INES: if (types( File::INES )) type = File::INES; break;
|
|
case File::ID_UNIF: if (types( File::UNIF )) type = File::UNIF; break;
|
|
case File::ID_FDS:
|
|
case File::ID_FDS_RAW: if (types( File::FDS )) type = File::FDS; break;
|
|
case File::ID_NSF: if (types( File::NSF )) type = File::NSF; break;
|
|
case File::ID_IPS: if (types( File::IPS )) type = File::IPS; break;
|
|
case File::ID_UPS: if (types( File::UPS )) type = File::UPS; break;
|
|
case File::ID_NSV: if (types( File::MOVIE )) type = File::MOVIE; break;
|
|
case File::ID_NST: if (types( File::STATE|File::SLOTS )) type = File::STATE; break;
|
|
case File::ID_ZIP:
|
|
case File::ID_7Z:
|
|
case File::ID_RAR: if (types( File::ARCHIVE )) type = File::ARCHIVE; break;
|
|
|
|
default:
|
|
|
|
switch (extensionId)
|
|
{
|
|
// raw or text file, must check the file extension
|
|
|
|
case FourCC<'s','a','v'>::V: if (types( File::BATTERY )) type = File::BATTERY; break;
|
|
case FourCC<'t','p'>::V: if (types( File::TAPE )) type = File::TAPE; break;
|
|
case FourCC<'r','o','m'>::V: if (types( File::ROM )) type = File::ROM; break;
|
|
case FourCC<'x','m','l'>::V: if (types( File::XML )) type = File::XML; break;
|
|
case FourCC<'p','a','l'>::V: if (types( File::PALETTE )) type = File::PALETTE; break;
|
|
case FourCC<'w','a','v'>::V: if (types( File::WAVE )) type = File::WAVE; break;
|
|
case FourCC<'a','v','i'>::V: if (types( File::AVI )) type = File::AVI; break;
|
|
|
|
case FourCC<'n','e','s'>::V:
|
|
case FourCC<'u','n','f'>::V:
|
|
case FourCC<'u','n','i'>::V:
|
|
case FourCC<'f','d','s'>::V:
|
|
case FourCC<'n','s','f'>::V:
|
|
case FourCC<'i','p','s'>::V:
|
|
case FourCC<'u','p','s'>::V:
|
|
case FourCC<'n','s','v'>::V:
|
|
case FourCC<'n','s','t'>::V:
|
|
case FourCC<'n','s','0'>::V:
|
|
case FourCC<'n','s','1'>::V:
|
|
case FourCC<'n','s','2'>::V:
|
|
case FourCC<'n','s','3'>::V:
|
|
case FourCC<'n','s','4'>::V:
|
|
case FourCC<'n','s','5'>::V:
|
|
case FourCC<'n','s','6'>::V:
|
|
case FourCC<'n','s','7'>::V:
|
|
case FourCC<'n','s','8'>::V:
|
|
case FourCC<'n','s','9'>::V:
|
|
case FourCC<'z','i','p'>::V:
|
|
case FourCC<'r','a','r'>::V:
|
|
case FourCC<'7','z'>::V:
|
|
|
|
// either corrupt data or wrong extension, bail..
|
|
|
|
break;
|
|
|
|
case FourCC<'b','i','n'>::V:
|
|
// If it's a .bin, just assume it's a VC ROM and fail elsewhere if not
|
|
type = File::ROM;
|
|
break;
|
|
|
|
default:
|
|
|
|
// extension is unknown, but the file may still be valid,
|
|
// allow it to pass if only one file type was selected
|
|
|
|
if (types(~uint(File::ARCHIVE|File::IMAGE)) == File::ROM)
|
|
{
|
|
type = File::ROM;
|
|
}
|
|
else
|
|
{
|
|
switch (types(~uint(File::ARCHIVE)))
|
|
{
|
|
case File::XML: type = File::XML; break;
|
|
case File::BATTERY: type = File::BATTERY; break;
|
|
case File::TAPE: type = File::TAPE; break;
|
|
case File::PALETTE: type = File::PALETTE; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return type;
|
|
}
|
|
}
|
|
}
|