mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-14 16:34:04 +09:00
app run integrated to command.js
This commit is contained in:
@@ -146,8 +146,8 @@ _TVDOS.variables = {
|
||||
DOSDIR: "\\tvdos",
|
||||
LANG: "EN",
|
||||
KEYBOARD: "us_qwerty",
|
||||
PATH: "\\tvdos\\bin;\\tbas;\\home",
|
||||
PATHEXT: ".com;.bat;.js",
|
||||
PATH: "\\tvdos\\bin;\\home",
|
||||
PATHEXT: ".com;.bat;.app;.js",
|
||||
HELPPATH: "\\tvdos\\help",
|
||||
OS_NAME: "TSVM Disk Operating System",
|
||||
OS_VERSION: _TVDOS.VERSION
|
||||
@@ -177,12 +177,20 @@ class TVDOSFileDescriptor {
|
||||
}
|
||||
else {
|
||||
let p = path0.replaceAll("/", "\\")
|
||||
// oh well...
|
||||
this._driveLetter = p[0]
|
||||
p = p.substring(2) // detaches A:
|
||||
// remove trailing slashes
|
||||
while (p.endsWith("\\")) {
|
||||
p = p.substring(0, p.length - 1)
|
||||
}
|
||||
this._driveLetter = p[0]
|
||||
this._path = p.substring(2) // detaches $:
|
||||
// remove initial slashes...
|
||||
while (p.startsWith("\\")) {
|
||||
p = p.substring(1)
|
||||
}
|
||||
// then add our own
|
||||
p = "\\" + p
|
||||
|
||||
this._path = p
|
||||
|
||||
if (driverID == undefined) driverID = "UNDEFINED"
|
||||
|
||||
@@ -276,6 +284,12 @@ class TVDOSFileDescriptor {
|
||||
get name() {
|
||||
return this.path.split("\\").last()
|
||||
}
|
||||
get extension() {
|
||||
let fname = this.name
|
||||
let dotpos = fname.lastIndexOf('.')
|
||||
if (dotpos < 0) return ''
|
||||
else return fname.substring(dotpos+1)
|
||||
}
|
||||
get parentPath() {
|
||||
// return this.path.split("\\").init().join("\\")
|
||||
let li = this.path.lastIndexOf("\\")
|
||||
|
||||
@@ -733,10 +733,7 @@ shell.execute = function(line) {
|
||||
}
|
||||
else {
|
||||
let programCode = searchFile.sread()
|
||||
let extension = undefined
|
||||
// get proper extension
|
||||
let dotSepTokens = cmd.split('.')
|
||||
if (dotSepTokens.length > 1) extension = dotSepTokens[dotSepTokens.length - 1].toUpperCase()
|
||||
let extension = searchFile.extension.toUpperCase()
|
||||
|
||||
if ("BAT" == extension) {
|
||||
// parse and run as batch file
|
||||
@@ -745,6 +742,13 @@ shell.execute = function(line) {
|
||||
shell.execute(line)
|
||||
})
|
||||
}
|
||||
else if ("APP" == extension) {
|
||||
let appexec = `A:${_TVDOS.variables.DOSDIR}\\sbin\\appexec.js`
|
||||
let foundFile = searchFile.fullPath
|
||||
|
||||
// println(`${appexec} ${foundFile} ${parsedTokens.tail().join(' ')}`)
|
||||
shell.execute(`${appexec} ${foundFile} ${parsedTokens.tail().join(' ')}`)
|
||||
}
|
||||
else {
|
||||
let gotError = false
|
||||
|
||||
|
||||
140
assets/disk0/tvdos/sbin/appexec.js
Normal file
140
assets/disk0/tvdos/sbin/appexec.js
Normal file
@@ -0,0 +1,140 @@
|
||||
const filepath = exec_args[1]
|
||||
|
||||
if (!filepath) {
|
||||
println(`Usage: appexec path/to/application.app`)
|
||||
return 0
|
||||
}
|
||||
|
||||
const file = files.open(_G.shell.resolvePathInput(filepath).full)
|
||||
|
||||
if (!file.exists) {
|
||||
println("File not found.")
|
||||
return 1
|
||||
}
|
||||
|
||||
if (file.isDirectory) {
|
||||
println("Not an app file.")
|
||||
return 2
|
||||
}
|
||||
|
||||
const filebytes = file.sread()
|
||||
|
||||
|
||||
// check magic
|
||||
if (filebytes.substring(0,4) != "\x7FApP") {
|
||||
println("Not an app file.")
|
||||
return 2
|
||||
}
|
||||
|
||||
const endianness = filebytes.charCodeAt(4)
|
||||
const sectionComp = filebytes.charCodeAt(6)
|
||||
const sectionCount = filebytes.charCodeAt(7)
|
||||
const targetOS = filebytes.charCodeAt(8)
|
||||
|
||||
const decompFun = (1 == sectionComp) ? (b) => gzip.decomp(b) : (b) => b
|
||||
const decompToPtrFun = (1 == sectionComp) ? (b, target) => gzip.decompTo(b, target) : TODO()
|
||||
|
||||
if (targetOS != 1 && targetOS != 0) {
|
||||
println("App is not an TVDOS executable.")
|
||||
return 3
|
||||
}
|
||||
|
||||
|
||||
function strToInt32(str) {
|
||||
let s = [...str].map(it=>it.charCodeAt(0))
|
||||
return (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]
|
||||
|
||||
}
|
||||
function makeHash(length) {
|
||||
let e = "YBNDRFG8EJKMCPQXOTLVWIS2A345H769"
|
||||
let m = e.length
|
||||
let s = ""
|
||||
for (let i = 0; i < length; i++) {
|
||||
s += e[Math.floor(Math.random()*m)]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const PATH_MOUNT = `$:/TMP/${makeHash(32)}/`
|
||||
|
||||
// READ SECTIONS
|
||||
|
||||
let sectionTable = []
|
||||
let rodata = {}
|
||||
|
||||
for (let i = 0; i < sectionCount; i++) {
|
||||
let sectName = filebytes.substring(16 * (i+1), 16 * (i+1) + 12).trimNull()
|
||||
let sectOffset = strToInt32(filebytes.substring(16 * (i+1) + 12, 16 * (i+1) + 16))
|
||||
sectionTable.push([sectName, sectOffset])
|
||||
}
|
||||
|
||||
for (let i = 0; i < sectionTable.length - 1; i++) {
|
||||
let [sectName, sectOffset] = sectionTable[i]
|
||||
let nextSectOffset = sectionTable[i+1][1]
|
||||
|
||||
let uncompLen = strToInt32(filebytes.substring(sectOffset, sectOffset + 4))
|
||||
let compPayload = filebytes.substring(sectOffset + 4, nextSectOffset)
|
||||
|
||||
if ("RODATA" == sectName) {
|
||||
let rodataPtr = 0
|
||||
while (rodataPtr < nextSectOffset - sectOffset) {
|
||||
let labelLen = filebytes.charCodeAt(sectOffset + rodataPtr)
|
||||
let label = filebytes.substring(sectOffset + rodataPtr + 1, sectOffset + rodataPtr + 1 + labelLen)
|
||||
let payloadLen = strToInt32(filebytes.substring(sectOffset + rodataPtr + 1 + labelLen, sectOffset + rodataPtr + 1 + labelLen + 4))
|
||||
let uncompLen = strToInt32(filebytes.substring(sectOffset + rodataPtr + 1 + labelLen + 4, sectOffset + rodataPtr + 1 + labelLen + 8))
|
||||
let sectPayload = filebytes.substring(sectOffset + rodataPtr + 1 + labelLen + 8, sectOffset + rodataPtr + 1 + labelLen + 8 + payloadLen)
|
||||
|
||||
|
||||
try {
|
||||
let ptr = sys.malloc(uncompLen)
|
||||
decompToPtrFun(sectPayload, ptr)
|
||||
rodata[label] = ptr
|
||||
}
|
||||
catch (e) {
|
||||
rodata[label] = null
|
||||
}
|
||||
|
||||
decompFun(payload)
|
||||
|
||||
rodataPtr += 9 + labelLen + payloadLen
|
||||
}
|
||||
}
|
||||
else if ("TEXT" == sectName) {
|
||||
let program = btostr(decompFun(compPayload))
|
||||
|
||||
// inject RODATA map
|
||||
let rodataSnippet = `const __RODATA=Object.freeze(${JSON.stringify(rodata)});`
|
||||
|
||||
files.open(PATH_MOUNT + "run.com").swrite(rodataSnippet+program)
|
||||
}
|
||||
else if ("VDISK" == sectName) {
|
||||
let bytes = btostr(decompFun(compPayload))
|
||||
// unpack vdisk
|
||||
if (bytes.substring(0, 9) != "TVDOSLFS\x01") {
|
||||
printerrln("VDISK is not LFS")
|
||||
return 2
|
||||
}
|
||||
let curs = 16
|
||||
while (curs < bytes.length) {
|
||||
let fileType = bytes.charCodeAt(curs)
|
||||
let pathlen = (bytes.charCodeAt(curs+1) << 8) | bytes.charCodeAt(curs+2)
|
||||
curs += 3
|
||||
let path = bytes.substring(curs, curs + pathlen)
|
||||
curs += pathlen
|
||||
let filelen = (bytes.charCodeAt(curs) << 24) | (bytes.charCodeAt(curs+1) << 16) | (bytes.charCodeAt(curs+2) << 8) | bytes.charCodeAt(curs+3)
|
||||
curs += 4
|
||||
let filebytes = bytes.substring(curs, curs + filelen)
|
||||
files.open(`${PATH_MOUNT}${path}`).swrite(filebytes)
|
||||
curs += filelen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let errorlevel = _G.shell.execute(PATH_MOUNT + "run.com" + " " + exec_args.tail().join(' '))
|
||||
|
||||
try {
|
||||
files.open(PATH_MOUNT).remove()
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
return errorlevel
|
||||
Reference in New Issue
Block a user