+%alltop{
+/*
+ * upkg: tool for manipulating Unreal Tournament packages.
+ * Copyright © 2011 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+%}
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <uobject/exportable.h>
+#include "pack.h"
+%}
+
+%h{
+#include <uobject/uobject.h>
+%}
+
+class Engine:Sound from U:Object (dynamic)
+ (interface U:Object:Exportable)
+{
+ interface U:Object:Exportable
+ private int export(U:Object *uo, FILE *outf)
+ {
+ struct upkg_file *f = uo->pkg_file;
+ unsigned char buf[1024];
+ size_t buflen;
+
+ if (upkg_export_seek(f, 0, SEEK_SET) != 0)
+ return -1;
+
+ do {
+ buflen = upkg_export_read(f, buf, sizeof buf);
+ if (fwrite(buf, buflen, 1, outf) != 1)
+ return -1;
+ } while (buflen == sizeof buf);
+
+ if (!f->eof)
+ return -1;
+ return 0;
+ }
+
+ interface U:Object:Exportable
+ private int export_name(U:Object *uo, char *buf, size_t n)
+ {
+ return snprintf(buf, n, "%s.wav", uo->pkg_file->name);
+ }
+
+ override (U:Object) int deserialize(U:Object *uo)
+ {
+ struct upkg_file *f = uo->pkg_file;
+ size_t rc, pos = 0, buflen;
+ unsigned char buf[32];
+ unsigned long end_offset;
+ const char *fmt_name;
+ long size, fmt;
+
+ PARENT_HANDLER(uo);
+
+ buflen = upkg_export_read(f, buf, sizeof buf);
+
+ /* This seems to be the name of the format. The only format
+ * that actually gets used is WAV, so we can check that. */
+ rc = upkg_decode_index(&fmt, buf+pos, buflen-pos);
+ if (rc == 0)
+ return -1;
+ pos += rc;
+
+ fmt_name = upkg_get_name(f->pkg, fmt);
+ if (!fmt_name || strcasecmp(fmt_name, "wav") != 0) {
+ u_err(uo, "format name is not WAV");
+ return -1;
+ }
+
+ /* Like textures, there's an (apparently useless) offset to
+ * the end of the sound data which is implied by the next
+ * field. Just validate it. */
+ if (f->pkg->version >= 63) {
+ if (pos + 4 > buflen)
+ return -1;
+ end_offset = unpack_32_le(buf+pos);
+ pos += 4;
+ }
+
+ rc = upkg_decode_index(&size, buf+pos, buflen-pos);
+ if (rc == 0 || size < 0 || size > f->len - pos)
+ return -1;
+ pos += rc;
+
+ f->base += pos;
+ f->len = size;
+ upkg_export_seek(f, 0, SEEK_SET);
+
+ if (f->pkg->version >= 63) {
+ if (end_offset != f->base + f->len) {
+ u_err(uo, "end offset does not match size");
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+}