mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
set svn:eol-style=native for **.cpp
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1442 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -1,103 +1,103 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "BannerLoader.h"
|
||||
#include "BannerLoaderWii.h"
|
||||
#include "BannerLoaderGC.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
bool IBannerLoader::CopyToStringAndCheck(std::string& _rDestination, const char* _src)
|
||||
{
|
||||
static bool bValidChars[256];
|
||||
static bool bInitialized = false;
|
||||
|
||||
if (!bInitialized)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
bValidChars[i] = false;
|
||||
}
|
||||
|
||||
// generate valid chars
|
||||
for (unsigned char c = 0x20; c <= 0x80; c++)
|
||||
{
|
||||
bValidChars[c] = true;
|
||||
}
|
||||
|
||||
bValidChars[0x0a] = true;
|
||||
bValidChars[0xa9] = true;
|
||||
bValidChars[0xe9] = true;
|
||||
|
||||
bInitialized = true;
|
||||
}
|
||||
|
||||
bool bResult = true;
|
||||
char destBuffer[2048];
|
||||
char* dest = destBuffer;
|
||||
const char* src = _src;
|
||||
|
||||
// copy the string and check for "unknown" characters
|
||||
while (*src != 0x00)
|
||||
{
|
||||
u8 c = *src;
|
||||
|
||||
if (c == 0x0a){c = 0x20;}
|
||||
|
||||
if (bValidChars[c] == false)
|
||||
{
|
||||
bResult = false;
|
||||
break;
|
||||
}
|
||||
|
||||
*dest = c;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
|
||||
// finalize the string
|
||||
if (bResult)
|
||||
{
|
||||
*dest = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = ' ';
|
||||
dest[1] = 0x00;
|
||||
}
|
||||
|
||||
_rDestination = destBuffer;
|
||||
|
||||
return(bResult);
|
||||
}
|
||||
|
||||
|
||||
IBannerLoader* CreateBannerLoader(DiscIO::IFileSystem& _rFileSystem)
|
||||
{
|
||||
if (IsVolumeWiiDisc(_rFileSystem.GetVolume()))
|
||||
{
|
||||
return(new CBannerLoaderWii(_rFileSystem));
|
||||
}
|
||||
|
||||
return(new CBannerLoaderGC(_rFileSystem));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "BannerLoader.h"
|
||||
#include "BannerLoaderWii.h"
|
||||
#include "BannerLoaderGC.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
bool IBannerLoader::CopyToStringAndCheck(std::string& _rDestination, const char* _src)
|
||||
{
|
||||
static bool bValidChars[256];
|
||||
static bool bInitialized = false;
|
||||
|
||||
if (!bInitialized)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
bValidChars[i] = false;
|
||||
}
|
||||
|
||||
// generate valid chars
|
||||
for (unsigned char c = 0x20; c <= 0x80; c++)
|
||||
{
|
||||
bValidChars[c] = true;
|
||||
}
|
||||
|
||||
bValidChars[0x0a] = true;
|
||||
bValidChars[0xa9] = true;
|
||||
bValidChars[0xe9] = true;
|
||||
|
||||
bInitialized = true;
|
||||
}
|
||||
|
||||
bool bResult = true;
|
||||
char destBuffer[2048];
|
||||
char* dest = destBuffer;
|
||||
const char* src = _src;
|
||||
|
||||
// copy the string and check for "unknown" characters
|
||||
while (*src != 0x00)
|
||||
{
|
||||
u8 c = *src;
|
||||
|
||||
if (c == 0x0a){c = 0x20;}
|
||||
|
||||
if (bValidChars[c] == false)
|
||||
{
|
||||
bResult = false;
|
||||
break;
|
||||
}
|
||||
|
||||
*dest = c;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
|
||||
// finalize the string
|
||||
if (bResult)
|
||||
{
|
||||
*dest = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = ' ';
|
||||
dest[1] = 0x00;
|
||||
}
|
||||
|
||||
_rDestination = destBuffer;
|
||||
|
||||
return(bResult);
|
||||
}
|
||||
|
||||
|
||||
IBannerLoader* CreateBannerLoader(DiscIO::IFileSystem& _rFileSystem)
|
||||
{
|
||||
if (IsVolumeWiiDisc(_rFileSystem.GetVolume()))
|
||||
{
|
||||
return(new CBannerLoaderWii(_rFileSystem));
|
||||
}
|
||||
|
||||
return(new CBannerLoaderGC(_rFileSystem));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -1,193 +1,193 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "BannerLoaderGC.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CBannerLoaderGC::CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem)
|
||||
: m_pBannerFile(NULL),
|
||||
m_IsValid(false)
|
||||
{
|
||||
// build LUT Table
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
lut3to8[i] = (i * 255) / 7;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
lut4to8[i] = (i * 255) / 15;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
lut5to8[i] = (i * 255) / 31;
|
||||
}
|
||||
|
||||
// load the opening.bnr
|
||||
size_t FileSize = _rFileSystem.GetFileSize("opening.bnr");
|
||||
|
||||
if (FileSize > 0)
|
||||
{
|
||||
m_pBannerFile = new u8[FileSize];
|
||||
_rFileSystem.ReadFile("opening.bnr", m_pBannerFile, FileSize);
|
||||
m_IsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CBannerLoaderGC::~CBannerLoaderGC()
|
||||
{
|
||||
delete [] m_pBannerFile;
|
||||
m_pBannerFile = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::IsValid()
|
||||
{
|
||||
return(m_IsValid);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetBanner(u32* _pBannerImage)
|
||||
{
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
decode5A3image(_pBannerImage, pBanner->image, DVD_BANNER_WIDTH, DVD_BANNER_HEIGHT);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetName(std::string& _rName, int language)
|
||||
{
|
||||
_rName = "invalid image";
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
|
||||
if (!CopyToStringAndCheck(_rName, language != 0 ? pBanner->comment[0].shortTitle : pBanner->comment[0].longTitle))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetCompany(std::string& _rCompany)
|
||||
{
|
||||
_rCompany = "invalid images";
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
|
||||
if (!CopyToStringAndCheck(_rCompany, pBanner->comment[0].shortMaker))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetDescription(std::string& _rDescription)
|
||||
{
|
||||
_rDescription = "invalid images";
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
|
||||
if (!CopyToStringAndCheck(_rDescription, pBanner->comment[0].comment))
|
||||
{
|
||||
_rDescription = "";
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
u32
|
||||
CBannerLoaderGC::decode5A3(u16 val)
|
||||
{
|
||||
u32 bannerBGColor = 0x00000000;
|
||||
|
||||
int r, g, b, a;
|
||||
|
||||
if ((val & 0x8000))
|
||||
{
|
||||
r = lut5to8[(val >> 10) & 0x1f];
|
||||
g = lut5to8[(val >> 5) & 0x1f];
|
||||
b = lut5to8[(val) & 0x1f];
|
||||
a = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = lut3to8[(val >> 12) & 0x7];
|
||||
r = (lut4to8[(val >> 8) & 0xf] * a + (bannerBGColor & 0xFF) * (255 - a)) / 255;
|
||||
g = (lut4to8[(val >> 4) & 0xf] * a + ((bannerBGColor >> 8) & 0xFF) * (255 - a)) / 255;
|
||||
b = (lut4to8[(val) & 0xf] * a + ((bannerBGColor >> 16) & 0xFF) * (255 - a)) / 255;
|
||||
a = 0xFF;
|
||||
}
|
||||
|
||||
return((a << 24) | (r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBannerLoaderGC::decode5A3image(u32* dst, u16* src, int width, int height)
|
||||
{
|
||||
for (int y = 0; y < height; y += 4)
|
||||
{
|
||||
for (int x = 0; x < width; x += 4)
|
||||
{
|
||||
for (int iy = 0; iy < 4; iy++, src += 4)
|
||||
{
|
||||
for (int ix = 0; ix < 4; ix++)
|
||||
{
|
||||
u32 RGBA = decode5A3(Common::swap16(src[ix]));
|
||||
dst[(y + iy) * width + (x + ix)] = RGBA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "BannerLoaderGC.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CBannerLoaderGC::CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem)
|
||||
: m_pBannerFile(NULL),
|
||||
m_IsValid(false)
|
||||
{
|
||||
// build LUT Table
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
lut3to8[i] = (i * 255) / 7;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
lut4to8[i] = (i * 255) / 15;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
lut5to8[i] = (i * 255) / 31;
|
||||
}
|
||||
|
||||
// load the opening.bnr
|
||||
size_t FileSize = _rFileSystem.GetFileSize("opening.bnr");
|
||||
|
||||
if (FileSize > 0)
|
||||
{
|
||||
m_pBannerFile = new u8[FileSize];
|
||||
_rFileSystem.ReadFile("opening.bnr", m_pBannerFile, FileSize);
|
||||
m_IsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CBannerLoaderGC::~CBannerLoaderGC()
|
||||
{
|
||||
delete [] m_pBannerFile;
|
||||
m_pBannerFile = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::IsValid()
|
||||
{
|
||||
return(m_IsValid);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetBanner(u32* _pBannerImage)
|
||||
{
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
decode5A3image(_pBannerImage, pBanner->image, DVD_BANNER_WIDTH, DVD_BANNER_HEIGHT);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetName(std::string& _rName, int language)
|
||||
{
|
||||
_rName = "invalid image";
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
|
||||
if (!CopyToStringAndCheck(_rName, language != 0 ? pBanner->comment[0].shortTitle : pBanner->comment[0].longTitle))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetCompany(std::string& _rCompany)
|
||||
{
|
||||
_rCompany = "invalid images";
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
|
||||
if (!CopyToStringAndCheck(_rCompany, pBanner->comment[0].shortMaker))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderGC::GetDescription(std::string& _rDescription)
|
||||
{
|
||||
_rDescription = "invalid images";
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
DVDBanner2* pBanner = (DVDBanner2*)m_pBannerFile;
|
||||
|
||||
if (!CopyToStringAndCheck(_rDescription, pBanner->comment[0].comment))
|
||||
{
|
||||
_rDescription = "";
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
u32
|
||||
CBannerLoaderGC::decode5A3(u16 val)
|
||||
{
|
||||
u32 bannerBGColor = 0x00000000;
|
||||
|
||||
int r, g, b, a;
|
||||
|
||||
if ((val & 0x8000))
|
||||
{
|
||||
r = lut5to8[(val >> 10) & 0x1f];
|
||||
g = lut5to8[(val >> 5) & 0x1f];
|
||||
b = lut5to8[(val) & 0x1f];
|
||||
a = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = lut3to8[(val >> 12) & 0x7];
|
||||
r = (lut4to8[(val >> 8) & 0xf] * a + (bannerBGColor & 0xFF) * (255 - a)) / 255;
|
||||
g = (lut4to8[(val >> 4) & 0xf] * a + ((bannerBGColor >> 8) & 0xFF) * (255 - a)) / 255;
|
||||
b = (lut4to8[(val) & 0xf] * a + ((bannerBGColor >> 16) & 0xFF) * (255 - a)) / 255;
|
||||
a = 0xFF;
|
||||
}
|
||||
|
||||
return((a << 24) | (r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBannerLoaderGC::decode5A3image(u32* dst, u16* src, int width, int height)
|
||||
{
|
||||
for (int y = 0; y < height; y += 4)
|
||||
{
|
||||
for (int x = 0; x < width; x += 4)
|
||||
{
|
||||
for (int iy = 0; iy < 4; iy++, src += 4)
|
||||
{
|
||||
for (int ix = 0; ix < 4; ix++)
|
||||
{
|
||||
u32 RGBA = decode5A3(Common::swap16(src[ix]));
|
||||
dst[(y + iy) * width + (x + ix)] = RGBA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
@ -1,224 +1,224 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "BannerLoaderWii.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CBannerLoaderWii::CBannerLoaderWii(DiscIO::IFileSystem& _rFileSystem)
|
||||
: m_pBannerFile(NULL)
|
||||
, m_IsValid(false)
|
||||
{
|
||||
InitLUTTable();
|
||||
|
||||
char Filename[260];
|
||||
char TitleID[4];
|
||||
|
||||
_rFileSystem.GetVolume()->Read(0, 4, (u8*)TitleID);
|
||||
sprintf(Filename, FULL_WII_USER_DIR "title/00010000/%02x%02x%02x%02x/data/banner.bin", (u8)TitleID[0], (u8)TitleID[1], (u8)TitleID[2], (u8)TitleID[3]);
|
||||
|
||||
// load the opening.bnr
|
||||
size_t FileSize = File::GetSize(Filename);
|
||||
|
||||
if (FileSize > 0)
|
||||
{
|
||||
m_pBannerFile = new u8[FileSize];
|
||||
FILE* pFile = fopen(Filename, "rb");
|
||||
if (pFile != NULL)
|
||||
{
|
||||
fread(m_pBannerFile, FileSize, 1, pFile);
|
||||
fclose(pFile);
|
||||
m_IsValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBannerLoaderWii::~CBannerLoaderWii()
|
||||
{
|
||||
if (m_pBannerFile)
|
||||
{
|
||||
delete [] m_pBannerFile;
|
||||
m_pBannerFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::IsValid()
|
||||
{
|
||||
return (m_IsValid);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetBanner(u32* _pBannerImage)
|
||||
{
|
||||
if (!IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
static u32 Buffer[192 * 64];
|
||||
decode5A3image(Buffer, (u16*)pBanner->m_BannerTexture, 192, 64);
|
||||
|
||||
// ugly scaling :)
|
||||
for (int y=0; y<32; y++)
|
||||
{
|
||||
for (int x=0; x<96; x++)
|
||||
{
|
||||
_pBannerImage[y*96+x] = Buffer[(y*192*2)+(x*2)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
CBannerLoaderWii::StupidWideCharToString(u16* _pSrc, size_t _max)
|
||||
{
|
||||
std::string temp;
|
||||
|
||||
u32 offset = 0;
|
||||
while (_pSrc[offset] != 0x0000)
|
||||
{
|
||||
temp += (char)(_pSrc[offset] >> 8);
|
||||
offset ++;
|
||||
|
||||
if (offset >= _max)
|
||||
break;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetName(std::string& _rName, int language)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
// very stupid
|
||||
_rName = StupidWideCharToString(pBanner->m_Comment[0], WII_BANNER_COMMENT_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetCompany(std::string& _rCompany)
|
||||
{
|
||||
_rCompany = "N/A";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetDescription(std::string& _rDescription)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
// very stupid
|
||||
_rDescription = StupidWideCharToString(pBanner->m_Comment[1], WII_BANNER_COMMENT_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBannerLoaderWii::InitLUTTable()
|
||||
{
|
||||
// build LUT Table
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
lut3to8[i] = (i * 255) / 7;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
lut4to8[i] = (i * 255) / 15;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
lut5to8[i] = (i * 255) / 31;
|
||||
}
|
||||
}
|
||||
|
||||
u32
|
||||
CBannerLoaderWii::decode5A3(u16 val)
|
||||
{
|
||||
u32 bannerBGColor = 0x00000000;
|
||||
|
||||
int r, g, b, a;
|
||||
|
||||
if ((val & 0x8000))
|
||||
{
|
||||
r = lut5to8[(val >> 10) & 0x1f];
|
||||
g = lut5to8[(val >> 5) & 0x1f];
|
||||
b = lut5to8[(val) & 0x1f];
|
||||
a = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = lut3to8[(val >> 12) & 0x7];
|
||||
r = (lut4to8[(val >> 8) & 0xf] * a + (bannerBGColor & 0xFF) * (255 - a)) / 255;
|
||||
g = (lut4to8[(val >> 4) & 0xf] * a + ((bannerBGColor >> 8) & 0xFF) * (255 - a)) / 255;
|
||||
b = (lut4to8[(val) & 0xf] * a + ((bannerBGColor >> 16) & 0xFF) * (255 - a)) / 255;
|
||||
a = 0xFF;
|
||||
}
|
||||
|
||||
return ((a << 24) | (r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBannerLoaderWii::decode5A3image(u32* dst, u16* src, int width, int height)
|
||||
{
|
||||
for (int y = 0; y < height; y += 4)
|
||||
{
|
||||
for (int x = 0; x < width; x += 4)
|
||||
{
|
||||
for (int iy = 0; iy < 4; iy++, src += 4)
|
||||
{
|
||||
for (int ix = 0; ix < 4; ix++)
|
||||
{
|
||||
u32 RGBA = decode5A3(Common::swap16(src[ix]));
|
||||
dst[(y + iy) * width + (x + ix)] = RGBA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "BannerLoaderWii.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CBannerLoaderWii::CBannerLoaderWii(DiscIO::IFileSystem& _rFileSystem)
|
||||
: m_pBannerFile(NULL)
|
||||
, m_IsValid(false)
|
||||
{
|
||||
InitLUTTable();
|
||||
|
||||
char Filename[260];
|
||||
char TitleID[4];
|
||||
|
||||
_rFileSystem.GetVolume()->Read(0, 4, (u8*)TitleID);
|
||||
sprintf(Filename, FULL_WII_USER_DIR "title/00010000/%02x%02x%02x%02x/data/banner.bin", (u8)TitleID[0], (u8)TitleID[1], (u8)TitleID[2], (u8)TitleID[3]);
|
||||
|
||||
// load the opening.bnr
|
||||
size_t FileSize = File::GetSize(Filename);
|
||||
|
||||
if (FileSize > 0)
|
||||
{
|
||||
m_pBannerFile = new u8[FileSize];
|
||||
FILE* pFile = fopen(Filename, "rb");
|
||||
if (pFile != NULL)
|
||||
{
|
||||
fread(m_pBannerFile, FileSize, 1, pFile);
|
||||
fclose(pFile);
|
||||
m_IsValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBannerLoaderWii::~CBannerLoaderWii()
|
||||
{
|
||||
if (m_pBannerFile)
|
||||
{
|
||||
delete [] m_pBannerFile;
|
||||
m_pBannerFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::IsValid()
|
||||
{
|
||||
return (m_IsValid);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetBanner(u32* _pBannerImage)
|
||||
{
|
||||
if (!IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
static u32 Buffer[192 * 64];
|
||||
decode5A3image(Buffer, (u16*)pBanner->m_BannerTexture, 192, 64);
|
||||
|
||||
// ugly scaling :)
|
||||
for (int y=0; y<32; y++)
|
||||
{
|
||||
for (int x=0; x<96; x++)
|
||||
{
|
||||
_pBannerImage[y*96+x] = Buffer[(y*192*2)+(x*2)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
CBannerLoaderWii::StupidWideCharToString(u16* _pSrc, size_t _max)
|
||||
{
|
||||
std::string temp;
|
||||
|
||||
u32 offset = 0;
|
||||
while (_pSrc[offset] != 0x0000)
|
||||
{
|
||||
temp += (char)(_pSrc[offset] >> 8);
|
||||
offset ++;
|
||||
|
||||
if (offset >= _max)
|
||||
break;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetName(std::string& _rName, int language)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
// very stupid
|
||||
_rName = StupidWideCharToString(pBanner->m_Comment[0], WII_BANNER_COMMENT_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetCompany(std::string& _rCompany)
|
||||
{
|
||||
_rCompany = "N/A";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CBannerLoaderWii::GetDescription(std::string& _rDescription)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
// very stupid
|
||||
_rDescription = StupidWideCharToString(pBanner->m_Comment[1], WII_BANNER_COMMENT_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBannerLoaderWii::InitLUTTable()
|
||||
{
|
||||
// build LUT Table
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
lut3to8[i] = (i * 255) / 7;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
lut4to8[i] = (i * 255) / 15;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
lut5to8[i] = (i * 255) / 31;
|
||||
}
|
||||
}
|
||||
|
||||
u32
|
||||
CBannerLoaderWii::decode5A3(u16 val)
|
||||
{
|
||||
u32 bannerBGColor = 0x00000000;
|
||||
|
||||
int r, g, b, a;
|
||||
|
||||
if ((val & 0x8000))
|
||||
{
|
||||
r = lut5to8[(val >> 10) & 0x1f];
|
||||
g = lut5to8[(val >> 5) & 0x1f];
|
||||
b = lut5to8[(val) & 0x1f];
|
||||
a = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = lut3to8[(val >> 12) & 0x7];
|
||||
r = (lut4to8[(val >> 8) & 0xf] * a + (bannerBGColor & 0xFF) * (255 - a)) / 255;
|
||||
g = (lut4to8[(val >> 4) & 0xf] * a + ((bannerBGColor >> 8) & 0xFF) * (255 - a)) / 255;
|
||||
b = (lut4to8[(val) & 0xf] * a + ((bannerBGColor >> 16) & 0xFF) * (255 - a)) / 255;
|
||||
a = 0xFF;
|
||||
}
|
||||
|
||||
return ((a << 24) | (r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CBannerLoaderWii::decode5A3image(u32* dst, u16* src, int width, int height)
|
||||
{
|
||||
for (int y = 0; y < height; y += 4)
|
||||
{
|
||||
for (int x = 0; x < width; x += 4)
|
||||
{
|
||||
for (int iy = 0; iy < 4; iy++, src += 4)
|
||||
{
|
||||
for (int ix = 0; ix < 4; ix++)
|
||||
{
|
||||
u32 RGBA = decode5A3(Common::swap16(src[ix]));
|
||||
dst[(y + iy) * width + (x + ix)] = RGBA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -1,110 +1,110 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Blob.h"
|
||||
#include "CompressedBlob.h"
|
||||
#include "FileBlob.h"
|
||||
#include "DriveBlob.h"
|
||||
#include "MappedFile.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
// Provides caching and split-operation-to-block-operations facilities.
|
||||
// Used for compressed blob reading and direct drive reading.
|
||||
|
||||
void SectorReader::SetSectorSize(int blocksize)
|
||||
{
|
||||
for (int i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
cache[i] = new u8[blocksize];
|
||||
cache_tags[i] = (u64)(s64) - 1;
|
||||
}
|
||||
m_blocksize = blocksize;
|
||||
}
|
||||
|
||||
SectorReader::~SectorReader() {
|
||||
for (int i = 0; i < CACHE_SIZE; i++)
|
||||
delete[] cache[i];
|
||||
}
|
||||
|
||||
const u8 *SectorReader::GetBlockData(u64 block_num)
|
||||
{
|
||||
if (cache_tags[0] == block_num)
|
||||
{
|
||||
return cache[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBlock(block_num, cache[0]);
|
||||
cache_tags[0] = block_num;
|
||||
return cache[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr)
|
||||
{
|
||||
u64 startingBlock = offset / m_blocksize;
|
||||
u64 remain = size;
|
||||
|
||||
int positionInBlock = (int)(offset % m_blocksize);
|
||||
u64 block = startingBlock;
|
||||
|
||||
while (remain > 0)
|
||||
{
|
||||
const u8* data = GetBlockData(block);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
u32 toCopy = m_blocksize - positionInBlock;
|
||||
if (toCopy >= remain)
|
||||
{
|
||||
// yay, we are done!
|
||||
memcpy(out_ptr, data + positionInBlock, (size_t)remain);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(out_ptr, data + positionInBlock, toCopy);
|
||||
out_ptr += toCopy;
|
||||
remain -= toCopy;
|
||||
positionInBlock = 0;
|
||||
block++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
IBlobReader* CreateBlobReader(const char* filename)
|
||||
{
|
||||
//if (strlen(filename) < 4 && filename[1] == ':') // Drive, for sure.
|
||||
// return DriveReader::Create(filename);
|
||||
|
||||
if (!File::Exists(filename))
|
||||
return 0;
|
||||
|
||||
if (IsCompressedBlob(filename))
|
||||
return CompressedBlobReader::Create(filename);
|
||||
|
||||
// Still here? Assume plain file.
|
||||
return PlainFileReader::Create(filename);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Blob.h"
|
||||
#include "CompressedBlob.h"
|
||||
#include "FileBlob.h"
|
||||
#include "DriveBlob.h"
|
||||
#include "MappedFile.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
// Provides caching and split-operation-to-block-operations facilities.
|
||||
// Used for compressed blob reading and direct drive reading.
|
||||
|
||||
void SectorReader::SetSectorSize(int blocksize)
|
||||
{
|
||||
for (int i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
cache[i] = new u8[blocksize];
|
||||
cache_tags[i] = (u64)(s64) - 1;
|
||||
}
|
||||
m_blocksize = blocksize;
|
||||
}
|
||||
|
||||
SectorReader::~SectorReader() {
|
||||
for (int i = 0; i < CACHE_SIZE; i++)
|
||||
delete[] cache[i];
|
||||
}
|
||||
|
||||
const u8 *SectorReader::GetBlockData(u64 block_num)
|
||||
{
|
||||
if (cache_tags[0] == block_num)
|
||||
{
|
||||
return cache[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBlock(block_num, cache[0]);
|
||||
cache_tags[0] = block_num;
|
||||
return cache[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr)
|
||||
{
|
||||
u64 startingBlock = offset / m_blocksize;
|
||||
u64 remain = size;
|
||||
|
||||
int positionInBlock = (int)(offset % m_blocksize);
|
||||
u64 block = startingBlock;
|
||||
|
||||
while (remain > 0)
|
||||
{
|
||||
const u8* data = GetBlockData(block);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
u32 toCopy = m_blocksize - positionInBlock;
|
||||
if (toCopy >= remain)
|
||||
{
|
||||
// yay, we are done!
|
||||
memcpy(out_ptr, data + positionInBlock, (size_t)remain);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(out_ptr, data + positionInBlock, toCopy);
|
||||
out_ptr += toCopy;
|
||||
remain -= toCopy;
|
||||
positionInBlock = 0;
|
||||
block++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
IBlobReader* CreateBlobReader(const char* filename)
|
||||
{
|
||||
//if (strlen(filename) < 4 && filename[1] == ':') // Drive, for sure.
|
||||
// return DriveReader::Create(filename);
|
||||
|
||||
if (!File::Exists(filename))
|
||||
return 0;
|
||||
|
||||
if (IsCompressedBlob(filename))
|
||||
return CompressedBlobReader::Create(filename);
|
||||
|
||||
// Still here? Assume plain file.
|
||||
return PlainFileReader::Create(filename);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,342 +1,342 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "CompressedBlob.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Hash.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../../../../Externals/zlib/zlib.h"
|
||||
#else
|
||||
// TODO: Include generic zlib.h
|
||||
#include "../../../../Externals/zlib/zlib.h"
|
||||
#endif
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
CompressedBlobReader::CompressedBlobReader(const char *filename)
|
||||
{
|
||||
file = fopen(filename, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
file_size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(&header, sizeof(CompressedBlobHeader), 1, file);
|
||||
|
||||
SetSectorSize(header.block_size);
|
||||
|
||||
// cache block pointers and hashes
|
||||
block_pointers = new u64[header.num_blocks];
|
||||
fread(block_pointers, sizeof(u64), header.num_blocks, file);
|
||||
hashes = new u32[header.num_blocks];
|
||||
fread(hashes, sizeof(u32), header.num_blocks, file);
|
||||
|
||||
data_offset = (sizeof(CompressedBlobHeader))
|
||||
+ (sizeof(u64)) * header.num_blocks // skip block pointers
|
||||
+ (sizeof(u32)) * header.num_blocks; // skip hashes
|
||||
|
||||
// A compressed block is never ever longer than a decompressed block, so just header.block_size should be fine.
|
||||
// I still add some safety margin.
|
||||
zlib_buffer_size = header.block_size + 64;
|
||||
zlib_buffer = new u8[zlib_buffer_size];
|
||||
memset(zlib_buffer, 0, zlib_buffer_size);
|
||||
}
|
||||
|
||||
CompressedBlobReader* CompressedBlobReader::Create(const char* filename)
|
||||
{
|
||||
if (IsCompressedBlob(filename))
|
||||
return new CompressedBlobReader(filename);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CompressedBlobReader::~CompressedBlobReader()
|
||||
{
|
||||
delete [] zlib_buffer;
|
||||
delete [] block_pointers;
|
||||
delete [] hashes;
|
||||
fclose(file);
|
||||
file = 0;
|
||||
}
|
||||
|
||||
// IMPORTANT: Calling this function invalidates all earlier pointers gotten from this function.
|
||||
u64 CompressedBlobReader::GetBlockCompressedSize(u64 block_num) const
|
||||
{
|
||||
u64 start = block_pointers[block_num];
|
||||
if (block_num < header.num_blocks - 1)
|
||||
return block_pointers[block_num + 1] - start;
|
||||
else if (block_num == header.num_blocks - 1)
|
||||
return header.compressed_data_size - start;
|
||||
else
|
||||
PanicAlert("GetBlockCompressedSize - illegal block number %i", (int)block_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
|
||||
{
|
||||
bool uncompressed = false;
|
||||
u32 comp_block_size = (u32)GetBlockCompressedSize(block_num);
|
||||
u64 offset = block_pointers[block_num] + data_offset;
|
||||
|
||||
if (offset & (1ULL << 63))
|
||||
{
|
||||
if (comp_block_size != header.block_size)
|
||||
PanicAlert("Uncompressed block with wrong size");
|
||||
uncompressed = true;
|
||||
offset &= ~(1ULL << 63);
|
||||
}
|
||||
|
||||
// clear unused part of zlib buffer. maybe this can be deleted when it works fully.
|
||||
memset(zlib_buffer + comp_block_size, 0, zlib_buffer_size - comp_block_size);
|
||||
|
||||
fseek(file, offset, SEEK_SET);
|
||||
fread(zlib_buffer, 1, comp_block_size, file);
|
||||
|
||||
u8* source = zlib_buffer;
|
||||
u8* dest = out_ptr;
|
||||
|
||||
// First, check hash.
|
||||
u32 block_hash = HashAdler32(source, comp_block_size);
|
||||
if (block_hash != hashes[block_num])
|
||||
PanicAlert("Hash of block %i is %08x instead of %08x. Your ISO is corrupt.",
|
||||
block_num, block_hash, hashes[block_num]);
|
||||
|
||||
if (uncompressed)
|
||||
{
|
||||
memcpy(dest, source, comp_block_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
z_stream z;
|
||||
memset(&z, 0, sizeof(z));
|
||||
z.next_in = source;
|
||||
z.avail_in = comp_block_size;
|
||||
if (z.avail_in > header.block_size)
|
||||
{
|
||||
PanicAlert("We have a problem");
|
||||
}
|
||||
z.next_out = dest;
|
||||
z.avail_out = header.block_size;
|
||||
inflateInit(&z);
|
||||
int status = inflate(&z, Z_FULL_FLUSH);
|
||||
u32 uncomp_size = header.block_size - z.avail_out;
|
||||
if (status != Z_STREAM_END)
|
||||
{
|
||||
// this seem to fire wrongly from time to time
|
||||
// to be sure, don't use compressed isos :P
|
||||
PanicAlert("Failure reading block %i - out of data and not at end.", block_num);
|
||||
}
|
||||
inflateEnd(&z);
|
||||
if (uncomp_size != header.block_size)
|
||||
PanicAlert("Wrong block size");
|
||||
}
|
||||
}
|
||||
|
||||
bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
|
||||
int block_size, CompressCB callback, void* arg)
|
||||
{
|
||||
if (File::GetSize(infile) > 2000000000ULL) {
|
||||
PanicAlert("Sorry - compressing Wii games not yet supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsCompressedBlob(infile))
|
||||
{
|
||||
PanicAlert("%s is already compressed! Cannot compress it further.", infile);
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* inf = fopen(infile, "rb");
|
||||
if (!inf)
|
||||
return false;
|
||||
|
||||
FILE* f = fopen(outfile, "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
callback("Files opened, ready to compress.", 0, arg);
|
||||
|
||||
fseek(inf, 0, SEEK_END);
|
||||
s64 insize = ftell(inf);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
CompressedBlobHeader header;
|
||||
header.magic_cookie = kBlobCookie;
|
||||
header.sub_type = sub_type;
|
||||
header.block_size = block_size;
|
||||
header.data_size = insize;
|
||||
|
||||
// round upwards!
|
||||
header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size);
|
||||
|
||||
u64* offsets = new u64[header.num_blocks];
|
||||
u32* hashes = new u32[header.num_blocks];
|
||||
u8* out_buf = new u8[block_size];
|
||||
u8* in_buf = new u8[block_size];
|
||||
|
||||
// seek past the header (we will write it at the end)
|
||||
fseek(f, sizeof(CompressedBlobHeader), SEEK_CUR);
|
||||
// seek past the offset and hash tables (we will write them at the end)
|
||||
fseek(f, (sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR);
|
||||
|
||||
// Now we are ready to write compressed data!
|
||||
u64 position = 0;
|
||||
int num_compressed = 0;
|
||||
int num_stored = 0;
|
||||
for (u32 i = 0; i < header.num_blocks; i++)
|
||||
{
|
||||
if (i % (header.num_blocks / 1000) == 0)
|
||||
{
|
||||
u64 inpos = ftell(inf);
|
||||
int ratio = 0;
|
||||
if (inpos != 0)
|
||||
ratio = (int)(100 * position / inpos);
|
||||
char temp[512];
|
||||
sprintf(temp, "%i of %i blocks. compression ratio %i%%", i, header.num_blocks, ratio);
|
||||
callback(temp, (float)i / (float)header.num_blocks, arg);
|
||||
}
|
||||
|
||||
offsets[i] = position;
|
||||
// u64 start = i * header.block_size;
|
||||
// u64 size = header.block_size;
|
||||
memset(in_buf, 0, header.block_size);
|
||||
fread(in_buf, header.block_size, 1, inf);
|
||||
z_stream z;
|
||||
memset(&z, 0, sizeof(z));
|
||||
z.zalloc = Z_NULL;
|
||||
z.zfree = Z_NULL;
|
||||
z.opaque = Z_NULL;
|
||||
z.next_in = in_buf;
|
||||
z.avail_in = header.block_size;
|
||||
z.next_out = out_buf;
|
||||
z.avail_out = block_size;
|
||||
int retval = deflateInit(&z, 9);
|
||||
|
||||
if (retval != Z_OK)
|
||||
{
|
||||
PanicAlert("Deflate failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int status = deflate(&z, Z_FINISH);
|
||||
int comp_size = block_size - z.avail_out;
|
||||
if ((status != Z_STREAM_END) || (z.avail_out < 10))
|
||||
{
|
||||
//PanicAlert("%i %i Store %i", i*block_size, position, comp_size);
|
||||
// let's store uncompressed
|
||||
offsets[i] |= 0x8000000000000000ULL;
|
||||
fwrite(in_buf, block_size, 1, f);
|
||||
hashes[i] = HashAdler32(in_buf, block_size);
|
||||
position += block_size;
|
||||
num_stored++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// let's store compressed
|
||||
//PanicAlert("Comp %i to %i", block_size, comp_size);
|
||||
fwrite(out_buf, comp_size, 1, f);
|
||||
hashes[i] = HashAdler32(out_buf, comp_size);
|
||||
position += comp_size;
|
||||
num_compressed++;
|
||||
}
|
||||
|
||||
deflateEnd(&z);
|
||||
}
|
||||
|
||||
header.compressed_data_size = position;
|
||||
|
||||
// Okay, go back and fill in headers
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fwrite(&header, sizeof(header), 1, f);
|
||||
fwrite(offsets, sizeof(u64), header.num_blocks, f);
|
||||
fwrite(hashes, sizeof(u32), header.num_blocks, f);
|
||||
|
||||
cleanup:
|
||||
// Cleanup
|
||||
delete[] in_buf;
|
||||
delete[] out_buf;
|
||||
delete[] offsets;
|
||||
fclose(f);
|
||||
fclose(inf);
|
||||
callback("Done compressing disc image.", 1.0f, arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecompressBlobToFile(const char* infile, const char* outfile, CompressCB callback, void* arg)
|
||||
{
|
||||
if (!IsCompressedBlob(infile))
|
||||
{
|
||||
PanicAlert("File not compressed");
|
||||
return false;
|
||||
}
|
||||
|
||||
CompressedBlobReader* reader = CompressedBlobReader::Create(infile);
|
||||
if (!reader) return false;
|
||||
|
||||
FILE* f = fopen(outfile, "wb");
|
||||
const CompressedBlobHeader &header = reader->GetHeader();
|
||||
u8* buffer = new u8[header.block_size];
|
||||
|
||||
for (u64 i = 0; i < header.num_blocks; i++)
|
||||
{
|
||||
if (i % (header.num_blocks / 100) == 0)
|
||||
{
|
||||
callback("Unpacking", (float)i / (float)header.num_blocks, arg);
|
||||
}
|
||||
reader->Read(i * header.block_size, header.block_size, buffer);
|
||||
fwrite(buffer, header.block_size, 1, f);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
#ifdef _WIN32
|
||||
// ector: _chsize sucks, not 64-bit safe
|
||||
// F|RES: changed to _chsize_s. i think it is 64-bit safe
|
||||
_chsize_s(_fileno(f), (long)header.data_size);
|
||||
#else
|
||||
ftruncate(fileno(f), header.data_size);
|
||||
#endif
|
||||
fclose(f);
|
||||
|
||||
delete reader;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsCompressedBlob(const char* filename)
|
||||
{
|
||||
FILE* f = fopen(filename, "rb");
|
||||
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
CompressedBlobHeader header;
|
||||
fread(&header, sizeof(header), 1, f);
|
||||
fclose(f);
|
||||
return header.magic_cookie == kBlobCookie;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "CompressedBlob.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Hash.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../../../../Externals/zlib/zlib.h"
|
||||
#else
|
||||
// TODO: Include generic zlib.h
|
||||
#include "../../../../Externals/zlib/zlib.h"
|
||||
#endif
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
CompressedBlobReader::CompressedBlobReader(const char *filename)
|
||||
{
|
||||
file = fopen(filename, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
file_size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(&header, sizeof(CompressedBlobHeader), 1, file);
|
||||
|
||||
SetSectorSize(header.block_size);
|
||||
|
||||
// cache block pointers and hashes
|
||||
block_pointers = new u64[header.num_blocks];
|
||||
fread(block_pointers, sizeof(u64), header.num_blocks, file);
|
||||
hashes = new u32[header.num_blocks];
|
||||
fread(hashes, sizeof(u32), header.num_blocks, file);
|
||||
|
||||
data_offset = (sizeof(CompressedBlobHeader))
|
||||
+ (sizeof(u64)) * header.num_blocks // skip block pointers
|
||||
+ (sizeof(u32)) * header.num_blocks; // skip hashes
|
||||
|
||||
// A compressed block is never ever longer than a decompressed block, so just header.block_size should be fine.
|
||||
// I still add some safety margin.
|
||||
zlib_buffer_size = header.block_size + 64;
|
||||
zlib_buffer = new u8[zlib_buffer_size];
|
||||
memset(zlib_buffer, 0, zlib_buffer_size);
|
||||
}
|
||||
|
||||
CompressedBlobReader* CompressedBlobReader::Create(const char* filename)
|
||||
{
|
||||
if (IsCompressedBlob(filename))
|
||||
return new CompressedBlobReader(filename);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CompressedBlobReader::~CompressedBlobReader()
|
||||
{
|
||||
delete [] zlib_buffer;
|
||||
delete [] block_pointers;
|
||||
delete [] hashes;
|
||||
fclose(file);
|
||||
file = 0;
|
||||
}
|
||||
|
||||
// IMPORTANT: Calling this function invalidates all earlier pointers gotten from this function.
|
||||
u64 CompressedBlobReader::GetBlockCompressedSize(u64 block_num) const
|
||||
{
|
||||
u64 start = block_pointers[block_num];
|
||||
if (block_num < header.num_blocks - 1)
|
||||
return block_pointers[block_num + 1] - start;
|
||||
else if (block_num == header.num_blocks - 1)
|
||||
return header.compressed_data_size - start;
|
||||
else
|
||||
PanicAlert("GetBlockCompressedSize - illegal block number %i", (int)block_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
|
||||
{
|
||||
bool uncompressed = false;
|
||||
u32 comp_block_size = (u32)GetBlockCompressedSize(block_num);
|
||||
u64 offset = block_pointers[block_num] + data_offset;
|
||||
|
||||
if (offset & (1ULL << 63))
|
||||
{
|
||||
if (comp_block_size != header.block_size)
|
||||
PanicAlert("Uncompressed block with wrong size");
|
||||
uncompressed = true;
|
||||
offset &= ~(1ULL << 63);
|
||||
}
|
||||
|
||||
// clear unused part of zlib buffer. maybe this can be deleted when it works fully.
|
||||
memset(zlib_buffer + comp_block_size, 0, zlib_buffer_size - comp_block_size);
|
||||
|
||||
fseek(file, offset, SEEK_SET);
|
||||
fread(zlib_buffer, 1, comp_block_size, file);
|
||||
|
||||
u8* source = zlib_buffer;
|
||||
u8* dest = out_ptr;
|
||||
|
||||
// First, check hash.
|
||||
u32 block_hash = HashAdler32(source, comp_block_size);
|
||||
if (block_hash != hashes[block_num])
|
||||
PanicAlert("Hash of block %i is %08x instead of %08x. Your ISO is corrupt.",
|
||||
block_num, block_hash, hashes[block_num]);
|
||||
|
||||
if (uncompressed)
|
||||
{
|
||||
memcpy(dest, source, comp_block_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
z_stream z;
|
||||
memset(&z, 0, sizeof(z));
|
||||
z.next_in = source;
|
||||
z.avail_in = comp_block_size;
|
||||
if (z.avail_in > header.block_size)
|
||||
{
|
||||
PanicAlert("We have a problem");
|
||||
}
|
||||
z.next_out = dest;
|
||||
z.avail_out = header.block_size;
|
||||
inflateInit(&z);
|
||||
int status = inflate(&z, Z_FULL_FLUSH);
|
||||
u32 uncomp_size = header.block_size - z.avail_out;
|
||||
if (status != Z_STREAM_END)
|
||||
{
|
||||
// this seem to fire wrongly from time to time
|
||||
// to be sure, don't use compressed isos :P
|
||||
PanicAlert("Failure reading block %i - out of data and not at end.", block_num);
|
||||
}
|
||||
inflateEnd(&z);
|
||||
if (uncomp_size != header.block_size)
|
||||
PanicAlert("Wrong block size");
|
||||
}
|
||||
}
|
||||
|
||||
bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
|
||||
int block_size, CompressCB callback, void* arg)
|
||||
{
|
||||
if (File::GetSize(infile) > 2000000000ULL) {
|
||||
PanicAlert("Sorry - compressing Wii games not yet supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsCompressedBlob(infile))
|
||||
{
|
||||
PanicAlert("%s is already compressed! Cannot compress it further.", infile);
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* inf = fopen(infile, "rb");
|
||||
if (!inf)
|
||||
return false;
|
||||
|
||||
FILE* f = fopen(outfile, "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
callback("Files opened, ready to compress.", 0, arg);
|
||||
|
||||
fseek(inf, 0, SEEK_END);
|
||||
s64 insize = ftell(inf);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
CompressedBlobHeader header;
|
||||
header.magic_cookie = kBlobCookie;
|
||||
header.sub_type = sub_type;
|
||||
header.block_size = block_size;
|
||||
header.data_size = insize;
|
||||
|
||||
// round upwards!
|
||||
header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size);
|
||||
|
||||
u64* offsets = new u64[header.num_blocks];
|
||||
u32* hashes = new u32[header.num_blocks];
|
||||
u8* out_buf = new u8[block_size];
|
||||
u8* in_buf = new u8[block_size];
|
||||
|
||||
// seek past the header (we will write it at the end)
|
||||
fseek(f, sizeof(CompressedBlobHeader), SEEK_CUR);
|
||||
// seek past the offset and hash tables (we will write them at the end)
|
||||
fseek(f, (sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR);
|
||||
|
||||
// Now we are ready to write compressed data!
|
||||
u64 position = 0;
|
||||
int num_compressed = 0;
|
||||
int num_stored = 0;
|
||||
for (u32 i = 0; i < header.num_blocks; i++)
|
||||
{
|
||||
if (i % (header.num_blocks / 1000) == 0)
|
||||
{
|
||||
u64 inpos = ftell(inf);
|
||||
int ratio = 0;
|
||||
if (inpos != 0)
|
||||
ratio = (int)(100 * position / inpos);
|
||||
char temp[512];
|
||||
sprintf(temp, "%i of %i blocks. compression ratio %i%%", i, header.num_blocks, ratio);
|
||||
callback(temp, (float)i / (float)header.num_blocks, arg);
|
||||
}
|
||||
|
||||
offsets[i] = position;
|
||||
// u64 start = i * header.block_size;
|
||||
// u64 size = header.block_size;
|
||||
memset(in_buf, 0, header.block_size);
|
||||
fread(in_buf, header.block_size, 1, inf);
|
||||
z_stream z;
|
||||
memset(&z, 0, sizeof(z));
|
||||
z.zalloc = Z_NULL;
|
||||
z.zfree = Z_NULL;
|
||||
z.opaque = Z_NULL;
|
||||
z.next_in = in_buf;
|
||||
z.avail_in = header.block_size;
|
||||
z.next_out = out_buf;
|
||||
z.avail_out = block_size;
|
||||
int retval = deflateInit(&z, 9);
|
||||
|
||||
if (retval != Z_OK)
|
||||
{
|
||||
PanicAlert("Deflate failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int status = deflate(&z, Z_FINISH);
|
||||
int comp_size = block_size - z.avail_out;
|
||||
if ((status != Z_STREAM_END) || (z.avail_out < 10))
|
||||
{
|
||||
//PanicAlert("%i %i Store %i", i*block_size, position, comp_size);
|
||||
// let's store uncompressed
|
||||
offsets[i] |= 0x8000000000000000ULL;
|
||||
fwrite(in_buf, block_size, 1, f);
|
||||
hashes[i] = HashAdler32(in_buf, block_size);
|
||||
position += block_size;
|
||||
num_stored++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// let's store compressed
|
||||
//PanicAlert("Comp %i to %i", block_size, comp_size);
|
||||
fwrite(out_buf, comp_size, 1, f);
|
||||
hashes[i] = HashAdler32(out_buf, comp_size);
|
||||
position += comp_size;
|
||||
num_compressed++;
|
||||
}
|
||||
|
||||
deflateEnd(&z);
|
||||
}
|
||||
|
||||
header.compressed_data_size = position;
|
||||
|
||||
// Okay, go back and fill in headers
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fwrite(&header, sizeof(header), 1, f);
|
||||
fwrite(offsets, sizeof(u64), header.num_blocks, f);
|
||||
fwrite(hashes, sizeof(u32), header.num_blocks, f);
|
||||
|
||||
cleanup:
|
||||
// Cleanup
|
||||
delete[] in_buf;
|
||||
delete[] out_buf;
|
||||
delete[] offsets;
|
||||
fclose(f);
|
||||
fclose(inf);
|
||||
callback("Done compressing disc image.", 1.0f, arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecompressBlobToFile(const char* infile, const char* outfile, CompressCB callback, void* arg)
|
||||
{
|
||||
if (!IsCompressedBlob(infile))
|
||||
{
|
||||
PanicAlert("File not compressed");
|
||||
return false;
|
||||
}
|
||||
|
||||
CompressedBlobReader* reader = CompressedBlobReader::Create(infile);
|
||||
if (!reader) return false;
|
||||
|
||||
FILE* f = fopen(outfile, "wb");
|
||||
const CompressedBlobHeader &header = reader->GetHeader();
|
||||
u8* buffer = new u8[header.block_size];
|
||||
|
||||
for (u64 i = 0; i < header.num_blocks; i++)
|
||||
{
|
||||
if (i % (header.num_blocks / 100) == 0)
|
||||
{
|
||||
callback("Unpacking", (float)i / (float)header.num_blocks, arg);
|
||||
}
|
||||
reader->Read(i * header.block_size, header.block_size, buffer);
|
||||
fwrite(buffer, header.block_size, 1, f);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
#ifdef _WIN32
|
||||
// ector: _chsize sucks, not 64-bit safe
|
||||
// F|RES: changed to _chsize_s. i think it is 64-bit safe
|
||||
_chsize_s(_fileno(f), (long)header.data_size);
|
||||
#else
|
||||
ftruncate(fileno(f), header.data_size);
|
||||
#endif
|
||||
fclose(f);
|
||||
|
||||
delete reader;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsCompressedBlob(const char* filename)
|
||||
{
|
||||
FILE* f = fopen(filename, "rb");
|
||||
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
CompressedBlobHeader header;
|
||||
fread(&header, sizeof(header), 1, f);
|
||||
fclose(f);
|
||||
return header.magic_cookie == kBlobCookie;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,25 +1,25 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "DriveBlob.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "DriveBlob.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
} // namespace
|
||||
|
@ -1,110 +1,110 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Blob.h"
|
||||
#include "FileBlob.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
PlainFileReader::PlainFileReader(HANDLE hFile_)
|
||||
{
|
||||
hFile = hFile_;
|
||||
DWORD size_low, size_high;
|
||||
size_low = GetFileSize(hFile, &size_high);
|
||||
size = ((u64)size_low) | ((u64)size_high << 32);
|
||||
}
|
||||
|
||||
PlainFileReader* PlainFileReader::Create(const char* filename)
|
||||
{
|
||||
HANDLE hFile = CreateFile(
|
||||
filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
return new PlainFileReader(hFile);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
PlainFileReader::~PlainFileReader()
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
||||
{
|
||||
LONG offset_high = (LONG)(offset >> 32);
|
||||
SetFilePointer(hFile, (DWORD)(offset & 0xFFFFFFFF), &offset_high, FILE_BEGIN);
|
||||
|
||||
if (nbytes >= 0x100000000ULL)
|
||||
return false; // WTF, does windows really have this limitation?
|
||||
|
||||
DWORD unused = 0;
|
||||
if (!ReadFile(hFile, out_ptr, DWORD(nbytes & 0xFFFFFFFF), &unused, NULL))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#else // POSIX
|
||||
|
||||
PlainFileReader::PlainFileReader(FILE* file__)
|
||||
{
|
||||
file_ = file__;
|
||||
#if 0
|
||||
fseek64(file_, 0, SEEK_END);
|
||||
#else
|
||||
fseek(file_, 0, SEEK_END); // I don't have fseek64 with gcc 4.3
|
||||
#endif
|
||||
size = ftell(file_);
|
||||
fseek(file_, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
PlainFileReader* PlainFileReader::Create(const char* filename)
|
||||
{
|
||||
FILE* file_ = fopen(filename, "rb");
|
||||
if (file_)
|
||||
return new PlainFileReader(file_);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
PlainFileReader::~PlainFileReader()
|
||||
{
|
||||
fclose(file_);
|
||||
}
|
||||
|
||||
bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
||||
{
|
||||
int seekStatus = fseek(file_, offset, SEEK_SET);
|
||||
if (seekStatus != 0)
|
||||
return false;
|
||||
size_t bytesRead = fread(out_ptr, 1, nbytes, file_);
|
||||
return bytesRead == nbytes;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Blob.h"
|
||||
#include "FileBlob.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
PlainFileReader::PlainFileReader(HANDLE hFile_)
|
||||
{
|
||||
hFile = hFile_;
|
||||
DWORD size_low, size_high;
|
||||
size_low = GetFileSize(hFile, &size_high);
|
||||
size = ((u64)size_low) | ((u64)size_high << 32);
|
||||
}
|
||||
|
||||
PlainFileReader* PlainFileReader::Create(const char* filename)
|
||||
{
|
||||
HANDLE hFile = CreateFile(
|
||||
filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
return new PlainFileReader(hFile);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
PlainFileReader::~PlainFileReader()
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
||||
{
|
||||
LONG offset_high = (LONG)(offset >> 32);
|
||||
SetFilePointer(hFile, (DWORD)(offset & 0xFFFFFFFF), &offset_high, FILE_BEGIN);
|
||||
|
||||
if (nbytes >= 0x100000000ULL)
|
||||
return false; // WTF, does windows really have this limitation?
|
||||
|
||||
DWORD unused = 0;
|
||||
if (!ReadFile(hFile, out_ptr, DWORD(nbytes & 0xFFFFFFFF), &unused, NULL))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#else // POSIX
|
||||
|
||||
PlainFileReader::PlainFileReader(FILE* file__)
|
||||
{
|
||||
file_ = file__;
|
||||
#if 0
|
||||
fseek64(file_, 0, SEEK_END);
|
||||
#else
|
||||
fseek(file_, 0, SEEK_END); // I don't have fseek64 with gcc 4.3
|
||||
#endif
|
||||
size = ftell(file_);
|
||||
fseek(file_, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
PlainFileReader* PlainFileReader::Create(const char* filename)
|
||||
{
|
||||
FILE* file_ = fopen(filename, "rb");
|
||||
if (file_)
|
||||
return new PlainFileReader(file_);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
PlainFileReader::~PlainFileReader()
|
||||
{
|
||||
fclose(file_);
|
||||
}
|
||||
|
||||
bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
||||
{
|
||||
int seekStatus = fseek(file_, offset, SEEK_SET);
|
||||
if (seekStatus != 0)
|
||||
return false;
|
||||
size_t bytesRead = fread(out_ptr, 1, nbytes, file_);
|
||||
return bytesRead == nbytes;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
@ -1,237 +1,237 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include "FileHandlerARC.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
|
||||
#define ARC_ID 0x55aa382d
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CARCFile::CARCFile(const u8* _pBuffer, size_t _BufferSize)
|
||||
: m_pBuffer(NULL),
|
||||
m_Initialized(false)
|
||||
{
|
||||
m_pBuffer = new u8[_BufferSize];
|
||||
|
||||
if (m_pBuffer)
|
||||
{
|
||||
memcpy(m_pBuffer, _pBuffer, _BufferSize);
|
||||
m_Initialized = ParseBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CARCFile::~CARCFile()
|
||||
{
|
||||
delete [] m_pBuffer;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::IsInitialized()
|
||||
{
|
||||
return(m_Initialized);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
CARCFile::GetFileSize(const std::string& _rFullPath)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo != NULL)
|
||||
{
|
||||
return(pFileInfo->m_FileSize);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
CARCFile::ReadFile(const std::string& _rFullPath, u8* _pBuffer, size_t _MaxBufferSize)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo == NULL)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (pFileInfo->m_FileSize > _MaxBufferSize)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
memcpy(_pBuffer, &m_pBuffer[pFileInfo->m_Offset], pFileInfo->m_FileSize);
|
||||
return(pFileInfo->m_FileSize);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
FILE* pFile = fopen(_rExportFilename.c_str(), "wb");
|
||||
|
||||
if (pFile == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
fwrite(&m_pBuffer[pFileInfo->m_Offset], pFileInfo->m_FileSize, 1, pFile);
|
||||
fclose(pFile);
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::ExportAllFiles(const std::string& _rFullPath)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::ParseBuffer()
|
||||
{
|
||||
// check ID
|
||||
u32 ID = Common::swap32(*(u32*)(m_pBuffer));
|
||||
|
||||
if (ID != ARC_ID)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
// read header
|
||||
u32 FSTOffset = Common::swap32(*(u32*)(m_pBuffer + 0x4));
|
||||
//u32 FSTSize = Common::swap32(*(u32*)(m_pBuffer + 0x8));
|
||||
//u32 FileOffset = Common::swap32(*(u32*)(m_pBuffer + 0xC));
|
||||
|
||||
// read all file infos
|
||||
SFileInfo Root;
|
||||
Root.m_NameOffset = Common::swap32(*(u32*)(m_pBuffer + FSTOffset + 0x0));
|
||||
Root.m_Offset = Common::swap32(*(u32*)(m_pBuffer + FSTOffset + 0x4));
|
||||
Root.m_FileSize = Common::swap32(*(u32*)(m_pBuffer + FSTOffset + 0x8));
|
||||
|
||||
if (Root.IsDirectory())
|
||||
{
|
||||
m_FileInfoVector.resize(Root.m_FileSize);
|
||||
const char* szNameTable = (char*)(m_pBuffer + FSTOffset);
|
||||
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
u8* Offset = m_pBuffer + FSTOffset + (i * 0xC);
|
||||
m_FileInfoVector[i].m_NameOffset = Common::swap32(*(u32*)(Offset + 0x0));
|
||||
m_FileInfoVector[i].m_Offset = Common::swap32(*(u32*)(Offset + 0x4));
|
||||
m_FileInfoVector[i].m_FileSize = Common::swap32(*(u32*)(Offset + 0x8));
|
||||
|
||||
szNameTable += 0xC;
|
||||
}
|
||||
|
||||
BuildFilenames(1, m_FileInfoVector.size(), NULL, szNameTable);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
CARCFile::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const char* _szDirectory, const char* _szNameTable)
|
||||
{
|
||||
size_t CurrentIndex = _FirstIndex;
|
||||
|
||||
while (CurrentIndex < _LastIndex)
|
||||
{
|
||||
SFileInfo& rFileInfo = m_FileInfoVector[CurrentIndex];
|
||||
int uOffset = rFileInfo.m_NameOffset & 0xFFFFFF;
|
||||
|
||||
// check next index
|
||||
if (rFileInfo.IsDirectory())
|
||||
{
|
||||
// this is a directory, build up the new szDirectory
|
||||
if (_szDirectory != NULL)
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s%s\\", _szDirectory, &_szNameTable[uOffset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s\\", &_szNameTable[uOffset]);
|
||||
}
|
||||
|
||||
CurrentIndex = BuildFilenames(CurrentIndex + 1, rFileInfo.m_FileSize, rFileInfo.m_FullPath, _szNameTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a filename
|
||||
if (_szDirectory != NULL)
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s%s", _szDirectory, &_szNameTable[uOffset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s", &_szNameTable[uOffset]);
|
||||
}
|
||||
|
||||
CurrentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return(CurrentIndex);
|
||||
}
|
||||
|
||||
|
||||
const SFileInfo*
|
||||
CARCFile::FindFileInfo(std::string _rFullPath) const
|
||||
{
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
if (!strcasecmp(m_FileInfoVector[i].m_FullPath, _rFullPath.c_str()))
|
||||
{
|
||||
return(&m_FileInfoVector[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include "FileHandlerARC.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
|
||||
#define ARC_ID 0x55aa382d
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CARCFile::CARCFile(const u8* _pBuffer, size_t _BufferSize)
|
||||
: m_pBuffer(NULL),
|
||||
m_Initialized(false)
|
||||
{
|
||||
m_pBuffer = new u8[_BufferSize];
|
||||
|
||||
if (m_pBuffer)
|
||||
{
|
||||
memcpy(m_pBuffer, _pBuffer, _BufferSize);
|
||||
m_Initialized = ParseBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CARCFile::~CARCFile()
|
||||
{
|
||||
delete [] m_pBuffer;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::IsInitialized()
|
||||
{
|
||||
return(m_Initialized);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
CARCFile::GetFileSize(const std::string& _rFullPath)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo != NULL)
|
||||
{
|
||||
return(pFileInfo->m_FileSize);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
CARCFile::ReadFile(const std::string& _rFullPath, u8* _pBuffer, size_t _MaxBufferSize)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo == NULL)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (pFileInfo->m_FileSize > _MaxBufferSize)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
memcpy(_pBuffer, &m_pBuffer[pFileInfo->m_Offset], pFileInfo->m_FileSize);
|
||||
return(pFileInfo->m_FileSize);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
FILE* pFile = fopen(_rExportFilename.c_str(), "wb");
|
||||
|
||||
if (pFile == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
fwrite(&m_pBuffer[pFileInfo->m_Offset], pFileInfo->m_FileSize, 1, pFile);
|
||||
fclose(pFile);
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::ExportAllFiles(const std::string& _rFullPath)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CARCFile::ParseBuffer()
|
||||
{
|
||||
// check ID
|
||||
u32 ID = Common::swap32(*(u32*)(m_pBuffer));
|
||||
|
||||
if (ID != ARC_ID)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
// read header
|
||||
u32 FSTOffset = Common::swap32(*(u32*)(m_pBuffer + 0x4));
|
||||
//u32 FSTSize = Common::swap32(*(u32*)(m_pBuffer + 0x8));
|
||||
//u32 FileOffset = Common::swap32(*(u32*)(m_pBuffer + 0xC));
|
||||
|
||||
// read all file infos
|
||||
SFileInfo Root;
|
||||
Root.m_NameOffset = Common::swap32(*(u32*)(m_pBuffer + FSTOffset + 0x0));
|
||||
Root.m_Offset = Common::swap32(*(u32*)(m_pBuffer + FSTOffset + 0x4));
|
||||
Root.m_FileSize = Common::swap32(*(u32*)(m_pBuffer + FSTOffset + 0x8));
|
||||
|
||||
if (Root.IsDirectory())
|
||||
{
|
||||
m_FileInfoVector.resize(Root.m_FileSize);
|
||||
const char* szNameTable = (char*)(m_pBuffer + FSTOffset);
|
||||
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
u8* Offset = m_pBuffer + FSTOffset + (i * 0xC);
|
||||
m_FileInfoVector[i].m_NameOffset = Common::swap32(*(u32*)(Offset + 0x0));
|
||||
m_FileInfoVector[i].m_Offset = Common::swap32(*(u32*)(Offset + 0x4));
|
||||
m_FileInfoVector[i].m_FileSize = Common::swap32(*(u32*)(Offset + 0x8));
|
||||
|
||||
szNameTable += 0xC;
|
||||
}
|
||||
|
||||
BuildFilenames(1, m_FileInfoVector.size(), NULL, szNameTable);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
CARCFile::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const char* _szDirectory, const char* _szNameTable)
|
||||
{
|
||||
size_t CurrentIndex = _FirstIndex;
|
||||
|
||||
while (CurrentIndex < _LastIndex)
|
||||
{
|
||||
SFileInfo& rFileInfo = m_FileInfoVector[CurrentIndex];
|
||||
int uOffset = rFileInfo.m_NameOffset & 0xFFFFFF;
|
||||
|
||||
// check next index
|
||||
if (rFileInfo.IsDirectory())
|
||||
{
|
||||
// this is a directory, build up the new szDirectory
|
||||
if (_szDirectory != NULL)
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s%s\\", _szDirectory, &_szNameTable[uOffset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s\\", &_szNameTable[uOffset]);
|
||||
}
|
||||
|
||||
CurrentIndex = BuildFilenames(CurrentIndex + 1, rFileInfo.m_FileSize, rFileInfo.m_FullPath, _szNameTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a filename
|
||||
if (_szDirectory != NULL)
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s%s", _szDirectory, &_szNameTable[uOffset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(rFileInfo.m_FullPath, "%s", &_szNameTable[uOffset]);
|
||||
}
|
||||
|
||||
CurrentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return(CurrentIndex);
|
||||
}
|
||||
|
||||
|
||||
const SFileInfo*
|
||||
CARCFile::FindFileInfo(std::string _rFullPath) const
|
||||
{
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
if (!strcasecmp(m_FileInfoVector[i].m_FullPath, _rFullPath.c_str()))
|
||||
{
|
||||
return(&m_FileInfoVector[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
} // namespace
|
||||
|
@ -1,249 +1,249 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "FileSystemGCWii.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CFileSystemGCWii::CFileSystemGCWii(const IVolume *_rVolume)
|
||||
: IFileSystem(_rVolume),
|
||||
m_Initialized(false),
|
||||
m_OffsetShift(0)
|
||||
{
|
||||
m_Initialized = InitFileSystem();
|
||||
}
|
||||
|
||||
|
||||
CFileSystemGCWii::~CFileSystemGCWii()
|
||||
{
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::IsInitialized() const
|
||||
{
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
u64 CFileSystemGCWii::GetFileSize(const char* _rFullPath) const
|
||||
{
|
||||
if (!m_Initialized)
|
||||
return 0;
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo != NULL)
|
||||
return pFileInfo->m_FileSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* CFileSystemGCWii::GetFileName(u64 _Address) const
|
||||
{
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
if ((m_FileInfoVector[i].m_Offset <= _Address) &&
|
||||
((m_FileInfoVector[i].m_Offset + m_FileInfoVector[i].m_FileSize) > _Address))
|
||||
{
|
||||
return m_FileInfoVector[i].m_FullPath;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 CFileSystemGCWii::ReadFile(const char* _rFullPath, u8* _pBuffer, size_t _MaxBufferSize) const
|
||||
{
|
||||
if (!m_Initialized)
|
||||
return 0;
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
if (pFileInfo == NULL)
|
||||
return 0;
|
||||
|
||||
if (pFileInfo->m_FileSize > _MaxBufferSize)
|
||||
return 0;
|
||||
|
||||
m_rVolume->Read(pFileInfo->m_Offset, pFileInfo->m_FileSize, _pBuffer);
|
||||
return pFileInfo->m_FileSize;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::ExportFile(const char* _rFullPath, const char* _rExportFilename) const
|
||||
{
|
||||
size_t filesize = GetFileSize(_rFullPath);
|
||||
|
||||
if (filesize == 0)
|
||||
return false;
|
||||
|
||||
u8* buffer = new u8[filesize];
|
||||
|
||||
if (!ReadFile(_rFullPath, buffer, filesize))
|
||||
{
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* f = fopen(_rExportFilename, "wb");
|
||||
|
||||
if (f)
|
||||
{
|
||||
fwrite(buffer, filesize, 1, f);
|
||||
fclose(f);
|
||||
delete[] buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::ExportAllFiles(const char* _rFullPath) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 CFileSystemGCWii::Read32(u64 _Offset) const
|
||||
{
|
||||
u32 Temp = 0;
|
||||
m_rVolume->Read(_Offset, 4, (u8*)&Temp);
|
||||
return Common::swap32(Temp);
|
||||
}
|
||||
|
||||
void CFileSystemGCWii::GetStringFromOffset(u64 _Offset, char* Filename) const
|
||||
{
|
||||
m_rVolume->Read(_Offset, 255, (u8*)Filename);
|
||||
}
|
||||
|
||||
size_t CFileSystemGCWii::GetFileList(std::vector<const SFileInfo *> &_rFilenames) const
|
||||
{
|
||||
if (_rFilenames.size())
|
||||
PanicAlert("GetFileList : input list has contents?");
|
||||
_rFilenames.clear();
|
||||
_rFilenames.reserve(m_FileInfoVector.size());
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
_rFilenames.push_back(&m_FileInfoVector[i]);
|
||||
return m_FileInfoVector.size();
|
||||
}
|
||||
|
||||
const SFileInfo* CFileSystemGCWii::FindFileInfo(const char* _rFullPath) const
|
||||
{
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
if (!strcasecmp(m_FileInfoVector[i].m_FullPath, _rFullPath))
|
||||
return &m_FileInfoVector[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::InitFileSystem()
|
||||
{
|
||||
if (Read32(0x18) == 0x5D1C9EA3)
|
||||
{
|
||||
m_OffsetShift = 2; // Wii file system
|
||||
}
|
||||
else if (Read32(0x1c) == 0xC2339F3D)
|
||||
{
|
||||
m_OffsetShift = 0; // GC file system
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the whole FST
|
||||
u64 FSTOffset = (u64)Read32(0x424) << m_OffsetShift;
|
||||
// u32 FSTSize = Read32(0x428);
|
||||
// u32 FSTMaxSize = Read32(0x42C);
|
||||
|
||||
|
||||
// read all fileinfos
|
||||
SFileInfo Root;
|
||||
Root.m_NameOffset = Read32(FSTOffset + 0x0);
|
||||
Root.m_Offset = (u64)Read32(FSTOffset + 0x4) << m_OffsetShift;
|
||||
Root.m_FileSize = Read32(FSTOffset + 0x8);
|
||||
|
||||
if (Root.IsDirectory())
|
||||
{
|
||||
if (m_FileInfoVector.size())
|
||||
PanicAlert("Wtf?");
|
||||
u64 NameTableOffset = FSTOffset;
|
||||
|
||||
m_FileInfoVector.reserve(Root.m_FileSize);
|
||||
for (u32 i = 0; i < Root.m_FileSize; i++)
|
||||
{
|
||||
SFileInfo sfi;
|
||||
u64 Offset = FSTOffset + (i * 0xC);
|
||||
sfi.m_NameOffset = Read32(Offset + 0x0);
|
||||
sfi.m_Offset = (u64)Read32(Offset + 0x4) << m_OffsetShift;
|
||||
sfi.m_FileSize = Read32(Offset + 0x8);
|
||||
|
||||
m_FileInfoVector.push_back(sfi);
|
||||
NameTableOffset += 0xC;
|
||||
}
|
||||
|
||||
BuildFilenames(1, m_FileInfoVector.size(), NULL, NameTableOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Changed this stuff from C++ string to C strings for speed in debug mode. Doesn't matter in release, but
|
||||
// std::string is SLOW in debug mode.
|
||||
size_t CFileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const char* _szDirectory, u64 _NameTableOffset)
|
||||
{
|
||||
size_t CurrentIndex = _FirstIndex;
|
||||
|
||||
while (CurrentIndex < _LastIndex)
|
||||
{
|
||||
SFileInfo *rFileInfo = &m_FileInfoVector[CurrentIndex];
|
||||
u64 uOffset = _NameTableOffset + (rFileInfo->m_NameOffset & 0xFFFFFF);
|
||||
char filename[512];
|
||||
memset(filename, 0, sizeof(filename));
|
||||
GetStringFromOffset(uOffset, filename);
|
||||
|
||||
// check next index
|
||||
if (rFileInfo->IsDirectory())
|
||||
{
|
||||
// this is a directory, build up the new szDirectory
|
||||
if (_szDirectory != NULL)
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s%s\\", _szDirectory, filename);
|
||||
else
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s\\", filename);
|
||||
|
||||
CurrentIndex = BuildFilenames(CurrentIndex + 1, rFileInfo->m_FileSize, rFileInfo->m_FullPath, _NameTableOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a filename
|
||||
if (_szDirectory != NULL)
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s%s", _szDirectory, filename);
|
||||
else
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s", filename);
|
||||
|
||||
CurrentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return CurrentIndex;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "FileSystemGCWii.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CFileSystemGCWii::CFileSystemGCWii(const IVolume *_rVolume)
|
||||
: IFileSystem(_rVolume),
|
||||
m_Initialized(false),
|
||||
m_OffsetShift(0)
|
||||
{
|
||||
m_Initialized = InitFileSystem();
|
||||
}
|
||||
|
||||
|
||||
CFileSystemGCWii::~CFileSystemGCWii()
|
||||
{
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::IsInitialized() const
|
||||
{
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
u64 CFileSystemGCWii::GetFileSize(const char* _rFullPath) const
|
||||
{
|
||||
if (!m_Initialized)
|
||||
return 0;
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (pFileInfo != NULL)
|
||||
return pFileInfo->m_FileSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* CFileSystemGCWii::GetFileName(u64 _Address) const
|
||||
{
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
if ((m_FileInfoVector[i].m_Offset <= _Address) &&
|
||||
((m_FileInfoVector[i].m_Offset + m_FileInfoVector[i].m_FileSize) > _Address))
|
||||
{
|
||||
return m_FileInfoVector[i].m_FullPath;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 CFileSystemGCWii::ReadFile(const char* _rFullPath, u8* _pBuffer, size_t _MaxBufferSize) const
|
||||
{
|
||||
if (!m_Initialized)
|
||||
return 0;
|
||||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
if (pFileInfo == NULL)
|
||||
return 0;
|
||||
|
||||
if (pFileInfo->m_FileSize > _MaxBufferSize)
|
||||
return 0;
|
||||
|
||||
m_rVolume->Read(pFileInfo->m_Offset, pFileInfo->m_FileSize, _pBuffer);
|
||||
return pFileInfo->m_FileSize;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::ExportFile(const char* _rFullPath, const char* _rExportFilename) const
|
||||
{
|
||||
size_t filesize = GetFileSize(_rFullPath);
|
||||
|
||||
if (filesize == 0)
|
||||
return false;
|
||||
|
||||
u8* buffer = new u8[filesize];
|
||||
|
||||
if (!ReadFile(_rFullPath, buffer, filesize))
|
||||
{
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* f = fopen(_rExportFilename, "wb");
|
||||
|
||||
if (f)
|
||||
{
|
||||
fwrite(buffer, filesize, 1, f);
|
||||
fclose(f);
|
||||
delete[] buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::ExportAllFiles(const char* _rFullPath) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 CFileSystemGCWii::Read32(u64 _Offset) const
|
||||
{
|
||||
u32 Temp = 0;
|
||||
m_rVolume->Read(_Offset, 4, (u8*)&Temp);
|
||||
return Common::swap32(Temp);
|
||||
}
|
||||
|
||||
void CFileSystemGCWii::GetStringFromOffset(u64 _Offset, char* Filename) const
|
||||
{
|
||||
m_rVolume->Read(_Offset, 255, (u8*)Filename);
|
||||
}
|
||||
|
||||
size_t CFileSystemGCWii::GetFileList(std::vector<const SFileInfo *> &_rFilenames) const
|
||||
{
|
||||
if (_rFilenames.size())
|
||||
PanicAlert("GetFileList : input list has contents?");
|
||||
_rFilenames.clear();
|
||||
_rFilenames.reserve(m_FileInfoVector.size());
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
_rFilenames.push_back(&m_FileInfoVector[i]);
|
||||
return m_FileInfoVector.size();
|
||||
}
|
||||
|
||||
const SFileInfo* CFileSystemGCWii::FindFileInfo(const char* _rFullPath) const
|
||||
{
|
||||
for (size_t i = 0; i < m_FileInfoVector.size(); i++)
|
||||
{
|
||||
if (!strcasecmp(m_FileInfoVector[i].m_FullPath, _rFullPath))
|
||||
return &m_FileInfoVector[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::InitFileSystem()
|
||||
{
|
||||
if (Read32(0x18) == 0x5D1C9EA3)
|
||||
{
|
||||
m_OffsetShift = 2; // Wii file system
|
||||
}
|
||||
else if (Read32(0x1c) == 0xC2339F3D)
|
||||
{
|
||||
m_OffsetShift = 0; // GC file system
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the whole FST
|
||||
u64 FSTOffset = (u64)Read32(0x424) << m_OffsetShift;
|
||||
// u32 FSTSize = Read32(0x428);
|
||||
// u32 FSTMaxSize = Read32(0x42C);
|
||||
|
||||
|
||||
// read all fileinfos
|
||||
SFileInfo Root;
|
||||
Root.m_NameOffset = Read32(FSTOffset + 0x0);
|
||||
Root.m_Offset = (u64)Read32(FSTOffset + 0x4) << m_OffsetShift;
|
||||
Root.m_FileSize = Read32(FSTOffset + 0x8);
|
||||
|
||||
if (Root.IsDirectory())
|
||||
{
|
||||
if (m_FileInfoVector.size())
|
||||
PanicAlert("Wtf?");
|
||||
u64 NameTableOffset = FSTOffset;
|
||||
|
||||
m_FileInfoVector.reserve(Root.m_FileSize);
|
||||
for (u32 i = 0; i < Root.m_FileSize; i++)
|
||||
{
|
||||
SFileInfo sfi;
|
||||
u64 Offset = FSTOffset + (i * 0xC);
|
||||
sfi.m_NameOffset = Read32(Offset + 0x0);
|
||||
sfi.m_Offset = (u64)Read32(Offset + 0x4) << m_OffsetShift;
|
||||
sfi.m_FileSize = Read32(Offset + 0x8);
|
||||
|
||||
m_FileInfoVector.push_back(sfi);
|
||||
NameTableOffset += 0xC;
|
||||
}
|
||||
|
||||
BuildFilenames(1, m_FileInfoVector.size(), NULL, NameTableOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Changed this stuff from C++ string to C strings for speed in debug mode. Doesn't matter in release, but
|
||||
// std::string is SLOW in debug mode.
|
||||
size_t CFileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const char* _szDirectory, u64 _NameTableOffset)
|
||||
{
|
||||
size_t CurrentIndex = _FirstIndex;
|
||||
|
||||
while (CurrentIndex < _LastIndex)
|
||||
{
|
||||
SFileInfo *rFileInfo = &m_FileInfoVector[CurrentIndex];
|
||||
u64 uOffset = _NameTableOffset + (rFileInfo->m_NameOffset & 0xFFFFFF);
|
||||
char filename[512];
|
||||
memset(filename, 0, sizeof(filename));
|
||||
GetStringFromOffset(uOffset, filename);
|
||||
|
||||
// check next index
|
||||
if (rFileInfo->IsDirectory())
|
||||
{
|
||||
// this is a directory, build up the new szDirectory
|
||||
if (_szDirectory != NULL)
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s%s\\", _szDirectory, filename);
|
||||
else
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s\\", filename);
|
||||
|
||||
CurrentIndex = BuildFilenames(CurrentIndex + 1, rFileInfo->m_FileSize, rFileInfo->m_FullPath, _NameTableOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a filename
|
||||
if (_szDirectory != NULL)
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s%s", _szDirectory, filename);
|
||||
else
|
||||
CharArrayFromFormat(rFileInfo->m_FullPath, "%s", filename);
|
||||
|
||||
CurrentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return CurrentIndex;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,50 +1,50 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Filesystem.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
#include "FileSystemGCWii.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
IFileSystem::IFileSystem(const IVolume *_rVolume)
|
||||
: m_rVolume(_rVolume)
|
||||
{}
|
||||
|
||||
|
||||
IFileSystem::~IFileSystem()
|
||||
{}
|
||||
|
||||
|
||||
IFileSystem* CreateFileSystem(const IVolume* _rVolume)
|
||||
{
|
||||
IFileSystem* pFileSystem = new CFileSystemGCWii(_rVolume);
|
||||
|
||||
if (!pFileSystem)
|
||||
return 0;
|
||||
|
||||
if (!pFileSystem->IsInitialized())
|
||||
{
|
||||
delete pFileSystem;
|
||||
pFileSystem = NULL;
|
||||
}
|
||||
|
||||
return pFileSystem;
|
||||
}
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Filesystem.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
#include "FileSystemGCWii.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
IFileSystem::IFileSystem(const IVolume *_rVolume)
|
||||
: m_rVolume(_rVolume)
|
||||
{}
|
||||
|
||||
|
||||
IFileSystem::~IFileSystem()
|
||||
{}
|
||||
|
||||
|
||||
IFileSystem* CreateFileSystem(const IVolume* _rVolume)
|
||||
{
|
||||
IFileSystem* pFileSystem = new CFileSystemGCWii(_rVolume);
|
||||
|
||||
if (!pFileSystem)
|
||||
return 0;
|
||||
|
||||
if (!pFileSystem->IsInitialized())
|
||||
{
|
||||
delete pFileSystem;
|
||||
pFileSystem = NULL;
|
||||
}
|
||||
|
||||
return pFileSystem;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -1,262 +1,262 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "AES/aes.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
|
||||
#include "Volume.h"
|
||||
#include "VolumeDirectory.h"
|
||||
#include "VolumeGC.h"
|
||||
#include "VolumeWiiCrypted.h"
|
||||
|
||||
#include "Hash.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
enum EDiscType
|
||||
{
|
||||
DISC_TYPE_UNK,
|
||||
DISC_TYPE_WII,
|
||||
DISC_TYPE_WII_CONTAINER,
|
||||
DISC_TYPE_GC
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
struct SPartition
|
||||
{
|
||||
u64 Offset;
|
||||
u32 Type;
|
||||
}; //gcc 4.3 cries if it's local
|
||||
#endif
|
||||
|
||||
class CBlobBigEndianReader
|
||||
{
|
||||
public:
|
||||
CBlobBigEndianReader(IBlobReader& _rReader) : m_rReader(_rReader) {}
|
||||
|
||||
u32 Read32(u64 _Offset)
|
||||
{
|
||||
u32 Temp;
|
||||
m_rReader.Read(_Offset, 4, (u8*)&Temp);
|
||||
return(Common::swap32(Temp));
|
||||
}
|
||||
|
||||
private:
|
||||
IBlobReader& m_rReader;
|
||||
};
|
||||
|
||||
unsigned char g_MasterKey[16];
|
||||
bool g_MasterKeyInit = false;
|
||||
|
||||
IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _VolumeType);
|
||||
EDiscType GetDiscType(IBlobReader& _rReader);
|
||||
|
||||
IVolume* CreateVolumeFromFilename(const std::string& _rFilename)
|
||||
{
|
||||
IBlobReader* pReader = CreateBlobReader(_rFilename.c_str());
|
||||
|
||||
if (pReader == NULL)
|
||||
return NULL;
|
||||
|
||||
switch (GetDiscType(*pReader))
|
||||
{
|
||||
case DISC_TYPE_WII:
|
||||
case DISC_TYPE_GC:
|
||||
return new CVolumeGC(pReader);
|
||||
|
||||
case DISC_TYPE_WII_CONTAINER:
|
||||
{
|
||||
IVolume* pVolume = CreateVolumeFromCryptedWiiImage(*pReader, 0);
|
||||
|
||||
if (pVolume == NULL)
|
||||
{
|
||||
delete pReader;
|
||||
}
|
||||
|
||||
return(pVolume);
|
||||
}
|
||||
break;
|
||||
|
||||
case DISC_TYPE_UNK:
|
||||
default:
|
||||
delete pReader;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// unreachable code
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IVolume* CreateVolumeFromDirectory(const std::string& _rDirectory, bool _bIsWii)
|
||||
{
|
||||
if (CVolumeDirectory::IsValidDirectory(_rDirectory))
|
||||
return new CVolumeDirectory(_rDirectory, _bIsWii);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IsVolumeWiiDisc(const IVolume *_rVolume)
|
||||
{
|
||||
u32 MagicWord = 0;
|
||||
_rVolume->Read(0x18, 4, (u8*)&MagicWord);
|
||||
|
||||
return (Common::swap32(MagicWord) == 0x5D1C9EA3);
|
||||
}
|
||||
|
||||
IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _VolumeType)
|
||||
{
|
||||
if (!g_MasterKeyInit)
|
||||
{
|
||||
FILE* pT = fopen(WII_MASTERKEY_FILE, "rb");
|
||||
if (pT == NULL)
|
||||
{
|
||||
if(PanicYesNo("Can't open '" WII_MASTERKEY_FILE "'.\n If you know the key, now it's the time to paste it into '"
|
||||
WII_MASTERKEY_FILE_HEX "' before pressing [YES]."))
|
||||
{
|
||||
pT = fopen(WII_MASTERKEY_FILE_HEX, "r");
|
||||
if(pT==NULL){
|
||||
PanicAlert("could not open " WII_MASTERKEY_FILE_HEX );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char hexkey[32];
|
||||
if(fread(hexkey,1,32,pT)<32)
|
||||
{
|
||||
PanicAlert(WII_MASTERKEY_FILE_HEX " is not the right size" );
|
||||
fclose(pT);
|
||||
return NULL;
|
||||
}
|
||||
fclose(pT);
|
||||
|
||||
static char binkey[16];
|
||||
char *t=hexkey;
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
char h[3]={*(t++),*(t++),0};
|
||||
binkey[i] = strtol(h,NULL,16);
|
||||
}
|
||||
|
||||
pT = fopen(WII_MASTERKEY_FILE, "wb");
|
||||
if(pT==NULL){
|
||||
PanicAlert("could not open/make '" WII_MASTERKEY_FILE "' for writing!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fwrite(binkey,16,1,pT);
|
||||
fclose(pT);
|
||||
|
||||
pT = fopen(WII_MASTERKEY_FILE, "rb");
|
||||
if(pT==NULL){
|
||||
PanicAlert("could not open '" WII_MASTERKEY_FILE "' for reading!\n did the file get deleted or locked after converting?");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fread(g_MasterKey, 16, 1, pT);
|
||||
fclose(pT);
|
||||
const u32 keyhash = 0x4bc30936;
|
||||
u32 hash = HashAdler32(g_MasterKey, 16);
|
||||
if (hash != keyhash)
|
||||
PanicAlert("Your Wii disc decryption key is bad.", keyhash, hash);
|
||||
else
|
||||
g_MasterKeyInit = true;
|
||||
}
|
||||
|
||||
CBlobBigEndianReader Reader(_rReader);
|
||||
|
||||
u32 numPartitions = Reader.Read32(0x40000);
|
||||
u64 PartitionsOffset = (u64)Reader.Read32(0x40004) << 2;
|
||||
#ifdef _WIN32
|
||||
struct SPartition
|
||||
{
|
||||
u64 Offset;
|
||||
u32 Type;
|
||||
};
|
||||
#endif
|
||||
std::vector<SPartition> PartitionsVec;
|
||||
|
||||
// read all partitions
|
||||
for (u32 i = 0; i < numPartitions; i++)
|
||||
{
|
||||
SPartition Partition;
|
||||
Partition.Offset = ((u64)Reader.Read32(PartitionsOffset + (i * 8) + 0)) << 2;
|
||||
Partition.Type = Reader.Read32(PartitionsOffset + (i * 8) + 4);
|
||||
PartitionsVec.push_back(Partition);
|
||||
}
|
||||
|
||||
// find the partition with the game... type == 1 is prolly the firmware update partition
|
||||
for (size_t i = 0; i < PartitionsVec.size(); i++)
|
||||
{
|
||||
const SPartition& rPartition = PartitionsVec[i];
|
||||
|
||||
if (rPartition.Type == _VolumeType)
|
||||
{
|
||||
u8 SubKey[16];
|
||||
_rReader.Read(rPartition.Offset + 0x1bf, 16, SubKey);
|
||||
|
||||
u8 IV[16];
|
||||
memset(IV, 0, 16);
|
||||
_rReader.Read(rPartition.Offset + 0x44c, 8, IV);
|
||||
|
||||
AES_KEY AES_KEY;
|
||||
AES_set_decrypt_key(g_MasterKey, 128, &AES_KEY);
|
||||
|
||||
u8 VolumeKey[16];
|
||||
AES_cbc_encrypt(SubKey, VolumeKey, 16, &AES_KEY, IV, AES_DECRYPT);
|
||||
|
||||
return new CVolumeWiiCrypted(&_rReader, rPartition.Offset + 0x20000, VolumeKey);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EDiscType GetDiscType(IBlobReader& _rReader)
|
||||
{
|
||||
CBlobBigEndianReader Reader(_rReader);
|
||||
|
||||
// check for wii
|
||||
{
|
||||
u32 MagicWord = Reader.Read32(0x18);
|
||||
|
||||
if (MagicWord == 0x5D1C9EA3)
|
||||
{
|
||||
if (Reader.Read32(0x60) != 0)
|
||||
return(DISC_TYPE_WII);
|
||||
else
|
||||
return(DISC_TYPE_WII_CONTAINER);
|
||||
}
|
||||
}
|
||||
|
||||
// check for GC
|
||||
{
|
||||
u32 MagicWord = Reader.Read32(0x1C);
|
||||
|
||||
if (MagicWord == 0xC2339F3D)
|
||||
return(DISC_TYPE_GC);
|
||||
}
|
||||
|
||||
return DISC_TYPE_UNK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "AES/aes.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
|
||||
#include "Volume.h"
|
||||
#include "VolumeDirectory.h"
|
||||
#include "VolumeGC.h"
|
||||
#include "VolumeWiiCrypted.h"
|
||||
|
||||
#include "Hash.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
enum EDiscType
|
||||
{
|
||||
DISC_TYPE_UNK,
|
||||
DISC_TYPE_WII,
|
||||
DISC_TYPE_WII_CONTAINER,
|
||||
DISC_TYPE_GC
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
struct SPartition
|
||||
{
|
||||
u64 Offset;
|
||||
u32 Type;
|
||||
}; //gcc 4.3 cries if it's local
|
||||
#endif
|
||||
|
||||
class CBlobBigEndianReader
|
||||
{
|
||||
public:
|
||||
CBlobBigEndianReader(IBlobReader& _rReader) : m_rReader(_rReader) {}
|
||||
|
||||
u32 Read32(u64 _Offset)
|
||||
{
|
||||
u32 Temp;
|
||||
m_rReader.Read(_Offset, 4, (u8*)&Temp);
|
||||
return(Common::swap32(Temp));
|
||||
}
|
||||
|
||||
private:
|
||||
IBlobReader& m_rReader;
|
||||
};
|
||||
|
||||
unsigned char g_MasterKey[16];
|
||||
bool g_MasterKeyInit = false;
|
||||
|
||||
IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _VolumeType);
|
||||
EDiscType GetDiscType(IBlobReader& _rReader);
|
||||
|
||||
IVolume* CreateVolumeFromFilename(const std::string& _rFilename)
|
||||
{
|
||||
IBlobReader* pReader = CreateBlobReader(_rFilename.c_str());
|
||||
|
||||
if (pReader == NULL)
|
||||
return NULL;
|
||||
|
||||
switch (GetDiscType(*pReader))
|
||||
{
|
||||
case DISC_TYPE_WII:
|
||||
case DISC_TYPE_GC:
|
||||
return new CVolumeGC(pReader);
|
||||
|
||||
case DISC_TYPE_WII_CONTAINER:
|
||||
{
|
||||
IVolume* pVolume = CreateVolumeFromCryptedWiiImage(*pReader, 0);
|
||||
|
||||
if (pVolume == NULL)
|
||||
{
|
||||
delete pReader;
|
||||
}
|
||||
|
||||
return(pVolume);
|
||||
}
|
||||
break;
|
||||
|
||||
case DISC_TYPE_UNK:
|
||||
default:
|
||||
delete pReader;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// unreachable code
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IVolume* CreateVolumeFromDirectory(const std::string& _rDirectory, bool _bIsWii)
|
||||
{
|
||||
if (CVolumeDirectory::IsValidDirectory(_rDirectory))
|
||||
return new CVolumeDirectory(_rDirectory, _bIsWii);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IsVolumeWiiDisc(const IVolume *_rVolume)
|
||||
{
|
||||
u32 MagicWord = 0;
|
||||
_rVolume->Read(0x18, 4, (u8*)&MagicWord);
|
||||
|
||||
return (Common::swap32(MagicWord) == 0x5D1C9EA3);
|
||||
}
|
||||
|
||||
IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _VolumeType)
|
||||
{
|
||||
if (!g_MasterKeyInit)
|
||||
{
|
||||
FILE* pT = fopen(WII_MASTERKEY_FILE, "rb");
|
||||
if (pT == NULL)
|
||||
{
|
||||
if(PanicYesNo("Can't open '" WII_MASTERKEY_FILE "'.\n If you know the key, now it's the time to paste it into '"
|
||||
WII_MASTERKEY_FILE_HEX "' before pressing [YES]."))
|
||||
{
|
||||
pT = fopen(WII_MASTERKEY_FILE_HEX, "r");
|
||||
if(pT==NULL){
|
||||
PanicAlert("could not open " WII_MASTERKEY_FILE_HEX );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char hexkey[32];
|
||||
if(fread(hexkey,1,32,pT)<32)
|
||||
{
|
||||
PanicAlert(WII_MASTERKEY_FILE_HEX " is not the right size" );
|
||||
fclose(pT);
|
||||
return NULL;
|
||||
}
|
||||
fclose(pT);
|
||||
|
||||
static char binkey[16];
|
||||
char *t=hexkey;
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
char h[3]={*(t++),*(t++),0};
|
||||
binkey[i] = strtol(h,NULL,16);
|
||||
}
|
||||
|
||||
pT = fopen(WII_MASTERKEY_FILE, "wb");
|
||||
if(pT==NULL){
|
||||
PanicAlert("could not open/make '" WII_MASTERKEY_FILE "' for writing!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fwrite(binkey,16,1,pT);
|
||||
fclose(pT);
|
||||
|
||||
pT = fopen(WII_MASTERKEY_FILE, "rb");
|
||||
if(pT==NULL){
|
||||
PanicAlert("could not open '" WII_MASTERKEY_FILE "' for reading!\n did the file get deleted or locked after converting?");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fread(g_MasterKey, 16, 1, pT);
|
||||
fclose(pT);
|
||||
const u32 keyhash = 0x4bc30936;
|
||||
u32 hash = HashAdler32(g_MasterKey, 16);
|
||||
if (hash != keyhash)
|
||||
PanicAlert("Your Wii disc decryption key is bad.", keyhash, hash);
|
||||
else
|
||||
g_MasterKeyInit = true;
|
||||
}
|
||||
|
||||
CBlobBigEndianReader Reader(_rReader);
|
||||
|
||||
u32 numPartitions = Reader.Read32(0x40000);
|
||||
u64 PartitionsOffset = (u64)Reader.Read32(0x40004) << 2;
|
||||
#ifdef _WIN32
|
||||
struct SPartition
|
||||
{
|
||||
u64 Offset;
|
||||
u32 Type;
|
||||
};
|
||||
#endif
|
||||
std::vector<SPartition> PartitionsVec;
|
||||
|
||||
// read all partitions
|
||||
for (u32 i = 0; i < numPartitions; i++)
|
||||
{
|
||||
SPartition Partition;
|
||||
Partition.Offset = ((u64)Reader.Read32(PartitionsOffset + (i * 8) + 0)) << 2;
|
||||
Partition.Type = Reader.Read32(PartitionsOffset + (i * 8) + 4);
|
||||
PartitionsVec.push_back(Partition);
|
||||
}
|
||||
|
||||
// find the partition with the game... type == 1 is prolly the firmware update partition
|
||||
for (size_t i = 0; i < PartitionsVec.size(); i++)
|
||||
{
|
||||
const SPartition& rPartition = PartitionsVec[i];
|
||||
|
||||
if (rPartition.Type == _VolumeType)
|
||||
{
|
||||
u8 SubKey[16];
|
||||
_rReader.Read(rPartition.Offset + 0x1bf, 16, SubKey);
|
||||
|
||||
u8 IV[16];
|
||||
memset(IV, 0, 16);
|
||||
_rReader.Read(rPartition.Offset + 0x44c, 8, IV);
|
||||
|
||||
AES_KEY AES_KEY;
|
||||
AES_set_decrypt_key(g_MasterKey, 128, &AES_KEY);
|
||||
|
||||
u8 VolumeKey[16];
|
||||
AES_cbc_encrypt(SubKey, VolumeKey, 16, &AES_KEY, IV, AES_DECRYPT);
|
||||
|
||||
return new CVolumeWiiCrypted(&_rReader, rPartition.Offset + 0x20000, VolumeKey);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EDiscType GetDiscType(IBlobReader& _rReader)
|
||||
{
|
||||
CBlobBigEndianReader Reader(_rReader);
|
||||
|
||||
// check for wii
|
||||
{
|
||||
u32 MagicWord = Reader.Read32(0x18);
|
||||
|
||||
if (MagicWord == 0x5D1C9EA3)
|
||||
{
|
||||
if (Reader.Read32(0x60) != 0)
|
||||
return(DISC_TYPE_WII);
|
||||
else
|
||||
return(DISC_TYPE_WII_CONTAINER);
|
||||
}
|
||||
}
|
||||
|
||||
// check for GC
|
||||
{
|
||||
u32 MagicWord = Reader.Read32(0x1C);
|
||||
|
||||
if (MagicWord == 0xC2339F3D)
|
||||
return(DISC_TYPE_GC);
|
||||
}
|
||||
|
||||
return DISC_TYPE_UNK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,466 +1,466 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "VolumeDirectory.h"
|
||||
#include "FileBlob.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
static const u8 ENTRY_SIZE = 0x0c;
|
||||
static const u8 FILE_ENTRY = 0;
|
||||
static const u8 DIRECTORY_ENTRY = 1;
|
||||
static const u64 FST_ADDRESS = 0x440;
|
||||
static const u32 MAX_NAME_LENGTH = 0x3df;
|
||||
|
||||
CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii)
|
||||
: m_totalNameSize(0)
|
||||
, m_dataStartAddress(-1)
|
||||
, m_fstSize(0)
|
||||
, m_FSTData(NULL)
|
||||
{
|
||||
m_rootDirectory = ExtractDirectoryName(_rDirectory);
|
||||
|
||||
// create the default disk header
|
||||
m_diskHeader = new u8[FST_ADDRESS];
|
||||
memset(m_diskHeader, 0, (size_t)FST_ADDRESS);
|
||||
SetUniqueID("RZDE01");
|
||||
SetName("Default name");
|
||||
|
||||
if(_bIsWii)
|
||||
{
|
||||
SetDiskTypeWii();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDiskTypeGC();
|
||||
}
|
||||
|
||||
BuildFST();
|
||||
}
|
||||
|
||||
CVolumeDirectory::~CVolumeDirectory()
|
||||
{
|
||||
delete m_FSTData;
|
||||
m_FSTData = NULL;
|
||||
|
||||
delete m_diskHeader;
|
||||
m_diskHeader = NULL;
|
||||
}
|
||||
|
||||
bool CVolumeDirectory::IsValidDirectory(const std::string& _rDirectory)
|
||||
{
|
||||
std::string directoryName = ExtractDirectoryName(_rDirectory);
|
||||
return File::IsDirectory(directoryName.c_str());
|
||||
}
|
||||
|
||||
bool CVolumeDirectory::Read(u64 _Offset, u64 _Length, u8* _pBuffer) const
|
||||
{
|
||||
if(_Offset < FST_ADDRESS)
|
||||
{
|
||||
WriteToBuffer(0, FST_ADDRESS, m_diskHeader, _Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
if(_Offset < m_dataStartAddress)
|
||||
{
|
||||
WriteToBuffer(FST_ADDRESS, m_fstSize, m_FSTData, _Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
if(m_virtualDisk.size() == 0)
|
||||
return true;
|
||||
|
||||
// Determine which file the offset refers to
|
||||
std::map<u64, std::string>::const_iterator fileIter = m_virtualDisk.lower_bound(_Offset);
|
||||
if(fileIter->first > _Offset && fileIter != m_virtualDisk.begin())
|
||||
--fileIter;
|
||||
|
||||
// zero fill to start of file data
|
||||
PadToAddress(fileIter->first, _Offset, _Length, _pBuffer);
|
||||
|
||||
while(fileIter != m_virtualDisk.end() && _Length > 0)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, fileIter->first <= _Offset);
|
||||
u64 fileOffset = _Offset - fileIter->first;
|
||||
|
||||
PlainFileReader* reader = PlainFileReader::Create(fileIter->second.c_str());
|
||||
if(reader == NULL)
|
||||
return false;
|
||||
|
||||
u64 fileSize = reader->GetDataSize();
|
||||
|
||||
if(fileOffset < fileSize)
|
||||
{
|
||||
u64 fileBytes = fileSize - fileOffset;
|
||||
if(_Length < fileBytes)
|
||||
fileBytes = _Length;
|
||||
|
||||
if(!reader->Read(fileOffset, fileBytes, _pBuffer))
|
||||
return false;
|
||||
|
||||
_Length -= fileBytes;
|
||||
_pBuffer += fileBytes;
|
||||
_Offset += fileBytes;
|
||||
}
|
||||
|
||||
++fileIter;
|
||||
|
||||
if(fileIter != m_virtualDisk.end())
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, fileIter->first >= _Offset);
|
||||
PadToAddress(fileIter->first, _Offset, _Length, _pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetUniqueID() const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
char buffer[7];
|
||||
memcpy(buffer, m_diskHeader, 6);
|
||||
buffer[6] = 0;
|
||||
|
||||
std::string id = buffer;
|
||||
return id;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetUniqueID(std::string _ID)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
u32 length = _ID.length();
|
||||
if(length > 6)
|
||||
length = 6;
|
||||
|
||||
memcpy(m_diskHeader, _ID.c_str(), length);
|
||||
}
|
||||
|
||||
IVolume::ECountry CVolumeDirectory::GetCountry() const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
u8 CountryCode = m_diskHeader[3];
|
||||
|
||||
ECountry country = COUNTRY_UNKNOWN;
|
||||
|
||||
switch (CountryCode)
|
||||
{
|
||||
case 'S':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL <- that is shitty :) zelda demo disc
|
||||
|
||||
case 'P':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'D':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'F':
|
||||
country = COUNTRY_FRANCE;
|
||||
break; // PAL
|
||||
|
||||
case 'X':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // XIII <- uses X but is PAL rip
|
||||
|
||||
case 'E':
|
||||
country = COUNTRY_USA;
|
||||
break; // USA
|
||||
|
||||
case 'J':
|
||||
country = COUNTRY_JAP;
|
||||
break; // JAP
|
||||
|
||||
case 'O':
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break; // SDK
|
||||
|
||||
default:
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return(country);
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetMakerID() const
|
||||
{
|
||||
return "VOID";
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetName() const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
std::string name = (char*)(m_diskHeader + 0x20);
|
||||
return name;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetName(std::string _Name)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
u32 length = _Name.length();
|
||||
if(length > MAX_NAME_LENGTH)
|
||||
length = MAX_NAME_LENGTH;
|
||||
|
||||
memcpy(m_diskHeader + 0x20, _Name.c_str(), length);
|
||||
m_diskHeader[length + 0x20] = 0;
|
||||
}
|
||||
|
||||
u32 CVolumeDirectory::GetFSTSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetApploaderDate() const
|
||||
{
|
||||
return "VOID";
|
||||
}
|
||||
|
||||
u64 CVolumeDirectory::GetSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char DIR_SEPARATOR =
|
||||
#ifdef _WIN32
|
||||
'\\';
|
||||
#else
|
||||
'/';
|
||||
#endif
|
||||
|
||||
std::string CVolumeDirectory::ExtractDirectoryName(const std::string& _rDirectory)
|
||||
{
|
||||
std::string directoryName = _rDirectory;
|
||||
|
||||
size_t lastSep = directoryName.find_last_of(DIR_SEPARATOR);
|
||||
|
||||
if(lastSep != directoryName.size() - 1)
|
||||
{
|
||||
// TODO: This assumes that file names will always have a dot in them
|
||||
// and directory names never will; both assumptions are often
|
||||
// right but in general wrong.
|
||||
size_t extensionStart = directoryName.find_last_of('.');
|
||||
if(extensionStart != std::string::npos && extensionStart > lastSep)
|
||||
{
|
||||
directoryName.resize(lastSep);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryName.resize(lastSep);
|
||||
}
|
||||
|
||||
return directoryName;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetDiskTypeWii()
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
m_diskHeader[0x18] = 0x5d;
|
||||
m_diskHeader[0x19] = 0x1c;
|
||||
m_diskHeader[0x1a] = 0x9e;
|
||||
m_diskHeader[0x1b] = 0xa3;
|
||||
memset(m_diskHeader + 0x1c, 0, 4);
|
||||
|
||||
m_addressShift = 2;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetDiskTypeGC()
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
memset(m_diskHeader + 0x18, 0, 4);
|
||||
m_diskHeader[0x1c] = 0xc2;
|
||||
m_diskHeader[0x1d] = 0x33;
|
||||
m_diskHeader[0x1e] = 0x9f;
|
||||
m_diskHeader[0x1f] = 0x3d;
|
||||
|
||||
m_addressShift = 0;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::BuildFST()
|
||||
{
|
||||
if(m_FSTData)
|
||||
{
|
||||
delete m_FSTData;
|
||||
}
|
||||
|
||||
File::FSTEntry rootEntry;
|
||||
|
||||
// read data from physical disk to rootEntry
|
||||
u32 totalEntries = AddDirectoryEntries(m_rootDirectory, rootEntry) + 1;
|
||||
|
||||
m_fstNameOffset = totalEntries * ENTRY_SIZE; // offset in FST nameTable
|
||||
m_fstSize = m_fstNameOffset + m_totalNameSize;
|
||||
m_FSTData = new u8[(u32)m_fstSize];
|
||||
|
||||
// 4 byte aligned start of data on disk
|
||||
m_dataStartAddress = (FST_ADDRESS + m_fstSize + 3) & ~3;
|
||||
u64 curDataAddress = m_dataStartAddress;
|
||||
|
||||
u32 fstOffset = 0; // offset within FST data
|
||||
u32 nameOffset = 0; // offset within name table
|
||||
u32 rootOffset = 0; // offset of root of FST
|
||||
|
||||
// write root entry
|
||||
WriteEntryData(fstOffset, DIRECTORY_ENTRY, 0, 0, totalEntries);
|
||||
|
||||
for(std::vector<File::FSTEntry>::iterator iter = rootEntry.children.begin(); iter != rootEntry.children.end(); ++iter)
|
||||
{
|
||||
WriteEntry(*iter, fstOffset, nameOffset, curDataAddress, rootOffset);
|
||||
}
|
||||
|
||||
// overflow check
|
||||
_dbg_assert_(DVDINTERFACE, nameOffset == m_fstSize);
|
||||
|
||||
// write FST size and location
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x0428, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x042c, m_diskHeader);
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, u8* _Src,
|
||||
u64& _Address, u64& _Length, u8*& _pBuffer) const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, _Address >= _SrcStartAddress);
|
||||
|
||||
u64 srcOffset = _Address - _SrcStartAddress;
|
||||
|
||||
if(srcOffset < _SrcLength)
|
||||
{
|
||||
u64 srcBytes = _SrcLength - srcOffset;
|
||||
if(_Length < srcBytes)
|
||||
srcBytes = _Length;
|
||||
|
||||
memcpy(_pBuffer, _Src + srcOffset, (size_t)srcBytes);
|
||||
|
||||
_Length -= srcBytes;
|
||||
_pBuffer += srcBytes;
|
||||
_Address += srcBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void CVolumeDirectory::PadToAddress(u64 _StartAddress, u64& _Address, u64& _Length, u8*& _pBuffer) const
|
||||
{
|
||||
if(_StartAddress <= _Address)
|
||||
return;
|
||||
|
||||
u64 padBytes = _StartAddress - _Address;
|
||||
if(padBytes > _Length)
|
||||
padBytes = _Length;
|
||||
|
||||
if(_Length > 0)
|
||||
{
|
||||
memset(_pBuffer, 0, (size_t)padBytes);
|
||||
_Length -= padBytes;
|
||||
_pBuffer += padBytes;
|
||||
_Address += padBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void CVolumeDirectory::Write32(u32 data, u32 offset, u8* buffer)
|
||||
{
|
||||
buffer[offset++] = (data >> 24);
|
||||
buffer[offset++] = (data >> 16) & 0xff;
|
||||
buffer[offset++] = (data >> 8) & 0xff;
|
||||
buffer[offset] = (data) & 0xff;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u32 length)
|
||||
{
|
||||
m_FSTData[entryOffset++] = type;
|
||||
|
||||
m_FSTData[entryOffset++] = (nameOffset >> 16) & 0xff;
|
||||
m_FSTData[entryOffset++] = (nameOffset >> 8) & 0xff;
|
||||
m_FSTData[entryOffset++] = (nameOffset) & 0xff;
|
||||
|
||||
Write32((u32)(dataOffset >> m_addressShift), entryOffset, m_FSTData);
|
||||
entryOffset += 4;
|
||||
|
||||
Write32((u32)length, entryOffset, m_FSTData);
|
||||
entryOffset += 4;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteEntryName(u32& nameOffset, const std::string& name)
|
||||
{
|
||||
strncpy((char*)(m_FSTData + nameOffset + m_fstNameOffset), name.c_str(), name.length() + 1);
|
||||
|
||||
nameOffset += (name.length() + 1);
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, u64& dataOffset, u32 parentEntryNum)
|
||||
{
|
||||
if(entry.isDirectory)
|
||||
{
|
||||
u32 myOffset = fstOffset;
|
||||
u32 myEntryNum = myOffset / ENTRY_SIZE;
|
||||
WriteEntryData(fstOffset, DIRECTORY_ENTRY, nameOffset, parentEntryNum, myEntryNum + entry.size + 1);
|
||||
WriteEntryName(nameOffset, entry.virtualName);
|
||||
|
||||
for(std::vector<File::FSTEntry>::const_iterator iter = entry.children.begin(); iter != entry.children.end(); ++iter)
|
||||
{
|
||||
WriteEntry(*iter, fstOffset, nameOffset, dataOffset, myEntryNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// put entry in FST
|
||||
WriteEntryData(fstOffset, FILE_ENTRY, nameOffset, dataOffset, entry.size);
|
||||
WriteEntryName(nameOffset, entry.virtualName);
|
||||
|
||||
// write entry to virtual disk
|
||||
_dbg_assert_(DVDINTERFACE, m_virtualDisk.find(dataOffset) == m_virtualDisk.end());
|
||||
m_virtualDisk.insert(make_pair(dataOffset, entry.physicalName));
|
||||
|
||||
// 4 byte aligned
|
||||
dataOffset = (dataOffset + entry.size + 3) & ~3ULL;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ComputeNameSize(const File::FSTEntry& parentEntry)
|
||||
{
|
||||
u32 nameSize = 0;
|
||||
const std::vector<File::FSTEntry>& children = parentEntry.children;
|
||||
for (std::vector<File::FSTEntry>::const_iterator it = children.begin();
|
||||
it != children.end(); ++it)
|
||||
{
|
||||
const File::FSTEntry& entry = *it;
|
||||
if (entry.isDirectory)
|
||||
{
|
||||
nameSize += ComputeNameSize(entry);
|
||||
}
|
||||
nameSize += entry.virtualName.length() + 1;
|
||||
}
|
||||
return nameSize;
|
||||
}
|
||||
|
||||
u32 CVolumeDirectory::AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry)
|
||||
{
|
||||
u32 foundEntries = ScanDirectoryTree(_Directory, parentEntry);
|
||||
m_totalNameSize += ComputeNameSize(parentEntry);
|
||||
return foundEntries;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "VolumeDirectory.h"
|
||||
#include "FileBlob.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
static const u8 ENTRY_SIZE = 0x0c;
|
||||
static const u8 FILE_ENTRY = 0;
|
||||
static const u8 DIRECTORY_ENTRY = 1;
|
||||
static const u64 FST_ADDRESS = 0x440;
|
||||
static const u32 MAX_NAME_LENGTH = 0x3df;
|
||||
|
||||
CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii)
|
||||
: m_totalNameSize(0)
|
||||
, m_dataStartAddress(-1)
|
||||
, m_fstSize(0)
|
||||
, m_FSTData(NULL)
|
||||
{
|
||||
m_rootDirectory = ExtractDirectoryName(_rDirectory);
|
||||
|
||||
// create the default disk header
|
||||
m_diskHeader = new u8[FST_ADDRESS];
|
||||
memset(m_diskHeader, 0, (size_t)FST_ADDRESS);
|
||||
SetUniqueID("RZDE01");
|
||||
SetName("Default name");
|
||||
|
||||
if(_bIsWii)
|
||||
{
|
||||
SetDiskTypeWii();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDiskTypeGC();
|
||||
}
|
||||
|
||||
BuildFST();
|
||||
}
|
||||
|
||||
CVolumeDirectory::~CVolumeDirectory()
|
||||
{
|
||||
delete m_FSTData;
|
||||
m_FSTData = NULL;
|
||||
|
||||
delete m_diskHeader;
|
||||
m_diskHeader = NULL;
|
||||
}
|
||||
|
||||
bool CVolumeDirectory::IsValidDirectory(const std::string& _rDirectory)
|
||||
{
|
||||
std::string directoryName = ExtractDirectoryName(_rDirectory);
|
||||
return File::IsDirectory(directoryName.c_str());
|
||||
}
|
||||
|
||||
bool CVolumeDirectory::Read(u64 _Offset, u64 _Length, u8* _pBuffer) const
|
||||
{
|
||||
if(_Offset < FST_ADDRESS)
|
||||
{
|
||||
WriteToBuffer(0, FST_ADDRESS, m_diskHeader, _Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
if(_Offset < m_dataStartAddress)
|
||||
{
|
||||
WriteToBuffer(FST_ADDRESS, m_fstSize, m_FSTData, _Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
if(m_virtualDisk.size() == 0)
|
||||
return true;
|
||||
|
||||
// Determine which file the offset refers to
|
||||
std::map<u64, std::string>::const_iterator fileIter = m_virtualDisk.lower_bound(_Offset);
|
||||
if(fileIter->first > _Offset && fileIter != m_virtualDisk.begin())
|
||||
--fileIter;
|
||||
|
||||
// zero fill to start of file data
|
||||
PadToAddress(fileIter->first, _Offset, _Length, _pBuffer);
|
||||
|
||||
while(fileIter != m_virtualDisk.end() && _Length > 0)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, fileIter->first <= _Offset);
|
||||
u64 fileOffset = _Offset - fileIter->first;
|
||||
|
||||
PlainFileReader* reader = PlainFileReader::Create(fileIter->second.c_str());
|
||||
if(reader == NULL)
|
||||
return false;
|
||||
|
||||
u64 fileSize = reader->GetDataSize();
|
||||
|
||||
if(fileOffset < fileSize)
|
||||
{
|
||||
u64 fileBytes = fileSize - fileOffset;
|
||||
if(_Length < fileBytes)
|
||||
fileBytes = _Length;
|
||||
|
||||
if(!reader->Read(fileOffset, fileBytes, _pBuffer))
|
||||
return false;
|
||||
|
||||
_Length -= fileBytes;
|
||||
_pBuffer += fileBytes;
|
||||
_Offset += fileBytes;
|
||||
}
|
||||
|
||||
++fileIter;
|
||||
|
||||
if(fileIter != m_virtualDisk.end())
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, fileIter->first >= _Offset);
|
||||
PadToAddress(fileIter->first, _Offset, _Length, _pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetUniqueID() const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
char buffer[7];
|
||||
memcpy(buffer, m_diskHeader, 6);
|
||||
buffer[6] = 0;
|
||||
|
||||
std::string id = buffer;
|
||||
return id;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetUniqueID(std::string _ID)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
u32 length = _ID.length();
|
||||
if(length > 6)
|
||||
length = 6;
|
||||
|
||||
memcpy(m_diskHeader, _ID.c_str(), length);
|
||||
}
|
||||
|
||||
IVolume::ECountry CVolumeDirectory::GetCountry() const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
u8 CountryCode = m_diskHeader[3];
|
||||
|
||||
ECountry country = COUNTRY_UNKNOWN;
|
||||
|
||||
switch (CountryCode)
|
||||
{
|
||||
case 'S':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL <- that is shitty :) zelda demo disc
|
||||
|
||||
case 'P':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'D':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'F':
|
||||
country = COUNTRY_FRANCE;
|
||||
break; // PAL
|
||||
|
||||
case 'X':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // XIII <- uses X but is PAL rip
|
||||
|
||||
case 'E':
|
||||
country = COUNTRY_USA;
|
||||
break; // USA
|
||||
|
||||
case 'J':
|
||||
country = COUNTRY_JAP;
|
||||
break; // JAP
|
||||
|
||||
case 'O':
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break; // SDK
|
||||
|
||||
default:
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return(country);
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetMakerID() const
|
||||
{
|
||||
return "VOID";
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetName() const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
std::string name = (char*)(m_diskHeader + 0x20);
|
||||
return name;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetName(std::string _Name)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
u32 length = _Name.length();
|
||||
if(length > MAX_NAME_LENGTH)
|
||||
length = MAX_NAME_LENGTH;
|
||||
|
||||
memcpy(m_diskHeader + 0x20, _Name.c_str(), length);
|
||||
m_diskHeader[length + 0x20] = 0;
|
||||
}
|
||||
|
||||
u32 CVolumeDirectory::GetFSTSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string CVolumeDirectory::GetApploaderDate() const
|
||||
{
|
||||
return "VOID";
|
||||
}
|
||||
|
||||
u64 CVolumeDirectory::GetSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char DIR_SEPARATOR =
|
||||
#ifdef _WIN32
|
||||
'\\';
|
||||
#else
|
||||
'/';
|
||||
#endif
|
||||
|
||||
std::string CVolumeDirectory::ExtractDirectoryName(const std::string& _rDirectory)
|
||||
{
|
||||
std::string directoryName = _rDirectory;
|
||||
|
||||
size_t lastSep = directoryName.find_last_of(DIR_SEPARATOR);
|
||||
|
||||
if(lastSep != directoryName.size() - 1)
|
||||
{
|
||||
// TODO: This assumes that file names will always have a dot in them
|
||||
// and directory names never will; both assumptions are often
|
||||
// right but in general wrong.
|
||||
size_t extensionStart = directoryName.find_last_of('.');
|
||||
if(extensionStart != std::string::npos && extensionStart > lastSep)
|
||||
{
|
||||
directoryName.resize(lastSep);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryName.resize(lastSep);
|
||||
}
|
||||
|
||||
return directoryName;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetDiskTypeWii()
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
m_diskHeader[0x18] = 0x5d;
|
||||
m_diskHeader[0x19] = 0x1c;
|
||||
m_diskHeader[0x1a] = 0x9e;
|
||||
m_diskHeader[0x1b] = 0xa3;
|
||||
memset(m_diskHeader + 0x1c, 0, 4);
|
||||
|
||||
m_addressShift = 2;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::SetDiskTypeGC()
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
|
||||
memset(m_diskHeader + 0x18, 0, 4);
|
||||
m_diskHeader[0x1c] = 0xc2;
|
||||
m_diskHeader[0x1d] = 0x33;
|
||||
m_diskHeader[0x1e] = 0x9f;
|
||||
m_diskHeader[0x1f] = 0x3d;
|
||||
|
||||
m_addressShift = 0;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::BuildFST()
|
||||
{
|
||||
if(m_FSTData)
|
||||
{
|
||||
delete m_FSTData;
|
||||
}
|
||||
|
||||
File::FSTEntry rootEntry;
|
||||
|
||||
// read data from physical disk to rootEntry
|
||||
u32 totalEntries = AddDirectoryEntries(m_rootDirectory, rootEntry) + 1;
|
||||
|
||||
m_fstNameOffset = totalEntries * ENTRY_SIZE; // offset in FST nameTable
|
||||
m_fstSize = m_fstNameOffset + m_totalNameSize;
|
||||
m_FSTData = new u8[(u32)m_fstSize];
|
||||
|
||||
// 4 byte aligned start of data on disk
|
||||
m_dataStartAddress = (FST_ADDRESS + m_fstSize + 3) & ~3;
|
||||
u64 curDataAddress = m_dataStartAddress;
|
||||
|
||||
u32 fstOffset = 0; // offset within FST data
|
||||
u32 nameOffset = 0; // offset within name table
|
||||
u32 rootOffset = 0; // offset of root of FST
|
||||
|
||||
// write root entry
|
||||
WriteEntryData(fstOffset, DIRECTORY_ENTRY, 0, 0, totalEntries);
|
||||
|
||||
for(std::vector<File::FSTEntry>::iterator iter = rootEntry.children.begin(); iter != rootEntry.children.end(); ++iter)
|
||||
{
|
||||
WriteEntry(*iter, fstOffset, nameOffset, curDataAddress, rootOffset);
|
||||
}
|
||||
|
||||
// overflow check
|
||||
_dbg_assert_(DVDINTERFACE, nameOffset == m_fstSize);
|
||||
|
||||
// write FST size and location
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x0428, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x042c, m_diskHeader);
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, u8* _Src,
|
||||
u64& _Address, u64& _Length, u8*& _pBuffer) const
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, _Address >= _SrcStartAddress);
|
||||
|
||||
u64 srcOffset = _Address - _SrcStartAddress;
|
||||
|
||||
if(srcOffset < _SrcLength)
|
||||
{
|
||||
u64 srcBytes = _SrcLength - srcOffset;
|
||||
if(_Length < srcBytes)
|
||||
srcBytes = _Length;
|
||||
|
||||
memcpy(_pBuffer, _Src + srcOffset, (size_t)srcBytes);
|
||||
|
||||
_Length -= srcBytes;
|
||||
_pBuffer += srcBytes;
|
||||
_Address += srcBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void CVolumeDirectory::PadToAddress(u64 _StartAddress, u64& _Address, u64& _Length, u8*& _pBuffer) const
|
||||
{
|
||||
if(_StartAddress <= _Address)
|
||||
return;
|
||||
|
||||
u64 padBytes = _StartAddress - _Address;
|
||||
if(padBytes > _Length)
|
||||
padBytes = _Length;
|
||||
|
||||
if(_Length > 0)
|
||||
{
|
||||
memset(_pBuffer, 0, (size_t)padBytes);
|
||||
_Length -= padBytes;
|
||||
_pBuffer += padBytes;
|
||||
_Address += padBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void CVolumeDirectory::Write32(u32 data, u32 offset, u8* buffer)
|
||||
{
|
||||
buffer[offset++] = (data >> 24);
|
||||
buffer[offset++] = (data >> 16) & 0xff;
|
||||
buffer[offset++] = (data >> 8) & 0xff;
|
||||
buffer[offset] = (data) & 0xff;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u32 length)
|
||||
{
|
||||
m_FSTData[entryOffset++] = type;
|
||||
|
||||
m_FSTData[entryOffset++] = (nameOffset >> 16) & 0xff;
|
||||
m_FSTData[entryOffset++] = (nameOffset >> 8) & 0xff;
|
||||
m_FSTData[entryOffset++] = (nameOffset) & 0xff;
|
||||
|
||||
Write32((u32)(dataOffset >> m_addressShift), entryOffset, m_FSTData);
|
||||
entryOffset += 4;
|
||||
|
||||
Write32((u32)length, entryOffset, m_FSTData);
|
||||
entryOffset += 4;
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteEntryName(u32& nameOffset, const std::string& name)
|
||||
{
|
||||
strncpy((char*)(m_FSTData + nameOffset + m_fstNameOffset), name.c_str(), name.length() + 1);
|
||||
|
||||
nameOffset += (name.length() + 1);
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, u64& dataOffset, u32 parentEntryNum)
|
||||
{
|
||||
if(entry.isDirectory)
|
||||
{
|
||||
u32 myOffset = fstOffset;
|
||||
u32 myEntryNum = myOffset / ENTRY_SIZE;
|
||||
WriteEntryData(fstOffset, DIRECTORY_ENTRY, nameOffset, parentEntryNum, myEntryNum + entry.size + 1);
|
||||
WriteEntryName(nameOffset, entry.virtualName);
|
||||
|
||||
for(std::vector<File::FSTEntry>::const_iterator iter = entry.children.begin(); iter != entry.children.end(); ++iter)
|
||||
{
|
||||
WriteEntry(*iter, fstOffset, nameOffset, dataOffset, myEntryNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// put entry in FST
|
||||
WriteEntryData(fstOffset, FILE_ENTRY, nameOffset, dataOffset, entry.size);
|
||||
WriteEntryName(nameOffset, entry.virtualName);
|
||||
|
||||
// write entry to virtual disk
|
||||
_dbg_assert_(DVDINTERFACE, m_virtualDisk.find(dataOffset) == m_virtualDisk.end());
|
||||
m_virtualDisk.insert(make_pair(dataOffset, entry.physicalName));
|
||||
|
||||
// 4 byte aligned
|
||||
dataOffset = (dataOffset + entry.size + 3) & ~3ULL;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ComputeNameSize(const File::FSTEntry& parentEntry)
|
||||
{
|
||||
u32 nameSize = 0;
|
||||
const std::vector<File::FSTEntry>& children = parentEntry.children;
|
||||
for (std::vector<File::FSTEntry>::const_iterator it = children.begin();
|
||||
it != children.end(); ++it)
|
||||
{
|
||||
const File::FSTEntry& entry = *it;
|
||||
if (entry.isDirectory)
|
||||
{
|
||||
nameSize += ComputeNameSize(entry);
|
||||
}
|
||||
nameSize += entry.virtualName.length() + 1;
|
||||
}
|
||||
return nameSize;
|
||||
}
|
||||
|
||||
u32 CVolumeDirectory::AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry)
|
||||
{
|
||||
u32 foundEntries = ScanDirectoryTree(_Directory, parentEntry);
|
||||
m_totalNameSize += ComputeNameSize(parentEntry);
|
||||
return foundEntries;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,169 +1,169 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "VolumeGC.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CVolumeGC::CVolumeGC(IBlobReader* _pReader)
|
||||
: m_pReader(_pReader)
|
||||
{}
|
||||
|
||||
CVolumeGC::~CVolumeGC()
|
||||
{
|
||||
delete m_pReader;
|
||||
}
|
||||
|
||||
bool CVolumeGC::Read(u64 _Offset, u64 _Length, u8* _pBuffer) const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
return m_pReader->Read(_Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetUniqueID() const
|
||||
{
|
||||
static const std::string NO_UID("NO_UID");
|
||||
if (m_pReader == NULL)
|
||||
return NO_UID;
|
||||
|
||||
char id[6];
|
||||
if (!Read(0, sizeof(id), reinterpret_cast<u8*>(id)))
|
||||
{
|
||||
PanicAlert("Failed to read unique ID from disc image");
|
||||
return NO_UID;
|
||||
}
|
||||
|
||||
return std::string(id, sizeof(id));
|
||||
}
|
||||
|
||||
IVolume::ECountry CVolumeGC::GetCountry() const
|
||||
{
|
||||
if (!m_pReader)
|
||||
return COUNTRY_UNKNOWN;
|
||||
|
||||
u8 CountryCode;
|
||||
m_pReader->Read(3, 1, &CountryCode);
|
||||
|
||||
ECountry country = COUNTRY_UNKNOWN;
|
||||
|
||||
switch (CountryCode)
|
||||
{
|
||||
case 'S':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL // <- that is shitty :) zelda demo disc
|
||||
|
||||
case 'P':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'D':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'F':
|
||||
country = COUNTRY_FRANCE;
|
||||
break; // PAL
|
||||
|
||||
case 'X':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // XIII <- uses X but is PAL
|
||||
|
||||
case 'E':
|
||||
country = COUNTRY_USA;
|
||||
break; // USA
|
||||
|
||||
case 'J':
|
||||
country = COUNTRY_JAP;
|
||||
break; // JAP
|
||||
|
||||
case 'O':
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break; // SDK
|
||||
|
||||
default:
|
||||
// PanicAlert(StringFromFormat("Unknown Country Code!").c_str());
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return(country);
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetMakerID() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
char makerID[3];
|
||||
if (!Read(0x4, 0x2, (u8*)&makerID))
|
||||
return false;
|
||||
makerID[2] = 0;
|
||||
|
||||
return makerID;
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetName() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
char name[128];
|
||||
if (!Read(0x20, 0x60, (u8*)&name))
|
||||
return false;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
u32 CVolumeGC::GetFSTSize() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
u32 size;
|
||||
if (!Read(0x428, 0x4, (u8*)&size))
|
||||
return false;
|
||||
|
||||
return Common::swap32(size);
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetApploaderDate() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
char date[16];
|
||||
if (!Read(0x2440, 0x10, (u8*)&date))
|
||||
return false;
|
||||
// Should be 0 already, but just in case
|
||||
date[10] = 0;
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
u64 CVolumeGC::GetSize() const
|
||||
{
|
||||
if (m_pReader)
|
||||
return (size_t)m_pReader->GetDataSize();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "VolumeGC.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CVolumeGC::CVolumeGC(IBlobReader* _pReader)
|
||||
: m_pReader(_pReader)
|
||||
{}
|
||||
|
||||
CVolumeGC::~CVolumeGC()
|
||||
{
|
||||
delete m_pReader;
|
||||
}
|
||||
|
||||
bool CVolumeGC::Read(u64 _Offset, u64 _Length, u8* _pBuffer) const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
return m_pReader->Read(_Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetUniqueID() const
|
||||
{
|
||||
static const std::string NO_UID("NO_UID");
|
||||
if (m_pReader == NULL)
|
||||
return NO_UID;
|
||||
|
||||
char id[6];
|
||||
if (!Read(0, sizeof(id), reinterpret_cast<u8*>(id)))
|
||||
{
|
||||
PanicAlert("Failed to read unique ID from disc image");
|
||||
return NO_UID;
|
||||
}
|
||||
|
||||
return std::string(id, sizeof(id));
|
||||
}
|
||||
|
||||
IVolume::ECountry CVolumeGC::GetCountry() const
|
||||
{
|
||||
if (!m_pReader)
|
||||
return COUNTRY_UNKNOWN;
|
||||
|
||||
u8 CountryCode;
|
||||
m_pReader->Read(3, 1, &CountryCode);
|
||||
|
||||
ECountry country = COUNTRY_UNKNOWN;
|
||||
|
||||
switch (CountryCode)
|
||||
{
|
||||
case 'S':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL // <- that is shitty :) zelda demo disc
|
||||
|
||||
case 'P':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'D':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'F':
|
||||
country = COUNTRY_FRANCE;
|
||||
break; // PAL
|
||||
|
||||
case 'X':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // XIII <- uses X but is PAL
|
||||
|
||||
case 'E':
|
||||
country = COUNTRY_USA;
|
||||
break; // USA
|
||||
|
||||
case 'J':
|
||||
country = COUNTRY_JAP;
|
||||
break; // JAP
|
||||
|
||||
case 'O':
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break; // SDK
|
||||
|
||||
default:
|
||||
// PanicAlert(StringFromFormat("Unknown Country Code!").c_str());
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return(country);
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetMakerID() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
char makerID[3];
|
||||
if (!Read(0x4, 0x2, (u8*)&makerID))
|
||||
return false;
|
||||
makerID[2] = 0;
|
||||
|
||||
return makerID;
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetName() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
char name[128];
|
||||
if (!Read(0x20, 0x60, (u8*)&name))
|
||||
return false;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
u32 CVolumeGC::GetFSTSize() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
u32 size;
|
||||
if (!Read(0x428, 0x4, (u8*)&size))
|
||||
return false;
|
||||
|
||||
return Common::swap32(size);
|
||||
}
|
||||
|
||||
std::string CVolumeGC::GetApploaderDate() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
return false;
|
||||
|
||||
char date[16];
|
||||
if (!Read(0x2440, 0x10, (u8*)&date))
|
||||
return false;
|
||||
// Should be 0 already, but just in case
|
||||
date[10] = 0;
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
u64 CVolumeGC::GetSize() const
|
||||
{
|
||||
if (m_pReader)
|
||||
return (size_t)m_pReader->GetDataSize();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,254 +1,254 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "VolumeWiiCrypted.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CVolumeWiiCrypted::CVolumeWiiCrypted(IBlobReader* _pReader, u64 _VolumeOffset, const unsigned char* _pVolumeKey)
|
||||
: m_pReader(_pReader),
|
||||
m_pBuffer(0),
|
||||
m_VolumeOffset(_VolumeOffset),
|
||||
m_LastDecryptedBlockOffset(-1)
|
||||
{
|
||||
AES_set_decrypt_key(_pVolumeKey, 128, &m_AES_KEY);
|
||||
m_pBuffer = new u8[0x8000];
|
||||
}
|
||||
|
||||
|
||||
CVolumeWiiCrypted::~CVolumeWiiCrypted()
|
||||
{
|
||||
delete m_pReader; // is this really our responsibility?
|
||||
m_pReader = NULL;
|
||||
delete[] m_pBuffer;
|
||||
m_pBuffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CVolumeWiiCrypted::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer) const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
while (_Length > 0)
|
||||
{
|
||||
static unsigned char IV[16];
|
||||
|
||||
// math block offset
|
||||
u64 Block = _ReadOffset / 0x7C00;
|
||||
u64 Offset = _ReadOffset % 0x7C00;
|
||||
|
||||
// read current block
|
||||
if (!m_pReader->Read(m_VolumeOffset + Block * 0x8000, 0x8000, m_pBuffer))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (m_LastDecryptedBlockOffset != Block)
|
||||
{
|
||||
memcpy(IV, m_pBuffer + 0x3d0, 16);
|
||||
AES_cbc_encrypt(m_pBuffer + 0x400, m_LastDecryptedBlock, 0x7C00, &m_AES_KEY, IV, AES_DECRYPT);
|
||||
|
||||
m_LastDecryptedBlockOffset = Block;
|
||||
}
|
||||
|
||||
// copy the encrypted data
|
||||
u64 MaxSizeToCopy = 0x7C00 - Offset;
|
||||
u64 CopySize = (_Length > MaxSizeToCopy) ? MaxSizeToCopy : _Length;
|
||||
memcpy(_pBuffer, &m_LastDecryptedBlock[Offset], (size_t)CopySize);
|
||||
|
||||
// increase buffers
|
||||
_Length -= CopySize;
|
||||
_pBuffer += CopySize;
|
||||
_ReadOffset += CopySize;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetUniqueID() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char ID[7];
|
||||
|
||||
if (!Read(0, 6, (u8*)ID))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
ID[6] = 0;
|
||||
|
||||
return(ID);
|
||||
}
|
||||
|
||||
|
||||
IVolume::ECountry
|
||||
CVolumeWiiCrypted::GetCountry() const
|
||||
{
|
||||
if (!m_pReader)
|
||||
{
|
||||
return(COUNTRY_UNKNOWN);
|
||||
}
|
||||
|
||||
u8 CountryCode;
|
||||
m_pReader->Read(3, 1, &CountryCode);
|
||||
|
||||
ECountry country = COUNTRY_UNKNOWN;
|
||||
|
||||
switch (CountryCode)
|
||||
{
|
||||
case 'S':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL // <- that is shitty :) zelda demo disc
|
||||
|
||||
case 'P':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'D':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'F':
|
||||
country = COUNTRY_FRANCE;
|
||||
break; // PAL
|
||||
|
||||
case 'X':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // XIII <- uses X but is PAL rip
|
||||
|
||||
case 'E':
|
||||
country = COUNTRY_USA;
|
||||
break; // USA
|
||||
|
||||
case 'J':
|
||||
country = COUNTRY_JAP;
|
||||
break; // JAP
|
||||
|
||||
case 'O':
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break; // SDK
|
||||
|
||||
default:
|
||||
PanicAlert(StringFromFormat("Unknown Country Code!").c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
return(country);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetMakerID() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char makerID[3];
|
||||
|
||||
if (!Read(0x4, 0x2, (u8*)&makerID))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
makerID[2] = 0;
|
||||
|
||||
return(makerID);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetName() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char name[0xFF];
|
||||
|
||||
if (!Read(0x20, 0x60, (u8*)&name))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(name);
|
||||
}
|
||||
|
||||
u32
|
||||
CVolumeWiiCrypted::GetFSTSize() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
u32 size;
|
||||
|
||||
if (!Read(0x428, 0x4, (u8*)&size))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetApploaderDate() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char date[16];
|
||||
|
||||
if (!Read(0x2440, 0x10, (u8*)&date))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
date[10] = 0;
|
||||
|
||||
return(date);
|
||||
}
|
||||
|
||||
|
||||
u64
|
||||
CVolumeWiiCrypted::GetSize() const
|
||||
{
|
||||
if (m_pReader)
|
||||
{
|
||||
return(m_pReader->GetDataSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "VolumeWiiCrypted.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CVolumeWiiCrypted::CVolumeWiiCrypted(IBlobReader* _pReader, u64 _VolumeOffset, const unsigned char* _pVolumeKey)
|
||||
: m_pReader(_pReader),
|
||||
m_pBuffer(0),
|
||||
m_VolumeOffset(_VolumeOffset),
|
||||
m_LastDecryptedBlockOffset(-1)
|
||||
{
|
||||
AES_set_decrypt_key(_pVolumeKey, 128, &m_AES_KEY);
|
||||
m_pBuffer = new u8[0x8000];
|
||||
}
|
||||
|
||||
|
||||
CVolumeWiiCrypted::~CVolumeWiiCrypted()
|
||||
{
|
||||
delete m_pReader; // is this really our responsibility?
|
||||
m_pReader = NULL;
|
||||
delete[] m_pBuffer;
|
||||
m_pBuffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CVolumeWiiCrypted::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer) const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
while (_Length > 0)
|
||||
{
|
||||
static unsigned char IV[16];
|
||||
|
||||
// math block offset
|
||||
u64 Block = _ReadOffset / 0x7C00;
|
||||
u64 Offset = _ReadOffset % 0x7C00;
|
||||
|
||||
// read current block
|
||||
if (!m_pReader->Read(m_VolumeOffset + Block * 0x8000, 0x8000, m_pBuffer))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (m_LastDecryptedBlockOffset != Block)
|
||||
{
|
||||
memcpy(IV, m_pBuffer + 0x3d0, 16);
|
||||
AES_cbc_encrypt(m_pBuffer + 0x400, m_LastDecryptedBlock, 0x7C00, &m_AES_KEY, IV, AES_DECRYPT);
|
||||
|
||||
m_LastDecryptedBlockOffset = Block;
|
||||
}
|
||||
|
||||
// copy the encrypted data
|
||||
u64 MaxSizeToCopy = 0x7C00 - Offset;
|
||||
u64 CopySize = (_Length > MaxSizeToCopy) ? MaxSizeToCopy : _Length;
|
||||
memcpy(_pBuffer, &m_LastDecryptedBlock[Offset], (size_t)CopySize);
|
||||
|
||||
// increase buffers
|
||||
_Length -= CopySize;
|
||||
_pBuffer += CopySize;
|
||||
_ReadOffset += CopySize;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetUniqueID() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char ID[7];
|
||||
|
||||
if (!Read(0, 6, (u8*)ID))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
ID[6] = 0;
|
||||
|
||||
return(ID);
|
||||
}
|
||||
|
||||
|
||||
IVolume::ECountry
|
||||
CVolumeWiiCrypted::GetCountry() const
|
||||
{
|
||||
if (!m_pReader)
|
||||
{
|
||||
return(COUNTRY_UNKNOWN);
|
||||
}
|
||||
|
||||
u8 CountryCode;
|
||||
m_pReader->Read(3, 1, &CountryCode);
|
||||
|
||||
ECountry country = COUNTRY_UNKNOWN;
|
||||
|
||||
switch (CountryCode)
|
||||
{
|
||||
case 'S':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL // <- that is shitty :) zelda demo disc
|
||||
|
||||
case 'P':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'D':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // PAL
|
||||
|
||||
case 'F':
|
||||
country = COUNTRY_FRANCE;
|
||||
break; // PAL
|
||||
|
||||
case 'X':
|
||||
country = COUNTRY_EUROPE;
|
||||
break; // XIII <- uses X but is PAL rip
|
||||
|
||||
case 'E':
|
||||
country = COUNTRY_USA;
|
||||
break; // USA
|
||||
|
||||
case 'J':
|
||||
country = COUNTRY_JAP;
|
||||
break; // JAP
|
||||
|
||||
case 'O':
|
||||
country = COUNTRY_UNKNOWN;
|
||||
break; // SDK
|
||||
|
||||
default:
|
||||
PanicAlert(StringFromFormat("Unknown Country Code!").c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
return(country);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetMakerID() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char makerID[3];
|
||||
|
||||
if (!Read(0x4, 0x2, (u8*)&makerID))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
makerID[2] = 0;
|
||||
|
||||
return(makerID);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetName() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char name[0xFF];
|
||||
|
||||
if (!Read(0x20, 0x60, (u8*)&name))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(name);
|
||||
}
|
||||
|
||||
u32
|
||||
CVolumeWiiCrypted::GetFSTSize() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
u32 size;
|
||||
|
||||
if (!Read(0x428, 0x4, (u8*)&size))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
std::string
|
||||
CVolumeWiiCrypted::GetApploaderDate() const
|
||||
{
|
||||
if (m_pReader == NULL)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
char date[16];
|
||||
|
||||
if (!Read(0x2440, 0x10, (u8*)&date))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
date[10] = 0;
|
||||
|
||||
return(date);
|
||||
}
|
||||
|
||||
|
||||
u64
|
||||
CVolumeWiiCrypted::GetSize() const
|
||||
{
|
||||
if (m_pReader)
|
||||
{
|
||||
return(m_pReader->GetDataSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
@ -1,21 +1,21 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
|
Reference in New Issue
Block a user