[SEGA, NiGHTS, PRS] Decompressing PRS in python

  • Thread starter Thread starter Micky
  • Start date Start date
Status
Not open for further replies.
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]
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()
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.
 
Nice. I can see this being adapted into a Python LZS decompressor.

Also, good luck on working with NiGHTS. I woudn't mind seeing a few mods, actually...
 
Oh noes no more Xenogears viewer? err Updates? I am greedy thats all don't mind me good work.
 
Oh noes no more Xenogears viewer? err Updates? I am greedy thats all don't mind me good work.
Are you after anything specific? I've seen the q-gears documentation has some more information, but I haven't looked through it, yet.
 
Status
Not open for further replies.
Back
Top