nestopia/source/core/NstPatcher.cpp
2012-09-02 13:13:55 -04:00

197 lines
4.3 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include <new>
#include "NstVector.hpp"
#include "NstPatcher.hpp"
#include "NstPatcherIps.hpp"
#include "NstPatcherUps.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Patcher::Patcher(bool b)
:
ips (NULL),
ups (NULL),
bypassChecksum (b)
{
}
Patcher::~Patcher()
{
Destroy();
}
void Patcher::Destroy()
{
delete ips;
ips = NULL;
delete ups;
ups = NULL;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
Result Patcher::Load(std::istream& stream)
{
Destroy();
if (Ips::IsIps( stream ))
{
ips = new (std::nothrow) Ips;
return ips ? ips->Load( stream ) : RESULT_ERR_OUT_OF_MEMORY;
}
if (Ups::IsUps( stream ))
{
ups = new (std::nothrow) Ups;
return ups ? ups->Load( stream, bypassChecksum ) : RESULT_ERR_OUT_OF_MEMORY;
}
return RESULT_ERR_INVALID_FILE;
}
Result Patcher::Load(std::istream& patchStream,std::istream& srcStream)
{
Result result = Load( patchStream );
if (NES_SUCCEEDED(result))
{
result = Test( srcStream );
if (NES_FAILED(result))
Destroy();
}
return result;
}
Result Patcher::Save(std::ostream& stream) const
{
return
(
ips ? ips->Save( stream ) :
ups ? ups->Save( stream ) : RESULT_ERR_NOT_READY
);
}
Result Patcher::Test(std::istream& stream) const
{
return
(
ips ? ips->Test( stream ) :
ups ? ups->Test( stream, bypassChecksum ) : RESULT_ERR_NOT_READY
);
}
Result Patcher::Test(const Block* const blocks,const uint numBlocks) const
{
NST_ASSERT( blocks || !numBlocks );
if (numBlocks > 1)
{
Vector<byte> buffer;
try
{
dword size = 0;
for (uint i=0; i < numBlocks; ++i)
size += blocks[i].size;
buffer.Reserve( size );
}
catch (...)
{
return RESULT_ERR_OUT_OF_MEMORY;
}
for (uint i=0; i < numBlocks; ++i)
buffer.Append( blocks[i].data, blocks[i].size );
return Test( buffer.Begin(), buffer.Size() );
}
else
{
return Test( blocks ? blocks->data : NULL, blocks ? blocks->size : 0 );
}
}
Result Patcher::Test(const byte* const data,const dword size) const
{
return
(
ips ? ips->Test( data, size ) :
ups ? ups->Test( data, size, bypassChecksum ) : RESULT_ERR_NOT_READY
);
}
bool Patcher::Patch(const byte* const src,byte* const dst,const dword size,const dword offset) const
{
return
(
ips ? ips->Patch( src, dst, size, offset ) :
ups ? ups->Patch( src, dst, size, offset ) : false
);
}
Result Patcher::Create(const Type type,const byte* const src,const byte* const dst,const dword length)
{
Destroy();
switch (type)
{
case IPS:
ips = new (std::nothrow) Ips;
return ips ? ips->Create( src, dst, length ) : RESULT_ERR_OUT_OF_MEMORY;
case UPS:
ups = new (std::nothrow) Ups;
return ups ? ups->Create( src, dst, length ) : RESULT_ERR_OUT_OF_MEMORY;
}
return RESULT_ERR_UNSUPPORTED;
}
bool Patcher::Empty() const
{
return
(
ips ? ips->Empty() :
ups ? ups->Empty() : true
);
}
}
}