]> git.draconx.ca Git - upkg.git/blobdiff - src/engine/sound.gob
engine: Implement Engine.Sound.
[upkg.git] / src / engine / sound.gob
diff --git a/src/engine/sound.gob b/src/engine/sound.gob
new file mode 100644 (file)
index 0000000..fd0a060
--- /dev/null
@@ -0,0 +1,117 @@
+%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;
+       }
+}