diff --git a/.vs/gust_g1t.vcxproj.user b/.vs/gust_g1t.vcxproj.user index 55efcc8..b405099 100644 --- a/.vs/gust_g1t.vcxproj.user +++ b/.vs/gust_g1t.vcxproj.user @@ -3,20 +3,20 @@ $(SolutionDir) WindowsLocalDebugger - book_dab_sophie_chapter3_030.g1t + ps3\c_bf.g1t $(SolutionDir) WindowsLocalDebugger - book_dab_sophie_chapter3_030.g1t + ps3\c_bf.g1t - book_dab_sophie_chapter3_030.g1t + ps3\c_bf.g1t $(SolutionDir) WindowsLocalDebugger - book_dab_sophie_chapter3_030.g1t + ps3\c_bf.g1t $(SolutionDir) WindowsLocalDebugger diff --git a/gust_enc.c b/gust_enc.c index 187b5d4..e2ee0bd 100644 --- a/gust_enc.c +++ b/gust_enc.c @@ -73,12 +73,12 @@ typedef struct { // Bitmap list prime numbers below a specific value static uint8_t* prime_list = NULL; static uint32_t random_seed[2]; -static bool big_endian = true; - -#define getdata16(x) (big_endian ? getbe16(x) : getle16(x)) -#define getdata32(x) (big_endian ? getbe32(x) : getle32(x)) -#define setdata16(x, v) (big_endian ? setbe16(x, v): setle16(x, v)) -#define setdata32(x, v) (big_endian ? setbe32(x, v): setle32(x, v)) +// TODO: Use endianness handling from util.[h/c] +static bool is_big_endian = true; +#define getdata16(x) (is_big_endian ? getbe16(x) : getle16(x)) +#define getdata32(x) (is_big_endian ? getbe32(x) : getle32(x)) +#define setdata16(x, v) (is_big_endian ? setbe16(x, v): setle16(x, v)) +#define setdata32(x, v) (is_big_endian ? setbe32(x, v): setle32(x, v)) /* * Helper functions to generate predictible semirandom numbers @@ -619,7 +619,7 @@ static uint32_t unscramble(uint8_t* payload, uint32_t payload_size, seed_data* s uint32_t version = getbe32(payload); if (version == 0x03000000) { version = 3; - big_endian = false; + is_big_endian = false; } if ((version != 2) && (version != 3)) { fprintf(stderr, "ERROR: Unsupported encoding version: 0x%08x\n", version); @@ -851,7 +851,7 @@ int main_utf8(int argc, char** argv) // Get the scrambler version to use uint32_t version = json_object_get_uint32(seeds_entry, "version"); if (version == 3) - big_endian = false; + is_big_endian = false; uint32_t max_seed_value = 0; for (size_t i = 0; i < array_size(seeds.main); i++) { seeds.main[i] = (uint32_t)json_array_get_number(json_object_get_array(seeds_entry, "main"), i); diff --git a/gust_g1t.c b/gust_g1t.c index 3245579..d5f7162 100644 --- a/gust_g1t.c +++ b/gust_g1t.c @@ -29,7 +29,8 @@ #include "dds.h" #define JSON_VERSION 1 -#define GT1G_MAGIC 0x47315447 // 'G1TG' +#define G1TG_LE_MAGIC 0x47315447 // 'GT1G' +#define G1TG_BE_MAGIC 0x47543147 // 'G1TG' // G1T texture flags #define G1T_FLAG_SRGB 0x02000000 // Not sure if this one is correct... @@ -37,7 +38,7 @@ // Known platforms #define SONY_PS2 0x00 -#define SONY_PS3 0x01 // Big Endian => unsupported! +#define SONY_PS3 0x01 #define MICROSOFT_X360 0x02 #define NINTENDO_WII 0x03 #define NINTENDO_DS 0x04 @@ -71,6 +72,7 @@ typedef struct { uint8_t dx : 4; uint8_t dy : 4; uint8_t unused; // Always 0x00 + // Seems to be an extra set of nibbles (that need to be reordered for Big Endian) uint32_t flags; // 0x10211000 or 0x00211000 or 0x12222000 for FT SRGB } g1t_tex_header; @@ -345,6 +347,8 @@ int main_utf8(int argc, char** argv) const char* version = json_object_get_string(json_object(json), "version"); if ((filename == NULL) || (version == NULL)) goto out; + if (json_object_get_uint32(json_object(json), "platform") == SONY_PS3) + data_endianness = big_endian; if (!flip_image) flip_image = json_object_get_boolean(json_object(json), "flip"); strcpy(path, argv[argc - 1]); @@ -362,40 +366,40 @@ int main_utf8(int argc, char** argv) goto out; } g1t_header hdr = { 0 }; - hdr.magic = GT1G_MAGIC; - hdr.version = getbe32(version); + hdr.magic = (data_endianness == little_endian) ? G1TG_LE_MAGIC : G1TG_BE_MAGIC; + hdr.version = getv32(getbe32(version)); hdr.total_size = 0; // To be rewritten when we're done - hdr.nb_textures = json_object_get_uint32(json_object(json), "nb_textures"); - hdr.platform = json_object_get_uint32(json_object(json), "platform"); - hdr.extra_size = json_object_get_uint32(json_object(json), "extra_size"); - hdr.header_size = sizeof(hdr) + hdr.nb_textures * sizeof(uint32_t); + hdr.nb_textures = getv32(json_object_get_uint32(json_object(json), "nb_textures")); + hdr.platform = getv32(json_object_get_uint32(json_object(json), "platform")); + hdr.extra_size = getv32(json_object_get_uint32(json_object(json), "extra_size")); + hdr.header_size = getv32(sizeof(hdr) + getv32(hdr.nb_textures) * sizeof(uint32_t)); if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) { fprintf(stderr, "ERROR: Can't write header\n"); goto out; } JSON_Array* extra_flags_array = json_object_get_array(json_object(json), "extra_flags"); - if (json_array_get_count(extra_flags_array) != hdr.nb_textures) { + if (json_array_get_count(extra_flags_array) != getv32(hdr.nb_textures)) { fprintf(stderr, "ERROR: number of extra flags doesn't match number of textures\n"); goto out; } - for (uint32_t i = 0; i < hdr.nb_textures; i++) { - uint32_t extra_flag = (uint32_t)json_array_get_number(extra_flags_array, i); + for (uint32_t i = 0; i < getv32(hdr.nb_textures); i++) { + uint32_t extra_flag = getv32((uint32_t)json_array_get_number(extra_flags_array, i)); if (fwrite(&extra_flag, sizeof(uint32_t), 1, file) != 1) { fprintf(stderr, "ERROR: Can't write extra flags\n"); goto out; } } - offset_table = calloc(hdr.nb_textures, sizeof(uint32_t)); - offset_table[0] = hdr.nb_textures * sizeof(uint32_t); - if (fwrite(offset_table, hdr.nb_textures * sizeof(uint32_t), 1, file) != 1) { + offset_table = calloc(getv32(hdr.nb_textures), sizeof(uint32_t)); + offset_table[0] = getv32(hdr.nb_textures) * sizeof(uint32_t); + if (fwrite(offset_table, getv32(hdr.nb_textures) * sizeof(uint32_t), 1, file) != 1) { fprintf(stderr, "ERROR: Can't write texture offsets\n"); goto out; } JSON_Array* textures_array = json_object_get_array(json_object(json), "textures"); - if (json_array_get_count(textures_array) != hdr.nb_textures) { + if (json_array_get_count(textures_array) != getv32(hdr.nb_textures)) { fprintf(stderr, "ERROR: number of textures in array doesn't match\n"); goto out; } @@ -410,8 +414,8 @@ int main_utf8(int argc, char** argv) for (size_t i = 0; i < strlen(_basename(argv[argc - 1])); i++) putchar(' '); printf(" DIMENSIONS MIPMAPS SUPPORTED?\n"); - for (uint32_t i = 0; i < hdr.nb_textures; i++) { - offset_table[i] = ftell(file) - hdr.header_size; + for (uint32_t i = 0; i < getv32(hdr.nb_textures); i++) { + offset_table[i] = ftell(file) - getv32(hdr.header_size); JSON_Object* texture_entry = json_array_get_object(textures_array, i); g1t_tex_header tex = { 0 }; tex.type = json_object_get_uint8(texture_entry, "type"); @@ -446,19 +450,30 @@ int main_utf8(int argc, char** argv) tex.dx = (uint8_t)find_msb(dds_header->width); tex.dy = (uint8_t)find_msb(dds_header->height); } + bool has_extra_content = (tex.flags & G1T_FLAG_EXTRA_CONTENT); + if (data_endianness != platform_endianness) { + uint8_t swap_tmp = tex.dx; + tex.dx = tex.dy; + tex.dy = swap_tmp; + swap_tmp = tex.exts; + tex.exts = tex.mipmaps; + tex.mipmaps = swap_tmp; + tex.flags = ((tex.flags & 0xf0f0f0f0) >> 4) | ((tex.flags & 0x0f0f0f0f) << 4); + } // Write texture header if (fwrite(&tex, sizeof(tex), 1, file) != 1) { fprintf(stderr, "ERROR: Can't write texture header\n"); goto out; } // Write extra data - if (tex.flags & G1T_FLAG_EXTRA_CONTENT) { + if (has_extra_content) { JSON_Array* extra_data_array = json_object_get_array(texture_entry, "extra_data"); uint32_t extra_data_size = (uint32_t)(json_array_get_count(extra_data_array) + 1) * sizeof(uint32_t); if (!po2_sizes && extra_data_size < 4 * sizeof(uint32_t)) { fprintf(stderr, "ERROR: Non power-of-two width or height is missing from extra data\n"); goto out; } + extra_data_size = getv32(extra_data_size); if (fwrite(&extra_data_size, sizeof(uint32_t), 1, file) != 1) { fprintf(stderr, "ERROR: Can't write extra data size\n"); goto out; @@ -473,6 +488,7 @@ int main_utf8(int argc, char** argv) fprintf(stderr, "ERROR: DDS height and extra data height don't match\n"); goto out; } + extra_data = getv32(extra_data); if (fwrite(&extra_data, sizeof(uint32_t), 1, file) != 1) { fprintf(stderr, "ERROR: Can't write extra data\n"); goto out; @@ -482,7 +498,7 @@ int main_utf8(int argc, char** argv) // Set the default ARGB format for the platform uint32_t default_texture_format; - switch (hdr.platform) { + switch (getv32(hdr.platform)) { case NINTENDO_DS: case NINTENDO_3DS: case SONY_PS4: @@ -555,7 +571,7 @@ int main_utf8(int argc, char** argv) goto out; } - if (flip_image || ((hdr.platform == NINTENDO_3DS) && (tex.type == 0x09 || tex.type == 0x45))) + if (flip_image || ((getv32(hdr.platform) == NINTENDO_3DS) && (tex.type == 0x09 || tex.type == 0x45))) flip(bpp, dds_payload, dds_size, dds_header->width); if (swizzled) { @@ -565,7 +581,7 @@ int main_utf8(int argc, char** argv) wf = 4; hf = 4; } - switch (hdr.platform) { + switch (getv32(hdr.platform)) { case SONY_PS4: case NINTENDO_3DS: mo = 3; @@ -588,22 +604,24 @@ int main_utf8(int argc, char** argv) } char dims[16]; snprintf(dims, sizeof(dims), "%dx%d", dds_header->width, dds_header->height); - printf("0x%02x 0x%08x 0x%08x %s %-10s %-7d %s\n", tex.type, hdr.header_size + offset_table[i], - (uint32_t)ftell(file) - offset_table[i] - hdr.header_size - (uint32_t)sizeof(g1t_tex_header), path, + printf("0x%02x 0x%08x 0x%08x %s %-10s %-7d %s\n", tex.type, getv32(hdr.header_size) + offset_table[i], + (uint32_t)ftell(file) - offset_table[i] - getv32(hdr.header_size) - (uint32_t)sizeof(g1t_tex_header), path, dims, dds_header->mipMapCount, supported ? "Y" : "N"); free(buf); buf = NULL; } // Update total size - uint32_t total_size = ftell(file); + uint32_t total_size = getv32(ftell(file)); fseek(file, 2 * sizeof(uint32_t), SEEK_SET); if (fwrite(&total_size, sizeof(uint32_t), 1, file) != 1) { fprintf(stderr, "ERROR: Can't update total size\n"); goto out; } // Update offset table - fseek(file, sizeof(hdr) + hdr.nb_textures * sizeof(uint32_t), SEEK_SET); - if (fwrite(offset_table, sizeof(uint32_t), hdr.nb_textures, file) != hdr.nb_textures) { + fseek(file, sizeof(hdr) + getv32(hdr.nb_textures) * sizeof(uint32_t), SEEK_SET); + for (uint32_t i = 0; i < getv32(hdr.nb_textures); i++) + offset_table[i] = getv32(offset_table[i]); + if (fwrite(offset_table, sizeof(uint32_t), getv32(hdr.nb_textures), file) != getv32(hdr.nb_textures)) { fprintf(stderr, "ERROR: Can't update texture offsets\n"); goto out; } @@ -628,10 +646,12 @@ int main_utf8(int argc, char** argv) fprintf(stderr, "ERROR: Can't read from '%s'", argv[argc - 1]); goto out; } - if (magic != GT1G_MAGIC) { + if ((magic != G1TG_LE_MAGIC) && (magic != G1TG_BE_MAGIC)) { fprintf(stderr, "ERROR: Not a G1T file (bad magic) or unsupported platform"); goto out; } + if (magic == G1TG_BE_MAGIC) + data_endianness = big_endian; fseek(file, 0L, SEEK_END); uint32_t g1t_size = (uint32_t)ftell(file); fseek(file, 0L, SEEK_SET); @@ -645,6 +665,15 @@ int main_utf8(int argc, char** argv) } g1t_header* hdr = (g1t_header*)buf; + if (data_endianness != platform_endianness) { + hdr->magic = bswap_uint32(hdr->magic); + hdr->version = bswap_uint32(hdr->version); + hdr->total_size = bswap_uint32(hdr->total_size); + hdr->header_size = bswap_uint32(hdr->header_size); + hdr->nb_textures = bswap_uint32(hdr->nb_textures); + hdr->platform = bswap_uint32(hdr->platform); + hdr->extra_size = bswap_uint32(hdr->extra_size); + } if (hdr->total_size != g1t_size) { fprintf(stderr, "ERROR: File size mismatch\n"); goto out; @@ -709,18 +738,27 @@ int main_utf8(int argc, char** argv) for (uint32_t i = 0; i < hdr->nb_textures; i++) { // There's an array of flags after the hdr json_array_append_number(json_array(json_flags_array), getle32(&buf[(uint32_t)sizeof(g1t_header) + 4 * i])); - uint32_t pos = hdr->header_size + x_offset_table[i]; + uint32_t pos = hdr->header_size + getv32(x_offset_table[i]); g1t_tex_header* tex = (g1t_tex_header*)&buf[pos]; + if (data_endianness != platform_endianness) { + uint8_t swap_tmp = tex->dx; + tex->dx = tex->dy; + tex->dy = swap_tmp; + swap_tmp = tex->exts; + tex->exts = tex->mipmaps; + tex->mipmaps = swap_tmp; + tex->flags = ((tex->flags & 0xf0f0f0f0) >> 4) | ((tex->flags & 0x0f0f0f0f) << 4); + } pos += sizeof(g1t_tex_header); uint32_t width = 1 << tex->dx; uint32_t height = 1 << tex->dy; - uint32_t extra_size = (tex->flags & G1T_FLAG_EXTRA_CONTENT) ? getle32(&buf[pos]) : 0; + uint32_t extra_size = (tex->flags & G1T_FLAG_EXTRA_CONTENT) ? getp32(&buf[pos]) : 0; // Non power-of-two width and height may be provided in the extra data if (extra_size >= 0x14) { if (width == 1) - width = getle32(&buf[pos + 0x0c]); + width = getp32(&buf[pos + 0x0c]); if (height == 1) - height = getle32(&buf[pos + 0x10]); + height = getp32(&buf[pos + 0x10]); } JSON_Value* json_texture = json_value_init_object(); @@ -771,7 +809,7 @@ int main_utf8(int argc, char** argv) for (int j = 0; j < tex->mipmaps - 1; j++) texture_size += highest_mipmap_size / (4 << (j * 2)); uint32_t expected_size = ((i + 1 == hdr->nb_textures) ? - g1t_size - hdr->header_size : x_offset_table[i + 1]) - x_offset_table[i]; + g1t_size - hdr->header_size : getv32(x_offset_table[i + 1])) - getv32(x_offset_table[i]); expected_size -= (uint32_t)sizeof(g1t_tex_header); if (texture_size > expected_size) { fprintf(stderr, "ERROR: Computed texture size is larger than actual size\n"); @@ -786,7 +824,7 @@ int main_utf8(int argc, char** argv) JSON_Value* json_extra_array_val = json_value_init_array(); JSON_Array* json_extra_array_obj = json_array(json_extra_array_val); for (uint32_t j = 4; j < extra_size; j += 4) - json_array_append_number(json_extra_array_obj, getle32(&buf[pos + j])); + json_array_append_number(json_extra_array_obj, getp32(&buf[pos + j])); json_object_set_value(json_object(json_texture), "extra_data", json_extra_array_val); } pos += extra_size; diff --git a/test_g1t.cmd b/test_g1t.cmd index b24752a..2a94863 100644 --- a/test_g1t.cmd +++ b/test_g1t.cmd @@ -8,7 +8,7 @@ setlocal EnableDelayedExpansion call build.cmd g1t if %ERRORLEVEL% neq 0 goto err -set list=type_01_sw type_09_ps4 type_10_psv type_12_psv type_12_psv_2 type_21_sw type_3c_3ds type_3d_3ds type_45_3ds type_59_win type_59_win_2 type_5b_win type_5f_win type_5f_win_2 type_62_ps4 type_62_ps4_2 +set list=type_01_sw type_08_ps3 type_09_ps4 type_10_psv type_12_psv type_12_psv_2 type_21_sw type_3c_3ds type_3d_3ds type_45_3ds type_59_win type_59_win_2 type_5b_win type_5f_win type_5f_win_2 type_62_ps4 type_62_ps4_2 for %%a in (%list%) do ( if exist %%a.g1t.bak move /y %%a.g1t.bak %%a.g1t >NUL 2>&1 diff --git a/util.c b/util.c index a24c71b..464a2ee 100644 --- a/util.c +++ b/util.c @@ -24,6 +24,10 @@ #include "utf8.h" #include "util.h" +// Flag to indicate whether the data being processed or the platform are Big Endian +endianness data_endianness = little_endian; +const endianness platform_endianness = little_endian; + bool create_path(char* path) { bool result = true; diff --git a/util.h b/util.h index bf4e457..b78682e 100644 --- a/util.h +++ b/util.h @@ -31,6 +31,11 @@ #pragma once +// Flags to indicate whether the data being processed or the platform are Big Endian +typedef enum { big_endian, little_endian } endianness; +extern endianness data_endianness; +extern const endianness platform_endianness; + #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) @@ -123,89 +128,174 @@ static __inline uint32_t find_msb(uint32_t v) static __inline uint16_t getle16(const void* p) { - return *(const uint16_t*)(const uint8_t*)(p); + if (platform_endianness == little_endian) + return *(const uint16_t*)(const uint8_t*)(p); + else + return bswap_uint16(getle16(p)); } static __inline void setle16(const void* p, const uint16_t v) { - *((uint16_t*)p) = v; + if (platform_endianness == little_endian) + *((uint16_t*)p) = v; + else + *((uint16_t*)p) = bswap_uint16(v); } static __inline uint16_t getbe16(const void* p) { - return bswap_uint16(getle16(p)); + if (platform_endianness == little_endian) + return bswap_uint16(getle16(p)); + else + return *(const uint16_t*)(const uint8_t*)(p); } static __inline void setbe16(const void* p, const uint16_t v) { - setle16(p, bswap_uint16(v)); + if (platform_endianness == little_endian) + *((uint16_t*)p) = bswap_uint16(v); + else + *((uint16_t*)p) = v; +} + +static __inline uint16_t getv16(uint16_t v) +{ + return (platform_endianness == data_endianness) ? v : bswap_uint16(v); +} + +static __inline uint16_t getp16(const void* p) +{ + return getv16(*(const uint16_t*)(const uint8_t*)(p)); } static __inline uint32_t getle24(const void* _p) { uint8_t* p = (uint8_t*)_p; - return p[0] | (p[1] << 8) | (p[2] << 16); + if (platform_endianness == little_endian) + return p[0] | (p[1] << 8) | (p[2] << 16); + else + return (p[0] << 16) | (p[1] << 8) | p[2]; } static __inline void setle24(const void* _p, const uint32_t v) { uint8_t* p = (uint8_t*)_p; - p[0] = v & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; + if (platform_endianness == little_endian) { + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + } else { + p[0] = (v >> 16) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = v & 0xff; + } } static __inline uint32_t getbe24(const void* _p) { uint8_t* p = (uint8_t*)_p; - return (p[0] << 16) | (p[1] << 8) | p[2]; + if (platform_endianness == little_endian) + return (p[0] << 16) | (p[1] << 8) | p[2]; + else + return p[0] | (p[1] << 8) | (p[2] << 16); } static __inline void setbe24(const void* _p, const uint32_t v) { uint8_t* p = (uint8_t*)_p; - p[0] = (v >> 16) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = v & 0xff; + if (platform_endianness == little_endian) { + p[0] = (v >> 16) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = v & 0xff; + } else { + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + } } static __inline uint32_t getle32(const void* p) { - return *(const uint32_t*)(const uint8_t*)(p); + if (platform_endianness == little_endian) + return *(const uint32_t*)(const uint8_t*)(p); + else + return bswap_uint32(getle32(p)); } static __inline void setle32(const void* p, const uint32_t v) { - *((uint32_t*)p) = v; + if (platform_endianness == little_endian) + *((uint32_t*)p) = v; + else + *((uint32_t*)p) = bswap_uint32(v); } static __inline uint32_t getbe32(const void* p) { - return bswap_uint32(getle32(p)); + if (platform_endianness == little_endian) + return bswap_uint32(getle32(p)); + else + return *(const uint32_t*)(const uint8_t*)(p); } static __inline void setbe32(const void* p, const uint32_t v) { - setle32(p, bswap_uint32(v)); + if (platform_endianness == little_endian) + *((uint32_t*)p) = bswap_uint32(v); + else + *((uint32_t*)p) = v; +} + +static __inline uint32_t getv32(uint32_t v) +{ + return (platform_endianness == data_endianness) ? v : bswap_uint32(v); +} + +static __inline uint32_t getp32(const void* p) +{ + return getv32 (*(const uint32_t*)(const uint8_t*)(p)); } static __inline uint64_t getle64(const void* p) { - return *(const uint64_t*)(const uint8_t*)(p); + if (platform_endianness == little_endian) + return *(const uint64_t*)(const uint8_t*)(p); + else + return bswap_uint64(*(const uint64_t*)(const uint8_t*)(p)); } static __inline void setle64(const void* p, const uint64_t v) { - *((uint64_t*)p) = v; + if (platform_endianness == little_endian) + *((uint64_t*)p) = v; + else + *((uint64_t*)p) = bswap_uint64(v); } + static __inline uint64_t getbe64(const void* p) { - return bswap_uint64(getle64(p)); + if (platform_endianness == little_endian) + return bswap_uint64(*(const uint64_t*)(const uint8_t*)(p)); + else + return *(const uint64_t*)(const uint8_t*)(p); } static __inline void setbe64(const void* p, const uint64_t v) { - setle64(p, bswap_uint64(v)); + if (platform_endianness == little_endian) + *((uint64_t*)p) = bswap_uint64(v); + else + *((uint64_t*)p) = v; +} + +static __inline uint64_t getv64(uint64_t v) +{ + return (platform_endianness == data_endianness) ? v : bswap_uint64(v); +} + +static __inline uint64_t getp64(const void* p) +{ + return getv64(*(const uint64_t*)(const uint8_t*)(p)); } bool create_path(char* path);