Advertisement
Guest User

gcz2tga.c

a guest
Apr 10th, 2017
470
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.64 KB | None | 0 0
  1. /* gcz2tga.c: Slice up a directory full of GCZ (texture) files into TGA files.
  2. *
  3. * Credit goes to afwefwe for reverse-engineering the texture format
  4. * and LZSS compression */
  5.  
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <stdio.h>
  9.  
  10. /* Assuming x86, usual endian crap is not accounted for */
  11. typedef unsigned char u8_t;
  12. typedef unsigned short u16_t;
  13. typedef unsigned int u32_t;
  14.  
  15. struct image
  16. {
  17. unsigned int width, height;
  18. u8_t *planes;
  19. };
  20.  
  21. struct clip
  22. {
  23. short x, y, w, h;
  24. };
  25.  
  26. static u16_t swab16(u16_t in)
  27. {
  28. /* GC headers are big-endian */
  29. return ((in & 0xFF) << 8) | (in >> 8);
  30. }
  31.  
  32. static void unpack_gc(struct image *out, u8_t *in, size_t out_sz)
  33. {
  34. unsigned int npixels;
  35. unsigned int i;
  36. unsigned int j;
  37. u16_t *pixels;
  38. u16_t *pheight;
  39. u16_t *pwidth;
  40. u16_t *pmagic;
  41. u16_t pixel;
  42.  
  43. pmagic = (u16_t *) in;
  44. pheight = (u16_t *) (in + 14);
  45. pwidth = (u16_t *) (in + 12);
  46.  
  47. if (*pmagic != 0x4347) {
  48. fprintf(stderr, "(FAIL: Invalid header)\n");
  49. exit(EXIT_FAILURE);
  50. }
  51.  
  52. /* Set up output image struct */
  53. in += 24;
  54. out->width = swab16(*pwidth);
  55. out->height = swab16(*pheight);
  56. out->planes = malloc(out->width * out->height * 4);
  57.  
  58. /* Clamp W/H (don't know why this is necessary but it is) */
  59. out->width = out->width > 1024 ? 1024 : out->width;
  60. out->height = out->height > 1024 ? 1024 : out->height;
  61.  
  62. fprintf(stderr, "(%dx%d)", out->width, out->height);
  63.  
  64. /* Unpack pixels */
  65. pixels = (u16_t *) in;
  66. npixels = out->width * out->height;
  67.  
  68. if (out_sz > npixels * 4) {
  69. /* Deep image (i.e. 32-bit) */
  70. memcpy(out->planes, pixels, npixels * 4);
  71. } else {
  72. /* Shallow image (i.e. 16-bit) */
  73. for (i = 0, j = 0 ; i < npixels ; i++) {
  74. pixel = pixels[i];
  75. out->planes[j++] = ((pixel ) & 0x1F) << 3; /* B */
  76. out->planes[j++] = ((pixel >> 5) & 0x1F) << 3; /* G */
  77. out->planes[j++] = ((pixel >> 10) ) << 3; /* R */
  78. out->planes[j++] = pixel & 0x8000 ? 0xFF : 0x00; /* A */
  79. }
  80. }
  81. }
  82.  
  83. static u8_t *expand_lzss(u8_t *lzss, size_t *pout_sz)
  84. {
  85. static u8_t ring[0x1000];
  86. unsigned int ring_pos = 0x0FEE;
  87. unsigned int chunk_offset;
  88. unsigned int chunk_length;
  89. u32_t control_word = 1;
  90. size_t length;
  91. u8_t cmd1;
  92. u8_t cmd2;
  93. u8_t *out;
  94. u8_t *pos;
  95. u8_t *in;
  96.  
  97. /* Header = 32 bit unpacked file length */
  98. length = *((u32_t *) lzss);
  99. *pout_sz = length;
  100.  
  101. if (length > 8000000) {
  102. fprintf(stderr, "(FAIL: Unreasonably large expanded size %d)\n",
  103. length);
  104.  
  105. exit(EXIT_FAILURE);
  106. }
  107.  
  108. out = malloc(length * 2); /* Seems to overrun */
  109. pos = out;
  110. in = lzss + 4;
  111.  
  112. while (length > 0) {
  113. if (control_word == 1) {
  114. /* Read a control byte */
  115. control_word = 0x100 | *in++;
  116. }
  117.  
  118. /* Decode a byte according to the current control byte bit */
  119. if (control_word & 1) {
  120. /* Straight copy */
  121. *pos++ = *in;
  122. ring[ring_pos] = *in++;
  123.  
  124. ring_pos = (ring_pos + 1) % 0x1000;
  125. length--;
  126. } else {
  127. /* Reference to data in ring buffer */
  128. cmd1 = *in++;
  129. cmd2 = *in++;
  130.  
  131. chunk_length = (cmd2 & 0x0F) + 3;
  132. chunk_offset = ((cmd2 & 0xF0) << 4) | cmd1;
  133.  
  134. for ( ; chunk_length > 0 ; chunk_length--) {
  135. /* Copy historical data to output AND current ring pos */
  136. *pos++ = ring[chunk_offset];
  137. ring[ring_pos] = ring[chunk_offset];
  138.  
  139. /* Update counters */
  140. chunk_offset = (chunk_offset + 1) % 0x1000;
  141. ring_pos = (ring_pos + 1) % 0x1000;
  142. length--;
  143. }
  144. }
  145.  
  146. /* Get next control bit */
  147. control_word >>= 1;
  148. }
  149.  
  150. return out;
  151. }
  152.  
  153. static void readfile(const char *filename, u8_t **data, long *nbytes)
  154. {
  155. FILE *f;
  156.  
  157. f = fopen(filename, "rb");
  158. if (f == NULL) abort();
  159.  
  160. fseek(f, 0, SEEK_END);
  161. *nbytes = ftell(f);
  162. fseek(f, 0, SEEK_SET);
  163.  
  164. *data = malloc(*nbytes);
  165. fread(*data, *nbytes, 1, f);
  166.  
  167. fclose(f);
  168. }
  169.  
  170. void put8(FILE *f, unsigned char val)
  171. {
  172. fwrite(&val, 1, 1, f);
  173. }
  174.  
  175. void put16(FILE *f, unsigned short val)
  176. {
  177. fwrite(&val, 2, 1, f);
  178. }
  179.  
  180. void split_images(const char *in_dir, const char *out_dir,
  181. struct image *images, int nimages)
  182. {
  183. struct clip *clips;
  184. char filename[512];
  185. long nbytes;
  186. u8_t *data;
  187. char *name;
  188. FILE *f;
  189. int i;
  190. int j;
  191. int k;
  192.  
  193. /* Read file and get TOC */
  194. sprintf(filename, "%s/system.idx", in_dir);
  195. readfile(filename, &data, &nbytes);
  196. clips = (struct clip *) (data + 0x01BC);
  197. name = (char *) (data + 8 + *((long *) data));
  198.  
  199. /* Guess how many clips there are with a heuristic */
  200. for (i = 0 ; clips[i].w != 0 && clips[i].h != 0 ; i++) {
  201. sprintf(filename, "%s/%s.tga", out_dir, name);
  202. name += strlen(name) + 3;
  203.  
  204. f = fopen(filename, "wb");
  205. if (f == NULL) abort();
  206.  
  207. /* Locate the correct source image */
  208. j = 0;
  209. while (clips[i].y > images[j].height) {
  210. clips[i].y -= images[j].height;
  211. j++;
  212. }
  213.  
  214. /* Write header */
  215. put8(f, 0); put8(f, 0); put8(f, 2);
  216. put16(f, 0); put16(f, 0); put8(f, 0);
  217. put16(f, 0); put16(f, 0); put16(f, clips[i].w); put16(f, clips[i].h);
  218. put8(f, 32); put8(f, 32);
  219.  
  220. /* Write scanlines */
  221. for (k = 0 ; k < clips[i].h ; k++) {
  222. if (clips[i].y == images[j].height) {
  223. clips[i].y = 0;
  224. j++;
  225. }
  226.  
  227. fwrite(images[j].planes + ((images[j].width * clips[i].y) +
  228. clips[i].x) * 4, clips[i].w, 4, f);
  229. clips[i].y++;
  230. }
  231.  
  232. /* Close output file */
  233. fclose(f);
  234. }
  235.  
  236. /* Cleanup */
  237. free(data);
  238. }
  239.  
  240. int main(int argc, char **argv)
  241. {
  242. char *in_dir;
  243. char *out_dir;
  244.  
  245. struct image images[32];
  246. char filename[256];
  247. unsigned int i;
  248. long filesize;
  249. u8_t *lzss, *gc;
  250. size_t out_sz;
  251. FILE *f;
  252.  
  253. /* Usage */
  254. if (argc != 3) {
  255. fprintf(stderr, "Usage: %s [indir] [outdir]\n", argv[0]);
  256. return EXIT_FAILURE;
  257. }
  258.  
  259. /* Setup */
  260. memset(images, 0, sizeof(images));
  261. in_dir = argv[1];
  262. out_dir = argv[2];
  263.  
  264. for (i = 0 ; i < 32 ; i++) {
  265. /* Open 0.gcz, 1.gcz etc ... */
  266. sprintf(filename, "%s/%d.gcz", in_dir, i);
  267. f = fopen(filename, "rb");
  268. if (f == NULL) break;
  269.  
  270. /* Read entire file */
  271. fseek(f, 0, SEEK_END);
  272. filesize = ftell(f);
  273. fseek(f, 0, SEEK_SET);
  274.  
  275. fprintf(stderr, "%s: fread", filename);
  276. lzss = malloc(filesize);
  277. fread(lzss, filesize, 1, f);
  278. fclose(f);
  279.  
  280. /* Decompress */
  281. fprintf(stderr, "(OK) expand_lzss");
  282. gc = expand_lzss(lzss, &out_sz);
  283. free(lzss);
  284.  
  285. /* Unpack GC to 32-bit RGBA */
  286. fprintf(stderr, "(OK) unpack_gc");
  287. unpack_gc(&images[i], gc, out_sz);
  288. free(gc);
  289.  
  290. fprintf(stderr, "(OK)\n");
  291. }
  292.  
  293. /* Sanity check */
  294. if (i == 0) {
  295. fprintf(stderr, "No GCZ files found\n");
  296. exit(EXIT_FAILURE);
  297. }
  298.  
  299. /* Emit pile of TGAs */
  300. fprintf(stderr, "split_images");
  301. split_images(in_dir, out_dir, images, i);
  302. fprintf(stderr, "(OK)\n\n");
  303.  
  304. return 0;
  305. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement