added libwdx as another possible resource packer (ok, ok, it's faster and better...
[awish.git] / tools / wdx / wpack.c
blob2063bbd6bafe93afa5cd45c6dcbebfa96d88402f
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://sam.zoy.org/wtfpl/COPYING for more details.
9 */
10 #ifndef _BSD_SOURCE
11 # define _BSD_SOURCE
12 #endif
13 #include <endian.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
25 #include "libwdx/libwdx.h"
28 static void reportError (void) {
29 fprintf(stderr, "ERROR: %s\n", strerror(errno));
33 static void *loadWholeFile (const char *fname, int *fsize) {
34 void *res = NULL;
35 off_t fsz;
36 int fd = open(fname, O_RDONLY);
38 if (fd < 0) goto error;
39 fsz = lseek(fd, 0, SEEK_END);
40 if (fsz <= (off_t)-1) goto error;
41 if (fsz > 0x7fffffff) { fprintf(stderr, "ERROR: file too big\n"); goto error1; }
42 if (lseek(fd, 0, SEEK_SET) <= (off_t)-1) goto error;
43 res = malloc(fsz+1);
44 if (!res) goto error;
45 if (fsz > 0) {
46 if (read(fd, res, fsz) != fsz) goto error;
48 if (close(fd) < 0) { fd = -1; goto error; }
49 *fsize = fsz;
50 return res;
51 error:
52 reportError();
53 error1:
54 if (fd >= 0) close(fd);
55 if (res) free(res);
56 return NULL;
60 static int writeUInt (int fd, uint32_t i) {
61 uint32_t v = htole32(i);
63 if (write(fd, &v, 4) != 4) { reportError(); return -1; }
64 return 0;
68 static uint32_t getUInt (const void *buf) {
69 uint32_t res;
71 memcpy(&res, buf, 4);
72 return le32toh(res);
76 static int writeWDX (const char *fname, const void *pbuf, int pSize, int origSize, uint32_t crc) {
77 static char *sign = "WDX0";
78 int fd;
80 if (pSize < 0) return -1;
81 fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644);
82 if (fd < 0) goto error;
83 if (write(fd, sign, 4) != 4) goto error;
84 if (writeUInt(fd, (uint32_t)origSize)) goto error1;
85 if (writeUInt(fd, crc)) goto error1;
86 if (writeUInt(fd, (uint32_t)pSize)) goto error1;
87 if (write(fd, pbuf, pSize) != pSize) goto error1;
88 if (close(fd) < 0) { unlink(fname); fd = -1; goto error; }
89 return 0;
90 error:
91 reportError();
92 error1:
93 if (fd >= 0) {
94 close(fd);
95 unlink(fname);
97 return -1;
101 static int pack (const char *fin, const char *fout) {
102 uint32_t crc;
103 void *ibuf, *obuf;
104 int isz, osz, psz;
106 if (!(ibuf = loadWholeFile(fin, &isz))) {
107 fprintf(stderr, "ERROR: can't read input file: %s\n", fin);
108 return 1;
110 osz = wdxPackBufferSize(isz);
111 obuf = malloc(osz);
112 if (!obuf) {
113 free(ibuf);
114 fprintf(stderr, "ERROR: out of memory!\n");
115 return 1;
117 crc = wdxCRC32(ibuf, isz);
118 fprintf(stdout, "packing %d bytes ... ", isz); fflush(stdout);
119 psz = wdxPack(obuf, osz, ibuf, isz);
120 free(ibuf);
121 if (psz < 0) {
122 free(obuf);
123 fprintf(stdout, "FAILED!\n");
124 fprintf(stderr, "ERROR: can't pack!\n");
125 return 1;
127 fprintf(stdout, "got %d packed bytes\n", psz); fflush(stdout);
128 osz = writeWDX(fout, obuf, psz, isz, crc);
129 free(obuf);
130 if (osz) {
131 fprintf(stderr, "ERROR: can't write output file: %s\n", fout);
132 return 1;
134 return 0;
138 static int unpack (const char *fin, const char *fout) {
139 uint32_t crc, ncrc;
140 uint8_t *ibuf, *obuf, *origBuf;
141 int isz, osz, psz, xsz;
142 int fo = -1;
144 if (!(ibuf = loadWholeFile(fin, &isz))) {
145 fprintf(stderr, "ERROR: can't read input file: %s\n", fin);
146 return 1;
148 if (isz < 16 || ibuf[0] != 'W' || ibuf[1] != 'D' || ibuf[2] != 'X' || ibuf[3] != '0') {
149 fprintf(stderr, "ERROR: invalid input file: %s\n", fin);
150 return 1;
152 origBuf = ibuf;
153 ibuf += 4; /* skip signature */
154 osz = getUInt(ibuf); ibuf += 4; /* unpacked size */
155 crc = getUInt(ibuf); ibuf += 4; /* crc */
156 psz = getUInt(ibuf); ibuf += 4; /* packed size */
157 obuf = malloc(osz);
158 if (!obuf) {
159 free(origBuf);
160 fprintf(stderr, "ERROR: out of memory!\n");
161 return 1;
163 fprintf(stdout, "unpacking %d bytes to %d bytes ... ", psz, osz); fflush(stdout);
164 xsz = wdxUnpack(obuf, osz, ibuf, psz);
165 free(origBuf);
166 if (xsz < 0 || xsz != osz) {
167 free(obuf);
168 fprintf(stdout, "FAILED!\n");
169 fprintf(stderr, "ERROR: can't unpack! (%d)\n", xsz);
170 return 1;
172 ncrc = wdxCRC32(obuf, xsz);
173 if (ncrc != crc) {
174 free(obuf);
175 fprintf(stdout, "FAILED!\n");
176 fprintf(stderr, "ERROR: CRC check failed!\n");
177 return 1;
179 fprintf(stdout, "OK\n");
180 fo = open(fout, O_CREAT | O_WRONLY | O_TRUNC, 0644);
181 if (fo < 0) {
182 reportError();
183 fprintf(stderr, "ERROR: can't write output file: %s\n", fout);
184 goto error;
186 if (write(fo, obuf, xsz) != xsz) {
187 reportError();
188 fprintf(stderr, "ERROR: can't write output file (1): %s\n", fout);
189 goto error;
191 if (close(fo) < 0) {
192 reportError();
193 fprintf(stderr, "ERROR: can't write output file (2): %s\n", fout);
194 unlink(fout);
195 fo = -1;
196 goto error;
198 free(obuf);
199 return 0;
200 error:
201 if (fo > 0) {
202 close(fo);
203 unlink(fout);
205 free(obuf);
206 return 0;
210 int main (int argc, char *argv[]) {
211 const char *inname = NULL, *outname = NULL;
213 if (argc == 3) {
214 inname = argv[2];
215 outname = argv[2];
216 } else if (argc > 3) {
217 inname = argv[2];
218 outname = argv[3];
219 } else {
220 fprintf(stderr, "usage: %s <c|d> infile [outfile]\n", argv[0]);
221 return 1;
223 if (!strcmp("c", argv[1]) || !strcmp("-c", argv[1])) return pack(inname, outname);
224 return unpack(inname, outname);