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/>.
23 #include <glib-object.h>
25 #include <uobject/uobject.h>
26 #include <uobject/module.h>
30 #define U_OBJECT_GET_PRIV(o) \
31 G_TYPE_INSTANCE_GET_PRIVATE(o, U_OBJECT_TYPE, struct u_object_priv)
51 struct u_object_priv {
55 unsigned char buf[2048];
59 G_DEFINE_TYPE(UObject, u_object, G_TYPE_OBJECT);
62 get_real_size(unsigned long *real, unsigned size, unsigned char *buf, size_t n)
68 case 0: *real = 1; return 0;
69 case 1: *real = 2; return 0;
70 case 2: *real = 4; return 0;
71 case 3: *real = 12; return 0;
72 case 4: *real = 16; return 0;
79 *real = unpack_16_le(buf);
83 *real = unpack_32_le(buf);
90 static int decode_object_property(UObject *uo, GValue *val, unsigned long len)
92 struct u_object_priv *priv = U_OBJECT_GET_PRIV(uo);
97 rc = upkg_decode_index(&index, priv->buf+len, priv->nbuf-len);
98 if (rc == 0 || index == 0)
102 fprintf(stderr, "Imports not supported yet.\n");
104 obj = u_object_new_from_package(uo->pkg, index-1);
107 g_value_init(val, U_OBJECT_TYPE);
108 g_value_take_object(val, obj);
113 * XXX: I must have been smoking the happy plant when I started property
114 * decoding. The tracking of various sizes in these functions makes no
119 decode_property(UObject *o, const char *name, struct upkg_file *f, unsigned long len)
121 struct u_object_priv *priv = U_OBJECT_GET_PRIV(o);
122 unsigned long real_size, rc;
126 if (priv->nbuf-len < 1)
129 type = (priv->buf[len] >> 0) & 0x0f;
130 size = (priv->buf[len] >> 4) & 0x07;
131 top = (priv->buf[len] >> 7) & 0x01;
134 rc = get_real_size(&real_size, size, priv->buf, priv->nbuf-len);
141 if (priv->nbuf-len < 1)
143 g_value_init(&val, G_TYPE_UCHAR);
144 g_value_set_uchar(&val, priv->buf[len]);
145 g_object_set_property(G_OBJECT(o), name, &val);
147 case PROPERTY_INTEGER:
148 if (priv->nbuf-len < 4)
150 g_value_init(&val, G_TYPE_ULONG);
151 g_value_set_ulong(&val, unpack_32_le(priv->buf+len));
152 g_object_set_property(G_OBJECT(o), name, &val);
154 case PROPERTY_OBJECT:
155 rc = decode_object_property(o, &val, len);
158 g_object_set_property(G_OBJECT(o), name, &val);
161 fprintf(stderr, "Unhandled property type %x\n", (unsigned)type);
165 if (real_size + len <= priv->nbuf) {
166 priv->nbuf -= real_size;
167 memmove(priv->buf, priv->buf+real_size, priv->nbuf);
169 long skip = real_size - priv->nbuf;
170 if (upkg_export_seek(f, skip, SEEK_CUR) != 0)
178 /* Deserialize properties from an Unreal package. */
179 static int deserialize(UObject *uo)
181 struct u_object_priv *priv = U_OBJECT_GET_PRIV(uo);
182 struct upkg_file *f = uo->pkg_file;
183 unsigned long rc, tot_len = 0;
186 unsigned long len = 0;
190 /* Read some data into buffer. */
192 void *buf = priv->buf + priv->nbuf;
193 size_t amt = sizeof priv->buf - priv->nbuf;
194 rc = upkg_export_read(f, buf, amt);
195 if (rc == 0 && priv->nbuf == 0)
200 /* Get the property name. */
201 rc = upkg_decode_index(&tmp, priv->buf+len, priv->nbuf-len);
206 name = upkg_get_name(uo->pkg, tmp);
209 } else if (strcmp(name, "None") == 0) {
214 rc = decode_property(uo, name, f, len);
224 upkg_export_seek(f, 0, SEEK_SET);
229 int u_object_deserialize(GObject *obj, struct upkg *pkg, unsigned long idx)
231 g_return_val_if_fail(IS_U_OBJECT(obj), -1);
232 UObject *uo = U_OBJECT(obj);
236 g_return_val_if_fail(uo->pkg_file == NULL, -1);
237 f = upkg_export_open(pkg, idx);
245 rc = U_OBJECT_GET_CLASS(obj)->deserialize(uo);
247 upkg_export_close(f);
254 GObject *u_object_new_from_package(struct upkg *upkg, unsigned long idx)
256 const struct upkg_export *export;
257 const char *class, *package;
261 class = upkg_export_class(upkg, idx, &package);
263 type = u_object_module_get_class(package, class);
265 obj = g_object_new(type, NULL);
266 if (u_object_deserialize(obj, upkg, idx) != 0) {
275 static void u_object_init(UObject *o)
281 static void u_object_finalize(GObject *o)
283 UObject *uo = U_OBJECT(o);
286 upkg_export_close(uo->pkg_file);
289 G_OBJECT_CLASS(u_object_parent_class)->finalize(o);
292 static void u_object_class_init(UObjectClass *class)
294 g_type_class_add_private(class, sizeof (struct u_object_priv));
295 GObjectClass *go = G_OBJECT_CLASS(class);
297 class->deserialize = deserialize;
298 go->finalize = u_object_finalize;