Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Last active October 10, 2023 06:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uyjulian/bb0400c3768ea33be395a22df61a0c70 to your computer and use it in GitHub Desktop.
Save uyjulian/bb0400c3768ea33be395a22df61a0c70 to your computer and use it in GitHub Desktop.
# SPDX-License-Identifier: MIT
# Script to extract and decompress data from Trails in the Sky / Sora no Kiseki dat/dir files.
# Better code have been released since then; see Trails Research Group: https://github.com/Trails-Research-Group
import sys
import os
import mmap
import struct
def open_and_map(filename):
# mmap filename
pass
def decompress(buffer, output, size):
offset = 0 # u16
bits = 8 # 8 to start off with, then 16
flags = int.from_bytes(buffer[offset:offset + 2], byteorder="little")
offset += 2
flags >>= 8
outputoffset = 0 # u16
def getflag():
nonlocal bits
nonlocal flags
nonlocal offset
if bits == 0:
slice_ = buffer[offset:offset + 2]
if len(slice_) < 2:
raise Exception("Out of data")
flags = int.from_bytes(slice_, byteorder="little")
offset += 2
bits = 16
flag = flags & 1
flags >>= 1
bits -= 1
return flag
def setup_run(prev_u_buffer_pos):
nonlocal offset
nonlocal buffer
nonlocal output
nonlocal outputoffset
run = 2 # u16
if getflag() == 0:
run += 1
if getflag() == 0:
run += 1
if getflag() == 0:
run += 1
if getflag() == 0:
if getflag() == 0:
slice_ = buffer[offset:offset + 1]
if len(slice_) < 1:
raise Exception("Out of data")
run = int.from_bytes(slice_, byteorder="little")
offset += 1
run += 0xE
else:
run = 0
for i in range(3):
run = (run << 1) | getflag()
run += 0x6
# Does the 'copy from buffer' thing
for i in range(run):
output[outputoffset] = output[outputoffset - prev_u_buffer_pos]
outputoffset += 1
while True:
if getflag() != 0: # Call next method to process next flag
if getflag() != 0: # Long look-back distance or exit program or repeating sequence (flags = 11)
run = 0 # u16
for i in range(5): # Load high-order distance from flags (max = 0x31)
run = (run << 1) | getflag()
prev_u_buffer_pos = int.from_bytes(buffer[offset:offset + 1], byteorder="little") # Load low-order distance (max = 0xFF)
# Also acts as flag byte
# run = 0 and byte = 0 -> exit program
# run = 0 and byte = 1 -> sequence of repeating bytes
offset += 1
if run != 0:
prev_u_buffer_pos = prev_u_buffer_pos | (run << 8) # Add high and low order distance (max distance = 0x31FF)
setup_run(prev_u_buffer_pos) # Get run length and finish unpacking (write to output)
elif prev_u_buffer_pos > 2: # Is this used? Seems inefficient.
setup_run(prev_u_buffer_pos)
elif prev_u_buffer_pos == 0: # Decompression complete. End program.
break
else: # Repeating byte
branch = getflag() # True = long repeating sequence (> 30)
for i in range(4):
run = (run << 1) | getflag()
if branch != 0:
run = (run << 0x8) | int.from_bytes(buffer[offset:offset + 1], byteorder="little") # Load run length from byte and add high-order run length (max = 0xFFF + 0xE)
offset += 1
run += 0xE
output[outputoffset:outputoffset + run] = bytes(buffer[offset:offset + 1]) * run
offset += 1
outputoffset += run
else: # Short look-back distance (flags = 10)
prev_u_buffer_pos = int.from_bytes(buffer[offset:offset + 1], byteorder="little") # Get the look-back distance (max = 0xFF)
offset += 1
setup_run(prev_u_buffer_pos) # Get run length and finish unpacking (write to output)
else: # Copy byte (flags = 0)
output[outputoffset:outputoffset + 1] = buffer[offset:offset + 1]
outputoffset += 1
offset += 1
return outputoffset, offset
def decompress2(buffer, output, size):
offset = 0 # u32
outputoffset = 0 # u16
while size > (offset + 2):
save1 = int.from_bytes(buffer[offset:offset + 1], byteorder="little")
offset += 1
if (save1 & 0x80) == 0:
if (save1 & 64) == 0:
length = save1 & 31
if (save1 & 32) == 0:
output[outputoffset:outputoffset + length] = buffer[offset:offset + length]
outputoffset += length
offset += length
else:
length = (length << 8) + int.from_bytes(buffer[offset:offset + 1], byteorder="little")
offset += 1
output[outputoffset:outputoffset + length] = buffer[offset:offset + length]
outputoffset += length
offset += length
else:
if (save1 & 16) == 0:
length = (save1 & 15) + 4
fillbyte = bytes(buffer[offset:offset + 1])
output[outputoffset:outputoffset + length] = fillbyte * length
offset += 1
outputoffset += length
else:
length = ((save1 & 15) << 8) + int.from_bytes(buffer[offset:offset + 1], byteorder="little") + 4
offset += 1
fillbyte = bytes(buffer[offset:offset + 1])
offset += 1
output[outputoffset:outputoffset + length] = fillbyte * length
outputoffset += length
else:
lookbacklength = ((save1 & 31) << 8) + int.from_bytes(buffer[offset:offset + 1], byteorder="little")
offset += 1
save2 = offset
lookbackptr = (outputoffset - lookbacklength)
length = ((save1 >> 5) & 3) + 4
if size > (offset + 2):
save3 = int.from_bytes(buffer[save2:save2 + 1], byteorder="little")
while ((save3 & 0xe0) == 96):
length += (save3 & 31)
offset += 1
if size <= (offset + 2):
save3 = 0
else:
save3 = int.from_bytes(buffer[offset:offset + 1], byteorder="little")
if lookbacklength < length:
for i in range(length): # this needs to be copied in this specific way:
output[outputoffset:outputoffset + 1] = output[lookbackptr:lookbackptr + 1]
outputoffset += 1
lookbackptr += 1
else:
output[outputoffset:outputoffset + length] = output[lookbackptr: lookbackptr + length]
outputoffset += length
if size != (offset + 2):
raise Exception("Malformed input")
return outputoffset, offset
output = bytearray(65535)
def decompress_FALCOM2_1(indata, pipi, length):
buffer = bytearray(length) # Should already be initialized with 0
buffer[0:length] = indata[0:length]
offset = 0 # u32
while len(buffer) > offset:
size = int.from_bytes(buffer[offset:offset + 2], byteorder="little")
offset += 2
if size == 0:
break
num1 = 0
output[0:len(output)] = b"\x00" * len(output)
if int.from_bytes(buffer[offset:offset + 1], byteorder="little") == 0:
num1, num2 = decompress(buffer[offset:offset + size], output, size)
offset += num2
else:
num1, num2 = decompress2(buffer[offset:offset + size], output, size)
offset += num2
pipi.write(output[0:num1])
flag = int.from_bytes(buffer[offset:offset + 1], byteorder="little")
offset += 1
if flag == 0:
break
return
inbuf_f = open(sys.argv[1], "rb")
inbuf = mmap.mmap(inbuf_f.fileno(), 0, prot=mmap.PROT_READ)
# print(sys.argv[1])
if inbuf[:6] != b"LB DIR":
raise Exception("not lb dir")
inoffset = 0
inoffset += 8
numentries = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
shouldbezero = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
if shouldbezero != 0:
raise Exception("zero not detect")
filels = []
for i in range(numentries):
filename = inbuf[inoffset:inoffset + 12]
inoffset += 12
timestamp2 = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
compress_size = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
uncompress_size = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
num5 = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
timestamp = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
offset = int.from_bytes(inbuf[inoffset:inoffset + 4], byteorder="little")
inoffset += 4
# print(filename, timestamp2, compress_size, uncompress_size, num5, timestamp, offset)
if filename != b"/_______.___" and filename[-4:-3] == b".":
# print(filename, timestamp2, compress_size, uncompress_size, num5, timestamp, offset)
d = {
"filename": filename,
"compress_size" : compress_size,
"uncompress_size" : uncompress_size,
"timestamp" : timestamp,
"offset" : offset,
}
filels.append(d)
dirname = sys.argv[1][0:-4]
inbufdat_f = open(dirname + ".dat", "rb")
infotbl = [
# Font files (most cases, pointless to convert, takes too much time)
{ "regex":r"FONT8\._DA", "bytes":1, "xres":8, "yres":3316, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT12\._DA", "bytes":1, "xres":12, "yres":43566, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT16\._DA", "bytes":1, "xres":16, "yres":58088, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT18\._DA", "bytes":1, "xres":18, "yres":65445, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT20\._DA", "bytes":1, "xres":20, "yres":72610, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT24\._DA", "bytes":1, "xres":24, "yres":87132, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT26\._DA", "bytes":1, "xres":26, "yres":94489, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT30\._DA", "bytes":1, "xres":30, "yres":109011, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT32\._DA", "bytes":1, "xres":32, "yres":116176, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT36\._DA", "bytes":1, "xres":36, "yres":130698, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT40\._DA", "bytes":1, "xres":40, "yres":145220, "imfmt":"gray", "imbits":8}, # TODO: calculated using proportions; verify
{ "regex":r"FONT44\._DA", "bytes":1, "xres":44, "yres":159742, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT48\._DA", "bytes":1, "xres":48, "yres":174264, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT50\._DA", "bytes":1, "xres":50, "yres":181621, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT54\._DA", "bytes":1, "xres":54, "yres":196143, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT60\._DA", "bytes":1, "xres":60, "yres":217830, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT64\._DA", "bytes":1, "xres":64, "yres":232352, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT72\._DA", "bytes":1, "xres":72, "yres":26496, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT80\._DA", "bytes":1, "xres":80, "yres":29440, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT96\._DA", "bytes":1, "xres":96, "yres":35328, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT128\._DA", "bytes":1, "xres":128, "yres":47104, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT144\._DA", "bytes":1, "xres":144, "yres":52992, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT160\._DA", "bytes":1, "xres":160, "yres":58880, "imfmt":"gray", "imbits":8},
{ "regex":r"FONT192\._DA", "bytes":1, "xres":192, "yres":70656, "imfmt":"gray", "imbits":8},
{ "regex":r"C_STCH\d\d\._CH", "bytes":4, "xres":512, "yres":512, "imfmt":"bgra", "imbits":8},
{ "regex":r"H_STCH\d\d\._CH", "bytes":4, "xres":1024, "yres":1024, "imfmt":"bgra", "imbits":8},
{ "regex":r"C_STCHR\d\._CH", "bytes":4, "xres":512, "yres":512, "imfmt":"bgra", "imbits":8},
{ "regex":r"H_STCHR\d\._CH", "bytes":4, "xres":1024, "yres":1024, "imfmt":"bgra", "imbits":8},
{ "regex":r"C_SUBTI\._CH", "bytes":4, "xres":256, "yres":256, "imfmt":"bgra", "imbits":8},
{ "regex":r"H_SUBTI\._CH", "bytes":4, "xres":512, "yres":512, "imfmt":"bgra", "imbits":8},
{ "regex":r"C_PASELE\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba4444"},
{ "regex":r"H_PASELE\._CH", "bytes":2, "xres":1024, "yres":1024, "fmt":"rgba4444"},
{ "regex":r"C_CAMP02\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{ "regex":r"C_CAMP03\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT00", "regex":r"C_CAMP04\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT00", "regex":r"H_CAMP04\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba1555"},
{ "regex":r"BFACE\d\d\d\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{ "regex":r"HFACE\d\d\d\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba1555"},
{ "regex":r"CTI\d\d\d\d\d\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{ "regex":r"H_CAMP02\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba1555"},
{ "regex":r"H_CAMP03\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba1555"},
{ "regex":r"C_MNBG01\._CH", "bytes":2, "xres":128, "yres":128, "fmt":"rgba4444"},
{ "regex":r"CA\d\d\d\d\d\._CH", "bytes":2, "xres":128, "yres":128, "fmt":"rgba1555"},
{ "regex":r"CA\d\d\d\d\d\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "regex":r"C_VIS419\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS438\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS439\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS448\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS478\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS530\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS531\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS532\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS533\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS534\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS535\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS536\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS537\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS538\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS539\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS540\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS541\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_VIS542\._CH", "bytes":2, "xres":512, "yres":768, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_MAP010\._CH", "bytes":2, "xres":512, "yres":1024, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_MAP011\._CH", "bytes":2, "xres":512, "yres":1024, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_PLAC\d\d\._CH", "bytes":2, "xres":256, "yres":256, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_PLAC\d\d\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_PLAC\d\d\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_TITLE1\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_TITLE2\._CH", "bytes":2, "xres":512, "yres":1024, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_TITLE3\._CH", "bytes":2, "xres":512, "yres":512, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"C_TITLE4\._CH", "bytes":2, "xres":512, "yres":1024, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_MAP010\._CH", "bytes":2, "xres":1024, "yres":2048, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_MAP011\._CH", "bytes":2, "xres":1024, "yres":2048, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_MAP012\._CH", "bytes":2, "xres":1024, "yres":2048, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_TITLE1\._CH", "bytes":2, "xres":1024, "yres":1024, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_VIS419\._CH", "bytes":2, "xres":1024, "yres":1536, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_VIS438\._CH", "bytes":2, "xres":1024, "yres":1536, "fmt":"rgba4444"},
{"dir":"ED6_DT24", "regex":r"H_VIS439\._CH", "bytes":2, "xres":1024, "yres":1536, "fmt":"rgba4444"},
{"dir":"ED6_DT04", "bytes":2, "xres":512, "yres":512, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":512, "yres":512, "fmt":"rgba1555"},
{"dir":"ED6_DT04", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT05", "bytes":2, "xres":128, "yres":128, "fmt":"rgba1555"},
{"dir":"ED6_DT25", "bytes":2, "xres":128, "yres":128, "fmt":"rgba1555"},
{"dir":"ED6_DT05", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT25", "bytes":2, "xres":256, "yres":256, "fmt":"rgba1555"},
{"dir":"ED6_DT04", "bytes":2, "xres":512, "yres":768, "fmt":"rgba1555"},
{"dir":"ED6_DT04", "bytes":2, "xres":1024, "yres":1536, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":512, "yres":768, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":1024, "yres":1536, "fmt":"rgba1555"},
{"dir":"ED6_DT04", "bytes":2, "xres":1024, "yres":2048, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":1024, "yres":2048, "fmt":"rgba1555"},
{"dir":"ED6_DT04", "bytes":2, "xres":512, "yres":1024, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":512, "yres":1024, "fmt":"rgba1555"},
{"dir":"ED6_DT04", "bytes":2, "xres":1024, "yres":1024, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":1024, "yres":1024, "fmt":"rgba1555"},
{"dir":"ED6_DT24", "bytes":2, "xres":256, "yres":512, "fmt":"rgba1555"},
{ "bytes":2, "xres":1024, "yres":1024, "fmt":"rgba4444"},
{ "bytes":2, "xres":176, "yres":208, "fmt":"rgba4444"},
{ "bytes":2, "xres":352, "yres":416, "fmt":"rgba4444"},
{ "bytes":2, "xres":256, "yres":256, "fmt":"rgba4444"},
{ "bytes":2, "xres":512, "yres":512, "fmt":"rgba4444"},
]
def stdincmd(s, cmd):
pass
def c8888topngfile(outfile, sizew, sizeh, depth, fmt, s):
pass
def mkddsheader(width, height, rflag, gflag, bflag, aflag, bits):
return b"DDS\x20" + struct.pack("<IIIIIIIIIIIIIIIIIIIIIIIIIIIIIII", 124, 0x1 | 0x2 | 0x4 | 0x1000 | 0x8, width, height, (height * bits + 7) // 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, (0x1 if (aflag != 0) else 0x0) | 0x40, 0, bits, rflag, gflag, bflag, aflag, 0x1000, 0, 0, 0, 0)
def dds_process(fname, blob):
if blob[0:3] == b"DDS":
with open(fname, "wb") as wf:
wf.write(blob)
return True
return False
def infoenum(dirname, fileinfo, blob, rawdata):
fname = dirname + b"/" + fileinfo["filename"].replace(b" ", b"")
if (fname[-3:] != "_CH") and (fname[-3:] != "_DS") and (fname[-3:] != "_DA"):
return False
if dds_process(fname, blob):
return True
for v in infotbl:
if v["regex"]:
# TODO: regex
continue
if v["bytes"]:
if (v["bytes"] * v["xres"] * x["yres"]) != len(blob):
continue
if v["dir"]:
if v["dir"] != dirname[-8:]:
continue
if v["fmt"]:
if v["fmt"] == "rgba4444":
dds_process(fname, mkddsheader(v["xres"], v["yres"], 0x0f00, 0x00f0, 0x000f, 0xf000, 16) + blob)
elif v["fmt"] == "rgba1555":
dds_process(fname, mkddsheader(v["xres"], v["yres"], 0x7c00, 0x03e0, 0x001f, 0x8000, 16) + blob)
else:
c8888topngfile(fname[0:-5], v["xres"], v["yres"], v["imbits"], v["imfmt"], blob)
return True
return False
os.makedirs(dirname, exist_ok=True)
# print(dirname)
# flush stdout
for v in filels:
if v["compress_size"] == 0:
continue
if v["uncompress_size"] == 0:
continue
fname = dirname + "/" + v["filename"].replace(b" ", b"").decode("ASCII")
if (fname[-3:] == "_CH" or fname[-3:] == "_DS" or fname[-3:] == "_DA") and (os.path.isfile(fname[0:-5] + ".png")):
continue
if os.path.isfile(fname):
continue
# print("FILE:", dirname, fname)
inbufdat_f.seek(v["offset"])
rawdata = inbufdat_f.read(v["compress_size"])
if dds_process(fname, rawdata):
continue
if (v["compress_size"] != v["uncompress_size"]) or ((dirname[-8:] != "ED6_DT16") and (fname[-3:] == "_X2")) or (fname[-3:] in ["_X3", "_OP", "_CL", "_CT", "_EF", "_EN", "_EP", "_HD", "_LM", "_MH"]):
with open(fname, "wb") as wf:
decompress_FALCOM2_1(rawdata, wf, v["compress_size"])
# if dcdata == None or dcdata == b"":
# raise Exception("No data")
# else:
# # if not (os.path.isfile(fname + ".raw"))
# # with open(fname + ".raw", "wb") as wf:
# # wf.write(dcdata)
# # if not (os.path.isfile(fname + ".dec"))
# # with open(fname + ".dec", "wb") as wf:
# # wf.write(dcdata)
# # if not infoenum(dirname, v, dcdata, rawdata)
# # with open(fname, "wb") as wf:
# # wf.write(dcdata)
# with open(fname, "wb") as wf:
# wf.write(dcdata)
else:
if (fname[-3:] == "_DS"):
with open(fname, "wb") as wf:
decompress_FALCOM2_1(rawdata, wf, v["compress_size"])
# with open(fname, "wb") as wf:
# wf.write(dcdata)
else:
with open(fname, "wb") as wf:
wf.write(rawdata[0:v["uncompress_size"]])
os.utime(fname, (v["timestamp"], v["timestamp"]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment