einstein/einsteingame/resources.py

128 lines
3.8 KiB
Python

from os import listdir
import struct
import io
from .buffer import Buffer
from .i18n import splitFileName, getScore, locale
class ResourceError(Exception):
def __init__(self, code=None):
self.code = code
class ResourceFile(object):
def __init__(self, fileName, buf=None):
self.__name = fileName
if buf is not None:
buffer = buf
ownBuffer = False
else:
buffer = Buffer()
ownBuffer = True
try:
self.__stream = open(self.__name, 'rb')
sign = self.__stream.read(4)
if sign != b'CRF\x00':
raise ResourceError(code='invalid')
major = self.readInt()
minor = self.readInt()
priority = self.readInt()
if major != 2 or minor < 0:
raise ResourceError(code='incompatible')
except ResourceError as e:
raise Exception("Invalid resource file: {}".format(e.code))
except IOError as e:
raise Exception("Error loading resource file '{}': {}".format(self.__name, e.message))
def readInt(self):
return struct.unpack('i', self.__stream.read(4))[0]
def readString(self):
string = b''
while True:
b = self.__stream.read(1)
if b == b'\x00' or b == b'':
break
string += b
return string.decode('ascii')
def getDirectory(self):
try:
self.__stream.seek(-8, io.SEEK_END);
except IOError:
raise Exception("Error reading {} directory".format(self.__name))
start = self.readInt()
count = self.readInt()
try:
self.__stream.seek(start, io.SEEK_SET);
except IOError:
raise Exception("Error reading {} directory".format(self.__name))
directory = []
try:
for i in range(0, count):
directory.append({
"name": self.readString(),
"unpackedSize": self.readInt(),
"offset": self.readInt(),
"packedSize": self.readInt(),
"level": self.readInt(),
"group": self.readString(),
})
except IOError:
raise Exception("Error reading {} directory".format(self.__name))
return directory
class ResourcesCollection:
def __init__(self, directories):
self.__files = []
self.__buffer = None
self.__resources = {}
self.loadResourceFiles(directories)
self.processFiles()
def loadResourceFiles(self, directories):
for directory in directories:
try:
for name in listdir(directory):
if not name.startswith('.') and name.endswith('.res'):
self.__files.append(
ResourceFile(directory + '/' + name,
buf=self.__buffer))
except OSError:
pass
def processFiles(self):
for res_file in self.__files:
directory = res_file.getDirectory()
for de in directory:
name, ext, language, country = splitFileName(de['name'])
score = getScore(language, country, locale)
if score > 0:
resName = name + '.' + ext
res = self.__resources.get(resName, None)
if not res:
res = Resource(res_file, score, de, resName)
self.__resources[resName] = res
if len(de.group) > 0:
groups[de.group].append(res)
else:
res.addVariant(file, score, de)
directory.clear()