summaryrefslogtreecommitdiff
path: root/libs/JSystem/src/JHostIO
diff options
context:
space:
mode:
authorLuke Street <luke@street.dev>2026-03-01 15:35:36 -0700
committerGitHub <noreply@github.com>2026-03-01 14:35:36 -0800
commit9649319ec4926457ef85e6094f8207474c977c2d (patch)
tree1c5cd4c7cc4c1aee03f28921213da47f2775444d /libs/JSystem/src/JHostIO
parent6e149819e13b1f70ecbf8a4c66b030c17ffed2bb (diff)
Reorganize library code into `libs/` (#3119)
* Reorganize files into libs/{dolphin,JSystem,PowerPC_EABI_Support,revolution,TRK_MINNOW_DOLPHIN} * Update configure.py and project.py for new libs structure * Refactor `#include <dolphin/x.h>` -> `<x.h>` * Remove `__REVOLUTION_SDK__` forwards from dolphin * Fix dolphin/ references in revolution * Wrap `#include <dolphin.h>` in `!__REVOLUTION_SDK__` * Always build TRK against dolphin headers * Resolve revolution SDK header resolution issues
Diffstat (limited to 'libs/JSystem/src/JHostIO')
-rw-r--r--libs/JSystem/src/JHostIO/JHIComm.cpp302
-rw-r--r--libs/JSystem/src/JHostIO/JHICommonMem.cpp18
-rw-r--r--libs/JSystem/src/JHostIO/JHIMccBuf.cpp458
-rw-r--r--libs/JSystem/src/JHostIO/JHIMemBuf.cpp75
-rw-r--r--libs/JSystem/src/JHostIO/JHIRMcc.cpp123
-rw-r--r--libs/JSystem/src/JHostIO/JHIhioASync.cpp174
-rw-r--r--libs/JSystem/src/JHostIO/JOREntry.cpp24
-rw-r--r--libs/JSystem/src/JHostIO/JORFile.cpp189
-rw-r--r--libs/JSystem/src/JHostIO/JORHostInfo.cpp58
-rw-r--r--libs/JSystem/src/JHostIO/JORMessageBox.cpp16
-rw-r--r--libs/JSystem/src/JHostIO/JORServer.cpp822
-rw-r--r--libs/JSystem/src/JHostIO/JORShellExecute.cpp18
12 files changed, 2277 insertions, 0 deletions
diff --git a/libs/JSystem/src/JHostIO/JHIComm.cpp b/libs/JSystem/src/JHostIO/JHIComm.cpp
new file mode 100644
index 0000000000..f406fb4a47
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JHIComm.cpp
@@ -0,0 +1,302 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JHIComm.h"
+
+static int min(int a, int b);
+
+void JHICommBufHeader::init() {
+ mp_memBuffer->writeIO(field_0x4 + field_0x1c, 0);
+ mp_memBuffer->writeIO(field_0x4 + field_0x18, 0);
+ mp_memBuffer->writeIO(field_0x4 + field_0x14, 'IS64');
+}
+
+void JHICommBufHeader::init(JHICommonMem* buffer, u32 param_1, u32 param_2, u32 alignment) {
+ m_alignment = alignment;
+
+ if (alignment == 4) {
+ field_0x14 = 0x00;
+ field_0x18 = 0x08;
+ field_0x1c = 0x14;
+ field_0x20 = 0x18;
+ field_0x24 = 0x20;
+ field_0x2c = ~0x3;
+ } else if (alignment == 32) {
+ field_0x14 = 0x00;
+ field_0x18 = 0x20;
+ field_0x1c = 0x40;
+ field_0x20 = 0x60;
+ field_0x24 = 0x80;
+ field_0x2c = ~0x1F;
+ }
+
+ mp_memBuffer = buffer;
+ field_0x4 = field_0x2c & (param_1 + m_alignment - 1);
+
+ u32 var_r30 = field_0x2c & (param_1 + param_2);
+ m_msgBufSize = var_r30 - field_0x4 - field_0x24;
+
+ init();
+}
+
+int JHICommBufHeader::load() {
+ u32 data;
+ mp_memBuffer->readIO(field_0x4 + field_0x14, &data);
+ if (data != 'IS64') {
+ return 1;
+ }
+
+ mp_memBuffer->readIO(field_0x4 + field_0x18, &field_0xc);
+ mp_memBuffer->readIO(field_0x4 + field_0x1c, &field_0x10);
+ return 0;
+}
+
+JHICommBufReader::JHICommBufReader(u32 param_0, u32 param_1, u32 alignment) {
+ mp_memBuffer = JHICommonMem::Instance();
+ m_header.init(mp_memBuffer, param_0, param_1, alignment);
+}
+
+void JHICommBufReader::Header::updateGetAdrs() {
+ if (field_0xc != field_0x30) {
+ mp_memBuffer->writeIO(field_0x4 + field_0x18, field_0xc);
+ }
+}
+
+u32 JHICommBufReader::Header::getReadableSize() const {
+ u32 size;
+ if (field_0xc <= field_0x10) {
+ size = field_0x10 - field_0xc;
+ } else {
+ size = m_msgBufSize - (field_0xc - field_0x10);
+ }
+
+ return size;
+}
+
+int JHICommBufReader::readBegin() {
+ return m_header.load();
+}
+
+void JHICommBufReader::readEnd() {
+ m_header.updateGetAdrs();
+}
+
+int JHICommBufReader::read(void* param_0, int param_1) {
+ int sp2C = min(param_1, m_header.getReadableSize());
+ u32 sp28;
+ int var_r28 = sp2C;
+ u8* var_r30 = (u8*)param_0;
+
+ int sp24;
+ if (var_r28 > 0 && (sp24 = m_header.getContSize()) > 0) {
+ int sp20 = min(var_r28, 4 - sp24);
+ m_header.alignGetAdrs();
+
+ mp_memBuffer->readIO(m_header.getGetAdrs(), &sp28);
+
+ int sp1C = sp24;
+ int sp18 = sp24 + sp20;
+ for (; sp1C < sp18; sp1C++) {
+ *var_r30 = sp28 >> ((3 - sp1C) * 8);
+ var_r30++;
+ }
+
+ var_r28 -= sp20;
+ m_header.addGetAdrs(sp24 + sp20);
+ }
+
+ while (var_r28 >= 4) {
+ mp_memBuffer->readIO(m_header.getGetAdrs(), &sp28);
+ var_r30[0] = sp28 >> 0x18;
+ var_r30[1] = sp28 >> 0x10;
+ var_r30[2] = sp28 >> 0x08;
+ var_r30[3] = sp28 >> 0x00;
+
+ var_r30 += 4;
+ var_r28 -= 4;
+
+ m_header.addGetAdrs(4);
+ }
+
+ if (var_r28 > 0) {
+ int sp14 = var_r28;
+ mp_memBuffer->readIO(m_header.getGetAdrs(), &sp28);
+
+ for (int i = 0; i < sp14; i++) {
+ *var_r30 = sp28 >> ((3 - i) * 8);
+ var_r30++;
+ }
+
+ var_r28 -= sp14;
+ m_header.addGetAdrs(sp14);
+ }
+
+ return sp2C;
+}
+
+void JHICommBufReader::Header::addGetAdrs(int param_0) {
+ field_0xc += param_0;
+ if (field_0xc >= m_msgBufSize) {
+ field_0xc -= m_msgBufSize;
+ }
+}
+
+u32 JHICommBufReader::Header::getGetAdrs() const {
+ return field_0xc + (field_0x4 + field_0x24);
+}
+
+void JHICommBufReader::Header::alignGetAdrs() {
+ field_0xc &= ~0x3;
+}
+
+int JHICommBufReader::Header::getContSize() {
+ return field_0xc & 3;
+}
+
+static int min(int a, int b) {
+ return a < b ? a : b;
+}
+
+JHICommBufWriter::JHICommBufWriter(u32 param_0, u32 param_1, u32 param_2) {
+ mp_memBuffer = JHICommonMem::Instance();
+ m_header.init(mp_memBuffer, param_0, param_1, param_2);
+}
+
+int JHICommBufWriter::Header::load() {
+ int var_r29 = JHICommBufHeader::load();
+ if (var_r29 == 0) {
+ field_0x34 = field_0x10;
+
+ if (getRemSize() > 0) {
+ u32 sp8;
+ mp_memBuffer->readIO(field_0x4 + field_0x20, &sp8);
+
+ field_0x30 = sp8 >> 0x18;
+ field_0x31 = sp8 >> 0x10;
+ field_0x32 = sp8 >> 0x08;
+ field_0x33 = sp8 >> 0x00;
+ }
+ }
+
+ return var_r29;
+}
+
+int JHICommBufWriter::Header::getRemSize() {
+ return field_0x10 & 3;
+}
+
+void JHICommBufWriter::Header::updatePutAdrs() {
+ if (field_0x10 != field_0x34) {
+ mp_memBuffer->writeIO(field_0x4 + field_0x1c, field_0x10);
+
+ if (getRemSize() > 0) {
+ mp_memBuffer->writeIO(field_0x4 + field_0x20,
+ (field_0x30 << 0x18) |
+ (field_0x31 << 0x10) |
+ (field_0x32 << 0x08) |
+ (field_0x33 << 0x00));
+ }
+ }
+}
+
+u32 JHICommBufWriter::Header::getWritebleSize() const {
+ u32 var_r31 = field_0xc & ~0x3;
+ u32 var_r30;
+
+ if (field_0x10 < var_r31) {
+ var_r30 = var_r31 - field_0x10;
+ } else {
+ var_r30 = var_r31 + (m_msgBufSize - field_0x10);
+ }
+
+ return var_r30 - 4;
+}
+
+int JHICommBufWriter::writeBegin() {
+ int var_r31;
+ if (m_header.load() != 0) {
+ var_r31 = -1;
+ } else {
+ var_r31 = m_header.getWritebleSize();
+ }
+
+ return var_r31;
+}
+
+void JHICommBufWriter::writeEnd() {
+ m_header.updatePutAdrs();
+}
+
+int JHICommBufWriter::write(void* param_0, int param_1) {
+ int sp28 = min(param_1, m_header.getWritebleSize());
+ int var_r27 = sp28;
+ u8* var_r29 = (u8*)param_0;
+ u8* var_r30 = &m_header.field_0x30;
+
+ int sp24;
+ if (var_r27 > 0 && (sp24 = m_header.getRemSize()) > 0) {
+ int sp20 = min(4 - sp24, var_r27);
+
+ int sp1C = sp24;
+ int sp18 = sp24 + sp20;
+ for (; sp1C < sp18; sp1C++) {
+ var_r30[sp1C] = *var_r29++;
+ }
+
+ var_r27 -= sp20;
+ m_header.alignPutAdrs();
+
+ mp_memBuffer->writeIO(m_header.getPutAdrs(),
+ (var_r30[0] << 0x18) |
+ (var_r30[1] << 0x10) |
+ (var_r30[2] << 0x08) |
+ (var_r30[3] << 0x00));
+ m_header.addPutAdrs(sp24 + sp20);
+ }
+
+ while (var_r27 >= 4) {
+ mp_memBuffer->writeIO(m_header.getPutAdrs(),
+ (var_r29[0] << 0x18) |
+ (var_r29[1] << 0x10) |
+ (var_r29[2] << 0x08) |
+ (var_r29[3] << 0x00));
+
+ var_r29 += 4;
+ var_r27 -= 4;
+
+ m_header.addPutAdrs(4);
+ }
+
+ if (var_r27 > 0) {
+ int sp14 = var_r27;
+
+ for (int i = 0; i < sp14; i++) {
+ var_r30[i] = *var_r29++;
+ }
+
+ mp_memBuffer->writeIO(m_header.getPutAdrs(),
+ (var_r30[0] << 0x18) |
+ (var_r30[1] << 0x10) |
+ (var_r30[2] << 0x08) |
+ (var_r30[3] << 0x00));
+
+ var_r27 -= sp14;
+ m_header.addPutAdrs(sp14);
+ }
+
+ return sp28;
+}
+
+void JHICommBufWriter::Header::addPutAdrs(int param_0) {
+ field_0x10 += param_0;
+ if (field_0x10 >= m_msgBufSize) {
+ field_0x10 -= m_msgBufSize;
+ }
+}
+
+u32 JHICommBufWriter::Header::getPutAdrs() const {
+ return field_0x10 + (field_0x4 + field_0x24);
+}
+
+void JHICommBufWriter::Header::alignPutAdrs() {
+ field_0x10 &= ~0x3;
+}
diff --git a/libs/JSystem/src/JHostIO/JHICommonMem.cpp b/libs/JSystem/src/JHostIO/JHICommonMem.cpp
new file mode 100644
index 0000000000..3d2f59fc49
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JHICommonMem.cpp
@@ -0,0 +1,18 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JHICommonMem.h"
+
+JHIMemBuf* JHICommonMem::instance;
+
+JHIMemBuf* JHICommonMem::Instance() {
+ if (instance == NULL) {
+ instance = new JHIMemBuf();
+ }
+
+ return instance;
+}
+
+JHIMemBuf::JHIMemBuf() {
+ mp_buffer = NULL;
+ create();
+}
diff --git a/libs/JSystem/src/JHostIO/JHIMccBuf.cpp b/libs/JSystem/src/JHostIO/JHIMccBuf.cpp
new file mode 100644
index 0000000000..f013947e26
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JHIMccBuf.cpp
@@ -0,0 +1,458 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JHIMccBuf.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#include "JSystem/JHostIO/JHIRMcc.h"
+#include <revolution/hio2.h>
+#include <cstring>
+
+void JHIReport(const char* fmt, ...) {}
+
+void JHIHalt(const char* fmt, ...) {}
+
+u8* JHIMccBuf::mTempBuf;
+u16 JHIMccBuf::mRefCount;
+
+JHIMccBuf::JHIMccBuf(u16 channel, u16 param_1, u32 param_2) {
+ initInstance(channel, param_1, param_2);
+ mRefCount++;
+}
+
+void JHIMccBuf::initInstance(u16 channel, u16 param_1, u32 param_2) {
+ mTag = 'MCHI';
+ field_0x8 = 0x20;
+ field_0xa = 0x40;
+ field_0xc = 0x60;
+ mChannel = channel;
+ field_0x10 = param_1;
+ field_0x20 = param_2;
+ mReadOffset = 0;
+ mWriteOffset = (int)(param_1 << 13) / 4;
+ field_0x1c = ((int)(param_1 << 13) / 4) - field_0xc;
+ mPortEnabled = false;
+}
+
+void JHIMccBuf::init() {
+ if (mTempBuf != NULL) {
+ initBuf();
+ } else {
+ mTempBuf = new (32) u8[0x18000];
+ if (mTempBuf == NULL) {
+ JHIHalt("ERROR: JHIMccBuf cannot alloc temp buf.\n");
+ } else {
+ JHIReport("DEBUG: JHIMccBuf alloc at %08x.\n", mTempBuf);
+ }
+
+ initBuf();
+ }
+}
+
+void JHIMccBuf::initBuf() {
+ setHeaderToBuf(mTag, 0, 0x20);
+ setHeaderToBuf(field_0xc, field_0x8, 0x20);
+ setHeaderToBuf(field_0xc, field_0xa, 0x20);
+
+ if (JHIMCCWrite(mChannel, mReadOffset, mTempBuf, 0x60)) {
+ JHIReport("DEBUG: Write to Channel:%d , Offset:%05x , Size: %d\n", mChannel, mReadOffset, 0x60);
+
+ if (JHIMCCWrite(mChannel, mWriteOffset, mTempBuf, 0x60)) {
+ JHIReport("DEBUG: Write to Channel:%d , Offset:%05x , Size: %d\n", mChannel, mWriteOffset, 0x60);
+ }
+ }
+}
+
+JHIMccBuf::~JHIMccBuf() {
+ mRefCount--;
+ if (mRefCount == 0) {
+ delete[] mTempBuf;
+ }
+}
+
+void JHIMccBuf::setHeaderToBuf(u32 data, u32 position, u16 size) {
+ u8* ptr = mTempBuf + position;
+ ptr[0] = (data >> 0x18) & 0xFF;
+ ptr[1] = (data >> 0x10) & 0xFF;
+ ptr[2] = (data >> 0x08) & 0xFF;
+ ptr[3] = (data >> 0x00) & 0xFF;
+
+ for (int i = 4; i < size; i++) {
+ ptr[i] = 0;
+ }
+}
+
+// NONMATCHING - storing var_r28 to stack instead of register
+u32 JHIMccBuf::setDataToBuf(void* pData, u16 size) {
+ u8* temp_buf = mTempBuf;
+ u32 i;
+ u8* data_buf = (u8*)pData;
+
+ temp_buf[0] = (mTag >> 0x18) & 0xFF;
+ temp_buf[1] = (mTag >> 0x10) & 0xFF;
+ temp_buf[2] = (mTag >> 0x08) & 0xFF;
+ temp_buf[3] = (mTag >> 0x00) & 0xFF;
+ temp_buf[4] = (size >> 0x8) & 0xFF;
+ temp_buf[5] = size & 0xFF;
+
+ for (i = 0; i < size; i++) {
+ temp_buf[6 + i] = data_buf[i];
+ }
+
+ u32 var_r28 = (size + 0x25) & ~0x1F;
+ for (i = size + 6; i < var_r28; i++) {
+ temp_buf[i] = 0;
+ }
+
+ return var_r28;
+}
+
+int JHIMccBuf::readData(u32 position, u32* pOutData) {
+ u8* temp_buf = mTempBuf;
+ u32 var_r30 = position;
+
+ if (!JHIMCCRead(mChannel, var_r30, temp_buf, 0x20)) {
+ return 0;
+ }
+
+ *pOutData = (temp_buf[0 + (position - var_r30)] << 0x18) |
+ (temp_buf[1 + (position - var_r30)] << 0x10) |
+ (temp_buf[2 + (position - var_r30)] << 0x08) |
+ (temp_buf[3 + (position - var_r30)] << 0x00);
+ return 1;
+}
+
+int JHIMccBuf::readDataFromBuf(void* pBuf, u32 size) {
+ u8* temp_buf = mTempBuf;
+ u8* u_buf = (u8*)pBuf;
+
+ u32 var_r28;
+ u32 var_r27 = 0;
+ u32 var_r26 = 0;
+ u32 var_r30 = 0;
+ while (var_r30 < size) {
+ u32 sp10 = (temp_buf[0 + var_r30] << 0x18) |
+ (temp_buf[1 + var_r30] << 0x10) |
+ (temp_buf[2 + var_r30] << 0x08) |
+ (temp_buf[3 + var_r30] << 0x00);
+ if (sp10 != mTag) {
+ return 0;
+ }
+
+ var_r26 = (temp_buf[4 + var_r30] << 0x8) |
+ (temp_buf[5 + var_r30] << 0x0);
+ if (u_buf != NULL) {
+ for (var_r28 = 0; var_r28 < var_r26; var_r28++) {
+ u_buf[var_r27 + var_r28] = temp_buf[6 + (var_r30 + var_r28)];
+ }
+ }
+
+ var_r30 += (var_r26 + 0x25) & ~0x1F;
+ var_r27 += var_r26;
+ var_r26 = 0;
+ }
+
+ return var_r27;
+}
+
+int JHIMccBuf::JHIRead(u32 channel, u32 offset, void* buffer, u32 size) {
+ JHIReport("DEBUG: MCCRead(%d, %06x, %08x, %d);\n", channel, offset, buffer, size);
+
+ if (!isPort()) {
+ memset(buffer, 0, size);
+ return 0;
+ }
+
+ int attempts = 0;
+ DCInvalidateRange(buffer, size);
+
+ if (offset & 3) {
+ disablePort();
+ return 0;
+ }
+
+ if (offset > (field_0x1c + field_0xc) * 2) {
+ OS_REPORT("ERROR: Illegal offset specified Error. -HIOWrite()\n");
+ OS_REPORT("ERROR: offset: %08x low:%08x high:%08x\n", offset, 0, (field_0x1c + field_0xc) * 2);
+ disablePort();
+ return 0;
+ }
+
+#if VERSION < VERSION_SHIELD_DEBUG
+ while (HIORead(offset + field_0x20, buffer, size) == 0 && attempts < 30) {
+ attempts++;
+ }
+#else
+ while (HIO2Read(JHIGetHIO2Handle(), offset + field_0x20, buffer, size) == 0 && attempts < 30) {
+ attempts++;
+ }
+#endif
+
+ if (attempts >= 30) {
+ OS_REPORT("ERROR: Communication Error. -HIORead()\n");
+ memset(buffer, 0, size);
+ disablePort();
+ return 0;
+ }
+
+ return 1;
+}
+
+int JHIMccBuf::JHIWrite(u32 channel, u32 offset, void* buffer, u32 size) {
+ JHIReport("DEBUG: MCCWrite(%d, %06x, %08x, %d);\n", channel, offset, buffer, size);
+
+ if (!isPort()) {
+ return 0;
+ }
+
+ int attempts = 0;
+ DCFlushRange(buffer, size);
+
+ if (offset & 3) {
+ disablePort();
+ return 0;
+ }
+
+ if (offset > (field_0x1c + field_0xc) * 2) {
+ OS_REPORT("ERROR: Illegal offset specified Error. -HIOWrite()\n");
+ OS_REPORT("ERROR: offset: %08x low:%08x high:%08x\n", offset, 0, (field_0x1c + field_0xc) * 2);
+ disablePort();
+ return 0;
+ }
+
+#if VERSION < VERSION_SHIELD_DEBUG
+ while (HIOWrite(offset + field_0x20, buffer, size) == 0 && attempts < 30) {
+ attempts++;
+ }
+#else
+ while (HIO2Write(JHIGetHIO2Handle(), offset + field_0x20, buffer, size) == 0 && attempts < 30) {
+ attempts++;
+ }
+#endif
+
+ if (attempts >= 30) {
+ JHIReport("ERROR: Communication Error. -HIOWrite()\n");
+ disablePort();
+ return 0;
+ }
+
+ return 1;
+}
+
+int JHIMccBuf::JHIMCCRead(u32 channel, u32 offset, void* buffer, u32 size) {
+ JHIReport("DEBUG: JHIMCCRead(%d, %06x, %08x, %d);\n", channel, offset, buffer, size);
+ if (!JHIRead(channel, offset, buffer, size)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int JHIMccBuf::JHIMCCWrite(u32 channel, u32 offset, void* buffer, u32 size) {
+ JHIReport("DEBUG: JHIMCCWrite(%d, %06x, %08x, %d);\n", channel, offset, buffer, size);
+ if (!JHIWrite(channel, offset, buffer, size)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+JHIMccBufReader::JHIMccBufReader(u16 channel, u16 param_1, u32 param_2)
+ : JHIMccBuf(channel, param_1, param_2) {}
+
+JHIMccBufReader::~JHIMccBufReader() {}
+
+u32 JHIMccBufReader::available() {
+ u32 var_r30 = 0;
+
+ if (!isPort()) {
+ return 0;
+ }
+
+ if (!readData(mReadOffset + field_0x8, &mBeginPos)) {
+ return 0;
+ }
+
+ if (!readData(mReadOffset + field_0xa, &mEndPos)) {
+ return 0;
+ }
+
+ if (mBeginPos < mEndPos) {
+ var_r30 = mEndPos - mBeginPos;
+ } else if (mBeginPos > mEndPos) {
+ var_r30 = field_0x1c - (mBeginPos - mEndPos);
+ }
+
+ return var_r30;
+}
+
+int JHIMccBufReader::readBegin() {
+ if (!isPort()) {
+ return 0;
+ }
+
+ if (!readData(mReadOffset + field_0x8, &mBeginPos)) {
+ return 0;
+ }
+
+ if (!readData(mReadOffset + field_0xa, &mEndPos)) {
+ return 0;
+ }
+
+ JHIReport("DEBUG: readBegin: R:%08x W:%08x\n", mBeginPos, mEndPos);
+ return 1;
+}
+
+int JHIMccBufReader::read(void* pBuf) {
+ if (!isPort()) {
+ return 0;
+ }
+
+ u32 size;
+ int var_r28 = 0;
+
+ if (mBeginPos < mEndPos) {
+ size = mEndPos - mBeginPos;
+ if (!JHIMCCRead(mChannel, mReadOffset + mBeginPos, mTempBuf, size)) {
+ return 0;
+ }
+
+ var_r28 = readDataFromBuf(pBuf, size);
+ } else if (mBeginPos > mEndPos) {
+ size = field_0x1c - (mBeginPos - mEndPos);
+ u32 var_r25 = (field_0xc + field_0x1c);
+ u32 var_r27 = var_r25 - mBeginPos;
+ u32 var_r26 = size - var_r27;
+
+ if (!JHIMCCRead(mChannel, mReadOffset + mBeginPos, mTempBuf, var_r27)) {
+ return 0;
+ } else if (var_r26 != 0) {
+ if (!JHIMCCRead(mChannel, mReadOffset + field_0xc, mTempBuf + var_r27, var_r26)) {
+ return 0;
+ }
+ }
+
+ var_r28 = readDataFromBuf(pBuf, size);
+ }
+
+ return var_r28;
+}
+
+void JHIMccBufReader::readEnd() {
+ if (isPort()) {
+ setHeaderToBuf(mEndPos, 0, 0x20);
+
+ JHIReport("DEBUG: readEnd: Point:%08x\n", mEndPos);
+
+ if (!JHIMCCWrite(mChannel, mReadOffset + field_0x8, mTempBuf, 0x20)) {
+ return;
+ }
+ }
+}
+
+JHIMccBufWriter::JHIMccBufWriter(u16 channel, u16 param_1, u32 param_2)
+ : JHIMccBuf(channel, param_1, param_2) {}
+
+JHIMccBufWriter::~JHIMccBufWriter() {}
+
+int JHIMccBufWriter::writeBegin() {
+ int var_r29 = 0;
+
+ if (!isPort()) {
+ return 0;
+ }
+
+ if (!readData(mWriteOffset + field_0x8, &mBeginPos)) {
+ return 0;
+ }
+
+ if (!readData(mWriteOffset + field_0xa, &mEndPos)) {
+ return 0;
+ }
+
+ u32 var_r30;
+ if (mBeginPos == field_0xc) {
+ var_r30 = field_0x1c + field_0xc;
+ var_r30 -= 0x20;
+ } else {
+ var_r30 = mBeginPos - 0x20;
+ }
+
+ if (mEndPos > var_r30) {
+ var_r29 = (field_0x1c - (mEndPos - var_r30)) - 0x20;
+ } else if (mEndPos < var_r30) {
+ var_r29 = (var_r30 - mEndPos) - 0x20;
+ }
+
+ JHIReport("DEBUG: writeBegin: R:%08x W:%08x\n", mBeginPos, mEndPos);
+ return var_r29;
+}
+
+int JHIMccBufWriter::write(void* pBuffer, u32 size) {
+ if (!isPort()) {
+ return 0;
+ }
+
+ u32 var_r26;
+ u32 var_r27;
+ u32 var_r28;
+
+ // Probably fake match
+ var_r28 = var_r28;
+
+ u32 var_r29 = setDataToBuf(pBuffer, size);
+ if (mBeginPos == field_0xc) {
+ var_r27 = field_0x1c + field_0xc;
+ var_r27 -= 0x20;
+ } else {
+ var_r27 = mBeginPos - 0x20;
+ }
+
+ if (mEndPos > var_r27) {
+ int x;
+ var_r26 = field_0x1c - (mEndPos - var_r27);
+ var_r28 = (field_0x1c + field_0xc) - mEndPos;
+
+ if (var_r28 >= var_r29) {
+ if (!JHIMCCWrite(mChannel, mWriteOffset + mEndPos, mTempBuf, var_r29)) {
+ return 0;
+ }
+
+ mEndPos += var_r29;
+ } else {
+ if (!JHIMCCWrite(mChannel, mWriteOffset + mEndPos, mTempBuf, var_r28)) {
+ return 0;
+ } else if (var_r29 - var_r28 != 0) {
+ if (!JHIMCCWrite(mChannel, mWriteOffset + field_0xc, mTempBuf + var_r28, var_r29 - var_r28)) {
+ return 0;
+ }
+ }
+
+ mEndPos = field_0xc + (var_r29 - var_r28);
+ }
+ } else if (mEndPos < var_r27) {
+ var_r26 = var_r27 - mEndPos;
+
+ if (!JHIMCCWrite(mChannel, mWriteOffset + mEndPos, mTempBuf, var_r29)) {
+ return 0;
+ }
+
+ mEndPos += var_r29;
+ }
+
+ if (mEndPos == field_0xc + field_0x1c) {
+ mEndPos = field_0xc;
+ }
+
+ return var_r29;
+}
+
+void JHIMccBufWriter::writeEnd() {
+ if (isPort()) {
+ setHeaderToBuf(mEndPos, 0, 0x20);
+
+ JHIReport("DEBUG: writeEnd: Point:%08x\n", mEndPos);
+
+ if (!JHIMCCWrite(mChannel, mWriteOffset + field_0xa, mTempBuf, 0x20)) {
+ return;
+ }
+ }
+}
diff --git a/libs/JSystem/src/JHostIO/JHIMemBuf.cpp b/libs/JSystem/src/JHostIO/JHIMemBuf.cpp
new file mode 100644
index 0000000000..4fec9ad532
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JHIMemBuf.cpp
@@ -0,0 +1,75 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JHICommonMem.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#ifdef __REVOLUTION_SDK__
+#include <revolution.h>
+#else
+#include <dolphin.h>
+#endif
+
+int JHIMemBuf::create() {
+ int rt = 1;
+ if (mp_buffer == NULL) {
+ mp_buffer = new (32) u8[0x20000];
+
+ if (mp_buffer == NULL) {
+ rt = 0;
+ OS_REPORT("ERROR: hioSync Alloc Mem NG!\n");
+ } else {
+ OS_REPORT("INFO: hioSync Alloc Mem OK! %08x\n", mp_buffer);
+ }
+ }
+
+ return rt;
+}
+
+int JHIMemBuf::open() {
+ return 1;
+}
+
+void JHIMemBuf::close() {
+ if (mp_buffer != NULL) {
+ delete[] mp_buffer;
+ }
+}
+
+JHIMemBuf::~JHIMemBuf() {
+ close();
+}
+
+u8* JHIMemBuf::getPointer() const {
+ return mp_buffer;
+}
+
+u32 JHIMemBuf::readIO(u32 position) const {
+ u32 data;
+ readIO(position, &data);
+ return data;
+}
+
+void JHIMemBuf::readIO(u32 position, u32* out_data) const {
+ u8* read_ptr = getPointer() + position;
+ *out_data = (read_ptr[0] << 0x18) |
+ (read_ptr[1] << 0x10) |
+ (read_ptr[2] << 0x08) |
+ (read_ptr[3] << 0x00);
+}
+
+void JHIMemBuf::writeIO(u32 position, u8* src_data, u32 length) const {
+ u8* write_ptr = getPointer() + position;
+
+ while (--length != 0) {
+ *write_ptr = *src_data++;
+ write_ptr++;
+ }
+}
+
+void JHIMemBuf::writeIO(u32 position, u32 data) const {
+ u8* write_ptr = getPointer() + position;
+
+ *write_ptr++ = data >> 0x18;
+ *write_ptr++ = data >> 0x10;
+ *write_ptr++ = data >> 0x08;
+ *write_ptr++ = data >> 0x00;
+}
diff --git a/libs/JSystem/src/JHostIO/JHIRMcc.cpp b/libs/JSystem/src/JHostIO/JHIRMcc.cpp
new file mode 100644
index 0000000000..b22a19d365
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JHIRMcc.cpp
@@ -0,0 +1,123 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JHIMccBuf.h"
+#include <revolution/hio2.h>
+
+HIO2DeviceType gExiDevice = HIO2_DEVICE_INVALID;
+u8 data_8074bd04 = 1;
+
+s32 ghHIO2;
+JHIMccContext tContext_old;
+JHIMccContext tContext_new;
+bool data_8074d138;
+u8 data_8074d139;
+
+BOOL JHIhio2CallbackEnum(HIO2DeviceType type) {
+ gExiDevice = type;
+ return 0;
+}
+
+void JHIhio2DisconnectCallback(s32) {
+ gExiDevice = HIO2_DEVICE_INVALID;
+}
+
+u32 JHIInitInterface() {
+ if (data_8074bd04) {
+ if (!HIO2Init()) {
+ return 0;
+ }
+
+ if (!HIO2EnumDevices(JHIhio2CallbackEnum)) {
+ return 0;
+ }
+
+ data_8074bd04 = 0;
+ }
+
+ if (gExiDevice == HIO2_DEVICE_INVALID) {
+ return 0;
+ }
+
+ if (data_8074d139 != 0) {
+ HIO2Close(ghHIO2);
+ data_8074d139 = 0;
+ }
+
+ if (data_8074d139 == 0) {
+ ghHIO2 = HIO2Open(gExiDevice, 0, JHIhio2DisconnectCallback);
+ if (ghHIO2 == -1) {
+ return 0;
+ }
+
+ data_8074d139 = 1;
+ }
+
+ return 1;
+}
+
+bool JHINegotiateInterface(u32) {
+ return 0;
+}
+
+JHIMccContext JHIGetHiSpeedContext() {
+ if (tContext_new.mp_reader == NULL) {
+ tContext_new.mp_reader = new JHIMccBufReader(1, 0x18, 0x6000);
+ }
+
+ if (tContext_new.mp_writer == NULL) {
+ tContext_new.mp_writer = new JHIMccBufWriter(1, 0x18, 0x6000);
+ }
+
+ return tContext_new;
+}
+
+JHIMccContext JHIGetLowSpeedContext() {
+ if (tContext_old.mp_reader == NULL) {
+ tContext_old.mp_reader = new JHIMccBufReader(1, 2, 0);
+ }
+
+ if (tContext_old.mp_writer == NULL) {
+ tContext_old.mp_writer = new JHIMccBufWriter(1, 2, 0);
+ }
+
+ return tContext_old;
+}
+
+BOOL JHIInitMCC(JHIMccContext* pCtx, bool* param_1) {
+ JHIGetHiSpeedContext();
+ JHIGetLowSpeedContext();
+
+ if (!JHIInitInterface()) {
+ *pCtx = tContext_old;
+ return FALSE;
+ }
+
+ data_8074d138 = JHINegotiateInterface(800);
+ if (data_8074d138) {
+ tContext_new.mp_reader->enablePort();
+ tContext_new.mp_writer->enablePort();
+ tContext_new.mp_reader->init();
+ tContext_new.mp_writer->init();
+ } else {
+ tContext_old.mp_reader->enablePort();
+ tContext_old.mp_writer->enablePort();
+ tContext_old.mp_reader->init();
+ tContext_old.mp_writer->init();
+ }
+
+ if (param_1 != NULL) {
+ *param_1 = data_8074d138;
+ }
+
+ if (data_8074d138) {
+ *pCtx = tContext_new;
+ } else {
+ *pCtx = tContext_old;
+ }
+
+ return TRUE;
+}
+
+s32 JHIGetHIO2Handle() {
+ return ghHIO2;
+}
diff --git a/libs/JSystem/src/JHostIO/JHIhioASync.cpp b/libs/JSystem/src/JHostIO/JHIhioASync.cpp
new file mode 100644
index 0000000000..bc8c5b9e2c
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JHIhioASync.cpp
@@ -0,0 +1,174 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JHIMccBuf.h"
+#include "JSystem/JHostIO/JHIRMcc.h"
+#ifdef __REVOLUTION_SDK__
+#include <revolution.h>
+#else
+#include <dolphin.h>
+#endif
+#include "global.h"
+
+u32 gsEnableHostio;
+u32 gsEnableInterface;
+u32 gsDataToRead;
+
+u8* gsReadBuf;
+u8* gsWriteBuf;
+JHICommBufReader* gsJHIrecvBuf;
+JHICommBufWriter* gsJHIsendBuf;
+
+JHIMccContext gMccContext;
+
+BOOL JHIInit(u32 enabled) {
+ gsEnableHostio = enabled;
+ gsDataToRead = 0;
+ gsEnableInterface = TRUE;
+
+ if (gsEnableHostio) {
+ OS_REPORT("INFO:********************************\n");
+ OS_REPORT("INFO: Opening Hostio service...\n");
+
+ if (!JHIInitMCC(&gMccContext, NULL)) {
+ gsEnableInterface = FALSE;
+ OS_REPORT("ERROR: Cannot Open HostIO Interface..\n");
+ OS_REPORT("INFO: *** Disable JHostIO ***\n");
+ }
+
+ gsReadBuf = new (32) u8[0xC000];
+ gsWriteBuf = new (32) u8[0xC000];
+
+ if (gsReadBuf == NULL || gsWriteBuf == NULL) {
+ gsEnableInterface = FALSE;
+ OS_REPORT("ERROR: Cannot alloc transport buffer..\n");
+ OS_REPORT("INFO: *** Disable JHostIO ***\n");
+ }
+ }
+
+ return gsEnableInterface && gsEnableHostio;
+}
+
+static void dummyString() {
+ DEAD_STRING("INFO:Quitting Hostio...");
+}
+
+u32 JHIEventLoop() {
+ static u32 tNowWrite;
+ static u32 tNowRead;
+ static u8* tReadBuf;
+ static u8* tWriteBuf;
+
+ int var_r30;
+ u32 available_size;
+
+ if (gsEnableHostio && gsEnableInterface) {
+ if (tNowRead != 0) {
+ var_r30 = gsJHIsendBuf->writeBegin();
+ if (var_r30 >= tNowRead) {
+ gsJHIsendBuf->write(tReadBuf, tNowRead);
+ gsJHIsendBuf->writeEnd();
+ tNowRead = 0;
+ tReadBuf = gsReadBuf;
+ } else if (var_r30 != 0) {
+ gsJHIsendBuf->write(tReadBuf, var_r30);
+ gsJHIsendBuf->writeEnd();
+ tNowRead -= var_r30;
+ tReadBuf += var_r30;
+ }
+ } else {
+ available_size = gMccContext.mp_reader->available();
+ if (available_size != 0) {
+ JHIReport("DEBUG: Dolphin <- PC Data Available : Size:%d\n", available_size);
+ gMccContext.mp_reader->readBegin();
+
+ u32 var_r27 = gMccContext.mp_reader->read(gsReadBuf);
+ if (var_r27 != 0) {
+ gMccContext.mp_reader->readEnd();
+ tNowRead = 0;
+ tReadBuf = gsReadBuf;
+
+ u32 var_r28 = gsJHIsendBuf->writeBegin();
+ if (var_r28 >= var_r27) {
+ gsJHIsendBuf->write(tReadBuf, var_r27);
+ gsJHIsendBuf->writeEnd();
+ } else {
+ if (var_r28 != 0) {
+ gsJHIsendBuf->write(tReadBuf, var_r28);
+ gsJHIsendBuf->writeEnd();
+ }
+ tNowRead = var_r27 - var_r28;
+ tReadBuf = gsReadBuf + var_r28;
+ }
+ }
+ }
+ }
+
+ if (tNowWrite != 0) {
+ var_r30 = gMccContext.mp_writer->writeBegin();
+ if (var_r30 > tNowWrite) {
+ gMccContext.mp_writer->write(tWriteBuf, tNowWrite);
+ gMccContext.mp_writer->writeEnd();
+ tNowWrite = 0;
+ tWriteBuf = gsWriteBuf;
+ } else if (var_r30 != 0) {
+ gMccContext.mp_writer->write(tWriteBuf, var_r30);
+ gMccContext.mp_writer->writeEnd();
+ tNowWrite -= var_r30;
+ tWriteBuf += var_r30;
+ }
+ } else {
+ available_size = gsJHIrecvBuf->available();
+ if (available_size != 0) {
+ JHIReport("DEBUG: Dolphin -> PC Data Available : Size:%d\n", available_size);
+
+ u32 temp_r26 = available_size < 0xC000 ? available_size : 0xC000;
+ gsJHIrecvBuf->readBegin();
+ gsJHIrecvBuf->read(gsWriteBuf, temp_r26);
+ gsJHIrecvBuf->readEnd();
+ tNowWrite = 0;
+ tWriteBuf = gsWriteBuf;
+
+ var_r30 = gMccContext.mp_writer->writeBegin();
+ if (var_r30 > temp_r26) {
+ gMccContext.mp_writer->write(tWriteBuf, temp_r26);
+ gMccContext.mp_writer->writeEnd();
+ } else if (var_r30 != 0) {
+ gMccContext.mp_writer->write(tWriteBuf, var_r30);
+ gMccContext.mp_writer->writeEnd();
+ tNowWrite = temp_r26 - var_r30;
+ tWriteBuf = gsWriteBuf + var_r30;
+ }
+ }
+ }
+
+ if (!gMccContext.mp_reader->isPort() || !gMccContext.mp_writer->isPort()) {
+ gsEnableInterface = 0;
+ }
+ (void)0;
+ } else if (!gsEnableInterface && gsEnableHostio != 0 && JHIInitInterface()) {
+ OS_REPORT("INFO: JHostIO: Enabled USB2EXI Interface\n");
+ bool sp8 = JHINegotiateInterface(800);
+ if (sp8) {
+ gMccContext = JHIGetHiSpeedContext();
+ } else {
+ gMccContext = JHIGetLowSpeedContext();
+ }
+
+ gMccContext.mp_reader->enablePort();
+ gMccContext.mp_writer->enablePort();
+ gMccContext.mp_reader->init();
+ gMccContext.mp_writer->init();
+ gsEnableInterface = TRUE;
+ }
+
+ return 0;
+}
+
+BOOL JOR_CHECKINTERFACE() {
+ return (gsEnableInterface && gsEnableHostio) != 0;
+}
+
+void JHISetBuffer(JHIContext* pCtx) {
+ gsJHIrecvBuf = pCtx->mp_reader;
+ gsJHIsendBuf = pCtx->mp_writer;
+}
diff --git a/libs/JSystem/src/JHostIO/JOREntry.cpp b/libs/JSystem/src/JHostIO/JOREntry.cpp
new file mode 100644
index 0000000000..0a6b0271c3
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JOREntry.cpp
@@ -0,0 +1,24 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JORServer.h"
+#include "JSystem/JHostIO/JOREntry.h"
+#include "JSystem/JHostIO/JHIhioASync.h"
+
+void JORInit() {
+ JHIInit(TRUE);
+
+ JHICommBufWriter* pComWriter = new JHICommBufWriter(0x10000, 0x10000, 4);
+ JHICommBufReader* pComReader = new JHICommBufReader(0, 0x10000, 4);
+
+ JHIContext ctx;
+ ctx.mp_reader = new JHICommBufReader(0x10000, 0x10000, 4);
+ ctx.mp_writer = new JHICommBufWriter(0, 0x10000, 4);
+
+ JHIComPortManager<JHICmnMem>* pPortMng = JHIComPortManager<JHICmnMem>::create();
+ pPortMng->getRefPort().setBuf(pComReader, pComWriter);
+ JHISetBuffer(&ctx);
+
+ JORServer* pServer = JORServer::create();
+ pPortMng->addTag(pServer);
+ pServer->sendReset();
+}
diff --git a/libs/JSystem/src/JHostIO/JORFile.cpp b/libs/JSystem/src/JHostIO/JORFile.cpp
new file mode 100644
index 0000000000..f689f06534
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JORFile.cpp
@@ -0,0 +1,189 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JORFile.h"
+#include "JSystem/JHostIO/JORServer.h"
+#ifdef __REVOLUTION_SDK__
+#include <revolution.h>
+#else
+#include <dolphin.h>
+#endif
+
+JORFile::JORFile()
+: mHandle(0),
+ mFileLength(0),
+ mStatus(EStatus_WAIT),
+ mNFileName(0),
+ field_0x18(0),
+ mDataStream() {}
+
+int JORFile::countMaskSize(const char* mask) {
+ u32 var_r28 = 0;
+ u32 var_r30 = 0;
+
+ while (true) {
+ u32 var_r27 = var_r30;
+
+ while (mask[var_r30] != 0) {
+ var_r30++;
+ if (var_r30 - var_r27 > 0xFF) {
+ return 0;
+ }
+ }
+
+ var_r30++;
+ while (mask[var_r30] != 0) {
+ var_r30++;
+ if (var_r30 - var_r27 > 0xFF) {
+ return 0;
+ }
+ }
+
+ var_r30++;
+ if (mask[var_r30] == 0) {
+ return var_r30 + 1;
+ }
+
+ var_r28++;
+ if (var_r28 > 0x28) {
+ return 0;
+ }
+ }
+}
+
+void JORFile::waitMessage_() {
+ while (mStatus == EStatus_WAIT) {
+ JOR_MESSAGELOOP();
+ }
+}
+
+int JORFile::open(const char* path, u32 flags, const char* extMask, const char* defaultExt, const char* param_4, const char* fileSuffix) {
+ if (mHandle != 0) {
+ return 0;
+ }
+
+ mStatus = EStatus_WAIT;
+ mFlags = flags;
+
+ if (extMask == NULL) {
+ extMask = "";
+ }
+
+ u32 mask_size = countMaskSize(extMask);
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->openFile(this, mFlags, path, extMask, mask_size, defaultExt, param_4, fileSuffix);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+
+ if (mHandle == 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
+void JORFile::close() {
+ JORMContext* mctx;
+ if (mHandle != 0) {
+ mStatus = EStatus_WAIT;
+ mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->closeFile(this);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+ mHandle = 0;
+ }
+}
+
+void JORFile::readBegin_(s32 len) {
+ mStatus = EStatus_WAIT;
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->readBegin(this, len);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+}
+
+void JORFile::readLoop_() {
+ mStatus = EStatus_WAIT;
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->readData(this);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+}
+
+s32 JORFile::readData(void* buffer, s32 length) {
+ if (mHandle == 0) {
+ return 0;
+ }
+
+ s32 len = length == 0 ? mFileLength : length;
+ setBuffer(buffer, len);
+ readBegin_(len);
+
+ do {
+ readLoop_();
+ if (mStatus == EStatus_READ_BEGIN) {
+ setBuffer(NULL, 0);
+ return 0;
+ }
+ } while (mStatus != EStatus_WRITE_END);
+
+ setBuffer(NULL, 0);
+ DCFlushRange(buffer, len);
+ return len;
+}
+
+void JORFile::setBuffer(void* buffer, s32 length) {
+ mDataStream.setBuffer(buffer, length);
+}
+
+void JORFile::writeBegin_(s32 len) {
+ mStatus = EStatus_WAIT;
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->writeBegin(this, mFlags, len);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+}
+
+void JORFile::writeLoop_(const void* pBuffer, s32 size, u32 pos) {
+ mStatus = EStatus_WAIT;
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->writeData(this, pBuffer, size, pos);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+}
+
+void JORFile::writeDone_(s32 len) {
+ mStatus = EStatus_WAIT;
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_FIO);
+ mctx->writeDone(this, len);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ waitMessage_();
+}
+
+s32 JORFile::writeData(const void* buffer, s32 length) {
+ if (mHandle == 0) {
+ return 0;
+ }
+
+ s32 len = length == 0 ? mFileLength : length;
+ writeBegin_(len);
+
+ u32 pos = 0;
+ s32 size = 0;
+ u8* buf_start = (u8*)buffer;
+ do {
+ size = len - pos > 0xF00 ? 0xF00 : len - pos;
+ writeLoop_(buf_start + pos, size, pos);
+
+ pos += size;
+ } while (len - pos != 0);
+
+ writeDone_(len);
+ return len;
+}
diff --git a/libs/JSystem/src/JHostIO/JORHostInfo.cpp b/libs/JSystem/src/JHostIO/JORHostInfo.cpp
new file mode 100644
index 0000000000..904cb27fbf
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JORHostInfo.cpp
@@ -0,0 +1,58 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JORHostInfo.h"
+#include "JSystem/JHostIO/JORServer.h"
+
+// End of each month in standard year
+static s32 YearDays[] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+};
+
+// End of each month in leap year
+static s32 LeapYearDays[] = {
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
+};
+
+static BOOL IsLeapYear(int year) {
+ return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
+}
+
+BOOL JORGetYearDays(int year, int mon) {
+ s32* days = IsLeapYear(year) ? LeapYearDays : YearDays;
+ return days[mon];
+}
+
+bool JORGetHostInfo(u32 request_type, JORHostInfo* pHostinfo) {
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_GET_HOST_INFO);
+ mctx->sendHostInfoRequest(request_type, pHostinfo);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ while (pHostinfo->getResult() == 0) {
+ JOR_MESSAGELOOP();
+ }
+
+ return pHostinfo->getResult() == 1;
+}
+
+void JORGetComputerName(char* buffer, u32 buffer_size) {
+ JORHostInfo_String string;
+ string.setStringBuffer(buffer);
+ string.setBufferSize(buffer_size);
+
+ JORGetHostInfo(HOSTINFO_REQ_COMPUTER_NAME, &string);
+}
+
+void JORGetUserName(char* buffer, u32 buffer_size) {
+ JORHostInfo_String string;
+ string.setStringBuffer(buffer);
+ string.setBufferSize(buffer_size);
+
+ JORGetHostInfo(HOSTINFO_REQ_USERNAME, &string);
+}
+
+void JORGetLocalTime(OSCalendarTime* pCalendarTime) {
+ JORHostInfo_CalendarTime calendar_time;
+ calendar_time.setCalendarTimeBuffer(pCalendarTime);
+
+ JORGetHostInfo(HOSTINFO_REQ_LOCAL_TIME, &calendar_time);
+}
diff --git a/libs/JSystem/src/JHostIO/JORMessageBox.cpp b/libs/JSystem/src/JHostIO/JORMessageBox.cpp
new file mode 100644
index 0000000000..e7ce1cc954
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JORMessageBox.cpp
@@ -0,0 +1,16 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JORServer.h"
+
+u32 JORMessageBox(const char* message, const char* title, u32 style) {
+ u32 status = 0;
+ JORMContext* mctx = JORServer::getInstance()->attachMCTX(MCTX_MSG_OPEN_MESSAGE_BOX);
+ mctx->openMessageBox(&status, style, message, title);
+ JORServer::getInstance()->releaseMCTX(mctx);
+
+ while (status == 0) {
+ JOR_MESSAGELOOP();
+ }
+
+ return status;
+}
diff --git a/libs/JSystem/src/JHostIO/JORServer.cpp b/libs/JSystem/src/JHostIO/JORServer.cpp
new file mode 100644
index 0000000000..18086d36d8
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JORServer.cpp
@@ -0,0 +1,822 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JORServer.h"
+#include "JSystem/JHostIO/JORReflexible.h"
+#include "JSystem/JHostIO/JORFile.h"
+#include "JSystem/JHostIO/JORHostInfo.h"
+#include "JSystem/JSupport/JSUMemoryStream.h"
+#include <cstring>
+
+void JOREventCallbackListNode::JORAppend() {
+ JORServer* pServer = JORServer::getInstance();
+ JUT_ASSERT(51, pServer!=NULL);
+ pServer->appendEventCallbackListNode(this);
+}
+
+void JOREventCallbackListNode::JORRemove() {
+ JORServer* pServer = JORServer::getInstance();
+ JUT_ASSERT(57, pServer!=NULL);
+ pServer->removeEventCallbackListNode(this);
+}
+
+JOREventCallbackListNode::JOREventCallbackListNode(u32 param_0, u32 param_1, bool append) {
+ field_0xc = param_0;
+ field_0x10 = param_1;
+
+ if (append) {
+ JORAppend();
+ }
+}
+
+JOREventCallbackListNode::~JOREventCallbackListNode() {
+ JORRemove();
+}
+
+void JORReflexible::listen(u32 command, const JOREvent* event) {
+ switch (command) {
+ case JORServer::ECommand_GenObjInfo:
+ genObjectInfo((JORGenEvent*)event);
+ break;
+ case JORServer::ECommand_NodeEvent:
+ listenNodeEvent((JORNodeEvent*)event);
+ break;
+ case JORServer::ECommand_PropertyEvent:
+ listenPropertyEvent((JORPropertyEvent*)event);
+ break;
+ }
+}
+
+void JORReflexible::genObjectInfo(const JORGenEvent* event) {
+ JORMContext* mctx = getJORServer()->attachMCTX(MCTX_MSG_GEN_OBJ_INFO);
+ mctx->startNode("", this, 0, 0);
+ genMessage(mctx);
+ mctx->endNode();
+ getJORServer()->releaseMCTX(mctx);
+}
+
+void JORReflexible::listenNodeEvent(const JORNodeEvent*) {}
+
+void JORReflexible::listenPropertyEvent(const JORPropertyEvent* pEvent) {
+ if (pEvent->kind & JORPropertyEvent::EKind_HasListener) {
+ JORServer* pServer = getJORServer();
+
+ JORPropertyEvent* event = (JORPropertyEvent*)pEvent;
+ event->kind &= ~JORPropertyEvent::EKind_HasListener;
+
+ switch (pEvent->type) {
+ case 'RNGf':
+ case 'RNGi':
+ case 'RBTN':
+ case 'CMBX':
+ if (pEvent->field_0x14 >= 4) {
+ pEvent->field_0x10->listenPropertyEvent(pEvent);
+ }
+ break;
+ case 'CHBX':
+ if (pEvent->field_0x14 >= 4) {
+ pEvent->field_0x10->listenPropertyEvent(pEvent);
+ }
+ break;
+ case 'EDBX':
+ case 'BUTN':
+ pEvent->field_0x10->listenPropertyEvent(pEvent);
+ break;
+ }
+
+ event->kind |= JORPropertyEvent::EKind_HasListener;
+ } else if (!(pEvent->kind & JORPropertyEvent::EKind_ValueID)) {
+ switch (pEvent->type) {
+ case 'RBTN':
+ case 'RNGi':
+ case 'RNGf':
+ case 'CMBX':
+ if (pEvent->field_0x14 >= 4) {
+ JORPropertyEvent* event = (JORPropertyEvent*)pEvent;
+ JORServer::defSetVal((void*)event->id, event->kind, event->field_0x18.U32);
+ }
+ break;
+ case 'CHBX':
+ if (pEvent->field_0x14 >= 4) {
+ JORPropertyEvent* event = (JORPropertyEvent*)pEvent;
+ JORServer::defSetBitVal((void*)event->id, event->kind, (u16)event->field_0x18.U16[0], (u16)event->field_0x18.U16[1]);
+ }
+ break;
+ case 'EDBX':
+ JORPropertyEvent* event = (JORPropertyEvent*)pEvent;
+ JSUMemoryInputStream stream(&event->field_0x18, event->field_0x14);
+ stream >> (char*)event->id;
+ break;
+ }
+ return;
+ }
+}
+
+JORServer* JORServer::instance;
+
+JORServer* JORServer::create() {
+ if (instance == NULL) {
+ instance = new JORServer();
+ }
+
+ return instance;
+}
+
+void JORServer::defSetVal(void* ptr, u32 kind, s32 val) {
+ switch (jhostio::GetEKindSize(kind)) {
+ case jhostio::EKind_8B:
+ *(u8*)ptr = val;
+ break;
+ case jhostio::EKind_16B:
+ *(u16*)ptr = val;
+ break;
+ case jhostio::EKind_32B:
+ *(u32*)ptr = val;
+ break;
+ }
+}
+
+void JORServer::defSetBitVal(void* ptr, u32 kind, u16 param_2, u16 param_3) {
+ param_2 &= param_3;
+
+ switch (jhostio::GetEKindSize(kind)) {
+ case jhostio::EKind_8B: {
+ u8* kptr = (u8*)ptr;
+ *kptr &= (u8)~param_3;
+ *kptr |= (u8)param_2;
+ break;
+ }
+ case jhostio::EKind_16B: {
+ u16* kptr = (u16*)ptr;
+ *kptr &= (u16)~param_3;
+ *kptr |= param_2;
+ }
+ }
+}
+
+JORMContext* JORServer::attachMCTX(u32 msgID) {
+ m_context.bufInit();
+ m_context.putMsgID(msgID);
+ return &m_context;
+}
+
+void JORServer::releaseMCTX(JORMContext* mctx) {
+ ASSERTMSGLINE(292, mctx->msgSize() < 0x10000, "JORServer:releaseMCTX: context buffer probably overflowed.\n");
+
+ if (mctx->msgSize() > 4) {
+ const s32 var_r28 = send(mctx->msgPtr(), mctx->msgSize());
+ }
+}
+
+void JORServer::receive(const char* pBuffer, s32 length) {
+ JSUMemoryInputStream stream(pBuffer, length);
+
+ u32 command;
+ stream >> command;
+
+ if (!stream.isGood()) {
+ OS_REPORT("JORServer::receive : データが足りない\n");
+ OS_REPORT("JORServer::receive : データが足りない\n");
+ return;
+ }
+
+ switch (command) {
+ case ECommand_GetRootObj:
+ if (mp_rootObj != NULL) {
+ OS_REPORT("Get RootObject ref(%08X)\n", mp_rootObj);
+ m_context.bufInit();
+ m_context.putMsgID(MCTX_MSG_GET_ROOT_OBJ);
+ m_context.genRootNode(m_rootName, mp_rootObj, field_0x10064, field_0x10068);
+ send(m_context.msgPtr(), m_context.msgSize());
+ }
+ break;
+ case ECommand_NodeEvent: {
+ u32 obj_addr;
+ stream.read(obj_addr);
+ JORNodeEvent* pEvent = (JORNodeEvent*)(pBuffer + stream.getPosition());
+ stream.skip(4);
+
+ if (stream.isGood()) {
+ reinterpret_cast<JORReflexible*>(obj_addr)->listen(command, pEvent);
+ }
+ }
+ break;
+ case ECommand_PropertyEvent: {
+ u32 obj_addr;
+ stream.read(obj_addr);
+ JORPropertyEvent* pEvent = (JORPropertyEvent*)(pBuffer + stream.getPosition());
+ stream.skip(0x18);
+
+ if (stream.isGood()) {
+ stream.skip(pEvent->field_0x14);
+ }
+
+ if (stream.isGood()) {
+ reinterpret_cast<JORReflexible*>(obj_addr)->listen(command, pEvent);
+ }
+ }
+ break;
+ case ECommand_GenObjInfo: {
+ u32 obj_addr;
+ stream.read(obj_addr);
+
+ if (stream.isGood()) {
+ reinterpret_cast<JORReflexible*>(obj_addr)->listen(command, NULL);
+ }
+ }
+ break;
+ case ECommand_FIO:
+ fio_dispatchMessage_(stream);
+ break;
+ case ECommand_DIR:
+ dir_dispatchMessage_(stream);
+ break;
+ case ECommand_ReadResultS32:
+ readResultS32_(stream);
+ break;
+ case ECommand_HostInfo:
+ hostinfo_dispatchMessage_(stream);
+ break;
+ case ECommand_ReadResultU32:
+ readResultU32_(stream);
+ break;
+ case ECommand_ReadOrEvent:
+ readOrEvent_(stream);
+ break;
+ }
+}
+
+void JORServer::fio_openFile_(JSUMemoryInputStream& stream) {
+ u32 file_addr;
+ stream >> file_addr;
+ JORFile* file = (JORFile*)file_addr;
+
+ u32 handle;
+ stream >> handle;
+
+ u32 file_len;
+ stream >> file_len;
+
+ u16 filename_len;
+ u16 basename_len;
+ u16 extension_name_len;
+ stream >> filename_len >> basename_len >> extension_name_len;
+
+ strncpy(file->getFilename(), (const char*)stream.getPointer(), filename_len);
+ file->getFilename()[filename_len] = 0;
+
+ file->setHandle(handle);
+ file->setFileLength(file_len);
+ file->setNFileName((u16)filename_len);
+ file->setNBaseName((u16)basename_len);
+ file->setNExtensionName((u16)extension_name_len);
+ file->setStatus(JORFile::EStatus_READ_DATA);
+}
+
+void JORServer::fio_closeFile_(JSUMemoryInputStream& stream) {
+ u32 file_addr;
+ stream >> file_addr;
+ JORFile* file = (JORFile*)file_addr;
+
+ u32 sp8;
+ stream >> sp8;
+
+ if (sp8 == 0) {
+ OS_REPORT("Close Failed!\n");
+ }
+
+ file->setStatus(JORFile::EStatus_READ_END);
+}
+
+void JORServer::fio_readData_(JSUMemoryInputStream& stream) {
+ u32 file_addr;
+ stream >> file_addr;
+ JORFile* file = (JORFile*)file_addr;
+
+ u32 status;
+ stream >> status;
+
+ if (status == JORFile::EStatus_READ_BEGIN) {
+ file->setStatus(status);
+ } else if (status == JORFile::EStatus_WRITE_BEGIN) {
+ file->setStatus(status);
+ } else if (status == JORFile::EStatus_WRITE_DATA) {
+ u32 position, data;
+ stream >> position >> data;
+ file->getDataStream().seek(position, JSUStreamSeekFrom_SET);
+
+ file->getDataStream().write(stream.getPointer(), data);
+ file->setStatus(status);
+ } else if (status == JORFile::EStatus_WRITE_END) {
+ file->setStatus(status);
+ }
+}
+
+void JORServer::fio_writeData_(JSUMemoryInputStream& stream) {
+ u32 file_addr;
+ stream >> file_addr;
+ JORFile* file = (JORFile*)file_addr;
+
+ u32 status;
+ stream >> status;
+
+ file->setStatus(status);
+}
+
+void JORServer::fio_dispatchMessage_(JSUMemoryInputStream& stream) {
+ u32 command;
+ stream >> command;
+
+ switch (command) {
+ case JORFile::ECommand_OPEN:
+ fio_openFile_(stream);
+ break;
+ case JORFile::ECommand_CLOSE:
+ fio_closeFile_(stream);
+ break;
+ case JORFile::ECommand_READ:
+ fio_readData_(stream);
+ break;
+ case JORFile::ECommand_WRITE:
+ fio_writeData_(stream);
+ break;
+ }
+}
+
+void JORServer::dir_dispatchMessage_(JSUMemoryInputStream& stream) {
+ u32 command, status, dir_addr;
+ stream >> command >> dir_addr >> status;
+
+ JORDir* dir = (JORDir*)dir_addr;
+ dir->setStatus(status);
+
+ if (status != 2) {
+ switch (command) {
+ case 1:
+ break;
+ case 2:
+ dir_findFirstFile_(stream, dir);
+ break;
+ case 3:
+ dir_findNextFile_(stream, dir);
+ break;
+ case 0:
+ dir_browseForFolder_(stream, dir);
+ break;
+ case 5:
+ dir_browseForFolder_(stream, dir);
+ break;
+ }
+ }
+}
+
+void JORServer::dir_findFirstFile_(JSUMemoryInputStream& stream, JORDir* directory) {
+ char namebuf[256];
+ u32 attribute, lo_time, hi_time, handle;
+ stream >> handle >> attribute >> lo_time >> hi_time >> namebuf;
+
+ directory->setFindHandle(handle);
+ directory->setFileAttribute(attribute);
+ directory->setLowDateTime(lo_time);
+ directory->setHighDateTime(hi_time);
+ strncpy(directory->getFilename(), namebuf, sizeof(namebuf) - 1);
+}
+
+void JORServer::dir_findNextFile_(JSUMemoryInputStream& stream, JORDir* directory) {
+ char namebuf[256];
+ u32 attribute, lo_time, hi_time;
+ stream >> attribute >> lo_time >> hi_time >> namebuf;
+
+ directory->setFileAttribute(attribute);
+ directory->setLowDateTime(lo_time);
+ directory->setHighDateTime(hi_time);
+ strncpy(directory->getFilename(), namebuf, sizeof(namebuf) - 1);
+}
+
+void JORServer::dir_browseForFolder_(JSUMemoryInputStream& stream, JORDir* directory) {
+ char namebuf[256];
+ u32 attribute, lo_time, hi_time;
+ stream >> attribute >> lo_time >> hi_time >> namebuf;
+
+ directory->setFileAttribute(attribute);
+ directory->setLowDateTime(lo_time);
+ directory->setHighDateTime(hi_time);
+ strncpy(directory->getFilename(), namebuf, sizeof(namebuf) - 1);
+}
+
+void JORServer::hostinfo_dispatchMessage_(JSUMemoryInputStream& stream) {
+ u32 command, spC, hostinfo_addr;
+ stream >> command >> hostinfo_addr >> spC;
+
+ JORHostInfo* hostinfo = (JORHostInfo*)hostinfo_addr;
+ hostinfo->setResult(spC != 0 ? 1 : 2);
+
+ if (spC != 0) {
+ switch (command) {
+ case HOSTINFO_REQ_COMPUTER_NAME:
+ hostinfo_recvString_(stream, (JORHostInfo_String*)hostinfo);
+ break;
+ case HOSTINFO_REQ_USERNAME:
+ hostinfo_recvString_(stream, (JORHostInfo_String*)hostinfo);
+ break;
+ case HOSTINFO_REQ_LOCAL_TIME:
+ hostinfo_localTime_(stream, (JORHostInfo_CalendarTime*)hostinfo);
+ break;
+ }
+ }
+}
+
+void JORServer::hostinfo_recvString_(JSUMemoryInputStream& stream, JORHostInfo_String* pString) {
+ char buffer[256];
+ stream >> buffer;
+ strncpy(pString->getString(), buffer, pString->getBufferSize());
+}
+
+void JORServer::hostinfo_localTime_(JSUMemoryInputStream& stream, JORHostInfo_CalendarTime* pCalendarTime) {
+ u16 year, month, weekday, monthday, hours, minutes, seconds, milliseconds;
+ stream >> year
+ >> month
+ >> weekday
+ >> monthday
+ >> hours
+ >> minutes
+ >> seconds
+ >> milliseconds;
+
+ OSCalendarTime* pTime = pCalendarTime->getCalendarTime();
+ pTime->sec = seconds;
+ pTime->min = minutes;
+ pTime->hour = hours;
+ pTime->mday = monthday;
+ pTime->mon = month - 1;
+ pTime->year = year;
+ pTime->wday = weekday;
+ pTime->msec = milliseconds;
+ pTime->usec = 0;
+ pTime->yday = monthday + JORGetYearDays(year, month - 1);
+}
+
+void JORServer::sendReset() {
+ u32 spC = JHIhtonl(0);
+ send(&spC, 4);
+}
+
+void JORServer::setRootNode(const char* name, JORReflexible* node, u32 param_2, u32 param_3) {
+ mp_rootObj = node;
+ if (name == NULL) {
+ name = "ルート";
+ }
+
+ strncpy(m_rootName, name, sizeof(m_rootName) - 1);
+ m_rootName[sizeof(m_rootName) - 1] = 0;
+ field_0x10064 = param_2;
+ field_0x10068 = param_3;
+}
+
+void JORServer::readResultU32_(JSUMemoryInputStream& stream) {
+ u32 ptr_addr, val;
+ stream >> ptr_addr >> val;
+
+ u32* ptr = (u32*)ptr_addr;
+ *ptr = val;
+}
+
+void JORServer::readResultS32_(JSUMemoryInputStream& stream) {
+ u32 ptr_addr, val;
+ stream >> ptr_addr >> val;
+
+ s32* ptr = (s32*)ptr_addr;
+ *ptr = val;
+}
+
+void JORServer::readOrEvent_(JSUMemoryInputStream& stream) {
+ if (m_eventDone) {
+ stream >> m_eventNum;
+
+ u16 name_len;
+ stream >> name_len;
+ if (name_len >= 0x1000) {
+ name_len = 0x1000 - 1;
+ }
+
+ stream.read(m_eventName, name_len);
+ m_eventName[name_len] = 0;
+ m_event = true;
+ }
+}
+
+void JORServer::doneEvent() {
+ if (!m_eventDone) {
+ m_eventDone = true;
+
+ u32 sp8 = JHIhtonl(0x10);
+ send(&sp8, 4);
+ }
+}
+
+void JORMContext::genNodeSub(const char* name, JORReflexible* node, u32 param_2, u32 param_3) {
+ mOutputStream << name;
+ putNode(node);
+
+ mOutputStream << param_2;
+
+ if (param_2 & 4) {
+ mOutputStream << param_3;
+ }
+}
+
+void JORMContext::endNode() {
+ mOutputStream << MCTX_COMMAND_END_NODE;
+}
+
+void JORMContext::invalidNode(JORReflexible* node, u32 param_1) {
+ mOutputStream << MCTX_COMMAND_INVALID_NODE;
+ putNode(node);
+
+ mOutputStream << param_1;
+}
+
+void JORMContext::genControl(u32 type, u32 kind, const char* label, u32 style, u32 id,
+ JOREventListener* pListener, u32 initValue)
+{
+ mOutputStream << type << kind << label << style << id;
+
+ if (kind & JORPropertyEvent::EKind_HasListener) {
+ mOutputStream << (uintptr_t)pListener;
+ }
+
+ if ((kind & JORPropertyEvent::EKind_ValueID) && type != 'EDBX') {
+ kind |= 0x20;
+ }
+
+ if (jhostio::GetEKindSize(kind) != 0) {
+ mOutputStream << initValue;
+ }
+}
+
+void JORMContext::genSliderSub(u32 kind, const char* label, u32 id, u32 style, s32 initValue, s32 rangeMin,
+ s32 rangeMax, JOREventListener* pListener, u16 posX, u16 posY,
+ u16 width, u16 height)
+{
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_GEN_CONTROL;
+ genControl(kind & JORPropertyEvent::EKind_FloatValue ? 'RNGf' : 'RNGi', kind, label, style, id, pListener, initValue);
+
+ mOutputStream << rangeMin << rangeMax;
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::genCheckBoxSub(u32 kind, const char* label, u32 id, u32 style, u16 initValue, u16 mask,
+ JOREventListener* pListener, u16 posX, u16 posY, u16 width,
+ u16 height)
+{
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_GEN_CONTROL;
+ genControl('CHBX', kind, label, style, id, pListener, (mask << 0x10) | initValue);
+
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::startSelectorSub(u32 type, u32 kind, const char* label, u32 id, u32 style, s32 initValue,
+ JOREventListener* pListener, u16 posX, u16 posY, u16 width,
+ u16 height)
+{
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_START_SELECTOR;
+ genControl(type, kind, label, style, id, pListener, initValue);
+
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::endSelectorSub() {
+ mOutputStream << MCTX_COMMAND_END_SELECTOR;
+}
+
+void JORMContext::genSelectorItemSub(const char* label, s32 itemNo, u32 param_2, u16 posX,
+ u16 posY, u16 width, u16 height)
+{
+ mOutputStream << MCTX_COMMAND_SELECTOR_ITEM << label << (u32)itemNo;
+ mOutputStream << param_2 << posX << posY << width << height;
+}
+
+void JORMContext::genButton(const char* label, u32 id, u32 style, JOREventListener* pListener,
+ u16 posX, u16 posY, u16 width, u16 height)
+{
+ u32 kind = 0;
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_GEN_CONTROL;
+ genControl('BUTN', kind, label, style, id, pListener, 0);
+
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::genLabel(const char* label, u32 id, u32 style, JOREventListener* pListener,
+ u16 posX, u16 posY, u16 width, u16 height)
+{
+ u32 kind = 0;
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_GEN_CONTROL;
+ genControl('LABL', kind, label, style, id, pListener, 0);
+
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::genGroupBox(const char* label, u32 id, u32 style, JOREventListener* pListener,
+ u16 posX, u16 posY, u16 width, u16 height)
+{
+ u32 kind = 0;
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_GEN_CONTROL;
+ genControl('GRBX', kind, label, style, id, pListener, 0);
+
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::genEditBoxID(const char* label, u32 id, const char* string, u16 length, u32 style,
+ JOREventListener* pListener, u16 posX, u16 posY, u16 width, u16 height)
+{
+ u32 kind = 0;
+ if (pListener != NULL) {
+ kind |= JORPropertyEvent::EKind_HasListener;
+ }
+
+ mOutputStream << MCTX_COMMAND_GEN_CONTROL;
+ genControl('EDBX', kind | JORPropertyEvent::EKind_ValueID, label, style, id, pListener, 0);
+
+ mOutputStream << length << string;
+ mOutputStream << posX << posY << width << height;
+}
+
+void JORMContext::updateControl(u32 mode, u32 id, u32 param_2) {
+ mOutputStream << MCTX_COMMAND_UPDATE_CONTROL << mode << id;
+
+ if (mode & 1) {
+ mOutputStream << param_2;
+ }
+}
+
+void JORMContext::updateControl(u32 mode, u32 id, const char* param_2) {
+ if (mode & 2) {
+ mOutputStream << MCTX_COMMAND_UPDATE_CONTROL << mode << id << param_2;
+ }
+}
+
+void JORMContext::updateSliderSub(u32 mode, u32 id, s32 value, s32 rangeMin, s32 rangeMax, u32 param_5) {
+ updateControl(mode, id, param_5);
+
+ if (mode & 2) {
+ mOutputStream << value;
+ }
+
+ if (mode & 4) {
+ mOutputStream << rangeMin << rangeMax;
+ }
+}
+
+void JORMContext::updateCheckBoxSub(u32 mode, u32 id, u16 value, u16 mask, u32 param_4) {
+ mOutputStream << MCTX_COMMAND_UPDATE_CONTROL << (mode | JORPropertyEvent::EKind_HasListener) << id << (u32)mask;
+
+ if (mode & 1) {
+ mOutputStream << param_4;
+ }
+
+ if (mode & 2) {
+ mOutputStream << (u32)((mask << 0x10) | value);
+ }
+}
+
+void JORMContext::updateSelectorSub(u32 mode, u32 id, s32 value, u32 param_3) {
+ updateControl(mode, id, param_3);
+
+ if (mode & 2) {
+ mOutputStream << value;
+ }
+}
+
+void JORMContext::updateEditBoxID(u32 mode, u32 id, const char* string, u32 param_3, u16 length) {
+ updateControl(mode, id, param_3);
+
+ if (mode & 2) {
+ mOutputStream << string;
+ }
+
+ if (mode & 0x10) {
+ mOutputStream << length;
+ }
+}
+
+void JORMContext::editComboBoxItem(u32 param_0, u32 id, const char* param_2, s32 param_3, u32 param_4) {
+ updateControl(8, id, (u32)0);
+
+ mOutputStream << param_0 << param_4 << param_2 << param_3;
+}
+
+void JORMContext::openFile(JORFile* pFile, u32 flags, const char* path, const char* extMask,
+ u32 maskSize, const char* defaultExt, const char* param_6, const char* fileSuffix)
+{
+ if (defaultExt != NULL) {
+ flags |= JORFile::EFlags_DEFAULT_EXT;
+ }
+
+ if (param_6 != NULL) {
+ flags |= JORFile::EFlags_UNK_0x20;
+ }
+
+ if (fileSuffix != NULL) {
+ flags |= JORFile::EFlags_HAS_SUFFIX;
+ }
+
+ mOutputStream << (u32)JORFile::ECommand_OPEN << (uintptr_t)pFile << flags << path;
+ mOutputStream << (u16)maskSize;
+ mOutputStream.write(extMask, maskSize);
+
+ if (defaultExt != NULL) {
+ mOutputStream << defaultExt;
+ }
+
+ if (param_6 != NULL) {
+ mOutputStream << param_6;
+ }
+
+ if (fileSuffix != NULL) {
+ mOutputStream << fileSuffix;
+ }
+}
+
+void JORMContext::closeFile(JORFile* pFile) {
+ mOutputStream << (u32)JORFile::ECommand_CLOSE << (uintptr_t)pFile << pFile->getHandle();
+}
+
+void JORMContext::readBegin(JORFile* pFile, s32 size) {
+ mOutputStream << (u32)JORFile::ECommand_READ
+ << (u32)JORFile::EStatus_READ_BEGIN
+ << (uintptr_t)pFile
+ << pFile->getHandle()
+ << (u32)size;
+}
+
+void JORMContext::readData(JORFile* pFile) {
+ mOutputStream << (u32)JORFile::ECommand_READ
+ << (u32)JORFile::EStatus_READ_DATA
+ << (uintptr_t)pFile
+ << pFile->getHandle();
+}
+
+void JORMContext::writeBegin(JORFile* pFile, u16 flags, u32 size) {
+ mOutputStream << (u32)JORFile::ECommand_WRITE
+ << (u32)JORFile::EStatus_WRITE_BEGIN
+ << (uintptr_t)pFile
+ << pFile->getHandle()
+ << (u32)size
+ << (u32)flags;
+}
+
+void JORMContext::writeData(JORFile* pFile, const void* pBuffer, s32 size, u32 position) {
+ mOutputStream << (u32)JORFile::ECommand_WRITE
+ << (u32)JORFile::EStatus_WRITE_DATA
+ << (uintptr_t)pFile
+ << pFile->getHandle()
+ << (u32)position;
+
+ mOutputStream << (u16)size;
+ mOutputStream.write(pBuffer, size);
+}
+
+void JORMContext::writeDone(JORFile* pFile, u32 size) {
+ mOutputStream << (u32)JORFile::ECommand_WRITE
+ << (u32)JORFile::EStatus_WRITE_END
+ << (uintptr_t)pFile
+ << pFile->getHandle()
+ << (u32)size;
+}
+
+void JORMContext::openMessageBox(void* param_0, u32 style, const char* message, const char* title) {
+ mOutputStream << (uintptr_t)param_0 << (u32)style << message << title;
+}
+
+void JORMContext::sendHostInfoRequest(u32 requestType, JORHostInfo* pHostInfo) {
+ mOutputStream << requestType << (uintptr_t)pHostInfo;
+}
+
+void JORMContext::sendShellExecuteRequest(void* param_0, const char* param_1, const char* param_2,
+ const char* param_3, const char* param_4, int param_5)
+{
+ mOutputStream << (uintptr_t)param_0 << param_1 << param_2 << param_3 << param_4 << (u32)param_5;
+}
diff --git a/libs/JSystem/src/JHostIO/JORShellExecute.cpp b/libs/JSystem/src/JHostIO/JORShellExecute.cpp
new file mode 100644
index 0000000000..107c978e49
--- /dev/null
+++ b/libs/JSystem/src/JHostIO/JORShellExecute.cpp
@@ -0,0 +1,18 @@
+#include "JSystem/JSystem.h" // IWYU pragma: keep
+
+#include "JSystem/JHostIO/JORServer.h"
+
+int JORShellExecute(const char* param_0, const char* param_1, const char* param_2, const char* param_3, int param_4) {
+ int rt = 0;
+ JORServer* instance = JORServer::getInstance();
+
+ JORMContext* mctx = instance->attachMCTX(MCTX_MSG_SHELL_EXEC);
+ mctx->sendShellExecuteRequest(&rt, param_0, param_1, param_2, param_3, param_4);
+ instance->releaseMCTX(mctx);
+
+ while (rt == 0) {
+ JOR_MESSAGELOOP();
+ }
+
+ return rt;
+}