mirror of https://github.com/n64decomp/mk64.git
262 lines
8.3 KiB
C
262 lines
8.3 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#define MAX_STRING_LENGTH 256
|
|
#define MAX_STRING_OUTPUT 10000
|
|
|
|
// Compile using gcc -o tools/displaylist_packer tools/displaylist_packer.c
|
|
// Run using ./displaylist_packer input.bin output.bin
|
|
|
|
void pack(FILE *input_file, FILE *output_file);
|
|
|
|
int main(int argc, char *argv[]) {
|
|
// Check if we have the correct number of arguments
|
|
if (argc != 3) {
|
|
printf("Usage: ./dl_unpack input.bin output.bin\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Open the input file
|
|
FILE *input_file = fopen(argv[1], "rb");
|
|
if (input_file == NULL) {
|
|
printf("Failed to open input file: %s\n", argv[1]);
|
|
exit(1);
|
|
}
|
|
|
|
// Create the output file
|
|
FILE *output_file = fopen(argv[2], "wb");
|
|
if (output_file == NULL) {
|
|
printf("Failed to create output file: %s\n", argv[2]);
|
|
exit(1);
|
|
}
|
|
|
|
pack(input_file, output_file);
|
|
return 0;
|
|
}
|
|
|
|
uint64_t swap_endian(uint64_t value) {
|
|
uint64_t result = 0;
|
|
int i;
|
|
for (i = 0; i < 8; i++) {
|
|
result = (result << 8) | ((value >> (i * 8)) & 0xFF);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
uint32_t compressB1(uint8_t a, uint8_t b, uint8_t c) {
|
|
return (a / 2) | ((b / 2) << 5) | ((c / 2) << 10);
|
|
}
|
|
|
|
#define ARG1(val) ((val) >> 48)
|
|
#define ARG1WORD(val) ((val) >> 32)
|
|
#define ARG2(val) ((val) >> 40)
|
|
#define ARG2WORD(val) ((val) >> 32)
|
|
#define OPCODE(val) (uint8_t)((val) >> 56)
|
|
|
|
void pack(FILE *input_file, FILE *output_file) {
|
|
|
|
// Initialize the string to an empty string
|
|
|
|
uint8_t p1;
|
|
uint8_t p2;
|
|
uint8_t p3;
|
|
uint8_t p4;
|
|
uint32_t p5;
|
|
uint32_t p6;
|
|
uint16_t p7;
|
|
uint64_t compare;
|
|
|
|
|
|
// Read every u32 in the input file and concatenate a string based on the value
|
|
uint64_t cmd;
|
|
uint8_t opCode;
|
|
uint32_t offset = 0;
|
|
uint32_t count = 0;
|
|
// Warning: Static variable size may result in overflow if input file is too large.
|
|
// Solution: Increase array size.
|
|
uint8_t data[50000];
|
|
while (fread(&cmd, sizeof(uint64_t), 1, input_file) == 1) {
|
|
cmd = swap_endian(cmd);
|
|
opCode = OPCODE(cmd);
|
|
//printf("%X \n", opCode);
|
|
switch (opCode) {
|
|
case 0xB9:
|
|
p7 = (uint16_t) cmd;
|
|
if (p7 == 0x2078) {
|
|
data[count++] = 0x18;
|
|
} else if (p7 == 0x3078) {
|
|
data[count++] = 0x19;
|
|
}
|
|
break;
|
|
case 0xBF:
|
|
data[count++] = 0x29;
|
|
p1 = (uint8_t) (cmd >> 16) / 2;
|
|
p2 = (uint8_t) (cmd >> 8) / 2;
|
|
p3 = (uint8_t) (cmd) / 2;
|
|
|
|
*(uint16_t*) (data + count) = (uint16_t) (p1 | (p2 << 5) | (p3 << 10));
|
|
count++; count++;
|
|
break;
|
|
case 0x06:
|
|
data[count++] = 0x2B;
|
|
*(uint16_t*) (data + count) = (uint16_t)(((uint32_t)cmd) / 8);
|
|
count++; count++;
|
|
break;
|
|
case 0xB1:
|
|
data[count++] = 0x58;
|
|
*(uint16_t*) (data + count) = compressB1(ARG1(cmd), ARG2(cmd), cmd >> 32);
|
|
count++; count++;
|
|
*(uint16_t*) (data + count) = compressB1(cmd >> 16, cmd >> 8, cmd);
|
|
count++; count++;
|
|
break;
|
|
case 0x04:
|
|
// Skip the opcode and read bytes 2/3 from the u64 (Byte 1 is the opcode 0x04).
|
|
data[count++] = (uint8_t)(((((uint16_t)ARG1WORD(cmd)) + 1) / 0x410) + 0x32);
|
|
// Read the right side of the u64 (as a u32).
|
|
*(uint16_t*) (data + count) = (uint16_t)(((uint32_t)cmd - 0x04000000) / 16);
|
|
count++; count++;
|
|
break;
|
|
case 0xFD:
|
|
p1 = (uint32_t)(cmd - 0x05000000) >> 11;
|
|
p2 = 0x00;
|
|
p3 = 0x70;
|
|
|
|
p4 = (uint8_t)ARG1(cmd);
|
|
|
|
|
|
fseek(input_file, 24, SEEK_CUR);
|
|
fread(&cmd, sizeof(uint64_t), 1, input_file);
|
|
cmd = swap_endian(cmd);
|
|
|
|
if (p4 == 0x70) {
|
|
cmd |= 0x300000000;
|
|
|
|
}
|
|
|
|
if (cmd == 0xF3000000073FF100) {
|
|
data[count++] = 0x20;
|
|
} else if (cmd == 0xF3000000077FF080) {
|
|
data[count++] = 0x21;
|
|
} else if (cmd == 0xF3000000077FF100) {
|
|
data[count++] = 0x22;
|
|
} else if (cmd == 0xF3000003073FF100) {
|
|
data[count++] = 0x23;
|
|
} else if (cmd == 0xF3000003077FF080) {
|
|
data[count++] = 0x24;
|
|
} else if (cmd == 0xF3000003077FF100) {
|
|
data[count++] = 0x25;
|
|
} else {
|
|
printf("Error: %s\n", "Unknown FD");
|
|
}
|
|
data[count++] = p1;
|
|
data[count++] = p2;
|
|
data[count++] = p3;
|
|
break;
|
|
case 0xE8:
|
|
|
|
// Read 0xF5
|
|
fread(&cmd, sizeof(uint64_t), 1, input_file);
|
|
cmd = swap_endian(cmd);
|
|
p5 = ARG1WORD(cmd);
|
|
|
|
p1 = (((cmd >> 14) & 0xF) << 4) | ((cmd >> 18) & 0xF);
|
|
p2 = (((cmd >> 4) & 0xF) << 4) | ((cmd >> 8) & 0xF);
|
|
|
|
// Read 0xF2
|
|
fread(&cmd, sizeof(uint64_t), 1, input_file);
|
|
cmd = swap_endian(cmd);
|
|
p6 = (uint32_t)cmd;
|
|
|
|
compare = ((uint64_t) p5 << 32 ) | p6;
|
|
|
|
switch (compare) {
|
|
case 0xF51011000007C07C:
|
|
data[count++] = 0x2C;
|
|
break;
|
|
case 0xF51010000007C07C:
|
|
data[count++] = 0x1A;
|
|
break;
|
|
case 0xF5102000000FC07C:
|
|
data[count++] = 0x1B;
|
|
break;
|
|
case 0xF51010000007C0FC:
|
|
data[count++] = 0x1C;
|
|
break;
|
|
case 0xF57010000007C07C:
|
|
data[count++] = 0x1D;
|
|
break;
|
|
case 0xF5702000000FC07C:
|
|
data[count++] = 0x1E;
|
|
break;
|
|
case 0xF57010000007C0FC:
|
|
data[count++] = 0x1F;
|
|
break;
|
|
}
|
|
|
|
data[count++] = p2;
|
|
|
|
data[count++] = p1;
|
|
break;
|
|
case 0xBB:
|
|
if ((uint16_t)cmd == 0x0001) {
|
|
data[count++] = 0x27;
|
|
} else if ((uint16_t)cmd == 0xFFFF) {
|
|
data[count++] = 0x26;
|
|
} else {
|
|
printf("Error: %s\n", "Unknown BB");
|
|
}
|
|
break;
|
|
case 0xB8:
|
|
data[count++] = 0x2A;
|
|
break;
|
|
case 0xBE:
|
|
data[count++] = 0x2D;
|
|
break;
|
|
case 0xD0:
|
|
data[count++] = 0xDD;
|
|
break;
|
|
case 0xFC:
|
|
p7 = (uint16_t)cmd;
|
|
if (p7 == 0xF3F9) {
|
|
data[count++] = 0x16;
|
|
} else if (p7 == 0xFFFF) {
|
|
data[count++] = 0x15;
|
|
} else if (p7 == 0x793C) {
|
|
data[count++] = 0x17;
|
|
}
|
|
//data[count++] = 0x53;
|
|
break;
|
|
case 0xB7:
|
|
data[count++] = 0x56;
|
|
break;
|
|
case 0xB6:
|
|
data[count++] = 0x57;
|
|
break;
|
|
//case 0xFF:
|
|
// data[count++] = 0xFF;
|
|
// goto eos; // end of switch
|
|
// break;
|
|
default:
|
|
printf("Error: Unknown Opcode: 0x%X\n", opCode);
|
|
printf("Opcode written to file as 0xEE\n");
|
|
data[count++] = 0xEE;
|
|
break;
|
|
}
|
|
|
|
offset += 4;
|
|
}
|
|
//eos: ;
|
|
data[count++] = 0xFF;
|
|
size_t num_elements_written = fwrite(data, sizeof(uint8_t), count, output_file);
|
|
if (num_elements_written != count) {
|
|
printf("Failed to write data to file.\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Close the files and free the memory
|
|
fclose(input_file);
|
|
fclose(output_file);
|
|
}
|