diff --git a/codec.hpp b/codec.hpp new file mode 100644 index 0000000..db6b466 --- /dev/null +++ b/codec.hpp @@ -0,0 +1,221 @@ +#ifndef __LIB_CRYPTXX +#define __LIB_CRYPTXX + +#include "lib.hpp" + +void BinaryOutput(FILE* fp, const char* str, long long len) { + for (long long i = 0; i < len; i++) { + putc(str[i], fp); + } +} + +void ReadBytes(FILE* fp, char* str, long long len) { + for (long long i = 0; i < len; i++) { + str[i] = getc(fp); + // printf("NSG %d\n", ((unsigned char*)str)[i]); + } +} + +#define charCodeAt(__ch, __pos) (unsigned char)((__ch >> (__pos << 3)) & 0xff) + +class EncodeArchive { +private: + string f; + long long arcVersion; + string sourceFiles[65536]; + long long ptrAt; + long long fileCount; + long long contentLengths[65536]; + FILE *fp; + bool e; +public: + EncodeArchive(string of) { + e = false; + f = of; + errno_t err = fopen_s(&fp, f.c_str(), "wb"); + if (err) { + printf("Failed when opening the output file \"%s\", code %d.\n", f.c_str(), err); + e = true; + } else { + ptrAt = 0; + fileCount = 0; + arcVersion = CURRENT_VERSION; + } + } + void CreateHeader() { + BinaryOutput(fp, "LLAR\x00\x00\x00\x00\x0AMirekintoc", 19); + ptrAt += 19; + } + bool Error() { + return e; + } + void MakeTable() { + unsigned char ver[8]; + for (int i = 0; i < fileCount; i++) { + for (int j = 7; j >= 0; j--) { + ver[7 - j] = charCodeAt(sourceFiles[i].length(), j); + } + BinaryOutput(fp, (char*)ver, 8); + BinaryOutput(fp, sourceFiles[i].c_str(), sourceFiles[i].length()); + for (int j = 7; j >= 0; j--) { + ver[7 - j] = charCodeAt(contentLengths[i], j); + } + BinaryOutput(fp, (char*)ver, 8); + ptrAt += 16 + sourceFiles[i].length(); + } + putc(0x7F, fp); + ptrAt++; + } + void AddFile(string f) { + printf("Adding file \"%s\"...\n", f.c_str()); + sourceFiles[fileCount] = f; + contentLengths[fileCount] = gfsize(f.c_str()); + if(contentLengths[fileCount] == -1) { + e = true; + } + fileCount++; + } + void ConstructFile() { + printf("Creating header...\n"); + CreateHeader(); + printf("Making table...\n"); + MakeTable(); + for (int i = 0; i < fileCount; i++) { + printf("Processing file \"%s\"...\n", sourceFiles[i].c_str()); + FILE* f = fopen(sourceFiles[i].c_str(), "rb"); + Mask0 msk; + msk.output_mask(fp); + msk.stream_encode(contentLengths[i], f, fp); + fclose(f); + } + printf("Done!\n"); + } +}; + +class DecodeArchive { +private: + string f; + long long contentLengths[65536]; + long long beginAddr[65536]; + string fileNames[65536]; + long long headerLength, fileCount; + FILE *fp; + bool e; +public: + DecodeArchive(string str) { + f = str; + char hdr[256]; + e = false; + unsigned char* ref = (unsigned char*)hdr; + errno_t err = fopen_s(&fp, str.c_str(), "rb"); + if (err) { + e = true; + printf("Failed when opening file \"%s\", code %d.\n", str.c_str(), err); + } else { + ReadBytes(fp, hdr, 4); + hdr[4] = 0; + string s = hdr; + if (s != "LLAR") { + e = true; + printf("File \"%s\" is not a valid LLAR file.\n", str.c_str()); + } else { + int ver; + ReadBytes(fp, hdr, 4); + ver = (ref[0] << 24) + (ref[1] << 16) + (ref[2] << 8) + ref[3]; + if (ver > 0) { + e = true; + printf("Unsupported file version %d\n", ver); + } + } + } + } + void GetInformations() { + char hdr[256]; + unsigned char* ref = (unsigned char*)hdr; + ReadBytes(fp, hdr, 1); + int cop = hdr[0]; + ReadBytes(fp, hdr, cop); + hdr[cop] = 0; + printf("Notice: This file is generated by %s\n", hdr); + headerLength = 9 + cop; + fileCount = 0; + while (true) { + ReadBytes(fp, hdr, 1); + if (hdr[0] == 0x7F) { + break; + } + ReadBytes(fp, hdr + 1, 7); + long long nl = 0; + for (int i = 0; i < 8; i++) { + nl |= ref[i] << ((7 - i) << 3); + // printf("ADD %lld %d %d\n", ref[i] << ((7 - i) << 3), hdr[i], ref[i]); + } + ReadBytes(fp, hdr, nl); + hdr[nl] = 0; + printf("New file got: \"%s\"\n", hdr); + fileNames[fileCount] = hdr; + ReadBytes(fp, hdr, 8); + contentLengths[fileCount] = 0; + for (int i = 0; i < 8; i++) { + contentLengths[fileCount] |= ref[i] << ((7 - i) << 3); + } + headerLength += 16 + nl; + fileCount++; + } + headerLength++; + long long ptrAt = headerLength; + for (int i = 0; i < fileCount; i++) { + beginAddr[i] = ptrAt; + ptrAt += contentLengths[i] + 256; + } + } + bool Error() { + return e; + } + void ExtractEach(string str) { + printf("Extracting \"%s\"...\n", str.c_str()); + int id = -1; + for (int i = 0; i < fileCount; i++) { + if (fileNames[i] == str) { + id = i; + break; + } + } + if (!~id) { + printf("Cannot find file \"%s\" in archive \"%s\".\n", str, f); + e = true; + return; + } + FILE *f1; + errno_t err = fopen_s(&f1, str.c_str(), "wb"); + if (err) { + printf("Failed when opening file \"%s\", code %d.\n", str, err); + e = true; + return; + } + int err1 = _fseeki64(fp, beginAddr[id], SEEK_SET); + if (err1) { + printf("Failed when moving cursor in \"%s\", code %d.\n", str, err1); + } + Mask0 msk(fp); + msk.stream_decode(contentLengths[id], fp, f1); + fclose(f1); + } + void ExtractAll() { + FILE* f1; + for (int i = 0; i < fileCount; i++) { + printf("Extracting \"%s\"...\n", fileNames[i].c_str()); + errno_t err = fopen_s(&f1, fileNames[i].c_str(), "wb"); + if (err) { + printf("Failed when opening file \"%s\", code %d.\n", fileNames[i], err); + e = true; + return; + } + Mask0 msk(fp); + msk.stream_decode(contentLengths[i], fp, f1); + fclose(f1); + } + } +}; + +#endif \ No newline at end of file diff --git a/compile.bat b/compile.bat new file mode 100644 index 0000000..b44cf76 --- /dev/null +++ b/compile.bat @@ -0,0 +1,12 @@ +@echo off + +setlocal + +cd /d %~dp0 +echo Compiling 'llarm.cpp' into 'llarm.exe'... +g++ llarm.cpp -O2 -static -Wl,--stack=256000000 -o llarm.exe +echo Compiling 'simpllar.cpp' into 'simpllar.exe'... +g++ simpllar.cpp -O2 -static -Wl,--stack=256000000 -o simpllar.exe +echo Done! + +endlocal diff --git a/lib.hpp b/lib.hpp new file mode 100644 index 0000000..c5b1afb --- /dev/null +++ b/lib.hpp @@ -0,0 +1,97 @@ +#ifndef __LIB_CRYPT +#define __LIB_CRYPT + +#define CURRENT_VERSION 0 + +#include +using namespace std; + +mt19937 rnd; + +void Init() { + rnd.seed(random_device{}()); +} + +class Mask0 { +private: + unsigned char conv[256], dconv[256]; +public: + Mask0() { + bool vis[258]; + memset(vis, 0, sizeof(vis)); + int nex, cnt, cur; + for (int i = 0; i < 256; i++) { + nex = rnd() % (256 - i); + cnt = 0; + cur = 0; + while (cnt <= nex) { + if (!vis[cur]) { + cnt++; + } + cur++; + } + conv[i] = cur - 1; + vis[cur - 1] = true; + } + for (int i = 0; i < 256; i++) { + dconv[conv[i]] = i; + } + } + Mask0(FILE *s) { + for (int i = 0; i < 256; i++) { + conv[i] = getc(s); + } + for (int i = 0; i < 256; i++) { + dconv[conv[i]] = i; + } + } + void output_mask(FILE* out) { + for (int i = 0; i < 256; i++) { + putc(conv[i], out); + } + } + void stream_encode(long long content_length, FILE* in, FILE* out) { + unsigned char ch, xorbase = 0; + for (long long i = 0; i < content_length; i++) { + ch = getc(in); + xorbase ^= ch; + putc(conv[xorbase], out); + } + } + void stream_decode(long long content_length, FILE* in, FILE* out) { + unsigned char ch, prev = conv[0]; + for (long long i = 0; i < content_length; i++) { + ch = getc(in); + putc(dconv[prev] ^ dconv[ch], out); + prev = ch; + } + } +}; + +long long gfsize(const char *fn) { + if (!fn) { + return -1; + } + FILE *fp = NULL; + long long res; + errno_t err0 = fopen_s(&fp, fn, "rb"); + if (err0 != 0) { + printf("Failed when opening file \"%s\", code %d.\n", fn, err0); + return -1; + } + int err1 = _fseeki64(fp, 0, SEEK_END); + if (err1 != 0) { + printf("Failed when moving cursor in file \"%s\" (SEEK_END), code %d.\n", fn, err1); + return -1; + } + res = _ftelli64(fp); + int err2 = _fseeki64(fp, 0, SEEK_SET); + if (err2 != 0) { + printf("Failed when moving cursor in file \"%s\" (SEEK_SET), code %d.\n", fn, err1); + return -1; + } + fclose(fp); + return res; +} + +#endif \ No newline at end of file diff --git a/llarm.cpp b/llarm.cpp new file mode 100644 index 0000000..9da2729 --- /dev/null +++ b/llarm.cpp @@ -0,0 +1,86 @@ +#include "codec.hpp" + +void About() { + puts("Mirekintoc's LLAR CLI v1.0.0"); + puts("Designed for LLAR v1.0"); + puts("LLAR (MOS-0001) is a definition, not a project."); + puts("Join the MOS (Mirekintoc Open Standards)!"); + puts("Copyright(C) 2009-2023 Mirekintoc Void."); + puts("Copyright(C) 2019-2023 Minphtis Development."); + puts("Under MIT License."); +} + +void Help() { + puts("Usage:"); + puts("llarm [d|e] \n"); + puts("Use \'d\' to decode a file."); + puts("If you used , than it will"); + puts("do not extract all files, but decode files"); + puts("mentioned. You can use it for not only once.\n"); + puts("Use \'e\' to encode a file."); + puts("If you do not used , than it"); + puts("will be an empty archive. Just contain something"); + puts("in it!\n"); + puts("\"llarm -h|--help\" will show help."); + puts("\"llarm -a|--about\" will show about."); +} + +int main(int argc, char *argv[]) { + Init(); + if (argc == 1) { + About(); + putchar('\n'); + Help(); + return 0; + } + if (argc == 2) { + string argv_1 = argv[1]; + if (argv_1 == "-h" || argv_1 == "--help") { + Help(); + return 0; + } + if (argv_1 == "-a" || argv_1 == "--about") { + About(); + return 0; + } + puts("Unknown usage!\n"); + Help(); + return 1; + } + string f = argv[1], opt = argv[2]; + if (opt == "d") { + DecodeArchive darch(f); + if (darch.Error()) { + return 1; + } + darch.GetInformations(); + if (argc > 3) { + for (int i = 3; i < argc; i++) { + darch.ExtractEach(argv[i]); + if (darch.Error()) { + return 1; + } + } + } else { + darch.ExtractAll(); + } + return darch.Error(); + } + if (opt == "e") { + EncodeArchive earch(f); + if (earch.Error()) { + return 1; + } + for (int i = 3; i < argc; i++) { + earch.AddFile(argv[i]); + if(earch.Error()) { + return 1; + } + } + earch.ConstructFile(); + return earch.Error(); + } + puts("Unknown operation!"); + Help(); + return 1; +} \ No newline at end of file diff --git a/simpllar.cpp b/simpllar.cpp new file mode 100644 index 0000000..60746dd --- /dev/null +++ b/simpllar.cpp @@ -0,0 +1,73 @@ +#include "codec.hpp" + +string fnproc(string fn) { + string ret = "", tmp = ""; + int len = fn.length(); + for (int i = 0; i < len; i++) { + if (fn[i] == '.') { + ret += tmp; + tmp = "."; + } else { + tmp += fn[i]; + } + } + if (ret == "") { + ret = tmp; + } + ret += ".llar"; + return ret; +} + +string getext(string fn) { + string res = ""; + int len = fn.length(); + for (int i = 0; i < len; i++) { + if (fn[i] == '.') { + res = ""; + } else { + res += fn[i]; + } + } + return res; +} + +int main(int argc, char *argv[]) { + Init(); + if (argc == 1) { + return 0; + } + if (argc == 2) { + if (getext(argv[1]) == "llar") { + DecodeArchive darch(argv[1]); + if (darch.Error()) { + return -1; + } + darch.GetInformations(); + darch.ExtractAll(); + return darch.Error(); + } else { + EncodeArchive earch(fnproc(argv[1])); + if (earch.Error()) { + return 1; + } + earch.AddFile(argv[1]); + if(earch.Error()) { + return 1; + } + earch.ConstructFile(); + return earch.Error(); + } + } + EncodeArchive earch("out.llar"); + if (earch.Error()) { + return 1; + } + for (int i = 1; i < argc; i++) { + earch.AddFile(argv[i]); + if(earch.Error()) { + return 1; + } + } + earch.ConstructFile(); + return earch.Error(); +} \ No newline at end of file