pkg文件--一种简单的游戏资源打包格式

来源:互联网 发布:南木梁知txt 编辑:程序博客网 时间:2024/06/07 03:35

.pkg文件的格式

[四字节] 固定的内容, 值不重要
[四字节] 文件数目(unsigned int)
[四字节] 文件名表 的偏移(unsigned int)
[四字节] 文件名表 的长度(字节数)(unsigned int)
……
中间一堆 各个文件的内容, 文件内容使用zlib压缩过
……
直到
文件名表:
[两字节] 文件名长度
[文件名长度那么多字节] 文件名
[四字节] 固定的内容,值不重要
[四字节] 文件原长度
[四字节] 文件偏移
[四字节] 文件压缩后的长度
[两字节] 又一个文件名的长度

例程:
打包 PKGEncode.py
用法 python PKGEncode.py dirname pathname.pkg

# -*- coding: utf-8 -*-import zlib, glob, os, sys, structfilelist = []class FileVisitor:    def __init__(self, startDir=os.curdir):        self.startDir = startDir    def run(self):        for dirname, subdirnames, filenames in os.walk(self.startDir, True):            for filename in filenames:                self.visit_file(os.path.join(dirname, filename))    def visit_file(self, pathname):        filelist.append({'filename':pathname, 'size':0, 'zlib_size':0, 'offset':0, 'relative_filename': pathname.replace(os.path.normpath(self.startDir)+os.sep, '')})        #print filelist[-1]['relative_filename']if __name__ == "__main__":    if len(sys.argv[1]) < 3:        print 'few parameter'    else:        source_dirname = sys.argv[1]        out_filename = sys.argv[2]        FileVisitor(source_dirname).run()        total = len(filelist)        fp = file(out_filename + '~', 'wb')        fp.write('\x64\x00\x00\x00')        fp.write(struct.pack('I', len(filelist)))        fp.write(struct.pack('I', 0))        fp.write(struct.pack('I', 0))        offset = 16        for index in range(total):            item = filelist[index]            item['offset'] = offset            infile = file(item['filename'], 'rb')            text = infile.read()            infile.close()            item['size'] = len(text)            text = zlib.compress(text)            item['zlib_size'] = len(text)            fp.write(text)            offset += item['zlib_size']            print u'已压缩文件 %d/%d' % (index+1, total)        filename_table_offset = offset        for index in range(total):            item = filelist[index]            fp.write(struct.pack('H', len(item['relative_filename'])))            fp.write(item['relative_filename'])            fp.write('\x01\x00\x00\x00')            fp.write(struct.pack('I', item['offset']))            fp.write(struct.pack('I', item['size']))            fp.write(struct.pack('I', item['zlib_size']))            offset += 2 + len(item['relative_filename']) + 16            print u'已输出路径 %d/%d' % (index+1, total)        filename_table_len = offset - filename_table_offset        fp.close()        fp = file(out_filename + '~', 'rb')        ret = file(out_filename, 'wb')        fp.read(16)        ret.write('\x64\x00\x00\x00')        ret.write(struct.pack('I', len(filelist)))        ret.write(struct.pack('I', filename_table_offset))        ret.write(struct.pack('I', filename_table_len))        copy_bytes = 16        total_bytes = offset        while True:            text = fp.read(2**20)            ret.write(text)            copy_bytes += len(text)            print u'最后的拷贝 %d%%' % (copy_bytes*100.0/total_bytes)            if not text:                break        fp.close()        ret.close()        os.remove(out_filename + '~')

解包 PKGDecode.py
用法 python PKGDecode.py pathname.pkg dirname

# -*- coding: utf-8 -*-import sys, os, struct, zlibif __name__ == "__main__":    if len(sys.argv) < 3:        print 'few argument'    else:        pkgfilename = sys.argv[1]        outdirname = sys.argv[2]        pkgfile = file(pkgfilename, 'rb')        pkgfile.read(4)        filenums, = struct.unpack('I', pkgfile.read(4))        filename_table_offset, = struct.unpack('I', pkgfile.read(4))        filename_table_len, = struct.unpack('I', pkgfile.read(4))        pkgfile.seek(filename_table_offset)        for index in range(filenums):            name_len, = struct.unpack('H', pkgfile.read(2))            name = pkgfile.read(name_len)            pkgfile.read(4)            offset, = struct.unpack('I', pkgfile.read(4))            size, = struct.unpack('I', pkgfile.read(4))            zlib_size, = struct.unpack('I', pkgfile.read(4))            current_pos = pkgfile.tell()            pkgfile.seek(offset)            text = pkgfile.read(zlib_size)            text = zlib.decompress(text)            pkgfile.seek(current_pos)            outfilename = os.path.join(outdirname, os.path.join(os.path.splitext(os.path.basename(pkgfilename))[0], name))            print u'进度 [%d/%d]: ' %(index+1, filenums), os.path.join(os.path.splitext(os.path.basename(pkgfilename))[0], name)            if not os.path.exists(os.path.dirname(outfilename)):                os.makedirs(os.path.dirname(outfilename))            file(outfilename, 'wb').write(text)

感谢python各种库的方便
这两个程序也可以作为自己的压缩解压工具

0 0