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();
}
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/program/SAF%E8%B5%84%E6%BA%90%E6%8F%90%E5%8F%96.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)