一、功能需求
1、需要实现的功能:
(1)、创建、打开和关闭资源包。
(2)、压缩资源包。消除数据添加、修改和删除带来的数据碎片,扩展索引表容量,重设资源包密钥。
(3)、合并资源包。将外部的资源包整合进当前打开的资源包。
(4)、释放资源文件。将资源包内的任意文件释放到磁盘。
(5)、创建文件夹。
(6)、(批量)添加文件。可以指定文件的独立密钥与压缩选项。
(7)、从文件夹添加数据(包括文件夹与文件)。可以指定文件的独立密钥与压缩选项。
(8)、(批量)更新文件。可以选择按列表顺序与按文件名两种方式进行数据更新。
(9)、(批量)复制、剪切、粘贴、删除和重命名单元。
(10)、查看和修改资源属性。
(11)、文件生成格式为.pkg格式
(12)、资源管理程序新增需求
ogre资源管理适配器,ogre本身有抽象的文件夹和文件流接口:zip文件和第三方自定义文件。实现这些接口可以让ogre使用第三方资源管理器,即我们现在做的这套。
2、性能需求:
压缩算法选择:压缩率高。加密算法选择:机密性好。同时在时间上有一定Deadline.
3、界面要求:
直观,大方,美观。
本软件在UI设计方面采用的是wxWidgets库,由于本库在跨平台方面做的已经比较成熟,可以满足软件移植的需要,而且它对常用的控件进行了封装,因而在设计的过程中可以减少界面设计的开销,可以把精力放在重点算法的实现上。本部分给出整个窗体的界面元素及其相关说明。
● 采用的wxWidgets图形用户界面(GUl)标准,感官上稍异于传统windows界面显示效果;
● 屏幕布局采用wxWidgets中的布局控件进行,尽量满足多分辨率的显示问题;
● 使用在图形用户界面上的软件组件,包括:
Ø 菜单:wxMenu
Ø 工具栏:wxToolBar
Ø 标准按钮:wxButton
Ø 树形控件:wxTreeCtrl
Ø 文件列表控件:wxListCtrl
Ø 文本显示框:wxTextCtrl
Ø 状态栏:wxStatusBar
● 快捷键:(参照菜单项)
● 各种显示格式的规定,包括:
Ø 不同情况下文字的对齐方式;
Ø 不同情况下数字的表现格式与对齐方式
Ø 程序和文件的编码方式采用Unicode编码
● 错误信息显示标准;
1、菜单
文件(E)-------新建(N) Ctrl + N
|----打开(O) Ctrl + O
|----重新打开(R)
|----关闭(O)
|----历史记录----…
|——————————
|----信息(I)
|——————————
|----退出(Q) Alt + Q
查看(V)-------ü工具栏(T)
|----ü预览(P)
|——————————
|----®大图标(G)
|----®小图标(M)
|----®列表(L)
|----®详细资料(D)
操作(E)-------打开(O)
|----打开方式…(W)
|——————————
|----解压缩(E) Ctrl + E
|----重命名(R) F2
|----删除(D) Delete
|——————————
|----属性(P)
|——————————
|----新建文件夹(N)
|----添加文件(A)
|----添加文件夹(T)
|——————————
|----选择列表文件(L)
|----全部解压(X)
|----重新压缩(C)
选项(P)-------文件类型选项(O) F6
|----语言------------®English
|----®Chinese
|----®Russian
帮助(H)-------关于(A)
2、工具栏
BTN_新建
BTN_打开
——————
BTN_信息
——————
BTN_
——————
BTN_加压缩
BTN_删除
——————
BTN_添加文件
BTN_添加文件夹
——————
BTN_大图标
BTN_小图标
BTN_列表
BTN_详细资料
——————
LIST_查找
3、主界面
左:wxTreeCtrl
右:wxListCtrl
下:wxTextCtrl
底:wxStatusBar
4、列表框右键菜单
|----打开(O)
|----打开方式…(W)
|——————————
|----解压缩(E)
|----重命名(R)
|----删除(D)
|——————————
|----属性(P)
|——————————
|----新建文件夹(N)
|----添加文件(A)
|----添加文件夹(T)
4、可以扩展的功能:
加密算法的可选择性、PKG文件的压缩
5、本系统目前还没有完成的功能如下:
(1). 加密算法及其加密算法的可选择性
(2). PKG文件的压缩
二、程序系统结构设计
1.整体逻辑框图
2.PKG包文件格式结
2.PKG包文件格式结构设计
3.空闲块链内存表示
4.目录树逻辑结构图
三、算法设计
1、文件添加流程
2、文件删除操作流程
3、PKG文件的创建及其PKG文件的读取流程
4、文件修改流程【暂时没有加入】
5、文件释放流程
6、 文件/文件夹重命名流程
四、接口设计
1、 PKG包操作
CreatePKG[创建PKG文件]
函数声明:
bool CreatePKG( char* sFilePath, long nTableSize );
函数说明:
新建一个空的PKG文件。
返回值:
bool,true表示成功,false表示失败。
参数列表:
sFilePath
[String],保存PKG文件的路径。
nTableSize
[DWord],新建PKG文件的索引表大小。
OpenPKG[打开PKG文件]
函数声明:
bool OpenPKG( char* sFilePath );
函数说明:
打开一个存在的PKG文件。
返回值:
bool,true表示成功,false表示失败。
参数列表:
sFilePath
[String],PKG文件的路径。
ClosePKG[关闭PKG文件]
函数声明:
bool ClosePKG();
函数说明:
关闭PKG文件,并做出相应的收尾工作。
返回值:
bool,true表示成功,false表示失败。
GetFileNum[取得PKG包中文件个数]
函数声明:
long GetFileNum();
函数说明:
[long],取得当前打开PKG文件中的文件个数。
返回值:
long:PKG文件中的文件个数。
GetTableSize [取得索引表的大小]
函数声明:
long GetTableSize();
函数说明:
取得指定文件的大小。
返回值:
[long],取得PKG头部索引表大小。
返回值:
long:PKG文件中的索引表的大小。
GetTableOffset[取得索引表偏移]
函数声明:
long GetTableOffset();
函数说明:
取得PKG文件中索引表的偏移量。
返回值:
long,索引表偏移量。
GetPKGVersion[获取PKG文件版本号]
函数声明:
long GetPKGVersion();
函数说明:
取得PKG文件的版本号。
返回值:
[long],取得PKG文件版本号。
2、 PKG内部文件操作
AddFileR[向PKG文件中添加文件]
函数声明:
bool ddFileR( char* strFileName, char* strRelName );
函数说明:
将一个文件添加到已经打开的PKG中。
返回值:
bool,成功:True;失败:false.
参数列表:
strFileName
[String],需要加入文件的路径。
strRelName
[String],加入到PKG文件中的相对路径。
DelFile[删除PKG文件中指定的文件]
函数声明:
bool DelFile(char *sFileName );
函数说明:
按照指定的文件名将此文件删除。
返回值:
bool,true表示成功,false表示失败。
参数列表:
sFileName
[String],文件名
DelFolder [删除PKG文件中指定的文件夹]
函数声明:
bool DelFolder( char *dirPath );
函数说明:
删除PKG文件中相对路径中的目录。
返回值:
bool,true表示成功,false表示失败。
参数列表:
dirPath
[String],PKG相对路径名
AddFolderR [添加文件夹]
函数声明:
Void AddFolderR(char * szFolderPath, char* strRelName );
函数说明:
向PKG相对路径中,递归添加目录。
返回值:
参数列表:
szFolderPath
[String]要添加的目录路径。
strRelName
[String]添加到的路径。
GetFileLen[取得文件大小]
函数声明:
long GetFileLen( string sFileName );
函数说明:
取得指定文件的大小。
返回值:
[long],取得指定文件名的文件大小。
参数列表:
sFileName
[String],指定的文件名。
GetFileOffset[取得文件偏移量]
函数声明:
long GetFileOffset( String sFileName );
函数说明:
取得已打开的PKG内指定序号文件的地址偏移,可使用此地址偏移直接取得数据。
返回值:
long,偏移地址
参数列表:
sFileName
[String],指定的文件名。
ReleaseFile[释放文件]
函数声明:
bool ReleaseFile( char* sSrcFileName, char* sDesDir );
bool ReleaseFile( unsigned long dwIndex, char* sDesDir );
函数说明:
将包中指定文件释放到硬盘。
返回值:
bool,true表示成功,false表示失败。
参数列表:
sSrcFileName
[String],PKG中指定的文件名。
sDesDir
[String],释放到的磁盘路径,没有则创建。
dwIndex
[DWORD],释放文件的索引。
RenameFile [重命名PKG中的文件]
函数声明:
bool RenameFile( char* strOldName, char* strNewName );;
函数说明:
将包中指定文件进行重命名。
返回值:
bool,true表示成功,false表示失败。
参数列表:
strOldName
[String],PKG中源文件名。
strNewName
[String],新文件名。
3、 PKG其它操作
五、Ogre资源扩展
1、修改OgreRoot和OgreStableHeaders,在其中仿照zip文件加入响应代码。
2、加入OgrePkg文件(进行扩充资源类型)
view plaincopy to clipboardprint?
#ifndef __Pkg_H__
#define __Pkg_H__
#include "OgrePrerequisites.h"
#include "OgreArchive.h"
#include "OgreArchiveFactory.h"
typedef struct pkg_dirent PKG_DIRENT;
typedef struct pkg_dirent PKG_STAT;
//--------------------------------------------------------------------------
// 提前声明,防止文件的依赖
typedef class CPkg PKG;
typedef class CPkgDir PKG_DIR;
typedef class CPkgFile PKG_FILE;
namespace Ogre {
class _OgreExport PkgArchive : public Archive
{
protected:
PKG* mPkg;
PKG_DIR* mPkgDir;
// pkg中文件列表
FileInfoList mFileList;
public:
PkgArchive(const String& name, const String& archType );
~PkgArchive();
// 不区分大小写
bool isCaseSensitive(void) const { return false; }
void load();
void unload();
DataStreamPtr open(const String& filename) const;
StringVectorPtr list(bool recursive = true, bool dirs = false);
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false);
StringVectorPtr find(const String& pattern, bool recursive = true,
bool dirs = false);
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false);
bool exists(const String& filename);
time_t getModifiedTime(const String& filename);
};
//--------------------------------------------------------------------------
// 用于Pkg文件的ArchiveFactory
class _OgrePrivate PkgArchiveFactory : public ArchiveFactory
{
public:
virtual ~PkgArchiveFactory() {}
const String& getType(void) const;
Archive *createInstance( const String& name )
{
return OGRE_NEW PkgArchive(name, "Pkg");
}
void destroyInstance( Archive* arch) { OGRE_DELETE arch; }
};
//--------------------------------------------------------------------------
// 处理PKG包中文件
class _OgrePrivate PkgDataStream : public DataStream
{
protected:
PKG_FILE* mPkgFile;
public:
PkgDataStream(PKG_FILE* pkgFile, size_t uncompressedSize);
PkgDataStream(const String& name, PKG_FILE* pkgFile, size_t uncompressedSize);
~PkgDataStream();
size_t read(void* buf, size_t count);
void skip(long count);
void seek( size_t pos );
size_t tell(void) const;
bool eof(void) const;
void close(void);
};
}
#endif
#ifndef __Pkg_H__
#define __Pkg_H__
#include "OgrePrerequisites.h"
#include "OgreArchive.h"
#include "OgreArchiveFactory.h"
typedef struct pkg_dirent PKG_DIRENT;
typedef struct pkg_dirent PKG_STAT;
//--------------------------------------------------------------------------
// 提前声明,防止文件的依赖
typedef class CPkg PKG;
typedef class CPkgDir PKG_DIR;
typedef class CPkgFile PKG_FILE;
namespace Ogre {
class _OgreExport PkgArchive : public Archive
{
protected:
PKG* mPkg;
PKG_DIR* mPkgDir;
// pkg中文件列表
FileInfoList mFileList;
public:
PkgArchive(const String& name, const String& archType );
~PkgArchive();
// 不区分大小写
bool isCaseSensitive(void) const { return false; }
void load();
void unload();
DataStreamPtr open(const String& filename) const;
StringVectorPtr list(bool recursive = true, bool dirs = false);
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false);
StringVectorPtr find(const String& pattern, bool recursive = true,
bool dirs = false);
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false);
bool exists(const String& filename);
time_t getModifiedTime(const String& filename);
};
//--------------------------------------------------------------------------
// 用于Pkg文件的ArchiveFactory
class _OgrePrivate PkgArchiveFactory : public ArchiveFactory
{
public:
virtual ~PkgArchiveFactory() {}
const String& getType(void) const;
Archive *createInstance( const String& name )
{
return OGRE_NEW PkgArchive(name, "Pkg");
}
void destroyInstance( Archive* arch) { OGRE_DELETE arch; }
};
//--------------------------------------------------------------------------
// 处理PKG包中文件
class _OgrePrivate PkgDataStream : public DataStream
{
protected:
PKG_FILE* mPkgFile;
public:
PkgDataStream(PKG_FILE* pkgFile, size_t uncompressedSize);
PkgDataStream(const String& name, PKG_FILE* pkgFile, size_t uncompressedSize);
~PkgDataStream();
size_t read(void* buf, size_t count);
void skip(long count);
void seek( size_t pos );
size_t tell(void) const;
bool eof(void) const;
void close(void);
};
}
#endif
view plaincopy to clipboardprint?
#include "OgreStableHeaders.h"
#include "OgrePkg.h"
#include "OgreLogManager.h"
#include "OgreException.h"
#include "OgreStringVector.h"
#include "OgreRoot.h"
#include "./pkg/TsPkg.h" // 接口
namespace Ogre {
//-----------------------------------------------------------------------
PkgArchive::PkgArchive(const String& name, const String& archType )
: Archive(name, archType), mPkgDir(0)
{
mPkg = new CPkg();
}
//-----------------------------------------------------------------------
PkgArchive::~PkgArchive()
{
unload();
}
//-----------------------------------------------------------------------
void PkgArchive::load()
{
char pkgPath[MAX_PATH];
strcpy_s( pkgPath, MAX_PATH, mName.c_str() );
mPkgDir = mPkg->pkg_open( pkgPath );
if (mPkgDir)
{
mPkgDir->pkg_dir_open(mName);
mPkgDir->pkg_dir_read();
vector<PKG_DIRENT> *vec = mPkgDir->GetDir();
vector<PKG_DIRENT>::iterator pkgdir = (*vec).begin();
while ( pkgdir != vec->end() )
{
FileInfo info;
info.archive = this;
// Get basename / path
StringUtil::splitFilename((*pkgdir).d_name, info.basename, info.path);
info.filename = (*pkgdir).d_name;
// Get sizes
info.compressedSize = static_cast<size_t>((*pkgdir).d_csize);
info.uncompressedSize = static_cast<size_t>((*pkgdir).st_size);
// folder entries
if (info.basename.empty())
{
info.filename = info.filename.substr (0, info.filename.length () - 1);
StringUtil::splitFilename(info.filename, info.basename, info.path);
// Set compressed size to -1 for folders; anyway nobody will check
// the compressed size of a folder, and if he does, its useless anyway
info.compressedSize = size_t (-1);
}
mFileList.push_back(info);
pkgdir++;
}
}
}
//-----------------------------------------------------------------------
void PkgArchive::unload()
{
if (mPkgDir)
{
mPkgDir->pkg_dir_close();
mPkgDir = 0;
mFileList.clear();
}
}
//-----------------------------------------------------------------------
DataStreamPtr PkgArchive::open(const String& filename) const
{
// Format not used here (always binary)
char openpath[MAX_PATH];
strcpy_s( openpath, MAX_PATH, filename.c_str() );
filesystem::path filepath( openpath,filesystem::native );
filepath.normalize();
string dirpath = filepath.branch_path().string();
PKG_FILE* pkgFile = mPkgDir->pkg_dir_openRel(dirpath);
char strFilename[_MAX_FNAME];
strcpy_s( strFilename, _MAX_FNAME, filepath.leaf().c_str() );
pkgFile->pkg_file_open( strFilename );
if (pkgFile < 0)
{
// return null pointer
return DataStreamPtr();
}
// Get uncompressed size too
PKG_STAT zstat;
//mPkgDir->pkg_dir_stat(filename, &zstat);
pkgFile->pkg_file_stat( &zstat );
// Construct & return stream
return DataStreamPtr(OGRE_NEW PkgDataStream(filename, pkgFile, static_cast<size_t>(zstat.st_size)));
}
//-----------------------------------------------------------------------
StringVectorPtr PkgArchive::list(bool recursive, bool dirs)
{
StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
FileInfoList::iterator i, iend;
iend = mFileList.end();
for (i = mFileList.begin(); i != iend; ++i)
if ((dirs == (i->compressedSize == size_t (-1))) &&
(recursive || i->path.empty()))
ret->push_back(i->filename);
return ret;
}
//-----------------------------------------------------------------------
FileInfoListPtr PkgArchive::listFileInfo(bool recursive, bool dirs)
{
FileInfoList* fil = OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)();
FileInfoList::const_iterator i, iend;
iend = mFileList.end();
for (i = mFileList.begin(); i != iend; ++i)
if ((dirs == (i->compressedSize == size_t (-1))) &&
(recursive || i->path.empty()))
fil->push_back(*i);
return FileInfoListPtr(fil, SPFM_DELETE_T);
}
//-----------------------------------------------------------------------
StringVectorPtr PkgArchive::find(const String& pattern, bool recursive, bool dirs)
{
recursive = true;
StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
// If pattern contains a directory name, do a full match
bool full_match = (pattern.find ('/') != String::npos) ||
(pattern.find ('//') != String::npos);
FileInfoList::iterator i, iend;
iend = mFileList.end();
for (i = mFileList.begin(); i != iend; ++i)
if ((dirs == (i->compressedSize == size_t (-1))) &&
(recursive || full_match || i->path.empty()))
// Check basename matches pattern (pkg is case insensitive)
if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
ret->push_back(i->filename);
return ret;
}
//-----------------------------------------------------------------------
FileInfoListPtr PkgArchive::findFileInfo(const String& pattern,
bool recursive, bool dirs)
{
recursive = true;
dirs = false;
FileInfoListPtr ret = FileInfoListPtr(OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
// If pattern contains a directory name, do a full match
bool full_match = (pattern.find ('/') != String::npos) ||
(pattern.find ('//') != String::npos);
FileInfoList::iterator i, iend;
iend = mFileList.end();
for (i = mFileList.begin(); i != iend; ++i)
{
if ((dirs == (i->compressedSize == size_t (-1))) &&
(recursive || full_match || i->path.empty()))
{
//Check name matches pattern (pkg is case insensitive)
if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
{
ret->push_back(*i);
}
}
}
return ret;
}
//--------------------------------------------------------------------
//bool PkgArchive::exists(const String& filename)
//{
// PKG_STAT pkgstat;
// return mPkgDir->pkg_dir_stat( filename, &pkgstat );
//}
//---------------------------------------------------------------------
//-----------------------------------------------------------------------
bool PkgArchive::exists(const String& filename)
{
PKG_STAT pkgstat;
return mPkgDir->pkg_dir_stat( filename, &pkgstat );
}
//---------------------------------------------------------------------
time_t PkgArchive::getModifiedTime(const String& filename)
{
// Pkglib doesn't yet support getting the modification time of individual files
// so just check the mod time of the pkg itself
struct stat tagStat;
bool ret = (stat(mName.c_str(), &tagStat) == 0);
if (ret)
{
return tagStat.st_mtime;
}
else
{
return 0;
}
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
PkgDataStream::PkgDataStream(PKG_FILE* pkgFile, size_t uncompressedSize)
: mPkgFile(pkgFile)
{
mSize = uncompressedSize;
}
//-----------------------------------------------------------------------
PkgDataStream::PkgDataStream(const String& name, PKG_FILE* pkgFile, size_t uncompressedSize)
:DataStream(name), mPkgFile(pkgFile)
{
mSize = uncompressedSize;
}
//-----------------------------------------------------------------------
PkgDataStream::~PkgDataStream()
{
close();
}
//-----------------------------------------------------------------------
size_t PkgDataStream::read(void* buf, size_t count)
{
int r = mPkgFile->pkg_file_read((char*)buf, (int)count);
if (r<0)
{// 文件读取失败处理
return 0;
}
return (size_t) r;
}
//-----------------------------------------------------------------------
void PkgDataStream::skip(long count)
{
mPkgFile->pkg_seek(static_cast<long>(count));
}
//-----------------------------------------------------------------------
void PkgDataStream::seek( size_t pos )
{
mPkgFile->pkg_seek( static_cast<long>(pos));
}
//-----------------------------------------------------------------------
size_t PkgDataStream::tell(void) const
{
return mPkgFile->pkg_tell();
}
//-----------------------------------------------------------------------
bool PkgDataStream::eof(void) const
{
if ( (mPkgFile->GetFilePoint()))
{
return false;
}
return ( mPkgFile->pkg_tell() >= static_cast<unsigned long>(mSize) );
}
//-----------------------------------------------------------------------
void PkgDataStream::close(void)
{
mPkgFile->pkg_file_close();
}
//-----------------------------------------------------------------------
const String& PkgArchiveFactory::getType(void) const
{
static String name = "Pkg";
return name;
}
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/eaglewood2005/archive/2010/01/03/5123803.aspx