backend-infra-engineer: Release 0.2.2 snapshot
This commit is contained in:
@@ -6,19 +6,299 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
#define DEBUG_LOG(msg) std::cout << msg << std::endl
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
namespace lc_lz2 {
|
||||
std::vector<uint8_t> HyruleMagicCompress(uint8_t const* const src,
|
||||
int const oldsize, int* const size,
|
||||
int const flag) {
|
||||
unsigned char* b2 =
|
||||
(unsigned char*)malloc(0x1000); // allocate a 2^12 sized buffer
|
||||
|
||||
// Compression commands
|
||||
int i, j, k, l, m = 0, n, o = 0, bd = 0, p, q = 0, r;
|
||||
|
||||
for (i = 0; i < oldsize;) {
|
||||
l = src[i]; // grab a char from the buffer.
|
||||
|
||||
k = 0;
|
||||
|
||||
r = !!q; // r = the same logical value (0 or 1) as q, but not the same
|
||||
// value necesarily.
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
if (src[j] == l) {
|
||||
m = oldsize - j;
|
||||
|
||||
for (n = 0; n < m; n++)
|
||||
if (src[n + j] != src[n + i]) break;
|
||||
|
||||
if (n > k) k = n, o = j;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = i + 1; n < oldsize; n++) {
|
||||
if (src[n] != l) {
|
||||
// look for chars identical to the first one.
|
||||
// stop if we can't find one.
|
||||
// n will reach i+k+1 for some k >= 0.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n -= i; // offset back by i. i.e. n = k+1 as above.
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 1;
|
||||
else {
|
||||
m = src[i + 1];
|
||||
|
||||
for (n = i + 2; n < oldsize; n++) {
|
||||
if (src[n] != l) break;
|
||||
|
||||
n++;
|
||||
|
||||
if (src[n] != m) break;
|
||||
}
|
||||
|
||||
n -= i;
|
||||
|
||||
if (n > 2 + r)
|
||||
p = 2;
|
||||
else {
|
||||
m = oldsize - i;
|
||||
|
||||
for (n = 1; n < m; n++)
|
||||
if (src[i + n] != l + n) break;
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 3;
|
||||
else
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (k > 3 + r && k > n + (p & 1)) p = 4, n = k;
|
||||
|
||||
if (!p)
|
||||
q++, i++;
|
||||
else {
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
q = 0;
|
||||
}
|
||||
|
||||
i += n;
|
||||
n--;
|
||||
|
||||
if (n > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (n >> 8) + (p << 2));
|
||||
b2[bd++] = (unsigned char)n;
|
||||
} else
|
||||
b2[bd++] = (unsigned char)((p << 5) + n);
|
||||
|
||||
switch (p) {
|
||||
case 1:
|
||||
case 3:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
b2[bd++] = (unsigned char)m;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (flag) {
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
b2[bd++] = (unsigned char)o;
|
||||
} else {
|
||||
b2[bd++] = (unsigned char)o;
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
}
|
||||
|
||||
b2[bd++] = 255;
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
*size = bd;
|
||||
|
||||
std::vector<uint8_t> compressed_data(b2, b2 + bd);
|
||||
free(b2);
|
||||
return compressed_data;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> HyruleMagicDecompress(uint8_t const* src, int* const size,
|
||||
int const p_big_endian) {
|
||||
unsigned char* b2 = (unsigned char*)malloc(1024);
|
||||
|
||||
int bd = 0, bs = 1024;
|
||||
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned short c, d;
|
||||
|
||||
for (;;) {
|
||||
// retrieve a uchar from the buffer.
|
||||
a = *(src++);
|
||||
|
||||
// end the decompression routine if we encounter 0xff.
|
||||
if (a == 0xff) break;
|
||||
|
||||
// examine the top 3 bits of a.
|
||||
b = (a >> 5);
|
||||
|
||||
if (b == 7) // i.e. 0b 111
|
||||
{
|
||||
// get bits 0b 0001 1100
|
||||
b = ((a >> 2) & 7);
|
||||
|
||||
// get bits 0b 0000 0011, multiply by 256, OR with the next byte.
|
||||
c = ((a & 0x0003) << 8);
|
||||
c |= *(src++);
|
||||
} else
|
||||
// or get bits 0b 0001 1111
|
||||
c = (uint16_t)(a & 31);
|
||||
|
||||
c++;
|
||||
|
||||
if ((bd + c) > (bs - 512)) {
|
||||
// need to increase the buffer size.
|
||||
bs += 1024;
|
||||
b2 = (uint8_t*)realloc(b2, bs);
|
||||
}
|
||||
|
||||
// 7 was handled, here we handle other decompression codes.
|
||||
|
||||
switch (b) {
|
||||
case 0: // 0b 000
|
||||
|
||||
// raw copy
|
||||
|
||||
// copy info from the src buffer to our new buffer,
|
||||
// at offset bd (which we'll be increasing;
|
||||
memcpy(b2 + bd, src, c);
|
||||
|
||||
// increment the src pointer accordingly.
|
||||
src += c;
|
||||
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 1: // 0b 001
|
||||
|
||||
// rle copy
|
||||
|
||||
// make c duplicates of one byte, inc the src pointer.
|
||||
memset(b2 + bd, *(src++), c);
|
||||
|
||||
// increase the b2 offset.
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 2: // 0b 010
|
||||
|
||||
// rle 16-bit alternating copy
|
||||
|
||||
d = core::ldle16b(src);
|
||||
|
||||
src += 2;
|
||||
|
||||
while (c > 1) {
|
||||
// copy that 16-bit number c/2 times into the b2 buffer.
|
||||
core::stle16b(b2 + bd, d);
|
||||
|
||||
bd += 2;
|
||||
c -= 2; // hence c/2
|
||||
}
|
||||
|
||||
if (c) // if there's a remainder of c/2, this handles it.
|
||||
b2[bd++] = (char)d;
|
||||
|
||||
break;
|
||||
|
||||
case 3: // 0b 011
|
||||
|
||||
// incrementing copy
|
||||
|
||||
// get the current src byte.
|
||||
a = *(src++);
|
||||
|
||||
while (c--) {
|
||||
// increment that byte and copy to b2 in c iterations.
|
||||
// e.g. a = 4, b2 will have 4,5,6,7,8... written to it.
|
||||
b2[bd++] = a++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // 0b 100, 101, 110
|
||||
|
||||
// lz copy
|
||||
|
||||
if (p_big_endian) {
|
||||
d = (*src << 8) + src[1];
|
||||
} else {
|
||||
d = core::ldle16b(src);
|
||||
}
|
||||
|
||||
while (c--) {
|
||||
// copy from a different location in the buffer.
|
||||
b2[bd++] = b2[d++];
|
||||
}
|
||||
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
|
||||
if (size) (*size) = bd;
|
||||
|
||||
// return the unsigned char* buffer b2, which contains the uncompressed data.
|
||||
std::vector<uint8_t> decompressed_data(b2, b2 + bd);
|
||||
free(b2);
|
||||
return decompressed_data;
|
||||
}
|
||||
|
||||
namespace lc_lz2 {
|
||||
|
||||
void PrintCompressionPiece(const CompressionPiecePointer& piece) {
|
||||
std::cout << "Command: " << std::to_string(piece->command) << "\n";
|
||||
@@ -179,9 +459,6 @@ void CompressionCommandAlternative(const uchar* rom_data,
|
||||
comp_accumulator = 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Compression V2
|
||||
|
||||
void CheckByteRepeatV2(const uchar* data, uint& src_pos, const uint last_pos,
|
||||
CompressionCommand& cmd) {
|
||||
uint i = 0;
|
||||
@@ -380,15 +657,17 @@ absl::StatusOr<CompressionPiecePointer> SplitCompressionPiece(
|
||||
new_piece->argument[0] =
|
||||
(char)(piece->argument[0] + kMaxLengthCompression);
|
||||
break;
|
||||
case kCommandDirectCopy:
|
||||
case kCommandDirectCopy: {
|
||||
std::string empty;
|
||||
piece->argument_length = kMaxLengthCompression;
|
||||
new_piece = std::make_shared<CompressionPiece>(
|
||||
piece->command, length_left, nullptr, length_left);
|
||||
piece->command, length_left, empty, length_left);
|
||||
// MEMCPY
|
||||
for (int i = 0; i < length_left; ++i) {
|
||||
new_piece->argument[i] = piece->argument[i + kMaxLengthCompression];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kCommandRepeatingBytes: {
|
||||
piece->argument_length = kMaxLengthCompression;
|
||||
uint offset = piece->argument[0] + (piece->argument[1] << 8);
|
||||
@@ -526,7 +805,9 @@ absl::StatusOr<std::vector<uint8_t>> CompressV2(const uchar* data,
|
||||
}
|
||||
|
||||
// Worst case should be a copy of the string with extended header
|
||||
auto compressed_chain = std::make_shared<CompressionPiece>(1, 1, "aaa", 2);
|
||||
std::string worst_case = "aaa";
|
||||
auto compressed_chain =
|
||||
std::make_shared<CompressionPiece>(1, 1, worst_case, 2);
|
||||
auto compressed_chain_start = compressed_chain;
|
||||
|
||||
CompressionCommand current_cmd = {/*argument*/ {{}},
|
||||
@@ -590,286 +871,6 @@ absl::StatusOr<std::vector<uint8_t>> CompressV2(const uchar* data,
|
||||
return CreateCompressionString(compressed_chain_start->next, mode);
|
||||
}
|
||||
|
||||
// Hyrule Magic
|
||||
uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size,
|
||||
int const flag) {
|
||||
unsigned char* b2 =
|
||||
(unsigned char*)malloc(0x1000); // allocate a 2^12 sized buffer
|
||||
|
||||
int i, j, k, l, m = 0, n, o = 0, bd = 0, p, q = 0, r;
|
||||
|
||||
for (i = 0; i < oldsize;) {
|
||||
l = src[i]; // grab a char from the buffer.
|
||||
|
||||
k = 0;
|
||||
|
||||
r = !!q; // r = the same logical value (0 or 1) as q, but not the same
|
||||
// value necesarily.
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
if (src[j] == l) {
|
||||
m = oldsize - j;
|
||||
|
||||
for (n = 0; n < m; n++)
|
||||
if (src[n + j] != src[n + i]) break;
|
||||
|
||||
if (n > k) k = n, o = j;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = i + 1; n < oldsize; n++) {
|
||||
if (src[n] != l) {
|
||||
// look for chars identical to the first one.
|
||||
// stop if we can't find one.
|
||||
// n will reach i+k+1 for some k >= 0.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n -= i; // offset back by i. i.e. n = k+1 as above.
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 1;
|
||||
else {
|
||||
m = src[i + 1];
|
||||
|
||||
for (n = i + 2; n < oldsize; n++) {
|
||||
if (src[n] != l) break;
|
||||
|
||||
n++;
|
||||
|
||||
if (src[n] != m) break;
|
||||
}
|
||||
|
||||
n -= i;
|
||||
|
||||
if (n > 2 + r)
|
||||
p = 2;
|
||||
else {
|
||||
m = oldsize - i;
|
||||
|
||||
for (n = 1; n < m; n++)
|
||||
if (src[i + n] != l + n) break;
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 3;
|
||||
else
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (k > 3 + r && k > n + (p & 1)) p = 4, n = k;
|
||||
|
||||
if (!p)
|
||||
q++, i++;
|
||||
else {
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
q = 0;
|
||||
}
|
||||
|
||||
i += n;
|
||||
n--;
|
||||
|
||||
if (n > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (n >> 8) + (p << 2));
|
||||
b2[bd++] = (unsigned char)n;
|
||||
} else
|
||||
b2[bd++] = (unsigned char)((p << 5) + n);
|
||||
|
||||
switch (p) {
|
||||
case 1:
|
||||
case 3:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
b2[bd++] = (unsigned char)m;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (flag) {
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
b2[bd++] = (unsigned char)o;
|
||||
} else {
|
||||
b2[bd++] = (unsigned char)o;
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
}
|
||||
|
||||
b2[bd++] = 255;
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
*size = bd;
|
||||
|
||||
return b2;
|
||||
}
|
||||
|
||||
uint8_t* Uncompress(uint8_t const* src, int* const size,
|
||||
int const p_big_endian) {
|
||||
unsigned char* b2 = (unsigned char*)malloc(1024);
|
||||
|
||||
int bd = 0, bs = 1024;
|
||||
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned short c, d;
|
||||
|
||||
for (;;) {
|
||||
// retrieve a uchar from the buffer.
|
||||
a = *(src++);
|
||||
|
||||
// end the decompression routine if we encounter 0xff.
|
||||
if (a == 0xff) break;
|
||||
|
||||
// examine the top 3 bits of a.
|
||||
b = (a >> 5);
|
||||
|
||||
if (b == 7) // i.e. 0b 111
|
||||
{
|
||||
// get bits 0b 0001 1100
|
||||
b = ((a >> 2) & 7);
|
||||
|
||||
// get bits 0b 0000 0011, multiply by 256, OR with the next byte.
|
||||
c = ((a & 0x0003) << 8);
|
||||
c |= *(src++);
|
||||
} else
|
||||
// or get bits 0b 0001 1111
|
||||
c = (uint16_t)(a & 31);
|
||||
|
||||
c++;
|
||||
|
||||
if ((bd + c) > (bs - 512)) {
|
||||
// need to increase the buffer size.
|
||||
bs += 1024;
|
||||
b2 = (uint8_t*)realloc(b2, bs);
|
||||
}
|
||||
|
||||
// 7 was handled, here we handle other decompression codes.
|
||||
|
||||
switch (b) {
|
||||
case 0: // 0b 000
|
||||
|
||||
// raw copy
|
||||
|
||||
// copy info from the src buffer to our new buffer,
|
||||
// at offset bd (which we'll be increasing;
|
||||
memcpy(b2 + bd, src, c);
|
||||
|
||||
// increment the src pointer accordingly.
|
||||
src += c;
|
||||
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 1: // 0b 001
|
||||
|
||||
// rle copy
|
||||
|
||||
// make c duplicates of one byte, inc the src pointer.
|
||||
memset(b2 + bd, *(src++), c);
|
||||
|
||||
// increase the b2 offset.
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 2: // 0b 010
|
||||
|
||||
// rle 16-bit alternating copy
|
||||
|
||||
d = core::ldle16b(src);
|
||||
|
||||
src += 2;
|
||||
|
||||
while (c > 1) {
|
||||
// copy that 16-bit number c/2 times into the b2 buffer.
|
||||
core::stle16b(b2 + bd, d);
|
||||
|
||||
bd += 2;
|
||||
c -= 2; // hence c/2
|
||||
}
|
||||
|
||||
if (c) // if there's a remainder of c/2, this handles it.
|
||||
b2[bd++] = (char)d;
|
||||
|
||||
break;
|
||||
|
||||
case 3: // 0b 011
|
||||
|
||||
// incrementing copy
|
||||
|
||||
// get the current src byte.
|
||||
a = *(src++);
|
||||
|
||||
while (c--) {
|
||||
// increment that byte and copy to b2 in c iterations.
|
||||
// e.g. a = 4, b2 will have 4,5,6,7,8... written to it.
|
||||
b2[bd++] = a++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // 0b 100, 101, 110
|
||||
|
||||
// lz copy
|
||||
|
||||
if (p_big_endian) {
|
||||
d = (*src << 8) + src[1];
|
||||
} else {
|
||||
d = core::ldle16b(src);
|
||||
}
|
||||
|
||||
while (c--) {
|
||||
// copy from a different location in the buffer.
|
||||
b2[bd++] = b2[d++];
|
||||
}
|
||||
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
|
||||
if (size) (*size) = bd;
|
||||
|
||||
// return the unsigned char* buffer b2, which contains the uncompressed data.
|
||||
return b2;
|
||||
}
|
||||
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressGraphics(const uchar* data,
|
||||
const int pos,
|
||||
const int length) {
|
||||
@@ -887,9 +888,6 @@ absl::StatusOr<std::vector<uint8_t>> CompressOverworld(
|
||||
return CompressV3(data, pos, length, kNintendoMode1);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Compression V3
|
||||
|
||||
void CheckByteRepeatV3(CompressionContext& context) {
|
||||
uint pos = context.src_pos;
|
||||
|
||||
@@ -1209,15 +1207,17 @@ absl::StatusOr<CompressionPiece> SplitCompressionPieceV3(
|
||||
piece.argument_length);
|
||||
new_piece.argument[0] = (char)(piece.argument[0] + kMaxLengthCompression);
|
||||
break;
|
||||
case kCommandDirectCopy:
|
||||
case kCommandDirectCopy: {
|
||||
piece.argument_length = kMaxLengthCompression;
|
||||
new_piece =
|
||||
CompressionPiece(piece.command, length_left, nullptr, length_left);
|
||||
std::string empty_string = "";
|
||||
new_piece = CompressionPiece(piece.command, length_left, empty_string,
|
||||
length_left);
|
||||
// MEMCPY
|
||||
for (int i = 0; i < length_left; ++i) {
|
||||
new_piece.argument[i] = piece.argument[i + kMaxLengthCompression];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kCommandRepeatingBytes: {
|
||||
piece.argument_length = kMaxLengthCompression;
|
||||
uint offset = piece.argument[0] + (piece.argument[1] << 8);
|
||||
@@ -1340,8 +1340,6 @@ absl::StatusOr<std::vector<uint8_t>> CompressV3(
|
||||
context.compressed_data.end());
|
||||
}
|
||||
|
||||
// Decompression
|
||||
|
||||
std::string SetBuffer(const uchar* data, int src_pos, int comp_accumulator) {
|
||||
std::string buffer;
|
||||
for (int i = 0; i < comp_accumulator; ++i) {
|
||||
@@ -1473,5 +1471,4 @@ absl::StatusOr<std::vector<uint8_t>> DecompressOverworld(
|
||||
|
||||
} // namespace lc_lz2
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
} // namespace yaze
|
||||
|
||||
Reference in New Issue
Block a user