2 * upkg: tool for manipulating Unreal Tournament packages.
3 * Copyright © 2009-2011 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 3 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, see <http://www.gnu.org/licenses/>.
24 #include <glib-object.h>
26 #include <uobject/uobject.h>
27 #include <uobject/module.h>
31 #define U_OBJECT_GET_PRIV(o) \
32 G_TYPE_INSTANCE_GET_PRIVATE(o, U_TYPE_OBJECT, struct u_object_priv)
36 const char *prop_name, *struct_name;
37 unsigned long size, array_idx;
60 struct u_object_priv {
64 unsigned char buf[2048];
68 G_DEFINE_TYPE(UObject, u_object, G_TYPE_OBJECT);
71 * Determine the actual size (in bytes) of a property, given the 3-bit encoded
72 * size from the tag byte. Depending on the tag size, there will be 0, 1, 2
73 * or 4 additional size bytes, which are to be found in the provided buffer
74 * which is at least n bytes long. The result is stored in *size.
76 * Returns the number of bytes that were read from the buffer, which may be 0.
77 * On failure, (i.e., there was not enough material in the buffer) 0 is stored
81 decode_tag_size(unsigned long *size, unsigned tag_size,
82 const unsigned char *buf, unsigned long n)
87 case 0: *size = 1; return 0;
88 case 1: *size = 2; return 0;
89 case 2: *size = 4; return 0;
90 case 3: *size = 12; return 0;
91 case 4: *size = 16; return 0;
100 *size = unpack_16_le(buf);
105 *size = unpack_32_le(buf);
113 decode_array_index(unsigned long *index, const unsigned char *buf,
119 /* TODO: Actually implement this instead of aborting. */
120 assert("FIXME" && !(buf[0] & 0x80));
127 * Decode the (mostly) generic property header, filling out the struct pointed
128 * to by head. Returns the number of bytes read from the buffer, or 0 on
132 decode_prop_header(struct upkg *upkg, struct prop_head *head,
133 const unsigned char *buf, unsigned long n)
135 unsigned long rc, len = 0;
136 unsigned char tag_size;
139 rc = upkg_decode_index(&index, buf+len, n-len);
142 if (!(head->prop_name = upkg_get_name(upkg, index)))
146 /* A property called "None" terminates the list, and does not have
147 * the usual header. */
148 if (!strcmp(head->prop_name, "None")) {
149 head->type = PROPERTY_END;
156 head->tag_msb = (buf[len] >> 7) & 0x01;
157 tag_size = (buf[len] >> 4) & 0x07;
158 head->type = (buf[len] >> 0) & 0x0f;
162 * TODO: Confirm the correct relative ordering of the next three
165 if (head->type == PROPERTY_STRUCT) {
166 rc = upkg_decode_index(&index, buf+len, n-len);
169 if (!(head->struct_name = upkg_get_name(upkg, index)))
174 rc = decode_tag_size(&head->size, tag_size, buf+len, n-len);
180 if (head->tag_msb && head->type != PROPERTY_BOOLEAN) {
181 rc = decode_array_index(&head->array_idx, buf+len, n-len);
190 static int decode_object_property(UObject *uo, GValue *val, unsigned long len)
192 struct u_object_priv *priv = U_OBJECT_GET_PRIV(uo);
197 rc = upkg_decode_index(&index, priv->buf+len, priv->nbuf-len);
198 if (rc == 0 || index == 0)
202 fprintf(stderr, "Imports not supported yet.\n");
204 obj = u_object_new_from_package(uo->pkg, index-1);
207 g_value_init(val, U_TYPE_OBJECT);
208 g_value_take_object(val, obj);
212 static unsigned long deserialize_property(UObject *uo, struct prop_head *head)
214 struct u_object_priv *priv = U_OBJECT_GET_PRIV(uo);
215 unsigned long rc, len = 0;
218 rc = decode_prop_header(uo->pkg, head, priv->buf, priv->nbuf);
223 switch (head->type) {
227 if (priv->nbuf-len < 1)
229 g_value_init(&val, G_TYPE_UCHAR);
230 g_value_set_uchar(&val, priv->buf[len]);
231 g_object_set_property(G_OBJECT(uo), head->prop_name, &val);
233 case PROPERTY_INTEGER:
234 if (priv->nbuf-len < 4)
236 g_value_init(&val, G_TYPE_ULONG);
237 g_value_set_ulong(&val, unpack_32_le(priv->buf+len));
238 g_object_set_property(G_OBJECT(uo), head->prop_name, &val);
240 case PROPERTY_OBJECT:
241 rc = decode_object_property(uo, &val, len);
244 g_object_set_property(G_OBJECT(uo), head->prop_name, &val);
247 fprintf(stderr, "Unhandled property type %x\n",
248 (unsigned)head->type);
252 if (len > priv->nbuf) {
253 long skip = len - priv->nbuf;
255 /* XXX: Long properties are not supported yet, so just seek
256 * past them for now. */
257 if (upkg_export_seek(uo->pkg_file, skip, SEEK_CUR) != 0)
263 memmove(priv->buf, priv->buf+len, priv->nbuf-len);
269 /* Deserialize properties from an Unreal package. */
270 static int deserialize(UObject *uo)
272 struct u_object_priv *priv = U_OBJECT_GET_PRIV(uo);
273 struct upkg_file *f = uo->pkg_file;
274 unsigned long rc, tot_len = 0;
277 struct prop_head head;
279 /* Prime the buffer; deserialize_property assumes that there's
280 * enough data for "small" properties already available. */
282 void *buf = priv->buf + priv->nbuf;
283 size_t amt = sizeof priv->buf - priv->nbuf;
284 rc = upkg_export_read(f, buf, amt);
285 if (rc == 0 && priv->nbuf == 0)
290 rc = deserialize_property(uo, &head);
296 if (head.type == PROPERTY_END)
302 upkg_export_seek(f, 0, SEEK_SET);
307 int u_object_deserialize(GObject *obj, struct upkg *pkg, unsigned long idx)
309 g_return_val_if_fail(IS_U_OBJECT(obj), -1);
310 UObject *uo = U_OBJECT(obj);
314 g_return_val_if_fail(uo->pkg_file == NULL, -1);
315 f = upkg_export_open(pkg, idx);
323 rc = U_OBJECT_GET_CLASS(obj)->deserialize(uo);
325 upkg_export_close(f);
332 GObject *u_object_new_from_package(struct upkg *upkg, unsigned long idx)
334 const struct upkg_export *export;
335 const char *class, *package;
339 class = upkg_export_class(upkg, idx, &package);
341 type = u_object_module_get_class(package, class);
343 obj = g_object_new(type, NULL);
344 if (u_object_deserialize(obj, upkg, idx) != 0) {
353 static void u_object_init(UObject *o)
359 static void u_object_finalize(GObject *o)
361 UObject *uo = U_OBJECT(o);
364 upkg_export_close(uo->pkg_file);
367 G_OBJECT_CLASS(u_object_parent_class)->finalize(o);
370 static void u_object_class_init(UObjectClass *class)
372 g_type_class_add_private(class, sizeof (struct u_object_priv));
373 GObjectClass *go = G_OBJECT_CLASS(class);
375 class->deserialize = deserialize;
376 go->finalize = u_object_finalize;