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许可证)