/* * upkg: tool for manipulating Unreal Tournament packages. * Copyright (C) 2009 Nick Bowler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "uobject.h" #include "upkg.h" #include "pack.h" #define U_OBJECT_GET_PRIV(o) \ G_TYPE_INSTANCE_GET_PRIVATE(o, U_OBJECT_TYPE, struct uobject_priv) enum { PROPERTY_BYTE = 1, PROPERTY_INTEGER, PROPERTY_BOOLEAN, PROPERTY_FLOAT, PROPERTY_OBJECT, PROPERTY_NAME, PROPERTY_STRING, PROPERTY_CLASS, PROPERTY_ARRAY, PROPERTY_STRUCT, PROPERTY_VECTOR, PROPERTY_ROTATOR, PROPERTY_STR, PROPERTY_MAP, PROPERTY_FIXEDARRAY, }; struct uobject_property { const char *name; GValue val; }; struct uobject_priv { struct upkg_file *f; size_t base, len; unsigned char buf[2048]; unsigned long nbuf; }; static unsigned long get_real_size(unsigned long *real, unsigned size, unsigned char *buf, size_t n) { assert(size < 8); *real = 0; switch (size) { case 0: *real = 1; return 0; case 1: *real = 2; return 0; case 2: *real = 4; return 0; case 3: *real = 12; return 0; case 4: *real = 16; return 0; case 5: if (n < 1) return 0; *real = *buf; return 1; case 6: if (n < 2) return 0; *real = unpack_16_le(buf); return 2; case 7: if (n < 4) return 0; *real = unpack_32_le(buf); return 4; } return 0; } static unsigned long decode_property(UObject *o, const char *name, struct upkg_file *f, unsigned long len) { struct uobject_priv *priv = U_OBJECT_GET_PRIV(o); unsigned long real_size, rc; int type, size, top; GValue val = {0}; if (priv->nbuf-len < 1) return 0; type = (priv->buf[len] >> 0) & 0x0f; size = (priv->buf[len] >> 4) & 0x07; top = (priv->buf[len] >> 7) & 0x01; len += 1; rc = get_real_size(&real_size, size, priv->buf, priv->nbuf-len); if (real_size == 0) return 0; len += rc; switch (type) { case PROPERTY_BYTE: if (priv->nbuf-len < 1) return 0; g_value_init(&val, G_TYPE_UCHAR); g_value_set_uchar(&val, priv->buf[len]); g_object_set_property(G_OBJECT(o), name, &val); break; case PROPERTY_INTEGER: if (priv->nbuf-len < 4) return 0; g_value_init(&val, G_TYPE_ULONG); g_value_set_ulong(&val, unpack_32_le(priv->buf+len)); g_object_set_property(G_OBJECT(o), name, &val); break; default: fprintf(stderr, "Unhandled property type %x\n", (unsigned)type); } real_size += len; if (real_size + len <= priv->nbuf) { priv->nbuf -= real_size; memmove(priv->buf, priv->buf+real_size, priv->nbuf); } else { long skip = real_size - priv->nbuf; if (upkg_export_seek(f, skip, SEEK_CUR) != 0) return 0; priv->nbuf = 0; } return real_size; } /* Deserialize properties from an Unreal package. */ static int deserialize(UObject *o, struct upkg_file *f) { struct uobject_priv *priv = U_OBJECT_GET_PRIV(o); unsigned long rc, tot_len = 0; while (1) { unsigned long len = 0; const char *name; long tmp; /* Read some data into buffer. */ if (!f->eof) { void *buf = priv->buf + priv->nbuf; size_t amt = sizeof priv->buf - priv->nbuf; rc = upkg_export_read(f, buf, amt); if (rc == 0) return -1; priv->nbuf += rc; } /* Get the property name. */ rc = upkg_decode_index(&tmp, priv->buf+len, priv->nbuf-len); if (rc == 0) return -1; len = rc; name = upkg_get_name(f->pkg, tmp); if (!name) { return -1; } else if (strcmp(name, "None") == 0) { tot_len += len; break; } rc = decode_property(U_OBJECT(o), name, f, len); if (rc == 0) return -1; len = rc; tot_len += len; } f->base += tot_len; f->len -= tot_len; upkg_export_seek(f, 0, SEEK_SET); return 0; } int u_object_deserialize(GObject *obj, struct upkg_file *f) { g_return_val_if_fail(IS_U_OBJECT(obj), -1); return U_OBJECT_GET_CLASS(obj)->deserialize(U_OBJECT(obj), f); } static void u_object_init(UObject *o) { struct uobject_priv *priv = U_OBJECT_GET_PRIV(o); } static void u_object_class_init(UObjectClass *class) { g_type_class_add_private(class, sizeof (struct uobject_priv)); class->deserialize = deserialize; } G_DEFINE_TYPE(UObject, u_object, G_TYPE_OBJECT);