//////////////////////////////////////////////////////////////////////////////////////// // // 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 #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 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 ); } } }