add pr2 compression and decompression
This commit is contained in:
+48
-4
@@ -98,10 +98,12 @@ The actions are:\n\
|
|||||||
You\'re reading it now.\n\
|
You\'re reading it now.\n\
|
||||||
compress-prs [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
compress-prs [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
||||||
decompress-prs [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
decompress-prs [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
||||||
|
compress-pr2 [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
||||||
|
decompress-pr2 [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
||||||
compress-bc0 [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
compress-bc0 [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
||||||
decompress-bc0 [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
decompress-bc0 [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
|
||||||
Compress or decompress data using the PRS or BC0 algorithms. When\n\
|
Compress or decompress data using the PRS, PR2, or BC0 algorithms. When\n\
|
||||||
compressing with PRS, the --compression-level=N option (default 1)\n\
|
compressing with PRS or PR2, the --compression-level=N option (default 1)\n\
|
||||||
specifies how aggressive the compressor should be in searching for literal\n\
|
specifies how aggressive the compressor should be in searching for literal\n\
|
||||||
sequences. A higher value generally means slower compression and a smaller\n\
|
sequences. A higher value generally means slower compression and a smaller\n\
|
||||||
output size. If 0 is given, the data is PRS-encoded but not actually\n\
|
output size. If 0 is given, the data is PRS-encoded but not actually\n\
|
||||||
@@ -210,6 +212,8 @@ enum class Behavior {
|
|||||||
RUN_SERVER = 0,
|
RUN_SERVER = 0,
|
||||||
COMPRESS_PRS,
|
COMPRESS_PRS,
|
||||||
DECOMPRESS_PRS,
|
DECOMPRESS_PRS,
|
||||||
|
COMPRESS_PR2,
|
||||||
|
DECOMPRESS_PR2,
|
||||||
COMPRESS_BC0,
|
COMPRESS_BC0,
|
||||||
DECOMPRESS_BC0,
|
DECOMPRESS_BC0,
|
||||||
PRS_SIZE,
|
PRS_SIZE,
|
||||||
@@ -244,6 +248,8 @@ enum class Behavior {
|
|||||||
static bool behavior_takes_input_filename(Behavior b) {
|
static bool behavior_takes_input_filename(Behavior b) {
|
||||||
return (b == Behavior::COMPRESS_PRS) ||
|
return (b == Behavior::COMPRESS_PRS) ||
|
||||||
(b == Behavior::DECOMPRESS_PRS) ||
|
(b == Behavior::DECOMPRESS_PRS) ||
|
||||||
|
(b == Behavior::COMPRESS_PR2) ||
|
||||||
|
(b == Behavior::DECOMPRESS_PR2) ||
|
||||||
(b == Behavior::COMPRESS_BC0) ||
|
(b == Behavior::COMPRESS_BC0) ||
|
||||||
(b == Behavior::DECOMPRESS_BC0) ||
|
(b == Behavior::DECOMPRESS_BC0) ||
|
||||||
(b == Behavior::PRS_SIZE) ||
|
(b == Behavior::PRS_SIZE) ||
|
||||||
@@ -273,6 +279,8 @@ static bool behavior_takes_input_filename(Behavior b) {
|
|||||||
static bool behavior_takes_output_filename(Behavior b) {
|
static bool behavior_takes_output_filename(Behavior b) {
|
||||||
return (b == Behavior::COMPRESS_PRS) ||
|
return (b == Behavior::COMPRESS_PRS) ||
|
||||||
(b == Behavior::DECOMPRESS_PRS) ||
|
(b == Behavior::DECOMPRESS_PRS) ||
|
||||||
|
(b == Behavior::COMPRESS_PR2) ||
|
||||||
|
(b == Behavior::DECOMPRESS_PR2) ||
|
||||||
(b == Behavior::COMPRESS_BC0) ||
|
(b == Behavior::COMPRESS_BC0) ||
|
||||||
(b == Behavior::DECOMPRESS_BC0) ||
|
(b == Behavior::DECOMPRESS_BC0) ||
|
||||||
(b == Behavior::ENCRYPT_DATA) ||
|
(b == Behavior::ENCRYPT_DATA) ||
|
||||||
@@ -403,6 +411,10 @@ int main(int argc, char** argv) {
|
|||||||
behavior = Behavior::COMPRESS_PRS;
|
behavior = Behavior::COMPRESS_PRS;
|
||||||
} else if (!strcmp(argv[x], "decompress-prs")) {
|
} else if (!strcmp(argv[x], "decompress-prs")) {
|
||||||
behavior = Behavior::DECOMPRESS_PRS;
|
behavior = Behavior::DECOMPRESS_PRS;
|
||||||
|
} else if (!strcmp(argv[x], "compress-pr2")) {
|
||||||
|
behavior = Behavior::COMPRESS_PR2;
|
||||||
|
} else if (!strcmp(argv[x], "decompress-pr2")) {
|
||||||
|
behavior = Behavior::DECOMPRESS_PR2;
|
||||||
} else if (!strcmp(argv[x], "compress-bc0")) {
|
} else if (!strcmp(argv[x], "compress-bc0")) {
|
||||||
behavior = Behavior::COMPRESS_BC0;
|
behavior = Behavior::COMPRESS_BC0;
|
||||||
} else if (!strcmp(argv[x], "decompress-bc0")) {
|
} else if (!strcmp(argv[x], "decompress-bc0")) {
|
||||||
@@ -561,9 +573,25 @@ int main(int argc, char** argv) {
|
|||||||
switch (behavior) {
|
switch (behavior) {
|
||||||
case Behavior::COMPRESS_PRS:
|
case Behavior::COMPRESS_PRS:
|
||||||
case Behavior::DECOMPRESS_PRS:
|
case Behavior::DECOMPRESS_PRS:
|
||||||
|
case Behavior::COMPRESS_PR2:
|
||||||
|
case Behavior::DECOMPRESS_PR2:
|
||||||
case Behavior::COMPRESS_BC0:
|
case Behavior::COMPRESS_BC0:
|
||||||
case Behavior::DECOMPRESS_BC0: {
|
case Behavior::DECOMPRESS_BC0: {
|
||||||
string data = read_input_data();
|
string data = read_input_data();
|
||||||
|
|
||||||
|
size_t pr2_expected_size = 0;
|
||||||
|
if (behavior == Behavior::DECOMPRESS_PR2) {
|
||||||
|
if (data.size() < 8) {
|
||||||
|
throw runtime_error("not enough data for PR2 header");
|
||||||
|
}
|
||||||
|
data.resize((data.size() + 3) & (~3));
|
||||||
|
StringReader r(data);
|
||||||
|
pr2_expected_size = r.get_u32l();
|
||||||
|
PSOV2Encryption crypt(r.get_u32l());
|
||||||
|
crypt.decrypt(data.data() + 8, data.size() - 8);
|
||||||
|
data = data.substr(8);
|
||||||
|
}
|
||||||
|
|
||||||
size_t input_bytes = data.size();
|
size_t input_bytes = data.size();
|
||||||
auto progress_fn = [&](size_t input_progress, size_t output_progress) -> void {
|
auto progress_fn = [&](size_t input_progress, size_t output_progress) -> void {
|
||||||
float progress = static_cast<float>(input_progress * 100) / input_bytes;
|
float progress = static_cast<float>(input_progress * 100) / input_bytes;
|
||||||
@@ -580,13 +608,13 @@ int main(int argc, char** argv) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint64_t start = now();
|
uint64_t start = now();
|
||||||
if (behavior == Behavior::COMPRESS_PRS) {
|
if ((behavior == Behavior::COMPRESS_PRS) || (behavior == Behavior::COMPRESS_PR2)) {
|
||||||
if (compress_optimal) {
|
if (compress_optimal) {
|
||||||
data = prs_compress_optimal(data.data(), data.size(), optimal_progress_fn);
|
data = prs_compress_optimal(data.data(), data.size(), optimal_progress_fn);
|
||||||
} else {
|
} else {
|
||||||
data = prs_compress(data, compression_level, progress_fn);
|
data = prs_compress(data, compression_level, progress_fn);
|
||||||
}
|
}
|
||||||
} else if (behavior == Behavior::DECOMPRESS_PRS) {
|
} else if ((behavior == Behavior::DECOMPRESS_PRS) || (behavior == Behavior::DECOMPRESS_PR2)) {
|
||||||
data = prs_decompress(data);
|
data = prs_decompress(data);
|
||||||
} else if (behavior == Behavior::COMPRESS_BC0) {
|
} else if (behavior == Behavior::COMPRESS_BC0) {
|
||||||
if (compress_optimal) {
|
if (compress_optimal) {
|
||||||
@@ -610,6 +638,22 @@ int main(int argc, char** argv) {
|
|||||||
log_info("%zu (0x%zX) bytes input => %zu (0x%zX) bytes output (%g%%) in %s (%s / sec)",
|
log_info("%zu (0x%zX) bytes input => %zu (0x%zX) bytes output (%g%%) in %s (%s / sec)",
|
||||||
input_bytes, input_bytes, data.size(), data.size(), size_ratio, time_str.c_str(), bytes_per_sec_str.c_str());
|
input_bytes, input_bytes, data.size(), data.size(), size_ratio, time_str.c_str(), bytes_per_sec_str.c_str());
|
||||||
|
|
||||||
|
if ((behavior == Behavior::DECOMPRESS_PR2) && (data.size() != pr2_expected_size)) {
|
||||||
|
log_warning("Result data size (%zu bytes) does not match expected size from PR2 header (%zu bytes)", data.size(), pr2_expected_size);
|
||||||
|
} else if (behavior == Behavior::COMPRESS_PR2) {
|
||||||
|
uint32_t pr2_seed = seed.empty() ? random_object<uint32_t>() : stoul(seed, nullptr, 16);
|
||||||
|
size_t orig_size = data.size();
|
||||||
|
data.resize((data.size() + 3) & (~3));
|
||||||
|
PSOV2Encryption crypt(pr2_seed);
|
||||||
|
crypt.encrypt(data.data(), data.size());
|
||||||
|
data.resize(orig_size);
|
||||||
|
StringWriter w;
|
||||||
|
w.put_u32l(input_bytes);
|
||||||
|
w.put_u32l(pr2_seed);
|
||||||
|
w.write(data);
|
||||||
|
data = std::move(w.str());
|
||||||
|
}
|
||||||
|
|
||||||
write_output_data(data.data(), data.size());
|
write_output_data(data.data(), data.size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user