The chara.one in world.fs is an older type of chara.one. They were used in the PS1's FF8 demo and sometimes appear in the old, unlinked field archives, but the one in world.fs appears to be the only actual use of the old format in the final version.
Some details about the format. I don't know if this is the right term, but there's a "footer". To read it, you have to work backwards from the end of the file. Unlike the headers in standard chara.one files, all offsets are absolute, not relative.
import struct
import os.path
from os import mkdir
class genericEntry:
def __init__(self):
self.location = 0
self.size = 0
self.isNPC = False
self.MCHNumber = -1
self.TIMlocations = []
self.modelLoc = 0
self.sizeBeforeAnims = 0
self.anims = []
def unread(src):
loc = src.tell()
curResult = struct.unpack("<I", src.read(4))[0]
src.seek(loc - 4)
return curResult
name = raw_input('File name:')
src = open(name, 'rb')
charaEnd = struct.unpack("<I", src.read(4))[0]
src.seek(charaEnd - 4)
totalModels = unread(src)
models = []
for i in range(totalModels):
mdl = genericEntry()
firstNum = unread(src)
if (firstNum & 0xD0000000) == 0xD0000000:
mdl.MCHNumber = firstNum & 0xFFFF
mdl.location = unread(src)
else:
mdl.isNPC = True
mdl.TIMlocations.append(firstNum)
loc = unread(src)
while loc != 0xFFFFFFFF:
mdl.TIMlocations.append(loc)
loc = unread(src)
mdl.modelLoc = unread(src)
mdl.location = firstNum & 0xFFFFFF
models.append(mdl)
fillerplace = genericEntry()
fillerplace.location = src.tell() + 4
models.append(fillerplace)
if not os.path.exists("%s_extract" % (name)):
mkdir("%s_extract" % (name))
for i in range(totalModels):
src.seek(models[i].location)
curmdl = models[i]
rawdata = src.read(models[i + 1].location - models[i].location)
if curmdl.isNPC == True:
outmdl = open('%s_extract\\mdl%02d.mch' % (name, i), 'wb')
for offs in curmdl.TIMlocations:
outmdl.write(struct.pack("I", offs + 0x100 - curmdl.location))
outmdl.write(struct.pack("I", 0xFFFFFFFF))
outmdl.write(struct.pack("I", curmdl.modelLoc + 0x100 - curmdl.location))
while outmdl.tell() < 0x100:
outmdl.write(chr(0))
outmdl.write(rawdata)
outmdl.close()
else:
outmdl = open('%s_extract\\d%03d_anim.bin' % (name, curmdl.MCHNumber), 'wb')
outmdl.write(rawdata)
outmdl.close()
src.close()