//////////////////////////////////////////////////////////////////////////
// low level function, reads directly from the file
// TODO: remove all those pOSSaveReader parameter chains and make it a member, passing it along is not needed anymore
void CReader::ReadDataFromFileInternal( IPlatformOS::ISaveReaderPtr& pOSSaveReader, void* pDst, uint32 numBytes )
{
	assert( pOSSaveReader.get() );
	
	if (!m_errorReading)
	{
		IPlatformOS::EFileOperationCode code = pOSSaveReader->ReadBytes( pDst, numBytes );
		CheckErrorFlag( code );
	}
}
bool CReader::CheckFileCorruption( IPlatformOS::ISaveReaderPtr& pOSSaveReader, const SFileHeader& fileHeader, uint32 totalSize )
{
	bool error = false;

	if (totalSize<=sizeof(fileHeader))
	{
		CryWarning( VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "XMLCPB ERROR: size check failed. savegame File corrupted! (probably not fully saved)" );
		error = true;
		return error;
	}

	uint32 sizeToCheck = totalSize - sizeof(fileHeader);

	char* pBuf = new char[sizeToCheck];
	pOSSaveReader->Seek( 0, IPlatformOS::ISaveReader::ESM_BEGIN );
	ReadDataFromFileInternal( pOSSaveReader, pBuf, sizeToCheck );
	
	IZLibCompressor* pZLib = GetISystem()->GetIZLibCompressor();

	if (!pZLib)
	{
		SAFE_DELETE_ARRAY(pBuf);
		error = true;
		return error;
	}

	SMD5Context context;
	char MD5signature[SFileHeader::MD5_SIGNATURE_SIZE];
	pZLib->MD5Init(&context);
	pZLib->MD5Update(&context, pBuf, sizeToCheck); 

	SFileHeader tempFileHeader = fileHeader;
	for (uint32 i=0; i<SFileHeader::MD5_SIGNATURE_SIZE; ++i) tempFileHeader.m_MD5Signature[i] = 0; // the original signature is always calculated with this zeroed.
	pZLib->MD5Update(&context, (const char*)(&tempFileHeader), sizeof(tempFileHeader));
	pZLib->MD5Final(&context, MD5signature); 
	
	SAFE_DELETE_ARRAY( pBuf );

	for (uint32 i=0; i<SFileHeader::MD5_SIGNATURE_SIZE; ++i)
	{
		if (fileHeader.m_MD5Signature[i]!=MD5signature[i])
		{
			CryWarning( VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "XMLCPB ERROR: md5 check failed. savegame File corrupted!" );
			error = true;
			break;
		}
	}

	return error;
}
bool CReader::ReadBinaryFile( const char* pFileName )
{
	IPlatformOS::ISaveReaderPtr pOSSaveReader = gEnv->pSystem->GetPlatformOS()->SaveGetReader( pFileName, IPlatformOS::Unknown_User );
	if (!m_pZLibBuffer)
		m_pZLibBuffer = new uint8[ XMLCPB_ZLIB_BUFFER_SIZE ];
	if (!m_pZLibCompressedBuffer)
		m_pZLibCompressedBuffer = new uint8[ XMLCPB_ZLIB_BUFFER_SIZE ];
	m_errorReading = pOSSaveReader.get()==NULL;
	
	if (!m_errorReading)
	{
		size_t totalNumBytesInFile = 0;
		IPlatformOS::EFileOperationCode code = pOSSaveReader->GetNumBytes( totalNumBytesInFile );
		m_totalSize = totalNumBytesInFile;
		CheckErrorFlag( code );

		if (!m_errorReading)
		{
			SFileHeader fileHeader;
			pOSSaveReader->Seek( -int(sizeof(fileHeader)), IPlatformOS::ISaveReader::ESM_END );
			ReadDataFromFileInternal( pOSSaveReader, &fileHeader, sizeof(fileHeader) );
#ifdef XMLCPB_CHECK_FILE_INTEGRITY			
			m_errorReading = CheckFileCorruption( pOSSaveReader, fileHeader, m_totalSize );
#endif			
			
			pOSSaveReader->Seek( 0, IPlatformOS::ISaveReader::ESM_BEGIN );
			
			if (fileHeader.m_fileTypeCheck!=fileHeader.FILETYPECHECK)
			{
				CryWarning( VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "XMLCPB ERROR: file type signature not correct. Savegame File corrupted!" );
				m_errorReading = true;
			}
			
			if (!m_errorReading)
			{
				m_nodesDataSize = fileHeader.m_sizeNodes;
				m_numNodes = fileHeader.m_numNodes;
				m_buffer.ReadFromFile( *this, pOSSaveReader, fileHeader.m_sizeNodes );
				m_tableTags.ReadFromFile( *this, pOSSaveReader, fileHeader.m_tags );
				m_tableAttrNames.ReadFromFile( *this, pOSSaveReader, fileHeader.m_attrNames );
				m_tableStrData.ReadFromFile( *this, pOSSaveReader, fileHeader.m_strData );
				m_tableAttrSets.ReadFromFile( *this, pOSSaveReader, fileHeader );
				CreateNodeAddressTables();
			}
			
			if (!m_errorReading)
			{
				const CNodeLiveReader& root = ActivateLiveNodeFromCompact( m_numNodes - 1 ); // the last node is always the root
				assert( root.GetLiveId()==XMLCPB_ROOTNODE_ID );

				pOSSaveReader->TouchFile();
			}
		}	

		pOSSaveReader->Close();
	}
	
	CryLog("[LOAD GAME] --Binary saveload: reading done--");
		
	if (m_errorReading)
		CryWarning( VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "XMLCPB ERROR: while reading the file: '%s'", pFileName );

	return !m_errorReading;
}
예제 #4
0
bool CXmlLoadGame::Init( const char * name )
{
#ifdef XML_LOADGAME_USE_COMPRESSION
	#if defined(XENON) || defined(PS3)
		CryWarning(VALIDATOR_MODULE_GAME,VALIDATOR_ERROR, "CXmlLoadGame::Init  not supported yet, strings cannot grow beyond 32767 chars\n");
		return false;
	#endif

	const unsigned int nFileSizeBits = GetISystem()->GetCompressedFileSize(name);
	const unsigned int nFileSizeBytes = nFileSizeBits / 8 + ((nFileSizeBits & 7) + 7) / 8;
	if (nFileSizeBytes <= 0)
	{
		return false;
	}

	char* const pXmlData = new char[nFileSizeBytes+16];
	GetISystem()->ReadCompressedFile(name, pXmlData,nFileSizeBits);

	m_pImpl->root = GetISystem()->LoadXmlFromBuffer(pXmlData, nFileSizeBytes);

	delete []pXmlData;
#else
	if (GetISystem()->GetPlatformOS()->UsePlatformSavingAPI() )
	{
		IPlatformOS::ISaveReaderPtr pSaveReader = GetISystem()->GetPlatformOS()->SaveGetReader(name);
		if (!pSaveReader)
		{
			return false;
		}

		size_t nFileSize;

		if ((pSaveReader->GetNumBytes(nFileSize) == IPlatformOS::eFOC_Failure) || (nFileSize <= 0))
		{
			return false;
		}

		std::vector<char> xmlData;
		xmlData.resize(nFileSize);
		
		if (pSaveReader->ReadBytes(&xmlData[0], nFileSize) == IPlatformOS::eFOC_Failure)
		{
			return false;
		}

		m_pImpl->root = GetISystem()->LoadXmlFromBuffer(&xmlData[0], nFileSize);
	}
	else
	{
		m_pImpl->root = GetISystem()->LoadXmlFromFile(name);
	}
#endif

	if (!m_pImpl->root)
		return false;

	m_pImpl->inputFile = name;

	m_pImpl->metadata = m_pImpl->root->findChild("Metadata");
	if (!m_pImpl->metadata)
		return false;

	return true;
}