Fix bug with classes, use slim exclusively, add package private data and change rehaul cmake configs

This commit is contained in:
2026-05-29 20:52:26 -05:00
parent d26e357448
commit abea319ea0
110 changed files with 25714 additions and 31014 deletions
+290 -308
View File
@@ -1,324 +1,306 @@
#include "CrossLang.hpp"
#include <iostream>
namespace Tesses::CrossLang
{
void CrossArchiveCreate(std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs,std::shared_ptr<Tesses::Framework::Streams::Stream> strm,std::string name, TVMVersion version, std::string info, std::string icon)
{
std::vector<std::string> ignored_files;
std::string file = "/.crossarchiveignore";
if(vfs->FileExists(file))
{
auto strm = vfs->OpenFile(file,"rb");
if(strm != nullptr)
{
Tesses::Framework::TextStreams::StreamReader reader(strm);
std::string ignores;
while(reader.ReadLine(ignores))
{
if(!ignores.empty() && ignores[0] != '#')
{
ignored_files.push_back(ignores);
}
ignores.clear();
namespace Tesses::CrossLang {
void CrossArchiveCreate(
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs,
std::shared_ptr<Tesses::Framework::Streams::Stream> strm, std::string name,
TVMVersion version, std::string info, std::string icon) {
std::vector<std::string> ignored_files;
std::string file = "/.crossarchiveignore";
if (vfs->FileExists(file)) {
auto strm = vfs->OpenFile(file, "rb");
if (strm != nullptr) {
Tesses::Framework::TextStreams::StreamReader reader(strm);
std::string ignores;
while (reader.ReadLine(ignores)) {
if (!ignores.empty() && ignores[0] != '#') {
ignored_files.push_back(ignores);
}
ignores.clear();
}
}
static std::vector<uint8_t> error_message_byte_code = {
PUSHSTRING,
0,
0,
0,
2,
GETVARIABLE,
PUSHSTRING,
0,
0,
0,
3,
PUSHSTRING,
0,
0,
0,
4,
PUSHLONG,
0,
0,
0,
0,
0,
0,
0,
1,
CALLMETHOD,
RET
};
auto writeInt = [](std::shared_ptr<Tesses::Framework::Streams::Stream> strm,uint32_t number)->void{
uint8_t buff[4];
BitConverter::FromUint32BE(buff[0],number);
strm->WriteBlock(buff,4);
};
auto writeStr = [&writeInt](std::shared_ptr<Tesses::Framework::Streams::Stream> strm,std::string text)->void {
writeInt(strm,(uint32_t)text.size());
strm->WriteBlock((const uint8_t*)text.c_str(),text.size());
};
std::vector<std::string> strs;
strs.push_back(name);
strs.push_back(info);
strs.push_back("Console");
strs.push_back("WriteLine");
strs.push_back("You are trying to run a crvm archive, stop it you won't get anywhere!\nUse crossarchiveextract instead.");
std::vector<std::string> resources;
auto ensureResource = [&resources](std::string path)->uint32_t {
for(uint32_t i = 0; i < (uint32_t)resources.size(); i++)
{
if(resources[i] == path) return i;
}
uint32_t index = (uint32_t)resources.size();
resources.push_back(path);
return index;
};
auto ensureString = [&strs](std::string str)->uint32_t {
for(uint32_t i = 0; i < (uint32_t)strs.size(); i++)
{
if(strs[i] == str) return i;
}
uint32_t index = (uint32_t)strs.size();
strs.push_back(str);
return index;
};
auto ms = std::make_shared<Tesses::Framework::Streams::MemoryStream>(true);
std::function<void(Tesses::Framework::Filesystem::VFSPath)> walkFS = [&ignored_files,vfs,&ensureString,&ensureResource,&ms,&walkFS,&writeInt](Tesses::Framework::Filesystem::VFSPath path)->void {
if(vfs->DirectoryExists(path))
{
ms->WriteByte(1);
std::vector<std::string> paths;
for(auto item : vfs->EnumeratePaths(path))
{
if(!item.relative && item.path.size() == 1 && item.path[0] == "__resdir_tmp") continue;
if(!item.relative && item.path.size() == 1 && item.path[0] == ".crossarchiveignore") continue;
std::string filename = item.GetFileName();
bool shallIgnore=false;
for(auto ign : ignored_files) if(ign == filename) {shallIgnore=true; break;}
if(shallIgnore) continue;
if(vfs->DirectoryExists(item) || vfs->RegularFileExists(item))
paths.push_back(item.GetFileName());
}
writeInt(ms,(uint32_t)paths.size());
for(auto item : paths)
{
writeInt(ms,ensureString(item));
walkFS(path / item);
}
}
else if(vfs->RegularFileExists(path))
{
ms->WriteByte(0);
writeInt(ms,ensureResource(path.ToString()));
}
};
walkFS(std::string("/"));
if(!icon.empty())
ensureResource(icon);
uint8_t main_header[18];
memcpy(main_header,"TCROSSVM",8);
TVMVersion rtVersion(CROSSLANG_BYTECODE_MAJOR,CROSSLANG_BYTECODE_MINOR,CROSSLANG_BYTECODE_PATCH,CROSSLANG_BYTECODE_BUILD,CROSSLANG_BYTECODE_VERSIONSTAGE);
rtVersion.ToArray(main_header+8);
version.ToArray(main_header+13);
strm->WriteBlock(main_header,sizeof(main_header));
writeInt(strm,(uint32_t)((icon.empty() ? 5 : 6)+resources.size()));
strm->WriteBlock((const uint8_t*)"STRS",4);
uint32_t sz=4;
for(auto str : strs)
sz += (uint32_t)(4 + str.size());
writeInt(strm,sz);
writeInt(strm,(uint32_t)strs.size());
for(auto str : strs)
{
writeStr(strm,str);
}
strm->WriteBlock((const uint8_t*)"NAME",4);
writeInt(strm,4);
writeInt(strm,0);
strm->WriteBlock((const uint8_t*)"INFO",4);
writeInt(strm,4);
writeInt(strm,1);
if(!icon.empty())
{
strm->WriteBlock((const uint8_t*)"ICON",4);
writeInt(strm,4);
writeInt(strm,ensureResource(icon));
}
strm->WriteBlock((const uint8_t*)"CHKS",4);
writeInt(strm,(uint32_t)(12+error_message_byte_code.size()));
writeInt(strm,1);
writeInt(strm,0);
writeInt(strm,(uint32_t)error_message_byte_code.size());
strm->WriteBlock(error_message_byte_code.data(),error_message_byte_code.size());
for(auto res : resources)
{
strm->WriteBlock((const uint8_t*)"RESO",4);
auto strm2 = vfs->OpenFile(res,"rb");
writeInt(strm,(uint32_t)strm2->GetLength());
strm2->CopyTo(strm);
}
strm->WriteBlock((const uint8_t*)"ARCV",4);
writeInt(strm,(uint32_t)ms->GetLength());
ms->Seek(0,Tesses::Framework::Streams::SeekOrigin::Begin);
ms->CopyTo(strm);
}
std::pair<std::pair<std::string,TVMVersion>,std::string> CrossArchiveExtract(std::shared_ptr<Tesses::Framework::Streams::Stream> strm,std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs)
{
auto ensure = [strm](uint8_t* buffer,size_t count)->void{
static std::vector<uint8_t> error_message_byte_code = {
PUSHSTRING, 0, 0, 0, 2, GETVARIABLE, PUSHSTRING, 0, 0, 0,
3, PUSHSTRING, 0, 0, 0, 4, PUSHLONG, 0, 0, 0,
0, 0, 0, 0, 1, CALLMETHOD, RET};
auto writeInt = [](std::shared_ptr<Tesses::Framework::Streams::Stream> strm,
uint32_t number) -> void {
uint8_t buff[4];
BitConverter::FromUint32BE(buff[0], number);
strm->WriteBlock(buff, 4);
};
auto writeStr =
[&writeInt](std::shared_ptr<Tesses::Framework::Streams::Stream> strm,
std::string text) -> void {
writeInt(strm, (uint32_t)text.size());
strm->WriteBlock((const uint8_t *)text.c_str(), text.size());
};
size_t read = strm->ReadBlock(buffer, count);
if(read < count) throw VMException("End of file, could not read " + std::to_string((int64_t)count) + " byte(s)., offset=" + std::to_string(strm->GetLength()));
};
auto ensureInt = [&ensure]()->uint32_t {
uint8_t buffer[4];
ensure(buffer,4);
return BitConverter::ToUint32BE(buffer[0]);
};
auto ensureStr = [&ensure,&ensureInt]()-> std::string {
auto len = ensureInt();
if(len == 0) return {};
std::string str={};
str.resize((size_t)len);
ensure((uint8_t*)str.data(),str.size());
return str;
};
std::vector<std::string> strs;
auto getStr = [&ensure,&ensureInt,&strs]()-> std::string {
auto index = ensureInt();
if(index > strs.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(strs.size()));
return strs[index];
};
uint8_t main_header[18];
ensure(main_header,sizeof(main_header));
if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image.");
TVMVersion version(main_header+8);
if(version.CompareToRuntime() == 1)
{
throw VMException("Runtime is too old.");
std::vector<std::string> strs;
strs.push_back(name);
strs.push_back(info);
strs.push_back("Console");
strs.push_back("WriteLine");
strs.push_back("You are trying to run a crvm archive, stop it you won't "
"get anywhere!\nUse crossarchiveextract instead.");
std::vector<std::string> resources;
auto ensureResource = [&resources](std::string path) -> uint32_t {
for (uint32_t i = 0; i < (uint32_t)resources.size(); i++) {
if (resources[i] == path)
return i;
}
TVMVersion v2(main_header+13);
std::string name;
std::string info;
uint32_t index = (uint32_t)resources.size();
resources.push_back(path);
return index;
};
auto ensureString = [&strs](std::string str) -> uint32_t {
for (uint32_t i = 0; i < (uint32_t)strs.size(); i++) {
if (strs[i] == str)
return i;
}
uint32_t index = (uint32_t)strs.size();
strs.push_back(str);
return index;
};
auto ms = std::make_shared<Tesses::Framework::Streams::MemoryStream>(true);
size_t _len = (size_t)ensureInt();
std::function<void(Tesses::Framework::Filesystem::VFSPath)> walkFS =
[&ignored_files, vfs, &ensureString, &ensureResource, &ms, &walkFS,
&writeInt](Tesses::Framework::Filesystem::VFSPath path) -> void {
if (vfs->DirectoryExists(path)) {
char table_name[4];
uint32_t resource_id = 0;
Tesses::Framework::Filesystem::VFSPath tmpDir("/__resdir_tmp");
vfs->CreateDirectory(tmpDir);
for(size_t i = 0;i < _len; i++)
{
ensure((uint8_t*)table_name,sizeof(table_name));
size_t tableLen = (size_t)ensureInt();
if(strncmp(table_name,"NAME",4) == 0)
{
name = getStr();
}
else if(strncmp(table_name,"INFO",4) == 0)
{
info = getStr();
}
else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed)
{
auto path = tmpDir /std::to_string(resource_id);
auto strm2 = vfs->OpenFile(path,"wb");
size_t read = 0;
size_t offset = 0;
uint8_t buff[1024];
do {
read = std::min(std::min(tableLen-offset,tableLen), sizeof(buff));
read = strm->Read(buff,read);
if(read > 0)
strm2->WriteBlock(buff,read);
offset+=read;
} while(read > 0);
resource_id++;
}
else if(strncmp(table_name,"STRS",4) == 0) //strings
{
size_t strsLen = (size_t)ensureInt();
for(size_t j = 0;j < strsLen;j++)
{
strs.push_back(ensureStr());
}
}
else if(strncmp(table_name,"ARCV",4) == 0)
{
size_t offset = 0;
std::function<void(Tesses::Framework::Filesystem::VFSPath)> walkEntry = [strm,vfs,&getStr,&ensureInt,&tmpDir,&tableLen,&offset,&walkEntry](Tesses::Framework::Filesystem::VFSPath path)->void {
if(offset + 1 > tableLen) return;
uint8_t type = strm->ReadByte();
offset++;
if(type == 1)
{
//ISDIR
vfs->CreateDirectory(path);
if(offset + 4 > tableLen) return;
uint32_t count = ensureInt();
offset +=4;
for(uint32_t i = 0; i < count; i++)
{
if(offset + 4 > tableLen) return;
std::string name = getStr();
offset +=4;
walkEntry(path / name);
}
}
else if(type == 0)
{
if(offset + 4 > tableLen) return;
uint32_t index = ensureInt();
auto fSrc = tmpDir /std::to_string(index);
vfs->MoveFile(fSrc, path);
ms->WriteByte(1);
std::vector<std::string> paths;
for (auto item : vfs->EnumeratePaths(path)) {
if (!item.relative && item.path.size() == 1 &&
item.path[0] == "__resdir_tmp")
continue;
if (!item.relative && item.path.size() == 1 &&
item.path[0] == ".crossarchiveignore")
continue;
std::string filename = item.GetFileName();
bool shallIgnore = false;
for (auto ign : ignored_files)
if (ign == filename) {
shallIgnore = true;
break;
}
};
walkEntry(std::string("/"));
if (shallIgnore)
continue;
if (vfs->DirectoryExists(item) || vfs->RegularFileExists(item))
paths.push_back(item.GetFileName());
}
else
{
if(strm->CanSeek())
{
strm->Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current);
}
else{
uint8_t* buffer=new uint8_t[tableLen];
ensure(buffer,tableLen);
delete[] buffer;
}
writeInt(ms, (uint32_t)paths.size());
for (auto item : paths) {
writeInt(ms, ensureString(item));
walkFS(path / item);
}
} else if (vfs->RegularFileExists(path)) {
ms->WriteByte(0);
writeInt(ms, ensureResource(path.ToString()));
}
vfs->DeleteDirectoryRecurse(tmpDir);
return std::pair<std::pair<std::string,TVMVersion>,std::string>(std::pair<std::string,TVMVersion>(name,v2),info);
};
walkFS(std::string("/"));
if (!icon.empty())
ensureResource(icon);
uint8_t main_header[18];
memcpy(main_header, "TCROSSVM", 8);
TVMVersion rtVersion(CROSSLANG_BYTECODE_MAJOR, CROSSLANG_BYTECODE_MINOR,
CROSSLANG_BYTECODE_PATCH, CROSSLANG_BYTECODE_BUILD,
CROSSLANG_BYTECODE_VERSIONSTAGE);
rtVersion.ToArray(main_header + 8);
version.ToArray(main_header + 13);
strm->WriteBlock(main_header, sizeof(main_header));
writeInt(strm, (uint32_t)((icon.empty() ? 5 : 6) + resources.size()));
strm->WriteBlock((const uint8_t *)"STRS", 4);
uint32_t sz = 4;
for (auto str : strs)
sz += (uint32_t)(4 + str.size());
writeInt(strm, sz);
writeInt(strm, (uint32_t)strs.size());
for (auto str : strs) {
writeStr(strm, str);
}
strm->WriteBlock((const uint8_t *)"NAME", 4);
writeInt(strm, 4);
writeInt(strm, 0);
strm->WriteBlock((const uint8_t *)"INFO", 4);
writeInt(strm, 4);
writeInt(strm, 1);
if (!icon.empty()) {
strm->WriteBlock((const uint8_t *)"ICON", 4);
writeInt(strm, 4);
writeInt(strm, ensureResource(icon));
}
strm->WriteBlock((const uint8_t *)"CHKS", 4);
writeInt(strm, (uint32_t)(12 + error_message_byte_code.size()));
writeInt(strm, 1);
writeInt(strm, 0);
writeInt(strm, (uint32_t)error_message_byte_code.size());
strm->WriteBlock(error_message_byte_code.data(),
error_message_byte_code.size());
for (auto res : resources) {
strm->WriteBlock((const uint8_t *)"RESO", 4);
auto strm2 = vfs->OpenFile(res, "rb");
writeInt(strm, (uint32_t)strm2->GetLength());
strm2->CopyTo(strm);
}
strm->WriteBlock((const uint8_t *)"ARCV", 4);
writeInt(strm, (uint32_t)ms->GetLength());
ms->Seek(0, Tesses::Framework::Streams::SeekOrigin::Begin);
ms->CopyTo(strm);
}
std::pair<std::pair<std::string, TVMVersion>, std::string>
CrossArchiveExtract(std::shared_ptr<Tesses::Framework::Streams::Stream> strm,
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs) {
auto ensure = [strm](uint8_t *buffer, size_t count) -> void {
size_t read = strm->ReadBlock(buffer, count);
if (read < count)
throw VMException(
"End of file, could not read " +
std::to_string((int64_t)count) +
" byte(s)., offset=" + std::to_string(strm->GetLength()));
};
auto ensureInt = [&ensure]() -> uint32_t {
uint8_t buffer[4];
ensure(buffer, 4);
return BitConverter::ToUint32BE(buffer[0]);
};
auto ensureStr = [&ensure, &ensureInt]() -> std::string {
auto len = ensureInt();
if (len == 0)
return {};
std::string str = {};
str.resize((size_t)len);
ensure((uint8_t *)str.data(), str.size());
return str;
};
std::vector<std::string> strs;
auto getStr = [&ensure, &ensureInt, &strs]() -> std::string {
auto index = ensureInt();
if (index > strs.size())
throw VMException("String does not exist in TCrossVM file, "
"expected string index: " +
std::to_string(index) + ", total strings: " +
std::to_string(strs.size()));
return strs[index];
};
uint8_t main_header[18];
ensure(main_header, sizeof(main_header));
if (strncmp((const char *)main_header, "TCROSSVM", 8) != 0)
throw VMException("Invalid TCrossVM image.");
TVMVersion version(main_header + 8);
if (version.CompareToRuntime() == 1) {
throw VMException("Runtime is too old.");
}
TVMVersion v2(main_header + 13);
std::string name;
std::string info;
size_t _len = (size_t)ensureInt();
char table_name[4];
uint32_t resource_id = 0;
Tesses::Framework::Filesystem::VFSPath tmpDir("/__resdir_tmp");
vfs->CreateDirectory(tmpDir);
for (size_t i = 0; i < _len; i++) {
ensure((uint8_t *)table_name, sizeof(table_name));
size_t tableLen = (size_t)ensureInt();
if (strncmp(table_name, "NAME", 4) == 0) {
name = getStr();
} else if (strncmp(table_name, "INFO", 4) == 0) {
info = getStr();
}
else if (strncmp(table_name, "RESO", 4) == 0) // resources (using embed)
{
auto path = tmpDir / std::to_string(resource_id);
auto strm2 = vfs->OpenFile(path, "wb");
size_t read = 0;
size_t offset = 0;
uint8_t buff[1024];
do {
read = std::min(std::min(tableLen - offset, tableLen),
sizeof(buff));
read = strm->Read(buff, read);
if (read > 0)
strm2->WriteBlock(buff, read);
offset += read;
} while (read > 0);
resource_id++;
}
else if (strncmp(table_name, "STRS", 4) == 0) // strings
{
size_t strsLen = (size_t)ensureInt();
for (size_t j = 0; j < strsLen; j++) {
strs.push_back(ensureStr());
}
} else if (strncmp(table_name, "ARCV", 4) == 0) {
size_t offset = 0;
std::function<void(Tesses::Framework::Filesystem::VFSPath)>
walkEntry =
[strm, vfs, &getStr, &ensureInt, &tmpDir, &tableLen,
&offset, &walkEntry](
Tesses::Framework::Filesystem::VFSPath path) -> void {
if (offset + 1 > tableLen)
return;
uint8_t type = strm->ReadByte();
offset++;
if (type == 1) {
// ISDIR
vfs->CreateDirectory(path);
if (offset + 4 > tableLen)
return;
uint32_t count = ensureInt();
offset += 4;
for (uint32_t i = 0; i < count; i++) {
if (offset + 4 > tableLen)
return;
std::string name = getStr();
offset += 4;
walkEntry(path / name);
}
} else if (type == 0) {
if (offset + 4 > tableLen)
return;
uint32_t index = ensureInt();
auto fSrc = tmpDir / std::to_string(index);
vfs->MoveFile(fSrc, path);
}
};
walkEntry(std::string("/"));
} else {
if (strm->CanSeek()) {
strm->Seek((int64_t)tableLen,
Tesses::Framework::Streams::SeekOrigin::Current);
} else {
uint8_t *buffer = new uint8_t[tableLen];
ensure(buffer, tableLen);
delete[] buffer;
}
}
}
vfs->DeleteDirectoryRecurse(tmpDir);
return std::pair<std::pair<std::string, TVMVersion>, std::string>(
std::pair<std::string, TVMVersion>(name, v2), info);
}
} // namespace Tesses::CrossLang