diff --git a/README.md b/README.md index 97b99dfe..0565a23b 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ There are multiple PSO quest formats out there; newserv supports most of them. I | Format | Extension | Supported online? | Offline decode option | |---------------------------|-------------------|-------------------|---------------------------| | Compressed | .bin/.dat | Yes | None (1) | -| Uncompressed | .bind/.datd | Yes | None (2) | +| Uncompressed | .bind/.datd | Yes | --compress-data (2) | | Unencrypted GCI | .bin.gci/.dat.gci | Yes | --decode-gci=FILENAME | | Encrypted GCI with key | .bin.gci/.dat.gci | Yes | --decode-gci=FILENAME | | Encrypted GCI without key | .bin.gci/.dat.gci | No | --decode-gci=FILENAME (3) | @@ -106,8 +106,8 @@ There are multiple PSO quest formats out there; newserv supports most of them. I | QST | .qst | Yes | --decode-qst=FILENAME | *Notes:* -1. *This is the default format. You can convert these to uncompressed format with [gctools](https://github.com/fuzziqersoftware/gctools)' prsd like this: `prsd -d < FILENAME.bin > FILENAME.bind`* -2. *As in (1), to compress an uncompressed quest file: `prsd < FILENAME.bind > FILENAME.bin`* +1. *This is the default format. You can convert these to uncompressed format like this: `newserv --decompress-data < FILENAME.bin > FILENAME.bind`* +2. *Similar to (1), to compress an uncompressed quest file: `newserv --compress-data < FILENAME.bind > FILENAME.bin`* 3. *If you know the encryption seed (serial number), pass it in as a hex string with the `--seed=` option. If you don't know the encryption seed, newserv will find it for you, which will likely take a long time.* Episode 3 quests consist only of a .bin file - there is no corresponding .dat file. Episode 3 .bin files can be encoded in any of the formats described above, except .qst. diff --git a/src/Main.cc b/src/Main.cc index 178b2946..b1b801ed 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -12,6 +12,7 @@ #include #include "CatSession.hh" +#include "Compression.hh" #include "DNSServer.hh" #include "IPStackSimulator.hh" #include "Loggers.hh" @@ -223,6 +224,9 @@ system/config.json for more information.\n\ \n\ When options are given, newserv will do things other than running the server.\n\ Specifically:\n\ + --compress-data\n\ + --decompress-data\n\ + Compress or decompress data using the PRS algorithm.\n\ --decrypt-data\n\ --encrypt-data\n\ Read from stdin, encrypt or decrypt the data, and write the result to\n\ @@ -291,6 +295,8 @@ A few options apply to multiple modes described above:\n\ enum class Behavior { RUN_SERVER = 0, + DECOMPRESS_DATA, + COMPRESS_DATA, DECRYPT_DATA, ENCRYPT_DATA, FIND_DECRYPTION_SEED, @@ -334,6 +340,10 @@ int main(int argc, char** argv) { if (!strcmp(argv[x], "--help")) { print_usage(); return 0; + } else if (!strcmp(argv[x], "--decompress-data")) { + behavior = Behavior::DECOMPRESS_DATA; + } else if (!strcmp(argv[x], "--compress-data")) { + behavior = Behavior::COMPRESS_DATA; } else if (!strcmp(argv[x], "--decrypt-data")) { behavior = Behavior::DECRYPT_DATA; } else if (!strcmp(argv[x], "--encrypt-data")) { @@ -412,6 +422,31 @@ int main(int argc, char** argv) { } switch (behavior) { + case Behavior::DECOMPRESS_DATA: + case Behavior::COMPRESS_DATA: { + string data = read_all(stdin); + if (parse_data) { + data = parse_data_string(data); + } + + if (behavior == Behavior::DECOMPRESS_DATA) { + data = prs_decompress(data); + } else if (behavior == Behavior::COMPRESS_DATA) { + data = prs_compress(data); + } else { + throw logic_error("invalid behavior"); + } + + if (isatty(fileno(stdout))) { + print_data(stdout, data); + } else { + fwritex(stdout, data); + } + fflush(stdout); + + break; + } + case Behavior::DECRYPT_DATA: case Behavior::ENCRYPT_DATA: { shared_ptr crypt;