2 * upkg: tool for manipulating Unreal Tournament packages.
3 * Copyright (C) 2009 Nick Bowler
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #define MIN(a, b) ((a) < (b) ? (a) : (b))
37 long package, class, super;
39 unsigned long size, offset;
43 const char *class_package, *class_name, *object_name;
50 struct upkg_name *names;
51 struct upkg_export *exports;
52 struct upkg_import *imports;
54 unsigned long name_offset, export_offset, import_offset;
55 unsigned char guid[16];
59 * Decode the compact index format from the upkg. This format is fucked.
60 * Stores the result in *val and returns the number of input bytes read (or 0
61 * if the input is invalid, in which case *val is undefined).
63 static size_t decode_index(long *val, unsigned char *bytes, size_t n)
68 while (i < MIN(n, 5)) {
70 * Least significant bytes are first, so we need to do this
73 long tmp = bytes[i] & (i == 0 ? 0x3f : 0x7f);
76 if (i > 1) tmp <<= 7*(i-1);
79 if (!(bytes[i] & (i == 0 ? 0x40 : 0x80))) {
87 if (i > MIN(n, 5) || n == 0)
94 static struct upkg *init_upkg(unsigned char hdr[static UPKG_HDR_SIZE])
98 pkg = malloc(sizeof *pkg);
103 pkg->priv = malloc(sizeof *pkg->priv);
109 pkg->version = unpack_16_le(hdr+4);
110 pkg->license = unpack_16_le(hdr+6);
111 pkg->flags = unpack_32_le(hdr+8);
112 pkg->name_count = unpack_32_le(hdr+12);
113 pkg->export_count = unpack_32_le(hdr+20);
114 pkg->import_count = unpack_32_le(hdr+28);
116 pkg->priv->name_offset = unpack_32_le(hdr+16);
117 pkg->priv->export_offset = unpack_32_le(hdr+24);
118 pkg->priv->import_offset = unpack_32_le(hdr+32);
123 static int pkg_init_names(struct upkg *pkg)
125 size_t rc, len, nbuf = 0;
126 unsigned long index = 0;
129 if (fseek(pkg->priv->f, pkg->priv->name_offset, SEEK_SET) != 0)
132 pkg->priv->names = malloc(pkg->name_count * sizeof *pkg->priv->names);
133 if (!pkg->priv->names)
136 while (index < pkg->name_count) {
137 struct upkg_name *name = &pkg->priv->names[index];
139 /* Read some data into buffer. */
140 if (!feof(pkg->priv->f)) {
141 rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f);
147 if (pkg->version >= 64) {
149 if (nbuf <= len + 4 || buf[len])
151 name->name = malloc(len);
154 memcpy(name->name, buf+1, len);
155 name->flags = unpack_32_le(buf+len+1);
159 memmove(buf, buf+len+1, nbuf);
162 char *c = memchr(buf, 0, nbuf);
163 if (!c || nbuf <= c - buf + 5)
166 name->name = malloc(len);
169 memcpy(name->name, buf, len);
170 name->flags = unpack_32_le(buf+len);
174 memmove(buf, buf+len, nbuf);
181 for (unsigned i = 0; i < index; i++)
182 free(pkg->priv->names[i].name);
183 free(pkg->priv->names);
187 static int pkg_init_exports(struct upkg *pkg)
189 size_t rc, len, nbuf = 0;
190 unsigned long index = 0;
193 if (fseek(pkg->priv->f, pkg->priv->export_offset, SEEK_SET) != 0)
196 pkg->priv->exports = malloc(pkg->export_count * sizeof *pkg->priv->exports);
197 if (!pkg->priv->exports)
200 while (index < pkg->export_count) {
201 struct upkg_export *export = &pkg->priv->exports[index];
204 /* Read some data into buffer. */
205 if (!feof(pkg->priv->f)) {
206 rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f);
213 rc = decode_index(&export->class, buf+len, nbuf-len);
214 if (rc == 0) goto err;
217 rc = decode_index(&export->super, buf+len, nbuf-len);
218 if (rc == 0) goto err;
221 if (nbuf-len < 4) goto err;
222 export->package = unpack_32_le(buf+len);
225 rc = decode_index(&tmp, buf+len, nbuf-len);
226 if (rc == 0 || tmp < 0 || tmp >= pkg->name_count) goto err;
227 export->name = pkg->priv->names[tmp].name;
230 if (nbuf-len < 4) goto err;
231 export->flags = unpack_32_le(buf+len);
234 rc = decode_index(&export->size, buf+len, nbuf-len);
235 if (rc == 0) goto err;
239 rc = decode_index(&export->offset, buf+len, nbuf-len);
240 if (rc == 0) goto err;
245 memmove(buf, buf+len, nbuf);
251 free(pkg->priv->exports);
255 static int pkg_init_imports(struct upkg *pkg)
257 size_t rc, len, nbuf = 0;
258 unsigned long index = 0;
261 if (fseek(pkg->priv->f, pkg->priv->import_offset, SEEK_SET) != 0)
264 pkg->priv->imports = malloc(pkg->import_count * sizeof *pkg->priv->imports);
265 if (!pkg->priv->imports)
268 while (index < pkg->import_count) {
269 struct upkg_import *import = &pkg->priv->imports[index];
272 /* Read some data into buffer. */
273 if (!feof(pkg->priv->f)) {
274 rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f);
281 rc = decode_index(&tmp, buf+len, nbuf-len);
282 if (rc == 0 || len < 0 || len >= pkg->name_count) goto err;
283 import->class_package = pkg->priv->names[tmp].name;
286 rc = decode_index(&tmp, buf+len, nbuf-len);
287 if (rc == 0 || len < 0 || len >= pkg->name_count) goto err;
288 import->class_name = pkg->priv->names[tmp].name;
291 if (nbuf-len < 4) goto err;
292 import->package = unpack_32_le(buf+len);
295 rc = decode_index(&tmp, buf+len, nbuf-len);
296 if (rc == 0 || len < 0 || len >= pkg->name_count) goto err;
297 import->object_name = pkg->priv->names[tmp].name;
301 memmove(buf, buf+len, nbuf);
307 free(pkg->priv->imports);
311 struct upkg *upkg_fopen(const char *path)
313 unsigned char hdr_buf[UPKG_HDR_SIZE];
317 if (!(f = fopen(path, "rb"))) {
320 if (fread(hdr_buf, sizeof hdr_buf, 1, f) != 1) {
323 if (unpack_32_le(hdr_buf) != UPKG_HDR_MAGIC) {
327 /* Initialize package structure. */
328 pkg = init_upkg(hdr_buf);
334 if (pkg_init_names(pkg) != 0) {
338 if (pkg_init_exports(pkg) != 0) {
342 if (pkg_init_imports(pkg) != 0) {
348 free(pkg->priv->exports);
350 for (unsigned i = 0; i < pkg->name_count; i++)
351 free(pkg->priv->names[i].name);
352 free(pkg->priv->names);
361 int upkg_close(struct upkg *pkg)
366 rc = fclose(pkg->priv->f);
368 for (unsigned i = 0; i < pkg->name_count; i++) {
369 free(pkg->priv->names[i].name);
373 free(pkg->priv->imports);
374 free(pkg->priv->exports);
375 free(pkg->priv->names);
382 const char *upkg_get_name(struct upkg *pkg, unsigned long idx)
384 if (idx >= pkg->name_count)
386 return pkg->priv->names[idx].name;