M
Micky
Guest
This is both kind-of on and off topic... I plan to investigate what kind of data I can extract from Panzer Dragoon Saga, and one of the few Sega-internal formats is PRS. I found a closed-source decompressor, and a few open-source (in cpp and c#) that seemed to be unnecessarily complicated. I implemented this routine in python so that other people have a better reference, and I can investigate Saga. I compared the output on NiGHTS with the closed-source decompressor, and the result is identical.
Unfortunately I don't have a model or texture viewer, yet.
(On-topic because the algorithm is based on LZS similar to Xenogears and FF7, so maybe useful if this extension was picked up by square.)
Code: (python) [Select]
No fancy user interface, you'll have to fix the path to your data in the main routine, or integrate it into your own framework.
Unfortunately I don't have a model or texture viewer, yet.
(On-topic because the algorithm is based on LZS similar to Xenogears and FF7, so maybe useful if this extension was picked up by square.)
Code: (python) [Select]
Code:
# SEGA PRS Decompression (LZS variant)# Credits:# based on information/comparing output with # Nemesis/http://www.romhacking.net/utils/671/# puyotools/http://code.google.com/p/puyotools/# fuzziqer software prs/http://www.fuzziqersoftware.com/projects.phpimport arrayclass DecompressPrs: def __init__(self, data): self.ibuf = array.array("B", data) self.obuf = array.array("B") self.iofs = 0 self.bit = 0 self.cmd = 0 def getByte(self): val = self.ibuf[self.iofs] self.iofs += 1 return val def getBit(self): if self.bit == 0: self.cmd = self.getByte() self.bit = 8 bit = self.cmd & 1 self.cmd >>= 1 self.bit -= 1 return bit def decompress(self): while self.iofs < len(self.ibuf): cmd = self.getBit() if cmd: self.obuf.append(self.ibuf[self.iofs]) self.iofs += 1 else: t = self.getBit() if t: a = self.getByte() b = self.getByte() offset = ((b << 8) | a) >> 3 amount = a & 7 if self.iofs < len(self.ibuf): if amount == 0: amount = self.getByte() + 1 else: amount += 2 start = len(self.obuf) - 0x2000 + offset else: amount = 0 for j in xrange(2): amount <<= 1 amount |= self.getBit() offset = self.getByte() amount += 2 start = len(self.obuf) - 0x100 + offset for j in xrange(amount): if start < 0: self.obuf.append(0) elif start < len(self.obuf): self.obuf.append(self.obuf[start]) else: self.obuf.append(0) start += 1 return self.obuf.tostring() def main(): import glob, os list = glob.glob("NiGHTS/*.PRS") for file in list: f = open(file, "rb") data = f.read() f.close() prs = DecompressPrs(data) data = prs.decompress() outfile = os.path.splitext(file)[0] + ".bin" f = open(outfile, "wb") f.write(data) f.close()if __name__ == "__main__": main()