summaryrefslogtreecommitdiff
path: root/tools/packageISO.py
blob: ad2f222172a894a86704879e65789b74f0021ccc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import sys
import os
from pathlib import Path
import struct

def addPaddingToFile(file,padding):
    file.write(bytearray(padding - (file.tell() % padding)))

def sortFileList(x):
    l = []
    for c in x:
        c = ord(c.lower())
        if c==ord('_'):
            l.append(255)
        else:
            l.append(c)
    return l

def parseDir(dir,stringTable,currentEntryNum,parent):
    os.chdir(dir)
    entries = sorted(os.listdir('./'), key=sortFileList)
    table = []
    for entry in entries:
        currentEntryNum = currentEntryNum + 1
        tableEntry = {"name": entry, "children": None, "size": None,"stringTableOffset": len(stringTable),"entryNum": currentEntryNum,"parent": parent, "path": None}
        stringTable = stringTable+entry+"\0"
        if os.path.isdir(entry):
            tableEntry["children"],stringTable,currentEntryNum = parseDir(entry,stringTable,currentEntryNum,tableEntry)
        else:
            tableEntry["size"] = os.path.getsize(entry)
            tableEntry["path"] = os.path.abspath(entry)
        
        table.append(tableEntry)
    os.chdir("..")
    return table,stringTable,currentEntryNum

def recurseWriteFst(files,fstBin,isoFile):
    for currentFile in files:
        if currentFile["children"]: #is a directory
            nextDirEntryNum = 0
            testLastEntryFile = currentFile["children"][-1]
            parentEntryNum = 0
            while True:
                if testLastEntryFile["children"]:
                    testLastEntryFile = testLastEntryFile["children"][-1]
                else:
                    nextDirEntryNum = testLastEntryFile["entryNum"]+1
                    break
            if currentFile["parent"]:
                parentEntryNum = currentFile["parent"]["entryNum"]
            fstBin.append(struct.pack(">BBHII",1,(currentFile["stringTableOffset"]>>16)&0xFF,currentFile["stringTableOffset"]&0xFFFF,parentEntryNum,nextDirEntryNum))
            recurseWriteFst(currentFile["children"],fstBin,isoFile)
        else: #is a file
            fstBin.append(struct.pack(">BBHII",0,(currentFile["stringTableOffset"]>>16)&0xFF,currentFile["stringTableOffset"]&0xFFFF,isoFile.tell(),currentFile["size"]))
            isoFile.write(open(currentFile["path"],"rb").read())
            addPaddingToFile(isoFile,0x100)


def packageISO(sourcePath,destPath):
    print("Converting filesystem into ISO")

    ISOfile = open(destPath,"wb")
    #write sys files
    ISOfile.write(open(sourcePath/"sys/boot.bin","rb").read())
    ISOfile.write(open(sourcePath/"sys/bi2.bin","rb").read())
    ISOfile.write(open(sourcePath/"sys/apploader.img","rb").read())
    addPaddingToFile(ISOfile,0x100)

    dolStartPos = ISOfile.tell()
    ISOfile.seek(0x420)
    ISOfile.write(struct.pack(">I",dolStartPos))
    ISOfile.seek(dolStartPos)

    ISOfile.write(open(sourcePath/"sys/main.dol","rb").read())
    addPaddingToFile(ISOfile,0x100)

    fstStartPos = ISOfile.tell()

    files,stringTable,entryLength = parseDir(sourcePath/"files","",0,None)
    entryLength = entryLength + 1

    ISOfile.seek(0x424)
    ISOfile.write(struct.pack(">II",fstStartPos,(entryLength*12)+len(stringTable)))
    

    #print(stringTable)
    #print(files)
    #print(hex(entryLength))
    #print(files[0]["entryNum"])
    
    fstBin = []
    fstBin.append(struct.pack(">BBHII",1,0,0,0,entryLength))

    ISOfile.seek(fstStartPos+(entryLength*12)+len(stringTable))
    addPaddingToFile(ISOfile,0x100)
    recurseWriteFst(files,fstBin,ISOfile)

    ISOfile.write(bytearray(1459978240 - (ISOfile.tell())))
    
    ISOfile.seek(fstStartPos)
    for fileEntry in fstBin:
        ISOfile.write(fileEntry)
    ISOfile.seek((entryLength*12) + fstStartPos)
    ISOfile.write(bytearray(stringTable,"utf8"))

    
    


if __name__ == "__main__":
    packageISO(Path(sys.argv[1]),Path(sys.argv[2]))