Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os,sys,struct,zlib
- reload(sys)
- sys.setdefaultencoding('sjis')
- def get_data(filename):
- totalbytes = os.path.getsize(filename)
- infile = open(filename, 'rb')
- totalfiledata = infile.read(totalbytes)
- return totalfiledata
- def decrypt(filedata,adlr,start):
- xor = (adlr >> 0xc) & 0xFF
- for i in range(start,len(filedata)):
- filedata[i] = filedata[i] ^ xor
- return filedata
- def decrypt_scenario(filedata):
- newfiledata = ''
- lenremaining = len(filedata) % 0x2
- for i in range(0,len(filedata)-lenremaining,2):
- word = struct.unpack('<H',filedata[i:i+2])[0]
- word2 = word
- word &= 0x5555
- word2 &= 0xAAAAAAAA
- word2 = word2 >> 1
- word += word
- word = (word2 & 0xFFFF) | (word & 0xFFFF)
- newfiledata += struct.pack('<H',word)
- newfiledata += filedata[len(filedata)-lenremaining:]
- return newfiledata
- def extract_xp3(filenam):
- filedata = get_data(filenam)
- if struct.unpack('<B',filedata[0xb:0xc])[0] == 0x17:
- tocpos = struct.unpack('<Q',filedata[0x20:0x28])[0]
- else:
- tocpos = struct.unpack('<Q',filedata[0xb:0x13])[0]
- compchk = struct.unpack('<B',filedata[tocpos:tocpos+1])[0]
- toccomplen = struct.unpack('<Q',filedata[tocpos+1:tocpos+1+8])[0]
- if compchk == 1:
- tocuncomplen = struct.unpack('<Q',filedata[tocpos+1+8:tocpos+1+8+8])[0]
- tocpos += 17
- toc = zlib.decompress(filedata[tocpos:tocpos+toccomplen])
- else:
- tocpos += 9
- toc = filedata[tocpos:tocpos+toccomplen]
- pos = 0
- filecnt = 0
- while pos < len(toc):
- filelen = struct.unpack('<Q',toc[pos+4:pos+4+8])[0]
- pos += 12
- endpos = pos+filelen
- while pos < endpos:
- if toc[pos:pos+4] == 'info':
- infolen = struct.unpack('<Q',toc[pos+4:pos+4+8])[0]
- pos += 12
- encryptchk = struct.unpack('<I',toc[pos:pos+4])[0]
- uncompsize = struct.unpack('<Q',toc[pos+4:pos+12])[0]
- compsize = struct.unpack('<Q',toc[pos+12:pos+20])[0]
- filenamelen = struct.unpack('<H',toc[pos+20:pos+22])[0]
- pos += 22
- filename = toc[pos:pos+filenamelen*2]
- filename = filename.decode('utf-16')
- if filename.find('$$$') != -1:
- filename = '$$$ This is a protected archive $$$.txt'
- print 'Extracting %s' % filename
- pos += filenamelen*2
- while toc[pos:pos+1] == '\x00':
- pos += 1
- elif toc[pos:pos+4] == 'segm':
- segmentcnt = struct.unpack('<Q',toc[pos+4:pos+4+8])[0] / 28
- pos += 12
- segments = []
- for i in range(0,segmentcnt):
- segcompchk = struct.unpack('<I',toc[pos:pos+4])[0]
- segoffset = struct.unpack('<Q',toc[pos+4:pos+12])[0]
- seguncompsize = struct.unpack('<Q',toc[pos+12:pos+20])[0]
- segcompsize = struct.unpack('<Q',toc[pos+20:pos+28])[0]
- segments.append([segcompchk,segoffset,seguncompsize,segcompsize])
- pos += 28
- elif toc[pos:pos+4] == 'adlr':
- adlr = struct.unpack('<I',toc[pos+0xc:pos+0xc+4])[0]
- pos += 0xc+4
- elif toc[pos:pos+4] == 'time':
- pos += 12 + struct.unpack('<Q',toc[pos+4:pos+12])[0]
- else:
- print 'Unknown .xp3 file type %s at pos %x in file %s' % (toc[pos:pos+4],pos,filenam)
- sys.exit()
- newfiledata = ''
- for i in range(0,segmentcnt):
- if segments[i][0] == 0x1:
- newfiledata += zlib.decompress(filedata[segments[i][1]:segments[i][1]+segments[i][3]])
- else:
- newfiledata += filedata[segments[i][1]:segments[i][1]+segments[i][3]]
- startdecryptpos = 5
- scenariofile = False
- if (newfiledata[:1] == '\xff' and newfiledata[1:2] == '\xfe'):
- newfiledata = newfiledata[2:]
- startdecryptpos = 3
- elif (newfiledata[:1] == '\xfe' and newfiledata[1:2] == '\xfe'):
- if ord(newfiledata[2:3]) == 0x2:
- newfiledata = zlib.decompress(newfiledata[0x5:])
- startdecryptpos = 0
- else:
- newfiledata = newfiledata[5:]
- startdecryptpos = 0
- scenariofile = True
- #Encrypt var broken, just use adlr instead
- if (adlr != zlib.adler32(newfiledata) & 0xFFFFFFFF) and (filename.find('$$$') == -1):
- newfiledata = decrypt(bytearray(newfiledata),adlr,startdecryptpos)
- if scenariofile == True:
- newfiledata = decrypt_scenario(newfiledata)
- if not os.path.isdir(sys.argv[2].split('.',1)[0]):
- os.mkdir(sys.argv[2].split('.',1)[0])
- filepath = filename.split('/')
- newfolder = ''
- currpath = sys.argv[2].split('.',1)[0]
- for i in range(0,len(filepath)-1):
- if filepath[i] != '':
- if not os.path.isdir(currpath + '\\' + filepath[i]):
- os.mkdir(currpath + '\\' + filepath[i])
- currpath += '\\' + filepath[i]
- outfile = open(currpath + '\\' + filepath[len(filepath)-1],'wb')
- outfile.write(newfiledata)
- outfile.close()
- filecnt += 1
- def compile_xp3(infolder):
- toc = ''
- tochdr = '\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- #new ver
- newfiledata = '\x58\x50\x33\x0D\x0A\x20\x0A\x1A\x8B\x67\x01\x17\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00'
- #old ver
- #newfiledata = '\x58\x50\x33\x0D\x0A\x20\x0A\x1A\x8B\x67\x01'
- newfiledata += '\x00\x00\x00\x00\x00\x00\x00\x00' #toc loc
- #don't need this protect file in old ver
- newfiledata += '\x89\x50\x4E\x47\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53\xDE\x00\x00\x00\xA5\x74\x45\x58\x74\x57\x61\x72\x6E\x69\x6E\x67\x00'
- for root, dirs, files in os.walk(infolder):
- for filename in files:
- filedata = get_data(os.path.join(root,filename))
- uncompfilesize = len(filedata)
- adler = zlib.adler32(filedata) & 0xFFFFFFFF
- if filename.find('$$$') == -1:
- filedata = ''.join(map(chr,decrypt(bytearray(filedata),adler)))
- protectedfile = False
- else:
- protectedfile = True
- if filename.find('$$$') == -1:
- notcompressed = False
- filedata = zlib.compress(filedata,9)
- else:
- notcompressed = True
- compfilesize = len(filedata)
- filename1 = ''.join(os.path.join(root,filename)).encode('utf-16')
- filename1 = filename1[(len(sys.argv[2])*2)+4:]
- filename1 = filename1.replace('\\','/')
- #print filename1
- if protectedfile == False:
- #new ver
- tmpinfo = struct.pack('<I',0x80000000) #encryption flag
- #old ver
- #tmpinfo = struct.pack('<I',0x00000000) #encryption flag
- else:
- tmpinfo = struct.pack('<I',0x0) #encryption flag
- tmpinfo += struct.pack('<Q',uncompfilesize) #uncomp filesize
- tmpinfo += struct.pack('<Q',compfilesize) #comp filesize
- tmpinfo += struct.pack('<H',len(filename1) / 2) #filename len
- tmpinfo += filename1
- tmpsegm = 'segm'
- tmpsegm += struct.pack('<Q',0x1c)
- if notcompressed == False:
- tmpsegm += struct.pack('<I',0x1) #comp flag
- else:
- tmpsegm += struct.pack('<I',0x0) #comp flag
- tmpsegm += struct.pack('<Q',len(newfiledata)) #file offset
- tmpsegm += struct.pack('<Q',uncompfilesize) #uncomp filesize
- tmpsegm += struct.pack('<Q',compfilesize) #comp filesize
- tmpadlr = 'adlr'
- tmpadlr += struct.pack('<Q',0x4)
- tmpadlr += struct.pack('<I',adler)
- tmpfile = 'File'
- tmpfile += struct.pack('<Q',len(tmpinfo)+12+len(tmpsegm)+len(tmpadlr)) #File section len
- tmpfile += 'info'
- tmpfile += struct.pack('<Q',len(tmpinfo)) #info section len
- toc += tmpfile + tmpinfo + tmpsegm + tmpadlr
- newfiledata += filedata
- tochdr = tochdr[:9] + struct.pack('<Q',len(toc))
- toc = zlib.compress(toc,9)
- tochdr = tochdr[:1] + struct.pack('<Q',len(toc)) + tochdr[9:]
- #new ver
- newfiledata = newfiledata[:0x20] + struct.pack('<Q',len(newfiledata)) + newfiledata[0x28:]
- #old ver
- #newfiledata = newfiledata[:0xb] + struct.pack('<Q',len(newfiledata)) + newfiledata[0x13:]
- newfiledata += tochdr + toc
- outfile = open(infolder + '.xp3','wb')
- outfile.write(newfiledata)
- outfile.close()
- if __name__ == '__main__':
- if sys.argv[1] == '-e':
- extract_xp3(sys.argv[2])
- elif sys.argv[1] == '-c':
- compile_xp3(sys.argv[2])
- else:
- print 'Usage: -e/-c <filename/foldername>'
- print '-e: Extract .xp3 archive'
- print '-c: Compile a folder to .xp3 archive'
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement