DEADSOFTWARE

Add graphics convertor
[awtools.git] / unpk.c
1 #include <stdint.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdbool.h>
6 #include <arpa/inet.h>
8 /*
9 * Another World game data unpacker
10 * Only DOS version are supported
11 */
13 #define MAX_MEMINFO 256
14 #define MSG_OPENERR "can't open file %s.\n"
15 #define MSG_WRITEERR "can't create file %s.\n"
16 #define MSG_UNPKERR "error while unpack file %s.\n"
18 struct __attribute__ ((__packed__)) memrec {
19 uint8_t state;
20 uint8_t type;
21 uint32_t unk0;
22 uint8_t unk1;
23 uint8_t bank;
24 uint32_t offset;
25 uint16_t unk2;
26 uint16_t pksize;
27 uint16_t unk3;
28 uint16_t size;
29 };
31 FILE *fp;
32 struct memrec meminfo[MAX_MEMINFO];
33 int count;
35 uint8_t *pk;
36 uint32_t size, datasize;
37 uint32_t start, idx, oidx;
38 uint32_t crc, chk;
40 uint32_t pkint(int adr) {
41 return ((pk[adr]) << 24) |
42 ((pk[adr + 1]) << 16) |
43 ((pk[adr + 2]) << 8) |
44 (pk[adr + 3]);
45 }
47 bool rcr(bool cf) {
48 bool rcf = chk & 1;
49 chk >>= 1;
50 if(cf)
51 chk |= 0x80000000;
52 return rcf;
53 }
55 bool nextChunk() {
56 bool cf = rcr(false);
57 if(chk == 0) {
58 chk = pkint(idx);
59 idx -= 4;
60 crc ^= chk;
61 cf = rcr(true);
62 }
63 return cf;
64 }
66 int getCode(int numChunks) {
67 int c = 0;
68 while(numChunks--) {
69 c <<= 1;
70 if(nextChunk())
71 c |= 1;
72 }
73 return c;
74 }
76 void decUnk1(int numChunks, int addCount) {
77 int count = getCode(numChunks) + addCount + 1;
78 datasize -= count;
79 while(count--) {
80 pk[oidx] = getCode(8);
81 --oidx;
82 }
83 }
85 void decUnk2(int numChunks) {
86 int i = getCode(numChunks);
87 int count = size + 1;
88 datasize -= count;
89 while(count--) {
90 pk[oidx] = pk[oidx + i];
91 --oidx;
92 }
93 }
95 bool unpack() {
96 size = 0;
97 datasize = pkint(idx);
98 idx -= 4;
99 oidx = start + datasize - 1;
100 crc = pkint(idx);
101 idx -= 4;
102 chk = pkint(idx);
103 idx -= 4;
104 crc ^= chk;
106 do {
107 if(!nextChunk()) {
108 size = 1;
109 if(!nextChunk())
110 decUnk1(3, 0);
111 else
112 decUnk2(8);
113 } else {
114 int c = getCode(2);
115 if(c == 3) {
116 decUnk1(8, 8);
117 } else {
118 if(c < 2) {
119 size = c + 2;
120 decUnk2(c + 9);
121 } else {
122 size = getCode(8);
123 decUnk2(12);
127 } while(datasize > 0);
129 return crc == 0;
132 bool pkload(int i) {
133 struct memrec *r = &meminfo[i];
135 char name[64];
136 char *nnum = (r->bank <= 0xF)?"0":"";
137 snprintf(name, 64, "BANK%s%X", nnum, r->bank);
139 if((fp = fopen(name, "r")) == NULL) {
140 printf(MSG_OPENERR, name);
141 return 0;
144 pk = malloc(r->size);
146 fseek(fp, r->offset, SEEK_SET);
147 fread(pk, r->pksize, 1, fp);
148 fclose(fp);
150 if(r->pksize == r->size) {
151 return true;
152 } else {
153 start = 0;
154 idx = start + r->pksize - 4;
155 return unpack();
159 void readmem() {
160 count = 0;
162 printf("NUM STATE TYPE BANK OFFSET PKSIZE SIZE\n");
164 while(count < MAX_MEMINFO) {
165 struct memrec *r = &meminfo[count];
166 fread(r, sizeof(struct memrec), 1, fp);
167 r->offset = ntohl(r->offset);
168 r->pksize = ntohs(r->pksize);
169 r->size = ntohs(r->size);
170 printf("%3i %5u %4u %4X %8X %6u %5u\n", count, r->state, r->type,
171 r->bank, r->offset, r->pksize, r->size);
173 if(r->state == 0xFF)
174 break;
176 ++count;
180 int main(int argc, char **argv) {
181 if((fp = fopen("MEMLIST.BIN", "r")) == NULL) {
182 printf(MSG_OPENERR, "MEMLIST.BIN");
183 exit(1);
186 readmem();
188 fclose(fp);
190 for(int i = 0; i < count - 1; i++) {
191 char name[64];
192 char *ext;
194 switch(meminfo[i].type) {
195 case 0: /* sound */
196 ext = "snd";
197 break;
198 case 1: /* music */
199 ext = "mus";
200 break;
201 case 2: /* bitmap */
202 ext = "bmp";
203 break;
204 case 3: /* palette */
205 ext = "pal";
206 break;
207 case 4: /* code */
208 ext = "obj";
209 break;
210 case 5: /* polygons */
211 ext = "spr";
212 break;
213 default: /* other */
214 ext = "unk";
215 break;
218 snprintf(name, 64, "file%i.%s", i, ext);
220 if(!pkload(i)) {
221 printf(MSG_UNPKERR, name);
222 goto error;
225 if((fp = fopen(name, "w")) == NULL) {
226 printf(MSG_WRITEERR, name);
227 goto error;
230 fwrite(pk, meminfo[i].size, 1, fp);
232 fclose(fp);
233 error:
234 free(pk);
237 return 0;