Обитель Злобного Гения
Сборник гениальных идей, рецептов, мыслей и изобретений
-
Ethornell (BGI) package extractor
Posted on May 15th, 2010 No commentsA Python script to extract files from packages used by the Ethornell BGI (Buriko) engine. Has been successfully used to extract some music in Ogg Vorbis format.
import struct, os from optparse import OptionParser class Unpacker: files = [] def __init__(self, options, file): self.opts = options self.file = file self.readtoc(file) if self.opts.verbose: print "There are %d files in the package" % (len(self.files)) def readfmt(self, format): return struct.unpack(format, self.input.read(struct.calcsize(format))) def sizefmt(self, num): for x in ['bytes','KB','MB','GB','TB']: if num < 1024.0: return "%3.1f%s" % (num, x) num /= 1024.0 def entryfmt(self, entry): name, offset, size, zero = entry; assert(zero == 0) return (name.rstrip("\x00"), offset, size) def entryrepr(self, entry): (name, offset, size) = entry; return "%s (%s)" % (name, self.sizefmt(size)) def readtoc(self, file): self.input = open(file, "rb") header, count = self.readfmt("12sl") assert(header.rstrip() == "PackFile") for n in range(0, count): entry = self.entryfmt(self.readfmt("16sllQ")) self.files.append(entry) if self.opts.list: print self.entryrepr(entry) optsize = self.readfmt("l")[0] # heuristics to detect presence of the data block if (optsize != 64): optdata = False self.input.seek(-4, os.SEEK_CUR) else: optdata = True self.input.seek(optsize - 4, os.SEEK_CUR) def extract(self, ext, dir): self.data_offset = self.input.tell() if os.path.isdir(dir) == False: os.mkdir(dir) if self.opts.verbose: print "data offset: %d" % (self.data_offset) for file in self.files: (name, offset, size) = file dest = "%s/%s.%s" % (dir, name, ext) print "extracting: %s to %s" % (self.entryrepr(file), dest) self.extractf(dest, offset, size) def extractf(self, dest, offset, size): output = open(dest, "wb") self.input.seek(self.data_offset) self.input.seek(offset, 1) output.write(self.input.read(size)) output.close() def main(): usage = "usage: %prog [options] args" parser = OptionParser(usage) parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="show verbose output") parser.add_option("-l", "--list", action="store_true", dest="list", help="list package contents") parser.add_option("-e", "--extension", dest="extension", help="append EXTENSION to output files") parser.add_option("-x", "--extract", action="store_true", dest="extract", help="extract package contents") parser.add_option("-d", "--directory", dest="directory", help="extract into the specified directory") parser.set_defaults(directory=".", extension="dat") (options, args) = parser.parse_args() if len(args) != 1: parser.error("incorrect number of arguments") unpacker = Unpacker(options, args[0]) if options.extract: unpacker.extract(options.extension, options.directory) if __name__ == "__main__": main()

