朱皮特的博客 自由的飞翔

SAF资源提取

2009-06-10
朱皮特
 
阅读量:

SAF资源提取下了一个“大鱼吃小鱼”的小游戏,感觉比较有意思。这个游戏的资源文件存放在.saf文件中,该格式组织得比较简单,就是把N个小文件放在一起。这两天在看HGE游戏编程方面的东西,不过没有游戏素材,于是想借用一下别人的,提取出来压缩成zip包加上个密码就能为HGE使用了,多方便啊! 主要代码:

#pragma pack(1)

typedef struct SAFHEAD {
	DWORD nSign;              // equal 'SAFF'
	DWORD nUnknow;             // always equal 0x00000001
	DWORD nOffset;              // the start postion of files info from the SAF begin 
}*PSAFHEAD;

typedef struct SAFTAIL {
	DWORD nUnknow1;            // always equal 0x00000001
	DWORD nUnknow2[4];        // may be include checknum or Hash key
	DWORD nFileCount;           // how many files included in this pack 
}*PSAFTAIL;

typedef struct SUBFILEINFO {
	DWORD nFileOffset;
	DWORD nFileSize;
	DWORD nUnknow[4];
	WORD nFileNameLen;        // the length of the file name
	//char* pFileName;              // a string 
}*PSUBFILEINFO;

//从文件srcFile中的偏移nOffset读取nSize大小保存为strFileName文件
void SaveFile(CFile*srcFile, int nOffset, int nSize, CString strFileName) {
	char buff[1024];
	int nReaded = 0;
	ULONGLONG nReadPointer = srcFile->Seek(0, CFile::current);
	srcFile->Seek(nOffset, CFile::begin);
	CFile dstFile;
	dstFile.Open(strFileName, CFile::modeCreate | CFile::modeWrite);

	while (nSize > sizeof(buff)) {
		nReaded = srcFile->Read(buff, sizeof(buff));
		if (nReaded == 0)
			break;
		dstFile.Write(buff, nReaded);
		nSize -= nReaded;
	}

	nReaded = srcFile->Read(buff, nSize);
	dstFile.Write(buff, nReaded);
	nSize -= nReaded;

	dstFile.Close();
	srcFile->Seek(nReadPointer, CFile::begin);
}


void CSafEditorDlg::OnBnClickedButtonExtract() {
	CString strFile;
	m_edtSafFile.GetWindowText(strFile);
	if (strFile == "")
		return;

	CString strFileRoot;
	int nPos = strFile.ReverseFind('.');
	strFileRoot = strFile.Left(nPos);
	CreateDirectory(strFileRoot, NULL);

	CString strText;
	SAFHEAD safHead;
	SAFTAIL safTail;
	SUBFILEINFO subFileInfo;
	CFile safFile;
	char szFileName[MAX_PATH * 2];

	safFile.Open(strFile, CFile::modeRead);
	safFile.Seek(0, CFile::begin);
	safFile.Read(&safHead, sizeof(safHead));

	strText.Format("尾部偏移:0x%x", safHead.nOffset);
	AppendMsg(strText);

	safFile.Seek(safHead.nOffset, CFile::begin);
	safFile.Read(&safTail, sizeof(safTail));

	strText.Format("共含有%d个文件", safTail.nFileCount);
	AppendMsg(strText);

	for (int i = 0; i < safTail.nFileCount; i++) {
		safFile.Read(&subFileInfo, sizeof(subFileInfo));
		if (subFileInfo.nFileNameLen) {
			safFile.Read(szFileName, subFileInfo.nFileNameLen);
			szFileName[subFileInfo.nFileNameLen] = 0;
			AppendMsg(szFileName);
		}
		CString strDstFile;
		strDstFile.Format("%s\\%s", strFileRoot, szFileName);
		strDstFile.Replace('/', '\\');

		int nRootLen = strFileRoot.GetLength();
		while (TRUE) {
			nPos = strDstFile.Find('\\', nRootLen + 1);
			if (nPos <= nRootLen)
				break;
			nRootLen = nPos;
			if (!PathFileExists(strDstFile.Left(nRootLen))) {
				CreateDirectory(strDstFile.Left(nRootLen), NULL);
			}
		}

		SaveFile(&safFile, subFileInfo.nFileOffset, subFileInfo.nFileSize, strDstFile);
		strText.Format("编号:%d 文件偏移:0x%x 文件大小:%d", i + 1, subFileInfo.nFileOffset, subFileInfo.nFileSize);
		AppendMsg(strText);
	}

	safFile.Close();
}

Comments

Content