Skip to content

Instantly share code, notes, and snippets.

@khang06
Last active November 3, 2018 03:16
Show Gist options
  • Save khang06/e407b25d86923bb881ff1923a4447667 to your computer and use it in GitHub Desktop.
Save khang06/e407b25d86923bb881ff1923a4447667 to your computer and use it in GitHub Desktop.
terrible yaz0 c++ thing
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
namespace Yaz0 {
struct Header {
uint16_t magic[4];
uint32_t decmp_size;
int32_t unknown[2];
};
int GetDecompressedSize(const char *src) {
Header header;
header = *reinterpret_cast<const Header*>(src);
if (memcmp(&header.magic, "Yaz0", 4)) {
throw "Input is not Yaz0!";
}
return header.decmp_size;
}
void Decompress(const char *src, const uint32_t src_size, char *dst) {
Header header;
uint16_t code_byte;
uint32_t valid_bit_count = 0;
uint32_t src_pos = 16;
uint32_t dst_pos = 0;
uint16_t byte1;
uint16_t byte2;
uint32_t copy_src;
uint32_t copy_len;
if (src_size < 16) {
throw "Input is too small!";
}
header = *reinterpret_cast<const Header*>(src);
if (memcmp(&header.magic, "Yaz0", 4)) {
// if (*reinterpret_cast<const int32_t*>(src) != *reinterpret_cast<const int32_t*>("Yaz0")) { // this looks like shit
// if (*(const int32_t*)src != *(const int32_t*)"Yaz0") {
throw "Input is not Yaz0!";
}
code_byte = src[16];
while (dst_pos < header.decmp_size) {
// printf("while loop hit\n");
if (valid_bit_count == 0) {
code_byte = src[src_pos];
src_pos++;
valid_bit_count = 8;
}
if ((code_byte & 0x80) != 0) {
//printf("no compression\n");
dst[dst_pos] = src[src_pos];
src_pos++;
dst_pos++;
}
else {
//printf("compression\n");
byte1 = src[src_pos];
//printf("byte1: %u\n", byte1);
src_pos++;
byte2 = src[src_pos];
src_pos++;
copy_src = dst_pos - ((byte1 & 0x0f) << 8 | byte2) - 1;
//printf("byte1: %u\n", byte1);
copy_len = byte1 >> 4;
//printf("copy_len: %u\n", copy_len);
if (copy_len == 0) {
copy_len = src[src_pos] + 0x12;
//printf("copy_len 1: %u\n", copy_len);
src_pos++;
}
else {
copy_len += 2;
//printf("copy_len 2: %u\n", copy_len);
}
//printf("start copy run: %u\n", copy_len);
//if (copy_len > 128)
// printf("wtf\n");
//copy_len = copy_len; // lol i just needed this for a breakpoint
for (uint32_t i = 0; i < copy_len; i++) {
if (copy_src > header.decmp_size)
printf("oob copy_src: %08X\n", copy_src);
if (dst_pos > header.decmp_size)
printf("oob dst_pos: %08X\n", dst_pos);
//printf("copy from %08X to %08X\n", copy_src, dst_pos);
dst[dst_pos] = dst[copy_src];
copy_src++;
dst_pos++;
}
}
code_byte <<= 1;
valid_bit_count -= 1;
}
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s [input] [output]\n", argv[0]);
return 1;
}
std::ifstream input;
std::ofstream output;
input.open(argv[1], std::ios::in | std::ios::binary | std::ios::ate);
output.open(argv[2], std::ios::out | std::ios::binary);
if (!input.is_open()) {
printf("Unable to open %s.\n", argv[1]);
return 2;
}
if (!output.is_open()) {
printf("Unable to open %s.\n", argv[2]);
return 3;
}
std::streamsize size = input.tellg();
input.seekg(0, std::ios::beg);
std::vector<char> compressed_buffer(size);
if (!input.read(compressed_buffer.data(), size))
{
printf("Unable to read %s.\n", argv[1]);
}
try {
int decompressed_size = Yaz0::GetDecompressedSize(compressed_buffer.data());
std::vector<char> decompressed_buffer(decompressed_size);
Yaz0::Decompress(compressed_buffer.data(), compressed_buffer.size(), decompressed_buffer.data());
for (const auto &byte : decompressed_buffer) output << byte;
}
catch(const char *msg) {
printf("%s\n", msg);
return 4;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment